clnt_dg.c revision 105189
174462Salfred/* $NetBSD: clnt_dg.c,v 1.4 2000/07/14 08:40:41 fvdl Exp $ */ 274462Salfred 374462Salfred/* 474462Salfred * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 574462Salfred * unrestricted use provided that this legend is included on all tape 674462Salfred * media and as a part of the software program in whole or part. Users 774462Salfred * may copy or modify Sun RPC without charge, but are not authorized 874462Salfred * to license or distribute it to anyone else except as part of a product or 974462Salfred * program developed by the user. 1074462Salfred * 1174462Salfred * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 1274462Salfred * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 1374462Salfred * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 1474462Salfred * 1574462Salfred * Sun RPC is provided with no support and without any obligation on the 1674462Salfred * part of Sun Microsystems, Inc. to assist in its use, correction, 1774462Salfred * modification or enhancement. 1874462Salfred * 1974462Salfred * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 2074462Salfred * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 2174462Salfred * OR ANY PART THEREOF. 2274462Salfred * 2374462Salfred * In no event will Sun Microsystems, Inc. be liable for any lost revenue 2474462Salfred * or profits or other special, indirect and consequential damages, even if 2574462Salfred * Sun has been advised of the possibility of such damages. 2674462Salfred * 2774462Salfred * Sun Microsystems, Inc. 2874462Salfred * 2550 Garcia Avenue 2974462Salfred * Mountain View, California 94043 3074462Salfred */ 3174462Salfred/* 3274462Salfred * Copyright (c) 1986-1991 by Sun Microsystems Inc. 3374462Salfred */ 3474462Salfred 3574462Salfred/* #ident "@(#)clnt_dg.c 1.23 94/04/22 SMI" */ 3674462Salfred 3774462Salfred#if !defined(lint) && defined(SCCSIDS) 3874462Salfredstatic char sccsid[] = "@(#)clnt_dg.c 1.19 89/03/16 Copyr 1988 Sun Micro"; 3974462Salfred#endif 4092990Sobrien#include <sys/cdefs.h> 4192990Sobrien__FBSDID("$FreeBSD: head/lib/libc/rpc/clnt_dg.c 105189 2002-10-15 22:28:59Z iedowse $"); 4274462Salfred 4374462Salfred/* 4474462Salfred * Implements a connectionless client side RPC. 4574462Salfred */ 4674462Salfred 4775094Siedowse#include "namespace.h" 4874462Salfred#include "reentrant.h" 4974462Salfred#include <sys/types.h> 50105189Siedowse#include <sys/event.h> 5174462Salfred#include <sys/time.h> 5274462Salfred#include <sys/socket.h> 5374462Salfred#include <sys/ioctl.h> 5490868Smike#include <arpa/inet.h> 5574462Salfred#include <rpc/rpc.h> 5674462Salfred#include <errno.h> 5774462Salfred#include <stdlib.h> 5874462Salfred#include <string.h> 5974462Salfred#include <signal.h> 6074462Salfred#include <unistd.h> 6174462Salfred#include <err.h> 6274462Salfred#include "un-namespace.h" 6374462Salfred#include "rpc_com.h" 6474462Salfred 6574462Salfred 6674462Salfred#define RPC_MAX_BACKOFF 30 /* seconds */ 6774462Salfred 6874462Salfred 6992905Sobrienstatic struct clnt_ops *clnt_dg_ops(void); 7092905Sobrienstatic bool_t time_not_ok(struct timeval *); 7195658Sdesstatic enum clnt_stat clnt_dg_call(CLIENT *, rpcproc_t, xdrproc_t, void *, 7295658Sdes xdrproc_t, void *, struct timeval); 7392905Sobrienstatic void clnt_dg_geterr(CLIENT *, struct rpc_err *); 7495658Sdesstatic bool_t clnt_dg_freeres(CLIENT *, xdrproc_t, void *); 7592905Sobrienstatic void clnt_dg_abort(CLIENT *); 7699996Salfredstatic bool_t clnt_dg_control(CLIENT *, u_int, void *); 7792905Sobrienstatic void clnt_dg_destroy(CLIENT *); 7874462Salfred 7974462Salfred 8074462Salfred 8174462Salfred 8274462Salfred/* 8374462Salfred * This machinery implements per-fd locks for MT-safety. It is not 8474462Salfred * sufficient to do per-CLIENT handle locks for MT-safety because a 8574462Salfred * user may create more than one CLIENT handle with the same fd behind 8674462Salfred * it. Therfore, we allocate an array of flags (dg_fd_locks), protected 8774462Salfred * by the clnt_fd_lock mutex, and an array (dg_cv) of condition variables 8874462Salfred * similarly protected. Dg_fd_lock[fd] == 1 => a call is activte on some 8974462Salfred * CLIENT handle created for that fd. 9074462Salfred * The current implementation holds locks across the entire RPC and reply, 9174462Salfred * including retransmissions. Yes, this is silly, and as soon as this 9274462Salfred * code is proven to work, this should be the first thing fixed. One step 9374462Salfred * at a time. 9474462Salfred */ 9574462Salfredstatic int *dg_fd_locks; 9674462Salfredextern mutex_t clnt_fd_lock; 9774462Salfredstatic cond_t *dg_cv; 9874462Salfred#define release_fd_lock(fd, mask) { \ 9974462Salfred mutex_lock(&clnt_fd_lock); \ 10075144Siedowse dg_fd_locks[fd] = 0; \ 10174462Salfred mutex_unlock(&clnt_fd_lock); \ 102105189Siedowse thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \ 10374462Salfred cond_signal(&dg_cv[fd]); \ 10474462Salfred} 10574462Salfred 10674462Salfredstatic const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory"; 10774462Salfred 10874462Salfred/* VARIABLES PROTECTED BY clnt_fd_lock: dg_fd_locks, dg_cv */ 10974462Salfred 11074462Salfred/* 11174462Salfred * Private data kept per client handle 11274462Salfred */ 11374462Salfredstruct cu_data { 11474462Salfred int cu_fd; /* connections fd */ 11574462Salfred bool_t cu_closeit; /* opened by library */ 11674462Salfred struct sockaddr_storage cu_raddr; /* remote address */ 11774462Salfred int cu_rlen; 11874462Salfred struct timeval cu_wait; /* retransmit interval */ 11974462Salfred struct timeval cu_total; /* total time for the call */ 12074462Salfred struct rpc_err cu_error; 12174462Salfred XDR cu_outxdrs; 12274462Salfred u_int cu_xdrpos; 12374462Salfred u_int cu_sendsz; /* send size */ 12474462Salfred char *cu_outbuf; 12574462Salfred u_int cu_recvsz; /* recv size */ 12674879Swpaul int cu_async; 12778678Siedowse int cu_connect; /* Use connect(). */ 12878678Siedowse int cu_connected; /* Have done connect(). */ 129105189Siedowse struct kevent cu_kin; 130105189Siedowse int cu_kq; 13174462Salfred char cu_inbuf[1]; 13274462Salfred}; 13374462Salfred 13474462Salfred/* 13574462Salfred * Connection less client creation returns with client handle parameters. 13674462Salfred * Default options are set, which the user can change using clnt_control(). 13774462Salfred * fd should be open and bound. 13874462Salfred * NB: The rpch->cl_auth is initialized to null authentication. 13974462Salfred * Caller may wish to set this something more useful. 14074462Salfred * 14174462Salfred * sendsz and recvsz are the maximum allowable packet sizes that can be 14274462Salfred * sent and received. Normally they are the same, but they can be 14374462Salfred * changed to improve the program efficiency and buffer allocation. 14474462Salfred * If they are 0, use the transport default. 14574462Salfred * 14674462Salfred * If svcaddr is NULL, returns NULL. 14774462Salfred */ 14874462SalfredCLIENT * 14974462Salfredclnt_dg_create(fd, svcaddr, program, version, sendsz, recvsz) 15074462Salfred int fd; /* open file descriptor */ 15174462Salfred const struct netbuf *svcaddr; /* servers address */ 15274462Salfred rpcprog_t program; /* program number */ 15374462Salfred rpcvers_t version; /* version number */ 15474462Salfred u_int sendsz; /* buffer recv size */ 15574462Salfred u_int recvsz; /* buffer send size */ 15674462Salfred{ 15774462Salfred CLIENT *cl = NULL; /* client handle */ 15874462Salfred struct cu_data *cu = NULL; /* private data */ 15974462Salfred struct timeval now; 16074462Salfred struct rpc_msg call_msg; 16174462Salfred sigset_t mask; 16274462Salfred sigset_t newmask; 16374462Salfred struct __rpc_sockinfo si; 16474462Salfred int one = 1; 16574462Salfred 16674462Salfred sigfillset(&newmask); 16774462Salfred thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 16874462Salfred mutex_lock(&clnt_fd_lock); 16974462Salfred if (dg_fd_locks == (int *) NULL) { 17074462Salfred int cv_allocsz; 17174462Salfred size_t fd_allocsz; 17274462Salfred int dtbsize = __rpc_dtbsize(); 17374462Salfred 17474462Salfred fd_allocsz = dtbsize * sizeof (int); 17574462Salfred dg_fd_locks = (int *) mem_alloc(fd_allocsz); 17674462Salfred if (dg_fd_locks == (int *) NULL) { 17774462Salfred mutex_unlock(&clnt_fd_lock); 17874462Salfred thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 17974462Salfred goto err1; 18074462Salfred } else 18174462Salfred memset(dg_fd_locks, '\0', fd_allocsz); 18274462Salfred 18374462Salfred cv_allocsz = dtbsize * sizeof (cond_t); 18474462Salfred dg_cv = (cond_t *) mem_alloc(cv_allocsz); 18574462Salfred if (dg_cv == (cond_t *) NULL) { 18674462Salfred mem_free(dg_fd_locks, fd_allocsz); 18774462Salfred dg_fd_locks = (int *) NULL; 18874462Salfred mutex_unlock(&clnt_fd_lock); 18974462Salfred thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 19074462Salfred goto err1; 19174462Salfred } else { 19274462Salfred int i; 19374462Salfred 19474462Salfred for (i = 0; i < dtbsize; i++) 19574462Salfred cond_init(&dg_cv[i], 0, (void *) 0); 19674462Salfred } 19774462Salfred } 19874462Salfred 19974462Salfred mutex_unlock(&clnt_fd_lock); 20074462Salfred thr_sigsetmask(SIG_SETMASK, &(mask), NULL); 20174462Salfred 20274462Salfred if (svcaddr == NULL) { 20374462Salfred rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 20474462Salfred return (NULL); 20574462Salfred } 20674462Salfred 20774462Salfred if (!__rpc_fd2sockinfo(fd, &si)) { 20874462Salfred rpc_createerr.cf_stat = RPC_TLIERROR; 20974462Salfred rpc_createerr.cf_error.re_errno = 0; 21074462Salfred return (NULL); 21174462Salfred } 21274462Salfred /* 21374462Salfred * Find the receive and the send size 21474462Salfred */ 21574462Salfred sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 21674462Salfred recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 21774462Salfred if ((sendsz == 0) || (recvsz == 0)) { 21874462Salfred rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */ 21974462Salfred rpc_createerr.cf_error.re_errno = 0; 22074462Salfred return (NULL); 22174462Salfred } 22274462Salfred 22374462Salfred if ((cl = mem_alloc(sizeof (CLIENT))) == NULL) 22474462Salfred goto err1; 22574462Salfred /* 22674462Salfred * Should be multiple of 4 for XDR. 22774462Salfred */ 22874462Salfred sendsz = ((sendsz + 3) / 4) * 4; 22974462Salfred recvsz = ((recvsz + 3) / 4) * 4; 23074462Salfred cu = mem_alloc(sizeof (*cu) + sendsz + recvsz); 23174462Salfred if (cu == NULL) 23274462Salfred goto err1; 23374462Salfred (void) memcpy(&cu->cu_raddr, svcaddr->buf, (size_t)svcaddr->len); 23474462Salfred cu->cu_rlen = svcaddr->len; 23574462Salfred cu->cu_outbuf = &cu->cu_inbuf[recvsz]; 23674462Salfred /* Other values can also be set through clnt_control() */ 23774462Salfred cu->cu_wait.tv_sec = 15; /* heuristically chosen */ 23874462Salfred cu->cu_wait.tv_usec = 0; 23974462Salfred cu->cu_total.tv_sec = -1; 24074462Salfred cu->cu_total.tv_usec = -1; 24174462Salfred cu->cu_sendsz = sendsz; 24274462Salfred cu->cu_recvsz = recvsz; 24374879Swpaul cu->cu_async = FALSE; 24478678Siedowse cu->cu_connect = FALSE; 24578678Siedowse cu->cu_connected = FALSE; 24674462Salfred (void) gettimeofday(&now, NULL); 24774462Salfred call_msg.rm_xid = __RPC_GETXID(&now); 24874462Salfred call_msg.rm_call.cb_prog = program; 24974462Salfred call_msg.rm_call.cb_vers = version; 25074462Salfred xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE); 25174462Salfred if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { 25274462Salfred rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */ 25374462Salfred rpc_createerr.cf_error.re_errno = 0; 25474462Salfred goto err2; 25574462Salfred } 25674462Salfred cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); 25774462Salfred 25874462Salfred /* XXX fvdl - do we still want this? */ 25974462Salfred#if 0 26074462Salfred (void)bindresvport_sa(fd, (struct sockaddr *)svcaddr->buf); 26174462Salfred#endif 26274462Salfred _ioctl(fd, FIONBIO, (char *)(void *)&one); 26374462Salfred 26474462Salfred /* 26574462Salfred * By default, closeit is always FALSE. It is users responsibility 26674462Salfred * to do a close on it, else the user may use clnt_control 26774462Salfred * to let clnt_destroy do it for him/her. 26874462Salfred */ 26974462Salfred cu->cu_closeit = FALSE; 27074462Salfred cu->cu_fd = fd; 27174462Salfred cl->cl_ops = clnt_dg_ops(); 27274462Salfred cl->cl_private = (caddr_t)(void *)cu; 27374462Salfred cl->cl_auth = authnone_create(); 27474462Salfred cl->cl_tp = NULL; 27574462Salfred cl->cl_netid = NULL; 276105189Siedowse cu->cu_kq = -1; 277105189Siedowse EV_SET(&cu->cu_kin, cu->cu_fd, EVFILT_READ, EV_ADD, 0, 0, 0); 27874462Salfred return (cl); 27974462Salfrederr1: 28074462Salfred warnx(mem_err_clnt_dg); 28174462Salfred rpc_createerr.cf_stat = RPC_SYSTEMERROR; 28274462Salfred rpc_createerr.cf_error.re_errno = errno; 28374462Salfrederr2: 28474462Salfred if (cl) { 28574462Salfred mem_free(cl, sizeof (CLIENT)); 28674462Salfred if (cu) 28774462Salfred mem_free(cu, sizeof (*cu) + sendsz + recvsz); 28874462Salfred } 28974462Salfred return (NULL); 29074462Salfred} 29174462Salfred 29274462Salfredstatic enum clnt_stat 29374462Salfredclnt_dg_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) 29474462Salfred CLIENT *cl; /* client handle */ 29574462Salfred rpcproc_t proc; /* procedure number */ 29674462Salfred xdrproc_t xargs; /* xdr routine for args */ 29795658Sdes void *argsp; /* pointer to args */ 29874462Salfred xdrproc_t xresults; /* xdr routine for results */ 29995658Sdes void *resultsp; /* pointer to results */ 30074462Salfred struct timeval utimeout; /* seconds to wait before giving up */ 30174462Salfred{ 30274462Salfred struct cu_data *cu = (struct cu_data *)cl->cl_private; 30374462Salfred XDR *xdrs; 304105189Siedowse size_t outlen = 0; 30574462Salfred struct rpc_msg reply_msg; 30674462Salfred XDR reply_xdrs; 30774462Salfred bool_t ok; 30874462Salfred int nrefreshes = 2; /* number of times to refresh cred */ 30974462Salfred struct timeval timeout; 31074462Salfred struct timeval retransmit_time; 311105189Siedowse struct timeval next_sendtime, starttime, time_waited, tv; 312105189Siedowse struct timespec ts; 313105189Siedowse struct kevent kv; 31478678Siedowse struct sockaddr *sa; 31574462Salfred sigset_t mask; 31674462Salfred sigset_t newmask; 31778678Siedowse socklen_t inlen, salen; 31874462Salfred ssize_t recvlen = 0; 319105189Siedowse int kin_len, n, rpc_lock_value; 32074879Swpaul u_int32_t xid; 32174462Salfred 32290271Salfred outlen = 0; 32374462Salfred sigfillset(&newmask); 32474462Salfred thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 32574462Salfred mutex_lock(&clnt_fd_lock); 32674462Salfred while (dg_fd_locks[cu->cu_fd]) 32774462Salfred cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); 32874462Salfred if (__isthreaded) 32974462Salfred rpc_lock_value = 1; 33074462Salfred else 33174462Salfred rpc_lock_value = 0; 33274462Salfred dg_fd_locks[cu->cu_fd] = rpc_lock_value; 33374462Salfred mutex_unlock(&clnt_fd_lock); 33474462Salfred if (cu->cu_total.tv_usec == -1) { 33574462Salfred timeout = utimeout; /* use supplied timeout */ 33674462Salfred } else { 33774462Salfred timeout = cu->cu_total; /* use default timeout */ 33874462Salfred } 33974462Salfred 34078678Siedowse if (cu->cu_connect && !cu->cu_connected) { 34178678Siedowse if (_connect(cu->cu_fd, (struct sockaddr *)&cu->cu_raddr, 34278678Siedowse cu->cu_rlen) < 0) { 34378678Siedowse cu->cu_error.re_errno = errno; 344105189Siedowse cu->cu_error.re_status = RPC_CANTSEND; 345105189Siedowse goto out; 34678678Siedowse } 34778678Siedowse cu->cu_connected = 1; 34878678Siedowse } 34978678Siedowse if (cu->cu_connected) { 35078678Siedowse sa = NULL; 35178678Siedowse salen = 0; 35278678Siedowse } else { 35378678Siedowse sa = (struct sockaddr *)&cu->cu_raddr; 35478678Siedowse salen = cu->cu_rlen; 35578678Siedowse } 35674462Salfred time_waited.tv_sec = 0; 35774462Salfred time_waited.tv_usec = 0; 358105189Siedowse retransmit_time = next_sendtime = cu->cu_wait; 359105189Siedowse gettimeofday(&starttime, NULL); 36074462Salfred 361105189Siedowse /* Clean up in case the last call ended in a longjmp(3) call. */ 362105189Siedowse if (cu->cu_kq >= 0) 363105189Siedowse _close(cu->cu_kq); 364105189Siedowse if ((cu->cu_kq = kqueue()) < 0) { 365105189Siedowse cu->cu_error.re_errno = errno; 366105189Siedowse cu->cu_error.re_status = RPC_CANTSEND; 367105189Siedowse goto out; 368105189Siedowse } 369105189Siedowse kin_len = 1; 370105189Siedowse 37174462Salfredcall_again: 37274462Salfred xdrs = &(cu->cu_outxdrs); 37374879Swpaul if (cu->cu_async == TRUE && xargs == NULL) 37474879Swpaul goto get_reply; 37574462Salfred xdrs->x_op = XDR_ENCODE; 37674462Salfred XDR_SETPOS(xdrs, cu->cu_xdrpos); 37774462Salfred /* 37874462Salfred * the transaction is the first thing in the out buffer 37974879Swpaul * XXX Yes, and it's in network byte order, so we should to 38074879Swpaul * be careful when we increment it, shouldn't we. 38174462Salfred */ 38274879Swpaul xid = ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf)); 38374879Swpaul xid++; 38474879Swpaul *(u_int32_t *)(void *)(cu->cu_outbuf) = htonl(xid); 38574879Swpaul 38674462Salfred if ((! XDR_PUTINT32(xdrs, &proc)) || 38774462Salfred (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || 38874462Salfred (! (*xargs)(xdrs, argsp))) { 389105189Siedowse cu->cu_error.re_status = RPC_CANTENCODEARGS; 390105189Siedowse goto out; 39174462Salfred } 39274462Salfred outlen = (size_t)XDR_GETPOS(xdrs); 39374462Salfred 39474462Salfredsend_again: 39578678Siedowse if (_sendto(cu->cu_fd, cu->cu_outbuf, outlen, 0, sa, salen) != outlen) { 39674462Salfred cu->cu_error.re_errno = errno; 397105189Siedowse cu->cu_error.re_status = RPC_CANTSEND; 398105189Siedowse goto out; 39974462Salfred } 40074462Salfred 40174462Salfred /* 40274462Salfred * Hack to provide rpc-based message passing 40374462Salfred */ 40474462Salfred if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 405105189Siedowse cu->cu_error.re_status = RPC_TIMEDOUT; 406105189Siedowse goto out; 40774462Salfred } 40874879Swpaul 40974879Swpaulget_reply: 41074879Swpaul 41174462Salfred /* 41274462Salfred * sub-optimal code appears here because we have 41374462Salfred * some clock time to spare while the packets are in flight. 41474462Salfred * (We assume that this is actually only executed once.) 41574462Salfred */ 41674462Salfred reply_msg.acpted_rply.ar_verf = _null_auth; 41774462Salfred reply_msg.acpted_rply.ar_results.where = resultsp; 41874462Salfred reply_msg.acpted_rply.ar_results.proc = xresults; 41974462Salfred 42074462Salfred for (;;) { 421105189Siedowse /* Decide how long to wait. */ 422105189Siedowse if (timercmp(&next_sendtime, &timeout, <)) 423105189Siedowse timersub(&next_sendtime, &time_waited, &tv); 424105189Siedowse else 425105189Siedowse timersub(&timeout, &time_waited, &tv); 426105189Siedowse if (tv.tv_sec < 0 || tv.tv_usec < 0) 427105189Siedowse tv.tv_sec = tv.tv_usec = 0; 428105189Siedowse TIMEVAL_TO_TIMESPEC(&tv, &ts); 42974462Salfred 430105189Siedowse n = _kevent(cu->cu_kq, &cu->cu_kin, kin_len, &kv, 1, &ts); 431105189Siedowse /* We don't need to register the event again. */ 432105189Siedowse kin_len = 0; 43374462Salfred 434105189Siedowse if (n == 1) { 435105189Siedowse if (kv.flags & EV_ERROR) { 436105189Siedowse cu->cu_error.re_errno = kv.data; 437105189Siedowse cu->cu_error.re_status = RPC_CANTRECV; 438105189Siedowse goto out; 439105189Siedowse } 440105189Siedowse /* We have some data now */ 441105189Siedowse do { 442105189Siedowse recvlen = _recvfrom(cu->cu_fd, cu->cu_inbuf, 443105189Siedowse cu->cu_recvsz, 0, NULL, NULL); 444105189Siedowse } while (recvlen < 0 && errno == EINTR); 445105189Siedowse if (recvlen < 0 && errno != EWOULDBLOCK) { 44674462Salfred cu->cu_error.re_errno = errno; 447105189Siedowse cu->cu_error.re_status = RPC_CANTRECV; 448105189Siedowse goto out; 44974462Salfred } 450105189Siedowse if (recvlen >= sizeof(u_int32_t) && 451105189Siedowse (cu->cu_async == TRUE || 452105189Siedowse *((u_int32_t *)(void *)(cu->cu_inbuf)) == 453105189Siedowse *((u_int32_t *)(void *)(cu->cu_outbuf)))) { 454105189Siedowse /* We now assume we have the proper reply. */ 455105189Siedowse break; 45674462Salfred } 457105189Siedowse } 458105189Siedowse if (n == -1 && errno != EINTR) { 459105189Siedowse cu->cu_error.re_errno = errno; 46074462Salfred cu->cu_error.re_status = RPC_CANTRECV; 461105189Siedowse goto out; 46274462Salfred } 463105189Siedowse gettimeofday(&tv, NULL); 464105189Siedowse timersub(&tv, &starttime, &time_waited); 46574462Salfred 466105189Siedowse /* Check for timeout. */ 467105189Siedowse if (timercmp(&time_waited, &timeout, >)) { 468105189Siedowse cu->cu_error.re_status = RPC_TIMEDOUT; 469105189Siedowse goto out; 47074462Salfred } 471105189Siedowse 472105189Siedowse /* Retransmit if necessary. */ 473105189Siedowse if (timercmp(&time_waited, &next_sendtime, >)) { 474105189Siedowse /* update retransmit_time */ 475105189Siedowse if (retransmit_time.tv_sec < RPC_MAX_BACKOFF) 476105189Siedowse timeradd(&retransmit_time, &retransmit_time, 477105189Siedowse &retransmit_time); 478105189Siedowse timeradd(&next_sendtime, &retransmit_time, 479105189Siedowse &next_sendtime); 480105189Siedowse goto send_again; 481105189Siedowse } 48274462Salfred } 48374462Salfred inlen = (socklen_t)recvlen; 48474462Salfred 48574462Salfred /* 48674462Salfred * now decode and validate the response 48774462Salfred */ 48874462Salfred 48974462Salfred xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE); 49074462Salfred ok = xdr_replymsg(&reply_xdrs, &reply_msg); 49174462Salfred /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ 49274462Salfred if (ok) { 49374462Salfred if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && 49474462Salfred (reply_msg.acpted_rply.ar_stat == SUCCESS)) 49574462Salfred cu->cu_error.re_status = RPC_SUCCESS; 49674462Salfred else 49774462Salfred _seterr_reply(&reply_msg, &(cu->cu_error)); 49874462Salfred 49974462Salfred if (cu->cu_error.re_status == RPC_SUCCESS) { 50074462Salfred if (! AUTH_VALIDATE(cl->cl_auth, 50174462Salfred &reply_msg.acpted_rply.ar_verf)) { 50274462Salfred cu->cu_error.re_status = RPC_AUTHERROR; 50374462Salfred cu->cu_error.re_why = AUTH_INVALIDRESP; 50474462Salfred } 50574462Salfred if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 50674462Salfred xdrs->x_op = XDR_FREE; 50774462Salfred (void) xdr_opaque_auth(xdrs, 50874462Salfred &(reply_msg.acpted_rply.ar_verf)); 50974462Salfred } 51074462Salfred } /* end successful completion */ 51174462Salfred /* 51274462Salfred * If unsuccesful AND error is an authentication error 51374462Salfred * then refresh credentials and try again, else break 51474462Salfred */ 51574462Salfred else if (cu->cu_error.re_status == RPC_AUTHERROR) 51674462Salfred /* maybe our credentials need to be refreshed ... */ 51774462Salfred if (nrefreshes > 0 && 51874462Salfred AUTH_REFRESH(cl->cl_auth, &reply_msg)) { 51974462Salfred nrefreshes--; 52074462Salfred goto call_again; 52174462Salfred } 52274462Salfred /* end of unsuccessful completion */ 52374462Salfred } /* end of valid reply message */ 52474462Salfred else { 52574462Salfred cu->cu_error.re_status = RPC_CANTDECODERES; 52674462Salfred 52774462Salfred } 528105189Siedowseout: 529105189Siedowse if (cu->cu_kq >= 0) 530105189Siedowse _close(cu->cu_kq); 531105189Siedowse cu->cu_kq = -1; 53274462Salfred release_fd_lock(cu->cu_fd, mask); 53374462Salfred return (cu->cu_error.re_status); 53474462Salfred} 53574462Salfred 53674462Salfredstatic void 53774462Salfredclnt_dg_geterr(cl, errp) 53874462Salfred CLIENT *cl; 53974462Salfred struct rpc_err *errp; 54074462Salfred{ 54174462Salfred struct cu_data *cu = (struct cu_data *)cl->cl_private; 54274462Salfred 54374462Salfred *errp = cu->cu_error; 54474462Salfred} 54574462Salfred 54674462Salfredstatic bool_t 54774462Salfredclnt_dg_freeres(cl, xdr_res, res_ptr) 54874462Salfred CLIENT *cl; 54974462Salfred xdrproc_t xdr_res; 55095658Sdes void *res_ptr; 55174462Salfred{ 55274462Salfred struct cu_data *cu = (struct cu_data *)cl->cl_private; 55374462Salfred XDR *xdrs = &(cu->cu_outxdrs); 55474462Salfred bool_t dummy; 55574462Salfred sigset_t mask; 55674462Salfred sigset_t newmask; 55774462Salfred 55874462Salfred sigfillset(&newmask); 55974462Salfred thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 56074462Salfred mutex_lock(&clnt_fd_lock); 56174462Salfred while (dg_fd_locks[cu->cu_fd]) 56274462Salfred cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); 56374462Salfred xdrs->x_op = XDR_FREE; 56474462Salfred dummy = (*xdr_res)(xdrs, res_ptr); 56574462Salfred mutex_unlock(&clnt_fd_lock); 56674462Salfred thr_sigsetmask(SIG_SETMASK, &mask, NULL); 56774462Salfred cond_signal(&dg_cv[cu->cu_fd]); 56874462Salfred return (dummy); 56974462Salfred} 57074462Salfred 57174462Salfred/*ARGSUSED*/ 57274462Salfredstatic void 57374462Salfredclnt_dg_abort(h) 57474462Salfred CLIENT *h; 57574462Salfred{ 57674462Salfred} 57774462Salfred 57874462Salfredstatic bool_t 57974462Salfredclnt_dg_control(cl, request, info) 58074462Salfred CLIENT *cl; 58174462Salfred u_int request; 58299996Salfred void *info; 58374462Salfred{ 58474462Salfred struct cu_data *cu = (struct cu_data *)cl->cl_private; 58574462Salfred struct netbuf *addr; 58674462Salfred sigset_t mask; 58774462Salfred sigset_t newmask; 58874462Salfred int rpc_lock_value; 58974462Salfred 59074462Salfred sigfillset(&newmask); 59174462Salfred thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 59274462Salfred mutex_lock(&clnt_fd_lock); 59374462Salfred while (dg_fd_locks[cu->cu_fd]) 59474462Salfred cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock); 59574462Salfred if (__isthreaded) 59674462Salfred rpc_lock_value = 1; 59774462Salfred else 59874462Salfred rpc_lock_value = 0; 59974462Salfred dg_fd_locks[cu->cu_fd] = rpc_lock_value; 60074462Salfred mutex_unlock(&clnt_fd_lock); 60174462Salfred switch (request) { 60274462Salfred case CLSET_FD_CLOSE: 60374462Salfred cu->cu_closeit = TRUE; 60474462Salfred release_fd_lock(cu->cu_fd, mask); 60574462Salfred return (TRUE); 60674462Salfred case CLSET_FD_NCLOSE: 60774462Salfred cu->cu_closeit = FALSE; 60874462Salfred release_fd_lock(cu->cu_fd, mask); 60974462Salfred return (TRUE); 61074462Salfred } 61174462Salfred 61274462Salfred /* for other requests which use info */ 61374462Salfred if (info == NULL) { 61474462Salfred release_fd_lock(cu->cu_fd, mask); 61574462Salfred return (FALSE); 61674462Salfred } 61774462Salfred switch (request) { 61874462Salfred case CLSET_TIMEOUT: 61999996Salfred if (time_not_ok((struct timeval *)info)) { 62074462Salfred release_fd_lock(cu->cu_fd, mask); 62174462Salfred return (FALSE); 62274462Salfred } 62399996Salfred cu->cu_total = *(struct timeval *)info; 62474462Salfred break; 62574462Salfred case CLGET_TIMEOUT: 62699996Salfred *(struct timeval *)info = cu->cu_total; 62774462Salfred break; 62874462Salfred case CLGET_SERVER_ADDR: /* Give him the fd address */ 62974462Salfred /* Now obsolete. Only for backward compatibility */ 63074462Salfred (void) memcpy(info, &cu->cu_raddr, (size_t)cu->cu_rlen); 63174462Salfred break; 63274462Salfred case CLSET_RETRY_TIMEOUT: 63399996Salfred if (time_not_ok((struct timeval *)info)) { 63474462Salfred release_fd_lock(cu->cu_fd, mask); 63574462Salfred return (FALSE); 63674462Salfred } 63799996Salfred cu->cu_wait = *(struct timeval *)info; 63874462Salfred break; 63974462Salfred case CLGET_RETRY_TIMEOUT: 64099996Salfred *(struct timeval *)info = cu->cu_wait; 64174462Salfred break; 64274462Salfred case CLGET_FD: 64399996Salfred *(int *)info = cu->cu_fd; 64474462Salfred break; 64574462Salfred case CLGET_SVC_ADDR: 64699996Salfred addr = (struct netbuf *)info; 64774462Salfred addr->buf = &cu->cu_raddr; 64874462Salfred addr->len = cu->cu_rlen; 64974462Salfred addr->maxlen = sizeof cu->cu_raddr; 65074462Salfred break; 65174462Salfred case CLSET_SVC_ADDR: /* set to new address */ 65299996Salfred addr = (struct netbuf *)info; 65375097Siedowse if (addr->len < sizeof cu->cu_raddr) { 65475097Siedowse release_fd_lock(cu->cu_fd, mask); 65574462Salfred return (FALSE); 65675097Siedowse } 65774462Salfred (void) memcpy(&cu->cu_raddr, addr->buf, addr->len); 65874462Salfred cu->cu_rlen = addr->len; 65974462Salfred break; 66074462Salfred case CLGET_XID: 66174462Salfred /* 66274462Salfred * use the knowledge that xid is the 66374462Salfred * first element in the call structure *. 66474462Salfred * This will get the xid of the PREVIOUS call 66574462Salfred */ 66699996Salfred *(u_int32_t *)info = 66774462Salfred ntohl(*(u_int32_t *)(void *)cu->cu_outbuf); 66874462Salfred break; 66974462Salfred 67074462Salfred case CLSET_XID: 67174462Salfred /* This will set the xid of the NEXT call */ 67274462Salfred *(u_int32_t *)(void *)cu->cu_outbuf = 67399996Salfred htonl(*(u_int32_t *)info - 1); 67474462Salfred /* decrement by 1 as clnt_dg_call() increments once */ 67574462Salfred break; 67674462Salfred 67774462Salfred case CLGET_VERS: 67874462Salfred /* 67974462Salfred * This RELIES on the information that, in the call body, 68074462Salfred * the version number field is the fifth field from the 68174462Salfred * begining of the RPC header. MUST be changed if the 68274462Salfred * call_struct is changed 68374462Salfred */ 68499996Salfred *(u_int32_t *)info = 68574462Salfred ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf + 68674462Salfred 4 * BYTES_PER_XDR_UNIT)); 68774462Salfred break; 68874462Salfred 68974462Salfred case CLSET_VERS: 69074462Salfred *(u_int32_t *)(void *)(cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT) 69199996Salfred = htonl(*(u_int32_t *)info); 69274462Salfred break; 69374462Salfred 69474462Salfred case CLGET_PROG: 69574462Salfred /* 69674462Salfred * This RELIES on the information that, in the call body, 69774462Salfred * the program number field is the fourth field from the 69874462Salfred * begining of the RPC header. MUST be changed if the 69974462Salfred * call_struct is changed 70074462Salfred */ 70199996Salfred *(u_int32_t *)info = 70274462Salfred ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf + 70374462Salfred 3 * BYTES_PER_XDR_UNIT)); 70474462Salfred break; 70574462Salfred 70674462Salfred case CLSET_PROG: 70774462Salfred *(u_int32_t *)(void *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT) 70899996Salfred = htonl(*(u_int32_t *)info); 70974462Salfred break; 71074879Swpaul case CLSET_ASYNC: 71199996Salfred cu->cu_async = *(int *)info; 71274879Swpaul break; 71378678Siedowse case CLSET_CONNECT: 71499996Salfred cu->cu_connect = *(int *)info; 71578678Siedowse break; 71674462Salfred default: 71774462Salfred release_fd_lock(cu->cu_fd, mask); 71874462Salfred return (FALSE); 71974462Salfred } 72074462Salfred release_fd_lock(cu->cu_fd, mask); 72174462Salfred return (TRUE); 72274462Salfred} 72374462Salfred 72474462Salfredstatic void 72574462Salfredclnt_dg_destroy(cl) 72674462Salfred CLIENT *cl; 72774462Salfred{ 72874462Salfred struct cu_data *cu = (struct cu_data *)cl->cl_private; 72974462Salfred int cu_fd = cu->cu_fd; 73074462Salfred sigset_t mask; 73174462Salfred sigset_t newmask; 73274462Salfred 73374462Salfred sigfillset(&newmask); 73474462Salfred thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 73574462Salfred mutex_lock(&clnt_fd_lock); 73674462Salfred while (dg_fd_locks[cu_fd]) 73774462Salfred cond_wait(&dg_cv[cu_fd], &clnt_fd_lock); 73874462Salfred if (cu->cu_closeit) 73974462Salfred (void)_close(cu_fd); 740105189Siedowse if (cu->cu_kq >= 0) 741105189Siedowse _close(cu->cu_kq); 74274462Salfred XDR_DESTROY(&(cu->cu_outxdrs)); 74374462Salfred mem_free(cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz)); 74474462Salfred if (cl->cl_netid && cl->cl_netid[0]) 74574462Salfred mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); 74674462Salfred if (cl->cl_tp && cl->cl_tp[0]) 74774462Salfred mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); 74874462Salfred mem_free(cl, sizeof (CLIENT)); 74974462Salfred mutex_unlock(&clnt_fd_lock); 75074462Salfred thr_sigsetmask(SIG_SETMASK, &mask, NULL); 75174462Salfred cond_signal(&dg_cv[cu_fd]); 75274462Salfred} 75374462Salfred 75474462Salfredstatic struct clnt_ops * 75574462Salfredclnt_dg_ops() 75674462Salfred{ 75774462Salfred static struct clnt_ops ops; 75874462Salfred extern mutex_t ops_lock; 75974462Salfred sigset_t mask; 76074462Salfred sigset_t newmask; 76174462Salfred 76274462Salfred/* VARIABLES PROTECTED BY ops_lock: ops */ 76374462Salfred 76474462Salfred sigfillset(&newmask); 76574462Salfred thr_sigsetmask(SIG_SETMASK, &newmask, &mask); 76674462Salfred mutex_lock(&ops_lock); 76774462Salfred if (ops.cl_call == NULL) { 76874462Salfred ops.cl_call = clnt_dg_call; 76974462Salfred ops.cl_abort = clnt_dg_abort; 77074462Salfred ops.cl_geterr = clnt_dg_geterr; 77174462Salfred ops.cl_freeres = clnt_dg_freeres; 77274462Salfred ops.cl_destroy = clnt_dg_destroy; 77374462Salfred ops.cl_control = clnt_dg_control; 77474462Salfred } 77574462Salfred mutex_unlock(&ops_lock); 77674462Salfred thr_sigsetmask(SIG_SETMASK, &mask, NULL); 77774462Salfred return (&ops); 77874462Salfred} 77974462Salfred 78074462Salfred/* 78174462Salfred * Make sure that the time is not garbage. -1 value is allowed. 78274462Salfred */ 78374462Salfredstatic bool_t 78474462Salfredtime_not_ok(t) 78574462Salfred struct timeval *t; 78674462Salfred{ 78774462Salfred return (t->tv_sec < -1 || t->tv_sec > 100000000 || 78874462Salfred t->tv_usec < -1 || t->tv_usec > 1000000); 78974462Salfred} 79074462Salfred 791