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