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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * Module for all network transactions. SLP messages can be multicast,
31 * unicast over UDP, or unicast over TCP; this module provides routines
32 * for all three. TCP transactions are handled by a single dedicated
33 * thread, while multicast and UDP unicast messages are sent by the
34 * calling thread.
35 *
36 * slp_uc_tcp_send: enqueues a message on the TCP transaction thread's
37 * queue.
38 * slp_tcp_wait: blocks until all TCP-enqueued transactions for
39 * a given SLP handle are complete
40 * slp_uc_udp_send: unicasts a message using a datagram
41 * slp_mc_send: multicasts a message
42 */
43
44 /*
45 * todo: correct multicast interfaces;
46 */
47
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <syslog.h>
51 #include <sys/types.h>
52 #include <sys/socket.h>
53 #include <arpa/inet.h>
54 #include <errno.h>
55 #include <unistd.h>
56 #include <time.h>
57 #include <string.h>
58 #include <slp-internal.h>
59 #include <slp_net_utils.h>
60
61 /*
62 * TCP thread particulars
63 */
64 static SLPBoolean tcp_thr_running = SLP_FALSE;
65 static slp_queue_t *tcp_q;
66 static int tcp_sockfd;
67 static mutex_t start_lock = DEFAULTMUTEX;
68
69 /* Used to pass arguments to the TCP thread, via 'tcp_q' */
70 struct tcp_rqst {
71 slp_handle_impl_t *hp;
72 slp_target_t *target;
73 const char *scopes;
74 SLPBoolean free_target;
75 unsigned short xid;
76 };
77
78 /* Used to keep track of broadcast interfaces */
79 struct bc_ifs {
80 struct sockaddr_in *sin;
81 int num_ifs;
82 };
83
84 /*
85 * Private utility routines
86 */
87 static SLPError start_tcp_thr();
88 static void tcp_thread();
89 static SLPError make_header(slp_handle_impl_t *, char *, const char *);
90 static void udp_make_msghdr(struct sockaddr_in *, struct iovec *, int,
91 struct msghdr *);
92 static SLPError make_mc_target(slp_handle_impl_t *,
93 struct sockaddr_in *, char *,
94 struct pollfd **, nfds_t *, struct bc_ifs *);
95 static SLPError make_bc_target(slp_handle_impl_t *, struct in_addr *,
96 int, struct bc_ifs *);
97 static SLPError mc_sendmsg(struct pollfd *, struct msghdr *,
98 struct bc_ifs *);
99 static SLPError bc_sendmsg(struct pollfd *, struct msghdr *, struct bc_ifs *);
100 static void mc_recvmsg(struct pollfd *, nfds_t, slp_handle_impl_t *,
101 const char *, char *, void **, unsigned long long,
102 unsigned long long, unsigned long long *,
103 int *, int *, int);
104 static void free_pfds(struct pollfd *, nfds_t);
105 static void tcp_handoff(slp_handle_impl_t *, const char *,
106 struct sockaddr_in *, unsigned short);
107 static unsigned long long now_millis();
108 static int wait_for_response(unsigned long long, int *,
109 unsigned long long, unsigned long long *,
110 struct pollfd [], nfds_t);
111 static int add2pr_list(slp_msg_t *, struct sockaddr_in *, void **);
112 static void free_pr_node(void *, VISIT, int, void *);
113
114 /*
115 * Unicasts a message using TCP. 'target' is a targets list
116 * containing DAs corresponding to 'scopes'. 'free_target' directs
117 * tcp_thread to free the target list when finished; this is useful
118 * when a target needs to be synthesised by another message thread
119 * (such as slp_mc_send for tcp_handoffs). If this message is a
120 * retransmission due to a large reply, 'xid' should be the same as for
121 * the original message.
122 *
123 * This call returns as soon as the message has been enqueued on 'tcp_q'.
124 * Callers interested in knowing when the transaction has completed
125 * should call slp_tcp_wait with the same SLP handle.
126 */
slp_uc_tcp_send(slp_handle_impl_t * hp,slp_target_t * target,const char * scopes,SLPBoolean free_target,unsigned short xid)127 void slp_uc_tcp_send(slp_handle_impl_t *hp, slp_target_t *target,
128 const char *scopes, SLPBoolean free_target,
129 unsigned short xid) {
130 struct tcp_rqst *rqst;
131
132 /* initialize TCP vars in handle, if necessary */
133 if (!hp->tcp_lock) {
134 if (!(hp->tcp_lock = malloc(sizeof (*(hp->tcp_lock))))) {
135 slp_err(LOG_CRIT, 0, "slp_uc_tcp_send",
136 "out of memory");
137 return;
138 }
139 (void) mutex_init(hp->tcp_lock, NULL, NULL);
140 }
141 if (!hp->tcp_wait) {
142 if (!(hp->tcp_wait = malloc(sizeof (*(hp->tcp_wait))))) {
143 slp_err(LOG_CRIT, 0, "slp_uc_tcp_send",
144 "out of memory");
145 return;
146 }
147 (void) cond_init(hp->tcp_wait, NULL, NULL);
148 }
149 (void) mutex_lock(hp->tcp_lock);
150 (hp->tcp_ref_cnt)++;
151 (void) mutex_unlock(hp->tcp_lock);
152
153 /* start TCP thread, if not already running */
154 if (!tcp_thr_running)
155 if (start_tcp_thr() != SLP_OK)
156 return;
157
158 /* create and enqueue the request */
159 if (!(rqst = malloc(sizeof (*rqst)))) {
160 slp_err(LOG_CRIT, 0, "slp_uc_tcp_send", "out of memory");
161 return;
162 }
163 rqst->hp = hp;
164 rqst->target = target;
165 rqst->scopes = scopes;
166 rqst->free_target = free_target;
167 rqst->xid = xid;
168 (void) slp_enqueue(tcp_q, rqst);
169 }
170
171 /*
172 * Wait for TCP to complete, if a transaction corresponding to this
173 * SLP handle is pending. If none are pending, returns immediately.
174 */
slp_tcp_wait(slp_handle_impl_t * hp)175 void slp_tcp_wait(slp_handle_impl_t *hp) {
176 (void) mutex_lock(hp->tcp_lock);
177 while (hp->tcp_ref_cnt > 0)
178 (void) cond_wait(hp->tcp_wait, hp->tcp_lock);
179 (void) mutex_unlock(hp->tcp_lock);
180 }
181
182 /*
183 * Unicasts a message using datagrams. 'target' should contain a
184 * list of DAs corresponding to 'scopes'.
185 *
186 * This call does not return until the transaction has completed. It
187 * may handoff a message to the TCP thread if necessary, but will not
188 * wait for that transaction to complete. Hence callers should always
189 * invoke slp_tcp_wait before cleaning up resources.
190 */
slp_uc_udp_send(slp_handle_impl_t * hp,slp_target_t * target,const char * scopes)191 void slp_uc_udp_send(slp_handle_impl_t *hp, slp_target_t *target,
192 const char *scopes) {
193 slp_target_t *ctarg;
194 struct sockaddr_in *sin;
195 struct msghdr msg[1];
196 char header[SLP_DEFAULT_SENDMTU];
197 int sockfd;
198 size_t mtu;
199 SLPBoolean use_tcp;
200 struct pollfd pfd[1];
201 unsigned long long now, sent;
202 char *reply = NULL;
203
204 use_tcp = SLP_FALSE;
205 /* build the header and iovec */
206 if (make_header(hp, header, scopes) != SLP_OK)
207 return;
208
209 mtu = slp_get_mtu();
210
211 /* walk targets list until we either succeed or run out of targets */
212 for (ctarg = target; ctarg; ctarg = slp_next_failover(ctarg)) {
213 char *state;
214 const char *timeouts;
215 int timeout;
216
217 sin = (struct sockaddr_in *)slp_get_target_sin(ctarg);
218
219 /* make the socket, msghdr and reply buf */
220 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
221 slp_err(LOG_CRIT, 0, "slp_uc_udp_send",
222 "could not create socket: %s",
223 strerror(errno));
224 return;
225 }
226 pfd[0].fd = sockfd;
227 pfd[0].events = POLLRDNORM;
228
229 udp_make_msghdr(sin, hp->msg.iov, hp->msg.iovlen, msg);
230 if (!reply && !(reply = malloc(mtu))) {
231 (void) close(sockfd);
232 slp_err(LOG_CRIT, 0, "slp_uc_udp_send",
233 "out of memory");
234 return;
235 }
236
237 /* timeout loop */
238 timeouts = SLPGetProperty(SLP_CONFIG_DATAGRAMTIMEOUTS);
239 state = (char *)timeouts;
240 for (timeout = slp_get_next_onlist(&state);
241 timeout != -1 &&
242 !hp->cancel;
243 timeout = slp_get_next_onlist(&state)) {
244 int pollerr;
245
246 if (sendmsg(sockfd, msg, 0) < 0) {
247 slp_err(LOG_CRIT, 0, "slp_uc_udp_send",
248 "sendmsg failed: %s", strerror(errno));
249 continue; /* try again */
250 }
251 sent = now_millis();
252
253 pollerr = wait_for_response(
254 0, &timeout, sent, &now, pfd, 1);
255
256 if (pollerr == 0)
257 /* timeout */
258 continue;
259 if (pollerr < 0)
260 break;
261
262 /* only using one fd, so no need to scan pfd */
263 if (recvfrom(sockfd, reply, mtu, 0, NULL, NULL) < 0) {
264 /* if reply overflows, hand off to TCP */
265 if (errno == ENOMEM) {
266 free(reply); reply = NULL;
267 use_tcp = SLP_TRUE;
268 break;
269 }
270 slp_err(LOG_CRIT, 0, "slp_uc_udp_send",
271 "recvfrom failed: %s",
272 strerror(errno));
273 } else {
274 /* success -- but check error code */
275 slp_proto_err errcode = slp_get_errcode(reply);
276 switch (errcode) {
277 case SLP_MSG_PARSE_ERROR:
278 case SLP_VER_NOT_SUPPORTED:
279 case SLP_SICK_DA:
280 case SLP_DA_BUSY_NOW:
281 case SLP_OPTION_NOT_UNDERSTOOD:
282 case SLP_RQST_NOT_SUPPORTED: {
283 char addrbuf[INET6_ADDRSTRLEN], *cname;
284
285 cname = slp_ntop(addrbuf, INET6_ADDRSTRLEN,
286 (const void *) &(sin->sin_addr));
287 cname = cname ? cname : "[invalid addr]";
288
289 /* drop it */
290 slp_err(LOG_INFO, 0,
291 "DA %s returned error code %d; dropping reply",
292 cname, errcode);
293 free(reply); reply = NULL;
294 }
295 }
296 }
297 break;
298 }
299 if (timeout != -1)
300 /* success or cancel */
301 break;
302 /* else failure */
303 slp_mark_target_failed(ctarg);
304 }
305 (void) close(sockfd);
306 if (!ctarg || hp->cancel) {
307 /* failed all attempts or canceled by consumer */
308 if (reply) free(reply);
309 return;
310 }
311 /* success or tcp handoff */
312 if (reply) {
313 if (slp_get_overflow(reply))
314 use_tcp = SLP_TRUE;
315 else
316 slp_mark_target_used(ctarg);
317 (void) slp_enqueue(hp->q, reply);
318 }
319 if (use_tcp)
320 slp_uc_tcp_send(
321 hp, ctarg, scopes, SLP_FALSE, slp_get_xid(header));
322 }
323
324 /*
325 * Multicasts (or broadcasts) a message, using multicast convergance
326 * to collect results. Large replies will cause the message to be handed
327 * off to the TCP thread.
328 *
329 * This call does not return until the transaction is complete. It does
330 * not, however, wait until pending TCP transactions are complete, so
331 * callers should always invoke slp_tcp_wait before cleaning up any
332 * resources.
333 */
slp_mc_send(slp_handle_impl_t * hp,const char * scopes)334 void slp_mc_send(slp_handle_impl_t *hp, const char *scopes) {
335 char header[SLP_DEFAULT_SENDMTU], *state;
336 const char *timeouts;
337 struct sockaddr_in sin[1];
338 struct msghdr msg[1];
339 int maxwait, timeout, noresults, anyresults;
340 unsigned long long final_to, now, sent;
341 struct pollfd *pfd;
342 nfds_t nfds;
343 void *collator = NULL;
344 struct bc_ifs bcifs;
345
346 /* build the header and iovec */
347 if (make_header(hp, header, scopes) != SLP_OK)
348 return;
349
350 (void) memset(sin, 0, sizeof (sin));
351 if (make_mc_target(hp, sin, header, &pfd, &nfds, &bcifs) != SLP_OK)
352 return;
353 udp_make_msghdr(sin, hp->msg.iov, hp->msg.iovlen, msg);
354
355 maxwait = slp_get_mcmaxwait();
356 maxwait = maxwait ? maxwait : SLP_DEFAULT_MAXWAIT;
357
358 /* set the final timeout */
359 now = now_millis();
360 final_to = now + maxwait;
361
362 /* timeout prep and loop */
363 timeouts = SLPGetProperty(SLP_CONFIG_MULTICASTTIMEOUTS);
364 state = (char *)timeouts;
365 noresults = anyresults = 0;
366
367 for (timeout = slp_get_next_onlist(&state);
368 timeout != -1 &&
369 now < final_to &&
370 noresults < 2 &&
371 !hp->cancel;
372 timeout = slp_get_next_onlist(&state)) {
373
374 /* send msg */
375 if (mc_sendmsg(pfd, msg, &bcifs) != SLP_OK) {
376 continue; /* try again */
377 }
378 sent = now_millis();
379
380 /* receive results */
381 mc_recvmsg(pfd, nfds, hp, scopes, header, &collator, final_to,
382 sent, &now, &noresults, &anyresults, timeout);
383
384 if (!anyresults)
385 noresults++;
386 anyresults = 0;
387 }
388 /* clean up PR list collator */
389 if (collator)
390 slp_twalk(collator, free_pr_node, 0, NULL);
391
392 /* close all fds in pfd */
393 free_pfds(pfd, nfds);
394
395 /* free broadcast addrs, if used */
396 if (bcifs.sin) free(bcifs.sin);
397 }
398
399 /*
400 * Private net helper routines
401 */
402
403 /*
404 * Starts the tcp_thread and allocates any necessary resources.
405 */
start_tcp_thr()406 static SLPError start_tcp_thr() {
407 SLPError err;
408 int terr;
409
410 (void) mutex_lock(&start_lock);
411 /* make sure someone else hasn't already intialized the thread */
412 if (tcp_thr_running) {
413 (void) mutex_unlock(&start_lock);
414 return (SLP_OK);
415 }
416
417 /* create the tcp queue */
418 if (!(tcp_q = slp_new_queue(&err))) {
419 (void) mutex_unlock(&start_lock);
420 return (err);
421 }
422
423 /* start the tcp thread */
424 if ((terr = thr_create(0, NULL, (void *(*)(void *)) tcp_thread,
425 NULL, 0, NULL)) != 0) {
426 slp_err(LOG_CRIT, 0, "start_tcp_thr",
427 "could not start thread: %s", strerror(terr));
428 (void) mutex_unlock(&start_lock);
429 return (SLP_INTERNAL_SYSTEM_ERROR);
430 }
431
432 tcp_thr_running = SLP_TRUE;
433 (void) mutex_unlock(&start_lock);
434 return (SLP_OK);
435 }
436
437 /*
438 * Called by the tcp thread to shut itself down. The queue must be
439 * empty (and should be, since the tcp thread will only shut itself
440 * down if nothing has been put in its queue for the timeout period).
441 */
end_tcp_thr()442 static void end_tcp_thr() {
443 (void) mutex_lock(&start_lock);
444
445 tcp_thr_running = SLP_FALSE;
446 slp_destroy_queue(tcp_q);
447
448 (void) mutex_unlock(&start_lock);
449 thr_exit(NULL);
450 }
451
452 /*
453 * The thread of control for the TCP thread. This sits in a loop, waiting
454 * on 'tcp_q' for new messages. If no message appear after 30 seconds,
455 * this thread cleans up resources and shuts itself down.
456 */
tcp_thread()457 static void tcp_thread() {
458 struct tcp_rqst *rqst;
459 char *reply, header[SLP_DEFAULT_SENDMTU];
460 timestruc_t to[1];
461 to->tv_nsec = 0;
462
463 for (;;) {
464 slp_target_t *ctarg, *targets;
465 slp_handle_impl_t *hp;
466 const char *scopes;
467 struct sockaddr_in *sin;
468 SLPBoolean free_target, etimed;
469 unsigned short xid;
470
471 /* set idle shutdown timeout */
472 to->tv_sec = time(NULL) + 30;
473 /* get the next request from the tcp queue */
474 if (!(rqst = slp_dequeue_timed(tcp_q, to, &etimed))) {
475 if (!etimed)
476 continue;
477 else
478 end_tcp_thr();
479 }
480
481 hp = rqst->hp;
482 scopes = rqst->scopes;
483 targets = rqst->target;
484 free_target = rqst->free_target;
485 xid = rqst->xid;
486 free(rqst);
487 reply = NULL;
488
489 /* Check if this handle has been cancelled */
490 if (hp->cancel)
491 goto transaction_complete;
492
493 /* build the header and iovec */
494 if (make_header(hp, header, scopes) != SLP_OK) {
495 if (free_target) slp_free_target(targets);
496 continue;
497 }
498 if (xid)
499 slp_set_xid(header, xid);
500
501 /* walk targets list until we either succeed or run out of targets */
502 for (ctarg = targets;
503 ctarg && !hp->cancel;
504 ctarg = slp_next_failover(ctarg)) {
505
506 sin = (struct sockaddr_in *)slp_get_target_sin(ctarg);
507
508 /* create the socket */
509 if ((tcp_sockfd = socket(AF_INET, SOCK_STREAM, 0))
510 < 0) {
511 slp_err(LOG_CRIT, 0, "tcp_thread",
512 "could not create socket: %s",
513 strerror(errno));
514 ctarg = NULL;
515 break;
516 }
517
518 /* connect to target */
519 if (connect(tcp_sockfd, (struct sockaddr *)sin,
520 sizeof (*sin)) < 0) {
521 slp_err(LOG_INFO, 0, "tcp_thread",
522 "could not connect, error = %s",
523 strerror(errno));
524 goto failed;
525 }
526
527 /* send the message and read the reply */
528 if (writev(tcp_sockfd, hp->msg.iov, hp->msg.iovlen)
529 == -1) {
530 slp_err(LOG_INFO, 0, "tcp_thread",
531 "could not send, error = %s",
532 strerror(errno));
533 goto failed;
534 }
535
536 /* if success, break out of failover loop */
537 if ((slp_tcp_read(tcp_sockfd, &reply)) == SLP_OK) {
538 (void) close(tcp_sockfd);
539 break;
540 }
541
542 /* else if timed out, mark target failed and try next one */
543 failed:
544 (void) close(tcp_sockfd);
545 slp_mark_target_failed(ctarg);
546 }
547
548 if (hp->cancel) {
549 if (reply) {
550 free(reply);
551 }
552 } else if (ctarg) {
553 /* success */
554 (void) slp_enqueue(hp->q, reply);
555 slp_mark_target_used(ctarg);
556 }
557
558 /* If all TCP transactions on this handle are complete, send notice */
559 transaction_complete:
560 (void) mutex_lock(hp->tcp_lock);
561 if (--(hp->tcp_ref_cnt) == 0)
562 (void) cond_signal(hp->tcp_wait);
563 (void) mutex_unlock(hp->tcp_lock);
564
565 if (free_target)
566 slp_free_target(targets);
567 }
568 }
569
570 /*
571 * Performs a full read for TCP replies, dynamically allocating a
572 * buffer large enough to hold the reply.
573 */
slp_tcp_read(int sockfd,char ** reply)574 SLPError slp_tcp_read(int sockfd, char **reply) {
575 char lenbuf[5], *p;
576 size_t nleft;
577 ssize_t nread;
578 unsigned int len;
579
580 /* find out how long the reply is */
581 nleft = 5;
582 p = lenbuf;
583 while (nleft != 0) {
584 if ((nread = read(sockfd, p, 5)) < 0) {
585 if (errno == EINTR)
586 nread = 0;
587 else
588 return (SLP_NETWORK_ERROR);
589 } else if (nread == 0)
590 /* shouldn't hit EOF here */
591 return (SLP_NETWORK_ERROR);
592 nleft -= nread;
593 p += nread;
594 }
595
596 len = slp_get_length(lenbuf);
597
598 /* allocate space for the reply, and copy in what we've already read */
599 /* This buffer gets freed by a msg-specific unpacking routine later */
600 if (!(*reply = malloc(len))) {
601 slp_err(LOG_CRIT, 0, "tcp_read", "out of memory");
602 return (SLP_MEMORY_ALLOC_FAILED);
603 }
604 (void) memcpy(*reply, lenbuf, 5);
605
606 /* read the rest of the message */
607 nleft = len - 5;
608 p = *reply + 5;
609 while (nleft != 0) {
610 if ((nread = read(sockfd, p, nleft)) < 0) {
611 if (errno == EINTR)
612 nread = 0;
613 else {
614 free(*reply);
615 return (SLP_NETWORK_ERROR);
616 }
617 } else if (nread == 0)
618 /*
619 * shouldn't hit EOF here, but perhaps we've
620 * gotten something useful, so return OK.
621 */
622 return (SLP_OK);
623
624 nleft -= nread;
625 p += nread;
626 }
627
628 return (SLP_OK);
629 }
630
631 /*
632 * Lays in a SLP header for this message into the scatter / gather
633 * array 'iov'. 'header' is the buffer used to contain the header,
634 * and must contain enough space. 'scopes' should contain a string
635 * with the scopes to be used for this message.
636 */
make_header(slp_handle_impl_t * hp,char * header,const char * scopes)637 static SLPError make_header(slp_handle_impl_t *hp, char *header,
638 const char *scopes) {
639 SLPError err;
640 size_t msgLen, off;
641 int i;
642 size_t mtu;
643 unsigned short slen = (unsigned short)strlen(scopes);
644
645 mtu = slp_get_mtu();
646 msgLen = slp_hdrlang_length(hp);
647 hp->msg.iov[0].iov_base = header;
648 hp->msg.iov[0].iov_len = msgLen; /* now the length of the hdr */
649
650 /* use the remaining buffer in header for the prlist */
651 hp->msg.prlist->iov_base = header + msgLen;
652
653 for (i = 1; i < hp->msg.iovlen; i++) {
654 msgLen += hp->msg.iov[i].iov_len;
655 }
656 msgLen += slen;
657
658 off = 0;
659 if ((err = slp_add_header(hp->locale, header, mtu,
660 hp->fid, msgLen, &off)) != SLP_OK)
661 return (err);
662
663 /* start out with empty prlist */
664 hp->msg.prlist->iov_len = 0;
665
666 /* store the scope string len into the space provided by the caller */
667 off = 0;
668 if ((err = slp_add_sht((char *)hp->msg.scopeslen.iov_base,
669 2, slen, &off)) != SLP_OK) {
670 return (err);
671 }
672 hp->msg.scopes->iov_base = (caddr_t)scopes;
673 hp->msg.scopes->iov_len = slen;
674
675 return (SLP_OK);
676 }
677
678 /*
679 * Populates a struct msghdr suitable for use with sendmsg.
680 */
udp_make_msghdr(struct sockaddr_in * sin,struct iovec * iov,int iovlen,struct msghdr * msg)681 static void udp_make_msghdr(struct sockaddr_in *sin, struct iovec *iov,
682 int iovlen, struct msghdr *msg) {
683 msg->msg_name = (caddr_t)sin;
684 msg->msg_namelen = 16;
685 msg->msg_iov = iov;
686 msg->msg_iovlen = iovlen;
687 msg->msg_accrights = NULL;
688 msg->msg_accrightslen = 0;
689 }
690
691 /*
692 * Sets the address on 'sin', sets the flag in the message header,
693 * and creates an array of pollfds for all interfaces we need to
694 * use. If we need to use only broadcast, and net.slp.interfaces
695 * is set, fills bcifs with an array of subnet broadcast addresses
696 * to which we should send. Returns err != SLP_OK only on catastrophic
697 * error.
698 */
make_mc_target(slp_handle_impl_t * hp,struct sockaddr_in * sin,char * header,struct pollfd ** fds,nfds_t * nfds,struct bc_ifs * bcifs)699 static SLPError make_mc_target(slp_handle_impl_t *hp,
700 struct sockaddr_in *sin, char *header,
701 struct pollfd **fds, nfds_t *nfds,
702 struct bc_ifs *bcifs) {
703
704 unsigned char ttl = slp_get_multicastTTL();
705 char *ifs_string;
706 SLPBoolean have_valid_if = SLP_FALSE;
707 SLPBoolean use_broadcast = slp_get_usebroadcast();
708 int fd, i, num_givenifs;
709 struct in_addr *given_ifs = NULL;
710 nfds_t nfd_i;
711
712 sin->sin_port = htons(SLP_PORT);
713 sin->sin_family = AF_INET;
714 slp_set_mcast(header);
715
716 /* Get the desired multicast interfaces, if set */
717 bcifs->sin = NULL;
718 *fds = NULL;
719 if ((ifs_string = (char *)SLPGetProperty(
720 SLP_CONFIG_INTERFACES)) != NULL && *ifs_string) {
721
722 char *p, *tstate;
723
724 /* count the number of IFs given */
725 p = strchr(ifs_string, ',');
726 for (num_givenifs = 1; p; num_givenifs++) {
727 p = strchr(p + 1, ',');
728 }
729
730 /* copy the given IFs into an array for easier processing */
731 if (!(given_ifs = calloc(num_givenifs, sizeof (*given_ifs)))) {
732 slp_err(LOG_CRIT, 0, "make_mc_target",
733 "out of memory");
734 return (SLP_MEMORY_ALLOC_FAILED);
735 }
736
737 i = 0;
738 /* strtok_r will destructively modify, so make a copy first */
739 if (!(ifs_string = strdup(ifs_string))) {
740 slp_err(LOG_CRIT, 0, "make_mc_target",
741 "out of memory");
742 free(given_ifs);
743 return (SLP_MEMORY_ALLOC_FAILED);
744 }
745 for (
746 p = strtok_r(ifs_string, ",", &tstate);
747 p;
748 p = strtok_r(NULL, ",", &tstate)) {
749
750 if (slp_pton(p, &(given_ifs[i])) < 1) {
751 /* skip */
752 num_givenifs--;
753 continue;
754 }
755 i++;
756 }
757 *nfds = num_givenifs;
758 free(ifs_string);
759
760 /* allocate a pollfd array for all interfaces */
761 if (!(*fds = calloc(num_givenifs, sizeof (**fds)))) {
762 slp_err(LOG_CRIT, 0, "make_mc_target",
763 "out of memory");
764 free(ifs_string);
765 free(given_ifs);
766 return (SLP_MEMORY_ALLOC_FAILED);
767 }
768
769 /* lay the given interfaces into the pollfd array */
770 for (i = 0; i < num_givenifs; i++) {
771
772 /* create a socket to bind to this interface */
773 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
774 slp_err(LOG_CRIT, 0, "make_mc_target",
775 "could not create socket: %s",
776 strerror(errno));
777 free_pfds(*fds, *nfds);
778 return (SLP_INTERNAL_SYSTEM_ERROR);
779 }
780
781 /* fill in the pollfd structure */
782 (*fds)[i].fd = fd;
783 (*fds)[i].events |= POLLRDNORM;
784
785 if (use_broadcast) {
786 struct sockaddr_in bcsin[1];
787
788 (void) memcpy(
789 &(bcsin->sin_addr), &(given_ifs[i]),
790 sizeof (bcsin->sin_addr));
791 bcsin->sin_family = AF_INET;
792 bcsin->sin_port = 0;
793
794 /* bind fd to interface */
795 if (bind(fd, (struct sockaddr *)bcsin,
796 sizeof (*bcsin)) == 0) {
797 continue;
798 }
799 /* else fallthru to default (multicast) */
800 slp_err(LOG_INFO, 0, "make_mc_target",
801 "could not set broadcast interface: %s",
802 strerror(errno));
803 }
804 /* else use multicast */
805 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
806 &(given_ifs[i]), sizeof (given_ifs[i]))
807 < 0) {
808
809 slp_err(LOG_INFO, 0, "make_mc_target",
810 "could not set multicast interface: %s",
811 strerror(errno));
812 continue;
813 }
814
815 have_valid_if = SLP_TRUE;
816 }
817
818 if (use_broadcast) {
819 SLPError err;
820
821 if ((err = make_bc_target(
822 hp, given_ifs, num_givenifs, bcifs))
823 != SLP_OK) {
824
825 if (err == SLP_MEMORY_ALLOC_FAILED) {
826 /* the only thing which is really a showstopper */
827 return (err);
828 }
829
830 /* else no valid interfaces */
831 have_valid_if = SLP_FALSE;
832 }
833 }
834 free(given_ifs);
835 }
836
837 if (!have_valid_if) {
838 if (*fds && !have_valid_if) {
839 /* couldn't process net.slp.interfaces property */
840 free(*fds);
841 }
842
843 /* bind to default interface */
844 if (!(*fds = calloc(1, sizeof (**fds)))) {
845 slp_err(LOG_CRIT, 0, "make_mc_target",
846 "out of memory");
847 return (SLP_MEMORY_ALLOC_FAILED);
848 }
849
850 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
851 slp_err(LOG_CRIT, 0, "make_mc_target",
852 "could not create socket: %s",
853 strerror(errno));
854 free(*fds);
855 return (SLP_INTERNAL_SYSTEM_ERROR);
856 }
857
858 (**fds).fd = fd;
859 (**fds).events |= POLLRDNORM;
860 *nfds = 1;
861 }
862
863 /* set required options on all configured fds */
864 for (nfd_i = 0; nfd_i < *nfds; nfd_i++) {
865 if (use_broadcast) {
866 const int on = 1;
867 if (setsockopt((*fds)[nfd_i].fd, SOL_SOCKET,
868 SO_BROADCAST,
869 (void *) &on, sizeof (on)) < 0) {
870 slp_err(LOG_CRIT, 0, "make_mc_target",
871 "could not enable broadcast: %s",
872 strerror(errno));
873 }
874 } else {
875 if (setsockopt((*fds)[nfd_i].fd, IPPROTO_IP,
876 IP_MULTICAST_TTL, &ttl, 1) < 0) {
877 slp_err(LOG_CRIT, 0, "make_mc_target",
878 "could not set multicast TTL: %s",
879 strerror(errno));
880 }
881 }
882 }
883
884 if (use_broadcast) {
885 sin->sin_addr.s_addr = INADDR_BROADCAST;
886 } else {
887 sin->sin_addr.s_addr = SLP_MULTICAST_ADDRESS;
888 }
889
890 return (SLP_OK);
891 }
892
893 /*
894 * Obtains the subnet broadcast address for each interface specified
895 * in net.slp.interfaces, and fill bcifs->sin with an array of these
896 * addresses.
897 */
make_bc_target(slp_handle_impl_t * hp,struct in_addr * given_ifs,int num_givenifs,struct bc_ifs * bcifs)898 static SLPError make_bc_target(slp_handle_impl_t *hp,
899 struct in_addr *given_ifs,
900 int num_givenifs, struct bc_ifs *bcifs) {
901 SLPError err;
902 int i;
903
904 if ((err = slp_broadcast_addrs(hp, given_ifs, num_givenifs,
905 &(bcifs->sin), &(bcifs->num_ifs)))
906 != SLP_OK) {
907 return (err);
908 }
909
910 /* set SLP port on each sockaddr_in */
911 for (i = 0; i < bcifs->num_ifs; i++) {
912 bcifs->sin[i].sin_port = htons(SLP_PORT);
913 }
914
915 return (SLP_OK);
916 }
917
918 /*
919 * Sends msg on 1st fd in fds for multicast, or on all interfaces
920 * specified in net.slp.interfaces for broadcast. Returns SLP_OK if
921 * msg was sent successfully on at least one interface; otherwise
922 * returns SLP_NETWORK_ERROR if msg was not sent on any interfaces.
923 */
mc_sendmsg(struct pollfd * fds,struct msghdr * msg,struct bc_ifs * bcifs)924 static SLPError mc_sendmsg(struct pollfd *fds,
925 struct msghdr *msg, struct bc_ifs *bcifs) {
926
927 if (slp_get_usebroadcast()) {
928 char *ifs = (char *)SLPGetProperty(SLP_CONFIG_INTERFACES);
929
930 /* hand off to broadcast-specific send function */
931 if (ifs && *ifs && bc_sendmsg(fds, msg, bcifs) == SLP_OK) {
932 return (SLP_OK);
933 }
934
935 /*
936 * else no ifs given, or bc_sendmsg failed, so send on
937 * general broadcast addr (255.255.255.255). This will
938 * cause the message to be sent on all interfaces. The
939 * address will have been set in make_mc_target.
940 */
941 }
942
943 /*
944 * Send only on one interface -- let routing take care of
945 * sending the message everywhere it needs to go. Sending
946 * on more than one interface can cause nasty routing loops.
947 * Note that this approach doesn't work with partitioned
948 * networks.
949 */
950 if (sendmsg(fds[0].fd, msg, 0) < 0) {
951 slp_err(LOG_CRIT, 0, "mc_sendmsg",
952 "sendmsg failed: %s", strerror(errno));
953 return (SLP_NETWORK_ERROR);
954 }
955
956 return (SLP_OK);
957 }
958
959 /*
960 * Send msg to each subnet broadcast address in bcifs->sin. Note
961 * that we can send on any fd (regardless of which interface to which
962 * it is bound), since the kernel will take care of routing for us.
963 * Returns err != SLP_OK only if no message was sent on any interface.
964 */
bc_sendmsg(struct pollfd * fds,struct msghdr * msg,struct bc_ifs * bcifs)965 static SLPError bc_sendmsg(struct pollfd *fds, struct msghdr *msg,
966 struct bc_ifs *bcifs) {
967 int i;
968 SLPBoolean sent_one = SLP_FALSE;
969
970 for (i = 0; i < bcifs->num_ifs; i++) {
971 msg->msg_name = (caddr_t)&(bcifs->sin[i]);
972
973 if (sendmsg(fds[0].fd, msg, 0) < 0) {
974 slp_err(LOG_CRIT, 0, "bc_sendmsg",
975 "sendmsg failed: %s", strerror(errno));
976 continue;
977 }
978 sent_one = SLP_TRUE;
979 }
980 return (sent_one ? SLP_OK : SLP_NETWORK_ERROR);
981 }
982
983 /*
984 * This is where the bulk of the multicast convergance algorithm resides.
985 * mc_recvmsg() waits for data to be ready on any fd in pfd, iterates
986 * through pfd and reads data from ready fd's. It also checks timeouts
987 * and user-cancels.
988 *
989 * Parameters:
990 * pfd IN an array of pollfd structs containing fds to poll
991 * nfds IN number of elements in pfd
992 * hp IN SLPHandle from originating call
993 * scopes IN scopes to use for this message
994 * header IN the SLP message header for this message
995 * collator IN/OUT btree collator for PR list
996 * final_to IN final timeout
997 * sent IN time when message was sent
998 * now IN/OUT set to current time at beginning of convergance
999 * noresults OUT set to 0 if any results are received
1000 * anyresults OUT set to true if any results are received
1001 * timeout IN time for this convergence iteration
1002 *
1003 * Returns only if an error has occured, or if either this retransmit
1004 * timeout or the final timeout has expired, or if hp->cancel becomes true.
1005 */
mc_recvmsg(struct pollfd * pfd,nfds_t nfds,slp_handle_impl_t * hp,const char * scopes,char * header,void ** collator,unsigned long long final_to,unsigned long long sent,unsigned long long * now,int * noresults,int * anyresults,int timeout)1006 static void mc_recvmsg(struct pollfd *pfd, nfds_t nfds, slp_handle_impl_t *hp,
1007 const char *scopes, char *header, void **collator,
1008 unsigned long long final_to,
1009 unsigned long long sent,
1010 unsigned long long *now,
1011 int *noresults, int *anyresults, int timeout) {
1012 char *reply = NULL;
1013 nfds_t i;
1014 struct sockaddr_in responder;
1015 int pollerr;
1016 socklen_t addrlen = sizeof (responder);
1017 size_t mtu = slp_get_mtu();
1018
1019 for (; !hp->cancel; ) {
1020 /* wait until we can read something */
1021 pollerr = wait_for_response(
1022 final_to, &timeout, sent, now, pfd, nfds);
1023 if (pollerr == 0)
1024 /* timeout */
1025 goto cleanup;
1026 if (pollerr < 0)
1027 /* error */
1028 goto cleanup;
1029
1030 /* iterate through all fds to find one with data to read */
1031 for (i = 0; !hp->cancel && i < nfds; i++) {
1032
1033 if (pfd[i].fd < 0 ||
1034 !(pfd[i].revents & (POLLRDNORM | POLLERR))) {
1035
1036 /* unused fd or unwanted event */
1037 continue;
1038 }
1039
1040 /* alloc reply buffer */
1041 if (!reply && !(reply = malloc(mtu))) {
1042 slp_err(LOG_CRIT, 0, "mc_revcmsg", "out of memory");
1043 return;
1044 }
1045 if (recvfrom(pfd[i].fd, reply, mtu, 0,
1046 (struct sockaddr *)&responder,
1047 (int *)&addrlen) < 0) {
1048
1049 /* if reply overflows, hand off to TCP */
1050 if (errno == ENOMEM) {
1051 free(reply); reply = NULL;
1052 tcp_handoff(hp, scopes,
1053 &responder, slp_get_xid(header));
1054 continue;
1055 }
1056
1057 /* else something nasty happened */
1058 slp_err(LOG_CRIT, 0, "mc_recvmsg",
1059 "recvfrom failed: %s",
1060 strerror(errno));
1061 continue;
1062 } else {
1063 /* success */
1064 if (slp_get_overflow(reply)) {
1065 tcp_handoff(hp, scopes,
1066 &responder, slp_get_xid(header));
1067 }
1068 /*
1069 * Add to the PR list. If this responder has already
1070 * answered, it doesn't count.
1071 */
1072 if (add2pr_list(&(hp->msg), &responder, collator)) {
1073 (void) slp_enqueue(hp->q, reply);
1074 *noresults = 0;
1075 *anyresults = 1;
1076 reply = NULL;
1077 }
1078
1079 /* if we've exceeded maxwait, break out */
1080 *now = now_millis();
1081 if (*now > final_to)
1082 goto cleanup;
1083
1084 } /* end successful receive */
1085
1086 } /* end fd iteration */
1087
1088 /* reset poll's timeout */
1089 timeout = timeout - (int)(*now - sent);
1090 if (timeout <= 0) {
1091 goto cleanup;
1092 }
1093
1094 } /* end main poll loop */
1095
1096 cleanup:
1097 if (reply) {
1098 free(reply);
1099 }
1100 }
1101
1102 /*
1103 * Closes any open sockets and frees the pollfd array.
1104 */
free_pfds(struct pollfd * pfds,nfds_t nfds)1105 static void free_pfds(struct pollfd *pfds, nfds_t nfds) {
1106 nfds_t i;
1107
1108 for (i = 0; i < nfds; i++) {
1109 if (pfds[i].fd <= 0) {
1110 continue;
1111 }
1112
1113 (void) close(pfds[i].fd);
1114 }
1115
1116 free(pfds);
1117 }
1118
1119 /*
1120 * Hands off a message to the TCP thread, fabricating a new target
1121 * from 'sin'. 'xid' will be used to create the XID for the TCP message.
1122 */
tcp_handoff(slp_handle_impl_t * hp,const char * scopes,struct sockaddr_in * sin,unsigned short xid)1123 static void tcp_handoff(slp_handle_impl_t *hp, const char *scopes,
1124 struct sockaddr_in *sin, unsigned short xid) {
1125 slp_target_t *target;
1126
1127 target = slp_fabricate_target(sin);
1128 slp_uc_tcp_send(hp, target, scopes, SLP_TRUE, xid);
1129 }
1130
1131 /*
1132 * Returns the current time in milliseconds.
1133 */
now_millis()1134 static unsigned long long now_millis() {
1135 unsigned long long i;
1136 struct timeval tv[1];
1137
1138 (void) gettimeofday(tv, NULL);
1139 i = (unsigned long long) tv->tv_sec * 1000;
1140 i += tv->tv_usec / 1000;
1141 return (i);
1142 }
1143
1144 /*
1145 * A wrapper around poll which waits until a reply comes in. This will
1146 * wait no longer than 'timeout' before returning. poll can return
1147 * even if no data is on the pipe or timeout has occured, so the
1148 * additional paramaters are used to break out of the wait loop if
1149 * we have exceeded the timeout value. 'final_to' is ignored if it is 0.
1150 *
1151 * returns: < 0 on error
1152 * 0 on timeout
1153 * > 0 on success (i.e. ready to read data).
1154 * side effect: 'now' is set to the time when poll found data on the pipe.
1155 */
wait_for_response(unsigned long long final_to,int * timeout,unsigned long long sent,unsigned long long * now,struct pollfd pfd[],nfds_t nfds)1156 static int wait_for_response(
1157 unsigned long long final_to,
1158 int *timeout,
1159 unsigned long long sent,
1160 unsigned long long *now,
1161 struct pollfd pfd[], nfds_t nfds) {
1162
1163 int when, pollerr;
1164
1165 /* wait until we can read something */
1166 for (;;) {
1167 pollerr = poll(pfd, nfds, *timeout);
1168 *now = now_millis();
1169
1170 /* ready to read */
1171 if (pollerr > 0)
1172 return (pollerr);
1173
1174 /* time out */
1175 if (pollerr == 0)
1176 /* timeout */
1177 return (0);
1178
1179 /* error */
1180 if (pollerr < 0)
1181 if (errno == EAGAIN || errno == EINTR) {
1182 /* poll is weird. */
1183 when = (int)(*now - sent);
1184 if (
1185 (final_to != 0 && *now > final_to) ||
1186 when > *timeout)
1187 break;
1188 *timeout = *timeout - when;
1189 continue;
1190 } else {
1191 slp_err(LOG_INFO, 0, "wait for response",
1192 "poll error: %s",
1193 strerror(errno));
1194 return (pollerr);
1195 }
1196 }
1197
1198 return (0);
1199 }
1200
1201 /*
1202 * Adds the cname of the host whose address is in 'sin' to this message's
1203 * previous responder list. The message is contained in 'msg'.
1204 * 'collator' contains the complete previous responder list, so that
1205 * even if the PR list in the message overflows and must be truncated,
1206 * the function can still correctly determine if we have heard from this
1207 * host before.
1208 *
1209 * returns: 1 if this is the first time we've heard from this host
1210 * 0 is this is a duplicate reply
1211 */
add2pr_list(slp_msg_t * msg,struct sockaddr_in * sin,void ** collator)1212 static int add2pr_list(
1213 slp_msg_t *msg,
1214 struct sockaddr_in *sin,
1215 void **collator) {
1216
1217 char **res, *cname, *p, *header;
1218 size_t mtu;
1219 size_t len, off, namelen;
1220 unsigned short prlen;
1221
1222 /* Attempt to resolve the responder's IP address to its host name */
1223 if (!(cname = slp_gethostbyaddr((char *)&(sin->sin_addr),
1224 sizeof (sin->sin_addr))))
1225 return (0);
1226
1227 res = slp_tsearch(
1228 cname, collator,
1229 (int (*)(const void *, const void *)) strcasecmp);
1230 if (*res != cname) {
1231 /* duplicate */
1232 slp_err(LOG_INFO, 0, "add2pr_list",
1233 "drop PR ignored by host: %s",
1234 cname);
1235 free(cname);
1236 return (0);
1237 }
1238
1239 /* new responder: add to the msg PR list if there is room */
1240 mtu = slp_get_mtu();
1241
1242 header = msg->iov[0].iov_base;
1243 len = slp_get_length(header);
1244
1245 namelen = strlen(cname);
1246 if ((namelen + 2 + len) >= mtu)
1247 return (1); /* no room */
1248
1249 /* else there is enough room */
1250 prlen = (unsigned short)msg->prlist->iov_len;
1251 p = msg->prlist->iov_base + prlen;
1252 *p = 0;
1253
1254 if (prlen) {
1255 namelen++; /* add the ',' */
1256 (void) strcat(p, ",");
1257 }
1258 (void) strcat(p, cname);
1259
1260 /* update msg and pr list length */
1261 len += namelen;
1262 slp_set_length(header, len);
1263 prlen += (unsigned short)namelen;
1264 off = 0;
1265 (void) slp_add_sht(msg->prlistlen.iov_base, 2, prlen, &off);
1266 msg->prlist->iov_len += namelen;
1267
1268 return (1);
1269 }
1270
1271 /*
1272 * The iterator function used while traversing the previous responder
1273 * tree. Just frees resources.
1274 */
1275 /*ARGSUSED2*/
free_pr_node(void * node,VISIT order,int level,void * cookie)1276 static void free_pr_node(void *node, VISIT order, int level, void *cookie) {
1277 if (order == endorder || order == leaf) {
1278 char *pr = *(char **)node;
1279 free(pr);
1280 free(node);
1281 }
1282 }
1283