svc_vc.c revision 193332
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 193332 2009-06-02 18:26:17Z rwatson $");
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	soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt);
164	SOCKBUF_UNLOCK(&so->so_rcv);
165
166	return (xprt);
167cleanup_svc_vc_create:
168	if (xprt)
169		svc_xprt_free(xprt);
170	return (NULL);
171}
172
173/*
174 * Create a new transport for a socket optained via soaccept().
175 */
176SVCXPRT *
177svc_vc_create_conn(SVCPOOL *pool, struct socket *so, struct sockaddr *raddr)
178{
179	SVCXPRT *xprt = NULL;
180	struct cf_conn *cd = NULL;
181	struct sockaddr* sa = NULL;
182	struct sockopt opt;
183	int one = 1;
184	int error;
185
186	bzero(&opt, sizeof(struct sockopt));
187	opt.sopt_dir = SOPT_SET;
188	opt.sopt_level = SOL_SOCKET;
189	opt.sopt_name = SO_KEEPALIVE;
190	opt.sopt_val = &one;
191	opt.sopt_valsize = sizeof(one);
192	error = sosetopt(so, &opt);
193	if (error)
194		return (NULL);
195
196	if (so->so_proto->pr_protocol == IPPROTO_TCP) {
197		bzero(&opt, sizeof(struct sockopt));
198		opt.sopt_dir = SOPT_SET;
199		opt.sopt_level = IPPROTO_TCP;
200		opt.sopt_name = TCP_NODELAY;
201		opt.sopt_val = &one;
202		opt.sopt_valsize = sizeof(one);
203		error = sosetopt(so, &opt);
204		if (error)
205			return (NULL);
206	}
207
208	cd = mem_alloc(sizeof(*cd));
209	cd->strm_stat = XPRT_IDLE;
210
211	xprt = svc_xprt_alloc();
212	sx_init(&xprt->xp_lock, "xprt->xp_lock");
213	xprt->xp_pool = pool;
214	xprt->xp_socket = so;
215	xprt->xp_p1 = cd;
216	xprt->xp_p2 = NULL;
217	xprt->xp_ops = &svc_vc_ops;
218
219	/*
220	 * See http://www.connectathon.org/talks96/nfstcp.pdf - client
221	 * has a 5 minute timer, server has a 6 minute timer.
222	 */
223	xprt->xp_idletimeout = 6 * 60;
224
225	memcpy(&xprt->xp_rtaddr, raddr, raddr->sa_len);
226
227	error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
228	if (error)
229		goto cleanup_svc_vc_create;
230
231	memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
232	free(sa, M_SONAME);
233
234	xprt_register(xprt);
235
236	SOCKBUF_LOCK(&so->so_rcv);
237	soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt);
238	SOCKBUF_UNLOCK(&so->so_rcv);
239
240	/*
241	 * Throw the transport into the active list in case it already
242	 * has some data buffered.
243	 */
244	sx_xlock(&xprt->xp_lock);
245	xprt_active(xprt);
246	sx_xunlock(&xprt->xp_lock);
247
248	return (xprt);
249cleanup_svc_vc_create:
250	if (xprt) {
251		mem_free(xprt, sizeof(*xprt));
252	}
253	if (cd)
254		mem_free(cd, sizeof(*cd));
255	return (NULL);
256}
257
258/*
259 * This does all of the accept except the final call to soaccept. The
260 * caller will call soaccept after dropping its locks (soaccept may
261 * call malloc).
262 */
263int
264svc_vc_accept(struct socket *head, struct socket **sop)
265{
266	int error = 0;
267	struct socket *so;
268
269	if ((head->so_options & SO_ACCEPTCONN) == 0) {
270		error = EINVAL;
271		goto done;
272	}
273#ifdef MAC
274	error = mac_socket_check_accept(td->td_ucred, head);
275	if (error != 0)
276		goto done;
277#endif
278	ACCEPT_LOCK();
279	if (TAILQ_EMPTY(&head->so_comp)) {
280		ACCEPT_UNLOCK();
281		error = EWOULDBLOCK;
282		goto done;
283	}
284	so = TAILQ_FIRST(&head->so_comp);
285	KASSERT(!(so->so_qstate & SQ_INCOMP), ("svc_vc_accept: so SQ_INCOMP"));
286	KASSERT(so->so_qstate & SQ_COMP, ("svc_vc_accept: so not SQ_COMP"));
287
288	/*
289	 * Before changing the flags on the socket, we have to bump the
290	 * reference count.  Otherwise, if the protocol calls sofree(),
291	 * the socket will be released due to a zero refcount.
292	 * XXX might not need soref() since this is simpler than kern_accept.
293	 */
294	SOCK_LOCK(so);			/* soref() and so_state update */
295	soref(so);			/* file descriptor reference */
296
297	TAILQ_REMOVE(&head->so_comp, so, so_list);
298	head->so_qlen--;
299	so->so_state |= (head->so_state & SS_NBIO);
300	so->so_qstate &= ~SQ_COMP;
301	so->so_head = NULL;
302
303	SOCK_UNLOCK(so);
304	ACCEPT_UNLOCK();
305
306	*sop = so;
307
308	/* connection has been removed from the listen queue */
309	KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0);
310done:
311	return (error);
312}
313
314/*ARGSUSED*/
315static bool_t
316svc_vc_rendezvous_recv(SVCXPRT *xprt, struct rpc_msg *msg,
317    struct sockaddr **addrp, struct mbuf **mp)
318{
319	struct socket *so = NULL;
320	struct sockaddr *sa = NULL;
321	int error;
322
323	/*
324	 * The socket upcall calls xprt_active() which will eventually
325	 * cause the server to call us here. We attempt to accept a
326	 * connection from the socket and turn it into a new
327	 * transport. If the accept fails, we have drained all pending
328	 * connections so we call xprt_inactive().
329	 */
330	sx_xlock(&xprt->xp_lock);
331
332	error = svc_vc_accept(xprt->xp_socket, &so);
333
334	if (error == EWOULDBLOCK) {
335		/*
336		 * We must re-test for new connections after taking
337		 * the lock to protect us in the case where a new
338		 * connection arrives after our call to accept fails
339		 * with EWOULDBLOCK. The pool lock protects us from
340		 * racing the upcall after our TAILQ_EMPTY() call
341		 * returns false.
342		 */
343		ACCEPT_LOCK();
344		mtx_lock(&xprt->xp_pool->sp_lock);
345		if (TAILQ_EMPTY(&xprt->xp_socket->so_comp))
346			xprt_inactive_locked(xprt);
347		mtx_unlock(&xprt->xp_pool->sp_lock);
348		ACCEPT_UNLOCK();
349		sx_xunlock(&xprt->xp_lock);
350		return (FALSE);
351	}
352
353	if (error) {
354		SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
355		soupcall_clear(xprt->xp_socket, SO_RCV);
356		SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
357		xprt_inactive(xprt);
358		sx_xunlock(&xprt->xp_lock);
359		return (FALSE);
360	}
361
362	sx_xunlock(&xprt->xp_lock);
363
364	sa = 0;
365	error = soaccept(so, &sa);
366
367	if (error) {
368		/*
369		 * XXX not sure if I need to call sofree or soclose here.
370		 */
371		if (sa)
372			free(sa, M_SONAME);
373		return (FALSE);
374	}
375
376	/*
377	 * svc_vc_create_conn will call xprt_register - we don't need
378	 * to do anything with the new connection.
379	 */
380	if (!svc_vc_create_conn(xprt->xp_pool, so, sa))
381		soclose(so);
382
383	free(sa, M_SONAME);
384
385	return (FALSE); /* there is never an rpc msg to be processed */
386}
387
388/*ARGSUSED*/
389static enum xprt_stat
390svc_vc_rendezvous_stat(SVCXPRT *xprt)
391{
392
393	return (XPRT_IDLE);
394}
395
396static void
397svc_vc_destroy_common(SVCXPRT *xprt)
398{
399	SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
400	soupcall_clear(xprt->xp_socket, SO_RCV);
401	SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
402
403	sx_destroy(&xprt->xp_lock);
404	if (xprt->xp_socket)
405		(void)soclose(xprt->xp_socket);
406
407	if (xprt->xp_netid)
408		(void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1);
409	svc_xprt_free(xprt);
410}
411
412static void
413svc_vc_rendezvous_destroy(SVCXPRT *xprt)
414{
415
416	svc_vc_destroy_common(xprt);
417}
418
419static void
420svc_vc_destroy(SVCXPRT *xprt)
421{
422	struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1;
423
424	svc_vc_destroy_common(xprt);
425
426	if (cd->mreq)
427		m_freem(cd->mreq);
428	if (cd->mpending)
429		m_freem(cd->mpending);
430	mem_free(cd, sizeof(*cd));
431}
432
433/*ARGSUSED*/
434static bool_t
435svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in)
436{
437	return (FALSE);
438}
439
440static bool_t
441svc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in)
442{
443
444	return (FALSE);
445}
446
447static enum xprt_stat
448svc_vc_stat(SVCXPRT *xprt)
449{
450	struct cf_conn *cd;
451	struct mbuf *m;
452	size_t n;
453
454	cd = (struct cf_conn *)(xprt->xp_p1);
455
456	if (cd->strm_stat == XPRT_DIED)
457		return (XPRT_DIED);
458
459	/*
460	 * Return XPRT_MOREREQS if we have buffered data and we are
461	 * mid-record or if we have enough data for a record
462	 * marker. Since this is only a hint, we read mpending and
463	 * resid outside the lock. We do need to take the lock if we
464	 * have to traverse the mbuf chain.
465	 */
466	if (cd->mpending) {
467		if (cd->resid)
468			return (XPRT_MOREREQS);
469		n = 0;
470		sx_xlock(&xprt->xp_lock);
471		m = cd->mpending;
472		while (m && n < sizeof(uint32_t)) {
473			n += m->m_len;
474			m = m->m_next;
475		}
476		sx_xunlock(&xprt->xp_lock);
477		if (n >= sizeof(uint32_t))
478			return (XPRT_MOREREQS);
479	}
480
481	if (soreadable(xprt->xp_socket))
482		return (XPRT_MOREREQS);
483
484	return (XPRT_IDLE);
485}
486
487static bool_t
488svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg,
489    struct sockaddr **addrp, struct mbuf **mp)
490{
491	struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
492	struct uio uio;
493	struct mbuf *m;
494	XDR xdrs;
495	int error, rcvflag;
496
497	/*
498	 * Serialise access to the socket and our own record parsing
499	 * state.
500	 */
501	sx_xlock(&xprt->xp_lock);
502
503	for (;;) {
504		/*
505		 * If we have an mbuf chain in cd->mpending, try to parse a
506		 * record from it, leaving the result in cd->mreq. If we don't
507		 * have a complete record, leave the partial result in
508		 * cd->mreq and try to read more from the socket.
509		 */
510		if (cd->mpending) {
511			/*
512			 * If cd->resid is non-zero, we have part of the
513			 * record already, otherwise we are expecting a record
514			 * marker.
515			 */
516			if (!cd->resid) {
517				/*
518				 * See if there is enough data buffered to
519				 * make up a record marker. Make sure we can
520				 * handle the case where the record marker is
521				 * split across more than one mbuf.
522				 */
523				size_t n = 0;
524				uint32_t header;
525
526				m = cd->mpending;
527				while (n < sizeof(uint32_t) && m) {
528					n += m->m_len;
529					m = m->m_next;
530				}
531				if (n < sizeof(uint32_t))
532					goto readmore;
533				if (cd->mpending->m_len < sizeof(uint32_t))
534					cd->mpending = m_pullup(cd->mpending,
535					    sizeof(uint32_t));
536				memcpy(&header, mtod(cd->mpending, uint32_t *),
537				    sizeof(header));
538				header = ntohl(header);
539				cd->eor = (header & 0x80000000) != 0;
540				cd->resid = header & 0x7fffffff;
541				m_adj(cd->mpending, sizeof(uint32_t));
542			}
543
544			/*
545			 * Start pulling off mbufs from cd->mpending
546			 * until we either have a complete record or
547			 * we run out of data. We use m_split to pull
548			 * data - it will pull as much as possible and
549			 * split the last mbuf if necessary.
550			 */
551			while (cd->mpending && cd->resid) {
552				m = cd->mpending;
553				if (cd->mpending->m_next
554				    || cd->mpending->m_len > cd->resid)
555					cd->mpending = m_split(cd->mpending,
556					    cd->resid, M_WAIT);
557				else
558					cd->mpending = NULL;
559				if (cd->mreq)
560					m_last(cd->mreq)->m_next = m;
561				else
562					cd->mreq = m;
563				while (m) {
564					cd->resid -= m->m_len;
565					m = m->m_next;
566				}
567			}
568
569			/*
570			 * If cd->resid is zero now, we have managed to
571			 * receive a record fragment from the stream. Check
572			 * for the end-of-record mark to see if we need more.
573			 */
574			if (cd->resid == 0) {
575				if (!cd->eor)
576					continue;
577
578				/*
579				 * Success - we have a complete record in
580				 * cd->mreq.
581				 */
582				xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE);
583				cd->mreq = NULL;
584				sx_xunlock(&xprt->xp_lock);
585
586				if (! xdr_callmsg(&xdrs, msg)) {
587					XDR_DESTROY(&xdrs);
588					return (FALSE);
589				}
590
591				*addrp = NULL;
592				*mp = xdrmbuf_getall(&xdrs);
593				XDR_DESTROY(&xdrs);
594
595				return (TRUE);
596			}
597		}
598
599	readmore:
600		/*
601		 * The socket upcall calls xprt_active() which will eventually
602		 * cause the server to call us here. We attempt to
603		 * read as much as possible from the socket and put
604		 * the result in cd->mpending. If the read fails,
605		 * we have drained both cd->mpending and the socket so
606		 * we can call xprt_inactive().
607		 */
608		uio.uio_resid = 1000000000;
609		uio.uio_td = curthread;
610		m = NULL;
611		rcvflag = MSG_DONTWAIT;
612		error = soreceive(xprt->xp_socket, NULL, &uio, &m, NULL,
613		    &rcvflag);
614
615		if (error == EWOULDBLOCK) {
616			/*
617			 * We must re-test for readability after
618			 * taking the lock to protect us in the case
619			 * where a new packet arrives on the socket
620			 * after our call to soreceive fails with
621			 * EWOULDBLOCK. The pool lock protects us from
622			 * racing the upcall after our soreadable()
623			 * call returns false.
624			 */
625			mtx_lock(&xprt->xp_pool->sp_lock);
626			if (!soreadable(xprt->xp_socket))
627				xprt_inactive_locked(xprt);
628			mtx_unlock(&xprt->xp_pool->sp_lock);
629			sx_xunlock(&xprt->xp_lock);
630			return (FALSE);
631		}
632
633		if (error) {
634			SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
635			soupcall_clear(xprt->xp_socket, SO_RCV);
636			SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
637			xprt_inactive(xprt);
638			cd->strm_stat = XPRT_DIED;
639			sx_xunlock(&xprt->xp_lock);
640			return (FALSE);
641		}
642
643		if (!m) {
644			/*
645			 * EOF - the other end has closed the socket.
646			 */
647			xprt_inactive(xprt);
648			cd->strm_stat = XPRT_DIED;
649			sx_xunlock(&xprt->xp_lock);
650			return (FALSE);
651		}
652
653		if (cd->mpending)
654			m_last(cd->mpending)->m_next = m;
655		else
656			cd->mpending = m;
657	}
658}
659
660static bool_t
661svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg,
662    struct sockaddr *addr, struct mbuf *m)
663{
664	XDR xdrs;
665	struct mbuf *mrep;
666	bool_t stat = TRUE;
667	int error;
668
669	/*
670	 * Leave space for record mark.
671	 */
672	MGETHDR(mrep, M_WAIT, MT_DATA);
673	mrep->m_len = 0;
674	mrep->m_data += sizeof(uint32_t);
675
676	xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);
677
678	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
679	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
680		if (!xdr_replymsg(&xdrs, msg))
681			stat = FALSE;
682		else
683			xdrmbuf_append(&xdrs, m);
684	} else {
685		stat = xdr_replymsg(&xdrs, msg);
686	}
687
688	if (stat) {
689		m_fixhdr(mrep);
690
691		/*
692		 * Prepend a record marker containing the reply length.
693		 */
694		M_PREPEND(mrep, sizeof(uint32_t), M_WAIT);
695		*mtod(mrep, uint32_t *) =
696			htonl(0x80000000 | (mrep->m_pkthdr.len
697				- sizeof(uint32_t)));
698		error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL,
699		    0, curthread);
700		if (!error) {
701			stat = TRUE;
702		}
703	} else {
704		m_freem(mrep);
705	}
706
707	XDR_DESTROY(&xdrs);
708	xprt->xp_p2 = NULL;
709
710	return (stat);
711}
712
713static bool_t
714svc_vc_null()
715{
716
717	return (FALSE);
718}
719
720static int
721svc_vc_soupcall(struct socket *so, void *arg, int waitflag)
722{
723	SVCXPRT *xprt = (SVCXPRT *) arg;
724
725	xprt_active(xprt);
726	return (SU_OK);
727}
728
729#if 0
730/*
731 * Get the effective UID of the sending process. Used by rpcbind, keyserv
732 * and rpc.yppasswdd on AF_LOCAL.
733 */
734int
735__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) {
736	int sock, ret;
737	gid_t egid;
738	uid_t euid;
739	struct sockaddr *sa;
740
741	sock = transp->xp_fd;
742	sa = (struct sockaddr *)transp->xp_rtaddr;
743	if (sa->sa_family == AF_LOCAL) {
744		ret = getpeereid(sock, &euid, &egid);
745		if (ret == 0)
746			*uid = euid;
747		return (ret);
748	} else
749		return (-1);
750}
751#endif
752