xref: /freebsd/lib/libc/rpc/svc_vc.c (revision eb8ba6fb74f2d957bd5df357ae73f66a6002014a)
18360efbdSAlfred Perlstein /*	$NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $	*/
28360efbdSAlfred Perlstein 
32e322d37SHiroki Sato /*-
48a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
58a16b7a1SPedro F. Giffuni  *
62e322d37SHiroki Sato  * Copyright (c) 2009, Sun Microsystems, Inc.
72e322d37SHiroki Sato  * All rights reserved.
88360efbdSAlfred Perlstein  *
92e322d37SHiroki Sato  * Redistribution and use in source and binary forms, with or without
102e322d37SHiroki Sato  * modification, are permitted provided that the following conditions are met:
112e322d37SHiroki Sato  * - Redistributions of source code must retain the above copyright notice,
122e322d37SHiroki Sato  *   this list of conditions and the following disclaimer.
132e322d37SHiroki Sato  * - Redistributions in binary form must reproduce the above copyright notice,
142e322d37SHiroki Sato  *   this list of conditions and the following disclaimer in the documentation
152e322d37SHiroki Sato  *   and/or other materials provided with the distribution.
162e322d37SHiroki Sato  * - Neither the name of Sun Microsystems, Inc. nor the names of its
172e322d37SHiroki Sato  *   contributors may be used to endorse or promote products derived
182e322d37SHiroki Sato  *   from this software without specific prior written permission.
198360efbdSAlfred Perlstein  *
202e322d37SHiroki Sato  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
212e322d37SHiroki Sato  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
222e322d37SHiroki Sato  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
232e322d37SHiroki Sato  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
242e322d37SHiroki Sato  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
252e322d37SHiroki Sato  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
262e322d37SHiroki Sato  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
272e322d37SHiroki Sato  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
282e322d37SHiroki Sato  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
292e322d37SHiroki Sato  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
302e322d37SHiroki Sato  * POSSIBILITY OF SUCH DAMAGE.
318360efbdSAlfred Perlstein  */
328360efbdSAlfred Perlstein 
338360efbdSAlfred Perlstein /*
348360efbdSAlfred Perlstein  * svc_vc.c, Server side for Connection Oriented based RPC.
358360efbdSAlfred Perlstein  *
368360efbdSAlfred Perlstein  * Actually implements two flavors of transporter -
37*eb8ba6fbSAssume-Zhan  * a tcp rendezvouser (a listener and connection establisher)
388360efbdSAlfred Perlstein  * and a record/tcp stream.
398360efbdSAlfred Perlstein  */
408360efbdSAlfred Perlstein 
418360efbdSAlfred Perlstein #include "namespace.h"
429f5afc13SIan Dowse #include "reentrant.h"
438360efbdSAlfred Perlstein #include <sys/param.h>
448360efbdSAlfred Perlstein #include <sys/poll.h>
458360efbdSAlfred Perlstein #include <sys/socket.h>
468360efbdSAlfred Perlstein #include <sys/un.h>
4708497c02SMartin Blapp #include <sys/time.h>
488360efbdSAlfred Perlstein #include <sys/uio.h>
498360efbdSAlfred Perlstein #include <netinet/in.h>
508360efbdSAlfred Perlstein #include <netinet/tcp.h>
518360efbdSAlfred Perlstein 
528360efbdSAlfred Perlstein #include <assert.h>
538360efbdSAlfred Perlstein #include <err.h>
548360efbdSAlfred Perlstein #include <errno.h>
5508497c02SMartin Blapp #include <fcntl.h>
568360efbdSAlfred Perlstein #include <stdio.h>
578360efbdSAlfred Perlstein #include <stdlib.h>
588360efbdSAlfred Perlstein #include <string.h>
598360efbdSAlfred Perlstein #include <unistd.h>
608360efbdSAlfred Perlstein 
618360efbdSAlfred Perlstein #include <rpc/rpc.h>
628360efbdSAlfred Perlstein 
638360efbdSAlfred Perlstein #include "rpc_com.h"
64235baf26SDaniel Eischen #include "mt_misc.h"
658360efbdSAlfred Perlstein #include "un-namespace.h"
668360efbdSAlfred Perlstein 
67c05ac53bSDavid E. O'Brien static SVCXPRT *makefd_xprt(int, u_int, u_int);
68c05ac53bSDavid E. O'Brien static bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *);
69c05ac53bSDavid E. O'Brien static enum xprt_stat rendezvous_stat(SVCXPRT *);
70c05ac53bSDavid E. O'Brien static void svc_vc_destroy(SVCXPRT *);
7108497c02SMartin Blapp static void __svc_vc_dodestroy (SVCXPRT *);
72f249dbccSDag-Erling Smørgrav static int read_vc(void *, void *, int);
73f249dbccSDag-Erling Smørgrav static int write_vc(void *, void *, int);
74c05ac53bSDavid E. O'Brien static enum xprt_stat svc_vc_stat(SVCXPRT *);
75c05ac53bSDavid E. O'Brien static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *);
76f249dbccSDag-Erling Smørgrav static bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, void *);
77f249dbccSDag-Erling Smørgrav static bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, void *);
78c05ac53bSDavid E. O'Brien static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *);
79c05ac53bSDavid E. O'Brien static void svc_vc_rendezvous_ops(SVCXPRT *);
80c05ac53bSDavid E. O'Brien static void svc_vc_ops(SVCXPRT *);
81c05ac53bSDavid E. O'Brien static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in);
8208497c02SMartin Blapp static bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq,
8308497c02SMartin Blapp 				   	     void *in);
848360efbdSAlfred Perlstein 
858360efbdSAlfred Perlstein struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */
868360efbdSAlfred Perlstein 	u_int sendsize;
878360efbdSAlfred Perlstein 	u_int recvsize;
8808497c02SMartin Blapp 	int maxrec;
898360efbdSAlfred Perlstein };
908360efbdSAlfred Perlstein 
918360efbdSAlfred Perlstein struct cf_conn {  /* kept in xprt->xp_p1 for actual connection */
928360efbdSAlfred Perlstein 	enum xprt_stat strm_stat;
938360efbdSAlfred Perlstein 	u_int32_t x_id;
948360efbdSAlfred Perlstein 	XDR xdrs;
958360efbdSAlfred Perlstein 	char verf_body[MAX_AUTH_BYTES];
9608497c02SMartin Blapp 	u_int sendsize;
9708497c02SMartin Blapp 	u_int recvsize;
9808497c02SMartin Blapp 	int maxrec;
9908497c02SMartin Blapp 	bool_t nonblock;
10008497c02SMartin Blapp 	struct timeval last_recv_time;
1018360efbdSAlfred Perlstein };
1028360efbdSAlfred Perlstein 
1038360efbdSAlfred Perlstein /*
1048360efbdSAlfred Perlstein  * Usage:
1058360efbdSAlfred Perlstein  *	xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
1068360efbdSAlfred Perlstein  *
1078360efbdSAlfred Perlstein  * Creates, registers, and returns a (rpc) tcp based transporter.
1088360efbdSAlfred Perlstein  * Once *xprt is initialized, it is registered as a transporter
1098360efbdSAlfred Perlstein  * see (svc.h, xprt_register).  This routine returns
1108360efbdSAlfred Perlstein  * a NULL if a problem occurred.
1118360efbdSAlfred Perlstein  *
1128360efbdSAlfred Perlstein  * The filedescriptor passed in is expected to refer to a bound, but
1138360efbdSAlfred Perlstein  * not yet connected socket.
1148360efbdSAlfred Perlstein  *
1158360efbdSAlfred Perlstein  * Since streams do buffered io similar to stdio, the caller can specify
1168360efbdSAlfred Perlstein  * how big the send and receive buffers are via the second and third parms;
1178360efbdSAlfred Perlstein  * 0 => use the system default.
1188360efbdSAlfred Perlstein  */
1198360efbdSAlfred Perlstein SVCXPRT *
svc_vc_create(int fd,u_int sendsize,u_int recvsize)12068895e38SCraig Rodrigues svc_vc_create(int fd, u_int sendsize, u_int recvsize)
1218360efbdSAlfred Perlstein {
122e742fdffSPedro F. Giffuni 	SVCXPRT *xprt = NULL;
1238360efbdSAlfred Perlstein 	struct cf_rendezvous *r = NULL;
1248360efbdSAlfred Perlstein 	struct __rpc_sockinfo si;
1258360efbdSAlfred Perlstein 	struct sockaddr_storage sslocal;
1268360efbdSAlfred Perlstein 	socklen_t slen;
1278360efbdSAlfred Perlstein 
128794295baSMartin Blapp 	if (!__rpc_fd2sockinfo(fd, &si))
129794295baSMartin Blapp 		return NULL;
130794295baSMartin Blapp 
1318360efbdSAlfred Perlstein 	r = mem_alloc(sizeof(*r));
1328360efbdSAlfred Perlstein 	if (r == NULL) {
1338360efbdSAlfred Perlstein 		warnx("svc_vc_create: out of memory");
1348360efbdSAlfred Perlstein 		goto cleanup_svc_vc_create;
1358360efbdSAlfred Perlstein 	}
1368360efbdSAlfred Perlstein 	r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize);
1378360efbdSAlfred Perlstein 	r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize);
13808497c02SMartin Blapp 	r->maxrec = __svc_maxrec;
1398f55a568SDoug Rabson 	xprt = svc_xprt_alloc();
1408360efbdSAlfred Perlstein 	if (xprt == NULL) {
1418360efbdSAlfred Perlstein 		warnx("svc_vc_create: out of memory");
1428360efbdSAlfred Perlstein 		goto cleanup_svc_vc_create;
1438360efbdSAlfred Perlstein 	}
144f249dbccSDag-Erling Smørgrav 	xprt->xp_p1 = r;
1458360efbdSAlfred Perlstein 	xprt->xp_verf = _null_auth;
1468360efbdSAlfred Perlstein 	svc_vc_rendezvous_ops(xprt);
1478360efbdSAlfred Perlstein 	xprt->xp_port = (u_short)-1;	/* It is the rendezvouser */
1488360efbdSAlfred Perlstein 	xprt->xp_fd = fd;
1498360efbdSAlfred Perlstein 
1508360efbdSAlfred Perlstein 	slen = sizeof (struct sockaddr_storage);
1518360efbdSAlfred Perlstein 	if (_getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) {
1528360efbdSAlfred Perlstein 		warnx("svc_vc_create: could not retrieve local addr");
1538360efbdSAlfred Perlstein 		goto cleanup_svc_vc_create;
1548360efbdSAlfred Perlstein 	}
1558360efbdSAlfred Perlstein 
1568360efbdSAlfred Perlstein 	xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len;
1578360efbdSAlfred Perlstein 	xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len);
1588360efbdSAlfred Perlstein 	if (xprt->xp_ltaddr.buf == NULL) {
1598360efbdSAlfred Perlstein 		warnx("svc_vc_create: no mem for local addr");
1608360efbdSAlfred Perlstein 		goto cleanup_svc_vc_create;
1618360efbdSAlfred Perlstein 	}
1628360efbdSAlfred Perlstein 	memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len);
1638360efbdSAlfred Perlstein 
1648360efbdSAlfred Perlstein 	xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage);
1658360efbdSAlfred Perlstein 	xprt_register(xprt);
1668360efbdSAlfred Perlstein 	return (xprt);
1678360efbdSAlfred Perlstein cleanup_svc_vc_create:
168794295baSMartin Blapp 	if (xprt)
169794295baSMartin Blapp 		mem_free(xprt, sizeof(*xprt));
1708360efbdSAlfred Perlstein 	if (r != NULL)
1718360efbdSAlfred Perlstein 		mem_free(r, sizeof(*r));
1728360efbdSAlfred Perlstein 	return (NULL);
1738360efbdSAlfred Perlstein }
1748360efbdSAlfred Perlstein 
1758360efbdSAlfred Perlstein /*
1768360efbdSAlfred Perlstein  * Like svtcp_create(), except the routine takes any *open* UNIX file
1778360efbdSAlfred Perlstein  * descriptor as its first input.
1788360efbdSAlfred Perlstein  */
1798360efbdSAlfred Perlstein SVCXPRT *
svc_fd_create(int fd,u_int sendsize,u_int recvsize)18068895e38SCraig Rodrigues svc_fd_create(int fd, u_int sendsize, u_int recvsize)
1818360efbdSAlfred Perlstein {
1828360efbdSAlfred Perlstein 	struct sockaddr_storage ss;
1838360efbdSAlfred Perlstein 	socklen_t slen;
1848360efbdSAlfred Perlstein 	SVCXPRT *ret;
1858360efbdSAlfred Perlstein 
1868360efbdSAlfred Perlstein 	assert(fd != -1);
1878360efbdSAlfred Perlstein 
1888360efbdSAlfred Perlstein 	ret = makefd_xprt(fd, sendsize, recvsize);
1898360efbdSAlfred Perlstein 	if (ret == NULL)
1908360efbdSAlfred Perlstein 		return NULL;
1918360efbdSAlfred Perlstein 
1928360efbdSAlfred Perlstein 	slen = sizeof (struct sockaddr_storage);
1938360efbdSAlfred Perlstein 	if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
1948360efbdSAlfred Perlstein 		warnx("svc_fd_create: could not retrieve local addr");
1958360efbdSAlfred Perlstein 		goto freedata;
1968360efbdSAlfred Perlstein 	}
1978360efbdSAlfred Perlstein 	ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len;
1988360efbdSAlfred Perlstein 	ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len);
1998360efbdSAlfred Perlstein 	if (ret->xp_ltaddr.buf == NULL) {
2008360efbdSAlfred Perlstein 		warnx("svc_fd_create: no mem for local addr");
2018360efbdSAlfred Perlstein 		goto freedata;
2028360efbdSAlfred Perlstein 	}
2038360efbdSAlfred Perlstein 	memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len);
2048360efbdSAlfred Perlstein 
2058360efbdSAlfred Perlstein 	slen = sizeof (struct sockaddr_storage);
2068360efbdSAlfred Perlstein 	if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
2078360efbdSAlfred Perlstein 		warnx("svc_fd_create: could not retrieve remote addr");
2088360efbdSAlfred Perlstein 		goto freedata;
2098360efbdSAlfred Perlstein 	}
2108360efbdSAlfred Perlstein 	ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len;
2118360efbdSAlfred Perlstein 	ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len);
2128360efbdSAlfred Perlstein 	if (ret->xp_rtaddr.buf == NULL) {
2138360efbdSAlfred Perlstein 		warnx("svc_fd_create: no mem for local addr");
2148360efbdSAlfred Perlstein 		goto freedata;
2158360efbdSAlfred Perlstein 	}
2168360efbdSAlfred Perlstein 	memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len);
2178360efbdSAlfred Perlstein #ifdef PORTMAP
2182abd9cf1SAlfred Perlstein 	if (ss.ss_family == AF_INET || ss.ss_family == AF_LOCAL) {
2198360efbdSAlfred Perlstein 		ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf;
2208360efbdSAlfred Perlstein 		ret->xp_addrlen = sizeof (struct sockaddr_in);
2218360efbdSAlfred Perlstein 	}
2228360efbdSAlfred Perlstein #endif				/* PORTMAP */
2238360efbdSAlfred Perlstein 
2248360efbdSAlfred Perlstein 	return ret;
2258360efbdSAlfred Perlstein 
2268360efbdSAlfred Perlstein freedata:
2278360efbdSAlfred Perlstein 	if (ret->xp_ltaddr.buf != NULL)
2288360efbdSAlfred Perlstein 		mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen);
2298360efbdSAlfred Perlstein 
2308360efbdSAlfred Perlstein 	return NULL;
2318360efbdSAlfred Perlstein }
2328360efbdSAlfred Perlstein 
2338360efbdSAlfred Perlstein static SVCXPRT *
makefd_xprt(int fd,u_int sendsize,u_int recvsize)23468895e38SCraig Rodrigues makefd_xprt(int fd, u_int sendsize, u_int recvsize)
2358360efbdSAlfred Perlstein {
2368360efbdSAlfred Perlstein 	SVCXPRT *xprt;
2378360efbdSAlfred Perlstein 	struct cf_conn *cd;
2388360efbdSAlfred Perlstein 	const char *netid;
2398360efbdSAlfred Perlstein 	struct __rpc_sockinfo si;
2408360efbdSAlfred Perlstein 
2418360efbdSAlfred Perlstein 	assert(fd != -1);
2428360efbdSAlfred Perlstein 
2438f55a568SDoug Rabson 	xprt = svc_xprt_alloc();
2448360efbdSAlfred Perlstein 	if (xprt == NULL) {
2458360efbdSAlfred Perlstein 		warnx("svc_vc: makefd_xprt: out of memory");
2468360efbdSAlfred Perlstein 		goto done;
2478360efbdSAlfred Perlstein 	}
2488360efbdSAlfred Perlstein 	cd = mem_alloc(sizeof(struct cf_conn));
2498360efbdSAlfred Perlstein 	if (cd == NULL) {
2508360efbdSAlfred Perlstein 		warnx("svc_tcp: makefd_xprt: out of memory");
2518f55a568SDoug Rabson 		svc_xprt_free(xprt);
2528360efbdSAlfred Perlstein 		xprt = NULL;
2538360efbdSAlfred Perlstein 		goto done;
2548360efbdSAlfred Perlstein 	}
2558360efbdSAlfred Perlstein 	cd->strm_stat = XPRT_IDLE;
2568360efbdSAlfred Perlstein 	xdrrec_create(&(cd->xdrs), sendsize, recvsize,
257f249dbccSDag-Erling Smørgrav 	    xprt, read_vc, write_vc);
258f249dbccSDag-Erling Smørgrav 	xprt->xp_p1 = cd;
2598360efbdSAlfred Perlstein 	xprt->xp_verf.oa_base = cd->verf_body;
26032223c1bSPedro F. Giffuni 	svc_vc_ops(xprt);  /* truly deals with calls */
2618360efbdSAlfred Perlstein 	xprt->xp_port = 0;  /* this is a connection, not a rendezvouser */
2628360efbdSAlfred Perlstein 	xprt->xp_fd = fd;
2638360efbdSAlfred Perlstein         if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid))
2648360efbdSAlfred Perlstein 		xprt->xp_netid = strdup(netid);
2658360efbdSAlfred Perlstein 
2668360efbdSAlfred Perlstein 	xprt_register(xprt);
2678360efbdSAlfred Perlstein done:
2688360efbdSAlfred Perlstein 	return (xprt);
2698360efbdSAlfred Perlstein }
2708360efbdSAlfred Perlstein 
2718360efbdSAlfred Perlstein /*ARGSUSED*/
2728360efbdSAlfred Perlstein static bool_t
rendezvous_request(SVCXPRT * xprt,struct rpc_msg * msg)27368895e38SCraig Rodrigues rendezvous_request(SVCXPRT *xprt, struct rpc_msg *msg)
2748360efbdSAlfred Perlstein {
27508497c02SMartin Blapp 	int sock, flags;
2768360efbdSAlfred Perlstein 	struct cf_rendezvous *r;
27708497c02SMartin Blapp 	struct cf_conn *cd;
2785eff94eeSStanislav Sedov 	struct sockaddr_storage addr, sslocal;
2795eff94eeSStanislav Sedov 	socklen_t len, slen;
2808360efbdSAlfred Perlstein 	struct __rpc_sockinfo si;
28108497c02SMartin Blapp 	SVCXPRT *newxprt;
28208497c02SMartin Blapp 	fd_set cleanfds;
2838360efbdSAlfred Perlstein 
2848360efbdSAlfred Perlstein 	assert(xprt != NULL);
2858360efbdSAlfred Perlstein 	assert(msg != NULL);
2868360efbdSAlfred Perlstein 
2878360efbdSAlfred Perlstein 	r = (struct cf_rendezvous *)xprt->xp_p1;
2888360efbdSAlfred Perlstein again:
2898360efbdSAlfred Perlstein 	len = sizeof addr;
2908360efbdSAlfred Perlstein 	if ((sock = _accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr,
2918360efbdSAlfred Perlstein 	    &len)) < 0) {
2928360efbdSAlfred Perlstein 		if (errno == EINTR)
2938360efbdSAlfred Perlstein 			goto again;
29408497c02SMartin Blapp 		/*
29508497c02SMartin Blapp 		 * Clean out the most idle file descriptor when we're
29608497c02SMartin Blapp 		 * running out.
29708497c02SMartin Blapp 		 */
29808497c02SMartin Blapp 		if (errno == EMFILE || errno == ENFILE) {
29908497c02SMartin Blapp 			cleanfds = svc_fdset;
30008497c02SMartin Blapp 			__svc_clean_idle(&cleanfds, 0, FALSE);
30108497c02SMartin Blapp 			goto again;
30208497c02SMartin Blapp 		}
3038360efbdSAlfred Perlstein 		return (FALSE);
3048360efbdSAlfred Perlstein 	}
3058360efbdSAlfred Perlstein 	/*
3068360efbdSAlfred Perlstein 	 * make a new transporter (re-uses xprt)
3078360efbdSAlfred Perlstein 	 */
30808497c02SMartin Blapp 	newxprt = makefd_xprt(sock, r->sendsize, r->recvsize);
30908497c02SMartin Blapp 	newxprt->xp_rtaddr.buf = mem_alloc(len);
31008497c02SMartin Blapp 	if (newxprt->xp_rtaddr.buf == NULL)
3118360efbdSAlfred Perlstein 		return (FALSE);
31208497c02SMartin Blapp 	memcpy(newxprt->xp_rtaddr.buf, &addr, len);
31308497c02SMartin Blapp 	newxprt->xp_rtaddr.len = len;
3148360efbdSAlfred Perlstein #ifdef PORTMAP
315866e3c90SAlfred Perlstein 	if (addr.ss_family == AF_INET || addr.ss_family == AF_LOCAL) {
31608497c02SMartin Blapp 		newxprt->xp_raddr = *(struct sockaddr_in *)newxprt->xp_rtaddr.buf;
31708497c02SMartin Blapp 		newxprt->xp_addrlen = sizeof (struct sockaddr_in);
3188360efbdSAlfred Perlstein 	}
3198360efbdSAlfred Perlstein #endif				/* PORTMAP */
3208360efbdSAlfred Perlstein 	if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) {
3218360efbdSAlfred Perlstein 		len = 1;
3228360efbdSAlfred Perlstein 		/* XXX fvdl - is this useful? */
3238360efbdSAlfred Perlstein 		_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &len, sizeof (len));
3248360efbdSAlfred Perlstein 	}
32508497c02SMartin Blapp 
32608497c02SMartin Blapp 	cd = (struct cf_conn *)newxprt->xp_p1;
32708497c02SMartin Blapp 
32808497c02SMartin Blapp 	cd->recvsize = r->recvsize;
32908497c02SMartin Blapp 	cd->sendsize = r->sendsize;
33008497c02SMartin Blapp 	cd->maxrec = r->maxrec;
33108497c02SMartin Blapp 
33208497c02SMartin Blapp 	if (cd->maxrec != 0) {
3330ae0e1eaSMartin Blapp 		flags = _fcntl(sock, F_GETFL, 0);
33408497c02SMartin Blapp 		if (flags  == -1)
33508497c02SMartin Blapp 			return (FALSE);
3360ae0e1eaSMartin Blapp 		if (_fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
33708497c02SMartin Blapp 			return (FALSE);
33808497c02SMartin Blapp 		if (cd->recvsize > cd->maxrec)
33908497c02SMartin Blapp 			cd->recvsize = cd->maxrec;
34008497c02SMartin Blapp 		cd->nonblock = TRUE;
34108497c02SMartin Blapp 		__xdrrec_setnonblock(&cd->xdrs, cd->maxrec);
34208497c02SMartin Blapp 	} else
34308497c02SMartin Blapp 		cd->nonblock = FALSE;
3445eff94eeSStanislav Sedov 	slen = sizeof(struct sockaddr_storage);
3455eff94eeSStanislav Sedov 	if(_getsockname(sock, (struct sockaddr *)(void *)&sslocal, &slen) < 0) {
3465eff94eeSStanislav Sedov 		warnx("svc_vc_create: could not retrieve local addr");
3475eff94eeSStanislav Sedov 		newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = 0;
3485eff94eeSStanislav Sedov 	} else {
3495eff94eeSStanislav Sedov 		newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = sslocal.ss_len;
3505eff94eeSStanislav Sedov 		newxprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len);
3515eff94eeSStanislav Sedov 		if (newxprt->xp_ltaddr.buf == NULL) {
3525eff94eeSStanislav Sedov 			warnx("svc_vc_create: no mem for local addr");
3535eff94eeSStanislav Sedov 			newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = 0;
3545eff94eeSStanislav Sedov 		} else {
3555eff94eeSStanislav Sedov 			memcpy(newxprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len);
3565eff94eeSStanislav Sedov 		}
3575eff94eeSStanislav Sedov 	}
35808497c02SMartin Blapp 
35908497c02SMartin Blapp 	gettimeofday(&cd->last_recv_time, NULL);
36008497c02SMartin Blapp 
3618360efbdSAlfred Perlstein 	return (FALSE); /* there is never an rpc msg to be processed */
3628360efbdSAlfred Perlstein }
3638360efbdSAlfred Perlstein 
3648360efbdSAlfred Perlstein /*ARGSUSED*/
3658360efbdSAlfred Perlstein static enum xprt_stat
rendezvous_stat(SVCXPRT * xprt)36668895e38SCraig Rodrigues rendezvous_stat(SVCXPRT *xprt)
3678360efbdSAlfred Perlstein {
3688360efbdSAlfred Perlstein 
3698360efbdSAlfred Perlstein 	return (XPRT_IDLE);
3708360efbdSAlfred Perlstein }
3718360efbdSAlfred Perlstein 
3728360efbdSAlfred Perlstein static void
svc_vc_destroy(SVCXPRT * xprt)37368895e38SCraig Rodrigues svc_vc_destroy(SVCXPRT *xprt)
3748360efbdSAlfred Perlstein {
37508497c02SMartin Blapp 	assert(xprt != NULL);
37608497c02SMartin Blapp 
37708497c02SMartin Blapp 	xprt_unregister(xprt);
37808497c02SMartin Blapp 	__svc_vc_dodestroy(xprt);
37908497c02SMartin Blapp }
38008497c02SMartin Blapp 
38108497c02SMartin Blapp static void
__svc_vc_dodestroy(SVCXPRT * xprt)38268895e38SCraig Rodrigues __svc_vc_dodestroy(SVCXPRT *xprt)
38308497c02SMartin Blapp {
3848360efbdSAlfred Perlstein 	struct cf_conn *cd;
3858360efbdSAlfred Perlstein 	struct cf_rendezvous *r;
3868360efbdSAlfred Perlstein 
3878360efbdSAlfred Perlstein 	cd = (struct cf_conn *)xprt->xp_p1;
3888360efbdSAlfred Perlstein 
3898360efbdSAlfred Perlstein 	if (xprt->xp_fd != RPC_ANYFD)
3908360efbdSAlfred Perlstein 		(void)_close(xprt->xp_fd);
3918360efbdSAlfred Perlstein 	if (xprt->xp_port != 0) {
3928360efbdSAlfred Perlstein 		/* a rendezvouser socket */
3938360efbdSAlfred Perlstein 		r = (struct cf_rendezvous *)xprt->xp_p1;
3948360efbdSAlfred Perlstein 		mem_free(r, sizeof (struct cf_rendezvous));
3958360efbdSAlfred Perlstein 		xprt->xp_port = 0;
3968360efbdSAlfred Perlstein 	} else {
3978360efbdSAlfred Perlstein 		/* an actual connection socket */
3988360efbdSAlfred Perlstein 		XDR_DESTROY(&(cd->xdrs));
3998360efbdSAlfred Perlstein 		mem_free(cd, sizeof(struct cf_conn));
4008360efbdSAlfred Perlstein 	}
4018360efbdSAlfred Perlstein 	if (xprt->xp_rtaddr.buf)
4028360efbdSAlfred Perlstein 		mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen);
4038360efbdSAlfred Perlstein 	if (xprt->xp_ltaddr.buf)
4048360efbdSAlfred Perlstein 		mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen);
4058360efbdSAlfred Perlstein 	free(xprt->xp_tp);
4068360efbdSAlfred Perlstein 	free(xprt->xp_netid);
4078f55a568SDoug Rabson 	svc_xprt_free(xprt);
4088360efbdSAlfred Perlstein }
4098360efbdSAlfred Perlstein 
4108360efbdSAlfred Perlstein /*ARGSUSED*/
4118360efbdSAlfred Perlstein static bool_t
svc_vc_control(SVCXPRT * xprt,const u_int rq,void * in)41268895e38SCraig Rodrigues svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in)
4138360efbdSAlfred Perlstein {
4148360efbdSAlfred Perlstein 	return (FALSE);
4158360efbdSAlfred Perlstein }
4168360efbdSAlfred Perlstein 
41708497c02SMartin Blapp static bool_t
svc_vc_rendezvous_control(SVCXPRT * xprt,const u_int rq,void * in)41868895e38SCraig Rodrigues svc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in)
41908497c02SMartin Blapp {
42008497c02SMartin Blapp 	struct cf_rendezvous *cfp;
42108497c02SMartin Blapp 
42208497c02SMartin Blapp 	cfp = (struct cf_rendezvous *)xprt->xp_p1;
42308497c02SMartin Blapp 	if (cfp == NULL)
42408497c02SMartin Blapp 		return (FALSE);
42508497c02SMartin Blapp 	switch (rq) {
42608497c02SMartin Blapp 		case SVCGET_CONNMAXREC:
42708497c02SMartin Blapp 			*(int *)in = cfp->maxrec;
42808497c02SMartin Blapp 			break;
42908497c02SMartin Blapp 		case SVCSET_CONNMAXREC:
43008497c02SMartin Blapp 			cfp->maxrec = *(int *)in;
43108497c02SMartin Blapp 			break;
43208497c02SMartin Blapp 		default:
43308497c02SMartin Blapp 			return (FALSE);
43408497c02SMartin Blapp 	}
43508497c02SMartin Blapp 	return (TRUE);
43608497c02SMartin Blapp }
43708497c02SMartin Blapp 
4388360efbdSAlfred Perlstein /*
4398360efbdSAlfred Perlstein  * reads data from the tcp or uip connection.
4408360efbdSAlfred Perlstein  * any error is fatal and the connection is closed.
4418360efbdSAlfred Perlstein  * (And a read of zero bytes is a half closed stream => error.)
4428360efbdSAlfred Perlstein  * All read operations timeout after 35 seconds.  A timeout is
4438360efbdSAlfred Perlstein  * fatal for the connection.
4448360efbdSAlfred Perlstein  */
4458360efbdSAlfred Perlstein static int
read_vc(void * xprtp,void * buf,int len)44668895e38SCraig Rodrigues read_vc(void *xprtp, void *buf, int len)
4478360efbdSAlfred Perlstein {
4488360efbdSAlfred Perlstein 	SVCXPRT *xprt;
4498360efbdSAlfred Perlstein 	int sock;
4508360efbdSAlfred Perlstein 	int milliseconds = 35 * 1000;
4518360efbdSAlfred Perlstein 	struct pollfd pollfd;
45208497c02SMartin Blapp 	struct cf_conn *cfp;
4538360efbdSAlfred Perlstein 
454f249dbccSDag-Erling Smørgrav 	xprt = (SVCXPRT *)xprtp;
4558360efbdSAlfred Perlstein 	assert(xprt != NULL);
4568360efbdSAlfred Perlstein 
4578360efbdSAlfred Perlstein 	sock = xprt->xp_fd;
4588360efbdSAlfred Perlstein 
45908497c02SMartin Blapp 	cfp = (struct cf_conn *)xprt->xp_p1;
46008497c02SMartin Blapp 
46108497c02SMartin Blapp 	if (cfp->nonblock) {
4620ae0e1eaSMartin Blapp 		len = _read(sock, buf, (size_t)len);
46308497c02SMartin Blapp 		if (len < 0) {
46408497c02SMartin Blapp 			if (errno == EAGAIN)
46508497c02SMartin Blapp 				len = 0;
46608497c02SMartin Blapp 			else
46708497c02SMartin Blapp 				goto fatal_err;
46808497c02SMartin Blapp 		}
46908497c02SMartin Blapp 		if (len != 0)
47008497c02SMartin Blapp 			gettimeofday(&cfp->last_recv_time, NULL);
47108497c02SMartin Blapp 		return len;
47208497c02SMartin Blapp 	}
47308497c02SMartin Blapp 
4748360efbdSAlfred Perlstein 	do {
4758360efbdSAlfred Perlstein 		pollfd.fd = sock;
4768360efbdSAlfred Perlstein 		pollfd.events = POLLIN;
4778360efbdSAlfred Perlstein 		pollfd.revents = 0;
4788360efbdSAlfred Perlstein 		switch (_poll(&pollfd, 1, milliseconds)) {
4798360efbdSAlfred Perlstein 		case -1:
480fa87b7eaSAlfred Perlstein 			if (errno == EINTR)
4818360efbdSAlfred Perlstein 				continue;
4828360efbdSAlfred Perlstein 			/*FALLTHROUGH*/
4838360efbdSAlfred Perlstein 		case 0:
4848360efbdSAlfred Perlstein 			goto fatal_err;
4854ed6d634SAlfred Perlstein 
4868360efbdSAlfred Perlstein 		default:
4878360efbdSAlfred Perlstein 			break;
4888360efbdSAlfred Perlstein 		}
4898360efbdSAlfred Perlstein 	} while ((pollfd.revents & POLLIN) == 0);
4908360efbdSAlfred Perlstein 
4910ae0e1eaSMartin Blapp 	if ((len = _read(sock, buf, (size_t)len)) > 0) {
49208497c02SMartin Blapp 		gettimeofday(&cfp->last_recv_time, NULL);
4938360efbdSAlfred Perlstein 		return (len);
4948360efbdSAlfred Perlstein 	}
4958360efbdSAlfred Perlstein 
4968360efbdSAlfred Perlstein fatal_err:
4978360efbdSAlfred Perlstein 	((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
4988360efbdSAlfred Perlstein 	return (-1);
4998360efbdSAlfred Perlstein }
5008360efbdSAlfred Perlstein 
5018360efbdSAlfred Perlstein /*
5028360efbdSAlfred Perlstein  * writes data to the tcp connection.
5038360efbdSAlfred Perlstein  * Any error is fatal and the connection is closed.
5048360efbdSAlfred Perlstein  */
5058360efbdSAlfred Perlstein static int
write_vc(void * xprtp,void * buf,int len)50668895e38SCraig Rodrigues write_vc(void *xprtp, void *buf, int len)
5078360efbdSAlfred Perlstein {
5088360efbdSAlfred Perlstein 	SVCXPRT *xprt;
5098360efbdSAlfred Perlstein 	int i, cnt;
51008497c02SMartin Blapp 	struct cf_conn *cd;
51108497c02SMartin Blapp 	struct timeval tv0, tv1;
5128360efbdSAlfred Perlstein 
513f249dbccSDag-Erling Smørgrav 	xprt = (SVCXPRT *)xprtp;
5148360efbdSAlfred Perlstein 	assert(xprt != NULL);
5158360efbdSAlfred Perlstein 
51608497c02SMartin Blapp 	cd = (struct cf_conn *)xprt->xp_p1;
51708497c02SMartin Blapp 
51808497c02SMartin Blapp 	if (cd->nonblock)
51908497c02SMartin Blapp 		gettimeofday(&tv0, NULL);
52008497c02SMartin Blapp 
521361de173SStefan Farfeleder 	for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) {
52208497c02SMartin Blapp 		i = _write(xprt->xp_fd, buf, (size_t)cnt);
52308497c02SMartin Blapp 		if (i  < 0) {
52408497c02SMartin Blapp 			if (errno != EAGAIN || !cd->nonblock) {
52508497c02SMartin Blapp 				cd->strm_stat = XPRT_DIED;
5268360efbdSAlfred Perlstein 				return (-1);
5278360efbdSAlfred Perlstein 			}
528e2c83f74SRick Macklem 			if (cd->nonblock) {
52908497c02SMartin Blapp 				/*
53008497c02SMartin Blapp 				 * For non-blocking connections, do not
53108497c02SMartin Blapp 				 * take more than 2 seconds writing the
53208497c02SMartin Blapp 				 * data out.
53308497c02SMartin Blapp 				 *
53408497c02SMartin Blapp 				 * XXX 2 is an arbitrary amount.
53508497c02SMartin Blapp 				 */
53608497c02SMartin Blapp 				gettimeofday(&tv1, NULL);
53708497c02SMartin Blapp 				if (tv1.tv_sec - tv0.tv_sec >= 2) {
53808497c02SMartin Blapp 					cd->strm_stat = XPRT_DIED;
5398360efbdSAlfred Perlstein 					return (-1);
5408360efbdSAlfred Perlstein 				}
5418360efbdSAlfred Perlstein 			}
542e2c83f74SRick Macklem 			i = 0;
5438360efbdSAlfred Perlstein 		}
54408497c02SMartin Blapp 	}
5458360efbdSAlfred Perlstein 
5468360efbdSAlfred Perlstein 	return (len);
5478360efbdSAlfred Perlstein }
5488360efbdSAlfred Perlstein 
5498360efbdSAlfred Perlstein static enum xprt_stat
svc_vc_stat(SVCXPRT * xprt)55068895e38SCraig Rodrigues svc_vc_stat(SVCXPRT *xprt)
5518360efbdSAlfred Perlstein {
5528360efbdSAlfred Perlstein 	struct cf_conn *cd;
5538360efbdSAlfred Perlstein 
5548360efbdSAlfred Perlstein 	assert(xprt != NULL);
5558360efbdSAlfred Perlstein 
5568360efbdSAlfred Perlstein 	cd = (struct cf_conn *)(xprt->xp_p1);
5578360efbdSAlfred Perlstein 
5588360efbdSAlfred Perlstein 	if (cd->strm_stat == XPRT_DIED)
5598360efbdSAlfred Perlstein 		return (XPRT_DIED);
5608360efbdSAlfred Perlstein 	if (! xdrrec_eof(&(cd->xdrs)))
5618360efbdSAlfred Perlstein 		return (XPRT_MOREREQS);
5628360efbdSAlfred Perlstein 	return (XPRT_IDLE);
5638360efbdSAlfred Perlstein }
5648360efbdSAlfred Perlstein 
5658360efbdSAlfred Perlstein static bool_t
svc_vc_recv(SVCXPRT * xprt,struct rpc_msg * msg)56668895e38SCraig Rodrigues svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg)
5678360efbdSAlfred Perlstein {
5688360efbdSAlfred Perlstein 	struct cf_conn *cd;
5698360efbdSAlfred Perlstein 	XDR *xdrs;
5708360efbdSAlfred Perlstein 
5718360efbdSAlfred Perlstein 	assert(xprt != NULL);
5728360efbdSAlfred Perlstein 	assert(msg != NULL);
5738360efbdSAlfred Perlstein 
5748360efbdSAlfred Perlstein 	cd = (struct cf_conn *)(xprt->xp_p1);
5758360efbdSAlfred Perlstein 	xdrs = &(cd->xdrs);
5768360efbdSAlfred Perlstein 
57708497c02SMartin Blapp 	if (cd->nonblock) {
57808497c02SMartin Blapp 		if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE))
57908497c02SMartin Blapp 			return FALSE;
580ecc03b80SDoug Rabson 	} else {
581ecc03b80SDoug Rabson 		(void)xdrrec_skiprecord(xdrs);
58208497c02SMartin Blapp 	}
58308497c02SMartin Blapp 
5848360efbdSAlfred Perlstein 	xdrs->x_op = XDR_DECODE;
5858360efbdSAlfred Perlstein 	if (xdr_callmsg(xdrs, msg)) {
5868360efbdSAlfred Perlstein 		cd->x_id = msg->rm_xid;
5878360efbdSAlfred Perlstein 		return (TRUE);
5888360efbdSAlfred Perlstein 	}
5898360efbdSAlfred Perlstein 	cd->strm_stat = XPRT_DIED;
5908360efbdSAlfred Perlstein 	return (FALSE);
5918360efbdSAlfred Perlstein }
5928360efbdSAlfred Perlstein 
5938360efbdSAlfred Perlstein static bool_t
svc_vc_getargs(SVCXPRT * xprt,xdrproc_t xdr_args,void * args_ptr)59468895e38SCraig Rodrigues svc_vc_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
5958360efbdSAlfred Perlstein {
5968f55a568SDoug Rabson 	struct cf_conn *cd;
5978360efbdSAlfred Perlstein 
5988360efbdSAlfred Perlstein 	assert(xprt != NULL);
5998f55a568SDoug Rabson 	cd = (struct cf_conn *)(xprt->xp_p1);
6008f55a568SDoug Rabson 	return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt),
6018f55a568SDoug Rabson 		&cd->xdrs, xdr_args, args_ptr));
6028360efbdSAlfred Perlstein }
6038360efbdSAlfred Perlstein 
6048360efbdSAlfred Perlstein static bool_t
svc_vc_freeargs(SVCXPRT * xprt,xdrproc_t xdr_args,void * args_ptr)60568895e38SCraig Rodrigues svc_vc_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
6068360efbdSAlfred Perlstein {
6078360efbdSAlfred Perlstein 	XDR *xdrs;
6088360efbdSAlfred Perlstein 
6098360efbdSAlfred Perlstein 	assert(xprt != NULL);
6108360efbdSAlfred Perlstein 	/* args_ptr may be NULL */
6118360efbdSAlfred Perlstein 
6128360efbdSAlfred Perlstein 	xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs);
6138360efbdSAlfred Perlstein 
6148360efbdSAlfred Perlstein 	xdrs->x_op = XDR_FREE;
6158360efbdSAlfred Perlstein 	return ((*xdr_args)(xdrs, args_ptr));
6168360efbdSAlfred Perlstein }
6178360efbdSAlfred Perlstein 
6188360efbdSAlfred Perlstein static bool_t
svc_vc_reply(SVCXPRT * xprt,struct rpc_msg * msg)61968895e38SCraig Rodrigues svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg)
6208360efbdSAlfred Perlstein {
6218360efbdSAlfred Perlstein 	struct cf_conn *cd;
6228360efbdSAlfred Perlstein 	XDR *xdrs;
62308497c02SMartin Blapp 	bool_t rstat;
6248f55a568SDoug Rabson 	xdrproc_t xdr_proc;
6258f55a568SDoug Rabson 	caddr_t xdr_where;
6268f55a568SDoug Rabson 	u_int pos;
6278360efbdSAlfred Perlstein 
6288360efbdSAlfred Perlstein 	assert(xprt != NULL);
6298360efbdSAlfred Perlstein 	assert(msg != NULL);
6308360efbdSAlfred Perlstein 
6318360efbdSAlfred Perlstein 	cd = (struct cf_conn *)(xprt->xp_p1);
6328360efbdSAlfred Perlstein 	xdrs = &(cd->xdrs);
6338360efbdSAlfred Perlstein 
6348360efbdSAlfred Perlstein 	xdrs->x_op = XDR_ENCODE;
6358360efbdSAlfred Perlstein 	msg->rm_xid = cd->x_id;
6368f55a568SDoug Rabson 	rstat = TRUE;
6378f55a568SDoug Rabson 	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
6388f55a568SDoug Rabson 	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
6398f55a568SDoug Rabson 		xdr_proc = msg->acpted_rply.ar_results.proc;
6408f55a568SDoug Rabson 		xdr_where = msg->acpted_rply.ar_results.where;
6418f55a568SDoug Rabson 		msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
6428f55a568SDoug Rabson 		msg->acpted_rply.ar_results.where = NULL;
6438f55a568SDoug Rabson 
6448f55a568SDoug Rabson 		pos = XDR_GETPOS(xdrs);
6458f55a568SDoug Rabson 		if (!xdr_replymsg(xdrs, msg) ||
6468f55a568SDoug Rabson 		    !SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where)) {
6478f55a568SDoug Rabson 			XDR_SETPOS(xdrs, pos);
6488f55a568SDoug Rabson 			rstat = FALSE;
6498f55a568SDoug Rabson 		}
6508f55a568SDoug Rabson 	} else {
65108497c02SMartin Blapp 		rstat = xdr_replymsg(xdrs, msg);
6528f55a568SDoug Rabson 	}
6538f55a568SDoug Rabson 
6548f55a568SDoug Rabson 	if (rstat)
6558360efbdSAlfred Perlstein 		(void)xdrrec_endofrecord(xdrs, TRUE);
6568f55a568SDoug Rabson 
65708497c02SMartin Blapp 	return (rstat);
6588360efbdSAlfred Perlstein }
6598360efbdSAlfred Perlstein 
6608360efbdSAlfred Perlstein static void
svc_vc_ops(SVCXPRT * xprt)66168895e38SCraig Rodrigues svc_vc_ops(SVCXPRT *xprt)
6628360efbdSAlfred Perlstein {
6638360efbdSAlfred Perlstein 	static struct xp_ops ops;
6648360efbdSAlfred Perlstein 	static struct xp_ops2 ops2;
6658360efbdSAlfred Perlstein 
6668360efbdSAlfred Perlstein /* VARIABLES PROTECTED BY ops_lock: ops, ops2 */
6678360efbdSAlfred Perlstein 
6688360efbdSAlfred Perlstein 	mutex_lock(&ops_lock);
6698360efbdSAlfred Perlstein 	if (ops.xp_recv == NULL) {
6708360efbdSAlfred Perlstein 		ops.xp_recv = svc_vc_recv;
6718360efbdSAlfred Perlstein 		ops.xp_stat = svc_vc_stat;
6728360efbdSAlfred Perlstein 		ops.xp_getargs = svc_vc_getargs;
6738360efbdSAlfred Perlstein 		ops.xp_reply = svc_vc_reply;
6748360efbdSAlfred Perlstein 		ops.xp_freeargs = svc_vc_freeargs;
6758360efbdSAlfred Perlstein 		ops.xp_destroy = svc_vc_destroy;
6768360efbdSAlfred Perlstein 		ops2.xp_control = svc_vc_control;
6778360efbdSAlfred Perlstein 	}
6788360efbdSAlfred Perlstein 	xprt->xp_ops = &ops;
6798360efbdSAlfred Perlstein 	xprt->xp_ops2 = &ops2;
6808360efbdSAlfred Perlstein 	mutex_unlock(&ops_lock);
6818360efbdSAlfred Perlstein }
6828360efbdSAlfred Perlstein 
6838360efbdSAlfred Perlstein static void
svc_vc_rendezvous_ops(SVCXPRT * xprt)68468895e38SCraig Rodrigues svc_vc_rendezvous_ops(SVCXPRT *xprt)
6858360efbdSAlfred Perlstein {
6868360efbdSAlfred Perlstein 	static struct xp_ops ops;
6878360efbdSAlfred Perlstein 	static struct xp_ops2 ops2;
6888360efbdSAlfred Perlstein 
6898360efbdSAlfred Perlstein 	mutex_lock(&ops_lock);
6908360efbdSAlfred Perlstein 	if (ops.xp_recv == NULL) {
6918360efbdSAlfred Perlstein 		ops.xp_recv = rendezvous_request;
6928360efbdSAlfred Perlstein 		ops.xp_stat = rendezvous_stat;
6938360efbdSAlfred Perlstein 		ops.xp_getargs =
694f249dbccSDag-Erling Smørgrav 		    (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort;
6958360efbdSAlfred Perlstein 		ops.xp_reply =
6961372519bSDavid E. O'Brien 		    (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort;
6978360efbdSAlfred Perlstein 		ops.xp_freeargs =
6988e60fa95SPedro F. Giffuni 		    (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort;
6998360efbdSAlfred Perlstein 		ops.xp_destroy = svc_vc_destroy;
70008497c02SMartin Blapp 		ops2.xp_control = svc_vc_rendezvous_control;
7018360efbdSAlfred Perlstein 	}
7028360efbdSAlfred Perlstein 	xprt->xp_ops = &ops;
7038360efbdSAlfred Perlstein 	xprt->xp_ops2 = &ops2;
7048360efbdSAlfred Perlstein 	mutex_unlock(&ops_lock);
7058360efbdSAlfred Perlstein }
7068360efbdSAlfred Perlstein 
7074ed6d634SAlfred Perlstein /*
708ce9bc43cSMartin Blapp  * Get the effective UID of the sending process. Used by rpcbind, keyserv
709ce9bc43cSMartin Blapp  * and rpc.yppasswdd on AF_LOCAL.
7104ed6d634SAlfred Perlstein  */
7114ed6d634SAlfred Perlstein int
__rpc_get_local_uid(SVCXPRT * transp,uid_t * uid)712ce9bc43cSMartin Blapp __rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) {
713ce9bc43cSMartin Blapp 	int sock, ret;
714ce9bc43cSMartin Blapp 	gid_t egid;
715ce9bc43cSMartin Blapp 	uid_t euid;
716ce9bc43cSMartin Blapp 	struct sockaddr *sa;
71708760d5aSAlfred Perlstein 
718ce9bc43cSMartin Blapp 	sock = transp->xp_fd;
719ce9bc43cSMartin Blapp 	sa = (struct sockaddr *)transp->xp_rtaddr.buf;
720ce9bc43cSMartin Blapp 	if (sa->sa_family == AF_LOCAL) {
721ce9bc43cSMartin Blapp 		ret = getpeereid(sock, &euid, &egid);
722ce9bc43cSMartin Blapp 		if (ret == 0)
723ce9bc43cSMartin Blapp 			*uid = euid;
724ce9bc43cSMartin Blapp 		return (ret);
725ce9bc43cSMartin Blapp 	} else
72608760d5aSAlfred Perlstein 		return (-1);
7274ed6d634SAlfred Perlstein }
72808497c02SMartin Blapp 
72908497c02SMartin Blapp /*
73008497c02SMartin Blapp  * Destroy xprts that have not have had any activity in 'timeout' seconds.
73108497c02SMartin Blapp  * If 'cleanblock' is true, blocking connections (the default) are also
73208497c02SMartin Blapp  * cleaned. If timeout is 0, the least active connection is picked.
73308497c02SMartin Blapp  */
73408497c02SMartin Blapp bool_t
__svc_clean_idle(fd_set * fds,int timeout,bool_t cleanblock)73508497c02SMartin Blapp __svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock)
73608497c02SMartin Blapp {
73708497c02SMartin Blapp 	int i, ncleaned;
73808497c02SMartin Blapp 	SVCXPRT *xprt, *least_active;
73908497c02SMartin Blapp 	struct timeval tv, tdiff, tmax;
74008497c02SMartin Blapp 	struct cf_conn *cd;
74108497c02SMartin Blapp 
74208497c02SMartin Blapp 	gettimeofday(&tv, NULL);
74308497c02SMartin Blapp 	tmax.tv_sec = tmax.tv_usec = 0;
74408497c02SMartin Blapp 	least_active = NULL;
74508497c02SMartin Blapp 	rwlock_wrlock(&svc_fd_lock);
74608497c02SMartin Blapp 	for (i = ncleaned = 0; i <= svc_maxfd; i++) {
74708497c02SMartin Blapp 		if (FD_ISSET(i, fds)) {
74808497c02SMartin Blapp 			xprt = __svc_xports[i];
74908497c02SMartin Blapp 			if (xprt == NULL || xprt->xp_ops == NULL ||
75008497c02SMartin Blapp 			    xprt->xp_ops->xp_recv != svc_vc_recv)
75108497c02SMartin Blapp 				continue;
75208497c02SMartin Blapp 			cd = (struct cf_conn *)xprt->xp_p1;
75308497c02SMartin Blapp 			if (!cleanblock && !cd->nonblock)
75408497c02SMartin Blapp 				continue;
75508497c02SMartin Blapp 			if (timeout == 0) {
75608497c02SMartin Blapp 				timersub(&tv, &cd->last_recv_time, &tdiff);
75708497c02SMartin Blapp 				if (timercmp(&tdiff, &tmax, >)) {
75808497c02SMartin Blapp 					tmax = tdiff;
75908497c02SMartin Blapp 					least_active = xprt;
76008497c02SMartin Blapp 				}
76108497c02SMartin Blapp 				continue;
76208497c02SMartin Blapp 			}
76308497c02SMartin Blapp 			if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) {
76408497c02SMartin Blapp 				__xprt_unregister_unlocked(xprt);
76508497c02SMartin Blapp 				__svc_vc_dodestroy(xprt);
76608497c02SMartin Blapp 				ncleaned++;
76708497c02SMartin Blapp 			}
76808497c02SMartin Blapp 		}
76908497c02SMartin Blapp 	}
77008497c02SMartin Blapp 	if (timeout == 0 && least_active != NULL) {
77108497c02SMartin Blapp 		__xprt_unregister_unlocked(least_active);
77208497c02SMartin Blapp 		__svc_vc_dodestroy(least_active);
77308497c02SMartin Blapp 		ncleaned++;
77408497c02SMartin Blapp 	}
77508497c02SMartin Blapp 	rwlock_unlock(&svc_fd_lock);
77608497c02SMartin Blapp 	return ncleaned > 0 ? TRUE : FALSE;
77708497c02SMartin Blapp }
778