home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume6 / rpc2 / part06 / rpc / rpclib / clnt_udp.c < prev   
Encoding:
C/C++ Source or Header  |  1986-11-30  |  10.2 KB  |  375 lines

  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[] = "@(#)clnt_udp.c 1.1 86/02/03 Copyr 1984 Sun Micro";
  31. #endif
  32.  
  33. /*
  34.  * clnt_udp.c, Implements a UPD/IP based, client side RPC.
  35.  *
  36.  * Copyright (C) 1984, Sun Microsystems, Inc.
  37.  */
  38.  
  39. #include <stdio.h>
  40. #include "types.h"
  41. #include <sys/socket.h>
  42. #include <sys/time.h>
  43. #include <sys/ioctl.h>
  44. #include <netinet/in.h>
  45. #include <netdb.h>
  46. #include <errno.h>
  47. #include "xdr.h"
  48. #include "auth.h"
  49. #include "clnt.h"
  50. #include "rpc_msg.h"
  51. #include "pmap_clnt.h"
  52.  
  53. char *malloc();
  54. extern int errno;
  55.  
  56. /*
  57.  * UDP bases client side rpc operations
  58.  */
  59. static enum clnt_stat    clntudp_call();
  60. static void        clntudp_abort();
  61. static void        clntudp_geterr();
  62. static bool_t        clntudp_freeres();
  63. static void        clntudp_destroy();
  64.  
  65. static struct clnt_ops udp_ops = {
  66.     clntudp_call,
  67.     clntudp_abort,
  68.     clntudp_geterr,
  69.     clntudp_freeres,
  70.     clntudp_destroy
  71. };
  72.  
  73. /* 
  74.  * Private data kept per client handle
  75.  */
  76. struct cu_data {
  77.     int           cu_sock;
  78.     struct sockaddr_in cu_raddr;
  79.     int           cu_rlen;
  80.     struct timeval       cu_wait;
  81.     struct rpc_err       cu_error;
  82.     XDR           cu_outxdrs;
  83.     u_int           cu_xdrpos;
  84.     u_int           cu_sendsz;
  85.     char           *cu_outbuf;
  86.     u_int           cu_recvsz;
  87.     char           cu_inbuf[1];
  88. };
  89.  
  90. /*
  91.  * Create a UDP based client handle.
  92.  * If *sockp<0, *sockp is set to a newly created UPD socket.
  93.  * If raddr->sin_port is 0 a binder on the remote machine
  94.  * is consulted for the correct port number.
  95.  * NB: It is the clients responsibility to close *sockp.
  96.  * NB: The rpch->cl_auth is initialized to null authentication.
  97.  *     Caller may wish to set this something more useful.
  98.  *
  99.  * wait is the amount of time used between retransmitting a call if
  100.  * no response has been heard;  retransmition occurs until the actual
  101.  * rpc call times out.
  102.  *
  103.  * sendsz and recvsz are the maximum allowable packet sizes that can be
  104.  * sent and received.
  105.  */
  106. CLIENT *
  107. clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz)
  108.     struct sockaddr_in *raddr;
  109.     u_long program;
  110.     u_long version;
  111.     struct timeval wait;
  112.     register int *sockp;
  113.     u_int sendsz;
  114.     u_int recvsz;
  115. {
  116.     CLIENT *cl;
  117.     register struct cu_data *cu;
  118.     struct timeval now;
  119.     struct rpc_msg call_msg;
  120.  
  121.     cl = (CLIENT *)mem_alloc(sizeof(CLIENT));
  122.     if (cl == NULL) {
  123.         fprintf(stderr, "clntudp_create: out of memory\n");
  124.         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  125.         rpc_createerr.cf_error.re_errno = errno;
  126.         goto fooy;
  127.     }
  128.     sendsz = ((sendsz + 3) / 4) * 4;
  129.     recvsz = ((recvsz + 3) / 4) * 4;
  130.     cu = (struct cu_data *)mem_alloc(sizeof(*cu) + sendsz + recvsz);
  131.     if (cu == NULL) {
  132.         fprintf(stderr, "clntudp_create: out of memory\n");
  133.         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  134.         rpc_createerr.cf_error.re_errno = errno;
  135.         goto fooy;
  136.     }
  137.     cu->cu_outbuf = &cu->cu_inbuf[recvsz];
  138.  
  139.     (void)gettimeofday(&now, (struct timezone *)0);
  140.     if (raddr->sin_port == 0) {
  141.         u_short port;
  142.         if ((port =
  143.             pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) {
  144.             goto fooy;
  145.         }
  146.         raddr->sin_port = htons(port);
  147.     }
  148.     cl->cl_ops = &udp_ops;
  149.     cl->cl_private = (caddr_t)cu;
  150.     cu->cu_raddr = *raddr;
  151.     cu->cu_rlen = sizeof (cu->cu_raddr);
  152.     cu->cu_wait = wait;
  153.     cu->cu_sendsz = sendsz;
  154.     cu->cu_recvsz = recvsz;
  155.     call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
  156.     call_msg.rm_direction = CALL;
  157.     call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
  158.     call_msg.rm_call.cb_prog = program;
  159.     call_msg.rm_call.cb_vers = version;
  160.     xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf,
  161.         sendsz, XDR_ENCODE);
  162.     if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) {
  163.         goto fooy;
  164.     }
  165.     cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
  166.     if (*sockp < 0) {
  167.         int dontblock = 1;
  168.  
  169.         *sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  170.         if (*sockp < 0) {
  171.             rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  172.             rpc_createerr.cf_error.re_errno = errno;
  173.             goto fooy;
  174.         }
  175.         /* the sockets rpc controls are non-blocking */
  176.         (void)ioctl(*sockp, FIONBIO, &dontblock);
  177.     }
  178.     cu->cu_sock = *sockp;
  179.     cl->cl_auth = authnone_create();
  180.     return (cl);
  181. fooy:
  182.     if (cu)
  183.         mem_free((caddr_t)cu, sizeof(*cu) + sendsz + recvsz);
  184.     if (cl)
  185.         mem_free((caddr_t)cl, sizeof(CLIENT));
  186.     return ((CLIENT *)NULL);
  187. }
  188.  
  189. CLIENT *
  190. clntudp_create(raddr, program, version, wait, sockp)
  191.     struct sockaddr_in *raddr;
  192.     u_long program;
  193.     u_long version;
  194.     struct timeval wait;
  195.     register int *sockp;
  196. {
  197.  
  198.     return(clntudp_bufcreate(raddr, program, version, wait, sockp,
  199.         UDPMSGSIZE, UDPMSGSIZE));
  200. }
  201.  
  202. static enum clnt_stat 
  203. clntudp_call(cl, proc, xargs, argsp, xresults, resultsp, timeout)
  204.     register CLIENT    *cl;        /* client handle */
  205.     u_long        proc;        /* procedure number */
  206.     xdrproc_t    xargs;        /* xdr routine for args */
  207.     caddr_t        argsp;        /* pointer to args */
  208.     xdrproc_t    xresults;    /* xdr routine for results */
  209.     caddr_t        resultsp;    /* pointer to results */
  210.     struct timeval    timeout;    /* seconds to wait before giving up */
  211. {
  212.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  213.     register XDR *xdrs;
  214.     register int outlen;
  215.     register int inlen;
  216.     int readfds, fromlen;
  217.     register int mask;
  218.     struct sockaddr_in from;
  219.     struct rpc_msg reply_msg;
  220.     XDR reply_xdrs;
  221.     struct timeval time_waited;
  222.     bool_t ok;
  223.  
  224. call_again:
  225.     time_waited.tv_sec = 0;
  226.     time_waited.tv_usec = 0;
  227.     xdrs = &(cu->cu_outxdrs);
  228.     xdrs->x_op = XDR_ENCODE;
  229.     XDR_SETPOS(xdrs, cu->cu_xdrpos);
  230.     /*
  231.      * the transaction is the first thing in the out buffer
  232.      */
  233.     (*(u_short *)(cu->cu_outbuf))++;
  234.     if ((! XDR_PUTLONG(xdrs, (long *)&proc)) ||
  235.         (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
  236.         (! (*xargs)(xdrs, argsp)))
  237.         return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
  238.     outlen = (int)XDR_GETPOS(xdrs);
  239.     while (TRUE) {
  240.  
  241.         if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0,
  242.             (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen)
  243.             != outlen) {
  244.             cu->cu_error.re_errno = errno;
  245.             return (cu->cu_error.re_status = RPC_CANTSEND);
  246.         }
  247.         /*
  248.          * sub-optimal code appears inside the loop because we have
  249.          * some clock time to spare while the packets are in flight.
  250.          * (We assume that this is actually only executed once.)
  251.          */
  252.         reply_msg.acpted_rply.ar_verf = _null_auth;
  253.         reply_msg.acpted_rply.ar_results.where = resultsp;
  254.         reply_msg.acpted_rply.ar_results.proc = xresults;
  255.         mask = 1 << cu->cu_sock;
  256. rcv_again:
  257.         readfds = mask;
  258.         switch (select(32, &readfds, (int *)NULL, (int *)NULL,
  259.             &(cu->cu_wait))) {
  260.  
  261.         case 0:
  262.             time_waited.tv_sec += cu->cu_wait.tv_sec;
  263.             time_waited.tv_usec += cu->cu_wait.tv_usec;
  264.             while (time_waited.tv_usec >= 1000000) {
  265.                 time_waited.tv_sec++;
  266.                 time_waited.tv_usec -= 1000000;
  267.             }
  268.             if ((time_waited.tv_sec < timeout.tv_sec) ||
  269.                 ((time_waited.tv_sec == timeout.tv_sec) &&
  270.                 (time_waited.tv_usec < timeout.tv_usec)))
  271.                 continue;
  272.             return (cu->cu_error.re_status = RPC_TIMEDOUT);
  273.  
  274.         case -1:
  275.             if (errno == EINTR)
  276.                 goto rcv_again;
  277.             cu->cu_error.re_errno = errno;
  278.             return (cu->cu_error.re_status = RPC_CANTRECV);
  279.         }
  280.         if ((readfds & mask) == 0)
  281.             goto rcv_again;
  282. tryagain:
  283.         fromlen = sizeof(struct sockaddr);
  284.         inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, cu->cu_recvsz, 0,
  285.             (struct sockaddr *)&from, &fromlen);
  286.         if (inlen < 0) {
  287.             if (errno == EINTR)
  288.                 goto tryagain;
  289.             if (errno == EWOULDBLOCK)
  290.                 goto rcv_again;
  291.             cu->cu_error.re_errno = errno;
  292.             return (cu->cu_error.re_status = RPC_CANTRECV);
  293.         }
  294.         if (inlen < sizeof(u_long))
  295.             goto rcv_again;
  296.         /* see if reply transaction id matches sent id */
  297.         if (*((u_long *)(cu->cu_inbuf)) != *((u_long *)(cu->cu_outbuf)))
  298.             goto rcv_again;
  299.         /* we now assume we have the proper reply */
  300.         break;
  301.     }
  302.  
  303.     /*
  304.      * now decode and validate the response
  305.      */
  306.     xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE);
  307.     ok = xdr_replymsg(&reply_xdrs, &reply_msg);
  308.     /* XDR_DESTROY(&reply_xdrs);  save a few cycles on noop destroy */
  309.     if (ok) {
  310.         _seterr_reply(&reply_msg, &(cu->cu_error));
  311.         if (cu->cu_error.re_status == RPC_SUCCESS) {
  312.             if (! AUTH_VALIDATE(cl->cl_auth,
  313.                 &reply_msg.acpted_rply.ar_verf)) {
  314.                 cu->cu_error.re_status = RPC_AUTHERROR;
  315.                 cu->cu_error.re_why = AUTH_INVALIDRESP;
  316.             }
  317.             if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
  318.                 xdrs->x_op = XDR_FREE;
  319.                 (void)xdr_opaque_auth(xdrs,
  320.                     &(reply_msg.acpted_rply.ar_verf));
  321.             } 
  322.         }  /* end successful completion */
  323.         else {
  324.             /* maybe our credentials need to be refreshed ... */
  325.             if (AUTH_REFRESH(cl->cl_auth))
  326.                 goto call_again;
  327.         }  /* end of unsuccessful completion */
  328.     }  /* end of valid reply message */
  329.     else {
  330.         cu->cu_error.re_status = RPC_CANTDECODERES;
  331.     }
  332.     return (cu->cu_error.re_status);
  333. }
  334.  
  335. static void
  336. clntudp_geterr(cl, errp)
  337.     CLIENT *cl;
  338.     struct rpc_err *errp;
  339. {
  340.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  341.  
  342.     *errp = cu->cu_error;
  343. }
  344.  
  345.  
  346. static bool_t
  347. clntudp_freeres(cl, xdr_res, res_ptr)
  348.     CLIENT *cl;
  349.     xdrproc_t xdr_res;
  350.     caddr_t res_ptr;
  351. {
  352.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  353.     register XDR *xdrs = &(cu->cu_outxdrs);
  354.  
  355.     xdrs->x_op = XDR_FREE;
  356.     return ((*xdr_res)(xdrs, res_ptr));
  357. }
  358.  
  359. static void 
  360. clntudp_abort(/*h*/)
  361.     /*CLIENT *h;*/
  362. {
  363. }
  364.  
  365. static void
  366. clntudp_destroy(cl)
  367.     CLIENT *cl;
  368. {
  369.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  370.  
  371.     XDR_DESTROY(&(cu->cu_outxdrs));
  372.     mem_free((caddr_t)cu, (sizeof(*cu) + cu->cu_sendsz + cu->cu_recvsz));
  373.     mem_free((caddr_t)cl, sizeof(CLIENT));
  374. }
  375.