size_t fromlen;
socklen_t fromlen;
clntudp_call (cl, proc, xargs, argsp, xresults, resultsp, utimeout)     CLIENT *cl;	/* client handle */     u_long proc;		/* procedure number */     xdrproc_t xargs;		/* xdr routine for args */     caddr_t argsp;		/* pointer to args */     xdrproc_t xresults;	/* xdr routine for results */     caddr_t resultsp;		/* pointer to results */     struct timeval utimeout;	/* seconds to wait before giving up */{  struct cu_data *cu = (struct cu_data *) cl->cl_private;  XDR *xdrs;  int outlen = 0;  int inlen;  size_t fromlen;#ifdef FD_SETSIZE  fd_set readfds;  fd_set mask;#else  int readfds;  int mask;#endif /* def FD_SETSIZE */  struct sockaddr_in from;  struct rpc_msg reply_msg;  XDR reply_xdrs;  struct timeval time_waited;  bool_t ok;  int nrefreshes = 2;		/* number of times to refresh cred */  struct timeval timeout;  if (cu->cu_total.tv_usec == -1)    {      timeout = utimeout;	/* use supplied timeout */    }  else    {      timeout = cu->cu_total;	/* use default timeout */    }  time_waited.tv_sec = 0;  time_waited.tv_usec = 0;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   */  (*(u_short *) (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);    }  /*   * Hack to provide rpc-based message passing   */  if (timeout.tv_sec == 0 && timeout.tv_usec == 0)    {      return (cu->cu_error.re_status = RPC_TIMEDOUT);    } get_reply:  /*   * sub-optimal code appears here because we have   * some clock time to spare while the packets are in flight.   * (We assume that this is actually only executed once.)   */  reply_msg.acpted_rply.ar_verf = _null_auth;  reply_msg.acpted_rply.ar_results.where = resultsp;  reply_msg.acpted_rply.ar_results.proc = xresults;#ifdef FD_SETSIZE  FD_ZERO (&mask);  FD_SET (cu->cu_sock, &mask);#else  mask = 1 << cu->cu_sock;#endif /* def FD_SETSIZE */  for (;;)    {      struct timeval cu_wait = cu->cu_wait;      readfds = mask;      switch (select (_rpc_dtablesize (), &readfds, (fd_set*) NULL,		      (fd_set*) NULL, &cu_wait))	{	case 0:	  time_waited.tv_sec += cu->cu_wait.tv_sec;	  time_waited.tv_usec += cu->cu_wait.tv_usec;	  while (time_waited.tv_usec >= 1000000)	    {	      time_waited.tv_sec++;	      time_waited.tv_usec -= 1000000;	    }	  if ((time_waited.tv_sec < timeout.tv_sec) ||	      ((time_waited.tv_sec == timeout.tv_sec) &&	       (time_waited.tv_usec < timeout.tv_usec)))	    goto send_again;	  return (cu->cu_error.re_status = RPC_TIMEDOUT);	  /*	   * buggy in other cases because time_waited is not being	   * updated.	   */	case -1:	  if (errno == EINTR)	    continue;	  cu->cu_error.re_errno = errno;	  return (cu->cu_error.re_status = RPC_CANTRECV);	}      do	{	  fromlen = sizeof (struct sockaddr);	  inlen = recvfrom (cu->cu_sock, cu->cu_inbuf,			    (int) cu->cu_recvsz, 0,			    (struct sockaddr *) &from, &fromlen);	}      while (inlen < 0 && errno == EINTR);      if (inlen < 0)	{	  if (errno == EWOULDBLOCK)	    continue;	  cu->cu_error.re_errno = errno;	  return (cu->cu_error.re_status = RPC_CANTRECV);	}      if (inlen < 4)	continue;      /* see if reply transaction id matches sent id */      if (*((u_int32_t *) (cu->cu_inbuf)) != *((u_int32_t *) (cu->cu_outbuf)))	continue;      /* we now assume we have the proper reply */      break;    }  /*   * 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;}