clnt_vc.c revision 74627
121308Sache/*	$NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $	*/
221308Sache/*	$FreeBSD: head/lib/libc/rpc/clnt_vc.c 74627 2001-03-22 04:31:30Z alfred $ */
321308Sache
421308Sache/*
521308Sache * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
621308Sache * unrestricted use provided that this legend is included on all tape
721308Sache * media and as a part of the software program in whole or part.  Users
821308Sache * may copy or modify Sun RPC without charge, but are not authorized
921308Sache * to license or distribute it to anyone else except as part of a product or
1058310Sache * program developed by the user.
1121308Sache *
1221308Sache * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
1321308Sache * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
1421308Sache * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
1521308Sache *
1621308Sache * Sun RPC is provided with no support and without any obligation on the
1721308Sache * part of Sun Microsystems, Inc. to assist in its use, correction,
1821308Sache * modification or enhancement.
1921308Sache *
2021308Sache * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
2158310Sache * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
2221308Sache * OR ANY PART THEREOF.
2321308Sache *
2421308Sache * In no event will Sun Microsystems, Inc. be liable for any lost revenue
2521308Sache * or profits or other special, indirect and consequential damages, even if
2621308Sache * Sun has been advised of the possibility of such damages.
2721308Sache *
2821308Sache * Sun Microsystems, Inc.
2921308Sache * 2550 Garcia Avenue
3021308Sache * Mountain View, California  94043
3121308Sache */
3221308Sache
3321308Sache#include <sys/cdefs.h>
3421308Sache#if defined(LIBC_SCCS) && !defined(lint)
3521308Sachestatic char *sccsid = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
3675406Sachestatic char *sccsid = "@(#)clnt_tcp.c	2.2 88/08/01 4.0 RPCSRC";
3775406Sachestatic char sccsid[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro";
3875406Sache#endif
3975406Sache
4075406Sache/*
4175406Sache * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
4275406Sache *
4375406Sache * Copyright (C) 1984, Sun Microsystems, Inc.
44119610Sache *
4575406Sache * TCP based RPC supports 'batched calls'.
4675406Sache * A sequence of calls may be batched-up in a send buffer.  The rpc call
4775406Sache * return immediately to the client even though the call was not necessarily
4875406Sache * sent.  The batching occurs if the results' xdr routine is NULL (0) AND
4975406Sache * the rpc timeout value is zero (see clnt.h, rpc).
5075406Sache *
5175406Sache * Clients should NOT casually batch calls that in fact return results; that is,
5275406Sache * the server side should be aware that a call is batched and not produce any
5375406Sache * return message.  Batched calls that produce many result messages can
5475406Sache * deadlock (netlock) the client and the server....
5575406Sache *
5675406Sache * Now go hang yourself.
5775406Sache */
5875406Sache
5975406Sache#include "reentrant.h"
6075406Sache#include "namespace.h"
6175406Sache#include <sys/types.h>
6275406Sache#include <sys/poll.h>
6321308Sache#include <sys/syslog.h>
6475406Sache#include <sys/socket.h>
6575406Sache#include <sys/un.h>
6675406Sache#include <sys/uio.h>
6775406Sache
6875406Sache#include <assert.h>
6921308Sache#include <err.h>
7021308Sache#include <errno.h>
71119610Sache#include <netdb.h>
7275406Sache#include <stdio.h>
7375406Sache#include <stdlib.h>
7475406Sache#include <string.h>
7575406Sache#include <unistd.h>
7675406Sache#include <signal.h>
7775406Sache
7875406Sache#include <rpc/rpc.h>
7975406Sache#include "un-namespace.h"
8075406Sache#include "rpc_com.h"
8175406Sache
8275406Sache#define MCALL_MSG_SIZE 24
8375406Sache
8475406Sachestatic enum clnt_stat clnt_vc_call __P((CLIENT *, rpcproc_t, xdrproc_t, caddr_t,
8575406Sache    xdrproc_t, caddr_t, struct timeval));
8675406Sachestatic void clnt_vc_geterr __P((CLIENT *, struct rpc_err *));
8721308Sachestatic bool_t clnt_vc_freeres __P((CLIENT *, xdrproc_t, caddr_t));
8821308Sachestatic void clnt_vc_abort __P((CLIENT *));
8975406Sachestatic bool_t clnt_vc_control __P((CLIENT *, u_int, char *));
9075406Sachestatic void clnt_vc_destroy __P((CLIENT *));
9175406Sachestatic struct clnt_ops *clnt_vc_ops __P((void));
9275406Sachestatic bool_t time_not_ok __P((struct timeval *));
9375406Sachestatic int read_vc __P((caddr_t, caddr_t, int));
9475406Sachestatic int write_vc __P((caddr_t, caddr_t, int));
9575406Sachestatic int __msgwrite(int, void *, size_t);
9675406Sachestatic int __msgread(int, void *, size_t);
9775406Sache
9875406Sachestruct ct_data {
9921308Sache	int		ct_fd;		/* connection's fd */
10021308Sache	bool_t		ct_closeit;	/* close it on destroy */
10175406Sache	struct timeval	ct_wait;	/* wait interval in milliseconds */
10275406Sache	bool_t          ct_waitset;	/* wait set by clnt_control? */
10375406Sache	struct netbuf	ct_addr;	/* remote addr */
10475406Sache	struct rpc_err	ct_error;
10575406Sache	union {
10675406Sache		char	ct_mcallc[MCALL_MSG_SIZE];	/* marshalled callmsg */
10775406Sache		u_int32_t ct_mcalli;
10821308Sache	} ct_u;
10921308Sache	u_int		ct_mpos;	/* pos after marshal */
11075406Sache	XDR		ct_xdrs;	/* XDR stream */
11175406Sache};
11275406Sache
11375406Sache/*
11475406Sache *      This machinery implements per-fd locks for MT-safety.  It is not
11575406Sache *      sufficient to do per-CLIENT handle locks for MT-safety because a
11675406Sache *      user may create more than one CLIENT handle with the same fd behind
11775406Sache *      it.  Therfore, we allocate an array of flags (vc_fd_locks), protected
11875406Sache *      by the clnt_fd_lock mutex, and an array (vc_cv) of condition variables
11975406Sache *      similarly protected.  Vc_fd_lock[fd] == 1 => a call is activte on some
12075406Sache *      CLIENT handle created for that fd.
12175406Sache *      The current implementation holds locks across the entire RPC and reply.
12275406Sache *      Yes, this is silly, and as soon as this code is proven to work, this
12375406Sache *      should be the first thing fixed.  One step at a time.
12475406Sache */
12575406Sachestatic int      *vc_fd_locks;
12675406Sacheextern mutex_t  clnt_fd_lock;
12775406Sachestatic cond_t   *vc_cv;
12875406Sache#define release_fd_lock(fd, mask) {	\
12975406Sache	mutex_lock(&clnt_fd_lock);	\
13075406Sache	if (__isthreaded)		\
13175406Sache		vc_fd_locks[fd] = 0;	\
13275406Sache	mutex_unlock(&clnt_fd_lock);	\
133157184Sache	thr_sigsetmask(SIG_SETMASK, &(mask), (sigset_t *) NULL);	\
13475406Sache	cond_signal(&vc_cv[fd]);	\
13575406Sache}
13621308Sache
13721308Sachestatic const char clnt_vc_errstr[] = "%s : %s";
13875406Sachestatic const char clnt_vc_str[] = "clnt_vc_create";
13975406Sachestatic const char clnt_read_vc_str[] = "read_vc";
14075406Sachestatic const char __no_mem_str[] = "out of memory";
14175406Sache
14275406Sache/*
14375406Sache * Create a client handle for a connection.
14421308Sache * Default options are set, which the user can change using clnt_control()'s.
14521308Sache * The rpc/vc package does buffering similar to stdio, so the client
14675406Sache * must pick send and receive buffer sizes, 0 => use the default.
14775406Sache * NB: fd is copied into a private area.
14875406Sache * NB: The rpch->cl_auth is set null authentication. Caller may wish to
14975406Sache * set this something more useful.
15075406Sache *
15175406Sache * fd should be an open socket
15275406Sache */
153119610SacheCLIENT *
15475406Sacheclnt_vc_create(fd, raddr, prog, vers, sendsz, recvsz)
15575406Sache	int fd;				/* open file descriptor */
15675406Sache	const struct netbuf *raddr;	/* servers address */
157119610Sache	rpcprog_t prog;			/* program number */
15875406Sache	rpcvers_t vers;			/* version number */
15975406Sache	u_int sendsz;			/* buffer recv size */
16075406Sache	u_int recvsz;			/* buffer send size */
16175406Sache{
16275406Sache	CLIENT *cl;			/* client handle */
16375406Sache	struct ct_data *ct = NULL;	/* client handle */
16475406Sache	struct timeval now;
16575406Sache	struct rpc_msg call_msg;
16675406Sache	static u_int32_t disrupt;
16775406Sache	sigset_t mask;
16875406Sache	sigset_t newmask;
16975406Sache	struct sockaddr_storage ss;
17075406Sache	socklen_t slen;
17175406Sache	struct __rpc_sockinfo si;
17221308Sache
17321308Sache	if (disrupt == 0)
17475406Sache		disrupt = (u_int32_t)(long)raddr;
17575406Sache
17675406Sache	cl = (CLIENT *)mem_alloc(sizeof (*cl));
17775406Sache	ct = (struct ct_data *)mem_alloc(sizeof (*ct));
17875406Sache	if ((cl == (CLIENT *)NULL) || (ct == (struct ct_data *)NULL)) {
17921308Sache		(void) syslog(LOG_ERR, clnt_vc_errstr,
18021308Sache		    clnt_vc_str, __no_mem_str);
18121308Sache		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
18275406Sache		rpc_createerr.cf_error.re_errno = errno;
18375406Sache		goto err;
18475406Sache	}
18575406Sache	ct->ct_addr.buf = NULL;
18675406Sache	sigfillset(&newmask);
18775406Sache	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
18875406Sache	mutex_lock(&clnt_fd_lock);
18975406Sache	if (vc_fd_locks == (int *) NULL) {
19075406Sache		int cv_allocsz, fd_allocsz;
19175406Sache		int dtbsize = __rpc_dtbsize();
19275406Sache
19375406Sache		fd_allocsz = dtbsize * sizeof (int);
19475406Sache		vc_fd_locks = (int *) mem_alloc(fd_allocsz);
19575406Sache		if (vc_fd_locks == (int *) NULL) {
19675406Sache			mutex_unlock(&clnt_fd_lock);
19775406Sache			thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
19875406Sache			goto err;
19975406Sache		} else
20075406Sache			memset(vc_fd_locks, '\0', fd_allocsz);
20175406Sache
20275406Sache		assert(vc_cv == (cond_t *) NULL);
20375406Sache		cv_allocsz = dtbsize * sizeof (cond_t);
20475406Sache		vc_cv = (cond_t *) mem_alloc(cv_allocsz);
20575406Sache		if (vc_cv == (cond_t *) NULL) {
20675406Sache			mem_free(vc_fd_locks, fd_allocsz);
20775406Sache			vc_fd_locks = (int *) NULL;
20875406Sache			mutex_unlock(&clnt_fd_lock);
20975406Sache			thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
21075406Sache			goto err;
21175406Sache		} else {
21275406Sache			int i;
21375406Sache
21475406Sache			for (i = 0; i < dtbsize; i++)
21575406Sache				cond_init(&vc_cv[i], 0, (void *) 0);
21675406Sache		}
21775406Sache	} else
21875406Sache		assert(vc_cv != (cond_t *) NULL);
21975406Sache
22075406Sache	/*
22175406Sache	 * XXX - fvdl connecting while holding a mutex?
22275406Sache	 */
22375406Sache	slen = sizeof ss;
22475406Sache	if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
22575406Sache		if (errno != ENOTCONN) {
22675406Sache			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
22775406Sache			rpc_createerr.cf_error.re_errno = errno;
22875406Sache			mutex_unlock(&clnt_fd_lock);
22975406Sache			goto err;
23075406Sache		}
23175406Sache		if (_connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){
23275406Sache			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
23375406Sache			rpc_createerr.cf_error.re_errno = errno;
23475406Sache			mutex_unlock(&clnt_fd_lock);
23575406Sache			goto err;
23675406Sache		}
23775406Sache	}
23875406Sache	mutex_unlock(&clnt_fd_lock);
23975406Sache	if (!__rpc_fd2sockinfo(fd, &si))
24075406Sache		goto err;
24175406Sache	thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
24275406Sache
24375406Sache	ct->ct_closeit = FALSE;
24475406Sache
24575406Sache	/*
24675406Sache	 * Set up private data struct
24775406Sache	 */
24875406Sache	ct->ct_fd = fd;
24975406Sache	ct->ct_wait.tv_usec = 0;
25075406Sache	ct->ct_waitset = FALSE;
25175406Sache	ct->ct_addr.buf = malloc(raddr->maxlen);
25275406Sache	if (ct->ct_addr.buf == NULL)
25375406Sache		goto err;
25475406Sache	memcpy(ct->ct_addr.buf, &raddr->buf, raddr->len);
25575406Sache	ct->ct_addr.len = raddr->maxlen;
25675406Sache	ct->ct_addr.maxlen = raddr->maxlen;
25775406Sache
25875406Sache	/*
25975406Sache	 * Initialize call message
26075406Sache	 */
26175406Sache	(void)gettimeofday(&now, NULL);
26275406Sache	call_msg.rm_xid = ((u_int32_t)++disrupt) ^ __RPC_GETXID(&now);
26375406Sache	call_msg.rm_direction = CALL;
26475406Sache	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
26575406Sache	call_msg.rm_call.cb_prog = (u_int32_t)prog;
26675406Sache	call_msg.rm_call.cb_vers = (u_int32_t)vers;
26775406Sache
26875406Sache	/*
26975406Sache	 * pre-serialize the static part of the call msg and stash it away
27075406Sache	 */
27175406Sache	xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE,
27275406Sache	    XDR_ENCODE);
27375406Sache	if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
27475406Sache		if (ct->ct_closeit) {
27575406Sache			(void)_close(fd);
27675406Sache		}
27775406Sache		goto err;
27875406Sache	}
27975406Sache	ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
28075406Sache	XDR_DESTROY(&(ct->ct_xdrs));
28175406Sache
28275406Sache	/*
28375406Sache	 * Create a client handle which uses xdrrec for serialization
28475406Sache	 * and authnone for authentication.
28575406Sache	 */
28675406Sache	cl->cl_ops = clnt_vc_ops();
28775406Sache	cl->cl_private = ct;
28875406Sache	cl->cl_auth = authnone_create();
28975406Sache	sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz);
29075406Sache	recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz);
29175406Sache	xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
29275406Sache	    cl->cl_private, read_vc, write_vc);
29375406Sache	return (cl);
29475406Sache
29575406Sacheerr:
29675406Sache	if (cl) {
29775406Sache		if (ct) {
29875406Sache			if (ct->ct_addr.len)
29975406Sache				mem_free(ct->ct_addr.buf, ct->ct_addr.len);
30075406Sache			mem_free((caddr_t)ct, sizeof (struct ct_data));
30175406Sache		}
30275406Sache		if (cl)
30375406Sache			mem_free((caddr_t)cl, sizeof (CLIENT));
30475406Sache	}
30575406Sache	return ((CLIENT *)NULL);
30675406Sache}
30775406Sache
30875406Sachestatic enum clnt_stat
30975406Sacheclnt_vc_call(cl, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
31021308Sache	CLIENT *cl;
31121308Sache	rpcproc_t proc;
31221308Sache	xdrproc_t xdr_args;
31321308Sache	caddr_t args_ptr;
31421308Sache	xdrproc_t xdr_results;
31521308Sache	caddr_t results_ptr;
31675406Sache	struct timeval timeout;
31775406Sache{
31875406Sache	struct ct_data *ct = (struct ct_data *) cl->cl_private;
31975406Sache	XDR *xdrs = &(ct->ct_xdrs);
32075406Sache	struct rpc_msg reply_msg;
32175406Sache	u_int32_t x_id;
32275406Sache	u_int32_t *msg_x_id = &ct->ct_u.ct_mcalli;    /* yuk */
32375406Sache	bool_t shipnow;
32475406Sache	int refreshes = 2;
32575406Sache	sigset_t mask, newmask;
32675406Sache	int rpc_lock_value;
32775406Sache
32875406Sache	assert(cl != NULL);
32975406Sache
33075406Sache	sigfillset(&newmask);
33175406Sache	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
33275406Sache	mutex_lock(&clnt_fd_lock);
33375406Sache	while (vc_fd_locks[ct->ct_fd])
33475406Sache		cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
33575406Sache	if (__isthreaded)
33675406Sache                rpc_lock_value = 1;
33775406Sache        else
33875406Sache                rpc_lock_value = 0;
33975406Sache	vc_fd_locks[ct->ct_fd] = rpc_lock_value;
34075406Sache	mutex_unlock(&clnt_fd_lock);
34175406Sache	if (!ct->ct_waitset) {
34275406Sache		/* If time is not within limits, we ignore it. */
34321308Sache		if (time_not_ok(&timeout) == FALSE)
34475406Sache			ct->ct_wait = timeout;
34575406Sache	}
34675406Sache
34775406Sache	shipnow =
34875406Sache	    (xdr_results == NULL && timeout.tv_sec == 0
34921308Sache	    && timeout.tv_usec == 0) ? FALSE : TRUE;
35021308Sache
35175406Sachecall_again:
35275406Sache	xdrs->x_op = XDR_ENCODE;
35375406Sache	ct->ct_error.re_status = RPC_SUCCESS;
35475406Sache	x_id = ntohl(--(*msg_x_id));
35575406Sache
35675406Sache	if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) ||
35775406Sache	    (! XDR_PUTINT32(xdrs, &proc)) ||
35875406Sache	    (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
35975406Sache	    (! (*xdr_args)(xdrs, args_ptr))) {
36075406Sache		if (ct->ct_error.re_status == RPC_SUCCESS)
36175406Sache			ct->ct_error.re_status = RPC_CANTENCODEARGS;
36275406Sache		(void)xdrrec_endofrecord(xdrs, TRUE);
36375406Sache		release_fd_lock(ct->ct_fd, mask);
36475406Sache		return (ct->ct_error.re_status);
36575406Sache	}
36675406Sache	if (! xdrrec_endofrecord(xdrs, shipnow)) {
36721308Sache		release_fd_lock(ct->ct_fd, mask);
36821308Sache		return (ct->ct_error.re_status = RPC_CANTSEND);
36975406Sache	}
37075406Sache	if (! shipnow) {
37175406Sache		release_fd_lock(ct->ct_fd, mask);
37275406Sache		return (RPC_SUCCESS);
37375406Sache	}
37475406Sache	/*
37575406Sache	 * Hack to provide rpc-based message passing
37675406Sache	 */
37775406Sache	if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
37875406Sache		release_fd_lock(ct->ct_fd, mask);
37921308Sache		return(ct->ct_error.re_status = RPC_TIMEDOUT);
38021308Sache	}
38175406Sache
38275406Sache
38375406Sache	/*
38475406Sache	 * Keep receiving until we get a valid transaction id
38575406Sache	 */
38675406Sache	xdrs->x_op = XDR_DECODE;
38775406Sache	while (TRUE) {
38821308Sache		reply_msg.acpted_rply.ar_verf = _null_auth;
38921308Sache		reply_msg.acpted_rply.ar_results.where = NULL;
39075406Sache		reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
39175406Sache		if (! xdrrec_skiprecord(xdrs)) {
39275406Sache			release_fd_lock(ct->ct_fd, mask);
39375406Sache			return (ct->ct_error.re_status);
39475406Sache		}
39575406Sache		/* now decode and validate the response header */
39675406Sache		if (! xdr_replymsg(xdrs, &reply_msg)) {
39775406Sache			if (ct->ct_error.re_status == RPC_SUCCESS)
39875406Sache				continue;
39975406Sache			release_fd_lock(ct->ct_fd, mask);
40075406Sache			return (ct->ct_error.re_status);
40175406Sache		}
40275406Sache		if (reply_msg.rm_xid == x_id)
40375406Sache			break;
40475406Sache	}
40575406Sache
40675406Sache	/*
40775406Sache	 * process header
40875406Sache	 */
40975406Sache	_seterr_reply(&reply_msg, &(ct->ct_error));
41075406Sache	if (ct->ct_error.re_status == RPC_SUCCESS) {
41175406Sache		if (! AUTH_VALIDATE(cl->cl_auth,
41275406Sache		    &reply_msg.acpted_rply.ar_verf)) {
41375406Sache			ct->ct_error.re_status = RPC_AUTHERROR;
41475406Sache			ct->ct_error.re_why = AUTH_INVALIDRESP;
41575406Sache		} else if (! (*xdr_results)(xdrs, results_ptr)) {
41621308Sache			if (ct->ct_error.re_status == RPC_SUCCESS)
41721308Sache				ct->ct_error.re_status = RPC_CANTDECODERES;
41875406Sache		}
41975406Sache		/* free verifier ... */
42075406Sache		if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
42175406Sache			xdrs->x_op = XDR_FREE;
42275406Sache			(void)xdr_opaque_auth(xdrs,
42375406Sache			    &(reply_msg.acpted_rply.ar_verf));
42421308Sache		}
42521308Sache	}  /* end successful completion */
42675406Sache	else {
42775406Sache		/* maybe our credentials need to be refreshed ... */
42875406Sache		if (refreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg))
42975406Sache			goto call_again;
43075406Sache	}  /* end of unsuccessful completion */
43175406Sache	release_fd_lock(ct->ct_fd, mask);
43275406Sache	return (ct->ct_error.re_status);
43375406Sache}
43475406Sache
43575406Sachestatic void
43675406Sacheclnt_vc_geterr(cl, errp)
43775406Sache	CLIENT *cl;
43875406Sache	struct rpc_err *errp;
43975406Sache{
44075406Sache	struct ct_data *ct;
44175406Sache
44275406Sache	assert(cl != NULL);
44375406Sache	assert(errp != NULL);
44475406Sache
44575406Sache	ct = (struct ct_data *) cl->cl_private;
44675406Sache	*errp = ct->ct_error;
44775406Sache}
44875406Sache
44975406Sachestatic bool_t
45075406Sacheclnt_vc_freeres(cl, xdr_res, res_ptr)
45175406Sache	CLIENT *cl;
45221308Sache	xdrproc_t xdr_res;
45321308Sache	caddr_t res_ptr;
45475406Sache{
45575406Sache	struct ct_data *ct;
45675406Sache	XDR *xdrs;
45775406Sache	bool_t dummy;
45875406Sache	sigset_t mask;
45921308Sache	sigset_t newmask;
46021308Sache
46121308Sache	assert(cl != NULL);
46221308Sache
46321308Sache	ct = (struct ct_data *)cl->cl_private;
46421308Sache	xdrs = &(ct->ct_xdrs);
46521308Sache
46621308Sache	sigfillset(&newmask);
46721308Sache	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
46821308Sache	mutex_lock(&clnt_fd_lock);
46921308Sache	while (vc_fd_locks[ct->ct_fd])
47021308Sache		cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
47121308Sache	xdrs->x_op = XDR_FREE;
47221308Sache	dummy = (*xdr_res)(xdrs, res_ptr);
47321308Sache	mutex_unlock(&clnt_fd_lock);
47421308Sache	thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
47521308Sache	cond_signal(&vc_cv[ct->ct_fd]);
47621308Sache
47721308Sache	return dummy;
47821308Sache}
47921308Sache
48021308Sache/*ARGSUSED*/
48121308Sachestatic void
48221308Sacheclnt_vc_abort(cl)
48321308Sache	CLIENT *cl;
48421308Sache{
48521308Sache}
48621308Sache
48721308Sachestatic bool_t
48821308Sacheclnt_vc_control(cl, request, info)
48921308Sache	CLIENT *cl;
49021308Sache	u_int request;
49121308Sache	char *info;
49221308Sache{
49321308Sache	struct ct_data *ct;
49421308Sache	void *infop = info;
49521308Sache	sigset_t mask;
49621308Sache	sigset_t newmask;
49721308Sache	int rpc_lock_value;
49821308Sache
49921308Sache	assert(cl != NULL);
50021308Sache
50121308Sache	ct = (struct ct_data *)cl->cl_private;
50221308Sache
50321308Sache	sigfillset(&newmask);
50421308Sache	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
50521308Sache	mutex_lock(&clnt_fd_lock);
50621308Sache	while (vc_fd_locks[ct->ct_fd])
50721308Sache		cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
50821308Sache	if (__isthreaded)
50921308Sache                rpc_lock_value = 1;
51021308Sache        else
51121308Sache                rpc_lock_value = 0;
51221308Sache	vc_fd_locks[ct->ct_fd] = rpc_lock_value;
51321308Sache	mutex_unlock(&clnt_fd_lock);
51421308Sache
51521308Sache	switch (request) {
51621308Sache	case CLSET_FD_CLOSE:
51721308Sache		ct->ct_closeit = TRUE;
51821308Sache		release_fd_lock(ct->ct_fd, mask);
51921308Sache		return (TRUE);
52021308Sache	case CLSET_FD_NCLOSE:
52121308Sache		ct->ct_closeit = FALSE;
52221308Sache		release_fd_lock(ct->ct_fd, mask);
52321308Sache		return (TRUE);
52421308Sache	default:
52521308Sache		break;
52621308Sache	}
52721308Sache
52821308Sache	/* for other requests which use info */
52921308Sache	if (info == NULL) {
53021308Sache		release_fd_lock(ct->ct_fd, mask);
53121308Sache		return (FALSE);
53221308Sache	}
53321308Sache	switch (request) {
53421308Sache	case CLSET_TIMEOUT:
53521308Sache		if (time_not_ok((struct timeval *)(void *)info)) {
53621308Sache			release_fd_lock(ct->ct_fd, mask);
53721308Sache			return (FALSE);
53821308Sache		}
53921308Sache		ct->ct_wait = *(struct timeval *)infop;
54021308Sache		ct->ct_waitset = TRUE;
54121308Sache		break;
54221308Sache	case CLGET_TIMEOUT:
54321308Sache		*(struct timeval *)infop = ct->ct_wait;
54421308Sache		break;
54521308Sache	case CLGET_SERVER_ADDR:
54621308Sache		(void) memcpy(info, ct->ct_addr.buf, (size_t)ct->ct_addr.len);
54721308Sache		break;
54821308Sache	case CLGET_FD:
54921308Sache		*(int *)(void *)info = ct->ct_fd;
55021308Sache		break;
55121308Sache	case CLGET_SVC_ADDR:
55221308Sache		/* The caller should not free this memory area */
55321308Sache		*(struct netbuf *)(void *)info = ct->ct_addr;
55421308Sache		break;
55521308Sache	case CLSET_SVC_ADDR:		/* set to new address */
55621308Sache		release_fd_lock(ct->ct_fd, mask);
55721308Sache		return (FALSE);
55821308Sache	case CLGET_XID:
55921308Sache		/*
56021308Sache		 * use the knowledge that xid is the
56121308Sache		 * first element in the call structure
56221308Sache		 * This will get the xid of the PREVIOUS call
56321308Sache		 */
56421308Sache		*(u_int32_t *)(void *)info =
56521308Sache		    ntohl(*(u_int32_t *)(void *)&ct->ct_u.ct_mcalli);
56621308Sache		break;
56721308Sache	case CLSET_XID:
56821308Sache		/* This will set the xid of the NEXT call */
56921308Sache		*(u_int32_t *)(void *)&ct->ct_u.ct_mcalli =
57021308Sache		    htonl(*((u_int32_t *)(void *)info) + 1);
57121308Sache		/* increment by 1 as clnt_vc_call() decrements once */
57221308Sache		break;
57321308Sache	case CLGET_VERS:
57421308Sache		/*
57521308Sache		 * This RELIES on the information that, in the call body,
57621308Sache		 * the version number field is the fifth field from the
57721308Sache		 * begining of the RPC header. MUST be changed if the
57821308Sache		 * call_struct is changed
57921308Sache		 */
58021308Sache		*(u_int32_t *)(void *)info =
58121308Sache		    ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc +
58221308Sache		    4 * BYTES_PER_XDR_UNIT));
58321308Sache		break;
58421308Sache
58521308Sache	case CLSET_VERS:
58621308Sache		*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc +
58721308Sache		    4 * BYTES_PER_XDR_UNIT) =
58821308Sache		    htonl(*(u_int32_t *)(void *)info);
58921308Sache		break;
59021308Sache
59121308Sache	case CLGET_PROG:
59221308Sache		/*
59321308Sache		 * This RELIES on the information that, in the call body,
59421308Sache		 * the program number field is the fourth field from the
59521308Sache		 * begining of the RPC header. MUST be changed if the
59621308Sache		 * call_struct is changed
59721308Sache		 */
59821308Sache		*(u_int32_t *)(void *)info =
59921308Sache		    ntohl(*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc +
60021308Sache		    3 * BYTES_PER_XDR_UNIT));
60175406Sache		break;
60275406Sache
60375406Sache	case CLSET_PROG:
60475406Sache		*(u_int32_t *)(void *)(ct->ct_u.ct_mcallc +
60575406Sache		    3 * BYTES_PER_XDR_UNIT) =
60675406Sache		    htonl(*(u_int32_t *)(void *)info);
60775406Sache		break;
60875406Sache
60975406Sache	default:
61075406Sache		release_fd_lock(ct->ct_fd, mask);
61175406Sache		return (FALSE);
61275406Sache	}
61375406Sache	release_fd_lock(ct->ct_fd, mask);
61475406Sache	return (TRUE);
61575406Sache}
61675406Sache
61775406Sache
61875406Sachestatic void
61975406Sacheclnt_vc_destroy(cl)
62075406Sache	CLIENT *cl;
62175406Sache{
62275406Sache	struct ct_data *ct = (struct ct_data *) cl->cl_private;
62375406Sache	int ct_fd = ct->ct_fd;
62475406Sache	sigset_t mask;
62575406Sache	sigset_t newmask;
62675406Sache
62775406Sache	assert(cl != NULL);
62821308Sache
62975406Sache	ct = (struct ct_data *) cl->cl_private;
63075406Sache
63175406Sache	sigfillset(&newmask);
63275406Sache	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
63375406Sache	mutex_lock(&clnt_fd_lock);
63421308Sache	while (vc_fd_locks[ct_fd])
63521308Sache		cond_wait(&vc_cv[ct_fd], &clnt_fd_lock);
63675406Sache	if (ct->ct_closeit && ct->ct_fd != -1) {
63775406Sache		(void)_close(ct->ct_fd);
63875406Sache	}
63975406Sache	XDR_DESTROY(&(ct->ct_xdrs));
64075406Sache	if (ct->ct_addr.buf)
64175406Sache		free(ct->ct_addr.buf);
64275406Sache	mem_free(ct, sizeof(struct ct_data));
64375406Sache	mem_free(cl, sizeof(CLIENT));
64475406Sache	mutex_unlock(&clnt_fd_lock);
64575406Sache	thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
64675406Sache	cond_signal(&vc_cv[ct_fd]);
64775406Sache}
64875406Sache
64975406Sache/*
65075406Sache * Interface between xdr serializer and tcp connection.
65175406Sache * Behaves like the system calls, read & write, but keeps some error state
65221308Sache * around for the rpc level.
65321308Sache */
65475406Sachestatic int
65575406Sacheread_vc(ctp, buf, len)
65675406Sache	caddr_t ctp;
65775406Sache	caddr_t buf;
65875406Sache	int len;
65975406Sache{
66075406Sache	struct sockaddr sa;
66175406Sache	socklen_t sal;
66275406Sache	struct ct_data *ct = (struct ct_data *)(void *)ctp;
66375406Sache	struct pollfd fd;
66421308Sache	int milliseconds = (int)((ct->ct_wait.tv_sec * 1000) +
66521308Sache	    (ct->ct_wait.tv_usec / 1000));
66675406Sache
66775406Sache	if (len == 0)
66875406Sache		return (0);
66975406Sache	fd.fd = ct->ct_fd;
67075406Sache	fd.events = POLLIN;
67175406Sache	for (;;) {
67275406Sache		switch (_poll(&fd, 1, milliseconds)) {
67321308Sache		case 0:
67421308Sache			ct->ct_error.re_status = RPC_TIMEDOUT;
67575406Sache			return (-1);
67675406Sache
67775406Sache		case -1:
67875406Sache			if (errno == EINTR)
67975406Sache				continue;
68075406Sache			ct->ct_error.re_status = RPC_CANTRECV;
68175406Sache			ct->ct_error.re_errno = errno;
68275406Sache			return (-1);
68375406Sache		}
68475406Sache		break;
68575406Sache	}
68675406Sache
68775406Sache	sal = sizeof(sa);
68875406Sache	if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) &&
68975406Sache	    (sa.sa_family == AF_LOCAL)) {
69075406Sache		len = __msgread(ct->ct_fd, buf, (size_t)len);
69175406Sache	} else {
69275406Sache		len = _read(ct->ct_fd, buf, (size_t)len);
69375406Sache	}
69475406Sache
69575406Sache	switch (len) {
69675406Sache	case 0:
69775406Sache		/* premature eof */
69875406Sache		ct->ct_error.re_errno = ECONNRESET;
69975406Sache		ct->ct_error.re_status = RPC_CANTRECV;
70075406Sache		len = -1;  /* it's really an error */
70121308Sache		break;
70221308Sache
70375406Sache	case -1:
70475406Sache		ct->ct_error.re_errno = errno;
70575406Sache		ct->ct_error.re_status = RPC_CANTRECV;
70675406Sache		break;
70775406Sache	}
70875406Sache	return (len);
70921308Sache}
71021308Sache
71175406Sachestatic int
71275406Sachewrite_vc(ctp, buf, len)
71375406Sache	caddr_t ctp;
71475406Sache	caddr_t buf;
71575406Sache	int len;
71675406Sache{
71775406Sache	struct sockaddr sa;
71875406Sache	socklen_t sal;
71975406Sache	struct ct_data *ct = (struct ct_data *)(void *)ctp;
72075406Sache	int i, cnt;
72175406Sache
72275406Sache	sal = sizeof(sa);
72375406Sache	if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) &&
72475406Sache	    (sa.sa_family == AF_LOCAL)) {
72575406Sache		for (cnt = len; cnt > 0; cnt -= i, buf += i) {
72675406Sache			if ((i = __msgwrite(ct->ct_fd, buf,
72775406Sache			     (size_t)cnt)) == -1) {
72875406Sache				ct->ct_error.re_errno = errno;
72975406Sache				ct->ct_error.re_status = RPC_CANTSEND;
73075406Sache				return (-1);
73175406Sache			}
73275406Sache		}
73375406Sache	} else {
73475406Sache		for (cnt = len; cnt > 0; cnt -= i, buf += i) {
73575406Sache			if ((i = _write(ct->ct_fd, buf, (size_t)cnt)) == -1) {
73675406Sache				ct->ct_error.re_errno = errno;
73721308Sache				ct->ct_error.re_status = RPC_CANTSEND;
73821308Sache				return (-1);
73975406Sache			}
74075406Sache		}
74175406Sache	}
74275406Sache	return (len);
74375406Sache}
74421308Sache
74521308Sachestatic struct clnt_ops *
74621308Sacheclnt_vc_ops()
74775406Sache{
74875406Sache	static struct clnt_ops ops;
74975406Sache	extern mutex_t  ops_lock;
75075406Sache	sigset_t mask, newmask;
75175406Sache
75275406Sache	/* VARIABLES PROTECTED BY ops_lock: ops */
75375406Sache
75475406Sache	sigfillset(&newmask);
75575406Sache	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
75675406Sache	mutex_lock(&ops_lock);
75775406Sache	if (ops.cl_call == NULL) {
75875406Sache		ops.cl_call = clnt_vc_call;
75975406Sache		ops.cl_abort = clnt_vc_abort;
76075406Sache		ops.cl_geterr = clnt_vc_geterr;
76175406Sache		ops.cl_freeres = clnt_vc_freeres;
76275406Sache		ops.cl_destroy = clnt_vc_destroy;
76375406Sache		ops.cl_control = clnt_vc_control;
76475406Sache	}
76575406Sache	mutex_unlock(&ops_lock);
76675406Sache	thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
76775406Sache	return (&ops);
76875406Sache}
76975406Sache
77075406Sache/*
77175406Sache * Make sure that the time is not garbage.   -1 value is disallowed.
77275406Sache * Note this is different from time_not_ok in clnt_dg.c
77375406Sache */
77475406Sachestatic bool_t
77575406Sachetime_not_ok(t)
77675406Sache	struct timeval *t;
77775406Sache{
77875406Sache	return (t->tv_sec <= -1 || t->tv_sec > 100000000 ||
77975406Sache		t->tv_usec <= -1 || t->tv_usec > 1000000);
78075406Sache}
78175406Sache
78275406Sachestatic int
78375406Sache__msgread(sock, buf, cnt)
78475406Sache	int sock;
78575406Sache	void *buf;
78675406Sache	size_t cnt;
78775406Sache{
78875406Sache	struct iovec iov[1];
78975406Sache	struct msghdr msg;
79075406Sache	struct cmessage cm;
79175406Sache
79275406Sache	bzero((char *)&cm, sizeof(cm));
79375406Sache	iov[0].iov_base = buf;
79475406Sache	iov[0].iov_len = cnt;
79575406Sache
79675406Sache	msg.msg_iov = iov;
79775406Sache	msg.msg_iovlen = 1;
79875406Sache	msg.msg_name = NULL;
79975406Sache	msg.msg_namelen = 0;
80075406Sache	msg.msg_control = (caddr_t)&cm;
80175406Sache	msg.msg_controllen = sizeof(struct cmessage);
80275406Sache	msg.msg_flags = 0;
80375406Sache
80475406Sache	return(_recvmsg(sock, &msg, 0));
80575406Sache}
80675406Sache
80775406Sachestatic int
80875406Sache__msgwrite(sock, buf, cnt)
80975406Sache	int sock;
81075406Sache	void *buf;
81175406Sache	size_t cnt;
81275406Sache{
81375406Sache	struct iovec iov[1];
81475406Sache	struct msghdr msg;
81575406Sache	struct cmessage cm;
81675406Sache
81775406Sache	bzero((char *)&cm, sizeof(cm));
81875406Sache	iov[0].iov_base = buf;
81975406Sache	iov[0].iov_len = cnt;
82075406Sache
82175406Sache	cm.cmsg.cmsg_type = SCM_CREDS;
82275406Sache	cm.cmsg.cmsg_level = SOL_SOCKET;
82375406Sache	cm.cmsg.cmsg_len = sizeof(struct cmessage);
82475406Sache
82575406Sache	msg.msg_iov = iov;
82675406Sache	msg.msg_iovlen = 1;
82775406Sache	msg.msg_name = NULL;
82875406Sache	msg.msg_namelen = 0;
82975406Sache	msg.msg_control = (caddr_t)&cm;
83075406Sache	msg.msg_controllen = sizeof(struct cmessage);
83175406Sache	msg.msg_flags = 0;
83275406Sache
83375406Sache	return(_sendmsg(sock, &msg, 0));
83475406Sache}
83575406Sache