1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Copyright (c) 2018, Joyent, Inc. 28 */ 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <strings.h> 34 #include <sys/types.h> 35 #include <errno.h> 36 #include <syslog.h> 37 #include <unistd.h> 38 #include <sys/types.h> 39 #include <sys/socket.h> 40 #include <sys/time.h> 41 #include <netinet/in.h> 42 #include <arpa/inet.h> 43 #include <netdb.h> 44 #include <sys/stat.h> 45 #include <sys/sdt.h> 46 #include <signal.h> 47 #include <fcntl.h> 48 #include <libstmfproxy.h> 49 50 /* 51 * NOTE: 52 * This is demo code to be used with the existing demo proxy daemon 53 * svc-stmfproxy in /usr/demo/comstar. 54 */ 55 56 struct _s_handle { 57 int sockfd; 58 }; 59 60 typedef struct _s_handle s_handle_t; 61 62 static ssize_t 63 pt_socket_recv(void *handle, void *buf, size_t len) 64 { 65 s_handle_t *sh = handle; 66 67 return (recv(sh->sockfd, buf, len, MSG_WAITALL)); 68 } 69 70 static ssize_t 71 pt_socket_send(void *handle, void *buf, size_t len) 72 { 73 s_handle_t *sh = handle; 74 75 return (send(sh->sockfd, buf, len, 0)); 76 } 77 78 static void * 79 pt_socket_connect(int server_node, char *server) 80 { 81 int sfd, new_sfd; 82 s_handle_t *sh = NULL; 83 int on = 1; 84 struct sockaddr_in cli_addr, serv_addr; 85 struct sockaddr_in sin; 86 int cliLen = sizeof (cli_addr); 87 88 if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) <= 0) { 89 syslog(LOG_DAEMON|LOG_WARNING, 90 "socket() call failed: %d", errno); 91 return (NULL); 92 } 93 94 if (server_node) { 95 96 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, 97 sizeof (on)) < 0) { 98 syslog(LOG_DAEMON|LOG_WARNING, 99 "setsockopt() failed: %d", errno); 100 goto serv_out; 101 } 102 103 bzero(&serv_addr, sizeof (serv_addr)); 104 serv_addr.sin_family = AF_INET; 105 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 106 /* XXX get from smf? */ 107 serv_addr.sin_port = htons(6543); 108 109 if (bind(sfd, (struct sockaddr *)&serv_addr, 110 sizeof (serv_addr)) < 0) { 111 syslog(LOG_DAEMON|LOG_WARNING, "bind() call failed: %d", 112 errno); 113 goto serv_out; 114 } 115 116 (void) listen(sfd, 5); 117 118 new_sfd = accept(sfd, (struct sockaddr *)&cli_addr, &cliLen); 119 120 if (new_sfd < 0) { 121 syslog(LOG_DAEMON|LOG_WARNING, "accept failed: %d", 122 errno); 123 goto serv_out; 124 } 125 sh = malloc(sizeof (*sh)); 126 sh->sockfd = new_sfd; 127 serv_out: 128 (void) close(sfd); 129 } else { 130 struct hostent *hp; 131 132 /* 133 * Assume IP dot notation or if that fails, gethostbyname() 134 * If that fails, return 135 */ 136 if ((inet_aton(server, &sin.sin_addr)) == 0) { 137 if ((hp = gethostbyname(server)) != NULL) { 138 memcpy(&sin.sin_addr.s_addr, hp->h_addr, 139 hp->h_length); 140 } else { 141 syslog(LOG_DAEMON|LOG_CRIT, 142 "Cannot get IP address for %s", server); 143 (void) close(sfd); 144 return (NULL); 145 } 146 } else { 147 fprintf(stderr, 148 "Sorry, cannot use ip address format\n"); 149 (void) close(sfd); 150 return (NULL); 151 } 152 sin.sin_family = AF_INET; 153 /* XXX pass in from smf */ 154 sin.sin_port = htons(6543); 155 156 while (connect(sfd, (struct sockaddr *)&sin, 157 sizeof (sin)) < 0) { 158 (void) close(sfd); 159 if (errno == ECONNREFUSED) { 160 /* get a fresh socket and retry */ 161 sfd = socket(AF_INET, SOCK_STREAM, 0); 162 if (sfd < 0) { 163 syslog(LOG_DAEMON|LOG_WARNING, 164 "socket() call failed: %d", errno); 165 return (NULL); 166 } 167 (void) sleep(2); 168 } else { 169 syslog(LOG_DAEMON|LOG_CRIT, 170 "Cannot connect %s - %d", server, errno); 171 return (NULL); 172 } 173 } 174 sh = malloc(sizeof (*sh)); 175 sh->sockfd = sfd; 176 } 177 return (sh); 178 } 179 180 pt_ops_t pt_socket_ops = { 181 pt_socket_connect, 182 pt_socket_send, 183 pt_socket_recv 184 }; 185 186 int 187 stmf_proxy_transport_init(char *transport, pt_ops_t **pt_ops) 188 { 189 if (strcmp(transport, "sockets") == 0) { 190 *pt_ops = &pt_socket_ops; 191 return (0); 192 } else { 193 return (-1); 194 } 195 }