svc_vc.c revision 90316
174462Salfred/*	$NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $	*/
274462Salfred/*	$FreeBSD: head/lib/libc/rpc/svc_vc.c 90316 2002-02-06 19:14:02Z alfred $ */
374462Salfred
474462Salfred/*
574462Salfred * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
674462Salfred * unrestricted use provided that this legend is included on all tape
774462Salfred * media and as a part of the software program in whole or part.  Users
874462Salfred * may copy or modify Sun RPC without charge, but are not authorized
974462Salfred * to license or distribute it to anyone else except as part of a product or
1074462Salfred * program developed by the user.
1174462Salfred *
1274462Salfred * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
1374462Salfred * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
1474462Salfred * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
1574462Salfred *
1674462Salfred * Sun RPC is provided with no support and without any obligation on the
1774462Salfred * part of Sun Microsystems, Inc. to assist in its use, correction,
1874462Salfred * modification or enhancement.
1974462Salfred *
2074462Salfred * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
2174462Salfred * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
2274462Salfred * OR ANY PART THEREOF.
2374462Salfred *
2474462Salfred * In no event will Sun Microsystems, Inc. be liable for any lost revenue
2574462Salfred * or profits or other special, indirect and consequential damages, even if
2674462Salfred * Sun has been advised of the possibility of such damages.
2774462Salfred *
2874462Salfred * Sun Microsystems, Inc.
2974462Salfred * 2550 Garcia Avenue
3074462Salfred * Mountain View, California  94043
3174462Salfred */
3274462Salfred
3374462Salfred#include <sys/cdefs.h>
3474462Salfred#if defined(LIBC_SCCS) && !defined(lint)
3574462Salfredstatic char *sccsid = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
3674462Salfredstatic char *sccsid = "@(#)svc_tcp.c	2.2 88/08/01 4.0 RPCSRC";
3774462Salfred#endif
3874462Salfred
3974462Salfred/*
4074462Salfred * svc_vc.c, Server side for Connection Oriented based RPC.
4174462Salfred *
4274462Salfred * Actually implements two flavors of transporter -
4374462Salfred * a tcp rendezvouser (a listner and connection establisher)
4474462Salfred * and a record/tcp stream.
4574462Salfred */
4674462Salfred
4775094Siedowse#include "namespace.h"
4874462Salfred#include "reentrant.h"
4974462Salfred#include <sys/types.h>
5074462Salfred#include <sys/param.h>
5174462Salfred#include <sys/poll.h>
5274462Salfred#include <sys/socket.h>
5374462Salfred#include <sys/un.h>
5474462Salfred#include <sys/uio.h>
5574462Salfred#include <netinet/in.h>
5674462Salfred#include <netinet/tcp.h>
5774462Salfred
5874462Salfred#include <assert.h>
5974462Salfred#include <err.h>
6074462Salfred#include <errno.h>
6174462Salfred#include <stdio.h>
6274462Salfred#include <stdlib.h>
6374462Salfred#include <string.h>
6474462Salfred#include <unistd.h>
6574462Salfred
6674462Salfred#include <rpc/rpc.h>
6774462Salfred
6874462Salfred#include "rpc_com.h"
6974462Salfred#include "un-namespace.h"
7074462Salfred
7174660Salfredstruct cmessage {
7274660Salfred        struct cmsghdr cmsg;
7374660Salfred        struct cmsgcred cmcred;
7474660Salfred};
7574462Salfred
7674462Salfredstatic SVCXPRT *makefd_xprt __P((int, u_int, u_int));
7774462Salfredstatic bool_t rendezvous_request __P((SVCXPRT *, struct rpc_msg *));
7874462Salfredstatic enum xprt_stat rendezvous_stat __P((SVCXPRT *));
7974462Salfredstatic void svc_vc_destroy __P((SVCXPRT *));
8074462Salfredstatic int read_vc __P((caddr_t, caddr_t, int));
8174462Salfredstatic int write_vc __P((caddr_t, caddr_t, int));
8274462Salfredstatic enum xprt_stat svc_vc_stat __P((SVCXPRT *));
8374462Salfredstatic bool_t svc_vc_recv __P((SVCXPRT *, struct rpc_msg *));
8474462Salfredstatic bool_t svc_vc_getargs __P((SVCXPRT *, xdrproc_t, caddr_t));
8574462Salfredstatic bool_t svc_vc_freeargs __P((SVCXPRT *, xdrproc_t, caddr_t));
8674462Salfredstatic bool_t svc_vc_reply __P((SVCXPRT *, struct rpc_msg *));
8774462Salfredstatic void svc_vc_rendezvous_ops __P((SVCXPRT *));
8874462Salfredstatic void svc_vc_ops __P((SVCXPRT *));
8974462Salfredstatic bool_t svc_vc_control __P((SVCXPRT *xprt, const u_int rq, void *in));
9074627Salfredstatic int __msgread_withcred(int, void *, size_t, struct cmessage *);
9174462Salfredstatic int __msgwrite(int, void *, size_t);
9274462Salfred
9374462Salfredstruct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */
9474462Salfred	u_int sendsize;
9574462Salfred	u_int recvsize;
9674462Salfred};
9774462Salfred
9874462Salfredstruct cf_conn {  /* kept in xprt->xp_p1 for actual connection */
9974462Salfred	enum xprt_stat strm_stat;
10074462Salfred	u_int32_t x_id;
10174462Salfred	XDR xdrs;
10274462Salfred	char verf_body[MAX_AUTH_BYTES];
10374462Salfred};
10474462Salfred
10574462Salfred/*
10674462Salfred * Usage:
10774462Salfred *	xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
10874462Salfred *
10974462Salfred * Creates, registers, and returns a (rpc) tcp based transporter.
11074462Salfred * Once *xprt is initialized, it is registered as a transporter
11174462Salfred * see (svc.h, xprt_register).  This routine returns
11274462Salfred * a NULL if a problem occurred.
11374462Salfred *
11474462Salfred * The filedescriptor passed in is expected to refer to a bound, but
11574462Salfred * not yet connected socket.
11674462Salfred *
11774462Salfred * Since streams do buffered io similar to stdio, the caller can specify
11874462Salfred * how big the send and receive buffers are via the second and third parms;
11974462Salfred * 0 => use the system default.
12074462Salfred */
12174462SalfredSVCXPRT *
12274462Salfredsvc_vc_create(fd, sendsize, recvsize)
12374462Salfred	int fd;
12474462Salfred	u_int sendsize;
12574462Salfred	u_int recvsize;
12674462Salfred{
12774462Salfred	SVCXPRT *xprt;
12874462Salfred	struct cf_rendezvous *r = NULL;
12974462Salfred	struct __rpc_sockinfo si;
13074462Salfred	struct sockaddr_storage sslocal;
13174462Salfred	socklen_t slen;
13274462Salfred
13374462Salfred	r = mem_alloc(sizeof(*r));
13474462Salfred	if (r == NULL) {
13574462Salfred		warnx("svc_vc_create: out of memory");
13674462Salfred		goto cleanup_svc_vc_create;
13774462Salfred	}
13874462Salfred	if (!__rpc_fd2sockinfo(fd, &si))
13974462Salfred		return NULL;
14074462Salfred	r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize);
14174462Salfred	r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize);
14274462Salfred	xprt = mem_alloc(sizeof(SVCXPRT));
14374462Salfred	if (xprt == NULL) {
14474462Salfred		warnx("svc_vc_create: out of memory");
14574462Salfred		goto cleanup_svc_vc_create;
14674462Salfred	}
14774462Salfred	xprt->xp_tp = NULL;
14874462Salfred	xprt->xp_p1 = (caddr_t)(void *)r;
14974462Salfred	xprt->xp_p2 = NULL;
15074462Salfred	xprt->xp_p3 = NULL;
15174462Salfred	xprt->xp_verf = _null_auth;
15274462Salfred	svc_vc_rendezvous_ops(xprt);
15374462Salfred	xprt->xp_port = (u_short)-1;	/* It is the rendezvouser */
15474462Salfred	xprt->xp_fd = fd;
15574462Salfred
15674462Salfred	slen = sizeof (struct sockaddr_storage);
15774462Salfred	if (_getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) {
15874462Salfred		warnx("svc_vc_create: could not retrieve local addr");
15974462Salfred		goto cleanup_svc_vc_create;
16074462Salfred	}
16174462Salfred
16274462Salfred	xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len;
16374462Salfred	xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len);
16474462Salfred	if (xprt->xp_ltaddr.buf == NULL) {
16574462Salfred		warnx("svc_vc_create: no mem for local addr");
16674462Salfred		goto cleanup_svc_vc_create;
16774462Salfred	}
16874462Salfred	memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len);
16974462Salfred
17074462Salfred	xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage);
17174462Salfred	xprt_register(xprt);
17274462Salfred	return (xprt);
17374462Salfredcleanup_svc_vc_create:
17474462Salfred	if (r != NULL)
17574462Salfred		mem_free(r, sizeof(*r));
17674462Salfred	return (NULL);
17774462Salfred}
17874462Salfred
17974462Salfred/*
18074462Salfred * Like svtcp_create(), except the routine takes any *open* UNIX file
18174462Salfred * descriptor as its first input.
18274462Salfred */
18374462SalfredSVCXPRT *
18474462Salfredsvc_fd_create(fd, sendsize, recvsize)
18574462Salfred	int fd;
18674462Salfred	u_int sendsize;
18774462Salfred	u_int recvsize;
18874462Salfred{
18974462Salfred	struct sockaddr_storage ss;
19074462Salfred	socklen_t slen;
19174462Salfred	SVCXPRT *ret;
19274462Salfred
19374462Salfred	assert(fd != -1);
19474462Salfred
19574462Salfred	ret = makefd_xprt(fd, sendsize, recvsize);
19674462Salfred	if (ret == NULL)
19774462Salfred		return NULL;
19874462Salfred
19974462Salfred	slen = sizeof (struct sockaddr_storage);
20074462Salfred	if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
20174462Salfred		warnx("svc_fd_create: could not retrieve local addr");
20274462Salfred		goto freedata;
20374462Salfred	}
20474462Salfred	ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len;
20574462Salfred	ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len);
20674462Salfred	if (ret->xp_ltaddr.buf == NULL) {
20774462Salfred		warnx("svc_fd_create: no mem for local addr");
20874462Salfred		goto freedata;
20974462Salfred	}
21074462Salfred	memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len);
21174462Salfred
21274462Salfred	slen = sizeof (struct sockaddr_storage);
21374462Salfred	if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
21474462Salfred		warnx("svc_fd_create: could not retrieve remote addr");
21574462Salfred		goto freedata;
21674462Salfred	}
21774462Salfred	ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len;
21874462Salfred	ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len);
21974462Salfred	if (ret->xp_rtaddr.buf == NULL) {
22074462Salfred		warnx("svc_fd_create: no mem for local addr");
22174462Salfred		goto freedata;
22274462Salfred	}
22374462Salfred	memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len);
22474462Salfred#ifdef PORTMAP
22590272Salfred	if (ss.ss_family == AF_INET || ss.ss_family == AF_LOCAL) {
22674462Salfred		ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf;
22774462Salfred		ret->xp_addrlen = sizeof (struct sockaddr_in);
22874462Salfred	}
22974462Salfred#endif				/* PORTMAP */
23074462Salfred
23174462Salfred	return ret;
23274462Salfred
23374462Salfredfreedata:
23474462Salfred	if (ret->xp_ltaddr.buf != NULL)
23574462Salfred		mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen);
23674462Salfred
23774462Salfred	return NULL;
23874462Salfred}
23974462Salfred
24074462Salfredstatic SVCXPRT *
24174462Salfredmakefd_xprt(fd, sendsize, recvsize)
24274462Salfred	int fd;
24374462Salfred	u_int sendsize;
24474462Salfred	u_int recvsize;
24574462Salfred{
24674462Salfred	SVCXPRT *xprt;
24774462Salfred	struct cf_conn *cd;
24874462Salfred	const char *netid;
24974462Salfred	struct __rpc_sockinfo si;
25074462Salfred
25174462Salfred	assert(fd != -1);
25274462Salfred
25374462Salfred	xprt = mem_alloc(sizeof(SVCXPRT));
25474462Salfred	if (xprt == NULL) {
25574462Salfred		warnx("svc_vc: makefd_xprt: out of memory");
25674462Salfred		goto done;
25774462Salfred	}
25874462Salfred	memset(xprt, 0, sizeof *xprt);
25974462Salfred	cd = mem_alloc(sizeof(struct cf_conn));
26074462Salfred	if (cd == NULL) {
26174462Salfred		warnx("svc_tcp: makefd_xprt: out of memory");
26274462Salfred		mem_free(xprt, sizeof(SVCXPRT));
26374462Salfred		xprt = NULL;
26474462Salfred		goto done;
26574462Salfred	}
26674462Salfred	cd->strm_stat = XPRT_IDLE;
26774462Salfred	xdrrec_create(&(cd->xdrs), sendsize, recvsize,
26874462Salfred	    (caddr_t)(void *)xprt, read_vc, write_vc);
26974462Salfred	xprt->xp_p1 = (caddr_t)(void *)cd;
27074462Salfred	xprt->xp_verf.oa_base = cd->verf_body;
27174462Salfred	svc_vc_ops(xprt);  /* truely deals with calls */
27274462Salfred	xprt->xp_port = 0;  /* this is a connection, not a rendezvouser */
27374462Salfred	xprt->xp_fd = fd;
27474462Salfred        if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid))
27574462Salfred		xprt->xp_netid = strdup(netid);
27674462Salfred
27774462Salfred	xprt_register(xprt);
27874462Salfreddone:
27974462Salfred	return (xprt);
28074462Salfred}
28174462Salfred
28274462Salfred/*ARGSUSED*/
28374462Salfredstatic bool_t
28474462Salfredrendezvous_request(xprt, msg)
28574462Salfred	SVCXPRT *xprt;
28674462Salfred	struct rpc_msg *msg;
28774462Salfred{
28874462Salfred	int sock;
28974462Salfred	struct cf_rendezvous *r;
29074462Salfred	struct sockaddr_storage addr;
29174462Salfred	socklen_t len;
29274462Salfred	struct __rpc_sockinfo si;
29374462Salfred
29474462Salfred	assert(xprt != NULL);
29574462Salfred	assert(msg != NULL);
29674462Salfred
29774462Salfred	r = (struct cf_rendezvous *)xprt->xp_p1;
29874462Salfredagain:
29974462Salfred	len = sizeof addr;
30074462Salfred	if ((sock = _accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr,
30174462Salfred	    &len)) < 0) {
30274462Salfred		if (errno == EINTR)
30374462Salfred			goto again;
30474462Salfred	       return (FALSE);
30574462Salfred	}
30674462Salfred	/*
30774462Salfred	 * make a new transporter (re-uses xprt)
30874462Salfred	 */
30974462Salfred	xprt = makefd_xprt(sock, r->sendsize, r->recvsize);
31074462Salfred	xprt->xp_rtaddr.buf = mem_alloc(len);
31174462Salfred	if (xprt->xp_rtaddr.buf == NULL)
31274462Salfred		return (FALSE);
31374462Salfred	memcpy(xprt->xp_rtaddr.buf, &addr, len);
31474462Salfred	xprt->xp_rtaddr.len = len;
31574462Salfred#ifdef PORTMAP
31690316Salfred	if (addr.ss_family == AF_INET || addr.ss_family == AF_LOCAL) {
31774462Salfred		xprt->xp_raddr = *(struct sockaddr_in *)xprt->xp_rtaddr.buf;
31874462Salfred		xprt->xp_addrlen = sizeof (struct sockaddr_in);
31974462Salfred	}
32074462Salfred#endif				/* PORTMAP */
32174462Salfred	if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) {
32274462Salfred		len = 1;
32374462Salfred		/* XXX fvdl - is this useful? */
32474462Salfred		_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &len, sizeof (len));
32574462Salfred	}
32674462Salfred	return (FALSE); /* there is never an rpc msg to be processed */
32774462Salfred}
32874462Salfred
32974462Salfred/*ARGSUSED*/
33074462Salfredstatic enum xprt_stat
33174462Salfredrendezvous_stat(xprt)
33274462Salfred	SVCXPRT *xprt;
33374462Salfred{
33474462Salfred
33574462Salfred	return (XPRT_IDLE);
33674462Salfred}
33774462Salfred
33874462Salfredstatic void
33974462Salfredsvc_vc_destroy(xprt)
34074462Salfred	SVCXPRT *xprt;
34174462Salfred{
34274462Salfred	struct cf_conn *cd;
34374462Salfred	struct cf_rendezvous *r;
34474462Salfred
34574462Salfred	assert(xprt != NULL);
34674462Salfred
34774462Salfred	cd = (struct cf_conn *)xprt->xp_p1;
34874462Salfred
34974462Salfred	xprt_unregister(xprt);
35074462Salfred	if (xprt->xp_fd != RPC_ANYFD)
35174462Salfred		(void)_close(xprt->xp_fd);
35274462Salfred	if (xprt->xp_port != 0) {
35374462Salfred		/* a rendezvouser socket */
35474462Salfred		r = (struct cf_rendezvous *)xprt->xp_p1;
35574462Salfred		mem_free(r, sizeof (struct cf_rendezvous));
35674462Salfred		xprt->xp_port = 0;
35774462Salfred	} else {
35874462Salfred		/* an actual connection socket */
35974462Salfred		XDR_DESTROY(&(cd->xdrs));
36074462Salfred		mem_free(cd, sizeof(struct cf_conn));
36174462Salfred	}
36274462Salfred	if (xprt->xp_rtaddr.buf)
36374462Salfred		mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen);
36474462Salfred	if (xprt->xp_ltaddr.buf)
36574462Salfred		mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen);
36674462Salfred	if (xprt->xp_tp)
36774462Salfred		free(xprt->xp_tp);
36874462Salfred	if (xprt->xp_netid)
36974462Salfred		free(xprt->xp_netid);
37074462Salfred	mem_free(xprt, sizeof(SVCXPRT));
37174462Salfred}
37274462Salfred
37374462Salfred/*ARGSUSED*/
37474462Salfredstatic bool_t
37574462Salfredsvc_vc_control(xprt, rq, in)
37674462Salfred	SVCXPRT *xprt;
37774462Salfred	const u_int rq;
37874462Salfred	void *in;
37974462Salfred{
38074462Salfred	return (FALSE);
38174462Salfred}
38274462Salfred
38374462Salfred/*
38474462Salfred * reads data from the tcp or uip connection.
38574462Salfred * any error is fatal and the connection is closed.
38674462Salfred * (And a read of zero bytes is a half closed stream => error.)
38774462Salfred * All read operations timeout after 35 seconds.  A timeout is
38874462Salfred * fatal for the connection.
38974462Salfred */
39074462Salfredstatic int
39174462Salfredread_vc(xprtp, buf, len)
39274462Salfred	caddr_t xprtp;
39374462Salfred	caddr_t buf;
39474462Salfred	int len;
39574462Salfred{
39674462Salfred	SVCXPRT *xprt;
39774462Salfred	int sock;
39874462Salfred	int milliseconds = 35 * 1000;
39974462Salfred	struct pollfd pollfd;
40074462Salfred	struct sockaddr *sa;
40174462Salfred	struct cmessage *cm;
40274462Salfred
40374462Salfred	xprt = (SVCXPRT *)(void *)xprtp;
40474462Salfred	assert(xprt != NULL);
40574462Salfred
40674462Salfred	sock = xprt->xp_fd;
40774462Salfred
40874536Salfred	do {
40974536Salfred		pollfd.fd = sock;
41074536Salfred		pollfd.events = POLLIN;
41174462Salfred		pollfd.revents = 0;
41274536Salfred		switch (_poll(&pollfd, 1, milliseconds)) {
41374536Salfred		case -1:
41474536Salfred			if (errno == EINTR)
41574536Salfred				continue;
41674536Salfred			/*FALLTHROUGH*/
41774627Salfred		case 0:
41874627Salfred			goto fatal_err;
41974627Salfred
42074627Salfred		default:
42174627Salfred			break;
42274536Salfred		}
42374536Salfred	} while ((pollfd.revents & POLLIN) == 0);
42474462Salfred
42590257Salfred	cm = NULL;
42674462Salfred	sa = (struct sockaddr *)xprt->xp_rtaddr.buf;
42774462Salfred	if (sa->sa_family == AF_LOCAL) {
42874627Salfred		cm = (struct cmessage *)xprt->xp_verf.oa_base;
42974627Salfred		if ((len = __msgread_withcred(sock, buf, len, cm)) > 0) {
43084472Sdwmalone			xprt->xp_p2 = &cm->cmcred;
43174462Salfred			return (len);
43290257Salfred		} else
43390257Salfred			goto fatal_err;
43474462Salfred	} else {
43574462Salfred		if ((len = _read(sock, buf, (size_t)len)) > 0)
43674462Salfred			return (len);
43774462Salfred	}
43874462Salfred
43974462Salfredfatal_err:
44074462Salfred	((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
44174462Salfred	return (-1);
44274462Salfred}
44374462Salfred
44474462Salfred/*
44574462Salfred * writes data to the tcp connection.
44674462Salfred * Any error is fatal and the connection is closed.
44774462Salfred */
44874462Salfredstatic int
44974462Salfredwrite_vc(xprtp, buf, len)
45074462Salfred	caddr_t xprtp;
45174462Salfred	caddr_t buf;
45274462Salfred	int len;
45374462Salfred{
45474462Salfred	SVCXPRT *xprt;
45574462Salfred	int i, cnt;
45674462Salfred	struct sockaddr *sa;
45774462Salfred
45874462Salfred	xprt = (SVCXPRT *)(void *)xprtp;
45974462Salfred	assert(xprt != NULL);
46074462Salfred
46174462Salfred	sa = (struct sockaddr *)xprt->xp_rtaddr.buf;
46274462Salfred        if (sa->sa_family == AF_LOCAL) {
46374462Salfred		for (cnt = len; cnt > 0; cnt -= i, buf += i) {
46474462Salfred			if ((i = __msgwrite(xprt->xp_fd, buf,
46574462Salfred			    (size_t)cnt)) < 0) {
46674462Salfred				((struct cf_conn *)(xprt->xp_p1))->strm_stat =
46774462Salfred				    XPRT_DIED;
46874462Salfred				return (-1);
46974462Salfred			}
47074462Salfred		}
47174462Salfred	} else {
47274462Salfred		for (cnt = len; cnt > 0; cnt -= i, buf += i) {
47374462Salfred			if ((i = _write(xprt->xp_fd, buf,
47474462Salfred			    (size_t)cnt)) < 0) {
47574462Salfred				((struct cf_conn *)(xprt->xp_p1))->strm_stat =
47674462Salfred				    XPRT_DIED;
47774462Salfred				return (-1);
47874462Salfred			}
47974462Salfred		}
48074462Salfred	}
48174462Salfred
48274462Salfred	return (len);
48374462Salfred}
48474462Salfred
48574462Salfredstatic enum xprt_stat
48674462Salfredsvc_vc_stat(xprt)
48774462Salfred	SVCXPRT *xprt;
48874462Salfred{
48974462Salfred	struct cf_conn *cd;
49074462Salfred
49174462Salfred	assert(xprt != NULL);
49274462Salfred
49374462Salfred	cd = (struct cf_conn *)(xprt->xp_p1);
49474462Salfred
49574462Salfred	if (cd->strm_stat == XPRT_DIED)
49674462Salfred		return (XPRT_DIED);
49774462Salfred	if (! xdrrec_eof(&(cd->xdrs)))
49874462Salfred		return (XPRT_MOREREQS);
49974462Salfred	return (XPRT_IDLE);
50074462Salfred}
50174462Salfred
50274462Salfredstatic bool_t
50374462Salfredsvc_vc_recv(xprt, msg)
50474462Salfred	SVCXPRT *xprt;
50574462Salfred	struct rpc_msg *msg;
50674462Salfred{
50774462Salfred	struct cf_conn *cd;
50874462Salfred	XDR *xdrs;
50974462Salfred
51074462Salfred	assert(xprt != NULL);
51174462Salfred	assert(msg != NULL);
51274462Salfred
51374462Salfred	cd = (struct cf_conn *)(xprt->xp_p1);
51474462Salfred	xdrs = &(cd->xdrs);
51574462Salfred
51674462Salfred	xdrs->x_op = XDR_DECODE;
51774462Salfred	(void)xdrrec_skiprecord(xdrs);
51874462Salfred	if (xdr_callmsg(xdrs, msg)) {
51974462Salfred		cd->x_id = msg->rm_xid;
52074462Salfred		return (TRUE);
52174462Salfred	}
52274462Salfred	cd->strm_stat = XPRT_DIED;
52374462Salfred	return (FALSE);
52474462Salfred}
52574462Salfred
52674462Salfredstatic bool_t
52774462Salfredsvc_vc_getargs(xprt, xdr_args, args_ptr)
52874462Salfred	SVCXPRT *xprt;
52974462Salfred	xdrproc_t xdr_args;
53074462Salfred	caddr_t args_ptr;
53174462Salfred{
53274462Salfred
53374462Salfred	assert(xprt != NULL);
53474462Salfred	/* args_ptr may be NULL */
53574462Salfred	return ((*xdr_args)(&(((struct cf_conn *)(xprt->xp_p1))->xdrs),
53674462Salfred	    args_ptr));
53774462Salfred}
53874462Salfred
53974462Salfredstatic bool_t
54074462Salfredsvc_vc_freeargs(xprt, xdr_args, args_ptr)
54174462Salfred	SVCXPRT *xprt;
54274462Salfred	xdrproc_t xdr_args;
54374462Salfred	caddr_t args_ptr;
54474462Salfred{
54574462Salfred	XDR *xdrs;
54674462Salfred
54774462Salfred	assert(xprt != NULL);
54874462Salfred	/* args_ptr may be NULL */
54974462Salfred
55074462Salfred	xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs);
55174462Salfred
55274462Salfred	xdrs->x_op = XDR_FREE;
55374462Salfred	return ((*xdr_args)(xdrs, args_ptr));
55474462Salfred}
55574462Salfred
55674462Salfredstatic bool_t
55774462Salfredsvc_vc_reply(xprt, msg)
55874462Salfred	SVCXPRT *xprt;
55974462Salfred	struct rpc_msg *msg;
56074462Salfred{
56174462Salfred	struct cf_conn *cd;
56274462Salfred	XDR *xdrs;
56374462Salfred	bool_t stat;
56474462Salfred
56574462Salfred	assert(xprt != NULL);
56674462Salfred	assert(msg != NULL);
56774462Salfred
56874462Salfred	cd = (struct cf_conn *)(xprt->xp_p1);
56974462Salfred	xdrs = &(cd->xdrs);
57074462Salfred
57174462Salfred	xdrs->x_op = XDR_ENCODE;
57274462Salfred	msg->rm_xid = cd->x_id;
57374462Salfred	stat = xdr_replymsg(xdrs, msg);
57474462Salfred	(void)xdrrec_endofrecord(xdrs, TRUE);
57574462Salfred	return (stat);
57674462Salfred}
57774462Salfred
57874462Salfredstatic void
57974462Salfredsvc_vc_ops(xprt)
58074462Salfred	SVCXPRT *xprt;
58174462Salfred{
58274462Salfred	static struct xp_ops ops;
58374462Salfred	static struct xp_ops2 ops2;
58474462Salfred	extern mutex_t ops_lock;
58574462Salfred
58674462Salfred/* VARIABLES PROTECTED BY ops_lock: ops, ops2 */
58774462Salfred
58874462Salfred	mutex_lock(&ops_lock);
58974462Salfred	if (ops.xp_recv == NULL) {
59074462Salfred		ops.xp_recv = svc_vc_recv;
59174462Salfred		ops.xp_stat = svc_vc_stat;
59274462Salfred		ops.xp_getargs = svc_vc_getargs;
59374462Salfred		ops.xp_reply = svc_vc_reply;
59474462Salfred		ops.xp_freeargs = svc_vc_freeargs;
59574462Salfred		ops.xp_destroy = svc_vc_destroy;
59674462Salfred		ops2.xp_control = svc_vc_control;
59774462Salfred	}
59874462Salfred	xprt->xp_ops = &ops;
59974462Salfred	xprt->xp_ops2 = &ops2;
60074462Salfred	mutex_unlock(&ops_lock);
60174462Salfred}
60274462Salfred
60374462Salfredstatic void
60474462Salfredsvc_vc_rendezvous_ops(xprt)
60574462Salfred	SVCXPRT *xprt;
60674462Salfred{
60774462Salfred	static struct xp_ops ops;
60874462Salfred	static struct xp_ops2 ops2;
60974462Salfred	extern mutex_t ops_lock;
61074462Salfred
61174462Salfred	mutex_lock(&ops_lock);
61274462Salfred	if (ops.xp_recv == NULL) {
61374462Salfred		ops.xp_recv = rendezvous_request;
61474462Salfred		ops.xp_stat = rendezvous_stat;
61574462Salfred		ops.xp_getargs =
61674462Salfred		    (bool_t (*) __P((SVCXPRT *, xdrproc_t, caddr_t)))abort;
61774462Salfred		ops.xp_reply =
61874462Salfred		    (bool_t (*) __P((SVCXPRT *, struct rpc_msg *)))abort;
61974462Salfred		ops.xp_freeargs =
62074462Salfred		    (bool_t (*) __P((SVCXPRT *, xdrproc_t, caddr_t)))abort,
62174462Salfred		ops.xp_destroy = svc_vc_destroy;
62274462Salfred		ops2.xp_control = svc_vc_control;
62374462Salfred	}
62474462Salfred	xprt->xp_ops = &ops;
62574462Salfred	xprt->xp_ops2 = &ops2;
62674462Salfred	mutex_unlock(&ops_lock);
62774462Salfred}
62874462Salfred
62974627Salfredint
63074627Salfred__msgread_withcred(sock, buf, cnt, cmp)
63174462Salfred	int sock;
63274462Salfred	void *buf;
63374462Salfred	size_t cnt;
63474627Salfred	struct cmessage *cmp;
63574462Salfred{
63674462Salfred	struct iovec iov[1];
63774462Salfred	struct msghdr msg;
63884472Sdwmalone	union {
63984472Sdwmalone		struct cmsghdr cmsg;
64084472Sdwmalone		char control[CMSG_SPACE(sizeof(struct cmsgcred))];
64184472Sdwmalone	} cm;
64284472Sdwmalone	int ret;
64384472Sdwmalone
64474462Salfred
64584472Sdwmalone	bzero(&cm, sizeof(cm));
64674462Salfred	iov[0].iov_base = buf;
64774462Salfred	iov[0].iov_len = cnt;
64874462Salfred
64974462Salfred	msg.msg_iov = iov;
65074462Salfred	msg.msg_iovlen = 1;
65174462Salfred	msg.msg_name = NULL;
65274462Salfred	msg.msg_namelen = 0;
65384472Sdwmalone	msg.msg_control = &cm;
65484472Sdwmalone	msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
65574462Salfred	msg.msg_flags = 0;
65674462Salfred
65784472Sdwmalone	ret = _recvmsg(sock, &msg, 0);
65884472Sdwmalone	bcopy(&cm.cmsg, &cmp->cmsg, sizeof(cmp->cmsg));
65984472Sdwmalone	bcopy(CMSG_DATA(&cm), &cmp->cmcred, sizeof(cmp->cmcred));
66090257Salfred
66190257Salfred	if (msg.msg_controllen == 0 ||
66290257Salfred	   (msg.msg_flags & MSG_CTRUNC) != 0)
66390257Salfred		return (-1);
66490257Salfred
66590257Salfred	return (ret);
66674462Salfred}
66774627Salfred
66874462Salfredstatic int
66974462Salfred__msgwrite(sock, buf, cnt)
67074462Salfred	int sock;
67174462Salfred	void *buf;
67274462Salfred	size_t cnt;
67374462Salfred{
67474462Salfred	struct iovec iov[1];
67574462Salfred	struct msghdr msg;
67674462Salfred	struct cmessage cm;
67774462Salfred
67874462Salfred	bzero((char *)&cm, sizeof(cm));
67974462Salfred	iov[0].iov_base = buf;
68074462Salfred	iov[0].iov_len = cnt;
68174462Salfred
68274462Salfred	cm.cmsg.cmsg_type = SCM_CREDS;
68374462Salfred	cm.cmsg.cmsg_level = SOL_SOCKET;
68474462Salfred	cm.cmsg.cmsg_len = sizeof(struct cmessage);
68574462Salfred
68674462Salfred	msg.msg_iov = iov;
68774462Salfred	msg.msg_iovlen = 1;
68874462Salfred	msg.msg_name = NULL;
68974462Salfred	msg.msg_namelen = 0;
69074462Salfred	msg.msg_control = (caddr_t)&cm;
69174462Salfred	msg.msg_controllen = sizeof(struct cmessage);
69274462Salfred	msg.msg_flags = 0;
69374462Salfred
69474462Salfred	return(_sendmsg(sock, &msg, 0));
69574462Salfred}
69674627Salfred
69774627Salfred/*
69874627Salfred * Get the effective UID of the sending process. Used by rpcbind and keyserv
69974627Salfred * (AF_LOCAL).
70074627Salfred */
70174627Salfredint
70274627Salfred__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid)
70374627Salfred{
70474627Salfred	struct cmsgcred *cmcred;
70590257Salfred	struct cmessage *cm;
70690257Salfred	struct cmsghdr *cmp;
70790257Salfred
70890257Salfred	cm = (struct cmessage *)transp->xp_verf.oa_base;
70990257Salfred
71090257Salfred	if (cm == NULL)
71190257Salfred		return (-1);
71290257Salfred	cmp = &cm->cmsg;
71390257Salfred	if (cmp == NULL || cmp->cmsg_level != SOL_SOCKET ||
71490257Salfred	   cmp->cmsg_type != SCM_CREDS)
71590257Salfred		return (-1);
71674627Salfred
71774627Salfred	cmcred = __svc_getcallercreds(transp);
71874627Salfred	if (cmcred == NULL)
71990258Salfred		return (-1);
72074627Salfred	*uid = cmcred->cmcred_euid;
72190258Salfred	return (0);
72274627Salfred}
723