mirror of
				https://sourceware.org/git/glibc.git
				synced 2025-10-30 10:45:40 +03:00 
			
		
		
		
	This patch changes the remaining uses of the old nonstandard u_intN_t types in glibc to use the C99 uintN_t instead, except for the definitions of those typedefs and the tests of them in the c++-types test. This follows the previous such fix for libm, and being consistent in using uintN_t makes sense as a global cleanup. Tested for x86_64, and with build-many-glibcs.py. * catgets/catgets.c (catgets): Use uintN_t instead of u_intN_t. * catgets/catgetsinfo.h (struct catalog_obj): Likewise. (struct catalog_info): Likewise. * inet/htontest.c (lo): Likewise. (foo): Likewise. * inet/inet_lnaof.c (inet_lnaof): Likewise. * inet/inet_net.c (inet_network): Likewise. * inet/inet_netof.c (inet_netof): Likewise. * inet/rcmd.c (__ivaliduser): Likewise. (iruserok): Likewise. * locale/loadlocale.c (_nl_intern_locale_data): Likewise. * locale/programs/locale-spec.c (locale_special): Likewise. * nis/nis_findserv.c (struct findserv_req): Likewise. (__nis_findfastest_with_timeout): Likewise. * nss/test-netdb.c (test_network): Likewise. * resolv/inet_neta.c (inet_neta): Likewise. * resolv/ns_date.c (ns_datetosecs): Likewise. (SECS_PER_DAY): Likewise. * resolv/nss_dns/dns-network.c (_nss_dns_getnetbyaddr_r): Likewise. * resolv/res_comp.c (__putlong): Likewise. (__putshort): Likewise. (_getlong): Likewise. (_getshort): Likewise. * resolv/res_debug.c (p_time): Likewise. (precsize_ntoa): Likewise. (precsize_aton): Likewise. (latlon2ul): Likewise. (loc_aton): Likewise. (loc_ntoa): Likewise. * resolv/res_hconf.c (struct netaddr): Likewise. (_res_hconf_reorder_addrs): Likewise. * sunrpc/clnt_tcp.c (clnttcp_call): Likewise. (clnttcp_control): Likewise. * sunrpc/clnt_udp.c (clntudp_call): Likewise. (clntudp_control): Likewise. * sunrpc/clnt_unix.c (clntunix_call): Likewise. (clntunix_control): Likewise. * sunrpc/pmap_rmt.c (clnt_broadcast): Likewise. * sunrpc/rpc/auth.h (union des_block): Likewise. * sunrpc/tst-udp-nonblocking.c (do_test): Likewise. * sunrpc/xdr_rec.c (struct rec_strm): Likewise. (xdrrec_create): Likewise. (xdrrec_endofrecord): Likewise. (flush_out): Likewise. * sunrpc/xdr_stdio.c (xdrstdio_getlong): Likewise. (xdrstdio_putlong): Likewise. * sysdeps/unix/sysv/linux/errqueue.h (struct sock_extended_err): Likewise.
		
			
				
	
	
		
			647 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			647 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * clnt_udp.c, Implements a UDP/IP based, client side RPC.
 | |
|  *
 | |
|  * Copyright (c) 2010, Oracle America, Inc.
 | |
|  *
 | |
|  * Redistribution and use in source and binary forms, with or without
 | |
|  * modification, are permitted provided that the following conditions are
 | |
|  * met:
 | |
|  *
 | |
|  *     * Redistributions of source code must retain the above copyright
 | |
|  *       notice, this list of conditions and the following disclaimer.
 | |
|  *     * Redistributions in binary form must reproduce the above
 | |
|  *       copyright notice, this list of conditions and the following
 | |
|  *       disclaimer in the documentation and/or other materials
 | |
|  *       provided with the distribution.
 | |
|  *     * Neither the name of the "Oracle America, Inc." nor the names of its
 | |
|  *       contributors may be used to endorse or promote products derived
 | |
|  *       from this software without specific prior written permission.
 | |
|  *
 | |
|  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | |
|  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | |
|  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 | |
|  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 | |
|  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 | |
|  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | |
|  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 | |
|  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | |
|  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | |
|  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | |
|  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | |
|  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <unistd.h>
 | |
