17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate * with the License.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate * and limitations under the License.
137c478bd9Sstevel@tonic-gate *
147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate *
207c478bd9Sstevel@tonic-gate * CDDL HEADER END
217c478bd9Sstevel@tonic-gate */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate * Module for all network transactions. SLP messages can be multicast,
297c478bd9Sstevel@tonic-gate * unicast over UDP, or unicast over TCP; this module provides routines
307c478bd9Sstevel@tonic-gate * for all three. TCP transactions are handled by a single dedicated
317c478bd9Sstevel@tonic-gate * thread, while multicast and UDP unicast messages are sent by the
327c478bd9Sstevel@tonic-gate * calling thread.
337c478bd9Sstevel@tonic-gate *
347c478bd9Sstevel@tonic-gate * slp_uc_tcp_send: enqueues a message on the TCP transaction thread's
357c478bd9Sstevel@tonic-gate * queue.
367c478bd9Sstevel@tonic-gate * slp_tcp_wait: blocks until all TCP-enqueued transactions for
377c478bd9Sstevel@tonic-gate * a given SLP handle are complete
387c478bd9Sstevel@tonic-gate * slp_uc_udp_send: unicasts a message using a datagram
397c478bd9Sstevel@tonic-gate * slp_mc_send: multicasts a message
407c478bd9Sstevel@tonic-gate */
417c478bd9Sstevel@tonic-gate
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate * todo: correct multicast interfaces;
447c478bd9Sstevel@tonic-gate */
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gate #include <stdio.h>
477c478bd9Sstevel@tonic-gate #include <stdlib.h>
487c478bd9Sstevel@tonic-gate #include <syslog.h>
497c478bd9Sstevel@tonic-gate #include <sys/types.h>
507c478bd9Sstevel@tonic-gate #include <sys/socket.h>
517c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
527c478bd9Sstevel@tonic-gate #include <errno.h>
537c478bd9Sstevel@tonic-gate #include <unistd.h>
547c478bd9Sstevel@tonic-gate #include <time.h>
557c478bd9Sstevel@tonic-gate #include <string.h>
567c478bd9Sstevel@tonic-gate #include <slp-internal.h>
577c478bd9Sstevel@tonic-gate #include <slp_net_utils.h>
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate /*
607c478bd9Sstevel@tonic-gate * TCP thread particulars
617c478bd9Sstevel@tonic-gate */
627c478bd9Sstevel@tonic-gate static SLPBoolean tcp_thr_running = SLP_FALSE;
637c478bd9Sstevel@tonic-gate static slp_queue_t *tcp_q;
647c478bd9Sstevel@tonic-gate static int tcp_sockfd;
657c478bd9Sstevel@tonic-gate static mutex_t start_lock = DEFAULTMUTEX;
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate /* Used to pass arguments to the TCP thread, via 'tcp_q' */
687c478bd9Sstevel@tonic-gate struct tcp_rqst {
697c478bd9Sstevel@tonic-gate slp_handle_impl_t *hp;
707c478bd9Sstevel@tonic-gate slp_target_t *target;
717c478bd9Sstevel@tonic-gate const char *scopes;
727c478bd9Sstevel@tonic-gate SLPBoolean free_target;
737c478bd9Sstevel@tonic-gate unsigned short xid;
747c478bd9Sstevel@tonic-gate };
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate /* Used to keep track of broadcast interfaces */
777c478bd9Sstevel@tonic-gate struct bc_ifs {
787c478bd9Sstevel@tonic-gate struct sockaddr_in *sin;
797c478bd9Sstevel@tonic-gate int num_ifs;
807c478bd9Sstevel@tonic-gate };
817c478bd9Sstevel@tonic-gate
827c478bd9Sstevel@tonic-gate /*
837c478bd9Sstevel@tonic-gate * Private utility routines
847c478bd9Sstevel@tonic-gate */
857c478bd9Sstevel@tonic-gate static SLPError start_tcp_thr();
86*48d1bcbbSToomas Soome static void *tcp_thread(void *);
877c478bd9Sstevel@tonic-gate static SLPError make_header(slp_handle_impl_t *, char *, const char *);
887c478bd9Sstevel@tonic-gate static void udp_make_msghdr(struct sockaddr_in *, struct iovec *, int,
897c478bd9Sstevel@tonic-gate struct msghdr *);
907c478bd9Sstevel@tonic-gate static SLPError make_mc_target(slp_handle_impl_t *,
917c478bd9Sstevel@tonic-gate struct sockaddr_in *, char *,
927c478bd9Sstevel@tonic-gate struct pollfd **, nfds_t *, struct bc_ifs *);
937c478bd9Sstevel@tonic-gate static SLPError make_bc_target(slp_handle_impl_t *, struct in_addr *,
947c478bd9Sstevel@tonic-gate int, struct bc_ifs *);
957c478bd9Sstevel@tonic-gate static SLPError mc_sendmsg(struct pollfd *, struct msghdr *,
967c478bd9Sstevel@tonic-gate struct bc_ifs *);
977c478bd9Sstevel@tonic-gate static SLPError bc_sendmsg(struct pollfd *, struct msghdr *, struct bc_ifs *);
987c478bd9Sstevel@tonic-gate static void mc_recvmsg(struct pollfd *, nfds_t, slp_handle_impl_t *,
997c478bd9Sstevel@tonic-gate const char *, char *, void **, unsigned long long,
1007c478bd9Sstevel@tonic-gate unsigned long long, unsigned long long *,
1017c478bd9Sstevel@tonic-gate int *, int *, int);
1027c478bd9Sstevel@tonic-gate static void free_pfds(struct pollfd *, nfds_t);
1037c478bd9Sstevel@tonic-gate static void tcp_handoff(slp_handle_impl_t *, const char *,
1047c478bd9Sstevel@tonic-gate struct sockaddr_in *, unsigned short);
1057c478bd9Sstevel@tonic-gate static unsigned long long now_millis();
1067c478bd9Sstevel@tonic-gate static int wait_for_response(unsigned long long, int *,
1077c478bd9Sstevel@tonic-gate unsigned long long, unsigned long long *,
1087c478bd9Sstevel@tonic-gate struct pollfd [], nfds_t);
1097c478bd9Sstevel@tonic-gate static int add2pr_list(slp_msg_t *, struct sockaddr_in *, void **);
1107c478bd9Sstevel@tonic-gate static void free_pr_node(void *, VISIT, int, void *);
1117c478bd9Sstevel@tonic-gate
1127c478bd9Sstevel@tonic-gate /*
1137c478bd9Sstevel@tonic-gate * Unicasts a message using TCP. 'target' is a targets list
1147c478bd9Sstevel@tonic-gate * containing DAs corresponding to 'scopes'. 'free_target' directs
1157c478bd9Sstevel@tonic-gate * tcp_thread to free the target list when finished; this is useful
1167c478bd9Sstevel@tonic-gate * when a target needs to be synthesised by another message thread
1177c478bd9Sstevel@tonic-gate * (such as slp_mc_send for tcp_handoffs). If this message is a
1187c478bd9Sstevel@tonic-gate * retransmission due to a large reply, 'xid' should be the same as for
1197c478bd9Sstevel@tonic-gate * the original message.
1207c478bd9Sstevel@tonic-gate *
1217c478bd9Sstevel@tonic-gate * This call returns as soon as the message has been enqueued on 'tcp_q'.
1227c478bd9Sstevel@tonic-gate * Callers interested in knowing when the transaction has completed
1237c478bd9Sstevel@tonic-gate * should call slp_tcp_wait with the same SLP handle.
1247c478bd9Sstevel@tonic-gate */
slp_uc_tcp_send(slp_handle_impl_t * hp,slp_target_t * target,const char * scopes,SLPBoolean free_target,unsigned short xid)1257c478bd9Sstevel@tonic-gate void slp_uc_tcp_send(slp_handle_impl_t *hp, slp_target_t *target,
1267c478bd9Sstevel@tonic-gate const char *scopes, SLPBoolean free_target,
1277c478bd9Sstevel@tonic-gate unsigned short xid) {
1287c478bd9Sstevel@tonic-gate struct tcp_rqst *rqst;
1297c478bd9Sstevel@tonic-gate
1307c478bd9Sstevel@tonic-gate /* initialize TCP vars in handle, if necessary */
1317c478bd9Sstevel@tonic-gate if (!hp->tcp_lock) {
1327c478bd9Sstevel@tonic-gate if (!(hp->tcp_lock = malloc(sizeof (*(hp->tcp_lock))))) {
1337c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "slp_uc_tcp_send",
1347c478bd9Sstevel@tonic-gate "out of memory");
1357c478bd9Sstevel@tonic-gate return;
1367c478bd9Sstevel@tonic-gate }
1370daffde0SToomas Soome (void) mutex_init(hp->tcp_lock, USYNC_THREAD, NULL);
1387c478bd9Sstevel@tonic-gate }
1397c478bd9Sstevel@tonic-gate if (!hp->tcp_wait) {
1407c478bd9Sstevel@tonic-gate if (!(hp->tcp_wait = malloc(sizeof (*(hp->tcp_wait))))) {
1417c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "slp_uc_tcp_send",
1427c478bd9Sstevel@tonic-gate "out of memory");
1437c478bd9Sstevel@tonic-gate return;
1447c478bd9Sstevel@tonic-gate }
1450daffde0SToomas Soome (void) cond_init(hp->tcp_wait, USYNC_THREAD, NULL);
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate (void) mutex_lock(hp->tcp_lock);
1487c478bd9Sstevel@tonic-gate (hp->tcp_ref_cnt)++;
1497c478bd9Sstevel@tonic-gate (void) mutex_unlock(hp->tcp_lock);
1507c478bd9Sstevel@tonic-gate
1517c478bd9Sstevel@tonic-gate /* start TCP thread, if not already running */
1527c478bd9Sstevel@tonic-gate if (!tcp_thr_running)
1537c478bd9Sstevel@tonic-gate if (start_tcp_thr() != SLP_OK)
1547c478bd9Sstevel@tonic-gate return;
1557c478bd9Sstevel@tonic-gate
1567c478bd9Sstevel@tonic-gate /* create and enqueue the request */
1577c478bd9Sstevel@tonic-gate if (!(rqst = malloc(sizeof (*rqst)))) {
1587c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "slp_uc_tcp_send", "out of memory");
1597c478bd9Sstevel@tonic-gate return;
1607c478bd9Sstevel@tonic-gate }
1617c478bd9Sstevel@tonic-gate rqst->hp = hp;
1627c478bd9Sstevel@tonic-gate rqst->target = target;
1637c478bd9Sstevel@tonic-gate rqst->scopes = scopes;
1647c478bd9Sstevel@tonic-gate rqst->free_target = free_target;
1657c478bd9Sstevel@tonic-gate rqst->xid = xid;
1667c478bd9Sstevel@tonic-gate (void) slp_enqueue(tcp_q, rqst);
1677c478bd9Sstevel@tonic-gate }
1687c478bd9Sstevel@tonic-gate
1697c478bd9Sstevel@tonic-gate /*
1707c478bd9Sstevel@tonic-gate * Wait for TCP to complete, if a transaction corresponding to this
1717c478bd9Sstevel@tonic-gate * SLP handle is pending. If none are pending, returns immediately.
1727c478bd9Sstevel@tonic-gate */
slp_tcp_wait(slp_handle_impl_t * hp)1737c478bd9Sstevel@tonic-gate void slp_tcp_wait(slp_handle_impl_t *hp) {
1747c478bd9Sstevel@tonic-gate (void) mutex_lock(hp->tcp_lock);
1757c478bd9Sstevel@tonic-gate while (hp->tcp_ref_cnt > 0)
1767c478bd9Sstevel@tonic-gate (void) cond_wait(hp->tcp_wait, hp->tcp_lock);
1777c478bd9Sstevel@tonic-gate (void) mutex_unlock(hp->tcp_lock);
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate /*
1817c478bd9Sstevel@tonic-gate * Unicasts a message using datagrams. 'target' should contain a
1827c478bd9Sstevel@tonic-gate * list of DAs corresponding to 'scopes'.
1837c478bd9Sstevel@tonic-gate *
1847c478bd9Sstevel@tonic-gate * This call does not return until the transaction has completed. It
1857c478bd9Sstevel@tonic-gate * may handoff a message to the TCP thread if necessary, but will not
1867c478bd9Sstevel@tonic-gate * wait for that transaction to complete. Hence callers should always
1877c478bd9Sstevel@tonic-gate * invoke slp_tcp_wait before cleaning up resources.
1887c478bd9Sstevel@tonic-gate */
slp_uc_udp_send(slp_handle_impl_t * hp,slp_target_t * target,const char * scopes)1897c478bd9Sstevel@tonic-gate void slp_uc_udp_send(slp_handle_impl_t *hp, slp_target_t *target,
1907c478bd9Sstevel@tonic-gate const char *scopes) {
1917c478bd9Sstevel@tonic-gate slp_target_t *ctarg;
1927c478bd9Sstevel@tonic-gate struct sockaddr_in *sin;
1937c478bd9Sstevel@tonic-gate struct msghdr msg[1];
1947c478bd9Sstevel@tonic-gate char header[SLP_DEFAULT_SENDMTU];
1957c478bd9Sstevel@tonic-gate int sockfd;
1967c478bd9Sstevel@tonic-gate size_t mtu;
1977c478bd9Sstevel@tonic-gate SLPBoolean use_tcp;
1987c478bd9Sstevel@tonic-gate struct pollfd pfd[1];
1997c478bd9Sstevel@tonic-gate unsigned long long now, sent;
2007c478bd9Sstevel@tonic-gate char *reply = NULL;
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate use_tcp = SLP_FALSE;
2037c478bd9Sstevel@tonic-gate /* build the header and iovec */
2047c478bd9Sstevel@tonic-gate if (make_header(hp, header, scopes) != SLP_OK)
2057c478bd9Sstevel@tonic-gate return;
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate mtu = slp_get_mtu();
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate /* walk targets list until we either succeed or run out of targets */
2107c478bd9Sstevel@tonic-gate for (ctarg = target; ctarg; ctarg = slp_next_failover(ctarg)) {
2117c478bd9Sstevel@tonic-gate char *state;
2127c478bd9Sstevel@tonic-gate const char *timeouts;
2137c478bd9Sstevel@tonic-gate int timeout;
2147c478bd9Sstevel@tonic-gate
2157c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)slp_get_target_sin(ctarg);
2167c478bd9Sstevel@tonic-gate
2177c478bd9Sstevel@tonic-gate /* make the socket, msghdr and reply buf */
2187c478bd9Sstevel@tonic-gate if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
2197c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "slp_uc_udp_send",
2207c478bd9Sstevel@tonic-gate "could not create socket: %s",
2217c478bd9Sstevel@tonic-gate strerror(errno));
2227c478bd9Sstevel@tonic-gate return;
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate pfd[0].fd = sockfd;
2257c478bd9Sstevel@tonic-gate pfd[0].events = POLLRDNORM;
2267c478bd9Sstevel@tonic-gate
2277c478bd9Sstevel@tonic-gate udp_make_msghdr(sin, hp->msg.iov, hp->msg.iovlen, msg);
2287c478bd9Sstevel@tonic-gate if (!reply && !(reply = malloc(mtu))) {
2297c478bd9Sstevel@tonic-gate (void) close(sockfd);
2307c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "slp_uc_udp_send",
2317c478bd9Sstevel@tonic-gate "out of memory");
2327c478bd9Sstevel@tonic-gate return;
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate
2357c478bd9Sstevel@tonic-gate /* timeout loop */
2367c478bd9Sstevel@tonic-gate timeouts = SLPGetProperty(SLP_CONFIG_DATAGRAMTIMEOUTS);
2377c478bd9Sstevel@tonic-gate state = (char *)timeouts;
2387c478bd9Sstevel@tonic-gate for (timeout = slp_get_next_onlist(&state);
2397c478bd9Sstevel@tonic-gate timeout != -1 &&
2407c478bd9Sstevel@tonic-gate !hp->cancel;
2417c478bd9Sstevel@tonic-gate timeout = slp_get_next_onlist(&state)) {
2427c478bd9Sstevel@tonic-gate int pollerr;
2437c478bd9Sstevel@tonic-gate
2447c478bd9Sstevel@tonic-gate if (sendmsg(sockfd, msg, 0) < 0) {
2457c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "slp_uc_udp_send",
2467c478bd9Sstevel@tonic-gate "sendmsg failed: %s", strerror(errno));
2477c478bd9Sstevel@tonic-gate continue; /* try again */
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate sent = now_millis();
2507c478bd9Sstevel@tonic-gate
2517c478bd9Sstevel@tonic-gate pollerr = wait_for_response(
2527c478bd9Sstevel@tonic-gate 0, &timeout, sent, &now, pfd, 1);
2537c478bd9Sstevel@tonic-gate
2547c478bd9Sstevel@tonic-gate if (pollerr == 0)
2557c478bd9Sstevel@tonic-gate /* timeout */
2567c478bd9Sstevel@tonic-gate continue;
2577c478bd9Sstevel@tonic-gate if (pollerr < 0)
2587c478bd9Sstevel@tonic-gate break;
2597c478bd9Sstevel@tonic-gate
2607c478bd9Sstevel@tonic-gate /* only using one fd, so no need to scan pfd */
2617c478bd9Sstevel@tonic-gate if (recvfrom(sockfd, reply, mtu, 0, NULL, NULL) < 0) {
2627c478bd9Sstevel@tonic-gate /* if reply overflows, hand off to TCP */
2637c478bd9Sstevel@tonic-gate if (errno == ENOMEM) {
2647c478bd9Sstevel@tonic-gate free(reply); reply = NULL;
2657c478bd9Sstevel@tonic-gate use_tcp = SLP_TRUE;
2667c478bd9Sstevel@tonic-gate break;
2677c478bd9Sstevel@tonic-gate }
2687c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "slp_uc_udp_send",
2697c478bd9Sstevel@tonic-gate "recvfrom failed: %s",
2707c478bd9Sstevel@tonic-gate strerror(errno));
2717c478bd9Sstevel@tonic-gate } else {
2727c478bd9Sstevel@tonic-gate /* success -- but check error code */
2737c478bd9Sstevel@tonic-gate slp_proto_err errcode = slp_get_errcode(reply);
2747c478bd9Sstevel@tonic-gate switch (errcode) {
2757c478bd9Sstevel@tonic-gate case SLP_MSG_PARSE_ERROR:
2767c478bd9Sstevel@tonic-gate case SLP_VER_NOT_SUPPORTED:
2777c478bd9Sstevel@tonic-gate case SLP_SICK_DA:
2787c478bd9Sstevel@tonic-gate case SLP_DA_BUSY_NOW:
2797c478bd9Sstevel@tonic-gate case SLP_OPTION_NOT_UNDERSTOOD:
2807c478bd9Sstevel@tonic-gate case SLP_RQST_NOT_SUPPORTED: {
2817c478bd9Sstevel@tonic-gate char addrbuf[INET6_ADDRSTRLEN], *cname;
2827c478bd9Sstevel@tonic-gate
2837c478bd9Sstevel@tonic-gate cname = slp_ntop(addrbuf, INET6_ADDRSTRLEN,
2847c478bd9Sstevel@tonic-gate (const void *) &(sin->sin_addr));
2857c478bd9Sstevel@tonic-gate cname = cname ? cname : "[invalid addr]";
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate /* drop it */
2887c478bd9Sstevel@tonic-gate slp_err(LOG_INFO, 0,
2897c478bd9Sstevel@tonic-gate "DA %s returned error code %d; dropping reply",
2907c478bd9Sstevel@tonic-gate cname, errcode);
2917c478bd9Sstevel@tonic-gate free(reply); reply = NULL;
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate }
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate break;
2967c478bd9Sstevel@tonic-gate }
2977c478bd9Sstevel@tonic-gate if (timeout != -1)
2987c478bd9Sstevel@tonic-gate /* success or cancel */
2997c478bd9Sstevel@tonic-gate break;
3007c478bd9Sstevel@tonic-gate /* else failure */
3017c478bd9Sstevel@tonic-gate slp_mark_target_failed(ctarg);
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate (void) close(sockfd);
3047c478bd9Sstevel@tonic-gate if (!ctarg || hp->cancel) {
3057c478bd9Sstevel@tonic-gate /* failed all attempts or canceled by consumer */
3067c478bd9Sstevel@tonic-gate if (reply) free(reply);
3077c478bd9Sstevel@tonic-gate return;
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate /* success or tcp handoff */
3107c478bd9Sstevel@tonic-gate if (reply) {
3117c478bd9Sstevel@tonic-gate if (slp_get_overflow(reply))
3127c478bd9Sstevel@tonic-gate use_tcp = SLP_TRUE;
3137c478bd9Sstevel@tonic-gate else
3147c478bd9Sstevel@tonic-gate slp_mark_target_used(ctarg);
3157c478bd9Sstevel@tonic-gate (void) slp_enqueue(hp->q, reply);
3167c478bd9Sstevel@tonic-gate }
3177c478bd9Sstevel@tonic-gate if (use_tcp)
3187c478bd9Sstevel@tonic-gate slp_uc_tcp_send(
3197c478bd9Sstevel@tonic-gate hp, ctarg, scopes, SLP_FALSE, slp_get_xid(header));
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate
3227c478bd9Sstevel@tonic-gate /*
3237c478bd9Sstevel@tonic-gate * Multicasts (or broadcasts) a message, using multicast convergance
3247c478bd9Sstevel@tonic-gate * to collect results. Large replies will cause the message to be handed
3257c478bd9Sstevel@tonic-gate * off to the TCP thread.
3267c478bd9Sstevel@tonic-gate *
3277c478bd9Sstevel@tonic-gate * This call does not return until the transaction is complete. It does
3287c478bd9Sstevel@tonic-gate * not, however, wait until pending TCP transactions are complete, so
3297c478bd9Sstevel@tonic-gate * callers should always invoke slp_tcp_wait before cleaning up any
3307c478bd9Sstevel@tonic-gate * resources.
3317c478bd9Sstevel@tonic-gate */
slp_mc_send(slp_handle_impl_t * hp,const char * scopes)3327c478bd9Sstevel@tonic-gate void slp_mc_send(slp_handle_impl_t *hp, const char *scopes) {
3337c478bd9Sstevel@tonic-gate char header[SLP_DEFAULT_SENDMTU], *state;
3347c478bd9Sstevel@tonic-gate const char *timeouts;
3357c478bd9Sstevel@tonic-gate struct sockaddr_in sin[1];
3367c478bd9Sstevel@tonic-gate struct msghdr msg[1];
3377c478bd9Sstevel@tonic-gate int maxwait, timeout, noresults, anyresults;
3387c478bd9Sstevel@tonic-gate unsigned long long final_to, now, sent;
3397c478bd9Sstevel@tonic-gate struct pollfd *pfd;
3407c478bd9Sstevel@tonic-gate nfds_t nfds;
3417c478bd9Sstevel@tonic-gate void *collator = NULL;
3427c478bd9Sstevel@tonic-gate struct bc_ifs bcifs;
3437c478bd9Sstevel@tonic-gate
3447c478bd9Sstevel@tonic-gate /* build the header and iovec */
3457c478bd9Sstevel@tonic-gate if (make_header(hp, header, scopes) != SLP_OK)
3467c478bd9Sstevel@tonic-gate return;
3477c478bd9Sstevel@tonic-gate
3487c478bd9Sstevel@tonic-gate (void) memset(sin, 0, sizeof (sin));
3497c478bd9Sstevel@tonic-gate if (make_mc_target(hp, sin, header, &pfd, &nfds, &bcifs) != SLP_OK)
3507c478bd9Sstevel@tonic-gate return;
3517c478bd9Sstevel@tonic-gate udp_make_msghdr(sin, hp->msg.iov, hp->msg.iovlen, msg);
3527c478bd9Sstevel@tonic-gate
3537c478bd9Sstevel@tonic-gate maxwait = slp_get_mcmaxwait();
3547c478bd9Sstevel@tonic-gate maxwait = maxwait ? maxwait : SLP_DEFAULT_MAXWAIT;
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate /* set the final timeout */
3577c478bd9Sstevel@tonic-gate now = now_millis();
3587c478bd9Sstevel@tonic-gate final_to = now + maxwait;
3597c478bd9Sstevel@tonic-gate
3607c478bd9Sstevel@tonic-gate /* timeout prep and loop */
3617c478bd9Sstevel@tonic-gate timeouts = SLPGetProperty(SLP_CONFIG_MULTICASTTIMEOUTS);
3627c478bd9Sstevel@tonic-gate state = (char *)timeouts;
3637c478bd9Sstevel@tonic-gate noresults = anyresults = 0;
3647c478bd9Sstevel@tonic-gate
3657c478bd9Sstevel@tonic-gate for (timeout = slp_get_next_onlist(&state);
3667c478bd9Sstevel@tonic-gate timeout != -1 &&
3677c478bd9Sstevel@tonic-gate now < final_to &&
3687c478bd9Sstevel@tonic-gate noresults < 2 &&
3697c478bd9Sstevel@tonic-gate !hp->cancel;
3707c478bd9Sstevel@tonic-gate timeout = slp_get_next_onlist(&state)) {
3717c478bd9Sstevel@tonic-gate
3727c478bd9Sstevel@tonic-gate /* send msg */
3737c478bd9Sstevel@tonic-gate if (mc_sendmsg(pfd, msg, &bcifs) != SLP_OK) {
3747c478bd9Sstevel@tonic-gate continue; /* try again */
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate sent = now_millis();
3777c478bd9Sstevel@tonic-gate
3787c478bd9Sstevel@tonic-gate /* receive results */
3797c478bd9Sstevel@tonic-gate mc_recvmsg(pfd, nfds, hp, scopes, header, &collator, final_to,
3807c478bd9Sstevel@tonic-gate sent, &now, &noresults, &anyresults, timeout);
3817c478bd9Sstevel@tonic-gate
3827c478bd9Sstevel@tonic-gate if (!anyresults)
3837c478bd9Sstevel@tonic-gate noresults++;
3847c478bd9Sstevel@tonic-gate anyresults = 0;
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate /* clean up PR list collator */
3877c478bd9Sstevel@tonic-gate if (collator)
3887c478bd9Sstevel@tonic-gate slp_twalk(collator, free_pr_node, 0, NULL);
3897c478bd9Sstevel@tonic-gate
3907c478bd9Sstevel@tonic-gate /* close all fds in pfd */
3917c478bd9Sstevel@tonic-gate free_pfds(pfd, nfds);
3927c478bd9Sstevel@tonic-gate
3937c478bd9Sstevel@tonic-gate /* free broadcast addrs, if used */
3947c478bd9Sstevel@tonic-gate if (bcifs.sin) free(bcifs.sin);
3957c478bd9Sstevel@tonic-gate }
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate /*
3987c478bd9Sstevel@tonic-gate * Private net helper routines
3997c478bd9Sstevel@tonic-gate */
4007c478bd9Sstevel@tonic-gate
4017c478bd9Sstevel@tonic-gate /*
4027c478bd9Sstevel@tonic-gate * Starts the tcp_thread and allocates any necessary resources.
4037c478bd9Sstevel@tonic-gate */
404*48d1bcbbSToomas Soome static SLPError
start_tcp_thr(void)405*48d1bcbbSToomas Soome start_tcp_thr(void)
406*48d1bcbbSToomas Soome {
4077c478bd9Sstevel@tonic-gate SLPError err;
4087c478bd9Sstevel@tonic-gate int terr;
4097c478bd9Sstevel@tonic-gate
4107c478bd9Sstevel@tonic-gate (void) mutex_lock(&start_lock);
4117c478bd9Sstevel@tonic-gate /* make sure someone else hasn't already intialized the thread */
4127c478bd9Sstevel@tonic-gate if (tcp_thr_running) {
4137c478bd9Sstevel@tonic-gate (void) mutex_unlock(&start_lock);
4147c478bd9Sstevel@tonic-gate return (SLP_OK);
4157c478bd9Sstevel@tonic-gate }
4167c478bd9Sstevel@tonic-gate
4177c478bd9Sstevel@tonic-gate /* create the tcp queue */
4187c478bd9Sstevel@tonic-gate if (!(tcp_q = slp_new_queue(&err))) {
4197c478bd9Sstevel@tonic-gate (void) mutex_unlock(&start_lock);
4207c478bd9Sstevel@tonic-gate return (err);
4217c478bd9Sstevel@tonic-gate }
4227c478bd9Sstevel@tonic-gate
4237c478bd9Sstevel@tonic-gate /* start the tcp thread */
424*48d1bcbbSToomas Soome if ((terr = thr_create(0, 0, tcp_thread, NULL, 0, NULL)) != 0) {
425*48d1bcbbSToomas Soome slp_err(LOG_CRIT, 0, "start_tcp_thr",
4267c478bd9Sstevel@tonic-gate "could not start thread: %s", strerror(terr));
427*48d1bcbbSToomas Soome (void) mutex_unlock(&start_lock);
428*48d1bcbbSToomas Soome return (SLP_INTERNAL_SYSTEM_ERROR);
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate
4317c478bd9Sstevel@tonic-gate tcp_thr_running = SLP_TRUE;
4327c478bd9Sstevel@tonic-gate (void) mutex_unlock(&start_lock);
4337c478bd9Sstevel@tonic-gate return (SLP_OK);
4347c478bd9Sstevel@tonic-gate }
4357c478bd9Sstevel@tonic-gate
4367c478bd9Sstevel@tonic-gate /*
4377c478bd9Sstevel@tonic-gate * Called by the tcp thread to shut itself down. The queue must be
4387c478bd9Sstevel@tonic-gate * empty (and should be, since the tcp thread will only shut itself
4397c478bd9Sstevel@tonic-gate * down if nothing has been put in its queue for the timeout period).
4407c478bd9Sstevel@tonic-gate */
end_tcp_thr()4417c478bd9Sstevel@tonic-gate static void end_tcp_thr() {
4427c478bd9Sstevel@tonic-gate (void) mutex_lock(&start_lock);
4437c478bd9Sstevel@tonic-gate
4447c478bd9Sstevel@tonic-gate tcp_thr_running = SLP_FALSE;
4457c478bd9Sstevel@tonic-gate slp_destroy_queue(tcp_q);
4467c478bd9Sstevel@tonic-gate
4477c478bd9Sstevel@tonic-gate (void) mutex_unlock(&start_lock);
4487c478bd9Sstevel@tonic-gate thr_exit(NULL);
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate
4517c478bd9Sstevel@tonic-gate /*
4527c478bd9Sstevel@tonic-gate * The thread of control for the TCP thread. This sits in a loop, waiting
4537c478bd9Sstevel@tonic-gate * on 'tcp_q' for new messages. If no message appear after 30 seconds,
4547c478bd9Sstevel@tonic-gate * this thread cleans up resources and shuts itself down.
4557c478bd9Sstevel@tonic-gate */
456*48d1bcbbSToomas Soome static void *
tcp_thread(void * arg __unused)457*48d1bcbbSToomas Soome tcp_thread(void *arg __unused)
458*48d1bcbbSToomas Soome {
4597c478bd9Sstevel@tonic-gate struct tcp_rqst *rqst;
4607c478bd9Sstevel@tonic-gate char *reply, header[SLP_DEFAULT_SENDMTU];
4617c478bd9Sstevel@tonic-gate timestruc_t to[1];
4627c478bd9Sstevel@tonic-gate to->tv_nsec = 0;
4637c478bd9Sstevel@tonic-gate
4647c478bd9Sstevel@tonic-gate for (;;) {
4657c478bd9Sstevel@tonic-gate slp_target_t *ctarg, *targets;
4667c478bd9Sstevel@tonic-gate slp_handle_impl_t *hp;
4677c478bd9Sstevel@tonic-gate const char *scopes;
4687c478bd9Sstevel@tonic-gate struct sockaddr_in *sin;
4697c478bd9Sstevel@tonic-gate SLPBoolean free_target, etimed;
4707c478bd9Sstevel@tonic-gate unsigned short xid;
4717c478bd9Sstevel@tonic-gate
4727c478bd9Sstevel@tonic-gate /* set idle shutdown timeout */
4737c478bd9Sstevel@tonic-gate to->tv_sec = time(NULL) + 30;
4747c478bd9Sstevel@tonic-gate /* get the next request from the tcp queue */
4757c478bd9Sstevel@tonic-gate if (!(rqst = slp_dequeue_timed(tcp_q, to, &etimed))) {
4767c478bd9Sstevel@tonic-gate if (!etimed)
4777c478bd9Sstevel@tonic-gate continue;
4787c478bd9Sstevel@tonic-gate else
4797c478bd9Sstevel@tonic-gate end_tcp_thr();
4807c478bd9Sstevel@tonic-gate }
4817c478bd9Sstevel@tonic-gate
4827c478bd9Sstevel@tonic-gate hp = rqst->hp;
4837c478bd9Sstevel@tonic-gate scopes = rqst->scopes;
4847c478bd9Sstevel@tonic-gate targets = rqst->target;
4857c478bd9Sstevel@tonic-gate free_target = rqst->free_target;
4867c478bd9Sstevel@tonic-gate xid = rqst->xid;
4877c478bd9Sstevel@tonic-gate free(rqst);
4887c478bd9Sstevel@tonic-gate reply = NULL;
4897c478bd9Sstevel@tonic-gate
4907c478bd9Sstevel@tonic-gate /* Check if this handle has been cancelled */
4917c478bd9Sstevel@tonic-gate if (hp->cancel)
4927c478bd9Sstevel@tonic-gate goto transaction_complete;
4937c478bd9Sstevel@tonic-gate
4947c478bd9Sstevel@tonic-gate /* build the header and iovec */
4957c478bd9Sstevel@tonic-gate if (make_header(hp, header, scopes) != SLP_OK) {
4967c478bd9Sstevel@tonic-gate if (free_target) slp_free_target(targets);
4977c478bd9Sstevel@tonic-gate continue;
4987c478bd9Sstevel@tonic-gate }
4997c478bd9Sstevel@tonic-gate if (xid)
5007c478bd9Sstevel@tonic-gate slp_set_xid(header, xid);
5017c478bd9Sstevel@tonic-gate
5027c478bd9Sstevel@tonic-gate /* walk targets list until we either succeed or run out of targets */
503*48d1bcbbSToomas Soome for (ctarg = targets; ctarg && !hp->cancel;
504*48d1bcbbSToomas Soome ctarg = slp_next_failover(ctarg)) {
5057c478bd9Sstevel@tonic-gate
5067c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)slp_get_target_sin(ctarg);
5077c478bd9Sstevel@tonic-gate
5087c478bd9Sstevel@tonic-gate /* create the socket */
5097c478bd9Sstevel@tonic-gate if ((tcp_sockfd = socket(AF_INET, SOCK_STREAM, 0))
5107c478bd9Sstevel@tonic-gate < 0) {
5117c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "tcp_thread",
512*48d1bcbbSToomas Soome "could not create socket: %s",
513*48d1bcbbSToomas Soome strerror(errno));
5147c478bd9Sstevel@tonic-gate ctarg = NULL;
5157c478bd9Sstevel@tonic-gate break;
5167c478bd9Sstevel@tonic-gate }
5177c478bd9Sstevel@tonic-gate
5187c478bd9Sstevel@tonic-gate /* connect to target */
5197c478bd9Sstevel@tonic-gate if (connect(tcp_sockfd, (struct sockaddr *)sin,
520*48d1bcbbSToomas Soome sizeof (*sin)) < 0) {
5217c478bd9Sstevel@tonic-gate slp_err(LOG_INFO, 0, "tcp_thread",
522*48d1bcbbSToomas Soome "could not connect, error = %s",
523*48d1bcbbSToomas Soome strerror(errno));
5247c478bd9Sstevel@tonic-gate goto failed;
5257c478bd9Sstevel@tonic-gate }
5267c478bd9Sstevel@tonic-gate
5277c478bd9Sstevel@tonic-gate /* send the message and read the reply */
5287c478bd9Sstevel@tonic-gate if (writev(tcp_sockfd, hp->msg.iov, hp->msg.iovlen)
5297c478bd9Sstevel@tonic-gate == -1) {
5307c478bd9Sstevel@tonic-gate slp_err(LOG_INFO, 0, "tcp_thread",
531*48d1bcbbSToomas Soome "could not send, error = %s",
532*48d1bcbbSToomas Soome strerror(errno));
5337c478bd9Sstevel@tonic-gate goto failed;
5347c478bd9Sstevel@tonic-gate }
5357c478bd9Sstevel@tonic-gate
5367c478bd9Sstevel@tonic-gate /* if success, break out of failover loop */
5377c478bd9Sstevel@tonic-gate if ((slp_tcp_read(tcp_sockfd, &reply)) == SLP_OK) {
5387c478bd9Sstevel@tonic-gate (void) close(tcp_sockfd);
5397c478bd9Sstevel@tonic-gate break;
5407c478bd9Sstevel@tonic-gate }
5417c478bd9Sstevel@tonic-gate
5427c478bd9Sstevel@tonic-gate /* else if timed out, mark target failed and try next one */
5437c478bd9Sstevel@tonic-gate failed:
5447c478bd9Sstevel@tonic-gate (void) close(tcp_sockfd);
5457c478bd9Sstevel@tonic-gate slp_mark_target_failed(ctarg);
5467c478bd9Sstevel@tonic-gate }
5477c478bd9Sstevel@tonic-gate
5487c478bd9Sstevel@tonic-gate if (hp->cancel) {
5497c478bd9Sstevel@tonic-gate if (reply) {
5507c478bd9Sstevel@tonic-gate free(reply);
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate } else if (ctarg) {
5537c478bd9Sstevel@tonic-gate /* success */
5547c478bd9Sstevel@tonic-gate (void) slp_enqueue(hp->q, reply);
5557c478bd9Sstevel@tonic-gate slp_mark_target_used(ctarg);
5567c478bd9Sstevel@tonic-gate }
5577c478bd9Sstevel@tonic-gate
5587c478bd9Sstevel@tonic-gate /* If all TCP transactions on this handle are complete, send notice */
5597c478bd9Sstevel@tonic-gate transaction_complete:
5607c478bd9Sstevel@tonic-gate (void) mutex_lock(hp->tcp_lock);
5617c478bd9Sstevel@tonic-gate if (--(hp->tcp_ref_cnt) == 0)
5627c478bd9Sstevel@tonic-gate (void) cond_signal(hp->tcp_wait);
5637c478bd9Sstevel@tonic-gate (void) mutex_unlock(hp->tcp_lock);
5647c478bd9Sstevel@tonic-gate
5657c478bd9Sstevel@tonic-gate if (free_target)
5667c478bd9Sstevel@tonic-gate slp_free_target(targets);
5677c478bd9Sstevel@tonic-gate }
568*48d1bcbbSToomas Soome return (NULL);
5697c478bd9Sstevel@tonic-gate }
5707c478bd9Sstevel@tonic-gate
5717c478bd9Sstevel@tonic-gate /*
5727c478bd9Sstevel@tonic-gate * Performs a full read for TCP replies, dynamically allocating a
5737c478bd9Sstevel@tonic-gate * buffer large enough to hold the reply.
5747c478bd9Sstevel@tonic-gate */
slp_tcp_read(int sockfd,char ** reply)5757c478bd9Sstevel@tonic-gate SLPError slp_tcp_read(int sockfd, char **reply) {
5767c478bd9Sstevel@tonic-gate char lenbuf[5], *p;
5777c478bd9Sstevel@tonic-gate size_t nleft;
5787c478bd9Sstevel@tonic-gate ssize_t nread;
5797c478bd9Sstevel@tonic-gate unsigned int len;
5807c478bd9Sstevel@tonic-gate
5817c478bd9Sstevel@tonic-gate /* find out how long the reply is */
5827c478bd9Sstevel@tonic-gate nleft = 5;
5837c478bd9Sstevel@tonic-gate p = lenbuf;
5847c478bd9Sstevel@tonic-gate while (nleft != 0) {
5857c478bd9Sstevel@tonic-gate if ((nread = read(sockfd, p, 5)) < 0) {
5867c478bd9Sstevel@tonic-gate if (errno == EINTR)
5877c478bd9Sstevel@tonic-gate nread = 0;
5887c478bd9Sstevel@tonic-gate else
5897c478bd9Sstevel@tonic-gate return (SLP_NETWORK_ERROR);
5907c478bd9Sstevel@tonic-gate } else if (nread == 0)
5917c478bd9Sstevel@tonic-gate /* shouldn't hit EOF here */
5927c478bd9Sstevel@tonic-gate return (SLP_NETWORK_ERROR);
5937c478bd9Sstevel@tonic-gate nleft -= nread;
5947c478bd9Sstevel@tonic-gate p += nread;
5957c478bd9Sstevel@tonic-gate }
5967c478bd9Sstevel@tonic-gate
5977c478bd9Sstevel@tonic-gate len = slp_get_length(lenbuf);
5987c478bd9Sstevel@tonic-gate
5997c478bd9Sstevel@tonic-gate /* allocate space for the reply, and copy in what we've already read */
6007c478bd9Sstevel@tonic-gate /* This buffer gets freed by a msg-specific unpacking routine later */
6017c478bd9Sstevel@tonic-gate if (!(*reply = malloc(len))) {
6027c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "tcp_read", "out of memory");
6037c478bd9Sstevel@tonic-gate return (SLP_MEMORY_ALLOC_FAILED);
6047c478bd9Sstevel@tonic-gate }
6057c478bd9Sstevel@tonic-gate (void) memcpy(*reply, lenbuf, 5);
6067c478bd9Sstevel@tonic-gate
6077c478bd9Sstevel@tonic-gate /* read the rest of the message */
6087c478bd9Sstevel@tonic-gate nleft = len - 5;
6097c478bd9Sstevel@tonic-gate p = *reply + 5;
6107c478bd9Sstevel@tonic-gate while (nleft != 0) {
6117c478bd9Sstevel@tonic-gate if ((nread = read(sockfd, p, nleft)) < 0) {
6127c478bd9Sstevel@tonic-gate if (errno == EINTR)
6137c478bd9Sstevel@tonic-gate nread = 0;
6147c478bd9Sstevel@tonic-gate else {
6157c478bd9Sstevel@tonic-gate free(*reply);
6167c478bd9Sstevel@tonic-gate return (SLP_NETWORK_ERROR);
6177c478bd9Sstevel@tonic-gate }
6187c478bd9Sstevel@tonic-gate } else if (nread == 0)
6197c478bd9Sstevel@tonic-gate /*
6207c478bd9Sstevel@tonic-gate * shouldn't hit EOF here, but perhaps we've
6217c478bd9Sstevel@tonic-gate * gotten something useful, so return OK.
6227c478bd9Sstevel@tonic-gate */
6237c478bd9Sstevel@tonic-gate return (SLP_OK);
6247c478bd9Sstevel@tonic-gate
6257c478bd9Sstevel@tonic-gate nleft -= nread;
6267c478bd9Sstevel@tonic-gate p += nread;
6277c478bd9Sstevel@tonic-gate }
6287c478bd9Sstevel@tonic-gate
6297c478bd9Sstevel@tonic-gate return (SLP_OK);
6307c478bd9Sstevel@tonic-gate }
6317c478bd9Sstevel@tonic-gate
6327c478bd9Sstevel@tonic-gate /*
6337c478bd9Sstevel@tonic-gate * Lays in a SLP header for this message into the scatter / gather
6347c478bd9Sstevel@tonic-gate * array 'iov'. 'header' is the buffer used to contain the header,
6357c478bd9Sstevel@tonic-gate * and must contain enough space. 'scopes' should contain a string
6367c478bd9Sstevel@tonic-gate * with the scopes to be used for this message.
6377c478bd9Sstevel@tonic-gate */
make_header(slp_handle_impl_t * hp,char * header,const char * scopes)6387c478bd9Sstevel@tonic-gate static SLPError make_header(slp_handle_impl_t *hp, char *header,
6397c478bd9Sstevel@tonic-gate const char *scopes) {
6407c478bd9Sstevel@tonic-gate SLPError err;
6417c478bd9Sstevel@tonic-gate size_t msgLen, off;
6427c478bd9Sstevel@tonic-gate int i;
6437c478bd9Sstevel@tonic-gate size_t mtu;
6447c478bd9Sstevel@tonic-gate unsigned short slen = (unsigned short)strlen(scopes);
6457c478bd9Sstevel@tonic-gate
6467c478bd9Sstevel@tonic-gate mtu = slp_get_mtu();
6477c478bd9Sstevel@tonic-gate msgLen = slp_hdrlang_length(hp);
6487c478bd9Sstevel@tonic-gate hp->msg.iov[0].iov_base = header;
6497c478bd9Sstevel@tonic-gate hp->msg.iov[0].iov_len = msgLen; /* now the length of the hdr */
6507c478bd9Sstevel@tonic-gate
6517c478bd9Sstevel@tonic-gate /* use the remaining buffer in header for the prlist */
6527c478bd9Sstevel@tonic-gate hp->msg.prlist->iov_base = header + msgLen;
6537c478bd9Sstevel@tonic-gate
6547c478bd9Sstevel@tonic-gate for (i = 1; i < hp->msg.iovlen; i++) {
6557c478bd9Sstevel@tonic-gate msgLen += hp->msg.iov[i].iov_len;
6567c478bd9Sstevel@tonic-gate }
6577c478bd9Sstevel@tonic-gate msgLen += slen;
6587c478bd9Sstevel@tonic-gate
6597c478bd9Sstevel@tonic-gate off = 0;
6607c478bd9Sstevel@tonic-gate if ((err = slp_add_header(hp->locale, header, mtu,
6617c478bd9Sstevel@tonic-gate hp->fid, msgLen, &off)) != SLP_OK)
6627c478bd9Sstevel@tonic-gate return (err);
6637c478bd9Sstevel@tonic-gate
6647c478bd9Sstevel@tonic-gate /* start out with empty prlist */
6657c478bd9Sstevel@tonic-gate hp->msg.prlist->iov_len = 0;
6667c478bd9Sstevel@tonic-gate
6677c478bd9Sstevel@tonic-gate /* store the scope string len into the space provided by the caller */
6687c478bd9Sstevel@tonic-gate off = 0;
6697c478bd9Sstevel@tonic-gate if ((err = slp_add_sht((char *)hp->msg.scopeslen.iov_base,
6707c478bd9Sstevel@tonic-gate 2, slen, &off)) != SLP_OK) {
6717c478bd9Sstevel@tonic-gate return (err);
6727c478bd9Sstevel@tonic-gate }
6737c478bd9Sstevel@tonic-gate hp->msg.scopes->iov_base = (caddr_t)scopes;
6747c478bd9Sstevel@tonic-gate hp->msg.scopes->iov_len = slen;
6757c478bd9Sstevel@tonic-gate
6767c478bd9Sstevel@tonic-gate return (SLP_OK);
6777c478bd9Sstevel@tonic-gate }
6787c478bd9Sstevel@tonic-gate
6797c478bd9Sstevel@tonic-gate /*
6807c478bd9Sstevel@tonic-gate * Populates a struct msghdr suitable for use with sendmsg.
6817c478bd9Sstevel@tonic-gate */
udp_make_msghdr(struct sockaddr_in * sin,struct iovec * iov,int iovlen,struct msghdr * msg)6827c478bd9Sstevel@tonic-gate static void udp_make_msghdr(struct sockaddr_in *sin, struct iovec *iov,
6837c478bd9Sstevel@tonic-gate int iovlen, struct msghdr *msg) {
6847c478bd9Sstevel@tonic-gate msg->msg_name = (caddr_t)sin;
6857c478bd9Sstevel@tonic-gate msg->msg_namelen = 16;
6867c478bd9Sstevel@tonic-gate msg->msg_iov = iov;
6877c478bd9Sstevel@tonic-gate msg->msg_iovlen = iovlen;
6887c478bd9Sstevel@tonic-gate msg->msg_accrights = NULL;
6897c478bd9Sstevel@tonic-gate msg->msg_accrightslen = 0;
6907c478bd9Sstevel@tonic-gate }
6917c478bd9Sstevel@tonic-gate
6927c478bd9Sstevel@tonic-gate /*
6937c478bd9Sstevel@tonic-gate * Sets the address on 'sin', sets the flag in the message header,
6947c478bd9Sstevel@tonic-gate * and creates an array of pollfds for all interfaces we need to
6957c478bd9Sstevel@tonic-gate * use. If we need to use only broadcast, and net.slp.interfaces
6967c478bd9Sstevel@tonic-gate * is set, fills bcifs with an array of subnet broadcast addresses
6977c478bd9Sstevel@tonic-gate * to which we should send. Returns err != SLP_OK only on catastrophic
6987c478bd9Sstevel@tonic-gate * error.
6997c478bd9Sstevel@tonic-gate */
make_mc_target(slp_handle_impl_t * hp,struct sockaddr_in * sin,char * header,struct pollfd ** fds,nfds_t * nfds,struct bc_ifs * bcifs)7007c478bd9Sstevel@tonic-gate static SLPError make_mc_target(slp_handle_impl_t *hp,
7017c478bd9Sstevel@tonic-gate struct sockaddr_in *sin, char *header,
7027c478bd9Sstevel@tonic-gate struct pollfd **fds, nfds_t *nfds,
7037c478bd9Sstevel@tonic-gate struct bc_ifs *bcifs) {
7047c478bd9Sstevel@tonic-gate
7057c478bd9Sstevel@tonic-gate unsigned char ttl = slp_get_multicastTTL();
7067c478bd9Sstevel@tonic-gate char *ifs_string;
7077c478bd9Sstevel@tonic-gate SLPBoolean have_valid_if = SLP_FALSE;
7087c478bd9Sstevel@tonic-gate SLPBoolean use_broadcast = slp_get_usebroadcast();
7097c478bd9Sstevel@tonic-gate int fd, i, num_givenifs;
7107c478bd9Sstevel@tonic-gate struct in_addr *given_ifs = NULL;
7117c478bd9Sstevel@tonic-gate nfds_t nfd_i;
7127c478bd9Sstevel@tonic-gate
7137c478bd9Sstevel@tonic-gate sin->sin_port = htons(SLP_PORT);
7147c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET;
7157c478bd9Sstevel@tonic-gate slp_set_mcast(header);
7167c478bd9Sstevel@tonic-gate
7177c478bd9Sstevel@tonic-gate /* Get the desired multicast interfaces, if set */
7187c478bd9Sstevel@tonic-gate bcifs->sin = NULL;
7197c478bd9Sstevel@tonic-gate *fds = NULL;
7207c478bd9Sstevel@tonic-gate if ((ifs_string = (char *)SLPGetProperty(
7217c478bd9Sstevel@tonic-gate SLP_CONFIG_INTERFACES)) != NULL && *ifs_string) {
7227c478bd9Sstevel@tonic-gate
7237c478bd9Sstevel@tonic-gate char *p, *tstate;
7247c478bd9Sstevel@tonic-gate
7257c478bd9Sstevel@tonic-gate /* count the number of IFs given */
7267c478bd9Sstevel@tonic-gate p = strchr(ifs_string, ',');
7277c478bd9Sstevel@tonic-gate for (num_givenifs = 1; p; num_givenifs++) {
7287c478bd9Sstevel@tonic-gate p = strchr(p + 1, ',');
7297c478bd9Sstevel@tonic-gate }
7307c478bd9Sstevel@tonic-gate
7317c478bd9Sstevel@tonic-gate /* copy the given IFs into an array for easier processing */
7327c478bd9Sstevel@tonic-gate if (!(given_ifs = calloc(num_givenifs, sizeof (*given_ifs)))) {
7337c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "make_mc_target",
7347c478bd9Sstevel@tonic-gate "out of memory");
7357c478bd9Sstevel@tonic-gate return (SLP_MEMORY_ALLOC_FAILED);
7367c478bd9Sstevel@tonic-gate }
7377c478bd9Sstevel@tonic-gate
7387c478bd9Sstevel@tonic-gate i = 0;
7397c478bd9Sstevel@tonic-gate /* strtok_r will destructively modify, so make a copy first */
7407c478bd9Sstevel@tonic-gate if (!(ifs_string = strdup(ifs_string))) {
7417c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "make_mc_target",
7427c478bd9Sstevel@tonic-gate "out of memory");
7437c478bd9Sstevel@tonic-gate free(given_ifs);
7447c478bd9Sstevel@tonic-gate return (SLP_MEMORY_ALLOC_FAILED);
7457c478bd9Sstevel@tonic-gate }
7467c478bd9Sstevel@tonic-gate for (
7477c478bd9Sstevel@tonic-gate p = strtok_r(ifs_string, ",", &tstate);
7487c478bd9Sstevel@tonic-gate p;
7497c478bd9Sstevel@tonic-gate p = strtok_r(NULL, ",", &tstate)) {
7507c478bd9Sstevel@tonic-gate
7517c478bd9Sstevel@tonic-gate if (slp_pton(p, &(given_ifs[i])) < 1) {
7527c478bd9Sstevel@tonic-gate /* skip */
7537c478bd9Sstevel@tonic-gate num_givenifs--;
7547c478bd9Sstevel@tonic-gate continue;
7557c478bd9Sstevel@tonic-gate }
7567c478bd9Sstevel@tonic-gate i++;
7577c478bd9Sstevel@tonic-gate }
7587c478bd9Sstevel@tonic-gate *nfds = num_givenifs;
7597c478bd9Sstevel@tonic-gate free(ifs_string);
7607c478bd9Sstevel@tonic-gate
7617c478bd9Sstevel@tonic-gate /* allocate a pollfd array for all interfaces */
7627c478bd9Sstevel@tonic-gate if (!(*fds = calloc(num_givenifs, sizeof (**fds)))) {
7637c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "make_mc_target",
7647c478bd9Sstevel@tonic-gate "out of memory");
7657c478bd9Sstevel@tonic-gate free(ifs_string);
7667c478bd9Sstevel@tonic-gate free(given_ifs);
7677c478bd9Sstevel@tonic-gate return (SLP_MEMORY_ALLOC_FAILED);
7687c478bd9Sstevel@tonic-gate }
7697c478bd9Sstevel@tonic-gate
7707c478bd9Sstevel@tonic-gate /* lay the given interfaces into the pollfd array */
7717c478bd9Sstevel@tonic-gate for (i = 0; i < num_givenifs; i++) {
7727c478bd9Sstevel@tonic-gate
7737c478bd9Sstevel@tonic-gate /* create a socket to bind to this interface */
7747c478bd9Sstevel@tonic-gate if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
7757c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "make_mc_target",
7767c478bd9Sstevel@tonic-gate "could not create socket: %s",
7777c478bd9Sstevel@tonic-gate strerror(errno));
7787c478bd9Sstevel@tonic-gate free_pfds(*fds, *nfds);
7797c478bd9Sstevel@tonic-gate return (SLP_INTERNAL_SYSTEM_ERROR);
7807c478bd9Sstevel@tonic-gate }
7817c478bd9Sstevel@tonic-gate
7827c478bd9Sstevel@tonic-gate /* fill in the pollfd structure */
7837c478bd9Sstevel@tonic-gate (*fds)[i].fd = fd;
7847c478bd9Sstevel@tonic-gate (*fds)[i].events |= POLLRDNORM;
7857c478bd9Sstevel@tonic-gate
7867c478bd9Sstevel@tonic-gate if (use_broadcast) {
7877c478bd9Sstevel@tonic-gate struct sockaddr_in bcsin[1];
7887c478bd9Sstevel@tonic-gate
7897c478bd9Sstevel@tonic-gate (void) memcpy(
7907c478bd9Sstevel@tonic-gate &(bcsin->sin_addr), &(given_ifs[i]),
7917c478bd9Sstevel@tonic-gate sizeof (bcsin->sin_addr));
7927c478bd9Sstevel@tonic-gate bcsin->sin_family = AF_INET;
7937c478bd9Sstevel@tonic-gate bcsin->sin_port = 0;
7947c478bd9Sstevel@tonic-gate
7957c478bd9Sstevel@tonic-gate /* bind fd to interface */
7967c478bd9Sstevel@tonic-gate if (bind(fd, (struct sockaddr *)bcsin,
7977c478bd9Sstevel@tonic-gate sizeof (*bcsin)) == 0) {
7987c478bd9Sstevel@tonic-gate continue;
7997c478bd9Sstevel@tonic-gate }
8007c478bd9Sstevel@tonic-gate /* else fallthru to default (multicast) */
8017c478bd9Sstevel@tonic-gate slp_err(LOG_INFO, 0, "make_mc_target",
8027c478bd9Sstevel@tonic-gate "could not set broadcast interface: %s",
8037c478bd9Sstevel@tonic-gate strerror(errno));
8047c478bd9Sstevel@tonic-gate }
8057c478bd9Sstevel@tonic-gate /* else use multicast */
8067c478bd9Sstevel@tonic-gate if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
8077c478bd9Sstevel@tonic-gate &(given_ifs[i]), sizeof (given_ifs[i]))
8087c478bd9Sstevel@tonic-gate < 0) {
8097c478bd9Sstevel@tonic-gate
8107c478bd9Sstevel@tonic-gate slp_err(LOG_INFO, 0, "make_mc_target",
8117c478bd9Sstevel@tonic-gate "could not set multicast interface: %s",
8127c478bd9Sstevel@tonic-gate strerror(errno));
8137c478bd9Sstevel@tonic-gate continue;
8147c478bd9Sstevel@tonic-gate }
8157c478bd9Sstevel@tonic-gate
8167c478bd9Sstevel@tonic-gate have_valid_if = SLP_TRUE;
8177c478bd9Sstevel@tonic-gate }
8187c478bd9Sstevel@tonic-gate
8197c478bd9Sstevel@tonic-gate if (use_broadcast) {
8207c478bd9Sstevel@tonic-gate SLPError err;
8217c478bd9Sstevel@tonic-gate
8227c478bd9Sstevel@tonic-gate if ((err = make_bc_target(
8237c478bd9Sstevel@tonic-gate hp, given_ifs, num_givenifs, bcifs))
8247c478bd9Sstevel@tonic-gate != SLP_OK) {
8257c478bd9Sstevel@tonic-gate
8267c478bd9Sstevel@tonic-gate if (err == SLP_MEMORY_ALLOC_FAILED) {
8277c478bd9Sstevel@tonic-gate /* the only thing which is really a showstopper */
8287c478bd9Sstevel@tonic-gate return (err);
8297c478bd9Sstevel@tonic-gate }
8307c478bd9Sstevel@tonic-gate
8317c478bd9Sstevel@tonic-gate /* else no valid interfaces */
8327c478bd9Sstevel@tonic-gate have_valid_if = SLP_FALSE;
8337c478bd9Sstevel@tonic-gate }
8347c478bd9Sstevel@tonic-gate }
8357c478bd9Sstevel@tonic-gate free(given_ifs);
8367c478bd9Sstevel@tonic-gate }
8377c478bd9Sstevel@tonic-gate
8387c478bd9Sstevel@tonic-gate if (!have_valid_if) {
8397c478bd9Sstevel@tonic-gate if (*fds && !have_valid_if) {
8407c478bd9Sstevel@tonic-gate /* couldn't process net.slp.interfaces property */
8417c478bd9Sstevel@tonic-gate free(*fds);
8427c478bd9Sstevel@tonic-gate }
8437c478bd9Sstevel@tonic-gate
8447c478bd9Sstevel@tonic-gate /* bind to default interface */
8457c478bd9Sstevel@tonic-gate if (!(*fds = calloc(1, sizeof (**fds)))) {
8467c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "make_mc_target",
8477c478bd9Sstevel@tonic-gate "out of memory");
8487c478bd9Sstevel@tonic-gate return (SLP_MEMORY_ALLOC_FAILED);
8497c478bd9Sstevel@tonic-gate }
8507c478bd9Sstevel@tonic-gate
8517c478bd9Sstevel@tonic-gate if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
8527c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "make_mc_target",
8537c478bd9Sstevel@tonic-gate "could not create socket: %s",
8547c478bd9Sstevel@tonic-gate strerror(errno));
8557c478bd9Sstevel@tonic-gate free(*fds);
8567c478bd9Sstevel@tonic-gate return (SLP_INTERNAL_SYSTEM_ERROR);
8577c478bd9Sstevel@tonic-gate }
8587c478bd9Sstevel@tonic-gate
8597c478bd9Sstevel@tonic-gate (**fds).fd = fd;
8607c478bd9Sstevel@tonic-gate (**fds).events |= POLLRDNORM;
8617c478bd9Sstevel@tonic-gate *nfds = 1;
8627c478bd9Sstevel@tonic-gate }
8637c478bd9Sstevel@tonic-gate
8647c478bd9Sstevel@tonic-gate /* set required options on all configured fds */
8657c478bd9Sstevel@tonic-gate for (nfd_i = 0; nfd_i < *nfds; nfd_i++) {
8667c478bd9Sstevel@tonic-gate if (use_broadcast) {
8677c478bd9Sstevel@tonic-gate const int on = 1;
8687c478bd9Sstevel@tonic-gate if (setsockopt((*fds)[nfd_i].fd, SOL_SOCKET,
8697c478bd9Sstevel@tonic-gate SO_BROADCAST,
8707c478bd9Sstevel@tonic-gate (void *) &on, sizeof (on)) < 0) {
8717c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "make_mc_target",
8727c478bd9Sstevel@tonic-gate "could not enable broadcast: %s",
8737c478bd9Sstevel@tonic-gate strerror(errno));
8747c478bd9Sstevel@tonic-gate }
8757c478bd9Sstevel@tonic-gate } else {
8767c478bd9Sstevel@tonic-gate if (setsockopt((*fds)[nfd_i].fd, IPPROTO_IP,
8777c478bd9Sstevel@tonic-gate IP_MULTICAST_TTL, &ttl, 1) < 0) {
8787c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "make_mc_target",
8797c478bd9Sstevel@tonic-gate "could not set multicast TTL: %s",
8807c478bd9Sstevel@tonic-gate strerror(errno));
8817c478bd9Sstevel@tonic-gate }
8827c478bd9Sstevel@tonic-gate }
8837c478bd9Sstevel@tonic-gate }
8847c478bd9Sstevel@tonic-gate
8857c478bd9Sstevel@tonic-gate if (use_broadcast) {
8867c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = INADDR_BROADCAST;
8877c478bd9Sstevel@tonic-gate } else {
8887c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = SLP_MULTICAST_ADDRESS;
8897c478bd9Sstevel@tonic-gate }
8907c478bd9Sstevel@tonic-gate
8917c478bd9Sstevel@tonic-gate return (SLP_OK);
8927c478bd9Sstevel@tonic-gate }
8937c478bd9Sstevel@tonic-gate
8947c478bd9Sstevel@tonic-gate /*
8957c478bd9Sstevel@tonic-gate * Obtains the subnet broadcast address for each interface specified
8967c478bd9Sstevel@tonic-gate * in net.slp.interfaces, and fill bcifs->sin with an array of these
8977c478bd9Sstevel@tonic-gate * addresses.
8987c478bd9Sstevel@tonic-gate */
make_bc_target(slp_handle_impl_t * hp,struct in_addr * given_ifs,int num_givenifs,struct bc_ifs * bcifs)8997c478bd9Sstevel@tonic-gate static SLPError make_bc_target(slp_handle_impl_t *hp,
9007c478bd9Sstevel@tonic-gate struct in_addr *given_ifs,
9017c478bd9Sstevel@tonic-gate int num_givenifs, struct bc_ifs *bcifs) {
9027c478bd9Sstevel@tonic-gate SLPError err;
9037c478bd9Sstevel@tonic-gate int i;
9047c478bd9Sstevel@tonic-gate
9057c478bd9Sstevel@tonic-gate if ((err = slp_broadcast_addrs(hp, given_ifs, num_givenifs,
9067c478bd9Sstevel@tonic-gate &(bcifs->sin), &(bcifs->num_ifs)))
9077c478bd9Sstevel@tonic-gate != SLP_OK) {
9087c478bd9Sstevel@tonic-gate return (err);
9097c478bd9Sstevel@tonic-gate }
9107c478bd9Sstevel@tonic-gate
9117c478bd9Sstevel@tonic-gate /* set SLP port on each sockaddr_in */
9127c478bd9Sstevel@tonic-gate for (i = 0; i < bcifs->num_ifs; i++) {
9137c478bd9Sstevel@tonic-gate bcifs->sin[i].sin_port = htons(SLP_PORT);
9147c478bd9Sstevel@tonic-gate }
9157c478bd9Sstevel@tonic-gate
9167c478bd9Sstevel@tonic-gate return (SLP_OK);
9177c478bd9Sstevel@tonic-gate }
9187c478bd9Sstevel@tonic-gate
9197c478bd9Sstevel@tonic-gate /*
9207c478bd9Sstevel@tonic-gate * Sends msg on 1st fd in fds for multicast, or on all interfaces
9217c478bd9Sstevel@tonic-gate * specified in net.slp.interfaces for broadcast. Returns SLP_OK if
9227c478bd9Sstevel@tonic-gate * msg was sent successfully on at least one interface; otherwise
9237c478bd9Sstevel@tonic-gate * returns SLP_NETWORK_ERROR if msg was not sent on any interfaces.
9247c478bd9Sstevel@tonic-gate */
mc_sendmsg(struct pollfd * fds,struct msghdr * msg,struct bc_ifs * bcifs)9257c478bd9Sstevel@tonic-gate static SLPError mc_sendmsg(struct pollfd *fds,
9267c478bd9Sstevel@tonic-gate struct msghdr *msg, struct bc_ifs *bcifs) {
9277c478bd9Sstevel@tonic-gate
9287c478bd9Sstevel@tonic-gate if (slp_get_usebroadcast()) {
9297c478bd9Sstevel@tonic-gate char *ifs = (char *)SLPGetProperty(SLP_CONFIG_INTERFACES);
9307c478bd9Sstevel@tonic-gate
9317c478bd9Sstevel@tonic-gate /* hand off to broadcast-specific send function */
9327c478bd9Sstevel@tonic-gate if (ifs && *ifs && bc_sendmsg(fds, msg, bcifs) == SLP_OK) {
9337c478bd9Sstevel@tonic-gate return (SLP_OK);
9347c478bd9Sstevel@tonic-gate }
9357c478bd9Sstevel@tonic-gate
9367c478bd9Sstevel@tonic-gate /*
9377c478bd9Sstevel@tonic-gate * else no ifs given, or bc_sendmsg failed, so send on
9387c478bd9Sstevel@tonic-gate * general broadcast addr (255.255.255.255). This will
9397c478bd9Sstevel@tonic-gate * cause the message to be sent on all interfaces. The
9407c478bd9Sstevel@tonic-gate * address will have been set in make_mc_target.
9417c478bd9Sstevel@tonic-gate */
9427c478bd9Sstevel@tonic-gate }
9437c478bd9Sstevel@tonic-gate
9447c478bd9Sstevel@tonic-gate /*
9457c478bd9Sstevel@tonic-gate * Send only on one interface -- let routing take care of
9467c478bd9Sstevel@tonic-gate * sending the message everywhere it needs to go. Sending
9477c478bd9Sstevel@tonic-gate * on more than one interface can cause nasty routing loops.
9487c478bd9Sstevel@tonic-gate * Note that this approach doesn't work with partitioned
9497c478bd9Sstevel@tonic-gate * networks.
9507c478bd9Sstevel@tonic-gate */
9517c478bd9Sstevel@tonic-gate if (sendmsg(fds[0].fd, msg, 0) < 0) {
9527c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "mc_sendmsg",
9537c478bd9Sstevel@tonic-gate "sendmsg failed: %s", strerror(errno));
9547c478bd9Sstevel@tonic-gate return (SLP_NETWORK_ERROR);
9557c478bd9Sstevel@tonic-gate }
9567c478bd9Sstevel@tonic-gate
9577c478bd9Sstevel@tonic-gate return (SLP_OK);
9587c478bd9Sstevel@tonic-gate }
9597c478bd9Sstevel@tonic-gate
9607c478bd9Sstevel@tonic-gate /*
9617c478bd9Sstevel@tonic-gate * Send msg to each subnet broadcast address in bcifs->sin. Note
9627c478bd9Sstevel@tonic-gate * that we can send on any fd (regardless of which interface to which
9637c478bd9Sstevel@tonic-gate * it is bound), since the kernel will take care of routing for us.
9647c478bd9Sstevel@tonic-gate * Returns err != SLP_OK only if no message was sent on any interface.
9657c478bd9Sstevel@tonic-gate */
bc_sendmsg(struct pollfd * fds,struct msghdr * msg,struct bc_ifs * bcifs)9667c478bd9Sstevel@tonic-gate static SLPError bc_sendmsg(struct pollfd *fds, struct msghdr *msg,
9677c478bd9Sstevel@tonic-gate struct bc_ifs *bcifs) {
9687c478bd9Sstevel@tonic-gate int i;
9697c478bd9Sstevel@tonic-gate SLPBoolean sent_one = SLP_FALSE;
9707c478bd9Sstevel@tonic-gate
9717c478bd9Sstevel@tonic-gate for (i = 0; i < bcifs->num_ifs; i++) {
9727c478bd9Sstevel@tonic-gate msg->msg_name = (caddr_t)&(bcifs->sin[i]);
9737c478bd9Sstevel@tonic-gate
9747c478bd9Sstevel@tonic-gate if (sendmsg(fds[0].fd, msg, 0) < 0) {
9757c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "bc_sendmsg",
9767c478bd9Sstevel@tonic-gate "sendmsg failed: %s", strerror(errno));
9777c478bd9Sstevel@tonic-gate continue;
9787c478bd9Sstevel@tonic-gate }
9797c478bd9Sstevel@tonic-gate sent_one = SLP_TRUE;
9807c478bd9Sstevel@tonic-gate }
9817c478bd9Sstevel@tonic-gate return (sent_one ? SLP_OK : SLP_NETWORK_ERROR);
9827c478bd9Sstevel@tonic-gate }
9837c478bd9Sstevel@tonic-gate
9847c478bd9Sstevel@tonic-gate /*
9857c478bd9Sstevel@tonic-gate * This is where the bulk of the multicast convergance algorithm resides.
9867c478bd9Sstevel@tonic-gate * mc_recvmsg() waits for data to be ready on any fd in pfd, iterates
9877c478bd9Sstevel@tonic-gate * through pfd and reads data from ready fd's. It also checks timeouts
9887c478bd9Sstevel@tonic-gate * and user-cancels.
9897c478bd9Sstevel@tonic-gate *
9907c478bd9Sstevel@tonic-gate * Parameters:
9917c478bd9Sstevel@tonic-gate * pfd IN an array of pollfd structs containing fds to poll
9927c478bd9Sstevel@tonic-gate * nfds IN number of elements in pfd
9937c478bd9Sstevel@tonic-gate * hp IN SLPHandle from originating call
9947c478bd9Sstevel@tonic-gate * scopes IN scopes to use for this message
9957c478bd9Sstevel@tonic-gate * header IN the SLP message header for this message
9967c478bd9Sstevel@tonic-gate * collator IN/OUT btree collator for PR list
9977c478bd9Sstevel@tonic-gate * final_to IN final timeout
9987c478bd9Sstevel@tonic-gate * sent IN time when message was sent
9997c478bd9Sstevel@tonic-gate * now IN/OUT set to current time at beginning of convergance
10007c478bd9Sstevel@tonic-gate * noresults OUT set to 0 if any results are received
10017c478bd9Sstevel@tonic-gate * anyresults OUT set to true if any results are received
10027c478bd9Sstevel@tonic-gate * timeout IN time for this convergence iteration
10037c478bd9Sstevel@tonic-gate *
10047c478bd9Sstevel@tonic-gate * Returns only if an error has occured, or if either this retransmit
10057c478bd9Sstevel@tonic-gate * timeout or the final timeout has expired, or if hp->cancel becomes true.
10067c478bd9Sstevel@tonic-gate */
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)10077c478bd9Sstevel@tonic-gate static void mc_recvmsg(struct pollfd *pfd, nfds_t nfds, slp_handle_impl_t *hp,
10087c478bd9Sstevel@tonic-gate const char *scopes, char *header, void **collator,
10097c478bd9Sstevel@tonic-gate unsigned long long final_to,
10107c478bd9Sstevel@tonic-gate unsigned long long sent,
10117c478bd9Sstevel@tonic-gate unsigned long long *now,
10127c478bd9Sstevel@tonic-gate int *noresults, int *anyresults, int timeout) {
10137c478bd9Sstevel@tonic-gate char *reply = NULL;
10147c478bd9Sstevel@tonic-gate nfds_t i;
10157c478bd9Sstevel@tonic-gate struct sockaddr_in responder;
10167c478bd9Sstevel@tonic-gate int pollerr;
10177c478bd9Sstevel@tonic-gate socklen_t addrlen = sizeof (responder);
10187c478bd9Sstevel@tonic-gate size_t mtu = slp_get_mtu();
10197c478bd9Sstevel@tonic-gate
10207c478bd9Sstevel@tonic-gate for (; !hp->cancel; ) {
10217c478bd9Sstevel@tonic-gate /* wait until we can read something */
10227c478bd9Sstevel@tonic-gate pollerr = wait_for_response(
10237c478bd9Sstevel@tonic-gate final_to, &timeout, sent, now, pfd, nfds);
10247c478bd9Sstevel@tonic-gate if (pollerr == 0)
10257c478bd9Sstevel@tonic-gate /* timeout */
10267c478bd9Sstevel@tonic-gate goto cleanup;
10277c478bd9Sstevel@tonic-gate if (pollerr < 0)
10287c478bd9Sstevel@tonic-gate /* error */
10297c478bd9Sstevel@tonic-gate goto cleanup;
10307c478bd9Sstevel@tonic-gate
10317c478bd9Sstevel@tonic-gate /* iterate through all fds to find one with data to read */
10327c478bd9Sstevel@tonic-gate for (i = 0; !hp->cancel && i < nfds; i++) {
10337c478bd9Sstevel@tonic-gate
10347c478bd9Sstevel@tonic-gate if (pfd[i].fd < 0 ||
10357c478bd9Sstevel@tonic-gate !(pfd[i].revents & (POLLRDNORM | POLLERR))) {
10367c478bd9Sstevel@tonic-gate
10377c478bd9Sstevel@tonic-gate /* unused fd or unwanted event */
10387c478bd9Sstevel@tonic-gate continue;
10397c478bd9Sstevel@tonic-gate }
10407c478bd9Sstevel@tonic-gate
10417c478bd9Sstevel@tonic-gate /* alloc reply buffer */
10427c478bd9Sstevel@tonic-gate if (!reply && !(reply = malloc(mtu))) {
10437c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "mc_revcmsg", "out of memory");
10447c478bd9Sstevel@tonic-gate return;
10457c478bd9Sstevel@tonic-gate }
10467c478bd9Sstevel@tonic-gate if (recvfrom(pfd[i].fd, reply, mtu, 0,
10477c478bd9Sstevel@tonic-gate (struct sockaddr *)&responder,
10487c478bd9Sstevel@tonic-gate (int *)&addrlen) < 0) {
10497c478bd9Sstevel@tonic-gate
10507c478bd9Sstevel@tonic-gate /* if reply overflows, hand off to TCP */
10517c478bd9Sstevel@tonic-gate if (errno == ENOMEM) {
10527c478bd9Sstevel@tonic-gate free(reply); reply = NULL;
10537c478bd9Sstevel@tonic-gate tcp_handoff(hp, scopes,
10547c478bd9Sstevel@tonic-gate &responder, slp_get_xid(header));
10557c478bd9Sstevel@tonic-gate continue;
10567c478bd9Sstevel@tonic-gate }
10577c478bd9Sstevel@tonic-gate
10587c478bd9Sstevel@tonic-gate /* else something nasty happened */
10597c478bd9Sstevel@tonic-gate slp_err(LOG_CRIT, 0, "mc_recvmsg",
10607c478bd9Sstevel@tonic-gate "recvfrom failed: %s",
10617c478bd9Sstevel@tonic-gate strerror(errno));
10627c478bd9Sstevel@tonic-gate continue;
10637c478bd9Sstevel@tonic-gate } else {
10647c478bd9Sstevel@tonic-gate /* success */
10657c478bd9Sstevel@tonic-gate if (slp_get_overflow(reply)) {
10667c478bd9Sstevel@tonic-gate tcp_handoff(hp, scopes,
10677c478bd9Sstevel@tonic-gate &responder, slp_get_xid(header));
10687c478bd9Sstevel@tonic-gate }
10697c478bd9Sstevel@tonic-gate /*
10707c478bd9Sstevel@tonic-gate * Add to the PR list. If this responder has already
10717c478bd9Sstevel@tonic-gate * answered, it doesn't count.
10727c478bd9Sstevel@tonic-gate */
10737c478bd9Sstevel@tonic-gate if (add2pr_list(&(hp->msg), &responder, collator)) {
10747c478bd9Sstevel@tonic-gate (void) slp_enqueue(hp->q, reply);
10757c478bd9Sstevel@tonic-gate *noresults = 0;
10767c478bd9Sstevel@tonic-gate *anyresults = 1;
10777c478bd9Sstevel@tonic-gate reply = NULL;
10787c478bd9Sstevel@tonic-gate }
10797c478bd9Sstevel@tonic-gate
10807c478bd9Sstevel@tonic-gate /* if we've exceeded maxwait, break out */
10817c478bd9Sstevel@tonic-gate *now = now_millis();
10827c478bd9Sstevel@tonic-gate if (*now > final_to)
10837c478bd9Sstevel@tonic-gate goto cleanup;
10847c478bd9Sstevel@tonic-gate
10857c478bd9Sstevel@tonic-gate } /* end successful receive */
10867c478bd9Sstevel@tonic-gate
10877c478bd9Sstevel@tonic-gate } /* end fd iteration */
10887c478bd9Sstevel@tonic-gate
10897c478bd9Sstevel@tonic-gate /* reset poll's timeout */
10907c478bd9Sstevel@tonic-gate timeout = timeout - (int)(*now - sent);
10917c478bd9Sstevel@tonic-gate if (timeout <= 0) {
10927c478bd9Sstevel@tonic-gate goto cleanup;
10937c478bd9Sstevel@tonic-gate }
10947c478bd9Sstevel@tonic-gate
10957c478bd9Sstevel@tonic-gate } /* end main poll loop */
10967c478bd9Sstevel@tonic-gate
10977c478bd9Sstevel@tonic-gate cleanup:
10987c478bd9Sstevel@tonic-gate if (reply) {
10997c478bd9Sstevel@tonic-gate free(reply);
11007c478bd9Sstevel@tonic-gate }
11017c478bd9Sstevel@tonic-gate }
11027c478bd9Sstevel@tonic-gate
11037c478bd9Sstevel@tonic-gate /*
11047c478bd9Sstevel@tonic-gate * Closes any open sockets and frees the pollfd array.
11057c478bd9Sstevel@tonic-gate */
free_pfds(struct pollfd * pfds,nfds_t nfds)11067c478bd9Sstevel@tonic-gate static void free_pfds(struct pollfd *pfds, nfds_t nfds) {
11077c478bd9Sstevel@tonic-gate nfds_t i;
11087c478bd9Sstevel@tonic-gate
11097c478bd9Sstevel@tonic-gate for (i = 0; i < nfds; i++) {
11107c478bd9Sstevel@tonic-gate if (pfds[i].fd <= 0) {
11117c478bd9Sstevel@tonic-gate continue;
11127c478bd9Sstevel@tonic-gate }
11137c478bd9Sstevel@tonic-gate
11147c478bd9Sstevel@tonic-gate (void) close(pfds[i].fd);
11157c478bd9Sstevel@tonic-gate }
11167c478bd9Sstevel@tonic-gate
11177c478bd9Sstevel@tonic-gate free(pfds);
11187c478bd9Sstevel@tonic-gate }
11197c478bd9Sstevel@tonic-gate
11207c478bd9Sstevel@tonic-gate /*
11217c478bd9Sstevel@tonic-gate * Hands off a message to the TCP thread, fabricating a new target
11227c478bd9Sstevel@tonic-gate * from 'sin'. 'xid' will be used to create the XID for the TCP message.
11237c478bd9Sstevel@tonic-gate */
tcp_handoff(slp_handle_impl_t * hp,const char * scopes,struct sockaddr_in * sin,unsigned short xid)11247c478bd9Sstevel@tonic-gate static void tcp_handoff(slp_handle_impl_t *hp, const char *scopes,
11257c478bd9Sstevel@tonic-gate struct sockaddr_in *sin, unsigned short xid) {
11267c478bd9Sstevel@tonic-gate slp_target_t *target;
11277c478bd9Sstevel@tonic-gate
11287c478bd9Sstevel@tonic-gate target = slp_fabricate_target(sin);
11297c478bd9Sstevel@tonic-gate slp_uc_tcp_send(hp, target, scopes, SLP_TRUE, xid);
11307c478bd9Sstevel@tonic-gate }
11317c478bd9Sstevel@tonic-gate
11327c478bd9Sstevel@tonic-gate /*
11337c478bd9Sstevel@tonic-gate * Returns the current time in milliseconds.
11347c478bd9Sstevel@tonic-gate */
now_millis()11357c478bd9Sstevel@tonic-gate static unsigned long long now_millis() {
11367c478bd9Sstevel@tonic-gate unsigned long long i;
11377c478bd9Sstevel@tonic-gate struct timeval tv[1];
11387c478bd9Sstevel@tonic-gate
11397c478bd9Sstevel@tonic-gate (void) gettimeofday(tv, NULL);
11407c478bd9Sstevel@tonic-gate i = (unsigned long long) tv->tv_sec * 1000;
11417c478bd9Sstevel@tonic-gate i += tv->tv_usec / 1000;
11427c478bd9Sstevel@tonic-gate return (i);
11437c478bd9Sstevel@tonic-gate }
11447c478bd9Sstevel@tonic-gate
11457c478bd9Sstevel@tonic-gate /*
11467c478bd9Sstevel@tonic-gate * A wrapper around poll which waits until a reply comes in. This will
11477c478bd9Sstevel@tonic-gate * wait no longer than 'timeout' before returning. poll can return
11487c478bd9Sstevel@tonic-gate * even if no data is on the pipe or timeout has occured, so the
11497c478bd9Sstevel@tonic-gate * additional paramaters are used to break out of the wait loop if
11507c478bd9Sstevel@tonic-gate * we have exceeded the timeout value. 'final_to' is ignored if it is 0.
11517c478bd9Sstevel@tonic-gate *
11527c478bd9Sstevel@tonic-gate * returns: < 0 on error
11537c478bd9Sstevel@tonic-gate * 0 on timeout
11547c478bd9Sstevel@tonic-gate * > 0 on success (i.e. ready to read data).
11557c478bd9Sstevel@tonic-gate * side effect: 'now' is set to the time when poll found data on the pipe.
11567c478bd9Sstevel@tonic-gate */
wait_for_response(unsigned long long final_to,int * timeout,unsigned long long sent,unsigned long long * now,struct pollfd pfd[],nfds_t nfds)11577c478bd9Sstevel@tonic-gate static int wait_for_response(
11587c478bd9Sstevel@tonic-gate unsigned long long final_to,
11597c478bd9Sstevel@tonic-gate int *timeout,
11607c478bd9Sstevel@tonic-gate unsigned long long sent,
11617c478bd9Sstevel@tonic-gate unsigned long long *now,
11627c478bd9Sstevel@tonic-gate struct pollfd pfd[], nfds_t nfds) {
11637c478bd9Sstevel@tonic-gate
11647c478bd9Sstevel@tonic-gate int when, pollerr;
11657c478bd9Sstevel@tonic-gate
11667c478bd9Sstevel@tonic-gate /* wait until we can read something */
11677c478bd9Sstevel@tonic-gate for (;;) {
11687c478bd9Sstevel@tonic-gate pollerr = poll(pfd, nfds, *timeout);
11697c478bd9Sstevel@tonic-gate *now = now_millis();
11707c478bd9Sstevel@tonic-gate
11717c478bd9Sstevel@tonic-gate /* ready to read */
11727c478bd9Sstevel@tonic-gate if (pollerr > 0)
11737c478bd9Sstevel@tonic-gate return (pollerr);
11747c478bd9Sstevel@tonic-gate
11757c478bd9Sstevel@tonic-gate /* time out */
11767c478bd9Sstevel@tonic-gate if (pollerr == 0)
11777c478bd9Sstevel@tonic-gate /* timeout */
11787c478bd9Sstevel@tonic-gate return (0);
11797c478bd9Sstevel@tonic-gate
11807c478bd9Sstevel@tonic-gate /* error */
11817c478bd9Sstevel@tonic-gate if (pollerr < 0)
11827c478bd9Sstevel@tonic-gate if (errno == EAGAIN || errno == EINTR) {
11837c478bd9Sstevel@tonic-gate /* poll is weird. */
11847c478bd9Sstevel@tonic-gate when = (int)(*now - sent);
11857c478bd9Sstevel@tonic-gate if (
11867c478bd9Sstevel@tonic-gate (final_to != 0 && *now > final_to) ||
11877c478bd9Sstevel@tonic-gate when > *timeout)
11887c478bd9Sstevel@tonic-gate break;
11897c478bd9Sstevel@tonic-gate *timeout = *timeout - when;
11907c478bd9Sstevel@tonic-gate continue;
11917c478bd9Sstevel@tonic-gate } else {
11927c478bd9Sstevel@tonic-gate slp_err(LOG_INFO, 0, "wait for response",
11937c478bd9Sstevel@tonic-gate "poll error: %s",
11947c478bd9Sstevel@tonic-gate strerror(errno));
11957c478bd9Sstevel@tonic-gate return (pollerr);
11967c478bd9Sstevel@tonic-gate }
11977c478bd9Sstevel@tonic-gate }
11987c478bd9Sstevel@tonic-gate
11997c478bd9Sstevel@tonic-gate return (0);
12007c478bd9Sstevel@tonic-gate }
12017c478bd9Sstevel@tonic-gate
12027c478bd9Sstevel@tonic-gate /*
12037c478bd9Sstevel@tonic-gate * Adds the cname of the host whose address is in 'sin' to this message's
12047c478bd9Sstevel@tonic-gate * previous responder list. The message is contained in 'msg'.
12057c478bd9Sstevel@tonic-gate * 'collator' contains the complete previous responder list, so that
12067c478bd9Sstevel@tonic-gate * even if the PR list in the message overflows and must be truncated,
12077c478bd9Sstevel@tonic-gate * the function can still correctly determine if we have heard from this
12087c478bd9Sstevel@tonic-gate * host before.
12097c478bd9Sstevel@tonic-gate *
12107c478bd9Sstevel@tonic-gate * returns: 1 if this is the first time we've heard from this host
12117c478bd9Sstevel@tonic-gate * 0 is this is a duplicate reply
12127c478bd9Sstevel@tonic-gate */
add2pr_list(slp_msg_t * msg,struct sockaddr_in * sin,void ** collator)12137c478bd9Sstevel@tonic-gate static int add2pr_list(
12147c478bd9Sstevel@tonic-gate slp_msg_t *msg,
12157c478bd9Sstevel@tonic-gate struct sockaddr_in *sin,
12167c478bd9Sstevel@tonic-gate void **collator) {
12177c478bd9Sstevel@tonic-gate
12187c478bd9Sstevel@tonic-gate char **res, *cname, *p, *header;
12197c478bd9Sstevel@tonic-gate size_t mtu;
12207c478bd9Sstevel@tonic-gate size_t len, off, namelen;
12217c478bd9Sstevel@tonic-gate unsigned short prlen;
12227c478bd9Sstevel@tonic-gate
12237c478bd9Sstevel@tonic-gate /* Attempt to resolve the responder's IP address to its host name */
12247c478bd9Sstevel@tonic-gate if (!(cname = slp_gethostbyaddr((char *)&(sin->sin_addr),
12257c478bd9Sstevel@tonic-gate sizeof (sin->sin_addr))))
12267c478bd9Sstevel@tonic-gate return (0);
12277c478bd9Sstevel@tonic-gate
12287c478bd9Sstevel@tonic-gate res = slp_tsearch(
12297c478bd9Sstevel@tonic-gate cname, collator,
12307c478bd9Sstevel@tonic-gate (int (*)(const void *, const void *)) strcasecmp);
12317c478bd9Sstevel@tonic-gate if (*res != cname) {
12327c478bd9Sstevel@tonic-gate /* duplicate */
12337c478bd9Sstevel@tonic-gate slp_err(LOG_INFO, 0, "add2pr_list",
12347c478bd9Sstevel@tonic-gate "drop PR ignored by host: %s",
12357c478bd9Sstevel@tonic-gate cname);
12367c478bd9Sstevel@tonic-gate free(cname);
12377c478bd9Sstevel@tonic-gate return (0);
12387c478bd9Sstevel@tonic-gate }
12397c478bd9Sstevel@tonic-gate
12407c478bd9Sstevel@tonic-gate /* new responder: add to the msg PR list if there is room */
12417c478bd9Sstevel@tonic-gate mtu = slp_get_mtu();
12427c478bd9Sstevel@tonic-gate
12437c478bd9Sstevel@tonic-gate header = msg->iov[0].iov_base;
12447c478bd9Sstevel@tonic-gate len = slp_get_length(header);
12457c478bd9Sstevel@tonic-gate
12467c478bd9Sstevel@tonic-gate namelen = strlen(cname);
12477c478bd9Sstevel@tonic-gate if ((namelen + 2 + len) >= mtu)
12487c478bd9Sstevel@tonic-gate return (1); /* no room */
12497c478bd9Sstevel@tonic-gate
12507c478bd9Sstevel@tonic-gate /* else there is enough room */
12517c478bd9Sstevel@tonic-gate prlen = (unsigned short)msg->prlist->iov_len;
12527c478bd9Sstevel@tonic-gate p = msg->prlist->iov_base + prlen;
12537c478bd9Sstevel@tonic-gate *p = 0;
12547c478bd9Sstevel@tonic-gate
12557c478bd9Sstevel@tonic-gate if (prlen) {
12567c478bd9Sstevel@tonic-gate namelen++; /* add the ',' */
12577c478bd9Sstevel@tonic-gate (void) strcat(p, ",");
12587c478bd9Sstevel@tonic-gate }
12597c478bd9Sstevel@tonic-gate (void) strcat(p, cname);
12607c478bd9Sstevel@tonic-gate
12617c478bd9Sstevel@tonic-gate /* update msg and pr list length */
12627c478bd9Sstevel@tonic-gate len += namelen;
12637c478bd9Sstevel@tonic-gate slp_set_length(header, len);
12647c478bd9Sstevel@tonic-gate prlen += (unsigned short)namelen;
12657c478bd9Sstevel@tonic-gate off = 0;
12667c478bd9Sstevel@tonic-gate (void) slp_add_sht(msg->prlistlen.iov_base, 2, prlen, &off);
12677c478bd9Sstevel@tonic-gate msg->prlist->iov_len += namelen;
12687c478bd9Sstevel@tonic-gate
12697c478bd9Sstevel@tonic-gate return (1);
12707c478bd9Sstevel@tonic-gate }
12717c478bd9Sstevel@tonic-gate
12727c478bd9Sstevel@tonic-gate /*
12737c478bd9Sstevel@tonic-gate * The iterator function used while traversing the previous responder
12747c478bd9Sstevel@tonic-gate * tree. Just frees resources.
12757c478bd9Sstevel@tonic-gate */
12767c478bd9Sstevel@tonic-gate /*ARGSUSED2*/
free_pr_node(void * node,VISIT order,int level,void * cookie)12777c478bd9Sstevel@tonic-gate static void free_pr_node(void *node, VISIT order, int level, void *cookie) {
12787c478bd9Sstevel@tonic-gate if (order == endorder || order == leaf) {
12797c478bd9Sstevel@tonic-gate char *pr = *(char **)node;
12807c478bd9Sstevel@tonic-gate free(pr);
12817c478bd9Sstevel@tonic-gate free(node);
12827c478bd9Sstevel@tonic-gate }
12837c478bd9Sstevel@tonic-gate }
1284