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 / clnt_udp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-01  |  12.6 KB  |  479 lines

  1. /* @(#)clnt_udp.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[] = "@(#)clnt_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro";
  32. #endif
  33.  
  34. /*
  35.  * clnt_udp.c, Implements a UDP/IP based, client side RPC.
  36.  *
  37.  * Copyright (C) 1984, Sun Microsystems, Inc.
  38.  */
  39.  
  40. #include <stdio.h>
  41. #include <rpc/rpc.h>
  42. #include <sys/socket.h>
  43. #include <sys/ioctl.h>
  44. #include <netdb.h>
  45. #include <errno.h>
  46. #include <rpc/pmap_clnt.h>
  47.  
  48. #ifdef __STDC__
  49. #include <stdlib.h>
  50. #endif
  51.  
  52. #if NLS
  53. #include "nl_types.h"
  54. #endif
  55.  
  56. extern int errno;
  57.  
  58. /*
  59.  * UDP bases client side rpc operations
  60.  */
  61. static enum clnt_stat    clntudp_call();
  62. static void        clntudp_abort();
  63. static void        clntudp_geterr();
  64. static bool_t        clntudp_freeres();
  65. static bool_t           clntudp_control();
  66. static void        clntudp_destroy();
  67.  
  68. static struct clnt_ops udp_ops = {
  69.     clntudp_call,
  70.     clntudp_abort,
  71.     clntudp_geterr,
  72.     clntudp_freeres,
  73.     clntudp_destroy,
  74.     clntudp_control
  75. };
  76.  
  77. /* 
  78.  * Private data kept per client handle
  79.  */
  80. struct cu_data {
  81.     int           cu_sock;
  82.     bool_t           cu_closeit;
  83.     struct sockaddr_in cu_raddr;
  84.     int           cu_rlen;
  85.     struct timeval       cu_wait;
  86.     struct timeval     cu_total;
  87.     struct rpc_err       cu_error;
  88.     XDR           cu_outxdrs;
  89.     u_int           cu_xdrpos;
  90.     u_int           cu_sendsz;
  91.     char           *cu_outbuf;
  92.     u_int           cu_recvsz;
  93.     char           cu_inbuf[1];
  94. };
  95.  
  96. /*
  97.  * Create a UDP based client handle.
  98.  * If *sockp<0, *sockp is set to a newly created UPD socket.
  99.  * If raddr->sin_port is 0 a binder on the remote machine
  100.  * is consulted for the correct port number.
  101.  * NB: It is the clients responsibility to close *sockp.
  102.  * NB: The rpch->cl_auth is initialized to null authentication.
  103.  *     Caller may wish to set this something more useful.
  104.  *
  105.  * wait is the amount of time used between retransmitting a call if
  106.  * no response has been heard;  retransmition occurs until the actual
  107.  * rpc call times out.
  108.  *
  109.  * sendsz and recvsz are the maximum allowable packet sizes that can be
  110.  * sent and received.
  111.  */
  112. CLIENT *
  113. clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz)
  114.     struct sockaddr_in *raddr;
  115.     u_long program;
  116.     u_long version;
  117.     struct timeval wait;
  118.     register int *sockp;
  119.     u_int sendsz;
  120.     u_int recvsz;
  121. {
  122.     CLIENT *cl;
  123.     register struct cu_data *cu = NULL;
  124.     struct timeval now;
  125.     struct rpc_msg call_msg;
  126.  
  127. #if NLS
  128.     libc_nls_init();
  129. #endif
  130.     cl = (CLIENT *)mem_alloc(sizeof(CLIENT));
  131.     if (cl == NULL) {
  132. #if NLS
  133.         (void) fprintf(stderr, "clntudp_create: %s\n",
  134.                               catgets(_libc_cat, RpcMiscSet,
  135.                                       RpcMiscOutOfMemory, "out of memory"));
  136. #else
  137.         (void) fprintf(stderr, "clntudp_create: out of memory\n");
  138. #endif
  139.         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  140.         rpc_createerr.cf_error.re_errno = errno;
  141.         goto fooy;
  142.     }
  143.     sendsz = ((sendsz + 3) / 4) * 4;
  144.     recvsz = ((recvsz + 3) / 4) * 4;
  145.     cu = (struct cu_data *)mem_alloc(sizeof(*cu) + sendsz + recvsz);
  146.     if (cu == NULL) {
  147. #if NLS
  148.         (void) fprintf(stderr, "clntudp_create: %s\n",
  149.                               catgets(_libc_cat, RpcMiscSet,
  150.                                       RpcMiscOutOfMemory, "out of memory"));
  151. #else
  152.         (void) fprintf(stderr, "clntudp_create: out of memory\n");
  153. #endif
  154.         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  155.         rpc_createerr.cf_error.re_errno = errno;
  156.         goto fooy;
  157.     }
  158.     cu->cu_outbuf = &cu->cu_inbuf[recvsz];
  159.  
  160.     (void)gettimeofday(&now, (struct timezone *)0);
  161.     if (raddr->sin_port == 0) {
  162.         u_short port;
  163.         if ((port =
  164.             pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) {
  165.             goto fooy;
  166.         }
  167.         raddr->sin_port = htons(port);
  168.     }
  169.     cl->cl_ops = &udp_ops;
  170.     cl->cl_private = (caddr_t)cu;
  171.     cu->cu_raddr = *raddr;
  172.     cu->cu_rlen = sizeof (cu->cu_raddr);
  173.     cu->cu_wait = wait;
  174.     cu->cu_total.tv_sec = -1;
  175.     cu->cu_total.tv_usec = -1;
  176.     cu->cu_sendsz = sendsz;
  177.     cu->cu_recvsz = recvsz;
  178.     call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
  179.     call_msg.rm_direction = CALL;
  180.     call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
  181.     call_msg.rm_call.cb_prog = program;
  182.     call_msg.rm_call.cb_vers = version;
  183.     xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf,
  184.         sendsz, XDR_ENCODE);
  185.     if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) {
  186.         goto fooy;
  187.     }
  188.     cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
  189.     if (*sockp < 0) {
  190.         int dontblock = 1;
  191.  
  192.         *sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  193.         if (*sockp < 0) {
  194.             rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  195.             rpc_createerr.cf_error.re_errno = errno;
  196.             goto fooy;
  197.         }
  198.         /* attempt to bind to prov port */
  199.         (void)bindresvport(*sockp, (struct sockaddr_in *)0);
  200.         /* the sockets rpc controls are non-blocking */
  201.         (void)ioctl(*sockp, FIONBIO, (char *) &dontblock);
  202.         cu->cu_closeit = TRUE;
  203.     } else {
  204.         cu->cu_closeit = FALSE;
  205.     }
  206.     cu->cu_sock = *sockp;
  207.     cl->cl_auth = authnone_create();
  208.     return (cl);
  209. fooy:
  210.     if (cu)
  211.         mem_free((caddr_t)cu, sizeof(*cu) + sendsz + recvsz);
  212.     if (cl)
  213.         mem_free((caddr_t)cl, sizeof(CLIENT));
  214.     return ((CLIENT *)NULL);
  215. }
  216.  
  217. CLIENT *
  218. clntudp_create(raddr, program, version, wait, sockp)
  219.     struct sockaddr_in *raddr;
  220.     u_long program;
  221.     u_long version;
  222.     struct timeval wait;
  223.     register int *sockp;
  224. {
  225.  
  226.     return(clntudp_bufcreate(raddr, program, version, wait, sockp,
  227.         UDPMSGSIZE, UDPMSGSIZE));
  228. }
  229.  
  230. static enum clnt_stat 
  231. clntudp_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout)
  232.     register CLIENT    *cl;        /* client handle */
  233.     u_long        proc;        /* procedure number */
  234.     xdrproc_t    xargs;        /* xdr routine for args */
  235.     caddr_t        argsp;        /* pointer to args */
  236.     xdrproc_t    xresults;    /* xdr routine for results */
  237.     caddr_t        resultsp;    /* pointer to results */
  238.     struct timeval    utimeout;    /* seconds to wait before giving up */
  239. {
  240.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  241.     register XDR *xdrs;
  242.     register int outlen;
  243.     register int inlen;
  244.     int fromlen;
  245. #ifdef FD_SETSIZE
  246.     fd_set readfds;
  247.     fd_set mask;
  248. #else
  249.     int readfds;
  250.     register int mask;
  251. #endif /* def FD_SETSIZE */
  252.     struct sockaddr_in from;
  253.     struct rpc_msg reply_msg;
  254.     XDR reply_xdrs;
  255.     struct timeval time_waited;
  256.     bool_t ok;
  257.     int nrefreshes = 2;    /* number of times to refresh cred */
  258.     struct timeval timeout;
  259.  
  260.     if (cu->cu_total.tv_usec == -1) {
  261.         timeout = utimeout;     /* use supplied timeout */
  262.     } else {
  263.         timeout = cu->cu_total; /* use default timeout */
  264.     }
  265.  
  266.     time_waited.tv_sec = 0;
  267.     time_waited.tv_usec = 0;
  268. call_again:
  269.     xdrs = &(cu->cu_outxdrs);
  270.     xdrs->x_op = XDR_ENCODE;
  271.     XDR_SETPOS(xdrs, cu->cu_xdrpos);
  272.     /*
  273.      * the transaction is the first thing in the out buffer
  274.      */
  275.     (*(u_short *)(cu->cu_outbuf))++;
  276.     if ((! XDR_PUTLONG(xdrs, (long *)&proc)) ||
  277.         (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
  278.         (! (*xargs)(xdrs, argsp)))
  279.         return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
  280.     outlen = (int)XDR_GETPOS(xdrs);
  281.  
  282. send_again:
  283.     if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0,
  284.         (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen)
  285.         != outlen) {
  286.         cu->cu_error.re_errno = errno;
  287.         return (cu->cu_error.re_status = RPC_CANTSEND);
  288.     }
  289.  
  290.     /*
  291.      * Hack to provide rpc-based message passing
  292.      */
  293.     if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
  294.         return (cu->cu_error.re_status = RPC_TIMEDOUT);
  295.     }
  296.     /*
  297.      * sub-optimal code appears here because we have
  298.      * some clock time to spare while the packets are in flight.
  299.      * (We assume that this is actually only executed once.)
  300.      */
  301.     reply_msg.acpted_rply.ar_verf = _null_auth;
  302.     reply_msg.acpted_rply.ar_results.where = resultsp;
  303.     reply_msg.acpted_rply.ar_results.proc = xresults;
  304. #ifdef FD_SETSIZE
  305.     FD_ZERO(&mask);
  306.     FD_SET(cu->cu_sock, &mask);
  307. #else
  308.     mask = 1 << cu->cu_sock;
  309. #endif /* def FD_SETSIZE */
  310.     for (;;) {
  311. #ifdef linux
  312.         struct timeval oneshot_timeout;
  313.  
  314.         readfds = mask;
  315.         oneshot_timeout = cu->cu_wait;
  316.         switch (select(_rpc_dtablesize(), &readfds, (void *)NULL, 
  317.                    (void *)NULL, &oneshot_timeout)) {
  318. #else
  319.         readfds = mask;
  320.         switch (select(_rpc_dtablesize(), &readfds, (void *)NULL, 
  321.                    (void *)NULL, &(cu->cu_wait))) {
  322. #endif
  323.  
  324.         case 0:
  325.             time_waited.tv_sec += cu->cu_wait.tv_sec;
  326.             time_waited.tv_usec += cu->cu_wait.tv_usec;
  327.             while (time_waited.tv_usec >= 1000000) {
  328.                 time_waited.tv_sec++;
  329.                 time_waited.tv_usec -= 1000000;
  330.             }
  331.             if ((time_waited.tv_sec < timeout.tv_sec) ||
  332.                 ((time_waited.tv_sec == timeout.tv_sec) &&
  333.                 (time_waited.tv_usec < timeout.tv_usec)))
  334.                 goto send_again;    
  335.             return (cu->cu_error.re_status = RPC_TIMEDOUT);
  336.  
  337.         /*
  338.          * buggy in other cases because time_waited is not being
  339.          * updated.
  340.          */
  341.         case -1:
  342.             if (errno == EINTR)
  343.                 continue;    
  344.             cu->cu_error.re_errno = errno;
  345.             return (cu->cu_error.re_status = RPC_CANTRECV);
  346.         }
  347.         do {
  348.             fromlen = sizeof(struct sockaddr);
  349.             inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, 
  350.                 (int) cu->cu_recvsz, 0,
  351.                 (struct sockaddr *)&from, &fromlen);
  352.         } while (inlen < 0 && errno == EINTR);
  353.         if (inlen < 0) {
  354. #ifdef linux
  355.             if (errno == EWOULDBLOCK || errno == EAGAIN)
  356. #else
  357.             if (errno == EWOULDBLOCK)
  358. #endif
  359.                 continue;    
  360.             cu->cu_error.re_errno = errno;
  361.             return (cu->cu_error.re_status = RPC_CANTRECV);
  362.         }
  363.         if (inlen < sizeof(u_long))
  364.             continue;    
  365.         /* see if reply transaction id matches sent id */
  366.         if (*((u_long *)(cu->cu_inbuf)) != *((u_long *)(cu->cu_outbuf)))
  367.             continue;    
  368.         /* we now assume we have the proper reply */
  369.         break;
  370.     }
  371.  
  372.     /*
  373.      * now decode and validate the response
  374.      */
  375.     xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE);
  376.     ok = xdr_replymsg(&reply_xdrs, &reply_msg);
  377.     /* XDR_DESTROY(&reply_xdrs);  save a few cycles on noop destroy */
  378.     if (ok) {
  379.         _seterr_reply(&reply_msg, &(cu->cu_error));
  380.         if (cu->cu_error.re_status == RPC_SUCCESS) {
  381.             if (! AUTH_VALIDATE(cl->cl_auth,
  382.                 &reply_msg.acpted_rply.ar_verf)) {
  383.                 cu->cu_error.re_status = RPC_AUTHERROR;
  384.                 cu->cu_error.re_why = AUTH_INVALIDRESP;
  385.             }
  386.             if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
  387.                 xdrs->x_op = XDR_FREE;
  388.                 (void)xdr_opaque_auth(xdrs,
  389.                     &(reply_msg.acpted_rply.ar_verf));
  390.             } 
  391.         }  /* end successful completion */
  392.         else {
  393.             /* maybe our credentials need to be refreshed ... */
  394.             if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) {
  395.                 nrefreshes--;
  396.                 goto call_again;
  397.             }
  398.         }  /* end of unsuccessful completion */
  399.     }  /* end of valid reply message */
  400.     else {
  401.         cu->cu_error.re_status = RPC_CANTDECODERES;
  402.     }
  403.     return (cu->cu_error.re_status);
  404. }
  405.  
  406. static void
  407. clntudp_geterr(cl, errp)
  408.     CLIENT *cl;
  409.     struct rpc_err *errp;
  410. {
  411.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  412.  
  413.     *errp = cu->cu_error;
  414. }
  415.  
  416.  
  417. static bool_t
  418. clntudp_freeres(cl, xdr_res, res_ptr)
  419.     CLIENT *cl;
  420.     xdrproc_t xdr_res;
  421.     caddr_t res_ptr;
  422. {
  423.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  424.     register XDR *xdrs = &(cu->cu_outxdrs);
  425.  
  426.     xdrs->x_op = XDR_FREE;
  427.     return ((*xdr_res)(xdrs, res_ptr));
  428. }
  429.  
  430. static void 
  431. clntudp_abort(/*h*/)
  432.     /*CLIENT *h;*/
  433. {
  434. }
  435.  
  436. static bool_t
  437. clntudp_control(cl, request, info)
  438.     CLIENT *cl;
  439.     int request;
  440.     char *info;
  441. {
  442.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  443.  
  444.     switch (request) {
  445.     case CLSET_TIMEOUT:
  446.         cu->cu_total = *(struct timeval *)info;
  447.         break;
  448.     case CLGET_TIMEOUT:
  449.         *(struct timeval *)info = cu->cu_total;
  450.         break;
  451.     case CLSET_RETRY_TIMEOUT:
  452.         cu->cu_wait = *(struct timeval *)info;
  453.         break;
  454.     case CLGET_RETRY_TIMEOUT:
  455.         *(struct timeval *)info = cu->cu_wait;
  456.         break;
  457.     case CLGET_SERVER_ADDR:
  458.         *(struct sockaddr_in *)info = cu->cu_raddr;
  459.         break;
  460.     default:
  461.         return (FALSE);
  462.     }
  463.     return (TRUE);
  464. }
  465.     
  466. static void
  467. clntudp_destroy(cl)
  468.     CLIENT *cl;
  469. {
  470.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  471.  
  472.     if (cu->cu_closeit) {
  473.         (void)close(cu->cu_sock);
  474.     }
  475.     XDR_DESTROY(&(cu->cu_outxdrs));
  476.     mem_free((caddr_t)cu, (sizeof(*cu) + cu->cu_sendsz + cu->cu_recvsz));
  477.     mem_free((caddr_t)cl, sizeof(CLIENT));
  478. }
  479.