| #include <libintl.h>
 | |
| #include <rpc/rpc.h>
 | |
| #include <rpc/xdr.h>
 | |
| #include <rpc/clnt.h>
 | |
| #include <sys/poll.h>
 | |
| #include <sys/socket.h>
 | |
| #include <sys/ioctl.h>
 | |
| #include <netdb.h>
 | |
| #include <errno.h>
 | |
| #include <stdint.h>
 | |
| #include <rpc/pmap_clnt.h>
 | |
| #include <net/if.h>
 | |
| #include <ifaddrs.h>
 | |
| #include <wchar.h>
 | |
| #include <fcntl.h>
 | |
| 
 | |
| #ifdef IP_RECVERR
 | |
| #include <errqueue.h>
 | |
| #include <sys/uio.h>
 | |
| #endif
 | |
| 
 | |
| #include <kernel-features.h>
 | |
| #include <inet/net-internal.h>
 | |
| #include <shlib-compat.h>
 | |
| 
 | |
| extern u_long _create_xid (void);
 | |
| 
 | |
| /*
 | |
|  * UDP bases client side rpc operations
 | |
|  */
 | |
| static enum clnt_stat clntudp_call (CLIENT *, u_long, xdrproc_t, caddr_t,
 | |
| 				    xdrproc_t, caddr_t, struct timeval);
 | |
| static void clntudp_abort (void);
 | |
| static void clntudp_geterr (CLIENT *, struct rpc_err *);
 | |
| static bool_t clntudp_freeres (CLIENT *, xdrproc_t, caddr_t);
 | |
| static bool_t clntudp_control (CLIENT *, int, char *);
 | |
| static void clntudp_destroy (CLIENT *);
 | |
| 
 | |
| static const struct clnt_ops udp_ops =
 | |
| {
 | |
|   clntudp_call,
 | |
|   clntudp_abort,
 | |
|   clntudp_geterr,
 | |
|   clntudp_freeres,
 | |
|   clntudp_destroy,
 | |
|   clntudp_control
 | |
| };
 | |
| 
 | |
| /*
 | |
|  * Private data kept per client handle.  This private struct is
 | |
|  * unfortunately part of the ABI; ypbind contains a copy of it and
 | |
|  * accesses it through CLIENT::cl_private field.
 | |
|  */
 | |
| struct cu_data
 | |
|   {
 | |
|     int cu_sock;
 | |
|     bool_t cu_closeit;
 | |
|     struct sockaddr_in cu_raddr;
 | |
|     int cu_rlen;
 | |
|     struct timeval cu_wait;
 | |
|     struct timeval cu_total;
 | |
|     struct rpc_err cu_error;
 | |
|     XDR cu_outxdrs;
 | |
|     u_int cu_xdrpos;
 | |
|     u_int cu_sendsz;
 | |
|     char *cu_outbuf;
 | |
|     u_int cu_recvsz;
 | |
|     char cu_inbuf[1];
 | |
|   };
 | |
| 
 | |
| /*
 | |
|  * Create a UDP based client handle.
 | |
|  * If *sockp<0, *sockp is set to a newly created UPD socket.
 | |
|  * If raddr->sin_port is 0 a binder on the remote machine
 | |
|  * is consulted for the correct port number.
 | |
|  * NB: It is the clients responsibility to close *sockp.
 | |
|  * NB: The rpch->cl_auth is initialized to null authentication.
 | |
|  *     Caller may wish to set this something more useful.
 | |
|  *
 | |
|  * wait is the amount of time used between retransmitting a call if
 | |
|  * no response has been heard; retransmission occurs until the actual
 | |
|  * rpc call times out.
 | |
|  *
 | |
|  * sendsz and recvsz are the maximum allowable packet sizes that can be
 | |
|  * sent and received.
 | |
|  */
 | |
| CLIENT *
 | |
| __libc_clntudp_bufcreate (struct sockaddr_in *raddr, u_long program,
 | |
| 			  u_long version, struct timeval wait, int *sockp,
 | |
| 			  u_int sendsz, u_int recvsz, int flags)
 | |
