1*45129Smckusick /* @(#)pmap_rmt.c 2.2 88/08/01 4.0 RPCSRC */ 2*45129Smckusick /* 3*45129Smckusick * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 4*45129Smckusick * unrestricted use provided that this legend is included on all tape 5*45129Smckusick * media and as a part of the software program in whole or part. Users 6*45129Smckusick * may copy or modify Sun RPC without charge, but are not authorized 7*45129Smckusick * to license or distribute it to anyone else except as part of a product or 8*45129Smckusick * program developed by the user. 9*45129Smckusick * 10*45129Smckusick * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 11*45129Smckusick * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 12*45129Smckusick * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 13*45129Smckusick * 14*45129Smckusick * Sun RPC is provided with no support and without any obligation on the 15*45129Smckusick * part of Sun Microsystems, Inc. to assist in its use, correction, 16*45129Smckusick * modification or enhancement. 17*45129Smckusick * 18*45129Smckusick * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 19*45129Smckusick * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 20*45129Smckusick * OR ANY PART THEREOF. 21*45129Smckusick * 22*45129Smckusick * In no event will Sun Microsystems, Inc. be liable for any lost revenue 23*45129Smckusick * or profits or other special, indirect and consequential damages, even if 24*45129Smckusick * Sun has been advised of the possibility of such damages. 25*45129Smckusick * 26*45129Smckusick * Sun Microsystems, Inc. 27*45129Smckusick * 2550 Garcia Avenue 28*45129Smckusick * Mountain View, California 94043 29*45129Smckusick */ 30*45129Smckusick #if !defined(lint) && defined(SCCSIDS) 31*45129Smckusick static char sccsid[] = "@(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro"; 32*45129Smckusick #endif 33*45129Smckusick 34*45129Smckusick /* 35*45129Smckusick * pmap_rmt.c 36*45129Smckusick * Client interface to pmap rpc service. 37*45129Smckusick * remote call and broadcast service 38*45129Smckusick * 39*45129Smckusick * Copyright (C) 1984, Sun Microsystems, Inc. 40*45129Smckusick */ 41*45129Smckusick 42*45129Smckusick #include <rpc/rpc.h> 43*45129Smckusick #include <rpc/pmap_prot.h> 44*45129Smckusick #include <rpc/pmap_clnt.h> 45*45129Smckusick #include <rpc/pmap_rmt.h> 46*45129Smckusick #include <sys/socket.h> 47*45129Smckusick #include <stdio.h> 48*45129Smckusick #include <errno.h> 49*45129Smckusick #include <net/if.h> 50*45129Smckusick #include <sys/ioctl.h> 51*45129Smckusick #include <arpa/inet.h> 52*45129Smckusick #define MAX_BROADCAST_SIZE 1400 53*45129Smckusick 54*45129Smckusick extern int errno; 55*45129Smckusick static struct timeval timeout = { 3, 0 }; 56*45129Smckusick 57*45129Smckusick 58*45129Smckusick /* 59*45129Smckusick * pmapper remote-call-service interface. 60*45129Smckusick * This routine is used to call the pmapper remote call service 61*45129Smckusick * which will look up a service program in the port maps, and then 62*45129Smckusick * remotely call that routine with the given parameters. This allows 63*45129Smckusick * programs to do a lookup and call in one step. 64*45129Smckusick */ 65*45129Smckusick enum clnt_stat 66*45129Smckusick pmap_rmtcall(addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout, port_ptr) 67*45129Smckusick struct sockaddr_in *addr; 68*45129Smckusick u_long prog, vers, proc; 69*45129Smckusick xdrproc_t xdrargs, xdrres; 70*45129Smckusick caddr_t argsp, resp; 71*45129Smckusick struct timeval tout; 72*45129Smckusick u_long *port_ptr; 73*45129Smckusick { 74*45129Smckusick int socket = -1; 75*45129Smckusick register CLIENT *client; 76*45129Smckusick struct rmtcallargs a; 77*45129Smckusick struct rmtcallres r; 78*45129Smckusick enum clnt_stat stat; 79*45129Smckusick 80*45129Smckusick addr->sin_port = htons(PMAPPORT); 81*45129Smckusick client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &socket); 82*45129Smckusick if (client != (CLIENT *)NULL) { 83*45129Smckusick a.prog = prog; 84*45129Smckusick a.vers = vers; 85*45129Smckusick a.proc = proc; 86*45129Smckusick a.args_ptr = argsp; 87*45129Smckusick a.xdr_args = xdrargs; 88*45129Smckusick r.port_ptr = port_ptr; 89*45129Smckusick r.results_ptr = resp; 90*45129Smckusick r.xdr_results = xdrres; 91*45129Smckusick stat = CLNT_CALL(client, PMAPPROC_CALLIT, xdr_rmtcall_args, &a, 92*45129Smckusick xdr_rmtcallres, &r, tout); 93*45129Smckusick CLNT_DESTROY(client); 94*45129Smckusick } else { 95*45129Smckusick stat = RPC_FAILED; 96*45129Smckusick } 97*45129Smckusick (void)close(socket); 98*45129Smckusick addr->sin_port = 0; 99*45129Smckusick return (stat); 100*45129Smckusick } 101*45129Smckusick 102*45129Smckusick 103*45129Smckusick /* 104*45129Smckusick * XDR remote call arguments 105*45129Smckusick * written for XDR_ENCODE direction only 106*45129Smckusick */ 107*45129Smckusick bool_t 108*45129Smckusick xdr_rmtcall_args(xdrs, cap) 109*45129Smckusick register XDR *xdrs; 110*45129Smckusick register struct rmtcallargs *cap; 111*45129Smckusick { 112*45129Smckusick u_int lenposition, argposition, position; 113*45129Smckusick 114*45129Smckusick if (xdr_u_long(xdrs, &(cap->prog)) && 115*45129Smckusick xdr_u_long(xdrs, &(cap->vers)) && 116*45129Smckusick xdr_u_long(xdrs, &(cap->proc))) { 117*45129Smckusick lenposition = XDR_GETPOS(xdrs); 118*45129Smckusick if (! xdr_u_long(xdrs, &(cap->arglen))) 119*45129Smckusick return (FALSE); 120*45129Smckusick argposition = XDR_GETPOS(xdrs); 121*45129Smckusick if (! (*(cap->xdr_args))(xdrs, cap->args_ptr)) 122*45129Smckusick return (FALSE); 123*45129Smckusick position = XDR_GETPOS(xdrs); 124*45129Smckusick cap->arglen = (u_long)position - (u_long)argposition; 125*45129Smckusick XDR_SETPOS(xdrs, lenposition); 126*45129Smckusick if (! xdr_u_long(xdrs, &(cap->arglen))) 127*45129Smckusick return (FALSE); 128*45129Smckusick XDR_SETPOS(xdrs, position); 129*45129Smckusick return (TRUE); 130*45129Smckusick } 131*45129Smckusick return (FALSE); 132*45129Smckusick } 133*45129Smckusick 134*45129Smckusick /* 135*45129Smckusick * XDR remote call results 136*45129Smckusick * written for XDR_DECODE direction only 137*45129Smckusick */ 138*45129Smckusick bool_t 139*45129Smckusick xdr_rmtcallres(xdrs, crp) 140*45129Smckusick register XDR *xdrs; 141*45129Smckusick register struct rmtcallres *crp; 142*45129Smckusick { 143*45129Smckusick caddr_t port_ptr; 144*45129Smckusick 145*45129Smckusick port_ptr = (caddr_t)crp->port_ptr; 146*45129Smckusick if (xdr_reference(xdrs, &port_ptr, sizeof (u_long), 147*45129Smckusick xdr_u_long) && xdr_u_long(xdrs, &crp->resultslen)) { 148*45129Smckusick crp->port_ptr = (u_long *)port_ptr; 149*45129Smckusick return ((*(crp->xdr_results))(xdrs, crp->results_ptr)); 150*45129Smckusick } 151*45129Smckusick return (FALSE); 152*45129Smckusick } 153*45129Smckusick 154*45129Smckusick 155*45129Smckusick /* 156*45129Smckusick * The following is kludged-up support for simple rpc broadcasts. 157*45129Smckusick * Someday a large, complicated system will replace these trivial 158*45129Smckusick * routines which only support udp/ip . 159*45129Smckusick */ 160*45129Smckusick 161*45129Smckusick static int 162*45129Smckusick getbroadcastnets(addrs, sock, buf) 163*45129Smckusick struct in_addr *addrs; 164*45129Smckusick int sock; /* any valid socket will do */ 165*45129Smckusick char *buf; /* why allocxate more when we can use existing... */ 166*45129Smckusick { 167*45129Smckusick struct ifconf ifc; 168*45129Smckusick struct ifreq ifreq, *ifr; 169*45129Smckusick struct sockaddr_in *sin; 170*45129Smckusick int n, i; 171*45129Smckusick 172*45129Smckusick ifc.ifc_len = UDPMSGSIZE; 173*45129Smckusick ifc.ifc_buf = buf; 174*45129Smckusick if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { 175*45129Smckusick perror("broadcast: ioctl (get interface configuration)"); 176*45129Smckusick return (0); 177*45129Smckusick } 178*45129Smckusick ifr = ifc.ifc_req; 179*45129Smckusick for (i = 0, n = ifc.ifc_len/sizeof (struct ifreq); n > 0; n--, ifr++) { 180*45129Smckusick ifreq = *ifr; 181*45129Smckusick if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq) < 0) { 182*45129Smckusick perror("broadcast: ioctl (get interface flags)"); 183*45129Smckusick continue; 184*45129Smckusick } 185*45129Smckusick if ((ifreq.ifr_flags & IFF_BROADCAST) && 186*45129Smckusick (ifreq.ifr_flags & IFF_UP) && 187*45129Smckusick ifr->ifr_addr.sa_family == AF_INET) { 188*45129Smckusick sin = (struct sockaddr_in *)&ifr->ifr_addr; 189*45129Smckusick #ifdef SIOCGIFBRDADDR /* 4.3BSD */ 190*45129Smckusick if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { 191*45129Smckusick addrs[i++] = inet_makeaddr(inet_netof 192*45129Smckusick (sin->sin_addr.s_addr), INADDR_ANY); 193*45129Smckusick } else { 194*45129Smckusick addrs[i++] = ((struct sockaddr_in*) 195*45129Smckusick &ifreq.ifr_addr)->sin_addr; 196*45129Smckusick } 197*45129Smckusick #else /* 4.2 BSD */ 198*45129Smckusick addrs[i++] = inet_makeaddr(inet_netof 199*45129Smckusick (sin->sin_addr.s_addr), INADDR_ANY); 200*45129Smckusick #endif 201*45129Smckusick } 202*45129Smckusick } 203*45129Smckusick return (i); 204*45129Smckusick } 205*45129Smckusick 206*45129Smckusick typedef bool_t (*resultproc_t)(); 207*45129Smckusick 208*45129Smckusick enum clnt_stat 209*45129Smckusick clnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult) 210*45129Smckusick u_long prog; /* program number */ 211*45129Smckusick u_long vers; /* version number */ 212*45129Smckusick u_long proc; /* procedure number */ 213*45129Smckusick xdrproc_t xargs; /* xdr routine for args */ 214*45129Smckusick caddr_t argsp; /* pointer to args */ 215*45129Smckusick xdrproc_t xresults; /* xdr routine for results */ 216*45129Smckusick caddr_t resultsp; /* pointer to results */ 217*45129Smckusick resultproc_t eachresult; /* call with each result obtained */ 218*45129Smckusick { 219*45129Smckusick enum clnt_stat stat; 220*45129Smckusick AUTH *unix_auth = authunix_create_default(); 221*45129Smckusick XDR xdr_stream; 222*45129Smckusick register XDR *xdrs = &xdr_stream; 223*45129Smckusick int outlen, inlen, fromlen, nets; 224*45129Smckusick register int sock; 225*45129Smckusick int on = 1; 226*45129Smckusick #ifdef FD_SETSIZE 227*45129Smckusick fd_set mask; 228*45129Smckusick fd_set readfds; 229*45129Smckusick #else 230*45129Smckusick int readfds; 231*45129Smckusick register int mask; 232*45129Smckusick #endif /* def FD_SETSIZE */ 233*45129Smckusick register int i; 234*45129Smckusick bool_t done = FALSE; 235*45129Smckusick register u_long xid; 236*45129Smckusick u_long port; 237*45129Smckusick struct in_addr addrs[20]; 238*45129Smckusick struct sockaddr_in baddr, raddr; /* broadcast and response addresses */ 239*45129Smckusick struct rmtcallargs a; 240*45129Smckusick struct rmtcallres r; 241*45129Smckusick struct rpc_msg msg; 242*45129Smckusick struct timeval t; 243*45129Smckusick char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE]; 244*45129Smckusick 245*45129Smckusick /* 246*45129Smckusick * initialization: create a socket, a broadcast address, and 247*45129Smckusick * preserialize the arguments into a send buffer. 248*45129Smckusick */ 249*45129Smckusick if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 250*45129Smckusick perror("Cannot create socket for broadcast rpc"); 251*45129Smckusick stat = RPC_CANTSEND; 252*45129Smckusick goto done_broad; 253*45129Smckusick } 254*45129Smckusick #ifdef SO_BROADCAST 255*45129Smckusick if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) { 256*45129Smckusick perror("Cannot set socket option SO_BROADCAST"); 257*45129Smckusick stat = RPC_CANTSEND; 258*45129Smckusick goto done_broad; 259*45129Smckusick } 260*45129Smckusick #endif /* def SO_BROADCAST */ 261*45129Smckusick #ifdef FD_SETSIZE 262*45129Smckusick FD_ZERO(&mask); 263*45129Smckusick FD_SET(sock, &mask); 264*45129Smckusick #else 265*45129Smckusick mask = (1 << sock); 266*45129Smckusick #endif /* def FD_SETSIZE */ 267*45129Smckusick nets = getbroadcastnets(addrs, sock, inbuf); 268*45129Smckusick bzero((char *)&baddr, sizeof (baddr)); 269*45129Smckusick baddr.sin_family = AF_INET; 270*45129Smckusick baddr.sin_port = htons(PMAPPORT); 271*45129Smckusick baddr.sin_addr.s_addr = htonl(INADDR_ANY); 272*45129Smckusick /* baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */ 273*45129Smckusick (void)gettimeofday(&t, (struct timezone *)0); 274*45129Smckusick msg.rm_xid = xid = getpid() ^ t.tv_sec ^ t.tv_usec; 275*45129Smckusick t.tv_usec = 0; 276*45129Smckusick msg.rm_direction = CALL; 277*45129Smckusick msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 278*45129Smckusick msg.rm_call.cb_prog = PMAPPROG; 279*45129Smckusick msg.rm_call.cb_vers = PMAPVERS; 280*45129Smckusick msg.rm_call.cb_proc = PMAPPROC_CALLIT; 281*45129Smckusick msg.rm_call.cb_cred = unix_auth->ah_cred; 282*45129Smckusick msg.rm_call.cb_verf = unix_auth->ah_verf; 283*45129Smckusick a.prog = prog; 284*45129Smckusick a.vers = vers; 285*45129Smckusick a.proc = proc; 286*45129Smckusick a.xdr_args = xargs; 287*45129Smckusick a.args_ptr = argsp; 288*45129Smckusick r.port_ptr = &port; 289*45129Smckusick r.xdr_results = xresults; 290*45129Smckusick r.results_ptr = resultsp; 291*45129Smckusick xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE); 292*45129Smckusick if ((! xdr_callmsg(xdrs, &msg)) || (! xdr_rmtcall_args(xdrs, &a))) { 293*45129Smckusick stat = RPC_CANTENCODEARGS; 294*45129Smckusick goto done_broad; 295*45129Smckusick } 296*45129Smckusick outlen = (int)xdr_getpos(xdrs); 297*45129Smckusick xdr_destroy(xdrs); 298*45129Smckusick /* 299*45129Smckusick * Basic loop: broadcast a packet and wait a while for response(s). 300*45129Smckusick * The response timeout grows larger per iteration. 301*45129Smckusick */ 302*45129Smckusick for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2) { 303*45129Smckusick for (i = 0; i < nets; i++) { 304*45129Smckusick baddr.sin_addr = addrs[i]; 305*45129Smckusick if (sendto(sock, outbuf, outlen, 0, 306*45129Smckusick (struct sockaddr *)&baddr, 307*45129Smckusick sizeof (struct sockaddr)) != outlen) { 308*45129Smckusick perror("Cannot send broadcast packet"); 309*45129Smckusick stat = RPC_CANTSEND; 310*45129Smckusick goto done_broad; 311*45129Smckusick } 312*45129Smckusick } 313*45129Smckusick if (eachresult == NULL) { 314*45129Smckusick stat = RPC_SUCCESS; 315*45129Smckusick goto done_broad; 316*45129Smckusick } 317*45129Smckusick recv_again: 318*45129Smckusick msg.acpted_rply.ar_verf = _null_auth; 319*45129Smckusick msg.acpted_rply.ar_results.where = (caddr_t)&r; 320*45129Smckusick msg.acpted_rply.ar_results.proc = xdr_rmtcallres; 321*45129Smckusick readfds = mask; 322*45129Smckusick switch (select(_rpc_dtablesize(), &readfds, (int *)NULL, 323*45129Smckusick (int *)NULL, &t)) { 324*45129Smckusick 325*45129Smckusick case 0: /* timed out */ 326*45129Smckusick stat = RPC_TIMEDOUT; 327*45129Smckusick continue; 328*45129Smckusick 329*45129Smckusick case -1: /* some kind of error */ 330*45129Smckusick if (errno == EINTR) 331*45129Smckusick goto recv_again; 332*45129Smckusick perror("Broadcast select problem"); 333*45129Smckusick stat = RPC_CANTRECV; 334*45129Smckusick goto done_broad; 335*45129Smckusick 336*45129Smckusick } /* end of select results switch */ 337*45129Smckusick try_again: 338*45129Smckusick fromlen = sizeof(struct sockaddr); 339*45129Smckusick inlen = recvfrom(sock, inbuf, UDPMSGSIZE, 0, 340*45129Smckusick (struct sockaddr *)&raddr, &fromlen); 341*45129Smckusick if (inlen < 0) { 342*45129Smckusick if (errno == EINTR) 343*45129Smckusick goto try_again; 344*45129Smckusick perror("Cannot receive reply to broadcast"); 345*45129Smckusick stat = RPC_CANTRECV; 346*45129Smckusick goto done_broad; 347*45129Smckusick } 348*45129Smckusick if (inlen < sizeof(u_long)) 349*45129Smckusick goto recv_again; 350*45129Smckusick /* 351*45129Smckusick * see if reply transaction id matches sent id. 352*45129Smckusick * If so, decode the results. 353*45129Smckusick */ 354*45129Smckusick xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE); 355*45129Smckusick if (xdr_replymsg(xdrs, &msg)) { 356*45129Smckusick if ((msg.rm_xid == xid) && 357*45129Smckusick (msg.rm_reply.rp_stat == MSG_ACCEPTED) && 358*45129Smckusick (msg.acpted_rply.ar_stat == SUCCESS)) { 359*45129Smckusick raddr.sin_port = htons((u_short)port); 360*45129Smckusick done = (*eachresult)(resultsp, &raddr); 361*45129Smckusick } 362*45129Smckusick /* otherwise, we just ignore the errors ... */ 363*45129Smckusick } else { 364*45129Smckusick #ifdef notdef 365*45129Smckusick /* some kind of deserialization problem ... */ 366*45129Smckusick if (msg.rm_xid == xid) 367*45129Smckusick fprintf(stderr, "Broadcast deserialization problem"); 368*45129Smckusick /* otherwise, just random garbage */ 369*45129Smckusick #endif 370*45129Smckusick } 371*45129Smckusick xdrs->x_op = XDR_FREE; 372*45129Smckusick msg.acpted_rply.ar_results.proc = xdr_void; 373*45129Smckusick (void)xdr_replymsg(xdrs, &msg); 374*45129Smckusick (void)(*xresults)(xdrs, resultsp); 375*45129Smckusick xdr_destroy(xdrs); 376*45129Smckusick if (done) { 377*45129Smckusick stat = RPC_SUCCESS; 378*45129Smckusick goto done_broad; 379*45129Smckusick } else { 380*45129Smckusick goto recv_again; 381*45129Smckusick } 382*45129Smckusick } 383*45129Smckusick done_broad: 384*45129Smckusick (void)close(sock); 385*45129Smckusick AUTH_DESTROY(unix_auth); 386*45129Smckusick return (stat); 387*45129Smckusick } 388*45129Smckusick 389