xref: /dflybsd-src/lib/libc/rpc/svc_vc.c (revision 3a05fd2acf14ca94c4e30809432212d52e1241e4)
1ba96d07fShrs /*-
2ba96d07fShrs  * Copyright (c) 2009, Sun Microsystems, Inc.
3ba96d07fShrs  * All rights reserved.
4ce0e08e2SPeter Avalos  *
5ba96d07fShrs  * Redistribution and use in source and binary forms, with or without
6ba96d07fShrs  * modification, are permitted provided that the following conditions are met:
7ba96d07fShrs  * - Redistributions of source code must retain the above copyright notice,
8ba96d07fShrs  *   this list of conditions and the following disclaimer.
9ba96d07fShrs  * - Redistributions in binary form must reproduce the above copyright notice,
10ba96d07fShrs  *   this list of conditions and the following disclaimer in the documentation
11ba96d07fShrs  *   and/or other materials provided with the distribution.
12ba96d07fShrs  * - Neither the name of Sun Microsystems, Inc. nor the names of its
13ba96d07fShrs  *   contributors may be used to endorse or promote products derived
14ba96d07fShrs  *   from this software without specific prior written permission.
15ce0e08e2SPeter Avalos  *
16ba96d07fShrs  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17ba96d07fShrs  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18ba96d07fShrs  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19ba96d07fShrs  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20ba96d07fShrs  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21ba96d07fShrs  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22ba96d07fShrs  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23ba96d07fShrs  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24ba96d07fShrs  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25ba96d07fShrs  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26ba96d07fShrs  * POSSIBILITY OF SUCH DAMAGE.
27ce0e08e2SPeter Avalos  *
28ce0e08e2SPeter Avalos  * @(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro
29ce0e08e2SPeter Avalos  * @(#)svc_tcp.c	2.2 88/08/01 4.0 RPCSRC
30ce0e08e2SPeter Avalos  * $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $
31ce0e08e2SPeter Avalos  * $FreeBSD: src/lib/libc/rpc/svc_vc.c,v 1.27 2008/03/30 09:36:17 dfr Exp $
32ce0e08e2SPeter Avalos  */
33ce0e08e2SPeter Avalos 
34ce0e08e2SPeter Avalos /*
35ce0e08e2SPeter Avalos  * svc_vc.c, Server side for Connection Oriented based RPC.
36ce0e08e2SPeter Avalos  *
37ce0e08e2SPeter Avalos  * Actually implements two flavors of transporter -
38ce0e08e2SPeter Avalos  * a tcp rendezvouser (a listner and connection establisher)
39ce0e08e2SPeter Avalos  * and a record/tcp stream.
40ce0e08e2SPeter Avalos  */
41ce0e08e2SPeter Avalos 
42ce0e08e2SPeter Avalos #include "namespace.h"
43ce0e08e2SPeter Avalos #include "reentrant.h"
44ce0e08e2SPeter Avalos #include <sys/types.h>
45ce0e08e2SPeter Avalos #include <sys/param.h>
46ce0e08e2SPeter Avalos #include <sys/poll.h>
47ce0e08e2SPeter Avalos #include <sys/socket.h>
48ce0e08e2SPeter Avalos #include <sys/un.h>
49ce0e08e2SPeter Avalos #include <sys/time.h>
50ce0e08e2SPeter Avalos #include <sys/uio.h>
51ce0e08e2SPeter Avalos #include <netinet/in.h>
52ce0e08e2SPeter Avalos #include <netinet/tcp.h>
53ce0e08e2SPeter Avalos 
54ce0e08e2SPeter Avalos #include <assert.h>
55ce0e08e2SPeter Avalos #include <err.h>
56ce0e08e2SPeter Avalos #include <errno.h>
57ce0e08e2SPeter Avalos #include <fcntl.h>
58ce0e08e2SPeter Avalos #include <stdio.h>
59ce0e08e2SPeter Avalos #include <stdlib.h>
60ce0e08e2SPeter Avalos #include <string.h>
61ce0e08e2SPeter Avalos #include <unistd.h>
62ce0e08e2SPeter Avalos 
63ce0e08e2SPeter Avalos #include <rpc/rpc.h>
64ce0e08e2SPeter Avalos 
65ce0e08e2SPeter Avalos #include "rpc_com.h"
66ce0e08e2SPeter Avalos #include "mt_misc.h"
67ce0e08e2SPeter Avalos #include "un-namespace.h"
68ce0e08e2SPeter Avalos 
69ce0e08e2SPeter Avalos static SVCXPRT		*makefd_xprt(int, u_int, u_int);
70ce0e08e2SPeter Avalos static bool_t		rendezvous_request(SVCXPRT *, struct rpc_msg *);
71ce0e08e2SPeter Avalos static enum xprt_stat	rendezvous_stat(SVCXPRT *);
72ce0e08e2SPeter Avalos static void		svc_vc_destroy(SVCXPRT *);
73ce0e08e2SPeter Avalos static void		__svc_vc_dodestroy (SVCXPRT *);
74ce0e08e2SPeter Avalos static int		read_vc(void *, void *, int);
75ce0e08e2SPeter Avalos static int		write_vc(void *, void *, int);
76ce0e08e2SPeter Avalos static enum xprt_stat	svc_vc_stat(SVCXPRT *);
77ce0e08e2SPeter Avalos static bool_t		svc_vc_recv(SVCXPRT *, struct rpc_msg *);
78ce0e08e2SPeter Avalos static bool_t		svc_vc_getargs(SVCXPRT *, xdrproc_t, void *);
79ce0e08e2SPeter Avalos static bool_t		svc_vc_freeargs(SVCXPRT *, xdrproc_t, void *);
80ce0e08e2SPeter Avalos static bool_t		svc_vc_reply(SVCXPRT *, struct rpc_msg *);
81ce0e08e2SPeter Avalos static void		svc_vc_rendezvous_ops(SVCXPRT *);
82ce0e08e2SPeter Avalos static void		svc_vc_ops(SVCXPRT *);
83ce0e08e2SPeter Avalos static bool_t		svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in);
84ce0e08e2SPeter Avalos static bool_t		svc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq,
85ce0e08e2SPeter Avalos 						  void *in);
86ce0e08e2SPeter Avalos 
87ce0e08e2SPeter Avalos struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */
88ce0e08e2SPeter Avalos 	u_int sendsize;
89ce0e08e2SPeter Avalos 	u_int recvsize;
90ce0e08e2SPeter Avalos 	int maxrec;
91ce0e08e2SPeter Avalos };
92ce0e08e2SPeter Avalos 
93ce0e08e2SPeter Avalos struct cf_conn {  /* kept in xprt->xp_p1 for actual connection */
94ce0e08e2SPeter Avalos 	enum xprt_stat strm_stat;
95ce0e08e2SPeter Avalos 	u_int32_t x_id;
96ce0e08e2SPeter Avalos 	XDR xdrs;
97ce0e08e2SPeter Avalos 	char verf_body[MAX_AUTH_BYTES];
98ce0e08e2SPeter Avalos 	u_int sendsize;
99ce0e08e2SPeter Avalos 	u_int recvsize;
100ce0e08e2SPeter Avalos 	int maxrec;
101ce0e08e2SPeter Avalos 	bool_t nonblock;
102ce0e08e2SPeter Avalos 	struct timeval last_recv_time;
103ce0e08e2SPeter Avalos };
104ce0e08e2SPeter Avalos 
105ce0e08e2SPeter Avalos /*
106ce0e08e2SPeter Avalos  * Usage:
107ce0e08e2SPeter Avalos  *	xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
108ce0e08e2SPeter Avalos  *
109ce0e08e2SPeter Avalos  * Creates, registers, and returns a (rpc) tcp based transporter.
110ce0e08e2SPeter Avalos  * Once *xprt is initialized, it is registered as a transporter
111ce0e08e2SPeter Avalos  * see (svc.h, xprt_register).  This routine returns
112ce0e08e2SPeter Avalos  * a NULL if a problem occurred.
113ce0e08e2SPeter Avalos  *
114ce0e08e2SPeter Avalos  * The filedescriptor passed in is expected to refer to a bound, but
115ce0e08e2SPeter Avalos  * not yet connected socket.
116ce0e08e2SPeter Avalos  *
117ce0e08e2SPeter Avalos  * Since streams do buffered io similar to stdio, the caller can specify
118ce0e08e2SPeter Avalos  * how big the send and receive buffers are via the second and third parms;
119ce0e08e2SPeter Avalos  * 0 => use the system default.
120ce0e08e2SPeter Avalos  */
121ce0e08e2SPeter Avalos SVCXPRT *
svc_vc_create(int fd,u_int sendsize,u_int recvsize)122ce0e08e2SPeter Avalos svc_vc_create(int fd, u_int sendsize, u_int recvsize)
123ce0e08e2SPeter Avalos {
124e5154c07SSascha Wildner 	SVCXPRT *xprt = NULL;
125ce0e08e2SPeter Avalos 	struct cf_rendezvous *r = NULL;
126ce0e08e2SPeter Avalos 	struct __rpc_sockinfo si;
127ce0e08e2SPeter Avalos 	struct sockaddr_storage sslocal;
128ce0e08e2SPeter Avalos 	socklen_t slen;
129ce0e08e2SPeter Avalos 
130ce0e08e2SPeter Avalos 	if (!__rpc_fd2sockinfo(fd, &si))
131ce0e08e2SPeter Avalos 		return NULL;
132ce0e08e2SPeter Avalos 
133ce0e08e2SPeter Avalos 	r = mem_alloc(sizeof(*r));
134ce0e08e2SPeter Avalos 	if (r == NULL) {
135ce0e08e2SPeter Avalos 		warnx("svc_vc_create: out of memory");
136ce0e08e2SPeter Avalos 		goto cleanup_svc_vc_create;
137ce0e08e2SPeter Avalos 	}
138ce0e08e2SPeter Avalos 	r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize);
139ce0e08e2SPeter Avalos 	r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize);
140ce0e08e2SPeter Avalos 	r->maxrec = __svc_maxrec;
141ce0e08e2SPeter Avalos 	xprt = mem_alloc(sizeof(SVCXPRT));
142ce0e08e2SPeter Avalos 	if (xprt == NULL) {
143ce0e08e2SPeter Avalos 		warnx("svc_vc_create: out of memory");
144ce0e08e2SPeter Avalos 		goto cleanup_svc_vc_create;
145ce0e08e2SPeter Avalos 	}
146ce0e08e2SPeter Avalos 	xprt->xp_tp = NULL;
147ce0e08e2SPeter Avalos 	xprt->xp_p1 = r;
148ce0e08e2SPeter Avalos 	xprt->xp_p2 = NULL;
149ce0e08e2SPeter Avalos 	xprt->xp_p3 = NULL;
150ce0e08e2SPeter Avalos 	xprt->xp_verf = _null_auth;
151ce0e08e2SPeter Avalos 	svc_vc_rendezvous_ops(xprt);
152ce0e08e2SPeter Avalos 	xprt->xp_port = (u_short)-1;	/* It is the rendezvouser */
153ce0e08e2SPeter Avalos 	xprt->xp_fd = fd;
154ce0e08e2SPeter Avalos 
155ce0e08e2SPeter Avalos 	slen = sizeof (struct sockaddr_storage);
156ce0e08e2SPeter Avalos 	if (_getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) {
157ce0e08e2SPeter Avalos 		warnx("svc_vc_create: could not retrieve local addr");
158ce0e08e2SPeter Avalos 		goto cleanup_svc_vc_create;
159ce0e08e2SPeter Avalos 	}
160ce0e08e2SPeter Avalos 
161ce0e08e2SPeter Avalos 	xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len;
162ce0e08e2SPeter Avalos 	xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len);
163ce0e08e2SPeter Avalos 	if (xprt->xp_ltaddr.buf == NULL) {
164ce0e08e2SPeter Avalos 		warnx("svc_vc_create: no mem for local addr");
165ce0e08e2SPeter Avalos 		goto cleanup_svc_vc_create;
166ce0e08e2SPeter Avalos 	}
167ce0e08e2SPeter Avalos 	memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len);
168ce0e08e2SPeter Avalos 
169ce0e08e2SPeter Avalos 	xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage);
170ce0e08e2SPeter Avalos 	xprt_register(xprt);
171ce0e08e2SPeter Avalos 	return (xprt);
172ce0e08e2SPeter Avalos cleanup_svc_vc_create:
173ce0e08e2SPeter Avalos 	if (xprt)
174ce0e08e2SPeter Avalos 		mem_free(xprt, sizeof(*xprt));
175ce0e08e2SPeter Avalos 	if (r != NULL)
176ce0e08e2SPeter Avalos 		mem_free(r, sizeof(*r));
177ce0e08e2SPeter Avalos 	return (NULL);
178ce0e08e2SPeter Avalos }
179ce0e08e2SPeter Avalos 
180ce0e08e2SPeter Avalos /*
181ce0e08e2SPeter Avalos  * Like svtcp_create(), except the routine takes any *open* UNIX file
182ce0e08e2SPeter Avalos  * descriptor as its first input.
183ce0e08e2SPeter Avalos  */
184ce0e08e2SPeter Avalos SVCXPRT *
svc_fd_create(int fd,u_int sendsize,u_int recvsize)185ce0e08e2SPeter Avalos svc_fd_create(int fd, u_int sendsize, u_int recvsize)
186ce0e08e2SPeter Avalos {
187ce0e08e2SPeter Avalos 	struct sockaddr_storage ss;
188ce0e08e2SPeter Avalos 	socklen_t slen;
189ce0e08e2SPeter Avalos 	SVCXPRT *ret;
190ce0e08e2SPeter Avalos 
191ce0e08e2SPeter Avalos 	assert(fd != -1);
192ce0e08e2SPeter Avalos 
193ce0e08e2SPeter Avalos 	ret = makefd_xprt(fd, sendsize, recvsize);
194ce0e08e2SPeter Avalos 	if (ret == NULL)
195ce0e08e2SPeter Avalos 		return NULL;
196ce0e08e2SPeter Avalos 
197ce0e08e2SPeter Avalos 	slen = sizeof (struct sockaddr_storage);
198ce0e08e2SPeter Avalos 	if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
199ce0e08e2SPeter Avalos 		warnx("svc_fd_create: could not retrieve local addr");
200ce0e08e2SPeter Avalos 		goto freedata;
201ce0e08e2SPeter Avalos 	}
202ce0e08e2SPeter Avalos 	ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len;
203ce0e08e2SPeter Avalos 	ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len);
204ce0e08e2SPeter Avalos 	if (ret->xp_ltaddr.buf == NULL) {
205ce0e08e2SPeter Avalos 		warnx("svc_fd_create: no mem for local addr");
206ce0e08e2SPeter Avalos 		goto freedata;
207ce0e08e2SPeter Avalos 	}
208ce0e08e2SPeter Avalos 	memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len);
209ce0e08e2SPeter Avalos 
210ce0e08e2SPeter Avalos 	slen = sizeof (struct sockaddr_storage);
211ce0e08e2SPeter Avalos 	if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
212ce0e08e2SPeter Avalos 		warnx("svc_fd_create: could not retrieve remote addr");
213ce0e08e2SPeter Avalos 		goto freedata;
214ce0e08e2SPeter Avalos 	}
215ce0e08e2SPeter Avalos 	ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len;
216ce0e08e2SPeter Avalos 	ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len);
217ce0e08e2SPeter Avalos 	if (ret->xp_rtaddr.buf == NULL) {
218ce0e08e2SPeter Avalos 		warnx("svc_fd_create: no mem for local addr");
219ce0e08e2SPeter Avalos 		goto freedata;
220ce0e08e2SPeter Avalos 	}
221ce0e08e2SPeter Avalos 	memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len);
222ce0e08e2SPeter Avalos #ifdef PORTMAP
223ce0e08e2SPeter Avalos 	if (ss.ss_family == AF_INET || ss.ss_family == AF_LOCAL) {
224ce0e08e2SPeter Avalos 		ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf;
225ce0e08e2SPeter Avalos 		ret->xp_addrlen = sizeof (struct sockaddr_in);
226ce0e08e2SPeter Avalos 	}
227ce0e08e2SPeter Avalos #endif				/* PORTMAP */
228ce0e08e2SPeter Avalos 
229ce0e08e2SPeter Avalos 	return ret;
230ce0e08e2SPeter Avalos 
231ce0e08e2SPeter Avalos freedata:
232ce0e08e2SPeter Avalos 	if (ret->xp_ltaddr.buf != NULL)
233ce0e08e2SPeter Avalos 		mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen);
234ce0e08e2SPeter Avalos 
235ce0e08e2SPeter Avalos 	return NULL;
236ce0e08e2SPeter Avalos }
237ce0e08e2SPeter Avalos 
238ce0e08e2SPeter Avalos static SVCXPRT *
makefd_xprt(int fd,u_int sendsize,u_int recvsize)239ce0e08e2SPeter Avalos makefd_xprt(int fd, u_int sendsize, u_int recvsize)
240ce0e08e2SPeter Avalos {
241ce0e08e2SPeter Avalos 	SVCXPRT *xprt;
242ce0e08e2SPeter Avalos 	struct cf_conn *cd;
243ce0e08e2SPeter Avalos 	const char *netid;
244ce0e08e2SPeter Avalos 	struct __rpc_sockinfo si;
245ce0e08e2SPeter Avalos 
246ce0e08e2SPeter Avalos 	assert(fd != -1);
247ce0e08e2SPeter Avalos 
248ce0e08e2SPeter Avalos 	xprt = mem_alloc(sizeof(SVCXPRT));
249ce0e08e2SPeter Avalos 	if (xprt == NULL) {
250ce0e08e2SPeter Avalos 		warnx("svc_vc: makefd_xprt: out of memory");
251ce0e08e2SPeter Avalos 		goto done;
252ce0e08e2SPeter Avalos 	}
253ce0e08e2SPeter Avalos 	memset(xprt, 0, sizeof *xprt);
254ce0e08e2SPeter Avalos 	cd = mem_alloc(sizeof(struct cf_conn));
255ce0e08e2SPeter Avalos 	if (cd == NULL) {
256ce0e08e2SPeter Avalos 		warnx("svc_tcp: makefd_xprt: out of memory");
257ce0e08e2SPeter Avalos 		mem_free(xprt, sizeof(SVCXPRT));
258ce0e08e2SPeter Avalos 		xprt = NULL;
259ce0e08e2SPeter Avalos 		goto done;
260ce0e08e2SPeter Avalos 	}
261ce0e08e2SPeter Avalos 	cd->strm_stat = XPRT_IDLE;
262ce0e08e2SPeter Avalos 	xdrrec_create(&(cd->xdrs), sendsize, recvsize,
263ce0e08e2SPeter Avalos 	    xprt, read_vc, write_vc);
264ce0e08e2SPeter Avalos 	xprt->xp_p1 = cd;
265ce0e08e2SPeter Avalos 	xprt->xp_verf.oa_base = cd->verf_body;
266ce0e08e2SPeter Avalos 	svc_vc_ops(xprt);  /* truely deals with calls */
267ce0e08e2SPeter Avalos 	xprt->xp_port = 0;  /* this is a connection, not a rendezvouser */
268ce0e08e2SPeter Avalos 	xprt->xp_fd = fd;
269ce0e08e2SPeter Avalos         if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid))
270ce0e08e2SPeter Avalos 		xprt->xp_netid = strdup(netid);
271ce0e08e2SPeter Avalos 
272ce0e08e2SPeter Avalos 	xprt_register(xprt);
273ce0e08e2SPeter Avalos done:
274ce0e08e2SPeter Avalos 	return (xprt);
275ce0e08e2SPeter Avalos }
276ce0e08e2SPeter Avalos 
277ce0e08e2SPeter Avalos /*ARGSUSED*/
278ce0e08e2SPeter Avalos static bool_t
rendezvous_request(SVCXPRT * xprt,struct rpc_msg * msg)279ce0e08e2SPeter Avalos rendezvous_request(SVCXPRT *xprt, struct rpc_msg *msg)
280ce0e08e2SPeter Avalos {
281ce0e08e2SPeter Avalos 	int sock, flags;
282ce0e08e2SPeter Avalos 	struct cf_rendezvous *r;
283ce0e08e2SPeter Avalos 	struct cf_conn *cd;
284ce0e08e2SPeter Avalos 	struct sockaddr_storage addr;
285ce0e08e2SPeter Avalos 	socklen_t len;
286ce0e08e2SPeter Avalos 	struct __rpc_sockinfo si;
287ce0e08e2SPeter Avalos 	SVCXPRT *newxprt;
288ce0e08e2SPeter Avalos 	fd_set cleanfds;
289ce0e08e2SPeter Avalos 
290ce0e08e2SPeter Avalos 	assert(xprt != NULL);
291ce0e08e2SPeter Avalos 	assert(msg != NULL);
292ce0e08e2SPeter Avalos 
293ce0e08e2SPeter Avalos 	r = (struct cf_rendezvous *)xprt->xp_p1;
294ce0e08e2SPeter Avalos again:
295ce0e08e2SPeter Avalos 	len = sizeof addr;
296ce0e08e2SPeter Avalos 	if ((sock = _accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr,
297ce0e08e2SPeter Avalos 	    &len)) < 0) {
298ce0e08e2SPeter Avalos 		if (errno == EINTR)
299ce0e08e2SPeter Avalos 			goto again;
300ce0e08e2SPeter Avalos 		/*
301ce0e08e2SPeter Avalos 		 * Clean out the most idle file descriptor when we're
302ce0e08e2SPeter Avalos 		 * running out.
303ce0e08e2SPeter Avalos 		 */
304ce0e08e2SPeter Avalos 		if (errno == EMFILE || errno == ENFILE) {
305ce0e08e2SPeter Avalos 			cleanfds = svc_fdset;
306ce0e08e2SPeter Avalos 			__svc_clean_idle(&cleanfds, 0, FALSE);
307ce0e08e2SPeter Avalos 			goto again;
308ce0e08e2SPeter Avalos 		}
309ce0e08e2SPeter Avalos 		return (FALSE);
310ce0e08e2SPeter Avalos 	}
311ce0e08e2SPeter Avalos 	/*
312ce0e08e2SPeter Avalos 	 * make a new transporter (re-uses xprt)
313ce0e08e2SPeter Avalos 	 */
314ce0e08e2SPeter Avalos 	newxprt = makefd_xprt(sock, r->sendsize, r->recvsize);
315ce0e08e2SPeter Avalos 	newxprt->xp_rtaddr.buf = mem_alloc(len);
316ce0e08e2SPeter Avalos 	if (newxprt->xp_rtaddr.buf == NULL)
317ce0e08e2SPeter Avalos 		return (FALSE);
318ce0e08e2SPeter Avalos 	memcpy(newxprt->xp_rtaddr.buf, &addr, len);
319ce0e08e2SPeter Avalos 	newxprt->xp_rtaddr.len = len;
320ce0e08e2SPeter Avalos #ifdef PORTMAP
321ce0e08e2SPeter Avalos 	if (addr.ss_family == AF_INET || addr.ss_family == AF_LOCAL) {
322ce0e08e2SPeter Avalos 		newxprt->xp_raddr = *(struct sockaddr_in *)newxprt->xp_rtaddr.buf;
323ce0e08e2SPeter Avalos 		newxprt->xp_addrlen = sizeof (struct sockaddr_in);
324ce0e08e2SPeter Avalos 	}
325ce0e08e2SPeter Avalos #endif				/* PORTMAP */
326ce0e08e2SPeter Avalos 	if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) {
327ce0e08e2SPeter Avalos 		len = 1;
328ce0e08e2SPeter Avalos 		/* XXX fvdl - is this useful? */
329ce0e08e2SPeter Avalos 		_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &len, sizeof (len));
330ce0e08e2SPeter Avalos 	}
331ce0e08e2SPeter Avalos 
332ce0e08e2SPeter Avalos 	cd = (struct cf_conn *)newxprt->xp_p1;
333ce0e08e2SPeter Avalos 
334ce0e08e2SPeter Avalos 	cd->recvsize = r->recvsize;
335ce0e08e2SPeter Avalos 	cd->sendsize = r->sendsize;
336ce0e08e2SPeter Avalos 	cd->maxrec = r->maxrec;
337ce0e08e2SPeter Avalos 
338ce0e08e2SPeter Avalos 	if (cd->maxrec != 0) {
339ce0e08e2SPeter Avalos 		flags = _fcntl(sock, F_GETFL, 0);
340ce0e08e2SPeter Avalos 		if (flags  == -1)
341ce0e08e2SPeter Avalos 			return (FALSE);
342ce0e08e2SPeter Avalos 		if (_fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
343ce0e08e2SPeter Avalos 			return (FALSE);
344ce0e08e2SPeter Avalos 		if (cd->recvsize > cd->maxrec)
345ce0e08e2SPeter Avalos 			cd->recvsize = cd->maxrec;
346ce0e08e2SPeter Avalos 		cd->nonblock = TRUE;
347ce0e08e2SPeter Avalos 		__xdrrec_setnonblock(&cd->xdrs, cd->maxrec);
348ce0e08e2SPeter Avalos 	} else
349ce0e08e2SPeter Avalos 		cd->nonblock = FALSE;
350ce0e08e2SPeter Avalos 
351ce0e08e2SPeter Avalos 	gettimeofday(&cd->last_recv_time, NULL);
352ce0e08e2SPeter Avalos 
353ce0e08e2SPeter Avalos 	return (FALSE); /* there is never an rpc msg to be processed */
354ce0e08e2SPeter Avalos }
355ce0e08e2SPeter Avalos 
356ce0e08e2SPeter Avalos /*ARGSUSED*/
357ce0e08e2SPeter Avalos static enum xprt_stat
rendezvous_stat(SVCXPRT * xprt __unused)3586d7019e6SSascha Wildner rendezvous_stat(SVCXPRT *xprt __unused)
359ce0e08e2SPeter Avalos {
360ce0e08e2SPeter Avalos 
361ce0e08e2SPeter Avalos 	return (XPRT_IDLE);
362ce0e08e2SPeter Avalos }
363ce0e08e2SPeter Avalos 
364ce0e08e2SPeter Avalos static void
svc_vc_destroy(SVCXPRT * xprt)365ce0e08e2SPeter Avalos svc_vc_destroy(SVCXPRT *xprt)
366ce0e08e2SPeter Avalos {
367ce0e08e2SPeter Avalos 	assert(xprt != NULL);
368ce0e08e2SPeter Avalos 
369ce0e08e2SPeter Avalos 	xprt_unregister(xprt);
370ce0e08e2SPeter Avalos 	__svc_vc_dodestroy(xprt);
371ce0e08e2SPeter Avalos }
372ce0e08e2SPeter Avalos 
373ce0e08e2SPeter Avalos static void
__svc_vc_dodestroy(SVCXPRT * xprt)374ce0e08e2SPeter Avalos __svc_vc_dodestroy(SVCXPRT *xprt)
375ce0e08e2SPeter Avalos {
376ce0e08e2SPeter Avalos 	struct cf_conn *cd;
377ce0e08e2SPeter Avalos 	struct cf_rendezvous *r;
378ce0e08e2SPeter Avalos 
379ce0e08e2SPeter Avalos 	cd = (struct cf_conn *)xprt->xp_p1;
380ce0e08e2SPeter Avalos 
381ce0e08e2SPeter Avalos 	if (xprt->xp_fd != RPC_ANYFD)
382ce0e08e2SPeter Avalos 		_close(xprt->xp_fd);
383ce0e08e2SPeter Avalos 	if (xprt->xp_port != 0) {
384ce0e08e2SPeter Avalos 		/* a rendezvouser socket */
385ce0e08e2SPeter Avalos 		r = (struct cf_rendezvous *)xprt->xp_p1;
386ce0e08e2SPeter Avalos 		mem_free(r, sizeof (struct cf_rendezvous));
387ce0e08e2SPeter Avalos 		xprt->xp_port = 0;
388ce0e08e2SPeter Avalos 	} else {
389ce0e08e2SPeter Avalos 		/* an actual connection socket */
390ce0e08e2SPeter Avalos 		XDR_DESTROY(&(cd->xdrs));
391ce0e08e2SPeter Avalos 		mem_free(cd, sizeof(struct cf_conn));
392ce0e08e2SPeter Avalos 	}
393ce0e08e2SPeter Avalos 	if (xprt->xp_rtaddr.buf)
394ce0e08e2SPeter Avalos 		mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen);
395ce0e08e2SPeter Avalos 	if (xprt->xp_ltaddr.buf)
396ce0e08e2SPeter Avalos 		mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen);
397ce0e08e2SPeter Avalos 	if (xprt->xp_tp)
398ce0e08e2SPeter Avalos 		free(xprt->xp_tp);
399ce0e08e2SPeter Avalos 	if (xprt->xp_netid)
400ce0e08e2SPeter Avalos 		free(xprt->xp_netid);
401ce0e08e2SPeter Avalos 	mem_free(xprt, sizeof(SVCXPRT));
402ce0e08e2SPeter Avalos }
403ce0e08e2SPeter Avalos 
404ce0e08e2SPeter Avalos /*ARGSUSED*/
405ce0e08e2SPeter Avalos static bool_t
svc_vc_control(SVCXPRT * xprt __unused,const u_int rq __unused,void * in __unused)4066d7019e6SSascha Wildner svc_vc_control(SVCXPRT *xprt __unused, const u_int rq __unused,
4076d7019e6SSascha Wildner     void *in __unused)
408ce0e08e2SPeter Avalos {
409ce0e08e2SPeter Avalos 	return (FALSE);
410ce0e08e2SPeter Avalos }
411ce0e08e2SPeter Avalos 
412ce0e08e2SPeter Avalos static bool_t
svc_vc_rendezvous_control(SVCXPRT * xprt,const u_int rq,void * in)413ce0e08e2SPeter Avalos svc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in)
414ce0e08e2SPeter Avalos {
415ce0e08e2SPeter Avalos 	struct cf_rendezvous *cfp;
416ce0e08e2SPeter Avalos 
417ce0e08e2SPeter Avalos 	cfp = (struct cf_rendezvous *)xprt->xp_p1;
418ce0e08e2SPeter Avalos 	if (cfp == NULL)
419ce0e08e2SPeter Avalos 		return (FALSE);
420ce0e08e2SPeter Avalos 	switch (rq) {
421ce0e08e2SPeter Avalos 		case SVCGET_CONNMAXREC:
422ce0e08e2SPeter Avalos 			*(int *)in = cfp->maxrec;
423ce0e08e2SPeter Avalos 			break;
424ce0e08e2SPeter Avalos 		case SVCSET_CONNMAXREC:
425ce0e08e2SPeter Avalos 			cfp->maxrec = *(int *)in;
426ce0e08e2SPeter Avalos 			break;
427ce0e08e2SPeter Avalos 		default:
428ce0e08e2SPeter Avalos 			return (FALSE);
429ce0e08e2SPeter Avalos 	}
430ce0e08e2SPeter Avalos 	return (TRUE);
431ce0e08e2SPeter Avalos }
432ce0e08e2SPeter Avalos 
433ce0e08e2SPeter Avalos /*
434ce0e08e2SPeter Avalos  * reads data from the tcp or uip connection.
435ce0e08e2SPeter Avalos  * any error is fatal and the connection is closed.
436ce0e08e2SPeter Avalos  * (And a read of zero bytes is a half closed stream => error.)
437ce0e08e2SPeter Avalos  * All read operations timeout after 35 seconds.  A timeout is
438ce0e08e2SPeter Avalos  * fatal for the connection.
439ce0e08e2SPeter Avalos  */
440ce0e08e2SPeter Avalos static int
read_vc(void * xprtp,void * buf,int len)441ce0e08e2SPeter Avalos read_vc(void *xprtp, void *buf, int len)
442ce0e08e2SPeter Avalos {
443ce0e08e2SPeter Avalos 	SVCXPRT *xprt;
444ce0e08e2SPeter Avalos 	int sock;
445ce0e08e2SPeter Avalos 	int milliseconds = 35 * 1000;
446ce0e08e2SPeter Avalos 	struct pollfd pollfd;
447ce0e08e2SPeter Avalos 	struct cf_conn *cfp;
448ce0e08e2SPeter Avalos 
449ce0e08e2SPeter Avalos 	xprt = (SVCXPRT *)xprtp;
450ce0e08e2SPeter Avalos 	assert(xprt != NULL);
451ce0e08e2SPeter Avalos 
452ce0e08e2SPeter Avalos 	sock = xprt->xp_fd;
453ce0e08e2SPeter Avalos 
454ce0e08e2SPeter Avalos 	cfp = (struct cf_conn *)xprt->xp_p1;
455ce0e08e2SPeter Avalos 
456ce0e08e2SPeter Avalos 	if (cfp->nonblock) {
457ce0e08e2SPeter Avalos 		len = _read(sock, buf, (size_t)len);
458ce0e08e2SPeter Avalos 		if (len < 0) {
459ce0e08e2SPeter Avalos 			if (errno == EAGAIN)
460ce0e08e2SPeter Avalos 				len = 0;
461ce0e08e2SPeter Avalos 			else
462ce0e08e2SPeter Avalos 				goto fatal_err;
463ce0e08e2SPeter Avalos 		}
464ce0e08e2SPeter Avalos 		if (len != 0)
465ce0e08e2SPeter Avalos 			gettimeofday(&cfp->last_recv_time, NULL);
466ce0e08e2SPeter Avalos 		return len;
467ce0e08e2SPeter Avalos 	}
468ce0e08e2SPeter Avalos 
469ce0e08e2SPeter Avalos 	do {
470ce0e08e2SPeter Avalos 		pollfd.fd = sock;
471ce0e08e2SPeter Avalos 		pollfd.events = POLLIN;
472ce0e08e2SPeter Avalos 		pollfd.revents = 0;
473ce0e08e2SPeter Avalos 		switch (_poll(&pollfd, 1, milliseconds)) {
474ce0e08e2SPeter Avalos 		case -1:
475ce0e08e2SPeter Avalos 			if (errno == EINTR)
476ce0e08e2SPeter Avalos 				continue;
477ce0e08e2SPeter Avalos 			/*FALLTHROUGH*/
478ce0e08e2SPeter Avalos 		case 0:
479ce0e08e2SPeter Avalos 			goto fatal_err;
480ce0e08e2SPeter Avalos 
481ce0e08e2SPeter Avalos 		default:
482ce0e08e2SPeter Avalos 			break;
483ce0e08e2SPeter Avalos 		}
484ce0e08e2SPeter Avalos 	} while ((pollfd.revents & POLLIN) == 0);
485ce0e08e2SPeter Avalos 
486ce0e08e2SPeter Avalos 	if ((len = _read(sock, buf, (size_t)len)) > 0) {
487ce0e08e2SPeter Avalos 		gettimeofday(&cfp->last_recv_time, NULL);
488ce0e08e2SPeter Avalos 		return (len);
489ce0e08e2SPeter Avalos 	}
490ce0e08e2SPeter Avalos 
491ce0e08e2SPeter Avalos fatal_err:
492ce0e08e2SPeter Avalos 	((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
493ce0e08e2SPeter Avalos 	return (-1);
494ce0e08e2SPeter Avalos }
495ce0e08e2SPeter Avalos 
496ce0e08e2SPeter Avalos /*
497ce0e08e2SPeter Avalos  * writes data to the tcp connection.
498ce0e08e2SPeter Avalos  * Any error is fatal and the connection is closed.
499ce0e08e2SPeter Avalos  */
500ce0e08e2SPeter Avalos static int
write_vc(void * xprtp,void * buf,int len)501ce0e08e2SPeter Avalos write_vc(void *xprtp, void *buf, int len)
502ce0e08e2SPeter Avalos {
503ce0e08e2SPeter Avalos 	SVCXPRT *xprt;
504ce0e08e2SPeter Avalos 	int i, cnt;
505ce0e08e2SPeter Avalos 	struct cf_conn *cd;
506ce0e08e2SPeter Avalos 	struct timeval tv0, tv1;
507ce0e08e2SPeter Avalos 
508ce0e08e2SPeter Avalos 	xprt = (SVCXPRT *)xprtp;
509ce0e08e2SPeter Avalos 	assert(xprt != NULL);
510ce0e08e2SPeter Avalos 
511ce0e08e2SPeter Avalos 	cd = (struct cf_conn *)xprt->xp_p1;
512ce0e08e2SPeter Avalos 
513ce0e08e2SPeter Avalos 	if (cd->nonblock)
514ce0e08e2SPeter Avalos 		gettimeofday(&tv0, NULL);
515ce0e08e2SPeter Avalos 
516ce0e08e2SPeter Avalos 	for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) {
517ce0e08e2SPeter Avalos 		i = _write(xprt->xp_fd, buf, (size_t)cnt);
518ce0e08e2SPeter Avalos 		if (i  < 0) {
519ce0e08e2SPeter Avalos 			if (errno != EAGAIN || !cd->nonblock) {
520ce0e08e2SPeter Avalos 				cd->strm_stat = XPRT_DIED;
521ce0e08e2SPeter Avalos 				return (-1);
522ce0e08e2SPeter Avalos 			}
523ce0e08e2SPeter Avalos 			if (cd->nonblock && i != cnt) {
524ce0e08e2SPeter Avalos 				/*
525ce0e08e2SPeter Avalos 				 * For non-blocking connections, do not
526ce0e08e2SPeter Avalos 				 * take more than 2 seconds writing the
527ce0e08e2SPeter Avalos 				 * data out.
528ce0e08e2SPeter Avalos 				 *
529ce0e08e2SPeter Avalos 				 * XXX 2 is an arbitrary amount.
530ce0e08e2SPeter Avalos 				 */
531ce0e08e2SPeter Avalos 				gettimeofday(&tv1, NULL);
532ce0e08e2SPeter Avalos 				if (tv1.tv_sec - tv0.tv_sec >= 2) {
533ce0e08e2SPeter Avalos 					cd->strm_stat = XPRT_DIED;
534ce0e08e2SPeter Avalos 					return (-1);
535ce0e08e2SPeter Avalos 				}
536ce0e08e2SPeter Avalos 			}
537ce0e08e2SPeter Avalos 		}
538ce0e08e2SPeter Avalos 	}
539ce0e08e2SPeter Avalos 
540ce0e08e2SPeter Avalos 	return (len);
541ce0e08e2SPeter Avalos }
542ce0e08e2SPeter Avalos 
543ce0e08e2SPeter Avalos static enum xprt_stat
svc_vc_stat(SVCXPRT * xprt)544ce0e08e2SPeter Avalos svc_vc_stat(SVCXPRT *xprt)
545ce0e08e2SPeter Avalos {
546ce0e08e2SPeter Avalos 	struct cf_conn *cd;
547ce0e08e2SPeter Avalos 
548ce0e08e2SPeter Avalos 	assert(xprt != NULL);
549ce0e08e2SPeter Avalos 
550ce0e08e2SPeter Avalos 	cd = (struct cf_conn *)(xprt->xp_p1);
551ce0e08e2SPeter Avalos 
552ce0e08e2SPeter Avalos 	if (cd->strm_stat == XPRT_DIED)
553ce0e08e2SPeter Avalos 		return (XPRT_DIED);
554ce0e08e2SPeter Avalos 	if (! xdrrec_eof(&(cd->xdrs)))
555ce0e08e2SPeter Avalos 		return (XPRT_MOREREQS);
556ce0e08e2SPeter Avalos 	return (XPRT_IDLE);
557ce0e08e2SPeter Avalos }
558ce0e08e2SPeter Avalos 
559ce0e08e2SPeter Avalos static bool_t
svc_vc_recv(SVCXPRT * xprt,struct rpc_msg * msg)560ce0e08e2SPeter Avalos svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg)
561ce0e08e2SPeter Avalos {
562ce0e08e2SPeter Avalos 	struct cf_conn *cd;
563ce0e08e2SPeter Avalos 	XDR *xdrs;
564ce0e08e2SPeter Avalos 
565ce0e08e2SPeter Avalos 	assert(xprt != NULL);
566ce0e08e2SPeter Avalos 	assert(msg != NULL);
567ce0e08e2SPeter Avalos 
568ce0e08e2SPeter Avalos 	cd = (struct cf_conn *)(xprt->xp_p1);
569ce0e08e2SPeter Avalos 	xdrs = &(cd->xdrs);
570ce0e08e2SPeter Avalos 
571ce0e08e2SPeter Avalos 	if (cd->nonblock) {
572ce0e08e2SPeter Avalos 		if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE))
573ce0e08e2SPeter Avalos 			return FALSE;
574ce0e08e2SPeter Avalos 	} else {
575ce0e08e2SPeter Avalos 		xdrrec_skiprecord(xdrs);
576ce0e08e2SPeter Avalos 	}
577ce0e08e2SPeter Avalos 
578ce0e08e2SPeter Avalos 	xdrs->x_op = XDR_DECODE;
579ce0e08e2SPeter Avalos 	if (xdr_callmsg(xdrs, msg)) {
580ce0e08e2SPeter Avalos 		cd->x_id = msg->rm_xid;
581ce0e08e2SPeter Avalos 		return (TRUE);
582ce0e08e2SPeter Avalos 	}
583ce0e08e2SPeter Avalos 	cd->strm_stat = XPRT_DIED;
584ce0e08e2SPeter Avalos 	return (FALSE);
585ce0e08e2SPeter Avalos }
586ce0e08e2SPeter Avalos 
587ce0e08e2SPeter Avalos static bool_t
svc_vc_getargs(SVCXPRT * xprt,xdrproc_t xdr_args,void * args_ptr)588ce0e08e2SPeter Avalos svc_vc_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
589ce0e08e2SPeter Avalos {
590ce0e08e2SPeter Avalos 
591ce0e08e2SPeter Avalos 	assert(xprt != NULL);
592ce0e08e2SPeter Avalos 	/* args_ptr may be NULL */
593ce0e08e2SPeter Avalos 	return ((*xdr_args)(&(((struct cf_conn *)(xprt->xp_p1))->xdrs),
594ce0e08e2SPeter Avalos 	    args_ptr));
595ce0e08e2SPeter Avalos }
596ce0e08e2SPeter Avalos 
597ce0e08e2SPeter Avalos static bool_t
svc_vc_freeargs(SVCXPRT * xprt,xdrproc_t xdr_args,void * args_ptr)598ce0e08e2SPeter Avalos svc_vc_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
599ce0e08e2SPeter Avalos {
600ce0e08e2SPeter Avalos 	XDR *xdrs;
601ce0e08e2SPeter Avalos 
602ce0e08e2SPeter Avalos 	assert(xprt != NULL);
603ce0e08e2SPeter Avalos 	/* args_ptr may be NULL */
604ce0e08e2SPeter Avalos 
605ce0e08e2SPeter Avalos 	xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs);
606ce0e08e2SPeter Avalos 
607ce0e08e2SPeter Avalos 	xdrs->x_op = XDR_FREE;
608ce0e08e2SPeter Avalos 	return ((*xdr_args)(xdrs, args_ptr));
609ce0e08e2SPeter Avalos }
610ce0e08e2SPeter Avalos 
611ce0e08e2SPeter Avalos static bool_t
svc_vc_reply(SVCXPRT * xprt,struct rpc_msg * msg)612ce0e08e2SPeter Avalos svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg)
613ce0e08e2SPeter Avalos {
614ce0e08e2SPeter Avalos 	struct cf_conn *cd;
615ce0e08e2SPeter Avalos 	XDR *xdrs;
616ce0e08e2SPeter Avalos 	bool_t rstat;
617ce0e08e2SPeter Avalos 
618ce0e08e2SPeter Avalos 	assert(xprt != NULL);
619ce0e08e2SPeter Avalos 	assert(msg != NULL);
620ce0e08e2SPeter Avalos 
621ce0e08e2SPeter Avalos 	cd = (struct cf_conn *)(xprt->xp_p1);
622ce0e08e2SPeter Avalos 	xdrs = &(cd->xdrs);
623ce0e08e2SPeter Avalos 
624ce0e08e2SPeter Avalos 	xdrs->x_op = XDR_ENCODE;
625ce0e08e2SPeter Avalos 	msg->rm_xid = cd->x_id;
626ce0e08e2SPeter Avalos 	rstat = xdr_replymsg(xdrs, msg);
627ce0e08e2SPeter Avalos 	xdrrec_endofrecord(xdrs, TRUE);
628ce0e08e2SPeter Avalos 	return (rstat);
629ce0e08e2SPeter Avalos }
630ce0e08e2SPeter Avalos 
631ce0e08e2SPeter Avalos static void
svc_vc_ops(SVCXPRT * xprt)632ce0e08e2SPeter Avalos svc_vc_ops(SVCXPRT *xprt)
633ce0e08e2SPeter Avalos {
634ce0e08e2SPeter Avalos 	static struct xp_ops ops;
635ce0e08e2SPeter Avalos 	static struct xp_ops2 ops2;
636ce0e08e2SPeter Avalos 
637ce0e08e2SPeter Avalos /* VARIABLES PROTECTED BY ops_lock: ops, ops2 */
638ce0e08e2SPeter Avalos 
639ce0e08e2SPeter Avalos 	mutex_lock(&ops_lock);
640ce0e08e2SPeter Avalos 	if (ops.xp_recv == NULL) {
641ce0e08e2SPeter Avalos 		ops.xp_recv = svc_vc_recv;
642ce0e08e2SPeter Avalos 		ops.xp_stat = svc_vc_stat;
643ce0e08e2SPeter Avalos 		ops.xp_getargs = svc_vc_getargs;
644ce0e08e2SPeter Avalos 		ops.xp_reply = svc_vc_reply;
645ce0e08e2SPeter Avalos 		ops.xp_freeargs = svc_vc_freeargs;
646ce0e08e2SPeter Avalos 		ops.xp_destroy = svc_vc_destroy;
647ce0e08e2SPeter Avalos 		ops2.xp_control = svc_vc_control;
648ce0e08e2SPeter Avalos 	}
649ce0e08e2SPeter Avalos 	xprt->xp_ops = &ops;
650ce0e08e2SPeter Avalos 	xprt->xp_ops2 = &ops2;
651ce0e08e2SPeter Avalos 	mutex_unlock(&ops_lock);
652ce0e08e2SPeter Avalos }
653ce0e08e2SPeter Avalos 
654ce0e08e2SPeter Avalos static void
svc_vc_rendezvous_ops(SVCXPRT * xprt)655ce0e08e2SPeter Avalos svc_vc_rendezvous_ops(SVCXPRT *xprt)
656ce0e08e2SPeter Avalos {
657ce0e08e2SPeter Avalos 	static struct xp_ops ops;
658ce0e08e2SPeter Avalos 	static struct xp_ops2 ops2;
659ce0e08e2SPeter Avalos 
660ce0e08e2SPeter Avalos 	mutex_lock(&ops_lock);
661ce0e08e2SPeter Avalos 	if (ops.xp_recv == NULL) {
662ce0e08e2SPeter Avalos 		ops.xp_recv = rendezvous_request;
663ce0e08e2SPeter Avalos 		ops.xp_stat = rendezvous_stat;
664ce0e08e2SPeter Avalos 		ops.xp_getargs =
665ce0e08e2SPeter Avalos 		    (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort;
666ce0e08e2SPeter Avalos 		ops.xp_reply =
667ce0e08e2SPeter Avalos 		    (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort;
668ce0e08e2SPeter Avalos 		ops.xp_freeargs =
669*3a05fd2aSSascha Wildner 		    (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort;
670ce0e08e2SPeter Avalos 		ops.xp_destroy = svc_vc_destroy;
671ce0e08e2SPeter Avalos 		ops2.xp_control = svc_vc_rendezvous_control;
672ce0e08e2SPeter Avalos 	}
673ce0e08e2SPeter Avalos 	xprt->xp_ops = &ops;
674ce0e08e2SPeter Avalos 	xprt->xp_ops2 = &ops2;
675ce0e08e2SPeter Avalos 	mutex_unlock(&ops_lock);
676ce0e08e2SPeter Avalos }
677ce0e08e2SPeter Avalos 
678ce0e08e2SPeter Avalos /*
679ce0e08e2SPeter Avalos  * Get the effective UID of the sending process. Used by rpcbind, keyserv
680ce0e08e2SPeter Avalos  * and rpc.yppasswdd on AF_LOCAL.
681ce0e08e2SPeter Avalos  */
682ce0e08e2SPeter Avalos int
__rpc_get_local_uid(SVCXPRT * transp,uid_t * uid)683ce0e08e2SPeter Avalos __rpc_get_local_uid(SVCXPRT *transp, uid_t *uid)
684ce0e08e2SPeter Avalos {
685ce0e08e2SPeter Avalos 	int sock, ret;
686ce0e08e2SPeter Avalos 	gid_t egid;
687ce0e08e2SPeter Avalos 	uid_t euid;
688ce0e08e2SPeter Avalos 	struct sockaddr *sa;
689ce0e08e2SPeter Avalos 
690ce0e08e2SPeter Avalos 	sock = transp->xp_fd;
691ce0e08e2SPeter Avalos 	sa = (struct sockaddr *)transp->xp_rtaddr.buf;
692ce0e08e2SPeter Avalos 	if (sa->sa_family == AF_LOCAL) {
693ce0e08e2SPeter Avalos 		ret = getpeereid(sock, &euid, &egid);
694ce0e08e2SPeter Avalos 		if (ret == 0)
695ce0e08e2SPeter Avalos 			*uid = euid;
696ce0e08e2SPeter Avalos 		return (ret);
697ce0e08e2SPeter Avalos 	} else
698ce0e08e2SPeter Avalos 		return (-1);
699ce0e08e2SPeter Avalos }
700ce0e08e2SPeter Avalos 
701ce0e08e2SPeter Avalos /*
702ce0e08e2SPeter Avalos  * Destroy xprts that have not have had any activity in 'timeout' seconds.
703ce0e08e2SPeter Avalos  * If 'cleanblock' is true, blocking connections (the default) are also
704ce0e08e2SPeter Avalos  * cleaned. If timeout is 0, the least active connection is picked.
705ce0e08e2SPeter Avalos  */
706ce0e08e2SPeter Avalos bool_t
__svc_clean_idle(fd_set * fds,int timeout,bool_t cleanblock)707ce0e08e2SPeter Avalos __svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock)
708ce0e08e2SPeter Avalos {
709ce0e08e2SPeter Avalos 	int i, ncleaned;
710ce0e08e2SPeter Avalos 	SVCXPRT *xprt, *least_active;
711ce0e08e2SPeter Avalos 	struct timeval tv, tdiff, tmax;
712ce0e08e2SPeter Avalos 	struct cf_conn *cd;
713ce0e08e2SPeter Avalos 
714ce0e08e2SPeter Avalos 	gettimeofday(&tv, NULL);
715ce0e08e2SPeter Avalos 	tmax.tv_sec = tmax.tv_usec = 0;
716ce0e08e2SPeter Avalos 	least_active = NULL;
717ce0e08e2SPeter Avalos 	rwlock_wrlock(&svc_fd_lock);
718ce0e08e2SPeter Avalos 	for (i = ncleaned = 0; i <= svc_maxfd; i++) {
719ce0e08e2SPeter Avalos 		if (FD_ISSET(i, fds)) {
720ce0e08e2SPeter Avalos 			xprt = __svc_xports[i];
721ce0e08e2SPeter Avalos 			if (xprt == NULL || xprt->xp_ops == NULL ||
722ce0e08e2SPeter Avalos 			    xprt->xp_ops->xp_recv != svc_vc_recv)
723ce0e08e2SPeter Avalos 				continue;
724ce0e08e2SPeter Avalos 			cd = (struct cf_conn *)xprt->xp_p1;
725ce0e08e2SPeter Avalos 			if (!cleanblock && !cd->nonblock)
726ce0e08e2SPeter Avalos 				continue;
727ce0e08e2SPeter Avalos 			if (timeout == 0) {
728ce0e08e2SPeter Avalos 				timersub(&tv, &cd->last_recv_time, &tdiff);
729ce0e08e2SPeter Avalos 				if (timercmp(&tdiff, &tmax, >)) {
730ce0e08e2SPeter Avalos 					tmax = tdiff;
731ce0e08e2SPeter Avalos 					least_active = xprt;
732ce0e08e2SPeter Avalos 				}
733ce0e08e2SPeter Avalos 				continue;
734ce0e08e2SPeter Avalos 			}
735ce0e08e2SPeter Avalos 			if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) {
736ce0e08e2SPeter Avalos 				__xprt_unregister_unlocked(xprt);
737ce0e08e2SPeter Avalos 				__svc_vc_dodestroy(xprt);
738ce0e08e2SPeter Avalos 				ncleaned++;
739ce0e08e2SPeter Avalos 			}
740ce0e08e2SPeter Avalos 		}
741ce0e08e2SPeter Avalos 	}
742ce0e08e2SPeter Avalos 	if (timeout == 0 && least_active != NULL) {
743ce0e08e2SPeter Avalos 		__xprt_unregister_unlocked(least_active);
744ce0e08e2SPeter Avalos 		__svc_vc_dodestroy(least_active);
745ce0e08e2SPeter Avalos 		ncleaned++;
746ce0e08e2SPeter Avalos 	}
747ce0e08e2SPeter Avalos 	rwlock_unlock(&svc_fd_lock);
748ce0e08e2SPeter Avalos 	return ncleaned > 0 ? TRUE : FALSE;
749ce0e08e2SPeter Avalos }
750