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 <stdlib.h> 28 #include <stdio.h> 29 #include <sys/types.h> 30 #include <sys/socket.h> 31 #include <netinet/in.h> 32 #include <arpa/inet.h> 33 #include <unistd.h> 34 #include <string.h> 35 #include <pthread.h> 36 #include <poll.h> 37 #ifdef DEBUG 38 #include <time.h> 39 #endif 40 41 #include "isns_server.h" 42 #include "isns_cache.h" 43 #include "isns_pdu.h" 44 #include "isns_msgq.h" 45 #include "isns_func.h" 46 #include "isns_log.h" 47 #include "isns_provider.h" 48 49 /* external functions */ 50 #ifdef DEBUG 51 extern void dump_pdu1(isns_pdu_t *); 52 extern int verbose_tc; 53 #endif 54 55 extern boolean_t time_to_exit; 56 57 void * 58 isns_connection( 59 void *arg 60 ) 61 { 62 int status = 0; 63 64 conn_arg_t *conn; 65 66 isns_pdu_t *pdu, *combined_pdu, *new_combined_pdu; 67 uint8_t *payload_ptr; 68 size_t pdu_sz; 69 70 conn = (conn_arg_t *)arg; 71 72 conn->out_packet.pdu = NULL; 73 conn->out_packet.sz = 0; 74 combined_pdu = NULL; 75 pdu = NULL; 76 77 while (status == 0 && 78 time_to_exit == B_FALSE && 79 isns_rcv_pdu(conn->so, &pdu, &pdu_sz, ISNS_RCV_TIMEOUT) > 0) { 80 uint16_t flags = pdu->flags; 81 if (ISNS_MSG_RECEIVED_ENABLED()) { 82 char buf[INET6_ADDRSTRLEN]; 83 struct sockaddr_storage *ssp = &conn->ss; 84 struct sockaddr_in *sinp = (struct sockaddr_in *)ssp; 85 if (ssp->ss_family == AF_INET) { 86 (void) inet_ntop(AF_INET, 87 (void *)&(sinp->sin_addr), 88 buf, sizeof (buf)); 89 } else { 90 (void) inet_ntop(AF_INET6, 91 (void *)&(sinp->sin_addr), 92 buf, sizeof (buf)); 93 } 94 ISNS_MSG_RECEIVED((uintptr_t)buf); 95 } 96 97 if ((flags & ISNS_FLAG_FIRST_PDU) == ISNS_FLAG_FIRST_PDU) { 98 if (combined_pdu != NULL || pdu->seq != 0) { 99 goto conn_done; 100 } 101 combined_pdu = pdu; 102 pdu = NULL; 103 } else { 104 if (combined_pdu == NULL || 105 combined_pdu->func_id != pdu->func_id || 106 combined_pdu->xid != pdu->xid || 107 (combined_pdu->seq + 1) != pdu->seq) { 108 /* expect the first pdu, the same tranx id */ 109 /* and the next sequence id */ 110 goto conn_done; 111 } 112 new_combined_pdu = (isns_pdu_t *)malloc( 113 ISNSP_HEADER_SIZE + 114 combined_pdu->payload_len + 115 pdu->payload_len); 116 if (new_combined_pdu == NULL) { 117 goto conn_done; 118 } 119 (void) memcpy((void *)new_combined_pdu, 120 (void *)combined_pdu, 121 ISNSP_HEADER_SIZE + combined_pdu->payload_len); 122 payload_ptr = new_combined_pdu->payload + 123 combined_pdu->payload_len; 124 (void) memcpy((void *)payload_ptr, 125 (void *)pdu->payload, 126 pdu->payload_len); 127 new_combined_pdu->seq = pdu->seq; 128 free(combined_pdu); 129 combined_pdu = new_combined_pdu; 130 free(pdu); 131 pdu = NULL; 132 } 133 if ((flags & ISNS_FLAG_LAST_PDU) == ISNS_FLAG_LAST_PDU) { 134 #ifdef DEBUG 135 time_t t; 136 clock_t c; 137 138 dump_pdu1(combined_pdu); 139 140 if (verbose_tc != 0) { 141 t = time(NULL); 142 c = clock(); 143 } 144 #endif 145 146 conn->in_packet.pdu = combined_pdu; 147 conn->out_packet.pl = 0; 148 conn->ec = 0; 149 150 if (packet_split_verify(conn) == 0) { 151 (void) cache_lock(conn->lock); 152 status = conn->handler(conn); 153 conn->ec = cache_unlock(conn->lock, conn->ec); 154 } 155 156 switch (status) { 157 case -1: 158 /* error */ 159 break; 160 case 0: 161 status = isns_response(conn); 162 163 isnslog(LOG_DEBUG, "isns_connection", 164 "Response status: %d.", status); 165 if (ISNS_MSG_RESPONDED_ENABLED()) { 166 char buf[INET6_ADDRSTRLEN]; 167 struct sockaddr_storage *ssp = 168 &conn->ss; 169 struct sockaddr_in *sinp = 170 (struct sockaddr_in *)ssp; 171 if (ssp->ss_family == AF_INET) { 172 (void) inet_ntop(AF_INET, 173 (void *)&(sinp->sin_addr), 174 buf, sizeof (buf)); 175 } else { 176 (void) inet_ntop(AF_INET6, 177 (void *)&(sinp->sin_addr), 178 buf, sizeof (buf)); 179 } 180 ISNS_MSG_RESPONDED((uintptr_t)buf); 181 } 182 break; 183 default: 184 /* no need to send response message */ 185 status = 0; 186 break; 187 } 188 189 #ifdef DEBUG 190 if (verbose_tc != 0) { 191 t = time(NULL) - t; 192 c = clock() - c; 193 printf("time %d clock %.4lf -msg response\n", 194 t, c / (double)CLOCKS_PER_SEC); 195 } 196 #endif 197 free(combined_pdu); 198 combined_pdu = NULL; 199 } 200 } 201 202 conn_done: 203 if (pdu != NULL) { 204 free(pdu); 205 } 206 if (combined_pdu != NULL) { 207 free(combined_pdu); 208 } 209 (void) close(conn->so); 210 (void) free(conn->out_packet.pdu); 211 (void) free(conn); 212 213 /* decrease the thread ref count */ 214 dec_thr_count(); 215 216 return (NULL); 217 } 218 219 /* the iSNS server port watcher */ 220 221 void * 222 isns_port_watcher( 223 /* LINTED E_FUNC_ARG_UNUSED */ 224 void *arg 225 ) 226 { 227 int s, f; 228 int opt = 1; 229 struct sockaddr_in sin; 230 struct sockaddr_in *sinp; 231 struct sockaddr_storage *ssp; 232 socklen_t sslen; 233 char buf[INET6_ADDRSTRLEN]; 234 pthread_t tid; 235 struct pollfd fds; 236 int poll_ret; 237 238 conn_arg_t *conn; 239 240 if ((s = socket(AF_INET, SOCK_STREAM, 0)) != -1) { 241 /* IPv4 */ 242 isnslog(LOG_DEBUG, "isns_port_watcher", "IPv4 socket created."); 243 (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, 244 sizeof (opt)); 245 246 sin.sin_family = AF_INET; 247 sin.sin_port = htons(ISNS_DEFAULT_SERVER_PORT); 248 sin.sin_addr.s_addr = htonl(INADDR_ANY); 249 250 if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) < 0) { 251 isnslog(LOG_DEBUG, "isns_port_watcher", 252 "binding on server port failed: %%m"); 253 goto watch_failed; 254 } 255 isnslog(LOG_DEBUG, "isns_port_watcher", 256 "successful binding on server port."); 257 } else { 258 isnslog(LOG_DEBUG, "isns_port_watcher", 259 "cannot create socket: %%m."); 260 goto watch_failed; 261 } 262 263 if (listen(s, 5) < 0) { 264 isnslog(LOG_DEBUG, "isns_port_watcher", 265 "listening on server port failed: %%m."); 266 goto watch_failed; 267 } 268 isnslog(LOG_DEBUG, "isns_port_watcher", "listening on server port ok."); 269 270 fds.fd = s; 271 fds.events = (POLLIN | POLLRDNORM); 272 fds.revents = 0; 273 274 /* waiting for connections */ 275 for (;;) { 276 if (time_to_exit) { 277 return (NULL); 278 } 279 280 poll_ret = poll(&fds, 1, 1000); 281 if (poll_ret <= 0) { 282 continue; 283 } 284 285 /* allocate a connection argument */ 286 conn = (conn_arg_t *)malloc(sizeof (conn_arg_t)); 287 if (conn == NULL) { 288 isnslog(LOG_DEBUG, "isns_port_watcher", 289 "malloc() failed."); 290 goto watch_failed; 291 } 292 ssp = &conn->ss; 293 sslen = sizeof (conn->ss); 294 f = accept(s, (struct sockaddr *)ssp, &sslen); 295 if (f < 0) { 296 isnslog(LOG_DEBUG, "isns_port_watcher", 297 "accepting connection failed: %%m."); 298 goto watch_failed; 299 } 300 sinp = (struct sockaddr_in *)ssp; 301 if (ssp->ss_family == AF_INET) { 302 (void) inet_ntop(AF_INET, (void *)&(sinp->sin_addr), 303 buf, sizeof (buf)); 304 } else { 305 (void) inet_ntop(AF_INET6, (void *)&(sinp->sin_addr), 306 buf, sizeof (buf)); 307 } 308 isnslog(LOG_DEBUG, "isns_port_watcher", 309 "connection from %s:%d.", buf, 310 sinp->sin_port); 311 312 if (ISNS_CONNECTION_ACCEPTED_ENABLED()) { 313 ISNS_CONNECTION_ACCEPTED((uintptr_t)buf); 314 } 315 316 conn->so = f; 317 /* create an isns connection */ 318 if (pthread_create(&tid, NULL, 319 isns_connection, (void *)conn) != 0) { 320 (void) close(f); 321 (void) free(conn); 322 isnslog(LOG_DEBUG, "isns_port_watcher", 323 "pthread_create() failed."); 324 } else { 325 /* increase the thread ref count */ 326 inc_thr_count(); 327 } 328 } 329 330 watch_failed: 331 shutdown_server(); 332 return (NULL); 333 } 334 335 static uint16_t xid = 0; 336 static pthread_mutex_t xid_mtx = PTHREAD_MUTEX_INITIALIZER; 337 uint16_t 338 get_server_xid( 339 ) 340 { 341 uint16_t tmp; 342 343 (void) pthread_mutex_lock(&xid_mtx); 344 tmp = ++ xid; 345 (void) pthread_mutex_unlock(&xid_mtx); 346 347 return (tmp); 348 } 349