home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume6 / rpc2 / part06 / rpc / rpclib / clnt_tcp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-11-30  |  10.6 KB  |  409 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_tcp.c 1.1 86/02/03 Copyr 1984 Sun Micro";
  31. #endif
  32.  
  33. /*
  34.  * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
  35.  *
  36.  * Copyright (C) 1984, Sun Microsystems, Inc.
  37.  *
  38.  * TCP based RPC supports 'batched calls'.
  39.  * A sequence of calls may be batched-up in a send buffer.  The rpc call
  40.  * return immediately to the client even though the call was not necessarily
  41.  * sent.  The batching occurs iff the results' xdr routine is NULL (0) AND
  42.  * the rpc timeout value is zero (see clnt.h, rpc).
  43.  *
  44.  * Clients should NOT casually batch calls that in fact return results; that is,
  45.  * the server side should be aware that a call is batched and not produce any
  46.  * return message.  Batched calls that produce many result messages can
  47.  * deadlock (netlock) the client and the server....
  48.  *
  49.  * Now go hang yourself.
  50.  */
  51.  
  52. #include <stdio.h>
  53. #include "types.h"
  54. #include <sys/socket.h>
  55. #include <sys/time.h>
  56. #include <netinet/in.h>
  57. #include <netdb.h>
  58. #include <errno.h>
  59. #include "xdr.h"
  60. #include "auth.h"
  61. #include "clnt.h"
  62. #include "rpc_msg.h"
  63. #include "pmap_clnt.h"
  64.  
  65. #define MCALL_MSG_SIZE 24
  66.  
  67. char *malloc();
  68. extern int errno;
  69.  
  70. static int    readtcp();
  71. static int    writetcp();
  72.  
  73. static enum clnt_stat    clnttcp_call();
  74. static void        clnttcp_abort();
  75. static void        clnttcp_geterr();
  76. static bool_t        clnttcp_freeres();
  77. static void        clnttcp_destroy();
  78.  
  79. static struct clnt_ops tcp_ops = {
  80.     clnttcp_call,
  81.     clnttcp_abort,
  82.     clnttcp_geterr,
  83.     clnttcp_freeres,
  84.     clnttcp_destroy
  85. };
  86.  
  87. struct ct_data {
  88.     int        ct_sock;
  89.     struct timeval    ct_wait;
  90.     struct rpc_err    ct_error;
  91.     char        ct_mcall[MCALL_MSG_SIZE];    /* marshalled callmsg */
  92.     u_int        ct_mpos;            /* pos after marshal */
  93.     XDR        ct_xdrs;
  94. };
  95.  
  96. /*
  97.  * Create a client handle for a tcp/ip connection.
  98.  * If *sockp<0, *sockp is set to a newly created TCP socket and it is
  99.  * connected to raddr.  If *sockp non-negative then
  100.  * raddr is ignored.  The rpc/tcp package does buffering
  101.  * similar to stdio, so the client must pick send and receive buffer sizes,];
  102.  * 0 => use the default.
  103.  * If raddr->sin_port is 0, then a binder on the remote machine is
  104.  * consulted for the right port number.
  105.  * NB: *sockp is copied into a private area.
  106.  * NB: It is the clients responsibility to close *sockp.
  107.  * NB: The rpch->cl_auth is set null authentication.  Caller may wish to set this
  108.  * something more useful.
  109.  */
  110. CLIENT *
  111. clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz)
  112.     struct sockaddr_in *raddr;
  113.     u_long prog;
  114.     u_long vers;
  115.     register int *sockp;
  116.     u_int sendsz;
  117.     u_int recvsz;
  118. {
  119.     CLIENT *h;
  120.     register struct ct_data *ct;
  121.     struct timeval now;
  122.     struct rpc_msg call_msg;
  123.  
  124.     h  = (CLIENT *)mem_alloc(sizeof(*h));
  125.     if (h == NULL) {
  126.         fprintf(stderr, "clnttcp_create: out of memory\n");
  127.         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  128.         rpc_createerr.cf_error.re_errno = errno;
  129.         goto fooy;
  130.     }
  131.     ct = (struct ct_data *)mem_alloc(sizeof(*ct));
  132.     if (ct == NULL) {
  133.         fprintf(stderr, "clnttcp_create: out of memory\n");
  134.         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  135.         rpc_createerr.cf_error.re_errno = errno;
  136.         goto fooy;
  137.     }
  138.  
  139.     /*
  140.      * If no port number given ask the pmap for one
  141.      */
  142.     if (raddr->sin_port == 0) {
  143.         u_short port;
  144.         if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) {
  145.             mem_free((caddr_t)ct, sizeof(struct ct_data));
  146.             mem_free((caddr_t)h, sizeof(CLIENT));
  147.             return ((CLIENT *)NULL);
  148.         }
  149.         raddr->sin_port = htons(port);
  150.     }
  151.  
  152.     /*
  153.      * If no socket given, open one
  154.      */
  155.     if (*sockp < 0) {
  156.         if (((*sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
  157.             || (connect(*sockp, (struct sockaddr *)raddr,
  158.             sizeof(*raddr)) < 0)) {
  159.             rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  160.             rpc_createerr.cf_error.re_errno = errno;
  161.             goto fooy;
  162.         }
  163.     }
  164.  
  165.     /*
  166.      * Set up private data struct
  167.      */
  168.     ct->ct_sock = *sockp;
  169.     ct->ct_wait.tv_usec = 0;
  170.  
  171.     /*
  172.      * Initialize call message
  173.      */
  174.     (void)gettimeofday(&now, (struct timezone *)0);
  175.     call_msg.rm_xid = getpid() ^  now.tv_sec ^ now.tv_usec;
  176.     call_msg.rm_direction = CALL;
  177.     call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
  178.     call_msg.rm_call.cb_prog = prog;
  179.     call_msg.rm_call.cb_vers = vers;
  180.  
  181.     /*
  182.      * pre-serialize the staic part of the call msg and stash it away
  183.      */
  184.     xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE,
  185.         XDR_ENCODE);
  186.     if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
  187.         goto fooy;
  188.     }
  189.     ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
  190.     XDR_DESTROY(&(ct->ct_xdrs));
  191.  
  192.     /*
  193.      * Create a client handle which uses xdrrec for serialization
  194.      * and authnone for authentication.
  195.      */
  196.     xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
  197.         (caddr_t)ct, readtcp, writetcp);
  198.     h->cl_ops = &tcp_ops;
  199.     h->cl_private = (caddr_t) ct;
  200.     h->cl_auth = authnone_create();
  201.     return (h);
  202.  
  203. fooy:
  204.     /*
  205.      * Something goofed, free stuff and barf
  206.      */
  207.     mem_free((caddr_t)ct, sizeof(struct ct_data));
  208.     mem_free((caddr_t)h, sizeof(CLIENT));
  209.     (void)close(*sockp);
  210.     return ((CLIENT *)NULL);
  211. }
  212.  
  213. static enum clnt_stat
  214. clnttcp_call(h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
  215.     register CLIENT *h;
  216.     u_long proc;
  217.     xdrproc_t xdr_args;
  218.     caddr_t args_ptr;
  219.     xdrproc_t xdr_results;
  220.     caddr_t results_ptr;
  221.     struct timeval timeout;
  222. {
  223.     register struct ct_data *ct = (struct ct_data *) h->cl_private;
  224.     register XDR *xdrs = &(ct->ct_xdrs);
  225.     struct rpc_msg reply_msg;
  226.     u_long x_id;
  227.     u_long *msg_x_id = (u_long *)(ct->ct_mcall);    /* yuk */
  228.     register bool_t shipnow;
  229.  
  230.     ct->ct_wait = timeout;
  231.     shipnow =
  232.         (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0
  233.         && timeout.tv_usec == 0) ? FALSE : TRUE;
  234.  
  235. call_again:
  236.     xdrs->x_op = XDR_ENCODE;
  237.     ct->ct_error.re_status = RPC_SUCCESS;
  238.     x_id = ntohl(--(*msg_x_id));
  239.     if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) ||
  240.         (! XDR_PUTLONG(xdrs, (long *)&proc)) ||
  241.         (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
  242.         (! (*xdr_args)(xdrs, args_ptr))) {
  243.         if (ct->ct_error.re_status == RPC_SUCCESS)
  244.             ct->ct_error.re_status = RPC_CANTENCODEARGS;
  245.         (void)xdrrec_endofrecord(xdrs, TRUE);
  246.         return (ct->ct_error.re_status);
  247.     }
  248.     if (! xdrrec_endofrecord(xdrs, shipnow))
  249.         return (ct->ct_error.re_status = RPC_CANTSEND);
  250.     if (! shipnow)
  251.         return (RPC_SUCCESS);
  252.     xdrs->x_op = XDR_DECODE;
  253.  
  254.     /*
  255.      * Keep receiving until we get a valid transaction id
  256.      */
  257.     while (TRUE) {
  258.         reply_msg.acpted_rply.ar_verf = _null_auth;
  259.         reply_msg.acpted_rply.ar_results.where = NULL;
  260.         reply_msg.acpted_rply.ar_results.proc = xdr_void;
  261.         if (! xdrrec_skiprecord(xdrs))
  262.             return (ct->ct_error.re_status);
  263.         /* now decode and validate the response header */
  264.         if (! xdr_replymsg(xdrs, &reply_msg)) {
  265.             if (ct->ct_error.re_status == RPC_SUCCESS)
  266.                 continue;
  267.             return (ct->ct_error.re_status);
  268.         }
  269.         if (reply_msg.rm_xid == x_id)
  270.             break;
  271.     }
  272.  
  273.     /*
  274.      * process header
  275.      */
  276.     _seterr_reply(&reply_msg, &(ct->ct_error));
  277.     if (ct->ct_error.re_status == RPC_SUCCESS) {
  278.         if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) {
  279.             ct->ct_error.re_status = RPC_AUTHERROR;
  280.             ct->ct_error.re_why = AUTH_INVALIDRESP;
  281.         } else if (! (*xdr_results)(xdrs, results_ptr)) {
  282.             if (ct->ct_error.re_status == RPC_SUCCESS)
  283.                 ct->ct_error.re_status = RPC_CANTDECODERES;
  284.         }
  285.         /* free verifier ... */
  286.         if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
  287.             xdrs->x_op = XDR_FREE;
  288.             (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf));
  289.         }
  290.     }  /* end successful completion */
  291.     else {
  292.         /* maybe our credentials need to be refreshed ... */
  293.         if (AUTH_REFRESH(h->cl_auth))
  294.             goto call_again;
  295.     }  /* end of unsuccessful completion */
  296.     return (ct->ct_error.re_status);
  297. }
  298.  
  299. static void
  300. clnttcp_geterr(h, errp)
  301.     CLIENT *h;
  302.     struct rpc_err *errp;
  303. {
  304.     register struct ct_data *ct =
  305.         (struct ct_data *) h->cl_private;
  306.  
  307.     *errp = ct->ct_error;
  308. }
  309.  
  310. static bool_t
  311. clnttcp_freeres(cl, xdr_res, res_ptr)
  312.     CLIENT *cl;
  313.     xdrproc_t xdr_res;
  314.     caddr_t res_ptr;
  315. {
  316.     register struct ct_data *ct = (struct ct_data *)cl->cl_private;
  317.     register XDR *xdrs = &(ct->ct_xdrs);
  318.  
  319.     xdrs->x_op = XDR_FREE;
  320.     return ((*xdr_res)(xdrs, res_ptr));
  321. }
  322.  
  323. static void
  324. clnttcp_abort()
  325. {
  326. }
  327.  
  328. static void
  329. clnttcp_destroy(h)
  330.     CLIENT *h;
  331. {
  332.     register struct ct_data *ct =
  333.         (struct ct_data *) h->cl_private;
  334.  
  335.     XDR_DESTROY(&(ct->ct_xdrs));
  336.     mem_free((caddr_t)ct, sizeof(struct ct_data));
  337.     mem_free((caddr_t)h, sizeof(CLIENT));
  338. }
  339.  
  340. /*
  341.  * Interface between xdr serializer and tcp connection.
  342.  * Behaves like the system calls, read & write, but keeps some error state
  343.  * around for the rpc level.
  344.  */
  345. static int
  346. readtcp(ct, buf, len)
  347.     register struct ct_data *ct;
  348.     caddr_t buf;
  349.     register int len;
  350. {
  351.     register int mask = 1 << (ct->ct_sock);
  352.     int readfds;
  353.  
  354.     if (len == 0)
  355.         return (0);
  356.     while (TRUE) {
  357.         readfds = mask;
  358.         switch (select(32, &readfds, (int*)NULL, (int*)NULL,
  359.             &(ct->ct_wait))) {
  360.  
  361.         case 0:
  362.             ct->ct_error.re_status = RPC_TIMEDOUT;
  363.             return (-1);
  364.  
  365.         case -1:
  366.             if (errno == EINTR)
  367.                 continue;
  368.             ct->ct_error.re_status = RPC_CANTRECV;
  369.             ct->ct_error.re_errno = errno;
  370.             return (-1);
  371.         }
  372.         if (readfds == mask)
  373.             break;
  374.     }
  375.     switch (len = read(ct->ct_sock, buf, len)) {
  376.  
  377.     case 0:
  378.         /* premature eof */
  379.         ct->ct_error.re_errno = ECONNRESET;
  380.         ct->ct_error.re_status = RPC_CANTRECV;
  381.         len = -1;  /* it's really an error */
  382.         break;
  383.  
  384.     case -1:
  385.         ct->ct_error.re_errno = errno;
  386.         ct->ct_error.re_status = RPC_CANTRECV;
  387.         break;
  388.     }
  389.     return (len);
  390. }
  391.  
  392. static int
  393. writetcp(ct, buf, len)
  394.     struct ct_data *ct;
  395.     caddr_t buf;
  396.     int len;
  397. {
  398.     register int i, cnt;
  399.  
  400.     for (cnt = len; cnt > 0; cnt -= i, buf += i) {
  401.         if ((i = write(ct->ct_sock, buf, cnt)) == -1) {
  402.             ct->ct_error.re_errno = errno;
  403.             ct->ct_error.re_status = RPC_CANTSEND;
  404.             return (-1);
  405.         }
  406.     }
  407.     return (len);
  408. }
  409.