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 *
isns_connection(void * arg)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 *
isns_port_watcher(void * arg)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
get_server_xid()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