clnt_vc.c revision 74627
174462Salfred/*	$NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $	*/
274462Salfred/*	$FreeBSD: head/lib/libc/rpc/clnt_vc.c 74627 2001-03-22 04:31:30Z alfred $ */
374462Salfred
474462Salfred/*
574462Salfred * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
674462Salfred * unrestricted use provided that this legend is included on all tape
774462Salfred * media and as a part of the software program in whole or part.  Users
874462Salfred * may copy or modify Sun RPC without charge, but are not authorized
974462Salfred * to license or distribute it to anyone else except as part of a product or
1074462Salfred * program developed by the user.
1174462Salfred *
1274462Salfred * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
1374462Salfred * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
1474462Salfred * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
1574462Salfred *
1674462Salfred * Sun RPC is provided with no support and without any obligation on the
1774462Salfred * part of Sun Microsystems, Inc. to assist in its use, correction,
1874462Salfred * modification or enhancement.
1974462Salfred *
2074462Salfred * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
2174462Salfred * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
2274462Salfred * OR ANY PART THEREOF.
2374462Salfred *
2474462Salfred * In no event will Sun Microsystems, Inc. be liable for any lost revenue
2574462Salfred * or profits or other special, indirect and consequential damages, even if
2674462Salfred * Sun has been advised of the possibility of such damages.
2774462Salfred *
2874462Salfred * Sun Microsystems, Inc.
2974462Salfred * 2550 Garcia Avenue
3074462Salfred * Mountain View, California  94043
3174462Salfred */
3274462Salfred
3374462Salfred#include <sys/cdefs.h>
3474462Salfred#if defined(LIBC_SCCS) && !defined(lint)
3574462Salfredstatic char *sccsid = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
3674462Salfredstatic char *sccsid = "@(#)clnt_tcp.c	2.2 88/08/01 4.0 RPCSRC";
3774462Salfredstatic char sccsid[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro";
3874462Salfred#endif
3974462Salfred
4074462Salfred/*
4174462Salfred * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
4274462Salfred *
4374462Salfred * Copyright (C) 1984, Sun Microsystems, Inc.
4474462Salfred *
4574462Salfred * TCP based RPC supports 'batched calls'.
4674462Salfred * A sequence of calls may be batched-up in a send buffer.  The rpc call
4774462Salfred * return immediately to the client even though the call was not necessarily
4874462Salfred * sent.  The batching occurs if the results' xdr routine is NULL (0) AND
4974462Salfred * the rpc timeout value is zero (see clnt.h, rpc).
5074462Salfred *
5174462Salfred * Clients should NOT casually batch calls that in fact return results; that is,
5274462Salfred * the server side should be aware that a call is batched and not produce any
5374462Salfred * return message.  Batched calls that produce many result messages can
5474462Salfred * deadlock (netlock) the client and the server....
5574462Salfred *
5674462Salfred * Now go hang yourself.
5774462Salfred */
5874462Salfred
5974462Salfred#include "reentrant.h"
6074462Salfred#include "namespace.h"
6174462Salfred#include <sys/types.h>
6274462Salfred#include <sys/poll.h>
6374462Salfred#include <sys/syslog.h>
6474462Salfred#include <sys/socket.h>
6574462Salfred#include <sys/un.h>
6674462Salfred#include <sys/uio.h>
6774462Salfred
6874462Salfred#include <assert.h>
6974462Salfred#include <err.h>
7074462Salfred#include <errno.h>
7174462Salfred#include <netdb.h>
7274462Salfred#include <stdio.h>
7374462Salfred#include <stdlib.h>
7474462Salfred#include <string.h>
7574462Salfred#include <unistd.h>
7674462Salfred#include <signal.h>
7774462Salfred
7874462Salfred#include <rpc/rpc.h>
7974462Salfred#include "un-namespace.h"
8074462Salfred#include "rpc_com.h"
8174462Salfred
8274462Salfred#define MCALL_MSG_SIZE 24
8374462Salfred
8474462Salfredstatic enum clnt_stat clnt_vc_call __P((CLIENT *, rpcproc_t, xdrproc_t, caddr_t,
8574462Salfred    xdrproc_t, caddr_t, struct timeval));
8674462Salfredstatic void clnt_vc_geterr __P((CLIENT *, struct rpc_err *));
8774462Salfredstatic bool_t clnt_vc_freeres __P((CLIENT *, xdrproc_t, caddr_t));
8874462Salfredstatic void clnt_vc_abort __P((CLIENT *));
8974462Salfredstatic bool_t clnt_vc_control __P((CLIENT *, u_int, char *));
9074462Salfredstatic void clnt_vc_destroy __P((CLIENT *));
9174462Salfredstatic struct clnt_ops *clnt_vc_ops __P((void));
9274462Salfredstatic bool_t time_not_ok __P((struct timeval *));
9374462Salfredstatic int read_vc __P((caddr_t, caddr_t, int));
9474462Salfredstatic int write_vc __P((caddr_t, caddr_t, int));
9574462Salfredstatic int __msgwrite(int, void *, size_t);
9674462Salfredstatic int __msgread(int, void *, size_t);
9774462Salfred
9874462Salfredstruct ct_data {
9974462Salfred	int		ct_fd;		/* connection's fd */
10074462Salfred	bool_t		ct_closeit;	/* close it on destroy */
10174462Salfred	struct timeval	ct_wait;	/* wait interval in milliseconds */
10274462Salfred	bool_t          ct_waitset;	/* wait set by clnt_control? */
10374462Salfred	struct netbuf	ct_addr;	/* remote addr */
10474462Salfred	struct rpc_err	ct_error;
10574462Salfred	union {
10674462Salfred		char	ct_mcallc[MCALL_MSG_SIZE];	/* marshalled callmsg */
10774462Salfred		u_int32_t ct_mcalli;
10874462Salfred	} ct_u;
10974462Salfred	u_int		ct_mpos;	/* pos after marshal */
11074462Salfred	XDR		ct_xdrs;	/* XDR stream */
11174462Salfred};
11274462Salfred
11374462Salfred/*
11474462Salfred *      This machinery implements per-fd locks for MT-safety.  It is not
11574462Salfred *      sufficient to do per-CLIENT handle locks for MT-safety because a
11674462Salfred *      user may create more than one CLIENT handle with the same fd behind
11774462Salfred *      it.  Therfore, we allocate an array of flags (vc_fd_locks), protected
11874462Salfred *      by the clnt_fd_lock mutex, and an array (vc_cv) of condition variables
11974462Salfred *      similarly protected.  Vc_fd_lock[fd] == 1 => a call is activte on some
12074462Salfred *      CLIENT handle created for that fd.
12174462Salfred *      The current implementation holds locks across the entire RPC and reply.
12274462Salfred *      Yes, this is silly, and as soon as this code is proven to work, this
12374462Salfred *      should be the first thing fixed.  One step at a time.
12474462Salfred */
12574462Salfredstatic int      *vc_fd_locks;
12674462Salfredextern mutex_t  clnt_fd_lock;
12774462Salfredstatic cond_t   *vc_cv;
12874462Salfred#define release_fd_lock(fd, mask) {	\
12974462Salfred	mutex_lock(&clnt_fd_lock);	\
13074462Salfred	if (__isthreaded)		\
13174462Salfred		vc_fd_locks[fd] = 0;	\
13274462Salfred	mutex_unlock(&clnt_fd_lock);	\
13374462Salfred	thr_sigsetmask(SIG_SETMASK, &(mask), (sigset_t *) NULL);	\
13474462Salfred	cond_signal(&vc_cv[fd]);	\
13574462Salfred}
13674462Salfred
13774462Salfredstatic const char clnt_vc_errstr[] = "%s : %s";
13874462Salfredstatic const char clnt_vc_str[] = "clnt_vc_create";
13974462Salfredstatic const char clnt_read_vc_str[] = "read_vc";
14074462Salfredstatic const char __no_mem_str[] = "out of memory";
14174462Salfred
14274462Salfred/*
14374462Salfred * Create a client handle for a connection.
14474462Salfred * Default options are set, which the user can change using clnt_control()'s.
14574462Salfred * The rpc/vc package does buffering similar to stdio, so the client
14674462Salfred * must pick send and receive buffer sizes, 0 => use the default.
14774462Salfred * NB: fd is copied into a private area.
14874462Salfred * NB: The rpch->cl_auth is set null authentication. Caller may wish to
14974462Salfred * set this something more useful.
15074462Salfred *
15174462Salfred * fd should be an open socket
15274462Salfred */
15374462SalfredCLIENT *
15474462Salfredclnt_vc_create(fd, raddr, prog, vers, sendsz, recvsz)
15574462Salfred	int fd;				/* open file descriptor */
15674462Salfred	const struct netbuf *raddr;	/* servers address */
15774462Salfred	rpcprog_t prog;			/* program number */
15874462Salfred	rpcvers_t vers;			/* version number */
15974462Salfred	u_int sendsz;			/* buffer recv size */
16074462Salfred	u_int recvsz;			/* buffer send size */
16174462Salfred{
16274462Salfred	CLIENT *cl;			/* client handle */
16374462Salfred	struct ct_data *ct = NULL;	/* client handle */
16474462Salfred	struct timeval now;
16574462Salfred	struct rpc_msg call_msg;
16674462Salfred	static u_int32_t disrupt;
16774462Salfred	sigset_t mask;
16874462Salfred	sigset_t newmask;
16974462Salfred	struct sockaddr_storage ss;
17074462Salfred	socklen_t slen;
17174462Salfred	struct __rpc_sockinfo si;
17274462Salfred
17374462Salfred	if (disrupt == 0)
17474462Salfred		disrupt = (u_int32_t)(long)raddr;
17574462Salfred
17674462Salfred	cl = (CLIENT *)mem_alloc(sizeof (*cl));
17774462Salfred	ct = (struct ct_data *)mem_alloc(sizeof (*ct));
17874462Salfred	if ((cl == (CLIENT *)NULL) || (ct == (struct ct_data *)NULL)) {
17974462Salfred		(void) syslog(LOG_ERR, clnt_vc_errstr,
18074462Salfred		    clnt_vc_str, __no_mem_str);
18174462Salfred		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
18274462Salfred		rpc_createerr.cf_error.re_errno = errno;
18374462Salfred		goto err;
18474462Salfred	}
18574462Salfred	ct->ct_addr.buf = NULL;
18674462Salfred	sigfillset(&newmask);
18774462Salfred	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
18874462Salfred	mutex_lock(&clnt_fd_lock);
18974462Salfred	if (vc_fd_locks == (int *) NULL) {
19074462Salfred		int cv_allocsz, fd_allocsz;
19174462Salfred		int dtbsize = __rpc_dtbsize();
19274462Salfred
19374462Salfred		fd_allocsz = dtbsize * sizeof (int);
19474462Salfred		vc_fd_locks = (int *) mem_alloc(fd_allocsz);
19574462Salfred		if (vc_fd_locks == (int *) NULL) {
19674462Salfred			mutex_unlock(&clnt_fd_lock);
19774462Salfred			thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
19874462Salfred			goto err;
19974462Salfred		} else
20074462Salfred			memset(vc_fd_locks, '\0', fd_allocsz);
20174462Salfred
20274462Salfred		assert(vc_cv == (cond_t *) NULL);
20374462Salfred		cv_allocsz = dtbsize * sizeof (cond_t);
20474462Salfred		vc_cv = (cond_t *) mem_alloc(cv_allocsz);
20574462Salfred		if (vc_cv == (cond_t *) NULL) {
20674462Salfred			mem_free(vc_fd_locks, fd_allocsz);
20774462Salfred			vc_fd_locks = (int *) NULL;
20874462Salfred			mutex_unlock(&clnt_fd_lock);
20974462Salfred			thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
21074462Salfred			goto err;
21174462Salfred		} else {
21274462Salfred			int i;
21374462Salfred
21474462Salfred			for (i = 0; i < dtbsize; i++)
21574462Salfred				cond_init(&vc_cv[i], 0, (void *) 0);
21674462Salfred		}
21774462Salfred	} else
21874462Salfred		assert(vc_cv != (cond_t *) NULL);
21974462Salfred
22074462Salfred	/*
22174462Salfred	 * XXX - fvdl connecting while holding a mutex?
22274462Salfred	 */
22374462Salfred	slen = sizeof ss;
22474462Salfred	if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
22574462Salfred		if (errno != ENOTCONN) {
22674462Salfred			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
22774462Salfred			rpc_createerr.cf_error.re_errno = errno;
22874462Salfred			mutex_unlock(&clnt_fd_lock);
22974462Salfred			goto err;
23074462Salfred		}
23174462Salfred		if (_connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){
23274462Salfred			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
23374462Salfred			rpc_createerr.cf_error.re_errno = errno;
23474462Salfred			mutex_unlock(&clnt_fd_lock);
23574462Salfred			goto err;
23674462Salfred		}
23774462Salfred	}
23874462Salfred	mutex_unlock(&clnt_fd_lock);
23974462Salfred	if (!__rpc_fd2sockinfo(fd, &si))
24074462Salfred		goto err;
24174462Salfred	thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
24274462Salfred
24374462Salfred	ct->ct_closeit = FALSE;
24474462Salfred
24574462Salfred	/*
24674462Salfred	 * Set up private data struct
24774462Salfred	 */
24874462Salfred	ct->ct_fd = fd;
24974462Salfred	ct->ct_wait.tv_usec = 0;
25074462Salfred	ct->ct_waitset = FALSE;
25174462Salfred	ct->ct_addr.buf = malloc(raddr->maxlen);
25274462Salfred	if (ct->ct_addr.buf == NULL)
25374462Salfred		goto err;
25474462Salfred	memcpy(ct->ct_addr.buf, &raddr->buf, raddr->len);
25574462Salfred	ct->ct_addr.len = raddr->maxlen;
25674462Salfred	ct->ct_addr.maxlen = raddr->maxlen;
25774462Salfred
25874462Salfred	/*
25974462Salfred	 * Initialize call message
26074462Salfred	 */
26174462Salfred	(void)gettimeofday(&now, NULL);
26274462Salfred	call_msg.rm_xid = ((u_int32_t)++disrupt) ^ __RPC_GETXID(&now);
26374462Salfred	call_msg.rm_direction = CALL;
26474462Salfred	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
26574462Salfred	call_msg.rm_call.cb_prog = (u_int32_t)prog;
26674462Salfred	call_msg.rm_call.cb_vers = (u_int32_t)vers;
26774462Salfred
26874462Salfred	/*
26974462Salfred	 * pre-serialize the static part of the call msg and stash it away
27074462Salfred	 */
27174462Salfred	xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE,
27274462Salfred	    XDR_ENCODE);
27374462Salfred	if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
27474462Salfred		if (ct->ct_closeit) {
27574462Salfred			(void)_close(fd);
27674462Salfred		}
27774462Salfred		goto err;
27874462Salfred	}
27974462Salfred	ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
28074462Salfred	XDR_DESTROY(&(ct->ct_xdrs));
28174462Salfred
28274462Salfred	/*
28374462Salfred	 * Create a client handle which uses xdrrec for serialization
28474462Salfred	 * and authnone for authentication.
28574462Salfred	 */
28674462Salfred	cl->cl_ops = clnt_vc_ops();
28774462Salfred	cl->cl_private = ct;
28874462Salfred	cl->cl_auth = authnone_create();
28974462Salfred	sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz);
29074462Salfred	recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz);
29174462Salfred	xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
29274462Salfred	    cl->cl_private, read_vc, write_vc);
29374462Salfred	return (cl);
29474462Salfred
29574462Salfrederr:
29674462Salfred	if (cl) {
29774462Salfred		if (ct) {
29874462Salfred			if (ct->ct_addr.len)
29974462Salfred				mem_free(ct->ct_addr.buf, ct->ct_addr.len);
30074462Salfred			mem_free((caddr_t)ct, sizeof (struct ct_data));
30174462Salfred		}
30274462Salfred		if (cl)
30374462Salfred			mem_free((caddr_t)cl, sizeof (CLIENT));
30474462Salfred	}
30574462Salfred	return ((CLIENT *)NULL);
30674462Salfred}
30774462Salfred
30874462Salfredstatic enum clnt_stat
30974462Salfredclnt_vc_call(cl, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
31074462Salfred	CLIENT *cl;
31174462Salfred	rpcproc_t proc;
31274462Salfred	xdrproc_t xdr_args;
31374462Salfred	caddr_t args_ptr;
31474462Salfred	xdrproc_t xdr_results;
31574462Salfred	caddr_t results_ptr;
31674462Salfred	struct timeval timeout;
31774462Salfred{
31874462Salfred	struct ct_data *ct = (struct ct_data *) cl->cl_private;
31974462Salfred	XDR *xdrs = &(ct->ct_xdrs);
32074462Salfred	struct rpc_msg reply_msg;
32174462Salfred	u_int32_t x_id;
32274462Salfred	u_int32_t *msg_x_id = &ct->ct_u.ct_mcalli;    /* yuk */
32374462Salfred	bool_t shipnow;
32474462Salfred	int refreshes = 2;
32574462Salfred	sigset_t mask, newmask;
32674462Salfred	int rpc_lock_value;
32774462Salfred
32874462Salfred	assert(cl != NULL);
32974462Salfred
33074462Salfred	sigfillset(&newmask);
33174462Salfred	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
33274462Salfred	mutex_lock(&clnt_fd_lock);
33374462Salfred	while (vc_fd_locks[ct->ct_fd])
33474462Salfred		cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
33574462Salfred	if (__isthreaded)
33674462Salfred                rpc_lock_value = 1;
33774462Salfred        else
33874462Salfred                rpc_lock_value = 0;
33974462Salfred	vc_fd_locks[ct->ct_fd] = rpc_lock_value;
34074462Salfred	mutex_unlock(&clnt_fd_lock);
34174462Salfred	if (!ct->ct_waitset) {
34274462Salfred		/* If time is not within limits, we ignore it. */
34374462Salfred		if (time_not_ok(&timeout) == FALSE)
34474462Salfred			ct->ct_wait = timeout;
34574462Salfred	}
34674462Salfred
34774462Salfred	shipnow =
34874462Salfred	    (xdr_results == NULL && timeout.tv_sec == 0
34974462Salfred	    && timeout.tv_usec == 0) ? FALSE : TRUE;
35074462Salfred
35174462Salfredcall_again:
35274462Salfred	xdrs->x_op = XDR_ENCODE;
35374462Salfred	ct->ct_error.re_status = RPC_SUCCESS;
35474462Salfred	x_id = ntohl(--(*msg_x_id));
35574462Salfred
35674462Salfred	if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) ||
35774462Salfred	    (! XDR_PUTINT32(xdrs, &proc)) ||
35874462Salfred	    (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
35974462Salfred	    (! (*xdr_args)(xdrs, args_ptr))) {
36074462Salfred		if (ct->ct_error.re_status == RPC_SUCCESS)
36174462Salfred			ct->ct_error.re_status = RPC_CANTENCODEARGS;
36274462Salfred		(void)xdrrec_endofrecord(xdrs, TRUE);
36374462Salfred		release_fd_lock(ct->ct_fd, mask);
36474462Salfred		return (ct->ct_error.re_status);
36574462Salfred	}
36674462Salfred	if (! xdrrec_endofrecord(xdrs, shipnow)) {
36774462Salfred		release_fd_lock(ct->ct_fd, mask);
36874462Salfred		return (ct->ct_error.re_status = RPC_CANTSEND);
36974462Salfred	}
37074462Salfred	if (! shipnow) {
37174462Salfred		release_fd_lock(ct->ct_fd, mask);
37274462Salfred		return (RPC_SUCCESS);
37374462Salfred	}
37474462Salfred	/*
37574462Salfred	 * Hack to provide rpc-based message passing
37674462Salfred	 */
37774462Salfred	if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
37874462Salfred		release_fd_lock(ct->ct_fd, mask);
37974462Salfred		return(ct->ct_error.re_status = RPC_TIMEDOUT);
38074462Salfred	}
38174462Salfred
38274462Salfred
38374462Salfred	/*
38474462Salfred	 * Keep receiving until we get a valid transaction id
38574462Salfred	 */
38674462Salfred	xdrs->x_op = XDR_DECODE;
38774462Salfred	while (TRUE) {
38874462Salfred		reply_msg.acpted_rply.ar_verf = _null_auth;
38974462Salfred		reply_msg.acpted_rply.ar_results.where = NULL;
39074462Salfred		reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
39174462Salfred		if (! xdrrec_skiprecord(xdrs)) {
39274462Salfred			release_fd_lock(ct->ct_fd, mask);
39374462Salfred			return (ct->ct_error.re_status);
39474462Salfred		}
39574462Salfred		/* now decode and validate the response header */
39674462Salfred		if (! xdr_replymsg(xdrs, &reply_msg)) {
39774462Salfred			if (ct->ct_error.re_status == RPC_SUCCESS)
39874462Salfred				continue;
39974462Salfred			release_fd_lock(ct->ct_fd, mask);
40074462Salfred			return (ct->ct_error.re_status);
40174462Salfred		}
40274462Salfred		if (reply_msg.rm_xid == x_id)
40374462Salfred			break;
40474462Salfred	}
40574462Salfred
40674462Salfred	/*
40774462Salfred	 * process header
40874462Salfred	 */
40974462Salfred	_seterr_reply(&reply_msg, &(ct->ct_error));
41074462Salfred	if (ct->ct_error.re_status == RPC_SUCCESS) {
41174462Salfred		if (! AUTH_VALIDATE(cl->cl_auth,
41274462Salfred		    &reply_msg.acpted_rply.ar_verf)) {
41374462Salfred			ct->ct_error.re_status = RPC_AUTHERROR;
41474462Salfred			ct->ct_error.re_why = AUTH_INVALIDRESP;
41574462Salfred		} else if (! (*xdr_results)(xdrs, results_ptr)) {
41674462Salfred			if (ct->ct_error.re_status == RPC_SUCCESS)
41774462Salfred				ct->ct_error.re_status = RPC_CANTDECODERES;
41874462Salfred		}
41974462Salfred		/* free verifier ... */
42074462Salfred		if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
42174462Salfred			xdrs->x_op = XDR_FREE;
42274462Salfred			(void)xdr_opaque_auth(xdrs,
42374462Salfred			    &(reply_msg.acpted_rply.ar_verf));
42474462Salfred		}
42574462Salfred	}  /* end successful completion */
42674462Salfred	else {
42774462Salfred		/* maybe our credentials need to be refreshed ... */
42874462Salfred		if (refreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg))
42974462Salfred			goto call_again;
43074462Salfred	}  /* end of unsuccessful completion */
43174462Salfred	release_fd_lock(ct->ct_fd, mask);
43274462Salfred	return (ct->ct_error.re_status);
43374462Salfred}
43474462Salfred
43574462Salfredstatic void
43674462Salfredclnt_vc_geterr(cl, errp)
43774462Salfred	CLIENT *cl;
43874462Salfred	struct rpc_err *errp;
43974462Salfred{
44074462Salfred	struct ct_data *ct;
44174462Salfred
44274462Salfred	assert(cl != NULL);
44374462Salfred	assert(errp != NULL);
44474462Salfred
44574462Salfred	ct = (struct ct_data *) cl->cl_private;
44674462Salfred	*errp = ct->ct_error;
44774462Salfred}
44874462Salfred
44974462Salfredstatic bool_t
45074462Salfredclnt_vc_freeres(cl, xdr_res, res_ptr)
45174462Salfred	CLIENT *cl;
45274462Salfred	xdrproc_t xdr_res;
45374462Salfred	caddr_t res_ptr;
45474462Salfred{
45574462Salfred	struct ct_data *ct;
45674462Salfred	XDR *xdrs;
45774462Salfred	bool_t dummy;
45874462Salfred	sigset_t mask;
45974462Salfred	sigset_t newmask;
46074462Salfred
46174462Salfred	assert(cl != NULL);
46274462Salfred
46374462Salfred	ct = (struct ct_data *)cl->cl_private;
46474462Salfred	xdrs = &(ct->ct_xdrs);
46574462Salfred
46674462Salfred	sigfillset(&newmask);
46774462Salfred	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
46874462Salfred	mutex_lock(&clnt_fd_lock);
46974462Salfred	while (vc_fd_locks[ct->ct_fd])
47074462Salfred		cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
47174462Salfred	xdrs->x_op = XDR_FREE;
47274462Salfred	dummy = (*xdr_res)(xdrs, res_ptr);
47374462Salfred	mutex_unlock(&clnt_fd_lock);
47474462Salfred	thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
47574462Salfred	cond_signal(&vc_cv[ct->ct_fd]);
47674462Salfred
47774462Salfred	return dummy;
47874462Salfred}
47974462Salfred
48074462Salfred/*ARGSUSED*/
48174462Salfredstatic void
48274462Salfredclnt_vc_abort(cl)
48374462Salfred	CLIENT *cl;
48474462Salfred{
48574462Salfred}
48674462Salfred
48774462Salfredstatic bool_t
48874462Salfredclnt_vc_control(cl, request, info)
48974462Salfred	CLIENT *cl;
49074462Salfred	u_int request;
49174462Salfred	char *info;
49274462Salfred{
49374462Salfred	struct ct_data *ct;
49474462Salfred	void *infop = info;
49574462Salfred	sigset_t mask;
49674462Salfred	sigset_t newmask;
49774462Salfred	int rpc_lock_value;
49874462Salfred
49974462Salfred	assert(cl != NULL);
50074462Salfred
50174462Salfred	ct = (struct ct_data *)cl->cl_private;
50274462Salfred
50374462Salfred	sigfillset(&newmask);
50474462Salfred	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
50574462Salfred	mutex_lock(&clnt_fd_lock);
50674462Salfred	while (vc_fd_locks[ct->ct_fd])
50774462Salfred		cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
50874462Salfred	if (__isthreaded)
50974462Salfred                rpc_lock_value = 1;
51074462Salfred        else
51174462Salfred                rpc_lock_value = 0;
51274462Salfred	vc_fd_locks[ct->ct_fd] = rpc_lock_value;
51374462Salfred	mutex_unlock(&clnt_fd_lock);
51474462Salfred
51574462Salfred	switch (request) {
51674462Salfred	case CLSET_FD_CLOSE:
51774462Salfred		ct->ct_closeit = TRUE;
51874462Salfred		release_fd_lock(ct->ct_fd, mask);
51974462Salfred		return (TRUE);
52074462Salfred	case CLSET_FD_NCLOSE:
52174462Salfred		ct->ct_closeit = FALSE;
52274462Salfred		release_fd_lock(ct->ct_fd, mask);
52374462Salfred		return (TRUE);
52474462Salfred	default:
52574462Salfred		break;
52674462Salfred	}
52774462Salfred
52874462Salfred	/* for other requests which use info */
52974462Salfred	if (info == NULL) {
53074462Salfred		release_fd_lock(ct->ct_fd, mask);
53174462Salfred		return (FALSE);
53274462Salfred	}
53374462Salfred	switch (request) {
53474462Salfred	case CLSET_TIMEOUT:
53574462Salfred		if (time_not_ok((struct timeval *)(void *)info)) {
53674462Salfred			release_fd_lock(ct->ct_fd, mask);
53774462Salfred			return (FALSE);
53874462Salfred		}
53974462Salfred		ct->ct_wait = *(struct timeval *)infop;
54074462Salfred		ct->ct_waitset = TRUE;
54174462Salfred		break;
54274462Salfred	case CLGET_TIMEOUT:
54374462Salfred		*(struct timeval *)infop = ct->ct_wait;
54474462Salfred		break;
54574462Salfred	case CLGET_SERVER_ADDR:
54674462Salfred		(void) memcpy(info, ct->ct_addr.buf, (size_t)ct->ct_addr.len);
54774462Salfred		break;
54874462Salfred	case CLGET_FD:
54974462Salfred		*(int *)(void *)info = ct->ct_fd;
55074462Salfred		break;
55174462Salfred	case CLGET_SVC_ADDR:
55274462Salfred		/* The caller should not free this memory area */
55374462Salfred		*(struct netbuf *)(void *)info = ct->ct_addr;
55474462Salfred		break;
55574462Salfred	case CLSET_SVC_ADDR:		/* set to new address */
55674462Salfred		release_fd_lock(ct->ct_fd, mask);
55774462Salfred		return (FALSE);
55874462Salfred	case CLGET_XID:
55974462Salfred		/*
56074462Salfred		 * use the knowledge that xid is the
56174462Salfred		 * first element in the call structure
56274462Salfred		 * This will get the xid of the PREVIOUS call
56374462Salfred		 */
56474462Salfred		*(u_int32_t *)(void *)info =
56574462Salfred		    ntohl(*(u_int32_t *)(void *)&ct->ct_u.ct_mcalli);
56674462Salfred		break;
56774462Salfred	case CLSET_XID:
56874462Salfred		/* This will set the xid of the NEXT call */
56974462Salfred		*(u_int32_t *)(void *)&ct->ct_u.ct_mcalli =
57074462Salfred		    htonl(*((u_int32_t *)(void *)info) + 1);
57174462Salfred		/* increment by 1 as clnt_vc_call() decrements once */
57274462Salfred		break;
57374462Salfred	case CLGET_VERS:
57474462Salfred		/*
57574462Salfred		 * This RELIES on the information that, in the call body,
57674462Salfred		 * the version number field is the fifth field from the
57774462Salfred		 * begining of the RPC header. MUST be changed if the
57874462Salfred		 * call_struct is changed
57974462Salfred		 */
58074462Salfred		*(u_int32_t *)(void *)info =
58174462Salfred		    ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc +
58274462Salfred		    4 * BYTES_PER_XDR_UNIT));
58374462Salfred		break;
58474462Salfred
58574462Salfred	case CLSET_VERS:
58674462Salfred		*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc +
58774462Salfred		    4 * BYTES_PER_XDR_UNIT) =
58874462Salfred		    htonl(*(u_int32_t *)(void *)info);
58974462Salfred		break;
59074462Salfred
59174462Salfred	case CLGET_PROG:
59274462Salfred		/*
59374462Salfred		 * This RELIES on the information that, in the call body,
59474462Salfred		 * the program number field is the fourth field from the
59574462Salfred		 * begining of the RPC header. MUST be changed if the
59674462Salfred		 * call_struct is changed
59774462Salfred		 */
59874462Salfred		*(u_int32_t *)(void *)info =
59974462Salfred		    ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc +
60074462Salfred		    3 * BYTES_PER_XDR_UNIT));
60174462Salfred		break;
60274462Salfred
60374462Salfred	case CLSET_PROG:
60474462Salfred		*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc +
60574462Salfred		    3 * BYTES_PER_XDR_UNIT) =
60674462Salfred		    htonl(*(u_int32_t *)(void *)info);
60774462Salfred		break;
60874462Salfred
60974462Salfred	default:
61074462Salfred		release_fd_lock(ct->ct_fd, mask);
61174462Salfred		return (FALSE);
61274462Salfred	}
61374462Salfred	release_fd_lock(ct->ct_fd, mask);
61474462Salfred	return (TRUE);
61574462Salfred}
61674462Salfred
61774462Salfred
61874462Salfredstatic void
61974462Salfredclnt_vc_destroy(cl)
62074462Salfred	CLIENT *cl;
62174462Salfred{
62274462Salfred	struct ct_data *ct = (struct ct_data *) cl->cl_private;
62374462Salfred	int ct_fd = ct->ct_fd;
62474462Salfred	sigset_t mask;
62574462Salfred	sigset_t newmask;
62674462Salfred
62774462Salfred	assert(cl != NULL);
62874462Salfred
62974462Salfred	ct = (struct ct_data *) cl->cl_private;
63074462Salfred
63174462Salfred	sigfillset(&newmask);
63274462Salfred	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
63374462Salfred	mutex_lock(&clnt_fd_lock);
63474462Salfred	while (vc_fd_locks[ct_fd])
63574462Salfred		cond_wait(&vc_cv[ct_fd], &clnt_fd_lock);
63674462Salfred	if (ct->ct_closeit && ct->ct_fd != -1) {
63774462Salfred		(void)_close(ct->ct_fd);
63874462Salfred	}
63974462Salfred	XDR_DESTROY(&(ct->ct_xdrs));
64074462Salfred	if (ct->ct_addr.buf)
64174462Salfred		free(ct->ct_addr.buf);
64274462Salfred	mem_free(ct, sizeof(struct ct_data));
64374462Salfred	mem_free(cl, sizeof(CLIENT));
64474462Salfred	mutex_unlock(&clnt_fd_lock);
64574462Salfred	thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
64674462Salfred	cond_signal(&vc_cv[ct_fd]);
64774462Salfred}
64874462Salfred
64974462Salfred/*
65074462Salfred * Interface between xdr serializer and tcp connection.
65174462Salfred * Behaves like the system calls, read & write, but keeps some error state
65274462Salfred * around for the rpc level.
65374462Salfred */
65474462Salfredstatic int
65574462Salfredread_vc(ctp, buf, len)
65674462Salfred	caddr_t ctp;
65774462Salfred	caddr_t buf;
65874462Salfred	int len;
65974462Salfred{
66074462Salfred	struct sockaddr sa;
66174462Salfred	socklen_t sal;
66274462Salfred	struct ct_data *ct = (struct ct_data *)(void *)ctp;
66374462Salfred	struct pollfd fd;
66474462Salfred	int milliseconds = (int)((ct->ct_wait.tv_sec * 1000) +
66574462Salfred	    (ct->ct_wait.tv_usec / 1000));
66674462Salfred
66774462Salfred	if (len == 0)
66874462Salfred		return (0);
66974462Salfred	fd.fd = ct->ct_fd;
67074462Salfred	fd.events = POLLIN;
67174462Salfred	for (;;) {
67274462Salfred		switch (_poll(&fd, 1, milliseconds)) {
67374462Salfred		case 0:
67474462Salfred			ct->ct_error.re_status = RPC_TIMEDOUT;
67574462Salfred			return (-1);
67674462Salfred
67774462Salfred		case -1:
67874462Salfred			if (errno == EINTR)
67974462Salfred				continue;
68074462Salfred			ct->ct_error.re_status = RPC_CANTRECV;
68174462Salfred			ct->ct_error.re_errno = errno;
68274462Salfred			return (-1);
68374462Salfred		}
68474462Salfred		break;
68574462Salfred	}
68674462Salfred
68774462Salfred	sal = sizeof(sa);
68874462Salfred	if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) &&
68974462Salfred	    (sa.sa_family == AF_LOCAL)) {
69074462Salfred		len = __msgread(ct->ct_fd, buf, (size_t)len);
69174462Salfred	} else {
69274462Salfred		len = _read(ct->ct_fd, buf, (size_t)len);
69374462Salfred	}
69474462Salfred
69574462Salfred	switch (len) {
69674462Salfred	case 0:
69774462Salfred		/* premature eof */
69874462Salfred		ct->ct_error.re_errno = ECONNRESET;
69974462Salfred		ct->ct_error.re_status = RPC_CANTRECV;
70074462Salfred		len = -1;  /* it's really an error */
70174462Salfred		break;
70274462Salfred
70374462Salfred	case -1:
70474462Salfred		ct->ct_error.re_errno = errno;
70574462Salfred		ct->ct_error.re_status = RPC_CANTRECV;
70674462Salfred		break;
70774462Salfred	}
70874462Salfred	return (len);
70974462Salfred}
71074462Salfred
71174462Salfredstatic int
71274462Salfredwrite_vc(ctp, buf, len)
71374462Salfred	caddr_t ctp;
71474462Salfred	caddr_t buf;
71574462Salfred	int len;
71674462Salfred{
71774462Salfred	struct sockaddr sa;
71874462Salfred	socklen_t sal;
71974462Salfred	struct ct_data *ct = (struct ct_data *)(void *)ctp;
72074462Salfred	int i, cnt;
72174462Salfred
72274462Salfred	sal = sizeof(sa);
72374462Salfred	if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) &&
72474462Salfred	    (sa.sa_family == AF_LOCAL)) {
72574462Salfred		for (cnt = len; cnt > 0; cnt -= i, buf += i) {
72674462Salfred			if ((i = __msgwrite(ct->ct_fd, buf,
72774462Salfred			     (size_t)cnt)) == -1) {
72874462Salfred				ct->ct_error.re_errno = errno;
72974462Salfred				ct->ct_error.re_status = RPC_CANTSEND;
73074462Salfred				return (-1);
73174462Salfred			}
73274462Salfred		}
73374462Salfred	} else {
73474462Salfred		for (cnt = len; cnt > 0; cnt -= i, buf += i) {
73574462Salfred			if ((i = _write(ct->ct_fd, buf, (size_t)cnt)) == -1) {
73674462Salfred				ct->ct_error.re_errno = errno;
73774462Salfred				ct->ct_error.re_status = RPC_CANTSEND;
73874462Salfred				return (-1);
73974462Salfred			}
74074462Salfred		}
74174462Salfred	}
74274462Salfred	return (len);
74374462Salfred}
74474462Salfred
74574462Salfredstatic struct clnt_ops *
74674462Salfredclnt_vc_ops()
74774462Salfred{
74874462Salfred	static struct clnt_ops ops;
74974462Salfred	extern mutex_t  ops_lock;
75074462Salfred	sigset_t mask, newmask;
75174462Salfred
75274462Salfred	/* VARIABLES PROTECTED BY ops_lock: ops */
75374462Salfred
75474462Salfred	sigfillset(&newmask);
75574462Salfred	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
75674462Salfred	mutex_lock(&ops_lock);
75774462Salfred	if (ops.cl_call == NULL) {
75874462Salfred		ops.cl_call = clnt_vc_call;
75974462Salfred		ops.cl_abort = clnt_vc_abort;
76074462Salfred		ops.cl_geterr = clnt_vc_geterr;
76174462Salfred		ops.cl_freeres = clnt_vc_freeres;
76274462Salfred		ops.cl_destroy = clnt_vc_destroy;
76374462Salfred		ops.cl_control = clnt_vc_control;
76474462Salfred	}
76574462Salfred	mutex_unlock(&ops_lock);
76674462Salfred	thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
76774462Salfred	return (&ops);
76874462Salfred}
76974462Salfred
77074462Salfred/*
77174462Salfred * Make sure that the time is not garbage.   -1 value is disallowed.
77274462Salfred * Note this is different from time_not_ok in clnt_dg.c
77374462Salfred */
77474462Salfredstatic bool_t
77574462Salfredtime_not_ok(t)
77674462Salfred	struct timeval *t;
77774462Salfred{
77874462Salfred	return (t->tv_sec <= -1 || t->tv_sec > 100000000 ||
77974462Salfred		t->tv_usec <= -1 || t->tv_usec > 1000000);
78074462Salfred}
78174462Salfred
78274627Salfredstatic int
78374462Salfred__msgread(sock, buf, cnt)
78474462Salfred	int sock;
78574462Salfred	void *buf;
78674462Salfred	size_t cnt;
78774462Salfred{
78874462Salfred	struct iovec iov[1];
78974462Salfred	struct msghdr msg;
79074462Salfred	struct cmessage cm;
79174462Salfred
79274462Salfred	bzero((char *)&cm, sizeof(cm));
79374462Salfred	iov[0].iov_base = buf;
79474462Salfred	iov[0].iov_len = cnt;
79574462Salfred
79674462Salfred	msg.msg_iov = iov;
79774462Salfred	msg.msg_iovlen = 1;
79874462Salfred	msg.msg_name = NULL;
79974462Salfred	msg.msg_namelen = 0;
80074462Salfred	msg.msg_control = (caddr_t)&cm;
80174462Salfred	msg.msg_controllen = sizeof(struct cmessage);
80274462Salfred	msg.msg_flags = 0;
80374462Salfred
80474462Salfred	return(_recvmsg(sock, &msg, 0));
80574462Salfred}
80674627Salfred
80774462Salfredstatic int
80874462Salfred__msgwrite(sock, buf, cnt)
80974462Salfred	int sock;
81074462Salfred	void *buf;
81174462Salfred	size_t cnt;
81274462Salfred{
81374462Salfred	struct iovec iov[1];
81474462Salfred	struct msghdr msg;
81574462Salfred	struct cmessage cm;
81674462Salfred
81774462Salfred	bzero((char *)&cm, sizeof(cm));
81874462Salfred	iov[0].iov_base = buf;
81974462Salfred	iov[0].iov_len = cnt;
82074462Salfred
82174462Salfred	cm.cmsg.cmsg_type = SCM_CREDS;
82274462Salfred	cm.cmsg.cmsg_level = SOL_SOCKET;
82374462Salfred	cm.cmsg.cmsg_len = sizeof(struct cmessage);
82474462Salfred
82574462Salfred	msg.msg_iov = iov;
82674462Salfred	msg.msg_iovlen = 1;
82774462Salfred	msg.msg_name = NULL;
82874462Salfred	msg.msg_namelen = 0;
82974462Salfred	msg.msg_control = (caddr_t)&cm;
83074462Salfred	msg.msg_controllen = sizeof(struct cmessage);
83174462Salfred	msg.msg_flags = 0;
83274462Salfred
83374462Salfred	return(_sendmsg(sock, &msg, 0));
83474462Salfred}
835