xref: /freebsd/lib/libc/rpc/svc_vc.c (revision a986ef5788bd3338d2a970eb96104824e4a0e3bb)
18360efbdSAlfred Perlstein /*	$NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $	*/
28360efbdSAlfred Perlstein 
38360efbdSAlfred Perlstein /*
48360efbdSAlfred Perlstein  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
58360efbdSAlfred Perlstein  * unrestricted use provided that this legend is included on all tape
68360efbdSAlfred Perlstein  * media and as a part of the software program in whole or part.  Users
78360efbdSAlfred Perlstein  * may copy or modify Sun RPC without charge, but are not authorized
88360efbdSAlfred Perlstein  * to license or distribute it to anyone else except as part of a product or
98360efbdSAlfred Perlstein  * program developed by the user.
108360efbdSAlfred Perlstein  *
118360efbdSAlfred Perlstein  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
128360efbdSAlfred Perlstein  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
138360efbdSAlfred Perlstein  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
148360efbdSAlfred Perlstein  *
158360efbdSAlfred Perlstein  * Sun RPC is provided with no support and without any obligation on the
168360efbdSAlfred Perlstein  * part of Sun Microsystems, Inc. to assist in its use, correction,
178360efbdSAlfred Perlstein  * modification or enhancement.
188360efbdSAlfred Perlstein  *
198360efbdSAlfred Perlstein  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
208360efbdSAlfred Perlstein  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
218360efbdSAlfred Perlstein  * OR ANY PART THEREOF.
228360efbdSAlfred Perlstein  *
238360efbdSAlfred Perlstein  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
248360efbdSAlfred Perlstein  * or profits or other special, indirect and consequential damages, even if
258360efbdSAlfred Perlstein  * Sun has been advised of the possibility of such damages.
268360efbdSAlfred Perlstein  *
278360efbdSAlfred Perlstein  * Sun Microsystems, Inc.
288360efbdSAlfred Perlstein  * 2550 Garcia Avenue
298360efbdSAlfred Perlstein  * Mountain View, California  94043
308360efbdSAlfred Perlstein  */
318360efbdSAlfred Perlstein 
328360efbdSAlfred Perlstein #if defined(LIBC_SCCS) && !defined(lint)
33a986ef57SDavid E. O'Brien static char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
348360efbdSAlfred Perlstein static char *sccsid = "@(#)svc_tcp.c	2.2 88/08/01 4.0 RPCSRC";
358360efbdSAlfred Perlstein #endif
36d3d20c82SDavid E. O'Brien #include <sys/cdefs.h>
37d3d20c82SDavid E. O'Brien __FBSDID("$FreeBSD$");
388360efbdSAlfred Perlstein 
398360efbdSAlfred Perlstein /*
408360efbdSAlfred Perlstein  * svc_vc.c, Server side for Connection Oriented based RPC.
418360efbdSAlfred Perlstein  *
428360efbdSAlfred Perlstein  * Actually implements two flavors of transporter -
438360efbdSAlfred Perlstein  * a tcp rendezvouser (a listner and connection establisher)
448360efbdSAlfred Perlstein  * and a record/tcp stream.
458360efbdSAlfred Perlstein  */
468360efbdSAlfred Perlstein 
478360efbdSAlfred Perlstein #include "namespace.h"
489f5afc13SIan Dowse #include "reentrant.h"
498360efbdSAlfred Perlstein #include <sys/types.h>
508360efbdSAlfred Perlstein #include <sys/param.h>
518360efbdSAlfred Perlstein #include <sys/poll.h>
528360efbdSAlfred Perlstein #include <sys/socket.h>
538360efbdSAlfred Perlstein #include <sys/un.h>
5408497c02SMartin Blapp #include <sys/time.h>
558360efbdSAlfred Perlstein #include <sys/uio.h>
568360efbdSAlfred Perlstein #include <netinet/in.h>
578360efbdSAlfred Perlstein #include <netinet/tcp.h>
588360efbdSAlfred Perlstein 
598360efbdSAlfred Perlstein #include <assert.h>
608360efbdSAlfred Perlstein #include <err.h>
618360efbdSAlfred Perlstein #include <errno.h>
6208497c02SMartin Blapp #include <fcntl.h>
638360efbdSAlfred Perlstein #include <stdio.h>
648360efbdSAlfred Perlstein #include <stdlib.h>
658360efbdSAlfred Perlstein #include <string.h>
668360efbdSAlfred Perlstein #include <unistd.h>
678360efbdSAlfred Perlstein 
688360efbdSAlfred Perlstein #include <rpc/rpc.h>
698360efbdSAlfred Perlstein 
708360efbdSAlfred Perlstein #include "rpc_com.h"
718360efbdSAlfred Perlstein #include "un-namespace.h"
728360efbdSAlfred Perlstein 
7308497c02SMartin Blapp extern rwlock_t svc_fd_lock;
7408497c02SMartin Blapp 
75c05ac53bSDavid E. O'Brien static SVCXPRT *makefd_xprt(int, u_int, u_int);
76c05ac53bSDavid E. O'Brien static bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *);
77c05ac53bSDavid E. O'Brien static enum xprt_stat rendezvous_stat(SVCXPRT *);
78c05ac53bSDavid E. O'Brien static void svc_vc_destroy(SVCXPRT *);
7908497c02SMartin Blapp static void __svc_vc_dodestroy (SVCXPRT *);
80f249dbccSDag-Erling Smørgrav static int read_vc(void *, void *, int);
81f249dbccSDag-Erling Smørgrav static int write_vc(void *, void *, int);
82c05ac53bSDavid E. O'Brien static enum xprt_stat svc_vc_stat(SVCXPRT *);
83c05ac53bSDavid E. O'Brien static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *);
84f249dbccSDag-Erling Smørgrav static bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, void *);
85f249dbccSDag-Erling Smørgrav static bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, void *);
86c05ac53bSDavid E. O'Brien static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *);
87c05ac53bSDavid E. O'Brien static void svc_vc_rendezvous_ops(SVCXPRT *);
88c05ac53bSDavid E. O'Brien static void svc_vc_ops(SVCXPRT *);
89c05ac53bSDavid E. O'Brien static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in);
9008497c02SMartin Blapp static bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq,
9108497c02SMartin Blapp 				   	     void *in);
928360efbdSAlfred Perlstein 
938360efbdSAlfred Perlstein struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */
948360efbdSAlfred Perlstein 	u_int sendsize;
958360efbdSAlfred Perlstein 	u_int recvsize;
9608497c02SMartin Blapp 	int maxrec;
978360efbdSAlfred Perlstein };
988360efbdSAlfred Perlstein 
998360efbdSAlfred Perlstein struct cf_conn {  /* kept in xprt->xp_p1 for actual connection */
1008360efbdSAlfred Perlstein 	enum xprt_stat strm_stat;
1018360efbdSAlfred Perlstein 	u_int32_t x_id;
1028360efbdSAlfred Perlstein 	XDR xdrs;
1038360efbdSAlfred Perlstein 	char verf_body[MAX_AUTH_BYTES];
10408497c02SMartin Blapp 	u_int sendsize;
10508497c02SMartin Blapp 	u_int recvsize;
10608497c02SMartin Blapp 	int maxrec;
10708497c02SMartin Blapp 	bool_t nonblock;
10808497c02SMartin Blapp 	struct timeval last_recv_time;
1098360efbdSAlfred Perlstein };
1108360efbdSAlfred Perlstein 
1118360efbdSAlfred Perlstein /*
1128360efbdSAlfred Perlstein  * Usage:
1138360efbdSAlfred Perlstein  *	xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
1148360efbdSAlfred Perlstein  *
1158360efbdSAlfred Perlstein  * Creates, registers, and returns a (rpc) tcp based transporter.
1168360efbdSAlfred Perlstein  * Once *xprt is initialized, it is registered as a transporter
1178360efbdSAlfred Perlstein  * see (svc.h, xprt_register).  This routine returns
1188360efbdSAlfred Perlstein  * a NULL if a problem occurred.
1198360efbdSAlfred Perlstein  *
1208360efbdSAlfred Perlstein  * The filedescriptor passed in is expected to refer to a bound, but
1218360efbdSAlfred Perlstein  * not yet connected socket.
1228360efbdSAlfred Perlstein  *
1238360efbdSAlfred Perlstein  * Since streams do buffered io similar to stdio, the caller can specify
1248360efbdSAlfred Perlstein  * how big the send and receive buffers are via the second and third parms;
1258360efbdSAlfred Perlstein  * 0 => use the system default.
1268360efbdSAlfred Perlstein  */
1278360efbdSAlfred Perlstein SVCXPRT *
1288360efbdSAlfred Perlstein svc_vc_create(fd, sendsize, recvsize)
1298360efbdSAlfred Perlstein 	int fd;
1308360efbdSAlfred Perlstein 	u_int sendsize;
1318360efbdSAlfred Perlstein 	u_int recvsize;
1328360efbdSAlfred Perlstein {
1338360efbdSAlfred Perlstein 	SVCXPRT *xprt;
1348360efbdSAlfred Perlstein 	struct cf_rendezvous *r = NULL;
1358360efbdSAlfred Perlstein 	struct __rpc_sockinfo si;
1368360efbdSAlfred Perlstein 	struct sockaddr_storage sslocal;
1378360efbdSAlfred Perlstein 	socklen_t slen;
1388360efbdSAlfred Perlstein 
1398360efbdSAlfred Perlstein 	r = mem_alloc(sizeof(*r));
1408360efbdSAlfred Perlstein 	if (r == NULL) {
1418360efbdSAlfred Perlstein 		warnx("svc_vc_create: out of memory");
1428360efbdSAlfred Perlstein 		goto cleanup_svc_vc_create;
1438360efbdSAlfred Perlstein 	}
1448360efbdSAlfred Perlstein 	if (!__rpc_fd2sockinfo(fd, &si))
1458360efbdSAlfred Perlstein 		return NULL;
1468360efbdSAlfred Perlstein 	r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize);
1478360efbdSAlfred Perlstein 	r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize);
14808497c02SMartin Blapp 	r->maxrec = __svc_maxrec;
1498360efbdSAlfred Perlstein 	xprt = mem_alloc(sizeof(SVCXPRT));
1508360efbdSAlfred Perlstein 	if (xprt == NULL) {
1518360efbdSAlfred Perlstein 		warnx("svc_vc_create: out of memory");
1528360efbdSAlfred Perlstein 		goto cleanup_svc_vc_create;
1538360efbdSAlfred Perlstein 	}
1548360efbdSAlfred Perlstein 	xprt->xp_tp = NULL;
155f249dbccSDag-Erling Smørgrav 	xprt->xp_p1 = r;
1568360efbdSAlfred Perlstein 	xprt->xp_p2 = NULL;
1578360efbdSAlfred Perlstein 	xprt->xp_p3 = NULL;
1588360efbdSAlfred Perlstein 	xprt->xp_verf = _null_auth;
1598360efbdSAlfred Perlstein 	svc_vc_rendezvous_ops(xprt);
1608360efbdSAlfred Perlstein 	xprt->xp_port = (u_short)-1;	/* It is the rendezvouser */
1618360efbdSAlfred Perlstein 	xprt->xp_fd = fd;
1628360efbdSAlfred Perlstein 
1638360efbdSAlfred Perlstein 	slen = sizeof (struct sockaddr_storage);
1648360efbdSAlfred Perlstein 	if (_getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) {
1658360efbdSAlfred Perlstein 		warnx("svc_vc_create: could not retrieve local addr");
1668360efbdSAlfred Perlstein 		goto cleanup_svc_vc_create;
1678360efbdSAlfred Perlstein 	}
1688360efbdSAlfred Perlstein 
1698360efbdSAlfred Perlstein 	xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len;
1708360efbdSAlfred Perlstein 	xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len);
1718360efbdSAlfred Perlstein 	if (xprt->xp_ltaddr.buf == NULL) {
1728360efbdSAlfred Perlstein 		warnx("svc_vc_create: no mem for local addr");
1738360efbdSAlfred Perlstein 		goto cleanup_svc_vc_create;
1748360efbdSAlfred Perlstein 	}
1758360efbdSAlfred Perlstein 	memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len);
1768360efbdSAlfred Perlstein 
1778360efbdSAlfred Perlstein 	xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage);
1788360efbdSAlfred Perlstein 	xprt_register(xprt);
1798360efbdSAlfred Perlstein 	return (xprt);
1808360efbdSAlfred Perlstein cleanup_svc_vc_create:
1818360efbdSAlfred Perlstein 	if (r != NULL)
1828360efbdSAlfred Perlstein 		mem_free(r, sizeof(*r));
1838360efbdSAlfred Perlstein 	return (NULL);
1848360efbdSAlfred Perlstein }
1858360efbdSAlfred Perlstein 
1868360efbdSAlfred Perlstein /*
1878360efbdSAlfred Perlstein  * Like svtcp_create(), except the routine takes any *open* UNIX file
1888360efbdSAlfred Perlstein  * descriptor as its first input.
1898360efbdSAlfred Perlstein  */
1908360efbdSAlfred Perlstein SVCXPRT *
1918360efbdSAlfred Perlstein svc_fd_create(fd, sendsize, recvsize)
1928360efbdSAlfred Perlstein 	int fd;
1938360efbdSAlfred Perlstein 	u_int sendsize;
1948360efbdSAlfred Perlstein 	u_int recvsize;
1958360efbdSAlfred Perlstein {
1968360efbdSAlfred Perlstein 	struct sockaddr_storage ss;
1978360efbdSAlfred Perlstein 	socklen_t slen;
1988360efbdSAlfred Perlstein 	SVCXPRT *ret;
1998360efbdSAlfred Perlstein 
2008360efbdSAlfred Perlstein 	assert(fd != -1);
2018360efbdSAlfred Perlstein 
2028360efbdSAlfred Perlstein 	ret = makefd_xprt(fd, sendsize, recvsize);
2038360efbdSAlfred Perlstein 	if (ret == NULL)
2048360efbdSAlfred Perlstein 		return NULL;
2058360efbdSAlfred Perlstein 
2068360efbdSAlfred Perlstein 	slen = sizeof (struct sockaddr_storage);
2078360efbdSAlfred Perlstein 	if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
2088360efbdSAlfred Perlstein 		warnx("svc_fd_create: could not retrieve local addr");
2098360efbdSAlfred Perlstein 		goto freedata;
2108360efbdSAlfred Perlstein 	}
2118360efbdSAlfred Perlstein 	ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len;
2128360efbdSAlfred Perlstein 	ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len);
2138360efbdSAlfred Perlstein 	if (ret->xp_ltaddr.buf == NULL) {
2148360efbdSAlfred Perlstein 		warnx("svc_fd_create: no mem for local addr");
2158360efbdSAlfred Perlstein 		goto freedata;
2168360efbdSAlfred Perlstein 	}
2178360efbdSAlfred Perlstein 	memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len);
2188360efbdSAlfred Perlstein 
2198360efbdSAlfred Perlstein 	slen = sizeof (struct sockaddr_storage);
2208360efbdSAlfred Perlstein 	if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
2218360efbdSAlfred Perlstein 		warnx("svc_fd_create: could not retrieve remote addr");
2228360efbdSAlfred Perlstein 		goto freedata;
2238360efbdSAlfred Perlstein 	}
2248360efbdSAlfred Perlstein 	ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len;
2258360efbdSAlfred Perlstein 	ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len);
2268360efbdSAlfred Perlstein 	if (ret->xp_rtaddr.buf == NULL) {
2278360efbdSAlfred Perlstein 		warnx("svc_fd_create: no mem for local addr");
2288360efbdSAlfred Perlstein 		goto freedata;
2298360efbdSAlfred Perlstein 	}
2308360efbdSAlfred Perlstein 	memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len);
2318360efbdSAlfred Perlstein #ifdef PORTMAP
2322abd9cf1SAlfred Perlstein 	if (ss.ss_family == AF_INET || ss.ss_family == AF_LOCAL) {
2338360efbdSAlfred Perlstein 		ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf;
2348360efbdSAlfred Perlstein 		ret->xp_addrlen = sizeof (struct sockaddr_in);
2358360efbdSAlfred Perlstein 	}
2368360efbdSAlfred Perlstein #endif				/* PORTMAP */
2378360efbdSAlfred Perlstein 
2388360efbdSAlfred Perlstein 	return ret;
2398360efbdSAlfred Perlstein 
2408360efbdSAlfred Perlstein freedata:
2418360efbdSAlfred Perlstein 	if (ret->xp_ltaddr.buf != NULL)
2428360efbdSAlfred Perlstein 		mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen);
2438360efbdSAlfred Perlstein 
2448360efbdSAlfred Perlstein 	return NULL;
2458360efbdSAlfred Perlstein }
2468360efbdSAlfred Perlstein 
2478360efbdSAlfred Perlstein static SVCXPRT *
2488360efbdSAlfred Perlstein makefd_xprt(fd, sendsize, recvsize)
2498360efbdSAlfred Perlstein 	int fd;
2508360efbdSAlfred Perlstein 	u_int sendsize;
2518360efbdSAlfred Perlstein 	u_int recvsize;
2528360efbdSAlfred Perlstein {
2538360efbdSAlfred Perlstein 	SVCXPRT *xprt;
2548360efbdSAlfred Perlstein 	struct cf_conn *cd;
2558360efbdSAlfred Perlstein 	const char *netid;
2568360efbdSAlfred Perlstein 	struct __rpc_sockinfo si;
2578360efbdSAlfred Perlstein 
2588360efbdSAlfred Perlstein 	assert(fd != -1);
2598360efbdSAlfred Perlstein 
2608360efbdSAlfred Perlstein 	xprt = mem_alloc(sizeof(SVCXPRT));
2618360efbdSAlfred Perlstein 	if (xprt == NULL) {
2628360efbdSAlfred Perlstein 		warnx("svc_vc: makefd_xprt: out of memory");
2638360efbdSAlfred Perlstein 		goto done;
2648360efbdSAlfred Perlstein 	}
2658360efbdSAlfred Perlstein 	memset(xprt, 0, sizeof *xprt);
2668360efbdSAlfred Perlstein 	cd = mem_alloc(sizeof(struct cf_conn));
2678360efbdSAlfred Perlstein 	if (cd == NULL) {
2688360efbdSAlfred Perlstein 		warnx("svc_tcp: makefd_xprt: out of memory");
2698360efbdSAlfred Perlstein 		mem_free(xprt, sizeof(SVCXPRT));
2708360efbdSAlfred Perlstein 		xprt = NULL;
2718360efbdSAlfred Perlstein 		goto done;
2728360efbdSAlfred Perlstein 	}
2738360efbdSAlfred Perlstein 	cd->strm_stat = XPRT_IDLE;
2748360efbdSAlfred Perlstein 	xdrrec_create(&(cd->xdrs), sendsize, recvsize,
275f249dbccSDag-Erling Smørgrav 	    xprt, read_vc, write_vc);
276f249dbccSDag-Erling Smørgrav 	xprt->xp_p1 = cd;
2778360efbdSAlfred Perlstein 	xprt->xp_verf.oa_base = cd->verf_body;
2788360efbdSAlfred Perlstein 	svc_vc_ops(xprt);  /* truely deals with calls */
2798360efbdSAlfred Perlstein 	xprt->xp_port = 0;  /* this is a connection, not a rendezvouser */
2808360efbdSAlfred Perlstein 	xprt->xp_fd = fd;
2818360efbdSAlfred Perlstein         if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid))
2828360efbdSAlfred Perlstein 		xprt->xp_netid = strdup(netid);
2838360efbdSAlfred Perlstein 
2848360efbdSAlfred Perlstein 	xprt_register(xprt);
2858360efbdSAlfred Perlstein done:
2868360efbdSAlfred Perlstein 	return (xprt);
2878360efbdSAlfred Perlstein }
2888360efbdSAlfred Perlstein 
2898360efbdSAlfred Perlstein /*ARGSUSED*/
2908360efbdSAlfred Perlstein static bool_t
2918360efbdSAlfred Perlstein rendezvous_request(xprt, msg)
2928360efbdSAlfred Perlstein 	SVCXPRT *xprt;
2938360efbdSAlfred Perlstein 	struct rpc_msg *msg;
2948360efbdSAlfred Perlstein {
29508497c02SMartin Blapp 	int sock, flags;
2968360efbdSAlfred Perlstein 	struct cf_rendezvous *r;
29708497c02SMartin Blapp 	struct cf_conn *cd;
2988360efbdSAlfred Perlstein 	struct sockaddr_storage addr;
2998360efbdSAlfred Perlstein 	socklen_t len;
3008360efbdSAlfred Perlstein 	struct __rpc_sockinfo si;
30108497c02SMartin Blapp 	SVCXPRT *newxprt;
30208497c02SMartin Blapp 	fd_set cleanfds;
3038360efbdSAlfred Perlstein 
3048360efbdSAlfred Perlstein 	assert(xprt != NULL);
3058360efbdSAlfred Perlstein 	assert(msg != NULL);
3068360efbdSAlfred Perlstein 
3078360efbdSAlfred Perlstein 	r = (struct cf_rendezvous *)xprt->xp_p1;
3088360efbdSAlfred Perlstein again:
3098360efbdSAlfred Perlstein 	len = sizeof addr;
3108360efbdSAlfred Perlstein 	if ((sock = _accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr,
3118360efbdSAlfred Perlstein 	    &len)) < 0) {
3128360efbdSAlfred Perlstein 		if (errno == EINTR)
3138360efbdSAlfred Perlstein 			goto again;
31408497c02SMartin Blapp 		/*
31508497c02SMartin Blapp 		 * Clean out the most idle file descriptor when we're
31608497c02SMartin Blapp 		 * running out.
31708497c02SMartin Blapp 		 */
31808497c02SMartin Blapp 		if (errno == EMFILE || errno == ENFILE) {
31908497c02SMartin Blapp 			cleanfds = svc_fdset;
32008497c02SMartin Blapp 			__svc_clean_idle(&cleanfds, 0, FALSE);
32108497c02SMartin Blapp 			goto again;
32208497c02SMartin Blapp 		}
3238360efbdSAlfred Perlstein 		return (FALSE);
3248360efbdSAlfred Perlstein 	}
3258360efbdSAlfred Perlstein 	/*
3268360efbdSAlfred Perlstein 	 * make a new transporter (re-uses xprt)
3278360efbdSAlfred Perlstein 	 */
32808497c02SMartin Blapp 	newxprt = makefd_xprt(sock, r->sendsize, r->recvsize);
32908497c02SMartin Blapp 	newxprt->xp_rtaddr.buf = mem_alloc(len);
33008497c02SMartin Blapp 	if (newxprt->xp_rtaddr.buf == NULL)
3318360efbdSAlfred Perlstein 		return (FALSE);
33208497c02SMartin Blapp 	memcpy(newxprt->xp_rtaddr.buf, &addr, len);
33308497c02SMartin Blapp 	newxprt->xp_rtaddr.len = len;
3348360efbdSAlfred Perlstein #ifdef PORTMAP
335866e3c90SAlfred Perlstein 	if (addr.ss_family == AF_INET || addr.ss_family == AF_LOCAL) {
33608497c02SMartin Blapp 		newxprt->xp_raddr = *(struct sockaddr_in *)newxprt->xp_rtaddr.buf;
33708497c02SMartin Blapp 		newxprt->xp_addrlen = sizeof (struct sockaddr_in);
3388360efbdSAlfred Perlstein 	}
3398360efbdSAlfred Perlstein #endif				/* PORTMAP */
3408360efbdSAlfred Perlstein 	if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) {
3418360efbdSAlfred Perlstein 		len = 1;
3428360efbdSAlfred Perlstein 		/* XXX fvdl - is this useful? */
3438360efbdSAlfred Perlstein 		_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &len, sizeof (len));
3448360efbdSAlfred Perlstein 	}
34508497c02SMartin Blapp 
34608497c02SMartin Blapp 	cd = (struct cf_conn *)newxprt->xp_p1;
34708497c02SMartin Blapp 
34808497c02SMartin Blapp 	cd->recvsize = r->recvsize;
34908497c02SMartin Blapp 	cd->sendsize = r->sendsize;
35008497c02SMartin Blapp 	cd->maxrec = r->maxrec;
35108497c02SMartin Blapp 
35208497c02SMartin Blapp 	if (cd->maxrec != 0) {
3530ae0e1eaSMartin Blapp 		flags = _fcntl(sock, F_GETFL, 0);
35408497c02SMartin Blapp 		if (flags  == -1)
35508497c02SMartin Blapp 			return (FALSE);
3560ae0e1eaSMartin Blapp 		if (_fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
35708497c02SMartin Blapp 			return (FALSE);
35808497c02SMartin Blapp 		if (cd->recvsize > cd->maxrec)
35908497c02SMartin Blapp 			cd->recvsize = cd->maxrec;
36008497c02SMartin Blapp 		cd->nonblock = TRUE;
36108497c02SMartin Blapp 		__xdrrec_setnonblock(&cd->xdrs, cd->maxrec);
36208497c02SMartin Blapp 	} else
36308497c02SMartin Blapp 		cd->nonblock = FALSE;
36408497c02SMartin Blapp 
36508497c02SMartin Blapp 	gettimeofday(&cd->last_recv_time, NULL);
36608497c02SMartin Blapp 
3678360efbdSAlfred Perlstein 	return (FALSE); /* there is never an rpc msg to be processed */
3688360efbdSAlfred Perlstein }
3698360efbdSAlfred Perlstein 
3708360efbdSAlfred Perlstein /*ARGSUSED*/
3718360efbdSAlfred Perlstein static enum xprt_stat
3728360efbdSAlfred Perlstein rendezvous_stat(xprt)
3738360efbdSAlfred Perlstein 	SVCXPRT *xprt;
3748360efbdSAlfred Perlstein {
3758360efbdSAlfred Perlstein 
3768360efbdSAlfred Perlstein 	return (XPRT_IDLE);
3778360efbdSAlfred Perlstein }
3788360efbdSAlfred Perlstein 
3798360efbdSAlfred Perlstein static void
3808360efbdSAlfred Perlstein svc_vc_destroy(xprt)
3818360efbdSAlfred Perlstein 	SVCXPRT *xprt;
3828360efbdSAlfred Perlstein {
38308497c02SMartin Blapp 	assert(xprt != NULL);
38408497c02SMartin Blapp 
38508497c02SMartin Blapp 	xprt_unregister(xprt);
38608497c02SMartin Blapp 	__svc_vc_dodestroy(xprt);
38708497c02SMartin Blapp }
38808497c02SMartin Blapp 
38908497c02SMartin Blapp static void
39008497c02SMartin Blapp __svc_vc_dodestroy(xprt)
39108497c02SMartin Blapp 	SVCXPRT *xprt;
39208497c02SMartin Blapp {
3938360efbdSAlfred Perlstein 	struct cf_conn *cd;
3948360efbdSAlfred Perlstein 	struct cf_rendezvous *r;
3958360efbdSAlfred Perlstein 
3968360efbdSAlfred Perlstein 	cd = (struct cf_conn *)xprt->xp_p1;
3978360efbdSAlfred Perlstein 
3988360efbdSAlfred Perlstein 	if (xprt->xp_fd != RPC_ANYFD)
3998360efbdSAlfred Perlstein 		(void)_close(xprt->xp_fd);
4008360efbdSAlfred Perlstein 	if (xprt->xp_port != 0) {
4018360efbdSAlfred Perlstein 		/* a rendezvouser socket */
4028360efbdSAlfred Perlstein 		r = (struct cf_rendezvous *)xprt->xp_p1;
4038360efbdSAlfred Perlstein 		mem_free(r, sizeof (struct cf_rendezvous));
4048360efbdSAlfred Perlstein 		xprt->xp_port = 0;
4058360efbdSAlfred Perlstein 	} else {
4068360efbdSAlfred Perlstein 		/* an actual connection socket */
4078360efbdSAlfred Perlstein 		XDR_DESTROY(&(cd->xdrs));
4088360efbdSAlfred Perlstein 		mem_free(cd, sizeof(struct cf_conn));
4098360efbdSAlfred Perlstein 	}
4108360efbdSAlfred Perlstein 	if (xprt->xp_rtaddr.buf)
4118360efbdSAlfred Perlstein 		mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen);
4128360efbdSAlfred Perlstein 	if (xprt->xp_ltaddr.buf)
4138360efbdSAlfred Perlstein 		mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen);
4148360efbdSAlfred Perlstein 	if (xprt->xp_tp)
4158360efbdSAlfred Perlstein 		free(xprt->xp_tp);
4168360efbdSAlfred Perlstein 	if (xprt->xp_netid)
4178360efbdSAlfred Perlstein 		free(xprt->xp_netid);
4188360efbdSAlfred Perlstein 	mem_free(xprt, sizeof(SVCXPRT));
4198360efbdSAlfred Perlstein }
4208360efbdSAlfred Perlstein 
4218360efbdSAlfred Perlstein /*ARGSUSED*/
4228360efbdSAlfred Perlstein static bool_t
4238360efbdSAlfred Perlstein svc_vc_control(xprt, rq, in)
4248360efbdSAlfred Perlstein 	SVCXPRT *xprt;
4258360efbdSAlfred Perlstein 	const u_int rq;
4268360efbdSAlfred Perlstein 	void *in;
4278360efbdSAlfred Perlstein {
4288360efbdSAlfred Perlstein 	return (FALSE);
4298360efbdSAlfred Perlstein }
4308360efbdSAlfred Perlstein 
43108497c02SMartin Blapp static bool_t
43208497c02SMartin Blapp svc_vc_rendezvous_control(xprt, rq, in)
43308497c02SMartin Blapp 	SVCXPRT *xprt;
43408497c02SMartin Blapp 	const u_int rq;
43508497c02SMartin Blapp 	void *in;
43608497c02SMartin Blapp {
43708497c02SMartin Blapp 	struct cf_rendezvous *cfp;
43808497c02SMartin Blapp 
43908497c02SMartin Blapp 	cfp = (struct cf_rendezvous *)xprt->xp_p1;
44008497c02SMartin Blapp 	if (cfp == NULL)
44108497c02SMartin Blapp 		return (FALSE);
44208497c02SMartin Blapp 	switch (rq) {
44308497c02SMartin Blapp 		case SVCGET_CONNMAXREC:
44408497c02SMartin Blapp 			*(int *)in = cfp->maxrec;
44508497c02SMartin Blapp 			break;
44608497c02SMartin Blapp 		case SVCSET_CONNMAXREC:
44708497c02SMartin Blapp 			cfp->maxrec = *(int *)in;
44808497c02SMartin Blapp 			break;
44908497c02SMartin Blapp 		default:
45008497c02SMartin Blapp 			return (FALSE);
45108497c02SMartin Blapp 	}
45208497c02SMartin Blapp 	return (TRUE);
45308497c02SMartin Blapp }
45408497c02SMartin Blapp 
4558360efbdSAlfred Perlstein /*
4568360efbdSAlfred Perlstein  * reads data from the tcp or uip connection.
4578360efbdSAlfred Perlstein  * any error is fatal and the connection is closed.
4588360efbdSAlfred Perlstein  * (And a read of zero bytes is a half closed stream => error.)
4598360efbdSAlfred Perlstein  * All read operations timeout after 35 seconds.  A timeout is
4608360efbdSAlfred Perlstein  * fatal for the connection.
4618360efbdSAlfred Perlstein  */
4628360efbdSAlfred Perlstein static int
4638360efbdSAlfred Perlstein read_vc(xprtp, buf, len)
464f249dbccSDag-Erling Smørgrav 	void *xprtp;
465f249dbccSDag-Erling Smørgrav 	void *buf;
4668360efbdSAlfred Perlstein 	int len;
4678360efbdSAlfred Perlstein {
4688360efbdSAlfred Perlstein 	SVCXPRT *xprt;
4698360efbdSAlfred Perlstein 	int sock;
4708360efbdSAlfred Perlstein 	int milliseconds = 35 * 1000;
4718360efbdSAlfred Perlstein 	struct pollfd pollfd;
47208497c02SMartin Blapp 	struct cf_conn *cfp;
4738360efbdSAlfred Perlstein 
474f249dbccSDag-Erling Smørgrav 	xprt = (SVCXPRT *)xprtp;
4758360efbdSAlfred Perlstein 	assert(xprt != NULL);
4768360efbdSAlfred Perlstein 
4778360efbdSAlfred Perlstein 	sock = xprt->xp_fd;
4788360efbdSAlfred Perlstein 
47908497c02SMartin Blapp 	cfp = (struct cf_conn *)xprt->xp_p1;
48008497c02SMartin Blapp 
48108497c02SMartin Blapp 	if (cfp->nonblock) {
4820ae0e1eaSMartin Blapp 		len = _read(sock, buf, (size_t)len);
48308497c02SMartin Blapp 		if (len < 0) {
48408497c02SMartin Blapp 			if (errno == EAGAIN)
48508497c02SMartin Blapp 				len = 0;
48608497c02SMartin Blapp 			else
48708497c02SMartin Blapp 				goto fatal_err;
48808497c02SMartin Blapp 		}
48908497c02SMartin Blapp 		if (len != 0)
49008497c02SMartin Blapp 			gettimeofday(&cfp->last_recv_time, NULL);
49108497c02SMartin Blapp 		return len;
49208497c02SMartin Blapp 	}
49308497c02SMartin Blapp 
4948360efbdSAlfred Perlstein 	do {
4958360efbdSAlfred Perlstein 		pollfd.fd = sock;
4968360efbdSAlfred Perlstein 		pollfd.events = POLLIN;
4978360efbdSAlfred Perlstein 		pollfd.revents = 0;
4988360efbdSAlfred Perlstein 		switch (_poll(&pollfd, 1, milliseconds)) {
4998360efbdSAlfred Perlstein 		case -1:
500fa87b7eaSAlfred Perlstein 			if (errno == EINTR)
5018360efbdSAlfred Perlstein 				continue;
5028360efbdSAlfred Perlstein 			/*FALLTHROUGH*/
5038360efbdSAlfred Perlstein 		case 0:
5048360efbdSAlfred Perlstein 			goto fatal_err;
5054ed6d634SAlfred Perlstein 
5068360efbdSAlfred Perlstein 		default:
5078360efbdSAlfred Perlstein 			break;
5088360efbdSAlfred Perlstein 		}
5098360efbdSAlfred Perlstein 	} while ((pollfd.revents & POLLIN) == 0);
5108360efbdSAlfred Perlstein 
5110ae0e1eaSMartin Blapp 	if ((len = _read(sock, buf, (size_t)len)) > 0) {
51208497c02SMartin Blapp 		gettimeofday(&cfp->last_recv_time, NULL);
5138360efbdSAlfred Perlstein 		return (len);
5148360efbdSAlfred Perlstein 	}
5158360efbdSAlfred Perlstein 
5168360efbdSAlfred Perlstein fatal_err:
5178360efbdSAlfred Perlstein 	((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
5188360efbdSAlfred Perlstein 	return (-1);
5198360efbdSAlfred Perlstein }
5208360efbdSAlfred Perlstein 
5218360efbdSAlfred Perlstein /*
5228360efbdSAlfred Perlstein  * writes data to the tcp connection.
5238360efbdSAlfred Perlstein  * Any error is fatal and the connection is closed.
5248360efbdSAlfred Perlstein  */
5258360efbdSAlfred Perlstein static int
5268360efbdSAlfred Perlstein write_vc(xprtp, buf, len)
527f249dbccSDag-Erling Smørgrav 	void *xprtp;
528f249dbccSDag-Erling Smørgrav 	void *buf;
5298360efbdSAlfred Perlstein 	int len;
5308360efbdSAlfred Perlstein {
5318360efbdSAlfred Perlstein 	SVCXPRT *xprt;
5328360efbdSAlfred Perlstein 	int i, cnt;
53308497c02SMartin Blapp 	struct cf_conn *cd;
53408497c02SMartin Blapp 	struct timeval tv0, tv1;
5358360efbdSAlfred Perlstein 
536f249dbccSDag-Erling Smørgrav 	xprt = (SVCXPRT *)xprtp;
5378360efbdSAlfred Perlstein 	assert(xprt != NULL);
5388360efbdSAlfred Perlstein 
53908497c02SMartin Blapp 	cd = (struct cf_conn *)xprt->xp_p1;
54008497c02SMartin Blapp 
54108497c02SMartin Blapp 	if (cd->nonblock)
54208497c02SMartin Blapp 		gettimeofday(&tv0, NULL);
54308497c02SMartin Blapp 
544361de173SStefan Farfeleder 	for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) {
54508497c02SMartin Blapp 		i = _write(xprt->xp_fd, buf, (size_t)cnt);
54608497c02SMartin Blapp 		if (i  < 0) {
54708497c02SMartin Blapp 			if (errno != EAGAIN || !cd->nonblock) {
54808497c02SMartin Blapp 				cd->strm_stat = XPRT_DIED;
5498360efbdSAlfred Perlstein 				return (-1);
5508360efbdSAlfred Perlstein 			}
55108497c02SMartin Blapp 			if (cd->nonblock && i != cnt) {
55208497c02SMartin Blapp 				/*
55308497c02SMartin Blapp 				 * For non-blocking connections, do not
55408497c02SMartin Blapp 				 * take more than 2 seconds writing the
55508497c02SMartin Blapp 				 * data out.
55608497c02SMartin Blapp 				 *
55708497c02SMartin Blapp 				 * XXX 2 is an arbitrary amount.
55808497c02SMartin Blapp 				 */
55908497c02SMartin Blapp 				gettimeofday(&tv1, NULL);
56008497c02SMartin Blapp 				if (tv1.tv_sec - tv0.tv_sec >= 2) {
56108497c02SMartin Blapp 					cd->strm_stat = XPRT_DIED;
5628360efbdSAlfred Perlstein 					return (-1);
5638360efbdSAlfred Perlstein 				}
5648360efbdSAlfred Perlstein 			}
5658360efbdSAlfred Perlstein 		}
56608497c02SMartin Blapp 	}
5678360efbdSAlfred Perlstein 
5688360efbdSAlfred Perlstein 	return (len);
5698360efbdSAlfred Perlstein }
5708360efbdSAlfred Perlstein 
5718360efbdSAlfred Perlstein static enum xprt_stat
5728360efbdSAlfred Perlstein svc_vc_stat(xprt)
5738360efbdSAlfred Perlstein 	SVCXPRT *xprt;
5748360efbdSAlfred Perlstein {
5758360efbdSAlfred Perlstein 	struct cf_conn *cd;
5768360efbdSAlfred Perlstein 
5778360efbdSAlfred Perlstein 	assert(xprt != NULL);
5788360efbdSAlfred Perlstein 
5798360efbdSAlfred Perlstein 	cd = (struct cf_conn *)(xprt->xp_p1);
5808360efbdSAlfred Perlstein 
5818360efbdSAlfred Perlstein 	if (cd->strm_stat == XPRT_DIED)
5828360efbdSAlfred Perlstein 		return (XPRT_DIED);
5838360efbdSAlfred Perlstein 	if (! xdrrec_eof(&(cd->xdrs)))
5848360efbdSAlfred Perlstein 		return (XPRT_MOREREQS);
5858360efbdSAlfred Perlstein 	return (XPRT_IDLE);
5868360efbdSAlfred Perlstein }
5878360efbdSAlfred Perlstein 
5888360efbdSAlfred Perlstein static bool_t
5898360efbdSAlfred Perlstein svc_vc_recv(xprt, msg)
5908360efbdSAlfred Perlstein 	SVCXPRT *xprt;
5918360efbdSAlfred Perlstein 	struct rpc_msg *msg;
5928360efbdSAlfred Perlstein {
5938360efbdSAlfred Perlstein 	struct cf_conn *cd;
5948360efbdSAlfred Perlstein 	XDR *xdrs;
5958360efbdSAlfred Perlstein 
5968360efbdSAlfred Perlstein 	assert(xprt != NULL);
5978360efbdSAlfred Perlstein 	assert(msg != NULL);
5988360efbdSAlfred Perlstein 
5998360efbdSAlfred Perlstein 	cd = (struct cf_conn *)(xprt->xp_p1);
6008360efbdSAlfred Perlstein 	xdrs = &(cd->xdrs);
6018360efbdSAlfred Perlstein 
60208497c02SMartin Blapp 	if (cd->nonblock) {
60308497c02SMartin Blapp 		if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE))
60408497c02SMartin Blapp 			return FALSE;
60508497c02SMartin Blapp 	}
60608497c02SMartin Blapp 
6078360efbdSAlfred Perlstein 	xdrs->x_op = XDR_DECODE;
6088360efbdSAlfred Perlstein 	(void)xdrrec_skiprecord(xdrs);
6098360efbdSAlfred Perlstein 	if (xdr_callmsg(xdrs, msg)) {
6108360efbdSAlfred Perlstein 		cd->x_id = msg->rm_xid;
6118360efbdSAlfred Perlstein 		return (TRUE);
6128360efbdSAlfred Perlstein 	}
6138360efbdSAlfred Perlstein 	cd->strm_stat = XPRT_DIED;
6148360efbdSAlfred Perlstein 	return (FALSE);
6158360efbdSAlfred Perlstein }
6168360efbdSAlfred Perlstein 
6178360efbdSAlfred Perlstein static bool_t
6188360efbdSAlfred Perlstein svc_vc_getargs(xprt, xdr_args, args_ptr)
6198360efbdSAlfred Perlstein 	SVCXPRT *xprt;
6208360efbdSAlfred Perlstein 	xdrproc_t xdr_args;
621f249dbccSDag-Erling Smørgrav 	void *args_ptr;
6228360efbdSAlfred Perlstein {
6238360efbdSAlfred Perlstein 
6248360efbdSAlfred Perlstein 	assert(xprt != NULL);
6258360efbdSAlfred Perlstein 	/* args_ptr may be NULL */
6268360efbdSAlfred Perlstein 	return ((*xdr_args)(&(((struct cf_conn *)(xprt->xp_p1))->xdrs),
6278360efbdSAlfred Perlstein 	    args_ptr));
6288360efbdSAlfred Perlstein }
6298360efbdSAlfred Perlstein 
6308360efbdSAlfred Perlstein static bool_t
6318360efbdSAlfred Perlstein svc_vc_freeargs(xprt, xdr_args, args_ptr)
6328360efbdSAlfred Perlstein 	SVCXPRT *xprt;
6338360efbdSAlfred Perlstein 	xdrproc_t xdr_args;
634f249dbccSDag-Erling Smørgrav 	void *args_ptr;
6358360efbdSAlfred Perlstein {
6368360efbdSAlfred Perlstein 	XDR *xdrs;
6378360efbdSAlfred Perlstein 
6388360efbdSAlfred Perlstein 	assert(xprt != NULL);
6398360efbdSAlfred Perlstein 	/* args_ptr may be NULL */
6408360efbdSAlfred Perlstein 
6418360efbdSAlfred Perlstein 	xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs);
6428360efbdSAlfred Perlstein 
6438360efbdSAlfred Perlstein 	xdrs->x_op = XDR_FREE;
6448360efbdSAlfred Perlstein 	return ((*xdr_args)(xdrs, args_ptr));
6458360efbdSAlfred Perlstein }
6468360efbdSAlfred Perlstein 
6478360efbdSAlfred Perlstein static bool_t
6488360efbdSAlfred Perlstein svc_vc_reply(xprt, msg)
6498360efbdSAlfred Perlstein 	SVCXPRT *xprt;
6508360efbdSAlfred Perlstein 	struct rpc_msg *msg;
6518360efbdSAlfred Perlstein {
6528360efbdSAlfred Perlstein 	struct cf_conn *cd;
6538360efbdSAlfred Perlstein 	XDR *xdrs;
65408497c02SMartin Blapp 	bool_t rstat;
6558360efbdSAlfred Perlstein 
6568360efbdSAlfred Perlstein 	assert(xprt != NULL);
6578360efbdSAlfred Perlstein 	assert(msg != NULL);
6588360efbdSAlfred Perlstein 
6598360efbdSAlfred Perlstein 	cd = (struct cf_conn *)(xprt->xp_p1);
6608360efbdSAlfred Perlstein 	xdrs = &(cd->xdrs);
6618360efbdSAlfred Perlstein 
6628360efbdSAlfred Perlstein 	xdrs->x_op = XDR_ENCODE;
6638360efbdSAlfred Perlstein 	msg->rm_xid = cd->x_id;
66408497c02SMartin Blapp 	rstat = xdr_replymsg(xdrs, msg);
6658360efbdSAlfred Perlstein 	(void)xdrrec_endofrecord(xdrs, TRUE);
66608497c02SMartin Blapp 	return (rstat);
6678360efbdSAlfred Perlstein }
6688360efbdSAlfred Perlstein 
6698360efbdSAlfred Perlstein static void
6708360efbdSAlfred Perlstein svc_vc_ops(xprt)
6718360efbdSAlfred Perlstein 	SVCXPRT *xprt;
6728360efbdSAlfred Perlstein {
6738360efbdSAlfred Perlstein 	static struct xp_ops ops;
6748360efbdSAlfred Perlstein 	static struct xp_ops2 ops2;
6758360efbdSAlfred Perlstein 	extern mutex_t ops_lock;
6768360efbdSAlfred Perlstein 
6778360efbdSAlfred Perlstein /* VARIABLES PROTECTED BY ops_lock: ops, ops2 */
6788360efbdSAlfred Perlstein 
6798360efbdSAlfred Perlstein 	mutex_lock(&ops_lock);
6808360efbdSAlfred Perlstein 	if (ops.xp_recv == NULL) {
6818360efbdSAlfred Perlstein 		ops.xp_recv = svc_vc_recv;
6828360efbdSAlfred Perlstein 		ops.xp_stat = svc_vc_stat;
6838360efbdSAlfred Perlstein 		ops.xp_getargs = svc_vc_getargs;
6848360efbdSAlfred Perlstein 		ops.xp_reply = svc_vc_reply;
6858360efbdSAlfred Perlstein 		ops.xp_freeargs = svc_vc_freeargs;
6868360efbdSAlfred Perlstein 		ops.xp_destroy = svc_vc_destroy;
6878360efbdSAlfred Perlstein 		ops2.xp_control = svc_vc_control;
6888360efbdSAlfred Perlstein 	}
6898360efbdSAlfred Perlstein 	xprt->xp_ops = &ops;
6908360efbdSAlfred Perlstein 	xprt->xp_ops2 = &ops2;
6918360efbdSAlfred Perlstein 	mutex_unlock(&ops_lock);
6928360efbdSAlfred Perlstein }
6938360efbdSAlfred Perlstein 
6948360efbdSAlfred Perlstein static void
6958360efbdSAlfred Perlstein svc_vc_rendezvous_ops(xprt)
6968360efbdSAlfred Perlstein 	SVCXPRT *xprt;
6978360efbdSAlfred Perlstein {
6988360efbdSAlfred Perlstein 	static struct xp_ops ops;
6998360efbdSAlfred Perlstein 	static struct xp_ops2 ops2;
7008360efbdSAlfred Perlstein 	extern mutex_t ops_lock;
7018360efbdSAlfred Perlstein 
7028360efbdSAlfred Perlstein 	mutex_lock(&ops_lock);
7038360efbdSAlfred Perlstein 	if (ops.xp_recv == NULL) {
7048360efbdSAlfred Perlstein 		ops.xp_recv = rendezvous_request;
7058360efbdSAlfred Perlstein 		ops.xp_stat = rendezvous_stat;
7068360efbdSAlfred Perlstein 		ops.xp_getargs =
707f249dbccSDag-Erling Smørgrav 		    (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort;
7088360efbdSAlfred Perlstein 		ops.xp_reply =
7091372519bSDavid E. O'Brien 		    (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort;
7108360efbdSAlfred Perlstein 		ops.xp_freeargs =
711f249dbccSDag-Erling Smørgrav 		    (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort,
7128360efbdSAlfred Perlstein 		ops.xp_destroy = svc_vc_destroy;
71308497c02SMartin Blapp 		ops2.xp_control = svc_vc_rendezvous_control;
7148360efbdSAlfred Perlstein 	}
7158360efbdSAlfred Perlstein 	xprt->xp_ops = &ops;
7168360efbdSAlfred Perlstein 	xprt->xp_ops2 = &ops2;
7178360efbdSAlfred Perlstein 	mutex_unlock(&ops_lock);
7188360efbdSAlfred Perlstein }
7198360efbdSAlfred Perlstein 
7204ed6d634SAlfred Perlstein /*
721ce9bc43cSMartin Blapp  * Get the effective UID of the sending process. Used by rpcbind, keyserv
722ce9bc43cSMartin Blapp  * and rpc.yppasswdd on AF_LOCAL.
7234ed6d634SAlfred Perlstein  */
7244ed6d634SAlfred Perlstein int
725ce9bc43cSMartin Blapp __rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) {
726ce9bc43cSMartin Blapp 	int sock, ret;
727ce9bc43cSMartin Blapp 	gid_t egid;
728ce9bc43cSMartin Blapp 	uid_t euid;
729ce9bc43cSMartin Blapp 	struct sockaddr *sa;
73008760d5aSAlfred Perlstein 
731ce9bc43cSMartin Blapp 	sock = transp->xp_fd;
732ce9bc43cSMartin Blapp 	sa = (struct sockaddr *)transp->xp_rtaddr.buf;
733ce9bc43cSMartin Blapp 	if (sa->sa_family == AF_LOCAL) {
734ce9bc43cSMartin Blapp 		ret = getpeereid(sock, &euid, &egid);
735ce9bc43cSMartin Blapp 		if (ret == 0)
736ce9bc43cSMartin Blapp 			*uid = euid;
737ce9bc43cSMartin Blapp 		return (ret);
738ce9bc43cSMartin Blapp 	} else
73908760d5aSAlfred Perlstein 		return (-1);
7404ed6d634SAlfred Perlstein }
74108497c02SMartin Blapp 
74208497c02SMartin Blapp /*
74308497c02SMartin Blapp  * Destroy xprts that have not have had any activity in 'timeout' seconds.
74408497c02SMartin Blapp  * If 'cleanblock' is true, blocking connections (the default) are also
74508497c02SMartin Blapp  * cleaned. If timeout is 0, the least active connection is picked.
74608497c02SMartin Blapp  */
74708497c02SMartin Blapp bool_t
74808497c02SMartin Blapp __svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock)
74908497c02SMartin Blapp {
75008497c02SMartin Blapp 	int i, ncleaned;
75108497c02SMartin Blapp 	SVCXPRT *xprt, *least_active;
75208497c02SMartin Blapp 	struct timeval tv, tdiff, tmax;
75308497c02SMartin Blapp 	struct cf_conn *cd;
75408497c02SMartin Blapp 
75508497c02SMartin Blapp 	gettimeofday(&tv, NULL);
75608497c02SMartin Blapp 	tmax.tv_sec = tmax.tv_usec = 0;
75708497c02SMartin Blapp 	least_active = NULL;
75808497c02SMartin Blapp 	rwlock_wrlock(&svc_fd_lock);
75908497c02SMartin Blapp 	for (i = ncleaned = 0; i <= svc_maxfd; i++) {
76008497c02SMartin Blapp 		if (FD_ISSET(i, fds)) {
76108497c02SMartin Blapp 			xprt = __svc_xports[i];
76208497c02SMartin Blapp 			if (xprt == NULL || xprt->xp_ops == NULL ||
76308497c02SMartin Blapp 			    xprt->xp_ops->xp_recv != svc_vc_recv)
76408497c02SMartin Blapp 				continue;
76508497c02SMartin Blapp 			cd = (struct cf_conn *)xprt->xp_p1;
76608497c02SMartin Blapp 			if (!cleanblock && !cd->nonblock)
76708497c02SMartin Blapp 				continue;
76808497c02SMartin Blapp 			if (timeout == 0) {
76908497c02SMartin Blapp 				timersub(&tv, &cd->last_recv_time, &tdiff);
77008497c02SMartin Blapp 				if (timercmp(&tdiff, &tmax, >)) {
77108497c02SMartin Blapp 					tmax = tdiff;
77208497c02SMartin Blapp 					least_active = xprt;
77308497c02SMartin Blapp 				}
77408497c02SMartin Blapp 				continue;
77508497c02SMartin Blapp 			}
77608497c02SMartin Blapp 			if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) {
77708497c02SMartin Blapp 				__xprt_unregister_unlocked(xprt);
77808497c02SMartin Blapp 				__svc_vc_dodestroy(xprt);
77908497c02SMartin Blapp 				ncleaned++;
78008497c02SMartin Blapp 			}
78108497c02SMartin Blapp 		}
78208497c02SMartin Blapp 	}
78308497c02SMartin Blapp 	if (timeout == 0 && least_active != NULL) {
78408497c02SMartin Blapp 		__xprt_unregister_unlocked(least_active);
78508497c02SMartin Blapp 		__svc_vc_dodestroy(least_active);
78608497c02SMartin Blapp 		ncleaned++;
78708497c02SMartin Blapp 	}
78808497c02SMartin Blapp 	rwlock_unlock(&svc_fd_lock);
78908497c02SMartin Blapp 	return ncleaned > 0 ? TRUE : FALSE;
79008497c02SMartin Blapp }
791