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