home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 3 / goldfish_volume_3.bin / files / comm / tcp / amitcp-sdk / src / rpclib / clnt_tcp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-29  |  11.3 KB  |  466 lines

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