1b2845e83SBill Paul /* 2b2845e83SBill Paul * Copyright (c) 1996, 1997 3b2845e83SBill Paul * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 4b2845e83SBill Paul * 5b2845e83SBill Paul * Redistribution and use in source and binary forms, with or without 6b2845e83SBill Paul * modification, are permitted provided that the following conditions 7b2845e83SBill Paul * are met: 8b2845e83SBill Paul * 1. Redistributions of source code must retain the above copyright 9b2845e83SBill Paul * notice, this list of conditions and the following disclaimer. 10b2845e83SBill Paul * 2. Redistributions in binary form must reproduce the above copyright 11b2845e83SBill Paul * notice, this list of conditions and the following disclaimer in the 12b2845e83SBill Paul * documentation and/or other materials provided with the distribution. 13b2845e83SBill Paul * 3. All advertising materials mentioning features or use of this software 14b2845e83SBill Paul * must display the following acknowledgement: 15b2845e83SBill Paul * This product includes software developed by Bill Paul. 16b2845e83SBill Paul * 4. Neither the name of the author nor the names of any co-contributors 17b2845e83SBill Paul * may be used to endorse or promote products derived from this software 18b2845e83SBill Paul * without specific prior written permission. 19b2845e83SBill Paul * 20b2845e83SBill Paul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21b2845e83SBill Paul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22b2845e83SBill Paul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23b2845e83SBill Paul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE 24b2845e83SBill Paul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25b2845e83SBill Paul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26b2845e83SBill Paul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27b2845e83SBill Paul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28b2845e83SBill Paul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29b2845e83SBill Paul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30b2845e83SBill Paul * SUCH DAMAGE. 31b2845e83SBill Paul */ 32b2845e83SBill Paul 33b2845e83SBill Paul /* 34b2845e83SBill Paul * What follows is a special version of clntudp_call() that has been 35b2845e83SBill Paul * hacked to send requests and receive replies asynchronously. Similar 36b2845e83SBill Paul * magic is used inside rpc.nisd(8) for the special non-blocking, 37b2845e83SBill Paul * non-fork()ing, non-threading callback support. 38b2845e83SBill Paul */ 39b2845e83SBill Paul 40b2845e83SBill Paul /* 41b2845e83SBill Paul * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 42b2845e83SBill Paul * unrestricted use provided that this legend is included on all tape 43b2845e83SBill Paul * media and as a part of the software program in whole or part. Users 44b2845e83SBill Paul * may copy or modify Sun RPC without charge, but are not authorized 45b2845e83SBill Paul * to license or distribute it to anyone else except as part of a product or 46b2845e83SBill Paul * program developed by the user. 47b2845e83SBill Paul * 48b2845e83SBill Paul * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 49b2845e83SBill Paul * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 50b2845e83SBill Paul * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 51b2845e83SBill Paul * 52b2845e83SBill Paul * Sun RPC is provided with no support and without any obligation on the 53b2845e83SBill Paul * part of Sun Microsystems, Inc. to assist in its use, correction, 54b2845e83SBill Paul * modification or enhancement. 55b2845e83SBill Paul * 56b2845e83SBill Paul * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 57b2845e83SBill Paul * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 58b2845e83SBill Paul * OR ANY PART THEREOF. 59b2845e83SBill Paul * 60b2845e83SBill Paul * In no event will Sun Microsystems, Inc. be liable for any lost revenue 61b2845e83SBill Paul * or profits or other special, indirect and consequential damages, even if 62b2845e83SBill Paul * Sun has been advised of the possibility of such damages. 63b2845e83SBill Paul * 64b2845e83SBill Paul * Sun Microsystems, Inc. 65b2845e83SBill Paul * 2550 Garcia Avenue 66b2845e83SBill Paul * Mountain View, California 94043 67b2845e83SBill Paul */ 68b2845e83SBill Paul 69b2845e83SBill Paul #ifndef lint 7077cbf0b3SPhilippe Charnier #if 0 7177cbf0b3SPhilippe Charnier static char *sccsid = "@(#)from: clnt_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro"; 7277cbf0b3SPhilippe Charnier static char *sccsid = "@(#)from: clnt_udp.c 2.2 88/08/01 4.0 RPCSRC"; 7377cbf0b3SPhilippe Charnier #endif 7477cbf0b3SPhilippe Charnier static const char rcsid[] = 7577cbf0b3SPhilippe Charnier "$Id$"; 76b2845e83SBill Paul #endif 77b2845e83SBill Paul 78b2845e83SBill Paul /* 79b2845e83SBill Paul * clnt_udp.c, Implements a UDP/IP based, client side RPC. 80b2845e83SBill Paul * 81b2845e83SBill Paul * Copyright (C) 1984, Sun Microsystems, Inc. 82b2845e83SBill Paul */ 83b2845e83SBill Paul 8477cbf0b3SPhilippe Charnier #include <errno.h> 8577cbf0b3SPhilippe Charnier #include <netdb.h> 86b2845e83SBill Paul #include <stdio.h> 87b2845e83SBill Paul #include <stdlib.h> 88b2845e83SBill Paul #include <string.h> 8977cbf0b3SPhilippe Charnier #include <unistd.h> 90b2845e83SBill Paul #include <rpc/rpc.h> 91b2845e83SBill Paul #include <rpc/pmap_clnt.h> 92b2845e83SBill Paul #include <rpc/pmap_prot.h> 93b2845e83SBill Paul #include <rpcsvc/yp.h> 9477cbf0b3SPhilippe Charnier #include <sys/socket.h> 9577cbf0b3SPhilippe Charnier #include <sys/ioctl.h> 9677cbf0b3SPhilippe Charnier #include <net/if.h> 97b2845e83SBill Paul #include "yp_ping.h" 98b2845e83SBill Paul 99b2845e83SBill Paul #ifndef timeradd 100b2845e83SBill Paul #ifndef KERNEL /* use timevaladd/timevalsub in kernel */ 101b2845e83SBill Paul /* NetBSD/OpenBSD compatable interfaces */ 102b2845e83SBill Paul #define timeradd(tvp, uvp, vvp) \ 103b2845e83SBill Paul do { \ 104b2845e83SBill Paul (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ 105b2845e83SBill Paul (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ 106b2845e83SBill Paul if ((vvp)->tv_usec >= 1000000) { \ 107b2845e83SBill Paul (vvp)->tv_sec++; \ 108b2845e83SBill Paul (vvp)->tv_usec -= 1000000; \ 109b2845e83SBill Paul } \ 110b2845e83SBill Paul } while (0) 111b2845e83SBill Paul #define timersub(tvp, uvp, vvp) \ 112b2845e83SBill Paul do { \ 113b2845e83SBill Paul (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ 114b2845e83SBill Paul (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ 115b2845e83SBill Paul if ((vvp)->tv_usec < 0) { \ 116b2845e83SBill Paul (vvp)->tv_sec--; \ 117b2845e83SBill Paul (vvp)->tv_usec += 1000000; \ 118b2845e83SBill Paul } \ 119b2845e83SBill Paul } while (0) 120b2845e83SBill Paul #endif 121b2845e83SBill Paul #endif 122b2845e83SBill Paul 123b2845e83SBill Paul /* 124b2845e83SBill Paul * Private data kept per client handle 125b2845e83SBill Paul */ 126b2845e83SBill Paul struct cu_data { 127b2845e83SBill Paul int cu_sock; 128b2845e83SBill Paul bool_t cu_closeit; 129b2845e83SBill Paul struct sockaddr_in cu_raddr; 130b2845e83SBill Paul int cu_rlen; 131b2845e83SBill Paul struct timeval cu_wait; 132b2845e83SBill Paul struct timeval cu_total; 133b2845e83SBill Paul struct rpc_err cu_error; 134b2845e83SBill Paul XDR cu_outxdrs; 135b2845e83SBill Paul u_int cu_xdrpos; 136b2845e83SBill Paul u_int cu_sendsz; 137b2845e83SBill Paul char *cu_outbuf; 138b2845e83SBill Paul u_int cu_recvsz; 139b2845e83SBill Paul char cu_inbuf[1]; 140b2845e83SBill Paul }; 141b2845e83SBill Paul 142b2845e83SBill Paul static enum clnt_stat 143b2845e83SBill Paul clntudp_a_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) 144b2845e83SBill Paul register CLIENT *cl; /* client handle */ 145b2845e83SBill Paul u_long proc; /* procedure number */ 146b2845e83SBill Paul xdrproc_t xargs; /* xdr routine for args */ 147b2845e83SBill Paul caddr_t argsp; /* pointer to args */ 148b2845e83SBill Paul xdrproc_t xresults; /* xdr routine for results */ 149b2845e83SBill Paul caddr_t resultsp; /* pointer to results */ 150b2845e83SBill Paul struct timeval utimeout; /* seconds to wait before giving up */ 151b2845e83SBill Paul { 152b2845e83SBill Paul register struct cu_data *cu = (struct cu_data *)cl->cl_private; 153b2845e83SBill Paul register XDR *xdrs; 154b2845e83SBill Paul register int outlen = 0; 155b2845e83SBill Paul register int inlen; 156b2845e83SBill Paul int fromlen; 157b2845e83SBill Paul fd_set *fds, readfds; 158b2845e83SBill Paul struct sockaddr_in from; 159b2845e83SBill Paul struct rpc_msg reply_msg; 160b2845e83SBill Paul XDR reply_xdrs; 161b2845e83SBill Paul struct timeval time_waited, start, after, tmp1, tmp2, tv; 162b2845e83SBill Paul bool_t ok; 163b2845e83SBill Paul int nrefreshes = 2; /* number of times to refresh cred */ 164b2845e83SBill Paul struct timeval timeout; 165b2845e83SBill Paul 166b2845e83SBill Paul if (cu->cu_total.tv_usec == -1) 167b2845e83SBill Paul timeout = utimeout; /* use supplied timeout */ 168b2845e83SBill Paul else 169b2845e83SBill Paul timeout = cu->cu_total; /* use default timeout */ 170b2845e83SBill Paul 171b2845e83SBill Paul if (cu->cu_sock + 1 > FD_SETSIZE) { 172b2845e83SBill Paul int bytes = howmany(cu->cu_sock + 1, NFDBITS) * sizeof(fd_mask); 173b2845e83SBill Paul fds = (fd_set *)malloc(bytes); 174b2845e83SBill Paul if (fds == NULL) 175b2845e83SBill Paul return (cu->cu_error.re_status = RPC_CANTSEND); 176b2845e83SBill Paul memset(fds, 0, bytes); 177b2845e83SBill Paul } else { 178b2845e83SBill Paul fds = &readfds; 179b2845e83SBill Paul FD_ZERO(fds); 180b2845e83SBill Paul } 181b2845e83SBill Paul 182b2845e83SBill Paul timerclear(&time_waited); 183b2845e83SBill Paul 184b2845e83SBill Paul call_again: 185b2845e83SBill Paul xdrs = &(cu->cu_outxdrs); 186b2845e83SBill Paul if (xargs == NULL) 187b2845e83SBill Paul goto get_reply; 188b2845e83SBill Paul xdrs->x_op = XDR_ENCODE; 189b2845e83SBill Paul XDR_SETPOS(xdrs, cu->cu_xdrpos); 190b2845e83SBill Paul /* 191b2845e83SBill Paul * the transaction is the first thing in the out buffer 192b2845e83SBill Paul */ 193b2845e83SBill Paul (*(u_short *)(cu->cu_outbuf))++; 194b2845e83SBill Paul if ((! XDR_PUTLONG(xdrs, (long *)&proc)) || 195b2845e83SBill Paul (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || 196b2845e83SBill Paul (! (*xargs)(xdrs, argsp))) { 197b2845e83SBill Paul if (fds != &readfds) 198b2845e83SBill Paul free(fds); 199b2845e83SBill Paul return (cu->cu_error.re_status = RPC_CANTENCODEARGS); 200b2845e83SBill Paul } 201b2845e83SBill Paul outlen = (int)XDR_GETPOS(xdrs); 202b2845e83SBill Paul 203b2845e83SBill Paul send_again: 204b2845e83SBill Paul if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0, 205b2845e83SBill Paul (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen) != outlen) { 206b2845e83SBill Paul cu->cu_error.re_errno = errno; 207b2845e83SBill Paul if (fds != &readfds) 208b2845e83SBill Paul free(fds); 209b2845e83SBill Paul return (cu->cu_error.re_status = RPC_CANTSEND); 210b2845e83SBill Paul } 211b2845e83SBill Paul 212b2845e83SBill Paul /* 213b2845e83SBill Paul * Hack to provide rpc-based message passing 214b2845e83SBill Paul */ 215b2845e83SBill Paul if (!timerisset(&timeout)) { 216b2845e83SBill Paul if (fds != &readfds) 217b2845e83SBill Paul free(fds); 218b2845e83SBill Paul return (cu->cu_error.re_status = RPC_TIMEDOUT); 219b2845e83SBill Paul } 220b2845e83SBill Paul 221b2845e83SBill Paul get_reply: 222b2845e83SBill Paul 223b2845e83SBill Paul /* 224b2845e83SBill Paul * sub-optimal code appears here because we have 225b2845e83SBill Paul * some clock time to spare while the packets are in flight. 226b2845e83SBill Paul * (We assume that this is actually only executed once.) 227b2845e83SBill Paul */ 228b2845e83SBill Paul reply_msg.acpted_rply.ar_verf = _null_auth; 229b2845e83SBill Paul reply_msg.acpted_rply.ar_results.where = resultsp; 230b2845e83SBill Paul reply_msg.acpted_rply.ar_results.proc = xresults; 231b2845e83SBill Paul 232b2845e83SBill Paul gettimeofday(&start, NULL); 233b2845e83SBill Paul for (;;) { 234b2845e83SBill Paul /* XXX we know the other bits are still clear */ 235b2845e83SBill Paul FD_SET(cu->cu_sock, fds); 236b2845e83SBill Paul tv = cu->cu_wait; 237b2845e83SBill Paul switch (select(cu->cu_sock+1, fds, NULL, NULL, &tv)) { 238b2845e83SBill Paul 239b2845e83SBill Paul case 0: 240b2845e83SBill Paul timeradd(&time_waited, &cu->cu_wait, &tmp1); 241b2845e83SBill Paul time_waited = tmp1; 242b2845e83SBill Paul if (timercmp(&time_waited, &timeout, <)) 243b2845e83SBill Paul goto send_again; 244b2845e83SBill Paul if (fds != &readfds) 245b2845e83SBill Paul free(fds); 246b2845e83SBill Paul return (cu->cu_error.re_status = RPC_TIMEDOUT); 247b2845e83SBill Paul 248b2845e83SBill Paul case -1: 249b2845e83SBill Paul if (errno == EINTR) { 250b2845e83SBill Paul gettimeofday(&after, NULL); 251b2845e83SBill Paul timersub(&after, &start, &tmp1); 252b2845e83SBill Paul timeradd(&time_waited, &tmp1, &tmp2); 253b2845e83SBill Paul time_waited = tmp2; 254b2845e83SBill Paul if (timercmp(&time_waited, &timeout, <)) 255b2845e83SBill Paul continue; 256b2845e83SBill Paul if (fds != &readfds) 257b2845e83SBill Paul free(fds); 258b2845e83SBill Paul return (cu->cu_error.re_status = RPC_TIMEDOUT); 259b2845e83SBill Paul } 260b2845e83SBill Paul cu->cu_error.re_errno = errno; 261b2845e83SBill Paul if (fds != &readfds) 262b2845e83SBill Paul free(fds); 263b2845e83SBill Paul return (cu->cu_error.re_status = RPC_CANTRECV); 264b2845e83SBill Paul } 265b2845e83SBill Paul 266b2845e83SBill Paul do { 267b2845e83SBill Paul fromlen = sizeof(struct sockaddr); 268b2845e83SBill Paul inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, 269b2845e83SBill Paul (int) cu->cu_recvsz, 0, 270b2845e83SBill Paul (struct sockaddr *)&from, &fromlen); 271b2845e83SBill Paul } while (inlen < 0 && errno == EINTR); 272b2845e83SBill Paul if (inlen < 0) { 273b2845e83SBill Paul if (errno == EWOULDBLOCK) 274b2845e83SBill Paul continue; 275b2845e83SBill Paul cu->cu_error.re_errno = errno; 276b2845e83SBill Paul if (fds != &readfds) 277b2845e83SBill Paul free(fds); 278b2845e83SBill Paul return (cu->cu_error.re_status = RPC_CANTRECV); 279b2845e83SBill Paul } 280b2845e83SBill Paul if (inlen < sizeof(u_int32_t)) 281b2845e83SBill Paul continue; 282b2845e83SBill Paul #ifdef dont_check_xid 283b2845e83SBill Paul /* see if reply transaction id matches sent id */ 284b2845e83SBill Paul if (*((u_int32_t *)(cu->cu_inbuf)) != *((u_int32_t *)(cu->cu_outbuf))) 285b2845e83SBill Paul continue; 286b2845e83SBill Paul #endif 287b2845e83SBill Paul /* we now assume we have the proper reply */ 288b2845e83SBill Paul break; 289b2845e83SBill Paul } 290b2845e83SBill Paul 291b2845e83SBill Paul /* 292b2845e83SBill Paul * now decode and validate the response 293b2845e83SBill Paul */ 294b2845e83SBill Paul xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE); 295b2845e83SBill Paul ok = xdr_replymsg(&reply_xdrs, &reply_msg); 296b2845e83SBill Paul /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ 297b2845e83SBill Paul if (ok) { 298b2845e83SBill Paul _seterr_reply(&reply_msg, &(cu->cu_error)); 299b2845e83SBill Paul if (cu->cu_error.re_status == RPC_SUCCESS) { 300b2845e83SBill Paul if (! AUTH_VALIDATE(cl->cl_auth, 301b2845e83SBill Paul &reply_msg.acpted_rply.ar_verf)) { 302b2845e83SBill Paul cu->cu_error.re_status = RPC_AUTHERROR; 303b2845e83SBill Paul cu->cu_error.re_why = AUTH_INVALIDRESP; 304b2845e83SBill Paul } 305b2845e83SBill Paul if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 306b2845e83SBill Paul xdrs->x_op = XDR_FREE; 307b2845e83SBill Paul (void)xdr_opaque_auth(xdrs, 308b2845e83SBill Paul &(reply_msg.acpted_rply.ar_verf)); 309b2845e83SBill Paul } 310b2845e83SBill Paul } /* end successful completion */ 311b2845e83SBill Paul else { 312b2845e83SBill Paul /* maybe our credentials need to be refreshed ... */ 313b2845e83SBill Paul if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) { 314b2845e83SBill Paul nrefreshes--; 315b2845e83SBill Paul goto call_again; 316b2845e83SBill Paul } 317b2845e83SBill Paul } /* end of unsuccessful completion */ 318b2845e83SBill Paul } /* end of valid reply message */ 319b2845e83SBill Paul else { 320b2845e83SBill Paul cu->cu_error.re_status = RPC_CANTDECODERES; 321b2845e83SBill Paul } 322b2845e83SBill Paul if (fds != &readfds) 323b2845e83SBill Paul free(fds); 324b2845e83SBill Paul return (cu->cu_error.re_status); 325b2845e83SBill Paul } 326b2845e83SBill Paul 327b2845e83SBill Paul 328b2845e83SBill Paul /* 329b2845e83SBill Paul * pmap_getport.c 330b2845e83SBill Paul * Client interface to pmap rpc service. 331b2845e83SBill Paul * 332b2845e83SBill Paul * Copyright (C) 1984, Sun Microsystems, Inc. 333b2845e83SBill Paul */ 334b2845e83SBill Paul 335b2845e83SBill Paul 336b2845e83SBill Paul static struct timeval timeout = { 1, 0 }; 337b2845e83SBill Paul static struct timeval tottimeout = { 1, 0 }; 338b2845e83SBill Paul 339b2845e83SBill Paul /* 340b2845e83SBill Paul * Find the mapped port for program,version. 341b2845e83SBill Paul * Calls the pmap service remotely to do the lookup. 342b2845e83SBill Paul * Returns 0 if no map exists. 343b2845e83SBill Paul */ 344b2845e83SBill Paul static u_short 345b2845e83SBill Paul __pmap_getport(address, program, version, protocol) 346b2845e83SBill Paul struct sockaddr_in *address; 347b2845e83SBill Paul u_long program; 348b2845e83SBill Paul u_long version; 349b2845e83SBill Paul u_int protocol; 350b2845e83SBill Paul { 351b2845e83SBill Paul u_short port = 0; 352b2845e83SBill Paul int sock = -1; 353b2845e83SBill Paul register CLIENT *client; 354b2845e83SBill Paul struct pmap parms; 355b2845e83SBill Paul 356b2845e83SBill Paul address->sin_port = htons(PMAPPORT); 357b2845e83SBill Paul 358b2845e83SBill Paul client = clntudp_bufcreate(address, PMAPPROG, 359b2845e83SBill Paul PMAPVERS, timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); 360b2845e83SBill Paul if (client != (CLIENT *)NULL) { 361b2845e83SBill Paul parms.pm_prog = program; 362b2845e83SBill Paul parms.pm_vers = version; 363b2845e83SBill Paul parms.pm_prot = protocol; 364b2845e83SBill Paul parms.pm_port = 0; /* not needed or used */ 365b2845e83SBill Paul if (CLNT_CALL(client, PMAPPROC_GETPORT, xdr_pmap, &parms, 366b2845e83SBill Paul xdr_u_short, &port, tottimeout) != RPC_SUCCESS){ 367b2845e83SBill Paul rpc_createerr.cf_stat = RPC_PMAPFAILURE; 368b2845e83SBill Paul clnt_geterr(client, &rpc_createerr.cf_error); 369b2845e83SBill Paul } else if (port == 0) { 370b2845e83SBill Paul rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; 371b2845e83SBill Paul } 372b2845e83SBill Paul CLNT_DESTROY(client); 373b2845e83SBill Paul } 374b2845e83SBill Paul if (sock != -1) 375b2845e83SBill Paul (void)close(sock); 376b2845e83SBill Paul address->sin_port = 0; 377b2845e83SBill Paul return (port); 378b2845e83SBill Paul } 379b2845e83SBill Paul 380b2845e83SBill Paul /* 381b2845e83SBill Paul * Transmit to YPPROC_DOMAIN_NONACK, return immediately. 382b2845e83SBill Paul */ 383b2845e83SBill Paul static bool_t * 384b2845e83SBill Paul ypproc_domain_nonack_2_send(domainname *argp, CLIENT *clnt) 385b2845e83SBill Paul { 386b2845e83SBill Paul static bool_t clnt_res; 387b2845e83SBill Paul struct timeval TIMEOUT = { 0, 0 }; 388b2845e83SBill Paul 389b2845e83SBill Paul memset((char *)&clnt_res, 0, sizeof (clnt_res)); 390b2845e83SBill Paul if (clnt_call(clnt, YPPROC_DOMAIN_NONACK, 391b2845e83SBill Paul (xdrproc_t) xdr_domainname, (caddr_t) argp, 392b2845e83SBill Paul (xdrproc_t) xdr_bool, (caddr_t) &clnt_res, 393b2845e83SBill Paul TIMEOUT) != RPC_SUCCESS) { 394b2845e83SBill Paul return (NULL); 395b2845e83SBill Paul } 396b2845e83SBill Paul return (&clnt_res); 397b2845e83SBill Paul } 398b2845e83SBill Paul 399b2845e83SBill Paul /* 400b2845e83SBill Paul * Receive response from YPPROC_DOMAIN_NONACK asynchronously. 401b2845e83SBill Paul */ 402b2845e83SBill Paul static bool_t * 403b2845e83SBill Paul ypproc_domain_nonack_2_recv(domainname *argp, CLIENT *clnt) 404b2845e83SBill Paul { 405b2845e83SBill Paul static bool_t clnt_res; 406b2845e83SBill Paul struct timeval TIMEOUT = { 0, 0 }; 407b2845e83SBill Paul 408b2845e83SBill Paul memset((char *)&clnt_res, 0, sizeof (clnt_res)); 409b2845e83SBill Paul if (clnt_call(clnt, YPPROC_DOMAIN_NONACK, 410b2845e83SBill Paul (xdrproc_t) NULL, (caddr_t) argp, 411b2845e83SBill Paul (xdrproc_t) xdr_bool, (caddr_t) &clnt_res, 412b2845e83SBill Paul TIMEOUT) != RPC_SUCCESS) { 413b2845e83SBill Paul return (NULL); 414b2845e83SBill Paul } 415b2845e83SBill Paul return (&clnt_res); 416b2845e83SBill Paul } 417b2845e83SBill Paul 418b2845e83SBill Paul /* 419b2845e83SBill Paul * "We have the machine that goes 'ping!'" -- Monty Python 420b2845e83SBill Paul * 421b2845e83SBill Paul * This function blasts packets at the YPPROC_DOMAIN_NONACK procedures 422b2845e83SBill Paul * of the NIS servers listed in restricted_addrs structure. 423b2845e83SBill Paul * Whoever replies the fastest becomes our chosen server. 424b2845e83SBill Paul * 425b2845e83SBill Paul * Note: THIS IS NOT A BROADCAST OPERATION! We could use clnt_broadcast() 426b2845e83SBill Paul * for this, but that has the following problems: 427b2845e83SBill Paul * - We only get the address of the machine that replied in the 428b2845e83SBill Paul * 'eachresult' callback, and on multi-homed machines this can 429b2845e83SBill Paul * lead to confusion. 430b2845e83SBill Paul * - clnt_broadcast() only transmits to local networks, whereas with 431b2845e83SBill Paul * NIS+ you can have a perfectly good server located anywhere on or 432b2845e83SBill Paul * off the local network. 433b2845e83SBill Paul * - clnt_broadcast() blocks for an arbitrary amount of time which the 434b2845e83SBill Paul * caller can't control -- we want to avoid that. 435b2845e83SBill Paul * 436b2845e83SBill Paul * Also note that this has nothing to do with the NIS_PING procedure used 437b2845e83SBill Paul * for replica updates. 438b2845e83SBill Paul */ 439b2845e83SBill Paul 440b2845e83SBill Paul struct ping_req { 441b2845e83SBill Paul struct sockaddr_in sin; 442b2845e83SBill Paul unsigned long xid; 443b2845e83SBill Paul }; 444b2845e83SBill Paul 445b2845e83SBill Paul int __yp_ping(restricted_addrs, cnt, dom, port) 446b2845e83SBill Paul struct in_addr *restricted_addrs; 447b2845e83SBill Paul int cnt; 448b2845e83SBill Paul char *dom; 449b2845e83SBill Paul short *port; 450b2845e83SBill Paul { 451b2845e83SBill Paul struct timeval tv = { 5 , 0 }; 452b2845e83SBill Paul struct ping_req **reqs; 453b2845e83SBill Paul unsigned long i; 454b2845e83SBill Paul struct sockaddr_in sin, *any; 455b2845e83SBill Paul int winner = -1; 456b2845e83SBill Paul time_t xid_seed, xid_lookup; 457b2845e83SBill Paul int sock, dontblock = 1; 458b2845e83SBill Paul CLIENT *clnt; 459b2845e83SBill Paul char *foo = dom; 460b2845e83SBill Paul struct cu_data *cu; 461b2845e83SBill Paul enum clnt_stat (*oldfunc)(); 462bfb109dfSBill Paul int validsrvs = 0; 463b2845e83SBill Paul 464b2845e83SBill Paul /* Set up handles. */ 465b2845e83SBill Paul reqs = calloc(1, sizeof(struct ping_req *) * cnt); 466b2845e83SBill Paul xid_seed = time(NULL) ^ getpid(); 467b2845e83SBill Paul 468b2845e83SBill Paul for (i = 0; i < cnt; i++) { 469b2845e83SBill Paul bzero((char *)&sin, sizeof(sin)); 470b2845e83SBill Paul sin.sin_family = AF_INET; 471b2845e83SBill Paul bcopy((char *)&restricted_addrs[i], 472b2845e83SBill Paul (char *)&sin.sin_addr, sizeof(struct in_addr)); 473b2845e83SBill Paul sin.sin_port = htons(__pmap_getport(&sin, YPPROG, 474b2845e83SBill Paul YPVERS, IPPROTO_UDP)); 475b2845e83SBill Paul if (sin.sin_port == 0) 476b2845e83SBill Paul continue; 477b2845e83SBill Paul reqs[i] = calloc(1, sizeof(struct ping_req)); 478b2845e83SBill Paul bcopy((char *)&sin, (char *)&reqs[i]->sin, sizeof(sin)); 479b2845e83SBill Paul any = &reqs[i]->sin; 480b2845e83SBill Paul reqs[i]->xid = xid_seed; 481b2845e83SBill Paul xid_seed++; 482bfb109dfSBill Paul validsrvs++; 483b2845e83SBill Paul } 484b2845e83SBill Paul 485b2845e83SBill Paul /* Make sure at least one server was assigned */ 486bfb109dfSBill Paul if (!validsrvs) { 487b2845e83SBill Paul free(reqs); 488b2845e83SBill Paul return(-1); 489b2845e83SBill Paul } 490b2845e83SBill Paul 491b2845e83SBill Paul /* Create RPC handle */ 492b2845e83SBill Paul sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 493b2845e83SBill Paul clnt = clntudp_create(any, YPPROG, YPVERS, tv, &sock); 494b2845e83SBill Paul if (clnt == NULL) { 495b2845e83SBill Paul close(sock); 496b2845e83SBill Paul for (i = 0; i < cnt; i++) 497b2845e83SBill Paul if (reqs[i] != NULL) 498b2845e83SBill Paul free(reqs[i]); 499b2845e83SBill Paul free(reqs); 500b2845e83SBill Paul return(-1); 501b2845e83SBill Paul } 502b2845e83SBill Paul clnt->cl_auth = authunix_create_default(); 503b2845e83SBill Paul cu = (struct cu_data *)clnt->cl_private; 504b2845e83SBill Paul tv.tv_sec = 0; 505b2845e83SBill Paul clnt_control(clnt, CLSET_TIMEOUT, &tv); 506b2845e83SBill Paul ioctl(sock, FIONBIO, &dontblock); 507b2845e83SBill Paul oldfunc = clnt->cl_ops->cl_call; 508b2845e83SBill Paul clnt->cl_ops->cl_call = clntudp_a_call; 509b2845e83SBill Paul 510b2845e83SBill Paul /* Transmit */ 511b2845e83SBill Paul for (i = 0; i < cnt; i++) { 512b2845e83SBill Paul if (reqs[i] != NULL) { 513b2845e83SBill Paul /* subtract one; clntudp_call() will increment */ 514b2845e83SBill Paul *((u_int32_t *)(cu->cu_outbuf)) = reqs[i]->xid - 1; 515b2845e83SBill Paul bcopy((char *)&reqs[i]->sin, (char *)&cu->cu_raddr, 516b2845e83SBill Paul sizeof(struct sockaddr_in)); 517b2845e83SBill Paul ypproc_domain_nonack_2_send(&foo, clnt); 518b2845e83SBill Paul } 519b2845e83SBill Paul } 520b2845e83SBill Paul 521b2845e83SBill Paul /* Receive reply */ 522b2845e83SBill Paul ypproc_domain_nonack_2_recv(&foo, clnt); 523b2845e83SBill Paul 524b2845e83SBill Paul /* Got a winner -- look him up. */ 525b2845e83SBill Paul xid_lookup = *((u_int32_t *)(cu->cu_inbuf)); 526b2845e83SBill Paul for (i = 0; i < cnt; i++) { 527b2845e83SBill Paul if (reqs[i] != NULL && reqs[i]->xid == xid_lookup) { 528b2845e83SBill Paul winner = i; 529b2845e83SBill Paul *port = reqs[i]->sin.sin_port; 530b2845e83SBill Paul } 531b2845e83SBill Paul } 532b2845e83SBill Paul 533b2845e83SBill Paul /* Shut everything down */ 534b2845e83SBill Paul clnt->cl_ops->cl_call = oldfunc; 535b2845e83SBill Paul auth_destroy(clnt->cl_auth); 536b2845e83SBill Paul clnt_destroy(clnt); 537b2845e83SBill Paul close(sock); 538b2845e83SBill Paul 539b2845e83SBill Paul for (i = 0; i < cnt; i++) 540b2845e83SBill Paul if (reqs[i] != NULL) 541b2845e83SBill Paul free(reqs[i]); 542b2845e83SBill Paul free(reqs); 543b2845e83SBill Paul 544b2845e83SBill Paul return(winner); 545b2845e83SBill Paul } 546