| {
 | |
|   CLIENT *cl;
 | |
|   struct cu_data *cu = NULL;
 | |
|   struct rpc_msg call_msg;
 | |
| 
 | |
|   cl = (CLIENT *) mem_alloc (sizeof (CLIENT));
 | |
|   sendsz = ((sendsz + 3) / 4) * 4;
 | |
|   recvsz = ((recvsz + 3) / 4) * 4;
 | |
|   cu = (struct cu_data *) mem_alloc (sizeof (*cu) + sendsz + recvsz);
 | |
|   if (cl == NULL || cu == NULL)
 | |
|     {
 | |
|       struct rpc_createerr *ce = &get_rpc_createerr ();
 | |
|       (void) __fxprintf (NULL, "%s: %s",
 | |
| 			 "clntudp_create", _("out of memory\n"));
 | |
|       ce->cf_stat = RPC_SYSTEMERROR;
 | |
|       ce->cf_error.re_errno = ENOMEM;
 | |
|       goto fooy;
 | |
|     }
 | |
|   cu->cu_outbuf = &cu->cu_inbuf[recvsz];
 | |
| 
 | |
|   if (raddr->sin_port == 0)
 | |
|     {
 | |
|       u_short port;
 | |
|       if ((port =
 | |
| 	   pmap_getport (raddr, program, version, IPPROTO_UDP)) == 0)
 | |
| 	{
 | |
| 	  goto fooy;
 | |
| 	}
 | |
|       raddr->sin_port = htons (port);
 | |
|     }
 | |
|   cl->cl_ops = (struct clnt_ops *) &udp_ops;
 | |
|   cl->cl_private = (caddr_t) cu;
 | |
|   cu->cu_raddr = *raddr;
 | |
|   cu->cu_rlen = sizeof (cu->cu_raddr);
 | |
|   cu->cu_wait = wait;
 | |
|   cu->cu_total.tv_sec = -1;
 | |
|   cu->cu_total.tv_usec = -1;
 | |
|   cu->cu_sendsz = sendsz;
 | |
|   cu->cu_recvsz = recvsz;
 | |
|   call_msg.rm_xid = _create_xid ();
 | |
|   call_msg.rm_direction = CALL;
 | |
|   call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
 | |
|   call_msg.rm_call.cb_prog = program;
 | |
|   call_msg.rm_call.cb_vers = version;
 | |
|   xdrmem_create (&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE);
 | |
|   if (!xdr_callhdr (&(cu->cu_outxdrs), &call_msg))
 | |
|     {
 | |
|       goto fooy;
 | |
|     }
 | |
|   cu->cu_xdrpos = XDR_GETPOS (&(cu->cu_outxdrs));
 | |
|   if (*sockp < 0)
 | |
|     {
 | |
|       *sockp = __socket (AF_INET, SOCK_DGRAM|SOCK_NONBLOCK|flags, IPPROTO_UDP);
 | |
|       if (__glibc_unlikely (*sockp < 0))
 | |
| 	{
 | |
| 	  struct rpc_createerr *ce = &get_rpc_createerr ();
 | |
| 	  ce->cf_stat = RPC_SYSTEMERROR;
 | |
| 	  ce->cf_error.re_errno = errno;
 | |
| 	  goto fooy;
 | |
| 	}
 | |
|       /* attempt to bind to prov port */
 | |
|       (void) bindresvport (*sockp, (struct sockaddr_in *) 0);
 | |
| #ifdef IP_RECVERR
 | |
|       {
 | |
| 	int on = 1;
 | |
| 	__setsockopt (*sockp, SOL_IP, IP_RECVERR, &on, sizeof(on));
 | |
|       }
 | |
| #endif
 | |
|       cu->cu_closeit = TRUE;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       cu->cu_closeit = FALSE;
 | |
|     }
 | |
|   cu->cu_sock = *sockp;
 | |
|   cl->cl_auth = authnone_create ();
 | |
|   return cl;
 | |
| fooy:
 | |
|   if (cu)
 | |
|     mem_free ((caddr_t) cu, sizeof (*cu) + sendsz + recvsz);
 | |
|   if (cl)
 | |
|     mem_free ((caddr_t) cl, sizeof (CLIENT));
 | |
|   return (CLIENT *) NULL;
 | |
| }
 | |
