|
|
1.1 ! root 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: char *cp, *cplim; ! 188: int n, i = 0; ! 189: ! 190: ifc.ifc_len = MAX_BROADCAST_SIZE; ! 191: ifc.ifc_buf = buf; ! 192: if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { ! 193: perror("broadcast: ioctl (get interface configuration)"); ! 194: return (0); ! 195: } ! 196: #define max(a, b) (a > b ? a : b) ! 197: #define size(p) max((p).sa_len, sizeof(p)) ! 198: cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */ ! 199: for (cp = buf; cp < cplim; ! 200: cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) { ! 201: ifr = (struct ifreq *)cp; ! 202: if (ifr->ifr_addr.sa_family != AF_INET) ! 203: continue; ! 204: ifreq = *ifr; ! 205: if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq) < 0) { ! 206: perror("broadcast: ioctl (get interface flags)"); ! 207: continue; ! 208: } ! 209: if ((ifreq.ifr_flags & IFF_BROADCAST) && ! 210: (ifreq.ifr_flags & IFF_UP)) { ! 211: sin = (struct sockaddr_in *)&ifr->ifr_addr; ! 212: addrs[i++] = inet_makeaddr(inet_netof ! 213: (sin->sin_addr.s_addr), INADDR_ANY); ! 214: } ! 215: } ! 216: return (i); ! 217: } ! 218: ! 219: typedef bool_t (*resultproc_t)(); ! 220: ! 221: enum clnt_stat ! 222: clnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult) ! 223: u_long prog; /* program number */ ! 224: u_long vers; /* version number */ ! 225: u_long proc; /* procedure number */ ! 226: xdrproc_t xargs; /* xdr routine for args */ ! 227: caddr_t argsp; /* pointer to args */ ! 228: xdrproc_t xresults; /* xdr routine for results */ ! 229: caddr_t resultsp; /* pointer to results */ ! 230: resultproc_t eachresult; /* call with each result obtained */ ! 231: { ! 232: enum clnt_stat stat; ! 233: AUTH *unix_auth = authunix_create_default(); ! 234: XDR xdr_stream; ! 235: register XDR *xdrs = &xdr_stream; ! 236: int outlen, inlen, fromlen, readfds, nets; ! 237: register int sock, mask, i; ! 238: bool_t done = FALSE; ! 239: register u_long xid; ! 240: u_long port; ! 241: struct in_addr addrs[20]; ! 242: struct sockaddr_in baddr, raddr; /* broadcast and response addresses */ ! 243: struct rmtcallargs a; ! 244: struct rmtcallres r; ! 245: struct rpc_msg msg; ! 246: struct timeval t; ! 247: char outbuf[MAX_BROADCAST_SIZE], inbuf[MAX_BROADCAST_SIZE]; ! 248: ! 249: /* ! 250: * initialization: create a socket, a broadcast address, and ! 251: * preserialize the arguments into a send buffer. ! 252: */ ! 253: if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { ! 254: perror("Cannot create socket for broadcast rpc"); ! 255: stat = RPC_CANTSEND; ! 256: goto done_broad; ! 257: } ! 258: mask = (1 << sock); ! 259: nets = getbroadcastnets(addrs, sock, inbuf); ! 260: bzero(&baddr, sizeof (baddr)); ! 261: baddr.sin_family = AF_INET; ! 262: baddr.sin_port = htons(PMAPPORT); ! 263: baddr.sin_addr.s_addr = htonl(INADDR_ANY); ! 264: (void)gettimeofday(&t, (struct timezone *)0); ! 265: msg.rm_xid = xid = getpid() ^ t.tv_sec ^ t.tv_usec; ! 266: t.tv_usec = 0; ! 267: msg.rm_direction = CALL; ! 268: msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; ! 269: msg.rm_call.cb_prog = PMAPPROG; ! 270: msg.rm_call.cb_vers = PMAPVERS; ! 271: msg.rm_call.cb_proc = PMAPPROC_CALLIT; ! 272: msg.rm_call.cb_cred = unix_auth->ah_cred; ! 273: msg.rm_call.cb_verf = unix_auth->ah_verf; ! 274: a.prog = prog; ! 275: a.vers = vers; ! 276: a.proc = proc; ! 277: a.xdr_args = xargs; ! 278: a.args_ptr = argsp; ! 279: r.port_ptr = &port; ! 280: r.xdr_results = xresults; ! 281: r.results_ptr = resultsp; ! 282: xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE); ! 283: if ((! xdr_callmsg(xdrs, &msg)) || (! xdr_rmtcall_args(xdrs, &a))) { ! 284: stat = RPC_CANTENCODEARGS; ! 285: goto done_broad; ! 286: } ! 287: outlen = (int)xdr_getpos(xdrs); ! 288: xdr_destroy(xdrs); ! 289: /* ! 290: * Basic loop: broadcast a packet and wait a while for response(s). ! 291: * The response timeout grows larger per iteration. ! 292: */ ! 293: for (t.tv_sec = 2; t.tv_sec <= 6; t.tv_sec += 2) { ! 294: for (i = 0; i < nets; i++) { ! 295: baddr.sin_addr = addrs[i]; ! 296: if (sendto(sock, outbuf, outlen, 0, ! 297: (struct socketaddr *)&baddr, ! 298: sizeof (struct sockaddr)) != outlen) { ! 299: perror("Cannot send broadcast packet"); ! 300: stat = RPC_CANTSEND; ! 301: goto done_broad; ! 302: } ! 303: } ! 304: recv_again: ! 305: msg.acpted_rply.ar_verf = _null_auth; ! 306: msg.acpted_rply.ar_results.where = (caddr_t)&r; ! 307: msg.acpted_rply.ar_results.proc = xdr_rmtcallres; ! 308: readfds = mask; ! 309: switch (select(32, &readfds, (int *)NULL, (int *)NULL, &t)) { ! 310: ! 311: case 0: /* timed out */ ! 312: stat = RPC_TIMEDOUT; ! 313: continue; ! 314: ! 315: case -1: /* some kind of error */ ! 316: if (errno == EINTR) ! 317: goto recv_again; ! 318: perror("Broadcast select problem"); ! 319: stat = RPC_CANTRECV; ! 320: goto done_broad; ! 321: ! 322: } /* end of select results switch */ ! 323: if ((readfds & mask) == 0) ! 324: goto recv_again; ! 325: try_again: ! 326: fromlen = sizeof(struct sockaddr); ! 327: inlen = recvfrom(sock, inbuf, MAX_BROADCAST_SIZE, 0, ! 328: (struct sockaddr *)&raddr, &fromlen); ! 329: if (inlen < 0) { ! 330: if (errno == EINTR) ! 331: goto try_again; ! 332: perror("Cannot receive reply to broadcast"); ! 333: stat = RPC_CANTRECV; ! 334: goto done_broad; ! 335: } ! 336: if (inlen < sizeof(u_long)) ! 337: goto recv_again; ! 338: /* ! 339: * see if reply transaction id matches sent id. ! 340: * If so, decode the results. ! 341: */ ! 342: xdrmem_create(xdrs, inbuf, inlen, XDR_DECODE); ! 343: if (xdr_replymsg(xdrs, &msg)) { ! 344: if ((msg.rm_xid == xid) && ! 345: (msg.rm_reply.rp_stat == MSG_ACCEPTED) && ! 346: (msg.acpted_rply.ar_stat == SUCCESS)) { ! 347: raddr.sin_port = htons((u_short)port); ! 348: done = (*eachresult)(resultsp, &raddr); ! 349: } ! 350: /* otherwise, we just ignore the errors ... */ ! 351: } else { ! 352: /* some kind of deserialization problem ... */ ! 353: if (msg.rm_xid == xid) ! 354: fprintf(stderr, "Broadcast deserialization problem"); ! 355: /* otherwise, just random garbage */ ! 356: } ! 357: xdrs->x_op = XDR_FREE; ! 358: msg.acpted_rply.ar_results.proc = xdr_void; ! 359: (void)xdr_replymsg(xdrs, &msg); ! 360: (void)(*xresults)(xdrs, resultsp); ! 361: xdr_destroy(xdrs); ! 362: if (done) { ! 363: stat = RPC_SUCCESS; ! 364: goto done_broad; ! 365: } else { ! 366: goto recv_again; ! 367: } ! 368: } ! 369: done_broad: ! 370: (void)close(sock); ! 371: AUTH_DESTROY(unix_auth); ! 372: return (stat); ! 373: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.