xref: /minix3/lib/libc/rpc/svc_vc.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /*	$NetBSD: svc_vc.c,v 1.30 2013/03/11 20:19:29 tron Exp $	*/
22fe8fb19SBen Gras 
32fe8fb19SBen Gras /*
4*84d9c625SLionel Sambuc  * Copyright (c) 2010, Oracle America, Inc.
52fe8fb19SBen Gras  *
6*84d9c625SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
7*84d9c625SLionel Sambuc  * modification, are permitted provided that the following conditions are
8*84d9c625SLionel Sambuc  * met:
92fe8fb19SBen Gras  *
10*84d9c625SLionel Sambuc  *     * Redistributions of source code must retain the above copyright
11*84d9c625SLionel Sambuc  *       notice, this list of conditions and the following disclaimer.
12*84d9c625SLionel Sambuc  *     * Redistributions in binary form must reproduce the above
13*84d9c625SLionel Sambuc  *       copyright notice, this list of conditions and the following
14*84d9c625SLionel Sambuc  *       disclaimer in the documentation and/or other materials
15*84d9c625SLionel Sambuc  *       provided with the distribution.
16*84d9c625SLionel Sambuc  *     * Neither the name of the "Oracle America, Inc." nor the names of its
17*84d9c625SLionel Sambuc  *       contributors may be used to endorse or promote products derived
18*84d9c625SLionel Sambuc  *       from this software without specific prior written permission.
192fe8fb19SBen Gras  *
20*84d9c625SLionel Sambuc  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*84d9c625SLionel Sambuc  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*84d9c625SLionel Sambuc  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*84d9c625SLionel Sambuc  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24*84d9c625SLionel Sambuc  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25*84d9c625SLionel Sambuc  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26*84d9c625SLionel Sambuc  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27*84d9c625SLionel Sambuc  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28*84d9c625SLionel Sambuc  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29*84d9c625SLionel Sambuc  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30*84d9c625SLionel Sambuc  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31*84d9c625SLionel 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 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
382fe8fb19SBen Gras static char *sccsid = "@(#)svc_tcp.c	2.2 88/08/01 4.0 RPCSRC";
392fe8fb19SBen Gras #else
40*84d9c625SLionel Sambuc __RCSID("$NetBSD: svc_vc.c,v 1.30 2013/03/11 20:19:29 tron Exp $");
412fe8fb19SBen Gras #endif
422fe8fb19SBen Gras #endif
432fe8fb19SBen Gras 
442fe8fb19SBen Gras /*
452fe8fb19SBen Gras  * svc_vc.c, Server side for Connection Oriented based RPC.
462fe8fb19SBen Gras  *
472fe8fb19SBen Gras  * Actually implements two flavors of transporter -
482fe8fb19SBen Gras  * a tcp rendezvouser (a listner and connection establisher)
492fe8fb19SBen Gras  * and a record/tcp stream.
502fe8fb19SBen Gras  */
512fe8fb19SBen Gras 
522fe8fb19SBen Gras #include "namespace.h"
532fe8fb19SBen Gras #include "reentrant.h"
542fe8fb19SBen Gras #include <sys/types.h>
552fe8fb19SBen Gras #include <sys/param.h>
562fe8fb19SBen Gras #include <sys/poll.h>
572fe8fb19SBen Gras #include <sys/socket.h>
582fe8fb19SBen Gras #include <sys/un.h>
592fe8fb19SBen Gras #include <sys/time.h>
602fe8fb19SBen Gras #include <netinet/in.h>
612fe8fb19SBen Gras 
622fe8fb19SBen Gras #include <assert.h>
632fe8fb19SBen Gras #include <err.h>
642fe8fb19SBen Gras #include <errno.h>
652fe8fb19SBen Gras #include <fcntl.h>
662fe8fb19SBen Gras #include <stdio.h>
672fe8fb19SBen Gras #include <stdlib.h>
682fe8fb19SBen Gras #include <string.h>
692fe8fb19SBen Gras #include <unistd.h>
702fe8fb19SBen Gras 
712fe8fb19SBen Gras #include <rpc/rpc.h>
722fe8fb19SBen Gras 
73*84d9c625SLionel Sambuc #include "svc_fdset.h"
742fe8fb19SBen Gras #include "rpc_internal.h"
752fe8fb19SBen Gras 
762fe8fb19SBen Gras #ifdef __weak_alias
772fe8fb19SBen Gras __weak_alias(svc_fd_create,_svc_fd_create)
782fe8fb19SBen Gras __weak_alias(svc_vc_create,_svc_vc_create)
792fe8fb19SBen Gras #endif
802fe8fb19SBen Gras 
812fe8fb19SBen Gras #ifdef _REENTRANT
822fe8fb19SBen Gras extern rwlock_t svc_fd_lock;
832fe8fb19SBen Gras #endif
842fe8fb19SBen Gras 
85f14fb602SLionel Sambuc static SVCXPRT *makefd_xprt(int, u_int, u_int);
86f14fb602SLionel Sambuc static bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *);
87f14fb602SLionel Sambuc static enum xprt_stat rendezvous_stat(SVCXPRT *);
88f14fb602SLionel Sambuc static void svc_vc_destroy(SVCXPRT *);
89f14fb602SLionel Sambuc static void __svc_vc_dodestroy(SVCXPRT *);
90f14fb602SLionel Sambuc static int read_vc(caddr_t, caddr_t, int);
91f14fb602SLionel Sambuc static int write_vc(caddr_t, caddr_t, int);
92f14fb602SLionel Sambuc static enum xprt_stat svc_vc_stat(SVCXPRT *);
93f14fb602SLionel Sambuc static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *);
94f14fb602SLionel Sambuc static bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, caddr_t);
95f14fb602SLionel Sambuc static bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, caddr_t);
96f14fb602SLionel Sambuc static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *);
97f14fb602SLionel Sambuc static void svc_vc_rendezvous_ops(SVCXPRT *);
98f14fb602SLionel Sambuc static void svc_vc_ops(SVCXPRT *);
99f14fb602SLionel Sambuc static bool_t svc_vc_control(SVCXPRT *, const u_int, void *);
100f14fb602SLionel Sambuc static bool_t svc_vc_rendezvous_control(SVCXPRT *, const u_int, void *);
1012fe8fb19SBen Gras 
1022fe8fb19SBen Gras struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */
1032fe8fb19SBen Gras 	u_int sendsize;
1042fe8fb19SBen Gras 	u_int recvsize;
1052fe8fb19SBen Gras 	int maxrec;
1062fe8fb19SBen Gras };
1072fe8fb19SBen Gras 
1082fe8fb19SBen Gras struct cf_conn {  /* kept in xprt->xp_p1 for actual connection */
1092fe8fb19SBen Gras 	enum xprt_stat strm_stat;
1102fe8fb19SBen Gras 	u_int32_t x_id;
1112fe8fb19SBen Gras 	XDR xdrs;
1122fe8fb19SBen Gras 	char verf_body[MAX_AUTH_BYTES];
1132fe8fb19SBen Gras 	u_int sendsize;
1142fe8fb19SBen Gras 	u_int recvsize;
1152fe8fb19SBen Gras 	int maxrec;
1162fe8fb19SBen Gras 	bool_t nonblock;
1172fe8fb19SBen Gras 	struct timeval last_recv_time;
1182fe8fb19SBen Gras };
1192fe8fb19SBen Gras 
1202fe8fb19SBen Gras /*
1212fe8fb19SBen Gras  * Usage:
1222fe8fb19SBen Gras  *	xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
1232fe8fb19SBen Gras  *
1242fe8fb19SBen Gras  * Creates, registers, and returns a (rpc) tcp based transporter.
1252fe8fb19SBen Gras  * Once *xprt is initialized, it is registered as a transporter
1262fe8fb19SBen Gras  * see (svc.h, xprt_register).  This routine returns
1272fe8fb19SBen Gras  * a NULL if a problem occurred.
1282fe8fb19SBen Gras  *
1292fe8fb19SBen Gras  * The filedescriptor passed in is expected to refer to a bound, but
1302fe8fb19SBen Gras  * not yet connected socket.
1312fe8fb19SBen Gras  *
1322fe8fb19SBen Gras  * Since streams do buffered io similar to stdio, the caller can specify
1332fe8fb19SBen Gras  * how big the send and receive buffers are via the second and third parms;
1342fe8fb19SBen Gras  * 0 => use the system default.
1352fe8fb19SBen Gras  */
1362fe8fb19SBen Gras SVCXPRT *
svc_vc_create(int fd,u_int sendsize,u_int recvsize)137f14fb602SLionel Sambuc svc_vc_create(int fd, u_int sendsize, u_int recvsize)
1382fe8fb19SBen Gras {
1392fe8fb19SBen Gras 	SVCXPRT *xprt;
1402fe8fb19SBen Gras 	struct cf_rendezvous *r = NULL;
1412fe8fb19SBen Gras 	struct __rpc_sockinfo si;
1422fe8fb19SBen Gras 	struct sockaddr_storage sslocal;
1432fe8fb19SBen Gras 	socklen_t slen;
1442fe8fb19SBen Gras 	int one = 1;
1452fe8fb19SBen Gras 
1462fe8fb19SBen Gras 	if (!__rpc_fd2sockinfo(fd, &si))
1472fe8fb19SBen Gras 		return NULL;
1482fe8fb19SBen Gras 
1492fe8fb19SBen Gras 	r = mem_alloc(sizeof(*r));
1502fe8fb19SBen Gras 	if (r == NULL) {
151*84d9c625SLionel Sambuc 		warn("%s: out of memory", __func__);
1522fe8fb19SBen Gras 		return NULL;
1532fe8fb19SBen Gras 	}
1542fe8fb19SBen Gras 	r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize);
1552fe8fb19SBen Gras 	r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize);
1562fe8fb19SBen Gras 	r->maxrec = __svc_maxrec;
1572fe8fb19SBen Gras 	xprt = mem_alloc(sizeof(SVCXPRT));
1582fe8fb19SBen Gras 	if (xprt == NULL) {
159*84d9c625SLionel Sambuc 		warn("%s: out of memory", __func__);
1602fe8fb19SBen Gras 		goto cleanup_svc_vc_create;
1612fe8fb19SBen Gras 	}
1622fe8fb19SBen Gras 	xprt->xp_tp = NULL;
1632fe8fb19SBen Gras 	xprt->xp_p1 = (caddr_t)(void *)r;
1642fe8fb19SBen Gras 	xprt->xp_p2 = NULL;
1652fe8fb19SBen Gras 	xprt->xp_p3 = NULL;
1662fe8fb19SBen Gras 	xprt->xp_verf = _null_auth;
1672fe8fb19SBen Gras 	svc_vc_rendezvous_ops(xprt);
1682fe8fb19SBen Gras 	xprt->xp_port = (u_short)-1;	/* It is the rendezvouser */
1692fe8fb19SBen Gras 	xprt->xp_fd = fd;
1702fe8fb19SBen Gras 
1712fe8fb19SBen Gras 	slen = sizeof (struct sockaddr_storage);
1722fe8fb19SBen Gras 	if (getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) {
173*84d9c625SLionel Sambuc 		warn("%s: could not retrieve local addr", __func__);
1742fe8fb19SBen Gras 		goto cleanup_svc_vc_create;
1752fe8fb19SBen Gras 	}
1762fe8fb19SBen Gras 
1772fe8fb19SBen Gras 	/*
1782fe8fb19SBen Gras 	 * We want to be able to check credentials on local sockets.
1792fe8fb19SBen Gras 	 */
1802fe8fb19SBen Gras 	if (sslocal.ss_family == AF_LOCAL)
181f14fb602SLionel Sambuc 		if (setsockopt(fd, 0, LOCAL_CREDS, &one, (socklen_t)sizeof one)
182f14fb602SLionel Sambuc 		    == -1)
1832fe8fb19SBen Gras 			goto cleanup_svc_vc_create;
1842fe8fb19SBen Gras 
1852fe8fb19SBen Gras 	xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len;
1862fe8fb19SBen Gras 	xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len);
1872fe8fb19SBen Gras 	if (xprt->xp_ltaddr.buf == NULL) {
188*84d9c625SLionel Sambuc 		warn("%s: out of memory", __func__);
1892fe8fb19SBen Gras 		goto cleanup_svc_vc_create;
1902fe8fb19SBen Gras 	}
1912fe8fb19SBen Gras 	memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len);
1922fe8fb19SBen Gras 
1932fe8fb19SBen Gras 	xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage);
194*84d9c625SLionel Sambuc 	if (!xprt_register(xprt))
195*84d9c625SLionel Sambuc 		goto cleanup_svc_vc_create;
196f14fb602SLionel Sambuc 	return xprt;
1972fe8fb19SBen Gras cleanup_svc_vc_create:
1982fe8fb19SBen Gras 	if (xprt)
1992fe8fb19SBen Gras 		mem_free(xprt, sizeof(*xprt));
2002fe8fb19SBen Gras 	if (r != NULL)
2012fe8fb19SBen Gras 		mem_free(r, sizeof(*r));
202f14fb602SLionel Sambuc 	return NULL;
2032fe8fb19SBen Gras }
2042fe8fb19SBen Gras 
2052fe8fb19SBen Gras /*
2062fe8fb19SBen Gras  * Like svtcp_create(), except the routine takes any *open* UNIX file
2072fe8fb19SBen Gras  * descriptor as its first input.
2082fe8fb19SBen Gras  */
2092fe8fb19SBen Gras SVCXPRT *
svc_fd_create(int fd,u_int sendsize,u_int recvsize)210f14fb602SLionel Sambuc svc_fd_create(int fd, u_int sendsize, u_int recvsize)
2112fe8fb19SBen Gras {
2122fe8fb19SBen Gras 	struct sockaddr_storage ss;
2132fe8fb19SBen Gras 	socklen_t slen;
2142fe8fb19SBen Gras 	SVCXPRT *ret;
2152fe8fb19SBen Gras 
2162fe8fb19SBen Gras 	_DIAGASSERT(fd != -1);
2172fe8fb19SBen Gras 
2182fe8fb19SBen Gras 	ret = makefd_xprt(fd, sendsize, recvsize);
2192fe8fb19SBen Gras 	if (ret == NULL)
2202fe8fb19SBen Gras 		return NULL;
2212fe8fb19SBen Gras 
2222fe8fb19SBen Gras 	slen = sizeof (struct sockaddr_storage);
2232fe8fb19SBen Gras 	if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
224*84d9c625SLionel Sambuc 		warn("%s: could not retrieve local addr", __func__);
2252fe8fb19SBen Gras 		goto freedata;
2262fe8fb19SBen Gras 	}
2272fe8fb19SBen Gras 	ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len;
2282fe8fb19SBen Gras 	ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len);
2292fe8fb19SBen Gras 	if (ret->xp_ltaddr.buf == NULL) {
230*84d9c625SLionel Sambuc 		warn("%s: out of memory", __func__);
2312fe8fb19SBen Gras 		goto freedata;
2322fe8fb19SBen Gras 	}
2332fe8fb19SBen Gras 	memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len);
2342fe8fb19SBen Gras 
2352fe8fb19SBen Gras 	slen = sizeof (struct sockaddr_storage);
2362fe8fb19SBen Gras 	if (getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
237*84d9c625SLionel Sambuc 		warn("%s: could not retrieve remote addr", __func__);
2382fe8fb19SBen Gras 		goto freedata;
2392fe8fb19SBen Gras 	}
2402fe8fb19SBen Gras 	ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len;
2412fe8fb19SBen Gras 	ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len);
2422fe8fb19SBen Gras 	if (ret->xp_rtaddr.buf == NULL) {
243*84d9c625SLionel Sambuc 		warn("%s: out of memory", __func__);
2442fe8fb19SBen Gras 		goto freedata;
2452fe8fb19SBen Gras 	}
2462fe8fb19SBen Gras 	memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len);
2472fe8fb19SBen Gras #ifdef PORTMAP
2482fe8fb19SBen Gras 	if (ss.ss_family == AF_INET) {
2492fe8fb19SBen Gras 		ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf;
2502fe8fb19SBen Gras 		ret->xp_addrlen = sizeof (struct sockaddr_in);
2512fe8fb19SBen Gras 	}
2522fe8fb19SBen Gras #endif
2532fe8fb19SBen Gras 
2542fe8fb19SBen Gras 	return ret;
2552fe8fb19SBen Gras 
2562fe8fb19SBen Gras freedata:
2572fe8fb19SBen Gras 	if (ret->xp_ltaddr.buf != NULL)
2582fe8fb19SBen Gras 		mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen);
2592fe8fb19SBen Gras 
2602fe8fb19SBen Gras 	return NULL;
2612fe8fb19SBen Gras }
2622fe8fb19SBen Gras 
2632fe8fb19SBen Gras static SVCXPRT *
makefd_xprt(int fd,u_int sendsize,u_int recvsize)264f14fb602SLionel Sambuc makefd_xprt(int fd, u_int sendsize, u_int recvsize)
2652fe8fb19SBen Gras {
2662fe8fb19SBen Gras 	SVCXPRT *xprt;
2672fe8fb19SBen Gras 	struct cf_conn *cd;
2682fe8fb19SBen Gras 	const char *netid;
2692fe8fb19SBen Gras 	struct __rpc_sockinfo si;
2702fe8fb19SBen Gras 
2712fe8fb19SBen Gras 	_DIAGASSERT(fd != -1);
2722fe8fb19SBen Gras 
2732fe8fb19SBen Gras 	xprt = mem_alloc(sizeof(SVCXPRT));
2742fe8fb19SBen Gras 	if (xprt == NULL)
275*84d9c625SLionel Sambuc 		goto outofmem;
2762fe8fb19SBen Gras 	memset(xprt, 0, sizeof *xprt);
2772fe8fb19SBen Gras 	cd = mem_alloc(sizeof(struct cf_conn));
2782fe8fb19SBen Gras 	if (cd == NULL)
279*84d9c625SLionel Sambuc 		goto outofmem;
2802fe8fb19SBen Gras 	cd->strm_stat = XPRT_IDLE;
2812fe8fb19SBen Gras 	xdrrec_create(&(cd->xdrs), sendsize, recvsize,
2822fe8fb19SBen Gras 	    (caddr_t)(void *)xprt, read_vc, write_vc);
2832fe8fb19SBen Gras 	xprt->xp_p1 = (caddr_t)(void *)cd;
2842fe8fb19SBen Gras 	xprt->xp_verf.oa_base = cd->verf_body;
2852fe8fb19SBen Gras 	svc_vc_ops(xprt);  /* truely deals with calls */
2862fe8fb19SBen Gras 	xprt->xp_port = 0;  /* this is a connection, not a rendezvouser */
2872fe8fb19SBen Gras 	xprt->xp_fd = fd;
2882fe8fb19SBen Gras 	if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid))
2892fe8fb19SBen Gras 		if ((xprt->xp_netid = strdup(netid)) == NULL)
290*84d9c625SLionel Sambuc 			goto outofmem;
2912fe8fb19SBen Gras 
292*84d9c625SLionel Sambuc 	if (!xprt_register(xprt))
293*84d9c625SLionel Sambuc 		goto out;
294f14fb602SLionel Sambuc 	return xprt;
295*84d9c625SLionel Sambuc 
296*84d9c625SLionel Sambuc outofmem:
2972fe8fb19SBen Gras 	warn("svc_tcp: makefd_xprt");
298*84d9c625SLionel Sambuc out:
2992fe8fb19SBen Gras 	if (xprt)
3002fe8fb19SBen Gras 		mem_free(xprt, sizeof(SVCXPRT));
3012fe8fb19SBen Gras 	return NULL;
3022fe8fb19SBen Gras }
3032fe8fb19SBen Gras 
3042fe8fb19SBen Gras /*ARGSUSED*/
3052fe8fb19SBen Gras static bool_t
rendezvous_request(SVCXPRT * xprt,struct rpc_msg * msg)306f14fb602SLionel Sambuc rendezvous_request(SVCXPRT *xprt, struct rpc_msg *msg)
3072fe8fb19SBen Gras {
3082fe8fb19SBen Gras 	int sock, flags;
3092fe8fb19SBen Gras 	struct cf_rendezvous *r;
3102fe8fb19SBen Gras 	struct cf_conn *cd;
3112fe8fb19SBen Gras 	struct sockaddr_storage addr;
3122fe8fb19SBen Gras 	socklen_t len;
3132fe8fb19SBen Gras 	struct __rpc_sockinfo si;
3142fe8fb19SBen Gras 	SVCXPRT *newxprt;
3152fe8fb19SBen Gras 	fd_set cleanfds;
3162fe8fb19SBen Gras 
3172fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
3182fe8fb19SBen Gras 	_DIAGASSERT(msg != NULL);
3192fe8fb19SBen Gras 
3202fe8fb19SBen Gras 	r = (struct cf_rendezvous *)xprt->xp_p1;
3212fe8fb19SBen Gras again:
3222fe8fb19SBen Gras 	len = sizeof addr;
3232fe8fb19SBen Gras 	if ((sock = accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr,
3242fe8fb19SBen Gras 	    &len)) < 0) {
3252fe8fb19SBen Gras 		if (errno == EINTR)
3262fe8fb19SBen Gras 			goto again;
3272fe8fb19SBen Gras 		/*
3282fe8fb19SBen Gras 		 * Clean out the most idle file descriptor when we're
3292fe8fb19SBen Gras 		 * running out.
3302fe8fb19SBen Gras 		 */
3312fe8fb19SBen Gras 		if (errno == EMFILE || errno == ENFILE) {
332*84d9c625SLionel Sambuc 			cleanfds = *get_fdset();
3332fe8fb19SBen Gras 			if (__svc_clean_idle(&cleanfds, 0, FALSE))
3342fe8fb19SBen Gras 				goto again;
3352fe8fb19SBen Gras 		}
336f14fb602SLionel Sambuc 		return FALSE;
3372fe8fb19SBen Gras 	}
3382fe8fb19SBen Gras 	/*
3392fe8fb19SBen Gras 	 * make a new transporter (re-uses xprt)
3402fe8fb19SBen Gras 	 */
3412fe8fb19SBen Gras 	newxprt = makefd_xprt(sock, r->sendsize, r->recvsize);
3422fe8fb19SBen Gras 	if (newxprt == NULL)
3432fe8fb19SBen Gras 		goto out;
3442fe8fb19SBen Gras 	newxprt->xp_rtaddr.buf = mem_alloc(len);
3452fe8fb19SBen Gras 	if (newxprt->xp_rtaddr.buf == NULL)
3462fe8fb19SBen Gras 		goto out;
3472fe8fb19SBen Gras 	memcpy(newxprt->xp_rtaddr.buf, &addr, len);
3482fe8fb19SBen Gras 	newxprt->xp_rtaddr.len = len;
3492fe8fb19SBen Gras #ifdef PORTMAP
3502fe8fb19SBen Gras 	if (addr.ss_family == AF_INET) {
3512fe8fb19SBen Gras 		newxprt->xp_raddr = *(struct sockaddr_in *)newxprt->xp_rtaddr.buf;
3522fe8fb19SBen Gras 		newxprt->xp_addrlen = sizeof (struct sockaddr_in);
3532fe8fb19SBen Gras 	}
3542fe8fb19SBen Gras #endif
3552fe8fb19SBen Gras 	if (__rpc_fd2sockinfo(sock, &si))
3562fe8fb19SBen Gras 		__rpc_setnodelay(sock, &si);
3572fe8fb19SBen Gras 
3582fe8fb19SBen Gras 	cd = (struct cf_conn *)newxprt->xp_p1;
3592fe8fb19SBen Gras 
3602fe8fb19SBen Gras 	cd->recvsize = r->recvsize;
3612fe8fb19SBen Gras 	cd->sendsize = r->sendsize;
3622fe8fb19SBen Gras 	cd->maxrec = r->maxrec;
3632fe8fb19SBen Gras 
3642fe8fb19SBen Gras 	if (cd->maxrec != 0) {
3652fe8fb19SBen Gras 		flags = fcntl(sock, F_GETFL, 0);
3662fe8fb19SBen Gras 		if (flags  == -1)
3672fe8fb19SBen Gras 			goto out;
3682fe8fb19SBen Gras 		if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
3692fe8fb19SBen Gras 			goto out;
3702fe8fb19SBen Gras 		if (cd->recvsize > (u_int)cd->maxrec)
3712fe8fb19SBen Gras 			cd->recvsize = cd->maxrec;
3722fe8fb19SBen Gras 		cd->nonblock = TRUE;
3732fe8fb19SBen Gras 		__xdrrec_setnonblock(&cd->xdrs, cd->maxrec);
3742fe8fb19SBen Gras 	} else
3752fe8fb19SBen Gras 		cd->nonblock = FALSE;
3762fe8fb19SBen Gras 
3772fe8fb19SBen Gras 	(void)gettimeofday(&cd->last_recv_time, NULL);
3782fe8fb19SBen Gras 
379f14fb602SLionel Sambuc 	return FALSE; /* there is never an rpc msg to be processed */
3802fe8fb19SBen Gras out:
3812fe8fb19SBen Gras 	(void)close(sock);
382f14fb602SLionel Sambuc 	return FALSE; /* there was an error */
3832fe8fb19SBen Gras }
3842fe8fb19SBen Gras 
3852fe8fb19SBen Gras /*ARGSUSED*/
3862fe8fb19SBen Gras static enum xprt_stat
rendezvous_stat(SVCXPRT * xprt)387f14fb602SLionel Sambuc rendezvous_stat(SVCXPRT *xprt)
3882fe8fb19SBen Gras {
3892fe8fb19SBen Gras 
390f14fb602SLionel Sambuc 	return XPRT_IDLE;
3912fe8fb19SBen Gras }
3922fe8fb19SBen Gras 
3932fe8fb19SBen Gras static void
svc_vc_destroy(SVCXPRT * xprt)394f14fb602SLionel Sambuc svc_vc_destroy(SVCXPRT *xprt)
3952fe8fb19SBen Gras {
3962fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
3972fe8fb19SBen Gras 
3982fe8fb19SBen Gras 	xprt_unregister(xprt);
3992fe8fb19SBen Gras 	__svc_vc_dodestroy(xprt);
4002fe8fb19SBen Gras }
4012fe8fb19SBen Gras 
4022fe8fb19SBen Gras static void
__svc_vc_dodestroy(SVCXPRT * xprt)403f14fb602SLionel Sambuc __svc_vc_dodestroy(SVCXPRT *xprt)
4042fe8fb19SBen Gras {
4052fe8fb19SBen Gras 	struct cf_conn *cd;
4062fe8fb19SBen Gras 	struct cf_rendezvous *r;
4072fe8fb19SBen Gras 
4082fe8fb19SBen Gras 	cd = (struct cf_conn *)xprt->xp_p1;
4092fe8fb19SBen Gras 
4102fe8fb19SBen Gras 	if (xprt->xp_fd != RPC_ANYFD)
4112fe8fb19SBen Gras 		(void)close(xprt->xp_fd);
4122fe8fb19SBen Gras 	if (xprt->xp_port != 0) {
4132fe8fb19SBen Gras 		/* a rendezvouser socket */
4142fe8fb19SBen Gras 		r = (struct cf_rendezvous *)xprt->xp_p1;
4152fe8fb19SBen Gras 		mem_free(r, sizeof (struct cf_rendezvous));
4162fe8fb19SBen Gras 		xprt->xp_port = 0;
4172fe8fb19SBen Gras 	} else {
4182fe8fb19SBen Gras 		/* an actual connection socket */
4192fe8fb19SBen Gras 		XDR_DESTROY(&(cd->xdrs));
4202fe8fb19SBen Gras 		mem_free(cd, sizeof(struct cf_conn));
4212fe8fb19SBen Gras 	}
4222fe8fb19SBen Gras 	if (xprt->xp_rtaddr.buf)
4232fe8fb19SBen Gras 		mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen);
4242fe8fb19SBen Gras 	if (xprt->xp_ltaddr.buf)
4252fe8fb19SBen Gras 		mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen);
4262fe8fb19SBen Gras 	if (xprt->xp_tp)
4272fe8fb19SBen Gras 		free(xprt->xp_tp);
4282fe8fb19SBen Gras 	if (xprt->xp_netid)
4292fe8fb19SBen Gras 		free(xprt->xp_netid);
4302fe8fb19SBen Gras 	mem_free(xprt, sizeof(SVCXPRT));
4312fe8fb19SBen Gras }
4322fe8fb19SBen Gras 
4332fe8fb19SBen Gras /*ARGSUSED*/
4342fe8fb19SBen Gras static bool_t
svc_vc_control(SVCXPRT * xprt,const u_int rq,void * in)435f14fb602SLionel Sambuc svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in)
4362fe8fb19SBen Gras {
437f14fb602SLionel Sambuc 	return FALSE;
4382fe8fb19SBen Gras }
4392fe8fb19SBen Gras 
4402fe8fb19SBen Gras /*ARGSUSED*/
4412fe8fb19SBen Gras static bool_t
svc_vc_rendezvous_control(SVCXPRT * xprt,const u_int rq,void * in)442f14fb602SLionel Sambuc svc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in)
4432fe8fb19SBen Gras {
4442fe8fb19SBen Gras 	struct cf_rendezvous *cfp;
4452fe8fb19SBen Gras 
4462fe8fb19SBen Gras 	cfp = (struct cf_rendezvous *)xprt->xp_p1;
4472fe8fb19SBen Gras 	if (cfp == NULL)
448f14fb602SLionel Sambuc 		return FALSE;
4492fe8fb19SBen Gras 	switch (rq) {
4502fe8fb19SBen Gras 		case SVCGET_CONNMAXREC:
4512fe8fb19SBen Gras 			*(int *)in = cfp->maxrec;
4522fe8fb19SBen Gras 			break;
4532fe8fb19SBen Gras 		case SVCSET_CONNMAXREC:
4542fe8fb19SBen Gras 			cfp->maxrec = *(int *)in;
4552fe8fb19SBen Gras 			break;
4562fe8fb19SBen Gras 		default:
457f14fb602SLionel Sambuc 			return FALSE;
4582fe8fb19SBen Gras 	}
459f14fb602SLionel Sambuc 	return TRUE;
4602fe8fb19SBen Gras }
4612fe8fb19SBen Gras 
4622fe8fb19SBen Gras /*
4632fe8fb19SBen Gras  * reads data from the tcp connection.
4642fe8fb19SBen Gras  * any error is fatal and the connection is closed.
4652fe8fb19SBen Gras  * (And a read of zero bytes is a half closed stream => error.)
4662fe8fb19SBen Gras  * All read operations timeout after 35 seconds.  A timeout is
4672fe8fb19SBen Gras  * fatal for the connection.
4682fe8fb19SBen Gras  */
4692fe8fb19SBen Gras static int
read_vc(caddr_t xprtp,caddr_t buf,int len)470f14fb602SLionel Sambuc read_vc(caddr_t xprtp, caddr_t buf, int len)
4712fe8fb19SBen Gras {
4722fe8fb19SBen Gras 	SVCXPRT *xprt;
4732fe8fb19SBen Gras 	int sock;
4742fe8fb19SBen Gras 	struct pollfd pollfd;
4752fe8fb19SBen Gras 	struct sockaddr *sa;
4762fe8fb19SBen Gras 	struct msghdr msg;
4772fe8fb19SBen Gras 	struct cmsghdr *cmp;
4782fe8fb19SBen Gras 	void *crmsg = NULL;
4792fe8fb19SBen Gras 	struct sockcred *sc;
4802fe8fb19SBen Gras 	socklen_t crmsgsize;
4812fe8fb19SBen Gras 	struct cf_conn *cfp;
4822fe8fb19SBen Gras 	static const struct timespec ts = { 35, 0 };
4832fe8fb19SBen Gras 
4842fe8fb19SBen Gras 	xprt = (SVCXPRT *)(void *)xprtp;
4852fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
4862fe8fb19SBen Gras 
4872fe8fb19SBen Gras 	sock = xprt->xp_fd;
4882fe8fb19SBen Gras 
4892fe8fb19SBen Gras 	sa = (struct sockaddr *)xprt->xp_rtaddr.buf;
4902fe8fb19SBen Gras 	if (sa->sa_family == AF_LOCAL && xprt->xp_p2 == NULL) {
4912fe8fb19SBen Gras 		memset(&msg, 0, sizeof msg);
4922fe8fb19SBen Gras 		crmsgsize = CMSG_SPACE(SOCKCREDSIZE(NGROUPS));
4932fe8fb19SBen Gras 		crmsg = malloc(crmsgsize);
4942fe8fb19SBen Gras 		if (crmsg == NULL)
4952fe8fb19SBen Gras 			goto fatal_err;
4962fe8fb19SBen Gras 		memset(crmsg, 0, crmsgsize);
4972fe8fb19SBen Gras 
4982fe8fb19SBen Gras 		msg.msg_control = crmsg;
4992fe8fb19SBen Gras 		msg.msg_controllen = crmsgsize;
5002fe8fb19SBen Gras 
5012fe8fb19SBen Gras 		if (recvmsg(sock, &msg, 0) < 0)
5022fe8fb19SBen Gras 			goto fatal_err;
5032fe8fb19SBen Gras 
5042fe8fb19SBen Gras 		if (msg.msg_controllen == 0 ||
5052fe8fb19SBen Gras 		    (msg.msg_flags & MSG_CTRUNC) != 0)
5062fe8fb19SBen Gras 			goto fatal_err;
5072fe8fb19SBen Gras 
5082fe8fb19SBen Gras 		cmp = CMSG_FIRSTHDR(&msg);
5092fe8fb19SBen Gras 		if (cmp->cmsg_level != SOL_SOCKET ||
5102fe8fb19SBen Gras 		    cmp->cmsg_type != SCM_CREDS)
5112fe8fb19SBen Gras 			goto fatal_err;
5122fe8fb19SBen Gras 
5132fe8fb19SBen Gras 		sc = (struct sockcred *)(void *)CMSG_DATA(cmp);
5142fe8fb19SBen Gras 
5152fe8fb19SBen Gras 		xprt->xp_p2 = mem_alloc(SOCKCREDSIZE(sc->sc_ngroups));
5162fe8fb19SBen Gras 		if (xprt->xp_p2 == NULL)
5172fe8fb19SBen Gras 			goto fatal_err;
5182fe8fb19SBen Gras 
5192fe8fb19SBen Gras 		memcpy(xprt->xp_p2, sc, SOCKCREDSIZE(sc->sc_ngroups));
5202fe8fb19SBen Gras 		free(crmsg);
5212fe8fb19SBen Gras 		crmsg = NULL;
5222fe8fb19SBen Gras 	}
5232fe8fb19SBen Gras 
5242fe8fb19SBen Gras 	cfp = (struct cf_conn *)xprt->xp_p1;
5252fe8fb19SBen Gras 
5262fe8fb19SBen Gras 	if (cfp->nonblock) {
527f14fb602SLionel Sambuc 		len = (int)read(sock, buf, (size_t)len);
5282fe8fb19SBen Gras 		if (len < 0) {
5292fe8fb19SBen Gras 			if (errno == EAGAIN)
5302fe8fb19SBen Gras 				len = 0;
5312fe8fb19SBen Gras 			else
5322fe8fb19SBen Gras 				goto fatal_err;
5332fe8fb19SBen Gras 		}
5342fe8fb19SBen Gras 		if (len != 0)
5352fe8fb19SBen Gras 			gettimeofday(&cfp->last_recv_time, NULL);
5362fe8fb19SBen Gras 		return len;
5372fe8fb19SBen Gras 	}
5382fe8fb19SBen Gras 
5392fe8fb19SBen Gras 	do {
5402fe8fb19SBen Gras 		pollfd.fd = sock;
5412fe8fb19SBen Gras 		pollfd.events = POLLIN;
5422fe8fb19SBen Gras 		switch (pollts(&pollfd, 1, &ts, NULL)) {
5432fe8fb19SBen Gras 		case -1:
5442fe8fb19SBen Gras 			if (errno == EINTR) {
5452fe8fb19SBen Gras 				continue;
5462fe8fb19SBen Gras 			}
5472fe8fb19SBen Gras 			/*FALLTHROUGH*/
5482fe8fb19SBen Gras 		case 0:
5492fe8fb19SBen Gras 			goto fatal_err;
5502fe8fb19SBen Gras 
5512fe8fb19SBen Gras 		default:
5522fe8fb19SBen Gras 			break;
5532fe8fb19SBen Gras 		}
5542fe8fb19SBen Gras 	} while ((pollfd.revents & POLLIN) == 0);
5552fe8fb19SBen Gras 
556f14fb602SLionel Sambuc 	if ((len = (int)read(sock, buf, (size_t)len)) > 0) {
5572fe8fb19SBen Gras 		gettimeofday(&cfp->last_recv_time, NULL);
558f14fb602SLionel Sambuc 		return len;
5592fe8fb19SBen Gras 	}
5602fe8fb19SBen Gras 
5612fe8fb19SBen Gras fatal_err:
5622fe8fb19SBen Gras 	if (crmsg != NULL)
5632fe8fb19SBen Gras 		free(crmsg);
5642fe8fb19SBen Gras 	((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
565f14fb602SLionel Sambuc 	return -1;
5662fe8fb19SBen Gras }
5672fe8fb19SBen Gras 
5682fe8fb19SBen Gras /*
5692fe8fb19SBen Gras  * writes data to the tcp connection.
5702fe8fb19SBen Gras  * Any error is fatal and the connection is closed.
5712fe8fb19SBen Gras  */
5722fe8fb19SBen Gras static int
write_vc(caddr_t xprtp,caddr_t buf,int len)573f14fb602SLionel Sambuc write_vc(caddr_t xprtp, caddr_t buf, int len)
5742fe8fb19SBen Gras {
5752fe8fb19SBen Gras 	SVCXPRT *xprt;
5762fe8fb19SBen Gras 	int i, cnt;
5772fe8fb19SBen Gras 	struct cf_conn *cd;
5782fe8fb19SBen Gras 	struct timeval tv0, tv1;
5792fe8fb19SBen Gras 
5802fe8fb19SBen Gras 	xprt = (SVCXPRT *)(void *)xprtp;
5812fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
5822fe8fb19SBen Gras 
5832fe8fb19SBen Gras 	cd = (struct cf_conn *)xprt->xp_p1;
5842fe8fb19SBen Gras 
5852fe8fb19SBen Gras 	if (cd->nonblock)
5862fe8fb19SBen Gras 		gettimeofday(&tv0, NULL);
5872fe8fb19SBen Gras 
5882fe8fb19SBen Gras 	for (cnt = len; cnt > 0; cnt -= i, buf += i) {
589f14fb602SLionel Sambuc 		if ((i = (int)write(xprt->xp_fd, buf, (size_t)cnt)) < 0) {
5902fe8fb19SBen Gras 			if (errno != EAGAIN || !cd->nonblock) {
5912fe8fb19SBen Gras 				cd->strm_stat = XPRT_DIED;
592f14fb602SLionel Sambuc 				return -1;
5932fe8fb19SBen Gras 			}
594f14fb602SLionel Sambuc 			if (cd->nonblock) {
5952fe8fb19SBen Gras 				/*
5962fe8fb19SBen Gras 				 * For non-blocking connections, do not
5972fe8fb19SBen Gras 				 * take more than 2 seconds writing the
5982fe8fb19SBen Gras 				 * data out.
5992fe8fb19SBen Gras 				 *
6002fe8fb19SBen Gras 				 * XXX 2 is an arbitrary amount.
6012fe8fb19SBen Gras 				 */
6022fe8fb19SBen Gras 				gettimeofday(&tv1, NULL);
6032fe8fb19SBen Gras 				if (tv1.tv_sec - tv0.tv_sec >= 2) {
6042fe8fb19SBen Gras 					cd->strm_stat = XPRT_DIED;
605f14fb602SLionel Sambuc 					return -1;
6062fe8fb19SBen Gras 				}
6072fe8fb19SBen Gras 			}
608f14fb602SLionel Sambuc 			i = 0;
6092fe8fb19SBen Gras 		}
6102fe8fb19SBen Gras 	}
611f14fb602SLionel Sambuc 	return len;
6122fe8fb19SBen Gras }
6132fe8fb19SBen Gras 
6142fe8fb19SBen Gras static enum xprt_stat
svc_vc_stat(SVCXPRT * xprt)615f14fb602SLionel Sambuc svc_vc_stat(SVCXPRT *xprt)
6162fe8fb19SBen Gras {
6172fe8fb19SBen Gras 	struct cf_conn *cd;
6182fe8fb19SBen Gras 
6192fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
6202fe8fb19SBen Gras 
6212fe8fb19SBen Gras 	cd = (struct cf_conn *)(xprt->xp_p1);
6222fe8fb19SBen Gras 
6232fe8fb19SBen Gras 	if (cd->strm_stat == XPRT_DIED)
624f14fb602SLionel Sambuc 		return XPRT_DIED;
6252fe8fb19SBen Gras 	if (! xdrrec_eof(&(cd->xdrs)))
626f14fb602SLionel Sambuc 		return XPRT_MOREREQS;
627f14fb602SLionel Sambuc 	return XPRT_IDLE;
6282fe8fb19SBen Gras }
6292fe8fb19SBen Gras 
6302fe8fb19SBen Gras static bool_t
svc_vc_recv(SVCXPRT * xprt,struct rpc_msg * msg)631f14fb602SLionel Sambuc svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg)
6322fe8fb19SBen Gras {
6332fe8fb19SBen Gras 	struct cf_conn *cd;
6342fe8fb19SBen Gras 	XDR *xdrs;
6352fe8fb19SBen Gras 
6362fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
6372fe8fb19SBen Gras 	_DIAGASSERT(msg != NULL);
6382fe8fb19SBen Gras 
6392fe8fb19SBen Gras 	cd = (struct cf_conn *)(xprt->xp_p1);
6402fe8fb19SBen Gras 	xdrs = &(cd->xdrs);
6412fe8fb19SBen Gras 
6422fe8fb19SBen Gras 	if (cd->nonblock) {
6432fe8fb19SBen Gras 		if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE))
6442fe8fb19SBen Gras 			return FALSE;
6452fe8fb19SBen Gras 	}
6462fe8fb19SBen Gras 
6472fe8fb19SBen Gras 	xdrs->x_op = XDR_DECODE;
6482fe8fb19SBen Gras 	(void)xdrrec_skiprecord(xdrs);
6492fe8fb19SBen Gras 
6502fe8fb19SBen Gras 	if (xdr_callmsg(xdrs, msg)) {
6512fe8fb19SBen Gras 		cd->x_id = msg->rm_xid;
652f14fb602SLionel Sambuc 		return TRUE;
6532fe8fb19SBen Gras 	}
6542fe8fb19SBen Gras 	cd->strm_stat = XPRT_DIED;
655f14fb602SLionel Sambuc 	return FALSE;
6562fe8fb19SBen Gras }
6572fe8fb19SBen Gras 
6582fe8fb19SBen Gras static bool_t
svc_vc_getargs(SVCXPRT * xprt,xdrproc_t xdr_args,caddr_t args_ptr)659f14fb602SLionel Sambuc svc_vc_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
6602fe8fb19SBen Gras {
6612fe8fb19SBen Gras 
6622fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
6632fe8fb19SBen Gras 	/* args_ptr may be NULL */
6642fe8fb19SBen Gras 
665f14fb602SLionel Sambuc 	return (*xdr_args)(&(((struct cf_conn *)(xprt->xp_p1))->xdrs),
666f14fb602SLionel Sambuc 	    args_ptr);
6672fe8fb19SBen Gras }
6682fe8fb19SBen Gras 
6692fe8fb19SBen Gras static bool_t
svc_vc_freeargs(SVCXPRT * xprt,xdrproc_t xdr_args,caddr_t args_ptr)670f14fb602SLionel Sambuc svc_vc_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
6712fe8fb19SBen Gras {
6722fe8fb19SBen Gras 	XDR *xdrs;
6732fe8fb19SBen Gras 
6742fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
6752fe8fb19SBen Gras 	/* args_ptr may be NULL */
6762fe8fb19SBen Gras 
6772fe8fb19SBen Gras 	xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs);
6782fe8fb19SBen Gras 
6792fe8fb19SBen Gras 	xdrs->x_op = XDR_FREE;
680f14fb602SLionel Sambuc 	return (*xdr_args)(xdrs, args_ptr);
6812fe8fb19SBen Gras }
6822fe8fb19SBen Gras 
6832fe8fb19SBen Gras static bool_t
svc_vc_reply(SVCXPRT * xprt,struct rpc_msg * msg)684f14fb602SLionel Sambuc svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg)
6852fe8fb19SBen Gras {
6862fe8fb19SBen Gras 	struct cf_conn *cd;
6872fe8fb19SBen Gras 	XDR *xdrs;
6882fe8fb19SBen Gras 	bool_t rstat;
6892fe8fb19SBen Gras 
6902fe8fb19SBen Gras 	_DIAGASSERT(xprt != NULL);
6912fe8fb19SBen Gras 	_DIAGASSERT(msg != NULL);
6922fe8fb19SBen Gras 
6932fe8fb19SBen Gras 	cd = (struct cf_conn *)(xprt->xp_p1);
6942fe8fb19SBen Gras 	xdrs = &(cd->xdrs);
6952fe8fb19SBen Gras 
6962fe8fb19SBen Gras 	xdrs->x_op = XDR_ENCODE;
6972fe8fb19SBen Gras 	msg->rm_xid = cd->x_id;
6982fe8fb19SBen Gras 	rstat = xdr_replymsg(xdrs, msg);
6992fe8fb19SBen Gras 	(void)xdrrec_endofrecord(xdrs, TRUE);
700f14fb602SLionel Sambuc 	return rstat;
7012fe8fb19SBen Gras }
7022fe8fb19SBen Gras 
7032fe8fb19SBen Gras static void
svc_vc_ops(SVCXPRT * xprt)704f14fb602SLionel Sambuc svc_vc_ops(SVCXPRT *xprt)
7052fe8fb19SBen Gras {
7062fe8fb19SBen Gras 	static struct xp_ops ops;
7072fe8fb19SBen Gras 	static struct xp_ops2 ops2;
7082fe8fb19SBen Gras #ifdef _REENTRANT
7092fe8fb19SBen Gras 	extern mutex_t ops_lock;
7102fe8fb19SBen Gras #endif
7112fe8fb19SBen Gras 
7122fe8fb19SBen Gras /* VARIABLES PROTECTED BY ops_lock: ops, ops2 */
7132fe8fb19SBen Gras 
7142fe8fb19SBen Gras 	mutex_lock(&ops_lock);
7152fe8fb19SBen Gras 	if (ops.xp_recv == NULL) {
7162fe8fb19SBen Gras 		ops.xp_recv = svc_vc_recv;
7172fe8fb19SBen Gras 		ops.xp_stat = svc_vc_stat;
7182fe8fb19SBen Gras 		ops.xp_getargs = svc_vc_getargs;
7192fe8fb19SBen Gras 		ops.xp_reply = svc_vc_reply;
7202fe8fb19SBen Gras 		ops.xp_freeargs = svc_vc_freeargs;
7212fe8fb19SBen Gras 		ops.xp_destroy = svc_vc_destroy;
7222fe8fb19SBen Gras 		ops2.xp_control = svc_vc_control;
7232fe8fb19SBen Gras 	}
7242fe8fb19SBen Gras 	xprt->xp_ops = &ops;
7252fe8fb19SBen Gras 	xprt->xp_ops2 = &ops2;
7262fe8fb19SBen Gras 	mutex_unlock(&ops_lock);
7272fe8fb19SBen Gras }
7282fe8fb19SBen Gras 
7292fe8fb19SBen Gras static void
svc_vc_rendezvous_ops(SVCXPRT * xprt)730f14fb602SLionel Sambuc svc_vc_rendezvous_ops(SVCXPRT *xprt)
7312fe8fb19SBen Gras {
7322fe8fb19SBen Gras 	static struct xp_ops ops;
7332fe8fb19SBen Gras 	static struct xp_ops2 ops2;
7342fe8fb19SBen Gras #ifdef _REENTRANT
7352fe8fb19SBen Gras 	extern mutex_t ops_lock;
7362fe8fb19SBen Gras #endif
7372fe8fb19SBen Gras 	mutex_lock(&ops_lock);
7382fe8fb19SBen Gras 	if (ops.xp_recv == NULL) {
7392fe8fb19SBen Gras 		ops.xp_recv = rendezvous_request;
7402fe8fb19SBen Gras 		ops.xp_stat = rendezvous_stat;
7412fe8fb19SBen Gras 		ops.xp_getargs =
742f14fb602SLionel Sambuc 		    (bool_t (*)(SVCXPRT *, xdrproc_t, caddr_t))abort;
7432fe8fb19SBen Gras 		ops.xp_reply =
744f14fb602SLionel Sambuc 		    (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort;
7452fe8fb19SBen Gras 		ops.xp_freeargs =
746f14fb602SLionel Sambuc 		    (bool_t (*)(SVCXPRT *, xdrproc_t, caddr_t))abort;
7472fe8fb19SBen Gras 		ops.xp_destroy = svc_vc_destroy;
7482fe8fb19SBen Gras 		ops2.xp_control = svc_vc_rendezvous_control;
7492fe8fb19SBen Gras 	}
7502fe8fb19SBen Gras 	xprt->xp_ops = &ops;
7512fe8fb19SBen Gras 	xprt->xp_ops2 = &ops2;
7522fe8fb19SBen Gras 	mutex_unlock(&ops_lock);
7532fe8fb19SBen Gras }
7542fe8fb19SBen Gras 
7552fe8fb19SBen Gras /*
7562fe8fb19SBen Gras  * Destroy xprts that have not have had any activity in 'timeout' seconds.
7572fe8fb19SBen Gras  * If 'cleanblock' is true, blocking connections (the default) are also
7582fe8fb19SBen Gras  * cleaned. If timeout is 0, the least active connection is picked.
7592fe8fb19SBen Gras  */
7602fe8fb19SBen Gras bool_t
__svc_clean_idle(fd_set * fds,int timeout,bool_t cleanblock)7612fe8fb19SBen Gras __svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock)
7622fe8fb19SBen Gras {
7632fe8fb19SBen Gras 	int i, ncleaned;
7642fe8fb19SBen Gras 	SVCXPRT *xprt, *least_active;
7652fe8fb19SBen Gras 	struct timeval tv, tdiff, tmax;
7662fe8fb19SBen Gras 	struct cf_conn *cd;
7672fe8fb19SBen Gras 
7682fe8fb19SBen Gras 	gettimeofday(&tv, NULL);
7692fe8fb19SBen Gras 	tmax.tv_sec = tmax.tv_usec = 0;
7702fe8fb19SBen Gras 	least_active = NULL;
7712fe8fb19SBen Gras 	rwlock_wrlock(&svc_fd_lock);
7722fe8fb19SBen Gras 	for (i = ncleaned = 0; i <= svc_maxfd; i++) {
7732fe8fb19SBen Gras 		if (FD_ISSET(i, fds)) {
7742fe8fb19SBen Gras 			xprt = __svc_xports[i];
7752fe8fb19SBen Gras 			if (xprt == NULL || xprt->xp_ops == NULL ||
7762fe8fb19SBen Gras 			    xprt->xp_ops->xp_recv != svc_vc_recv)
7772fe8fb19SBen Gras 				continue;
7782fe8fb19SBen Gras 			cd = (struct cf_conn *)xprt->xp_p1;
7792fe8fb19SBen Gras 			if (!cleanblock && !cd->nonblock)
7802fe8fb19SBen Gras 				continue;
7812fe8fb19SBen Gras 			if (timeout == 0) {
7822fe8fb19SBen Gras 				timersub(&tv, &cd->last_recv_time, &tdiff);
7832fe8fb19SBen Gras 				if (timercmp(&tdiff, &tmax, >)) {
7842fe8fb19SBen Gras 					tmax = tdiff;
7852fe8fb19SBen Gras 					least_active = xprt;
7862fe8fb19SBen Gras 				}
7872fe8fb19SBen Gras 				continue;
7882fe8fb19SBen Gras 			}
7892fe8fb19SBen Gras 			if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) {
7902fe8fb19SBen Gras 				__xprt_unregister_unlocked(xprt);
7912fe8fb19SBen Gras 				__svc_vc_dodestroy(xprt);
7922fe8fb19SBen Gras 				ncleaned++;
7932fe8fb19SBen Gras 			}
7942fe8fb19SBen Gras 		}
7952fe8fb19SBen Gras 	}
7962fe8fb19SBen Gras 	if (timeout == 0 && least_active != NULL) {
7972fe8fb19SBen Gras 		__xprt_unregister_unlocked(least_active);
7982fe8fb19SBen Gras 		__svc_vc_dodestroy(least_active);
7992fe8fb19SBen Gras 		ncleaned++;
8002fe8fb19SBen Gras 	}
8012fe8fb19SBen Gras 	rwlock_unlock(&svc_fd_lock);
8022fe8fb19SBen Gras 	return ncleaned > 0 ? TRUE : FALSE;
8032fe8fb19SBen Gras }
804