xref: /netbsd-src/lib/libc/rpc/clnt_dg.c (revision 85f5e301f5b0e5c7695c7222d16769f8f55f6aeb)
1*85f5e301Schristos /*	$NetBSD: clnt_dg.c,v 1.33 2024/01/23 17:24:38 christos Exp $	*/
27df0ccbaSfvdl 
37df0ccbaSfvdl /*
447c0e0c3Stron  * Copyright (c) 2010, Oracle America, Inc.
57df0ccbaSfvdl  *
647c0e0c3Stron  * Redistribution and use in source and binary forms, with or without
747c0e0c3Stron  * modification, are permitted provided that the following conditions are
847c0e0c3Stron  * met:
97df0ccbaSfvdl  *
1047c0e0c3Stron  *     * Redistributions of source code must retain the above copyright
1147c0e0c3Stron  *       notice, this list of conditions and the following disclaimer.
1247c0e0c3Stron  *     * Redistributions in binary form must reproduce the above
1347c0e0c3Stron  *       copyright notice, this list of conditions and the following
1447c0e0c3Stron  *       disclaimer in the documentation and/or other materials
1547c0e0c3Stron  *       provided with the distribution.
1647c0e0c3Stron  *     * Neither the name of the "Oracle America, Inc." nor the names of its
1747c0e0c3Stron  *       contributors may be used to endorse or promote products derived
1847c0e0c3Stron  *       from this software without specific prior written permission.
197df0ccbaSfvdl  *
2047c0e0c3Stron  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2147c0e0c3Stron  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2247c0e0c3Stron  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2347c0e0c3Stron  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2447c0e0c3Stron  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
2547c0e0c3Stron  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2647c0e0c3Stron  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
2747c0e0c3Stron  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2847c0e0c3Stron  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2947c0e0c3Stron  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3047c0e0c3Stron  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3147c0e0c3Stron  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
327df0ccbaSfvdl  */
337df0ccbaSfvdl /*
347df0ccbaSfvdl  * Copyright (c) 1986-1991 by Sun Microsystems Inc.
357df0ccbaSfvdl  */
367df0ccbaSfvdl 
377df0ccbaSfvdl /* #ident	"@(#)clnt_dg.c	1.23	94/04/22 SMI" */
387df0ccbaSfvdl 
395c945215Sitojun #include <sys/cdefs.h>
405c945215Sitojun #if defined(LIBC_SCCS) && !defined(lint)
417df0ccbaSfvdl #if 0
427df0ccbaSfvdl static char sccsid[] = "@(#)clnt_dg.c 1.19 89/03/16 Copyr 1988 Sun Micro";
435c945215Sitojun #else
44*85f5e301Schristos __RCSID("$NetBSD: clnt_dg.c,v 1.33 2024/01/23 17:24:38 christos Exp $");
457df0ccbaSfvdl #endif
467df0ccbaSfvdl #endif
477df0ccbaSfvdl 
487df0ccbaSfvdl /*
497df0ccbaSfvdl  * Implements a connectionless client side RPC.
507df0ccbaSfvdl  */
517df0ccbaSfvdl 
527df0ccbaSfvdl #include "namespace.h"
537df0ccbaSfvdl #include "reentrant.h"
54ed97cebaSchs #include <sys/poll.h>
557df0ccbaSfvdl #include <sys/types.h>
567df0ccbaSfvdl #include <sys/time.h>
577df0ccbaSfvdl #include <sys/socket.h>
587df0ccbaSfvdl #include <sys/ioctl.h>
597df0ccbaSfvdl #include <rpc/rpc.h>
600e8cfd8fSlukem #include <assert.h>
617df0ccbaSfvdl #include <errno.h>
627df0ccbaSfvdl #include <stdlib.h>
6311e5c6ccSthorpej #include <string.h>
647df0ccbaSfvdl #include <signal.h>
657df0ccbaSfvdl #include <unistd.h>
667df0ccbaSfvdl #include <err.h>
672dec884dSchristos 
682dec884dSchristos #include "svc_fdset.h"
6979d5b270Sfvdl #include "rpc_internal.h"
707df0ccbaSfvdl 
717df0ccbaSfvdl #ifdef __weak_alias
727df0ccbaSfvdl __weak_alias(clnt_dg_create,_clnt_dg_create)
737df0ccbaSfvdl #endif
747df0ccbaSfvdl 
757df0ccbaSfvdl #define	RPC_MAX_BACKOFF		30 /* seconds */
767df0ccbaSfvdl 
777df0ccbaSfvdl 
78adb74221Smatt static struct clnt_ops *clnt_dg_ops(void);
79adb74221Smatt static bool_t time_not_ok(struct timeval *);
80adb74221Smatt static enum clnt_stat clnt_dg_call(CLIENT *, rpcproc_t, xdrproc_t,
81adb74221Smatt     const char *, xdrproc_t, caddr_t, struct timeval);
82adb74221Smatt static void clnt_dg_geterr(CLIENT *, struct rpc_err *);
83adb74221Smatt static bool_t clnt_dg_freeres(CLIENT *, xdrproc_t, caddr_t);
84adb74221Smatt static void clnt_dg_abort(CLIENT *);
85adb74221Smatt static bool_t clnt_dg_control(CLIENT *, u_int, char *);
86adb74221Smatt static void clnt_dg_destroy(CLIENT *);
877df0ccbaSfvdl 
887df0ccbaSfvdl 
897df0ccbaSfvdl 
907df0ccbaSfvdl 
917df0ccbaSfvdl /*
927df0ccbaSfvdl  *	This machinery implements per-fd locks for MT-safety.  It is not
937df0ccbaSfvdl  *	sufficient to do per-CLIENT handle locks for MT-safety because a
947df0ccbaSfvdl  *	user may create more than one CLIENT handle with the same fd behind
95c69f42d3Sandvar  *	it.  Therefore, we allocate an array of flags (dg_fd_locks), protected
967df0ccbaSfvdl  *	by the clnt_fd_lock mutex, and an array (dg_cv) of condition variables
97c69f42d3Sandvar  *	similarly protected.  Dg_fd_lock[fd] == 1 => a call is active on some
987df0ccbaSfvdl  *	CLIENT handle created for that fd.
997df0ccbaSfvdl  *	The current implementation holds locks across the entire RPC and reply,
1007df0ccbaSfvdl  *	including retransmissions.  Yes, this is silly, and as soon as this
1017df0ccbaSfvdl  *	code is proven to work, this should be the first thing fixed.  One step
1027df0ccbaSfvdl  *	at a time.
1037df0ccbaSfvdl  */
1047df0ccbaSfvdl static int	*dg_fd_locks;
1053fdac2b8Sthorpej #ifdef _REENTRANT
1063fdac2b8Sthorpej #define __rpc_lock_value __isthreaded;
1077df0ccbaSfvdl static cond_t	*dg_cv;
1087df0ccbaSfvdl #define	release_fd_lock(fd, mask) {		\
1097df0ccbaSfvdl 	mutex_lock(&clnt_fd_lock);	\
1107df0ccbaSfvdl 	dg_fd_locks[fd] = 0;		\
1117df0ccbaSfvdl 	mutex_unlock(&clnt_fd_lock);	\
112c9cdc302Schristos 	thr_sigsetmask(SIG_SETMASK, &(mask), NULL);	\
1137df0ccbaSfvdl 	cond_signal(&dg_cv[fd]);	\
1147df0ccbaSfvdl }
1157df0ccbaSfvdl #else
1167df0ccbaSfvdl #define release_fd_lock(fd,mask)
1177df0ccbaSfvdl #define __rpc_lock_value 0
1187df0ccbaSfvdl #endif
1197df0ccbaSfvdl 
1207df0ccbaSfvdl static const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory";
1217df0ccbaSfvdl 
1227df0ccbaSfvdl /* VARIABLES PROTECTED BY clnt_fd_lock: dg_fd_locks, dg_cv */
1237df0ccbaSfvdl 
1247df0ccbaSfvdl /*
1257df0ccbaSfvdl  * Private data kept per client handle
1267df0ccbaSfvdl  */
1277df0ccbaSfvdl struct cu_data {
1287df0ccbaSfvdl 	int			cu_fd;		/* connections fd */
1297df0ccbaSfvdl 	bool_t			cu_closeit;	/* opened by library */
1307df0ccbaSfvdl 	struct sockaddr_storage	cu_raddr;	/* remote address */
1317df0ccbaSfvdl 	int			cu_rlen;
1327df0ccbaSfvdl 	struct timeval		cu_wait;	/* retransmit interval */
1337df0ccbaSfvdl 	struct timeval		cu_total;	/* total time for the call */
1347df0ccbaSfvdl 	struct rpc_err		cu_error;
1357df0ccbaSfvdl 	XDR			cu_outxdrs;
1367df0ccbaSfvdl 	u_int			cu_xdrpos;
1377df0ccbaSfvdl 	u_int			cu_sendsz;	/* send size */
1387df0ccbaSfvdl 	char			*cu_outbuf;
1397df0ccbaSfvdl 	u_int			cu_recvsz;	/* recv size */
140ed97cebaSchs 	struct pollfd		cu_pfdp;
1417df0ccbaSfvdl 	char			cu_inbuf[1];
1427df0ccbaSfvdl };
1437df0ccbaSfvdl 
1447df0ccbaSfvdl /*
1457df0ccbaSfvdl  * Connection less client creation returns with client handle parameters.
1467df0ccbaSfvdl  * Default options are set, which the user can change using clnt_control().
1477df0ccbaSfvdl  * fd should be open and bound.
1487df0ccbaSfvdl  * NB: The rpch->cl_auth is initialized to null authentication.
1497df0ccbaSfvdl  * 	Caller may wish to set this something more useful.
1507df0ccbaSfvdl  *
1517df0ccbaSfvdl  * sendsz and recvsz are the maximum allowable packet sizes that can be
1527df0ccbaSfvdl  * sent and received. Normally they are the same, but they can be
1537df0ccbaSfvdl  * changed to improve the program efficiency and buffer allocation.
1547df0ccbaSfvdl  * If they are 0, use the transport default.
1557df0ccbaSfvdl  *
1567df0ccbaSfvdl  * If svcaddr is NULL, returns NULL.
1577df0ccbaSfvdl  */
1587df0ccbaSfvdl CLIENT *
clnt_dg_create(int fd,const struct netbuf * svcaddr,rpcprog_t program,rpcvers_t version,u_int sendsz,u_int recvsz)159adb74221Smatt clnt_dg_create(
160adb74221Smatt 	int fd,				/* open file descriptor */
161adb74221Smatt 	const struct netbuf *svcaddr,	/* servers address */
162adb74221Smatt 	rpcprog_t program,		/* program number */
163adb74221Smatt 	rpcvers_t version,		/* version number */
164adb74221Smatt 	u_int sendsz,			/* buffer recv size */
165adb74221Smatt 	u_int recvsz)			/* buffer send size */
1667df0ccbaSfvdl {
1677df0ccbaSfvdl 	CLIENT *cl = NULL;		/* client handle */
168b056680bSchristos 	struct cu_data *cu = NULL;	/* private data */
1697df0ccbaSfvdl 	struct rpc_msg call_msg;
1703fdac2b8Sthorpej #ifdef _REENTRANT
1717df0ccbaSfvdl 	sigset_t mask;
1727df0ccbaSfvdl #endif
1737df0ccbaSfvdl 	sigset_t newmask;
1747df0ccbaSfvdl 	struct __rpc_sockinfo si;
1757df0ccbaSfvdl 	int one = 1;
1767df0ccbaSfvdl 
1771eb9e03aSchristos 	__clnt_sigfillset(&newmask);
1787df0ccbaSfvdl 	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
1797df0ccbaSfvdl 	mutex_lock(&clnt_fd_lock);
180c9cdc302Schristos 	if (dg_fd_locks == NULL) {
1813fdac2b8Sthorpej #ifdef _REENTRANT
1823fdac2b8Sthorpej 		size_t cv_allocsz;
1837df0ccbaSfvdl #endif
184b056680bSchristos 		size_t fd_allocsz;
1857df0ccbaSfvdl 		int dtbsize = __rpc_dtbsize();
1867df0ccbaSfvdl 
1877df0ccbaSfvdl 		fd_allocsz = dtbsize * sizeof (int);
188c9cdc302Schristos 		dg_fd_locks = mem_alloc(fd_allocsz);
189c9cdc302Schristos 		if (dg_fd_locks == NULL) {
1901eb9e03aSchristos 			goto err0;
1917df0ccbaSfvdl 		} else
1927df0ccbaSfvdl 			memset(dg_fd_locks, '\0', fd_allocsz);
1937df0ccbaSfvdl 
1943fdac2b8Sthorpej #ifdef _REENTRANT
1957df0ccbaSfvdl 		cv_allocsz = dtbsize * sizeof (cond_t);
196c9cdc302Schristos 		dg_cv = mem_alloc(cv_allocsz);
197c9cdc302Schristos 		if (dg_cv == NULL) {
1987df0ccbaSfvdl 			mem_free(dg_fd_locks, fd_allocsz);
199c9cdc302Schristos 			dg_fd_locks = NULL;
2001eb9e03aSchristos 			goto err0;
2017df0ccbaSfvdl 		} else {
2027df0ccbaSfvdl 			int i;
2037df0ccbaSfvdl 
2047df0ccbaSfvdl 			for (i = 0; i < dtbsize; i++)
2057df0ccbaSfvdl 				cond_init(&dg_cv[i], 0, (void *) 0);
2067df0ccbaSfvdl 		}
2077df0ccbaSfvdl #endif
2087df0ccbaSfvdl 	}
2097df0ccbaSfvdl 
2107df0ccbaSfvdl 	mutex_unlock(&clnt_fd_lock);
2117df0ccbaSfvdl 	thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
2127df0ccbaSfvdl 
213b056680bSchristos 	if (svcaddr == NULL) {
2147df0ccbaSfvdl 		rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
215b056680bSchristos 		return (NULL);
2167df0ccbaSfvdl 	}
2177df0ccbaSfvdl 
2187df0ccbaSfvdl 	if (!__rpc_fd2sockinfo(fd, &si)) {
2197df0ccbaSfvdl 		rpc_createerr.cf_stat = RPC_TLIERROR;
2207df0ccbaSfvdl 		rpc_createerr.cf_error.re_errno = 0;
221b056680bSchristos 		return (NULL);
2227df0ccbaSfvdl 	}
2237df0ccbaSfvdl 	/*
2247df0ccbaSfvdl 	 * Find the receive and the send size
2257df0ccbaSfvdl 	 */
2267df0ccbaSfvdl 	sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz);
2277df0ccbaSfvdl 	recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz);
2287df0ccbaSfvdl 	if ((sendsz == 0) || (recvsz == 0)) {
2297df0ccbaSfvdl 		rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */
2307df0ccbaSfvdl 		rpc_createerr.cf_error.re_errno = 0;
231b056680bSchristos 		return (NULL);
2327df0ccbaSfvdl 	}
2337df0ccbaSfvdl 
234b056680bSchristos 	if ((cl = mem_alloc(sizeof (CLIENT))) == NULL)
2357df0ccbaSfvdl 		goto err1;
2367df0ccbaSfvdl 	/*
2377df0ccbaSfvdl 	 * Should be multiple of 4 for XDR.
2387df0ccbaSfvdl 	 */
2397df0ccbaSfvdl 	sendsz = ((sendsz + 3) / 4) * 4;
2407df0ccbaSfvdl 	recvsz = ((recvsz + 3) / 4) * 4;
2412d02304dSyamt 	cu = malloc(sizeof (*cu) + sendsz + recvsz);
242b056680bSchristos 	if (cu == NULL)
2437df0ccbaSfvdl 		goto err1;
2442d02304dSyamt 	memset(cu, 0, sizeof(*cu));
245b056680bSchristos 	(void) memcpy(&cu->cu_raddr, svcaddr->buf, (size_t)svcaddr->len);
2467df0ccbaSfvdl 	cu->cu_rlen = svcaddr->len;
2477df0ccbaSfvdl 	cu->cu_outbuf = &cu->cu_inbuf[recvsz];
2487df0ccbaSfvdl 	/* Other values can also be set through clnt_control() */
2492dec884dSchristos #ifdef RUMP_RPC
2507df0ccbaSfvdl 	cu->cu_wait.tv_sec = 15;	/* heuristically chosen */
2517df0ccbaSfvdl 	cu->cu_wait.tv_usec = 0;
2522dec884dSchristos #else
2532dec884dSchristos 	cu->cu_wait.tv_sec = 0;		/* for testing, 10x / second */
2542dec884dSchristos 	cu->cu_wait.tv_usec = 100000;
2552dec884dSchristos #endif
2567df0ccbaSfvdl 	cu->cu_total.tv_sec = -1;
2577df0ccbaSfvdl 	cu->cu_total.tv_usec = -1;
2587df0ccbaSfvdl 	cu->cu_sendsz = sendsz;
2597df0ccbaSfvdl 	cu->cu_recvsz = recvsz;
2608b08fa0dSitojun 	call_msg.rm_xid = __RPC_GETXID();
2617df0ccbaSfvdl 	call_msg.rm_call.cb_prog = program;
2627df0ccbaSfvdl 	call_msg.rm_call.cb_vers = version;
2637df0ccbaSfvdl 	xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE);
2647df0ccbaSfvdl 	if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) {
2657df0ccbaSfvdl 		rpc_createerr.cf_stat = RPC_CANTENCODEARGS;  /* XXX */
2667df0ccbaSfvdl 		rpc_createerr.cf_error.re_errno = 0;
2677df0ccbaSfvdl 		goto err2;
2687df0ccbaSfvdl 	}
2697df0ccbaSfvdl 	cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
2707df0ccbaSfvdl 
2717df0ccbaSfvdl 	/* XXX fvdl - do we still want this? */
2727df0ccbaSfvdl #if 0
2737df0ccbaSfvdl 	(void)bindresvport_sa(fd, (struct sockaddr *)svcaddr->buf);
2747df0ccbaSfvdl #endif
2757df0ccbaSfvdl 	ioctl(fd, FIONBIO, (char *)(void *)&one);
2767df0ccbaSfvdl 
2777df0ccbaSfvdl 	/*
2787df0ccbaSfvdl 	 * By default, closeit is always FALSE. It is users responsibility
2797df0ccbaSfvdl 	 * to do a close on it, else the user may use clnt_control
2807df0ccbaSfvdl 	 * to let clnt_destroy do it for him/her.
2817df0ccbaSfvdl 	 */
2827df0ccbaSfvdl 	cu->cu_closeit = FALSE;
2837df0ccbaSfvdl 	cu->cu_fd = fd;
284ed97cebaSchs 	cu->cu_pfdp.fd = cu->cu_fd;
285ed97cebaSchs 	cu->cu_pfdp.events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND;
2867df0ccbaSfvdl 	cl->cl_ops = clnt_dg_ops();
287b056680bSchristos 	cl->cl_private = (caddr_t)(void *)cu;
2887df0ccbaSfvdl 	cl->cl_auth = authnone_create();
289b056680bSchristos 	cl->cl_tp = NULL;
290b056680bSchristos 	cl->cl_netid = NULL;
2917df0ccbaSfvdl 	return (cl);
2921eb9e03aSchristos err0:
2931eb9e03aSchristos 	mutex_unlock(&clnt_fd_lock);
2941eb9e03aSchristos 	thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
2957df0ccbaSfvdl err1:
2967df0ccbaSfvdl 	warnx(mem_err_clnt_dg);
2977df0ccbaSfvdl 	rpc_createerr.cf_stat = RPC_SYSTEMERROR;
2987df0ccbaSfvdl 	rpc_createerr.cf_error.re_errno = errno;
2997df0ccbaSfvdl err2:
3007df0ccbaSfvdl 	if (cl) {
301b056680bSchristos 		mem_free(cl, sizeof (CLIENT));
3027df0ccbaSfvdl 		if (cu)
303b056680bSchristos 			mem_free(cu, sizeof (*cu) + sendsz + recvsz);
3047df0ccbaSfvdl 	}
305b056680bSchristos 	return (NULL);
3067df0ccbaSfvdl }
3077df0ccbaSfvdl 
3087df0ccbaSfvdl static enum clnt_stat
clnt_dg_call(CLIENT * cl,rpcproc_t proc,xdrproc_t xargs,const char * argsp,xdrproc_t xresults,caddr_t resultsp,struct timeval utimeout)309adb74221Smatt clnt_dg_call(
310adb74221Smatt 	CLIENT *	cl,		/* client handle */
311adb74221Smatt 	rpcproc_t	proc,		/* procedure number */
312adb74221Smatt 	xdrproc_t	xargs,		/* xdr routine for args */
313adb74221Smatt 	const char *	argsp,		/* pointer to args */
314adb74221Smatt 	xdrproc_t	xresults,	/* xdr routine for results */
315adb74221Smatt 	caddr_t		resultsp,	/* pointer to results */
316adb74221Smatt 	struct timeval	utimeout)	/* seconds to wait before giving up */
3177df0ccbaSfvdl {
3180e8cfd8fSlukem 	struct cu_data *cu;
319b056680bSchristos 	XDR *xdrs;
320b056680bSchristos 	size_t outlen;
3217df0ccbaSfvdl 	struct rpc_msg reply_msg;
3227df0ccbaSfvdl 	XDR reply_xdrs;
3237df0ccbaSfvdl 	bool_t ok;
3247df0ccbaSfvdl 	int nrefreshes = 2;		/* number of times to refresh cred */
3257df0ccbaSfvdl 	struct timeval timeout;
3267df0ccbaSfvdl 	struct timeval retransmit_time;
327b5e9a2e4Srpaulo 	struct timeval next_sendtime, starttime, time_waited, tv;
3283fdac2b8Sthorpej #ifdef _REENTRANT
329ed97cebaSchs 	sigset_t mask, *maskp = &mask;
330ed97cebaSchs #else
331ed97cebaSchs 	sigset_t *maskp = NULL;
3327df0ccbaSfvdl #endif
3337df0ccbaSfvdl 	sigset_t newmask;
334b056680bSchristos 	ssize_t recvlen = 0;
335fa92811fSchristos 	struct timespec ts;
336b5e9a2e4Srpaulo 	int n;
3377df0ccbaSfvdl 
3380e8cfd8fSlukem 	_DIAGASSERT(cl != NULL);
3390e8cfd8fSlukem 
3400e8cfd8fSlukem 	cu = (struct cu_data *)cl->cl_private;
3410e8cfd8fSlukem 
3421eb9e03aSchristos 	__clnt_sigfillset(&newmask);
3437df0ccbaSfvdl 	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
3447df0ccbaSfvdl 	mutex_lock(&clnt_fd_lock);
3457df0ccbaSfvdl 	while (dg_fd_locks[cu->cu_fd])
3467df0ccbaSfvdl 		cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock);
3477df0ccbaSfvdl 	dg_fd_locks[cu->cu_fd] = __rpc_lock_value;
3487df0ccbaSfvdl 	mutex_unlock(&clnt_fd_lock);
3497df0ccbaSfvdl 	if (cu->cu_total.tv_usec == -1) {
3507df0ccbaSfvdl 		timeout = utimeout;	/* use supplied timeout */
3517df0ccbaSfvdl 	} else {
3527df0ccbaSfvdl 		timeout = cu->cu_total;	/* use default timeout */
3537df0ccbaSfvdl 	}
3547df0ccbaSfvdl 
3557df0ccbaSfvdl 	time_waited.tv_sec = 0;
3567df0ccbaSfvdl 	time_waited.tv_usec = 0;
357b5e9a2e4Srpaulo 	retransmit_time = next_sendtime = cu->cu_wait;
358b5e9a2e4Srpaulo 	gettimeofday(&starttime, NULL);
359b5e9a2e4Srpaulo 
3607df0ccbaSfvdl call_again:
3617df0ccbaSfvdl 	xdrs = &(cu->cu_outxdrs);
3627df0ccbaSfvdl 	xdrs->x_op = XDR_ENCODE;
3637df0ccbaSfvdl 	XDR_SETPOS(xdrs, cu->cu_xdrpos);
3647df0ccbaSfvdl 	/*
3657df0ccbaSfvdl 	 * the transaction is the first thing in the out buffer
3667df0ccbaSfvdl 	 */
367b056680bSchristos 	(*(u_int32_t *)(void *)(cu->cu_outbuf))++;
368128bd71fSchristos 	if ((! XDR_PUTINT32(xdrs, (int32_t *)&proc)) ||
3697df0ccbaSfvdl 	    (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
370347f995cSyamt 	    (! (*xargs)(xdrs, __UNCONST(argsp)))) {
371b5e9a2e4Srpaulo 		cu->cu_error.re_status = RPC_CANTENCODEARGS;
372b5e9a2e4Srpaulo 		goto out;
3737df0ccbaSfvdl 	}
374b056680bSchristos 	outlen = (size_t)XDR_GETPOS(xdrs);
3757df0ccbaSfvdl 
3767df0ccbaSfvdl send_again:
377102c672aSlukem 	if ((size_t)sendto(cu->cu_fd, cu->cu_outbuf, outlen, 0,
378b056680bSchristos 	    (struct sockaddr *)(void *)&cu->cu_raddr, (socklen_t)cu->cu_rlen)
3797df0ccbaSfvdl 	    != outlen) {
3807df0ccbaSfvdl 		cu->cu_error.re_errno = errno;
381b5e9a2e4Srpaulo 		cu->cu_error.re_status = RPC_CANTSEND;
382b5e9a2e4Srpaulo 		goto out;
3837df0ccbaSfvdl 	}
3847df0ccbaSfvdl 
3857df0ccbaSfvdl 	/*
3867df0ccbaSfvdl 	 * Hack to provide rpc-based message passing
3877df0ccbaSfvdl 	 */
3887df0ccbaSfvdl 	if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
389b5e9a2e4Srpaulo 		cu->cu_error.re_status = RPC_TIMEDOUT;
390b5e9a2e4Srpaulo 		goto out;
3917df0ccbaSfvdl 	}
3927df0ccbaSfvdl 	/*
3937df0ccbaSfvdl 	 * sub-optimal code appears here because we have
3947df0ccbaSfvdl 	 * some clock time to spare while the packets are in flight.
3957df0ccbaSfvdl 	 * (We assume that this is actually only executed once.)
3967df0ccbaSfvdl 	 */
3977df0ccbaSfvdl 	reply_msg.acpted_rply.ar_verf = _null_auth;
3987df0ccbaSfvdl 	reply_msg.acpted_rply.ar_results.where = resultsp;
3997df0ccbaSfvdl 	reply_msg.acpted_rply.ar_results.proc = xresults;
4007df0ccbaSfvdl 
4017df0ccbaSfvdl 
4027df0ccbaSfvdl 	for (;;) {
403b5e9a2e4Srpaulo 		/* Decide how long to wait. */
404b5e9a2e4Srpaulo 		if (timercmp(&next_sendtime, &timeout, <))
405b5e9a2e4Srpaulo 			timersub(&next_sendtime, &time_waited, &tv);
406b5e9a2e4Srpaulo 		else
407b5e9a2e4Srpaulo 			timersub(&timeout, &time_waited, &tv);
408b5e9a2e4Srpaulo 		if (tv.tv_sec < 0 || tv.tv_usec < 0)
409b5e9a2e4Srpaulo 			tv.tv_sec = tv.tv_usec = 0;
410b5e9a2e4Srpaulo 		TIMEVAL_TO_TIMESPEC(&tv, &ts);
4117df0ccbaSfvdl 
412ed97cebaSchs 		n = pollts(&cu->cu_pfdp, 1, &ts, maskp);
413b5e9a2e4Srpaulo 		if (n == 1) {
414b5e9a2e4Srpaulo 			/* We have some data now */
415b5e9a2e4Srpaulo 			do {
416b5e9a2e4Srpaulo 				recvlen = recvfrom(cu->cu_fd, cu->cu_inbuf,
417b5e9a2e4Srpaulo 				    cu->cu_recvsz, 0, NULL, NULL);
418b5e9a2e4Srpaulo 			} while (recvlen < 0 && errno == EINTR);
419b5e9a2e4Srpaulo 
420b5e9a2e4Srpaulo 			if (recvlen < 0 && errno != EWOULDBLOCK) {
4217df0ccbaSfvdl 				cu->cu_error.re_errno = errno;
422b5e9a2e4Srpaulo 				cu->cu_error.re_status = RPC_CANTRECV;
423b5e9a2e4Srpaulo 				goto out;
4247df0ccbaSfvdl 			}
425493d3410Smrg 			if (recvlen >= (ssize_t)sizeof(uint32_t)) {
426493d3410Smrg 				if (memcmp(cu->cu_inbuf, cu->cu_outbuf,
427493d3410Smrg 				    sizeof(uint32_t)) == 0)
428493d3410Smrg 					/* Assume we have the proper reply. */
429b5e9a2e4Srpaulo 					break;
4307df0ccbaSfvdl 			}
4317df0ccbaSfvdl 		}
432b5e9a2e4Srpaulo 		if (n == -1) {
4337df0ccbaSfvdl 			cu->cu_error.re_errno = errno;
434b5e9a2e4Srpaulo 			cu->cu_error.re_status = RPC_CANTRECV;
435b5e9a2e4Srpaulo 			goto out;
4367df0ccbaSfvdl 		}
437b5e9a2e4Srpaulo 
438b5e9a2e4Srpaulo 		gettimeofday(&tv, NULL);
439b5e9a2e4Srpaulo 		timersub(&tv, &starttime, &time_waited);
440b5e9a2e4Srpaulo 
441b5e9a2e4Srpaulo 		/* Check for timeout. */
442b5e9a2e4Srpaulo 		if (timercmp(&time_waited, &timeout, >)) {
443b5e9a2e4Srpaulo 			cu->cu_error.re_status = RPC_TIMEDOUT;
444b5e9a2e4Srpaulo 			goto out;
445b5e9a2e4Srpaulo 		}
446b5e9a2e4Srpaulo 
447b5e9a2e4Srpaulo 		/* Retransmit if necessary. */
448b5e9a2e4Srpaulo 		if (timercmp(&time_waited, &next_sendtime, >)) {
449b5e9a2e4Srpaulo 			/* update retransmit_time */
450b5e9a2e4Srpaulo 			if (retransmit_time.tv_sec < RPC_MAX_BACKOFF)
451b5e9a2e4Srpaulo 				timeradd(&retransmit_time, &retransmit_time,
452b5e9a2e4Srpaulo 				    &retransmit_time);
453b5e9a2e4Srpaulo 			timeradd(&next_sendtime, &retransmit_time,
454b5e9a2e4Srpaulo 			    &next_sendtime);
455b5e9a2e4Srpaulo 			goto send_again;
456b5e9a2e4Srpaulo 		}
4577df0ccbaSfvdl 	}
4587df0ccbaSfvdl 
4597df0ccbaSfvdl 	/*
4607df0ccbaSfvdl 	 * now decode and validate the response
4617df0ccbaSfvdl 	 */
4627df0ccbaSfvdl 
46371baa97cSdrochner 	xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)recvlen, XDR_DECODE);
4647df0ccbaSfvdl 	ok = xdr_replymsg(&reply_xdrs, &reply_msg);
4657df0ccbaSfvdl 	/* XDR_DESTROY(&reply_xdrs);	save a few cycles on noop destroy */
4667df0ccbaSfvdl 	if (ok) {
4677df0ccbaSfvdl 		if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
4687df0ccbaSfvdl 			(reply_msg.acpted_rply.ar_stat == SUCCESS))
4697df0ccbaSfvdl 			cu->cu_error.re_status = RPC_SUCCESS;
4707df0ccbaSfvdl 		else
4717df0ccbaSfvdl 			_seterr_reply(&reply_msg, &(cu->cu_error));
4727df0ccbaSfvdl 
4737df0ccbaSfvdl 		if (cu->cu_error.re_status == RPC_SUCCESS) {
4747df0ccbaSfvdl 			if (! AUTH_VALIDATE(cl->cl_auth,
4757df0ccbaSfvdl 					    &reply_msg.acpted_rply.ar_verf)) {
4767df0ccbaSfvdl 				cu->cu_error.re_status = RPC_AUTHERROR;
4777df0ccbaSfvdl 				cu->cu_error.re_why = AUTH_INVALIDRESP;
4787df0ccbaSfvdl 			}
4797df0ccbaSfvdl 			if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
4807df0ccbaSfvdl 				xdrs->x_op = XDR_FREE;
4817df0ccbaSfvdl 				(void) xdr_opaque_auth(xdrs,
4827df0ccbaSfvdl 					&(reply_msg.acpted_rply.ar_verf));
4837df0ccbaSfvdl 			}
4847df0ccbaSfvdl 		}		/* end successful completion */
4857df0ccbaSfvdl 		/*
486e44b4c4dSmsaitoh 		 * If unsuccessful AND error is an authentication error
4877df0ccbaSfvdl 		 * then refresh credentials and try again, else break
4887df0ccbaSfvdl 		 */
4897df0ccbaSfvdl 		else if (cu->cu_error.re_status == RPC_AUTHERROR)
4907df0ccbaSfvdl 			/* maybe our credentials need to be refreshed ... */
4917df0ccbaSfvdl 			if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) {
4927df0ccbaSfvdl 				nrefreshes--;
4937df0ccbaSfvdl 				goto call_again;
4947df0ccbaSfvdl 			}
4957df0ccbaSfvdl 		/* end of unsuccessful completion */
4967df0ccbaSfvdl 	}	/* end of valid reply message */
4977df0ccbaSfvdl 	else {
4987df0ccbaSfvdl 		cu->cu_error.re_status = RPC_CANTDECODERES;
4997df0ccbaSfvdl 
5007df0ccbaSfvdl 	}
501b5e9a2e4Srpaulo out:
5027df0ccbaSfvdl 	release_fd_lock(cu->cu_fd, mask);
5037df0ccbaSfvdl 	return (cu->cu_error.re_status);
5047df0ccbaSfvdl }
5057df0ccbaSfvdl 
5067df0ccbaSfvdl static void
clnt_dg_geterr(CLIENT * cl,struct rpc_err * errp)507adb74221Smatt clnt_dg_geterr(CLIENT *cl, struct rpc_err *errp)
5087df0ccbaSfvdl {
5090e8cfd8fSlukem 	struct cu_data *cu;
5107df0ccbaSfvdl 
5110e8cfd8fSlukem 	_DIAGASSERT(cl != NULL);
5120e8cfd8fSlukem 	_DIAGASSERT(errp != NULL);
5130e8cfd8fSlukem 
5140e8cfd8fSlukem 	cu = (struct cu_data *)cl->cl_private;
5157df0ccbaSfvdl 	*errp = cu->cu_error;
5167df0ccbaSfvdl }
5177df0ccbaSfvdl 
5187df0ccbaSfvdl static bool_t
clnt_dg_freeres(CLIENT * cl,xdrproc_t xdr_res,caddr_t res_ptr)519adb74221Smatt clnt_dg_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr)
5207df0ccbaSfvdl {
5210e8cfd8fSlukem 	struct cu_data *cu;
5220e8cfd8fSlukem 	XDR *xdrs;
5237df0ccbaSfvdl 	bool_t dummy;
5243fdac2b8Sthorpej #ifdef _REENTRANT
5257df0ccbaSfvdl 	sigset_t mask;
5267df0ccbaSfvdl #endif
5277df0ccbaSfvdl 	sigset_t newmask;
5287df0ccbaSfvdl 
5290e8cfd8fSlukem 	_DIAGASSERT(cl != NULL);
5300e8cfd8fSlukem 	cu = (struct cu_data *)cl->cl_private;
5310e8cfd8fSlukem 	xdrs = &(cu->cu_outxdrs);
5320e8cfd8fSlukem 
5331eb9e03aSchristos 	__clnt_sigfillset(&newmask);
5347df0ccbaSfvdl 	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
5357df0ccbaSfvdl 	mutex_lock(&clnt_fd_lock);
5367df0ccbaSfvdl 	while (dg_fd_locks[cu->cu_fd])
5377df0ccbaSfvdl 		cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock);
5387df0ccbaSfvdl 	xdrs->x_op = XDR_FREE;
5397df0ccbaSfvdl 	dummy = (*xdr_res)(xdrs, res_ptr);
5407df0ccbaSfvdl 	mutex_unlock(&clnt_fd_lock);
5417df0ccbaSfvdl 	thr_sigsetmask(SIG_SETMASK, &mask, NULL);
5427df0ccbaSfvdl 	cond_signal(&dg_cv[cu->cu_fd]);
5437df0ccbaSfvdl 	return (dummy);
5447df0ccbaSfvdl }
5457df0ccbaSfvdl 
5467df0ccbaSfvdl /*ARGSUSED*/
5477df0ccbaSfvdl static void
clnt_dg_abort(CLIENT * h)548adb74221Smatt clnt_dg_abort(CLIENT *h)
5497df0ccbaSfvdl {
5507df0ccbaSfvdl }
5517df0ccbaSfvdl 
5527df0ccbaSfvdl static bool_t
clnt_dg_control(CLIENT * cl,u_int request,char * info)553adb74221Smatt clnt_dg_control(CLIENT *cl, u_int request, char *info)
5547df0ccbaSfvdl {
5550e8cfd8fSlukem 	struct cu_data *cu;
5567df0ccbaSfvdl 	struct netbuf *addr;
5573fdac2b8Sthorpej #ifdef _REENTRANT
5587df0ccbaSfvdl 	sigset_t mask;
5597df0ccbaSfvdl #endif
5607df0ccbaSfvdl 	sigset_t newmask;
5617df0ccbaSfvdl 
5620e8cfd8fSlukem 	_DIAGASSERT(cl != NULL);
5630e8cfd8fSlukem 	/* info is handled below */
5640e8cfd8fSlukem 
5650e8cfd8fSlukem 	cu = (struct cu_data *)cl->cl_private;
5660e8cfd8fSlukem 
5671eb9e03aSchristos 	__clnt_sigfillset(&newmask);
5687df0ccbaSfvdl 	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
5697df0ccbaSfvdl 	mutex_lock(&clnt_fd_lock);
5707df0ccbaSfvdl 	while (dg_fd_locks[cu->cu_fd])
5717df0ccbaSfvdl 		cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock);
5727df0ccbaSfvdl 	dg_fd_locks[cu->cu_fd] = __rpc_lock_value;
5737df0ccbaSfvdl 	mutex_unlock(&clnt_fd_lock);
5747df0ccbaSfvdl 	switch (request) {
5757df0ccbaSfvdl 	case CLSET_FD_CLOSE:
5767df0ccbaSfvdl 		cu->cu_closeit = TRUE;
5777df0ccbaSfvdl 		release_fd_lock(cu->cu_fd, mask);
5787df0ccbaSfvdl 		return (TRUE);
5797df0ccbaSfvdl 	case CLSET_FD_NCLOSE:
5807df0ccbaSfvdl 		cu->cu_closeit = FALSE;
5817df0ccbaSfvdl 		release_fd_lock(cu->cu_fd, mask);
5827df0ccbaSfvdl 		return (TRUE);
5837df0ccbaSfvdl 	}
5847df0ccbaSfvdl 
5857df0ccbaSfvdl 	/* for other requests which use info */
5867df0ccbaSfvdl 	if (info == NULL) {
5877df0ccbaSfvdl 		release_fd_lock(cu->cu_fd, mask);
5887df0ccbaSfvdl 		return (FALSE);
5897df0ccbaSfvdl 	}
5907df0ccbaSfvdl 	switch (request) {
5917df0ccbaSfvdl 	case CLSET_TIMEOUT:
592b056680bSchristos 		if (time_not_ok((struct timeval *)(void *)info)) {
5937df0ccbaSfvdl 			release_fd_lock(cu->cu_fd, mask);
5947df0ccbaSfvdl 			return (FALSE);
5957df0ccbaSfvdl 		}
596b056680bSchristos 		cu->cu_total = *(struct timeval *)(void *)info;
5977df0ccbaSfvdl 		break;
5987df0ccbaSfvdl 	case CLGET_TIMEOUT:
599b056680bSchristos 		*(struct timeval *)(void *)info = cu->cu_total;
6007df0ccbaSfvdl 		break;
6017df0ccbaSfvdl 	case CLGET_SERVER_ADDR:		/* Give him the fd address */
6027df0ccbaSfvdl 		/* Now obsolete. Only for backward compatibility */
603b056680bSchristos 		(void) memcpy(info, &cu->cu_raddr, (size_t)cu->cu_rlen);
6047df0ccbaSfvdl 		break;
6057df0ccbaSfvdl 	case CLSET_RETRY_TIMEOUT:
606b056680bSchristos 		if (time_not_ok((struct timeval *)(void *)info)) {
6077df0ccbaSfvdl 			release_fd_lock(cu->cu_fd, mask);
6087df0ccbaSfvdl 			return (FALSE);
6097df0ccbaSfvdl 		}
610b056680bSchristos 		cu->cu_wait = *(struct timeval *)(void *)info;
6117df0ccbaSfvdl 		break;
6127df0ccbaSfvdl 	case CLGET_RETRY_TIMEOUT:
613b056680bSchristos 		*(struct timeval *)(void *)info = cu->cu_wait;
6147df0ccbaSfvdl 		break;
6157df0ccbaSfvdl 	case CLGET_FD:
616b056680bSchristos 		*(int *)(void *)info = cu->cu_fd;
6177df0ccbaSfvdl 		break;
6187df0ccbaSfvdl 	case CLGET_SVC_ADDR:
619b056680bSchristos 		addr = (struct netbuf *)(void *)info;
6207df0ccbaSfvdl 		addr->buf = &cu->cu_raddr;
6217df0ccbaSfvdl 		addr->len = cu->cu_rlen;
6227df0ccbaSfvdl 		addr->maxlen = sizeof cu->cu_raddr;
6237df0ccbaSfvdl 		break;
6247df0ccbaSfvdl 	case CLSET_SVC_ADDR:		/* set to new address */
625b056680bSchristos 		addr = (struct netbuf *)(void *)info;
626675f9cd5Syamt 		if (addr->len < sizeof cu->cu_raddr) {
627675f9cd5Syamt 			release_fd_lock(cu->cu_fd, mask);
6287df0ccbaSfvdl 			return (FALSE);
629675f9cd5Syamt 		}
6301b235e3eSchristos 		(void) memcpy(&cu->cu_raddr, addr->buf, (size_t)addr->len);
6317df0ccbaSfvdl 		cu->cu_rlen = addr->len;
6327df0ccbaSfvdl 		break;
6337df0ccbaSfvdl 	case CLGET_XID:
6347df0ccbaSfvdl 		/*
6357df0ccbaSfvdl 		 * use the knowledge that xid is the
6367df0ccbaSfvdl 		 * first element in the call structure *.
6377df0ccbaSfvdl 		 * This will get the xid of the PREVIOUS call
6387df0ccbaSfvdl 		 */
639b056680bSchristos 		*(u_int32_t *)(void *)info =
640b056680bSchristos 		    ntohl(*(u_int32_t *)(void *)cu->cu_outbuf);
6417df0ccbaSfvdl 		break;
6427df0ccbaSfvdl 
6437df0ccbaSfvdl 	case CLSET_XID:
6447df0ccbaSfvdl 		/* This will set the xid of the NEXT call */
645b056680bSchristos 		*(u_int32_t *)(void *)cu->cu_outbuf =
646b056680bSchristos 		    htonl(*(u_int32_t *)(void *)info - 1);
6477df0ccbaSfvdl 		/* decrement by 1 as clnt_dg_call() increments once */
6487df0ccbaSfvdl 		break;
6497df0ccbaSfvdl 
6507df0ccbaSfvdl 	case CLGET_VERS:
6517df0ccbaSfvdl 		/*
6527df0ccbaSfvdl 		 * This RELIES on the information that, in the call body,
6537df0ccbaSfvdl 		 * the version number field is the fifth field from the
654492c086fSandvar 		 * beginning of the RPC header. MUST be changed if the
6557df0ccbaSfvdl 		 * call_struct is changed
6567df0ccbaSfvdl 		 */
657b056680bSchristos 		*(u_int32_t *)(void *)info =
658b056680bSchristos 		    ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf +
6597df0ccbaSfvdl 		    4 * BYTES_PER_XDR_UNIT));
6607df0ccbaSfvdl 		break;
6617df0ccbaSfvdl 
6627df0ccbaSfvdl 	case CLSET_VERS:
663b056680bSchristos 		*(u_int32_t *)(void *)(cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT)
664b056680bSchristos 			= htonl(*(u_int32_t *)(void *)info);
6657df0ccbaSfvdl 		break;
6667df0ccbaSfvdl 
6677df0ccbaSfvdl 	case CLGET_PROG:
6687df0ccbaSfvdl 		/*
6697df0ccbaSfvdl 		 * This RELIES on the information that, in the call body,
6707df0ccbaSfvdl 		 * the program number field is the fourth field from the
671492c086fSandvar 		 * beginning of the RPC header. MUST be changed if the
6727df0ccbaSfvdl 		 * call_struct is changed
6737df0ccbaSfvdl 		 */
674b056680bSchristos 		*(u_int32_t *)(void *)info =
675b056680bSchristos 		    ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf +
6767df0ccbaSfvdl 		    3 * BYTES_PER_XDR_UNIT));
6777df0ccbaSfvdl 		break;
6787df0ccbaSfvdl 
6797df0ccbaSfvdl 	case CLSET_PROG:
680b056680bSchristos 		*(u_int32_t *)(void *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT)
681b056680bSchristos 			= htonl(*(u_int32_t *)(void *)info);
6827df0ccbaSfvdl 		break;
6837df0ccbaSfvdl 
6847df0ccbaSfvdl 	default:
6857df0ccbaSfvdl 		release_fd_lock(cu->cu_fd, mask);
6867df0ccbaSfvdl 		return (FALSE);
6877df0ccbaSfvdl 	}
6887df0ccbaSfvdl 	release_fd_lock(cu->cu_fd, mask);
6897df0ccbaSfvdl 	return (TRUE);
6907df0ccbaSfvdl }
6917df0ccbaSfvdl 
6927df0ccbaSfvdl static void
clnt_dg_destroy(CLIENT * cl)693adb74221Smatt clnt_dg_destroy(CLIENT *cl)
6947df0ccbaSfvdl {
6950e8cfd8fSlukem 	struct cu_data *cu;
6960e8cfd8fSlukem 	int cu_fd;
6973fdac2b8Sthorpej #ifdef _REENTRANT
6987df0ccbaSfvdl 	sigset_t mask;
6997df0ccbaSfvdl #endif
7007df0ccbaSfvdl 	sigset_t newmask;
7017df0ccbaSfvdl 
7020e8cfd8fSlukem 	_DIAGASSERT(cl != NULL);
7030e8cfd8fSlukem 
7040e8cfd8fSlukem 	cu = (struct cu_data *)cl->cl_private;
7050e8cfd8fSlukem 	cu_fd = cu->cu_fd;
7060e8cfd8fSlukem 
7071eb9e03aSchristos 	__clnt_sigfillset(&newmask);
7087df0ccbaSfvdl 	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
7097df0ccbaSfvdl 	mutex_lock(&clnt_fd_lock);
7107df0ccbaSfvdl 	while (dg_fd_locks[cu_fd])
7117df0ccbaSfvdl 		cond_wait(&dg_cv[cu_fd], &clnt_fd_lock);
7127df0ccbaSfvdl 	if (cu->cu_closeit)
7137df0ccbaSfvdl 		(void) close(cu_fd);
7147df0ccbaSfvdl 	XDR_DESTROY(&(cu->cu_outxdrs));
715b056680bSchristos 	mem_free(cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz));
7167df0ccbaSfvdl 	if (cl->cl_netid && cl->cl_netid[0])
7177df0ccbaSfvdl 		mem_free(cl->cl_netid, strlen(cl->cl_netid) +1);
7187df0ccbaSfvdl 	if (cl->cl_tp && cl->cl_tp[0])
7197df0ccbaSfvdl 		mem_free(cl->cl_tp, strlen(cl->cl_tp) +1);
720b056680bSchristos 	mem_free(cl, sizeof (CLIENT));
7217df0ccbaSfvdl 	mutex_unlock(&clnt_fd_lock);
7227df0ccbaSfvdl 	thr_sigsetmask(SIG_SETMASK, &mask, NULL);
7237df0ccbaSfvdl 	cond_signal(&dg_cv[cu_fd]);
7247df0ccbaSfvdl }
7257df0ccbaSfvdl 
7267df0ccbaSfvdl static struct clnt_ops *
clnt_dg_ops(void)727adb74221Smatt clnt_dg_ops(void)
7287df0ccbaSfvdl {
7297df0ccbaSfvdl 	static struct clnt_ops ops;
7303fdac2b8Sthorpej #ifdef _REENTRANT
7317df0ccbaSfvdl 	sigset_t mask;
7327df0ccbaSfvdl #endif
7337df0ccbaSfvdl 	sigset_t newmask;
7347df0ccbaSfvdl 
7357df0ccbaSfvdl /* VARIABLES PROTECTED BY ops_lock: ops */
7367df0ccbaSfvdl 
7371eb9e03aSchristos 	__clnt_sigfillset(&newmask);
7387df0ccbaSfvdl 	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
7397df0ccbaSfvdl 	mutex_lock(&ops_lock);
7407df0ccbaSfvdl 	if (ops.cl_call == NULL) {
7417df0ccbaSfvdl 		ops.cl_call = clnt_dg_call;
7427df0ccbaSfvdl 		ops.cl_abort = clnt_dg_abort;
7437df0ccbaSfvdl 		ops.cl_geterr = clnt_dg_geterr;
7447df0ccbaSfvdl 		ops.cl_freeres = clnt_dg_freeres;
7457df0ccbaSfvdl 		ops.cl_destroy = clnt_dg_destroy;
7467df0ccbaSfvdl 		ops.cl_control = clnt_dg_control;
7477df0ccbaSfvdl 	}
7487df0ccbaSfvdl 	mutex_unlock(&ops_lock);
7497df0ccbaSfvdl 	thr_sigsetmask(SIG_SETMASK, &mask, NULL);
7507df0ccbaSfvdl 	return (&ops);
7517df0ccbaSfvdl }
7527df0ccbaSfvdl 
7537df0ccbaSfvdl /*
7547df0ccbaSfvdl  * Make sure that the time is not garbage.  -1 value is allowed.
7557df0ccbaSfvdl  */
7567df0ccbaSfvdl static bool_t
time_not_ok(struct timeval * t)757adb74221Smatt time_not_ok(struct timeval *t)
7587df0ccbaSfvdl {
7590e8cfd8fSlukem 
7600e8cfd8fSlukem 	_DIAGASSERT(t != NULL);
7610e8cfd8fSlukem 
7627df0ccbaSfvdl 	return (t->tv_sec < -1 || t->tv_sec > 100000000 ||
7637df0ccbaSfvdl 		t->tv_usec < -1 || t->tv_usec > 1000000);
7647df0ccbaSfvdl }
765