svc_vc.c revision 194407
1177633Sdfr/*	$NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $	*/
2177633Sdfr
3177633Sdfr/*
4177633Sdfr * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5177633Sdfr * unrestricted use provided that this legend is included on all tape
6177633Sdfr * media and as a part of the software program in whole or part.  Users
7177633Sdfr * may copy or modify Sun RPC without charge, but are not authorized
8177633Sdfr * to license or distribute it to anyone else except as part of a product or
9177633Sdfr * program developed by the user.
10177633Sdfr *
11177633Sdfr * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12177633Sdfr * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13177633Sdfr * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14177633Sdfr *
15177633Sdfr * Sun RPC is provided with no support and without any obligation on the
16177633Sdfr * part of Sun Microsystems, Inc. to assist in its use, correction,
17177633Sdfr * modification or enhancement.
18177633Sdfr *
19177633Sdfr * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20177633Sdfr * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21177633Sdfr * OR ANY PART THEREOF.
22177633Sdfr *
23177633Sdfr * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24177633Sdfr * or profits or other special, indirect and consequential damages, even if
25177633Sdfr * Sun has been advised of the possibility of such damages.
26177633Sdfr *
27177633Sdfr * Sun Microsystems, Inc.
28177633Sdfr * 2550 Garcia Avenue
29177633Sdfr * Mountain View, California  94043
30177633Sdfr */
31177633Sdfr
32177633Sdfr#if defined(LIBC_SCCS) && !defined(lint)
33177633Sdfrstatic char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
34177633Sdfrstatic char *sccsid = "@(#)svc_tcp.c	2.2 88/08/01 4.0 RPCSRC";
35177633Sdfr#endif
36177633Sdfr#include <sys/cdefs.h>
37177633Sdfr__FBSDID("$FreeBSD: head/sys/rpc/svc_vc.c 194407 2009-06-17 22:50:26Z rmacklem $");
38177633Sdfr
39177633Sdfr/*
40177633Sdfr * svc_vc.c, Server side for Connection Oriented based RPC.
41177633Sdfr *
42177633Sdfr * Actually implements two flavors of transporter -
43177633Sdfr * a tcp rendezvouser (a listner and connection establisher)
44177633Sdfr * and a record/tcp stream.
45177633Sdfr */
46177633Sdfr
47177633Sdfr#include <sys/param.h>
48177633Sdfr#include <sys/lock.h>
49177633Sdfr#include <sys/kernel.h>
50177633Sdfr#include <sys/malloc.h>
51177633Sdfr#include <sys/mbuf.h>
52177633Sdfr#include <sys/mutex.h>
53193509Srwatson#include <sys/proc.h>
54177633Sdfr#include <sys/protosw.h>
55177633Sdfr#include <sys/queue.h>
56177633Sdfr#include <sys/socket.h>
57177633Sdfr#include <sys/socketvar.h>
58184588Sdfr#include <sys/sx.h>
59177633Sdfr#include <sys/systm.h>
60177633Sdfr#include <sys/uio.h>
61177633Sdfr#include <netinet/tcp.h>
62177633Sdfr
63177633Sdfr#include <rpc/rpc.h>
64177633Sdfr
65177685Sdfr#include <rpc/rpc_com.h>
66177633Sdfr
67193509Srwatson#include <security/mac/mac_framework.h>
68193509Srwatson
69184588Sdfrstatic bool_t svc_vc_rendezvous_recv(SVCXPRT *, struct rpc_msg *,
70184588Sdfr    struct sockaddr **, struct mbuf **);
71177633Sdfrstatic enum xprt_stat svc_vc_rendezvous_stat(SVCXPRT *);
72177633Sdfrstatic void svc_vc_rendezvous_destroy(SVCXPRT *);
73177633Sdfrstatic bool_t svc_vc_null(void);
74177633Sdfrstatic void svc_vc_destroy(SVCXPRT *);
75177633Sdfrstatic enum xprt_stat svc_vc_stat(SVCXPRT *);
76184588Sdfrstatic bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *,
77184588Sdfr    struct sockaddr **, struct mbuf **);
78184588Sdfrstatic bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *,
79184588Sdfr    struct sockaddr *, struct mbuf *);
80177633Sdfrstatic bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in);
81177633Sdfrstatic bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq,
82177633Sdfr    void *in);
83177633Sdfrstatic SVCXPRT *svc_vc_create_conn(SVCPOOL *pool, struct socket *so,
84177633Sdfr    struct sockaddr *raddr);
85177633Sdfrstatic int svc_vc_accept(struct socket *head, struct socket **sop);
86193272Sjhbstatic int svc_vc_soupcall(struct socket *so, void *arg, int waitflag);
87177633Sdfr
88177633Sdfrstatic struct xp_ops svc_vc_rendezvous_ops = {
89177633Sdfr	.xp_recv =	svc_vc_rendezvous_recv,
90177633Sdfr	.xp_stat =	svc_vc_rendezvous_stat,
91184588Sdfr	.xp_reply =	(bool_t (*)(SVCXPRT *, struct rpc_msg *,
92184588Sdfr		struct sockaddr *, struct mbuf *))svc_vc_null,
93177633Sdfr	.xp_destroy =	svc_vc_rendezvous_destroy,
94177633Sdfr	.xp_control =	svc_vc_rendezvous_control
95177633Sdfr};
96177633Sdfr
97177633Sdfrstatic struct xp_ops svc_vc_ops = {
98177633Sdfr	.xp_recv =	svc_vc_recv,
99177633Sdfr	.xp_stat =	svc_vc_stat,
100177633Sdfr	.xp_reply =	svc_vc_reply,
101177633Sdfr	.xp_destroy =	svc_vc_destroy,
102177633Sdfr	.xp_control =	svc_vc_control
103177633Sdfr};
104177633Sdfr
105177633Sdfrstruct cf_conn {  /* kept in xprt->xp_p1 for actual connection */
106177633Sdfr	enum xprt_stat strm_stat;
107177633Sdfr	struct mbuf *mpending;	/* unparsed data read from the socket */
108177633Sdfr	struct mbuf *mreq;	/* current record being built from mpending */
109177633Sdfr	uint32_t resid;		/* number of bytes needed for fragment */
110177633Sdfr	bool_t eor;		/* reading last fragment of current record */
111177633Sdfr};
112177633Sdfr
113177633Sdfr/*
114177633Sdfr * Usage:
115177633Sdfr *	xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
116177633Sdfr *
117177633Sdfr * Creates, registers, and returns a (rpc) tcp based transporter.
118177633Sdfr * Once *xprt is initialized, it is registered as a transporter
119177633Sdfr * see (svc.h, xprt_register).  This routine returns
120177633Sdfr * a NULL if a problem occurred.
121177633Sdfr *
122177633Sdfr * The filedescriptor passed in is expected to refer to a bound, but
123177633Sdfr * not yet connected socket.
124177633Sdfr *
125177633Sdfr * Since streams do buffered io similar to stdio, the caller can specify
126177633Sdfr * how big the send and receive buffers are via the second and third parms;
127177633Sdfr * 0 => use the system default.
128177633Sdfr */
129177633SdfrSVCXPRT *
130177633Sdfrsvc_vc_create(SVCPOOL *pool, struct socket *so, size_t sendsize,
131177633Sdfr    size_t recvsize)
132177633Sdfr{
133177633Sdfr	SVCXPRT *xprt;
134177633Sdfr	struct sockaddr* sa;
135177633Sdfr	int error;
136177633Sdfr
137180025Sdfr	if (so->so_state & SS_ISCONNECTED) {
138180025Sdfr		error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa);
139180025Sdfr		if (error)
140180025Sdfr			return (NULL);
141180025Sdfr		xprt = svc_vc_create_conn(pool, so, sa);
142180025Sdfr		free(sa, M_SONAME);
143180025Sdfr		return (xprt);
144180025Sdfr	}
145180025Sdfr
146184588Sdfr	xprt = svc_xprt_alloc();
147184588Sdfr	sx_init(&xprt->xp_lock, "xprt->xp_lock");
148177633Sdfr	xprt->xp_pool = pool;
149177633Sdfr	xprt->xp_socket = so;
150177633Sdfr	xprt->xp_p1 = NULL;
151177633Sdfr	xprt->xp_p2 = NULL;
152177633Sdfr	xprt->xp_ops = &svc_vc_rendezvous_ops;
153177633Sdfr
154177633Sdfr	error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
155177633Sdfr	if (error)
156177633Sdfr		goto cleanup_svc_vc_create;
157177633Sdfr
158184588Sdfr	memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
159177633Sdfr	free(sa, M_SONAME);
160177633Sdfr
161177633Sdfr	xprt_register(xprt);
162177633Sdfr
163177633Sdfr	solisten(so, SOMAXCONN, curthread);
164177633Sdfr
165177633Sdfr	SOCKBUF_LOCK(&so->so_rcv);
166193436Srmacklem	xprt->xp_upcallset = 1;
167193272Sjhb	soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt);
168177633Sdfr	SOCKBUF_UNLOCK(&so->so_rcv);
169177633Sdfr
170177633Sdfr	return (xprt);
171177633Sdfrcleanup_svc_vc_create:
172177633Sdfr	if (xprt)
173184588Sdfr		svc_xprt_free(xprt);
174177633Sdfr	return (NULL);
175177633Sdfr}
176177633Sdfr
177177633Sdfr/*
178177633Sdfr * Create a new transport for a socket optained via soaccept().
179177633Sdfr */
180177633SdfrSVCXPRT *
181177633Sdfrsvc_vc_create_conn(SVCPOOL *pool, struct socket *so, struct sockaddr *raddr)
182177633Sdfr{
183177633Sdfr	SVCXPRT *xprt = NULL;
184177633Sdfr	struct cf_conn *cd = NULL;
185177633Sdfr	struct sockaddr* sa = NULL;
186180025Sdfr	struct sockopt opt;
187180025Sdfr	int one = 1;
188177633Sdfr	int error;
189177633Sdfr
190180025Sdfr	bzero(&opt, sizeof(struct sockopt));
191180025Sdfr	opt.sopt_dir = SOPT_SET;
192180025Sdfr	opt.sopt_level = SOL_SOCKET;
193180025Sdfr	opt.sopt_name = SO_KEEPALIVE;
194180025Sdfr	opt.sopt_val = &one;
195180025Sdfr	opt.sopt_valsize = sizeof(one);
196180025Sdfr	error = sosetopt(so, &opt);
197180025Sdfr	if (error)
198180025Sdfr		return (NULL);
199180025Sdfr
200180025Sdfr	if (so->so_proto->pr_protocol == IPPROTO_TCP) {
201180025Sdfr		bzero(&opt, sizeof(struct sockopt));
202180025Sdfr		opt.sopt_dir = SOPT_SET;
203180025Sdfr		opt.sopt_level = IPPROTO_TCP;
204180025Sdfr		opt.sopt_name = TCP_NODELAY;
205180025Sdfr		opt.sopt_val = &one;
206180025Sdfr		opt.sopt_valsize = sizeof(one);
207180025Sdfr		error = sosetopt(so, &opt);
208180025Sdfr		if (error)
209180025Sdfr			return (NULL);
210180025Sdfr	}
211180025Sdfr
212177633Sdfr	cd = mem_alloc(sizeof(*cd));
213177633Sdfr	cd->strm_stat = XPRT_IDLE;
214177633Sdfr
215184588Sdfr	xprt = svc_xprt_alloc();
216184588Sdfr	sx_init(&xprt->xp_lock, "xprt->xp_lock");
217177633Sdfr	xprt->xp_pool = pool;
218177633Sdfr	xprt->xp_socket = so;
219177633Sdfr	xprt->xp_p1 = cd;
220177633Sdfr	xprt->xp_p2 = NULL;
221177633Sdfr	xprt->xp_ops = &svc_vc_ops;
222177633Sdfr
223184588Sdfr	/*
224184588Sdfr	 * See http://www.connectathon.org/talks96/nfstcp.pdf - client
225184588Sdfr	 * has a 5 minute timer, server has a 6 minute timer.
226184588Sdfr	 */
227184588Sdfr	xprt->xp_idletimeout = 6 * 60;
228177633Sdfr
229184588Sdfr	memcpy(&xprt->xp_rtaddr, raddr, raddr->sa_len);
230184588Sdfr
231177633Sdfr	error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
232177633Sdfr	if (error)
233177633Sdfr		goto cleanup_svc_vc_create;
234177633Sdfr
235184588Sdfr	memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
236177633Sdfr	free(sa, M_SONAME);
237177633Sdfr
238177633Sdfr	xprt_register(xprt);
239177633Sdfr
240177633Sdfr	SOCKBUF_LOCK(&so->so_rcv);
241193436Srmacklem	xprt->xp_upcallset = 1;
242193272Sjhb	soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt);
243177633Sdfr	SOCKBUF_UNLOCK(&so->so_rcv);
244177633Sdfr
245177633Sdfr	/*
246177633Sdfr	 * Throw the transport into the active list in case it already
247177633Sdfr	 * has some data buffered.
248177633Sdfr	 */
249184588Sdfr	sx_xlock(&xprt->xp_lock);
250177633Sdfr	xprt_active(xprt);
251184588Sdfr	sx_xunlock(&xprt->xp_lock);
252177633Sdfr
253177633Sdfr	return (xprt);
254177633Sdfrcleanup_svc_vc_create:
255177633Sdfr	if (xprt) {
256177633Sdfr		mem_free(xprt, sizeof(*xprt));
257177633Sdfr	}
258177633Sdfr	if (cd)
259177633Sdfr		mem_free(cd, sizeof(*cd));
260177633Sdfr	return (NULL);
261177633Sdfr}
262177633Sdfr
263177633Sdfr/*
264177633Sdfr * This does all of the accept except the final call to soaccept. The
265177633Sdfr * caller will call soaccept after dropping its locks (soaccept may
266177633Sdfr * call malloc).
267177633Sdfr */
268177633Sdfrint
269177633Sdfrsvc_vc_accept(struct socket *head, struct socket **sop)
270177633Sdfr{
271177633Sdfr	int error = 0;
272177633Sdfr	struct socket *so;
273177633Sdfr
274177633Sdfr	if ((head->so_options & SO_ACCEPTCONN) == 0) {
275177633Sdfr		error = EINVAL;
276177633Sdfr		goto done;
277177633Sdfr	}
278177633Sdfr#ifdef MAC
279193509Srwatson	error = mac_socket_check_accept(curthread->td_ucred, head);
280177633Sdfr	if (error != 0)
281177633Sdfr		goto done;
282177633Sdfr#endif
283177633Sdfr	ACCEPT_LOCK();
284177633Sdfr	if (TAILQ_EMPTY(&head->so_comp)) {
285177633Sdfr		ACCEPT_UNLOCK();
286177633Sdfr		error = EWOULDBLOCK;
287177633Sdfr		goto done;
288177633Sdfr	}
289177633Sdfr	so = TAILQ_FIRST(&head->so_comp);
290177633Sdfr	KASSERT(!(so->so_qstate & SQ_INCOMP), ("svc_vc_accept: so SQ_INCOMP"));
291177633Sdfr	KASSERT(so->so_qstate & SQ_COMP, ("svc_vc_accept: so not SQ_COMP"));
292177633Sdfr
293177633Sdfr	/*
294177633Sdfr	 * Before changing the flags on the socket, we have to bump the
295177633Sdfr	 * reference count.  Otherwise, if the protocol calls sofree(),
296177633Sdfr	 * the socket will be released due to a zero refcount.
297177633Sdfr	 * XXX might not need soref() since this is simpler than kern_accept.
298177633Sdfr	 */
299177633Sdfr	SOCK_LOCK(so);			/* soref() and so_state update */
300177633Sdfr	soref(so);			/* file descriptor reference */
301177633Sdfr
302177633Sdfr	TAILQ_REMOVE(&head->so_comp, so, so_list);
303177633Sdfr	head->so_qlen--;
304177633Sdfr	so->so_state |= (head->so_state & SS_NBIO);
305177633Sdfr	so->so_qstate &= ~SQ_COMP;
306177633Sdfr	so->so_head = NULL;
307177633Sdfr
308177633Sdfr	SOCK_UNLOCK(so);
309177633Sdfr	ACCEPT_UNLOCK();
310177633Sdfr
311177633Sdfr	*sop = so;
312177633Sdfr
313177633Sdfr	/* connection has been removed from the listen queue */
314177633Sdfr	KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0);
315177633Sdfrdone:
316177633Sdfr	return (error);
317177633Sdfr}
318177633Sdfr
319177633Sdfr/*ARGSUSED*/
320177633Sdfrstatic bool_t
321184588Sdfrsvc_vc_rendezvous_recv(SVCXPRT *xprt, struct rpc_msg *msg,
322184588Sdfr    struct sockaddr **addrp, struct mbuf **mp)
323177633Sdfr{
324177633Sdfr	struct socket *so = NULL;
325177633Sdfr	struct sockaddr *sa = NULL;
326177633Sdfr	int error;
327194407Srmacklem	SVCXPRT *new_xprt;
328177633Sdfr
329177633Sdfr	/*
330177633Sdfr	 * The socket upcall calls xprt_active() which will eventually
331177633Sdfr	 * cause the server to call us here. We attempt to accept a
332177633Sdfr	 * connection from the socket and turn it into a new
333177633Sdfr	 * transport. If the accept fails, we have drained all pending
334177633Sdfr	 * connections so we call xprt_inactive().
335177633Sdfr	 */
336184588Sdfr	sx_xlock(&xprt->xp_lock);
337177633Sdfr
338177633Sdfr	error = svc_vc_accept(xprt->xp_socket, &so);
339177633Sdfr
340177633Sdfr	if (error == EWOULDBLOCK) {
341184588Sdfr		/*
342184588Sdfr		 * We must re-test for new connections after taking
343184588Sdfr		 * the lock to protect us in the case where a new
344184588Sdfr		 * connection arrives after our call to accept fails
345184588Sdfr		 * with EWOULDBLOCK. The pool lock protects us from
346184588Sdfr		 * racing the upcall after our TAILQ_EMPTY() call
347184588Sdfr		 * returns false.
348184588Sdfr		 */
349184588Sdfr		ACCEPT_LOCK();
350184588Sdfr		mtx_lock(&xprt->xp_pool->sp_lock);
351184588Sdfr		if (TAILQ_EMPTY(&xprt->xp_socket->so_comp))
352184588Sdfr			xprt_inactive_locked(xprt);
353184588Sdfr		mtx_unlock(&xprt->xp_pool->sp_lock);
354184588Sdfr		ACCEPT_UNLOCK();
355184588Sdfr		sx_xunlock(&xprt->xp_lock);
356177633Sdfr		return (FALSE);
357177633Sdfr	}
358177633Sdfr
359177633Sdfr	if (error) {
360177633Sdfr		SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
361193436Srmacklem		if (xprt->xp_upcallset) {
362193436Srmacklem			xprt->xp_upcallset = 0;
363193436Srmacklem			soupcall_clear(xprt->xp_socket, SO_RCV);
364193436Srmacklem		}
365177633Sdfr		SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
366177633Sdfr		xprt_inactive(xprt);
367184588Sdfr		sx_xunlock(&xprt->xp_lock);
368177633Sdfr		return (FALSE);
369177633Sdfr	}
370177633Sdfr
371184588Sdfr	sx_xunlock(&xprt->xp_lock);
372177633Sdfr
373177633Sdfr	sa = 0;
374177633Sdfr	error = soaccept(so, &sa);
375177633Sdfr
376177633Sdfr	if (error) {
377177633Sdfr		/*
378177633Sdfr		 * XXX not sure if I need to call sofree or soclose here.
379177633Sdfr		 */
380177633Sdfr		if (sa)
381177633Sdfr			free(sa, M_SONAME);
382177633Sdfr		return (FALSE);
383177633Sdfr	}
384177633Sdfr
385177633Sdfr	/*
386177633Sdfr	 * svc_vc_create_conn will call xprt_register - we don't need
387194407Srmacklem	 * to do anything with the new connection except derefence it.
388177633Sdfr	 */
389194407Srmacklem	new_xprt = svc_vc_create_conn(xprt->xp_pool, so, sa);
390194407Srmacklem	if (!new_xprt) {
391180025Sdfr		soclose(so);
392194407Srmacklem	} else {
393194407Srmacklem		SVC_RELEASE(new_xprt);
394194407Srmacklem	}
395180025Sdfr
396177633Sdfr	free(sa, M_SONAME);
397177633Sdfr
398177633Sdfr	return (FALSE); /* there is never an rpc msg to be processed */
399177633Sdfr}
400177633Sdfr
401177633Sdfr/*ARGSUSED*/
402177633Sdfrstatic enum xprt_stat
403177633Sdfrsvc_vc_rendezvous_stat(SVCXPRT *xprt)
404177633Sdfr{
405177633Sdfr
406177633Sdfr	return (XPRT_IDLE);
407177633Sdfr}
408177633Sdfr
409177633Sdfrstatic void
410177633Sdfrsvc_vc_destroy_common(SVCXPRT *xprt)
411177633Sdfr{
412177633Sdfr	SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
413193436Srmacklem	if (xprt->xp_upcallset) {
414193436Srmacklem		xprt->xp_upcallset = 0;
415193436Srmacklem		soupcall_clear(xprt->xp_socket, SO_RCV);
416193436Srmacklem	}
417177633Sdfr	SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
418177633Sdfr
419184588Sdfr	sx_destroy(&xprt->xp_lock);
420177633Sdfr	if (xprt->xp_socket)
421177633Sdfr		(void)soclose(xprt->xp_socket);
422177633Sdfr
423184588Sdfr	if (xprt->xp_netid)
424184588Sdfr		(void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1);
425184588Sdfr	svc_xprt_free(xprt);
426177633Sdfr}
427177633Sdfr
428177633Sdfrstatic void
429177633Sdfrsvc_vc_rendezvous_destroy(SVCXPRT *xprt)
430177633Sdfr{
431177633Sdfr
432177633Sdfr	svc_vc_destroy_common(xprt);
433177633Sdfr}
434177633Sdfr
435177633Sdfrstatic void
436177633Sdfrsvc_vc_destroy(SVCXPRT *xprt)
437177633Sdfr{
438177633Sdfr	struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1;
439177633Sdfr
440177633Sdfr	svc_vc_destroy_common(xprt);
441177633Sdfr
442177633Sdfr	if (cd->mreq)
443177633Sdfr		m_freem(cd->mreq);
444177633Sdfr	if (cd->mpending)
445177633Sdfr		m_freem(cd->mpending);
446177633Sdfr	mem_free(cd, sizeof(*cd));
447177633Sdfr}
448177633Sdfr
449177633Sdfr/*ARGSUSED*/
450177633Sdfrstatic bool_t
451177633Sdfrsvc_vc_control(SVCXPRT *xprt, const u_int rq, void *in)
452177633Sdfr{
453177633Sdfr	return (FALSE);
454177633Sdfr}
455177633Sdfr
456177633Sdfrstatic bool_t
457177633Sdfrsvc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in)
458177633Sdfr{
459177633Sdfr
460177633Sdfr	return (FALSE);
461177633Sdfr}
462177633Sdfr
463177633Sdfrstatic enum xprt_stat
464177633Sdfrsvc_vc_stat(SVCXPRT *xprt)
465177633Sdfr{
466177633Sdfr	struct cf_conn *cd;
467177633Sdfr	struct mbuf *m;
468177633Sdfr	size_t n;
469177633Sdfr
470177633Sdfr	cd = (struct cf_conn *)(xprt->xp_p1);
471177633Sdfr
472177633Sdfr	if (cd->strm_stat == XPRT_DIED)
473177633Sdfr		return (XPRT_DIED);
474177633Sdfr
475177633Sdfr	/*
476177633Sdfr	 * Return XPRT_MOREREQS if we have buffered data and we are
477184588Sdfr	 * mid-record or if we have enough data for a record
478184588Sdfr	 * marker. Since this is only a hint, we read mpending and
479184588Sdfr	 * resid outside the lock. We do need to take the lock if we
480184588Sdfr	 * have to traverse the mbuf chain.
481177633Sdfr	 */
482177633Sdfr	if (cd->mpending) {
483177633Sdfr		if (cd->resid)
484177633Sdfr			return (XPRT_MOREREQS);
485177633Sdfr		n = 0;
486184588Sdfr		sx_xlock(&xprt->xp_lock);
487177633Sdfr		m = cd->mpending;
488177633Sdfr		while (m && n < sizeof(uint32_t)) {
489177633Sdfr			n += m->m_len;
490177633Sdfr			m = m->m_next;
491177633Sdfr		}
492184588Sdfr		sx_xunlock(&xprt->xp_lock);
493177633Sdfr		if (n >= sizeof(uint32_t))
494177633Sdfr			return (XPRT_MOREREQS);
495177633Sdfr	}
496177633Sdfr
497184588Sdfr	if (soreadable(xprt->xp_socket))
498184588Sdfr		return (XPRT_MOREREQS);
499184588Sdfr
500177633Sdfr	return (XPRT_IDLE);
501177633Sdfr}
502177633Sdfr
503177633Sdfrstatic bool_t
504184588Sdfrsvc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg,
505184588Sdfr    struct sockaddr **addrp, struct mbuf **mp)
506177633Sdfr{
507177633Sdfr	struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
508177633Sdfr	struct uio uio;
509177633Sdfr	struct mbuf *m;
510184588Sdfr	XDR xdrs;
511177633Sdfr	int error, rcvflag;
512177633Sdfr
513184588Sdfr	/*
514184588Sdfr	 * Serialise access to the socket and our own record parsing
515184588Sdfr	 * state.
516184588Sdfr	 */
517184588Sdfr	sx_xlock(&xprt->xp_lock);
518184588Sdfr
519177633Sdfr	for (;;) {
520177633Sdfr		/*
521177633Sdfr		 * If we have an mbuf chain in cd->mpending, try to parse a
522177633Sdfr		 * record from it, leaving the result in cd->mreq. If we don't
523177633Sdfr		 * have a complete record, leave the partial result in
524177633Sdfr		 * cd->mreq and try to read more from the socket.
525177633Sdfr		 */
526177633Sdfr		if (cd->mpending) {
527177633Sdfr			/*
528177633Sdfr			 * If cd->resid is non-zero, we have part of the
529177633Sdfr			 * record already, otherwise we are expecting a record
530177633Sdfr			 * marker.
531177633Sdfr			 */
532177633Sdfr			if (!cd->resid) {
533177633Sdfr				/*
534177633Sdfr				 * See if there is enough data buffered to
535177633Sdfr				 * make up a record marker. Make sure we can
536177633Sdfr				 * handle the case where the record marker is
537177633Sdfr				 * split across more than one mbuf.
538177633Sdfr				 */
539177633Sdfr				size_t n = 0;
540177633Sdfr				uint32_t header;
541177633Sdfr
542177633Sdfr				m = cd->mpending;
543177633Sdfr				while (n < sizeof(uint32_t) && m) {
544177633Sdfr					n += m->m_len;
545177633Sdfr					m = m->m_next;
546177633Sdfr				}
547177633Sdfr				if (n < sizeof(uint32_t))
548177633Sdfr					goto readmore;
549184588Sdfr				if (cd->mpending->m_len < sizeof(uint32_t))
550184588Sdfr					cd->mpending = m_pullup(cd->mpending,
551184588Sdfr					    sizeof(uint32_t));
552177633Sdfr				memcpy(&header, mtod(cd->mpending, uint32_t *),
553177633Sdfr				    sizeof(header));
554177633Sdfr				header = ntohl(header);
555177633Sdfr				cd->eor = (header & 0x80000000) != 0;
556177633Sdfr				cd->resid = header & 0x7fffffff;
557177633Sdfr				m_adj(cd->mpending, sizeof(uint32_t));
558177633Sdfr			}
559177633Sdfr
560177633Sdfr			/*
561177633Sdfr			 * Start pulling off mbufs from cd->mpending
562177633Sdfr			 * until we either have a complete record or
563177633Sdfr			 * we run out of data. We use m_split to pull
564177633Sdfr			 * data - it will pull as much as possible and
565177633Sdfr			 * split the last mbuf if necessary.
566177633Sdfr			 */
567177633Sdfr			while (cd->mpending && cd->resid) {
568177633Sdfr				m = cd->mpending;
569184588Sdfr				if (cd->mpending->m_next
570184588Sdfr				    || cd->mpending->m_len > cd->resid)
571184588Sdfr					cd->mpending = m_split(cd->mpending,
572184588Sdfr					    cd->resid, M_WAIT);
573184588Sdfr				else
574184588Sdfr					cd->mpending = NULL;
575177633Sdfr				if (cd->mreq)
576177633Sdfr					m_last(cd->mreq)->m_next = m;
577177633Sdfr				else
578177633Sdfr					cd->mreq = m;
579177633Sdfr				while (m) {
580177633Sdfr					cd->resid -= m->m_len;
581177633Sdfr					m = m->m_next;
582177633Sdfr				}
583177633Sdfr			}
584177633Sdfr
585177633Sdfr			/*
586177633Sdfr			 * If cd->resid is zero now, we have managed to
587177633Sdfr			 * receive a record fragment from the stream. Check
588177633Sdfr			 * for the end-of-record mark to see if we need more.
589177633Sdfr			 */
590177633Sdfr			if (cd->resid == 0) {
591177633Sdfr				if (!cd->eor)
592177633Sdfr					continue;
593177633Sdfr
594177633Sdfr				/*
595177633Sdfr				 * Success - we have a complete record in
596177633Sdfr				 * cd->mreq.
597177633Sdfr				 */
598184588Sdfr				xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE);
599177633Sdfr				cd->mreq = NULL;
600184588Sdfr				sx_xunlock(&xprt->xp_lock);
601184588Sdfr
602184588Sdfr				if (! xdr_callmsg(&xdrs, msg)) {
603184588Sdfr					XDR_DESTROY(&xdrs);
604177633Sdfr					return (FALSE);
605177633Sdfr				}
606177633Sdfr
607184588Sdfr				*addrp = NULL;
608184588Sdfr				*mp = xdrmbuf_getall(&xdrs);
609184588Sdfr				XDR_DESTROY(&xdrs);
610184588Sdfr
611177633Sdfr				return (TRUE);
612177633Sdfr			}
613177633Sdfr		}
614177633Sdfr
615177633Sdfr	readmore:
616177633Sdfr		/*
617177633Sdfr		 * The socket upcall calls xprt_active() which will eventually
618177633Sdfr		 * cause the server to call us here. We attempt to
619177633Sdfr		 * read as much as possible from the socket and put
620177633Sdfr		 * the result in cd->mpending. If the read fails,
621177633Sdfr		 * we have drained both cd->mpending and the socket so
622177633Sdfr		 * we can call xprt_inactive().
623177633Sdfr		 */
624177633Sdfr		uio.uio_resid = 1000000000;
625177633Sdfr		uio.uio_td = curthread;
626177633Sdfr		m = NULL;
627177633Sdfr		rcvflag = MSG_DONTWAIT;
628177633Sdfr		error = soreceive(xprt->xp_socket, NULL, &uio, &m, NULL,
629177633Sdfr		    &rcvflag);
630177633Sdfr
631177633Sdfr		if (error == EWOULDBLOCK) {
632184588Sdfr			/*
633184588Sdfr			 * We must re-test for readability after
634184588Sdfr			 * taking the lock to protect us in the case
635184588Sdfr			 * where a new packet arrives on the socket
636184588Sdfr			 * after our call to soreceive fails with
637184588Sdfr			 * EWOULDBLOCK. The pool lock protects us from
638184588Sdfr			 * racing the upcall after our soreadable()
639184588Sdfr			 * call returns false.
640184588Sdfr			 */
641184588Sdfr			mtx_lock(&xprt->xp_pool->sp_lock);
642184588Sdfr			if (!soreadable(xprt->xp_socket))
643184588Sdfr				xprt_inactive_locked(xprt);
644184588Sdfr			mtx_unlock(&xprt->xp_pool->sp_lock);
645184588Sdfr			sx_xunlock(&xprt->xp_lock);
646177633Sdfr			return (FALSE);
647177633Sdfr		}
648177633Sdfr
649177633Sdfr		if (error) {
650177633Sdfr			SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
651193436Srmacklem			if (xprt->xp_upcallset) {
652193436Srmacklem				xprt->xp_upcallset = 0;
653193436Srmacklem				soupcall_clear(xprt->xp_socket, SO_RCV);
654193436Srmacklem			}
655177633Sdfr			SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
656177633Sdfr			xprt_inactive(xprt);
657177633Sdfr			cd->strm_stat = XPRT_DIED;
658184588Sdfr			sx_xunlock(&xprt->xp_lock);
659177633Sdfr			return (FALSE);
660177633Sdfr		}
661177633Sdfr
662177633Sdfr		if (!m) {
663177633Sdfr			/*
664177633Sdfr			 * EOF - the other end has closed the socket.
665177633Sdfr			 */
666184588Sdfr			xprt_inactive(xprt);
667177633Sdfr			cd->strm_stat = XPRT_DIED;
668184588Sdfr			sx_xunlock(&xprt->xp_lock);
669177633Sdfr			return (FALSE);
670177633Sdfr		}
671177633Sdfr
672177633Sdfr		if (cd->mpending)
673177633Sdfr			m_last(cd->mpending)->m_next = m;
674177633Sdfr		else
675177633Sdfr			cd->mpending = m;
676177633Sdfr	}
677177633Sdfr}
678177633Sdfr
679177633Sdfrstatic bool_t
680184588Sdfrsvc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg,
681184588Sdfr    struct sockaddr *addr, struct mbuf *m)
682177633Sdfr{
683177633Sdfr	XDR xdrs;
684177633Sdfr	struct mbuf *mrep;
685184588Sdfr	bool_t stat = TRUE;
686177633Sdfr	int error;
687177633Sdfr
688177633Sdfr	/*
689177633Sdfr	 * Leave space for record mark.
690177633Sdfr	 */
691177633Sdfr	MGETHDR(mrep, M_WAIT, MT_DATA);
692177633Sdfr	mrep->m_len = 0;
693177633Sdfr	mrep->m_data += sizeof(uint32_t);
694177633Sdfr
695184588Sdfr	xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);
696184588Sdfr
697184588Sdfr	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
698184588Sdfr	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
699184588Sdfr		if (!xdr_replymsg(&xdrs, msg))
700184588Sdfr			stat = FALSE;
701184588Sdfr		else
702184588Sdfr			xdrmbuf_append(&xdrs, m);
703184588Sdfr	} else {
704184588Sdfr		stat = xdr_replymsg(&xdrs, msg);
705184588Sdfr	}
706184588Sdfr
707184588Sdfr	if (stat) {
708177633Sdfr		m_fixhdr(mrep);
709177633Sdfr
710177633Sdfr		/*
711177633Sdfr		 * Prepend a record marker containing the reply length.
712177633Sdfr		 */
713177633Sdfr		M_PREPEND(mrep, sizeof(uint32_t), M_WAIT);
714177633Sdfr		*mtod(mrep, uint32_t *) =
715177633Sdfr			htonl(0x80000000 | (mrep->m_pkthdr.len
716177633Sdfr				- sizeof(uint32_t)));
717177633Sdfr		error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL,
718177633Sdfr		    0, curthread);
719177633Sdfr		if (!error) {
720177633Sdfr			stat = TRUE;
721177633Sdfr		}
722177633Sdfr	} else {
723177633Sdfr		m_freem(mrep);
724177633Sdfr	}
725177633Sdfr
726184588Sdfr	XDR_DESTROY(&xdrs);
727177633Sdfr	xprt->xp_p2 = NULL;
728177633Sdfr
729177633Sdfr	return (stat);
730177633Sdfr}
731177633Sdfr
732177633Sdfrstatic bool_t
733177633Sdfrsvc_vc_null()
734177633Sdfr{
735177633Sdfr
736177633Sdfr	return (FALSE);
737177633Sdfr}
738177633Sdfr
739193272Sjhbstatic int
740177633Sdfrsvc_vc_soupcall(struct socket *so, void *arg, int waitflag)
741177633Sdfr{
742177633Sdfr	SVCXPRT *xprt = (SVCXPRT *) arg;
743177633Sdfr
744177633Sdfr	xprt_active(xprt);
745193272Sjhb	return (SU_OK);
746177633Sdfr}
747177633Sdfr
748177633Sdfr#if 0
749177633Sdfr/*
750177633Sdfr * Get the effective UID of the sending process. Used by rpcbind, keyserv
751177633Sdfr * and rpc.yppasswdd on AF_LOCAL.
752177633Sdfr */
753177633Sdfrint
754177633Sdfr__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) {
755177633Sdfr	int sock, ret;
756177633Sdfr	gid_t egid;
757177633Sdfr	uid_t euid;
758177633Sdfr	struct sockaddr *sa;
759177633Sdfr
760177633Sdfr	sock = transp->xp_fd;
761184588Sdfr	sa = (struct sockaddr *)transp->xp_rtaddr;
762177633Sdfr	if (sa->sa_family == AF_LOCAL) {
763177633Sdfr		ret = getpeereid(sock, &euid, &egid);
764177633Sdfr		if (ret == 0)
765177633Sdfr			*uid = euid;
766177633Sdfr		return (ret);
767177633Sdfr	} else
768177633Sdfr		return (-1);
769177633Sdfr}
770177633Sdfr#endif
771