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