| #ifdef EXPORT_RPC_SYMBOLS
 | |
| libc_hidden_def (__libc_clntudp_bufcreate)
 | |
| #else
 | |
| libc_hidden_nolink_sunrpc (__libc_clntudp_bufcreate, GLIBC_PRIVATE)
 | |
| #endif
 | |
| 
 | |
| CLIENT *
 | |
| clntudp_bufcreate (struct sockaddr_in *raddr, u_long program, u_long version,
 | |
| 		   struct timeval wait, int *sockp, u_int sendsz,
 | |
| 		   u_int recvsz)
 | |
| {
 | |
|   return __libc_clntudp_bufcreate (raddr, program, version, wait,
 | |
| 				   sockp, sendsz, recvsz, 0);
 | |
| }
 | |
| libc_hidden_nolink_sunrpc (clntudp_bufcreate, GLIBC_2_0)
 | |
| 
 | |
| CLIENT *
 | |
| clntudp_create (struct sockaddr_in *raddr, u_long program, u_long version,
 | |
| 		struct timeval wait, int *sockp)
 | |
| {
 | |
|   return __libc_clntudp_bufcreate (raddr, program, version, wait,
 | |
| 				   sockp, UDPMSGSIZE, UDPMSGSIZE, 0);
 | |
| }
 | |
| #ifdef EXPORT_RPC_SYMBOLS
 | |
| libc_hidden_def (clntudp_create)
 | |
| #else
 | |
| libc_hidden_nolink_sunrpc (clntudp_create, GLIBC_2_0)
 | |
| #endif
 | |
| 
 | |
| static int
 | |
| is_network_up (int sock)
 | |
| {
 | |
|   struct ifaddrs *ifa;
 | |
| 
 | |
|   if (getifaddrs (&ifa) != 0)
 | |
|     return 0;
 | |
| 
 | |
|   struct ifaddrs *run = ifa;
 | |
|   while (run != NULL)
 | |
|     {
 | |
|       if ((run->ifa_flags & IFF_UP) != 0
 | |
| 	  && run->ifa_addr != NULL
 | |
| 	  && run->ifa_addr->sa_family == AF_INET)
 | |
| 	break;
 | |
| 
 | |
|       run = run->ifa_next;
 | |
|     }
 | |
| 
 | |
|   freeifaddrs (ifa);
 | |
| 
 | |
|   return run != NULL;
 | |
| }
 | |
| 
 | |
| static enum clnt_stat
 | |
| clntudp_call (/* client handle */
 | |
| 	      CLIENT *cl,
 | |
| 	      /* procedure number */
 | |
| 	      u_long proc,
 | |
| 	      /* xdr routine for args */
 | |
| 	      xdrproc_t xargs,
 | |
| 	      /* pointer to args */
 | |
| 	      caddr_t argsp,
 | |
| 	      /* xdr routine for results */
 | |
| 	      xdrproc_t xresults,
 | |
| 	      /* pointer to results */
 | |
| 	      caddr_t resultsp,
 | |
| 	      /* seconds to wait before giving up */
 | |
| 	      struct timeval utimeout)
 | |
