Back to index

glibc  2.9
pmap_rmt.c
Go to the documentation of this file.
00001 /* @(#)pmap_rmt.c    2.2 88/08/01 4.0 RPCSRC */
00002 /*
00003  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
00004  * unrestricted use provided that this legend is included on all tape
00005  * media and as a part of the software program in whole or part.  Users
00006  * may copy or modify Sun RPC without charge, but are not authorized
00007  * to license or distribute it to anyone else except as part of a product or
00008  * program developed by the user.
00009  *
00010  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
00011  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
00012  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
00013  *
00014  * Sun RPC is provided with no support and without any obligation on the
00015  * part of Sun Microsystems, Inc. to assist in its use, correction,
00016  * modification or enhancement.
00017  *
00018  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
00019  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
00020  * OR ANY PART THEREOF.
00021  *
00022  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
00023  * or profits or other special, indirect and consequential damages, even if
00024  * Sun has been advised of the possibility of such damages.
00025  *
00026  * Sun Microsystems, Inc.
00027  * 2550 Garcia Avenue
00028  * Mountain View, California  94043
00029  */
00030 #if !defined(lint) && defined(SCCSIDS)
00031 static char sccsid[] = "@(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro";
00032 #endif
00033 
00034 /*
00035  * pmap_rmt.c
00036  * Client interface to pmap rpc service.
00037  * remote call and broadcast service
00038  *
00039  * Copyright (C) 1984, Sun Microsystems, Inc.
00040  */
00041 
00042 #include <unistd.h>
00043 #include <string.h>
00044 #include <libintl.h>
00045 #include <rpc/rpc.h>
00046 #include <rpc/pmap_prot.h>
00047 #include <rpc/pmap_clnt.h>
00048 #include <rpc/pmap_rmt.h>
00049 #include <sys/poll.h>
00050 #include <sys/socket.h>
00051 #include <stdio.h>
00052 #include <errno.h>
00053 #undef  _POSIX_SOURCE              /* Ultrix <sys/param.h> needs --roland@gnu */
00054 #include <sys/param.h>             /* Ultrix needs before net/if --roland@gnu */
00055 #include <net/if.h>
00056 #include <ifaddrs.h>
00057 #include <sys/ioctl.h>
00058 #include <arpa/inet.h>
00059 #define MAX_BROADCAST_SIZE 1400
00060 
00061 extern u_long _create_xid (void);
00062 
00063 static const struct timeval timeout = {3, 0};
00064 
00065 /*
00066  * pmapper remote-call-service interface.
00067  * This routine is used to call the pmapper remote call service
00068  * which will look up a service program in the port maps, and then
00069  * remotely call that routine with the given parameters.  This allows
00070  * programs to do a lookup and call in one step.
00071  */
00072 enum clnt_stat
00073 pmap_rmtcall (addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout, port_ptr)
00074      struct sockaddr_in *addr;
00075      u_long prog, vers, proc;
00076      xdrproc_t xdrargs, xdrres;
00077      caddr_t argsp, resp;
00078      struct timeval tout;
00079      u_long *port_ptr;
00080 {
00081   int socket = -1;
00082   CLIENT *client;
00083   struct rmtcallargs a;
00084   struct rmtcallres r;
00085   enum clnt_stat stat;
00086 
00087   addr->sin_port = htons (PMAPPORT);
00088   client = INTUSE(clntudp_create) (addr, PMAPPROG, PMAPVERS, timeout, &socket);
00089   if (client != (CLIENT *) NULL)
00090     {
00091       a.prog = prog;
00092       a.vers = vers;
00093       a.proc = proc;
00094       a.args_ptr = argsp;
00095       a.xdr_args = xdrargs;
00096       r.port_ptr = port_ptr;
00097       r.results_ptr = resp;
00098       r.xdr_results = xdrres;
00099       stat = CLNT_CALL (client, PMAPPROC_CALLIT,
00100                      (xdrproc_t)INTUSE(xdr_rmtcall_args),
00101                      (caddr_t)&a, (xdrproc_t)INTUSE(xdr_rmtcallres),
00102                      (caddr_t)&r, tout);
00103       CLNT_DESTROY (client);
00104     }
00105   else
00106     {
00107       stat = RPC_FAILED;
00108     }
00109   /* (void)__close(socket); CLNT_DESTROY already closed it */
00110   addr->sin_port = 0;
00111   return stat;
00112 }
00113 
00114 
00115 /*
00116  * XDR remote call arguments
00117  * written for XDR_ENCODE direction only
00118  */
00119 bool_t
00120 xdr_rmtcall_args (XDR *xdrs, struct rmtcallargs *cap)
00121 {
00122   u_int lenposition, argposition, position;
00123 
00124   if (INTUSE(xdr_u_long) (xdrs, &(cap->prog)) &&
00125       INTUSE(xdr_u_long) (xdrs, &(cap->vers)) &&
00126       INTUSE(xdr_u_long) (xdrs, &(cap->proc)))
00127     {
00128       u_long dummy_arglen = 0;
00129       lenposition = XDR_GETPOS (xdrs);
00130       if (!INTUSE(xdr_u_long) (xdrs, &dummy_arglen))
00131        return FALSE;
00132       argposition = XDR_GETPOS (xdrs);
00133       if (!(*(cap->xdr_args)) (xdrs, cap->args_ptr))
00134        return FALSE;
00135       position = XDR_GETPOS (xdrs);
00136       cap->arglen = (u_long) position - (u_long) argposition;
00137       XDR_SETPOS (xdrs, lenposition);
00138       if (!INTUSE(xdr_u_long) (xdrs, &(cap->arglen)))
00139        return FALSE;
00140       XDR_SETPOS (xdrs, position);
00141       return TRUE;
00142     }
00143   return FALSE;
00144 }
00145 INTDEF(xdr_rmtcall_args)
00146 
00147 /*
00148  * XDR remote call results
00149  * written for XDR_DECODE direction only
00150  */
00151 bool_t
00152 xdr_rmtcallres (xdrs, crp)
00153      XDR *xdrs;
00154      struct rmtcallres *crp;
00155 {
00156   caddr_t port_ptr;
00157 
00158   port_ptr = (caddr_t) crp->port_ptr;
00159   if (INTUSE(xdr_reference) (xdrs, &port_ptr, sizeof (u_long),
00160                           (xdrproc_t) INTUSE(xdr_u_long))
00161       && INTUSE(xdr_u_long) (xdrs, &crp->resultslen))
00162     {
00163       crp->port_ptr = (u_long *) port_ptr;
00164       return (*(crp->xdr_results)) (xdrs, crp->results_ptr);
00165     }
00166   return FALSE;
00167 }
00168 INTDEF(xdr_rmtcallres)
00169 
00170 
00171 /*
00172  * The following is kludged-up support for simple rpc broadcasts.
00173  * Someday a large, complicated system will replace these trivial
00174  * routines which only support udp/ip .
00175  */
00176 
00177 static int
00178 internal_function
00179 getbroadcastnets (struct in_addr *addrs, int naddrs)
00180 {
00181   struct ifaddrs *ifa;
00182 
00183   if (getifaddrs (&ifa) != 0)
00184     {
00185       perror ("broadcast: getifaddrs");
00186       return 0;
00187     }
00188 
00189   int i = 0;
00190   struct ifaddrs *run = ifa;
00191   while (run != NULL && i < naddrs)
00192     {
00193       if ((run->ifa_flags & IFF_BROADCAST) != 0
00194          && (run->ifa_flags & IFF_UP) != 0
00195          && run->ifa_addr != NULL
00196          && run->ifa_addr->sa_family == AF_INET)
00197        /* Copy the broadcast address.  */
00198        addrs[i++] = ((struct sockaddr_in *) run->ifa_broadaddr)->sin_addr;
00199 
00200       run = run->ifa_next;
00201     }
00202 
00203   freeifaddrs (ifa);
00204 
00205   return i;
00206 }
00207 
00208 
00209 enum clnt_stat
00210 clnt_broadcast (prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult)
00211      u_long prog;           /* program number */
00212      u_long vers;           /* version number */
00213      u_long proc;           /* procedure number */
00214      xdrproc_t xargs;              /* xdr routine for args */
00215      caddr_t argsp;         /* pointer to args */
00216      xdrproc_t xresults;    /* xdr routine for results */
00217      caddr_t resultsp;             /* pointer to results */
00218      resultproc_t eachresult;      /* call with each result obtained */
00219 {
00220   enum clnt_stat stat = RPC_FAILED;
00221   AUTH *unix_auth = INTUSE(authunix_create_default) ();
00222   XDR xdr_stream;
00223   XDR *xdrs = &xdr_stream;
00224   struct timeval t;
00225   int outlen, inlen, nets;
00226   socklen_t fromlen;
00227   int sock;
00228   int on = 1;
00229   struct pollfd fd;
00230   int milliseconds;
00231   int i;
00232   bool_t done = FALSE;
00233   u_long xid;
00234   u_long port;
00235   struct in_addr addrs[20];
00236   struct sockaddr_in baddr, raddr; /* broadcast and response addresses */
00237   struct rmtcallargs a;
00238   struct rmtcallres r;
00239   struct rpc_msg msg;
00240   char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE];
00241 
00242   /*
00243    * initialization: create a socket, a broadcast address, and
00244    * preserialize the arguments into a send buffer.
00245    */
00246   if ((sock = __socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
00247     {
00248       perror (_("Cannot create socket for broadcast rpc"));
00249       stat = RPC_CANTSEND;
00250       goto done_broad;
00251     }
00252 #ifdef SO_BROADCAST
00253   if (__setsockopt (sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0)
00254     {
00255       perror (_("Cannot set socket option SO_BROADCAST"));
00256       stat = RPC_CANTSEND;
00257       goto done_broad;
00258     }
00259 #endif /* def SO_BROADCAST */
00260   fd.fd = sock;
00261   fd.events = POLLIN;
00262   nets = getbroadcastnets (addrs, sizeof (addrs) / sizeof (addrs[0]));
00263   __bzero ((char *) &baddr, sizeof (baddr));
00264   baddr.sin_family = AF_INET;
00265   baddr.sin_port = htons (PMAPPORT);
00266   baddr.sin_addr.s_addr = htonl (INADDR_ANY);
00267 /*      baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */
00268   msg.rm_xid = xid = _create_xid ();
00269   t.tv_usec = 0;
00270   msg.rm_direction = CALL;
00271   msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
00272   msg.rm_call.cb_prog = PMAPPROG;
00273   msg.rm_call.cb_vers = PMAPVERS;
00274   msg.rm_call.cb_proc = PMAPPROC_CALLIT;
00275   msg.rm_call.cb_cred = unix_auth->ah_cred;
00276   msg.rm_call.cb_verf = unix_auth->ah_verf;
00277   a.prog = prog;
00278   a.vers = vers;
00279   a.proc = proc;
00280   a.xdr_args = xargs;
00281   a.args_ptr = argsp;
00282   r.port_ptr = &port;
00283   r.xdr_results = xresults;
00284   r.results_ptr = resultsp;
00285   INTUSE(xdrmem_create) (xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE);
00286   if ((!INTUSE(xdr_callmsg) (xdrs, &msg))
00287       || (!INTUSE(xdr_rmtcall_args) (xdrs, &a)))
00288     {
00289       stat = RPC_CANTENCODEARGS;
00290       goto done_broad;
00291     }
00292   outlen = (int) xdr_getpos (xdrs);
00293   xdr_destroy (xdrs);
00294   /*
00295    * Basic loop: broadcast a packet and wait a while for response(s).
00296    * The response timeout grows larger per iteration.
00297    */
00298   for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2)
00299     {
00300       for (i = 0; i < nets; i++)
00301        {
00302          baddr.sin_addr = addrs[i];
00303          if (__sendto (sock, outbuf, outlen, 0,
00304                      (struct sockaddr *) &baddr,
00305                      sizeof (struct sockaddr)) != outlen)
00306            {
00307              perror (_("Cannot send broadcast packet"));
00308              stat = RPC_CANTSEND;
00309              goto done_broad;
00310            }
00311        }
00312       if (eachresult == NULL)
00313        {
00314          stat = RPC_SUCCESS;
00315          goto done_broad;
00316        }
00317     recv_again:
00318       msg.acpted_rply.ar_verf = _null_auth;
00319       msg.acpted_rply.ar_results.where = (caddr_t) & r;
00320       msg.acpted_rply.ar_results.proc = (xdrproc_t) INTUSE(xdr_rmtcallres);
00321       milliseconds = t.tv_sec * 1000 + t.tv_usec / 1000;
00322       switch (__poll(&fd, 1, milliseconds))
00323        {
00324 
00325        case 0:              /* timed out */
00326          stat = RPC_TIMEDOUT;
00327          continue;
00328 
00329        case -1:             /* some kind of error */
00330          if (errno == EINTR)
00331            goto recv_again;
00332          perror (_("Broadcast poll problem"));
00333          stat = RPC_CANTRECV;
00334          goto done_broad;
00335 
00336        }                    /* end of poll results switch */
00337     try_again:
00338       fromlen = sizeof (struct sockaddr);
00339       inlen = __recvfrom (sock, inbuf, UDPMSGSIZE, 0,
00340                        (struct sockaddr *) &raddr, &fromlen);
00341       if (inlen < 0)
00342        {
00343          if (errno == EINTR)
00344            goto try_again;
00345          perror (_("Cannot receive reply to broadcast"));
00346          stat = RPC_CANTRECV;
00347          goto done_broad;
00348        }
00349       if ((size_t) inlen < sizeof (u_long))
00350        goto recv_again;
00351       /*
00352        * see if reply transaction id matches sent id.
00353        * If so, decode the results.
00354        */
00355       INTUSE(xdrmem_create) (xdrs, inbuf, (u_int) inlen, XDR_DECODE);
00356       if (INTUSE(xdr_replymsg) (xdrs, &msg))
00357        {
00358          if (((u_int32_t) msg.rm_xid == (u_int32_t) xid) &&
00359              (msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
00360              (msg.acpted_rply.ar_stat == SUCCESS))
00361            {
00362              raddr.sin_port = htons ((u_short) port);
00363              done = (*eachresult) (resultsp, &raddr);
00364            }
00365          /* otherwise, we just ignore the errors ... */
00366        }
00367       else
00368        {
00369 #ifdef notdef
00370          /* some kind of deserialization problem ... */
00371          if ((u_int32_t) msg.rm_xid == (u_int32_t) xid)
00372            fprintf (stderr, "Broadcast deserialization problem");
00373          /* otherwise, just random garbage */
00374 #endif
00375        }
00376       xdrs->x_op = XDR_FREE;
00377       msg.acpted_rply.ar_results.proc = (xdrproc_t)INTUSE(xdr_void);
00378       (void) INTUSE(xdr_replymsg) (xdrs, &msg);
00379       (void) (*xresults) (xdrs, resultsp);
00380       xdr_destroy (xdrs);
00381       if (done)
00382        {
00383          stat = RPC_SUCCESS;
00384          goto done_broad;
00385        }
00386       else
00387        {
00388          goto recv_again;
00389        }
00390     }
00391 done_broad:
00392   (void) __close (sock);
00393   AUTH_DESTROY (unix_auth);
00394   return stat;
00395 }