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