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