Home | History | Annotate | Line # | Download | only in rpc
svc_vc.c revision 1.32
      1  1.32  christos /*	$NetBSD: svc_vc.c,v 1.32 2015/11/07 17:34:33 christos Exp $	*/
      2   1.1      fvdl 
      3   1.1      fvdl /*
      4  1.30      tron  * Copyright (c) 2010, Oracle America, Inc.
      5  1.30      tron  *
      6  1.30      tron  * Redistribution and use in source and binary forms, with or without
      7  1.30      tron  * modification, are permitted provided that the following conditions are
      8  1.30      tron  * met:
      9  1.30      tron  *
     10  1.30      tron  *     * Redistributions of source code must retain the above copyright
     11  1.30      tron  *       notice, this list of conditions and the following disclaimer.
     12  1.30      tron  *     * Redistributions in binary form must reproduce the above
     13  1.30      tron  *       copyright notice, this list of conditions and the following
     14  1.30      tron  *       disclaimer in the documentation and/or other materials
     15  1.30      tron  *       provided with the distribution.
     16  1.30      tron  *     * Neither the name of the "Oracle America, Inc." nor the names of its
     17  1.30      tron  *       contributors may be used to endorse or promote products derived
     18  1.30      tron  *       from this software without specific prior written permission.
     19  1.30      tron  *
     20  1.30      tron  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  1.30      tron  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22  1.30      tron  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     23  1.30      tron  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     24  1.30      tron  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     25  1.30      tron  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  1.30      tron  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     27  1.30      tron  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28  1.30      tron  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     29  1.30      tron  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     30  1.30      tron  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     31  1.30      tron  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32   1.1      fvdl  */
     33   1.1      fvdl 
     34   1.1      fvdl #include <sys/cdefs.h>
     35   1.1      fvdl #if defined(LIBC_SCCS) && !defined(lint)
     36   1.1      fvdl #if 0
     37   1.1      fvdl static char *sccsid = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
     38   1.1      fvdl static char *sccsid = "@(#)svc_tcp.c	2.2 88/08/01 4.0 RPCSRC";
     39   1.1      fvdl #else
     40  1.32  christos __RCSID("$NetBSD: svc_vc.c,v 1.32 2015/11/07 17:34:33 christos Exp $");
     41   1.1      fvdl #endif
     42   1.1      fvdl #endif
     43   1.1      fvdl 
     44   1.1      fvdl /*
     45   1.1      fvdl  * svc_vc.c, Server side for Connection Oriented based RPC.
     46   1.1      fvdl  *
     47   1.1      fvdl  * Actually implements two flavors of transporter -
     48   1.1      fvdl  * a tcp rendezvouser (a listner and connection establisher)
     49   1.1      fvdl  * and a record/tcp stream.
     50   1.1      fvdl  */
     51   1.1      fvdl 
     52   1.1      fvdl #include "namespace.h"
     53   1.1      fvdl #include "reentrant.h"
     54   1.1      fvdl #include <sys/types.h>
     55   1.1      fvdl #include <sys/param.h>
     56   1.1      fvdl #include <sys/poll.h>
     57   1.1      fvdl #include <sys/socket.h>
     58   1.1      fvdl #include <sys/un.h>
     59  1.10      fvdl #include <sys/time.h>
     60   1.1      fvdl #include <netinet/in.h>
     61   1.1      fvdl 
     62   1.1      fvdl #include <assert.h>
     63   1.1      fvdl #include <err.h>
     64   1.1      fvdl #include <errno.h>
     65  1.10      fvdl #include <fcntl.h>
     66   1.1      fvdl #include <stdio.h>
     67   1.1      fvdl #include <stdlib.h>
     68   1.1      fvdl #include <string.h>
     69   1.1      fvdl #include <unistd.h>
     70   1.1      fvdl 
     71   1.1      fvdl #include <rpc/rpc.h>
     72   1.1      fvdl 
     73  1.29  christos #include "svc_fdset.h"
     74  1.10      fvdl #include "rpc_internal.h"
     75   1.1      fvdl 
     76   1.1      fvdl #ifdef __weak_alias
     77   1.1      fvdl __weak_alias(svc_fd_create,_svc_fd_create)
     78   1.1      fvdl __weak_alias(svc_vc_create,_svc_vc_create)
     79  1.11     skrll #endif
     80  1.11     skrll 
     81  1.12   thorpej #ifdef _REENTRANT
     82  1.11     skrll extern rwlock_t svc_fd_lock;
     83   1.1      fvdl #endif
     84   1.1      fvdl 
     85  1.23  christos static SVCXPRT *makefd_xprt(int, u_int, u_int);
     86  1.23  christos static bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *);
     87  1.23  christos static enum xprt_stat rendezvous_stat(SVCXPRT *);
     88  1.23  christos static void svc_vc_destroy(SVCXPRT *);
     89  1.23  christos static void __svc_vc_dodestroy(SVCXPRT *);
     90  1.23  christos static int read_vc(caddr_t, caddr_t, int);
     91  1.23  christos static int write_vc(caddr_t, caddr_t, int);
     92  1.23  christos static enum xprt_stat svc_vc_stat(SVCXPRT *);
     93  1.23  christos static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *);
     94  1.23  christos static bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, caddr_t);
     95  1.23  christos static bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, caddr_t);
     96  1.23  christos static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *);
     97  1.23  christos static void svc_vc_rendezvous_ops(SVCXPRT *);
     98  1.23  christos static void svc_vc_ops(SVCXPRT *);
     99  1.23  christos static bool_t svc_vc_control(SVCXPRT *, const u_int, void *);
    100  1.23  christos static bool_t svc_vc_rendezvous_control(SVCXPRT *, const u_int, void *);
    101   1.1      fvdl 
    102   1.1      fvdl struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */
    103   1.1      fvdl 	u_int sendsize;
    104   1.1      fvdl 	u_int recvsize;
    105  1.10      fvdl 	int maxrec;
    106   1.1      fvdl };
    107   1.1      fvdl 
    108   1.1      fvdl struct cf_conn {  /* kept in xprt->xp_p1 for actual connection */
    109   1.1      fvdl 	enum xprt_stat strm_stat;
    110   1.1      fvdl 	u_int32_t x_id;
    111   1.1      fvdl 	XDR xdrs;
    112   1.1      fvdl 	char verf_body[MAX_AUTH_BYTES];
    113  1.10      fvdl 	u_int sendsize;
    114  1.10      fvdl 	u_int recvsize;
    115  1.10      fvdl 	int maxrec;
    116  1.10      fvdl 	bool_t nonblock;
    117  1.10      fvdl 	struct timeval last_recv_time;
    118   1.1      fvdl };
    119   1.1      fvdl 
    120   1.1      fvdl /*
    121   1.1      fvdl  * Usage:
    122   1.1      fvdl  *	xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
    123   1.1      fvdl  *
    124   1.1      fvdl  * Creates, registers, and returns a (rpc) tcp based transporter.
    125   1.1      fvdl  * Once *xprt is initialized, it is registered as a transporter
    126   1.1      fvdl  * see (svc.h, xprt_register).  This routine returns
    127   1.1      fvdl  * a NULL if a problem occurred.
    128   1.1      fvdl  *
    129   1.1      fvdl  * The filedescriptor passed in is expected to refer to a bound, but
    130   1.1      fvdl  * not yet connected socket.
    131   1.1      fvdl  *
    132   1.1      fvdl  * Since streams do buffered io similar to stdio, the caller can specify
    133   1.1      fvdl  * how big the send and receive buffers are via the second and third parms;
    134   1.1      fvdl  * 0 => use the system default.
    135   1.1      fvdl  */
    136   1.1      fvdl SVCXPRT *
    137  1.23  christos svc_vc_create(int fd, u_int sendsize, u_int recvsize)
    138   1.1      fvdl {
    139   1.1      fvdl 	SVCXPRT *xprt;
    140   1.1      fvdl 	struct cf_rendezvous *r = NULL;
    141   1.1      fvdl 	struct __rpc_sockinfo si;
    142   1.1      fvdl 	struct sockaddr_storage sslocal;
    143   1.1      fvdl 	socklen_t slen;
    144   1.3   thorpej 	int one = 1;
    145   1.1      fvdl 
    146  1.17  christos 	if (!__rpc_fd2sockinfo(fd, &si))
    147  1.17  christos 		return NULL;
    148  1.17  christos 
    149   1.5  christos 	r = mem_alloc(sizeof(*r));
    150   1.1      fvdl 	if (r == NULL) {
    151  1.27  christos 		warn("%s: out of memory", __func__);
    152  1.18  drochner 		return NULL;
    153   1.1      fvdl 	}
    154   1.5  christos 	r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize);
    155   1.5  christos 	r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize);
    156  1.10      fvdl 	r->maxrec = __svc_maxrec;
    157   1.5  christos 	xprt = mem_alloc(sizeof(SVCXPRT));
    158   1.1      fvdl 	if (xprt == NULL) {
    159  1.27  christos 		warn("%s: out of memory", __func__);
    160   1.1      fvdl 		goto cleanup_svc_vc_create;
    161   1.1      fvdl 	}
    162   1.1      fvdl 	xprt->xp_tp = NULL;
    163   1.1      fvdl 	xprt->xp_p1 = (caddr_t)(void *)r;
    164   1.1      fvdl 	xprt->xp_p2 = NULL;
    165   1.1      fvdl 	xprt->xp_p3 = NULL;
    166   1.1      fvdl 	xprt->xp_verf = _null_auth;
    167   1.6    kleink 	svc_vc_rendezvous_ops(xprt);
    168   1.5  christos 	xprt->xp_port = (u_short)-1;	/* It is the rendezvouser */
    169   1.1      fvdl 	xprt->xp_fd = fd;
    170   1.1      fvdl 
    171   1.1      fvdl 	slen = sizeof (struct sockaddr_storage);
    172   1.5  christos 	if (getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) {
    173  1.27  christos 		warn("%s: could not retrieve local addr", __func__);
    174   1.1      fvdl 		goto cleanup_svc_vc_create;
    175   1.1      fvdl 	}
    176   1.1      fvdl 
    177   1.1      fvdl 	/*
    178   1.1      fvdl 	 * We want to be able to check credentials on local sockets.
    179   1.1      fvdl 	 */
    180   1.1      fvdl 	if (sslocal.ss_family == AF_LOCAL)
    181  1.25  christos 		if (setsockopt(fd, 0, LOCAL_CREDS, &one, (socklen_t)sizeof one)
    182  1.25  christos 		    == -1)
    183   1.1      fvdl 			goto cleanup_svc_vc_create;
    184   1.1      fvdl 
    185   1.1      fvdl 	xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len;
    186   1.5  christos 	xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len);
    187   1.1      fvdl 	if (xprt->xp_ltaddr.buf == NULL) {
    188  1.27  christos 		warn("%s: out of memory", __func__);
    189   1.1      fvdl 		goto cleanup_svc_vc_create;
    190   1.1      fvdl 	}
    191   1.5  christos 	memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len);
    192   1.1      fvdl 
    193   1.1      fvdl 	xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage);
    194  1.28  christos 	if (!xprt_register(xprt))
    195  1.28  christos 		goto cleanup_svc_vc_create;
    196  1.23  christos 	return xprt;
    197   1.1      fvdl cleanup_svc_vc_create:
    198  1.16  christos 	if (xprt)
    199  1.16  christos 		mem_free(xprt, sizeof(*xprt));
    200   1.1      fvdl 	if (r != NULL)
    201   1.1      fvdl 		mem_free(r, sizeof(*r));
    202  1.23  christos 	return NULL;
    203   1.1      fvdl }
    204   1.1      fvdl 
    205   1.1      fvdl /*
    206   1.1      fvdl  * Like svtcp_create(), except the routine takes any *open* UNIX file
    207   1.1      fvdl  * descriptor as its first input.
    208   1.1      fvdl  */
    209   1.1      fvdl SVCXPRT *
    210  1.23  christos svc_fd_create(int fd, u_int sendsize, u_int recvsize)
    211   1.1      fvdl {
    212   1.1      fvdl 	struct sockaddr_storage ss;
    213   1.1      fvdl 	socklen_t slen;
    214   1.1      fvdl 	SVCXPRT *ret;
    215   1.1      fvdl 
    216   1.1      fvdl 	_DIAGASSERT(fd != -1);
    217   1.1      fvdl 
    218   1.1      fvdl 	ret = makefd_xprt(fd, sendsize, recvsize);
    219   1.1      fvdl 	if (ret == NULL)
    220   1.1      fvdl 		return NULL;
    221   1.1      fvdl 
    222   1.1      fvdl 	slen = sizeof (struct sockaddr_storage);
    223   1.5  christos 	if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
    224  1.27  christos 		warn("%s: could not retrieve local addr", __func__);
    225   1.1      fvdl 		goto freedata;
    226   1.1      fvdl 	}
    227   1.1      fvdl 	ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len;
    228   1.5  christos 	ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len);
    229   1.1      fvdl 	if (ret->xp_ltaddr.buf == NULL) {
    230  1.27  christos 		warn("%s: out of memory", __func__);
    231   1.1      fvdl 		goto freedata;
    232   1.1      fvdl 	}
    233   1.5  christos 	memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len);
    234   1.1      fvdl 
    235   1.1      fvdl 	slen = sizeof (struct sockaddr_storage);
    236   1.5  christos 	if (getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
    237  1.27  christos 		warn("%s: could not retrieve remote addr", __func__);
    238   1.1      fvdl 		goto freedata;
    239   1.1      fvdl 	}
    240   1.1      fvdl 	ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len;
    241   1.5  christos 	ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len);
    242   1.1      fvdl 	if (ret->xp_rtaddr.buf == NULL) {
    243  1.27  christos 		warn("%s: out of memory", __func__);
    244   1.1      fvdl 		goto freedata;
    245   1.1      fvdl 	}
    246   1.5  christos 	memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len);
    247   1.1      fvdl #ifdef PORTMAP
    248   1.1      fvdl 	if (ss.ss_family == AF_INET) {
    249   1.1      fvdl 		ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf;
    250   1.1      fvdl 		ret->xp_addrlen = sizeof (struct sockaddr_in);
    251   1.1      fvdl 	}
    252   1.1      fvdl #endif
    253   1.1      fvdl 
    254   1.1      fvdl 	return ret;
    255   1.1      fvdl 
    256   1.1      fvdl freedata:
    257   1.1      fvdl 	if (ret->xp_ltaddr.buf != NULL)
    258   1.1      fvdl 		mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen);
    259   1.1      fvdl 
    260   1.1      fvdl 	return NULL;
    261   1.1      fvdl }
    262   1.1      fvdl 
    263   1.1      fvdl static SVCXPRT *
    264  1.23  christos makefd_xprt(int fd, u_int sendsize, u_int recvsize)
    265   1.1      fvdl {
    266   1.1      fvdl 	SVCXPRT *xprt;
    267   1.1      fvdl 	struct cf_conn *cd;
    268   1.7      fvdl 	const char *netid;
    269   1.7      fvdl 	struct __rpc_sockinfo si;
    270   1.1      fvdl 
    271   1.1      fvdl 	_DIAGASSERT(fd != -1);
    272   1.1      fvdl 
    273   1.5  christos 	xprt = mem_alloc(sizeof(SVCXPRT));
    274  1.21  christos 	if (xprt == NULL)
    275  1.28  christos 		goto outofmem;
    276   1.2      fvdl 	memset(xprt, 0, sizeof *xprt);
    277   1.5  christos 	cd = mem_alloc(sizeof(struct cf_conn));
    278  1.21  christos 	if (cd == NULL)
    279  1.28  christos 		goto outofmem;
    280   1.1      fvdl 	cd->strm_stat = XPRT_IDLE;
    281   1.1      fvdl 	xdrrec_create(&(cd->xdrs), sendsize, recvsize,
    282   1.1      fvdl 	    (caddr_t)(void *)xprt, read_vc, write_vc);
    283   1.1      fvdl 	xprt->xp_p1 = (caddr_t)(void *)cd;
    284   1.1      fvdl 	xprt->xp_verf.oa_base = cd->verf_body;
    285   1.1      fvdl 	svc_vc_ops(xprt);  /* truely deals with calls */
    286   1.1      fvdl 	xprt->xp_port = 0;  /* this is a connection, not a rendezvouser */
    287   1.1      fvdl 	xprt->xp_fd = fd;
    288   1.8     lukem 	if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid))
    289  1.21  christos 		if ((xprt->xp_netid = strdup(netid)) == NULL)
    290  1.28  christos 			goto outofmem;
    291   1.7      fvdl 
    292  1.28  christos 	if (!xprt_register(xprt))
    293  1.28  christos 		goto out;
    294  1.23  christos 	return xprt;
    295  1.28  christos 
    296  1.28  christos outofmem:
    297  1.28  christos 	warn("svc_tcp: makefd_xprt");
    298  1.21  christos out:
    299  1.21  christos 	if (xprt)
    300  1.21  christos 		mem_free(xprt, sizeof(SVCXPRT));
    301  1.21  christos 	return NULL;
    302   1.1      fvdl }
    303   1.1      fvdl 
    304   1.1      fvdl /*ARGSUSED*/
    305   1.1      fvdl static bool_t
    306  1.23  christos rendezvous_request(SVCXPRT *xprt, struct rpc_msg *msg)
    307   1.1      fvdl {
    308  1.10      fvdl 	int sock, flags;
    309   1.1      fvdl 	struct cf_rendezvous *r;
    310  1.10      fvdl 	struct cf_conn *cd;
    311   1.1      fvdl 	struct sockaddr_storage addr;
    312   1.1      fvdl 	socklen_t len;
    313   1.1      fvdl 	struct __rpc_sockinfo si;
    314  1.10      fvdl 	SVCXPRT *newxprt;
    315   1.1      fvdl 
    316   1.1      fvdl 	_DIAGASSERT(xprt != NULL);
    317   1.1      fvdl 	_DIAGASSERT(msg != NULL);
    318   1.1      fvdl 
    319   1.1      fvdl 	r = (struct cf_rendezvous *)xprt->xp_p1;
    320   1.1      fvdl again:
    321   1.1      fvdl 	len = sizeof addr;
    322   1.5  christos 	if ((sock = accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr,
    323   1.5  christos 	    &len)) < 0) {
    324   1.1      fvdl 		if (errno == EINTR)
    325   1.1      fvdl 			goto again;
    326  1.10      fvdl 		/*
    327  1.10      fvdl 		 * Clean out the most idle file descriptor when we're
    328  1.10      fvdl 		 * running out.
    329  1.10      fvdl 		 */
    330  1.10      fvdl 		if (errno == EMFILE || errno == ENFILE) {
    331  1.31  christos 			fd_set *cleanfds = svc_fdset_copy(svc_fdset_get());
    332  1.32  christos 			int rv = 0;
    333  1.32  christos 			if (cleanfds)
    334  1.32  christos 				rv = __svc_clean_idle(cleanfds, 0, FALSE);
    335  1.31  christos 			free(cleanfds);
    336  1.31  christos 			if (rv)
    337  1.20  christos 				goto again;
    338  1.10      fvdl 		}
    339  1.23  christos 		return FALSE;
    340   1.1      fvdl 	}
    341   1.1      fvdl 	/*
    342   1.1      fvdl 	 * make a new transporter (re-uses xprt)
    343   1.1      fvdl 	 */
    344  1.10      fvdl 	newxprt = makefd_xprt(sock, r->sendsize, r->recvsize);
    345  1.21  christos 	if (newxprt == NULL)
    346  1.21  christos 		goto out;
    347  1.10      fvdl 	newxprt->xp_rtaddr.buf = mem_alloc(len);
    348  1.10      fvdl 	if (newxprt->xp_rtaddr.buf == NULL)
    349  1.21  christos 		goto out;
    350  1.10      fvdl 	memcpy(newxprt->xp_rtaddr.buf, &addr, len);
    351  1.10      fvdl 	newxprt->xp_rtaddr.len = len;
    352   1.1      fvdl #ifdef PORTMAP
    353   1.1      fvdl 	if (addr.ss_family == AF_INET) {
    354  1.10      fvdl 		newxprt->xp_raddr = *(struct sockaddr_in *)newxprt->xp_rtaddr.buf;
    355  1.10      fvdl 		newxprt->xp_addrlen = sizeof (struct sockaddr_in);
    356   1.1      fvdl 	}
    357   1.1      fvdl #endif
    358  1.19  christos 	if (__rpc_fd2sockinfo(sock, &si))
    359  1.19  christos 		__rpc_setnodelay(sock, &si);
    360  1.10      fvdl 
    361  1.10      fvdl 	cd = (struct cf_conn *)newxprt->xp_p1;
    362  1.10      fvdl 
    363  1.10      fvdl 	cd->recvsize = r->recvsize;
    364  1.10      fvdl 	cd->sendsize = r->sendsize;
    365  1.10      fvdl 	cd->maxrec = r->maxrec;
    366  1.10      fvdl 
    367  1.10      fvdl 	if (cd->maxrec != 0) {
    368  1.10      fvdl 		flags = fcntl(sock, F_GETFL, 0);
    369  1.10      fvdl 		if (flags  == -1)
    370  1.21  christos 			goto out;
    371  1.10      fvdl 		if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
    372  1.21  christos 			goto out;
    373  1.22     lukem 		if (cd->recvsize > (u_int)cd->maxrec)
    374  1.10      fvdl 			cd->recvsize = cd->maxrec;
    375  1.10      fvdl 		cd->nonblock = TRUE;
    376  1.10      fvdl 		__xdrrec_setnonblock(&cd->xdrs, cd->maxrec);
    377  1.10      fvdl 	} else
    378  1.10      fvdl 		cd->nonblock = FALSE;
    379  1.10      fvdl 
    380  1.21  christos 	(void)gettimeofday(&cd->last_recv_time, NULL);
    381  1.10      fvdl 
    382  1.23  christos 	return FALSE; /* there is never an rpc msg to be processed */
    383  1.21  christos out:
    384  1.21  christos 	(void)close(sock);
    385  1.23  christos 	return FALSE; /* there was an error */
    386   1.1      fvdl }
    387   1.1      fvdl 
    388   1.1      fvdl /*ARGSUSED*/
    389   1.1      fvdl static enum xprt_stat
    390  1.23  christos rendezvous_stat(SVCXPRT *xprt)
    391   1.1      fvdl {
    392   1.1      fvdl 
    393  1.23  christos 	return XPRT_IDLE;
    394   1.1      fvdl }
    395   1.1      fvdl 
    396   1.1      fvdl static void
    397  1.23  christos svc_vc_destroy(SVCXPRT *xprt)
    398   1.1      fvdl {
    399  1.10      fvdl 	_DIAGASSERT(xprt != NULL);
    400  1.10      fvdl 
    401  1.10      fvdl 	xprt_unregister(xprt);
    402  1.10      fvdl 	__svc_vc_dodestroy(xprt);
    403  1.10      fvdl }
    404  1.10      fvdl 
    405  1.10      fvdl static void
    406  1.23  christos __svc_vc_dodestroy(SVCXPRT *xprt)
    407  1.10      fvdl {
    408   1.1      fvdl 	struct cf_conn *cd;
    409   1.1      fvdl 	struct cf_rendezvous *r;
    410   1.1      fvdl 
    411   1.1      fvdl 	cd = (struct cf_conn *)xprt->xp_p1;
    412   1.1      fvdl 
    413   1.1      fvdl 	if (xprt->xp_fd != RPC_ANYFD)
    414   1.1      fvdl 		(void)close(xprt->xp_fd);
    415   1.1      fvdl 	if (xprt->xp_port != 0) {
    416   1.1      fvdl 		/* a rendezvouser socket */
    417   1.1      fvdl 		r = (struct cf_rendezvous *)xprt->xp_p1;
    418   1.1      fvdl 		mem_free(r, sizeof (struct cf_rendezvous));
    419   1.1      fvdl 		xprt->xp_port = 0;
    420   1.1      fvdl 	} else {
    421   1.1      fvdl 		/* an actual connection socket */
    422   1.1      fvdl 		XDR_DESTROY(&(cd->xdrs));
    423   1.1      fvdl 		mem_free(cd, sizeof(struct cf_conn));
    424   1.1      fvdl 	}
    425   1.1      fvdl 	if (xprt->xp_rtaddr.buf)
    426   1.1      fvdl 		mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen);
    427   1.1      fvdl 	if (xprt->xp_ltaddr.buf)
    428   1.1      fvdl 		mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen);
    429   1.1      fvdl 	if (xprt->xp_tp)
    430   1.1      fvdl 		free(xprt->xp_tp);
    431   1.1      fvdl 	if (xprt->xp_netid)
    432   1.1      fvdl 		free(xprt->xp_netid);
    433   1.1      fvdl 	mem_free(xprt, sizeof(SVCXPRT));
    434   1.1      fvdl }
    435   1.1      fvdl 
    436   1.5  christos /*ARGSUSED*/
    437   1.1      fvdl static bool_t
    438  1.23  christos svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in)
    439   1.1      fvdl {
    440  1.23  christos 	return FALSE;
    441   1.1      fvdl }
    442   1.1      fvdl 
    443  1.10      fvdl /*ARGSUSED*/
    444  1.10      fvdl static bool_t
    445  1.23  christos svc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in)
    446  1.10      fvdl {
    447  1.10      fvdl 	struct cf_rendezvous *cfp;
    448  1.10      fvdl 
    449  1.10      fvdl 	cfp = (struct cf_rendezvous *)xprt->xp_p1;
    450  1.10      fvdl 	if (cfp == NULL)
    451  1.23  christos 		return FALSE;
    452  1.10      fvdl 	switch (rq) {
    453  1.10      fvdl 		case SVCGET_CONNMAXREC:
    454  1.10      fvdl 			*(int *)in = cfp->maxrec;
    455  1.10      fvdl 			break;
    456  1.10      fvdl 		case SVCSET_CONNMAXREC:
    457  1.10      fvdl 			cfp->maxrec = *(int *)in;
    458  1.10      fvdl 			break;
    459  1.10      fvdl 		default:
    460  1.23  christos 			return FALSE;
    461  1.10      fvdl 	}
    462  1.23  christos 	return TRUE;
    463  1.10      fvdl }
    464  1.10      fvdl 
    465   1.1      fvdl /*
    466   1.9      cjep  * reads data from the tcp connection.
    467   1.1      fvdl  * any error is fatal and the connection is closed.
    468   1.1      fvdl  * (And a read of zero bytes is a half closed stream => error.)
    469   1.1      fvdl  * All read operations timeout after 35 seconds.  A timeout is
    470   1.1      fvdl  * fatal for the connection.
    471   1.1      fvdl  */
    472   1.1      fvdl static int
    473  1.23  christos read_vc(caddr_t xprtp, caddr_t buf, int len)
    474   1.1      fvdl {
    475   1.1      fvdl 	SVCXPRT *xprt;
    476   1.1      fvdl 	int sock;
    477   1.1      fvdl 	struct pollfd pollfd;
    478   1.1      fvdl 	struct sockaddr *sa;
    479   1.1      fvdl 	struct msghdr msg;
    480   1.1      fvdl 	struct cmsghdr *cmp;
    481   1.3   thorpej 	void *crmsg = NULL;
    482   1.1      fvdl 	struct sockcred *sc;
    483   1.3   thorpej 	socklen_t crmsgsize;
    484  1.10      fvdl 	struct cf_conn *cfp;
    485  1.13  christos 	static const struct timespec ts = { 35, 0 };
    486   1.1      fvdl 
    487   1.1      fvdl 	xprt = (SVCXPRT *)(void *)xprtp;
    488   1.1      fvdl 	_DIAGASSERT(xprt != NULL);
    489   1.1      fvdl 
    490   1.1      fvdl 	sock = xprt->xp_fd;
    491   1.1      fvdl 
    492   1.1      fvdl 	sa = (struct sockaddr *)xprt->xp_rtaddr.buf;
    493   1.1      fvdl 	if (sa->sa_family == AF_LOCAL && xprt->xp_p2 == NULL) {
    494   1.1      fvdl 		memset(&msg, 0, sizeof msg);
    495   1.3   thorpej 		crmsgsize = CMSG_SPACE(SOCKCREDSIZE(NGROUPS));
    496   1.3   thorpej 		crmsg = malloc(crmsgsize);
    497   1.3   thorpej 		if (crmsg == NULL)
    498   1.3   thorpej 			goto fatal_err;
    499   1.3   thorpej 		memset(crmsg, 0, crmsgsize);
    500   1.3   thorpej 
    501   1.3   thorpej 		msg.msg_control = crmsg;
    502   1.3   thorpej 		msg.msg_controllen = crmsgsize;
    503   1.1      fvdl 
    504   1.1      fvdl 		if (recvmsg(sock, &msg, 0) < 0)
    505   1.1      fvdl 			goto fatal_err;
    506   1.1      fvdl 
    507   1.3   thorpej 		if (msg.msg_controllen == 0 ||
    508   1.3   thorpej 		    (msg.msg_flags & MSG_CTRUNC) != 0)
    509   1.3   thorpej 			goto fatal_err;
    510   1.3   thorpej 
    511   1.1      fvdl 		cmp = CMSG_FIRSTHDR(&msg);
    512   1.1      fvdl 		if (cmp->cmsg_level != SOL_SOCKET ||
    513   1.1      fvdl 		    cmp->cmsg_type != SCM_CREDS)
    514   1.1      fvdl 			goto fatal_err;
    515   1.1      fvdl 
    516   1.5  christos 		sc = (struct sockcred *)(void *)CMSG_DATA(cmp);
    517   1.1      fvdl 
    518   1.1      fvdl 		xprt->xp_p2 = mem_alloc(SOCKCREDSIZE(sc->sc_ngroups));
    519   1.1      fvdl 		if (xprt->xp_p2 == NULL)
    520   1.1      fvdl 			goto fatal_err;
    521   1.1      fvdl 
    522   1.1      fvdl 		memcpy(xprt->xp_p2, sc, SOCKCREDSIZE(sc->sc_ngroups));
    523   1.3   thorpej 		free(crmsg);
    524   1.3   thorpej 		crmsg = NULL;
    525   1.1      fvdl 	}
    526  1.10      fvdl 
    527  1.10      fvdl 	cfp = (struct cf_conn *)xprt->xp_p1;
    528  1.10      fvdl 
    529  1.10      fvdl 	if (cfp->nonblock) {
    530  1.25  christos 		len = (int)read(sock, buf, (size_t)len);
    531  1.10      fvdl 		if (len < 0) {
    532  1.10      fvdl 			if (errno == EAGAIN)
    533  1.10      fvdl 				len = 0;
    534  1.10      fvdl 			else
    535  1.10      fvdl 				goto fatal_err;
    536  1.10      fvdl 		}
    537  1.10      fvdl 		if (len != 0)
    538  1.10      fvdl 			gettimeofday(&cfp->last_recv_time, NULL);
    539  1.10      fvdl 		return len;
    540  1.10      fvdl 	}
    541  1.10      fvdl 
    542   1.1      fvdl 	do {
    543   1.1      fvdl 		pollfd.fd = sock;
    544   1.1      fvdl 		pollfd.events = POLLIN;
    545  1.13  christos 		switch (pollts(&pollfd, 1, &ts, NULL)) {
    546   1.1      fvdl 		case -1:
    547   1.1      fvdl 			if (errno == EINTR) {
    548   1.1      fvdl 				continue;
    549   1.1      fvdl 			}
    550   1.1      fvdl 			/*FALLTHROUGH*/
    551   1.1      fvdl 		case 0:
    552   1.1      fvdl 			goto fatal_err;
    553   1.1      fvdl 
    554   1.1      fvdl 		default:
    555   1.1      fvdl 			break;
    556   1.1      fvdl 		}
    557   1.1      fvdl 	} while ((pollfd.revents & POLLIN) == 0);
    558   1.1      fvdl 
    559  1.25  christos 	if ((len = (int)read(sock, buf, (size_t)len)) > 0) {
    560  1.10      fvdl 		gettimeofday(&cfp->last_recv_time, NULL);
    561  1.23  christos 		return len;
    562  1.10      fvdl 	}
    563   1.1      fvdl 
    564   1.1      fvdl fatal_err:
    565   1.3   thorpej 	if (crmsg != NULL)
    566   1.3   thorpej 		free(crmsg);
    567   1.1      fvdl 	((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
    568  1.23  christos 	return -1;
    569   1.1      fvdl }
    570   1.1      fvdl 
    571   1.1      fvdl /*
    572   1.1      fvdl  * writes data to the tcp connection.
    573   1.1      fvdl  * Any error is fatal and the connection is closed.
    574   1.1      fvdl  */
    575   1.1      fvdl static int
    576  1.23  christos write_vc(caddr_t xprtp, caddr_t buf, int len)
    577   1.1      fvdl {
    578   1.1      fvdl 	SVCXPRT *xprt;
    579   1.1      fvdl 	int i, cnt;
    580  1.10      fvdl 	struct cf_conn *cd;
    581  1.10      fvdl 	struct timeval tv0, tv1;
    582   1.1      fvdl 
    583   1.1      fvdl 	xprt = (SVCXPRT *)(void *)xprtp;
    584   1.1      fvdl 	_DIAGASSERT(xprt != NULL);
    585   1.1      fvdl 
    586  1.10      fvdl 	cd = (struct cf_conn *)xprt->xp_p1;
    587  1.10      fvdl 
    588  1.10      fvdl 	if (cd->nonblock)
    589  1.10      fvdl 		gettimeofday(&tv0, NULL);
    590  1.10      fvdl 
    591   1.1      fvdl 	for (cnt = len; cnt > 0; cnt -= i, buf += i) {
    592  1.25  christos 		if ((i = (int)write(xprt->xp_fd, buf, (size_t)cnt)) < 0) {
    593  1.10      fvdl 			if (errno != EAGAIN || !cd->nonblock) {
    594  1.10      fvdl 				cd->strm_stat = XPRT_DIED;
    595  1.23  christos 				return -1;
    596  1.10      fvdl 			}
    597  1.24  christos 			if (cd->nonblock) {
    598  1.10      fvdl 				/*
    599  1.10      fvdl 				 * For non-blocking connections, do not
    600  1.10      fvdl 				 * take more than 2 seconds writing the
    601  1.10      fvdl 				 * data out.
    602  1.10      fvdl 				 *
    603  1.10      fvdl 				 * XXX 2 is an arbitrary amount.
    604  1.10      fvdl 				 */
    605  1.10      fvdl 				gettimeofday(&tv1, NULL);
    606  1.10      fvdl 				if (tv1.tv_sec - tv0.tv_sec >= 2) {
    607  1.10      fvdl 					cd->strm_stat = XPRT_DIED;
    608  1.23  christos 					return -1;
    609  1.10      fvdl 				}
    610  1.10      fvdl 			}
    611  1.24  christos 			i = 0;
    612   1.1      fvdl 		}
    613   1.1      fvdl 	}
    614  1.23  christos 	return len;
    615   1.1      fvdl }
    616   1.1      fvdl 
    617   1.1      fvdl static enum xprt_stat
    618  1.23  christos svc_vc_stat(SVCXPRT *xprt)
    619   1.1      fvdl {
    620   1.1      fvdl 	struct cf_conn *cd;
    621   1.1      fvdl 
    622   1.1      fvdl 	_DIAGASSERT(xprt != NULL);
    623   1.1      fvdl 
    624   1.1      fvdl 	cd = (struct cf_conn *)(xprt->xp_p1);
    625   1.1      fvdl 
    626   1.1      fvdl 	if (cd->strm_stat == XPRT_DIED)
    627  1.23  christos 		return XPRT_DIED;
    628   1.1      fvdl 	if (! xdrrec_eof(&(cd->xdrs)))
    629  1.23  christos 		return XPRT_MOREREQS;
    630  1.23  christos 	return XPRT_IDLE;
    631   1.1      fvdl }
    632   1.1      fvdl 
    633   1.1      fvdl static bool_t
    634  1.23  christos svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg)
    635   1.1      fvdl {
    636   1.1      fvdl 	struct cf_conn *cd;
    637   1.1      fvdl 	XDR *xdrs;
    638   1.1      fvdl 
    639   1.1      fvdl 	_DIAGASSERT(xprt != NULL);
    640   1.1      fvdl 	_DIAGASSERT(msg != NULL);
    641   1.1      fvdl 
    642   1.1      fvdl 	cd = (struct cf_conn *)(xprt->xp_p1);
    643   1.1      fvdl 	xdrs = &(cd->xdrs);
    644   1.1      fvdl 
    645  1.10      fvdl 	if (cd->nonblock) {
    646  1.10      fvdl 		if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE))
    647  1.10      fvdl 			return FALSE;
    648  1.10      fvdl 	}
    649  1.10      fvdl 
    650   1.1      fvdl 	xdrs->x_op = XDR_DECODE;
    651   1.1      fvdl 	(void)xdrrec_skiprecord(xdrs);
    652  1.10      fvdl 
    653   1.1      fvdl 	if (xdr_callmsg(xdrs, msg)) {
    654   1.1      fvdl 		cd->x_id = msg->rm_xid;
    655  1.23  christos 		return TRUE;
    656   1.1      fvdl 	}
    657   1.1      fvdl 	cd->strm_stat = XPRT_DIED;
    658  1.23  christos 	return FALSE;
    659   1.1      fvdl }
    660   1.1      fvdl 
    661   1.1      fvdl static bool_t
    662  1.23  christos svc_vc_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
    663   1.1      fvdl {
    664   1.1      fvdl 
    665   1.1      fvdl 	_DIAGASSERT(xprt != NULL);
    666   1.1      fvdl 	/* args_ptr may be NULL */
    667   1.1      fvdl 
    668  1.23  christos 	return (*xdr_args)(&(((struct cf_conn *)(xprt->xp_p1))->xdrs),
    669  1.23  christos 	    args_ptr);
    670   1.1      fvdl }
    671   1.1      fvdl 
    672   1.1      fvdl static bool_t
    673  1.23  christos svc_vc_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
    674   1.1      fvdl {
    675   1.1      fvdl 	XDR *xdrs;
    676   1.1      fvdl 
    677   1.1      fvdl 	_DIAGASSERT(xprt != NULL);
    678   1.1      fvdl 	/* args_ptr may be NULL */
    679   1.1      fvdl 
    680   1.1      fvdl 	xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs);
    681   1.1      fvdl 
    682   1.1      fvdl 	xdrs->x_op = XDR_FREE;
    683  1.23  christos 	return (*xdr_args)(xdrs, args_ptr);
    684   1.1      fvdl }
    685   1.1      fvdl 
    686   1.1      fvdl static bool_t
    687  1.23  christos svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg)
    688   1.1      fvdl {
    689   1.1      fvdl 	struct cf_conn *cd;
    690   1.1      fvdl 	XDR *xdrs;
    691  1.10      fvdl 	bool_t rstat;
    692   1.1      fvdl 
    693   1.1      fvdl 	_DIAGASSERT(xprt != NULL);
    694   1.1      fvdl 	_DIAGASSERT(msg != NULL);
    695   1.1      fvdl 
    696   1.1      fvdl 	cd = (struct cf_conn *)(xprt->xp_p1);
    697   1.1      fvdl 	xdrs = &(cd->xdrs);
    698   1.1      fvdl 
    699   1.1      fvdl 	xdrs->x_op = XDR_ENCODE;
    700   1.1      fvdl 	msg->rm_xid = cd->x_id;
    701  1.10      fvdl 	rstat = xdr_replymsg(xdrs, msg);
    702   1.1      fvdl 	(void)xdrrec_endofrecord(xdrs, TRUE);
    703  1.23  christos 	return rstat;
    704   1.1      fvdl }
    705   1.1      fvdl 
    706   1.1      fvdl static void
    707  1.23  christos svc_vc_ops(SVCXPRT *xprt)
    708   1.1      fvdl {
    709   1.1      fvdl 	static struct xp_ops ops;
    710   1.1      fvdl 	static struct xp_ops2 ops2;
    711  1.12   thorpej #ifdef _REENTRANT
    712   1.1      fvdl 	extern mutex_t ops_lock;
    713   1.1      fvdl #endif
    714   1.1      fvdl 
    715   1.1      fvdl /* VARIABLES PROTECTED BY ops_lock: ops, ops2 */
    716   1.1      fvdl 
    717   1.1      fvdl 	mutex_lock(&ops_lock);
    718   1.1      fvdl 	if (ops.xp_recv == NULL) {
    719   1.1      fvdl 		ops.xp_recv = svc_vc_recv;
    720   1.1      fvdl 		ops.xp_stat = svc_vc_stat;
    721   1.1      fvdl 		ops.xp_getargs = svc_vc_getargs;
    722   1.1      fvdl 		ops.xp_reply = svc_vc_reply;
    723   1.1      fvdl 		ops.xp_freeargs = svc_vc_freeargs;
    724   1.1      fvdl 		ops.xp_destroy = svc_vc_destroy;
    725   1.1      fvdl 		ops2.xp_control = svc_vc_control;
    726   1.1      fvdl 	}
    727   1.1      fvdl 	xprt->xp_ops = &ops;
    728   1.1      fvdl 	xprt->xp_ops2 = &ops2;
    729   1.1      fvdl 	mutex_unlock(&ops_lock);
    730   1.1      fvdl }
    731   1.1      fvdl 
    732   1.1      fvdl static void
    733  1.26      matt svc_vc_rendezvous_ops(SVCXPRT *xprt)
    734   1.1      fvdl {
    735   1.1      fvdl 	static struct xp_ops ops;
    736   1.1      fvdl 	static struct xp_ops2 ops2;
    737  1.12   thorpej #ifdef _REENTRANT
    738   1.1      fvdl 	extern mutex_t ops_lock;
    739   1.1      fvdl #endif
    740   1.1      fvdl 	mutex_lock(&ops_lock);
    741   1.1      fvdl 	if (ops.xp_recv == NULL) {
    742   1.1      fvdl 		ops.xp_recv = rendezvous_request;
    743   1.1      fvdl 		ops.xp_stat = rendezvous_stat;
    744   1.1      fvdl 		ops.xp_getargs =
    745  1.23  christos 		    (bool_t (*)(SVCXPRT *, xdrproc_t, caddr_t))abort;
    746   1.1      fvdl 		ops.xp_reply =
    747  1.23  christos 		    (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort;
    748   1.1      fvdl 		ops.xp_freeargs =
    749  1.23  christos 		    (bool_t (*)(SVCXPRT *, xdrproc_t, caddr_t))abort;
    750   1.1      fvdl 		ops.xp_destroy = svc_vc_destroy;
    751  1.10      fvdl 		ops2.xp_control = svc_vc_rendezvous_control;
    752   1.1      fvdl 	}
    753   1.1      fvdl 	xprt->xp_ops = &ops;
    754   1.1      fvdl 	xprt->xp_ops2 = &ops2;
    755   1.1      fvdl 	mutex_unlock(&ops_lock);
    756  1.10      fvdl }
    757  1.10      fvdl 
    758  1.10      fvdl /*
    759  1.10      fvdl  * Destroy xprts that have not have had any activity in 'timeout' seconds.
    760  1.10      fvdl  * If 'cleanblock' is true, blocking connections (the default) are also
    761  1.10      fvdl  * cleaned. If timeout is 0, the least active connection is picked.
    762  1.10      fvdl  */
    763  1.10      fvdl bool_t
    764  1.10      fvdl __svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock)
    765  1.10      fvdl {
    766  1.32  christos 	int i, ncleaned, *fdmax;
    767  1.10      fvdl 	SVCXPRT *xprt, *least_active;
    768  1.10      fvdl 	struct timeval tv, tdiff, tmax;
    769  1.10      fvdl 	struct cf_conn *cd;
    770  1.10      fvdl 
    771  1.10      fvdl 	gettimeofday(&tv, NULL);
    772  1.10      fvdl 	tmax.tv_sec = tmax.tv_usec = 0;
    773  1.10      fvdl 	least_active = NULL;
    774  1.10      fvdl 	rwlock_wrlock(&svc_fd_lock);
    775  1.32  christos 	fdmax = svc_fdset_getmax();
    776  1.32  christos 	if (fdmax == NULL)
    777  1.32  christos 		return FALSE;
    778  1.32  christos 	for (i = ncleaned = 0; i <= *fdmax; i++) {
    779  1.32  christos 		switch (svc_fdset_isset(i)) {
    780  1.32  christos 		case 0:
    781  1.32  christos 		case -1:
    782  1.31  christos 			continue;
    783  1.32  christos 		default:
    784  1.32  christos 			break;
    785  1.32  christos 		}
    786  1.31  christos 
    787  1.31  christos 		xprt = __svc_xports[i];
    788  1.31  christos 		if (xprt == NULL || xprt->xp_ops == NULL ||
    789  1.31  christos 		    xprt->xp_ops->xp_recv != svc_vc_recv)
    790  1.31  christos 			continue;
    791  1.31  christos 
    792  1.31  christos 		cd = (struct cf_conn *)xprt->xp_p1;
    793  1.31  christos 		if (!cleanblock && !cd->nonblock)
    794  1.31  christos 			continue;
    795  1.31  christos 
    796  1.31  christos 		if (timeout == 0) {
    797  1.31  christos 			timersub(&tv, &cd->last_recv_time, &tdiff);
    798  1.31  christos 			if (timercmp(&tdiff, &tmax, >)) {
    799  1.31  christos 				tmax = tdiff;
    800  1.31  christos 				least_active = xprt;
    801  1.10      fvdl 			}
    802  1.31  christos 			continue;
    803  1.31  christos 		}
    804  1.31  christos 
    805  1.31  christos 		if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) {
    806  1.31  christos 			__xprt_unregister_unlocked(xprt);
    807  1.31  christos 			__svc_vc_dodestroy(xprt);
    808  1.31  christos 			ncleaned++;
    809  1.10      fvdl 		}
    810  1.10      fvdl 	}
    811  1.10      fvdl 	if (timeout == 0 && least_active != NULL) {
    812  1.10      fvdl 		__xprt_unregister_unlocked(least_active);
    813  1.10      fvdl 		__svc_vc_dodestroy(least_active);
    814  1.10      fvdl 		ncleaned++;
    815  1.10      fvdl 	}
    816  1.10      fvdl 	rwlock_unlock(&svc_fd_lock);
    817  1.10      fvdl 	return ncleaned > 0 ? TRUE : FALSE;
    818   1.1      fvdl }
    819