1 /* $NetBSD: clnt_bcast.c,v 1.26 2013/03/11 20:19:28 tron 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 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 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 #include "svc_fdset.h" 87 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 */ 91 92 /* 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. 96 * 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. 101 * 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. 106 * 107 * The result size has to be smaller than the transport tsdu size. 108 * 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. 113 */ 114 115 #ifdef __weak_alias 116 __weak_alias(rpc_broadcast_exp,_rpc_broadcast_exp) 117 __weak_alias(rpc_broadcast,_rpc_broadcast) 118 #endif 119 120 struct broadif { 121 int index; 122 struct sockaddr_storage broadaddr; 123 TAILQ_ENTRY(broadif) link; 124 }; 125 126 typedef TAILQ_HEAD(, broadif) broadlist_t; 127 128 int __rpc_getbroadifs(int, int, int, broadlist_t *); 129 void __rpc_freebroadifs(broadlist_t *); 130 int __rpc_broadenable(int, int, struct broadif *); 131 132 int __rpc_lowvers = 0; 133 134 int 135 __rpc_getbroadifs(int af, int proto, int socktype, broadlist_t *list) 136 { 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; 145 146 _DIAGASSERT(list != NULL); 147 148 if (getifaddrs(&ifp) < 0) 149 return 0; 150 151 memset(&hints, 0, sizeof hints); 152 153 hints.ai_family = af; 154 hints.ai_protocol = proto; 155 hints.ai_socktype = socktype; 156 157 if (getaddrinfo(NULL, "sunrpc", &hints, &res) != 0) { 158 freeifaddrs(ifp); 159 return 0; 160 } 161 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 195 { 196 free(bip); 197 continue; 198 } 199 TAILQ_INSERT_TAIL(list, bip, link); 200 count++; 201 } 202 freeifaddrs(ifp); 203 freeaddrinfo(res); 204 205 return count; 206 } 207 208 void 209 __rpc_freebroadifs(broadlist_t *list) 210 { 211 struct broadif *bip, *next; 212 213 _DIAGASSERT(list != NULL); 214 215 bip = TAILQ_FIRST(list); 216 217 while (bip != NULL) { 218 next = TAILQ_NEXT(bip, link); 219 free(bip); 220 bip = next; 221 } 222 } 223 224 int 225 /*ARGSUSED*/ 226 __rpc_broadenable(int af, int s, struct broadif *bip) 227 { 228 int o = 1; 229 230 #if 0 231 _DIAGASSERT(bip != NULL); 232 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; 243 244 return 0; 245 } 246 247 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 */ 261 { 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; 297 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 */ 307 308 if (sys_auth == NULL) { 309 return (RPC_SYSTEMERROR); 310 } 311 /* 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. 316 */ 317 318 if (nettype == NULL) 319 nettype = "datagram_n"; 320 if ((handle = __rpc_setconf(nettype)) == NULL) { 321 AUTH_DESTROY(sys_auth); 322 return (RPC_UNKNOWNPROTO); 323 } 324 while ((nconf = __rpc_getconf(handle)) != NULL) { 325 int fd; 326 struct __rpc_sockinfo si; 327 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; 334 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; 339 340 fd = socket(si.si_af, si.si_socktype, si.si_proto); 341 if (fd < 0) { 342 stat = RPC_CANTSEND; 343 continue; 344 } 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, 354 0); 355 356 if (maxbufsize <= fdlist[fdlistno].dsize) 357 maxbufsize = fdlist[fdlistno].dsize; 358 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; 366 } 367 pmap_flag = 1; 368 } 369 #endif 370 fdlistno++; 371 } 372 373 if (fdlistno == 0) { 374 if (stat == RPC_SUCCESS) 375 stat = RPC_UNKNOWNPROTO; 376 goto done_broad; 377 } 378 if (maxbufsize == 0) { 379 if (stat == RPC_SUCCESS) 380 stat = RPC_CANTSEND; 381 goto done_broad; 382 } 383 inbuf = malloc(maxbufsize); 384 outbuf = malloc(maxbufsize); 385 if ((inbuf == NULL) || (outbuf == NULL)) { 386 stat = RPC_SYSTEMERROR; 387 goto done_broad; 388 } 389 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; 413 } 414 outlen = xdr_getpos(xdrs); 415 xdr_destroy(xdrs); 416 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; 437 } 438 outlen_pmap = xdr_getpos(xdrs); 439 xdr_destroy(xdrs); 440 } 441 #endif /* PORTMAP */ 442 443 /* 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. 449 */ 450 for (msec = inittime; msec <= waittime; msec += msec) { 451 struct broadif *bip; 452 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; 458 } 459 for (bip = TAILQ_FIRST(&fdlist[i].nal); bip != NULL; 460 bip = TAILQ_NEXT(bip, link)) { 461 void *addr; 462 463 addr = &bip->broadaddr; 464 465 __rpc_broadenable(fdlist[i].af, fdlist[i].fd, 466 bip); 467 468 /* 469 * Only use version 3 if lowvers is not set 470 */ 471 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; 481 } 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 489 /* 490 * Send the version 2 packet also 491 * for UDP/IP 492 */ 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; 504 } 505 } 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 */ 512 } 513 /* End for sending all packets on this transport */ 514 } /* End for sending on all transports */ 515 516 if (eachresult == NULL) { 517 stat = RPC_SUCCESS; 518 goto done_broad; 519 } 520 521 /* 522 * Get all the replies from these broadcast requests 523 */ 524 recv_again: 525 ts.tv_sec = msec / 1000; 526 ts.tv_nsec = (msec % 1000) * 1000000; 527 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 */ 535 536 for (i = fds_found = 0; 537 i < fdlistno && fds_found < pollretval; i++) { 538 bool_t done = FALSE; 539 540 if (pfd[i].revents == 0) 541 continue; 542 else if (pfd[i].revents & POLLNVAL) { 543 /* 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. 549 */ 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; 570 } 571 if (inlen < (ssize_t)sizeof(u_int32_t)) 572 continue; /* Drop that and go ahead */ 573 /* 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 577 */ 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; 605 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 629 } 630 #endif 631 } 632 /* otherwise, we just ignore the errors ... */ 633 } 634 /* else some kind of deserialization problem ... */ 635 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; 646 } 647 } /* The recv for loop */ 648 } /* The giant for loop */ 649 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); 662 } 663 AUTH_DESTROY(sys_auth); 664 (void) __rpc_endconf(handle); 665 666 return (stat); 667 } 668 669 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 */ 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