xref: /freebsd/lib/libc/rpc/svc_vc.c (revision 5eff94ee5676666a12c68ca18366cf379928d2cd)
18360efbdSAlfred Perlstein /*	$NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $	*/
28360efbdSAlfred Perlstein 
32e322d37SHiroki Sato /*-
42e322d37SHiroki Sato  * Copyright (c) 2009, Sun Microsystems, Inc.
52e322d37SHiroki Sato  * All rights reserved.
68360efbdSAlfred Perlstein  *
72e322d37SHiroki Sato  * Redistribution and use in source and binary forms, with or without
82e322d37SHiroki Sato  * modification, are permitted provided that the following conditions are met:
92e322d37SHiroki Sato  * - Redistributions of source code must retain the above copyright notice,
102e322d37SHiroki Sato  *   this list of conditions and the following disclaimer.
112e322d37SHiroki Sato  * - Redistributions in binary form must reproduce the above copyright notice,
122e322d37SHiroki Sato  *   this list of conditions and the following disclaimer in the documentation
132e322d37SHiroki Sato  *   and/or other materials provided with the distribution.
142e322d37SHiroki Sato  * - Neither the name of Sun Microsystems, Inc. nor the names of its
152e322d37SHiroki Sato  *   contributors may be used to endorse or promote products derived
162e322d37SHiroki Sato  *   from this software without specific prior written permission.
178360efbdSAlfred Perlstein  *
182e322d37SHiroki Sato  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
192e322d37SHiroki Sato  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
202e322d37SHiroki Sato  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
212e322d37SHiroki Sato  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
222e322d37SHiroki Sato  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
232e322d37SHiroki Sato  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
242e322d37SHiroki Sato  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
252e322d37SHiroki Sato  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
262e322d37SHiroki Sato  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
272e322d37SHiroki Sato  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
282e322d37SHiroki Sato  * POSSIBILITY OF SUCH DAMAGE.
298360efbdSAlfred Perlstein  */
308360efbdSAlfred Perlstein 
318360efbdSAlfred Perlstein #if defined(LIBC_SCCS) && !defined(lint)
32a986ef57SDavid E. O'Brien static char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
338360efbdSAlfred Perlstein static char *sccsid = "@(#)svc_tcp.c	2.2 88/08/01 4.0 RPCSRC";
348360efbdSAlfred Perlstein #endif
35d3d20c82SDavid E. O'Brien #include <sys/cdefs.h>
36d3d20c82SDavid E. O'Brien __FBSDID("$FreeBSD$");
378360efbdSAlfred Perlstein 
388360efbdSAlfred Perlstein /*
398360efbdSAlfred Perlstein  * svc_vc.c, Server side for Connection Oriented based RPC.
408360efbdSAlfred Perlstein  *
418360efbdSAlfred Perlstein  * Actually implements two flavors of transporter -
428360efbdSAlfred Perlstein  * a tcp rendezvouser (a listner and connection establisher)
438360efbdSAlfred Perlstein  * and a record/tcp stream.
448360efbdSAlfred Perlstein  */
458360efbdSAlfred Perlstein 
468360efbdSAlfred Perlstein #include "namespace.h"
479f5afc13SIan Dowse #include "reentrant.h"
488360efbdSAlfred Perlstein #include <sys/types.h>
498360efbdSAlfred Perlstein #include <sys/param.h>
508360efbdSAlfred Perlstein #include <sys/poll.h>
518360efbdSAlfred Perlstein #include <sys/socket.h>
528360efbdSAlfred Perlstein #include <sys/un.h>
5308497c02SMartin Blapp #include <sys/time.h>
548360efbdSAlfred Perlstein #include <sys/uio.h>
558360efbdSAlfred Perlstein #include <netinet/in.h>
568360efbdSAlfred Perlstein #include <netinet/tcp.h>
578360efbdSAlfred Perlstein 
588360efbdSAlfred Perlstein #include <assert.h>
598360efbdSAlfred Perlstein #include <err.h>
608360efbdSAlfred Perlstein #include <errno.h>
6108497c02SMartin Blapp #include <fcntl.h>
628360efbdSAlfred Perlstein #include <stdio.h>
638360efbdSAlfred Perlstein #include <stdlib.h>
648360efbdSAlfred Perlstein #include <string.h>
658360efbdSAlfred Perlstein #include <unistd.h>
668360efbdSAlfred Perlstein 
678360efbdSAlfred Perlstein #include <rpc/rpc.h>
688360efbdSAlfred Perlstein 
698360efbdSAlfred Perlstein #include "rpc_com.h"
70235baf26SDaniel Eischen #include "mt_misc.h"
718360efbdSAlfred Perlstein #include "un-namespace.h"
728360efbdSAlfred Perlstein 
73c05ac53bSDavid E. O'Brien static SVCXPRT *makefd_xprt(int, u_int, u_int);
74c05ac53bSDavid E. O'Brien static bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *);
75c05ac53bSDavid E. O'Brien static enum xprt_stat rendezvous_stat(SVCXPRT *);
76c05ac53bSDavid E. O'Brien static void svc_vc_destroy(SVCXPRT *);
7708497c02SMartin Blapp static void __svc_vc_dodestroy (SVCXPRT *);
78f249dbccSDag-Erling Smørgrav static int read_vc(void *, void *, int);
79f249dbccSDag-Erling Smørgrav static int write_vc(void *, void *, int);
80c05ac53bSDavid E. O'Brien static enum xprt_stat svc_vc_stat(SVCXPRT *);
81c05ac53bSDavid E. O'Brien static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *);
82f249dbccSDag-Erling Smørgrav static bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, void *);
83f249dbccSDag-Erling Smørgrav static bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, void *);
84c05ac53bSDavid E. O'Brien static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *);
85c05ac53bSDavid E. O'Brien static void svc_vc_rendezvous_ops(SVCXPRT *);
86c05ac53bSDavid E. O'Brien static void svc_vc_ops(SVCXPRT *);
87c05ac53bSDavid E. O'Brien static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in);
8808497c02SMartin Blapp static bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq,
8908497c02SMartin Blapp 				   	     void *in);
908360efbdSAlfred Perlstein 
918360efbdSAlfred Perlstein struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */
928360efbdSAlfred Perlstein 	u_int sendsize;
938360efbdSAlfred Perlstein 	u_int recvsize;
9408497c02SMartin Blapp 	int maxrec;
958360efbdSAlfred Perlstein };
968360efbdSAlfred Perlstein 
978360efbdSAlfred Perlstein struct cf_conn {  /* kept in xprt->xp_p1 for actual connection */
988360efbdSAlfred Perlstein 	enum xprt_stat strm_stat;
998360efbdSAlfred Perlstein 	u_int32_t x_id;
1008360efbdSAlfred Perlstein 	XDR xdrs;
1018360efbdSAlfred Perlstein 	char verf_body[MAX_AUTH_BYTES];
10208497c02SMartin Blapp 	u_int sendsize;
10308497c02SMartin Blapp 	u_int recvsize;
10408497c02SMartin Blapp 	int maxrec;
10508497c02SMartin Blapp 	bool_t nonblock;
10608497c02SMartin Blapp 	struct timeval last_recv_time;
1078360efbdSAlfred Perlstein };
1088360efbdSAlfred Perlstein 
1098360efbdSAlfred Perlstein /*
1108360efbdSAlfred Perlstein  * Usage:
1118360efbdSAlfred Perlstein  *	xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
1128360efbdSAlfred Perlstein  *
1138360efbdSAlfred Perlstein  * Creates, registers, and returns a (rpc) tcp based transporter.
1148360efbdSAlfred Perlstein  * Once *xprt is initialized, it is registered as a transporter
1158360efbdSAlfred Perlstein  * see (svc.h, xprt_register).  This routine returns
1168360efbdSAlfred Perlstein  * a NULL if a problem occurred.
1178360efbdSAlfred Perlstein  *
1188360efbdSAlfred Perlstein  * The filedescriptor passed in is expected to refer to a bound, but
1198360efbdSAlfred Perlstein  * not yet connected socket.
1208360efbdSAlfred Perlstein  *
1218360efbdSAlfred Perlstein  * Since streams do buffered io similar to stdio, the caller can specify
1228360efbdSAlfred Perlstein  * how big the send and receive buffers are via the second and third parms;
1238360efbdSAlfred Perlstein  * 0 => use the system default.
1248360efbdSAlfred Perlstein  */
1258360efbdSAlfred Perlstein SVCXPRT *
12668895e38SCraig Rodrigues svc_vc_create(int fd, u_int sendsize, u_int recvsize)
1278360efbdSAlfred Perlstein {
128e742fdffSPedro F. Giffuni 	SVCXPRT *xprt = NULL;
1298360efbdSAlfred Perlstein 	struct cf_rendezvous *r = NULL;
1308360efbdSAlfred Perlstein 	struct __rpc_sockinfo si;
1318360efbdSAlfred Perlstein 	struct sockaddr_storage sslocal;
1328360efbdSAlfred Perlstein 	socklen_t slen;
1338360efbdSAlfred Perlstein 
134794295baSMartin Blapp 	if (!__rpc_fd2sockinfo(fd, &si))
135794295baSMartin Blapp 		return NULL;
136794295baSMartin Blapp 
1378360efbdSAlfred Perlstein 	r = mem_alloc(sizeof(*r));
1388360efbdSAlfred Perlstein 	if (r == NULL) {
1398360efbdSAlfred Perlstein 		warnx("svc_vc_create: out of memory");
1408360efbdSAlfred Perlstein 		goto cleanup_svc_vc_create;
1418360efbdSAlfred Perlstein 	}
1428360efbdSAlfred Perlstein 	r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize);
1438360efbdSAlfred Perlstein 	r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize);
14408497c02SMartin Blapp 	r->maxrec = __svc_maxrec;
1458f55a568SDoug Rabson 	xprt = svc_xprt_alloc();
1468360efbdSAlfred Perlstein 	if (xprt == NULL) {
1478360efbdSAlfred Perlstein 		warnx("svc_vc_create: out of memory");
1488360efbdSAlfred Perlstein 		goto cleanup_svc_vc_create;
1498360efbdSAlfred Perlstein 	}
150f249dbccSDag-Erling Smørgrav 	xprt->xp_p1 = r;
1518360efbdSAlfred Perlstein 	xprt->xp_verf = _null_auth;
1528360efbdSAlfred Perlstein 	svc_vc_rendezvous_ops(xprt);
1538360efbdSAlfred Perlstein 	xprt->xp_port = (u_short)-1;	/* It is the rendezvouser */
1548360efbdSAlfred Perlstein 	xprt->xp_fd = fd;
1558360efbdSAlfred Perlstein 
1568360efbdSAlfred Perlstein 	slen = sizeof (struct sockaddr_storage);
1578360efbdSAlfred Perlstein 	if (_getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) {
1588360efbdSAlfred Perlstein 		warnx("svc_vc_create: could not retrieve local addr");
1598360efbdSAlfred Perlstein 		goto cleanup_svc_vc_create;
1608360efbdSAlfred Perlstein 	}
1618360efbdSAlfred Perlstein 
1628360efbdSAlfred Perlstein 	xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len;
1638360efbdSAlfred Perlstein 	xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len);
1648360efbdSAlfred Perlstein 	if (xprt->xp_ltaddr.buf == NULL) {
1658360efbdSAlfred Perlstein 		warnx("svc_vc_create: no mem for local addr");
1668360efbdSAlfred Perlstein 		goto cleanup_svc_vc_create;
1678360efbdSAlfred Perlstein 	}
1688360efbdSAlfred Perlstein 	memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len);
1698360efbdSAlfred Perlstein 
1708360efbdSAlfred Perlstein 	xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage);
1718360efbdSAlfred Perlstein 	xprt_register(xprt);
1728360efbdSAlfred Perlstein 	return (xprt);
1738360efbdSAlfred Perlstein cleanup_svc_vc_create:
174794295baSMartin Blapp 	if (xprt)
175794295baSMartin Blapp 		mem_free(xprt, sizeof(*xprt));
1768360efbdSAlfred Perlstein 	if (r != NULL)
1778360efbdSAlfred Perlstein 		mem_free(r, sizeof(*r));
1788360efbdSAlfred Perlstein 	return (NULL);
1798360efbdSAlfred Perlstein }
1808360efbdSAlfred Perlstein 
1818360efbdSAlfred Perlstein /*
1828360efbdSAlfred Perlstein  * Like svtcp_create(), except the routine takes any *open* UNIX file
1838360efbdSAlfred Perlstein  * descriptor as its first input.
1848360efbdSAlfred Perlstein  */
1858360efbdSAlfred Perlstein SVCXPRT *
18668895e38SCraig Rodrigues svc_fd_create(int fd, u_int sendsize, u_int recvsize)
1878360efbdSAlfred Perlstein {
1888360efbdSAlfred Perlstein 	struct sockaddr_storage ss;
1898360efbdSAlfred Perlstein 	socklen_t slen;
1908360efbdSAlfred Perlstein 	SVCXPRT *ret;
1918360efbdSAlfred Perlstein 
1928360efbdSAlfred Perlstein 	assert(fd != -1);
1938360efbdSAlfred Perlstein 
1948360efbdSAlfred Perlstein 	ret = makefd_xprt(fd, sendsize, recvsize);
1958360efbdSAlfred Perlstein 	if (ret == NULL)
1968360efbdSAlfred Perlstein 		return NULL;
1978360efbdSAlfred Perlstein 
1988360efbdSAlfred Perlstein 	slen = sizeof (struct sockaddr_storage);
1998360efbdSAlfred Perlstein 	if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
2008360efbdSAlfred Perlstein 		warnx("svc_fd_create: could not retrieve local addr");
2018360efbdSAlfred Perlstein 		goto freedata;
2028360efbdSAlfred Perlstein 	}
2038360efbdSAlfred Perlstein 	ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len;
2048360efbdSAlfred Perlstein 	ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len);
2058360efbdSAlfred Perlstein 	if (ret->xp_ltaddr.buf == NULL) {
2068360efbdSAlfred Perlstein 		warnx("svc_fd_create: no mem for local addr");
2078360efbdSAlfred Perlstein 		goto freedata;
2088360efbdSAlfred Perlstein 	}
2098360efbdSAlfred Perlstein 	memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len);
2108360efbdSAlfred Perlstein 
2118360efbdSAlfred Perlstein 	slen = sizeof (struct sockaddr_storage);
2128360efbdSAlfred Perlstein 	if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
2138360efbdSAlfred Perlstein 		warnx("svc_fd_create: could not retrieve remote addr");
2148360efbdSAlfred Perlstein 		goto freedata;
2158360efbdSAlfred Perlstein 	}
2168360efbdSAlfred Perlstein 	ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len;
2178360efbdSAlfred Perlstein 	ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len);
2188360efbdSAlfred Perlstein 	if (ret->xp_rtaddr.buf == NULL) {
2198360efbdSAlfred Perlstein 		warnx("svc_fd_create: no mem for local addr");
2208360efbdSAlfred Perlstein 		goto freedata;
2218360efbdSAlfred Perlstein 	}
2228360efbdSAlfred Perlstein 	memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len);
2238360efbdSAlfred Perlstein #ifdef PORTMAP
2242abd9cf1SAlfred Perlstein 	if (ss.ss_family == AF_INET || ss.ss_family == AF_LOCAL) {
2258360efbdSAlfred Perlstein 		ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf;
2268360efbdSAlfred Perlstein 		ret->xp_addrlen = sizeof (struct sockaddr_in);
2278360efbdSAlfred Perlstein 	}
2288360efbdSAlfred Perlstein #endif				/* PORTMAP */
2298360efbdSAlfred Perlstein 
2308360efbdSAlfred Perlstein 	return ret;
2318360efbdSAlfred Perlstein 
2328360efbdSAlfred Perlstein freedata:
2338360efbdSAlfred Perlstein 	if (ret->xp_ltaddr.buf != NULL)
2348360efbdSAlfred Perlstein 		mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen);
2358360efbdSAlfred Perlstein 
2368360efbdSAlfred Perlstein 	return NULL;
2378360efbdSAlfred Perlstein }
2388360efbdSAlfred Perlstein 
2398360efbdSAlfred Perlstein static SVCXPRT *
24068895e38SCraig Rodrigues makefd_xprt(int fd, u_int sendsize, u_int recvsize)
2418360efbdSAlfred Perlstein {
2428360efbdSAlfred Perlstein 	SVCXPRT *xprt;
2438360efbdSAlfred Perlstein 	struct cf_conn *cd;
2448360efbdSAlfred Perlstein 	const char *netid;
2458360efbdSAlfred Perlstein 	struct __rpc_sockinfo si;
2468360efbdSAlfred Perlstein 
2478360efbdSAlfred Perlstein 	assert(fd != -1);
2488360efbdSAlfred Perlstein 
2498f55a568SDoug Rabson 	xprt = svc_xprt_alloc();
2508360efbdSAlfred Perlstein 	if (xprt == NULL) {
2518360efbdSAlfred Perlstein 		warnx("svc_vc: makefd_xprt: out of memory");
2528360efbdSAlfred Perlstein 		goto done;
2538360efbdSAlfred Perlstein 	}
2548360efbdSAlfred Perlstein 	cd = mem_alloc(sizeof(struct cf_conn));
2558360efbdSAlfred Perlstein 	if (cd == NULL) {
2568360efbdSAlfred Perlstein 		warnx("svc_tcp: makefd_xprt: out of memory");
2578f55a568SDoug Rabson 		svc_xprt_free(xprt);
2588360efbdSAlfred Perlstein 		xprt = NULL;
2598360efbdSAlfred Perlstein 		goto done;
2608360efbdSAlfred Perlstein 	}
2618360efbdSAlfred Perlstein 	cd->strm_stat = XPRT_IDLE;
2628360efbdSAlfred Perlstein 	xdrrec_create(&(cd->xdrs), sendsize, recvsize,
263f249dbccSDag-Erling Smørgrav 	    xprt, read_vc, write_vc);
264f249dbccSDag-Erling Smørgrav 	xprt->xp_p1 = cd;
2658360efbdSAlfred Perlstein 	xprt->xp_verf.oa_base = cd->verf_body;
2668360efbdSAlfred Perlstein 	svc_vc_ops(xprt);  /* truely deals with calls */
2678360efbdSAlfred Perlstein 	xprt->xp_port = 0;  /* this is a connection, not a rendezvouser */
2688360efbdSAlfred Perlstein 	xprt->xp_fd = fd;
2698360efbdSAlfred Perlstein         if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid))
2708360efbdSAlfred Perlstein 		xprt->xp_netid = strdup(netid);
2718360efbdSAlfred Perlstein 
2728360efbdSAlfred Perlstein 	xprt_register(xprt);
2738360efbdSAlfred Perlstein done:
2748360efbdSAlfred Perlstein 	return (xprt);
2758360efbdSAlfred Perlstein }
2768360efbdSAlfred Perlstein 
2778360efbdSAlfred Perlstein /*ARGSUSED*/
2788360efbdSAlfred Perlstein static bool_t
27968895e38SCraig Rodrigues rendezvous_request(SVCXPRT *xprt, struct rpc_msg *msg)
2808360efbdSAlfred Perlstein {
28108497c02SMartin Blapp 	int sock, flags;
2828360efbdSAlfred Perlstein 	struct cf_rendezvous *r;
28308497c02SMartin Blapp 	struct cf_conn *cd;
284*5eff94eeSStanislav Sedov 	struct sockaddr_storage addr, sslocal;
285*5eff94eeSStanislav Sedov 	socklen_t len, slen;
2868360efbdSAlfred Perlstein 	struct __rpc_sockinfo si;
28708497c02SMartin Blapp 	SVCXPRT *newxprt;
28808497c02SMartin Blapp 	fd_set cleanfds;
2898360efbdSAlfred Perlstein 
2908360efbdSAlfred Perlstein 	assert(xprt != NULL);
2918360efbdSAlfred Perlstein 	assert(msg != NULL);
2928360efbdSAlfred Perlstein 
2938360efbdSAlfred Perlstein 	r = (struct cf_rendezvous *)xprt->xp_p1;
2948360efbdSAlfred Perlstein again:
2958360efbdSAlfred Perlstein 	len = sizeof addr;
2968360efbdSAlfred Perlstein 	if ((sock = _accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr,
2978360efbdSAlfred Perlstein 	    &len)) < 0) {
2988360efbdSAlfred Perlstein 		if (errno == EINTR)
2998360efbdSAlfred Perlstein 			goto again;
30008497c02SMartin Blapp 		/*
30108497c02SMartin Blapp 		 * Clean out the most idle file descriptor when we're
30208497c02SMartin Blapp 		 * running out.
30308497c02SMartin Blapp 		 */
30408497c02SMartin Blapp 		if (errno == EMFILE || errno == ENFILE) {
30508497c02SMartin Blapp 			cleanfds = svc_fdset;
30608497c02SMartin Blapp 			__svc_clean_idle(&cleanfds, 0, FALSE);
30708497c02SMartin Blapp 			goto again;
30808497c02SMartin Blapp 		}
3098360efbdSAlfred Perlstein 		return (FALSE);
3108360efbdSAlfred Perlstein 	}
3118360efbdSAlfred Perlstein 	/*
3128360efbdSAlfred Perlstein 	 * make a new transporter (re-uses xprt)
3138360efbdSAlfred Perlstein 	 */
31408497c02SMartin Blapp 	newxprt = makefd_xprt(sock, r->sendsize, r->recvsize);
31508497c02SMartin Blapp 	newxprt->xp_rtaddr.buf = mem_alloc(len);
31608497c02SMartin Blapp 	if (newxprt->xp_rtaddr.buf == NULL)
3178360efbdSAlfred Perlstein 		return (FALSE);
31808497c02SMartin Blapp 	memcpy(newxprt->xp_rtaddr.buf, &addr, len);
31908497c02SMartin Blapp 	newxprt->xp_rtaddr.len = len;
3208360efbdSAlfred Perlstein #ifdef PORTMAP
321866e3c90SAlfred Perlstein 	if (addr.ss_family == AF_INET || addr.ss_family == AF_LOCAL) {
32208497c02SMartin Blapp 		newxprt->xp_raddr = *(struct sockaddr_in *)newxprt->xp_rtaddr.buf;
32308497c02SMartin Blapp 		newxprt->xp_addrlen = sizeof (struct sockaddr_in);
3248360efbdSAlfred Perlstein 	}
3258360efbdSAlfred Perlstein #endif				/* PORTMAP */
3268360efbdSAlfred Perlstein 	if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) {
3278360efbdSAlfred Perlstein 		len = 1;
3288360efbdSAlfred Perlstein 		/* XXX fvdl - is this useful? */
3298360efbdSAlfred Perlstein 		_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &len, sizeof (len));
3308360efbdSAlfred Perlstein 	}
33108497c02SMartin Blapp 
33208497c02SMartin Blapp 	cd = (struct cf_conn *)newxprt->xp_p1;
33308497c02SMartin Blapp 
33408497c02SMartin Blapp 	cd->recvsize = r->recvsize;
33508497c02SMartin Blapp 	cd->sendsize = r->sendsize;
33608497c02SMartin Blapp 	cd->maxrec = r->maxrec;
33708497c02SMartin Blapp 
33808497c02SMartin Blapp 	if (cd->maxrec != 0) {
3390ae0e1eaSMartin Blapp 		flags = _fcntl(sock, F_GETFL, 0);
34008497c02SMartin Blapp 		if (flags  == -1)
34108497c02SMartin Blapp 			return (FALSE);
3420ae0e1eaSMartin Blapp 		if (_fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
34308497c02SMartin Blapp 			return (FALSE);
34408497c02SMartin Blapp 		if (cd->recvsize > cd->maxrec)
34508497c02SMartin Blapp 			cd->recvsize = cd->maxrec;
34608497c02SMartin Blapp 		cd->nonblock = TRUE;
34708497c02SMartin Blapp 		__xdrrec_setnonblock(&cd->xdrs, cd->maxrec);
34808497c02SMartin Blapp 	} else
34908497c02SMartin Blapp 		cd->nonblock = FALSE;
350*5eff94eeSStanislav Sedov 	slen = sizeof(struct sockaddr_storage);
351*5eff94eeSStanislav Sedov 	if(_getsockname(sock, (struct sockaddr *)(void *)&sslocal, &slen) < 0) {
352*5eff94eeSStanislav Sedov 		warnx("svc_vc_create: could not retrieve local addr");
353*5eff94eeSStanislav Sedov 		newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = 0;
354*5eff94eeSStanislav Sedov 	} else {
355*5eff94eeSStanislav Sedov 		newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = sslocal.ss_len;
356*5eff94eeSStanislav Sedov 		newxprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len);
357*5eff94eeSStanislav Sedov 		if (newxprt->xp_ltaddr.buf == NULL) {
358*5eff94eeSStanislav Sedov 			warnx("svc_vc_create: no mem for local addr");
359*5eff94eeSStanislav Sedov 			newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = 0;
360*5eff94eeSStanislav Sedov 		} else {
361*5eff94eeSStanislav Sedov 			memcpy(newxprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len);
362*5eff94eeSStanislav Sedov 		}
363*5eff94eeSStanislav Sedov 	}
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
37268895e38SCraig Rodrigues rendezvous_stat(SVCXPRT *xprt)
3738360efbdSAlfred Perlstein {
3748360efbdSAlfred Perlstein 
3758360efbdSAlfred Perlstein 	return (XPRT_IDLE);
3768360efbdSAlfred Perlstein }
3778360efbdSAlfred Perlstein 
3788360efbdSAlfred Perlstein static void
37968895e38SCraig Rodrigues svc_vc_destroy(SVCXPRT *xprt)
3808360efbdSAlfred Perlstein {
38108497c02SMartin Blapp 	assert(xprt != NULL);
38208497c02SMartin Blapp 
38308497c02SMartin Blapp 	xprt_unregister(xprt);
38408497c02SMartin Blapp 	__svc_vc_dodestroy(xprt);
38508497c02SMartin Blapp }
38608497c02SMartin Blapp 
38708497c02SMartin Blapp static void
38868895e38SCraig Rodrigues __svc_vc_dodestroy(SVCXPRT *xprt)
38908497c02SMartin Blapp {
3908360efbdSAlfred Perlstein 	struct cf_conn *cd;
3918360efbdSAlfred Perlstein 	struct cf_rendezvous *r;
3928360efbdSAlfred Perlstein 
3938360efbdSAlfred Perlstein 	cd = (struct cf_conn *)xprt->xp_p1;
3948360efbdSAlfred Perlstein 
3958360efbdSAlfred Perlstein 	if (xprt->xp_fd != RPC_ANYFD)
3968360efbdSAlfred Perlstein 		(void)_close(xprt->xp_fd);
3978360efbdSAlfred Perlstein 	if (xprt->xp_port != 0) {
3988360efbdSAlfred Perlstein 		/* a rendezvouser socket */
3998360efbdSAlfred Perlstein 		r = (struct cf_rendezvous *)xprt->xp_p1;
4008360efbdSAlfred Perlstein 		mem_free(r, sizeof (struct cf_rendezvous));
4018360efbdSAlfred Perlstein 		xprt->xp_port = 0;
4028360efbdSAlfred Perlstein 	} else {
4038360efbdSAlfred Perlstein 		/* an actual connection socket */
4048360efbdSAlfred Perlstein 		XDR_DESTROY(&(cd->xdrs));
4058360efbdSAlfred Perlstein 		mem_free(cd, sizeof(struct cf_conn));
4068360efbdSAlfred Perlstein 	}
4078360efbdSAlfred Perlstein 	if (xprt->xp_rtaddr.buf)
4088360efbdSAlfred Perlstein 		mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen);
4098360efbdSAlfred Perlstein 	if (xprt->xp_ltaddr.buf)
4108360efbdSAlfred Perlstein 		mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen);
4118360efbdSAlfred Perlstein 	free(xprt->xp_tp);
4128360efbdSAlfred Perlstein 	free(xprt->xp_netid);
4138f55a568SDoug Rabson 	svc_xprt_free(xprt);
4148360efbdSAlfred Perlstein }
4158360efbdSAlfred Perlstein 
4168360efbdSAlfred Perlstein /*ARGSUSED*/
4178360efbdSAlfred Perlstein static bool_t
41868895e38SCraig Rodrigues svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in)
4198360efbdSAlfred Perlstein {
4208360efbdSAlfred Perlstein 	return (FALSE);
4218360efbdSAlfred Perlstein }
4228360efbdSAlfred Perlstein 
42308497c02SMartin Blapp static bool_t
42468895e38SCraig Rodrigues svc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in)
42508497c02SMartin Blapp {
42608497c02SMartin Blapp 	struct cf_rendezvous *cfp;
42708497c02SMartin Blapp 
42808497c02SMartin Blapp 	cfp = (struct cf_rendezvous *)xprt->xp_p1;
42908497c02SMartin Blapp 	if (cfp == NULL)
43008497c02SMartin Blapp 		return (FALSE);
43108497c02SMartin Blapp 	switch (rq) {
43208497c02SMartin Blapp 		case SVCGET_CONNMAXREC:
43308497c02SMartin Blapp 			*(int *)in = cfp->maxrec;
43408497c02SMartin Blapp 			break;
43508497c02SMartin Blapp 		case SVCSET_CONNMAXREC:
43608497c02SMartin Blapp 			cfp->maxrec = *(int *)in;
43708497c02SMartin Blapp 			break;
43808497c02SMartin Blapp 		default:
43908497c02SMartin Blapp 			return (FALSE);
44008497c02SMartin Blapp 	}
44108497c02SMartin Blapp 	return (TRUE);
44208497c02SMartin Blapp }
44308497c02SMartin Blapp 
4448360efbdSAlfred Perlstein /*
4458360efbdSAlfred Perlstein  * reads data from the tcp or uip connection.
4468360efbdSAlfred Perlstein  * any error is fatal and the connection is closed.
4478360efbdSAlfred Perlstein  * (And a read of zero bytes is a half closed stream => error.)
4488360efbdSAlfred Perlstein  * All read operations timeout after 35 seconds.  A timeout is
4498360efbdSAlfred Perlstein  * fatal for the connection.
4508360efbdSAlfred Perlstein  */
4518360efbdSAlfred Perlstein static int
45268895e38SCraig Rodrigues read_vc(void *xprtp, void *buf, int len)
4538360efbdSAlfred Perlstein {
4548360efbdSAlfred Perlstein 	SVCXPRT *xprt;
4558360efbdSAlfred Perlstein 	int sock;
4568360efbdSAlfred Perlstein 	int milliseconds = 35 * 1000;
4578360efbdSAlfred Perlstein 	struct pollfd pollfd;
45808497c02SMartin Blapp 	struct cf_conn *cfp;
4598360efbdSAlfred Perlstein 
460f249dbccSDag-Erling Smørgrav 	xprt = (SVCXPRT *)xprtp;
4618360efbdSAlfred Perlstein 	assert(xprt != NULL);
4628360efbdSAlfred Perlstein 
4638360efbdSAlfred Perlstein 	sock = xprt->xp_fd;
4648360efbdSAlfred Perlstein 
46508497c02SMartin Blapp 	cfp = (struct cf_conn *)xprt->xp_p1;
46608497c02SMartin Blapp 
46708497c02SMartin Blapp 	if (cfp->nonblock) {
4680ae0e1eaSMartin Blapp 		len = _read(sock, buf, (size_t)len);
46908497c02SMartin Blapp 		if (len < 0) {
47008497c02SMartin Blapp 			if (errno == EAGAIN)
47108497c02SMartin Blapp 				len = 0;
47208497c02SMartin Blapp 			else
47308497c02SMartin Blapp 				goto fatal_err;
47408497c02SMartin Blapp 		}
47508497c02SMartin Blapp 		if (len != 0)
47608497c02SMartin Blapp 			gettimeofday(&cfp->last_recv_time, NULL);
47708497c02SMartin Blapp 		return len;
47808497c02SMartin Blapp 	}
47908497c02SMartin Blapp 
4808360efbdSAlfred Perlstein 	do {
4818360efbdSAlfred Perlstein 		pollfd.fd = sock;
4828360efbdSAlfred Perlstein 		pollfd.events = POLLIN;
4838360efbdSAlfred Perlstein 		pollfd.revents = 0;
4848360efbdSAlfred Perlstein 		switch (_poll(&pollfd, 1, milliseconds)) {
4858360efbdSAlfred Perlstein 		case -1:
486fa87b7eaSAlfred Perlstein 			if (errno == EINTR)
4878360efbdSAlfred Perlstein 				continue;
4888360efbdSAlfred Perlstein 			/*FALLTHROUGH*/
4898360efbdSAlfred Perlstein 		case 0:
4908360efbdSAlfred Perlstein 			goto fatal_err;
4914ed6d634SAlfred Perlstein 
4928360efbdSAlfred Perlstein 		default:
4938360efbdSAlfred Perlstein 			break;
4948360efbdSAlfred Perlstein 		}
4958360efbdSAlfred Perlstein 	} while ((pollfd.revents & POLLIN) == 0);
4968360efbdSAlfred Perlstein 
4970ae0e1eaSMartin Blapp 	if ((len = _read(sock, buf, (size_t)len)) > 0) {
49808497c02SMartin Blapp 		gettimeofday(&cfp->last_recv_time, NULL);
4998360efbdSAlfred Perlstein 		return (len);
5008360efbdSAlfred Perlstein 	}
5018360efbdSAlfred Perlstein 
5028360efbdSAlfred Perlstein fatal_err:
5038360efbdSAlfred Perlstein 	((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
5048360efbdSAlfred Perlstein 	return (-1);
5058360efbdSAlfred Perlstein }
5068360efbdSAlfred Perlstein 
5078360efbdSAlfred Perlstein /*
5088360efbdSAlfred Perlstein  * writes data to the tcp connection.
5098360efbdSAlfred Perlstein  * Any error is fatal and the connection is closed.
5108360efbdSAlfred Perlstein  */
5118360efbdSAlfred Perlstein static int
51268895e38SCraig Rodrigues write_vc(void *xprtp, void *buf, int len)
5138360efbdSAlfred Perlstein {
5148360efbdSAlfred Perlstein 	SVCXPRT *xprt;
5158360efbdSAlfred Perlstein 	int i, cnt;
51608497c02SMartin Blapp 	struct cf_conn *cd;
51708497c02SMartin Blapp 	struct timeval tv0, tv1;
5188360efbdSAlfred Perlstein 
519f249dbccSDag-Erling Smørgrav 	xprt = (SVCXPRT *)xprtp;
5208360efbdSAlfred Perlstein 	assert(xprt != NULL);
5218360efbdSAlfred Perlstein 
52208497c02SMartin Blapp 	cd = (struct cf_conn *)xprt->xp_p1;
52308497c02SMartin Blapp 
52408497c02SMartin Blapp 	if (cd->nonblock)
52508497c02SMartin Blapp 		gettimeofday(&tv0, NULL);
52608497c02SMartin Blapp 
527361de173SStefan Farfeleder 	for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) {
52808497c02SMartin Blapp 		i = _write(xprt->xp_fd, buf, (size_t)cnt);
52908497c02SMartin Blapp 		if (i  < 0) {
53008497c02SMartin Blapp 			if (errno != EAGAIN || !cd->nonblock) {
53108497c02SMartin Blapp 				cd->strm_stat = XPRT_DIED;
5328360efbdSAlfred Perlstein 				return (-1);
5338360efbdSAlfred Perlstein 			}
534e2c83f74SRick Macklem 			if (cd->nonblock) {
53508497c02SMartin Blapp 				/*
53608497c02SMartin Blapp 				 * For non-blocking connections, do not
53708497c02SMartin Blapp 				 * take more than 2 seconds writing the
53808497c02SMartin Blapp 				 * data out.
53908497c02SMartin Blapp 				 *
54008497c02SMartin Blapp 				 * XXX 2 is an arbitrary amount.
54108497c02SMartin Blapp 				 */
54208497c02SMartin Blapp 				gettimeofday(&tv1, NULL);
54308497c02SMartin Blapp 				if (tv1.tv_sec - tv0.tv_sec >= 2) {
54408497c02SMartin Blapp 					cd->strm_stat = XPRT_DIED;
5458360efbdSAlfred Perlstein 					return (-1);
5468360efbdSAlfred Perlstein 				}
5478360efbdSAlfred Perlstein 			}
548e2c83f74SRick Macklem 			i = 0;
5498360efbdSAlfred Perlstein 		}
55008497c02SMartin Blapp 	}
5518360efbdSAlfred Perlstein 
5528360efbdSAlfred Perlstein 	return (len);
5538360efbdSAlfred Perlstein }
5548360efbdSAlfred Perlstein 
5558360efbdSAlfred Perlstein static enum xprt_stat
55668895e38SCraig Rodrigues svc_vc_stat(SVCXPRT *xprt)
5578360efbdSAlfred Perlstein {
5588360efbdSAlfred Perlstein 	struct cf_conn *cd;
5598360efbdSAlfred Perlstein 
5608360efbdSAlfred Perlstein 	assert(xprt != NULL);
5618360efbdSAlfred Perlstein 
5628360efbdSAlfred Perlstein 	cd = (struct cf_conn *)(xprt->xp_p1);
5638360efbdSAlfred Perlstein 
5648360efbdSAlfred Perlstein 	if (cd->strm_stat == XPRT_DIED)
5658360efbdSAlfred Perlstein 		return (XPRT_DIED);
5668360efbdSAlfred Perlstein 	if (! xdrrec_eof(&(cd->xdrs)))
5678360efbdSAlfred Perlstein 		return (XPRT_MOREREQS);
5688360efbdSAlfred Perlstein 	return (XPRT_IDLE);
5698360efbdSAlfred Perlstein }
5708360efbdSAlfred Perlstein 
5718360efbdSAlfred Perlstein static bool_t
57268895e38SCraig Rodrigues svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg)
5738360efbdSAlfred Perlstein {
5748360efbdSAlfred Perlstein 	struct cf_conn *cd;
5758360efbdSAlfred Perlstein 	XDR *xdrs;
5768360efbdSAlfred Perlstein 
5778360efbdSAlfred Perlstein 	assert(xprt != NULL);
5788360efbdSAlfred Perlstein 	assert(msg != NULL);
5798360efbdSAlfred Perlstein 
5808360efbdSAlfred Perlstein 	cd = (struct cf_conn *)(xprt->xp_p1);
5818360efbdSAlfred Perlstein 	xdrs = &(cd->xdrs);
5828360efbdSAlfred Perlstein 
58308497c02SMartin Blapp 	if (cd->nonblock) {
58408497c02SMartin Blapp 		if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE))
58508497c02SMartin Blapp 			return FALSE;
586ecc03b80SDoug Rabson 	} else {
587ecc03b80SDoug Rabson 		(void)xdrrec_skiprecord(xdrs);
58808497c02SMartin Blapp 	}
58908497c02SMartin Blapp 
5908360efbdSAlfred Perlstein 	xdrs->x_op = XDR_DECODE;
5918360efbdSAlfred Perlstein 	if (xdr_callmsg(xdrs, msg)) {
5928360efbdSAlfred Perlstein 		cd->x_id = msg->rm_xid;
5938360efbdSAlfred Perlstein 		return (TRUE);
5948360efbdSAlfred Perlstein 	}
5958360efbdSAlfred Perlstein 	cd->strm_stat = XPRT_DIED;
5968360efbdSAlfred Perlstein 	return (FALSE);
5978360efbdSAlfred Perlstein }
5988360efbdSAlfred Perlstein 
5998360efbdSAlfred Perlstein static bool_t
60068895e38SCraig Rodrigues svc_vc_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
6018360efbdSAlfred Perlstein {
6028f55a568SDoug Rabson 	struct cf_conn *cd;
6038360efbdSAlfred Perlstein 
6048360efbdSAlfred Perlstein 	assert(xprt != NULL);
6058f55a568SDoug Rabson 	cd = (struct cf_conn *)(xprt->xp_p1);
6068f55a568SDoug Rabson 	return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt),
6078f55a568SDoug Rabson 		&cd->xdrs, xdr_args, args_ptr));
6088360efbdSAlfred Perlstein }
6098360efbdSAlfred Perlstein 
6108360efbdSAlfred Perlstein static bool_t
61168895e38SCraig Rodrigues svc_vc_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
6128360efbdSAlfred Perlstein {
6138360efbdSAlfred Perlstein 	XDR *xdrs;
6148360efbdSAlfred Perlstein 
6158360efbdSAlfred Perlstein 	assert(xprt != NULL);
6168360efbdSAlfred Perlstein 	/* args_ptr may be NULL */
6178360efbdSAlfred Perlstein 
6188360efbdSAlfred Perlstein 	xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs);
6198360efbdSAlfred Perlstein 
6208360efbdSAlfred Perlstein 	xdrs->x_op = XDR_FREE;
6218360efbdSAlfred Perlstein 	return ((*xdr_args)(xdrs, args_ptr));
6228360efbdSAlfred Perlstein }
6238360efbdSAlfred Perlstein 
6248360efbdSAlfred Perlstein static bool_t
62568895e38SCraig Rodrigues svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg)
6268360efbdSAlfred Perlstein {
6278360efbdSAlfred Perlstein 	struct cf_conn *cd;
6288360efbdSAlfred Perlstein 	XDR *xdrs;
62908497c02SMartin Blapp 	bool_t rstat;
6308f55a568SDoug Rabson 	xdrproc_t xdr_proc;
6318f55a568SDoug Rabson 	caddr_t xdr_where;
6328f55a568SDoug Rabson 	u_int pos;
6338360efbdSAlfred Perlstein 
6348360efbdSAlfred Perlstein 	assert(xprt != NULL);
6358360efbdSAlfred Perlstein 	assert(msg != NULL);
6368360efbdSAlfred Perlstein 
6378360efbdSAlfred Perlstein 	cd = (struct cf_conn *)(xprt->xp_p1);
6388360efbdSAlfred Perlstein 	xdrs = &(cd->xdrs);
6398360efbdSAlfred Perlstein 
6408360efbdSAlfred Perlstein 	xdrs->x_op = XDR_ENCODE;
6418360efbdSAlfred Perlstein 	msg->rm_xid = cd->x_id;
6428f55a568SDoug Rabson 	rstat = TRUE;
6438f55a568SDoug Rabson 	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
6448f55a568SDoug Rabson 	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
6458f55a568SDoug Rabson 		xdr_proc = msg->acpted_rply.ar_results.proc;
6468f55a568SDoug Rabson 		xdr_where = msg->acpted_rply.ar_results.where;
6478f55a568SDoug Rabson 		msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
6488f55a568SDoug Rabson 		msg->acpted_rply.ar_results.where = NULL;
6498f55a568SDoug Rabson 
6508f55a568SDoug Rabson 		pos = XDR_GETPOS(xdrs);
6518f55a568SDoug Rabson 		if (!xdr_replymsg(xdrs, msg) ||
6528f55a568SDoug Rabson 		    !SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where)) {
6538f55a568SDoug Rabson 			XDR_SETPOS(xdrs, pos);
6548f55a568SDoug Rabson 			rstat = FALSE;
6558f55a568SDoug Rabson 		}
6568f55a568SDoug Rabson 	} else {
65708497c02SMartin Blapp 		rstat = xdr_replymsg(xdrs, msg);
6588f55a568SDoug Rabson 	}
6598f55a568SDoug Rabson 
6608f55a568SDoug Rabson 	if (rstat)
6618360efbdSAlfred Perlstein 		(void)xdrrec_endofrecord(xdrs, TRUE);
6628f55a568SDoug Rabson 
66308497c02SMartin Blapp 	return (rstat);
6648360efbdSAlfred Perlstein }
6658360efbdSAlfred Perlstein 
6668360efbdSAlfred Perlstein static void
66768895e38SCraig Rodrigues svc_vc_ops(SVCXPRT *xprt)
6688360efbdSAlfred Perlstein {
6698360efbdSAlfred Perlstein 	static struct xp_ops ops;
6708360efbdSAlfred Perlstein 	static struct xp_ops2 ops2;
6718360efbdSAlfred Perlstein 
6728360efbdSAlfred Perlstein /* VARIABLES PROTECTED BY ops_lock: ops, ops2 */
6738360efbdSAlfred Perlstein 
6748360efbdSAlfred Perlstein 	mutex_lock(&ops_lock);
6758360efbdSAlfred Perlstein 	if (ops.xp_recv == NULL) {
6768360efbdSAlfred Perlstein 		ops.xp_recv = svc_vc_recv;
6778360efbdSAlfred Perlstein 		ops.xp_stat = svc_vc_stat;
6788360efbdSAlfred Perlstein 		ops.xp_getargs = svc_vc_getargs;
6798360efbdSAlfred Perlstein 		ops.xp_reply = svc_vc_reply;
6808360efbdSAlfred Perlstein 		ops.xp_freeargs = svc_vc_freeargs;
6818360efbdSAlfred Perlstein 		ops.xp_destroy = svc_vc_destroy;
6828360efbdSAlfred Perlstein 		ops2.xp_control = svc_vc_control;
6838360efbdSAlfred Perlstein 	}
6848360efbdSAlfred Perlstein 	xprt->xp_ops = &ops;
6858360efbdSAlfred Perlstein 	xprt->xp_ops2 = &ops2;
6868360efbdSAlfred Perlstein 	mutex_unlock(&ops_lock);
6878360efbdSAlfred Perlstein }
6888360efbdSAlfred Perlstein 
6898360efbdSAlfred Perlstein static void
69068895e38SCraig Rodrigues svc_vc_rendezvous_ops(SVCXPRT *xprt)
6918360efbdSAlfred Perlstein {
6928360efbdSAlfred Perlstein 	static struct xp_ops ops;
6938360efbdSAlfred Perlstein 	static struct xp_ops2 ops2;
6948360efbdSAlfred Perlstein 
6958360efbdSAlfred Perlstein 	mutex_lock(&ops_lock);
6968360efbdSAlfred Perlstein 	if (ops.xp_recv == NULL) {
6978360efbdSAlfred Perlstein 		ops.xp_recv = rendezvous_request;
6988360efbdSAlfred Perlstein 		ops.xp_stat = rendezvous_stat;
6998360efbdSAlfred Perlstein 		ops.xp_getargs =
700f249dbccSDag-Erling Smørgrav 		    (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort;
7018360efbdSAlfred Perlstein 		ops.xp_reply =
7021372519bSDavid E. O'Brien 		    (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort;
7038360efbdSAlfred Perlstein 		ops.xp_freeargs =
704f249dbccSDag-Erling Smørgrav 		    (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort,
7058360efbdSAlfred Perlstein 		ops.xp_destroy = svc_vc_destroy;
70608497c02SMartin Blapp 		ops2.xp_control = svc_vc_rendezvous_control;
7078360efbdSAlfred Perlstein 	}
7088360efbdSAlfred Perlstein 	xprt->xp_ops = &ops;
7098360efbdSAlfred Perlstein 	xprt->xp_ops2 = &ops2;
7108360efbdSAlfred Perlstein 	mutex_unlock(&ops_lock);
7118360efbdSAlfred Perlstein }
7128360efbdSAlfred Perlstein 
7134ed6d634SAlfred Perlstein /*
714ce9bc43cSMartin Blapp  * Get the effective UID of the sending process. Used by rpcbind, keyserv
715ce9bc43cSMartin Blapp  * and rpc.yppasswdd on AF_LOCAL.
7164ed6d634SAlfred Perlstein  */
7174ed6d634SAlfred Perlstein int
718ce9bc43cSMartin Blapp __rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) {
719ce9bc43cSMartin Blapp 	int sock, ret;
720ce9bc43cSMartin Blapp 	gid_t egid;
721ce9bc43cSMartin Blapp 	uid_t euid;
722ce9bc43cSMartin Blapp 	struct sockaddr *sa;
72308760d5aSAlfred Perlstein 
724ce9bc43cSMartin Blapp 	sock = transp->xp_fd;
725ce9bc43cSMartin Blapp 	sa = (struct sockaddr *)transp->xp_rtaddr.buf;
726ce9bc43cSMartin Blapp 	if (sa->sa_family == AF_LOCAL) {
727ce9bc43cSMartin Blapp 		ret = getpeereid(sock, &euid, &egid);
728ce9bc43cSMartin Blapp 		if (ret == 0)
729ce9bc43cSMartin Blapp 			*uid = euid;
730ce9bc43cSMartin Blapp 		return (ret);
731ce9bc43cSMartin Blapp 	} else
73208760d5aSAlfred Perlstein 		return (-1);
7334ed6d634SAlfred Perlstein }
73408497c02SMartin Blapp 
73508497c02SMartin Blapp /*
73608497c02SMartin Blapp  * Destroy xprts that have not have had any activity in 'timeout' seconds.
73708497c02SMartin Blapp  * If 'cleanblock' is true, blocking connections (the default) are also
73808497c02SMartin Blapp  * cleaned. If timeout is 0, the least active connection is picked.
73908497c02SMartin Blapp  */
74008497c02SMartin Blapp bool_t
74108497c02SMartin Blapp __svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock)
74208497c02SMartin Blapp {
74308497c02SMartin Blapp 	int i, ncleaned;
74408497c02SMartin Blapp 	SVCXPRT *xprt, *least_active;
74508497c02SMartin Blapp 	struct timeval tv, tdiff, tmax;
74608497c02SMartin Blapp 	struct cf_conn *cd;
74708497c02SMartin Blapp 
74808497c02SMartin Blapp 	gettimeofday(&tv, NULL);
74908497c02SMartin Blapp 	tmax.tv_sec = tmax.tv_usec = 0;
75008497c02SMartin Blapp 	least_active = NULL;
75108497c02SMartin Blapp 	rwlock_wrlock(&svc_fd_lock);
75208497c02SMartin Blapp 	for (i = ncleaned = 0; i <= svc_maxfd; i++) {
75308497c02SMartin Blapp 		if (FD_ISSET(i, fds)) {
75408497c02SMartin Blapp 			xprt = __svc_xports[i];
75508497c02SMartin Blapp 			if (xprt == NULL || xprt->xp_ops == NULL ||
75608497c02SMartin Blapp 			    xprt->xp_ops->xp_recv != svc_vc_recv)
75708497c02SMartin Blapp 				continue;
75808497c02SMartin Blapp 			cd = (struct cf_conn *)xprt->xp_p1;
75908497c02SMartin Blapp 			if (!cleanblock && !cd->nonblock)
76008497c02SMartin Blapp 				continue;
76108497c02SMartin Blapp 			if (timeout == 0) {
76208497c02SMartin Blapp 				timersub(&tv, &cd->last_recv_time, &tdiff);
76308497c02SMartin Blapp 				if (timercmp(&tdiff, &tmax, >)) {
76408497c02SMartin Blapp 					tmax = tdiff;
76508497c02SMartin Blapp 					least_active = xprt;
76608497c02SMartin Blapp 				}
76708497c02SMartin Blapp 				continue;
76808497c02SMartin Blapp 			}
76908497c02SMartin Blapp 			if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) {
77008497c02SMartin Blapp 				__xprt_unregister_unlocked(xprt);
77108497c02SMartin Blapp 				__svc_vc_dodestroy(xprt);
77208497c02SMartin Blapp 				ncleaned++;
77308497c02SMartin Blapp 			}
77408497c02SMartin Blapp 		}
77508497c02SMartin Blapp 	}
77608497c02SMartin Blapp 	if (timeout == 0 && least_active != NULL) {
77708497c02SMartin Blapp 		__xprt_unregister_unlocked(least_active);
77808497c02SMartin Blapp 		__svc_vc_dodestroy(least_active);
77908497c02SMartin Blapp 		ncleaned++;
78008497c02SMartin Blapp 	}
78108497c02SMartin Blapp 	rwlock_unlock(&svc_fd_lock);
78208497c02SMartin Blapp 	return ncleaned > 0 ? TRUE : FALSE;
78308497c02SMartin Blapp }
784