svc_vc.c revision 261047
1177633Sdfr/*	$NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $	*/
2177633Sdfr
3261046Smav/*-
4261046Smav * Copyright (c) 2009, Sun Microsystems, Inc.
5261046Smav * All rights reserved.
6261046Smav *
7261046Smav * Redistribution and use in source and binary forms, with or without
8261046Smav * modification, are permitted provided that the following conditions are met:
9261046Smav * - Redistributions of source code must retain the above copyright notice,
10261046Smav *   this list of conditions and the following disclaimer.
11261046Smav * - Redistributions in binary form must reproduce the above copyright notice,
12261046Smav *   this list of conditions and the following disclaimer in the documentation
13261046Smav *   and/or other materials provided with the distribution.
14261046Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its
15261046Smav *   contributors may be used to endorse or promote products derived
16261046Smav *   from this software without specific prior written permission.
17177633Sdfr *
18261046Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19261046Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20261046Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21261046Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22261046Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23261046Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24261046Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25261046Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26261046Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27261046Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28261046Smav * POSSIBILITY OF SUCH DAMAGE.
29177633Sdfr */
30177633Sdfr
31177633Sdfr#if defined(LIBC_SCCS) && !defined(lint)
32177633Sdfrstatic char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
33177633Sdfrstatic char *sccsid = "@(#)svc_tcp.c	2.2 88/08/01 4.0 RPCSRC";
34177633Sdfr#endif
35177633Sdfr#include <sys/cdefs.h>
36177633Sdfr__FBSDID("$FreeBSD: stable/10/sys/rpc/svc_vc.c 261047 2014-01-22 23:46:19Z mav $");
37177633Sdfr
38177633Sdfr/*
39177633Sdfr * svc_vc.c, Server side for Connection Oriented based RPC.
40177633Sdfr *
41177633Sdfr * Actually implements two flavors of transporter -
42177633Sdfr * a tcp rendezvouser (a listner and connection establisher)
43177633Sdfr * and a record/tcp stream.
44177633Sdfr */
45177633Sdfr
46177633Sdfr#include <sys/param.h>
47177633Sdfr#include <sys/lock.h>
48177633Sdfr#include <sys/kernel.h>
49177633Sdfr#include <sys/malloc.h>
50177633Sdfr#include <sys/mbuf.h>
51177633Sdfr#include <sys/mutex.h>
52193509Srwatson#include <sys/proc.h>
53177633Sdfr#include <sys/protosw.h>
54177633Sdfr#include <sys/queue.h>
55177633Sdfr#include <sys/socket.h>
56177633Sdfr#include <sys/socketvar.h>
57184588Sdfr#include <sys/sx.h>
58177633Sdfr#include <sys/systm.h>
59177633Sdfr#include <sys/uio.h>
60196503Szec
61196503Szec#include <net/vnet.h>
62196503Szec
63177633Sdfr#include <netinet/tcp.h>
64177633Sdfr
65177633Sdfr#include <rpc/rpc.h>
66177633Sdfr
67244008Srmacklem#include <rpc/krpc.h>
68177685Sdfr#include <rpc/rpc_com.h>
69177633Sdfr
70193509Srwatson#include <security/mac/mac_framework.h>
71193509Srwatson
72184588Sdfrstatic bool_t svc_vc_rendezvous_recv(SVCXPRT *, struct rpc_msg *,
73184588Sdfr    struct sockaddr **, struct mbuf **);
74177633Sdfrstatic enum xprt_stat svc_vc_rendezvous_stat(SVCXPRT *);
75177633Sdfrstatic void svc_vc_rendezvous_destroy(SVCXPRT *);
76177633Sdfrstatic bool_t svc_vc_null(void);
77177633Sdfrstatic void svc_vc_destroy(SVCXPRT *);
78177633Sdfrstatic enum xprt_stat svc_vc_stat(SVCXPRT *);
79184588Sdfrstatic bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *,
80184588Sdfr    struct sockaddr **, struct mbuf **);
81184588Sdfrstatic bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *,
82184588Sdfr    struct sockaddr *, struct mbuf *);
83177633Sdfrstatic bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in);
84177633Sdfrstatic bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq,
85177633Sdfr    void *in);
86244008Srmacklemstatic void svc_vc_backchannel_destroy(SVCXPRT *);
87244008Srmacklemstatic enum xprt_stat svc_vc_backchannel_stat(SVCXPRT *);
88244008Srmacklemstatic bool_t svc_vc_backchannel_recv(SVCXPRT *, struct rpc_msg *,
89244008Srmacklem    struct sockaddr **, struct mbuf **);
90244008Srmacklemstatic bool_t svc_vc_backchannel_reply(SVCXPRT *, struct rpc_msg *,
91244008Srmacklem    struct sockaddr *, struct mbuf *);
92244008Srmacklemstatic bool_t svc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq,
93244008Srmacklem    void *in);
94177633Sdfrstatic SVCXPRT *svc_vc_create_conn(SVCPOOL *pool, struct socket *so,
95177633Sdfr    struct sockaddr *raddr);
96177633Sdfrstatic int svc_vc_accept(struct socket *head, struct socket **sop);
97193272Sjhbstatic int svc_vc_soupcall(struct socket *so, void *arg, int waitflag);
98177633Sdfr
99177633Sdfrstatic struct xp_ops svc_vc_rendezvous_ops = {
100177633Sdfr	.xp_recv =	svc_vc_rendezvous_recv,
101177633Sdfr	.xp_stat =	svc_vc_rendezvous_stat,
102184588Sdfr	.xp_reply =	(bool_t (*)(SVCXPRT *, struct rpc_msg *,
103184588Sdfr		struct sockaddr *, struct mbuf *))svc_vc_null,
104177633Sdfr	.xp_destroy =	svc_vc_rendezvous_destroy,
105177633Sdfr	.xp_control =	svc_vc_rendezvous_control
106177633Sdfr};
107177633Sdfr
108177633Sdfrstatic struct xp_ops svc_vc_ops = {
109177633Sdfr	.xp_recv =	svc_vc_recv,
110177633Sdfr	.xp_stat =	svc_vc_stat,
111177633Sdfr	.xp_reply =	svc_vc_reply,
112177633Sdfr	.xp_destroy =	svc_vc_destroy,
113177633Sdfr	.xp_control =	svc_vc_control
114177633Sdfr};
115177633Sdfr
116244008Srmacklemstatic struct xp_ops svc_vc_backchannel_ops = {
117244008Srmacklem	.xp_recv =	svc_vc_backchannel_recv,
118244008Srmacklem	.xp_stat =	svc_vc_backchannel_stat,
119244008Srmacklem	.xp_reply =	svc_vc_backchannel_reply,
120244008Srmacklem	.xp_destroy =	svc_vc_backchannel_destroy,
121244008Srmacklem	.xp_control =	svc_vc_backchannel_control
122177633Sdfr};
123177633Sdfr
124177633Sdfr/*
125177633Sdfr * Usage:
126177633Sdfr *	xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
127177633Sdfr *
128177633Sdfr * Creates, registers, and returns a (rpc) tcp based transporter.
129177633Sdfr * Once *xprt is initialized, it is registered as a transporter
130177633Sdfr * see (svc.h, xprt_register).  This routine returns
131177633Sdfr * a NULL if a problem occurred.
132177633Sdfr *
133177633Sdfr * The filedescriptor passed in is expected to refer to a bound, but
134177633Sdfr * not yet connected socket.
135177633Sdfr *
136177633Sdfr * Since streams do buffered io similar to stdio, the caller can specify
137177633Sdfr * how big the send and receive buffers are via the second and third parms;
138177633Sdfr * 0 => use the system default.
139177633Sdfr */
140177633SdfrSVCXPRT *
141177633Sdfrsvc_vc_create(SVCPOOL *pool, struct socket *so, size_t sendsize,
142177633Sdfr    size_t recvsize)
143177633Sdfr{
144177633Sdfr	SVCXPRT *xprt;
145177633Sdfr	struct sockaddr* sa;
146177633Sdfr	int error;
147177633Sdfr
148249263Sjhb	SOCK_LOCK(so);
149249263Sjhb	if (so->so_state & (SS_ISCONNECTED|SS_ISDISCONNECTED)) {
150249263Sjhb		SOCK_UNLOCK(so);
151180025Sdfr		error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa);
152180025Sdfr		if (error)
153180025Sdfr			return (NULL);
154180025Sdfr		xprt = svc_vc_create_conn(pool, so, sa);
155180025Sdfr		free(sa, M_SONAME);
156180025Sdfr		return (xprt);
157180025Sdfr	}
158249263Sjhb	SOCK_UNLOCK(so);
159180025Sdfr
160184588Sdfr	xprt = svc_xprt_alloc();
161184588Sdfr	sx_init(&xprt->xp_lock, "xprt->xp_lock");
162177633Sdfr	xprt->xp_pool = pool;
163177633Sdfr	xprt->xp_socket = so;
164177633Sdfr	xprt->xp_p1 = NULL;
165177633Sdfr	xprt->xp_p2 = NULL;
166177633Sdfr	xprt->xp_ops = &svc_vc_rendezvous_ops;
167177633Sdfr
168177633Sdfr	error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
169196503Szec	if (error) {
170177633Sdfr		goto cleanup_svc_vc_create;
171196503Szec	}
172177633Sdfr
173184588Sdfr	memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
174177633Sdfr	free(sa, M_SONAME);
175177633Sdfr
176177633Sdfr	xprt_register(xprt);
177177633Sdfr
178177633Sdfr	solisten(so, SOMAXCONN, curthread);
179177633Sdfr
180177633Sdfr	SOCKBUF_LOCK(&so->so_rcv);
181193436Srmacklem	xprt->xp_upcallset = 1;
182193272Sjhb	soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt);
183177633Sdfr	SOCKBUF_UNLOCK(&so->so_rcv);
184177633Sdfr
185177633Sdfr	return (xprt);
186177633Sdfrcleanup_svc_vc_create:
187177633Sdfr	if (xprt)
188184588Sdfr		svc_xprt_free(xprt);
189177633Sdfr	return (NULL);
190177633Sdfr}
191177633Sdfr
192177633Sdfr/*
193177633Sdfr * Create a new transport for a socket optained via soaccept().
194177633Sdfr */
195177633SdfrSVCXPRT *
196177633Sdfrsvc_vc_create_conn(SVCPOOL *pool, struct socket *so, struct sockaddr *raddr)
197177633Sdfr{
198177633Sdfr	SVCXPRT *xprt = NULL;
199177633Sdfr	struct cf_conn *cd = NULL;
200177633Sdfr	struct sockaddr* sa = NULL;
201180025Sdfr	struct sockopt opt;
202180025Sdfr	int one = 1;
203177633Sdfr	int error;
204177633Sdfr
205180025Sdfr	bzero(&opt, sizeof(struct sockopt));
206180025Sdfr	opt.sopt_dir = SOPT_SET;
207180025Sdfr	opt.sopt_level = SOL_SOCKET;
208180025Sdfr	opt.sopt_name = SO_KEEPALIVE;
209180025Sdfr	opt.sopt_val = &one;
210180025Sdfr	opt.sopt_valsize = sizeof(one);
211180025Sdfr	error = sosetopt(so, &opt);
212196503Szec	if (error) {
213180025Sdfr		return (NULL);
214196503Szec	}
215180025Sdfr
216180025Sdfr	if (so->so_proto->pr_protocol == IPPROTO_TCP) {
217180025Sdfr		bzero(&opt, sizeof(struct sockopt));
218180025Sdfr		opt.sopt_dir = SOPT_SET;
219180025Sdfr		opt.sopt_level = IPPROTO_TCP;
220180025Sdfr		opt.sopt_name = TCP_NODELAY;
221180025Sdfr		opt.sopt_val = &one;
222180025Sdfr		opt.sopt_valsize = sizeof(one);
223180025Sdfr		error = sosetopt(so, &opt);
224196503Szec		if (error) {
225180025Sdfr			return (NULL);
226196503Szec		}
227180025Sdfr	}
228180025Sdfr
229177633Sdfr	cd = mem_alloc(sizeof(*cd));
230177633Sdfr	cd->strm_stat = XPRT_IDLE;
231177633Sdfr
232184588Sdfr	xprt = svc_xprt_alloc();
233184588Sdfr	sx_init(&xprt->xp_lock, "xprt->xp_lock");
234177633Sdfr	xprt->xp_pool = pool;
235177633Sdfr	xprt->xp_socket = so;
236177633Sdfr	xprt->xp_p1 = cd;
237177633Sdfr	xprt->xp_p2 = NULL;
238177633Sdfr	xprt->xp_ops = &svc_vc_ops;
239177633Sdfr
240184588Sdfr	/*
241184588Sdfr	 * See http://www.connectathon.org/talks96/nfstcp.pdf - client
242184588Sdfr	 * has a 5 minute timer, server has a 6 minute timer.
243184588Sdfr	 */
244184588Sdfr	xprt->xp_idletimeout = 6 * 60;
245177633Sdfr
246184588Sdfr	memcpy(&xprt->xp_rtaddr, raddr, raddr->sa_len);
247184588Sdfr
248177633Sdfr	error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
249177633Sdfr	if (error)
250177633Sdfr		goto cleanup_svc_vc_create;
251177633Sdfr
252184588Sdfr	memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
253177633Sdfr	free(sa, M_SONAME);
254177633Sdfr
255177633Sdfr	xprt_register(xprt);
256177633Sdfr
257177633Sdfr	SOCKBUF_LOCK(&so->so_rcv);
258193436Srmacklem	xprt->xp_upcallset = 1;
259193272Sjhb	soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt);
260177633Sdfr	SOCKBUF_UNLOCK(&so->so_rcv);
261177633Sdfr
262177633Sdfr	/*
263177633Sdfr	 * Throw the transport into the active list in case it already
264177633Sdfr	 * has some data buffered.
265177633Sdfr	 */
266184588Sdfr	sx_xlock(&xprt->xp_lock);
267177633Sdfr	xprt_active(xprt);
268184588Sdfr	sx_xunlock(&xprt->xp_lock);
269177633Sdfr
270177633Sdfr	return (xprt);
271177633Sdfrcleanup_svc_vc_create:
272177633Sdfr	if (xprt) {
273177633Sdfr		mem_free(xprt, sizeof(*xprt));
274177633Sdfr	}
275177633Sdfr	if (cd)
276177633Sdfr		mem_free(cd, sizeof(*cd));
277177633Sdfr	return (NULL);
278177633Sdfr}
279177633Sdfr
280177633Sdfr/*
281244008Srmacklem * Create a new transport for a backchannel on a clnt_vc socket.
282244008Srmacklem */
283244008SrmacklemSVCXPRT *
284244008Srmacklemsvc_vc_create_backchannel(SVCPOOL *pool)
285244008Srmacklem{
286244008Srmacklem	SVCXPRT *xprt = NULL;
287244008Srmacklem	struct cf_conn *cd = NULL;
288244008Srmacklem
289244008Srmacklem	cd = mem_alloc(sizeof(*cd));
290244008Srmacklem	cd->strm_stat = XPRT_IDLE;
291244008Srmacklem
292244008Srmacklem	xprt = svc_xprt_alloc();
293244008Srmacklem	sx_init(&xprt->xp_lock, "xprt->xp_lock");
294244008Srmacklem	xprt->xp_pool = pool;
295244008Srmacklem	xprt->xp_socket = NULL;
296244008Srmacklem	xprt->xp_p1 = cd;
297244008Srmacklem	xprt->xp_p2 = NULL;
298244008Srmacklem	xprt->xp_ops = &svc_vc_backchannel_ops;
299244008Srmacklem	return (xprt);
300244008Srmacklem}
301244008Srmacklem
302244008Srmacklem/*
303177633Sdfr * This does all of the accept except the final call to soaccept. The
304177633Sdfr * caller will call soaccept after dropping its locks (soaccept may
305177633Sdfr * call malloc).
306177633Sdfr */
307177633Sdfrint
308177633Sdfrsvc_vc_accept(struct socket *head, struct socket **sop)
309177633Sdfr{
310177633Sdfr	int error = 0;
311177633Sdfr	struct socket *so;
312177633Sdfr
313177633Sdfr	if ((head->so_options & SO_ACCEPTCONN) == 0) {
314177633Sdfr		error = EINVAL;
315177633Sdfr		goto done;
316177633Sdfr	}
317177633Sdfr#ifdef MAC
318193509Srwatson	error = mac_socket_check_accept(curthread->td_ucred, head);
319177633Sdfr	if (error != 0)
320177633Sdfr		goto done;
321177633Sdfr#endif
322177633Sdfr	ACCEPT_LOCK();
323177633Sdfr	if (TAILQ_EMPTY(&head->so_comp)) {
324177633Sdfr		ACCEPT_UNLOCK();
325177633Sdfr		error = EWOULDBLOCK;
326177633Sdfr		goto done;
327177633Sdfr	}
328177633Sdfr	so = TAILQ_FIRST(&head->so_comp);
329177633Sdfr	KASSERT(!(so->so_qstate & SQ_INCOMP), ("svc_vc_accept: so SQ_INCOMP"));
330177633Sdfr	KASSERT(so->so_qstate & SQ_COMP, ("svc_vc_accept: so not SQ_COMP"));
331177633Sdfr
332177633Sdfr	/*
333177633Sdfr	 * Before changing the flags on the socket, we have to bump the
334177633Sdfr	 * reference count.  Otherwise, if the protocol calls sofree(),
335177633Sdfr	 * the socket will be released due to a zero refcount.
336177633Sdfr	 * XXX might not need soref() since this is simpler than kern_accept.
337177633Sdfr	 */
338177633Sdfr	SOCK_LOCK(so);			/* soref() and so_state update */
339177633Sdfr	soref(so);			/* file descriptor reference */
340177633Sdfr
341177633Sdfr	TAILQ_REMOVE(&head->so_comp, so, so_list);
342177633Sdfr	head->so_qlen--;
343177633Sdfr	so->so_state |= (head->so_state & SS_NBIO);
344177633Sdfr	so->so_qstate &= ~SQ_COMP;
345177633Sdfr	so->so_head = NULL;
346177633Sdfr
347177633Sdfr	SOCK_UNLOCK(so);
348177633Sdfr	ACCEPT_UNLOCK();
349177633Sdfr
350177633Sdfr	*sop = so;
351177633Sdfr
352177633Sdfr	/* connection has been removed from the listen queue */
353177633Sdfr	KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0);
354177633Sdfrdone:
355177633Sdfr	return (error);
356177633Sdfr}
357177633Sdfr
358177633Sdfr/*ARGSUSED*/
359177633Sdfrstatic bool_t
360184588Sdfrsvc_vc_rendezvous_recv(SVCXPRT *xprt, struct rpc_msg *msg,
361184588Sdfr    struct sockaddr **addrp, struct mbuf **mp)
362177633Sdfr{
363177633Sdfr	struct socket *so = NULL;
364177633Sdfr	struct sockaddr *sa = NULL;
365177633Sdfr	int error;
366194407Srmacklem	SVCXPRT *new_xprt;
367177633Sdfr
368177633Sdfr	/*
369177633Sdfr	 * The socket upcall calls xprt_active() which will eventually
370177633Sdfr	 * cause the server to call us here. We attempt to accept a
371177633Sdfr	 * connection from the socket and turn it into a new
372177633Sdfr	 * transport. If the accept fails, we have drained all pending
373177633Sdfr	 * connections so we call xprt_inactive().
374177633Sdfr	 */
375184588Sdfr	sx_xlock(&xprt->xp_lock);
376177633Sdfr
377177633Sdfr	error = svc_vc_accept(xprt->xp_socket, &so);
378177633Sdfr
379177633Sdfr	if (error == EWOULDBLOCK) {
380184588Sdfr		/*
381184588Sdfr		 * We must re-test for new connections after taking
382184588Sdfr		 * the lock to protect us in the case where a new
383184588Sdfr		 * connection arrives after our call to accept fails
384261047Smav		 * with EWOULDBLOCK.
385184588Sdfr		 */
386184588Sdfr		ACCEPT_LOCK();
387184588Sdfr		if (TAILQ_EMPTY(&xprt->xp_socket->so_comp))
388261047Smav			xprt_inactive(xprt);
389184588Sdfr		ACCEPT_UNLOCK();
390184588Sdfr		sx_xunlock(&xprt->xp_lock);
391177633Sdfr		return (FALSE);
392177633Sdfr	}
393177633Sdfr
394177633Sdfr	if (error) {
395177633Sdfr		SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
396193436Srmacklem		if (xprt->xp_upcallset) {
397193436Srmacklem			xprt->xp_upcallset = 0;
398193436Srmacklem			soupcall_clear(xprt->xp_socket, SO_RCV);
399193436Srmacklem		}
400177633Sdfr		SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
401177633Sdfr		xprt_inactive(xprt);
402184588Sdfr		sx_xunlock(&xprt->xp_lock);
403177633Sdfr		return (FALSE);
404177633Sdfr	}
405177633Sdfr
406184588Sdfr	sx_xunlock(&xprt->xp_lock);
407177633Sdfr
408177633Sdfr	sa = 0;
409177633Sdfr	error = soaccept(so, &sa);
410177633Sdfr
411177633Sdfr	if (error) {
412177633Sdfr		/*
413177633Sdfr		 * XXX not sure if I need to call sofree or soclose here.
414177633Sdfr		 */
415177633Sdfr		if (sa)
416177633Sdfr			free(sa, M_SONAME);
417177633Sdfr		return (FALSE);
418177633Sdfr	}
419177633Sdfr
420177633Sdfr	/*
421177633Sdfr	 * svc_vc_create_conn will call xprt_register - we don't need
422194407Srmacklem	 * to do anything with the new connection except derefence it.
423177633Sdfr	 */
424194407Srmacklem	new_xprt = svc_vc_create_conn(xprt->xp_pool, so, sa);
425194407Srmacklem	if (!new_xprt) {
426180025Sdfr		soclose(so);
427194407Srmacklem	} else {
428194407Srmacklem		SVC_RELEASE(new_xprt);
429194407Srmacklem	}
430180025Sdfr
431177633Sdfr	free(sa, M_SONAME);
432177633Sdfr
433177633Sdfr	return (FALSE); /* there is never an rpc msg to be processed */
434177633Sdfr}
435177633Sdfr
436177633Sdfr/*ARGSUSED*/
437177633Sdfrstatic enum xprt_stat
438177633Sdfrsvc_vc_rendezvous_stat(SVCXPRT *xprt)
439177633Sdfr{
440177633Sdfr
441177633Sdfr	return (XPRT_IDLE);
442177633Sdfr}
443177633Sdfr
444177633Sdfrstatic void
445177633Sdfrsvc_vc_destroy_common(SVCXPRT *xprt)
446177633Sdfr{
447177633Sdfr	SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
448193436Srmacklem	if (xprt->xp_upcallset) {
449193436Srmacklem		xprt->xp_upcallset = 0;
450193436Srmacklem		soupcall_clear(xprt->xp_socket, SO_RCV);
451193436Srmacklem	}
452177633Sdfr	SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
453177633Sdfr
454184588Sdfr	sx_destroy(&xprt->xp_lock);
455177633Sdfr	if (xprt->xp_socket)
456177633Sdfr		(void)soclose(xprt->xp_socket);
457177633Sdfr
458184588Sdfr	if (xprt->xp_netid)
459184588Sdfr		(void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1);
460184588Sdfr	svc_xprt_free(xprt);
461177633Sdfr}
462177633Sdfr
463177633Sdfrstatic void
464177633Sdfrsvc_vc_rendezvous_destroy(SVCXPRT *xprt)
465177633Sdfr{
466177633Sdfr
467177633Sdfr	svc_vc_destroy_common(xprt);
468177633Sdfr}
469177633Sdfr
470177633Sdfrstatic void
471177633Sdfrsvc_vc_destroy(SVCXPRT *xprt)
472177633Sdfr{
473177633Sdfr	struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1;
474177633Sdfr
475177633Sdfr	svc_vc_destroy_common(xprt);
476177633Sdfr
477177633Sdfr	if (cd->mreq)
478177633Sdfr		m_freem(cd->mreq);
479177633Sdfr	if (cd->mpending)
480177633Sdfr		m_freem(cd->mpending);
481177633Sdfr	mem_free(cd, sizeof(*cd));
482177633Sdfr}
483177633Sdfr
484244008Srmacklemstatic void
485244008Srmacklemsvc_vc_backchannel_destroy(SVCXPRT *xprt)
486244008Srmacklem{
487244008Srmacklem	struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1;
488244008Srmacklem	struct mbuf *m, *m2;
489244008Srmacklem
490244008Srmacklem	svc_xprt_free(xprt);
491244008Srmacklem	m = cd->mreq;
492244008Srmacklem	while (m != NULL) {
493244008Srmacklem		m2 = m;
494244008Srmacklem		m = m->m_nextpkt;
495244008Srmacklem		m_freem(m2);
496244008Srmacklem	}
497244008Srmacklem	mem_free(cd, sizeof(*cd));
498244008Srmacklem}
499244008Srmacklem
500177633Sdfr/*ARGSUSED*/
501177633Sdfrstatic bool_t
502177633Sdfrsvc_vc_control(SVCXPRT *xprt, const u_int rq, void *in)
503177633Sdfr{
504177633Sdfr	return (FALSE);
505177633Sdfr}
506177633Sdfr
507177633Sdfrstatic bool_t
508177633Sdfrsvc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in)
509177633Sdfr{
510177633Sdfr
511177633Sdfr	return (FALSE);
512177633Sdfr}
513177633Sdfr
514244008Srmacklemstatic bool_t
515244008Srmacklemsvc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, void *in)
516244008Srmacklem{
517244008Srmacklem
518244008Srmacklem	return (FALSE);
519244008Srmacklem}
520244008Srmacklem
521177633Sdfrstatic enum xprt_stat
522177633Sdfrsvc_vc_stat(SVCXPRT *xprt)
523177633Sdfr{
524177633Sdfr	struct cf_conn *cd;
525177633Sdfr
526177633Sdfr	cd = (struct cf_conn *)(xprt->xp_p1);
527177633Sdfr
528177633Sdfr	if (cd->strm_stat == XPRT_DIED)
529177633Sdfr		return (XPRT_DIED);
530177633Sdfr
531261047Smav	if (cd->mreq != NULL && cd->resid == 0 && cd->eor)
532261047Smav		return (XPRT_MOREREQS);
533177633Sdfr
534184588Sdfr	if (soreadable(xprt->xp_socket))
535184588Sdfr		return (XPRT_MOREREQS);
536184588Sdfr
537177633Sdfr	return (XPRT_IDLE);
538177633Sdfr}
539177633Sdfr
540244008Srmacklemstatic enum xprt_stat
541244008Srmacklemsvc_vc_backchannel_stat(SVCXPRT *xprt)
542244008Srmacklem{
543244008Srmacklem	struct cf_conn *cd;
544244008Srmacklem
545244008Srmacklem	cd = (struct cf_conn *)(xprt->xp_p1);
546244008Srmacklem
547244008Srmacklem	if (cd->mreq != NULL)
548244008Srmacklem		return (XPRT_MOREREQS);
549244008Srmacklem
550244008Srmacklem	return (XPRT_IDLE);
551244008Srmacklem}
552244008Srmacklem
553261047Smav/*
554261047Smav * If we have an mbuf chain in cd->mpending, try to parse a record from it,
555261047Smav * leaving the result in cd->mreq. If we don't have a complete record, leave
556261047Smav * the partial result in cd->mreq and try to read more from the socket.
557261047Smav */
558261047Smavstatic void
559261047Smavsvc_vc_process_pending(SVCXPRT *xprt)
560261047Smav{
561261047Smav	struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
562261047Smav	struct socket *so = xprt->xp_socket;
563261047Smav	struct mbuf *m;
564261047Smav
565261047Smav	/*
566261047Smav	 * If cd->resid is non-zero, we have part of the
567261047Smav	 * record already, otherwise we are expecting a record
568261047Smav	 * marker.
569261047Smav	 */
570261047Smav	if (!cd->resid && cd->mpending) {
571261047Smav		/*
572261047Smav		 * See if there is enough data buffered to
573261047Smav		 * make up a record marker. Make sure we can
574261047Smav		 * handle the case where the record marker is
575261047Smav		 * split across more than one mbuf.
576261047Smav		 */
577261047Smav		size_t n = 0;
578261047Smav		uint32_t header;
579261047Smav
580261047Smav		m = cd->mpending;
581261047Smav		while (n < sizeof(uint32_t) && m) {
582261047Smav			n += m->m_len;
583261047Smav			m = m->m_next;
584261047Smav		}
585261047Smav		if (n < sizeof(uint32_t)) {
586261047Smav			so->so_rcv.sb_lowat = sizeof(uint32_t) - n;
587261047Smav			return;
588261047Smav		}
589261047Smav		m_copydata(cd->mpending, 0, sizeof(header),
590261047Smav		    (char *)&header);
591261047Smav		header = ntohl(header);
592261047Smav		cd->eor = (header & 0x80000000) != 0;
593261047Smav		cd->resid = header & 0x7fffffff;
594261047Smav		m_adj(cd->mpending, sizeof(uint32_t));
595261047Smav	}
596261047Smav
597261047Smav	/*
598261047Smav	 * Start pulling off mbufs from cd->mpending
599261047Smav	 * until we either have a complete record or
600261047Smav	 * we run out of data. We use m_split to pull
601261047Smav	 * data - it will pull as much as possible and
602261047Smav	 * split the last mbuf if necessary.
603261047Smav	 */
604261047Smav	while (cd->mpending && cd->resid) {
605261047Smav		m = cd->mpending;
606261047Smav		if (cd->mpending->m_next
607261047Smav		    || cd->mpending->m_len > cd->resid)
608261047Smav			cd->mpending = m_split(cd->mpending,
609261047Smav			    cd->resid, M_WAITOK);
610261047Smav		else
611261047Smav			cd->mpending = NULL;
612261047Smav		if (cd->mreq)
613261047Smav			m_last(cd->mreq)->m_next = m;
614261047Smav		else
615261047Smav			cd->mreq = m;
616261047Smav		while (m) {
617261047Smav			cd->resid -= m->m_len;
618261047Smav			m = m->m_next;
619261047Smav		}
620261047Smav	}
621261047Smav
622261047Smav	so->so_rcv.sb_lowat = imax(1, imin(cd->resid, so->so_rcv.sb_hiwat / 2));
623261047Smav}
624261047Smav
625177633Sdfrstatic bool_t
626184588Sdfrsvc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg,
627184588Sdfr    struct sockaddr **addrp, struct mbuf **mp)
628177633Sdfr{
629177633Sdfr	struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
630177633Sdfr	struct uio uio;
631177633Sdfr	struct mbuf *m;
632261047Smav	struct socket* so = xprt->xp_socket;
633184588Sdfr	XDR xdrs;
634177633Sdfr	int error, rcvflag;
635177633Sdfr
636184588Sdfr	/*
637184588Sdfr	 * Serialise access to the socket and our own record parsing
638184588Sdfr	 * state.
639184588Sdfr	 */
640184588Sdfr	sx_xlock(&xprt->xp_lock);
641184588Sdfr
642177633Sdfr	for (;;) {
643261047Smav		/* If we have no request ready, check pending queue. */
644261047Smav		while (cd->mpending &&
645261047Smav		    (cd->mreq == NULL || cd->resid != 0 || !cd->eor))
646261047Smav			svc_vc_process_pending(xprt);
647177633Sdfr
648261047Smav		/* Process and return complete request in cd->mreq. */
649261047Smav		if (cd->mreq != NULL && cd->resid == 0 && cd->eor) {
650177633Sdfr
651261047Smav			xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE);
652261047Smav			cd->mreq = NULL;
653261047Smav
654261047Smav			/* Check for next request in a pending queue. */
655261047Smav			svc_vc_process_pending(xprt);
656261047Smav			if (cd->mreq == NULL || cd->resid != 0) {
657261047Smav				SOCKBUF_LOCK(&so->so_rcv);
658261047Smav				if (!soreadable(so))
659261047Smav					xprt_inactive(xprt);
660261047Smav				SOCKBUF_UNLOCK(&so->so_rcv);
661177633Sdfr			}
662177633Sdfr
663261047Smav			sx_xunlock(&xprt->xp_lock);
664177633Sdfr
665261047Smav			if (! xdr_callmsg(&xdrs, msg)) {
666261047Smav				XDR_DESTROY(&xdrs);
667261047Smav				return (FALSE);
668261047Smav			}
669184588Sdfr
670261047Smav			*addrp = NULL;
671261047Smav			*mp = xdrmbuf_getall(&xdrs);
672261047Smav			XDR_DESTROY(&xdrs);
673177633Sdfr
674261047Smav			return (TRUE);
675177633Sdfr		}
676177633Sdfr
677177633Sdfr		/*
678177633Sdfr		 * The socket upcall calls xprt_active() which will eventually
679177633Sdfr		 * cause the server to call us here. We attempt to
680177633Sdfr		 * read as much as possible from the socket and put
681177633Sdfr		 * the result in cd->mpending. If the read fails,
682177633Sdfr		 * we have drained both cd->mpending and the socket so
683177633Sdfr		 * we can call xprt_inactive().
684177633Sdfr		 */
685177633Sdfr		uio.uio_resid = 1000000000;
686177633Sdfr		uio.uio_td = curthread;
687177633Sdfr		m = NULL;
688177633Sdfr		rcvflag = MSG_DONTWAIT;
689261047Smav		error = soreceive(so, NULL, &uio, &m, NULL, &rcvflag);
690177633Sdfr
691177633Sdfr		if (error == EWOULDBLOCK) {
692184588Sdfr			/*
693184588Sdfr			 * We must re-test for readability after
694184588Sdfr			 * taking the lock to protect us in the case
695184588Sdfr			 * where a new packet arrives on the socket
696184588Sdfr			 * after our call to soreceive fails with
697261047Smav			 * EWOULDBLOCK.
698184588Sdfr			 */
699261047Smav			SOCKBUF_LOCK(&so->so_rcv);
700261047Smav			if (!soreadable(so))
701261047Smav				xprt_inactive(xprt);
702261047Smav			SOCKBUF_UNLOCK(&so->so_rcv);
703184588Sdfr			sx_xunlock(&xprt->xp_lock);
704177633Sdfr			return (FALSE);
705177633Sdfr		}
706177633Sdfr
707177633Sdfr		if (error) {
708261047Smav			SOCKBUF_LOCK(&so->so_rcv);
709193436Srmacklem			if (xprt->xp_upcallset) {
710193436Srmacklem				xprt->xp_upcallset = 0;
711261047Smav				soupcall_clear(so, SO_RCV);
712193436Srmacklem			}
713261047Smav			SOCKBUF_UNLOCK(&so->so_rcv);
714177633Sdfr			xprt_inactive(xprt);
715177633Sdfr			cd->strm_stat = XPRT_DIED;
716184588Sdfr			sx_xunlock(&xprt->xp_lock);
717177633Sdfr			return (FALSE);
718177633Sdfr		}
719177633Sdfr
720177633Sdfr		if (!m) {
721177633Sdfr			/*
722177633Sdfr			 * EOF - the other end has closed the socket.
723177633Sdfr			 */
724184588Sdfr			xprt_inactive(xprt);
725177633Sdfr			cd->strm_stat = XPRT_DIED;
726184588Sdfr			sx_xunlock(&xprt->xp_lock);
727177633Sdfr			return (FALSE);
728177633Sdfr		}
729177633Sdfr
730177633Sdfr		if (cd->mpending)
731177633Sdfr			m_last(cd->mpending)->m_next = m;
732177633Sdfr		else
733177633Sdfr			cd->mpending = m;
734177633Sdfr	}
735177633Sdfr}
736177633Sdfr
737177633Sdfrstatic bool_t
738244008Srmacklemsvc_vc_backchannel_recv(SVCXPRT *xprt, struct rpc_msg *msg,
739244008Srmacklem    struct sockaddr **addrp, struct mbuf **mp)
740244008Srmacklem{
741244008Srmacklem	struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
742244008Srmacklem	struct ct_data *ct;
743244008Srmacklem	struct mbuf *m;
744244008Srmacklem	XDR xdrs;
745244008Srmacklem
746244008Srmacklem	sx_xlock(&xprt->xp_lock);
747244008Srmacklem	ct = (struct ct_data *)xprt->xp_p2;
748244008Srmacklem	if (ct == NULL) {
749244008Srmacklem		sx_xunlock(&xprt->xp_lock);
750244008Srmacklem		return (FALSE);
751244008Srmacklem	}
752244008Srmacklem	mtx_lock(&ct->ct_lock);
753244008Srmacklem	m = cd->mreq;
754244008Srmacklem	if (m == NULL) {
755244008Srmacklem		xprt_inactive(xprt);
756244008Srmacklem		mtx_unlock(&ct->ct_lock);
757244008Srmacklem		sx_xunlock(&xprt->xp_lock);
758244008Srmacklem		return (FALSE);
759244008Srmacklem	}
760244008Srmacklem	cd->mreq = m->m_nextpkt;
761244008Srmacklem	mtx_unlock(&ct->ct_lock);
762244008Srmacklem	sx_xunlock(&xprt->xp_lock);
763244008Srmacklem
764244008Srmacklem	xdrmbuf_create(&xdrs, m, XDR_DECODE);
765244008Srmacklem	if (! xdr_callmsg(&xdrs, msg)) {
766244008Srmacklem		XDR_DESTROY(&xdrs);
767244008Srmacklem		return (FALSE);
768244008Srmacklem	}
769244008Srmacklem	*addrp = NULL;
770244008Srmacklem	*mp = xdrmbuf_getall(&xdrs);
771244008Srmacklem	XDR_DESTROY(&xdrs);
772244008Srmacklem	return (TRUE);
773244008Srmacklem}
774244008Srmacklem
775244008Srmacklemstatic bool_t
776184588Sdfrsvc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg,
777184588Sdfr    struct sockaddr *addr, struct mbuf *m)
778177633Sdfr{
779177633Sdfr	XDR xdrs;
780177633Sdfr	struct mbuf *mrep;
781184588Sdfr	bool_t stat = TRUE;
782177633Sdfr	int error;
783177633Sdfr
784177633Sdfr	/*
785177633Sdfr	 * Leave space for record mark.
786177633Sdfr	 */
787248195Sglebius	mrep = m_gethdr(M_WAITOK, MT_DATA);
788177633Sdfr	mrep->m_data += sizeof(uint32_t);
789177633Sdfr
790184588Sdfr	xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);
791184588Sdfr
792184588Sdfr	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
793184588Sdfr	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
794184588Sdfr		if (!xdr_replymsg(&xdrs, msg))
795184588Sdfr			stat = FALSE;
796184588Sdfr		else
797184588Sdfr			xdrmbuf_append(&xdrs, m);
798184588Sdfr	} else {
799184588Sdfr		stat = xdr_replymsg(&xdrs, msg);
800184588Sdfr	}
801184588Sdfr
802184588Sdfr	if (stat) {
803177633Sdfr		m_fixhdr(mrep);
804177633Sdfr
805177633Sdfr		/*
806177633Sdfr		 * Prepend a record marker containing the reply length.
807177633Sdfr		 */
808243882Sglebius		M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK);
809177633Sdfr		*mtod(mrep, uint32_t *) =
810177633Sdfr			htonl(0x80000000 | (mrep->m_pkthdr.len
811177633Sdfr				- sizeof(uint32_t)));
812177633Sdfr		error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL,
813177633Sdfr		    0, curthread);
814177633Sdfr		if (!error) {
815177633Sdfr			stat = TRUE;
816177633Sdfr		}
817177633Sdfr	} else {
818177633Sdfr		m_freem(mrep);
819177633Sdfr	}
820177633Sdfr
821184588Sdfr	XDR_DESTROY(&xdrs);
822177633Sdfr	xprt->xp_p2 = NULL;
823177633Sdfr
824177633Sdfr	return (stat);
825177633Sdfr}
826177633Sdfr
827177633Sdfrstatic bool_t
828244008Srmacklemsvc_vc_backchannel_reply(SVCXPRT *xprt, struct rpc_msg *msg,
829244008Srmacklem    struct sockaddr *addr, struct mbuf *m)
830244008Srmacklem{
831244008Srmacklem	struct ct_data *ct;
832244008Srmacklem	XDR xdrs;
833244008Srmacklem	struct mbuf *mrep;
834244008Srmacklem	bool_t stat = TRUE;
835244008Srmacklem	int error;
836244008Srmacklem
837244008Srmacklem	/*
838244008Srmacklem	 * Leave space for record mark.
839244008Srmacklem	 */
840248195Sglebius	mrep = m_gethdr(M_WAITOK, MT_DATA);
841244008Srmacklem	mrep->m_data += sizeof(uint32_t);
842244008Srmacklem
843244008Srmacklem	xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);
844244008Srmacklem
845244008Srmacklem	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
846244008Srmacklem	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
847244008Srmacklem		if (!xdr_replymsg(&xdrs, msg))
848244008Srmacklem			stat = FALSE;
849244008Srmacklem		else
850244008Srmacklem			xdrmbuf_append(&xdrs, m);
851244008Srmacklem	} else {
852244008Srmacklem		stat = xdr_replymsg(&xdrs, msg);
853244008Srmacklem	}
854244008Srmacklem
855244008Srmacklem	if (stat) {
856244008Srmacklem		m_fixhdr(mrep);
857244008Srmacklem
858244008Srmacklem		/*
859244008Srmacklem		 * Prepend a record marker containing the reply length.
860244008Srmacklem		 */
861244008Srmacklem		M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK);
862244008Srmacklem		*mtod(mrep, uint32_t *) =
863244008Srmacklem			htonl(0x80000000 | (mrep->m_pkthdr.len
864244008Srmacklem				- sizeof(uint32_t)));
865244008Srmacklem		sx_xlock(&xprt->xp_lock);
866244008Srmacklem		ct = (struct ct_data *)xprt->xp_p2;
867244008Srmacklem		if (ct != NULL)
868244008Srmacklem			error = sosend(ct->ct_socket, NULL, NULL, mrep, NULL,
869244008Srmacklem			    0, curthread);
870244008Srmacklem		else
871244008Srmacklem			error = EPIPE;
872244008Srmacklem		sx_xunlock(&xprt->xp_lock);
873244008Srmacklem		if (!error) {
874244008Srmacklem			stat = TRUE;
875244008Srmacklem		}
876244008Srmacklem	} else {
877244008Srmacklem		m_freem(mrep);
878244008Srmacklem	}
879244008Srmacklem
880244008Srmacklem	XDR_DESTROY(&xdrs);
881244008Srmacklem
882244008Srmacklem	return (stat);
883244008Srmacklem}
884244008Srmacklem
885244008Srmacklemstatic bool_t
886177633Sdfrsvc_vc_null()
887177633Sdfr{
888177633Sdfr
889177633Sdfr	return (FALSE);
890177633Sdfr}
891177633Sdfr
892193272Sjhbstatic int
893177633Sdfrsvc_vc_soupcall(struct socket *so, void *arg, int waitflag)
894177633Sdfr{
895177633Sdfr	SVCXPRT *xprt = (SVCXPRT *) arg;
896177633Sdfr
897261047Smav	if (soreadable(xprt->xp_socket))
898261047Smav		xprt_active(xprt);
899193272Sjhb	return (SU_OK);
900177633Sdfr}
901177633Sdfr
902177633Sdfr#if 0
903177633Sdfr/*
904177633Sdfr * Get the effective UID of the sending process. Used by rpcbind, keyserv
905177633Sdfr * and rpc.yppasswdd on AF_LOCAL.
906177633Sdfr */
907177633Sdfrint
908177633Sdfr__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) {
909177633Sdfr	int sock, ret;
910177633Sdfr	gid_t egid;
911177633Sdfr	uid_t euid;
912177633Sdfr	struct sockaddr *sa;
913177633Sdfr
914177633Sdfr	sock = transp->xp_fd;
915184588Sdfr	sa = (struct sockaddr *)transp->xp_rtaddr;
916177633Sdfr	if (sa->sa_family == AF_LOCAL) {
917177633Sdfr		ret = getpeereid(sock, &euid, &egid);
918177633Sdfr		if (ret == 0)
919177633Sdfr			*uid = euid;
920177633Sdfr		return (ret);
921177633Sdfr	} else
922177633Sdfr		return (-1);
923177633Sdfr}
924177633Sdfr#endif
925