| {
 | |
|   struct cu_data *cu = (struct cu_data *) cl->cl_private;
 | |
|   XDR *xdrs;
 | |
|   int outlen = 0;
 | |
|   int inlen;
 | |
|   socklen_t fromlen;
 | |
|   struct pollfd fd;
 | |
|   struct sockaddr_in from;
 | |
|   struct rpc_msg reply_msg;
 | |
|   XDR reply_xdrs;
 | |
|   bool_t ok;
 | |
|   int nrefreshes = 2;		/* number of times to refresh cred */
 | |
|   int anyup;			/* any network interface up */
 | |
| 
 | |
|   struct deadline_current_time current_time = __deadline_current_time ();
 | |
|   struct deadline total_deadline; /* Determined once by overall timeout.  */
 | |
|   struct deadline response_deadline; /* Determined anew for each query.  */
 | |
| 
 | |
|   /* Choose the timeout value.  For non-sending usage (xargs == NULL),
 | |
|      the total deadline does not matter, only cu->cu_wait is used
 | |
|      below.  */
 | |
|   if (xargs != NULL)
 | |
|     {
 | |
|       struct timeval tv;
 | |
|       if (cu->cu_total.tv_usec == -1)
 | |
| 	/* Use supplied timeout.  */
 | |
| 	tv = utimeout;
 | |
|       else
 | |
| 	/* Use default timeout.  */
 | |
| 	tv = cu->cu_total;
 | |
|       if (!__is_timeval_valid_timeout (tv))
 | |
| 	return (cu->cu_error.re_status = RPC_TIMEDOUT);
 | |
|       total_deadline = __deadline_from_timeval (current_time, tv);
 | |
|     }
 | |
| 
 | |
|   /* Guard against bad timeout specification.  */
 | |
|   if (!__is_timeval_valid_timeout (cu->cu_wait))
 | |
|     return (cu->cu_error.re_status = RPC_TIMEDOUT);
 | |
| 
 | |
| call_again:
 | |
|   xdrs = &(cu->cu_outxdrs);
 | |
|   if (xargs == NULL)
 | |
|     goto get_reply;
 | |
|   xdrs->x_op = XDR_ENCODE;
 | |
|   XDR_SETPOS (xdrs, cu->cu_xdrpos);
 | |
|   /*
 | |
|    * the transaction is the first thing in the out buffer
 | |
|    */
 | |
|   (*(uint32_t *) (cu->cu_outbuf))++;
 | |
|   if ((!XDR_PUTLONG (xdrs, (long *) &proc)) ||
 | |
|       (!AUTH_MARSHALL (cl->cl_auth, xdrs)) ||
 | |
|       (!(*xargs) (xdrs, argsp)))
 | |
|     return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
 | |
|   outlen = (int) XDR_GETPOS (xdrs);
 | |
| 
 | |
| send_again:
 | |
|   if (__sendto (cu->cu_sock, cu->cu_outbuf, outlen, 0,
 | |
| 		(struct sockaddr *) &(cu->cu_raddr), cu->cu_rlen)
 | |
|       != outlen)
 | |
|     {
 | |
|       cu->cu_error.re_errno = errno;
 | |
|       return (cu->cu_error.re_status = RPC_CANTSEND);
 | |
|     }
 | |
| 
 | |
|   /* sendto may have blocked, so recompute the current time.  */
 | |
|   current_time = __deadline_current_time ();
 | |
|  get_reply:
 | |
|   response_deadline = __deadline_from_timeval (current_time, cu->cu_wait);
 | |
| 
 | |
|   reply_msg.acpted_rply.ar_verf = _null_auth;
 | |
|   reply_msg.acpted_rply.ar_results.where = resultsp;
 | |
|   reply_msg.acpted_rply.ar_results.proc = xresults;
 | |
|   fd.fd = cu->cu_sock;
 | |
|   fd.events = POLLIN;
 | |
|   anyup = 0;
 | |
| 
 | |
|   /* Per-response retry loop.  current_time must be up-to-date at the
 | |
|      top of the loop.  */
 | |
|   for (;;)
 | |
|     {
 | |
|       int milliseconds;
 | |
|       if (xargs != NULL)
 | |
| 	{
 | |
| 	  if (__deadline_elapsed (current_time, total_deadline))
 | |
| 	    /* Overall timeout expired.  */
 | |
| 	    return (cu->cu_error.re_status = RPC_TIMEDOUT);
 | |
| 	  milliseconds = __deadline_to_ms
 | |
| 	    (current_time, __deadline_first (total_deadline,
 | |
| 					     response_deadline));
 | |
| 	  if (milliseconds == 0)
 | |
| 	    /* Per-query timeout expired.  */
 | |
| 	    goto send_again;
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	  /* xatgs == NULL.  Collect a response without sending a
 | |
| 	     query.  In this mode, we need to ignore the total
 | |
| 	     deadline.  */
 | |
| 	  milliseconds = __deadline_to_ms (current_time, response_deadline);
 | |
| 	  if (milliseconds == 0)
 | |
| 	    /* Cannot send again, so bail out.  */
 | |
| 	    return (cu->cu_error.re_status = RPC_CANTSEND);
 | |
| 	}
 | |
| 
 | |
|       switch (__poll (&fd, 1, milliseconds))
 | |
| 	{
 | |
| 
 | |
| 	case 0:
 | |
| 	  if (anyup == 0)
 | |
| 	    {
 | |
| 	      anyup = is_network_up (cu->cu_sock);
 | |
| 	      if (!anyup)
 | |
| 		return (cu->cu_error.re_status = RPC_CANTRECV);
 | |
| 	    }
 | |
| 	  goto next_response;
 | |
| 	case -1:
 | |
| 	  if (errno == EINTR)
 | |
| 	    goto next_response;
 | |
| 	  cu->cu_error.re_errno = errno;
 | |
| 	  return (cu->cu_error.re_status = RPC_CANTRECV);
 | |
| 	}
 | |
| #ifdef IP_RECVERR
 | |
|       if (fd.revents & POLLERR)
 | |
| 	{
 | |
| 	  struct msghdr msg;
 | |
| 	  struct cmsghdr *cmsg;
 | |
| 	  struct sock_extended_err *e;
 | |
| 	  struct sockaddr_in err_addr;
 | |
| 	  struct iovec iov;
 | |
| 	  char *cbuf = malloc (outlen + 256);
 | |
| 	  int ret;
 | |
| 
 | |
| 	  if (cbuf == NULL)
 | |
| 	    {
 | |
| 	      cu->cu_error.re_errno = errno;
 | |
| 	      return (cu->cu_error.re_status = RPC_CANTRECV);
 | |
| 	    }
 | |
| 
 | |
| 	  iov.iov_base = cbuf + 256;
 | |
| 	  iov.iov_len = outlen;
 | |
| 	  msg.msg_name = (void *) &err_addr;
 | |
| 	  msg.msg_namelen = sizeof (err_addr);
 | |
| 	  msg.msg_iov = &iov;
 | |
| 	  msg.msg_iovlen = 1;
 | |
| 	  msg.msg_flags = 0;
 | |
| 	  msg.msg_control = cbuf;
 | |
| 	  msg.msg_controllen = 256;
 | |
| 	  ret = __recvmsg (cu->cu_sock, &msg, MSG_ERRQUEUE);
 | |
| 	  if (ret >= 0
 | |
| 	      && memcmp (cbuf + 256, cu->cu_outbuf, ret) == 0
 | |
| 	      && (msg.msg_flags & MSG_ERRQUEUE)
 | |
| 	      && ((msg.msg_namelen == 0
 | |
| 		   && ret >= 12)
 | |
| 		  || (msg.msg_namelen == sizeof (err_addr)
 | |
| 		      && err_addr.sin_family == AF_INET
 | |
| 		      && memcmp (&err_addr.sin_addr, &cu->cu_raddr.sin_addr,
 | |
| 				 sizeof (err_addr.sin_addr)) == 0
 | |
| 		      && err_addr.sin_port == cu->cu_raddr.sin_port)))
 | |
| 	    for (cmsg = CMSG_FIRSTHDR (&msg); cmsg;
 | |
| 		 cmsg = CMSG_NXTHDR (&msg, cmsg))
 | |
| 	      if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR)
 | |
| 		{
 | |
| 		  e = (struct sock_extended_err *) CMSG_DATA(cmsg);
 | |
| 		  cu->cu_error.re_errno = e->ee_errno;
 | |
| 		  free (cbuf);
 | |
| 		  return (cu->cu_error.re_status = RPC_CANTRECV);
 | |
| 		}
 | |
| 	  free (cbuf);
 | |
| 	}
 | |
| #endif
 | |
|       do
 | |
| 	{
 | |
| 	  fromlen = sizeof (struct sockaddr);
 | |
| 	  inlen = __recvfrom (cu->cu_sock, cu->cu_inbuf,
 | |
| 			      (int) cu->cu_recvsz, MSG_DONTWAIT,
 | |
| 			      (struct sockaddr *) &from, &fromlen);
 | |
| 	}
 | |
|       while (inlen < 0 && errno == EINTR);
 | |
|       if (inlen < 0)
 | |
| 	{
 | |
| 	  if (errno == EWOULDBLOCK)
 | |
| 	    goto next_response;
 | |
| 	  cu->cu_error.re_errno = errno;
 | |
| 	  return (cu->cu_error.re_status = RPC_CANTRECV);
 | |
| 	}
 | |
|       /* Accept the response if the packet is sufficiently long and
 | |
| 	 the transaction ID matches the query (if available).  */
 | |
|       if (inlen >= 4
 | |
| 	  && (xargs == NULL
 | |
| 	      || memcmp (cu->cu_inbuf, cu->cu_outbuf,
 | |
| 			 sizeof (uint32_t)) == 0))
 | |
| 	break;
 | |
| 
 | |
|     next_response:
 | |
|       /* Update the current time because poll and recvmsg waited for
 | |
| 	 an unknown time.  */
 | |
|       current_time = __deadline_current_time ();
 | |
|     }
 | |
