(root)/
glibc-2.38/
sunrpc/
clnt_tcp.c
       1  /*
       2   * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
       3   *
       4   * Copyright (c) 2010, Oracle America, Inc.
       5   *
       6   * Redistribution and use in source and binary forms, with or without
       7   * modification, are permitted provided that the following conditions are
       8   * met:
       9   *
      10   *     * Redistributions of source code must retain the above copyright
      11   *       notice, this list of conditions and the following disclaimer.
      12   *     * Redistributions in binary form must reproduce the above
      13   *       copyright notice, this list of conditions and the following
      14   *       disclaimer in the documentation and/or other materials
      15   *       provided with the distribution.
      16   *     * Neither the name of the "Oracle America, Inc." nor the names of its
      17   *       contributors may be used to endorse or promote products derived
      18   *       from this software without specific prior written permission.
      19   *
      20   *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      21   *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      22   *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
      23   *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
      24   *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
      25   *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26   *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
      27   *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      28   *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
      29   *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
      30   *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      31   *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      32   *
      33   * TCP based RPC supports 'batched calls'.
      34   * A sequence of calls may be batched-up in a send buffer.  The rpc call
      35   * return immediately to the client even though the call was not necessarily
      36   * sent.  The batching occurs if the results' xdr routine is NULL (0) AND
      37   * the rpc timeout value is zero (see clnt.h, rpc).
      38   *
      39   * Clients should NOT casually batch calls that in fact return results; that is,
      40   * the server side should be aware that a call is batched and not produce any
      41   * return message.  Batched calls that produce many result messages can
      42   * deadlock (netlock) the client and the server....
      43   *
      44   * Now go hang yourself.
      45   */
      46  
      47  #include <netdb.h>
      48  #include <errno.h>
      49  #include <stdio.h>
      50  #include <unistd.h>
      51  #include <libintl.h>
      52  #include <rpc/rpc.h>
      53  #include <sys/poll.h>
      54  #include <sys/socket.h>
      55  #include <rpc/pmap_clnt.h>
      56  #include <wchar.h>
      57  #include <shlib-compat.h>
      58  
      59  extern u_long _create_xid (void);
      60  
      61  #define MCALL_MSG_SIZE 24
      62  
      63  struct ct_data
      64    {
      65      int ct_sock;
      66      bool_t ct_closeit;
      67      struct timeval ct_wait;
      68      bool_t ct_waitset;		/* wait set by clnt_control? */
      69      struct sockaddr_in ct_addr;
      70      struct rpc_err ct_error;
      71      char ct_mcall[MCALL_MSG_SIZE];	/* marshalled callmsg */
      72      u_int ct_mpos;		/* pos after marshal */
      73      XDR ct_xdrs;
      74    };
      75  
      76  static int readtcp (char *, char *, int);
      77  static int writetcp (char *, char *, int);
      78  
      79  static enum clnt_stat clnttcp_call (CLIENT *, u_long, xdrproc_t, caddr_t,
      80  				    xdrproc_t, caddr_t, struct timeval);
      81  static void clnttcp_abort (void);
      82  static void clnttcp_geterr (CLIENT *, struct rpc_err *);
      83  static bool_t clnttcp_freeres (CLIENT *, xdrproc_t, caddr_t);
      84  static bool_t clnttcp_control (CLIENT *, int, char *);
      85  static void clnttcp_destroy (CLIENT *);
      86  
      87  static const struct clnt_ops tcp_ops =
      88  {
      89    clnttcp_call,
      90    clnttcp_abort,
      91    clnttcp_geterr,
      92    clnttcp_freeres,
      93    clnttcp_destroy,
      94    clnttcp_control
      95  };
      96  
      97  /*
      98   * Create a client handle for a tcp/ip connection.
      99   * If *sockp<0, *sockp is set to a newly created TCP socket and it is
     100   * connected to raddr.  If *sockp non-negative then
     101   * raddr is ignored.  The rpc/tcp package does buffering
     102   * similar to stdio, so the client must pick send and receive buffer sizes,];
     103   * 0 => use the default.
     104   * If raddr->sin_port is 0, then a binder on the remote machine is
     105   * consulted for the right port number.
     106   * NB: *sockp is copied into a private area.
     107   * NB: It is the clients responsibility to close *sockp.
     108   * NB: The rpch->cl_auth is set null authentication.  Caller may wish to set this
     109   * something more useful.
     110   */
     111  CLIENT *
     112  clnttcp_create (struct sockaddr_in *raddr, u_long prog, u_long vers,
     113  		int *sockp, u_int sendsz, u_int recvsz)
     114  {
     115    CLIENT *h;
     116    struct ct_data *ct;
     117    struct rpc_msg call_msg;
     118  
     119    h = (CLIENT *) mem_alloc (sizeof (*h));
     120    ct = (struct ct_data *) mem_alloc (sizeof (*ct));
     121    if (h == NULL || ct == NULL)
     122      {
     123        struct rpc_createerr *ce = &get_rpc_createerr ();
     124        (void) __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n"));
     125        ce->cf_stat = RPC_SYSTEMERROR;
     126        ce->cf_error.re_errno = ENOMEM;
     127        goto fooy;
     128      }
     129  
     130    /*
     131     * If no port number given ask the pmap for one
     132     */
     133    if (raddr->sin_port == 0)
     134      {
     135        u_short port;
     136        if ((port = pmap_getport (raddr, prog, vers, IPPROTO_TCP)) == 0)
     137  	{
     138  	  mem_free ((caddr_t) ct, sizeof (struct ct_data));
     139  	  mem_free ((caddr_t) h, sizeof (CLIENT));
     140  	  return ((CLIENT *) NULL);
     141  	}
     142        raddr->sin_port = htons (port);
     143      }
     144  
     145    /*
     146     * If no socket given, open one
     147     */
     148    if (*sockp < 0)
     149      {
     150        *sockp = __socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
     151        (void) bindresvport (*sockp, (struct sockaddr_in *) 0);
     152        if ((*sockp < 0)
     153  	  || (__connect (*sockp, (struct sockaddr *) raddr,
     154  			 sizeof (*raddr)) < 0))
     155  	{
     156  	  struct rpc_createerr *ce = &get_rpc_createerr ();
     157  	  ce->cf_stat = RPC_SYSTEMERROR;
     158  	  ce->cf_error.re_errno = errno;
     159  	  if (*sockp >= 0)
     160  	    (void) __close (*sockp);
     161  	  goto fooy;
     162  	}
     163        ct->ct_closeit = TRUE;
     164      }
     165    else
     166      {
     167        ct->ct_closeit = FALSE;
     168      }
     169  
     170    /*
     171     * Set up private data struct
     172     */
     173    ct->ct_sock = *sockp;
     174    ct->ct_wait.tv_usec = 0;
     175    ct->ct_waitset = FALSE;
     176    ct->ct_addr = *raddr;
     177  
     178    /*
     179     * Initialize call message
     180     */
     181    call_msg.rm_xid = _create_xid ();
     182    call_msg.rm_direction = CALL;
     183    call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
     184    call_msg.rm_call.cb_prog = prog;
     185    call_msg.rm_call.cb_vers = vers;
     186  
     187    /*
     188     * pre-serialize the static part of the call msg and stash it away
     189     */
     190    xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE);
     191    if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg))
     192      {
     193        if (ct->ct_closeit)
     194  	{
     195  	  (void) __close (*sockp);
     196  	}
     197        goto fooy;
     198      }
     199    ct->ct_mpos = XDR_GETPOS (&(ct->ct_xdrs));
     200    XDR_DESTROY (&(ct->ct_xdrs));
     201  
     202    /*
     203     * Create a client handle which uses xdrrec for serialization
     204     * and authnone for authentication.
     205     */
     206    xdrrec_create (&(ct->ct_xdrs), sendsz, recvsz,
     207  		 (caddr_t) ct, readtcp, writetcp);
     208    h->cl_ops = (struct clnt_ops *) &tcp_ops;
     209    h->cl_private = (caddr_t) ct;
     210    h->cl_auth = authnone_create ();
     211    return h;
     212  
     213  fooy:
     214    /*
     215     * Something goofed, free stuff and barf
     216     */
     217    mem_free ((caddr_t) ct, sizeof (struct ct_data));
     218    mem_free ((caddr_t) h, sizeof (CLIENT));
     219    return ((CLIENT *) NULL);
     220  }
     221  #ifdef EXPORT_RPC_SYMBOLS
     222  libc_hidden_def (clnttcp_create)
     223  #else
     224  libc_hidden_nolink_sunrpc (clnttcp_create, GLIBC_2_0)
     225  #endif
     226  
     227  static enum clnt_stat
     228  clnttcp_call (CLIENT *h, u_long proc, xdrproc_t xdr_args, caddr_t args_ptr,
     229  	      xdrproc_t xdr_results, caddr_t results_ptr,
     230  	      struct timeval timeout)
     231  {
     232    struct ct_data *ct = (struct ct_data *) h->cl_private;
     233    XDR *xdrs = &(ct->ct_xdrs);
     234    struct rpc_msg reply_msg;
     235    u_long x_id;
     236    uint32_t *msg_x_id = (uint32_t *) (ct->ct_mcall);	/* yuk */
     237    bool_t shipnow;
     238    int refreshes = 2;
     239  
     240    if (!ct->ct_waitset)
     241      {
     242        ct->ct_wait = timeout;
     243      }
     244  
     245    shipnow =
     246      (xdr_results == (xdrproc_t) 0 && ct->ct_wait.tv_sec == 0
     247       && ct->ct_wait.tv_usec == 0) ? FALSE : TRUE;
     248  
     249  call_again:
     250    xdrs->x_op = XDR_ENCODE;
     251    ct->ct_error.re_status = RPC_SUCCESS;
     252    x_id = ntohl (--(*msg_x_id));
     253    if ((!XDR_PUTBYTES (xdrs, ct->ct_mcall, ct->ct_mpos)) ||
     254        (!XDR_PUTLONG (xdrs, (long *) &proc)) ||
     255        (!AUTH_MARSHALL (h->cl_auth, xdrs)) ||
     256        (!(*xdr_args) (xdrs, args_ptr)))
     257      {
     258        if (ct->ct_error.re_status == RPC_SUCCESS)
     259  	ct->ct_error.re_status = RPC_CANTENCODEARGS;
     260        (void) xdrrec_endofrecord (xdrs, TRUE);
     261        return (ct->ct_error.re_status);
     262      }
     263    if (!xdrrec_endofrecord (xdrs, shipnow))
     264      return ct->ct_error.re_status = RPC_CANTSEND;
     265    if (!shipnow)
     266      return RPC_SUCCESS;
     267    /*
     268     * Hack to provide rpc-based message passing
     269     */
     270    if (ct->ct_wait.tv_sec == 0 && ct->ct_wait.tv_usec == 0)
     271      {
     272        return ct->ct_error.re_status = RPC_TIMEDOUT;
     273      }
     274  
     275  
     276    /*
     277     * Keep receiving until we get a valid transaction id
     278     */
     279    xdrs->x_op = XDR_DECODE;
     280    while (TRUE)
     281      {
     282        reply_msg.acpted_rply.ar_verf = _null_auth;
     283        reply_msg.acpted_rply.ar_results.where = NULL;
     284        reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
     285        if (!xdrrec_skiprecord (xdrs))
     286  	return (ct->ct_error.re_status);
     287        /* now decode and validate the response header */
     288        if (!xdr_replymsg (xdrs, &reply_msg))
     289  	{
     290  	  if (ct->ct_error.re_status == RPC_SUCCESS)
     291  	    continue;
     292  	  return ct->ct_error.re_status;
     293  	}
     294        if ((uint32_t) reply_msg.rm_xid == (uint32_t) x_id)
     295  	break;
     296      }
     297  
     298    /*
     299     * process header
     300     */
     301    _seterr_reply (&reply_msg, &(ct->ct_error));
     302    if (ct->ct_error.re_status == RPC_SUCCESS)
     303      {
     304        if (!AUTH_VALIDATE (h->cl_auth, &reply_msg.acpted_rply.ar_verf))
     305  	{
     306  	  ct->ct_error.re_status = RPC_AUTHERROR;
     307  	  ct->ct_error.re_why = AUTH_INVALIDRESP;
     308  	}
     309        else if (!(*xdr_results) (xdrs, results_ptr))
     310  	{
     311  	  if (ct->ct_error.re_status == RPC_SUCCESS)
     312  	    ct->ct_error.re_status = RPC_CANTDECODERES;
     313  	}
     314        /* free verifier ... */
     315        if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
     316  	{
     317  	  xdrs->x_op = XDR_FREE;
     318  	  (void) xdr_opaque_auth (xdrs, &(reply_msg.acpted_rply.ar_verf));
     319  	}
     320      }				/* end successful completion */
     321    else
     322      {
     323        /* maybe our credentials need to be refreshed ... */
     324        if (refreshes-- && AUTH_REFRESH (h->cl_auth))
     325  	goto call_again;
     326      }				/* end of unsuccessful completion */
     327    return ct->ct_error.re_status;
     328  }
     329  
     330  static void
     331  clnttcp_geterr (CLIENT *h, struct rpc_err *errp)
     332  {
     333    struct ct_data *ct =
     334    (struct ct_data *) h->cl_private;
     335  
     336    *errp = ct->ct_error;
     337  }
     338  
     339  static bool_t
     340  clnttcp_freeres (CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr)
     341  {
     342    struct ct_data *ct = (struct ct_data *) cl->cl_private;
     343    XDR *xdrs = &(ct->ct_xdrs);
     344  
     345    xdrs->x_op = XDR_FREE;
     346    return (*xdr_res) (xdrs, res_ptr);
     347  }
     348  
     349  static void
     350  clnttcp_abort (void)
     351  {
     352  }
     353  
     354  static bool_t
     355  clnttcp_control (CLIENT *cl, int request, char *info)
     356  {
     357    struct ct_data *ct = (struct ct_data *) cl->cl_private;
     358    u_long ul;
     359    uint32_t ui32;
     360  
     361  
     362    switch (request)
     363      {
     364      case CLSET_FD_CLOSE:
     365        ct->ct_closeit = TRUE;
     366        break;
     367      case CLSET_FD_NCLOSE:
     368        ct->ct_closeit = FALSE;
     369        break;
     370      case CLSET_TIMEOUT:
     371        ct->ct_wait = *(struct timeval *) info;
     372        ct->ct_waitset = TRUE;
     373        break;
     374      case CLGET_TIMEOUT:
     375        *(struct timeval *) info = ct->ct_wait;
     376        break;
     377      case CLGET_SERVER_ADDR:
     378        *(struct sockaddr_in *) info = ct->ct_addr;
     379        break;
     380      case CLGET_FD:
     381        *(int *)info = ct->ct_sock;
     382        break;
     383      case CLGET_XID:
     384        /*
     385         * use the knowledge that xid is the
     386         * first element in the call structure *.
     387         * This will get the xid of the PREVIOUS call
     388         */
     389        memcpy (&ui32, ct->ct_mcall, sizeof (ui32));
     390        ul = ntohl (ui32);
     391        memcpy (info, &ul, sizeof (ul));
     392        break;
     393      case CLSET_XID:
     394        /* This will set the xid of the NEXT call */
     395        memcpy (&ul, info, sizeof (ul));
     396        ui32 = htonl (ul - 1);
     397        memcpy (ct->ct_mcall, &ui32, sizeof (ui32));
     398        /* decrement by 1 as clnttcp_call() increments once */
     399        break;
     400      case CLGET_VERS:
     401        /*
     402         * This RELIES on the information that, in the call body,
     403         * the version number field is the fifth field from the
     404         * beginning of the RPC header. MUST be changed if the
     405         * call_struct is changed
     406         */
     407        memcpy (&ui32, ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT, sizeof (ui32));
     408        ul = ntohl (ui32);
     409        memcpy (info, &ul, sizeof (ul));
     410        break;
     411      case CLSET_VERS:
     412        memcpy (&ul, info, sizeof (ul));
     413        ui32 = htonl (ul);
     414        memcpy (ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT, &ui32, sizeof (ui32));
     415        break;
     416      case CLGET_PROG:
     417        /*
     418         * This RELIES on the information that, in the call body,
     419         * the program number field is the  field from the
     420         * beginning of the RPC header. MUST be changed if the
     421         * call_struct is changed
     422         */
     423        memcpy (&ui32, ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT, sizeof (ui32));
     424        ul = ntohl (ui32);
     425        memcpy (info, &ul, sizeof (ul));
     426        break;
     427      case CLSET_PROG:
     428        memcpy (&ul, info, sizeof (ul));
     429        ui32 = htonl (ul);
     430        memcpy (ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT, &ui32, sizeof (ui32));
     431        break;
     432      /* The following are only possible with TI-RPC */
     433      case CLGET_RETRY_TIMEOUT:
     434      case CLSET_RETRY_TIMEOUT:
     435      case CLGET_SVC_ADDR:
     436      case CLSET_SVC_ADDR:
     437      case CLSET_PUSH_TIMOD:
     438      case CLSET_POP_TIMOD:
     439      default:
     440        return FALSE;
     441      }
     442    return TRUE;
     443  }
     444  
     445  
     446  static void
     447  clnttcp_destroy (CLIENT *h)
     448  {
     449    struct ct_data *ct =
     450    (struct ct_data *) h->cl_private;
     451  
     452    if (ct->ct_closeit)
     453      {
     454        (void) __close (ct->ct_sock);
     455      }
     456    XDR_DESTROY (&(ct->ct_xdrs));
     457    mem_free ((caddr_t) ct, sizeof (struct ct_data));
     458    mem_free ((caddr_t) h, sizeof (CLIENT));
     459  }
     460  
     461  /*
     462   * Interface between xdr serializer and tcp connection.
     463   * Behaves like the system calls, read & write, but keeps some error state
     464   * around for the rpc level.
     465   */
     466  static int
     467  readtcp (char *ctptr, char *buf, int len)
     468  {
     469    struct ct_data *ct = (struct ct_data *)ctptr;
     470    struct pollfd fd;
     471    int milliseconds = (ct->ct_wait.tv_sec * 1000) +
     472      (ct->ct_wait.tv_usec / 1000);
     473  
     474    if (len == 0)
     475      return 0;
     476  
     477    fd.fd = ct->ct_sock;
     478    fd.events = POLLIN;
     479    while (TRUE)
     480      {
     481        switch (__poll(&fd, 1, milliseconds))
     482  	{
     483  	case 0:
     484  	  ct->ct_error.re_status = RPC_TIMEDOUT;
     485  	  return -1;
     486  
     487  	case -1:
     488  	  if (errno == EINTR)
     489  	    continue;
     490  	  ct->ct_error.re_status = RPC_CANTRECV;
     491  	  ct->ct_error.re_errno = errno;
     492  	  return -1;
     493  	}
     494        break;
     495      }
     496    switch (len = __read (ct->ct_sock, buf, len))
     497      {
     498  
     499      case 0:
     500        /* premature eof */
     501        ct->ct_error.re_errno = ECONNRESET;
     502        ct->ct_error.re_status = RPC_CANTRECV;
     503        len = -1;			/* it's really an error */
     504        break;
     505  
     506      case -1:
     507        ct->ct_error.re_errno = errno;
     508        ct->ct_error.re_status = RPC_CANTRECV;
     509        break;
     510      }
     511    return len;
     512  }
     513  
     514  static int
     515  writetcp (char *ctptr, char *buf, int len)
     516  {
     517    int i, cnt;
     518    struct ct_data *ct = (struct ct_data*)ctptr;
     519  
     520    for (cnt = len; cnt > 0; cnt -= i, buf += i)
     521      {
     522        if ((i = __write (ct->ct_sock, buf, cnt)) == -1)
     523  	{
     524  	  ct->ct_error.re_errno = errno;
     525  	  ct->ct_error.re_status = RPC_CANTSEND;
     526  	  return -1;
     527  	}
     528      }
     529    return len;
     530  }