18360efbdSAlfred Perlstein /* $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $ */ 28360efbdSAlfred Perlstein 32e322d37SHiroki Sato /*- 42e322d37SHiroki Sato * Copyright (c) 2009, Sun Microsystems, Inc. 52e322d37SHiroki Sato * All rights reserved. 68360efbdSAlfred Perlstein * 72e322d37SHiroki Sato * Redistribution and use in source and binary forms, with or without 82e322d37SHiroki Sato * modification, are permitted provided that the following conditions are met: 92e322d37SHiroki Sato * - Redistributions of source code must retain the above copyright notice, 102e322d37SHiroki Sato * this list of conditions and the following disclaimer. 112e322d37SHiroki Sato * - Redistributions in binary form must reproduce the above copyright notice, 122e322d37SHiroki Sato * this list of conditions and the following disclaimer in the documentation 132e322d37SHiroki Sato * and/or other materials provided with the distribution. 142e322d37SHiroki Sato * - Neither the name of Sun Microsystems, Inc. nor the names of its 152e322d37SHiroki Sato * contributors may be used to endorse or promote products derived 162e322d37SHiroki Sato * from this software without specific prior written permission. 178360efbdSAlfred Perlstein * 182e322d37SHiroki Sato * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 192e322d37SHiroki Sato * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 202e322d37SHiroki Sato * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 212e322d37SHiroki Sato * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 222e322d37SHiroki Sato * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 232e322d37SHiroki Sato * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 242e322d37SHiroki Sato * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 252e322d37SHiroki Sato * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 262e322d37SHiroki Sato * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 272e322d37SHiroki Sato * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 282e322d37SHiroki Sato * POSSIBILITY OF SUCH DAMAGE. 298360efbdSAlfred Perlstein */ 308360efbdSAlfred Perlstein 318360efbdSAlfred Perlstein #if defined(LIBC_SCCS) && !defined(lint) 32a986ef57SDavid E. O'Brien static char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; 338360efbdSAlfred Perlstein static char *sccsid = "@(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 348360efbdSAlfred Perlstein #endif 35d3d20c82SDavid E. O'Brien #include <sys/cdefs.h> 36d3d20c82SDavid E. O'Brien __FBSDID("$FreeBSD$"); 378360efbdSAlfred Perlstein 388360efbdSAlfred Perlstein /* 398360efbdSAlfred Perlstein * svc_vc.c, Server side for Connection Oriented based RPC. 408360efbdSAlfred Perlstein * 418360efbdSAlfred Perlstein * Actually implements two flavors of transporter - 428360efbdSAlfred Perlstein * a tcp rendezvouser (a listner and connection establisher) 438360efbdSAlfred Perlstein * and a record/tcp stream. 448360efbdSAlfred Perlstein */ 458360efbdSAlfred Perlstein 468360efbdSAlfred Perlstein #include "namespace.h" 479f5afc13SIan Dowse #include "reentrant.h" 488360efbdSAlfred Perlstein #include <sys/types.h> 498360efbdSAlfred Perlstein #include <sys/param.h> 508360efbdSAlfred Perlstein #include <sys/poll.h> 518360efbdSAlfred Perlstein #include <sys/socket.h> 528360efbdSAlfred Perlstein #include <sys/un.h> 5308497c02SMartin Blapp #include <sys/time.h> 548360efbdSAlfred Perlstein #include <sys/uio.h> 558360efbdSAlfred Perlstein #include <netinet/in.h> 568360efbdSAlfred Perlstein #include <netinet/tcp.h> 578360efbdSAlfred Perlstein 588360efbdSAlfred Perlstein #include <assert.h> 598360efbdSAlfred Perlstein #include <err.h> 608360efbdSAlfred Perlstein #include <errno.h> 6108497c02SMartin Blapp #include <fcntl.h> 628360efbdSAlfred Perlstein #include <stdio.h> 638360efbdSAlfred Perlstein #include <stdlib.h> 648360efbdSAlfred Perlstein #include <string.h> 658360efbdSAlfred Perlstein #include <unistd.h> 668360efbdSAlfred Perlstein 678360efbdSAlfred Perlstein #include <rpc/rpc.h> 688360efbdSAlfred Perlstein 698360efbdSAlfred Perlstein #include "rpc_com.h" 70235baf26SDaniel Eischen #include "mt_misc.h" 718360efbdSAlfred Perlstein #include "un-namespace.h" 728360efbdSAlfred Perlstein 73c05ac53bSDavid E. O'Brien static SVCXPRT *makefd_xprt(int, u_int, u_int); 74c05ac53bSDavid E. O'Brien static bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *); 75c05ac53bSDavid E. O'Brien static enum xprt_stat rendezvous_stat(SVCXPRT *); 76c05ac53bSDavid E. O'Brien static void svc_vc_destroy(SVCXPRT *); 7708497c02SMartin Blapp static void __svc_vc_dodestroy (SVCXPRT *); 78f249dbccSDag-Erling Smørgrav static int read_vc(void *, void *, int); 79f249dbccSDag-Erling Smørgrav static int write_vc(void *, void *, int); 80c05ac53bSDavid E. O'Brien static enum xprt_stat svc_vc_stat(SVCXPRT *); 81c05ac53bSDavid E. O'Brien static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *); 82f249dbccSDag-Erling Smørgrav static bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, void *); 83f249dbccSDag-Erling Smørgrav static bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, void *); 84c05ac53bSDavid E. O'Brien static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *); 85c05ac53bSDavid E. O'Brien static void svc_vc_rendezvous_ops(SVCXPRT *); 86c05ac53bSDavid E. O'Brien static void svc_vc_ops(SVCXPRT *); 87c05ac53bSDavid E. O'Brien static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in); 8808497c02SMartin Blapp static bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq, 8908497c02SMartin Blapp void *in); 908360efbdSAlfred Perlstein 918360efbdSAlfred Perlstein struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */ 928360efbdSAlfred Perlstein u_int sendsize; 938360efbdSAlfred Perlstein u_int recvsize; 9408497c02SMartin Blapp int maxrec; 958360efbdSAlfred Perlstein }; 968360efbdSAlfred Perlstein 978360efbdSAlfred Perlstein struct cf_conn { /* kept in xprt->xp_p1 for actual connection */ 988360efbdSAlfred Perlstein enum xprt_stat strm_stat; 998360efbdSAlfred Perlstein u_int32_t x_id; 1008360efbdSAlfred Perlstein XDR xdrs; 1018360efbdSAlfred Perlstein char verf_body[MAX_AUTH_BYTES]; 10208497c02SMartin Blapp u_int sendsize; 10308497c02SMartin Blapp u_int recvsize; 10408497c02SMartin Blapp int maxrec; 10508497c02SMartin Blapp bool_t nonblock; 10608497c02SMartin Blapp struct timeval last_recv_time; 1078360efbdSAlfred Perlstein }; 1088360efbdSAlfred Perlstein 1098360efbdSAlfred Perlstein /* 1108360efbdSAlfred Perlstein * Usage: 1118360efbdSAlfred Perlstein * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); 1128360efbdSAlfred Perlstein * 1138360efbdSAlfred Perlstein * Creates, registers, and returns a (rpc) tcp based transporter. 1148360efbdSAlfred Perlstein * Once *xprt is initialized, it is registered as a transporter 1158360efbdSAlfred Perlstein * see (svc.h, xprt_register). This routine returns 1168360efbdSAlfred Perlstein * a NULL if a problem occurred. 1178360efbdSAlfred Perlstein * 1188360efbdSAlfred Perlstein * The filedescriptor passed in is expected to refer to a bound, but 1198360efbdSAlfred Perlstein * not yet connected socket. 1208360efbdSAlfred Perlstein * 1218360efbdSAlfred Perlstein * Since streams do buffered io similar to stdio, the caller can specify 1228360efbdSAlfred Perlstein * how big the send and receive buffers are via the second and third parms; 1238360efbdSAlfred Perlstein * 0 => use the system default. 1248360efbdSAlfred Perlstein */ 1258360efbdSAlfred Perlstein SVCXPRT * 12668895e38SCraig Rodrigues svc_vc_create(int fd, u_int sendsize, u_int recvsize) 1278360efbdSAlfred Perlstein { 128e742fdffSPedro F. Giffuni SVCXPRT *xprt = NULL; 1298360efbdSAlfred Perlstein struct cf_rendezvous *r = NULL; 1308360efbdSAlfred Perlstein struct __rpc_sockinfo si; 1318360efbdSAlfred Perlstein struct sockaddr_storage sslocal; 1328360efbdSAlfred Perlstein socklen_t slen; 1338360efbdSAlfred Perlstein 134794295baSMartin Blapp if (!__rpc_fd2sockinfo(fd, &si)) 135794295baSMartin Blapp return NULL; 136794295baSMartin Blapp 1378360efbdSAlfred Perlstein r = mem_alloc(sizeof(*r)); 1388360efbdSAlfred Perlstein if (r == NULL) { 1398360efbdSAlfred Perlstein warnx("svc_vc_create: out of memory"); 1408360efbdSAlfred Perlstein goto cleanup_svc_vc_create; 1418360efbdSAlfred Perlstein } 1428360efbdSAlfred Perlstein r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); 1438360efbdSAlfred Perlstein r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); 14408497c02SMartin Blapp r->maxrec = __svc_maxrec; 1458f55a568SDoug Rabson xprt = svc_xprt_alloc(); 1468360efbdSAlfred Perlstein if (xprt == NULL) { 1478360efbdSAlfred Perlstein warnx("svc_vc_create: out of memory"); 1488360efbdSAlfred Perlstein goto cleanup_svc_vc_create; 1498360efbdSAlfred Perlstein } 150f249dbccSDag-Erling Smørgrav xprt->xp_p1 = r; 1518360efbdSAlfred Perlstein xprt->xp_verf = _null_auth; 1528360efbdSAlfred Perlstein svc_vc_rendezvous_ops(xprt); 1538360efbdSAlfred Perlstein xprt->xp_port = (u_short)-1; /* It is the rendezvouser */ 1548360efbdSAlfred Perlstein xprt->xp_fd = fd; 1558360efbdSAlfred Perlstein 1568360efbdSAlfred Perlstein slen = sizeof (struct sockaddr_storage); 1578360efbdSAlfred Perlstein if (_getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) { 1588360efbdSAlfred Perlstein warnx("svc_vc_create: could not retrieve local addr"); 1598360efbdSAlfred Perlstein goto cleanup_svc_vc_create; 1608360efbdSAlfred Perlstein } 1618360efbdSAlfred Perlstein 1628360efbdSAlfred Perlstein xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len; 1638360efbdSAlfred Perlstein xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len); 1648360efbdSAlfred Perlstein if (xprt->xp_ltaddr.buf == NULL) { 1658360efbdSAlfred Perlstein warnx("svc_vc_create: no mem for local addr"); 1668360efbdSAlfred Perlstein goto cleanup_svc_vc_create; 1678360efbdSAlfred Perlstein } 1688360efbdSAlfred Perlstein memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len); 1698360efbdSAlfred Perlstein 1708360efbdSAlfred Perlstein xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage); 1718360efbdSAlfred Perlstein xprt_register(xprt); 1728360efbdSAlfred Perlstein return (xprt); 1738360efbdSAlfred Perlstein cleanup_svc_vc_create: 174794295baSMartin Blapp if (xprt) 175794295baSMartin Blapp mem_free(xprt, sizeof(*xprt)); 1768360efbdSAlfred Perlstein if (r != NULL) 1778360efbdSAlfred Perlstein mem_free(r, sizeof(*r)); 1788360efbdSAlfred Perlstein return (NULL); 1798360efbdSAlfred Perlstein } 1808360efbdSAlfred Perlstein 1818360efbdSAlfred Perlstein /* 1828360efbdSAlfred Perlstein * Like svtcp_create(), except the routine takes any *open* UNIX file 1838360efbdSAlfred Perlstein * descriptor as its first input. 1848360efbdSAlfred Perlstein */ 1858360efbdSAlfred Perlstein SVCXPRT * 18668895e38SCraig Rodrigues svc_fd_create(int fd, u_int sendsize, u_int recvsize) 1878360efbdSAlfred Perlstein { 1888360efbdSAlfred Perlstein struct sockaddr_storage ss; 1898360efbdSAlfred Perlstein socklen_t slen; 1908360efbdSAlfred Perlstein SVCXPRT *ret; 1918360efbdSAlfred Perlstein 1928360efbdSAlfred Perlstein assert(fd != -1); 1938360efbdSAlfred Perlstein 1948360efbdSAlfred Perlstein ret = makefd_xprt(fd, sendsize, recvsize); 1958360efbdSAlfred Perlstein if (ret == NULL) 1968360efbdSAlfred Perlstein return NULL; 1978360efbdSAlfred Perlstein 1988360efbdSAlfred Perlstein slen = sizeof (struct sockaddr_storage); 1998360efbdSAlfred Perlstein if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { 2008360efbdSAlfred Perlstein warnx("svc_fd_create: could not retrieve local addr"); 2018360efbdSAlfred Perlstein goto freedata; 2028360efbdSAlfred Perlstein } 2038360efbdSAlfred Perlstein ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len; 2048360efbdSAlfred Perlstein ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len); 2058360efbdSAlfred Perlstein if (ret->xp_ltaddr.buf == NULL) { 2068360efbdSAlfred Perlstein warnx("svc_fd_create: no mem for local addr"); 2078360efbdSAlfred Perlstein goto freedata; 2088360efbdSAlfred Perlstein } 2098360efbdSAlfred Perlstein memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len); 2108360efbdSAlfred Perlstein 2118360efbdSAlfred Perlstein slen = sizeof (struct sockaddr_storage); 2128360efbdSAlfred Perlstein if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { 2138360efbdSAlfred Perlstein warnx("svc_fd_create: could not retrieve remote addr"); 2148360efbdSAlfred Perlstein goto freedata; 2158360efbdSAlfred Perlstein } 2168360efbdSAlfred Perlstein ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len; 2178360efbdSAlfred Perlstein ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len); 2188360efbdSAlfred Perlstein if (ret->xp_rtaddr.buf == NULL) { 2198360efbdSAlfred Perlstein warnx("svc_fd_create: no mem for local addr"); 2208360efbdSAlfred Perlstein goto freedata; 2218360efbdSAlfred Perlstein } 2228360efbdSAlfred Perlstein memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len); 2238360efbdSAlfred Perlstein #ifdef PORTMAP 2242abd9cf1SAlfred Perlstein if (ss.ss_family == AF_INET || ss.ss_family == AF_LOCAL) { 2258360efbdSAlfred Perlstein ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf; 2268360efbdSAlfred Perlstein ret->xp_addrlen = sizeof (struct sockaddr_in); 2278360efbdSAlfred Perlstein } 2288360efbdSAlfred Perlstein #endif /* PORTMAP */ 2298360efbdSAlfred Perlstein 2308360efbdSAlfred Perlstein return ret; 2318360efbdSAlfred Perlstein 2328360efbdSAlfred Perlstein freedata: 2338360efbdSAlfred Perlstein if (ret->xp_ltaddr.buf != NULL) 2348360efbdSAlfred Perlstein mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen); 2358360efbdSAlfred Perlstein 2368360efbdSAlfred Perlstein return NULL; 2378360efbdSAlfred Perlstein } 2388360efbdSAlfred Perlstein 2398360efbdSAlfred Perlstein static SVCXPRT * 24068895e38SCraig Rodrigues makefd_xprt(int fd, u_int sendsize, u_int recvsize) 2418360efbdSAlfred Perlstein { 2428360efbdSAlfred Perlstein SVCXPRT *xprt; 2438360efbdSAlfred Perlstein struct cf_conn *cd; 2448360efbdSAlfred Perlstein const char *netid; 2458360efbdSAlfred Perlstein struct __rpc_sockinfo si; 2468360efbdSAlfred Perlstein 2478360efbdSAlfred Perlstein assert(fd != -1); 2488360efbdSAlfred Perlstein 2498f55a568SDoug Rabson xprt = svc_xprt_alloc(); 2508360efbdSAlfred Perlstein if (xprt == NULL) { 2518360efbdSAlfred Perlstein warnx("svc_vc: makefd_xprt: out of memory"); 2528360efbdSAlfred Perlstein goto done; 2538360efbdSAlfred Perlstein } 2548360efbdSAlfred Perlstein cd = mem_alloc(sizeof(struct cf_conn)); 2558360efbdSAlfred Perlstein if (cd == NULL) { 2568360efbdSAlfred Perlstein warnx("svc_tcp: makefd_xprt: out of memory"); 2578f55a568SDoug Rabson svc_xprt_free(xprt); 2588360efbdSAlfred Perlstein xprt = NULL; 2598360efbdSAlfred Perlstein goto done; 2608360efbdSAlfred Perlstein } 2618360efbdSAlfred Perlstein cd->strm_stat = XPRT_IDLE; 2628360efbdSAlfred Perlstein xdrrec_create(&(cd->xdrs), sendsize, recvsize, 263f249dbccSDag-Erling Smørgrav xprt, read_vc, write_vc); 264f249dbccSDag-Erling Smørgrav xprt->xp_p1 = cd; 2658360efbdSAlfred Perlstein xprt->xp_verf.oa_base = cd->verf_body; 2668360efbdSAlfred Perlstein svc_vc_ops(xprt); /* truely deals with calls */ 2678360efbdSAlfred Perlstein xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ 2688360efbdSAlfred Perlstein xprt->xp_fd = fd; 2698360efbdSAlfred Perlstein if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid)) 2708360efbdSAlfred Perlstein xprt->xp_netid = strdup(netid); 2718360efbdSAlfred Perlstein 2728360efbdSAlfred Perlstein xprt_register(xprt); 2738360efbdSAlfred Perlstein done: 2748360efbdSAlfred Perlstein return (xprt); 2758360efbdSAlfred Perlstein } 2768360efbdSAlfred Perlstein 2778360efbdSAlfred Perlstein /*ARGSUSED*/ 2788360efbdSAlfred Perlstein static bool_t 27968895e38SCraig Rodrigues rendezvous_request(SVCXPRT *xprt, struct rpc_msg *msg) 2808360efbdSAlfred Perlstein { 28108497c02SMartin Blapp int sock, flags; 2828360efbdSAlfred Perlstein struct cf_rendezvous *r; 28308497c02SMartin Blapp struct cf_conn *cd; 284*5eff94eeSStanislav Sedov struct sockaddr_storage addr, sslocal; 285*5eff94eeSStanislav Sedov socklen_t len, slen; 2868360efbdSAlfred Perlstein struct __rpc_sockinfo si; 28708497c02SMartin Blapp SVCXPRT *newxprt; 28808497c02SMartin Blapp fd_set cleanfds; 2898360efbdSAlfred Perlstein 2908360efbdSAlfred Perlstein assert(xprt != NULL); 2918360efbdSAlfred Perlstein assert(msg != NULL); 2928360efbdSAlfred Perlstein 2938360efbdSAlfred Perlstein r = (struct cf_rendezvous *)xprt->xp_p1; 2948360efbdSAlfred Perlstein again: 2958360efbdSAlfred Perlstein len = sizeof addr; 2968360efbdSAlfred Perlstein if ((sock = _accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr, 2978360efbdSAlfred Perlstein &len)) < 0) { 2988360efbdSAlfred Perlstein if (errno == EINTR) 2998360efbdSAlfred Perlstein goto again; 30008497c02SMartin Blapp /* 30108497c02SMartin Blapp * Clean out the most idle file descriptor when we're 30208497c02SMartin Blapp * running out. 30308497c02SMartin Blapp */ 30408497c02SMartin Blapp if (errno == EMFILE || errno == ENFILE) { 30508497c02SMartin Blapp cleanfds = svc_fdset; 30608497c02SMartin Blapp __svc_clean_idle(&cleanfds, 0, FALSE); 30708497c02SMartin Blapp goto again; 30808497c02SMartin Blapp } 3098360efbdSAlfred Perlstein return (FALSE); 3108360efbdSAlfred Perlstein } 3118360efbdSAlfred Perlstein /* 3128360efbdSAlfred Perlstein * make a new transporter (re-uses xprt) 3138360efbdSAlfred Perlstein */ 31408497c02SMartin Blapp newxprt = makefd_xprt(sock, r->sendsize, r->recvsize); 31508497c02SMartin Blapp newxprt->xp_rtaddr.buf = mem_alloc(len); 31608497c02SMartin Blapp if (newxprt->xp_rtaddr.buf == NULL) 3178360efbdSAlfred Perlstein return (FALSE); 31808497c02SMartin Blapp memcpy(newxprt->xp_rtaddr.buf, &addr, len); 31908497c02SMartin Blapp newxprt->xp_rtaddr.len = len; 3208360efbdSAlfred Perlstein #ifdef PORTMAP 321866e3c90SAlfred Perlstein if (addr.ss_family == AF_INET || addr.ss_family == AF_LOCAL) { 32208497c02SMartin Blapp newxprt->xp_raddr = *(struct sockaddr_in *)newxprt->xp_rtaddr.buf; 32308497c02SMartin Blapp newxprt->xp_addrlen = sizeof (struct sockaddr_in); 3248360efbdSAlfred Perlstein } 3258360efbdSAlfred Perlstein #endif /* PORTMAP */ 3268360efbdSAlfred Perlstein if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) { 3278360efbdSAlfred Perlstein len = 1; 3288360efbdSAlfred Perlstein /* XXX fvdl - is this useful? */ 3298360efbdSAlfred Perlstein _setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &len, sizeof (len)); 3308360efbdSAlfred Perlstein } 33108497c02SMartin Blapp 33208497c02SMartin Blapp cd = (struct cf_conn *)newxprt->xp_p1; 33308497c02SMartin Blapp 33408497c02SMartin Blapp cd->recvsize = r->recvsize; 33508497c02SMartin Blapp cd->sendsize = r->sendsize; 33608497c02SMartin Blapp cd->maxrec = r->maxrec; 33708497c02SMartin Blapp 33808497c02SMartin Blapp if (cd->maxrec != 0) { 3390ae0e1eaSMartin Blapp flags = _fcntl(sock, F_GETFL, 0); 34008497c02SMartin Blapp if (flags == -1) 34108497c02SMartin Blapp return (FALSE); 3420ae0e1eaSMartin Blapp if (_fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) 34308497c02SMartin Blapp return (FALSE); 34408497c02SMartin Blapp if (cd->recvsize > cd->maxrec) 34508497c02SMartin Blapp cd->recvsize = cd->maxrec; 34608497c02SMartin Blapp cd->nonblock = TRUE; 34708497c02SMartin Blapp __xdrrec_setnonblock(&cd->xdrs, cd->maxrec); 34808497c02SMartin Blapp } else 34908497c02SMartin Blapp cd->nonblock = FALSE; 350*5eff94eeSStanislav Sedov slen = sizeof(struct sockaddr_storage); 351*5eff94eeSStanislav Sedov if(_getsockname(sock, (struct sockaddr *)(void *)&sslocal, &slen) < 0) { 352*5eff94eeSStanislav Sedov warnx("svc_vc_create: could not retrieve local addr"); 353*5eff94eeSStanislav Sedov newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = 0; 354*5eff94eeSStanislav Sedov } else { 355*5eff94eeSStanislav Sedov newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = sslocal.ss_len; 356*5eff94eeSStanislav Sedov newxprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len); 357*5eff94eeSStanislav Sedov if (newxprt->xp_ltaddr.buf == NULL) { 358*5eff94eeSStanislav Sedov warnx("svc_vc_create: no mem for local addr"); 359*5eff94eeSStanislav Sedov newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = 0; 360*5eff94eeSStanislav Sedov } else { 361*5eff94eeSStanislav Sedov memcpy(newxprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len); 362*5eff94eeSStanislav Sedov } 363*5eff94eeSStanislav Sedov } 36408497c02SMartin Blapp 36508497c02SMartin Blapp gettimeofday(&cd->last_recv_time, NULL); 36608497c02SMartin Blapp 3678360efbdSAlfred Perlstein return (FALSE); /* there is never an rpc msg to be processed */ 3688360efbdSAlfred Perlstein } 3698360efbdSAlfred Perlstein 3708360efbdSAlfred Perlstein /*ARGSUSED*/ 3718360efbdSAlfred Perlstein static enum xprt_stat 37268895e38SCraig Rodrigues rendezvous_stat(SVCXPRT *xprt) 3738360efbdSAlfred Perlstein { 3748360efbdSAlfred Perlstein 3758360efbdSAlfred Perlstein return (XPRT_IDLE); 3768360efbdSAlfred Perlstein } 3778360efbdSAlfred Perlstein 3788360efbdSAlfred Perlstein static void 37968895e38SCraig Rodrigues svc_vc_destroy(SVCXPRT *xprt) 3808360efbdSAlfred Perlstein { 38108497c02SMartin Blapp assert(xprt != NULL); 38208497c02SMartin Blapp 38308497c02SMartin Blapp xprt_unregister(xprt); 38408497c02SMartin Blapp __svc_vc_dodestroy(xprt); 38508497c02SMartin Blapp } 38608497c02SMartin Blapp 38708497c02SMartin Blapp static void 38868895e38SCraig Rodrigues __svc_vc_dodestroy(SVCXPRT *xprt) 38908497c02SMartin Blapp { 3908360efbdSAlfred Perlstein struct cf_conn *cd; 3918360efbdSAlfred Perlstein struct cf_rendezvous *r; 3928360efbdSAlfred Perlstein 3938360efbdSAlfred Perlstein cd = (struct cf_conn *)xprt->xp_p1; 3948360efbdSAlfred Perlstein 3958360efbdSAlfred Perlstein if (xprt->xp_fd != RPC_ANYFD) 3968360efbdSAlfred Perlstein (void)_close(xprt->xp_fd); 3978360efbdSAlfred Perlstein if (xprt->xp_port != 0) { 3988360efbdSAlfred Perlstein /* a rendezvouser socket */ 3998360efbdSAlfred Perlstein r = (struct cf_rendezvous *)xprt->xp_p1; 4008360efbdSAlfred Perlstein mem_free(r, sizeof (struct cf_rendezvous)); 4018360efbdSAlfred Perlstein xprt->xp_port = 0; 4028360efbdSAlfred Perlstein } else { 4038360efbdSAlfred Perlstein /* an actual connection socket */ 4048360efbdSAlfred Perlstein XDR_DESTROY(&(cd->xdrs)); 4058360efbdSAlfred Perlstein mem_free(cd, sizeof(struct cf_conn)); 4068360efbdSAlfred Perlstein } 4078360efbdSAlfred Perlstein if (xprt->xp_rtaddr.buf) 4088360efbdSAlfred Perlstein mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen); 4098360efbdSAlfred Perlstein if (xprt->xp_ltaddr.buf) 4108360efbdSAlfred Perlstein mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen); 4118360efbdSAlfred Perlstein free(xprt->xp_tp); 4128360efbdSAlfred Perlstein free(xprt->xp_netid); 4138f55a568SDoug Rabson svc_xprt_free(xprt); 4148360efbdSAlfred Perlstein } 4158360efbdSAlfred Perlstein 4168360efbdSAlfred Perlstein /*ARGSUSED*/ 4178360efbdSAlfred Perlstein static bool_t 41868895e38SCraig Rodrigues svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in) 4198360efbdSAlfred Perlstein { 4208360efbdSAlfred Perlstein return (FALSE); 4218360efbdSAlfred Perlstein } 4228360efbdSAlfred Perlstein 42308497c02SMartin Blapp static bool_t 42468895e38SCraig Rodrigues svc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in) 42508497c02SMartin Blapp { 42608497c02SMartin Blapp struct cf_rendezvous *cfp; 42708497c02SMartin Blapp 42808497c02SMartin Blapp cfp = (struct cf_rendezvous *)xprt->xp_p1; 42908497c02SMartin Blapp if (cfp == NULL) 43008497c02SMartin Blapp return (FALSE); 43108497c02SMartin Blapp switch (rq) { 43208497c02SMartin Blapp case SVCGET_CONNMAXREC: 43308497c02SMartin Blapp *(int *)in = cfp->maxrec; 43408497c02SMartin Blapp break; 43508497c02SMartin Blapp case SVCSET_CONNMAXREC: 43608497c02SMartin Blapp cfp->maxrec = *(int *)in; 43708497c02SMartin Blapp break; 43808497c02SMartin Blapp default: 43908497c02SMartin Blapp return (FALSE); 44008497c02SMartin Blapp } 44108497c02SMartin Blapp return (TRUE); 44208497c02SMartin Blapp } 44308497c02SMartin Blapp 4448360efbdSAlfred Perlstein /* 4458360efbdSAlfred Perlstein * reads data from the tcp or uip connection. 4468360efbdSAlfred Perlstein * any error is fatal and the connection is closed. 4478360efbdSAlfred Perlstein * (And a read of zero bytes is a half closed stream => error.) 4488360efbdSAlfred Perlstein * All read operations timeout after 35 seconds. A timeout is 4498360efbdSAlfred Perlstein * fatal for the connection. 4508360efbdSAlfred Perlstein */ 4518360efbdSAlfred Perlstein static int 45268895e38SCraig Rodrigues read_vc(void *xprtp, void *buf, int len) 4538360efbdSAlfred Perlstein { 4548360efbdSAlfred Perlstein SVCXPRT *xprt; 4558360efbdSAlfred Perlstein int sock; 4568360efbdSAlfred Perlstein int milliseconds = 35 * 1000; 4578360efbdSAlfred Perlstein struct pollfd pollfd; 45808497c02SMartin Blapp struct cf_conn *cfp; 4598360efbdSAlfred Perlstein 460f249dbccSDag-Erling Smørgrav xprt = (SVCXPRT *)xprtp; 4618360efbdSAlfred Perlstein assert(xprt != NULL); 4628360efbdSAlfred Perlstein 4638360efbdSAlfred Perlstein sock = xprt->xp_fd; 4648360efbdSAlfred Perlstein 46508497c02SMartin Blapp cfp = (struct cf_conn *)xprt->xp_p1; 46608497c02SMartin Blapp 46708497c02SMartin Blapp if (cfp->nonblock) { 4680ae0e1eaSMartin Blapp len = _read(sock, buf, (size_t)len); 46908497c02SMartin Blapp if (len < 0) { 47008497c02SMartin Blapp if (errno == EAGAIN) 47108497c02SMartin Blapp len = 0; 47208497c02SMartin Blapp else 47308497c02SMartin Blapp goto fatal_err; 47408497c02SMartin Blapp } 47508497c02SMartin Blapp if (len != 0) 47608497c02SMartin Blapp gettimeofday(&cfp->last_recv_time, NULL); 47708497c02SMartin Blapp return len; 47808497c02SMartin Blapp } 47908497c02SMartin Blapp 4808360efbdSAlfred Perlstein do { 4818360efbdSAlfred Perlstein pollfd.fd = sock; 4828360efbdSAlfred Perlstein pollfd.events = POLLIN; 4838360efbdSAlfred Perlstein pollfd.revents = 0; 4848360efbdSAlfred Perlstein switch (_poll(&pollfd, 1, milliseconds)) { 4858360efbdSAlfred Perlstein case -1: 486fa87b7eaSAlfred Perlstein if (errno == EINTR) 4878360efbdSAlfred Perlstein continue; 4888360efbdSAlfred Perlstein /*FALLTHROUGH*/ 4898360efbdSAlfred Perlstein case 0: 4908360efbdSAlfred Perlstein goto fatal_err; 4914ed6d634SAlfred Perlstein 4928360efbdSAlfred Perlstein default: 4938360efbdSAlfred Perlstein break; 4948360efbdSAlfred Perlstein } 4958360efbdSAlfred Perlstein } while ((pollfd.revents & POLLIN) == 0); 4968360efbdSAlfred Perlstein 4970ae0e1eaSMartin Blapp if ((len = _read(sock, buf, (size_t)len)) > 0) { 49808497c02SMartin Blapp gettimeofday(&cfp->last_recv_time, NULL); 4998360efbdSAlfred Perlstein return (len); 5008360efbdSAlfred Perlstein } 5018360efbdSAlfred Perlstein 5028360efbdSAlfred Perlstein fatal_err: 5038360efbdSAlfred Perlstein ((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; 5048360efbdSAlfred Perlstein return (-1); 5058360efbdSAlfred Perlstein } 5068360efbdSAlfred Perlstein 5078360efbdSAlfred Perlstein /* 5088360efbdSAlfred Perlstein * writes data to the tcp connection. 5098360efbdSAlfred Perlstein * Any error is fatal and the connection is closed. 5108360efbdSAlfred Perlstein */ 5118360efbdSAlfred Perlstein static int 51268895e38SCraig Rodrigues write_vc(void *xprtp, void *buf, int len) 5138360efbdSAlfred Perlstein { 5148360efbdSAlfred Perlstein SVCXPRT *xprt; 5158360efbdSAlfred Perlstein int i, cnt; 51608497c02SMartin Blapp struct cf_conn *cd; 51708497c02SMartin Blapp struct timeval tv0, tv1; 5188360efbdSAlfred Perlstein 519f249dbccSDag-Erling Smørgrav xprt = (SVCXPRT *)xprtp; 5208360efbdSAlfred Perlstein assert(xprt != NULL); 5218360efbdSAlfred Perlstein 52208497c02SMartin Blapp cd = (struct cf_conn *)xprt->xp_p1; 52308497c02SMartin Blapp 52408497c02SMartin Blapp if (cd->nonblock) 52508497c02SMartin Blapp gettimeofday(&tv0, NULL); 52608497c02SMartin Blapp 527361de173SStefan Farfeleder for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) { 52808497c02SMartin Blapp i = _write(xprt->xp_fd, buf, (size_t)cnt); 52908497c02SMartin Blapp if (i < 0) { 53008497c02SMartin Blapp if (errno != EAGAIN || !cd->nonblock) { 53108497c02SMartin Blapp cd->strm_stat = XPRT_DIED; 5328360efbdSAlfred Perlstein return (-1); 5338360efbdSAlfred Perlstein } 534e2c83f74SRick Macklem if (cd->nonblock) { 53508497c02SMartin Blapp /* 53608497c02SMartin Blapp * For non-blocking connections, do not 53708497c02SMartin Blapp * take more than 2 seconds writing the 53808497c02SMartin Blapp * data out. 53908497c02SMartin Blapp * 54008497c02SMartin Blapp * XXX 2 is an arbitrary amount. 54108497c02SMartin Blapp */ 54208497c02SMartin Blapp gettimeofday(&tv1, NULL); 54308497c02SMartin Blapp if (tv1.tv_sec - tv0.tv_sec >= 2) { 54408497c02SMartin Blapp cd->strm_stat = XPRT_DIED; 5458360efbdSAlfred Perlstein return (-1); 5468360efbdSAlfred Perlstein } 5478360efbdSAlfred Perlstein } 548e2c83f74SRick Macklem i = 0; 5498360efbdSAlfred Perlstein } 55008497c02SMartin Blapp } 5518360efbdSAlfred Perlstein 5528360efbdSAlfred Perlstein return (len); 5538360efbdSAlfred Perlstein } 5548360efbdSAlfred Perlstein 5558360efbdSAlfred Perlstein static enum xprt_stat 55668895e38SCraig Rodrigues svc_vc_stat(SVCXPRT *xprt) 5578360efbdSAlfred Perlstein { 5588360efbdSAlfred Perlstein struct cf_conn *cd; 5598360efbdSAlfred Perlstein 5608360efbdSAlfred Perlstein assert(xprt != NULL); 5618360efbdSAlfred Perlstein 5628360efbdSAlfred Perlstein cd = (struct cf_conn *)(xprt->xp_p1); 5638360efbdSAlfred Perlstein 5648360efbdSAlfred Perlstein if (cd->strm_stat == XPRT_DIED) 5658360efbdSAlfred Perlstein return (XPRT_DIED); 5668360efbdSAlfred Perlstein if (! xdrrec_eof(&(cd->xdrs))) 5678360efbdSAlfred Perlstein return (XPRT_MOREREQS); 5688360efbdSAlfred Perlstein return (XPRT_IDLE); 5698360efbdSAlfred Perlstein } 5708360efbdSAlfred Perlstein 5718360efbdSAlfred Perlstein static bool_t 57268895e38SCraig Rodrigues svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg) 5738360efbdSAlfred Perlstein { 5748360efbdSAlfred Perlstein struct cf_conn *cd; 5758360efbdSAlfred Perlstein XDR *xdrs; 5768360efbdSAlfred Perlstein 5778360efbdSAlfred Perlstein assert(xprt != NULL); 5788360efbdSAlfred Perlstein assert(msg != NULL); 5798360efbdSAlfred Perlstein 5808360efbdSAlfred Perlstein cd = (struct cf_conn *)(xprt->xp_p1); 5818360efbdSAlfred Perlstein xdrs = &(cd->xdrs); 5828360efbdSAlfred Perlstein 58308497c02SMartin Blapp if (cd->nonblock) { 58408497c02SMartin Blapp if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE)) 58508497c02SMartin Blapp return FALSE; 586ecc03b80SDoug Rabson } else { 587ecc03b80SDoug Rabson (void)xdrrec_skiprecord(xdrs); 58808497c02SMartin Blapp } 58908497c02SMartin Blapp 5908360efbdSAlfred Perlstein xdrs->x_op = XDR_DECODE; 5918360efbdSAlfred Perlstein if (xdr_callmsg(xdrs, msg)) { 5928360efbdSAlfred Perlstein cd->x_id = msg->rm_xid; 5938360efbdSAlfred Perlstein return (TRUE); 5948360efbdSAlfred Perlstein } 5958360efbdSAlfred Perlstein cd->strm_stat = XPRT_DIED; 5968360efbdSAlfred Perlstein return (FALSE); 5978360efbdSAlfred Perlstein } 5988360efbdSAlfred Perlstein 5998360efbdSAlfred Perlstein static bool_t 60068895e38SCraig Rodrigues svc_vc_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr) 6018360efbdSAlfred Perlstein { 6028f55a568SDoug Rabson struct cf_conn *cd; 6038360efbdSAlfred Perlstein 6048360efbdSAlfred Perlstein assert(xprt != NULL); 6058f55a568SDoug Rabson cd = (struct cf_conn *)(xprt->xp_p1); 6068f55a568SDoug Rabson return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt), 6078f55a568SDoug Rabson &cd->xdrs, xdr_args, args_ptr)); 6088360efbdSAlfred Perlstein } 6098360efbdSAlfred Perlstein 6108360efbdSAlfred Perlstein static bool_t 61168895e38SCraig Rodrigues svc_vc_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr) 6128360efbdSAlfred Perlstein { 6138360efbdSAlfred Perlstein XDR *xdrs; 6148360efbdSAlfred Perlstein 6158360efbdSAlfred Perlstein assert(xprt != NULL); 6168360efbdSAlfred Perlstein /* args_ptr may be NULL */ 6178360efbdSAlfred Perlstein 6188360efbdSAlfred Perlstein xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs); 6198360efbdSAlfred Perlstein 6208360efbdSAlfred Perlstein xdrs->x_op = XDR_FREE; 6218360efbdSAlfred Perlstein return ((*xdr_args)(xdrs, args_ptr)); 6228360efbdSAlfred Perlstein } 6238360efbdSAlfred Perlstein 6248360efbdSAlfred Perlstein static bool_t 62568895e38SCraig Rodrigues svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg) 6268360efbdSAlfred Perlstein { 6278360efbdSAlfred Perlstein struct cf_conn *cd; 6288360efbdSAlfred Perlstein XDR *xdrs; 62908497c02SMartin Blapp bool_t rstat; 6308f55a568SDoug Rabson xdrproc_t xdr_proc; 6318f55a568SDoug Rabson caddr_t xdr_where; 6328f55a568SDoug Rabson u_int pos; 6338360efbdSAlfred Perlstein 6348360efbdSAlfred Perlstein assert(xprt != NULL); 6358360efbdSAlfred Perlstein assert(msg != NULL); 6368360efbdSAlfred Perlstein 6378360efbdSAlfred Perlstein cd = (struct cf_conn *)(xprt->xp_p1); 6388360efbdSAlfred Perlstein xdrs = &(cd->xdrs); 6398360efbdSAlfred Perlstein 6408360efbdSAlfred Perlstein xdrs->x_op = XDR_ENCODE; 6418360efbdSAlfred Perlstein msg->rm_xid = cd->x_id; 6428f55a568SDoug Rabson rstat = TRUE; 6438f55a568SDoug Rabson if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 6448f55a568SDoug Rabson msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 6458f55a568SDoug Rabson xdr_proc = msg->acpted_rply.ar_results.proc; 6468f55a568SDoug Rabson xdr_where = msg->acpted_rply.ar_results.where; 6478f55a568SDoug Rabson msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; 6488f55a568SDoug Rabson msg->acpted_rply.ar_results.where = NULL; 6498f55a568SDoug Rabson 6508f55a568SDoug Rabson pos = XDR_GETPOS(xdrs); 6518f55a568SDoug Rabson if (!xdr_replymsg(xdrs, msg) || 6528f55a568SDoug Rabson !SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where)) { 6538f55a568SDoug Rabson XDR_SETPOS(xdrs, pos); 6548f55a568SDoug Rabson rstat = FALSE; 6558f55a568SDoug Rabson } 6568f55a568SDoug Rabson } else { 65708497c02SMartin Blapp rstat = xdr_replymsg(xdrs, msg); 6588f55a568SDoug Rabson } 6598f55a568SDoug Rabson 6608f55a568SDoug Rabson if (rstat) 6618360efbdSAlfred Perlstein (void)xdrrec_endofrecord(xdrs, TRUE); 6628f55a568SDoug Rabson 66308497c02SMartin Blapp return (rstat); 6648360efbdSAlfred Perlstein } 6658360efbdSAlfred Perlstein 6668360efbdSAlfred Perlstein static void 66768895e38SCraig Rodrigues svc_vc_ops(SVCXPRT *xprt) 6688360efbdSAlfred Perlstein { 6698360efbdSAlfred Perlstein static struct xp_ops ops; 6708360efbdSAlfred Perlstein static struct xp_ops2 ops2; 6718360efbdSAlfred Perlstein 6728360efbdSAlfred Perlstein /* VARIABLES PROTECTED BY ops_lock: ops, ops2 */ 6738360efbdSAlfred Perlstein 6748360efbdSAlfred Perlstein mutex_lock(&ops_lock); 6758360efbdSAlfred Perlstein if (ops.xp_recv == NULL) { 6768360efbdSAlfred Perlstein ops.xp_recv = svc_vc_recv; 6778360efbdSAlfred Perlstein ops.xp_stat = svc_vc_stat; 6788360efbdSAlfred Perlstein ops.xp_getargs = svc_vc_getargs; 6798360efbdSAlfred Perlstein ops.xp_reply = svc_vc_reply; 6808360efbdSAlfred Perlstein ops.xp_freeargs = svc_vc_freeargs; 6818360efbdSAlfred Perlstein ops.xp_destroy = svc_vc_destroy; 6828360efbdSAlfred Perlstein ops2.xp_control = svc_vc_control; 6838360efbdSAlfred Perlstein } 6848360efbdSAlfred Perlstein xprt->xp_ops = &ops; 6858360efbdSAlfred Perlstein xprt->xp_ops2 = &ops2; 6868360efbdSAlfred Perlstein mutex_unlock(&ops_lock); 6878360efbdSAlfred Perlstein } 6888360efbdSAlfred Perlstein 6898360efbdSAlfred Perlstein static void 69068895e38SCraig Rodrigues svc_vc_rendezvous_ops(SVCXPRT *xprt) 6918360efbdSAlfred Perlstein { 6928360efbdSAlfred Perlstein static struct xp_ops ops; 6938360efbdSAlfred Perlstein static struct xp_ops2 ops2; 6948360efbdSAlfred Perlstein 6958360efbdSAlfred Perlstein mutex_lock(&ops_lock); 6968360efbdSAlfred Perlstein if (ops.xp_recv == NULL) { 6978360efbdSAlfred Perlstein ops.xp_recv = rendezvous_request; 6988360efbdSAlfred Perlstein ops.xp_stat = rendezvous_stat; 6998360efbdSAlfred Perlstein ops.xp_getargs = 700f249dbccSDag-Erling Smørgrav (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort; 7018360efbdSAlfred Perlstein ops.xp_reply = 7021372519bSDavid E. O'Brien (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort; 7038360efbdSAlfred Perlstein ops.xp_freeargs = 704f249dbccSDag-Erling Smørgrav (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort, 7058360efbdSAlfred Perlstein ops.xp_destroy = svc_vc_destroy; 70608497c02SMartin Blapp ops2.xp_control = svc_vc_rendezvous_control; 7078360efbdSAlfred Perlstein } 7088360efbdSAlfred Perlstein xprt->xp_ops = &ops; 7098360efbdSAlfred Perlstein xprt->xp_ops2 = &ops2; 7108360efbdSAlfred Perlstein mutex_unlock(&ops_lock); 7118360efbdSAlfred Perlstein } 7128360efbdSAlfred Perlstein 7134ed6d634SAlfred Perlstein /* 714ce9bc43cSMartin Blapp * Get the effective UID of the sending process. Used by rpcbind, keyserv 715ce9bc43cSMartin Blapp * and rpc.yppasswdd on AF_LOCAL. 7164ed6d634SAlfred Perlstein */ 7174ed6d634SAlfred Perlstein int 718ce9bc43cSMartin Blapp __rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) { 719ce9bc43cSMartin Blapp int sock, ret; 720ce9bc43cSMartin Blapp gid_t egid; 721ce9bc43cSMartin Blapp uid_t euid; 722ce9bc43cSMartin Blapp struct sockaddr *sa; 72308760d5aSAlfred Perlstein 724ce9bc43cSMartin Blapp sock = transp->xp_fd; 725ce9bc43cSMartin Blapp sa = (struct sockaddr *)transp->xp_rtaddr.buf; 726ce9bc43cSMartin Blapp if (sa->sa_family == AF_LOCAL) { 727ce9bc43cSMartin Blapp ret = getpeereid(sock, &euid, &egid); 728ce9bc43cSMartin Blapp if (ret == 0) 729ce9bc43cSMartin Blapp *uid = euid; 730ce9bc43cSMartin Blapp return (ret); 731ce9bc43cSMartin Blapp } else 73208760d5aSAlfred Perlstein return (-1); 7334ed6d634SAlfred Perlstein } 73408497c02SMartin Blapp 73508497c02SMartin Blapp /* 73608497c02SMartin Blapp * Destroy xprts that have not have had any activity in 'timeout' seconds. 73708497c02SMartin Blapp * If 'cleanblock' is true, blocking connections (the default) are also 73808497c02SMartin Blapp * cleaned. If timeout is 0, the least active connection is picked. 73908497c02SMartin Blapp */ 74008497c02SMartin Blapp bool_t 74108497c02SMartin Blapp __svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock) 74208497c02SMartin Blapp { 74308497c02SMartin Blapp int i, ncleaned; 74408497c02SMartin Blapp SVCXPRT *xprt, *least_active; 74508497c02SMartin Blapp struct timeval tv, tdiff, tmax; 74608497c02SMartin Blapp struct cf_conn *cd; 74708497c02SMartin Blapp 74808497c02SMartin Blapp gettimeofday(&tv, NULL); 74908497c02SMartin Blapp tmax.tv_sec = tmax.tv_usec = 0; 75008497c02SMartin Blapp least_active = NULL; 75108497c02SMartin Blapp rwlock_wrlock(&svc_fd_lock); 75208497c02SMartin Blapp for (i = ncleaned = 0; i <= svc_maxfd; i++) { 75308497c02SMartin Blapp if (FD_ISSET(i, fds)) { 75408497c02SMartin Blapp xprt = __svc_xports[i]; 75508497c02SMartin Blapp if (xprt == NULL || xprt->xp_ops == NULL || 75608497c02SMartin Blapp xprt->xp_ops->xp_recv != svc_vc_recv) 75708497c02SMartin Blapp continue; 75808497c02SMartin Blapp cd = (struct cf_conn *)xprt->xp_p1; 75908497c02SMartin Blapp if (!cleanblock && !cd->nonblock) 76008497c02SMartin Blapp continue; 76108497c02SMartin Blapp if (timeout == 0) { 76208497c02SMartin Blapp timersub(&tv, &cd->last_recv_time, &tdiff); 76308497c02SMartin Blapp if (timercmp(&tdiff, &tmax, >)) { 76408497c02SMartin Blapp tmax = tdiff; 76508497c02SMartin Blapp least_active = xprt; 76608497c02SMartin Blapp } 76708497c02SMartin Blapp continue; 76808497c02SMartin Blapp } 76908497c02SMartin Blapp if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) { 77008497c02SMartin Blapp __xprt_unregister_unlocked(xprt); 77108497c02SMartin Blapp __svc_vc_dodestroy(xprt); 77208497c02SMartin Blapp ncleaned++; 77308497c02SMartin Blapp } 77408497c02SMartin Blapp } 77508497c02SMartin Blapp } 77608497c02SMartin Blapp if (timeout == 0 && least_active != NULL) { 77708497c02SMartin Blapp __xprt_unregister_unlocked(least_active); 77808497c02SMartin Blapp __svc_vc_dodestroy(least_active); 77908497c02SMartin Blapp ncleaned++; 78008497c02SMartin Blapp } 78108497c02SMartin Blapp rwlock_unlock(&svc_fd_lock); 78208497c02SMartin Blapp return ncleaned > 0 ? TRUE : FALSE; 78308497c02SMartin Blapp } 784