| 
 | |
|   /*
 | |
|    * now decode and validate the response
 | |
|    */
 | |
|   xdrmem_create (&reply_xdrs, cu->cu_inbuf, (u_int) inlen, XDR_DECODE);
 | |
|   ok = xdr_replymsg (&reply_xdrs, &reply_msg);
 | |
|   /* XDR_DESTROY(&reply_xdrs);  save a few cycles on noop destroy */
 | |
|   if (ok)
 | |
|     {
 | |
|       _seterr_reply (&reply_msg, &(cu->cu_error));
 | |
|       if (cu->cu_error.re_status == RPC_SUCCESS)
 | |
| 	{
 | |
| 	  if (!AUTH_VALIDATE (cl->cl_auth,
 | |
| 			      &reply_msg.acpted_rply.ar_verf))
 | |
| 	    {
 | |
| 	      cu->cu_error.re_status = RPC_AUTHERROR;
 | |
| 	      cu->cu_error.re_why = AUTH_INVALIDRESP;
 | |
| 	    }
 | |
| 	  if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
 | |
| 	    {
 | |
| 	      xdrs->x_op = XDR_FREE;
 | |
| 	      (void) xdr_opaque_auth (xdrs, &(reply_msg.acpted_rply.ar_verf));
 | |
| 	    }
 | |
| 	}			/* end successful completion */
 | |
|       else
 | |
| 	{
 | |
| 	  /* maybe our credentials need to be refreshed ... */
 | |
| 	  if (nrefreshes > 0 && AUTH_REFRESH (cl->cl_auth))
 | |
| 	    {
 | |
| 	      nrefreshes--;
 | |
| 	      goto call_again;
 | |
| 	    }
 | |
| 	}			/* end of unsuccessful completion */
 | |
|     }				/* end of valid reply message */
 | |
