174462Salfred/*	$NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $	*/
274462Salfred
3261057Smav/*-
4261057Smav * Copyright (c) 2009, Sun Microsystems, Inc.
5261057Smav * All rights reserved.
6261057Smav *
7261057Smav * Redistribution and use in source and binary forms, with or without
8261057Smav * modification, are permitted provided that the following conditions are met:
9261057Smav * - Redistributions of source code must retain the above copyright notice,
10261057Smav *   this list of conditions and the following disclaimer.
11261057Smav * - Redistributions in binary form must reproduce the above copyright notice,
12261057Smav *   this list of conditions and the following disclaimer in the documentation
13261057Smav *   and/or other materials provided with the distribution.
14261057Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its
15261057Smav *   contributors may be used to endorse or promote products derived
16261057Smav *   from this software without specific prior written permission.
1774462Salfred *
18261057Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19261057Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20261057Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21261057Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22261057Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23261057Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24261057Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25261057Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26261057Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27261057Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28261057Smav * POSSIBILITY OF SUCH DAMAGE.
2974462Salfred */
3074462Salfred
3174462Salfred#if defined(LIBC_SCCS) && !defined(lint)
32136581Sobrienstatic char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
3374462Salfredstatic char *sccsid = "@(#)svc_tcp.c	2.2 88/08/01 4.0 RPCSRC";
3474462Salfred#endif
3592990Sobrien#include <sys/cdefs.h>
3692990Sobrien__FBSDID("$FreeBSD$");
3774462Salfred
3874462Salfred/*
3974462Salfred * svc_vc.c, Server side for Connection Oriented based RPC.
4074462Salfred *
4174462Salfred * Actually implements two flavors of transporter -
4274462Salfred * a tcp rendezvouser (a listner and connection establisher)
4374462Salfred * and a record/tcp stream.
4474462Salfred */
4574462Salfred
4675094Siedowse#include "namespace.h"
4774462Salfred#include "reentrant.h"
4874462Salfred#include <sys/types.h>
4974462Salfred#include <sys/param.h>
5074462Salfred#include <sys/poll.h>
5174462Salfred#include <sys/socket.h>
5274462Salfred#include <sys/un.h>
53109359Smbr#include <sys/time.h>
5474462Salfred#include <sys/uio.h>
5574462Salfred#include <netinet/in.h>
5674462Salfred#include <netinet/tcp.h>
5774462Salfred
5874462Salfred#include <assert.h>
5974462Salfred#include <err.h>
6074462Salfred#include <errno.h>
61109359Smbr#include <fcntl.h>
6274462Salfred#include <stdio.h>
6374462Salfred#include <stdlib.h>
6474462Salfred#include <string.h>
6574462Salfred#include <unistd.h>
6674462Salfred
6774462Salfred#include <rpc/rpc.h>
6874462Salfred
6974462Salfred#include "rpc_com.h"
70156090Sdeischen#include "mt_misc.h"
7174462Salfred#include "un-namespace.h"
7274462Salfred
7392905Sobrienstatic SVCXPRT *makefd_xprt(int, u_int, u_int);
7492905Sobrienstatic bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *);
7592905Sobrienstatic enum xprt_stat rendezvous_stat(SVCXPRT *);
7692905Sobrienstatic void svc_vc_destroy(SVCXPRT *);
77109359Smbrstatic void __svc_vc_dodestroy (SVCXPRT *);
7895658Sdesstatic int read_vc(void *, void *, int);
7995658Sdesstatic int write_vc(void *, void *, int);
8092905Sobrienstatic enum xprt_stat svc_vc_stat(SVCXPRT *);
8192905Sobrienstatic bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *);
8295658Sdesstatic bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, void *);
8395658Sdesstatic bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, void *);
8492905Sobrienstatic bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *);
8592905Sobrienstatic void svc_vc_rendezvous_ops(SVCXPRT *);
8692905Sobrienstatic void svc_vc_ops(SVCXPRT *);
8792905Sobrienstatic bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in);
88109359Smbrstatic bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq,
89109359Smbr				   	     void *in);
9074462Salfred
9174462Salfredstruct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */
9274462Salfred	u_int sendsize;
9374462Salfred	u_int recvsize;
94109359Smbr	int maxrec;
9574462Salfred};
9674462Salfred
9774462Salfredstruct cf_conn {  /* kept in xprt->xp_p1 for actual connection */
9874462Salfred	enum xprt_stat strm_stat;
9974462Salfred	u_int32_t x_id;
10074462Salfred	XDR xdrs;
10174462Salfred	char verf_body[MAX_AUTH_BYTES];
102109359Smbr	u_int sendsize;
103109359Smbr	u_int recvsize;
104109359Smbr	int maxrec;
105109359Smbr	bool_t nonblock;
106109359Smbr	struct timeval last_recv_time;
10774462Salfred};
10874462Salfred
10974462Salfred/*
11074462Salfred * Usage:
11174462Salfred *	xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
11274462Salfred *
11374462Salfred * Creates, registers, and returns a (rpc) tcp based transporter.
11474462Salfred * Once *xprt is initialized, it is registered as a transporter
11574462Salfred * see (svc.h, xprt_register).  This routine returns
11674462Salfred * a NULL if a problem occurred.
11774462Salfred *
11874462Salfred * The filedescriptor passed in is expected to refer to a bound, but
11974462Salfred * not yet connected socket.
12074462Salfred *
12174462Salfred * Since streams do buffered io similar to stdio, the caller can specify
12274462Salfred * how big the send and receive buffers are via the second and third parms;
12374462Salfred * 0 => use the system default.
12474462Salfred */
12574462SalfredSVCXPRT *
12674462Salfredsvc_vc_create(fd, sendsize, recvsize)
12774462Salfred	int fd;
12874462Salfred	u_int sendsize;
12974462Salfred	u_int recvsize;
13074462Salfred{
13174462Salfred	SVCXPRT *xprt;
13274462Salfred	struct cf_rendezvous *r = NULL;
13374462Salfred	struct __rpc_sockinfo si;
13474462Salfred	struct sockaddr_storage sslocal;
13574462Salfred	socklen_t slen;
13674462Salfred
137162196Smbr	if (!__rpc_fd2sockinfo(fd, &si))
138162196Smbr		return NULL;
139162196Smbr
14074462Salfred	r = mem_alloc(sizeof(*r));
14174462Salfred	if (r == NULL) {
14274462Salfred		warnx("svc_vc_create: out of memory");
14374462Salfred		goto cleanup_svc_vc_create;
14474462Salfred	}
14574462Salfred	r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize);
14674462Salfred	r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize);
147109359Smbr	r->maxrec = __svc_maxrec;
148181344Sdfr	xprt = svc_xprt_alloc();
14974462Salfred	if (xprt == NULL) {
15074462Salfred		warnx("svc_vc_create: out of memory");
15174462Salfred		goto cleanup_svc_vc_create;
15274462Salfred	}
15395658Sdes	xprt->xp_p1 = r;
15474462Salfred	xprt->xp_verf = _null_auth;
15574462Salfred	svc_vc_rendezvous_ops(xprt);
15674462Salfred	xprt->xp_port = (u_short)-1;	/* It is the rendezvouser */
15774462Salfred	xprt->xp_fd = fd;
15874462Salfred
15974462Salfred	slen = sizeof (struct sockaddr_storage);
16074462Salfred	if (_getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) {
16174462Salfred		warnx("svc_vc_create: could not retrieve local addr");
16274462Salfred		goto cleanup_svc_vc_create;
16374462Salfred	}
16474462Salfred
16574462Salfred	xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len;
16674462Salfred	xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len);
16774462Salfred	if (xprt->xp_ltaddr.buf == NULL) {
16874462Salfred		warnx("svc_vc_create: no mem for local addr");
16974462Salfred		goto cleanup_svc_vc_create;
17074462Salfred	}
17174462Salfred	memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len);
17274462Salfred
17374462Salfred	xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage);
17474462Salfred	xprt_register(xprt);
17574462Salfred	return (xprt);
17674462Salfredcleanup_svc_vc_create:
177162196Smbr	if (xprt)
178162196Smbr		mem_free(xprt, sizeof(*xprt));
17974462Salfred	if (r != NULL)
18074462Salfred		mem_free(r, sizeof(*r));
18174462Salfred	return (NULL);
18274462Salfred}
18374462Salfred
18474462Salfred/*
18574462Salfred * Like svtcp_create(), except the routine takes any *open* UNIX file
18674462Salfred * descriptor as its first input.
18774462Salfred */
18874462SalfredSVCXPRT *
18974462Salfredsvc_fd_create(fd, sendsize, recvsize)
19074462Salfred	int fd;
19174462Salfred	u_int sendsize;
19274462Salfred	u_int recvsize;
19374462Salfred{
19474462Salfred	struct sockaddr_storage ss;
19574462Salfred	socklen_t slen;
19674462Salfred	SVCXPRT *ret;
19774462Salfred
19874462Salfred	assert(fd != -1);
19974462Salfred
20074462Salfred	ret = makefd_xprt(fd, sendsize, recvsize);
20174462Salfred	if (ret == NULL)
20274462Salfred		return NULL;
20374462Salfred
20474462Salfred	slen = sizeof (struct sockaddr_storage);
20574462Salfred	if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
20674462Salfred		warnx("svc_fd_create: could not retrieve local addr");
20774462Salfred		goto freedata;
20874462Salfred	}
20974462Salfred	ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len;
21074462Salfred	ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len);
21174462Salfred	if (ret->xp_ltaddr.buf == NULL) {
21274462Salfred		warnx("svc_fd_create: no mem for local addr");
21374462Salfred		goto freedata;
21474462Salfred	}
21574462Salfred	memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len);
21674462Salfred
21774462Salfred	slen = sizeof (struct sockaddr_storage);
21874462Salfred	if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
21974462Salfred		warnx("svc_fd_create: could not retrieve remote addr");
22074462Salfred		goto freedata;
22174462Salfred	}
22274462Salfred	ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len;
22374462Salfred	ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len);
22474462Salfred	if (ret->xp_rtaddr.buf == NULL) {
22574462Salfred		warnx("svc_fd_create: no mem for local addr");
22674462Salfred		goto freedata;
22774462Salfred	}
22874462Salfred	memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len);
22974462Salfred#ifdef PORTMAP
23090272Salfred	if (ss.ss_family == AF_INET || ss.ss_family == AF_LOCAL) {
23174462Salfred		ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf;
23274462Salfred		ret->xp_addrlen = sizeof (struct sockaddr_in);
23374462Salfred	}
23474462Salfred#endif				/* PORTMAP */
23574462Salfred
23674462Salfred	return ret;
23774462Salfred
23874462Salfredfreedata:
23974462Salfred	if (ret->xp_ltaddr.buf != NULL)
24074462Salfred		mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen);
24174462Salfred
24274462Salfred	return NULL;
24374462Salfred}
24474462Salfred
24574462Salfredstatic SVCXPRT *
24674462Salfredmakefd_xprt(fd, sendsize, recvsize)
24774462Salfred	int fd;
24874462Salfred	u_int sendsize;
24974462Salfred	u_int recvsize;
25074462Salfred{
25174462Salfred	SVCXPRT *xprt;
25274462Salfred	struct cf_conn *cd;
25374462Salfred	const char *netid;
25474462Salfred	struct __rpc_sockinfo si;
25574462Salfred
25674462Salfred	assert(fd != -1);
25774462Salfred
258181344Sdfr	xprt = svc_xprt_alloc();
25974462Salfred	if (xprt == NULL) {
26074462Salfred		warnx("svc_vc: makefd_xprt: out of memory");
26174462Salfred		goto done;
26274462Salfred	}
26374462Salfred	cd = mem_alloc(sizeof(struct cf_conn));
26474462Salfred	if (cd == NULL) {
26574462Salfred		warnx("svc_tcp: makefd_xprt: out of memory");
266181344Sdfr		svc_xprt_free(xprt);
26774462Salfred		xprt = NULL;
26874462Salfred		goto done;
26974462Salfred	}
27074462Salfred	cd->strm_stat = XPRT_IDLE;
27174462Salfred	xdrrec_create(&(cd->xdrs), sendsize, recvsize,
27295658Sdes	    xprt, read_vc, write_vc);
27395658Sdes	xprt->xp_p1 = cd;
27474462Salfred	xprt->xp_verf.oa_base = cd->verf_body;
27574462Salfred	svc_vc_ops(xprt);  /* truely deals with calls */
27674462Salfred	xprt->xp_port = 0;  /* this is a connection, not a rendezvouser */
27774462Salfred	xprt->xp_fd = fd;
27874462Salfred        if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid))
27974462Salfred		xprt->xp_netid = strdup(netid);
28074462Salfred
28174462Salfred	xprt_register(xprt);
28274462Salfreddone:
28374462Salfred	return (xprt);
28474462Salfred}
28574462Salfred
28674462Salfred/*ARGSUSED*/
28774462Salfredstatic bool_t
28874462Salfredrendezvous_request(xprt, msg)
28974462Salfred	SVCXPRT *xprt;
29074462Salfred	struct rpc_msg *msg;
29174462Salfred{
292109359Smbr	int sock, flags;
29374462Salfred	struct cf_rendezvous *r;
294109359Smbr	struct cf_conn *cd;
29574462Salfred	struct sockaddr_storage addr;
29674462Salfred	socklen_t len;
29774462Salfred	struct __rpc_sockinfo si;
298109359Smbr	SVCXPRT *newxprt;
299109359Smbr	fd_set cleanfds;
30074462Salfred
30174462Salfred	assert(xprt != NULL);
30274462Salfred	assert(msg != NULL);
30374462Salfred
30474462Salfred	r = (struct cf_rendezvous *)xprt->xp_p1;
30574462Salfredagain:
30674462Salfred	len = sizeof addr;
30774462Salfred	if ((sock = _accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr,
30874462Salfred	    &len)) < 0) {
30974462Salfred		if (errno == EINTR)
31074462Salfred			goto again;
311109359Smbr		/*
312109359Smbr		 * Clean out the most idle file descriptor when we're
313109359Smbr		 * running out.
314109359Smbr		 */
315109359Smbr		if (errno == EMFILE || errno == ENFILE) {
316109359Smbr			cleanfds = svc_fdset;
317109359Smbr			__svc_clean_idle(&cleanfds, 0, FALSE);
318109359Smbr			goto again;
319109359Smbr		}
320109359Smbr		return (FALSE);
32174462Salfred	}
32274462Salfred	/*
32374462Salfred	 * make a new transporter (re-uses xprt)
32474462Salfred	 */
325109359Smbr	newxprt = makefd_xprt(sock, r->sendsize, r->recvsize);
326109359Smbr	newxprt->xp_rtaddr.buf = mem_alloc(len);
327109359Smbr	if (newxprt->xp_rtaddr.buf == NULL)
32874462Salfred		return (FALSE);
329109359Smbr	memcpy(newxprt->xp_rtaddr.buf, &addr, len);
330109359Smbr	newxprt->xp_rtaddr.len = len;
33174462Salfred#ifdef PORTMAP
33290316Salfred	if (addr.ss_family == AF_INET || addr.ss_family == AF_LOCAL) {
333109359Smbr		newxprt->xp_raddr = *(struct sockaddr_in *)newxprt->xp_rtaddr.buf;
334109359Smbr		newxprt->xp_addrlen = sizeof (struct sockaddr_in);
33574462Salfred	}
33674462Salfred#endif				/* PORTMAP */
33774462Salfred	if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) {
33874462Salfred		len = 1;
33974462Salfred		/* XXX fvdl - is this useful? */
34074462Salfred		_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &len, sizeof (len));
34174462Salfred	}
342109359Smbr
343109359Smbr	cd = (struct cf_conn *)newxprt->xp_p1;
344109359Smbr
345109359Smbr	cd->recvsize = r->recvsize;
346109359Smbr	cd->sendsize = r->sendsize;
347109359Smbr	cd->maxrec = r->maxrec;
348109359Smbr
349109359Smbr	if (cd->maxrec != 0) {
350109904Smbr		flags = _fcntl(sock, F_GETFL, 0);
351109359Smbr		if (flags  == -1)
352109359Smbr			return (FALSE);
353109904Smbr		if (_fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
354109359Smbr			return (FALSE);
355109359Smbr		if (cd->recvsize > cd->maxrec)
356109359Smbr			cd->recvsize = cd->maxrec;
357109359Smbr		cd->nonblock = TRUE;
358109359Smbr		__xdrrec_setnonblock(&cd->xdrs, cd->maxrec);
359109359Smbr	} else
360109359Smbr		cd->nonblock = FALSE;
361109359Smbr
362109359Smbr	gettimeofday(&cd->last_recv_time, NULL);
363109359Smbr
36474462Salfred	return (FALSE); /* there is never an rpc msg to be processed */
36574462Salfred}
36674462Salfred
36774462Salfred/*ARGSUSED*/
36874462Salfredstatic enum xprt_stat
36974462Salfredrendezvous_stat(xprt)
37074462Salfred	SVCXPRT *xprt;
37174462Salfred{
37274462Salfred
37374462Salfred	return (XPRT_IDLE);
37474462Salfred}
37574462Salfred
37674462Salfredstatic void
37774462Salfredsvc_vc_destroy(xprt)
37874462Salfred	SVCXPRT *xprt;
37974462Salfred{
380109359Smbr	assert(xprt != NULL);
381109359Smbr
382109359Smbr	xprt_unregister(xprt);
383109359Smbr	__svc_vc_dodestroy(xprt);
384109359Smbr}
385109359Smbr
386109359Smbrstatic void
387109359Smbr__svc_vc_dodestroy(xprt)
388109359Smbr	SVCXPRT *xprt;
389109359Smbr{
39074462Salfred	struct cf_conn *cd;
39174462Salfred	struct cf_rendezvous *r;
39274462Salfred
39374462Salfred	cd = (struct cf_conn *)xprt->xp_p1;
39474462Salfred
39574462Salfred	if (xprt->xp_fd != RPC_ANYFD)
39674462Salfred		(void)_close(xprt->xp_fd);
39774462Salfred	if (xprt->xp_port != 0) {
39874462Salfred		/* a rendezvouser socket */
39974462Salfred		r = (struct cf_rendezvous *)xprt->xp_p1;
40074462Salfred		mem_free(r, sizeof (struct cf_rendezvous));
40174462Salfred		xprt->xp_port = 0;
40274462Salfred	} else {
40374462Salfred		/* an actual connection socket */
40474462Salfred		XDR_DESTROY(&(cd->xdrs));
40574462Salfred		mem_free(cd, sizeof(struct cf_conn));
40674462Salfred	}
40774462Salfred	if (xprt->xp_rtaddr.buf)
40874462Salfred		mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen);
40974462Salfred	if (xprt->xp_ltaddr.buf)
41074462Salfred		mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen);
41174462Salfred	if (xprt->xp_tp)
41274462Salfred		free(xprt->xp_tp);
41374462Salfred	if (xprt->xp_netid)
41474462Salfred		free(xprt->xp_netid);
415181344Sdfr	svc_xprt_free(xprt);
41674462Salfred}
41774462Salfred
41874462Salfred/*ARGSUSED*/
41974462Salfredstatic bool_t
42074462Salfredsvc_vc_control(xprt, rq, in)
42174462Salfred	SVCXPRT *xprt;
42274462Salfred	const u_int rq;
42374462Salfred	void *in;
42474462Salfred{
42574462Salfred	return (FALSE);
42674462Salfred}
42774462Salfred
428109359Smbrstatic bool_t
429109359Smbrsvc_vc_rendezvous_control(xprt, rq, in)
430109359Smbr	SVCXPRT *xprt;
431109359Smbr	const u_int rq;
432109359Smbr	void *in;
433109359Smbr{
434109359Smbr	struct cf_rendezvous *cfp;
435109359Smbr
436109359Smbr	cfp = (struct cf_rendezvous *)xprt->xp_p1;
437109359Smbr	if (cfp == NULL)
438109359Smbr		return (FALSE);
439109359Smbr	switch (rq) {
440109359Smbr		case SVCGET_CONNMAXREC:
441109359Smbr			*(int *)in = cfp->maxrec;
442109359Smbr			break;
443109359Smbr		case SVCSET_CONNMAXREC:
444109359Smbr			cfp->maxrec = *(int *)in;
445109359Smbr			break;
446109359Smbr		default:
447109359Smbr			return (FALSE);
448109359Smbr	}
449109359Smbr	return (TRUE);
450109359Smbr}
451109359Smbr
45274462Salfred/*
45374462Salfred * reads data from the tcp or uip connection.
45474462Salfred * any error is fatal and the connection is closed.
45574462Salfred * (And a read of zero bytes is a half closed stream => error.)
45674462Salfred * All read operations timeout after 35 seconds.  A timeout is
45774462Salfred * fatal for the connection.
45874462Salfred */
45974462Salfredstatic int
46074462Salfredread_vc(xprtp, buf, len)
46195658Sdes	void *xprtp;
46295658Sdes	void *buf;
46374462Salfred	int len;
46474462Salfred{
46574462Salfred	SVCXPRT *xprt;
46674462Salfred	int sock;
46774462Salfred	int milliseconds = 35 * 1000;
46874462Salfred	struct pollfd pollfd;
469109359Smbr	struct cf_conn *cfp;
47074462Salfred
47195658Sdes	xprt = (SVCXPRT *)xprtp;
47274462Salfred	assert(xprt != NULL);
47374462Salfred
47474462Salfred	sock = xprt->xp_fd;
47574462Salfred
476109359Smbr	cfp = (struct cf_conn *)xprt->xp_p1;
477109359Smbr
478109359Smbr	if (cfp->nonblock) {
479116391Smbr		len = _read(sock, buf, (size_t)len);
480109359Smbr		if (len < 0) {
481109359Smbr			if (errno == EAGAIN)
482109359Smbr				len = 0;
483109359Smbr			else
484109359Smbr				goto fatal_err;
485109359Smbr		}
486109359Smbr		if (len != 0)
487109359Smbr			gettimeofday(&cfp->last_recv_time, NULL);
488109359Smbr		return len;
489109359Smbr	}
490109359Smbr
49174536Salfred	do {
49274536Salfred		pollfd.fd = sock;
49374536Salfred		pollfd.events = POLLIN;
49474462Salfred		pollfd.revents = 0;
49574536Salfred		switch (_poll(&pollfd, 1, milliseconds)) {
49674536Salfred		case -1:
49774536Salfred			if (errno == EINTR)
49874536Salfred				continue;
49974536Salfred			/*FALLTHROUGH*/
50074627Salfred		case 0:
50174627Salfred			goto fatal_err;
50274627Salfred
50374627Salfred		default:
50474627Salfred			break;
50574536Salfred		}
50674536Salfred	} while ((pollfd.revents & POLLIN) == 0);
50774462Salfred
508116391Smbr	if ((len = _read(sock, buf, (size_t)len)) > 0) {
509116391Smbr		gettimeofday(&cfp->last_recv_time, NULL);
510116391Smbr		return (len);
51174462Salfred	}
51274462Salfred
51374462Salfredfatal_err:
51474462Salfred	((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
51574462Salfred	return (-1);
51674462Salfred}
51774462Salfred
51874462Salfred/*
51974462Salfred * writes data to the tcp connection.
52074462Salfred * Any error is fatal and the connection is closed.
52174462Salfred */
52274462Salfredstatic int
52374462Salfredwrite_vc(xprtp, buf, len)
52495658Sdes	void *xprtp;
52595658Sdes	void *buf;
52674462Salfred	int len;
52774462Salfred{
52874462Salfred	SVCXPRT *xprt;
52974462Salfred	int i, cnt;
530109359Smbr	struct cf_conn *cd;
531109359Smbr	struct timeval tv0, tv1;
53274462Salfred
53395658Sdes	xprt = (SVCXPRT *)xprtp;
53474462Salfred	assert(xprt != NULL);
535109359Smbr
536109359Smbr	cd = (struct cf_conn *)xprt->xp_p1;
537109359Smbr
538109359Smbr	if (cd->nonblock)
539109359Smbr		gettimeofday(&tv0, NULL);
54074462Salfred
541133693Sstefanf	for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) {
542116391Smbr		i = _write(xprt->xp_fd, buf, (size_t)cnt);
543109359Smbr		if (i  < 0) {
544109359Smbr			if (errno != EAGAIN || !cd->nonblock) {
545109359Smbr				cd->strm_stat = XPRT_DIED;
54674462Salfred				return (-1);
54774462Salfred			}
548220519Srmacklem			if (cd->nonblock) {
549109359Smbr				/*
550109359Smbr				 * For non-blocking connections, do not
551109359Smbr				 * take more than 2 seconds writing the
552109359Smbr				 * data out.
553109359Smbr				 *
554109359Smbr				 * XXX 2 is an arbitrary amount.
555109359Smbr				 */
556109359Smbr				gettimeofday(&tv1, NULL);
557109359Smbr				if (tv1.tv_sec - tv0.tv_sec >= 2) {
558109359Smbr					cd->strm_stat = XPRT_DIED;
559109359Smbr					return (-1);
560109359Smbr				}
56174462Salfred			}
562220519Srmacklem			i = 0;
56374462Salfred		}
56474462Salfred	}
56574462Salfred
56674462Salfred	return (len);
56774462Salfred}
56874462Salfred
56974462Salfredstatic enum xprt_stat
57074462Salfredsvc_vc_stat(xprt)
57174462Salfred	SVCXPRT *xprt;
57274462Salfred{
57374462Salfred	struct cf_conn *cd;
57474462Salfred
57574462Salfred	assert(xprt != NULL);
57674462Salfred
57774462Salfred	cd = (struct cf_conn *)(xprt->xp_p1);
57874462Salfred
57974462Salfred	if (cd->strm_stat == XPRT_DIED)
58074462Salfred		return (XPRT_DIED);
58174462Salfred	if (! xdrrec_eof(&(cd->xdrs)))
58274462Salfred		return (XPRT_MOREREQS);
58374462Salfred	return (XPRT_IDLE);
58474462Salfred}
58574462Salfred
58674462Salfredstatic bool_t
58774462Salfredsvc_vc_recv(xprt, msg)
58874462Salfred	SVCXPRT *xprt;
58974462Salfred	struct rpc_msg *msg;
59074462Salfred{
59174462Salfred	struct cf_conn *cd;
59274462Salfred	XDR *xdrs;
59374462Salfred
59474462Salfred	assert(xprt != NULL);
59574462Salfred	assert(msg != NULL);
59674462Salfred
59774462Salfred	cd = (struct cf_conn *)(xprt->xp_p1);
59874462Salfred	xdrs = &(cd->xdrs);
59974462Salfred
600109359Smbr	if (cd->nonblock) {
601109359Smbr		if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE))
602109359Smbr			return FALSE;
603177737Sdfr	} else {
604177737Sdfr		(void)xdrrec_skiprecord(xdrs);
605109359Smbr	}
606109359Smbr
60774462Salfred	xdrs->x_op = XDR_DECODE;
60874462Salfred	if (xdr_callmsg(xdrs, msg)) {
60974462Salfred		cd->x_id = msg->rm_xid;
61074462Salfred		return (TRUE);
61174462Salfred	}
61274462Salfred	cd->strm_stat = XPRT_DIED;
61374462Salfred	return (FALSE);
61474462Salfred}
61574462Salfred
61674462Salfredstatic bool_t
61774462Salfredsvc_vc_getargs(xprt, xdr_args, args_ptr)
61874462Salfred	SVCXPRT *xprt;
61974462Salfred	xdrproc_t xdr_args;
62095658Sdes	void *args_ptr;
62174462Salfred{
622181344Sdfr	struct cf_conn *cd;
62374462Salfred
62474462Salfred	assert(xprt != NULL);
625181344Sdfr	cd = (struct cf_conn *)(xprt->xp_p1);
626181344Sdfr	return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt),
627181344Sdfr		&cd->xdrs, xdr_args, args_ptr));
62874462Salfred}
62974462Salfred
63074462Salfredstatic bool_t
63174462Salfredsvc_vc_freeargs(xprt, xdr_args, args_ptr)
63274462Salfred	SVCXPRT *xprt;
63374462Salfred	xdrproc_t xdr_args;
63495658Sdes	void *args_ptr;
63574462Salfred{
63674462Salfred	XDR *xdrs;
63774462Salfred
63874462Salfred	assert(xprt != NULL);
63974462Salfred	/* args_ptr may be NULL */
64074462Salfred
64174462Salfred	xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs);
64274462Salfred
64374462Salfred	xdrs->x_op = XDR_FREE;
64474462Salfred	return ((*xdr_args)(xdrs, args_ptr));
64574462Salfred}
64674462Salfred
64774462Salfredstatic bool_t
64874462Salfredsvc_vc_reply(xprt, msg)
64974462Salfred	SVCXPRT *xprt;
65074462Salfred	struct rpc_msg *msg;
65174462Salfred{
65274462Salfred	struct cf_conn *cd;
65374462Salfred	XDR *xdrs;
654109359Smbr	bool_t rstat;
655181344Sdfr	xdrproc_t xdr_proc;
656181344Sdfr	caddr_t xdr_where;
657181344Sdfr	u_int pos;
65874462Salfred
65974462Salfred	assert(xprt != NULL);
66074462Salfred	assert(msg != NULL);
66174462Salfred
66274462Salfred	cd = (struct cf_conn *)(xprt->xp_p1);
66374462Salfred	xdrs = &(cd->xdrs);
66474462Salfred
66574462Salfred	xdrs->x_op = XDR_ENCODE;
66674462Salfred	msg->rm_xid = cd->x_id;
667181344Sdfr	rstat = TRUE;
668181344Sdfr	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
669181344Sdfr	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
670181344Sdfr		xdr_proc = msg->acpted_rply.ar_results.proc;
671181344Sdfr		xdr_where = msg->acpted_rply.ar_results.where;
672181344Sdfr		msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
673181344Sdfr		msg->acpted_rply.ar_results.where = NULL;
674181344Sdfr
675181344Sdfr		pos = XDR_GETPOS(xdrs);
676181344Sdfr		if (!xdr_replymsg(xdrs, msg) ||
677181344Sdfr		    !SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where)) {
678181344Sdfr			XDR_SETPOS(xdrs, pos);
679181344Sdfr			rstat = FALSE;
680181344Sdfr		}
681181344Sdfr	} else {
682181344Sdfr		rstat = xdr_replymsg(xdrs, msg);
683181344Sdfr	}
684181344Sdfr
685181344Sdfr	if (rstat)
686181344Sdfr		(void)xdrrec_endofrecord(xdrs, TRUE);
687181344Sdfr
688109359Smbr	return (rstat);
68974462Salfred}
69074462Salfred
69174462Salfredstatic void
69274462Salfredsvc_vc_ops(xprt)
69374462Salfred	SVCXPRT *xprt;
69474462Salfred{
69574462Salfred	static struct xp_ops ops;
69674462Salfred	static struct xp_ops2 ops2;
69774462Salfred
69874462Salfred/* VARIABLES PROTECTED BY ops_lock: ops, ops2 */
69974462Salfred
70074462Salfred	mutex_lock(&ops_lock);
70174462Salfred	if (ops.xp_recv == NULL) {
70274462Salfred		ops.xp_recv = svc_vc_recv;
70374462Salfred		ops.xp_stat = svc_vc_stat;
70474462Salfred		ops.xp_getargs = svc_vc_getargs;
70574462Salfred		ops.xp_reply = svc_vc_reply;
70674462Salfred		ops.xp_freeargs = svc_vc_freeargs;
70774462Salfred		ops.xp_destroy = svc_vc_destroy;
70874462Salfred		ops2.xp_control = svc_vc_control;
70974462Salfred	}
71074462Salfred	xprt->xp_ops = &ops;
71174462Salfred	xprt->xp_ops2 = &ops2;
71274462Salfred	mutex_unlock(&ops_lock);
71374462Salfred}
71474462Salfred
71574462Salfredstatic void
71674462Salfredsvc_vc_rendezvous_ops(xprt)
71774462Salfred	SVCXPRT *xprt;
71874462Salfred{
71974462Salfred	static struct xp_ops ops;
72074462Salfred	static struct xp_ops2 ops2;
72174462Salfred
72274462Salfred	mutex_lock(&ops_lock);
72374462Salfred	if (ops.xp_recv == NULL) {
72474462Salfred		ops.xp_recv = rendezvous_request;
72574462Salfred		ops.xp_stat = rendezvous_stat;
72674462Salfred		ops.xp_getargs =
72795658Sdes		    (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort;
72874462Salfred		ops.xp_reply =
72992941Sobrien		    (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort;
73074462Salfred		ops.xp_freeargs =
73195658Sdes		    (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort,
73274462Salfred		ops.xp_destroy = svc_vc_destroy;
733109359Smbr		ops2.xp_control = svc_vc_rendezvous_control;
73474462Salfred	}
73574462Salfred	xprt->xp_ops = &ops;
73674462Salfred	xprt->xp_ops2 = &ops2;
73774462Salfred	mutex_unlock(&ops_lock);
73874462Salfred}
73974462Salfred
74074627Salfred/*
741116391Smbr * Get the effective UID of the sending process. Used by rpcbind, keyserv
742116391Smbr * and rpc.yppasswdd on AF_LOCAL.
74374627Salfred */
74474627Salfredint
745116391Smbr__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) {
746116391Smbr	int sock, ret;
747116391Smbr	gid_t egid;
748116391Smbr	uid_t euid;
749116391Smbr	struct sockaddr *sa;
750116391Smbr
751116391Smbr	sock = transp->xp_fd;
752116391Smbr	sa = (struct sockaddr *)transp->xp_rtaddr.buf;
753116391Smbr	if (sa->sa_family == AF_LOCAL) {
754116391Smbr		ret = getpeereid(sock, &euid, &egid);
755116391Smbr		if (ret == 0)
756116391Smbr			*uid = euid;
757116391Smbr		return (ret);
758116391Smbr	} else
75990257Salfred		return (-1);
76074627Salfred}
761109359Smbr
762109359Smbr/*
763109359Smbr * Destroy xprts that have not have had any activity in 'timeout' seconds.
764109359Smbr * If 'cleanblock' is true, blocking connections (the default) are also
765109359Smbr * cleaned. If timeout is 0, the least active connection is picked.
766109359Smbr */
767109359Smbrbool_t
768109359Smbr__svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock)
769109359Smbr{
770109359Smbr	int i, ncleaned;
771109359Smbr	SVCXPRT *xprt, *least_active;
772109359Smbr	struct timeval tv, tdiff, tmax;
773109359Smbr	struct cf_conn *cd;
774109359Smbr
775109359Smbr	gettimeofday(&tv, NULL);
776109359Smbr	tmax.tv_sec = tmax.tv_usec = 0;
777109359Smbr	least_active = NULL;
778109359Smbr	rwlock_wrlock(&svc_fd_lock);
779109359Smbr	for (i = ncleaned = 0; i <= svc_maxfd; i++) {
780109359Smbr		if (FD_ISSET(i, fds)) {
781109359Smbr			xprt = __svc_xports[i];
782109359Smbr			if (xprt == NULL || xprt->xp_ops == NULL ||
783109359Smbr			    xprt->xp_ops->xp_recv != svc_vc_recv)
784109359Smbr				continue;
785109359Smbr			cd = (struct cf_conn *)xprt->xp_p1;
786109359Smbr			if (!cleanblock && !cd->nonblock)
787109359Smbr				continue;
788109359Smbr			if (timeout == 0) {
789109359Smbr				timersub(&tv, &cd->last_recv_time, &tdiff);
790109359Smbr				if (timercmp(&tdiff, &tmax, >)) {
791109359Smbr					tmax = tdiff;
792109359Smbr					least_active = xprt;
793109359Smbr				}
794109359Smbr				continue;
795109359Smbr			}
796109359Smbr			if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) {
797109359Smbr				__xprt_unregister_unlocked(xprt);
798109359Smbr				__svc_vc_dodestroy(xprt);
799109359Smbr				ncleaned++;
800109359Smbr			}
801109359Smbr		}
802109359Smbr	}
803109359Smbr	if (timeout == 0 && least_active != NULL) {
804109359Smbr		__xprt_unregister_unlocked(least_active);
805109359Smbr		__svc_vc_dodestroy(least_active);
806109359Smbr		ncleaned++;
807109359Smbr	}
808109359Smbr	rwlock_unlock(&svc_fd_lock);
809109359Smbr	return ncleaned > 0 ? TRUE : FALSE;
810109359Smbr}
811