174462Salfred/* $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $ */ 274462Salfred 3261057Smav/*- 4261057Smav * Copyright (c) 2009, Sun Microsystems, Inc. 5261057Smav * All rights reserved. 6261057Smav * 7261057Smav * Redistribution and use in source and binary forms, with or without 8261057Smav * modification, are permitted provided that the following conditions are met: 9261057Smav * - Redistributions of source code must retain the above copyright notice, 10261057Smav * this list of conditions and the following disclaimer. 11261057Smav * - Redistributions in binary form must reproduce the above copyright notice, 12261057Smav * this list of conditions and the following disclaimer in the documentation 13261057Smav * and/or other materials provided with the distribution. 14261057Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its 15261057Smav * contributors may be used to endorse or promote products derived 16261057Smav * from this software without specific prior written permission. 1774462Salfred * 18261057Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19261057Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20261057Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21261057Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22261057Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23261057Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24261057Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25261057Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26261057Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27261057Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28261057Smav * POSSIBILITY OF SUCH DAMAGE. 2974462Salfred */ 3074462Salfred 3174462Salfred#if defined(LIBC_SCCS) && !defined(lint) 32136581Sobrienstatic char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; 3374462Salfredstatic char *sccsid = "@(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 3474462Salfred#endif 3592990Sobrien#include <sys/cdefs.h> 3692990Sobrien__FBSDID("$FreeBSD$"); 3774462Salfred 3874462Salfred/* 3974462Salfred * svc_vc.c, Server side for Connection Oriented based RPC. 4074462Salfred * 4174462Salfred * Actually implements two flavors of transporter - 4274462Salfred * a tcp rendezvouser (a listner and connection establisher) 4374462Salfred * and a record/tcp stream. 4474462Salfred */ 4574462Salfred 4675094Siedowse#include "namespace.h" 4774462Salfred#include "reentrant.h" 4874462Salfred#include <sys/types.h> 4974462Salfred#include <sys/param.h> 5074462Salfred#include <sys/poll.h> 5174462Salfred#include <sys/socket.h> 5274462Salfred#include <sys/un.h> 53109359Smbr#include <sys/time.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> 61109359Smbr#include <fcntl.h> 6274462Salfred#include <stdio.h> 6374462Salfred#include <stdlib.h> 6474462Salfred#include <string.h> 6574462Salfred#include <unistd.h> 6674462Salfred 6774462Salfred#include <rpc/rpc.h> 6874462Salfred 6974462Salfred#include "rpc_com.h" 70156090Sdeischen#include "mt_misc.h" 7174462Salfred#include "un-namespace.h" 7274462Salfred 7392905Sobrienstatic SVCXPRT *makefd_xprt(int, u_int, u_int); 7492905Sobrienstatic bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *); 7592905Sobrienstatic enum xprt_stat rendezvous_stat(SVCXPRT *); 7692905Sobrienstatic void svc_vc_destroy(SVCXPRT *); 77109359Smbrstatic void __svc_vc_dodestroy (SVCXPRT *); 7895658Sdesstatic int read_vc(void *, void *, int); 7995658Sdesstatic int write_vc(void *, void *, int); 8092905Sobrienstatic enum xprt_stat svc_vc_stat(SVCXPRT *); 8192905Sobrienstatic bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *); 8295658Sdesstatic bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, void *); 8395658Sdesstatic bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, void *); 8492905Sobrienstatic bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *); 8592905Sobrienstatic void svc_vc_rendezvous_ops(SVCXPRT *); 8692905Sobrienstatic void svc_vc_ops(SVCXPRT *); 8792905Sobrienstatic bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in); 88109359Smbrstatic bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq, 89109359Smbr void *in); 9074462Salfred 9174462Salfredstruct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */ 9274462Salfred u_int sendsize; 9374462Salfred u_int recvsize; 94109359Smbr int maxrec; 9574462Salfred}; 9674462Salfred 9774462Salfredstruct cf_conn { /* kept in xprt->xp_p1 for actual connection */ 9874462Salfred enum xprt_stat strm_stat; 9974462Salfred u_int32_t x_id; 10074462Salfred XDR xdrs; 10174462Salfred char verf_body[MAX_AUTH_BYTES]; 102109359Smbr u_int sendsize; 103109359Smbr u_int recvsize; 104109359Smbr int maxrec; 105109359Smbr bool_t nonblock; 106109359Smbr struct timeval last_recv_time; 10774462Salfred}; 10874462Salfred 10974462Salfred/* 11074462Salfred * Usage: 11174462Salfred * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); 11274462Salfred * 11374462Salfred * Creates, registers, and returns a (rpc) tcp based transporter. 11474462Salfred * Once *xprt is initialized, it is registered as a transporter 11574462Salfred * see (svc.h, xprt_register). This routine returns 11674462Salfred * a NULL if a problem occurred. 11774462Salfred * 11874462Salfred * The filedescriptor passed in is expected to refer to a bound, but 11974462Salfred * not yet connected socket. 12074462Salfred * 12174462Salfred * Since streams do buffered io similar to stdio, the caller can specify 12274462Salfred * how big the send and receive buffers are via the second and third parms; 12374462Salfred * 0 => use the system default. 12474462Salfred */ 12574462SalfredSVCXPRT * 12674462Salfredsvc_vc_create(fd, sendsize, recvsize) 12774462Salfred int fd; 12874462Salfred u_int sendsize; 12974462Salfred u_int recvsize; 13074462Salfred{ 13174462Salfred SVCXPRT *xprt; 13274462Salfred struct cf_rendezvous *r = NULL; 13374462Salfred struct __rpc_sockinfo si; 13474462Salfred struct sockaddr_storage sslocal; 13574462Salfred socklen_t slen; 13674462Salfred 137162196Smbr if (!__rpc_fd2sockinfo(fd, &si)) 138162196Smbr return NULL; 139162196Smbr 14074462Salfred r = mem_alloc(sizeof(*r)); 14174462Salfred if (r == NULL) { 14274462Salfred warnx("svc_vc_create: out of memory"); 14374462Salfred goto cleanup_svc_vc_create; 14474462Salfred } 14574462Salfred r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); 14674462Salfred r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); 147109359Smbr r->maxrec = __svc_maxrec; 148181344Sdfr xprt = svc_xprt_alloc(); 14974462Salfred if (xprt == NULL) { 15074462Salfred warnx("svc_vc_create: out of memory"); 15174462Salfred goto cleanup_svc_vc_create; 15274462Salfred } 15395658Sdes xprt->xp_p1 = r; 15474462Salfred xprt->xp_verf = _null_auth; 15574462Salfred svc_vc_rendezvous_ops(xprt); 15674462Salfred xprt->xp_port = (u_short)-1; /* It is the rendezvouser */ 15774462Salfred xprt->xp_fd = fd; 15874462Salfred 15974462Salfred slen = sizeof (struct sockaddr_storage); 16074462Salfred if (_getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) { 16174462Salfred warnx("svc_vc_create: could not retrieve local addr"); 16274462Salfred goto cleanup_svc_vc_create; 16374462Salfred } 16474462Salfred 16574462Salfred xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len; 16674462Salfred xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len); 16774462Salfred if (xprt->xp_ltaddr.buf == NULL) { 16874462Salfred warnx("svc_vc_create: no mem for local addr"); 16974462Salfred goto cleanup_svc_vc_create; 17074462Salfred } 17174462Salfred memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len); 17274462Salfred 17374462Salfred xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage); 17474462Salfred xprt_register(xprt); 17574462Salfred return (xprt); 17674462Salfredcleanup_svc_vc_create: 177162196Smbr if (xprt) 178162196Smbr mem_free(xprt, sizeof(*xprt)); 17974462Salfred if (r != NULL) 18074462Salfred mem_free(r, sizeof(*r)); 18174462Salfred return (NULL); 18274462Salfred} 18374462Salfred 18474462Salfred/* 18574462Salfred * Like svtcp_create(), except the routine takes any *open* UNIX file 18674462Salfred * descriptor as its first input. 18774462Salfred */ 18874462SalfredSVCXPRT * 18974462Salfredsvc_fd_create(fd, sendsize, recvsize) 19074462Salfred int fd; 19174462Salfred u_int sendsize; 19274462Salfred u_int recvsize; 19374462Salfred{ 19474462Salfred struct sockaddr_storage ss; 19574462Salfred socklen_t slen; 19674462Salfred SVCXPRT *ret; 19774462Salfred 19874462Salfred assert(fd != -1); 19974462Salfred 20074462Salfred ret = makefd_xprt(fd, sendsize, recvsize); 20174462Salfred if (ret == NULL) 20274462Salfred return NULL; 20374462Salfred 20474462Salfred slen = sizeof (struct sockaddr_storage); 20574462Salfred if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { 20674462Salfred warnx("svc_fd_create: could not retrieve local addr"); 20774462Salfred goto freedata; 20874462Salfred } 20974462Salfred ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len; 21074462Salfred ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len); 21174462Salfred if (ret->xp_ltaddr.buf == NULL) { 21274462Salfred warnx("svc_fd_create: no mem for local addr"); 21374462Salfred goto freedata; 21474462Salfred } 21574462Salfred memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len); 21674462Salfred 21774462Salfred slen = sizeof (struct sockaddr_storage); 21874462Salfred if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { 21974462Salfred warnx("svc_fd_create: could not retrieve remote addr"); 22074462Salfred goto freedata; 22174462Salfred } 22274462Salfred ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len; 22374462Salfred ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len); 22474462Salfred if (ret->xp_rtaddr.buf == NULL) { 22574462Salfred warnx("svc_fd_create: no mem for local addr"); 22674462Salfred goto freedata; 22774462Salfred } 22874462Salfred memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len); 22974462Salfred#ifdef PORTMAP 23090272Salfred if (ss.ss_family == AF_INET || ss.ss_family == AF_LOCAL) { 23174462Salfred ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf; 23274462Salfred ret->xp_addrlen = sizeof (struct sockaddr_in); 23374462Salfred } 23474462Salfred#endif /* PORTMAP */ 23574462Salfred 23674462Salfred return ret; 23774462Salfred 23874462Salfredfreedata: 23974462Salfred if (ret->xp_ltaddr.buf != NULL) 24074462Salfred mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen); 24174462Salfred 24274462Salfred return NULL; 24374462Salfred} 24474462Salfred 24574462Salfredstatic SVCXPRT * 24674462Salfredmakefd_xprt(fd, sendsize, recvsize) 24774462Salfred int fd; 24874462Salfred u_int sendsize; 24974462Salfred u_int recvsize; 25074462Salfred{ 25174462Salfred SVCXPRT *xprt; 25274462Salfred struct cf_conn *cd; 25374462Salfred const char *netid; 25474462Salfred struct __rpc_sockinfo si; 25574462Salfred 25674462Salfred assert(fd != -1); 25774462Salfred 258181344Sdfr xprt = svc_xprt_alloc(); 25974462Salfred if (xprt == NULL) { 26074462Salfred warnx("svc_vc: makefd_xprt: out of memory"); 26174462Salfred goto done; 26274462Salfred } 26374462Salfred cd = mem_alloc(sizeof(struct cf_conn)); 26474462Salfred if (cd == NULL) { 26574462Salfred warnx("svc_tcp: makefd_xprt: out of memory"); 266181344Sdfr svc_xprt_free(xprt); 26774462Salfred xprt = NULL; 26874462Salfred goto done; 26974462Salfred } 27074462Salfred cd->strm_stat = XPRT_IDLE; 27174462Salfred xdrrec_create(&(cd->xdrs), sendsize, recvsize, 27295658Sdes xprt, read_vc, write_vc); 27395658Sdes xprt->xp_p1 = cd; 27474462Salfred xprt->xp_verf.oa_base = cd->verf_body; 27574462Salfred svc_vc_ops(xprt); /* truely deals with calls */ 27674462Salfred xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ 27774462Salfred xprt->xp_fd = fd; 27874462Salfred if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid)) 27974462Salfred xprt->xp_netid = strdup(netid); 28074462Salfred 28174462Salfred xprt_register(xprt); 28274462Salfreddone: 28374462Salfred return (xprt); 28474462Salfred} 28574462Salfred 28674462Salfred/*ARGSUSED*/ 28774462Salfredstatic bool_t 28874462Salfredrendezvous_request(xprt, msg) 28974462Salfred SVCXPRT *xprt; 29074462Salfred struct rpc_msg *msg; 29174462Salfred{ 292109359Smbr int sock, flags; 29374462Salfred struct cf_rendezvous *r; 294109359Smbr struct cf_conn *cd; 29574462Salfred struct sockaddr_storage addr; 29674462Salfred socklen_t len; 29774462Salfred struct __rpc_sockinfo si; 298109359Smbr SVCXPRT *newxprt; 299109359Smbr fd_set cleanfds; 30074462Salfred 30174462Salfred assert(xprt != NULL); 30274462Salfred assert(msg != NULL); 30374462Salfred 30474462Salfred r = (struct cf_rendezvous *)xprt->xp_p1; 30574462Salfredagain: 30674462Salfred len = sizeof addr; 30774462Salfred if ((sock = _accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr, 30874462Salfred &len)) < 0) { 30974462Salfred if (errno == EINTR) 31074462Salfred goto again; 311109359Smbr /* 312109359Smbr * Clean out the most idle file descriptor when we're 313109359Smbr * running out. 314109359Smbr */ 315109359Smbr if (errno == EMFILE || errno == ENFILE) { 316109359Smbr cleanfds = svc_fdset; 317109359Smbr __svc_clean_idle(&cleanfds, 0, FALSE); 318109359Smbr goto again; 319109359Smbr } 320109359Smbr return (FALSE); 32174462Salfred } 32274462Salfred /* 32374462Salfred * make a new transporter (re-uses xprt) 32474462Salfred */ 325109359Smbr newxprt = makefd_xprt(sock, r->sendsize, r->recvsize); 326109359Smbr newxprt->xp_rtaddr.buf = mem_alloc(len); 327109359Smbr if (newxprt->xp_rtaddr.buf == NULL) 32874462Salfred return (FALSE); 329109359Smbr memcpy(newxprt->xp_rtaddr.buf, &addr, len); 330109359Smbr newxprt->xp_rtaddr.len = len; 33174462Salfred#ifdef PORTMAP 33290316Salfred if (addr.ss_family == AF_INET || addr.ss_family == AF_LOCAL) { 333109359Smbr newxprt->xp_raddr = *(struct sockaddr_in *)newxprt->xp_rtaddr.buf; 334109359Smbr newxprt->xp_addrlen = sizeof (struct sockaddr_in); 33574462Salfred } 33674462Salfred#endif /* PORTMAP */ 33774462Salfred if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) { 33874462Salfred len = 1; 33974462Salfred /* XXX fvdl - is this useful? */ 34074462Salfred _setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &len, sizeof (len)); 34174462Salfred } 342109359Smbr 343109359Smbr cd = (struct cf_conn *)newxprt->xp_p1; 344109359Smbr 345109359Smbr cd->recvsize = r->recvsize; 346109359Smbr cd->sendsize = r->sendsize; 347109359Smbr cd->maxrec = r->maxrec; 348109359Smbr 349109359Smbr if (cd->maxrec != 0) { 350109904Smbr flags = _fcntl(sock, F_GETFL, 0); 351109359Smbr if (flags == -1) 352109359Smbr return (FALSE); 353109904Smbr if (_fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) 354109359Smbr return (FALSE); 355109359Smbr if (cd->recvsize > cd->maxrec) 356109359Smbr cd->recvsize = cd->maxrec; 357109359Smbr cd->nonblock = TRUE; 358109359Smbr __xdrrec_setnonblock(&cd->xdrs, cd->maxrec); 359109359Smbr } else 360109359Smbr cd->nonblock = FALSE; 361109359Smbr 362109359Smbr gettimeofday(&cd->last_recv_time, NULL); 363109359Smbr 36474462Salfred return (FALSE); /* there is never an rpc msg to be processed */ 36574462Salfred} 36674462Salfred 36774462Salfred/*ARGSUSED*/ 36874462Salfredstatic enum xprt_stat 36974462Salfredrendezvous_stat(xprt) 37074462Salfred SVCXPRT *xprt; 37174462Salfred{ 37274462Salfred 37374462Salfred return (XPRT_IDLE); 37474462Salfred} 37574462Salfred 37674462Salfredstatic void 37774462Salfredsvc_vc_destroy(xprt) 37874462Salfred SVCXPRT *xprt; 37974462Salfred{ 380109359Smbr assert(xprt != NULL); 381109359Smbr 382109359Smbr xprt_unregister(xprt); 383109359Smbr __svc_vc_dodestroy(xprt); 384109359Smbr} 385109359Smbr 386109359Smbrstatic void 387109359Smbr__svc_vc_dodestroy(xprt) 388109359Smbr SVCXPRT *xprt; 389109359Smbr{ 39074462Salfred struct cf_conn *cd; 39174462Salfred struct cf_rendezvous *r; 39274462Salfred 39374462Salfred cd = (struct cf_conn *)xprt->xp_p1; 39474462Salfred 39574462Salfred if (xprt->xp_fd != RPC_ANYFD) 39674462Salfred (void)_close(xprt->xp_fd); 39774462Salfred if (xprt->xp_port != 0) { 39874462Salfred /* a rendezvouser socket */ 39974462Salfred r = (struct cf_rendezvous *)xprt->xp_p1; 40074462Salfred mem_free(r, sizeof (struct cf_rendezvous)); 40174462Salfred xprt->xp_port = 0; 40274462Salfred } else { 40374462Salfred /* an actual connection socket */ 40474462Salfred XDR_DESTROY(&(cd->xdrs)); 40574462Salfred mem_free(cd, sizeof(struct cf_conn)); 40674462Salfred } 40774462Salfred if (xprt->xp_rtaddr.buf) 40874462Salfred mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen); 40974462Salfred if (xprt->xp_ltaddr.buf) 41074462Salfred mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen); 41174462Salfred if (xprt->xp_tp) 41274462Salfred free(xprt->xp_tp); 41374462Salfred if (xprt->xp_netid) 41474462Salfred free(xprt->xp_netid); 415181344Sdfr svc_xprt_free(xprt); 41674462Salfred} 41774462Salfred 41874462Salfred/*ARGSUSED*/ 41974462Salfredstatic bool_t 42074462Salfredsvc_vc_control(xprt, rq, in) 42174462Salfred SVCXPRT *xprt; 42274462Salfred const u_int rq; 42374462Salfred void *in; 42474462Salfred{ 42574462Salfred return (FALSE); 42674462Salfred} 42774462Salfred 428109359Smbrstatic bool_t 429109359Smbrsvc_vc_rendezvous_control(xprt, rq, in) 430109359Smbr SVCXPRT *xprt; 431109359Smbr const u_int rq; 432109359Smbr void *in; 433109359Smbr{ 434109359Smbr struct cf_rendezvous *cfp; 435109359Smbr 436109359Smbr cfp = (struct cf_rendezvous *)xprt->xp_p1; 437109359Smbr if (cfp == NULL) 438109359Smbr return (FALSE); 439109359Smbr switch (rq) { 440109359Smbr case SVCGET_CONNMAXREC: 441109359Smbr *(int *)in = cfp->maxrec; 442109359Smbr break; 443109359Smbr case SVCSET_CONNMAXREC: 444109359Smbr cfp->maxrec = *(int *)in; 445109359Smbr break; 446109359Smbr default: 447109359Smbr return (FALSE); 448109359Smbr } 449109359Smbr return (TRUE); 450109359Smbr} 451109359Smbr 45274462Salfred/* 45374462Salfred * reads data from the tcp or uip connection. 45474462Salfred * any error is fatal and the connection is closed. 45574462Salfred * (And a read of zero bytes is a half closed stream => error.) 45674462Salfred * All read operations timeout after 35 seconds. A timeout is 45774462Salfred * fatal for the connection. 45874462Salfred */ 45974462Salfredstatic int 46074462Salfredread_vc(xprtp, buf, len) 46195658Sdes void *xprtp; 46295658Sdes void *buf; 46374462Salfred int len; 46474462Salfred{ 46574462Salfred SVCXPRT *xprt; 46674462Salfred int sock; 46774462Salfred int milliseconds = 35 * 1000; 46874462Salfred struct pollfd pollfd; 469109359Smbr struct cf_conn *cfp; 47074462Salfred 47195658Sdes xprt = (SVCXPRT *)xprtp; 47274462Salfred assert(xprt != NULL); 47374462Salfred 47474462Salfred sock = xprt->xp_fd; 47574462Salfred 476109359Smbr cfp = (struct cf_conn *)xprt->xp_p1; 477109359Smbr 478109359Smbr if (cfp->nonblock) { 479116391Smbr len = _read(sock, buf, (size_t)len); 480109359Smbr if (len < 0) { 481109359Smbr if (errno == EAGAIN) 482109359Smbr len = 0; 483109359Smbr else 484109359Smbr goto fatal_err; 485109359Smbr } 486109359Smbr if (len != 0) 487109359Smbr gettimeofday(&cfp->last_recv_time, NULL); 488109359Smbr return len; 489109359Smbr } 490109359Smbr 49174536Salfred do { 49274536Salfred pollfd.fd = sock; 49374536Salfred pollfd.events = POLLIN; 49474462Salfred pollfd.revents = 0; 49574536Salfred switch (_poll(&pollfd, 1, milliseconds)) { 49674536Salfred case -1: 49774536Salfred if (errno == EINTR) 49874536Salfred continue; 49974536Salfred /*FALLTHROUGH*/ 50074627Salfred case 0: 50174627Salfred goto fatal_err; 50274627Salfred 50374627Salfred default: 50474627Salfred break; 50574536Salfred } 50674536Salfred } while ((pollfd.revents & POLLIN) == 0); 50774462Salfred 508116391Smbr if ((len = _read(sock, buf, (size_t)len)) > 0) { 509116391Smbr gettimeofday(&cfp->last_recv_time, NULL); 510116391Smbr return (len); 51174462Salfred } 51274462Salfred 51374462Salfredfatal_err: 51474462Salfred ((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; 51574462Salfred return (-1); 51674462Salfred} 51774462Salfred 51874462Salfred/* 51974462Salfred * writes data to the tcp connection. 52074462Salfred * Any error is fatal and the connection is closed. 52174462Salfred */ 52274462Salfredstatic int 52374462Salfredwrite_vc(xprtp, buf, len) 52495658Sdes void *xprtp; 52595658Sdes void *buf; 52674462Salfred int len; 52774462Salfred{ 52874462Salfred SVCXPRT *xprt; 52974462Salfred int i, cnt; 530109359Smbr struct cf_conn *cd; 531109359Smbr struct timeval tv0, tv1; 53274462Salfred 53395658Sdes xprt = (SVCXPRT *)xprtp; 53474462Salfred assert(xprt != NULL); 535109359Smbr 536109359Smbr cd = (struct cf_conn *)xprt->xp_p1; 537109359Smbr 538109359Smbr if (cd->nonblock) 539109359Smbr gettimeofday(&tv0, NULL); 54074462Salfred 541133693Sstefanf for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) { 542116391Smbr i = _write(xprt->xp_fd, buf, (size_t)cnt); 543109359Smbr if (i < 0) { 544109359Smbr if (errno != EAGAIN || !cd->nonblock) { 545109359Smbr cd->strm_stat = XPRT_DIED; 54674462Salfred return (-1); 54774462Salfred } 548220519Srmacklem if (cd->nonblock) { 549109359Smbr /* 550109359Smbr * For non-blocking connections, do not 551109359Smbr * take more than 2 seconds writing the 552109359Smbr * data out. 553109359Smbr * 554109359Smbr * XXX 2 is an arbitrary amount. 555109359Smbr */ 556109359Smbr gettimeofday(&tv1, NULL); 557109359Smbr if (tv1.tv_sec - tv0.tv_sec >= 2) { 558109359Smbr cd->strm_stat = XPRT_DIED; 559109359Smbr return (-1); 560109359Smbr } 56174462Salfred } 562220519Srmacklem i = 0; 56374462Salfred } 56474462Salfred } 56574462Salfred 56674462Salfred return (len); 56774462Salfred} 56874462Salfred 56974462Salfredstatic enum xprt_stat 57074462Salfredsvc_vc_stat(xprt) 57174462Salfred SVCXPRT *xprt; 57274462Salfred{ 57374462Salfred struct cf_conn *cd; 57474462Salfred 57574462Salfred assert(xprt != NULL); 57674462Salfred 57774462Salfred cd = (struct cf_conn *)(xprt->xp_p1); 57874462Salfred 57974462Salfred if (cd->strm_stat == XPRT_DIED) 58074462Salfred return (XPRT_DIED); 58174462Salfred if (! xdrrec_eof(&(cd->xdrs))) 58274462Salfred return (XPRT_MOREREQS); 58374462Salfred return (XPRT_IDLE); 58474462Salfred} 58574462Salfred 58674462Salfredstatic bool_t 58774462Salfredsvc_vc_recv(xprt, msg) 58874462Salfred SVCXPRT *xprt; 58974462Salfred struct rpc_msg *msg; 59074462Salfred{ 59174462Salfred struct cf_conn *cd; 59274462Salfred XDR *xdrs; 59374462Salfred 59474462Salfred assert(xprt != NULL); 59574462Salfred assert(msg != NULL); 59674462Salfred 59774462Salfred cd = (struct cf_conn *)(xprt->xp_p1); 59874462Salfred xdrs = &(cd->xdrs); 59974462Salfred 600109359Smbr if (cd->nonblock) { 601109359Smbr if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE)) 602109359Smbr return FALSE; 603177737Sdfr } else { 604177737Sdfr (void)xdrrec_skiprecord(xdrs); 605109359Smbr } 606109359Smbr 60774462Salfred xdrs->x_op = XDR_DECODE; 60874462Salfred if (xdr_callmsg(xdrs, msg)) { 60974462Salfred cd->x_id = msg->rm_xid; 61074462Salfred return (TRUE); 61174462Salfred } 61274462Salfred cd->strm_stat = XPRT_DIED; 61374462Salfred return (FALSE); 61474462Salfred} 61574462Salfred 61674462Salfredstatic bool_t 61774462Salfredsvc_vc_getargs(xprt, xdr_args, args_ptr) 61874462Salfred SVCXPRT *xprt; 61974462Salfred xdrproc_t xdr_args; 62095658Sdes void *args_ptr; 62174462Salfred{ 622181344Sdfr struct cf_conn *cd; 62374462Salfred 62474462Salfred assert(xprt != NULL); 625181344Sdfr cd = (struct cf_conn *)(xprt->xp_p1); 626181344Sdfr return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt), 627181344Sdfr &cd->xdrs, xdr_args, args_ptr)); 62874462Salfred} 62974462Salfred 63074462Salfredstatic bool_t 63174462Salfredsvc_vc_freeargs(xprt, xdr_args, args_ptr) 63274462Salfred SVCXPRT *xprt; 63374462Salfred xdrproc_t xdr_args; 63495658Sdes void *args_ptr; 63574462Salfred{ 63674462Salfred XDR *xdrs; 63774462Salfred 63874462Salfred assert(xprt != NULL); 63974462Salfred /* args_ptr may be NULL */ 64074462Salfred 64174462Salfred xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs); 64274462Salfred 64374462Salfred xdrs->x_op = XDR_FREE; 64474462Salfred return ((*xdr_args)(xdrs, args_ptr)); 64574462Salfred} 64674462Salfred 64774462Salfredstatic bool_t 64874462Salfredsvc_vc_reply(xprt, msg) 64974462Salfred SVCXPRT *xprt; 65074462Salfred struct rpc_msg *msg; 65174462Salfred{ 65274462Salfred struct cf_conn *cd; 65374462Salfred XDR *xdrs; 654109359Smbr bool_t rstat; 655181344Sdfr xdrproc_t xdr_proc; 656181344Sdfr caddr_t xdr_where; 657181344Sdfr u_int pos; 65874462Salfred 65974462Salfred assert(xprt != NULL); 66074462Salfred assert(msg != NULL); 66174462Salfred 66274462Salfred cd = (struct cf_conn *)(xprt->xp_p1); 66374462Salfred xdrs = &(cd->xdrs); 66474462Salfred 66574462Salfred xdrs->x_op = XDR_ENCODE; 66674462Salfred msg->rm_xid = cd->x_id; 667181344Sdfr rstat = TRUE; 668181344Sdfr if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 669181344Sdfr msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 670181344Sdfr xdr_proc = msg->acpted_rply.ar_results.proc; 671181344Sdfr xdr_where = msg->acpted_rply.ar_results.where; 672181344Sdfr msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; 673181344Sdfr msg->acpted_rply.ar_results.where = NULL; 674181344Sdfr 675181344Sdfr pos = XDR_GETPOS(xdrs); 676181344Sdfr if (!xdr_replymsg(xdrs, msg) || 677181344Sdfr !SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where)) { 678181344Sdfr XDR_SETPOS(xdrs, pos); 679181344Sdfr rstat = FALSE; 680181344Sdfr } 681181344Sdfr } else { 682181344Sdfr rstat = xdr_replymsg(xdrs, msg); 683181344Sdfr } 684181344Sdfr 685181344Sdfr if (rstat) 686181344Sdfr (void)xdrrec_endofrecord(xdrs, TRUE); 687181344Sdfr 688109359Smbr return (rstat); 68974462Salfred} 69074462Salfred 69174462Salfredstatic void 69274462Salfredsvc_vc_ops(xprt) 69374462Salfred SVCXPRT *xprt; 69474462Salfred{ 69574462Salfred static struct xp_ops ops; 69674462Salfred static struct xp_ops2 ops2; 69774462Salfred 69874462Salfred/* VARIABLES PROTECTED BY ops_lock: ops, ops2 */ 69974462Salfred 70074462Salfred mutex_lock(&ops_lock); 70174462Salfred if (ops.xp_recv == NULL) { 70274462Salfred ops.xp_recv = svc_vc_recv; 70374462Salfred ops.xp_stat = svc_vc_stat; 70474462Salfred ops.xp_getargs = svc_vc_getargs; 70574462Salfred ops.xp_reply = svc_vc_reply; 70674462Salfred ops.xp_freeargs = svc_vc_freeargs; 70774462Salfred ops.xp_destroy = svc_vc_destroy; 70874462Salfred ops2.xp_control = svc_vc_control; 70974462Salfred } 71074462Salfred xprt->xp_ops = &ops; 71174462Salfred xprt->xp_ops2 = &ops2; 71274462Salfred mutex_unlock(&ops_lock); 71374462Salfred} 71474462Salfred 71574462Salfredstatic void 71674462Salfredsvc_vc_rendezvous_ops(xprt) 71774462Salfred SVCXPRT *xprt; 71874462Salfred{ 71974462Salfred static struct xp_ops ops; 72074462Salfred static struct xp_ops2 ops2; 72174462Salfred 72274462Salfred mutex_lock(&ops_lock); 72374462Salfred if (ops.xp_recv == NULL) { 72474462Salfred ops.xp_recv = rendezvous_request; 72574462Salfred ops.xp_stat = rendezvous_stat; 72674462Salfred ops.xp_getargs = 72795658Sdes (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort; 72874462Salfred ops.xp_reply = 72992941Sobrien (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort; 73074462Salfred ops.xp_freeargs = 73195658Sdes (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort, 73274462Salfred ops.xp_destroy = svc_vc_destroy; 733109359Smbr ops2.xp_control = svc_vc_rendezvous_control; 73474462Salfred } 73574462Salfred xprt->xp_ops = &ops; 73674462Salfred xprt->xp_ops2 = &ops2; 73774462Salfred mutex_unlock(&ops_lock); 73874462Salfred} 73974462Salfred 74074627Salfred/* 741116391Smbr * Get the effective UID of the sending process. Used by rpcbind, keyserv 742116391Smbr * and rpc.yppasswdd on AF_LOCAL. 74374627Salfred */ 74474627Salfredint 745116391Smbr__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) { 746116391Smbr int sock, ret; 747116391Smbr gid_t egid; 748116391Smbr uid_t euid; 749116391Smbr struct sockaddr *sa; 750116391Smbr 751116391Smbr sock = transp->xp_fd; 752116391Smbr sa = (struct sockaddr *)transp->xp_rtaddr.buf; 753116391Smbr if (sa->sa_family == AF_LOCAL) { 754116391Smbr ret = getpeereid(sock, &euid, &egid); 755116391Smbr if (ret == 0) 756116391Smbr *uid = euid; 757116391Smbr return (ret); 758116391Smbr } else 75990257Salfred return (-1); 76074627Salfred} 761109359Smbr 762109359Smbr/* 763109359Smbr * Destroy xprts that have not have had any activity in 'timeout' seconds. 764109359Smbr * If 'cleanblock' is true, blocking connections (the default) are also 765109359Smbr * cleaned. If timeout is 0, the least active connection is picked. 766109359Smbr */ 767109359Smbrbool_t 768109359Smbr__svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock) 769109359Smbr{ 770109359Smbr int i, ncleaned; 771109359Smbr SVCXPRT *xprt, *least_active; 772109359Smbr struct timeval tv, tdiff, tmax; 773109359Smbr struct cf_conn *cd; 774109359Smbr 775109359Smbr gettimeofday(&tv, NULL); 776109359Smbr tmax.tv_sec = tmax.tv_usec = 0; 777109359Smbr least_active = NULL; 778109359Smbr rwlock_wrlock(&svc_fd_lock); 779109359Smbr for (i = ncleaned = 0; i <= svc_maxfd; i++) { 780109359Smbr if (FD_ISSET(i, fds)) { 781109359Smbr xprt = __svc_xports[i]; 782109359Smbr if (xprt == NULL || xprt->xp_ops == NULL || 783109359Smbr xprt->xp_ops->xp_recv != svc_vc_recv) 784109359Smbr continue; 785109359Smbr cd = (struct cf_conn *)xprt->xp_p1; 786109359Smbr if (!cleanblock && !cd->nonblock) 787109359Smbr continue; 788109359Smbr if (timeout == 0) { 789109359Smbr timersub(&tv, &cd->last_recv_time, &tdiff); 790109359Smbr if (timercmp(&tdiff, &tmax, >)) { 791109359Smbr tmax = tdiff; 792109359Smbr least_active = xprt; 793109359Smbr } 794109359Smbr continue; 795109359Smbr } 796109359Smbr if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) { 797109359Smbr __xprt_unregister_unlocked(xprt); 798109359Smbr __svc_vc_dodestroy(xprt); 799109359Smbr ncleaned++; 800109359Smbr } 801109359Smbr } 802109359Smbr } 803109359Smbr if (timeout == 0 && least_active != NULL) { 804109359Smbr __xprt_unregister_unlocked(least_active); 805109359Smbr __svc_vc_dodestroy(least_active); 806109359Smbr ncleaned++; 807109359Smbr } 808109359Smbr rwlock_unlock(&svc_fd_lock); 809109359Smbr return ncleaned > 0 ? TRUE : FALSE; 810109359Smbr} 811