1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate /* 28*7c478bd9Sstevel@tonic-gate * Copyright (c) 1984, 1986, 1987, 1988, 1989, 1996 AT&T 29*7c478bd9Sstevel@tonic-gate * All Rights Reserved 30*7c478bd9Sstevel@tonic-gate */ 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate /* 33*7c478bd9Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988 34*7c478bd9Sstevel@tonic-gate * The Regents of the University of California 35*7c478bd9Sstevel@tonic-gate * All Rights Reserved 36*7c478bd9Sstevel@tonic-gate * 37*7c478bd9Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from 38*7c478bd9Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 39*7c478bd9Sstevel@tonic-gate * contributors. 40*7c478bd9Sstevel@tonic-gate */ 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate /* 45*7c478bd9Sstevel@tonic-gate * clnt_udp.c, Implements a UDP/IP based, client side RPC. 46*7c478bd9Sstevel@tonic-gate */ 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate #include <rpc/rpc.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 52*7c478bd9Sstevel@tonic-gate #include <netdb.h> 53*7c478bd9Sstevel@tonic-gate #include <errno.h> 54*7c478bd9Sstevel@tonic-gate #include <rpc/pmap_clnt.h> 55*7c478bd9Sstevel@tonic-gate #include <rpc/clnt_soc.h> 56*7c478bd9Sstevel@tonic-gate #include <syslog.h> 57*7c478bd9Sstevel@tonic-gate #include <sys/filio.h> 58*7c478bd9Sstevel@tonic-gate #include <malloc.h> 59*7c478bd9Sstevel@tonic-gate #include <unistd.h> 60*7c478bd9Sstevel@tonic-gate #include <stropts.h> 61*7c478bd9Sstevel@tonic-gate #include <stdio.h> 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate extern int errno; 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate extern int _socket(int, int, int); 67*7c478bd9Sstevel@tonic-gate extern pid_t getpid(); 68*7c478bd9Sstevel@tonic-gate extern int bindresvport(int, struct sockaddr_in *); 69*7c478bd9Sstevel@tonic-gate extern bool_t xdr_opaque_auth(XDR *, struct opaque_auth *); 70*7c478bd9Sstevel@tonic-gate extern int _sendto(int, const char *, int, int, 71*7c478bd9Sstevel@tonic-gate const struct sockaddr *, int); 72*7c478bd9Sstevel@tonic-gate extern int _recvfrom(int, char *, int, int, 73*7c478bd9Sstevel@tonic-gate struct sockaddr *, int *); 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate static struct clnt_ops *clntudp_ops(); 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate /* 79*7c478bd9Sstevel@tonic-gate * Private data kept per client handle 80*7c478bd9Sstevel@tonic-gate */ 81*7c478bd9Sstevel@tonic-gate struct cu_data { 82*7c478bd9Sstevel@tonic-gate int cu_sock; 83*7c478bd9Sstevel@tonic-gate bool_t cu_closeit; 84*7c478bd9Sstevel@tonic-gate struct sockaddr_in cu_raddr; 85*7c478bd9Sstevel@tonic-gate int cu_rlen; 86*7c478bd9Sstevel@tonic-gate struct timeval cu_wait; 87*7c478bd9Sstevel@tonic-gate struct timeval cu_total; 88*7c478bd9Sstevel@tonic-gate struct rpc_err cu_error; 89*7c478bd9Sstevel@tonic-gate XDR cu_outxdrs; 90*7c478bd9Sstevel@tonic-gate u_int cu_xdrpos; 91*7c478bd9Sstevel@tonic-gate u_int cu_sendsz; 92*7c478bd9Sstevel@tonic-gate char *cu_outbuf; 93*7c478bd9Sstevel@tonic-gate u_int cu_recvsz; 94*7c478bd9Sstevel@tonic-gate char cu_inbuf[1]; 95*7c478bd9Sstevel@tonic-gate }; 96*7c478bd9Sstevel@tonic-gate 97*7c478bd9Sstevel@tonic-gate /* 98*7c478bd9Sstevel@tonic-gate * Create a UDP based client handle. 99*7c478bd9Sstevel@tonic-gate * If *sockp<0, *sockp is set to a newly created UPD socket. 100*7c478bd9Sstevel@tonic-gate * If raddr->sin_port is 0 a binder on the remote machine 101*7c478bd9Sstevel@tonic-gate * is consulted for the correct port number. 102*7c478bd9Sstevel@tonic-gate * NB: It is the clients responsibility to close *sockp. 103*7c478bd9Sstevel@tonic-gate * NB: The rpch->cl_auth is initialized to null authentication. 104*7c478bd9Sstevel@tonic-gate * Caller may wish to set this something more useful. 105*7c478bd9Sstevel@tonic-gate * 106*7c478bd9Sstevel@tonic-gate * wait is the amount of time used between retransmitting a call if 107*7c478bd9Sstevel@tonic-gate * no response has been heard; retransmition occurs until the actual 108*7c478bd9Sstevel@tonic-gate * rpc call times out. 109*7c478bd9Sstevel@tonic-gate * 110*7c478bd9Sstevel@tonic-gate * sendsz and recvsz are the maximum allowable packet sizes that can be 111*7c478bd9Sstevel@tonic-gate * sent and received. 112*7c478bd9Sstevel@tonic-gate */ 113*7c478bd9Sstevel@tonic-gate CLIENT * 114*7c478bd9Sstevel@tonic-gate clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz) 115*7c478bd9Sstevel@tonic-gate struct sockaddr_in *raddr; 116*7c478bd9Sstevel@tonic-gate rpcprog_t program; 117*7c478bd9Sstevel@tonic-gate rpcvers_t version; 118*7c478bd9Sstevel@tonic-gate struct timeval wait; 119*7c478bd9Sstevel@tonic-gate register int *sockp; 120*7c478bd9Sstevel@tonic-gate u_int sendsz; 121*7c478bd9Sstevel@tonic-gate u_int recvsz; 122*7c478bd9Sstevel@tonic-gate { 123*7c478bd9Sstevel@tonic-gate CLIENT *cl; 124*7c478bd9Sstevel@tonic-gate register struct cu_data *cu; 125*7c478bd9Sstevel@tonic-gate struct timeval now; 126*7c478bd9Sstevel@tonic-gate struct rpc_msg call_msg; 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate cl = (CLIENT *)mem_alloc(sizeof (CLIENT)); 129*7c478bd9Sstevel@tonic-gate if (cl == NULL) { 130*7c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "clntudp_create: out of memory"); 131*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SYSTEMERROR; 132*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_errno = errno; 133*7c478bd9Sstevel@tonic-gate goto fooy; 134*7c478bd9Sstevel@tonic-gate } 135*7c478bd9Sstevel@tonic-gate sendsz = ((sendsz + 3) / 4) * 4; 136*7c478bd9Sstevel@tonic-gate recvsz = ((recvsz + 3) / 4) * 4; 137*7c478bd9Sstevel@tonic-gate cu = (struct cu_data *)mem_alloc(sizeof (*cu) + sendsz + recvsz); 138*7c478bd9Sstevel@tonic-gate if (cu == NULL) { 139*7c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, "clntudp_create: out of memory"); 140*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SYSTEMERROR; 141*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_errno = errno; 142*7c478bd9Sstevel@tonic-gate goto fooy; 143*7c478bd9Sstevel@tonic-gate } 144*7c478bd9Sstevel@tonic-gate cu->cu_outbuf = &cu->cu_inbuf[recvsz]; 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate (void) gettimeofday(&now, (struct timezone *)0); 147*7c478bd9Sstevel@tonic-gate if (raddr->sin_port == 0) { 148*7c478bd9Sstevel@tonic-gate u_short port; 149*7c478bd9Sstevel@tonic-gate if ((port = 150*7c478bd9Sstevel@tonic-gate pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) { 151*7c478bd9Sstevel@tonic-gate goto fooy; 152*7c478bd9Sstevel@tonic-gate } 153*7c478bd9Sstevel@tonic-gate raddr->sin_port = htons(port); 154*7c478bd9Sstevel@tonic-gate } 155*7c478bd9Sstevel@tonic-gate cl->cl_ops = clntudp_ops(); 156*7c478bd9Sstevel@tonic-gate cl->cl_private = (caddr_t)cu; 157*7c478bd9Sstevel@tonic-gate cu->cu_raddr = *raddr; 158*7c478bd9Sstevel@tonic-gate cu->cu_rlen = sizeof (cu->cu_raddr); 159*7c478bd9Sstevel@tonic-gate cu->cu_wait = wait; 160*7c478bd9Sstevel@tonic-gate cu->cu_total.tv_sec = -1; 161*7c478bd9Sstevel@tonic-gate cu->cu_total.tv_usec = -1; 162*7c478bd9Sstevel@tonic-gate cu->cu_sendsz = sendsz; 163*7c478bd9Sstevel@tonic-gate cu->cu_recvsz = recvsz; 164*7c478bd9Sstevel@tonic-gate call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec; 165*7c478bd9Sstevel@tonic-gate call_msg.rm_direction = CALL; 166*7c478bd9Sstevel@tonic-gate call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 167*7c478bd9Sstevel@tonic-gate call_msg.rm_call.cb_prog = program; 168*7c478bd9Sstevel@tonic-gate call_msg.rm_call.cb_vers = version; 169*7c478bd9Sstevel@tonic-gate xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, 170*7c478bd9Sstevel@tonic-gate sendsz, XDR_ENCODE); 171*7c478bd9Sstevel@tonic-gate if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { 172*7c478bd9Sstevel@tonic-gate goto fooy; 173*7c478bd9Sstevel@tonic-gate } 174*7c478bd9Sstevel@tonic-gate cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); 175*7c478bd9Sstevel@tonic-gate if (*sockp < 0) { 176*7c478bd9Sstevel@tonic-gate int dontblock = 1; 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate *sockp = _socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 179*7c478bd9Sstevel@tonic-gate if (*sockp < 0) { 180*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SYSTEMERROR; 181*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_errno = errno; 182*7c478bd9Sstevel@tonic-gate goto fooy; 183*7c478bd9Sstevel@tonic-gate } 184*7c478bd9Sstevel@tonic-gate /* attempt to bind to prov port */ 185*7c478bd9Sstevel@tonic-gate (void) bindresvport(*sockp, (struct sockaddr_in *)0); 186*7c478bd9Sstevel@tonic-gate /* the sockets rpc controls are non-blocking */ 187*7c478bd9Sstevel@tonic-gate (void) ioctl(*sockp, FIONBIO, (char *) &dontblock); 188*7c478bd9Sstevel@tonic-gate cu->cu_closeit = TRUE; 189*7c478bd9Sstevel@tonic-gate } else { 190*7c478bd9Sstevel@tonic-gate cu->cu_closeit = FALSE; 191*7c478bd9Sstevel@tonic-gate } 192*7c478bd9Sstevel@tonic-gate cu->cu_sock = *sockp; 193*7c478bd9Sstevel@tonic-gate cl->cl_auth = authnone_create(); 194*7c478bd9Sstevel@tonic-gate return (cl); 195*7c478bd9Sstevel@tonic-gate fooy: 196*7c478bd9Sstevel@tonic-gate if (cu) 197*7c478bd9Sstevel@tonic-gate mem_free((caddr_t)cu, sizeof (*cu) + sendsz + recvsz); 198*7c478bd9Sstevel@tonic-gate if (cl) 199*7c478bd9Sstevel@tonic-gate mem_free((caddr_t)cl, sizeof (CLIENT)); 200*7c478bd9Sstevel@tonic-gate return ((CLIENT *)NULL); 201*7c478bd9Sstevel@tonic-gate } 202*7c478bd9Sstevel@tonic-gate 203*7c478bd9Sstevel@tonic-gate CLIENT * 204*7c478bd9Sstevel@tonic-gate clntudp_create(raddr, program, version, wait, sockp) 205*7c478bd9Sstevel@tonic-gate struct sockaddr_in *raddr; 206*7c478bd9Sstevel@tonic-gate rpcprog_t program; 207*7c478bd9Sstevel@tonic-gate rpcvers_t version; 208*7c478bd9Sstevel@tonic-gate struct timeval wait; 209*7c478bd9Sstevel@tonic-gate register int *sockp; 210*7c478bd9Sstevel@tonic-gate { 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate return (clntudp_bufcreate(raddr, program, version, wait, sockp, 213*7c478bd9Sstevel@tonic-gate UDPMSGSIZE, UDPMSGSIZE)); 214*7c478bd9Sstevel@tonic-gate } 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate static enum clnt_stat 217*7c478bd9Sstevel@tonic-gate clntudp_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) 218*7c478bd9Sstevel@tonic-gate register CLIENT *cl; /* client handle */ 219*7c478bd9Sstevel@tonic-gate rpcproc_t proc; /* procedure number */ 220*7c478bd9Sstevel@tonic-gate xdrproc_t xargs; /* xdr routine for args */ 221*7c478bd9Sstevel@tonic-gate caddr_t argsp; /* pointer to args */ 222*7c478bd9Sstevel@tonic-gate xdrproc_t xresults; /* xdr routine for results */ 223*7c478bd9Sstevel@tonic-gate caddr_t resultsp; /* pointer to results */ 224*7c478bd9Sstevel@tonic-gate struct timeval utimeout; /* seconds to wait before giving up */ 225*7c478bd9Sstevel@tonic-gate { 226*7c478bd9Sstevel@tonic-gate register struct cu_data *cu = (struct cu_data *)cl->cl_private; 227*7c478bd9Sstevel@tonic-gate register XDR *xdrs; 228*7c478bd9Sstevel@tonic-gate register int outlen; 229*7c478bd9Sstevel@tonic-gate register int inlen; 230*7c478bd9Sstevel@tonic-gate int fromlen; 231*7c478bd9Sstevel@tonic-gate fd_set readfds; 232*7c478bd9Sstevel@tonic-gate fd_set mask; 233*7c478bd9Sstevel@tonic-gate struct sockaddr_in from; 234*7c478bd9Sstevel@tonic-gate struct rpc_msg reply_msg; 235*7c478bd9Sstevel@tonic-gate XDR reply_xdrs; 236*7c478bd9Sstevel@tonic-gate struct timeval startime, curtime; 237*7c478bd9Sstevel@tonic-gate int firsttimeout = 1; 238*7c478bd9Sstevel@tonic-gate struct timeval time_waited; 239*7c478bd9Sstevel@tonic-gate struct timeval retransmit_time; 240*7c478bd9Sstevel@tonic-gate bool_t ok; 241*7c478bd9Sstevel@tonic-gate int nrefreshes = 2; /* number of times to refresh cred */ 242*7c478bd9Sstevel@tonic-gate struct timeval timeout; 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate if (cu->cu_total.tv_usec == -1) { 245*7c478bd9Sstevel@tonic-gate timeout = utimeout; /* use supplied timeout */ 246*7c478bd9Sstevel@tonic-gate } else { 247*7c478bd9Sstevel@tonic-gate timeout = cu->cu_total; /* use default timeout */ 248*7c478bd9Sstevel@tonic-gate } 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate time_waited.tv_sec = 0; 251*7c478bd9Sstevel@tonic-gate time_waited.tv_usec = 0; 252*7c478bd9Sstevel@tonic-gate retransmit_time = cu->cu_wait; 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate call_again: 255*7c478bd9Sstevel@tonic-gate xdrs = &(cu->cu_outxdrs); 256*7c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_ENCODE; 257*7c478bd9Sstevel@tonic-gate XDR_SETPOS(xdrs, cu->cu_xdrpos); 258*7c478bd9Sstevel@tonic-gate /* 259*7c478bd9Sstevel@tonic-gate * the transaction is the first thing in the out buffer 260*7c478bd9Sstevel@tonic-gate */ 261*7c478bd9Sstevel@tonic-gate (*(u_short *)(cu->cu_outbuf))++; 262*7c478bd9Sstevel@tonic-gate if ((! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || 263*7c478bd9Sstevel@tonic-gate (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || 264*7c478bd9Sstevel@tonic-gate (! (*xargs)(xdrs, argsp))) 265*7c478bd9Sstevel@tonic-gate return (cu->cu_error.re_status = RPC_CANTENCODEARGS); 266*7c478bd9Sstevel@tonic-gate outlen = (int)XDR_GETPOS(xdrs); 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate send_again: 269*7c478bd9Sstevel@tonic-gate if (_sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0, 270*7c478bd9Sstevel@tonic-gate (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen) 271*7c478bd9Sstevel@tonic-gate != outlen) { 272*7c478bd9Sstevel@tonic-gate cu->cu_error.re_errno = errno; 273*7c478bd9Sstevel@tonic-gate return (cu->cu_error.re_status = RPC_CANTSEND); 274*7c478bd9Sstevel@tonic-gate } 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate /* 277*7c478bd9Sstevel@tonic-gate * Hack to provide rpc-based message passing 278*7c478bd9Sstevel@tonic-gate */ 279*7c478bd9Sstevel@tonic-gate if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 280*7c478bd9Sstevel@tonic-gate return (cu->cu_error.re_status = RPC_TIMEDOUT); 281*7c478bd9Sstevel@tonic-gate } 282*7c478bd9Sstevel@tonic-gate /* 283*7c478bd9Sstevel@tonic-gate * sub-optimal code appears here because we have 284*7c478bd9Sstevel@tonic-gate * some clock time to spare while the packets are in flight. 285*7c478bd9Sstevel@tonic-gate * (We assume that this is actually only executed once.) 286*7c478bd9Sstevel@tonic-gate */ 287*7c478bd9Sstevel@tonic-gate reply_msg.acpted_rply.ar_verf = _null_auth; 288*7c478bd9Sstevel@tonic-gate reply_msg.acpted_rply.ar_results.where = resultsp; 289*7c478bd9Sstevel@tonic-gate reply_msg.acpted_rply.ar_results.proc = xresults; 290*7c478bd9Sstevel@tonic-gate FD_ZERO(&mask); 291*7c478bd9Sstevel@tonic-gate FD_SET(cu->cu_sock, &mask); 292*7c478bd9Sstevel@tonic-gate for (;;) { 293*7c478bd9Sstevel@tonic-gate readfds = mask; 294*7c478bd9Sstevel@tonic-gate switch (select(__rpc_dtbsize(), &readfds, NULL, 295*7c478bd9Sstevel@tonic-gate NULL, &(retransmit_time))) { 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate case 0: 298*7c478bd9Sstevel@tonic-gate time_waited.tv_sec += retransmit_time.tv_sec; 299*7c478bd9Sstevel@tonic-gate time_waited.tv_usec += retransmit_time.tv_usec; 300*7c478bd9Sstevel@tonic-gate while (time_waited.tv_usec >= 1000000) { 301*7c478bd9Sstevel@tonic-gate time_waited.tv_sec++; 302*7c478bd9Sstevel@tonic-gate time_waited.tv_usec -= 1000000; 303*7c478bd9Sstevel@tonic-gate } 304*7c478bd9Sstevel@tonic-gate 305*7c478bd9Sstevel@tonic-gate /* update retransmit_time */ 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate if (retransmit_time.tv_sec < RPC_MAX_BACKOFF) { 308*7c478bd9Sstevel@tonic-gate retransmit_time.tv_usec += retransmit_time.tv_usec; 309*7c478bd9Sstevel@tonic-gate retransmit_time.tv_sec += retransmit_time.tv_sec; 310*7c478bd9Sstevel@tonic-gate while (retransmit_time.tv_usec >= 1000000) { 311*7c478bd9Sstevel@tonic-gate retransmit_time.tv_sec++; 312*7c478bd9Sstevel@tonic-gate retransmit_time.tv_usec -= 1000000; 313*7c478bd9Sstevel@tonic-gate } 314*7c478bd9Sstevel@tonic-gate } 315*7c478bd9Sstevel@tonic-gate 316*7c478bd9Sstevel@tonic-gate if ((time_waited.tv_sec < timeout.tv_sec) || 317*7c478bd9Sstevel@tonic-gate ((time_waited.tv_sec == timeout.tv_sec) && 318*7c478bd9Sstevel@tonic-gate (time_waited.tv_usec < timeout.tv_usec))) 319*7c478bd9Sstevel@tonic-gate goto send_again; 320*7c478bd9Sstevel@tonic-gate return (cu->cu_error.re_status = RPC_TIMEDOUT); 321*7c478bd9Sstevel@tonic-gate 322*7c478bd9Sstevel@tonic-gate /* 323*7c478bd9Sstevel@tonic-gate * buggy in other cases because time_waited is not being 324*7c478bd9Sstevel@tonic-gate * updated. 325*7c478bd9Sstevel@tonic-gate */ 326*7c478bd9Sstevel@tonic-gate case -1: 327*7c478bd9Sstevel@tonic-gate if (errno != EINTR) { 328*7c478bd9Sstevel@tonic-gate cu->cu_error.re_errno = errno; 329*7c478bd9Sstevel@tonic-gate return (cu->cu_error.re_status = RPC_CANTRECV); 330*7c478bd9Sstevel@tonic-gate } 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate /* interrupted by another signal, update time_waited */ 333*7c478bd9Sstevel@tonic-gate if (firsttimeout) { 334*7c478bd9Sstevel@tonic-gate /* 335*7c478bd9Sstevel@tonic-gate * Could have done gettimeofday before clnt_call 336*7c478bd9Sstevel@tonic-gate * but that means 1 more system call per each 337*7c478bd9Sstevel@tonic-gate * clnt_call, so do it after first time out 338*7c478bd9Sstevel@tonic-gate */ 339*7c478bd9Sstevel@tonic-gate if (gettimeofday(&startime, 340*7c478bd9Sstevel@tonic-gate (struct timezone *) NULL) == -1) { 341*7c478bd9Sstevel@tonic-gate errno = 0; 342*7c478bd9Sstevel@tonic-gate continue; 343*7c478bd9Sstevel@tonic-gate } 344*7c478bd9Sstevel@tonic-gate firsttimeout = 0; 345*7c478bd9Sstevel@tonic-gate errno = 0; 346*7c478bd9Sstevel@tonic-gate continue; 347*7c478bd9Sstevel@tonic-gate }; 348*7c478bd9Sstevel@tonic-gate 349*7c478bd9Sstevel@tonic-gate if (gettimeofday(&curtime, 350*7c478bd9Sstevel@tonic-gate (struct timezone *) NULL) == -1) { 351*7c478bd9Sstevel@tonic-gate errno = 0; 352*7c478bd9Sstevel@tonic-gate continue; 353*7c478bd9Sstevel@tonic-gate }; 354*7c478bd9Sstevel@tonic-gate 355*7c478bd9Sstevel@tonic-gate time_waited.tv_sec += curtime.tv_sec - startime.tv_sec; 356*7c478bd9Sstevel@tonic-gate time_waited.tv_usec += curtime.tv_usec - 357*7c478bd9Sstevel@tonic-gate startime.tv_usec; 358*7c478bd9Sstevel@tonic-gate while (time_waited.tv_usec < 0) { 359*7c478bd9Sstevel@tonic-gate time_waited.tv_sec--; 360*7c478bd9Sstevel@tonic-gate time_waited.tv_usec += 1000000; 361*7c478bd9Sstevel@tonic-gate }; 362*7c478bd9Sstevel@tonic-gate while (time_waited.tv_usec >= 1000000) { 363*7c478bd9Sstevel@tonic-gate time_waited.tv_sec++; 364*7c478bd9Sstevel@tonic-gate time_waited.tv_usec -= 1000000; 365*7c478bd9Sstevel@tonic-gate } 366*7c478bd9Sstevel@tonic-gate startime.tv_sec = curtime.tv_sec; 367*7c478bd9Sstevel@tonic-gate startime.tv_usec = curtime.tv_usec; 368*7c478bd9Sstevel@tonic-gate if ((time_waited.tv_sec > timeout.tv_sec) || 369*7c478bd9Sstevel@tonic-gate ((time_waited.tv_sec == timeout.tv_sec) && 370*7c478bd9Sstevel@tonic-gate (time_waited.tv_usec > timeout.tv_usec))) { 371*7c478bd9Sstevel@tonic-gate return (cu->cu_error.re_status = RPC_TIMEDOUT); 372*7c478bd9Sstevel@tonic-gate } 373*7c478bd9Sstevel@tonic-gate errno = 0; /* reset it */ 374*7c478bd9Sstevel@tonic-gate continue; 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate } 377*7c478bd9Sstevel@tonic-gate do { 378*7c478bd9Sstevel@tonic-gate fromlen = sizeof (struct sockaddr); 379*7c478bd9Sstevel@tonic-gate inlen = _recvfrom(cu->cu_sock, cu->cu_inbuf, 380*7c478bd9Sstevel@tonic-gate (int) cu->cu_recvsz, 0, 381*7c478bd9Sstevel@tonic-gate (struct sockaddr *)&from, &fromlen); 382*7c478bd9Sstevel@tonic-gate } while (inlen < 0 && errno == EINTR); 383*7c478bd9Sstevel@tonic-gate if (inlen < 0) { 384*7c478bd9Sstevel@tonic-gate if (errno == EWOULDBLOCK) 385*7c478bd9Sstevel@tonic-gate continue; 386*7c478bd9Sstevel@tonic-gate cu->cu_error.re_errno = errno; 387*7c478bd9Sstevel@tonic-gate return (cu->cu_error.re_status = RPC_CANTRECV); 388*7c478bd9Sstevel@tonic-gate } 389*7c478bd9Sstevel@tonic-gate if (inlen < sizeof (uint32_t)) 390*7c478bd9Sstevel@tonic-gate continue; 391*7c478bd9Sstevel@tonic-gate /* see if reply transaction id matches sent id */ 392*7c478bd9Sstevel@tonic-gate if (*((uint32_t *)(cu->cu_inbuf)) != 393*7c478bd9Sstevel@tonic-gate *((uint32_t *)(cu->cu_outbuf))) 394*7c478bd9Sstevel@tonic-gate continue; 395*7c478bd9Sstevel@tonic-gate /* we now assume we have the proper reply */ 396*7c478bd9Sstevel@tonic-gate break; 397*7c478bd9Sstevel@tonic-gate } 398*7c478bd9Sstevel@tonic-gate 399*7c478bd9Sstevel@tonic-gate /* 400*7c478bd9Sstevel@tonic-gate * now decode and validate the response 401*7c478bd9Sstevel@tonic-gate */ 402*7c478bd9Sstevel@tonic-gate xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE); 403*7c478bd9Sstevel@tonic-gate ok = xdr_replymsg(&reply_xdrs, &reply_msg); 404*7c478bd9Sstevel@tonic-gate /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ 405*7c478bd9Sstevel@tonic-gate if (ok) { 406*7c478bd9Sstevel@tonic-gate __seterr_reply(&reply_msg, &(cu->cu_error)); 407*7c478bd9Sstevel@tonic-gate if (cu->cu_error.re_status == RPC_SUCCESS) { 408*7c478bd9Sstevel@tonic-gate if (! AUTH_VALIDATE(cl->cl_auth, 409*7c478bd9Sstevel@tonic-gate &reply_msg.acpted_rply.ar_verf)) { 410*7c478bd9Sstevel@tonic-gate cu->cu_error.re_status = RPC_AUTHERROR; 411*7c478bd9Sstevel@tonic-gate cu->cu_error.re_why = AUTH_INVALIDRESP; 412*7c478bd9Sstevel@tonic-gate } 413*7c478bd9Sstevel@tonic-gate if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 414*7c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_FREE; 415*7c478bd9Sstevel@tonic-gate (void) xdr_opaque_auth(xdrs, 416*7c478bd9Sstevel@tonic-gate &(reply_msg.acpted_rply.ar_verf)); 417*7c478bd9Sstevel@tonic-gate } 418*7c478bd9Sstevel@tonic-gate } /* end successful completion */ 419*7c478bd9Sstevel@tonic-gate else { 420*7c478bd9Sstevel@tonic-gate /* maybe our credentials need to be refreshed ... */ 421*7c478bd9Sstevel@tonic-gate if (nrefreshes > 0 && 422*7c478bd9Sstevel@tonic-gate AUTH_REFRESH(cl->cl_auth, &reply_msg)) { 423*7c478bd9Sstevel@tonic-gate nrefreshes--; 424*7c478bd9Sstevel@tonic-gate goto call_again; 425*7c478bd9Sstevel@tonic-gate } 426*7c478bd9Sstevel@tonic-gate } /* end of unsuccessful completion */ 427*7c478bd9Sstevel@tonic-gate } /* end of valid reply message */ 428*7c478bd9Sstevel@tonic-gate else { 429*7c478bd9Sstevel@tonic-gate cu->cu_error.re_status = RPC_CANTDECODERES; 430*7c478bd9Sstevel@tonic-gate } 431*7c478bd9Sstevel@tonic-gate return (cu->cu_error.re_status); 432*7c478bd9Sstevel@tonic-gate } 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate static void 435*7c478bd9Sstevel@tonic-gate clntudp_geterr(cl, errp) 436*7c478bd9Sstevel@tonic-gate CLIENT *cl; 437*7c478bd9Sstevel@tonic-gate struct rpc_err *errp; 438*7c478bd9Sstevel@tonic-gate { 439*7c478bd9Sstevel@tonic-gate register struct cu_data *cu = (struct cu_data *)cl->cl_private; 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate *errp = cu->cu_error; 442*7c478bd9Sstevel@tonic-gate } 443*7c478bd9Sstevel@tonic-gate 444*7c478bd9Sstevel@tonic-gate 445*7c478bd9Sstevel@tonic-gate static bool_t 446*7c478bd9Sstevel@tonic-gate clntudp_freeres(cl, xdr_res, res_ptr) 447*7c478bd9Sstevel@tonic-gate CLIENT *cl; 448*7c478bd9Sstevel@tonic-gate xdrproc_t xdr_res; 449*7c478bd9Sstevel@tonic-gate caddr_t res_ptr; 450*7c478bd9Sstevel@tonic-gate { 451*7c478bd9Sstevel@tonic-gate register struct cu_data *cu = (struct cu_data *)cl->cl_private; 452*7c478bd9Sstevel@tonic-gate register XDR *xdrs = &(cu->cu_outxdrs); 453*7c478bd9Sstevel@tonic-gate 454*7c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_FREE; 455*7c478bd9Sstevel@tonic-gate return ((*xdr_res)(xdrs, res_ptr)); 456*7c478bd9Sstevel@tonic-gate } 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate static void 459*7c478bd9Sstevel@tonic-gate clntudp_abort() 460*7c478bd9Sstevel@tonic-gate /* CLIENT *h; */ 461*7c478bd9Sstevel@tonic-gate { 462*7c478bd9Sstevel@tonic-gate } 463*7c478bd9Sstevel@tonic-gate 464*7c478bd9Sstevel@tonic-gate static bool_t 465*7c478bd9Sstevel@tonic-gate clntudp_control(cl, request, info) 466*7c478bd9Sstevel@tonic-gate CLIENT *cl; 467*7c478bd9Sstevel@tonic-gate int request; 468*7c478bd9Sstevel@tonic-gate char *info; 469*7c478bd9Sstevel@tonic-gate { 470*7c478bd9Sstevel@tonic-gate register struct cu_data *cu = (struct cu_data *)cl->cl_private; 471*7c478bd9Sstevel@tonic-gate 472*7c478bd9Sstevel@tonic-gate switch (request) { 473*7c478bd9Sstevel@tonic-gate case CLSET_TIMEOUT: 474*7c478bd9Sstevel@tonic-gate cu->cu_total = *(struct timeval *)info; 475*7c478bd9Sstevel@tonic-gate break; 476*7c478bd9Sstevel@tonic-gate case CLGET_TIMEOUT: 477*7c478bd9Sstevel@tonic-gate *(struct timeval *)info = cu->cu_total; 478*7c478bd9Sstevel@tonic-gate break; 479*7c478bd9Sstevel@tonic-gate case CLSET_RETRY_TIMEOUT: 480*7c478bd9Sstevel@tonic-gate cu->cu_wait = *(struct timeval *)info; 481*7c478bd9Sstevel@tonic-gate break; 482*7c478bd9Sstevel@tonic-gate case CLGET_RETRY_TIMEOUT: 483*7c478bd9Sstevel@tonic-gate *(struct timeval *)info = cu->cu_wait; 484*7c478bd9Sstevel@tonic-gate break; 485*7c478bd9Sstevel@tonic-gate case CLGET_SERVER_ADDR: 486*7c478bd9Sstevel@tonic-gate *(struct sockaddr_in *)info = cu->cu_raddr; 487*7c478bd9Sstevel@tonic-gate break; 488*7c478bd9Sstevel@tonic-gate case CLGET_FD: 489*7c478bd9Sstevel@tonic-gate *(int *)info = cu->cu_sock; 490*7c478bd9Sstevel@tonic-gate break; 491*7c478bd9Sstevel@tonic-gate case CLSET_FD_CLOSE: 492*7c478bd9Sstevel@tonic-gate cu->cu_closeit = TRUE; 493*7c478bd9Sstevel@tonic-gate break; 494*7c478bd9Sstevel@tonic-gate case CLSET_FD_NCLOSE: 495*7c478bd9Sstevel@tonic-gate cu->cu_closeit = FALSE; 496*7c478bd9Sstevel@tonic-gate break; 497*7c478bd9Sstevel@tonic-gate default: 498*7c478bd9Sstevel@tonic-gate return (FALSE); 499*7c478bd9Sstevel@tonic-gate } 500*7c478bd9Sstevel@tonic-gate return (TRUE); 501*7c478bd9Sstevel@tonic-gate } 502*7c478bd9Sstevel@tonic-gate 503*7c478bd9Sstevel@tonic-gate static void 504*7c478bd9Sstevel@tonic-gate clntudp_destroy(cl) 505*7c478bd9Sstevel@tonic-gate CLIENT *cl; 506*7c478bd9Sstevel@tonic-gate { 507*7c478bd9Sstevel@tonic-gate register struct cu_data *cu = (struct cu_data *)cl->cl_private; 508*7c478bd9Sstevel@tonic-gate 509*7c478bd9Sstevel@tonic-gate if (cu->cu_closeit) { 510*7c478bd9Sstevel@tonic-gate (void) close(cu->cu_sock); 511*7c478bd9Sstevel@tonic-gate } 512*7c478bd9Sstevel@tonic-gate XDR_DESTROY(&(cu->cu_outxdrs)); 513*7c478bd9Sstevel@tonic-gate mem_free((caddr_t)cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz)); 514*7c478bd9Sstevel@tonic-gate mem_free((caddr_t)cl, sizeof (CLIENT)); 515*7c478bd9Sstevel@tonic-gate } 516*7c478bd9Sstevel@tonic-gate 517*7c478bd9Sstevel@tonic-gate static struct clnt_ops * 518*7c478bd9Sstevel@tonic-gate clntudp_ops() 519*7c478bd9Sstevel@tonic-gate { 520*7c478bd9Sstevel@tonic-gate static struct clnt_ops ops; 521*7c478bd9Sstevel@tonic-gate 522*7c478bd9Sstevel@tonic-gate if (ops.cl_call == NULL) { 523*7c478bd9Sstevel@tonic-gate ops.cl_call = clntudp_call; 524*7c478bd9Sstevel@tonic-gate ops.cl_abort = clntudp_abort; 525*7c478bd9Sstevel@tonic-gate ops.cl_geterr = clntudp_geterr; 526*7c478bd9Sstevel@tonic-gate ops.cl_freeres = clntudp_freeres; 527*7c478bd9Sstevel@tonic-gate ops.cl_destroy = clntudp_destroy; 528*7c478bd9Sstevel@tonic-gate ops.cl_control = clntudp_control; 529*7c478bd9Sstevel@tonic-gate } 530*7c478bd9Sstevel@tonic-gate return (&ops); 531*7c478bd9Sstevel@tonic-gate } 532