174462Salfred/* $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $ */ 274462Salfred 3258578Shrs/*- 4258578Shrs * Copyright (c) 2009, Sun Microsystems, Inc. 5258578Shrs * All rights reserved. 6258578Shrs * 7258578Shrs * Redistribution and use in source and binary forms, with or without 8258578Shrs * modification, are permitted provided that the following conditions are met: 9258578Shrs * - Redistributions of source code must retain the above copyright notice, 10258578Shrs * this list of conditions and the following disclaimer. 11258578Shrs * - Redistributions in binary form must reproduce the above copyright notice, 12258578Shrs * this list of conditions and the following disclaimer in the documentation 13258578Shrs * and/or other materials provided with the distribution. 14258578Shrs * - Neither the name of Sun Microsystems, Inc. nor the names of its 15258578Shrs * contributors may be used to endorse or promote products derived 16258578Shrs * from this software without specific prior written permission. 1774462Salfred * 18258578Shrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19258578Shrs * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20258578Shrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21258578Shrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22258578Shrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23258578Shrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24258578Shrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25258578Shrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26258578Shrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27258578Shrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28258578Shrs * 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: releng/11.0/lib/libc/rpc/svc_vc.c 298830 2016-04-30 01:24:24Z pfg $"); 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/param.h> 4974462Salfred#include <sys/poll.h> 5074462Salfred#include <sys/socket.h> 5174462Salfred#include <sys/un.h> 52109359Smbr#include <sys/time.h> 5374462Salfred#include <sys/uio.h> 5474462Salfred#include <netinet/in.h> 5574462Salfred#include <netinet/tcp.h> 5674462Salfred 5774462Salfred#include <assert.h> 5874462Salfred#include <err.h> 5974462Salfred#include <errno.h> 60109359Smbr#include <fcntl.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" 69156090Sdeischen#include "mt_misc.h" 7074462Salfred#include "un-namespace.h" 7174462Salfred 7292905Sobrienstatic SVCXPRT *makefd_xprt(int, u_int, u_int); 7392905Sobrienstatic bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *); 7492905Sobrienstatic enum xprt_stat rendezvous_stat(SVCXPRT *); 7592905Sobrienstatic void svc_vc_destroy(SVCXPRT *); 76109359Smbrstatic void __svc_vc_dodestroy (SVCXPRT *); 7795658Sdesstatic int read_vc(void *, void *, int); 7895658Sdesstatic int write_vc(void *, void *, int); 7992905Sobrienstatic enum xprt_stat svc_vc_stat(SVCXPRT *); 8092905Sobrienstatic bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *); 8195658Sdesstatic bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, void *); 8295658Sdesstatic bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, void *); 8392905Sobrienstatic bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *); 8492905Sobrienstatic void svc_vc_rendezvous_ops(SVCXPRT *); 8592905Sobrienstatic void svc_vc_ops(SVCXPRT *); 8692905Sobrienstatic bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in); 87109359Smbrstatic bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq, 88109359Smbr void *in); 8974462Salfred 9074462Salfredstruct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */ 9174462Salfred u_int sendsize; 9274462Salfred u_int recvsize; 93109359Smbr int maxrec; 9474462Salfred}; 9574462Salfred 9674462Salfredstruct cf_conn { /* kept in xprt->xp_p1 for actual connection */ 9774462Salfred enum xprt_stat strm_stat; 9874462Salfred u_int32_t x_id; 9974462Salfred XDR xdrs; 10074462Salfred char verf_body[MAX_AUTH_BYTES]; 101109359Smbr u_int sendsize; 102109359Smbr u_int recvsize; 103109359Smbr int maxrec; 104109359Smbr bool_t nonblock; 105109359Smbr struct timeval last_recv_time; 10674462Salfred}; 10774462Salfred 10874462Salfred/* 10974462Salfred * Usage: 11074462Salfred * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); 11174462Salfred * 11274462Salfred * Creates, registers, and returns a (rpc) tcp based transporter. 11374462Salfred * Once *xprt is initialized, it is registered as a transporter 11474462Salfred * see (svc.h, xprt_register). This routine returns 11574462Salfred * a NULL if a problem occurred. 11674462Salfred * 11774462Salfred * The filedescriptor passed in is expected to refer to a bound, but 11874462Salfred * not yet connected socket. 11974462Salfred * 12074462Salfred * Since streams do buffered io similar to stdio, the caller can specify 12174462Salfred * how big the send and receive buffers are via the second and third parms; 12274462Salfred * 0 => use the system default. 12374462Salfred */ 12474462SalfredSVCXPRT * 125287341Srodrigcsvc_vc_create(int fd, u_int sendsize, u_int recvsize) 12674462Salfred{ 127278041Spfg SVCXPRT *xprt = NULL; 12874462Salfred struct cf_rendezvous *r = NULL; 12974462Salfred struct __rpc_sockinfo si; 13074462Salfred struct sockaddr_storage sslocal; 13174462Salfred socklen_t slen; 13274462Salfred 133162196Smbr if (!__rpc_fd2sockinfo(fd, &si)) 134162196Smbr return NULL; 135162196Smbr 13674462Salfred r = mem_alloc(sizeof(*r)); 13774462Salfred if (r == NULL) { 13874462Salfred warnx("svc_vc_create: out of memory"); 13974462Salfred goto cleanup_svc_vc_create; 14074462Salfred } 14174462Salfred r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); 14274462Salfred r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); 143109359Smbr r->maxrec = __svc_maxrec; 144181344Sdfr xprt = svc_xprt_alloc(); 14574462Salfred if (xprt == NULL) { 14674462Salfred warnx("svc_vc_create: out of memory"); 14774462Salfred goto cleanup_svc_vc_create; 14874462Salfred } 14995658Sdes xprt->xp_p1 = r; 15074462Salfred xprt->xp_verf = _null_auth; 15174462Salfred svc_vc_rendezvous_ops(xprt); 15274462Salfred xprt->xp_port = (u_short)-1; /* It is the rendezvouser */ 15374462Salfred xprt->xp_fd = fd; 15474462Salfred 15574462Salfred slen = sizeof (struct sockaddr_storage); 15674462Salfred if (_getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) { 15774462Salfred warnx("svc_vc_create: could not retrieve local addr"); 15874462Salfred goto cleanup_svc_vc_create; 15974462Salfred } 16074462Salfred 16174462Salfred xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len; 16274462Salfred xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len); 16374462Salfred if (xprt->xp_ltaddr.buf == NULL) { 16474462Salfred warnx("svc_vc_create: no mem for local addr"); 16574462Salfred goto cleanup_svc_vc_create; 16674462Salfred } 16774462Salfred memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len); 16874462Salfred 16974462Salfred xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage); 17074462Salfred xprt_register(xprt); 17174462Salfred return (xprt); 17274462Salfredcleanup_svc_vc_create: 173162196Smbr if (xprt) 174162196Smbr mem_free(xprt, sizeof(*xprt)); 17574462Salfred if (r != NULL) 17674462Salfred mem_free(r, sizeof(*r)); 17774462Salfred return (NULL); 17874462Salfred} 17974462Salfred 18074462Salfred/* 18174462Salfred * Like svtcp_create(), except the routine takes any *open* UNIX file 18274462Salfred * descriptor as its first input. 18374462Salfred */ 18474462SalfredSVCXPRT * 185287341Srodrigcsvc_fd_create(int fd, u_int sendsize, u_int recvsize) 18674462Salfred{ 18774462Salfred struct sockaddr_storage ss; 18874462Salfred socklen_t slen; 18974462Salfred SVCXPRT *ret; 19074462Salfred 19174462Salfred assert(fd != -1); 19274462Salfred 19374462Salfred ret = makefd_xprt(fd, sendsize, recvsize); 19474462Salfred if (ret == NULL) 19574462Salfred return NULL; 19674462Salfred 19774462Salfred slen = sizeof (struct sockaddr_storage); 19874462Salfred if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { 19974462Salfred warnx("svc_fd_create: could not retrieve local addr"); 20074462Salfred goto freedata; 20174462Salfred } 20274462Salfred ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len; 20374462Salfred ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len); 20474462Salfred if (ret->xp_ltaddr.buf == NULL) { 20574462Salfred warnx("svc_fd_create: no mem for local addr"); 20674462Salfred goto freedata; 20774462Salfred } 20874462Salfred memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len); 20974462Salfred 21074462Salfred slen = sizeof (struct sockaddr_storage); 21174462Salfred if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { 21274462Salfred warnx("svc_fd_create: could not retrieve remote addr"); 21374462Salfred goto freedata; 21474462Salfred } 21574462Salfred ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len; 21674462Salfred ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len); 21774462Salfred if (ret->xp_rtaddr.buf == NULL) { 21874462Salfred warnx("svc_fd_create: no mem for local addr"); 21974462Salfred goto freedata; 22074462Salfred } 22174462Salfred memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len); 22274462Salfred#ifdef PORTMAP 22390272Salfred if (ss.ss_family == AF_INET || ss.ss_family == AF_LOCAL) { 22474462Salfred ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf; 22574462Salfred ret->xp_addrlen = sizeof (struct sockaddr_in); 22674462Salfred } 22774462Salfred#endif /* PORTMAP */ 22874462Salfred 22974462Salfred return ret; 23074462Salfred 23174462Salfredfreedata: 23274462Salfred if (ret->xp_ltaddr.buf != NULL) 23374462Salfred mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen); 23474462Salfred 23574462Salfred return NULL; 23674462Salfred} 23774462Salfred 23874462Salfredstatic SVCXPRT * 239287341Srodrigcmakefd_xprt(int fd, u_int sendsize, u_int recvsize) 24074462Salfred{ 24174462Salfred SVCXPRT *xprt; 24274462Salfred struct cf_conn *cd; 24374462Salfred const char *netid; 24474462Salfred struct __rpc_sockinfo si; 24574462Salfred 24674462Salfred assert(fd != -1); 24774462Salfred 248181344Sdfr xprt = svc_xprt_alloc(); 24974462Salfred if (xprt == NULL) { 25074462Salfred warnx("svc_vc: makefd_xprt: out of memory"); 25174462Salfred goto done; 25274462Salfred } 25374462Salfred cd = mem_alloc(sizeof(struct cf_conn)); 25474462Salfred if (cd == NULL) { 25574462Salfred warnx("svc_tcp: makefd_xprt: out of memory"); 256181344Sdfr svc_xprt_free(xprt); 25774462Salfred xprt = NULL; 25874462Salfred goto done; 25974462Salfred } 26074462Salfred cd->strm_stat = XPRT_IDLE; 26174462Salfred xdrrec_create(&(cd->xdrs), sendsize, recvsize, 26295658Sdes xprt, read_vc, write_vc); 26395658Sdes xprt->xp_p1 = cd; 26474462Salfred xprt->xp_verf.oa_base = cd->verf_body; 265298830Spfg svc_vc_ops(xprt); /* truly deals with calls */ 26674462Salfred xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ 26774462Salfred xprt->xp_fd = fd; 26874462Salfred if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid)) 26974462Salfred xprt->xp_netid = strdup(netid); 27074462Salfred 27174462Salfred xprt_register(xprt); 27274462Salfreddone: 27374462Salfred return (xprt); 27474462Salfred} 27574462Salfred 27674462Salfred/*ARGSUSED*/ 27774462Salfredstatic bool_t 278287341Srodrigcrendezvous_request(SVCXPRT *xprt, struct rpc_msg *msg) 27974462Salfred{ 280109359Smbr int sock, flags; 28174462Salfred struct cf_rendezvous *r; 282109359Smbr struct cf_conn *cd; 283292047Sstas struct sockaddr_storage addr, sslocal; 284292047Sstas socklen_t len, slen; 28574462Salfred struct __rpc_sockinfo si; 286109359Smbr SVCXPRT *newxprt; 287109359Smbr fd_set cleanfds; 28874462Salfred 28974462Salfred assert(xprt != NULL); 29074462Salfred assert(msg != NULL); 29174462Salfred 29274462Salfred r = (struct cf_rendezvous *)xprt->xp_p1; 29374462Salfredagain: 29474462Salfred len = sizeof addr; 29574462Salfred if ((sock = _accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr, 29674462Salfred &len)) < 0) { 29774462Salfred if (errno == EINTR) 29874462Salfred goto again; 299109359Smbr /* 300109359Smbr * Clean out the most idle file descriptor when we're 301109359Smbr * running out. 302109359Smbr */ 303109359Smbr if (errno == EMFILE || errno == ENFILE) { 304109359Smbr cleanfds = svc_fdset; 305109359Smbr __svc_clean_idle(&cleanfds, 0, FALSE); 306109359Smbr goto again; 307109359Smbr } 308109359Smbr return (FALSE); 30974462Salfred } 31074462Salfred /* 31174462Salfred * make a new transporter (re-uses xprt) 31274462Salfred */ 313109359Smbr newxprt = makefd_xprt(sock, r->sendsize, r->recvsize); 314109359Smbr newxprt->xp_rtaddr.buf = mem_alloc(len); 315109359Smbr if (newxprt->xp_rtaddr.buf == NULL) 31674462Salfred return (FALSE); 317109359Smbr memcpy(newxprt->xp_rtaddr.buf, &addr, len); 318109359Smbr newxprt->xp_rtaddr.len = len; 31974462Salfred#ifdef PORTMAP 32090316Salfred if (addr.ss_family == AF_INET || addr.ss_family == AF_LOCAL) { 321109359Smbr newxprt->xp_raddr = *(struct sockaddr_in *)newxprt->xp_rtaddr.buf; 322109359Smbr newxprt->xp_addrlen = sizeof (struct sockaddr_in); 32374462Salfred } 32474462Salfred#endif /* PORTMAP */ 32574462Salfred if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) { 32674462Salfred len = 1; 32774462Salfred /* XXX fvdl - is this useful? */ 32874462Salfred _setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &len, sizeof (len)); 32974462Salfred } 330109359Smbr 331109359Smbr cd = (struct cf_conn *)newxprt->xp_p1; 332109359Smbr 333109359Smbr cd->recvsize = r->recvsize; 334109359Smbr cd->sendsize = r->sendsize; 335109359Smbr cd->maxrec = r->maxrec; 336109359Smbr 337109359Smbr if (cd->maxrec != 0) { 338109904Smbr flags = _fcntl(sock, F_GETFL, 0); 339109359Smbr if (flags == -1) 340109359Smbr return (FALSE); 341109904Smbr if (_fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) 342109359Smbr return (FALSE); 343109359Smbr if (cd->recvsize > cd->maxrec) 344109359Smbr cd->recvsize = cd->maxrec; 345109359Smbr cd->nonblock = TRUE; 346109359Smbr __xdrrec_setnonblock(&cd->xdrs, cd->maxrec); 347109359Smbr } else 348109359Smbr cd->nonblock = FALSE; 349292047Sstas slen = sizeof(struct sockaddr_storage); 350292047Sstas if(_getsockname(sock, (struct sockaddr *)(void *)&sslocal, &slen) < 0) { 351292047Sstas warnx("svc_vc_create: could not retrieve local addr"); 352292047Sstas newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = 0; 353292047Sstas } else { 354292047Sstas newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = sslocal.ss_len; 355292047Sstas newxprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len); 356292047Sstas if (newxprt->xp_ltaddr.buf == NULL) { 357292047Sstas warnx("svc_vc_create: no mem for local addr"); 358292047Sstas newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = 0; 359292047Sstas } else { 360292047Sstas memcpy(newxprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len); 361292047Sstas } 362292047Sstas } 363109359Smbr 364109359Smbr gettimeofday(&cd->last_recv_time, NULL); 365109359Smbr 36674462Salfred return (FALSE); /* there is never an rpc msg to be processed */ 36774462Salfred} 36874462Salfred 36974462Salfred/*ARGSUSED*/ 37074462Salfredstatic enum xprt_stat 371287341Srodrigcrendezvous_stat(SVCXPRT *xprt) 37274462Salfred{ 37374462Salfred 37474462Salfred return (XPRT_IDLE); 37574462Salfred} 37674462Salfred 37774462Salfredstatic void 378287341Srodrigcsvc_vc_destroy(SVCXPRT *xprt) 37974462Salfred{ 380109359Smbr assert(xprt != NULL); 381109359Smbr 382109359Smbr xprt_unregister(xprt); 383109359Smbr __svc_vc_dodestroy(xprt); 384109359Smbr} 385109359Smbr 386109359Smbrstatic void 387287341Srodrigc__svc_vc_dodestroy(SVCXPRT *xprt) 388109359Smbr{ 38974462Salfred struct cf_conn *cd; 39074462Salfred struct cf_rendezvous *r; 39174462Salfred 39274462Salfred cd = (struct cf_conn *)xprt->xp_p1; 39374462Salfred 39474462Salfred if (xprt->xp_fd != RPC_ANYFD) 39574462Salfred (void)_close(xprt->xp_fd); 39674462Salfred if (xprt->xp_port != 0) { 39774462Salfred /* a rendezvouser socket */ 39874462Salfred r = (struct cf_rendezvous *)xprt->xp_p1; 39974462Salfred mem_free(r, sizeof (struct cf_rendezvous)); 40074462Salfred xprt->xp_port = 0; 40174462Salfred } else { 40274462Salfred /* an actual connection socket */ 40374462Salfred XDR_DESTROY(&(cd->xdrs)); 40474462Salfred mem_free(cd, sizeof(struct cf_conn)); 40574462Salfred } 40674462Salfred if (xprt->xp_rtaddr.buf) 40774462Salfred mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen); 40874462Salfred if (xprt->xp_ltaddr.buf) 40974462Salfred mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen); 410290253Sngie free(xprt->xp_tp); 411290253Sngie free(xprt->xp_netid); 412181344Sdfr svc_xprt_free(xprt); 41374462Salfred} 41474462Salfred 41574462Salfred/*ARGSUSED*/ 41674462Salfredstatic bool_t 417287341Srodrigcsvc_vc_control(SVCXPRT *xprt, const u_int rq, void *in) 41874462Salfred{ 41974462Salfred return (FALSE); 42074462Salfred} 42174462Salfred 422109359Smbrstatic bool_t 423287341Srodrigcsvc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in) 424109359Smbr{ 425109359Smbr struct cf_rendezvous *cfp; 426109359Smbr 427109359Smbr cfp = (struct cf_rendezvous *)xprt->xp_p1; 428109359Smbr if (cfp == NULL) 429109359Smbr return (FALSE); 430109359Smbr switch (rq) { 431109359Smbr case SVCGET_CONNMAXREC: 432109359Smbr *(int *)in = cfp->maxrec; 433109359Smbr break; 434109359Smbr case SVCSET_CONNMAXREC: 435109359Smbr cfp->maxrec = *(int *)in; 436109359Smbr break; 437109359Smbr default: 438109359Smbr return (FALSE); 439109359Smbr } 440109359Smbr return (TRUE); 441109359Smbr} 442109359Smbr 44374462Salfred/* 44474462Salfred * reads data from the tcp or uip connection. 44574462Salfred * any error is fatal and the connection is closed. 44674462Salfred * (And a read of zero bytes is a half closed stream => error.) 44774462Salfred * All read operations timeout after 35 seconds. A timeout is 44874462Salfred * fatal for the connection. 44974462Salfred */ 45074462Salfredstatic int 451287341Srodrigcread_vc(void *xprtp, void *buf, int len) 45274462Salfred{ 45374462Salfred SVCXPRT *xprt; 45474462Salfred int sock; 45574462Salfred int milliseconds = 35 * 1000; 45674462Salfred struct pollfd pollfd; 457109359Smbr struct cf_conn *cfp; 45874462Salfred 45995658Sdes xprt = (SVCXPRT *)xprtp; 46074462Salfred assert(xprt != NULL); 46174462Salfred 46274462Salfred sock = xprt->xp_fd; 46374462Salfred 464109359Smbr cfp = (struct cf_conn *)xprt->xp_p1; 465109359Smbr 466109359Smbr if (cfp->nonblock) { 467116391Smbr len = _read(sock, buf, (size_t)len); 468109359Smbr if (len < 0) { 469109359Smbr if (errno == EAGAIN) 470109359Smbr len = 0; 471109359Smbr else 472109359Smbr goto fatal_err; 473109359Smbr } 474109359Smbr if (len != 0) 475109359Smbr gettimeofday(&cfp->last_recv_time, NULL); 476109359Smbr return len; 477109359Smbr } 478109359Smbr 47974536Salfred do { 48074536Salfred pollfd.fd = sock; 48174536Salfred pollfd.events = POLLIN; 48274462Salfred pollfd.revents = 0; 48374536Salfred switch (_poll(&pollfd, 1, milliseconds)) { 48474536Salfred case -1: 48574536Salfred if (errno == EINTR) 48674536Salfred continue; 48774536Salfred /*FALLTHROUGH*/ 48874627Salfred case 0: 48974627Salfred goto fatal_err; 49074627Salfred 49174627Salfred default: 49274627Salfred break; 49374536Salfred } 49474536Salfred } while ((pollfd.revents & POLLIN) == 0); 49574462Salfred 496116391Smbr if ((len = _read(sock, buf, (size_t)len)) > 0) { 497116391Smbr gettimeofday(&cfp->last_recv_time, NULL); 498116391Smbr return (len); 49974462Salfred } 50074462Salfred 50174462Salfredfatal_err: 50274462Salfred ((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; 50374462Salfred return (-1); 50474462Salfred} 50574462Salfred 50674462Salfred/* 50774462Salfred * writes data to the tcp connection. 50874462Salfred * Any error is fatal and the connection is closed. 50974462Salfred */ 51074462Salfredstatic int 511287341Srodrigcwrite_vc(void *xprtp, void *buf, int len) 51274462Salfred{ 51374462Salfred SVCXPRT *xprt; 51474462Salfred int i, cnt; 515109359Smbr struct cf_conn *cd; 516109359Smbr struct timeval tv0, tv1; 51774462Salfred 51895658Sdes xprt = (SVCXPRT *)xprtp; 51974462Salfred assert(xprt != NULL); 520109359Smbr 521109359Smbr cd = (struct cf_conn *)xprt->xp_p1; 522109359Smbr 523109359Smbr if (cd->nonblock) 524109359Smbr gettimeofday(&tv0, NULL); 52574462Salfred 526133693Sstefanf for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) { 527116391Smbr i = _write(xprt->xp_fd, buf, (size_t)cnt); 528109359Smbr if (i < 0) { 529109359Smbr if (errno != EAGAIN || !cd->nonblock) { 530109359Smbr cd->strm_stat = XPRT_DIED; 53174462Salfred return (-1); 53274462Salfred } 533220519Srmacklem if (cd->nonblock) { 534109359Smbr /* 535109359Smbr * For non-blocking connections, do not 536109359Smbr * take more than 2 seconds writing the 537109359Smbr * data out. 538109359Smbr * 539109359Smbr * XXX 2 is an arbitrary amount. 540109359Smbr */ 541109359Smbr gettimeofday(&tv1, NULL); 542109359Smbr if (tv1.tv_sec - tv0.tv_sec >= 2) { 543109359Smbr cd->strm_stat = XPRT_DIED; 544109359Smbr return (-1); 545109359Smbr } 54674462Salfred } 547220519Srmacklem i = 0; 54874462Salfred } 54974462Salfred } 55074462Salfred 55174462Salfred return (len); 55274462Salfred} 55374462Salfred 55474462Salfredstatic enum xprt_stat 555287341Srodrigcsvc_vc_stat(SVCXPRT *xprt) 55674462Salfred{ 55774462Salfred struct cf_conn *cd; 55874462Salfred 55974462Salfred assert(xprt != NULL); 56074462Salfred 56174462Salfred cd = (struct cf_conn *)(xprt->xp_p1); 56274462Salfred 56374462Salfred if (cd->strm_stat == XPRT_DIED) 56474462Salfred return (XPRT_DIED); 56574462Salfred if (! xdrrec_eof(&(cd->xdrs))) 56674462Salfred return (XPRT_MOREREQS); 56774462Salfred return (XPRT_IDLE); 56874462Salfred} 56974462Salfred 57074462Salfredstatic bool_t 571287341Srodrigcsvc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg) 57274462Salfred{ 57374462Salfred struct cf_conn *cd; 57474462Salfred XDR *xdrs; 57574462Salfred 57674462Salfred assert(xprt != NULL); 57774462Salfred assert(msg != NULL); 57874462Salfred 57974462Salfred cd = (struct cf_conn *)(xprt->xp_p1); 58074462Salfred xdrs = &(cd->xdrs); 58174462Salfred 582109359Smbr if (cd->nonblock) { 583109359Smbr if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE)) 584109359Smbr return FALSE; 585177737Sdfr } else { 586177737Sdfr (void)xdrrec_skiprecord(xdrs); 587109359Smbr } 588109359Smbr 58974462Salfred xdrs->x_op = XDR_DECODE; 59074462Salfred if (xdr_callmsg(xdrs, msg)) { 59174462Salfred cd->x_id = msg->rm_xid; 59274462Salfred return (TRUE); 59374462Salfred } 59474462Salfred cd->strm_stat = XPRT_DIED; 59574462Salfred return (FALSE); 59674462Salfred} 59774462Salfred 59874462Salfredstatic bool_t 599287341Srodrigcsvc_vc_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr) 60074462Salfred{ 601181344Sdfr struct cf_conn *cd; 60274462Salfred 60374462Salfred assert(xprt != NULL); 604181344Sdfr cd = (struct cf_conn *)(xprt->xp_p1); 605181344Sdfr return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt), 606181344Sdfr &cd->xdrs, xdr_args, args_ptr)); 60774462Salfred} 60874462Salfred 60974462Salfredstatic bool_t 610287341Srodrigcsvc_vc_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr) 61174462Salfred{ 61274462Salfred XDR *xdrs; 61374462Salfred 61474462Salfred assert(xprt != NULL); 61574462Salfred /* args_ptr may be NULL */ 61674462Salfred 61774462Salfred xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs); 61874462Salfred 61974462Salfred xdrs->x_op = XDR_FREE; 62074462Salfred return ((*xdr_args)(xdrs, args_ptr)); 62174462Salfred} 62274462Salfred 62374462Salfredstatic bool_t 624287341Srodrigcsvc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg) 62574462Salfred{ 62674462Salfred struct cf_conn *cd; 62774462Salfred XDR *xdrs; 628109359Smbr bool_t rstat; 629181344Sdfr xdrproc_t xdr_proc; 630181344Sdfr caddr_t xdr_where; 631181344Sdfr u_int pos; 63274462Salfred 63374462Salfred assert(xprt != NULL); 63474462Salfred assert(msg != NULL); 63574462Salfred 63674462Salfred cd = (struct cf_conn *)(xprt->xp_p1); 63774462Salfred xdrs = &(cd->xdrs); 63874462Salfred 63974462Salfred xdrs->x_op = XDR_ENCODE; 64074462Salfred msg->rm_xid = cd->x_id; 641181344Sdfr rstat = TRUE; 642181344Sdfr if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 643181344Sdfr msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 644181344Sdfr xdr_proc = msg->acpted_rply.ar_results.proc; 645181344Sdfr xdr_where = msg->acpted_rply.ar_results.where; 646181344Sdfr msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; 647181344Sdfr msg->acpted_rply.ar_results.where = NULL; 648181344Sdfr 649181344Sdfr pos = XDR_GETPOS(xdrs); 650181344Sdfr if (!xdr_replymsg(xdrs, msg) || 651181344Sdfr !SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where)) { 652181344Sdfr XDR_SETPOS(xdrs, pos); 653181344Sdfr rstat = FALSE; 654181344Sdfr } 655181344Sdfr } else { 656181344Sdfr rstat = xdr_replymsg(xdrs, msg); 657181344Sdfr } 658181344Sdfr 659181344Sdfr if (rstat) 660181344Sdfr (void)xdrrec_endofrecord(xdrs, TRUE); 661181344Sdfr 662109359Smbr return (rstat); 66374462Salfred} 66474462Salfred 66574462Salfredstatic void 666287341Srodrigcsvc_vc_ops(SVCXPRT *xprt) 66774462Salfred{ 66874462Salfred static struct xp_ops ops; 66974462Salfred static struct xp_ops2 ops2; 67074462Salfred 67174462Salfred/* VARIABLES PROTECTED BY ops_lock: ops, ops2 */ 67274462Salfred 67374462Salfred mutex_lock(&ops_lock); 67474462Salfred if (ops.xp_recv == NULL) { 67574462Salfred ops.xp_recv = svc_vc_recv; 67674462Salfred ops.xp_stat = svc_vc_stat; 67774462Salfred ops.xp_getargs = svc_vc_getargs; 67874462Salfred ops.xp_reply = svc_vc_reply; 67974462Salfred ops.xp_freeargs = svc_vc_freeargs; 68074462Salfred ops.xp_destroy = svc_vc_destroy; 68174462Salfred ops2.xp_control = svc_vc_control; 68274462Salfred } 68374462Salfred xprt->xp_ops = &ops; 68474462Salfred xprt->xp_ops2 = &ops2; 68574462Salfred mutex_unlock(&ops_lock); 68674462Salfred} 68774462Salfred 68874462Salfredstatic void 689287341Srodrigcsvc_vc_rendezvous_ops(SVCXPRT *xprt) 69074462Salfred{ 69174462Salfred static struct xp_ops ops; 69274462Salfred static struct xp_ops2 ops2; 69374462Salfred 69474462Salfred mutex_lock(&ops_lock); 69574462Salfred if (ops.xp_recv == NULL) { 69674462Salfred ops.xp_recv = rendezvous_request; 69774462Salfred ops.xp_stat = rendezvous_stat; 69874462Salfred ops.xp_getargs = 69995658Sdes (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort; 70074462Salfred ops.xp_reply = 70192941Sobrien (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort; 70274462Salfred ops.xp_freeargs = 70395658Sdes (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort, 70474462Salfred ops.xp_destroy = svc_vc_destroy; 705109359Smbr ops2.xp_control = svc_vc_rendezvous_control; 70674462Salfred } 70774462Salfred xprt->xp_ops = &ops; 70874462Salfred xprt->xp_ops2 = &ops2; 70974462Salfred mutex_unlock(&ops_lock); 71074462Salfred} 71174462Salfred 71274627Salfred/* 713116391Smbr * Get the effective UID of the sending process. Used by rpcbind, keyserv 714116391Smbr * and rpc.yppasswdd on AF_LOCAL. 71574627Salfred */ 71674627Salfredint 717116391Smbr__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) { 718116391Smbr int sock, ret; 719116391Smbr gid_t egid; 720116391Smbr uid_t euid; 721116391Smbr struct sockaddr *sa; 722116391Smbr 723116391Smbr sock = transp->xp_fd; 724116391Smbr sa = (struct sockaddr *)transp->xp_rtaddr.buf; 725116391Smbr if (sa->sa_family == AF_LOCAL) { 726116391Smbr ret = getpeereid(sock, &euid, &egid); 727116391Smbr if (ret == 0) 728116391Smbr *uid = euid; 729116391Smbr return (ret); 730116391Smbr } else 73190257Salfred return (-1); 73274627Salfred} 733109359Smbr 734109359Smbr/* 735109359Smbr * Destroy xprts that have not have had any activity in 'timeout' seconds. 736109359Smbr * If 'cleanblock' is true, blocking connections (the default) are also 737109359Smbr * cleaned. If timeout is 0, the least active connection is picked. 738109359Smbr */ 739109359Smbrbool_t 740109359Smbr__svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock) 741109359Smbr{ 742109359Smbr int i, ncleaned; 743109359Smbr SVCXPRT *xprt, *least_active; 744109359Smbr struct timeval tv, tdiff, tmax; 745109359Smbr struct cf_conn *cd; 746109359Smbr 747109359Smbr gettimeofday(&tv, NULL); 748109359Smbr tmax.tv_sec = tmax.tv_usec = 0; 749109359Smbr least_active = NULL; 750109359Smbr rwlock_wrlock(&svc_fd_lock); 751109359Smbr for (i = ncleaned = 0; i <= svc_maxfd; i++) { 752109359Smbr if (FD_ISSET(i, fds)) { 753109359Smbr xprt = __svc_xports[i]; 754109359Smbr if (xprt == NULL || xprt->xp_ops == NULL || 755109359Smbr xprt->xp_ops->xp_recv != svc_vc_recv) 756109359Smbr continue; 757109359Smbr cd = (struct cf_conn *)xprt->xp_p1; 758109359Smbr if (!cleanblock && !cd->nonblock) 759109359Smbr continue; 760109359Smbr if (timeout == 0) { 761109359Smbr timersub(&tv, &cd->last_recv_time, &tdiff); 762109359Smbr if (timercmp(&tdiff, &tmax, >)) { 763109359Smbr tmax = tdiff; 764109359Smbr least_active = xprt; 765109359Smbr } 766109359Smbr continue; 767109359Smbr } 768109359Smbr if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) { 769109359Smbr __xprt_unregister_unlocked(xprt); 770109359Smbr __svc_vc_dodestroy(xprt); 771109359Smbr ncleaned++; 772109359Smbr } 773109359Smbr } 774109359Smbr } 775109359Smbr if (timeout == 0 && least_active != NULL) { 776109359Smbr __xprt_unregister_unlocked(least_active); 777109359Smbr __svc_vc_dodestroy(least_active); 778109359Smbr ncleaned++; 779109359Smbr } 780109359Smbr rwlock_unlock(&svc_fd_lock); 781109359Smbr return ncleaned > 0 ? TRUE : FALSE; 782109359Smbr} 783