svc_vc.c revision 193436
1/*	$NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $	*/
2
3/*
4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5 * unrestricted use provided that this legend is included on all tape
6 * media and as a part of the software program in whole or part.  Users
7 * may copy or modify Sun RPC without charge, but are not authorized
8 * to license or distribute it to anyone else except as part of a product or
9 * program developed by the user.
10 *
11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14 *
15 * Sun RPC is provided with no support and without any obligation on the
16 * part of Sun Microsystems, Inc. to assist in its use, correction,
17 * modification or enhancement.
18 *
19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21 * OR ANY PART THEREOF.
22 *
23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24 * or profits or other special, indirect and consequential damages, even if
25 * Sun has been advised of the possibility of such damages.
26 *
27 * Sun Microsystems, Inc.
28 * 2550 Garcia Avenue
29 * Mountain View, California  94043
30 */
31
32#if defined(LIBC_SCCS) && !defined(lint)
33static char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
34static char *sccsid = "@(#)svc_tcp.c	2.2 88/08/01 4.0 RPCSRC";
35#endif
36#include <sys/cdefs.h>
37__FBSDID("$FreeBSD: head/sys/rpc/svc_vc.c 193436 2009-06-04 14:13:06Z rmacklem $");
38
39/*
40 * svc_vc.c, Server side for Connection Oriented based RPC.
41 *
42 * Actually implements two flavors of transporter -
43 * a tcp rendezvouser (a listner and connection establisher)
44 * and a record/tcp stream.
45 */
46
47#include <sys/param.h>
48#include <sys/lock.h>
49#include <sys/kernel.h>
50#include <sys/malloc.h>
51#include <sys/mbuf.h>
52#include <sys/mutex.h>
53#include <sys/protosw.h>
54#include <sys/queue.h>
55#include <sys/socket.h>
56#include <sys/socketvar.h>
57#include <sys/sx.h>
58#include <sys/systm.h>
59#include <sys/uio.h>
60#include <netinet/tcp.h>
61
62#include <rpc/rpc.h>
63
64#include <rpc/rpc_com.h>
65
66static bool_t svc_vc_rendezvous_recv(SVCXPRT *, struct rpc_msg *,
67    struct sockaddr **, struct mbuf **);
68static enum xprt_stat svc_vc_rendezvous_stat(SVCXPRT *);
69static void svc_vc_rendezvous_destroy(SVCXPRT *);
70static bool_t svc_vc_null(void);
71static void svc_vc_destroy(SVCXPRT *);
72static enum xprt_stat svc_vc_stat(SVCXPRT *);
73static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *,
74    struct sockaddr **, struct mbuf **);
75static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *,
76    struct sockaddr *, struct mbuf *);
77static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in);
78static bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq,
79    void *in);
80static SVCXPRT *svc_vc_create_conn(SVCPOOL *pool, struct socket *so,
81    struct sockaddr *raddr);
82static int svc_vc_accept(struct socket *head, struct socket **sop);
83static int svc_vc_soupcall(struct socket *so, void *arg, int waitflag);
84
85static struct xp_ops svc_vc_rendezvous_ops = {
86	.xp_recv =	svc_vc_rendezvous_recv,
87	.xp_stat =	svc_vc_rendezvous_stat,
88	.xp_reply =	(bool_t (*)(SVCXPRT *, struct rpc_msg *,
89		struct sockaddr *, struct mbuf *))svc_vc_null,
90	.xp_destroy =	svc_vc_rendezvous_destroy,
91	.xp_control =	svc_vc_rendezvous_control
92};
93
94static struct xp_ops svc_vc_ops = {
95	.xp_recv =	svc_vc_recv,
96	.xp_stat =	svc_vc_stat,
97	.xp_reply =	svc_vc_reply,
98	.xp_destroy =	svc_vc_destroy,
99	.xp_control =	svc_vc_control
100};
101
102struct cf_conn {  /* kept in xprt->xp_p1 for actual connection */
103	enum xprt_stat strm_stat;
104	struct mbuf *mpending;	/* unparsed data read from the socket */
105	struct mbuf *mreq;	/* current record being built from mpending */
106	uint32_t resid;		/* number of bytes needed for fragment */
107	bool_t eor;		/* reading last fragment of current record */
108};
109
110/*
111 * Usage:
112 *	xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
113 *
114 * Creates, registers, and returns a (rpc) tcp based transporter.
115 * Once *xprt is initialized, it is registered as a transporter
116 * see (svc.h, xprt_register).  This routine returns
117 * a NULL if a problem occurred.
118 *
119 * The filedescriptor passed in is expected to refer to a bound, but
120 * not yet connected socket.
121 *
122 * Since streams do buffered io similar to stdio, the caller can specify
123 * how big the send and receive buffers are via the second and third parms;
124 * 0 => use the system default.
125 */
126SVCXPRT *
127svc_vc_create(SVCPOOL *pool, struct socket *so, size_t sendsize,
128    size_t recvsize)
129{
130	SVCXPRT *xprt;
131	struct sockaddr* sa;
132	int error;
133
134	if (so->so_state & SS_ISCONNECTED) {
135		error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa);
136		if (error)
137			return (NULL);
138		xprt = svc_vc_create_conn(pool, so, sa);
139		free(sa, M_SONAME);
140		return (xprt);
141	}
142
143	xprt = svc_xprt_alloc();
144	sx_init(&xprt->xp_lock, "xprt->xp_lock");
145	xprt->xp_pool = pool;
146	xprt->xp_socket = so;
147	xprt->xp_p1 = NULL;
148	xprt->xp_p2 = NULL;
149	xprt->xp_ops = &svc_vc_rendezvous_ops;
150
151	error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
152	if (error)
153		goto cleanup_svc_vc_create;
154
155	memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
156	free(sa, M_SONAME);
157
158	xprt_register(xprt);
159
160	solisten(so, SOMAXCONN, curthread);
161
162	SOCKBUF_LOCK(&so->so_rcv);
163	xprt->xp_upcallset = 1;
164	soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt);
165	SOCKBUF_UNLOCK(&so->so_rcv);
166
167	return (xprt);
168cleanup_svc_vc_create:
169	if (xprt)
170		svc_xprt_free(xprt);
171	return (NULL);
172}
173
174/*
175 * Create a new transport for a socket optained via soaccept().
176 */
177SVCXPRT *
178svc_vc_create_conn(SVCPOOL *pool, struct socket *so, struct sockaddr *raddr)
179{
180	SVCXPRT *xprt = NULL;
181	struct cf_conn *cd = NULL;
182	struct sockaddr* sa = NULL;
183	struct sockopt opt;
184	int one = 1;
185	int error;
186
187	bzero(&opt, sizeof(struct sockopt));
188	opt.sopt_dir = SOPT_SET;
189	opt.sopt_level = SOL_SOCKET;
190	opt.sopt_name = SO_KEEPALIVE;
191	opt.sopt_val = &one;
192	opt.sopt_valsize = sizeof(one);
193	error = sosetopt(so, &opt);
194	if (error)
195		return (NULL);
196
197	if (so->so_proto->pr_protocol == IPPROTO_TCP) {
198		bzero(&opt, sizeof(struct sockopt));
199		opt.sopt_dir = SOPT_SET;
200		opt.sopt_level = IPPROTO_TCP;
201		opt.sopt_name = TCP_NODELAY;
202		opt.sopt_val = &one;
203		opt.sopt_valsize = sizeof(one);
204		error = sosetopt(so, &opt);
205		if (error)
206			return (NULL);
207	}
208
209	cd = mem_alloc(sizeof(*cd));
210	cd->strm_stat = XPRT_IDLE;
211
212	xprt = svc_xprt_alloc();
213	sx_init(&xprt->xp_lock, "xprt->xp_lock");
214	xprt->xp_pool = pool;
215	xprt->xp_socket = so;
216	xprt->xp_p1 = cd;
217	xprt->xp_p2 = NULL;
218	xprt->xp_ops = &svc_vc_ops;
219
220	/*
221	 * See http://www.connectathon.org/talks96/nfstcp.pdf - client
222	 * has a 5 minute timer, server has a 6 minute timer.
223	 */
224	xprt->xp_idletimeout = 6 * 60;
225
226	memcpy(&xprt->xp_rtaddr, raddr, raddr->sa_len);
227
228	error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
229	if (error)
230		goto cleanup_svc_vc_create;
231
232	memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
233	free(sa, M_SONAME);
234
235	xprt_register(xprt);
236
237	SOCKBUF_LOCK(&so->so_rcv);
238	xprt->xp_upcallset = 1;
239	soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt);
240	SOCKBUF_UNLOCK(&so->so_rcv);
241
242	/*
243	 * Throw the transport into the active list in case it already
244	 * has some data buffered.
245	 */
246	sx_xlock(&xprt->xp_lock);
247	xprt_active(xprt);
248	sx_xunlock(&xprt->xp_lock);
249
250	return (xprt);
251cleanup_svc_vc_create:
252	if (xprt) {
253		mem_free(xprt, sizeof(*xprt));
254	}
255	if (cd)
256		mem_free(cd, sizeof(*cd));
257	return (NULL);
258}
259
260/*
261 * This does all of the accept except the final call to soaccept. The
262 * caller will call soaccept after dropping its locks (soaccept may
263 * call malloc).
264 */
265int
266svc_vc_accept(struct socket *head, struct socket **sop)
267{
268	int error = 0;
269	struct socket *so;
270
271	if ((head->so_options & SO_ACCEPTCONN) == 0) {
272		error = EINVAL;
273		goto done;
274	}
275#ifdef MAC
276	error = mac_socket_check_accept(td->td_ucred, head);
277	if (error != 0)
278		goto done;
279#endif
280	ACCEPT_LOCK();
281	if (TAILQ_EMPTY(&head->so_comp)) {
282		ACCEPT_UNLOCK();
283		error = EWOULDBLOCK;
284		goto done;
285	}
286	so = TAILQ_FIRST(&head->so_comp);
287	KASSERT(!(so->so_qstate & SQ_INCOMP), ("svc_vc_accept: so SQ_INCOMP"));
288	KASSERT(so->so_qstate & SQ_COMP, ("svc_vc_accept: so not SQ_COMP"));
289
290	/*
291	 * Before changing the flags on the socket, we have to bump the
292	 * reference count.  Otherwise, if the protocol calls sofree(),
293	 * the socket will be released due to a zero refcount.
294	 * XXX might not need soref() since this is simpler than kern_accept.
295	 */
296	SOCK_LOCK(so);			/* soref() and so_state update */
297	soref(so);			/* file descriptor reference */
298
299	TAILQ_REMOVE(&head->so_comp, so, so_list);
300	head->so_qlen--;
301	so->so_state |= (head->so_state & SS_NBIO);
302	so->so_qstate &= ~SQ_COMP;
303	so->so_head = NULL;
304
305	SOCK_UNLOCK(so);
306	ACCEPT_UNLOCK();
307
308	*sop = so;
309
310	/* connection has been removed from the listen queue */
311	KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0);
312done:
313	return (error);
314}
315
316/*ARGSUSED*/
317static bool_t
318svc_vc_rendezvous_recv(SVCXPRT *xprt, struct rpc_msg *msg,
319    struct sockaddr **addrp, struct mbuf **mp)
320{
321	struct socket *so = NULL;
322	struct sockaddr *sa = NULL;
323	int error;
324
325	/*
326	 * The socket upcall calls xprt_active() which will eventually
327	 * cause the server to call us here. We attempt to accept a
328	 * connection from the socket and turn it into a new
329	 * transport. If the accept fails, we have drained all pending
330	 * connections so we call xprt_inactive().
331	 */
332	sx_xlock(&xprt->xp_lock);
333
334	error = svc_vc_accept(xprt->xp_socket, &so);
335
336	if (error == EWOULDBLOCK) {
337		/*
338		 * We must re-test for new connections after taking
339		 * the lock to protect us in the case where a new
340		 * connection arrives after our call to accept fails
341		 * with EWOULDBLOCK. The pool lock protects us from
342		 * racing the upcall after our TAILQ_EMPTY() call
343		 * returns false.
344		 */
345		ACCEPT_LOCK();
346		mtx_lock(&xprt->xp_pool->sp_lock);
347		if (TAILQ_EMPTY(&xprt->xp_socket->so_comp))
348			xprt_inactive_locked(xprt);
349		mtx_unlock(&xprt->xp_pool->sp_lock);
350		ACCEPT_UNLOCK();
351		sx_xunlock(&xprt->xp_lock);
352		return (FALSE);
353	}
354
355	if (error) {
356		SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
357		if (xprt->xp_upcallset) {
358			xprt->xp_upcallset = 0;
359			soupcall_clear(xprt->xp_socket, SO_RCV);
360		}
361		SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
362		xprt_inactive(xprt);
363		sx_xunlock(&xprt->xp_lock);
364		return (FALSE);
365	}
366
367	sx_xunlock(&xprt->xp_lock);
368
369	sa = 0;
370	error = soaccept(so, &sa);
371
372	if (error) {
373		/*
374		 * XXX not sure if I need to call sofree or soclose here.
375		 */
376		if (sa)
377			free(sa, M_SONAME);
378		return (FALSE);
379	}
380
381	/*
382	 * svc_vc_create_conn will call xprt_register - we don't need
383	 * to do anything with the new connection.
384	 */
385	if (!svc_vc_create_conn(xprt->xp_pool, so, sa))
386		soclose(so);
387
388	free(sa, M_SONAME);
389
390	return (FALSE); /* there is never an rpc msg to be processed */
391}
392
393/*ARGSUSED*/
394static enum xprt_stat
395svc_vc_rendezvous_stat(SVCXPRT *xprt)
396{
397
398	return (XPRT_IDLE);
399}
400
401static void
402svc_vc_destroy_common(SVCXPRT *xprt)
403{
404	SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
405	if (xprt->xp_upcallset) {
406		xprt->xp_upcallset = 0;
407		soupcall_clear(xprt->xp_socket, SO_RCV);
408	}
409	SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
410
411	sx_destroy(&xprt->xp_lock);
412	if (xprt->xp_socket)
413		(void)soclose(xprt->xp_socket);
414
415	if (xprt->xp_netid)
416		(void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1);
417	svc_xprt_free(xprt);
418}
419
420static void
421svc_vc_rendezvous_destroy(SVCXPRT *xprt)
422{
423
424	svc_vc_destroy_common(xprt);
425}
426
427static void
428svc_vc_destroy(SVCXPRT *xprt)
429{
430	struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1;
431
432	svc_vc_destroy_common(xprt);
433
434	if (cd->mreq)
435		m_freem(cd->mreq);
436	if (cd->mpending)
437		m_freem(cd->mpending);
438	mem_free(cd, sizeof(*cd));
439}
440
441/*ARGSUSED*/
442static bool_t
443svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in)
444{
445	return (FALSE);
446}
447
448static bool_t
449svc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in)
450{
451
452	return (FALSE);
453}
454
455static enum xprt_stat
456svc_vc_stat(SVCXPRT *xprt)
457{
458	struct cf_conn *cd;
459	struct mbuf *m;
460	size_t n;
461
462	cd = (struct cf_conn *)(xprt->xp_p1);
463
464	if (cd->strm_stat == XPRT_DIED)
465		return (XPRT_DIED);
466
467	/*
468	 * Return XPRT_MOREREQS if we have buffered data and we are
469	 * mid-record or if we have enough data for a record
470	 * marker. Since this is only a hint, we read mpending and
471	 * resid outside the lock. We do need to take the lock if we
472	 * have to traverse the mbuf chain.
473	 */
474	if (cd->mpending) {
475		if (cd->resid)
476			return (XPRT_MOREREQS);
477		n = 0;
478		sx_xlock(&xprt->xp_lock);
479		m = cd->mpending;
480		while (m && n < sizeof(uint32_t)) {
481			n += m->m_len;
482			m = m->m_next;
483		}
484		sx_xunlock(&xprt->xp_lock);
485		if (n >= sizeof(uint32_t))
486			return (XPRT_MOREREQS);
487	}
488
489	if (soreadable(xprt->xp_socket))
490		return (XPRT_MOREREQS);
491
492	return (XPRT_IDLE);
493}
494
495static bool_t
496svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg,
497    struct sockaddr **addrp, struct mbuf **mp)
498{
499	struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
500	struct uio uio;
501	struct mbuf *m;
502	XDR xdrs;
503	int error, rcvflag;
504
505	/*
506	 * Serialise access to the socket and our own record parsing
507	 * state.
508	 */
509	sx_xlock(&xprt->xp_lock);
510
511	for (;;) {
512		/*
513		 * If we have an mbuf chain in cd->mpending, try to parse a
514		 * record from it, leaving the result in cd->mreq. If we don't
515		 * have a complete record, leave the partial result in
516		 * cd->mreq and try to read more from the socket.
517		 */
518		if (cd->mpending) {
519			/*
520			 * If cd->resid is non-zero, we have part of the
521			 * record already, otherwise we are expecting a record
522			 * marker.
523			 */
524			if (!cd->resid) {
525				/*
526				 * See if there is enough data buffered to
527				 * make up a record marker. Make sure we can
528				 * handle the case where the record marker is
529				 * split across more than one mbuf.
530				 */
531				size_t n = 0;
532				uint32_t header;
533
534				m = cd->mpending;
535				while (n < sizeof(uint32_t) && m) {
536					n += m->m_len;
537					m = m->m_next;
538				}
539				if (n < sizeof(uint32_t))
540					goto readmore;
541				if (cd->mpending->m_len < sizeof(uint32_t))
542					cd->mpending = m_pullup(cd->mpending,
543					    sizeof(uint32_t));
544				memcpy(&header, mtod(cd->mpending, uint32_t *),
545				    sizeof(header));
546				header = ntohl(header);
547				cd->eor = (header & 0x80000000) != 0;
548				cd->resid = header & 0x7fffffff;
549				m_adj(cd->mpending, sizeof(uint32_t));
550			}
551
552			/*
553			 * Start pulling off mbufs from cd->mpending
554			 * until we either have a complete record or
555			 * we run out of data. We use m_split to pull
556			 * data - it will pull as much as possible and
557			 * split the last mbuf if necessary.
558			 */
559			while (cd->mpending && cd->resid) {
560				m = cd->mpending;
561				if (cd->mpending->m_next
562				    || cd->mpending->m_len > cd->resid)
563					cd->mpending = m_split(cd->mpending,
564					    cd->resid, M_WAIT);
565				else
566					cd->mpending = NULL;
567				if (cd->mreq)
568					m_last(cd->mreq)->m_next = m;
569				else
570					cd->mreq = m;
571				while (m) {
572					cd->resid -= m->m_len;
573					m = m->m_next;
574				}
575			}
576
577			/*
578			 * If cd->resid is zero now, we have managed to
579			 * receive a record fragment from the stream. Check
580			 * for the end-of-record mark to see if we need more.
581			 */
582			if (cd->resid == 0) {
583				if (!cd->eor)
584					continue;
585
586				/*
587				 * Success - we have a complete record in
588				 * cd->mreq.
589				 */
590				xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE);
591				cd->mreq = NULL;
592				sx_xunlock(&xprt->xp_lock);
593
594				if (! xdr_callmsg(&xdrs, msg)) {
595					XDR_DESTROY(&xdrs);
596					return (FALSE);
597				}
598
599				*addrp = NULL;
600				*mp = xdrmbuf_getall(&xdrs);
601				XDR_DESTROY(&xdrs);
602
603				return (TRUE);
604			}
605		}
606
607	readmore:
608		/*
609		 * The socket upcall calls xprt_active() which will eventually
610		 * cause the server to call us here. We attempt to
611		 * read as much as possible from the socket and put
612		 * the result in cd->mpending. If the read fails,
613		 * we have drained both cd->mpending and the socket so
614		 * we can call xprt_inactive().
615		 */
616		uio.uio_resid = 1000000000;
617		uio.uio_td = curthread;
618		m = NULL;
619		rcvflag = MSG_DONTWAIT;
620		error = soreceive(xprt->xp_socket, NULL, &uio, &m, NULL,
621		    &rcvflag);
622
623		if (error == EWOULDBLOCK) {
624			/*
625			 * We must re-test for readability after
626			 * taking the lock to protect us in the case
627			 * where a new packet arrives on the socket
628			 * after our call to soreceive fails with
629			 * EWOULDBLOCK. The pool lock protects us from
630			 * racing the upcall after our soreadable()
631			 * call returns false.
632			 */
633			mtx_lock(&xprt->xp_pool->sp_lock);
634			if (!soreadable(xprt->xp_socket))
635				xprt_inactive_locked(xprt);
636			mtx_unlock(&xprt->xp_pool->sp_lock);
637			sx_xunlock(&xprt->xp_lock);
638			return (FALSE);
639		}
640
641		if (error) {
642			SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
643			if (xprt->xp_upcallset) {
644				xprt->xp_upcallset = 0;
645				soupcall_clear(xprt->xp_socket, SO_RCV);
646			}
647			SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
648			xprt_inactive(xprt);
649			cd->strm_stat = XPRT_DIED;
650			sx_xunlock(&xprt->xp_lock);
651			return (FALSE);
652		}
653
654		if (!m) {
655			/*
656			 * EOF - the other end has closed the socket.
657			 */
658			xprt_inactive(xprt);
659			cd->strm_stat = XPRT_DIED;
660			sx_xunlock(&xprt->xp_lock);
661			return (FALSE);
662		}
663
664		if (cd->mpending)
665			m_last(cd->mpending)->m_next = m;
666		else
667			cd->mpending = m;
668	}
669}
670
671static bool_t
672svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg,
673    struct sockaddr *addr, struct mbuf *m)
674{
675	XDR xdrs;
676	struct mbuf *mrep;
677	bool_t stat = TRUE;
678	int error;
679
680	/*
681	 * Leave space for record mark.
682	 */
683	MGETHDR(mrep, M_WAIT, MT_DATA);
684	mrep->m_len = 0;
685	mrep->m_data += sizeof(uint32_t);
686
687	xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);
688
689	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
690	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
691		if (!xdr_replymsg(&xdrs, msg))
692			stat = FALSE;
693		else
694			xdrmbuf_append(&xdrs, m);
695	} else {
696		stat = xdr_replymsg(&xdrs, msg);
697	}
698
699	if (stat) {
700		m_fixhdr(mrep);
701
702		/*
703		 * Prepend a record marker containing the reply length.
704		 */
705		M_PREPEND(mrep, sizeof(uint32_t), M_WAIT);
706		*mtod(mrep, uint32_t *) =
707			htonl(0x80000000 | (mrep->m_pkthdr.len
708				- sizeof(uint32_t)));
709		error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL,
710		    0, curthread);
711		if (!error) {
712			stat = TRUE;
713		}
714	} else {
715		m_freem(mrep);
716	}
717
718	XDR_DESTROY(&xdrs);
719	xprt->xp_p2 = NULL;
720
721	return (stat);
722}
723
724static bool_t
725svc_vc_null()
726{
727
728	return (FALSE);
729}
730
731static int
732svc_vc_soupcall(struct socket *so, void *arg, int waitflag)
733{
734	SVCXPRT *xprt = (SVCXPRT *) arg;
735
736	xprt_active(xprt);
737	return (SU_OK);
738}
739
740#if 0
741/*
742 * Get the effective UID of the sending process. Used by rpcbind, keyserv
743 * and rpc.yppasswdd on AF_LOCAL.
744 */
745int
746__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) {
747	int sock, ret;
748	gid_t egid;
749	uid_t euid;
750	struct sockaddr *sa;
751
752	sock = transp->xp_fd;
753	sa = (struct sockaddr *)transp->xp_rtaddr;
754	if (sa->sa_family == AF_LOCAL) {
755		ret = getpeereid(sock, &euid, &egid);
756		if (ret == 0)
757			*uid = euid;
758		return (ret);
759	} else
760		return (-1);
761}
762#endif
763