1*84d9c625SLionel Sambuc /* $NetBSD: svc_vc.c,v 1.30 2013/03/11 20:19:29 tron Exp $ */
22fe8fb19SBen Gras
32fe8fb19SBen Gras /*
4*84d9c625SLionel Sambuc * Copyright (c) 2010, Oracle America, Inc.
52fe8fb19SBen Gras *
6*84d9c625SLionel Sambuc * Redistribution and use in source and binary forms, with or without
7*84d9c625SLionel Sambuc * modification, are permitted provided that the following conditions are
8*84d9c625SLionel Sambuc * met:
92fe8fb19SBen Gras *
10*84d9c625SLionel Sambuc * * Redistributions of source code must retain the above copyright
11*84d9c625SLionel Sambuc * notice, this list of conditions and the following disclaimer.
12*84d9c625SLionel Sambuc * * Redistributions in binary form must reproduce the above
13*84d9c625SLionel Sambuc * copyright notice, this list of conditions and the following
14*84d9c625SLionel Sambuc * disclaimer in the documentation and/or other materials
15*84d9c625SLionel Sambuc * provided with the distribution.
16*84d9c625SLionel Sambuc * * Neither the name of the "Oracle America, Inc." nor the names of its
17*84d9c625SLionel Sambuc * contributors may be used to endorse or promote products derived
18*84d9c625SLionel Sambuc * from this software without specific prior written permission.
192fe8fb19SBen Gras *
20*84d9c625SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*84d9c625SLionel Sambuc * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*84d9c625SLionel Sambuc * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*84d9c625SLionel Sambuc * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24*84d9c625SLionel Sambuc * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25*84d9c625SLionel Sambuc * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26*84d9c625SLionel Sambuc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27*84d9c625SLionel Sambuc * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28*84d9c625SLionel Sambuc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29*84d9c625SLionel Sambuc * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30*84d9c625SLionel Sambuc * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31*84d9c625SLionel Sambuc * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
322fe8fb19SBen Gras */
332fe8fb19SBen Gras
342fe8fb19SBen Gras #include <sys/cdefs.h>
352fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
362fe8fb19SBen Gras #if 0
372fe8fb19SBen Gras static char *sccsid = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
382fe8fb19SBen Gras static char *sccsid = "@(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC";
392fe8fb19SBen Gras #else
40*84d9c625SLionel Sambuc __RCSID("$NetBSD: svc_vc.c,v 1.30 2013/03/11 20:19:29 tron Exp $");
412fe8fb19SBen Gras #endif
422fe8fb19SBen Gras #endif
432fe8fb19SBen Gras
442fe8fb19SBen Gras /*
452fe8fb19SBen Gras * svc_vc.c, Server side for Connection Oriented based RPC.
462fe8fb19SBen Gras *
472fe8fb19SBen Gras * Actually implements two flavors of transporter -
482fe8fb19SBen Gras * a tcp rendezvouser (a listner and connection establisher)
492fe8fb19SBen Gras * and a record/tcp stream.
502fe8fb19SBen Gras */
512fe8fb19SBen Gras
522fe8fb19SBen Gras #include "namespace.h"
532fe8fb19SBen Gras #include "reentrant.h"
542fe8fb19SBen Gras #include <sys/types.h>
552fe8fb19SBen Gras #include <sys/param.h>
562fe8fb19SBen Gras #include <sys/poll.h>
572fe8fb19SBen Gras #include <sys/socket.h>
582fe8fb19SBen Gras #include <sys/un.h>
592fe8fb19SBen Gras #include <sys/time.h>
602fe8fb19SBen Gras #include <netinet/in.h>
612fe8fb19SBen Gras
622fe8fb19SBen Gras #include <assert.h>
632fe8fb19SBen Gras #include <err.h>
642fe8fb19SBen Gras #include <errno.h>
652fe8fb19SBen Gras #include <fcntl.h>
662fe8fb19SBen Gras #include <stdio.h>
672fe8fb19SBen Gras #include <stdlib.h>
682fe8fb19SBen Gras #include <string.h>
692fe8fb19SBen Gras #include <unistd.h>
702fe8fb19SBen Gras
712fe8fb19SBen Gras #include <rpc/rpc.h>
722fe8fb19SBen Gras
73*84d9c625SLionel Sambuc #include "svc_fdset.h"
742fe8fb19SBen Gras #include "rpc_internal.h"
752fe8fb19SBen Gras
762fe8fb19SBen Gras #ifdef __weak_alias
772fe8fb19SBen Gras __weak_alias(svc_fd_create,_svc_fd_create)
782fe8fb19SBen Gras __weak_alias(svc_vc_create,_svc_vc_create)
792fe8fb19SBen Gras #endif
802fe8fb19SBen Gras
812fe8fb19SBen Gras #ifdef _REENTRANT
822fe8fb19SBen Gras extern rwlock_t svc_fd_lock;
832fe8fb19SBen Gras #endif
842fe8fb19SBen Gras
85f14fb602SLionel Sambuc static SVCXPRT *makefd_xprt(int, u_int, u_int);
86f14fb602SLionel Sambuc static bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *);
87f14fb602SLionel Sambuc static enum xprt_stat rendezvous_stat(SVCXPRT *);
88f14fb602SLionel Sambuc static void svc_vc_destroy(SVCXPRT *);
89f14fb602SLionel Sambuc static void __svc_vc_dodestroy(SVCXPRT *);
90f14fb602SLionel Sambuc static int read_vc(caddr_t, caddr_t, int);
91f14fb602SLionel Sambuc static int write_vc(caddr_t, caddr_t, int);
92f14fb602SLionel Sambuc static enum xprt_stat svc_vc_stat(SVCXPRT *);
93f14fb602SLionel Sambuc static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *);
94f14fb602SLionel Sambuc static bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, caddr_t);
95f14fb602SLionel Sambuc static bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, caddr_t);
96f14fb602SLionel Sambuc static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *);
97f14fb602SLionel Sambuc static void svc_vc_rendezvous_ops(SVCXPRT *);
98f14fb602SLionel Sambuc static void svc_vc_ops(SVCXPRT *);
99f14fb602SLionel Sambuc static bool_t svc_vc_control(SVCXPRT *, const u_int, void *);
100f14fb602SLionel Sambuc static bool_t svc_vc_rendezvous_control(SVCXPRT *, const u_int, void *);
1012fe8fb19SBen Gras
1022fe8fb19SBen Gras struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */
1032fe8fb19SBen Gras u_int sendsize;
1042fe8fb19SBen Gras u_int recvsize;
1052fe8fb19SBen Gras int maxrec;
1062fe8fb19SBen Gras };
1072fe8fb19SBen Gras
1082fe8fb19SBen Gras struct cf_conn { /* kept in xprt->xp_p1 for actual connection */
1092fe8fb19SBen Gras enum xprt_stat strm_stat;
1102fe8fb19SBen Gras u_int32_t x_id;
1112fe8fb19SBen Gras XDR xdrs;
1122fe8fb19SBen Gras char verf_body[MAX_AUTH_BYTES];
1132fe8fb19SBen Gras u_int sendsize;
1142fe8fb19SBen Gras u_int recvsize;
1152fe8fb19SBen Gras int maxrec;
1162fe8fb19SBen Gras bool_t nonblock;
1172fe8fb19SBen Gras struct timeval last_recv_time;
1182fe8fb19SBen Gras };
1192fe8fb19SBen Gras
1202fe8fb19SBen Gras /*
1212fe8fb19SBen Gras * Usage:
1222fe8fb19SBen Gras * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
1232fe8fb19SBen Gras *
1242fe8fb19SBen Gras * Creates, registers, and returns a (rpc) tcp based transporter.
1252fe8fb19SBen Gras * Once *xprt is initialized, it is registered as a transporter
1262fe8fb19SBen Gras * see (svc.h, xprt_register). This routine returns
1272fe8fb19SBen Gras * a NULL if a problem occurred.
1282fe8fb19SBen Gras *
1292fe8fb19SBen Gras * The filedescriptor passed in is expected to refer to a bound, but
1302fe8fb19SBen Gras * not yet connected socket.
1312fe8fb19SBen Gras *
1322fe8fb19SBen Gras * Since streams do buffered io similar to stdio, the caller can specify
1332fe8fb19SBen Gras * how big the send and receive buffers are via the second and third parms;
1342fe8fb19SBen Gras * 0 => use the system default.
1352fe8fb19SBen Gras */
1362fe8fb19SBen Gras SVCXPRT *
svc_vc_create(int fd,u_int sendsize,u_int recvsize)137f14fb602SLionel Sambuc svc_vc_create(int fd, u_int sendsize, u_int recvsize)
1382fe8fb19SBen Gras {
1392fe8fb19SBen Gras SVCXPRT *xprt;
1402fe8fb19SBen Gras struct cf_rendezvous *r = NULL;
1412fe8fb19SBen Gras struct __rpc_sockinfo si;
1422fe8fb19SBen Gras struct sockaddr_storage sslocal;
1432fe8fb19SBen Gras socklen_t slen;
1442fe8fb19SBen Gras int one = 1;
1452fe8fb19SBen Gras
1462fe8fb19SBen Gras if (!__rpc_fd2sockinfo(fd, &si))
1472fe8fb19SBen Gras return NULL;
1482fe8fb19SBen Gras
1492fe8fb19SBen Gras r = mem_alloc(sizeof(*r));
1502fe8fb19SBen Gras if (r == NULL) {
151*84d9c625SLionel Sambuc warn("%s: out of memory", __func__);
1522fe8fb19SBen Gras return NULL;
1532fe8fb19SBen Gras }
1542fe8fb19SBen Gras r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize);
1552fe8fb19SBen Gras r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize);
1562fe8fb19SBen Gras r->maxrec = __svc_maxrec;
1572fe8fb19SBen Gras xprt = mem_alloc(sizeof(SVCXPRT));
1582fe8fb19SBen Gras if (xprt == NULL) {
159*84d9c625SLionel Sambuc warn("%s: out of memory", __func__);
1602fe8fb19SBen Gras goto cleanup_svc_vc_create;
1612fe8fb19SBen Gras }
1622fe8fb19SBen Gras xprt->xp_tp = NULL;
1632fe8fb19SBen Gras xprt->xp_p1 = (caddr_t)(void *)r;
1642fe8fb19SBen Gras xprt->xp_p2 = NULL;
1652fe8fb19SBen Gras xprt->xp_p3 = NULL;
1662fe8fb19SBen Gras xprt->xp_verf = _null_auth;
1672fe8fb19SBen Gras svc_vc_rendezvous_ops(xprt);
1682fe8fb19SBen Gras xprt->xp_port = (u_short)-1; /* It is the rendezvouser */
1692fe8fb19SBen Gras xprt->xp_fd = fd;
1702fe8fb19SBen Gras
1712fe8fb19SBen Gras slen = sizeof (struct sockaddr_storage);
1722fe8fb19SBen Gras if (getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) {
173*84d9c625SLionel Sambuc warn("%s: could not retrieve local addr", __func__);
1742fe8fb19SBen Gras goto cleanup_svc_vc_create;
1752fe8fb19SBen Gras }
1762fe8fb19SBen Gras
1772fe8fb19SBen Gras /*
1782fe8fb19SBen Gras * We want to be able to check credentials on local sockets.
1792fe8fb19SBen Gras */
1802fe8fb19SBen Gras if (sslocal.ss_family == AF_LOCAL)
181f14fb602SLionel Sambuc if (setsockopt(fd, 0, LOCAL_CREDS, &one, (socklen_t)sizeof one)
182f14fb602SLionel Sambuc == -1)
1832fe8fb19SBen Gras goto cleanup_svc_vc_create;
1842fe8fb19SBen Gras
1852fe8fb19SBen Gras xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len;
1862fe8fb19SBen Gras xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len);
1872fe8fb19SBen Gras if (xprt->xp_ltaddr.buf == NULL) {
188*84d9c625SLionel Sambuc warn("%s: out of memory", __func__);
1892fe8fb19SBen Gras goto cleanup_svc_vc_create;
1902fe8fb19SBen Gras }
1912fe8fb19SBen Gras memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len);
1922fe8fb19SBen Gras
1932fe8fb19SBen Gras xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage);
194*84d9c625SLionel Sambuc if (!xprt_register(xprt))
195*84d9c625SLionel Sambuc goto cleanup_svc_vc_create;
196f14fb602SLionel Sambuc return xprt;
1972fe8fb19SBen Gras cleanup_svc_vc_create:
1982fe8fb19SBen Gras if (xprt)
1992fe8fb19SBen Gras mem_free(xprt, sizeof(*xprt));
2002fe8fb19SBen Gras if (r != NULL)
2012fe8fb19SBen Gras mem_free(r, sizeof(*r));
202f14fb602SLionel Sambuc return NULL;
2032fe8fb19SBen Gras }
2042fe8fb19SBen Gras
2052fe8fb19SBen Gras /*
2062fe8fb19SBen Gras * Like svtcp_create(), except the routine takes any *open* UNIX file
2072fe8fb19SBen Gras * descriptor as its first input.
2082fe8fb19SBen Gras */
2092fe8fb19SBen Gras SVCXPRT *
svc_fd_create(int fd,u_int sendsize,u_int recvsize)210f14fb602SLionel Sambuc svc_fd_create(int fd, u_int sendsize, u_int recvsize)
2112fe8fb19SBen Gras {
2122fe8fb19SBen Gras struct sockaddr_storage ss;
2132fe8fb19SBen Gras socklen_t slen;
2142fe8fb19SBen Gras SVCXPRT *ret;
2152fe8fb19SBen Gras
2162fe8fb19SBen Gras _DIAGASSERT(fd != -1);
2172fe8fb19SBen Gras
2182fe8fb19SBen Gras ret = makefd_xprt(fd, sendsize, recvsize);
2192fe8fb19SBen Gras if (ret == NULL)
2202fe8fb19SBen Gras return NULL;
2212fe8fb19SBen Gras
2222fe8fb19SBen Gras slen = sizeof (struct sockaddr_storage);
2232fe8fb19SBen Gras if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
224*84d9c625SLionel Sambuc warn("%s: could not retrieve local addr", __func__);
2252fe8fb19SBen Gras goto freedata;
2262fe8fb19SBen Gras }
2272fe8fb19SBen Gras ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len;
2282fe8fb19SBen Gras ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len);
2292fe8fb19SBen Gras if (ret->xp_ltaddr.buf == NULL) {
230*84d9c625SLionel Sambuc warn("%s: out of memory", __func__);
2312fe8fb19SBen Gras goto freedata;
2322fe8fb19SBen Gras }
2332fe8fb19SBen Gras memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len);
2342fe8fb19SBen Gras
2352fe8fb19SBen Gras slen = sizeof (struct sockaddr_storage);
2362fe8fb19SBen Gras if (getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
237*84d9c625SLionel Sambuc warn("%s: could not retrieve remote addr", __func__);
2382fe8fb19SBen Gras goto freedata;
2392fe8fb19SBen Gras }
2402fe8fb19SBen Gras ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len;
2412fe8fb19SBen Gras ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len);
2422fe8fb19SBen Gras if (ret->xp_rtaddr.buf == NULL) {
243*84d9c625SLionel Sambuc warn("%s: out of memory", __func__);
2442fe8fb19SBen Gras goto freedata;
2452fe8fb19SBen Gras }
2462fe8fb19SBen Gras memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len);
2472fe8fb19SBen Gras #ifdef PORTMAP
2482fe8fb19SBen Gras if (ss.ss_family == AF_INET) {
2492fe8fb19SBen Gras ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf;
2502fe8fb19SBen Gras ret->xp_addrlen = sizeof (struct sockaddr_in);
2512fe8fb19SBen Gras }
2522fe8fb19SBen Gras #endif
2532fe8fb19SBen Gras
2542fe8fb19SBen Gras return ret;
2552fe8fb19SBen Gras
2562fe8fb19SBen Gras freedata:
2572fe8fb19SBen Gras if (ret->xp_ltaddr.buf != NULL)
2582fe8fb19SBen Gras mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen);
2592fe8fb19SBen Gras
2602fe8fb19SBen Gras return NULL;
2612fe8fb19SBen Gras }
2622fe8fb19SBen Gras
2632fe8fb19SBen Gras static SVCXPRT *
makefd_xprt(int fd,u_int sendsize,u_int recvsize)264f14fb602SLionel Sambuc makefd_xprt(int fd, u_int sendsize, u_int recvsize)
2652fe8fb19SBen Gras {
2662fe8fb19SBen Gras SVCXPRT *xprt;
2672fe8fb19SBen Gras struct cf_conn *cd;
2682fe8fb19SBen Gras const char *netid;
2692fe8fb19SBen Gras struct __rpc_sockinfo si;
2702fe8fb19SBen Gras
2712fe8fb19SBen Gras _DIAGASSERT(fd != -1);
2722fe8fb19SBen Gras
2732fe8fb19SBen Gras xprt = mem_alloc(sizeof(SVCXPRT));
2742fe8fb19SBen Gras if (xprt == NULL)
275*84d9c625SLionel Sambuc goto outofmem;
2762fe8fb19SBen Gras memset(xprt, 0, sizeof *xprt);
2772fe8fb19SBen Gras cd = mem_alloc(sizeof(struct cf_conn));
2782fe8fb19SBen Gras if (cd == NULL)
279*84d9c625SLionel Sambuc goto outofmem;
2802fe8fb19SBen Gras cd->strm_stat = XPRT_IDLE;
2812fe8fb19SBen Gras xdrrec_create(&(cd->xdrs), sendsize, recvsize,
2822fe8fb19SBen Gras (caddr_t)(void *)xprt, read_vc, write_vc);
2832fe8fb19SBen Gras xprt->xp_p1 = (caddr_t)(void *)cd;
2842fe8fb19SBen Gras xprt->xp_verf.oa_base = cd->verf_body;
2852fe8fb19SBen Gras svc_vc_ops(xprt); /* truely deals with calls */
2862fe8fb19SBen Gras xprt->xp_port = 0; /* this is a connection, not a rendezvouser */
2872fe8fb19SBen Gras xprt->xp_fd = fd;
2882fe8fb19SBen Gras if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid))
2892fe8fb19SBen Gras if ((xprt->xp_netid = strdup(netid)) == NULL)
290*84d9c625SLionel Sambuc goto outofmem;
2912fe8fb19SBen Gras
292*84d9c625SLionel Sambuc if (!xprt_register(xprt))
293*84d9c625SLionel Sambuc goto out;
294f14fb602SLionel Sambuc return xprt;
295*84d9c625SLionel Sambuc
296*84d9c625SLionel Sambuc outofmem:
2972fe8fb19SBen Gras warn("svc_tcp: makefd_xprt");
298*84d9c625SLionel Sambuc out:
2992fe8fb19SBen Gras if (xprt)
3002fe8fb19SBen Gras mem_free(xprt, sizeof(SVCXPRT));
3012fe8fb19SBen Gras return NULL;
3022fe8fb19SBen Gras }
3032fe8fb19SBen Gras
3042fe8fb19SBen Gras /*ARGSUSED*/
3052fe8fb19SBen Gras static bool_t
rendezvous_request(SVCXPRT * xprt,struct rpc_msg * msg)306f14fb602SLionel Sambuc rendezvous_request(SVCXPRT *xprt, struct rpc_msg *msg)
3072fe8fb19SBen Gras {
3082fe8fb19SBen Gras int sock, flags;
3092fe8fb19SBen Gras struct cf_rendezvous *r;
3102fe8fb19SBen Gras struct cf_conn *cd;
3112fe8fb19SBen Gras struct sockaddr_storage addr;
3122fe8fb19SBen Gras socklen_t len;
3132fe8fb19SBen Gras struct __rpc_sockinfo si;
3142fe8fb19SBen Gras SVCXPRT *newxprt;
3152fe8fb19SBen Gras fd_set cleanfds;
3162fe8fb19SBen Gras
3172fe8fb19SBen Gras _DIAGASSERT(xprt != NULL);
3182fe8fb19SBen Gras _DIAGASSERT(msg != NULL);
3192fe8fb19SBen Gras
3202fe8fb19SBen Gras r = (struct cf_rendezvous *)xprt->xp_p1;
3212fe8fb19SBen Gras again:
3222fe8fb19SBen Gras len = sizeof addr;
3232fe8fb19SBen Gras if ((sock = accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr,
3242fe8fb19SBen Gras &len)) < 0) {
3252fe8fb19SBen Gras if (errno == EINTR)
3262fe8fb19SBen Gras goto again;
3272fe8fb19SBen Gras /*
3282fe8fb19SBen Gras * Clean out the most idle file descriptor when we're
3292fe8fb19SBen Gras * running out.
3302fe8fb19SBen Gras */
3312fe8fb19SBen Gras if (errno == EMFILE || errno == ENFILE) {
332*84d9c625SLionel Sambuc cleanfds = *get_fdset();
3332fe8fb19SBen Gras if (__svc_clean_idle(&cleanfds, 0, FALSE))
3342fe8fb19SBen Gras goto again;
3352fe8fb19SBen Gras }
336f14fb602SLionel Sambuc return FALSE;
3372fe8fb19SBen Gras }
3382fe8fb19SBen Gras /*
3392fe8fb19SBen Gras * make a new transporter (re-uses xprt)
3402fe8fb19SBen Gras */
3412fe8fb19SBen Gras newxprt = makefd_xprt(sock, r->sendsize, r->recvsize);
3422fe8fb19SBen Gras if (newxprt == NULL)
3432fe8fb19SBen Gras goto out;
3442fe8fb19SBen Gras newxprt->xp_rtaddr.buf = mem_alloc(len);
3452fe8fb19SBen Gras if (newxprt->xp_rtaddr.buf == NULL)
3462fe8fb19SBen Gras goto out;
3472fe8fb19SBen Gras memcpy(newxprt->xp_rtaddr.buf, &addr, len);
3482fe8fb19SBen Gras newxprt->xp_rtaddr.len = len;
3492fe8fb19SBen Gras #ifdef PORTMAP
3502fe8fb19SBen Gras if (addr.ss_family == AF_INET) {
3512fe8fb19SBen Gras newxprt->xp_raddr = *(struct sockaddr_in *)newxprt->xp_rtaddr.buf;
3522fe8fb19SBen Gras newxprt->xp_addrlen = sizeof (struct sockaddr_in);
3532fe8fb19SBen Gras }
3542fe8fb19SBen Gras #endif
3552fe8fb19SBen Gras if (__rpc_fd2sockinfo(sock, &si))
3562fe8fb19SBen Gras __rpc_setnodelay(sock, &si);
3572fe8fb19SBen Gras
3582fe8fb19SBen Gras cd = (struct cf_conn *)newxprt->xp_p1;
3592fe8fb19SBen Gras
3602fe8fb19SBen Gras cd->recvsize = r->recvsize;
3612fe8fb19SBen Gras cd->sendsize = r->sendsize;
3622fe8fb19SBen Gras cd->maxrec = r->maxrec;
3632fe8fb19SBen Gras
3642fe8fb19SBen Gras if (cd->maxrec != 0) {
3652fe8fb19SBen Gras flags = fcntl(sock, F_GETFL, 0);
3662fe8fb19SBen Gras if (flags == -1)
3672fe8fb19SBen Gras goto out;
3682fe8fb19SBen Gras if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
3692fe8fb19SBen Gras goto out;
3702fe8fb19SBen Gras if (cd->recvsize > (u_int)cd->maxrec)
3712fe8fb19SBen Gras cd->recvsize = cd->maxrec;
3722fe8fb19SBen Gras cd->nonblock = TRUE;
3732fe8fb19SBen Gras __xdrrec_setnonblock(&cd->xdrs, cd->maxrec);
3742fe8fb19SBen Gras } else
3752fe8fb19SBen Gras cd->nonblock = FALSE;
3762fe8fb19SBen Gras
3772fe8fb19SBen Gras (void)gettimeofday(&cd->last_recv_time, NULL);
3782fe8fb19SBen Gras
379f14fb602SLionel Sambuc return FALSE; /* there is never an rpc msg to be processed */
3802fe8fb19SBen Gras out:
3812fe8fb19SBen Gras (void)close(sock);
382f14fb602SLionel Sambuc return FALSE; /* there was an error */
3832fe8fb19SBen Gras }
3842fe8fb19SBen Gras
3852fe8fb19SBen Gras /*ARGSUSED*/
3862fe8fb19SBen Gras static enum xprt_stat
rendezvous_stat(SVCXPRT * xprt)387f14fb602SLionel Sambuc rendezvous_stat(SVCXPRT *xprt)
3882fe8fb19SBen Gras {
3892fe8fb19SBen Gras
390f14fb602SLionel Sambuc return XPRT_IDLE;
3912fe8fb19SBen Gras }
3922fe8fb19SBen Gras
3932fe8fb19SBen Gras static void
svc_vc_destroy(SVCXPRT * xprt)394f14fb602SLionel Sambuc svc_vc_destroy(SVCXPRT *xprt)
3952fe8fb19SBen Gras {
3962fe8fb19SBen Gras _DIAGASSERT(xprt != NULL);
3972fe8fb19SBen Gras
3982fe8fb19SBen Gras xprt_unregister(xprt);
3992fe8fb19SBen Gras __svc_vc_dodestroy(xprt);
4002fe8fb19SBen Gras }
4012fe8fb19SBen Gras
4022fe8fb19SBen Gras static void
__svc_vc_dodestroy(SVCXPRT * xprt)403f14fb602SLionel Sambuc __svc_vc_dodestroy(SVCXPRT *xprt)
4042fe8fb19SBen Gras {
4052fe8fb19SBen Gras struct cf_conn *cd;
4062fe8fb19SBen Gras struct cf_rendezvous *r;
4072fe8fb19SBen Gras
4082fe8fb19SBen Gras cd = (struct cf_conn *)xprt->xp_p1;
4092fe8fb19SBen Gras
4102fe8fb19SBen Gras if (xprt->xp_fd != RPC_ANYFD)
4112fe8fb19SBen Gras (void)close(xprt->xp_fd);
4122fe8fb19SBen Gras if (xprt->xp_port != 0) {
4132fe8fb19SBen Gras /* a rendezvouser socket */
4142fe8fb19SBen Gras r = (struct cf_rendezvous *)xprt->xp_p1;
4152fe8fb19SBen Gras mem_free(r, sizeof (struct cf_rendezvous));
4162fe8fb19SBen Gras xprt->xp_port = 0;
4172fe8fb19SBen Gras } else {
4182fe8fb19SBen Gras /* an actual connection socket */
4192fe8fb19SBen Gras XDR_DESTROY(&(cd->xdrs));
4202fe8fb19SBen Gras mem_free(cd, sizeof(struct cf_conn));
4212fe8fb19SBen Gras }
4222fe8fb19SBen Gras if (xprt->xp_rtaddr.buf)
4232fe8fb19SBen Gras mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen);
4242fe8fb19SBen Gras if (xprt->xp_ltaddr.buf)
4252fe8fb19SBen Gras mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen);
4262fe8fb19SBen Gras if (xprt->xp_tp)
4272fe8fb19SBen Gras free(xprt->xp_tp);
4282fe8fb19SBen Gras if (xprt->xp_netid)
4292fe8fb19SBen Gras free(xprt->xp_netid);
4302fe8fb19SBen Gras mem_free(xprt, sizeof(SVCXPRT));
4312fe8fb19SBen Gras }
4322fe8fb19SBen Gras
4332fe8fb19SBen Gras /*ARGSUSED*/
4342fe8fb19SBen Gras static bool_t
svc_vc_control(SVCXPRT * xprt,const u_int rq,void * in)435f14fb602SLionel Sambuc svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in)
4362fe8fb19SBen Gras {
437f14fb602SLionel Sambuc return FALSE;
4382fe8fb19SBen Gras }
4392fe8fb19SBen Gras
4402fe8fb19SBen Gras /*ARGSUSED*/
4412fe8fb19SBen Gras static bool_t
svc_vc_rendezvous_control(SVCXPRT * xprt,const u_int rq,void * in)442f14fb602SLionel Sambuc svc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in)
4432fe8fb19SBen Gras {
4442fe8fb19SBen Gras struct cf_rendezvous *cfp;
4452fe8fb19SBen Gras
4462fe8fb19SBen Gras cfp = (struct cf_rendezvous *)xprt->xp_p1;
4472fe8fb19SBen Gras if (cfp == NULL)
448f14fb602SLionel Sambuc return FALSE;
4492fe8fb19SBen Gras switch (rq) {
4502fe8fb19SBen Gras case SVCGET_CONNMAXREC:
4512fe8fb19SBen Gras *(int *)in = cfp->maxrec;
4522fe8fb19SBen Gras break;
4532fe8fb19SBen Gras case SVCSET_CONNMAXREC:
4542fe8fb19SBen Gras cfp->maxrec = *(int *)in;
4552fe8fb19SBen Gras break;
4562fe8fb19SBen Gras default:
457f14fb602SLionel Sambuc return FALSE;
4582fe8fb19SBen Gras }
459f14fb602SLionel Sambuc return TRUE;
4602fe8fb19SBen Gras }
4612fe8fb19SBen Gras
4622fe8fb19SBen Gras /*
4632fe8fb19SBen Gras * reads data from the tcp connection.
4642fe8fb19SBen Gras * any error is fatal and the connection is closed.
4652fe8fb19SBen Gras * (And a read of zero bytes is a half closed stream => error.)
4662fe8fb19SBen Gras * All read operations timeout after 35 seconds. A timeout is
4672fe8fb19SBen Gras * fatal for the connection.
4682fe8fb19SBen Gras */
4692fe8fb19SBen Gras static int
read_vc(caddr_t xprtp,caddr_t buf,int len)470f14fb602SLionel Sambuc read_vc(caddr_t xprtp, caddr_t buf, int len)
4712fe8fb19SBen Gras {
4722fe8fb19SBen Gras SVCXPRT *xprt;
4732fe8fb19SBen Gras int sock;
4742fe8fb19SBen Gras struct pollfd pollfd;
4752fe8fb19SBen Gras struct sockaddr *sa;
4762fe8fb19SBen Gras struct msghdr msg;
4772fe8fb19SBen Gras struct cmsghdr *cmp;
4782fe8fb19SBen Gras void *crmsg = NULL;
4792fe8fb19SBen Gras struct sockcred *sc;
4802fe8fb19SBen Gras socklen_t crmsgsize;
4812fe8fb19SBen Gras struct cf_conn *cfp;
4822fe8fb19SBen Gras static const struct timespec ts = { 35, 0 };
4832fe8fb19SBen Gras
4842fe8fb19SBen Gras xprt = (SVCXPRT *)(void *)xprtp;
4852fe8fb19SBen Gras _DIAGASSERT(xprt != NULL);
4862fe8fb19SBen Gras
4872fe8fb19SBen Gras sock = xprt->xp_fd;
4882fe8fb19SBen Gras
4892fe8fb19SBen Gras sa = (struct sockaddr *)xprt->xp_rtaddr.buf;
4902fe8fb19SBen Gras if (sa->sa_family == AF_LOCAL && xprt->xp_p2 == NULL) {
4912fe8fb19SBen Gras memset(&msg, 0, sizeof msg);
4922fe8fb19SBen Gras crmsgsize = CMSG_SPACE(SOCKCREDSIZE(NGROUPS));
4932fe8fb19SBen Gras crmsg = malloc(crmsgsize);
4942fe8fb19SBen Gras if (crmsg == NULL)
4952fe8fb19SBen Gras goto fatal_err;
4962fe8fb19SBen Gras memset(crmsg, 0, crmsgsize);
4972fe8fb19SBen Gras
4982fe8fb19SBen Gras msg.msg_control = crmsg;
4992fe8fb19SBen Gras msg.msg_controllen = crmsgsize;
5002fe8fb19SBen Gras
5012fe8fb19SBen Gras if (recvmsg(sock, &msg, 0) < 0)
5022fe8fb19SBen Gras goto fatal_err;
5032fe8fb19SBen Gras
5042fe8fb19SBen Gras if (msg.msg_controllen == 0 ||
5052fe8fb19SBen Gras (msg.msg_flags & MSG_CTRUNC) != 0)
5062fe8fb19SBen Gras goto fatal_err;
5072fe8fb19SBen Gras
5082fe8fb19SBen Gras cmp = CMSG_FIRSTHDR(&msg);
5092fe8fb19SBen Gras if (cmp->cmsg_level != SOL_SOCKET ||
5102fe8fb19SBen Gras cmp->cmsg_type != SCM_CREDS)
5112fe8fb19SBen Gras goto fatal_err;
5122fe8fb19SBen Gras
5132fe8fb19SBen Gras sc = (struct sockcred *)(void *)CMSG_DATA(cmp);
5142fe8fb19SBen Gras
5152fe8fb19SBen Gras xprt->xp_p2 = mem_alloc(SOCKCREDSIZE(sc->sc_ngroups));
5162fe8fb19SBen Gras if (xprt->xp_p2 == NULL)
5172fe8fb19SBen Gras goto fatal_err;
5182fe8fb19SBen Gras
5192fe8fb19SBen Gras memcpy(xprt->xp_p2, sc, SOCKCREDSIZE(sc->sc_ngroups));
5202fe8fb19SBen Gras free(crmsg);
5212fe8fb19SBen Gras crmsg = NULL;
5222fe8fb19SBen Gras }
5232fe8fb19SBen Gras
5242fe8fb19SBen Gras cfp = (struct cf_conn *)xprt->xp_p1;
5252fe8fb19SBen Gras
5262fe8fb19SBen Gras if (cfp->nonblock) {
527f14fb602SLionel Sambuc len = (int)read(sock, buf, (size_t)len);
5282fe8fb19SBen Gras if (len < 0) {
5292fe8fb19SBen Gras if (errno == EAGAIN)
5302fe8fb19SBen Gras len = 0;
5312fe8fb19SBen Gras else
5322fe8fb19SBen Gras goto fatal_err;
5332fe8fb19SBen Gras }
5342fe8fb19SBen Gras if (len != 0)
5352fe8fb19SBen Gras gettimeofday(&cfp->last_recv_time, NULL);
5362fe8fb19SBen Gras return len;
5372fe8fb19SBen Gras }
5382fe8fb19SBen Gras
5392fe8fb19SBen Gras do {
5402fe8fb19SBen Gras pollfd.fd = sock;
5412fe8fb19SBen Gras pollfd.events = POLLIN;
5422fe8fb19SBen Gras switch (pollts(&pollfd, 1, &ts, NULL)) {
5432fe8fb19SBen Gras case -1:
5442fe8fb19SBen Gras if (errno == EINTR) {
5452fe8fb19SBen Gras continue;
5462fe8fb19SBen Gras }
5472fe8fb19SBen Gras /*FALLTHROUGH*/
5482fe8fb19SBen Gras case 0:
5492fe8fb19SBen Gras goto fatal_err;
5502fe8fb19SBen Gras
5512fe8fb19SBen Gras default:
5522fe8fb19SBen Gras break;
5532fe8fb19SBen Gras }
5542fe8fb19SBen Gras } while ((pollfd.revents & POLLIN) == 0);
5552fe8fb19SBen Gras
556f14fb602SLionel Sambuc if ((len = (int)read(sock, buf, (size_t)len)) > 0) {
5572fe8fb19SBen Gras gettimeofday(&cfp->last_recv_time, NULL);
558f14fb602SLionel Sambuc return len;
5592fe8fb19SBen Gras }
5602fe8fb19SBen Gras
5612fe8fb19SBen Gras fatal_err:
5622fe8fb19SBen Gras if (crmsg != NULL)
5632fe8fb19SBen Gras free(crmsg);
5642fe8fb19SBen Gras ((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
565f14fb602SLionel Sambuc return -1;
5662fe8fb19SBen Gras }
5672fe8fb19SBen Gras
5682fe8fb19SBen Gras /*
5692fe8fb19SBen Gras * writes data to the tcp connection.
5702fe8fb19SBen Gras * Any error is fatal and the connection is closed.
5712fe8fb19SBen Gras */
5722fe8fb19SBen Gras static int
write_vc(caddr_t xprtp,caddr_t buf,int len)573f14fb602SLionel Sambuc write_vc(caddr_t xprtp, caddr_t buf, int len)
5742fe8fb19SBen Gras {
5752fe8fb19SBen Gras SVCXPRT *xprt;
5762fe8fb19SBen Gras int i, cnt;
5772fe8fb19SBen Gras struct cf_conn *cd;
5782fe8fb19SBen Gras struct timeval tv0, tv1;
5792fe8fb19SBen Gras
5802fe8fb19SBen Gras xprt = (SVCXPRT *)(void *)xprtp;
5812fe8fb19SBen Gras _DIAGASSERT(xprt != NULL);
5822fe8fb19SBen Gras
5832fe8fb19SBen Gras cd = (struct cf_conn *)xprt->xp_p1;
5842fe8fb19SBen Gras
5852fe8fb19SBen Gras if (cd->nonblock)
5862fe8fb19SBen Gras gettimeofday(&tv0, NULL);
5872fe8fb19SBen Gras
5882fe8fb19SBen Gras for (cnt = len; cnt > 0; cnt -= i, buf += i) {
589f14fb602SLionel Sambuc if ((i = (int)write(xprt->xp_fd, buf, (size_t)cnt)) < 0) {
5902fe8fb19SBen Gras if (errno != EAGAIN || !cd->nonblock) {
5912fe8fb19SBen Gras cd->strm_stat = XPRT_DIED;
592f14fb602SLionel Sambuc return -1;
5932fe8fb19SBen Gras }
594f14fb602SLionel Sambuc if (cd->nonblock) {
5952fe8fb19SBen Gras /*
5962fe8fb19SBen Gras * For non-blocking connections, do not
5972fe8fb19SBen Gras * take more than 2 seconds writing the
5982fe8fb19SBen Gras * data out.
5992fe8fb19SBen Gras *
6002fe8fb19SBen Gras * XXX 2 is an arbitrary amount.
6012fe8fb19SBen Gras */
6022fe8fb19SBen Gras gettimeofday(&tv1, NULL);
6032fe8fb19SBen Gras if (tv1.tv_sec - tv0.tv_sec >= 2) {
6042fe8fb19SBen Gras cd->strm_stat = XPRT_DIED;
605f14fb602SLionel Sambuc return -1;
6062fe8fb19SBen Gras }
6072fe8fb19SBen Gras }
608f14fb602SLionel Sambuc i = 0;
6092fe8fb19SBen Gras }
6102fe8fb19SBen Gras }
611f14fb602SLionel Sambuc return len;
6122fe8fb19SBen Gras }
6132fe8fb19SBen Gras
6142fe8fb19SBen Gras static enum xprt_stat
svc_vc_stat(SVCXPRT * xprt)615f14fb602SLionel Sambuc svc_vc_stat(SVCXPRT *xprt)
6162fe8fb19SBen Gras {
6172fe8fb19SBen Gras struct cf_conn *cd;
6182fe8fb19SBen Gras
6192fe8fb19SBen Gras _DIAGASSERT(xprt != NULL);
6202fe8fb19SBen Gras
6212fe8fb19SBen Gras cd = (struct cf_conn *)(xprt->xp_p1);
6222fe8fb19SBen Gras
6232fe8fb19SBen Gras if (cd->strm_stat == XPRT_DIED)
624f14fb602SLionel Sambuc return XPRT_DIED;
6252fe8fb19SBen Gras if (! xdrrec_eof(&(cd->xdrs)))
626f14fb602SLionel Sambuc return XPRT_MOREREQS;
627f14fb602SLionel Sambuc return XPRT_IDLE;
6282fe8fb19SBen Gras }
6292fe8fb19SBen Gras
6302fe8fb19SBen Gras static bool_t
svc_vc_recv(SVCXPRT * xprt,struct rpc_msg * msg)631f14fb602SLionel Sambuc svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg)
6322fe8fb19SBen Gras {
6332fe8fb19SBen Gras struct cf_conn *cd;
6342fe8fb19SBen Gras XDR *xdrs;
6352fe8fb19SBen Gras
6362fe8fb19SBen Gras _DIAGASSERT(xprt != NULL);
6372fe8fb19SBen Gras _DIAGASSERT(msg != NULL);
6382fe8fb19SBen Gras
6392fe8fb19SBen Gras cd = (struct cf_conn *)(xprt->xp_p1);
6402fe8fb19SBen Gras xdrs = &(cd->xdrs);
6412fe8fb19SBen Gras
6422fe8fb19SBen Gras if (cd->nonblock) {
6432fe8fb19SBen Gras if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE))
6442fe8fb19SBen Gras return FALSE;
6452fe8fb19SBen Gras }
6462fe8fb19SBen Gras
6472fe8fb19SBen Gras xdrs->x_op = XDR_DECODE;
6482fe8fb19SBen Gras (void)xdrrec_skiprecord(xdrs);
6492fe8fb19SBen Gras
6502fe8fb19SBen Gras if (xdr_callmsg(xdrs, msg)) {
6512fe8fb19SBen Gras cd->x_id = msg->rm_xid;
652f14fb602SLionel Sambuc return TRUE;
6532fe8fb19SBen Gras }
6542fe8fb19SBen Gras cd->strm_stat = XPRT_DIED;
655f14fb602SLionel Sambuc return FALSE;
6562fe8fb19SBen Gras }
6572fe8fb19SBen Gras
6582fe8fb19SBen Gras static bool_t
svc_vc_getargs(SVCXPRT * xprt,xdrproc_t xdr_args,caddr_t args_ptr)659f14fb602SLionel Sambuc svc_vc_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
6602fe8fb19SBen Gras {
6612fe8fb19SBen Gras
6622fe8fb19SBen Gras _DIAGASSERT(xprt != NULL);
6632fe8fb19SBen Gras /* args_ptr may be NULL */
6642fe8fb19SBen Gras
665f14fb602SLionel Sambuc return (*xdr_args)(&(((struct cf_conn *)(xprt->xp_p1))->xdrs),
666f14fb602SLionel Sambuc args_ptr);
6672fe8fb19SBen Gras }
6682fe8fb19SBen Gras
6692fe8fb19SBen Gras static bool_t
svc_vc_freeargs(SVCXPRT * xprt,xdrproc_t xdr_args,caddr_t args_ptr)670f14fb602SLionel Sambuc svc_vc_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
6712fe8fb19SBen Gras {
6722fe8fb19SBen Gras XDR *xdrs;
6732fe8fb19SBen Gras
6742fe8fb19SBen Gras _DIAGASSERT(xprt != NULL);
6752fe8fb19SBen Gras /* args_ptr may be NULL */
6762fe8fb19SBen Gras
6772fe8fb19SBen Gras xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs);
6782fe8fb19SBen Gras
6792fe8fb19SBen Gras xdrs->x_op = XDR_FREE;
680f14fb602SLionel Sambuc return (*xdr_args)(xdrs, args_ptr);
6812fe8fb19SBen Gras }
6822fe8fb19SBen Gras
6832fe8fb19SBen Gras static bool_t
svc_vc_reply(SVCXPRT * xprt,struct rpc_msg * msg)684f14fb602SLionel Sambuc svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg)
6852fe8fb19SBen Gras {
6862fe8fb19SBen Gras struct cf_conn *cd;
6872fe8fb19SBen Gras XDR *xdrs;
6882fe8fb19SBen Gras bool_t rstat;
6892fe8fb19SBen Gras
6902fe8fb19SBen Gras _DIAGASSERT(xprt != NULL);
6912fe8fb19SBen Gras _DIAGASSERT(msg != NULL);
6922fe8fb19SBen Gras
6932fe8fb19SBen Gras cd = (struct cf_conn *)(xprt->xp_p1);
6942fe8fb19SBen Gras xdrs = &(cd->xdrs);
6952fe8fb19SBen Gras
6962fe8fb19SBen Gras xdrs->x_op = XDR_ENCODE;
6972fe8fb19SBen Gras msg->rm_xid = cd->x_id;
6982fe8fb19SBen Gras rstat = xdr_replymsg(xdrs, msg);
6992fe8fb19SBen Gras (void)xdrrec_endofrecord(xdrs, TRUE);
700f14fb602SLionel Sambuc return rstat;
7012fe8fb19SBen Gras }
7022fe8fb19SBen Gras
7032fe8fb19SBen Gras static void
svc_vc_ops(SVCXPRT * xprt)704f14fb602SLionel Sambuc svc_vc_ops(SVCXPRT *xprt)
7052fe8fb19SBen Gras {
7062fe8fb19SBen Gras static struct xp_ops ops;
7072fe8fb19SBen Gras static struct xp_ops2 ops2;
7082fe8fb19SBen Gras #ifdef _REENTRANT
7092fe8fb19SBen Gras extern mutex_t ops_lock;
7102fe8fb19SBen Gras #endif
7112fe8fb19SBen Gras
7122fe8fb19SBen Gras /* VARIABLES PROTECTED BY ops_lock: ops, ops2 */
7132fe8fb19SBen Gras
7142fe8fb19SBen Gras mutex_lock(&ops_lock);
7152fe8fb19SBen Gras if (ops.xp_recv == NULL) {
7162fe8fb19SBen Gras ops.xp_recv = svc_vc_recv;
7172fe8fb19SBen Gras ops.xp_stat = svc_vc_stat;
7182fe8fb19SBen Gras ops.xp_getargs = svc_vc_getargs;
7192fe8fb19SBen Gras ops.xp_reply = svc_vc_reply;
7202fe8fb19SBen Gras ops.xp_freeargs = svc_vc_freeargs;
7212fe8fb19SBen Gras ops.xp_destroy = svc_vc_destroy;
7222fe8fb19SBen Gras ops2.xp_control = svc_vc_control;
7232fe8fb19SBen Gras }
7242fe8fb19SBen Gras xprt->xp_ops = &ops;
7252fe8fb19SBen Gras xprt->xp_ops2 = &ops2;
7262fe8fb19SBen Gras mutex_unlock(&ops_lock);
7272fe8fb19SBen Gras }
7282fe8fb19SBen Gras
7292fe8fb19SBen Gras static void
svc_vc_rendezvous_ops(SVCXPRT * xprt)730f14fb602SLionel Sambuc svc_vc_rendezvous_ops(SVCXPRT *xprt)
7312fe8fb19SBen Gras {
7322fe8fb19SBen Gras static struct xp_ops ops;
7332fe8fb19SBen Gras static struct xp_ops2 ops2;
7342fe8fb19SBen Gras #ifdef _REENTRANT
7352fe8fb19SBen Gras extern mutex_t ops_lock;
7362fe8fb19SBen Gras #endif
7372fe8fb19SBen Gras mutex_lock(&ops_lock);
7382fe8fb19SBen Gras if (ops.xp_recv == NULL) {
7392fe8fb19SBen Gras ops.xp_recv = rendezvous_request;
7402fe8fb19SBen Gras ops.xp_stat = rendezvous_stat;
7412fe8fb19SBen Gras ops.xp_getargs =
742f14fb602SLionel Sambuc (bool_t (*)(SVCXPRT *, xdrproc_t, caddr_t))abort;
7432fe8fb19SBen Gras ops.xp_reply =
744f14fb602SLionel Sambuc (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort;
7452fe8fb19SBen Gras ops.xp_freeargs =
746f14fb602SLionel Sambuc (bool_t (*)(SVCXPRT *, xdrproc_t, caddr_t))abort;
7472fe8fb19SBen Gras ops.xp_destroy = svc_vc_destroy;
7482fe8fb19SBen Gras ops2.xp_control = svc_vc_rendezvous_control;
7492fe8fb19SBen Gras }
7502fe8fb19SBen Gras xprt->xp_ops = &ops;
7512fe8fb19SBen Gras xprt->xp_ops2 = &ops2;
7522fe8fb19SBen Gras mutex_unlock(&ops_lock);
7532fe8fb19SBen Gras }
7542fe8fb19SBen Gras
7552fe8fb19SBen Gras /*
7562fe8fb19SBen Gras * Destroy xprts that have not have had any activity in 'timeout' seconds.
7572fe8fb19SBen Gras * If 'cleanblock' is true, blocking connections (the default) are also
7582fe8fb19SBen Gras * cleaned. If timeout is 0, the least active connection is picked.
7592fe8fb19SBen Gras */
7602fe8fb19SBen Gras bool_t
__svc_clean_idle(fd_set * fds,int timeout,bool_t cleanblock)7612fe8fb19SBen Gras __svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock)
7622fe8fb19SBen Gras {
7632fe8fb19SBen Gras int i, ncleaned;
7642fe8fb19SBen Gras SVCXPRT *xprt, *least_active;
7652fe8fb19SBen Gras struct timeval tv, tdiff, tmax;
7662fe8fb19SBen Gras struct cf_conn *cd;
7672fe8fb19SBen Gras
7682fe8fb19SBen Gras gettimeofday(&tv, NULL);
7692fe8fb19SBen Gras tmax.tv_sec = tmax.tv_usec = 0;
7702fe8fb19SBen Gras least_active = NULL;
7712fe8fb19SBen Gras rwlock_wrlock(&svc_fd_lock);
7722fe8fb19SBen Gras for (i = ncleaned = 0; i <= svc_maxfd; i++) {
7732fe8fb19SBen Gras if (FD_ISSET(i, fds)) {
7742fe8fb19SBen Gras xprt = __svc_xports[i];
7752fe8fb19SBen Gras if (xprt == NULL || xprt->xp_ops == NULL ||
7762fe8fb19SBen Gras xprt->xp_ops->xp_recv != svc_vc_recv)
7772fe8fb19SBen Gras continue;
7782fe8fb19SBen Gras cd = (struct cf_conn *)xprt->xp_p1;
7792fe8fb19SBen Gras if (!cleanblock && !cd->nonblock)
7802fe8fb19SBen Gras continue;
7812fe8fb19SBen Gras if (timeout == 0) {
7822fe8fb19SBen Gras timersub(&tv, &cd->last_recv_time, &tdiff);
7832fe8fb19SBen Gras if (timercmp(&tdiff, &tmax, >)) {
7842fe8fb19SBen Gras tmax = tdiff;
7852fe8fb19SBen Gras least_active = xprt;
7862fe8fb19SBen Gras }
7872fe8fb19SBen Gras continue;
7882fe8fb19SBen Gras }
7892fe8fb19SBen Gras if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) {
7902fe8fb19SBen Gras __xprt_unregister_unlocked(xprt);
7912fe8fb19SBen Gras __svc_vc_dodestroy(xprt);
7922fe8fb19SBen Gras ncleaned++;
7932fe8fb19SBen Gras }
7942fe8fb19SBen Gras }
7952fe8fb19SBen Gras }
7962fe8fb19SBen Gras if (timeout == 0 && least_active != NULL) {
7972fe8fb19SBen Gras __xprt_unregister_unlocked(least_active);
7982fe8fb19SBen Gras __svc_vc_dodestroy(least_active);
7992fe8fb19SBen Gras ncleaned++;
8002fe8fb19SBen Gras }
8012fe8fb19SBen Gras rwlock_unlock(&svc_fd_lock);
8022fe8fb19SBen Gras return ncleaned > 0 ? TRUE : FALSE;
8032fe8fb19SBen Gras }
804