home *** CD-ROM | disk | FTP | other *** search
/ Serving the Web / ServingTheWeb1995.disc1of1.iso / linux / slacksrce / d / libc / libc-4.6 / libc-4 / libc-linux / rpc / pmap_rmt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-01  |  13.1 KB  |  493 lines

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