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