Imported Upstream version 0.2.5
[platform/upstream/libtirpc.git] / src / clnt_bcast.c
1 /*
2  * Copyright (c) 2009, Sun Microsystems, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * - Redistributions of source code must retain the above copyright notice,
8  *   this list of conditions and the following disclaimer.
9  * - Redistributions in binary form must reproduce the above copyright notice,
10  *   this list of conditions and the following disclaimer in the documentation
11  *   and/or other materials provided with the distribution.
12  * - Neither the name of Sun Microsystems, Inc. nor the names of its
13  *   contributors may be used to endorse or promote products derived
14  *   from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 /*
29  * Copyright (c) 1986-1991 by Sun Microsystems Inc. 
30  */
31 #include <sys/cdefs.h>
32
33 /*
34  * clnt_bcast.c
35  * Client interface to broadcast service.
36  *
37  * Copyright (C) 1988, Sun Microsystems, Inc.
38  *
39  * The following is kludged-up support for simple rpc broadcasts.
40  * Someday a large, complicated system will replace these routines.
41  */
42 #include <sys/socket.h>
43 #include <sys/types.h>
44 #include <sys/queue.h>
45
46 #include <net/if.h>
47 #include <netinet/in.h>
48 #include <ifaddrs.h>
49 #include <sys/poll.h>
50 #include <rpc/rpc.h>
51 #ifdef PORTMAP
52 #include <rpc/pmap_prot.h>
53 #include <rpc/pmap_clnt.h>
54 #include <rpc/pmap_rmt.h>
55 #endif                          /* PORTMAP */
56 #include <rpc/nettype.h>
57 #include <arpa/inet.h>
58 #include <stdio.h>
59 #include <errno.h>
60 #include <stdlib.h>
61 #include <unistd.h>
62 #include <netdb.h>
63 #include <err.h>
64 #include <string.h>
65
66 #include "rpc_com.h"
67 #include "debug.h"
68
69 #define MAXBCAST 20     /* Max no of broadcasting transports */
70 #define INITTIME 4000   /* Time to wait initially */
71 #define WAITTIME 8000   /* Maximum time to wait */
72
73 # define POLLRDNORM     0x040           /* Normal data may be read.  */
74 # define POLLRDBAND     0x080           /* Priority data may be read.  */
75
76
77
78 /*
79  * If nettype is NULL, it broadcasts on all the available
80  * datagram_n transports. May potentially lead to broadacst storms
81  * and hence should be used with caution, care and courage.
82  *
83  * The current parameter xdr packet size is limited by the max tsdu
84  * size of the transport. If the max tsdu size of any transport is
85  * smaller than the parameter xdr packet, then broadcast is not
86  * sent on that transport.
87  *
88  * Also, the packet size should be less the packet size of
89  * the data link layer (for ethernet it is 1400 bytes).  There is
90  * no easy way to find out the max size of the data link layer and
91  * we are assuming that the args would be smaller than that.
92  *
93  * The result size has to be smaller than the transport tsdu size.
94  *
95  * If PORTMAP has been defined, we send two packets for UDP, one for
96  * rpcbind and one for portmap. For those machines which support
97  * both rpcbind and portmap, it will cause them to reply twice, and
98  * also here it will get two responses ... inefficient and clumsy.
99  */
100
101 #define TAILQ_NEXT(elm, field)  ((elm)->field.tqe_next)
102
103 #define TAILQ_FIRST(head)       ((head)->tqh_first)
104
105
106 struct broadif {
107         int index;
108         struct sockaddr_storage broadaddr;
109         TAILQ_ENTRY(broadif) link;
110 };
111
112 typedef TAILQ_HEAD(, broadif) broadlist_t;
113
114 int __rpc_getbroadifs(int, int, int, broadlist_t *);
115 void __rpc_freebroadifs(broadlist_t *);
116 int __rpc_broadenable(int, int, struct broadif *);
117
118 int __rpc_lowvers = 0;
119
120 int
121 __rpc_getbroadifs(int af, int proto, int socktype, broadlist_t *list)
122 {
123         int count = 0;
124         struct broadif *bip;
125         struct ifaddrs *ifap, *ifp;
126 #ifdef INET6
127         struct sockaddr_in6 *sin6;
128 #endif
129         struct sockaddr_in *sin;
130         struct addrinfo hints, *res;
131
132         if (getifaddrs(&ifp) < 0)
133                 return 0;
134
135         memset(&hints, 0, sizeof hints);
136
137         hints.ai_family = af;
138         hints.ai_protocol = proto;
139         hints.ai_socktype = socktype;
140
141         if (getaddrinfo(NULL, "sunrpc", &hints, &res) != 0)
142                 return 0;
143
144         for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) {
145                 if (ifap->ifa_addr->sa_family != af ||
146                     !(ifap->ifa_flags & IFF_UP))
147                         continue;
148                 bip = (struct broadif *)malloc(sizeof *bip);
149                 if (bip == NULL)
150                         break;
151                 bip->index = if_nametoindex(ifap->ifa_name);
152                 if (
153 #ifdef INET6
154                 af != AF_INET6 &&
155 #endif
156                 (ifap->ifa_flags & IFF_BROADCAST) &&
157                  ifap->ifa_broadaddr) {
158                   /*    memcpy(&bip->broadaddr, ifap->ifa_broadaddr,
159                         (size_t)ifap->ifa_broadaddr->sa_len);*/
160                         memcpy(&bip->broadaddr, ifap->ifa_broadaddr,
161                                         sizeof(bip->broadaddr));
162                         sin = (struct sockaddr_in *)(void *)&bip->broadaddr;
163                         sin->sin_port =
164                             ((struct sockaddr_in *)
165                             (void *)res->ai_addr)->sin_port;
166                 } else
167 #ifdef INET6
168                 if (af == AF_INET6 && (ifap->ifa_flags & IFF_MULTICAST)) {
169                         sin6 = (struct sockaddr_in6 *)(void *)&bip->broadaddr;
170                         inet_pton(af, RPCB_MULTICAST_ADDR, &sin6->sin6_addr);
171                         sin6->sin6_family = af;
172                         sin6->sin6_port =
173                             ((struct sockaddr_in6 *)
174                             (void *)res->ai_addr)->sin6_port;
175                         sin6->sin6_scope_id = bip->index;
176                 } else
177 #endif
178                 {
179                         free(bip);
180                         continue;
181                 }
182                 TAILQ_INSERT_TAIL(list, bip, link);
183                 count++;
184         }
185         freeifaddrs(ifp);
186         freeaddrinfo(res);
187
188         return count;
189 }
190
191 void
192 __rpc_freebroadifs(broadlist_t *list)
193 {
194         struct broadif *bip, *next;
195
196         bip = TAILQ_FIRST(list);
197
198         while (bip != NULL) {
199                 next = TAILQ_NEXT(bip, link);
200                 free(bip);
201                 bip = next;
202         }
203 }
204
205 int
206 /*ARGSUSED*/
207 __rpc_broadenable(int af, int s, struct broadif *bip)
208 {
209         int o = 1;
210
211 #if 0
212         if (af == AF_INET6) {
213                 fprintf(stderr, "set v6 multicast if to %d\n", bip->index);
214                 if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &bip->index,
215                     sizeof bip->index) < 0)
216                         return -1;
217         } else
218 #endif
219                 if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &o, sizeof o) < 0)
220                         return -1;
221
222         return 0;
223 }
224
225
226 enum clnt_stat
227 rpc_broadcast_exp(prog, vers, proc, xargs, argsp, xresults, resultsp,
228         eachresult, inittime, waittime, nettype)
229         rpcprog_t       prog;           /* program number */
230         rpcvers_t       vers;           /* version number */
231         rpcproc_t       proc;           /* procedure number */
232         xdrproc_t       xargs;          /* xdr routine for args */
233         caddr_t         argsp;          /* pointer to args */
234         xdrproc_t       xresults;       /* xdr routine for results */
235         caddr_t         resultsp;       /* pointer to results */
236         resultproc_t    eachresult;     /* call with each result obtained */
237         int             inittime;       /* how long to wait initially */
238         int             waittime;       /* maximum time to wait */
239         const char              *nettype;       /* transport type */
240 {
241         enum clnt_stat  stat = RPC_SUCCESS; /* Return status */
242         XDR             xdr_stream; /* XDR stream */
243         XDR             *xdrs = &xdr_stream;
244         struct rpc_msg  msg;    /* RPC message */
245         struct timeval  t;
246         char            *outbuf = NULL; /* Broadcast msg buffer */
247         char            *inbuf = NULL; /* Reply buf */
248         int             inlen;
249         u_int           maxbufsize = 0;
250         AUTH            *sys_auth = authunix_create_default();
251         int             i;
252         void            *handle;
253         char            uaddress[1024]; /* A self imposed limit */
254         char            *uaddrp = uaddress;
255         int             pmap_reply_flag; /* reply recvd from PORTMAP */
256         /* An array of all the suitable broadcast transports */
257         struct {
258                 int fd;         /* File descriptor */
259                 int af;
260                 int proto;
261                 struct netconfig *nconf; /* Netconfig structure */
262                 u_int asize;    /* Size of the addr buf */
263                 u_int dsize;    /* Size of the data buf */
264                 struct sockaddr_storage raddr; /* Remote address */
265                 broadlist_t nal;
266         } fdlist[MAXBCAST];
267         struct pollfd pfd[MAXBCAST];
268         size_t fdlistno = 0;
269         struct r_rpcb_rmtcallargs barg; /* Remote arguments */
270         struct r_rpcb_rmtcallres bres; /* Remote results */
271         size_t outlen;
272         struct netconfig *nconf;
273         int msec;
274         int pollretval;
275         int fds_found;
276
277 #ifdef PORTMAP
278         size_t outlen_pmap = 0;
279         u_long port;            /* Remote port number */
280         int pmap_flag = 0;      /* UDP exists ? */
281         char *outbuf_pmap = NULL;
282         struct rmtcallargs barg_pmap;   /* Remote arguments */
283         struct rmtcallres bres_pmap; /* Remote results */
284         u_int udpbufsz = 0;
285 #endif                          /* PORTMAP */
286
287         if (sys_auth == NULL) {
288                 return (RPC_SYSTEMERROR);
289         }
290         /*
291          * initialization: create a fd, a broadcast address, and send the
292          * request on the broadcast transport.
293          * Listen on all of them and on replies, call the user supplied
294          * function.
295          */
296
297         if (nettype == NULL)
298                 nettype = "datagram_n";
299         if ((handle = __rpc_setconf(nettype)) == NULL) {
300                 return (RPC_UNKNOWNPROTO);
301         }
302         while ((nconf = __rpc_getconf(handle)) != NULL) {
303                 int fd;
304                 struct __rpc_sockinfo si;
305
306                 if (nconf->nc_semantics != NC_TPI_CLTS)
307                         continue;
308                 if (fdlistno >= MAXBCAST)
309                         break;  /* No more slots available */
310                 if (!__rpc_nconf2sockinfo(nconf, &si))
311                         continue;
312
313                 TAILQ_INIT(&fdlist[fdlistno].nal);
314                 if (__rpc_getbroadifs(si.si_af, si.si_proto, si.si_socktype, 
315                     &fdlist[fdlistno].nal) == 0)
316                         continue;
317
318                 fd = socket(si.si_af, si.si_socktype, si.si_proto);
319                 if (fd < 0) {
320                         stat = RPC_CANTSEND;
321                         continue;
322                 }
323                 fdlist[fdlistno].af = si.si_af;
324                 fdlist[fdlistno].proto = si.si_proto;
325                 fdlist[fdlistno].fd = fd;
326                 fdlist[fdlistno].nconf = nconf;
327                 fdlist[fdlistno].asize = __rpc_get_a_size(si.si_af);
328                 pfd[fdlistno].events = POLLIN | POLLPRI |
329                         POLLRDNORM | POLLRDBAND;
330                 pfd[fdlistno].fd = fdlist[fdlistno].fd = fd;
331                 fdlist[fdlistno].dsize = __rpc_get_t_size(si.si_af, si.si_proto,
332                                                           0);
333
334                 if (maxbufsize <= fdlist[fdlistno].dsize)
335                         maxbufsize = fdlist[fdlistno].dsize;
336
337 #ifdef PORTMAP
338                 if (si.si_af == AF_INET && si.si_proto == IPPROTO_UDP) {
339                         udpbufsz = fdlist[fdlistno].dsize;
340                         if ((outbuf_pmap = malloc(udpbufsz)) == NULL) {
341                                 close(fd);
342                                 stat = RPC_SYSTEMERROR;
343                                 goto done_broad;
344                         }
345                         pmap_flag = 1;
346                 }
347 #endif                          /* PORTMAP */
348                 fdlistno++;
349         }
350
351         if (fdlistno == 0) {
352                 if (stat == RPC_SUCCESS)
353                         stat = RPC_UNKNOWNPROTO;
354                 goto done_broad;
355         }
356         if (maxbufsize == 0) {
357                 if (stat == RPC_SUCCESS)
358                         stat = RPC_CANTSEND;
359                 goto done_broad;
360         }
361         inbuf = malloc(maxbufsize);
362         outbuf = malloc(maxbufsize);
363         if ((inbuf == NULL) || (outbuf == NULL)) {
364                 stat = RPC_SYSTEMERROR;
365                 goto done_broad;
366         }
367
368         /* Serialize all the arguments which have to be sent */
369         (void) gettimeofday(&t, NULL);
370         msg.rm_xid = __RPC_GETXID(&t);
371         msg.rm_direction = CALL;
372         msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
373         msg.rm_call.cb_prog = RPCBPROG;
374         msg.rm_call.cb_vers = RPCBVERS;
375         msg.rm_call.cb_proc = RPCBPROC_CALLIT;
376         barg.prog = prog;
377         barg.vers = vers;
378         barg.proc = proc;
379         barg.args.args_val = argsp;
380         barg.xdr_args = xargs;
381         bres.addr = uaddrp;
382         bres.results.results_val = resultsp;
383         bres.xdr_res = xresults;
384         msg.rm_call.cb_cred = sys_auth->ah_cred;
385         msg.rm_call.cb_verf = sys_auth->ah_verf;
386         xdrmem_create(xdrs, outbuf, maxbufsize, XDR_ENCODE);
387         if ((!xdr_callmsg(xdrs, &msg)) ||
388             (!xdr_rpcb_rmtcallargs(xdrs,
389             (struct rpcb_rmtcallargs *)(void *)&barg))) {
390                 stat = RPC_CANTENCODEARGS;
391                 goto done_broad;
392         }
393         outlen = xdr_getpos(xdrs);
394         xdr_destroy(xdrs);
395
396 #ifdef PORTMAP
397         /* Prepare the packet for version 2 PORTMAP */
398         if (pmap_flag) {
399                 msg.rm_xid++;   /* One way to distinguish */
400                 msg.rm_call.cb_prog = PMAPPROG;
401                 msg.rm_call.cb_vers = PMAPVERS;
402                 msg.rm_call.cb_proc = PMAPPROC_CALLIT;
403                 barg_pmap.prog = prog;
404                 barg_pmap.vers = vers;
405                 barg_pmap.proc = proc;
406                 barg_pmap.args_ptr = argsp;
407                 barg_pmap.xdr_args = xargs;
408                 bres_pmap.port_ptr = &port;
409                 bres_pmap.xdr_results = xresults;
410                 bres_pmap.results_ptr = resultsp;
411                 xdrmem_create(xdrs, outbuf_pmap, udpbufsz, XDR_ENCODE);
412                 if ((! xdr_callmsg(xdrs, &msg)) ||
413                     (! xdr_rmtcall_args(xdrs, &barg_pmap))) {
414                         stat = RPC_CANTENCODEARGS;
415                         goto done_broad;
416                 }
417                 outlen_pmap = xdr_getpos(xdrs);
418                 xdr_destroy(xdrs);
419         }
420 #endif                          /* PORTMAP */
421
422         /*
423          * Basic loop: broadcast the packets to transports which
424          * support data packets of size such that one can encode
425          * all the arguments.
426          * Wait a while for response(s).
427          * The response timeout grows larger per iteration.
428          */
429         for (msec = inittime; msec <= waittime; msec += msec) {
430                 struct broadif *bip;
431
432                 /* Broadcast all the packets now */
433                 for (i = 0; i < fdlistno; i++) {
434                         if (fdlist[i].dsize < outlen) {
435                                 stat = RPC_CANTSEND;
436                                 continue;
437                         }
438                         for (bip = TAILQ_FIRST(&fdlist[i].nal); bip != NULL;
439                              bip = TAILQ_NEXT(bip, link)) {
440                                 void *addr;
441
442                                 addr = &bip->broadaddr;
443
444                                 __rpc_broadenable(fdlist[i].af, fdlist[i].fd,
445                                     bip);
446
447                                 /*
448                                  * Only use version 3 if lowvers is not set
449                                  */
450
451                                 if (!__rpc_lowvers)
452                                         if (sendto(fdlist[i].fd, outbuf,
453                                             outlen, 0, (struct sockaddr*)addr,
454                                             (size_t)fdlist[i].asize) !=
455                                             outlen) {
456                                                 LIBTIRPC_DEBUG(1, 
457                                                         ("rpc_broadcast_exp: sendto failed: errno %d", errno));
458                                                 warnx("rpc_broadcast_exp: cannot send broadcast packet");
459                                                 stat = RPC_CANTSEND;
460                                                 continue;
461                                         };
462                                 if (!__rpc_lowvers)
463                                         LIBTIRPC_DEBUG(3, ("rpc_broadcast_exp: Broadcast packet sent for %s\n",
464                                                  fdlist[i].nconf->nc_netid));
465 #ifdef PORTMAP
466                                 /*
467                                  * Send the version 2 packet also
468                                  * for UDP/IP
469                                  */
470                                 if (pmap_flag &&
471                                     fdlist[i].proto == IPPROTO_UDP) {
472                                         if (sendto(fdlist[i].fd, outbuf_pmap,
473                                             outlen_pmap, 0, addr,
474                                             (size_t)fdlist[i].asize) !=
475                                                 outlen_pmap) {
476                                                 warnx("clnt_bcast: "
477                                                     "Cannot send broadcast packet");
478                                                 stat = RPC_CANTSEND;
479                                                 continue;
480                                         }
481                                 }
482                                 LIBTIRPC_DEBUG(3, ("rpc_broadcast_exp: PMAP Broadcast packet sent for %s\n",
483                                         fdlist[i].nconf->nc_netid));
484 #endif                          /* PORTMAP */
485                         }
486                         /* End for sending all packets on this transport */
487                 }       /* End for sending on all transports */
488
489                 if (eachresult == NULL) {
490                         stat = RPC_SUCCESS;
491                         goto done_broad;
492                 }
493
494                 /*
495                  * Get all the replies from these broadcast requests
496                  */
497         recv_again:
498
499                 switch (pollretval = poll(pfd, fdlistno, msec)) {
500                 case 0:         /* timed out */
501                         stat = RPC_TIMEDOUT;
502                         continue;
503                 case -1:        /* some kind of error - we ignore it */
504                         goto recv_again;
505                 }               /* end of poll results switch */
506
507                 for (i = fds_found = 0;
508                      i < fdlistno && fds_found < pollretval; i++) {
509                         bool_t done = FALSE;
510
511                         if (pfd[i].revents == 0)
512                                 continue;
513                         else if (pfd[i].revents & POLLNVAL) {
514                                 /*
515                                  * Something bad has happened to this descri-
516                                  * ptor. We can cause _poll() to ignore
517                                  * it simply by using a negative fd.  We do that
518                                  * rather than compacting the pfd[] and fdlist[]
519                                  * arrays.
520                                  */
521                                 pfd[i].fd = -1;
522                                 fds_found++;
523                                 continue;
524                         } else
525                                 fds_found++;
526                         LIBTIRPC_DEBUG(3, ("rpc_broadcast_exp: response for %s\n", 
527                                 fdlist[i].nconf->nc_netid));
528                 try_again:
529                         inlen = recvfrom(fdlist[i].fd, inbuf, fdlist[i].dsize,
530                             0, (struct sockaddr *)(void *)&fdlist[i].raddr,
531                             &fdlist[i].asize);
532                         if (inlen < 0) {
533                                 if (errno == EINTR)
534                                         goto try_again;
535                                 warnx("clnt_bcast: Cannot receive reply to "
536                                         "broadcast");
537                                 stat = RPC_CANTRECV;
538                                 continue;
539                         }
540                         if (inlen < sizeof (u_int32_t))
541                                 continue; /* Drop that and go ahead */
542                         /*
543                          * see if reply transaction id matches sent id.
544                          * If so, decode the results. If return id is xid + 1
545                          * it was a PORTMAP reply
546                          */
547                         if (*((u_int32_t *)(void *)(inbuf)) ==
548                             *((u_int32_t *)(void *)(outbuf))) {
549                                 pmap_reply_flag = 0;
550                                 msg.acpted_rply.ar_verf = _null_auth;
551                                 msg.acpted_rply.ar_results.where =
552                                         (caddr_t)(void *)&bres;
553                                 msg.acpted_rply.ar_results.proc =
554                                         (xdrproc_t)xdr_rpcb_rmtcallres;
555 #ifdef PORTMAP
556                         } else if (pmap_flag &&
557                                 *((u_int32_t *)(void *)(inbuf)) ==
558                                 *((u_int32_t *)(void *)(outbuf_pmap))) {
559                                 pmap_reply_flag = 1;
560                                 msg.acpted_rply.ar_verf = _null_auth;
561                                 msg.acpted_rply.ar_results.where =
562                                         (caddr_t)(void *)&bres_pmap;
563                                 msg.acpted_rply.ar_results.proc =
564                                         (xdrproc_t)xdr_rmtcallres;
565 #endif                          /* PORTMAP */
566                         } else
567                                 continue;
568                         xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE);
569                         if (xdr_replymsg(xdrs, &msg)) {
570                                 if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
571                                     (msg.acpted_rply.ar_stat == SUCCESS)) {
572                                         struct netbuf *np;
573 #ifdef PORTMAP
574                                         struct netbuf taddr;
575                                         struct sockaddr_in sin;
576
577                                         if (pmap_flag && pmap_reply_flag) {
578                                                 memcpy(&sin, &fdlist[i].raddr, sizeof(sin)); 
579                                                 sin.sin_port = htons((u_short)port);
580                                                 memcpy(&fdlist[i].raddr, &sin, sizeof(sin)); 
581                                                 taddr.len = taddr.maxlen = 
582                                                     sizeof(fdlist[i].raddr);
583                                                 taddr.buf = &fdlist[i].raddr;
584                                                 done = (*eachresult)(resultsp,
585                                                     &taddr, fdlist[i].nconf);
586                                         } else {
587 #endif                          /* PORTMAP */
588                                                 LIBTIRPC_DEBUG(3, ("rpc_broadcast_exp: uaddr %s\n", uaddrp));
589                                                 np = uaddr2taddr(
590                                                     fdlist[i].nconf, uaddrp);
591                                                 done = (*eachresult)(resultsp,
592                                                     np, fdlist[i].nconf);
593                                                 free(np);
594 #ifdef PORTMAP
595                                         }
596 #endif                          /* PORTMAP */
597                                 }
598                                 /* otherwise, we just ignore the errors ... */
599                         }
600                         /* else some kind of deserialization problem ... */
601
602                         xdrs->x_op = XDR_FREE;
603                         msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
604                         (void) xdr_replymsg(xdrs, &msg);
605                         (void) (*xresults)(xdrs, resultsp);
606                         XDR_DESTROY(xdrs);
607                         if (done) {
608                                 stat = RPC_SUCCESS;
609                                 goto done_broad;
610                         } else {
611                                 goto recv_again;
612                         }
613                 }               /* The recv for loop */
614         }                       /* The giant for loop */
615
616 done_broad:
617         if (inbuf)
618                 (void) free(inbuf);
619         if (outbuf)
620                 (void) free(outbuf);
621 #ifdef PORTMAP
622         if (outbuf_pmap)
623                 (void) free(outbuf_pmap);
624 #endif                          /* PORTMAP */
625         for (i = 0; i < fdlistno; i++) {
626                 (void)close(fdlist[i].fd);
627                 __rpc_freebroadifs(&fdlist[i].nal);
628         }
629         AUTH_DESTROY(sys_auth);
630         (void) __rpc_endconf(handle);
631
632         return (stat);
633 }
634
635
636 enum clnt_stat
637 rpc_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp,
638                         eachresult, nettype)
639         rpcprog_t       prog;           /* program number */
640         rpcvers_t       vers;           /* version number */
641         rpcproc_t       proc;           /* procedure number */
642         xdrproc_t       xargs;          /* xdr routine for args */
643         caddr_t         argsp;          /* pointer to args */
644         xdrproc_t       xresults;       /* xdr routine for results */
645         caddr_t         resultsp;       /* pointer to results */
646         resultproc_t    eachresult;     /* call with each result obtained */
647         const char              *nettype;       /* transport type */
648 {
649         enum clnt_stat  dummy;
650
651         dummy = rpc_broadcast_exp(prog, vers, proc, xargs, argsp,
652                 xresults, resultsp, eachresult,
653                 INITTIME, WAITTIME, nettype);
654         return (dummy);
655 }