svc_vc.c revision 116391
174462Salfred/* $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $ */ 274462Salfred 374462Salfred/* 474462Salfred * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 574462Salfred * unrestricted use provided that this legend is included on all tape 674462Salfred * media and as a part of the software program in whole or part. Users 774462Salfred * may copy or modify Sun RPC without charge, but are not authorized 874462Salfred * to license or distribute it to anyone else except as part of a product or 974462Salfred * program developed by the user. 1074462Salfred * 1174462Salfred * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 1274462Salfred * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 1374462Salfred * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 1474462Salfred * 1574462Salfred * Sun RPC is provided with no support and without any obligation on the 1674462Salfred * part of Sun Microsystems, Inc. to assist in its use, correction, 1774462Salfred * modification or enhancement. 1874462Salfred * 1974462Salfred * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 2074462Salfred * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 2174462Salfred * OR ANY PART THEREOF. 2274462Salfred * 2374462Salfred * In no event will Sun Microsystems, Inc. be liable for any lost revenue 2474462Salfred * or profits or other special, indirect and consequential damages, even if 2574462Salfred * Sun has been advised of the possibility of such damages. 2674462Salfred * 2774462Salfred * Sun Microsystems, Inc. 2874462Salfred * 2550 Garcia Avenue 2974462Salfred * Mountain View, California 94043 3074462Salfred */ 3174462Salfred 3274462Salfred#if defined(LIBC_SCCS) && !defined(lint) 3374462Salfredstatic char *sccsid = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; 3474462Salfredstatic char *sccsid = "@(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 3574462Salfred#endif 3692990Sobrien#include <sys/cdefs.h> 3792990Sobrien__FBSDID("$FreeBSD: head/lib/libc/rpc/svc_vc.c 116391 2003-06-15 10:32:01Z mbr $"); 3874462Salfred 3974462Salfred/* 4074462Salfred * svc_vc.c, Server side for Connection Oriented based RPC. 4174462Salfred * 4274462Salfred * Actually implements two flavors of transporter - 4374462Salfred * a tcp rendezvouser (a listner and connection establisher) 4474462Salfred * and a record/tcp stream. 4574462Salfred */ 4674462Salfred 4775094Siedowse#include "namespace.h" 4874462Salfred#include "reentrant.h" 4974462Salfred#include <sys/types.h> 5074462Salfred#include <sys/param.h> 5174462Salfred#include <sys/poll.h> 5274462Salfred#include <sys/socket.h> 5374462Salfred#include <sys/un.h> 54109359Smbr#include <sys/time.h> 5574462Salfred#include <sys/uio.h> 5674462Salfred#include <netinet/in.h> 5774462Salfred#include <netinet/tcp.h> 5874462Salfred 5974462Salfred#include <assert.h> 6074462Salfred#include <err.h> 6174462Salfred#include <errno.h> 62109359Smbr#include <fcntl.h> 6374462Salfred#include <stdio.h> 6474462Salfred#include <stdlib.h> 6574462Salfred#include <string.h> 6674462Salfred#include <unistd.h> 6774462Salfred 6874462Salfred#include <rpc/rpc.h> 6974462Salfred 7074462Salfred#include "rpc_com.h" 7174462Salfred#include "un-namespace.h" 7274462Salfred 73109359Smbrextern rwlock_t svc_fd_lock; 74109359Smbr 7592905Sobrienstatic SVCXPRT *makefd_xprt(int, u_int, u_int); 7692905Sobrienstatic bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *); 7792905Sobrienstatic enum xprt_stat rendezvous_stat(SVCXPRT *); 7892905Sobrienstatic void svc_vc_destroy(SVCXPRT *); 79109359Smbrstatic void __svc_vc_dodestroy (SVCXPRT *); 8095658Sdesstatic int read_vc(void *, void *, int); 8195658Sdesstatic int write_vc(void *, void *, int); 8292905Sobrienstatic enum xprt_stat svc_vc_stat(SVCXPRT *); 8392905Sobrienstatic bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *); 8495658Sdesstatic bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, void *); 8595658Sdesstatic bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, void *); 8692905Sobrienstatic bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *); 8792905Sobrienstatic void svc_vc_rendezvous_ops(SVCXPRT *); 8892905Sobrienstatic void svc_vc_ops(SVCXPRT *); 8992905Sobrienstatic bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in); 90109359Smbrstatic bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq, 91109359Smbr void *in); 9274462Salfredstatic int __msgwrite(int, void *, size_t); 9374462Salfred 9474462Salfredstruct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */ 9574462Salfred u_int sendsize; 9674462Salfred u_int recvsize; 97109359Smbr int maxrec; 9874462Salfred}; 9974462Salfred 10074462Salfredstruct cf_conn { /* kept in xprt->xp_p1 for actual connection */ 10174462Salfred enum xprt_stat strm_stat; 10274462Salfred u_int32_t x_id; 10374462Salfred XDR xdrs; 10474462Salfred char verf_body[MAX_AUTH_BYTES]; 105109359Smbr u_int sendsize; 106109359Smbr u_int recvsize; 107109359Smbr int maxrec; 108109359Smbr bool_t nonblock; 109109359Smbr struct timeval last_recv_time; 11074462Salfred}; 11174462Salfred 11274462Salfred/* 11374462Salfred * Usage: 11474462Salfred * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); 11574462Salfred * 11674462Salfred * Creates, registers, and returns a (rpc) tcp based transporter. 11774462Salfred * Once *xprt is initialized, it is registered as a transporter 11874462Salfred * see (svc.h, xprt_register). This routine returns 11974462Salfred * a NULL if a problem occurred. 12074462Salfred * 12174462Salfred * The filedescriptor passed in is expected to refer to a bound, but 12274462Salfred * not yet connected socket. 12374462Salfred * 12474462Salfred * Since streams do buffered io similar to stdio, the caller can specify 12574462Salfred * how big the send and receive buffers are via the second and third parms; 12674462Salfred * 0 => use the system default. 12774462Salfred */ 12874462SalfredSVCXPRT * 12974462Salfredsvc_vc_create(fd, sendsize, recvsize) 13074462Salfred int fd; 13174462Salfred u_int sendsize; 13274462Salfred u_int recvsize; 13374462Salfred{ 13474462Salfred SVCXPRT *xprt; 13574462Salfred struct cf_rendezvous *r = NULL; 13674462Salfred struct __rpc_sockinfo si; 13774462Salfred struct sockaddr_storage sslocal; 13874462Salfred socklen_t slen; 13974462Salfred 14074462Salfred r = mem_alloc(sizeof(*r)); 14174462Salfred if (r == NULL) { 14274462Salfred warnx("svc_vc_create: out of memory"); 14374462Salfred goto cleanup_svc_vc_create; 14474462Salfred } 14574462Salfred if (!__rpc_fd2sockinfo(fd, &si)) 14674462Salfred return NULL; 14774462Salfred r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize); 14874462Salfred r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize); 149109359Smbr r->maxrec = __svc_maxrec; 15074462Salfred xprt = mem_alloc(sizeof(SVCXPRT)); 15174462Salfred if (xprt == NULL) { 15274462Salfred warnx("svc_vc_create: out of memory"); 15374462Salfred goto cleanup_svc_vc_create; 15474462Salfred } 15574462Salfred xprt->xp_tp = NULL; 15695658Sdes xprt->xp_p1 = r; 15774462Salfred xprt->xp_p2 = NULL; 15874462Salfred xprt->xp_p3 = NULL; 15974462Salfred xprt->xp_verf = _null_auth; 16074462Salfred svc_vc_rendezvous_ops(xprt); 16174462Salfred xprt->xp_port = (u_short)-1; /* It is the rendezvouser */ 16274462Salfred xprt->xp_fd = fd; 16374462Salfred 16474462Salfred slen = sizeof (struct sockaddr_storage); 16574462Salfred if (_getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) { 16674462Salfred warnx("svc_vc_create: could not retrieve local addr"); 16774462Salfred goto cleanup_svc_vc_create; 16874462Salfred } 16974462Salfred 17074462Salfred xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len; 17174462Salfred xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len); 17274462Salfred if (xprt->xp_ltaddr.buf == NULL) { 17374462Salfred warnx("svc_vc_create: no mem for local addr"); 17474462Salfred goto cleanup_svc_vc_create; 17574462Salfred } 17674462Salfred memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len); 17774462Salfred 17874462Salfred xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage); 17974462Salfred xprt_register(xprt); 18074462Salfred return (xprt); 18174462Salfredcleanup_svc_vc_create: 18274462Salfred if (r != NULL) 18374462Salfred mem_free(r, sizeof(*r)); 18474462Salfred return (NULL); 18574462Salfred} 18674462Salfred 18774462Salfred/* 18874462Salfred * Like svtcp_create(), except the routine takes any *open* UNIX file 18974462Salfred * descriptor as its first input. 19074462Salfred */ 19174462SalfredSVCXPRT * 19274462Salfredsvc_fd_create(fd, sendsize, recvsize) 19374462Salfred int fd; 19474462Salfred u_int sendsize; 19574462Salfred u_int recvsize; 19674462Salfred{ 19774462Salfred struct sockaddr_storage ss; 19874462Salfred socklen_t slen; 19974462Salfred SVCXPRT *ret; 20074462Salfred 20174462Salfred assert(fd != -1); 20274462Salfred 20374462Salfred ret = makefd_xprt(fd, sendsize, recvsize); 20474462Salfred if (ret == NULL) 20574462Salfred return NULL; 20674462Salfred 20774462Salfred slen = sizeof (struct sockaddr_storage); 20874462Salfred if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { 20974462Salfred warnx("svc_fd_create: could not retrieve local addr"); 21074462Salfred goto freedata; 21174462Salfred } 21274462Salfred ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len; 21374462Salfred ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len); 21474462Salfred if (ret->xp_ltaddr.buf == NULL) { 21574462Salfred warnx("svc_fd_create: no mem for local addr"); 21674462Salfred goto freedata; 21774462Salfred } 21874462Salfred memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len); 21974462Salfred 22074462Salfred slen = sizeof (struct sockaddr_storage); 22174462Salfred if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) { 22274462Salfred warnx("svc_fd_create: could not retrieve remote addr"); 22374462Salfred goto freedata; 22474462Salfred } 22574462Salfred ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len; 22674462Salfred ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len); 22774462Salfred if (ret->xp_rtaddr.buf == NULL) { 22874462Salfred warnx("svc_fd_create: no mem for local addr"); 22974462Salfred goto freedata; 23074462Salfred } 23174462Salfred memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len); 23274462Salfred#ifdef PORTMAP 23390272Salfred if (ss.ss_family == AF_INET || ss.ss_family == AF_LOCAL) { 23474462Salfred ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf; 23574462Salfred ret->xp_addrlen = sizeof (struct sockaddr_in); 23674462Salfred } 23774462Salfred#endif /* PORTMAP */ 23874462Salfred 23974462Salfred return ret; 24074462Salfred 24174462Salfredfreedata: 24274462Salfred if (ret->xp_ltaddr.buf != NULL) 24374462Salfred mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen); 24474462Salfred 24574462Salfred return NULL; 24674462Salfred} 24774462Salfred 24874462Salfredstatic SVCXPRT * 24974462Salfredmakefd_xprt(fd, sendsize, recvsize) 25074462Salfred int fd; 25174462Salfred u_int sendsize; 25274462Salfred u_int recvsize; 25374462Salfred{ 25474462Salfred SVCXPRT *xprt; 25574462Salfred struct cf_conn *cd; 25674462Salfred const char *netid; 25774462Salfred struct __rpc_sockinfo si; 25874462Salfred 25974462Salfred assert(fd != -1); 26074462Salfred 26174462Salfred xprt = mem_alloc(sizeof(SVCXPRT)); 26274462Salfred if (xprt == NULL) { 26374462Salfred warnx("svc_vc: makefd_xprt: out of memory"); 26474462Salfred goto done; 26574462Salfred } 26674462Salfred memset(xprt, 0, sizeof *xprt); 26774462Salfred cd = mem_alloc(sizeof(struct cf_conn)); 26874462Salfred if (cd == NULL) { 26974462Salfred warnx("svc_tcp: makefd_xprt: out of memory"); 27074462Salfred mem_free(xprt, sizeof(SVCXPRT)); 27174462Salfred xprt = NULL; 27274462Salfred goto done; 27374462Salfred } 27474462Salfred cd->strm_stat = XPRT_IDLE; 27574462Salfred xdrrec_create(&(cd->xdrs), sendsize, recvsize, 27695658Sdes xprt, read_vc, write_vc); 27795658Sdes xprt->xp_p1 = cd; 27874462Salfred xprt->xp_verf.oa_base = cd->verf_body; 27974462Salfred svc_vc_ops(xprt); /* truely deals with calls */ 28074462Salfred xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ 28174462Salfred xprt->xp_fd = fd; 28274462Salfred if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid)) 28374462Salfred xprt->xp_netid = strdup(netid); 28474462Salfred 28574462Salfred xprt_register(xprt); 28674462Salfreddone: 28774462Salfred return (xprt); 28874462Salfred} 28974462Salfred 29074462Salfred/*ARGSUSED*/ 29174462Salfredstatic bool_t 29274462Salfredrendezvous_request(xprt, msg) 29374462Salfred SVCXPRT *xprt; 29474462Salfred struct rpc_msg *msg; 29574462Salfred{ 296109359Smbr int sock, flags; 29774462Salfred struct cf_rendezvous *r; 298109359Smbr struct cf_conn *cd; 29974462Salfred struct sockaddr_storage addr; 30074462Salfred socklen_t len; 30174462Salfred struct __rpc_sockinfo si; 302109359Smbr SVCXPRT *newxprt; 303109359Smbr fd_set cleanfds; 30474462Salfred 30574462Salfred assert(xprt != NULL); 30674462Salfred assert(msg != NULL); 30774462Salfred 30874462Salfred r = (struct cf_rendezvous *)xprt->xp_p1; 30974462Salfredagain: 31074462Salfred len = sizeof addr; 31174462Salfred if ((sock = _accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr, 31274462Salfred &len)) < 0) { 31374462Salfred if (errno == EINTR) 31474462Salfred goto again; 315109359Smbr /* 316109359Smbr * Clean out the most idle file descriptor when we're 317109359Smbr * running out. 318109359Smbr */ 319109359Smbr if (errno == EMFILE || errno == ENFILE) { 320109359Smbr cleanfds = svc_fdset; 321109359Smbr __svc_clean_idle(&cleanfds, 0, FALSE); 322109359Smbr goto again; 323109359Smbr } 324109359Smbr return (FALSE); 32574462Salfred } 32674462Salfred /* 32774462Salfred * make a new transporter (re-uses xprt) 32874462Salfred */ 329109359Smbr newxprt = makefd_xprt(sock, r->sendsize, r->recvsize); 330109359Smbr newxprt->xp_rtaddr.buf = mem_alloc(len); 331109359Smbr if (newxprt->xp_rtaddr.buf == NULL) 33274462Salfred return (FALSE); 333109359Smbr memcpy(newxprt->xp_rtaddr.buf, &addr, len); 334109359Smbr newxprt->xp_rtaddr.len = len; 33574462Salfred#ifdef PORTMAP 33690316Salfred if (addr.ss_family == AF_INET || addr.ss_family == AF_LOCAL) { 337109359Smbr newxprt->xp_raddr = *(struct sockaddr_in *)newxprt->xp_rtaddr.buf; 338109359Smbr newxprt->xp_addrlen = sizeof (struct sockaddr_in); 33974462Salfred } 34074462Salfred#endif /* PORTMAP */ 34174462Salfred if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) { 34274462Salfred len = 1; 34374462Salfred /* XXX fvdl - is this useful? */ 34474462Salfred _setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &len, sizeof (len)); 34574462Salfred } 346109359Smbr 347109359Smbr cd = (struct cf_conn *)newxprt->xp_p1; 348109359Smbr 349109359Smbr cd->recvsize = r->recvsize; 350109359Smbr cd->sendsize = r->sendsize; 351109359Smbr cd->maxrec = r->maxrec; 352109359Smbr 353109359Smbr if (cd->maxrec != 0) { 354109904Smbr flags = _fcntl(sock, F_GETFL, 0); 355109359Smbr if (flags == -1) 356109359Smbr return (FALSE); 357109904Smbr if (_fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) 358109359Smbr return (FALSE); 359109359Smbr if (cd->recvsize > cd->maxrec) 360109359Smbr cd->recvsize = cd->maxrec; 361109359Smbr cd->nonblock = TRUE; 362109359Smbr __xdrrec_setnonblock(&cd->xdrs, cd->maxrec); 363109359Smbr } else 364109359Smbr cd->nonblock = FALSE; 365109359Smbr 366109359Smbr gettimeofday(&cd->last_recv_time, NULL); 367109359Smbr 36874462Salfred return (FALSE); /* there is never an rpc msg to be processed */ 36974462Salfred} 37074462Salfred 37174462Salfred/*ARGSUSED*/ 37274462Salfredstatic enum xprt_stat 37374462Salfredrendezvous_stat(xprt) 37474462Salfred SVCXPRT *xprt; 37574462Salfred{ 37674462Salfred 37774462Salfred return (XPRT_IDLE); 37874462Salfred} 37974462Salfred 38074462Salfredstatic void 38174462Salfredsvc_vc_destroy(xprt) 38274462Salfred SVCXPRT *xprt; 38374462Salfred{ 384109359Smbr assert(xprt != NULL); 385109359Smbr 386109359Smbr xprt_unregister(xprt); 387109359Smbr __svc_vc_dodestroy(xprt); 388109359Smbr} 389109359Smbr 390109359Smbrstatic void 391109359Smbr__svc_vc_dodestroy(xprt) 392109359Smbr SVCXPRT *xprt; 393109359Smbr{ 39474462Salfred struct cf_conn *cd; 39574462Salfred struct cf_rendezvous *r; 39674462Salfred 39774462Salfred cd = (struct cf_conn *)xprt->xp_p1; 39874462Salfred 39974462Salfred if (xprt->xp_fd != RPC_ANYFD) 40074462Salfred (void)_close(xprt->xp_fd); 40174462Salfred if (xprt->xp_port != 0) { 40274462Salfred /* a rendezvouser socket */ 40374462Salfred r = (struct cf_rendezvous *)xprt->xp_p1; 40474462Salfred mem_free(r, sizeof (struct cf_rendezvous)); 40574462Salfred xprt->xp_port = 0; 40674462Salfred } else { 40774462Salfred /* an actual connection socket */ 40874462Salfred XDR_DESTROY(&(cd->xdrs)); 40974462Salfred mem_free(cd, sizeof(struct cf_conn)); 41074462Salfred } 41174462Salfred if (xprt->xp_rtaddr.buf) 41274462Salfred mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen); 41374462Salfred if (xprt->xp_ltaddr.buf) 41474462Salfred mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen); 41574462Salfred if (xprt->xp_tp) 41674462Salfred free(xprt->xp_tp); 41774462Salfred if (xprt->xp_netid) 41874462Salfred free(xprt->xp_netid); 41974462Salfred mem_free(xprt, sizeof(SVCXPRT)); 42074462Salfred} 42174462Salfred 42274462Salfred/*ARGSUSED*/ 42374462Salfredstatic bool_t 42474462Salfredsvc_vc_control(xprt, rq, in) 42574462Salfred SVCXPRT *xprt; 42674462Salfred const u_int rq; 42774462Salfred void *in; 42874462Salfred{ 42974462Salfred return (FALSE); 43074462Salfred} 43174462Salfred 432109359Smbrstatic bool_t 433109359Smbrsvc_vc_rendezvous_control(xprt, rq, in) 434109359Smbr SVCXPRT *xprt; 435109359Smbr const u_int rq; 436109359Smbr void *in; 437109359Smbr{ 438109359Smbr struct cf_rendezvous *cfp; 439109359Smbr 440109359Smbr cfp = (struct cf_rendezvous *)xprt->xp_p1; 441109359Smbr if (cfp == NULL) 442109359Smbr return (FALSE); 443109359Smbr switch (rq) { 444109359Smbr case SVCGET_CONNMAXREC: 445109359Smbr *(int *)in = cfp->maxrec; 446109359Smbr break; 447109359Smbr case SVCSET_CONNMAXREC: 448109359Smbr cfp->maxrec = *(int *)in; 449109359Smbr break; 450109359Smbr default: 451109359Smbr return (FALSE); 452109359Smbr } 453109359Smbr return (TRUE); 454109359Smbr} 455109359Smbr 45674462Salfred/* 45774462Salfred * reads data from the tcp or uip connection. 45874462Salfred * any error is fatal and the connection is closed. 45974462Salfred * (And a read of zero bytes is a half closed stream => error.) 46074462Salfred * All read operations timeout after 35 seconds. A timeout is 46174462Salfred * fatal for the connection. 46274462Salfred */ 46374462Salfredstatic int 46474462Salfredread_vc(xprtp, buf, len) 46595658Sdes void *xprtp; 46695658Sdes void *buf; 46774462Salfred int len; 46874462Salfred{ 46974462Salfred SVCXPRT *xprt; 47074462Salfred int sock; 47174462Salfred int milliseconds = 35 * 1000; 47274462Salfred struct pollfd pollfd; 473109359Smbr struct cf_conn *cfp; 47474462Salfred 47595658Sdes xprt = (SVCXPRT *)xprtp; 47674462Salfred assert(xprt != NULL); 47774462Salfred 47874462Salfred sock = xprt->xp_fd; 47974462Salfred 480109359Smbr cfp = (struct cf_conn *)xprt->xp_p1; 481109359Smbr 482109359Smbr if (cfp->nonblock) { 483116391Smbr len = _read(sock, buf, (size_t)len); 484109359Smbr if (len < 0) { 485109359Smbr if (errno == EAGAIN) 486109359Smbr len = 0; 487109359Smbr else 488109359Smbr goto fatal_err; 489109359Smbr } 490109359Smbr if (len != 0) 491109359Smbr gettimeofday(&cfp->last_recv_time, NULL); 492109359Smbr return len; 493109359Smbr } 494109359Smbr 49574536Salfred do { 49674536Salfred pollfd.fd = sock; 49774536Salfred pollfd.events = POLLIN; 49874462Salfred pollfd.revents = 0; 49974536Salfred switch (_poll(&pollfd, 1, milliseconds)) { 50074536Salfred case -1: 50174536Salfred if (errno == EINTR) 50274536Salfred continue; 50374536Salfred /*FALLTHROUGH*/ 50474627Salfred case 0: 50574627Salfred goto fatal_err; 50674627Salfred 50774627Salfred default: 50874627Salfred break; 50974536Salfred } 51074536Salfred } while ((pollfd.revents & POLLIN) == 0); 51174462Salfred 512116391Smbr if ((len = _read(sock, buf, (size_t)len)) > 0) { 513116391Smbr gettimeofday(&cfp->last_recv_time, NULL); 514116391Smbr return (len); 51574462Salfred } 51674462Salfred 51774462Salfredfatal_err: 51874462Salfred ((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; 51974462Salfred return (-1); 52074462Salfred} 52174462Salfred 52274462Salfred/* 52374462Salfred * writes data to the tcp connection. 52474462Salfred * Any error is fatal and the connection is closed. 52574462Salfred */ 52674462Salfredstatic int 52774462Salfredwrite_vc(xprtp, buf, len) 52895658Sdes void *xprtp; 52995658Sdes void *buf; 53074462Salfred int len; 53174462Salfred{ 53274462Salfred SVCXPRT *xprt; 53374462Salfred int i, cnt; 534109359Smbr struct cf_conn *cd; 535109359Smbr struct timeval tv0, tv1; 53674462Salfred 53795658Sdes xprt = (SVCXPRT *)xprtp; 53874462Salfred assert(xprt != NULL); 539109359Smbr 540109359Smbr cd = (struct cf_conn *)xprt->xp_p1; 541109359Smbr 542109359Smbr if (cd->nonblock) 543109359Smbr gettimeofday(&tv0, NULL); 54474462Salfred 545109359Smbr for (cnt = len; cnt > 0; cnt -= i, buf += i) { 546116391Smbr i = _write(xprt->xp_fd, buf, (size_t)cnt); 547109359Smbr if (i < 0) { 548109359Smbr if (errno != EAGAIN || !cd->nonblock) { 549109359Smbr cd->strm_stat = XPRT_DIED; 55074462Salfred return (-1); 55174462Salfred } 552109359Smbr if (cd->nonblock && i != cnt) { 553109359Smbr /* 554109359Smbr * For non-blocking connections, do not 555109359Smbr * take more than 2 seconds writing the 556109359Smbr * data out. 557109359Smbr * 558109359Smbr * XXX 2 is an arbitrary amount. 559109359Smbr */ 560109359Smbr gettimeofday(&tv1, NULL); 561109359Smbr if (tv1.tv_sec - tv0.tv_sec >= 2) { 562109359Smbr cd->strm_stat = XPRT_DIED; 563109359Smbr return (-1); 564109359Smbr } 56574462Salfred } 56674462Salfred } 56774462Salfred } 56874462Salfred 56974462Salfred return (len); 57074462Salfred} 57174462Salfred 57274462Salfredstatic enum xprt_stat 57374462Salfredsvc_vc_stat(xprt) 57474462Salfred SVCXPRT *xprt; 57574462Salfred{ 57674462Salfred struct cf_conn *cd; 57774462Salfred 57874462Salfred assert(xprt != NULL); 57974462Salfred 58074462Salfred cd = (struct cf_conn *)(xprt->xp_p1); 58174462Salfred 58274462Salfred if (cd->strm_stat == XPRT_DIED) 58374462Salfred return (XPRT_DIED); 58474462Salfred if (! xdrrec_eof(&(cd->xdrs))) 58574462Salfred return (XPRT_MOREREQS); 58674462Salfred return (XPRT_IDLE); 58774462Salfred} 58874462Salfred 58974462Salfredstatic bool_t 59074462Salfredsvc_vc_recv(xprt, msg) 59174462Salfred SVCXPRT *xprt; 59274462Salfred struct rpc_msg *msg; 59374462Salfred{ 59474462Salfred struct cf_conn *cd; 59574462Salfred XDR *xdrs; 59674462Salfred 59774462Salfred assert(xprt != NULL); 59874462Salfred assert(msg != NULL); 59974462Salfred 60074462Salfred cd = (struct cf_conn *)(xprt->xp_p1); 60174462Salfred xdrs = &(cd->xdrs); 60274462Salfred 603109359Smbr if (cd->nonblock) { 604109359Smbr if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE)) 605109359Smbr return FALSE; 606109359Smbr } 607109359Smbr 60874462Salfred xdrs->x_op = XDR_DECODE; 60974462Salfred (void)xdrrec_skiprecord(xdrs); 61074462Salfred if (xdr_callmsg(xdrs, msg)) { 61174462Salfred cd->x_id = msg->rm_xid; 61274462Salfred return (TRUE); 61374462Salfred } 61474462Salfred cd->strm_stat = XPRT_DIED; 61574462Salfred return (FALSE); 61674462Salfred} 61774462Salfred 61874462Salfredstatic bool_t 61974462Salfredsvc_vc_getargs(xprt, xdr_args, args_ptr) 62074462Salfred SVCXPRT *xprt; 62174462Salfred xdrproc_t xdr_args; 62295658Sdes void *args_ptr; 62374462Salfred{ 62474462Salfred 62574462Salfred assert(xprt != NULL); 62674462Salfred /* args_ptr may be NULL */ 62774462Salfred return ((*xdr_args)(&(((struct cf_conn *)(xprt->xp_p1))->xdrs), 62874462Salfred args_ptr)); 62974462Salfred} 63074462Salfred 63174462Salfredstatic bool_t 63274462Salfredsvc_vc_freeargs(xprt, xdr_args, args_ptr) 63374462Salfred SVCXPRT *xprt; 63474462Salfred xdrproc_t xdr_args; 63595658Sdes void *args_ptr; 63674462Salfred{ 63774462Salfred XDR *xdrs; 63874462Salfred 63974462Salfred assert(xprt != NULL); 64074462Salfred /* args_ptr may be NULL */ 64174462Salfred 64274462Salfred xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs); 64374462Salfred 64474462Salfred xdrs->x_op = XDR_FREE; 64574462Salfred return ((*xdr_args)(xdrs, args_ptr)); 64674462Salfred} 64774462Salfred 64874462Salfredstatic bool_t 64974462Salfredsvc_vc_reply(xprt, msg) 65074462Salfred SVCXPRT *xprt; 65174462Salfred struct rpc_msg *msg; 65274462Salfred{ 65374462Salfred struct cf_conn *cd; 65474462Salfred XDR *xdrs; 655109359Smbr bool_t rstat; 65674462Salfred 65774462Salfred assert(xprt != NULL); 65874462Salfred assert(msg != NULL); 65974462Salfred 66074462Salfred cd = (struct cf_conn *)(xprt->xp_p1); 66174462Salfred xdrs = &(cd->xdrs); 66274462Salfred 66374462Salfred xdrs->x_op = XDR_ENCODE; 66474462Salfred msg->rm_xid = cd->x_id; 665109359Smbr rstat = xdr_replymsg(xdrs, msg); 66674462Salfred (void)xdrrec_endofrecord(xdrs, TRUE); 667109359Smbr return (rstat); 66874462Salfred} 66974462Salfred 67074462Salfredstatic void 67174462Salfredsvc_vc_ops(xprt) 67274462Salfred SVCXPRT *xprt; 67374462Salfred{ 67474462Salfred static struct xp_ops ops; 67574462Salfred static struct xp_ops2 ops2; 67674462Salfred extern mutex_t ops_lock; 67774462Salfred 67874462Salfred/* VARIABLES PROTECTED BY ops_lock: ops, ops2 */ 67974462Salfred 68074462Salfred mutex_lock(&ops_lock); 68174462Salfred if (ops.xp_recv == NULL) { 68274462Salfred ops.xp_recv = svc_vc_recv; 68374462Salfred ops.xp_stat = svc_vc_stat; 68474462Salfred ops.xp_getargs = svc_vc_getargs; 68574462Salfred ops.xp_reply = svc_vc_reply; 68674462Salfred ops.xp_freeargs = svc_vc_freeargs; 68774462Salfred ops.xp_destroy = svc_vc_destroy; 68874462Salfred ops2.xp_control = svc_vc_control; 68974462Salfred } 69074462Salfred xprt->xp_ops = &ops; 69174462Salfred xprt->xp_ops2 = &ops2; 69274462Salfred mutex_unlock(&ops_lock); 69374462Salfred} 69474462Salfred 69574462Salfredstatic void 69674462Salfredsvc_vc_rendezvous_ops(xprt) 69774462Salfred SVCXPRT *xprt; 69874462Salfred{ 69974462Salfred static struct xp_ops ops; 70074462Salfred static struct xp_ops2 ops2; 70174462Salfred extern mutex_t ops_lock; 70274462Salfred 70374462Salfred mutex_lock(&ops_lock); 70474462Salfred if (ops.xp_recv == NULL) { 70574462Salfred ops.xp_recv = rendezvous_request; 70674462Salfred ops.xp_stat = rendezvous_stat; 70774462Salfred ops.xp_getargs = 70895658Sdes (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort; 70974462Salfred ops.xp_reply = 71092941Sobrien (bool_t (*)(SVCXPRT *, struct rpc_msg *))abort; 71174462Salfred ops.xp_freeargs = 71295658Sdes (bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort, 71374462Salfred ops.xp_destroy = svc_vc_destroy; 714109359Smbr ops2.xp_control = svc_vc_rendezvous_control; 71574462Salfred } 71674462Salfred xprt->xp_ops = &ops; 71774462Salfred xprt->xp_ops2 = &ops2; 71874462Salfred mutex_unlock(&ops_lock); 71974462Salfred} 72074462Salfred 72174627Salfred/* 722116391Smbr * Get the effective UID of the sending process. Used by rpcbind, keyserv 723116391Smbr * and rpc.yppasswdd on AF_LOCAL. 72474627Salfred */ 72574627Salfredint 726116391Smbr__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) { 727116391Smbr int sock, ret; 728116391Smbr gid_t egid; 729116391Smbr uid_t euid; 730116391Smbr struct sockaddr *sa; 731116391Smbr 732116391Smbr sock = transp->xp_fd; 733116391Smbr sa = (struct sockaddr *)transp->xp_rtaddr.buf; 734116391Smbr if (sa->sa_family == AF_LOCAL) { 735116391Smbr ret = getpeereid(sock, &euid, &egid); 736116391Smbr if (ret == 0) 737116391Smbr *uid = euid; 738116391Smbr return (ret); 739116391Smbr } else 74090257Salfred return (-1); 74174627Salfred} 742109359Smbr 743109359Smbr/* 744109359Smbr * Destroy xprts that have not have had any activity in 'timeout' seconds. 745109359Smbr * If 'cleanblock' is true, blocking connections (the default) are also 746109359Smbr * cleaned. If timeout is 0, the least active connection is picked. 747109359Smbr */ 748109359Smbrbool_t 749109359Smbr__svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock) 750109359Smbr{ 751109359Smbr int i, ncleaned; 752109359Smbr SVCXPRT *xprt, *least_active; 753109359Smbr struct timeval tv, tdiff, tmax; 754109359Smbr struct cf_conn *cd; 755109359Smbr 756109359Smbr gettimeofday(&tv, NULL); 757109359Smbr tmax.tv_sec = tmax.tv_usec = 0; 758109359Smbr least_active = NULL; 759109359Smbr rwlock_wrlock(&svc_fd_lock); 760109359Smbr for (i = ncleaned = 0; i <= svc_maxfd; i++) { 761109359Smbr if (FD_ISSET(i, fds)) { 762109359Smbr xprt = __svc_xports[i]; 763109359Smbr if (xprt == NULL || xprt->xp_ops == NULL || 764109359Smbr xprt->xp_ops->xp_recv != svc_vc_recv) 765109359Smbr continue; 766109359Smbr cd = (struct cf_conn *)xprt->xp_p1; 767109359Smbr if (!cleanblock && !cd->nonblock) 768109359Smbr continue; 769109359Smbr if (timeout == 0) { 770109359Smbr timersub(&tv, &cd->last_recv_time, &tdiff); 771109359Smbr if (timercmp(&tdiff, &tmax, >)) { 772109359Smbr tmax = tdiff; 773109359Smbr least_active = xprt; 774109359Smbr } 775109359Smbr continue; 776109359Smbr } 777109359Smbr if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) { 778109359Smbr __xprt_unregister_unlocked(xprt); 779109359Smbr __svc_vc_dodestroy(xprt); 780109359Smbr ncleaned++; 781109359Smbr } 782109359Smbr } 783109359Smbr } 784109359Smbr if (timeout == 0 && least_active != NULL) { 785109359Smbr __xprt_unregister_unlocked(least_active); 786109359Smbr __svc_vc_dodestroy(least_active); 787109359Smbr ncleaned++; 788109359Smbr } 789109359Smbr rwlock_unlock(&svc_fd_lock); 790109359Smbr return ncleaned > 0 ? TRUE : FALSE; 791109359Smbr} 792