xref: /illumos-gate/usr/src/cmd/isns/isnsd/server.c (revision 1f5207b7604fb44407eb4342aff613f7c4508508)
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