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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/socket.h> 29 #include <string.h> 30 #include <strings.h> 31 #include <stdlib.h> 32 #include <stdio.h> 33 #include <errno.h> 34 #include <netinet/in.h> 35 #include <netinet/tcp.h> 36 #include <assert.h> 37 #include <syslog.h> 38 #include <unistd.h> 39 40 #include "queue.h" 41 #include "port.h" 42 #include "iscsi_conn.h" 43 #include "utility.h" 44 45 pthread_mutex_t port_mutex; 46 int port_conn_num; 47 iscsi_conn_t *conn_head = NULL; 48 iscsi_conn_t *conn_tail = NULL; 49 50 void 51 port_init(void) 52 { 53 (void) pthread_mutex_init(&port_mutex, NULL); 54 port_conn_num = 0; 55 } 56 57 void 58 canonicalize_sockaddr(struct sockaddr_storage *st) 59 { 60 struct in6_addr *addr6 = &((struct sockaddr_in6 *)st)->sin6_addr; 61 62 /* 63 * If target address is IPv4 mapped IPv6 address convert it to IPv4 64 * address. 65 */ 66 if (st->ss_family == AF_INET6 && 67 (IN6_IS_ADDR_V4MAPPED(addr6) || IN6_IS_ADDR_V4COMPAT(addr6))) { 68 struct in_addr *addr = &((struct sockaddr_in *)st)->sin_addr; 69 IN6_V4MAPPED_TO_INADDR(addr6, addr); 70 st->ss_family = AF_INET; 71 } 72 } 73 74 75 void * 76 port_watcher(void *v) 77 { 78 int s; 79 int fd; 80 int on = 1; 81 char debug[80]; 82 struct sockaddr_in sin_ip; 83 struct sockaddr_in6 sin6_ip; 84 struct sockaddr_storage st; 85 socklen_t socklen; 86 iscsi_conn_t *conn; 87 port_args_t *p = (port_args_t *)v; 88 target_queue_t *q = p->port_mgmtq; 89 int l; 90 const int just_say_no = 1; 91 pthread_t junk; 92 93 /* 94 * Try creating an IPv6 socket first 95 * If failed, try creating an IPv4 socket 96 */ 97 if ((s = socket(PF_INET6, SOCK_STREAM, 0)) == -1) { 98 99 queue_str(q, Q_GEN_ERRS, msg_log, "Opening IPv4 socket"); 100 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) { 101 queue_str(q, Q_GEN_ERRS, msg_log, 102 "Can't open socket"); 103 return (NULL); 104 } else { 105 bzero(&sin_ip, sizeof (sin_ip)); 106 sin_ip.sin_family = AF_INET; 107 sin_ip.sin_port = htons(p->port_num); 108 sin_ip.sin_addr.s_addr = INADDR_ANY; 109 110 (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 111 (char *)&on, sizeof (on)); 112 113 if ((bind(s, (struct sockaddr *)&sin_ip, 114 sizeof (sin_ip))) < 0) { 115 (void) snprintf(debug, sizeof (debug), 116 "bind on port %d failed, errno %d", 117 p->port_num, errno); 118 queue_str(q, Q_GEN_ERRS, msg_status, debug); 119 return (NULL); 120 } 121 } 122 123 } else { 124 125 queue_str(q, Q_GEN_DETAILS, msg_log, "Got IPv6 socket"); 126 bzero(&sin6_ip, sizeof (sin6_ip)); 127 sin6_ip.sin6_family = AF_INET6; 128 sin6_ip.sin6_port = htons(p->port_num); 129 sin6_ip.sin6_addr = in6addr_any; 130 131 (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, 132 sizeof (on)); 133 134 if ((bind(s, (struct sockaddr *)&sin6_ip, sizeof (sin6_ip))) 135 < 0) { 136 (void) snprintf(debug, sizeof (debug), 137 "bind on port %d failed, errno %d", 138 p->port_num, errno); 139 queue_str(q, Q_GEN_ERRS, msg_status, debug); 140 return (NULL); 141 } 142 } 143 144 if (listen(s, 128) < 0) { 145 queue_str(q, Q_GEN_ERRS, msg_status, "listen failed"); 146 return (NULL); 147 } 148 149 /*CONSTANTCONDITION*/ 150 while (1) { 151 152 socklen = sizeof (st); 153 if ((fd = accept(s, (struct sockaddr *)&st, 154 &socklen)) < 0) { 155 if (errno != EINTR) 156 queue_prt(q, Q_GEN_ERRS, 157 "accept failed, %s", strerror(errno)); 158 (void) sleep(1); 159 continue; 160 } 161 162 l = 128 * 1024; 163 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&l, 164 sizeof (l)) < 0) 165 queue_str(q, Q_GEN_ERRS, msg_status, 166 "setsockopt failed"); 167 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *)&l, 168 sizeof (l)) < 0) 169 queue_str(q, Q_GEN_ERRS, msg_status, 170 "setsockopt failed"); 171 l = 1; 172 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&l, 173 sizeof (l)) < 0) 174 queue_str(q, Q_GEN_ERRS, msg_status, 175 "setsockopt keepalive failed"); 176 177 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, 178 (char *)&just_say_no, sizeof (just_say_no)) != 0) 179 queue_str(q, Q_GEN_ERRS, msg_status, 180 "setsockopt NODELAY failed"); 181 182 if ((conn = calloc(1, sizeof (iscsi_conn_t))) == NULL) { 183 /* 184 * If we fail to get memory this is all rather 185 * pointless, since it's unlikely that queue_str 186 * could malloc memory to send a message. 187 */ 188 queue_str(q, Q_GEN_ERRS, msg_status, 189 "connection malloc failed"); 190 return (NULL); 191 } 192 193 /* 194 * Save initiator address for future use. 195 */ 196 canonicalize_sockaddr(&st); 197 conn->c_initiator_sockaddr = st; 198 199 /* 200 * Save target address for future use. 201 */ 202 socklen = sizeof (st); 203 if (getsockname(fd, (struct sockaddr *)&st, &socklen) == 0) 204 canonicalize_sockaddr(&st); 205 else 206 st.ss_family = AF_UNSPEC; 207 conn->c_target_sockaddr = st; 208 209 conn->c_fd = fd; 210 conn->c_mgmtq = q; 211 conn->c_up_at = time(NULL); 212 conn->c_state = S1_FREE; 213 (void) pthread_mutex_init(&conn->c_mutex, NULL); 214 (void) pthread_mutex_init(&conn->c_state_mutex, NULL); 215 (void) pthread_mutex_lock(&port_mutex); 216 conn->c_num = port_conn_num++; 217 if (conn_head == NULL) { 218 conn_head = conn; 219 assert(conn_tail == NULL); 220 conn_tail = conn; 221 } else { 222 conn_tail->c_next = conn; 223 conn->c_prev = conn_tail; 224 conn_tail = conn; 225 } 226 (void) pthread_mutex_unlock(&port_mutex); 227 228 (void) pthread_create(&junk, NULL, conn_process, conn); 229 } 230 return (NULL); 231 } 232 233 void 234 port_conn_remove(iscsi_conn_t *c) 235 { 236 iscsi_conn_t *n; 237 238 (void) pthread_mutex_lock(&port_mutex); 239 if (conn_head == c) { 240 conn_head = c->c_next; 241 if (conn_head == NULL) 242 conn_tail = NULL; 243 else 244 conn_head->c_prev = NULL; 245 } else { 246 n = c->c_prev; 247 n->c_next = c->c_next; 248 if (c->c_next != NULL) 249 c->c_next->c_prev = n; 250 else { 251 assert(conn_tail == c); 252 conn_tail = n; 253 } 254 } 255 256 /* 257 * The connection queue is freed here so that it's protected by 258 * locks. The main thread of the deamon when processing incoming 259 * management requests will send them on the connection queues. 260 * The main thread will grab the port_mutex so that we know the 261 * queue is still valid. 262 */ 263 queue_free(c->c_dataq, conn_queue_data_remove); 264 (void) pthread_mutex_unlock(&port_mutex); 265 } 266