|   else
 | |
|     {
 | |
|       cu->cu_error.re_status = RPC_CANTDECODERES;
 | |
|     }
 | |
|   return cu->cu_error.re_status;
 | |
| }
 | |
| 
 | |
| static void
 | |
| clntudp_geterr (CLIENT *cl, struct rpc_err *errp)
 | |
| {
 | |
|   struct cu_data *cu = (struct cu_data *) cl->cl_private;
 | |
| 
 | |
|   *errp = cu->cu_error;
 | |
| }
 | |
| 
 | |
| 
 | |
| static bool_t
 | |
| clntudp_freeres (CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr)
 | |
| {
 | |
|   struct cu_data *cu = (struct cu_data *) cl->cl_private;
 | |
|   XDR *xdrs = &(cu->cu_outxdrs);
 | |
| 
 | |
|   xdrs->x_op = XDR_FREE;
 | |
|   return (*xdr_res) (xdrs, res_ptr);
 | |
| }
 | |
| 
 | |
| static void
 | |
| clntudp_abort (void)
 | |
| {
 | |
| }
 | |
| 
 | |
| static bool_t
 | |
| clntudp_control (CLIENT *cl, int request, char *info)
 | |
| {
 | |
|   struct cu_data *cu = (struct cu_data *) cl->cl_private;
 | |
|   u_long ul;
 | |
|   uint32_t ui32;
 | |
| 
 | |
|   switch (request)
 | |
|     {
 | |
|     case CLSET_FD_CLOSE:
 | |
|       cu->cu_closeit = TRUE;
 | |
|       break;
 | |
|     case CLSET_FD_NCLOSE:
 | |
|       cu->cu_closeit = FALSE;
 | |
|       break;
 | |
|     case CLSET_TIMEOUT:
 | |
|       cu->cu_total = *(struct timeval *) info;
 | |
|       break;
 | |
|     case CLGET_TIMEOUT:
 | |
|       *(struct timeval *) info = cu->cu_total;
 | |
|       break;
 | |
|     case CLSET_RETRY_TIMEOUT:
 | |
|       cu->cu_wait = *(struct timeval *) info;
 | |
|       break;
 | |
|     case CLGET_RETRY_TIMEOUT:
 | |
|       *(struct timeval *) info = cu->cu_wait;
 | |
|       break;
 | |
|     case CLGET_SERVER_ADDR:
 | |
|       *(struct sockaddr_in *) info = cu->cu_raddr;
 | |
|       break;
 | |
|     case CLGET_FD:
 | |
|       *(int *)info = cu->cu_sock;
 | |
|       break;
 | |
|     case CLGET_XID:
 | |
|       /*
 | |
|        * use the knowledge that xid is the
 | |
|        * first element in the call structure *.
 | |
|        * This will get the xid of the PREVIOUS call
 | |
|        */
 | |
|       memcpy (&ui32, cu->cu_outbuf, sizeof (ui32));
 | |
|       ul = ntohl (ui32);
 | |
|       memcpy (info, &ul, sizeof (ul));
 | |
|       break;
 | |
|     case CLSET_XID:
 | |
|       /* This will set the xid of the NEXT call */
 | |
|       memcpy (&ul, info, sizeof (ul));
 | |
|       ui32 = htonl (ul - 1);
 | |
|       memcpy (cu->cu_outbuf, &ui32, sizeof (ui32));
 | |
|       /* decrement by 1 as clntudp_call() increments once */
 | |
|       break;
 | |
|     case CLGET_VERS:
 | |
|       /*
 | |
|        * This RELIES on the information that, in the call body,
 | |
|        * the version number field is the fifth field from the
 | |
|        * beginning of the RPC header. MUST be changed if the
 | |
|        * call_struct is changed
 | |
|        */
 | |
|       memcpy (&ui32, cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT, sizeof (ui32));
 | |
|       ul = ntohl (ui32);
 | |
|       memcpy (info, &ul, sizeof (ul));
 | |
|       break;
 | |
|     case CLSET_VERS:
 | |
|       memcpy (&ul, info, sizeof (ul));
 | |
|       ui32 = htonl (ul);
 | |
|       memcpy (cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT, &ui32, sizeof (ui32));
 | |
|       break;
 | |
|     case CLGET_PROG:
 | |
|       /*
 | |
|        * This RELIES on the information that, in the call body,
 | |
|        * the program number field is the  field from the
 | |
|        * beginning of the RPC header. MUST be changed if the
 | |
|        * call_struct is changed
 | |
|        */
 | |
|       memcpy (&ui32, cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT, sizeof (ui32));
 | |
|       ul = ntohl (ui32);
 | |
|       memcpy (info, &ul, sizeof (ul));
 | |
|       break;
 | |
|     case CLSET_PROG:
 | |
|       memcpy (&ul, info, sizeof (ul));
 | |
|       ui32 = htonl (ul);
 | |
|       memcpy (cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT, &ui32, sizeof (ui32));
 | |
|       break;
 | |
|     /* The following are only possible with TI-RPC */
 | |
|     case CLGET_SVC_ADDR:
 | |
|     case CLSET_SVC_ADDR:
 | |
|     case CLSET_PUSH_TIMOD:
 | |
|     case CLSET_POP_TIMOD:
 | |
|     default:
 | |
|       return FALSE;
 | |
|     }
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| clntudp_destroy (CLIENT *cl)
 | |
| {
 | |
|   struct cu_data *cu = (struct cu_data *) cl->cl_private;
 | |
| 
 | |
|   if (cu->cu_closeit)
 | |
|     {
 | |
|       (void) __close (cu->cu_sock);
 | |
|     }
 | |
|   XDR_DESTROY (&(cu->cu_outxdrs));
 | |
|   mem_free ((caddr_t) cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz));
 | |
|   mem_free ((caddr_t) cl, sizeof (CLIENT));
 | |
| }
 |