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

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