xref: /minix3/lib/libc/rpc/clnt_vc.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: clnt_vc.c,v 1.26 2015/01/20 18:31:25 christos Exp $	*/
22fe8fb19SBen Gras 
32fe8fb19SBen Gras /*
484d9c625SLionel Sambuc  * Copyright (c) 2010, Oracle America, Inc.
52fe8fb19SBen Gras  *
684d9c625SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
784d9c625SLionel Sambuc  * modification, are permitted provided that the following conditions are
884d9c625SLionel Sambuc  * met:
92fe8fb19SBen Gras  *
1084d9c625SLionel Sambuc  *     * Redistributions of source code must retain the above copyright
1184d9c625SLionel Sambuc  *       notice, this list of conditions and the following disclaimer.
1284d9c625SLionel Sambuc  *     * Redistributions in binary form must reproduce the above
1384d9c625SLionel Sambuc  *       copyright notice, this list of conditions and the following
1484d9c625SLionel Sambuc  *       disclaimer in the documentation and/or other materials
1584d9c625SLionel Sambuc  *       provided with the distribution.
1684d9c625SLionel Sambuc  *     * Neither the name of the "Oracle America, Inc." nor the names of its
1784d9c625SLionel Sambuc  *       contributors may be used to endorse or promote products derived
1884d9c625SLionel Sambuc  *       from this software without specific prior written permission.
192fe8fb19SBen Gras  *
2084d9c625SLionel Sambuc  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2184d9c625SLionel Sambuc  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2284d9c625SLionel Sambuc  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2384d9c625SLionel Sambuc  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2484d9c625SLionel Sambuc  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
2584d9c625SLionel Sambuc  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2684d9c625SLionel Sambuc  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
2784d9c625SLionel Sambuc  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2884d9c625SLionel Sambuc  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2984d9c625SLionel Sambuc  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3084d9c625SLionel Sambuc  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3184d9c625SLionel Sambuc  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
322fe8fb19SBen Gras  */
332fe8fb19SBen Gras 
342fe8fb19SBen Gras #include <sys/cdefs.h>
352fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
362fe8fb19SBen Gras #if 0
372fe8fb19SBen Gras static char *sccsid = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
382fe8fb19SBen Gras static char *sccsid = "@(#)clnt_tcp.c	2.2 88/08/01 4.0 RPCSRC";
392fe8fb19SBen Gras static char sccsid[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro";
402fe8fb19SBen Gras #else
41*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: clnt_vc.c,v 1.26 2015/01/20 18:31:25 christos Exp $");
422fe8fb19SBen Gras #endif
432fe8fb19SBen Gras #endif
442fe8fb19SBen Gras 
452fe8fb19SBen Gras /*
462fe8fb19SBen Gras  * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
472fe8fb19SBen Gras  *
482fe8fb19SBen Gras  * Copyright (C) 1984, Sun Microsystems, Inc.
492fe8fb19SBen Gras  *
502fe8fb19SBen Gras  * TCP based RPC supports 'batched calls'.
512fe8fb19SBen Gras  * A sequence of calls may be batched-up in a send buffer.  The rpc call
522fe8fb19SBen Gras  * return immediately to the client even though the call was not necessarily
532fe8fb19SBen Gras  * sent.  The batching occurs if the results' xdr routine is NULL (0) AND
542fe8fb19SBen Gras  * the rpc timeout value is zero (see clnt.h, rpc).
552fe8fb19SBen Gras  *
562fe8fb19SBen Gras  * Clients should NOT casually batch calls that in fact return results; that is,
572fe8fb19SBen Gras  * the server side should be aware that a call is batched and not produce any
582fe8fb19SBen Gras  * return message.  Batched calls that produce many result messages can
592fe8fb19SBen Gras  * deadlock (netlock) the client and the server....
602fe8fb19SBen Gras  *
612fe8fb19SBen Gras  * Now go hang yourself.
622fe8fb19SBen Gras  */
632fe8fb19SBen Gras 
642fe8fb19SBen Gras #include "namespace.h"
652fe8fb19SBen Gras #include "reentrant.h"
662fe8fb19SBen Gras #include <sys/types.h>
672fe8fb19SBen Gras #include <sys/poll.h>
682fe8fb19SBen Gras #include <sys/socket.h>
692fe8fb19SBen Gras 
702fe8fb19SBen Gras #include <assert.h>
712fe8fb19SBen Gras #include <err.h>
722fe8fb19SBen Gras #include <errno.h>
732fe8fb19SBen Gras #include <netdb.h>
742fe8fb19SBen Gras #include <stdio.h>
752fe8fb19SBen Gras #include <stdlib.h>
762fe8fb19SBen Gras #include <string.h>
772fe8fb19SBen Gras #include <unistd.h>
782fe8fb19SBen Gras #include <signal.h>
792fe8fb19SBen Gras 
802fe8fb19SBen Gras #include <rpc/rpc.h>
812fe8fb19SBen Gras 
8284d9c625SLionel Sambuc #include "svc_fdset.h"
832fe8fb19SBen Gras #include "rpc_internal.h"
842fe8fb19SBen Gras 
852fe8fb19SBen Gras #ifdef __weak_alias
862fe8fb19SBen Gras __weak_alias(clnt_vc_create,_clnt_vc_create)
872fe8fb19SBen Gras #endif
882fe8fb19SBen Gras 
892fe8fb19SBen Gras #define MCALL_MSG_SIZE 24
902fe8fb19SBen Gras 
91f14fb602SLionel Sambuc static enum clnt_stat clnt_vc_call(CLIENT *, rpcproc_t, xdrproc_t,
92f14fb602SLionel Sambuc     const char *, xdrproc_t, caddr_t, struct timeval);
93f14fb602SLionel Sambuc static void clnt_vc_geterr(CLIENT *, struct rpc_err *);
94f14fb602SLionel Sambuc static bool_t clnt_vc_freeres(CLIENT *, xdrproc_t, caddr_t);
95f14fb602SLionel Sambuc static void clnt_vc_abort(CLIENT *);
96f14fb602SLionel Sambuc static bool_t clnt_vc_control(CLIENT *, u_int, char *);
97f14fb602SLionel Sambuc static void clnt_vc_destroy(CLIENT *);
98f14fb602SLionel Sambuc static struct clnt_ops *clnt_vc_ops(void);
99f14fb602SLionel Sambuc static bool_t time_not_ok(struct timeval *);
100f14fb602SLionel Sambuc static int read_vc(caddr_t, caddr_t, int);
101f14fb602SLionel Sambuc static int write_vc(caddr_t, caddr_t, int);
1022fe8fb19SBen Gras 
1032fe8fb19SBen Gras struct ct_data {
1042fe8fb19SBen Gras 	int		ct_fd;
1052fe8fb19SBen Gras 	bool_t		ct_closeit;
1062fe8fb19SBen Gras 	struct timeval	ct_wait;
1072fe8fb19SBen Gras 	bool_t          ct_waitset;       /* wait set by clnt_control? */
1082fe8fb19SBen Gras 	struct netbuf	ct_addr;
1092fe8fb19SBen Gras 	struct rpc_err	ct_error;
1102fe8fb19SBen Gras 	union {
1112fe8fb19SBen Gras 		char	ct_mcallc[MCALL_MSG_SIZE];	/* marshalled callmsg */
1122fe8fb19SBen Gras 		u_int32_t ct_mcalli;
1132fe8fb19SBen Gras 	} ct_u;
1142fe8fb19SBen Gras 	u_int		ct_mpos;			/* pos after marshal */
1152fe8fb19SBen Gras 	XDR		ct_xdrs;
1162fe8fb19SBen Gras };
1172fe8fb19SBen Gras 
1182fe8fb19SBen Gras /*
1192fe8fb19SBen Gras  *      This machinery implements per-fd locks for MT-safety.  It is not
1202fe8fb19SBen Gras  *      sufficient to do per-CLIENT handle locks for MT-safety because a
1212fe8fb19SBen Gras  *      user may create more than one CLIENT handle with the same fd behind
1222fe8fb19SBen Gras  *      it.  Therfore, we allocate an array of flags (vc_fd_locks), protected
1232fe8fb19SBen Gras  *      by the clnt_fd_lock mutex, and an array (vc_cv) of condition variables
1242fe8fb19SBen Gras  *      similarly protected.  Vc_fd_lock[fd] == 1 => a call is activte on some
1252fe8fb19SBen Gras  *      CLIENT handle created for that fd.
1262fe8fb19SBen Gras  *      The current implementation holds locks across the entire RPC and reply.
1272fe8fb19SBen Gras  *      Yes, this is silly, and as soon as this code is proven to work, this
1282fe8fb19SBen Gras  *      should be the first thing fixed.  One step at a time.
1292fe8fb19SBen Gras  */
1302fe8fb19SBen Gras #ifdef _REENTRANT
1312fe8fb19SBen Gras static int      *vc_fd_locks;
1322fe8fb19SBen Gras #define __rpc_lock_value __isthreaded;
1332fe8fb19SBen Gras extern mutex_t  clnt_fd_lock;
1342fe8fb19SBen Gras static cond_t   *vc_cv;
1352fe8fb19SBen Gras #define release_fd_lock(fd, mask) {             \
1362fe8fb19SBen Gras 	mutex_lock(&clnt_fd_lock);      \
1372fe8fb19SBen Gras 	vc_fd_locks[fd] = 0;            \
1382fe8fb19SBen Gras 	mutex_unlock(&clnt_fd_lock);    \
1392fe8fb19SBen Gras 	thr_sigsetmask(SIG_SETMASK, &(mask), NULL);        \
1402fe8fb19SBen Gras 	cond_signal(&vc_cv[fd]);        \
1412fe8fb19SBen Gras }
1422fe8fb19SBen Gras #else
1432fe8fb19SBen Gras #define release_fd_lock(fd,mask)
1442fe8fb19SBen Gras #define __rpc_lock_value 0
1452fe8fb19SBen Gras #endif
1462fe8fb19SBen Gras 
14784d9c625SLionel Sambuc static __inline void
htonlp(void * dst,const void * src,uint32_t incr)148*0a6a1f1dSLionel Sambuc htonlp(void *dst, const void *src, uint32_t incr)
14984d9c625SLionel Sambuc {
15084d9c625SLionel Sambuc #if 0
15184d9c625SLionel Sambuc 	uint32_t tmp;
15284d9c625SLionel Sambuc 	memcpy(&tmp, src, sizeof(tmp));
153*0a6a1f1dSLionel Sambuc 	tmp = htonl(tmp + incr);
15484d9c625SLionel Sambuc 	memcpy(dst, &tmp, sizeof(tmp));
15584d9c625SLionel Sambuc #else
15684d9c625SLionel Sambuc 	/* We are aligned, so we think */
157*0a6a1f1dSLionel Sambuc 	*(uint32_t *)dst = htonl(*(const uint32_t *)src + incr);
15884d9c625SLionel Sambuc #endif
15984d9c625SLionel Sambuc }
16084d9c625SLionel Sambuc 
16184d9c625SLionel Sambuc static __inline void
ntohlp(void * dst,const void * src)16284d9c625SLionel Sambuc ntohlp(void *dst, const void *src)
16384d9c625SLionel Sambuc {
16484d9c625SLionel Sambuc #if 0
16584d9c625SLionel Sambuc 	uint32_t tmp;
16684d9c625SLionel Sambuc 	memcpy(&tmp, src, sizeof(tmp));
16784d9c625SLionel Sambuc 	tmp = ntohl(tmp);
16884d9c625SLionel Sambuc 	memcpy(dst, &tmp, sizeof(tmp));
16984d9c625SLionel Sambuc #else
17084d9c625SLionel Sambuc 	/* We are aligned, so we think */
17184d9c625SLionel Sambuc 	*(uint32_t *)dst = htonl(*(const uint32_t *)src);
17284d9c625SLionel Sambuc #endif
17384d9c625SLionel Sambuc }
1742fe8fb19SBen Gras 
1752fe8fb19SBen Gras /*
1762fe8fb19SBen Gras  * Create a client handle for a connection.
1772fe8fb19SBen Gras  * Default options are set, which the user can change using clnt_control()'s.
1782fe8fb19SBen Gras  * The rpc/vc package does buffering similar to stdio, so the client
1792fe8fb19SBen Gras  * must pick send and receive buffer sizes, 0 => use the default.
1802fe8fb19SBen Gras  * NB: fd is copied into a private area.
1812fe8fb19SBen Gras  * NB: The rpch->cl_auth is set null authentication. Caller may wish to
1822fe8fb19SBen Gras  * set this something more useful.
1832fe8fb19SBen Gras  *
1842fe8fb19SBen Gras  * fd should be an open socket
1852fe8fb19SBen Gras  */
1862fe8fb19SBen Gras CLIENT *
clnt_vc_create(int fd,const struct netbuf * raddr,rpcprog_t prog,rpcvers_t vers,u_int sendsz,u_int recvsz)187f14fb602SLionel Sambuc clnt_vc_create(
188f14fb602SLionel Sambuc 	int fd,
189f14fb602SLionel Sambuc 	const struct netbuf *raddr,
190f14fb602SLionel Sambuc 	rpcprog_t prog,
191f14fb602SLionel Sambuc 	rpcvers_t vers,
192f14fb602SLionel Sambuc 	u_int sendsz,
193f14fb602SLionel Sambuc 	u_int recvsz
194f14fb602SLionel Sambuc )
1952fe8fb19SBen Gras {
1962fe8fb19SBen Gras 	CLIENT *h;
1972fe8fb19SBen Gras 	struct ct_data *ct = NULL;
1982fe8fb19SBen Gras 	struct rpc_msg call_msg;
1992fe8fb19SBen Gras #ifdef _REENTRANT
2002fe8fb19SBen Gras 	sigset_t mask;
2012fe8fb19SBen Gras #endif
2022fe8fb19SBen Gras 	sigset_t newmask;
2032fe8fb19SBen Gras 	struct sockaddr_storage ss;
2042fe8fb19SBen Gras 	socklen_t slen;
2052fe8fb19SBen Gras 	struct __rpc_sockinfo si;
2062fe8fb19SBen Gras 
2072fe8fb19SBen Gras 	_DIAGASSERT(raddr != NULL);
2082fe8fb19SBen Gras 
2092fe8fb19SBen Gras 	h  = mem_alloc(sizeof(*h));
2102fe8fb19SBen Gras 	if (h == NULL) {
2112fe8fb19SBen Gras 		warnx("clnt_vc_create: out of memory");
2122fe8fb19SBen Gras 		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
2132fe8fb19SBen Gras 		rpc_createerr.cf_error.re_errno = errno;
2142fe8fb19SBen Gras 		goto fooy;
2152fe8fb19SBen Gras 	}
2162fe8fb19SBen Gras 	ct = mem_alloc(sizeof(*ct));
2172fe8fb19SBen Gras 	if (ct == NULL) {
2182fe8fb19SBen Gras 		warnx("clnt_vc_create: out of memory");
2192fe8fb19SBen Gras 		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
2202fe8fb19SBen Gras 		rpc_createerr.cf_error.re_errno = errno;
2212fe8fb19SBen Gras 		goto fooy;
2222fe8fb19SBen Gras 	}
2232fe8fb19SBen Gras 
22484d9c625SLionel Sambuc 	__clnt_sigfillset(&newmask);
2252fe8fb19SBen Gras 	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
2262fe8fb19SBen Gras #ifdef _REENTRANT
2272fe8fb19SBen Gras 	mutex_lock(&clnt_fd_lock);
2282fe8fb19SBen Gras 	if (vc_fd_locks == NULL) {
2292fe8fb19SBen Gras 		size_t cv_allocsz, fd_allocsz;
2302fe8fb19SBen Gras 		int dtbsize = __rpc_dtbsize();
2312fe8fb19SBen Gras 
2322fe8fb19SBen Gras 		fd_allocsz = dtbsize * sizeof (int);
2332fe8fb19SBen Gras 		vc_fd_locks = mem_alloc(fd_allocsz);
2342fe8fb19SBen Gras 		if (vc_fd_locks == NULL) {
23584d9c625SLionel Sambuc 			goto blooy;
2362fe8fb19SBen Gras 		} else
2372fe8fb19SBen Gras 			memset(vc_fd_locks, '\0', fd_allocsz);
2382fe8fb19SBen Gras 
2392fe8fb19SBen Gras 		_DIAGASSERT(vc_cv == NULL);
2402fe8fb19SBen Gras 		cv_allocsz = dtbsize * sizeof (cond_t);
2412fe8fb19SBen Gras 		vc_cv = mem_alloc(cv_allocsz);
2422fe8fb19SBen Gras 		if (vc_cv == NULL) {
2432fe8fb19SBen Gras 			mem_free(vc_fd_locks, fd_allocsz);
2442fe8fb19SBen Gras 			vc_fd_locks = NULL;
24584d9c625SLionel Sambuc 			goto blooy;
2462fe8fb19SBen Gras 		} else {
2472fe8fb19SBen Gras 			int i;
2482fe8fb19SBen Gras 
2492fe8fb19SBen Gras 			for (i = 0; i < dtbsize; i++)
2502fe8fb19SBen Gras 				cond_init(&vc_cv[i], 0, (void *) 0);
2512fe8fb19SBen Gras 		}
2522fe8fb19SBen Gras 	} else
2532fe8fb19SBen Gras 		_DIAGASSERT(vc_cv != NULL);
2542fe8fb19SBen Gras #endif
2552fe8fb19SBen Gras 
2562fe8fb19SBen Gras 	/*
2572fe8fb19SBen Gras 	 * XXX - fvdl connecting while holding a mutex?
2582fe8fb19SBen Gras 	 */
2592fe8fb19SBen Gras 	slen = sizeof ss;
2602fe8fb19SBen Gras 	if (getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
2612fe8fb19SBen Gras 		if (errno != ENOTCONN) {
2622fe8fb19SBen Gras 			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
2632fe8fb19SBen Gras 			rpc_createerr.cf_error.re_errno = errno;
26484d9c625SLionel Sambuc 			goto blooy;
2652fe8fb19SBen Gras 		}
2662fe8fb19SBen Gras 		if (connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){
2672fe8fb19SBen Gras 			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
2682fe8fb19SBen Gras 			rpc_createerr.cf_error.re_errno = errno;
26984d9c625SLionel Sambuc 			goto blooy;
2702fe8fb19SBen Gras 		}
2712fe8fb19SBen Gras 	}
2722fe8fb19SBen Gras 	mutex_unlock(&clnt_fd_lock);
2732fe8fb19SBen Gras 	thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
2742fe8fb19SBen Gras 	if (!__rpc_fd2sockinfo(fd, &si))
2752fe8fb19SBen Gras 		goto fooy;
2762fe8fb19SBen Gras 
2772fe8fb19SBen Gras 	ct->ct_closeit = FALSE;
2782fe8fb19SBen Gras 
2792fe8fb19SBen Gras 	/*
2802fe8fb19SBen Gras 	 * Set up private data struct
2812fe8fb19SBen Gras 	 */
2822fe8fb19SBen Gras 	ct->ct_fd = fd;
2832fe8fb19SBen Gras 	ct->ct_wait.tv_usec = 0;
2842fe8fb19SBen Gras 	ct->ct_waitset = FALSE;
2852fe8fb19SBen Gras 	ct->ct_addr.buf = malloc((size_t)raddr->maxlen);
2862fe8fb19SBen Gras 	if (ct->ct_addr.buf == NULL)
2872fe8fb19SBen Gras 		goto fooy;
28884d9c625SLionel Sambuc 	memcpy(ct->ct_addr.buf, raddr->buf, (size_t)raddr->len);
28984d9c625SLionel Sambuc 	ct->ct_addr.len = raddr->len;
2902fe8fb19SBen Gras 	ct->ct_addr.maxlen = raddr->maxlen;
2912fe8fb19SBen Gras 
2922fe8fb19SBen Gras 	/*
2932fe8fb19SBen Gras 	 * Initialize call message
2942fe8fb19SBen Gras 	 */
2952fe8fb19SBen Gras 	call_msg.rm_xid = __RPC_GETXID();
2962fe8fb19SBen Gras 	call_msg.rm_direction = CALL;
2972fe8fb19SBen Gras 	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
2982fe8fb19SBen Gras 	call_msg.rm_call.cb_prog = (u_int32_t)prog;
2992fe8fb19SBen Gras 	call_msg.rm_call.cb_vers = (u_int32_t)vers;
3002fe8fb19SBen Gras 
3012fe8fb19SBen Gras 	/*
3022fe8fb19SBen Gras 	 * pre-serialize the static part of the call msg and stash it away
3032fe8fb19SBen Gras 	 */
3042fe8fb19SBen Gras 	xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE,
3052fe8fb19SBen Gras 	    XDR_ENCODE);
3062fe8fb19SBen Gras 	if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
3072fe8fb19SBen Gras 		if (ct->ct_closeit) {
3082fe8fb19SBen Gras 			(void)close(fd);
3092fe8fb19SBen Gras 		}
3102fe8fb19SBen Gras 		goto fooy;
3112fe8fb19SBen Gras 	}
3122fe8fb19SBen Gras 	ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
3132fe8fb19SBen Gras 	XDR_DESTROY(&(ct->ct_xdrs));
3142fe8fb19SBen Gras 
3152fe8fb19SBen Gras 	/*
3162fe8fb19SBen Gras 	 * Create a client handle which uses xdrrec for serialization
3172fe8fb19SBen Gras 	 * and authnone for authentication.
3182fe8fb19SBen Gras 	 */
3192fe8fb19SBen Gras 	h->cl_ops = clnt_vc_ops();
3202fe8fb19SBen Gras 	h->cl_private = ct;
3212fe8fb19SBen Gras 	h->cl_auth = authnone_create();
3222fe8fb19SBen Gras 	sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz);
3232fe8fb19SBen Gras 	recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz);
3242fe8fb19SBen Gras 	xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
3252fe8fb19SBen Gras 	    h->cl_private, read_vc, write_vc);
3262fe8fb19SBen Gras 	return (h);
3272fe8fb19SBen Gras 
32884d9c625SLionel Sambuc blooy:
32984d9c625SLionel Sambuc 	mutex_unlock(&clnt_fd_lock);
33084d9c625SLionel Sambuc 	thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
3312fe8fb19SBen Gras fooy:
3322fe8fb19SBen Gras 	/*
3332fe8fb19SBen Gras 	 * Something goofed, free stuff and barf
3342fe8fb19SBen Gras 	 */
3352fe8fb19SBen Gras 	if (ct)
3362fe8fb19SBen Gras 		mem_free(ct, sizeof(struct ct_data));
3372fe8fb19SBen Gras 	if (h)
3382fe8fb19SBen Gras 		mem_free(h, sizeof(CLIENT));
3392fe8fb19SBen Gras 	return (NULL);
3402fe8fb19SBen Gras }
3412fe8fb19SBen Gras 
3422fe8fb19SBen Gras static enum clnt_stat
clnt_vc_call(CLIENT * h,rpcproc_t proc,xdrproc_t xdr_args,const char * args_ptr,xdrproc_t xdr_results,caddr_t results_ptr,struct timeval timeout)343f14fb602SLionel Sambuc clnt_vc_call(
344f14fb602SLionel Sambuc 	CLIENT *h,
345f14fb602SLionel Sambuc 	rpcproc_t proc,
346f14fb602SLionel Sambuc 	xdrproc_t xdr_args,
347f14fb602SLionel Sambuc 	const char *args_ptr,
348f14fb602SLionel Sambuc 	xdrproc_t xdr_results,
349f14fb602SLionel Sambuc 	caddr_t results_ptr,
350f14fb602SLionel Sambuc 	struct timeval timeout
351f14fb602SLionel Sambuc )
3522fe8fb19SBen Gras {
3532fe8fb19SBen Gras 	struct ct_data *ct;
3542fe8fb19SBen Gras 	XDR *xdrs;
3552fe8fb19SBen Gras 	struct rpc_msg reply_msg;
3562fe8fb19SBen Gras 	u_int32_t x_id;
3572fe8fb19SBen Gras 	u_int32_t *msg_x_id;
3582fe8fb19SBen Gras 	bool_t shipnow;
3592fe8fb19SBen Gras 	int refreshes = 2;
3602fe8fb19SBen Gras #ifdef _REENTRANT
3612fe8fb19SBen Gras 	sigset_t mask, newmask;
3622fe8fb19SBen Gras #endif
3632fe8fb19SBen Gras 
3642fe8fb19SBen Gras 	_DIAGASSERT(h != NULL);
3652fe8fb19SBen Gras 
3662fe8fb19SBen Gras 	ct = (struct ct_data *) h->cl_private;
3672fe8fb19SBen Gras 
3682fe8fb19SBen Gras #ifdef _REENTRANT
36984d9c625SLionel Sambuc 	__clnt_sigfillset(&newmask);
3702fe8fb19SBen Gras 	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
3712fe8fb19SBen Gras 	mutex_lock(&clnt_fd_lock);
3722fe8fb19SBen Gras 	while (vc_fd_locks[ct->ct_fd])
3732fe8fb19SBen Gras 		cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
3742fe8fb19SBen Gras 	vc_fd_locks[ct->ct_fd] = __rpc_lock_value;
3752fe8fb19SBen Gras 	mutex_unlock(&clnt_fd_lock);
3762fe8fb19SBen Gras #endif
3772fe8fb19SBen Gras 
3782fe8fb19SBen Gras 	xdrs = &(ct->ct_xdrs);
3792fe8fb19SBen Gras 	msg_x_id = &ct->ct_u.ct_mcalli;
3802fe8fb19SBen Gras 
3812fe8fb19SBen Gras 	if (!ct->ct_waitset) {
3822fe8fb19SBen Gras 		if (time_not_ok(&timeout) == FALSE)
3832fe8fb19SBen Gras 		ct->ct_wait = timeout;
3842fe8fb19SBen Gras 	}
3852fe8fb19SBen Gras 
3862fe8fb19SBen Gras 	shipnow =
3872fe8fb19SBen Gras 	    (xdr_results == NULL && timeout.tv_sec == 0
3882fe8fb19SBen Gras 	    && timeout.tv_usec == 0) ? FALSE : TRUE;
3892fe8fb19SBen Gras 
3902fe8fb19SBen Gras call_again:
3912fe8fb19SBen Gras 	xdrs->x_op = XDR_ENCODE;
3922fe8fb19SBen Gras 	ct->ct_error.re_status = RPC_SUCCESS;
3932fe8fb19SBen Gras 	x_id = ntohl(--(*msg_x_id));
3942fe8fb19SBen Gras 	if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) ||
3952fe8fb19SBen Gras 	    (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) ||
3962fe8fb19SBen Gras 	    (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
3972fe8fb19SBen Gras 	    (! (*xdr_args)(xdrs, __UNCONST(args_ptr)))) {
3982fe8fb19SBen Gras 		if (ct->ct_error.re_status == RPC_SUCCESS)
3992fe8fb19SBen Gras 			ct->ct_error.re_status = RPC_CANTENCODEARGS;
4002fe8fb19SBen Gras 		(void)xdrrec_endofrecord(xdrs, TRUE);
4012fe8fb19SBen Gras 		release_fd_lock(ct->ct_fd, mask);
4022fe8fb19SBen Gras 		return (ct->ct_error.re_status);
4032fe8fb19SBen Gras 	}
4042fe8fb19SBen Gras 	if (! xdrrec_endofrecord(xdrs, shipnow)) {
4052fe8fb19SBen Gras 		release_fd_lock(ct->ct_fd, mask);
4062fe8fb19SBen Gras 		return (ct->ct_error.re_status = RPC_CANTSEND);
4072fe8fb19SBen Gras 	}
4082fe8fb19SBen Gras 	if (! shipnow) {
4092fe8fb19SBen Gras 		release_fd_lock(ct->ct_fd, mask);
4102fe8fb19SBen Gras 		return (RPC_SUCCESS);
4112fe8fb19SBen Gras 	}
4122fe8fb19SBen Gras 	/*
4132fe8fb19SBen Gras 	 * Hack to provide rpc-based message passing
4142fe8fb19SBen Gras 	 */
4152fe8fb19SBen Gras 	if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
4162fe8fb19SBen Gras 		release_fd_lock(ct->ct_fd, mask);
4172fe8fb19SBen Gras 		return(ct->ct_error.re_status = RPC_TIMEDOUT);
4182fe8fb19SBen Gras 	}
4192fe8fb19SBen Gras 
4202fe8fb19SBen Gras 
4212fe8fb19SBen Gras 	/*
4222fe8fb19SBen Gras 	 * Keep receiving until we get a valid transaction id
4232fe8fb19SBen Gras 	 */
4242fe8fb19SBen Gras 	xdrs->x_op = XDR_DECODE;
4252fe8fb19SBen Gras 	for (;;) {
4262fe8fb19SBen Gras 		reply_msg.acpted_rply.ar_verf = _null_auth;
4272fe8fb19SBen Gras 		reply_msg.acpted_rply.ar_results.where = NULL;
4282fe8fb19SBen Gras 		reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
4292fe8fb19SBen Gras 		if (! xdrrec_skiprecord(xdrs)) {
4302fe8fb19SBen Gras 			release_fd_lock(ct->ct_fd, mask);
4312fe8fb19SBen Gras 			return (ct->ct_error.re_status);
4322fe8fb19SBen Gras 		}
4332fe8fb19SBen Gras 		/* now decode and validate the response header */
4342fe8fb19SBen Gras 		if (! xdr_replymsg(xdrs, &reply_msg)) {
4352fe8fb19SBen Gras 			if (ct->ct_error.re_status == RPC_SUCCESS)
4362fe8fb19SBen Gras 				continue;
4372fe8fb19SBen Gras 			release_fd_lock(ct->ct_fd, mask);
4382fe8fb19SBen Gras 			return (ct->ct_error.re_status);
4392fe8fb19SBen Gras 		}
4402fe8fb19SBen Gras 		if (reply_msg.rm_xid == x_id)
4412fe8fb19SBen Gras 			break;
4422fe8fb19SBen Gras 	}
4432fe8fb19SBen Gras 
4442fe8fb19SBen Gras 	/*
4452fe8fb19SBen Gras 	 * process header
4462fe8fb19SBen Gras 	 */
4472fe8fb19SBen Gras 	_seterr_reply(&reply_msg, &(ct->ct_error));
4482fe8fb19SBen Gras 	if (ct->ct_error.re_status == RPC_SUCCESS) {
4492fe8fb19SBen Gras 		if (! AUTH_VALIDATE(h->cl_auth,
4502fe8fb19SBen Gras 		    &reply_msg.acpted_rply.ar_verf)) {
4512fe8fb19SBen Gras 			ct->ct_error.re_status = RPC_AUTHERROR;
4522fe8fb19SBen Gras 			ct->ct_error.re_why = AUTH_INVALIDRESP;
4532fe8fb19SBen Gras 		} else if (! (*xdr_results)(xdrs, results_ptr)) {
4542fe8fb19SBen Gras 			if (ct->ct_error.re_status == RPC_SUCCESS)
4552fe8fb19SBen Gras 				ct->ct_error.re_status = RPC_CANTDECODERES;
4562fe8fb19SBen Gras 		}
4572fe8fb19SBen Gras 		/* free verifier ... */
4582fe8fb19SBen Gras 		if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
4592fe8fb19SBen Gras 			xdrs->x_op = XDR_FREE;
4602fe8fb19SBen Gras 			(void)xdr_opaque_auth(xdrs,
4612fe8fb19SBen Gras 			    &(reply_msg.acpted_rply.ar_verf));
4622fe8fb19SBen Gras 		}
4632fe8fb19SBen Gras 	}  /* end successful completion */
4642fe8fb19SBen Gras 	else {
4652fe8fb19SBen Gras 		/* maybe our credentials need to be refreshed ... */
4662fe8fb19SBen Gras 		if (refreshes-- && AUTH_REFRESH(h->cl_auth))
4672fe8fb19SBen Gras 			goto call_again;
4682fe8fb19SBen Gras 	}  /* end of unsuccessful completion */
4692fe8fb19SBen Gras 	release_fd_lock(ct->ct_fd, mask);
4702fe8fb19SBen Gras 	return (ct->ct_error.re_status);
4712fe8fb19SBen Gras }
4722fe8fb19SBen Gras 
4732fe8fb19SBen Gras static void
clnt_vc_geterr(CLIENT * h,struct rpc_err * errp)474f14fb602SLionel Sambuc clnt_vc_geterr(
475f14fb602SLionel Sambuc 	CLIENT *h,
476f14fb602SLionel Sambuc 	struct rpc_err *errp
477f14fb602SLionel Sambuc )
4782fe8fb19SBen Gras {
4792fe8fb19SBen Gras 	struct ct_data *ct;
4802fe8fb19SBen Gras 
4812fe8fb19SBen Gras 	_DIAGASSERT(h != NULL);
4822fe8fb19SBen Gras 	_DIAGASSERT(errp != NULL);
4832fe8fb19SBen Gras 
4842fe8fb19SBen Gras 	ct = (struct ct_data *) h->cl_private;
4852fe8fb19SBen Gras 	*errp = ct->ct_error;
4862fe8fb19SBen Gras }
4872fe8fb19SBen Gras 
4882fe8fb19SBen Gras static bool_t
clnt_vc_freeres(CLIENT * cl,xdrproc_t xdr_res,caddr_t res_ptr)489f14fb602SLionel Sambuc clnt_vc_freeres(
490f14fb602SLionel Sambuc 	CLIENT *cl,
491f14fb602SLionel Sambuc 	xdrproc_t xdr_res,
492f14fb602SLionel Sambuc 	caddr_t res_ptr
493f14fb602SLionel Sambuc )
4942fe8fb19SBen Gras {
4952fe8fb19SBen Gras 	struct ct_data *ct;
4962fe8fb19SBen Gras 	XDR *xdrs;
4972fe8fb19SBen Gras 	bool_t dummy;
4982fe8fb19SBen Gras #ifdef _REENTRANT
4992fe8fb19SBen Gras 	sigset_t mask;
5002fe8fb19SBen Gras #endif
5012fe8fb19SBen Gras 	sigset_t newmask;
5022fe8fb19SBen Gras 
5032fe8fb19SBen Gras 	_DIAGASSERT(cl != NULL);
5042fe8fb19SBen Gras 
5052fe8fb19SBen Gras 	ct = (struct ct_data *)cl->cl_private;
5062fe8fb19SBen Gras 	xdrs = &(ct->ct_xdrs);
5072fe8fb19SBen Gras 
50884d9c625SLionel Sambuc 	__clnt_sigfillset(&newmask);
5092fe8fb19SBen Gras 	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
5102fe8fb19SBen Gras 	mutex_lock(&clnt_fd_lock);
5112fe8fb19SBen Gras #ifdef _REENTRANT
5122fe8fb19SBen Gras 	while (vc_fd_locks[ct->ct_fd])
5132fe8fb19SBen Gras 		cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
5142fe8fb19SBen Gras #endif
5152fe8fb19SBen Gras 
5162fe8fb19SBen Gras 	xdrs->x_op = XDR_FREE;
5172fe8fb19SBen Gras 	dummy = (*xdr_res)(xdrs, res_ptr);
5182fe8fb19SBen Gras 	mutex_unlock(&clnt_fd_lock);
5192fe8fb19SBen Gras 	thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
5202fe8fb19SBen Gras 	cond_signal(&vc_cv[ct->ct_fd]);
5212fe8fb19SBen Gras 
5222fe8fb19SBen Gras 	return dummy;
5232fe8fb19SBen Gras }
5242fe8fb19SBen Gras 
5252fe8fb19SBen Gras /*ARGSUSED*/
5262fe8fb19SBen Gras static void
clnt_vc_abort(CLIENT * cl)527f14fb602SLionel Sambuc clnt_vc_abort(CLIENT *cl)
5282fe8fb19SBen Gras {
5292fe8fb19SBen Gras }
5302fe8fb19SBen Gras 
5312fe8fb19SBen Gras static bool_t
clnt_vc_control(CLIENT * cl,u_int request,char * info)532f14fb602SLionel Sambuc clnt_vc_control(
533f14fb602SLionel Sambuc 	CLIENT *cl,
534f14fb602SLionel Sambuc 	u_int request,
535f14fb602SLionel Sambuc 	char *info
536f14fb602SLionel Sambuc )
5372fe8fb19SBen Gras {
5382fe8fb19SBen Gras 	struct ct_data *ct;
5392fe8fb19SBen Gras 	void *infop = info;
5402fe8fb19SBen Gras #ifdef _REENTRANT
5412fe8fb19SBen Gras 	sigset_t mask;
5422fe8fb19SBen Gras #endif
5432fe8fb19SBen Gras 	sigset_t newmask;
5442fe8fb19SBen Gras 
5452fe8fb19SBen Gras 	_DIAGASSERT(cl != NULL);
5462fe8fb19SBen Gras 
5472fe8fb19SBen Gras 	ct = (struct ct_data *)cl->cl_private;
5482fe8fb19SBen Gras 
54984d9c625SLionel Sambuc 	__clnt_sigfillset(&newmask);
5502fe8fb19SBen Gras 	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
5512fe8fb19SBen Gras 	mutex_lock(&clnt_fd_lock);
5522fe8fb19SBen Gras #ifdef _REENTRANT
5532fe8fb19SBen Gras 	while (vc_fd_locks[ct->ct_fd])
5542fe8fb19SBen Gras 		cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
5552fe8fb19SBen Gras 	vc_fd_locks[ct->ct_fd] = __rpc_lock_value;
5562fe8fb19SBen Gras #endif
5572fe8fb19SBen Gras 	mutex_unlock(&clnt_fd_lock);
5582fe8fb19SBen Gras 
5592fe8fb19SBen Gras 	switch (request) {
5602fe8fb19SBen Gras 	case CLSET_FD_CLOSE:
5612fe8fb19SBen Gras 		ct->ct_closeit = TRUE;
5622fe8fb19SBen Gras 		release_fd_lock(ct->ct_fd, mask);
5632fe8fb19SBen Gras 		return (TRUE);
5642fe8fb19SBen Gras 	case CLSET_FD_NCLOSE:
5652fe8fb19SBen Gras 		ct->ct_closeit = FALSE;
5662fe8fb19SBen Gras 		release_fd_lock(ct->ct_fd, mask);
5672fe8fb19SBen Gras 		return (TRUE);
5682fe8fb19SBen Gras 	default:
5692fe8fb19SBen Gras 		break;
5702fe8fb19SBen Gras 	}
5712fe8fb19SBen Gras 
5722fe8fb19SBen Gras 	/* for other requests which use info */
5732fe8fb19SBen Gras 	if (info == NULL) {
5742fe8fb19SBen Gras 		release_fd_lock(ct->ct_fd, mask);
5752fe8fb19SBen Gras 		return (FALSE);
5762fe8fb19SBen Gras 	}
5772fe8fb19SBen Gras 	switch (request) {
5782fe8fb19SBen Gras 	case CLSET_TIMEOUT:
5792fe8fb19SBen Gras 		if (time_not_ok((struct timeval *)(void *)info)) {
5802fe8fb19SBen Gras 			release_fd_lock(ct->ct_fd, mask);
5812fe8fb19SBen Gras 			return (FALSE);
5822fe8fb19SBen Gras 		}
5832fe8fb19SBen Gras 		ct->ct_wait = *(struct timeval *)infop;
5842fe8fb19SBen Gras 		ct->ct_waitset = TRUE;
5852fe8fb19SBen Gras 		break;
5862fe8fb19SBen Gras 	case CLGET_TIMEOUT:
5872fe8fb19SBen Gras 		*(struct timeval *)infop = ct->ct_wait;
5882fe8fb19SBen Gras 		break;
5892fe8fb19SBen Gras 	case CLGET_SERVER_ADDR:
5902fe8fb19SBen Gras 		(void) memcpy(info, ct->ct_addr.buf, (size_t)ct->ct_addr.len);
5912fe8fb19SBen Gras 		break;
5922fe8fb19SBen Gras 	case CLGET_FD:
5932fe8fb19SBen Gras 		*(int *)(void *)info = ct->ct_fd;
5942fe8fb19SBen Gras 		break;
5952fe8fb19SBen Gras 	case CLGET_SVC_ADDR:
5962fe8fb19SBen Gras 		/* The caller should not free this memory area */
5972fe8fb19SBen Gras 		*(struct netbuf *)(void *)info = ct->ct_addr;
5982fe8fb19SBen Gras 		break;
5992fe8fb19SBen Gras 	case CLSET_SVC_ADDR:		/* set to new address */
6002fe8fb19SBen Gras 		release_fd_lock(ct->ct_fd, mask);
6012fe8fb19SBen Gras 		return (FALSE);
6022fe8fb19SBen Gras 	case CLGET_XID:
6032fe8fb19SBen Gras 		/*
6042fe8fb19SBen Gras 		 * use the knowledge that xid is the
6052fe8fb19SBen Gras 		 * first element in the call structure
6062fe8fb19SBen Gras 		 * This will get the xid of the PREVIOUS call
6072fe8fb19SBen Gras 		 */
60884d9c625SLionel Sambuc 		ntohlp(info, &ct->ct_u.ct_mcalli);
6092fe8fb19SBen Gras 		break;
6102fe8fb19SBen Gras 	case CLSET_XID:
6112fe8fb19SBen Gras 		/* This will set the xid of the NEXT call */
6122fe8fb19SBen Gras 		/* increment by 1 as clnt_vc_call() decrements once */
613*0a6a1f1dSLionel Sambuc 		htonlp(&ct->ct_u.ct_mcalli, info, 1);
6142fe8fb19SBen Gras 		break;
6152fe8fb19SBen Gras 	case CLGET_VERS:
6162fe8fb19SBen Gras 		/*
6172fe8fb19SBen Gras 		 * This RELIES on the information that, in the call body,
6182fe8fb19SBen Gras 		 * the version number field is the fifth field from the
6192fe8fb19SBen Gras 		 * begining of the RPC header. MUST be changed if the
6202fe8fb19SBen Gras 		 * call_struct is changed
6212fe8fb19SBen Gras 		 */
62284d9c625SLionel Sambuc 		ntohlp(info, ct->ct_u.ct_mcallc + 4 * BYTES_PER_XDR_UNIT);
6232fe8fb19SBen Gras 		break;
6242fe8fb19SBen Gras 
6252fe8fb19SBen Gras 	case CLSET_VERS:
626*0a6a1f1dSLionel Sambuc 		htonlp(ct->ct_u.ct_mcallc + 4 * BYTES_PER_XDR_UNIT, info, 0);
6272fe8fb19SBen Gras 		break;
6282fe8fb19SBen Gras 
6292fe8fb19SBen Gras 	case CLGET_PROG:
6302fe8fb19SBen Gras 		/*
6312fe8fb19SBen Gras 		 * This RELIES on the information that, in the call body,
6322fe8fb19SBen Gras 		 * the program number field is the fourth field from the
6332fe8fb19SBen Gras 		 * begining of the RPC header. MUST be changed if the
6342fe8fb19SBen Gras 		 * call_struct is changed
6352fe8fb19SBen Gras 		 */
63684d9c625SLionel Sambuc 		ntohlp(info, ct->ct_u.ct_mcallc + 3 * BYTES_PER_XDR_UNIT);
6372fe8fb19SBen Gras 		break;
6382fe8fb19SBen Gras 
6392fe8fb19SBen Gras 	case CLSET_PROG:
640*0a6a1f1dSLionel Sambuc 		htonlp(ct->ct_u.ct_mcallc + 3 * BYTES_PER_XDR_UNIT, info, 0);
6412fe8fb19SBen Gras 		break;
6422fe8fb19SBen Gras 
6432fe8fb19SBen Gras 	default:
6442fe8fb19SBen Gras 		release_fd_lock(ct->ct_fd, mask);
6452fe8fb19SBen Gras 		return (FALSE);
6462fe8fb19SBen Gras 	}
6472fe8fb19SBen Gras 	release_fd_lock(ct->ct_fd, mask);
6482fe8fb19SBen Gras 	return (TRUE);
6492fe8fb19SBen Gras }
6502fe8fb19SBen Gras 
6512fe8fb19SBen Gras 
6522fe8fb19SBen Gras static void
clnt_vc_destroy(CLIENT * cl)653f14fb602SLionel Sambuc clnt_vc_destroy(CLIENT *cl)
6542fe8fb19SBen Gras {
6552fe8fb19SBen Gras 	struct ct_data *ct;
6562fe8fb19SBen Gras #ifdef _REENTRANT
6572fe8fb19SBen Gras 	int ct_fd;
6582fe8fb19SBen Gras 	sigset_t mask;
6592fe8fb19SBen Gras #endif
6602fe8fb19SBen Gras 	sigset_t newmask;
6612fe8fb19SBen Gras 
6622fe8fb19SBen Gras 	_DIAGASSERT(cl != NULL);
6632fe8fb19SBen Gras 
6642fe8fb19SBen Gras 	ct = (struct ct_data *) cl->cl_private;
6652fe8fb19SBen Gras 
66684d9c625SLionel Sambuc 	__clnt_sigfillset(&newmask);
6672fe8fb19SBen Gras 	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
6682fe8fb19SBen Gras 	mutex_lock(&clnt_fd_lock);
6692fe8fb19SBen Gras #ifdef _REENTRANT
670*0a6a1f1dSLionel Sambuc 	ct_fd = ct->ct_fd;
6712fe8fb19SBen Gras 	while (vc_fd_locks[ct_fd])
6722fe8fb19SBen Gras 		cond_wait(&vc_cv[ct_fd], &clnt_fd_lock);
6732fe8fb19SBen Gras #endif
6742fe8fb19SBen Gras 	if (ct->ct_closeit && ct->ct_fd != -1) {
6752fe8fb19SBen Gras 		(void)close(ct->ct_fd);
6762fe8fb19SBen Gras 	}
6772fe8fb19SBen Gras 	XDR_DESTROY(&(ct->ct_xdrs));
6782fe8fb19SBen Gras 	if (ct->ct_addr.buf)
6792fe8fb19SBen Gras 		free(ct->ct_addr.buf);
6802fe8fb19SBen Gras 	mem_free(ct, sizeof(struct ct_data));
6812fe8fb19SBen Gras 	mem_free(cl, sizeof(CLIENT));
6822fe8fb19SBen Gras 	mutex_unlock(&clnt_fd_lock);
6832fe8fb19SBen Gras 	thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
6842fe8fb19SBen Gras 
6852fe8fb19SBen Gras 	cond_signal(&vc_cv[ct_fd]);
6862fe8fb19SBen Gras }
6872fe8fb19SBen Gras 
6882fe8fb19SBen Gras /*
6892fe8fb19SBen Gras  * Interface between xdr serializer and tcp connection.
6902fe8fb19SBen Gras  * Behaves like the system calls, read & write, but keeps some error state
6912fe8fb19SBen Gras  * around for the rpc level.
6922fe8fb19SBen Gras  */
6932fe8fb19SBen Gras static int
read_vc(char * ctp,char * buf,int len)694f14fb602SLionel Sambuc read_vc(char *ctp, char *buf, int len)
6952fe8fb19SBen Gras {
6962fe8fb19SBen Gras 	struct ct_data *ct = (struct ct_data *)(void *)ctp;
6972fe8fb19SBen Gras 	struct pollfd fd;
6982fe8fb19SBen Gras 	struct timespec ts;
699f14fb602SLionel Sambuc 	ssize_t nread;
7002fe8fb19SBen Gras 
7012fe8fb19SBen Gras 	if (len == 0)
7022fe8fb19SBen Gras 		return (0);
7032fe8fb19SBen Gras 
7042fe8fb19SBen Gras 	TIMEVAL_TO_TIMESPEC(&ct->ct_wait, &ts);
7052fe8fb19SBen Gras 	fd.fd = ct->ct_fd;
7062fe8fb19SBen Gras 	fd.events = POLLIN;
7072fe8fb19SBen Gras 	for (;;) {
7082fe8fb19SBen Gras 		switch (pollts(&fd, 1, &ts, NULL)) {
7092fe8fb19SBen Gras 		case 0:
7102fe8fb19SBen Gras 			ct->ct_error.re_status = RPC_TIMEDOUT;
7112fe8fb19SBen Gras 			return (-1);
7122fe8fb19SBen Gras 
7132fe8fb19SBen Gras 		case -1:
7142fe8fb19SBen Gras 			if (errno == EINTR)
7152fe8fb19SBen Gras 				continue;
7162fe8fb19SBen Gras 			ct->ct_error.re_status = RPC_CANTRECV;
7172fe8fb19SBen Gras 			ct->ct_error.re_errno = errno;
7182fe8fb19SBen Gras 			return (-1);
7192fe8fb19SBen Gras 		}
7202fe8fb19SBen Gras 		break;
7212fe8fb19SBen Gras 	}
722f14fb602SLionel Sambuc 	switch (nread = read(ct->ct_fd, buf, (size_t)len)) {
7232fe8fb19SBen Gras 
7242fe8fb19SBen Gras 	case 0:
7252fe8fb19SBen Gras 		/* premature eof */
7262fe8fb19SBen Gras 		ct->ct_error.re_errno = ECONNRESET;
7272fe8fb19SBen Gras 		ct->ct_error.re_status = RPC_CANTRECV;
72884d9c625SLionel Sambuc 		nread = -1;  /* it's really an error */
7292fe8fb19SBen Gras 		break;
7302fe8fb19SBen Gras 
7312fe8fb19SBen Gras 	case -1:
7322fe8fb19SBen Gras 		ct->ct_error.re_errno = errno;
7332fe8fb19SBen Gras 		ct->ct_error.re_status = RPC_CANTRECV;
7342fe8fb19SBen Gras 		break;
7352fe8fb19SBen Gras 	}
736f14fb602SLionel Sambuc 	return (int)nread;
7372fe8fb19SBen Gras }
7382fe8fb19SBen Gras 
7392fe8fb19SBen Gras static int
write_vc(char * ctp,char * buf,int len)740f14fb602SLionel Sambuc write_vc(char *ctp, char *buf, int len)
7412fe8fb19SBen Gras {
7422fe8fb19SBen Gras 	struct ct_data *ct = (struct ct_data *)(void *)ctp;
743f14fb602SLionel Sambuc 	ssize_t i;
744f14fb602SLionel Sambuc 	size_t cnt;
7452fe8fb19SBen Gras 
7462fe8fb19SBen Gras 	for (cnt = len; cnt > 0; cnt -= i, buf += i) {
747f14fb602SLionel Sambuc 		if ((i = write(ct->ct_fd, buf, cnt)) == -1) {
7482fe8fb19SBen Gras 			ct->ct_error.re_errno = errno;
7492fe8fb19SBen Gras 			ct->ct_error.re_status = RPC_CANTSEND;
7502fe8fb19SBen Gras 			return (-1);
7512fe8fb19SBen Gras 		}
7522fe8fb19SBen Gras 	}
753f14fb602SLionel Sambuc 	return len;
7542fe8fb19SBen Gras }
7552fe8fb19SBen Gras 
7562fe8fb19SBen Gras static struct clnt_ops *
clnt_vc_ops(void)757f14fb602SLionel Sambuc clnt_vc_ops(void)
7582fe8fb19SBen Gras {
7592fe8fb19SBen Gras 	static struct clnt_ops ops;
7602fe8fb19SBen Gras #ifdef _REENTRANT
7612fe8fb19SBen Gras 	extern mutex_t  ops_lock;
7622fe8fb19SBen Gras 	sigset_t mask;
7632fe8fb19SBen Gras #endif
7642fe8fb19SBen Gras 	sigset_t newmask;
7652fe8fb19SBen Gras 
7662fe8fb19SBen Gras 	/* VARIABLES PROTECTED BY ops_lock: ops */
7672fe8fb19SBen Gras 
76884d9c625SLionel Sambuc 	__clnt_sigfillset(&newmask);
7692fe8fb19SBen Gras 	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
7702fe8fb19SBen Gras 	mutex_lock(&ops_lock);
7712fe8fb19SBen Gras 	if (ops.cl_call == NULL) {
7722fe8fb19SBen Gras 		ops.cl_call = clnt_vc_call;
7732fe8fb19SBen Gras 		ops.cl_abort = clnt_vc_abort;
7742fe8fb19SBen Gras 		ops.cl_geterr = clnt_vc_geterr;
7752fe8fb19SBen Gras 		ops.cl_freeres = clnt_vc_freeres;
7762fe8fb19SBen Gras 		ops.cl_destroy = clnt_vc_destroy;
7772fe8fb19SBen Gras 		ops.cl_control = clnt_vc_control;
7782fe8fb19SBen Gras 	}
7792fe8fb19SBen Gras 	mutex_unlock(&ops_lock);
7802fe8fb19SBen Gras 	thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
7812fe8fb19SBen Gras 	return (&ops);
7822fe8fb19SBen Gras }
7832fe8fb19SBen Gras 
7842fe8fb19SBen Gras /*
7852fe8fb19SBen Gras  * Make sure that the time is not garbage.   -1 value is disallowed.
7862fe8fb19SBen Gras  * Note this is different from time_not_ok in clnt_dg.c
7872fe8fb19SBen Gras  */
7882fe8fb19SBen Gras static bool_t
time_not_ok(struct timeval * t)789f14fb602SLionel Sambuc time_not_ok(struct timeval *t)
7902fe8fb19SBen Gras {
7912fe8fb19SBen Gras 
7922fe8fb19SBen Gras 	_DIAGASSERT(t != NULL);
7932fe8fb19SBen Gras 
7942fe8fb19SBen Gras 	return (t->tv_sec <= -1 || t->tv_sec > 100000000 ||
7952fe8fb19SBen Gras 		t->tv_usec <= -1 || t->tv_usec > 1000000);
7962fe8fb19SBen Gras }
797