svc_vc.c revision 267654
119370Spst/* $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $ */ 298948Sobrien 3130809Smarcel/*- 498948Sobrien * Copyright (c) 2009, Sun Microsystems, Inc. 519370Spst * All rights reserved. 619370Spst * 798948Sobrien * Redistribution and use in source and binary forms, with or without 819370Spst * modification, are permitted provided that the following conditions are met: 998948Sobrien * - Redistributions of source code must retain the above copyright notice, 1098948Sobrien * this list of conditions and the following disclaimer. 1198948Sobrien * - Redistributions in binary form must reproduce the above copyright notice, 1298948Sobrien * this list of conditions and the following disclaimer in the documentation 1319370Spst * and/or other materials provided with the distribution. 1498948Sobrien * - Neither the name of Sun Microsystems, Inc. nor the names of its 1598948Sobrien * contributors may be used to endorse or promote products derived 1698948Sobrien * from this software without specific prior written permission. 1798948Sobrien * 1819370Spst * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1998948Sobrien * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2098948Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2198948Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 2298948Sobrien * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2319370Spst * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2419370Spst * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2519370Spst * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2619370Spst * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2746283Sdfr * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2819370Spst * POSSIBILITY OF SUCH DAMAGE. 2919370Spst */ 3019370Spst 31130809Smarcel#if defined(LIBC_SCCS) && !defined(lint) 3219370Spststatic char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; 3319370Spststatic char *sccsid = "@(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 3419370Spst#endif 3519370Spst#include <sys/cdefs.h> 3619370Spst__FBSDID("$FreeBSD: releng/9.3/sys/rpc/svc_vc.c 261082 2014-01-23 17:27:16Z mav $"); 3719370Spst 3819370Spst/* 3919370Spst * svc_vc.c, Server side for Connection Oriented based RPC. 4019370Spst * 4119370Spst * Actually implements two flavors of transporter - 4219370Spst * a tcp rendezvouser (a listner and connection establisher) 4319370Spst * and a record/tcp stream. 4498948Sobrien */ 45130809Smarcel 46130809Smarcel#include <sys/param.h> 4719370Spst#include <sys/limits.h> 48130809Smarcel#include <sys/lock.h> 49130809Smarcel#include <sys/kernel.h> 5098948Sobrien#include <sys/malloc.h> 5119370Spst#include <sys/mbuf.h> 5298948Sobrien#include <sys/mutex.h> 5398948Sobrien#include <sys/proc.h> 5498948Sobrien#include <sys/protosw.h> 5598948Sobrien#include <sys/queue.h> 5619370Spst#include <sys/socket.h> 5798948Sobrien#include <sys/socketvar.h> 5898948Sobrien#include <sys/sx.h> 5998948Sobrien#include <sys/systm.h> 6098948Sobrien#include <sys/uio.h> 6198948Sobrien 6298948Sobrien#include <net/vnet.h> 6398948Sobrien 6419370Spst#include <netinet/tcp.h> 6519370Spst 6619370Spst#include <rpc/rpc.h> 6719370Spst 6819370Spst#include <rpc/krpc.h> 6919370Spst#include <rpc/rpc_com.h> 7019370Spst 7119370Spst#include <security/mac/mac_framework.h> 7219370Spst 7319370Spststatic bool_t svc_vc_rendezvous_recv(SVCXPRT *, struct rpc_msg *, 7419370Spst struct sockaddr **, struct mbuf **); 7519370Spststatic enum xprt_stat svc_vc_rendezvous_stat(SVCXPRT *); 7619370Spststatic void svc_vc_rendezvous_destroy(SVCXPRT *); 7719370Spststatic bool_t svc_vc_null(void); 7819370Spststatic void svc_vc_destroy(SVCXPRT *); 7919370Spststatic enum xprt_stat svc_vc_stat(SVCXPRT *); 8019370Spststatic bool_t svc_vc_ack(SVCXPRT *, uint32_t *); 8119370Spststatic bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *, 8219370Spst struct sockaddr **, struct mbuf **); 8319370Spststatic bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *, 8419370Spst struct sockaddr *, struct mbuf *, uint32_t *seq); 8519370Spststatic bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in); 8619370Spststatic bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq, 8719370Spst void *in); 8819370Spststatic void svc_vc_backchannel_destroy(SVCXPRT *); 8919370Spststatic enum xprt_stat svc_vc_backchannel_stat(SVCXPRT *); 9019370Spststatic bool_t svc_vc_backchannel_recv(SVCXPRT *, struct rpc_msg *, 9119370Spst struct sockaddr **, struct mbuf **); 9219370Spststatic bool_t svc_vc_backchannel_reply(SVCXPRT *, struct rpc_msg *, 9319370Spst struct sockaddr *, struct mbuf *, uint32_t *); 9419370Spststatic bool_t svc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, 9519370Spst void *in); 9619370Spststatic SVCXPRT *svc_vc_create_conn(SVCPOOL *pool, struct socket *so, 9719370Spst struct sockaddr *raddr); 9819370Spststatic int svc_vc_accept(struct socket *head, struct socket **sop); 9998948Sobrienstatic int svc_vc_soupcall(struct socket *so, void *arg, int waitflag); 10098948Sobrien 10198948Sobrienstatic struct xp_ops svc_vc_rendezvous_ops = { 10298948Sobrien .xp_recv = svc_vc_rendezvous_recv, 10319370Spst .xp_stat = svc_vc_rendezvous_stat, 10419370Spst .xp_reply = (bool_t (*)(SVCXPRT *, struct rpc_msg *, 10519370Spst struct sockaddr *, struct mbuf *, uint32_t *))svc_vc_null, 10619370Spst .xp_destroy = svc_vc_rendezvous_destroy, 10719370Spst .xp_control = svc_vc_rendezvous_control 10898948Sobrien}; 10919370Spst 11019370Spststatic struct xp_ops svc_vc_ops = { 11119370Spst .xp_recv = svc_vc_recv, 11219370Spst .xp_stat = svc_vc_stat, 11319370Spst .xp_ack = svc_vc_ack, 11498948Sobrien .xp_reply = svc_vc_reply, 11598948Sobrien .xp_destroy = svc_vc_destroy, 11698948Sobrien .xp_control = svc_vc_control 11719370Spst}; 11846283Sdfr 11946283Sdfrstatic struct xp_ops svc_vc_backchannel_ops = { 12046283Sdfr .xp_recv = svc_vc_backchannel_recv, 12146283Sdfr .xp_stat = svc_vc_backchannel_stat, 12219370Spst .xp_reply = svc_vc_backchannel_reply, 12319370Spst .xp_destroy = svc_vc_backchannel_destroy, 12419370Spst .xp_control = svc_vc_backchannel_control 12519370Spst}; 12619370Spst 12719370Spst/* 12819370Spst * Usage: 12998948Sobrien * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); 13098948Sobrien * 13198948Sobrien * Creates, registers, and returns a (rpc) tcp based transporter. 13298948Sobrien * Once *xprt is initialized, it is registered as a transporter 13398948Sobrien * see (svc.h, xprt_register). This routine returns 13498948Sobrien * a NULL if a problem occurred. 13598948Sobrien * 13698948Sobrien * The filedescriptor passed in is expected to refer to a bound, but 13798948Sobrien * not yet connected socket. 13898948Sobrien * 13919370Spst * Since streams do buffered io similar to stdio, the caller can specify 14098948Sobrien * how big the send and receive buffers are via the second and third parms; 14119370Spst * 0 => use the system default. 14298948Sobrien */ 14319370SpstSVCXPRT * 14498948Sobriensvc_vc_create(SVCPOOL *pool, struct socket *so, size_t sendsize, 14598948Sobrien size_t recvsize) 14619370Spst{ 14798948Sobrien SVCXPRT *xprt; 14898948Sobrien struct sockaddr* sa; 14919370Spst int error; 15098948Sobrien 15198948Sobrien SOCK_LOCK(so); 15298948Sobrien if (so->so_state & (SS_ISCONNECTED|SS_ISDISCONNECTED)) { 15319370Spst SOCK_UNLOCK(so); 15498948Sobrien error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa); 15519370Spst if (error) 15698948Sobrien return (NULL); 15798948Sobrien xprt = svc_vc_create_conn(pool, so, sa); 15898948Sobrien free(sa, M_SONAME); 15919370Spst return (xprt); 16098948Sobrien } 16119370Spst SOCK_UNLOCK(so); 16298948Sobrien 16319370Spst xprt = svc_xprt_alloc(); 16498948Sobrien sx_init(&xprt->xp_lock, "xprt->xp_lock"); 16519370Spst xprt->xp_pool = pool; 16698948Sobrien xprt->xp_socket = so; 16719370Spst xprt->xp_p1 = NULL; 16898948Sobrien xprt->xp_p2 = NULL; 16919370Spst xprt->xp_ops = &svc_vc_rendezvous_ops; 17098948Sobrien 17119370Spst error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 17298948Sobrien if (error) { 17319370Spst goto cleanup_svc_vc_create; 17498948Sobrien } 17519370Spst 17698948Sobrien memcpy(&xprt->xp_ltaddr, sa, sa->sa_len); 17719370Spst free(sa, M_SONAME); 17898948Sobrien 17919370Spst xprt_register(xprt); 18098948Sobrien 18198948Sobrien solisten(so, SOMAXCONN, curthread); 18219370Spst 18398948Sobrien SOCKBUF_LOCK(&so->so_rcv); 18419370Spst xprt->xp_upcallset = 1; 18519370Spst soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt); 18619370Spst SOCKBUF_UNLOCK(&so->so_rcv); 18719370Spst 18819370Spst return (xprt); 18919370Spstcleanup_svc_vc_create: 19019370Spst if (xprt) { 19119370Spst sx_destroy(&xprt->xp_lock); 19219370Spst svc_xprt_free(xprt); 19319370Spst } 19419370Spst return (NULL); 19519370Spst} 19698948Sobrien 19719370Spst/* 198130809Smarcel * Create a new transport for a socket optained via soaccept(). 19919370Spst */ 20019370SpstSVCXPRT * 20119370Spstsvc_vc_create_conn(SVCPOOL *pool, struct socket *so, struct sockaddr *raddr) 20219370Spst{ 203130809Smarcel SVCXPRT *xprt = NULL; 20419370Spst struct cf_conn *cd = NULL; 20519370Spst struct sockaddr* sa = NULL; 20619370Spst struct sockopt opt; 20719370Spst int one = 1; 20819370Spst int error; 20919370Spst 21019370Spst bzero(&opt, sizeof(struct sockopt)); 21119370Spst opt.sopt_dir = SOPT_SET; 212130809Smarcel opt.sopt_level = SOL_SOCKET; 21319370Spst opt.sopt_name = SO_KEEPALIVE; 21419370Spst opt.sopt_val = &one; 21519370Spst opt.sopt_valsize = sizeof(one); 21619370Spst error = sosetopt(so, &opt); 21719370Spst if (error) { 21819370Spst return (NULL); 21919370Spst } 22019370Spst 22119370Spst if (so->so_proto->pr_protocol == IPPROTO_TCP) { 22219370Spst bzero(&opt, sizeof(struct sockopt)); 22398948Sobrien opt.sopt_dir = SOPT_SET; 22419370Spst opt.sopt_level = IPPROTO_TCP; 22519370Spst opt.sopt_name = TCP_NODELAY; 22619370Spst opt.sopt_val = &one; 22719370Spst opt.sopt_valsize = sizeof(one); 22819370Spst error = sosetopt(so, &opt); 22919370Spst if (error) { 23019370Spst return (NULL); 23119370Spst } 23219370Spst } 23319370Spst 23419370Spst cd = mem_alloc(sizeof(*cd)); 23519370Spst cd->strm_stat = XPRT_IDLE; 23619370Spst 23719370Spst xprt = svc_xprt_alloc(); 23898948Sobrien sx_init(&xprt->xp_lock, "xprt->xp_lock"); 23998948Sobrien xprt->xp_pool = pool; 24098948Sobrien xprt->xp_socket = so; 24119370Spst xprt->xp_p1 = cd; 24219370Spst xprt->xp_p2 = NULL; 24319370Spst xprt->xp_ops = &svc_vc_ops; 24419370Spst 24519370Spst /* 24698948Sobrien * See http://www.connectathon.org/talks96/nfstcp.pdf - client 24719370Spst * has a 5 minute timer, server has a 6 minute timer. 24898948Sobrien */ 24998948Sobrien xprt->xp_idletimeout = 6 * 60; 25098948Sobrien 25198948Sobrien memcpy(&xprt->xp_rtaddr, raddr, raddr->sa_len); 25298948Sobrien 25319370Spst error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 25498948Sobrien if (error) 25598948Sobrien goto cleanup_svc_vc_create; 25619370Spst 25798948Sobrien memcpy(&xprt->xp_ltaddr, sa, sa->sa_len); 25819370Spst free(sa, M_SONAME); 25946283Sdfr 26019370Spst xprt_register(xprt); 26119370Spst 26219370Spst SOCKBUF_LOCK(&so->so_rcv); 26319370Spst xprt->xp_upcallset = 1; 26498948Sobrien soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt); 26519370Spst SOCKBUF_UNLOCK(&so->so_rcv); 26646283Sdfr 26746283Sdfr /* 26898948Sobrien * Throw the transport into the active list in case it already 26946283Sdfr * has some data buffered. 27019370Spst */ 27146283Sdfr sx_xlock(&xprt->xp_lock); 27219370Spst xprt_active(xprt); 27346283Sdfr sx_xunlock(&xprt->xp_lock); 27446283Sdfr 27546283Sdfr return (xprt); 27646283Sdfrcleanup_svc_vc_create: 27798948Sobrien if (xprt) { 27846283Sdfr sx_destroy(&xprt->xp_lock); 27998948Sobrien svc_xprt_free(xprt); 28046283Sdfr } 28198948Sobrien if (cd) 28298948Sobrien mem_free(cd, sizeof(*cd)); 28346283Sdfr return (NULL); 28419370Spst} 28519370Spst 28619370Spst/* 28746283Sdfr * Create a new transport for a backchannel on a clnt_vc socket. 28846283Sdfr */ 28998948SobrienSVCXPRT * 29046283Sdfrsvc_vc_create_backchannel(SVCPOOL *pool) 29146283Sdfr{ 29298948Sobrien SVCXPRT *xprt = NULL; 29346283Sdfr struct cf_conn *cd = NULL; 29446283Sdfr 29546283Sdfr cd = mem_alloc(sizeof(*cd)); 29646283Sdfr cd->strm_stat = XPRT_IDLE; 29746283Sdfr 29846283Sdfr xprt = svc_xprt_alloc(); 29946283Sdfr sx_init(&xprt->xp_lock, "xprt->xp_lock"); 30046283Sdfr xprt->xp_pool = pool; 30146283Sdfr xprt->xp_socket = NULL; 30246283Sdfr xprt->xp_p1 = cd; 30346283Sdfr xprt->xp_p2 = NULL; 30446283Sdfr xprt->xp_ops = &svc_vc_backchannel_ops; 30546283Sdfr return (xprt); 30619370Spst} 30719370Spst 30819370Spst/* 30919370Spst * This does all of the accept except the final call to soaccept. The 31019370Spst * caller will call soaccept after dropping its locks (soaccept may 31119370Spst * call malloc). 31219370Spst */ 31319370Spstint 314130809Smarcelsvc_vc_accept(struct socket *head, struct socket **sop) 31519370Spst{ 31619370Spst int error = 0; 31719370Spst struct socket *so; 31819370Spst 31919370Spst if ((head->so_options & SO_ACCEPTCONN) == 0) { 32019370Spst error = EINVAL; 32198948Sobrien goto done; 32219370Spst } 32319370Spst#ifdef MAC 32419370Spst error = mac_socket_check_accept(curthread->td_ucred, head); 32519370Spst if (error != 0) 32619370Spst goto done; 32719370Spst#endif 32898948Sobrien ACCEPT_LOCK(); 32919370Spst if (TAILQ_EMPTY(&head->so_comp)) { 33019370Spst ACCEPT_UNLOCK(); 33119370Spst error = EWOULDBLOCK; 33219370Spst goto done; 33319370Spst } 33419370Spst so = TAILQ_FIRST(&head->so_comp); 33519370Spst KASSERT(!(so->so_qstate & SQ_INCOMP), ("svc_vc_accept: so SQ_INCOMP")); 33619370Spst KASSERT(so->so_qstate & SQ_COMP, ("svc_vc_accept: so not SQ_COMP")); 33719370Spst 33898948Sobrien /* 33919370Spst * Before changing the flags on the socket, we have to bump the 340130809Smarcel * reference count. Otherwise, if the protocol calls sofree(), 341130809Smarcel * the socket will be released due to a zero refcount. 34219370Spst * XXX might not need soref() since this is simpler than kern_accept. 34319370Spst */ 34419370Spst SOCK_LOCK(so); /* soref() and so_state update */ 34519370Spst soref(so); /* file descriptor reference */ 34619370Spst 34719370Spst TAILQ_REMOVE(&head->so_comp, so, so_list); 34819370Spst head->so_qlen--; 34919370Spst so->so_state |= (head->so_state & SS_NBIO); 35019370Spst so->so_qstate &= ~SQ_COMP; 35119370Spst so->so_head = NULL; 35219370Spst 35319370Spst SOCK_UNLOCK(so); 35419370Spst ACCEPT_UNLOCK(); 35519370Spst 35619370Spst *sop = so; 35719370Spst 35819370Spst /* connection has been removed from the listen queue */ 35998948Sobrien KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0); 36019370Spstdone: 36119370Spst return (error); 36298948Sobrien} 36398948Sobrien 36498948Sobrien/*ARGSUSED*/ 36598948Sobrienstatic bool_t 36698948Sobriensvc_vc_rendezvous_recv(SVCXPRT *xprt, struct rpc_msg *msg, 36798948Sobrien struct sockaddr **addrp, struct mbuf **mp) 36898948Sobrien{ 36998948Sobrien struct socket *so = NULL; 37098948Sobrien struct sockaddr *sa = NULL; 37198948Sobrien int error; 37246283Sdfr SVCXPRT *new_xprt; 37319370Spst 37419370Spst /* 37519370Spst * The socket upcall calls xprt_active() which will eventually 37619370Spst * cause the server to call us here. We attempt to accept a 37719370Spst * connection from the socket and turn it into a new 37819370Spst * transport. If the accept fails, we have drained all pending 37919370Spst * connections so we call xprt_inactive(). 38019370Spst */ 38198948Sobrien sx_xlock(&xprt->xp_lock); 38219370Spst 38319370Spst error = svc_vc_accept(xprt->xp_socket, &so); 38498948Sobrien 38519370Spst if (error == EWOULDBLOCK) { 38619370Spst /* 38719370Spst * We must re-test for new connections after taking 38819370Spst * the lock to protect us in the case where a new 38998948Sobrien * connection arrives after our call to accept fails 39098948Sobrien * with EWOULDBLOCK. 39119370Spst */ 392130809Smarcel ACCEPT_LOCK(); 393130809Smarcel if (TAILQ_EMPTY(&xprt->xp_socket->so_comp)) 39419370Spst xprt_inactive_self(xprt); 39519370Spst ACCEPT_UNLOCK(); 39619370Spst sx_xunlock(&xprt->xp_lock); 39719370Spst return (FALSE); 39819370Spst } 39919370Spst 40019370Spst if (error) { 40119370Spst SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 40219370Spst if (xprt->xp_upcallset) { 40398948Sobrien xprt->xp_upcallset = 0; 40419370Spst soupcall_clear(xprt->xp_socket, SO_RCV); 40519370Spst } 40619370Spst SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 40719370Spst xprt_inactive_self(xprt); 40819370Spst sx_xunlock(&xprt->xp_lock); 40998948Sobrien return (FALSE); 41019370Spst } 41119370Spst 41219370Spst sx_xunlock(&xprt->xp_lock); 41319370Spst 41419370Spst sa = 0; 41519370Spst error = soaccept(so, &sa); 41619370Spst 41719370Spst if (error) { 41819370Spst /* 41998948Sobrien * XXX not sure if I need to call sofree or soclose here. 42098948Sobrien */ 42119370Spst if (sa) 42219370Spst free(sa, M_SONAME); 42398948Sobrien return (FALSE); 42498948Sobrien } 42519370Spst 42646283Sdfr /* 42719370Spst * svc_vc_create_conn will call xprt_register - we don't need 42819370Spst * to do anything with the new connection except derefence it. 42919370Spst */ 43019370Spst new_xprt = svc_vc_create_conn(xprt->xp_pool, so, sa); 43119370Spst if (!new_xprt) { 43219370Spst soclose(so); 43319370Spst } else { 43419370Spst SVC_RELEASE(new_xprt); 43519370Spst } 43619370Spst 43719370Spst free(sa, M_SONAME); 43819370Spst 43919370Spst return (FALSE); /* there is never an rpc msg to be processed */ 44019370Spst} 44119370Spst 44219370Spst/*ARGSUSED*/ 44398948Sobrienstatic enum xprt_stat 44419370Spstsvc_vc_rendezvous_stat(SVCXPRT *xprt) 44519370Spst{ 44646283Sdfr 44719370Spst return (XPRT_IDLE); 44819370Spst} 44998948Sobrien 45098948Sobrienstatic void 45119370Spstsvc_vc_destroy_common(SVCXPRT *xprt) 45219370Spst{ 45319370Spst SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 45419370Spst if (xprt->xp_upcallset) { 45519370Spst xprt->xp_upcallset = 0; 45619370Spst soupcall_clear(xprt->xp_socket, SO_RCV); 45719370Spst } 45819370Spst SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 45919370Spst 46019370Spst if (xprt->xp_socket) 46119370Spst (void)soclose(xprt->xp_socket); 46219370Spst 46319370Spst if (xprt->xp_netid) 46419370Spst (void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1); 46519370Spst svc_xprt_free(xprt); 46619370Spst} 46719370Spst 46819370Spststatic void 46919370Spstsvc_vc_rendezvous_destroy(SVCXPRT *xprt) 47019370Spst{ 471130809Smarcel 47219370Spst svc_vc_destroy_common(xprt); 47319370Spst} 47419370Spst 47519370Spststatic void 47619370Spstsvc_vc_destroy(SVCXPRT *xprt) 47719370Spst{ 47819370Spst struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1; 47919370Spst 48019370Spst svc_vc_destroy_common(xprt); 48119370Spst 48219370Spst if (cd->mreq) 48319370Spst m_freem(cd->mreq); 48419370Spst if (cd->mpending) 48598948Sobrien m_freem(cd->mpending); 48619370Spst mem_free(cd, sizeof(*cd)); 48719370Spst} 48819370Spst 48919370Spststatic void 49019370Spstsvc_vc_backchannel_destroy(SVCXPRT *xprt) 49119370Spst{ 49219370Spst struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1; 49319370Spst struct mbuf *m, *m2; 49419370Spst 49519370Spst svc_xprt_free(xprt); 49619370Spst m = cd->mreq; 49719370Spst while (m != NULL) { 49819370Spst m2 = m; 49919370Spst m = m->m_nextpkt; 50019370Spst m_freem(m2); 50119370Spst } 50219370Spst mem_free(cd, sizeof(*cd)); 50319370Spst} 50419370Spst 50519370Spst/*ARGSUSED*/ 50619370Spststatic bool_t 50798948Sobriensvc_vc_control(SVCXPRT *xprt, const u_int rq, void *in) 50819370Spst{ 50919370Spst return (FALSE); 51019370Spst} 51119370Spst 51219370Spststatic bool_t 51319370Spstsvc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in) 514130809Smarcel{ 51598948Sobrien 51619370Spst return (FALSE); 51719370Spst} 518130809Smarcel 51919370Spststatic bool_t 52098948Sobriensvc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, void *in) 52198948Sobrien{ 52298948Sobrien 52398948Sobrien return (FALSE); 52446283Sdfr} 52598948Sobrien 52619370Spststatic enum xprt_stat 52719370Spstsvc_vc_stat(SVCXPRT *xprt) 52898948Sobrien{ 52998948Sobrien struct cf_conn *cd; 53098948Sobrien 53198948Sobrien cd = (struct cf_conn *)(xprt->xp_p1); 53219370Spst 53319370Spst if (cd->strm_stat == XPRT_DIED) 53419370Spst return (XPRT_DIED); 53519370Spst 53619370Spst if (cd->mreq != NULL && cd->resid == 0 && cd->eor) 53798948Sobrien return (XPRT_MOREREQS); 53819370Spst 53998948Sobrien if (soreadable(xprt->xp_socket)) 54098948Sobrien return (XPRT_MOREREQS); 54198948Sobrien 54219370Spst return (XPRT_IDLE); 54319370Spst} 54419370Spst 54519370Spststatic bool_t 54698948Sobriensvc_vc_ack(SVCXPRT *xprt, uint32_t *ack) 54719370Spst{ 54898948Sobrien 54946283Sdfr *ack = atomic_load_acq_32(&xprt->xp_snt_cnt); 55046283Sdfr *ack -= xprt->xp_socket->so_snd.sb_cc; 55146283Sdfr return (TRUE); 55246283Sdfr} 55346283Sdfr 55446283Sdfrstatic enum xprt_stat 55598948Sobriensvc_vc_backchannel_stat(SVCXPRT *xprt) 55698948Sobrien{ 55798948Sobrien struct cf_conn *cd; 55846283Sdfr 55919370Spst cd = (struct cf_conn *)(xprt->xp_p1); 56019370Spst 56119370Spst if (cd->mreq != NULL) 56219370Spst return (XPRT_MOREREQS); 56319370Spst 564130809Smarcel return (XPRT_IDLE); 56519370Spst} 566130809Smarcel 567130809Smarcel/* 568130809Smarcel * If we have an mbuf chain in cd->mpending, try to parse a record from it, 569130809Smarcel * leaving the result in cd->mreq. If we don't have a complete record, leave 570130809Smarcel * the partial result in cd->mreq and try to read more from the socket. 571130809Smarcel */ 572130809Smarcelstatic int 573130809Smarcelsvc_vc_process_pending(SVCXPRT *xprt) 574130809Smarcel{ 575130809Smarcel struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 576130809Smarcel struct socket *so = xprt->xp_socket; 577130809Smarcel struct mbuf *m; 578130809Smarcel 579130809Smarcel /* 580130809Smarcel * If cd->resid is non-zero, we have part of the 581130809Smarcel * record already, otherwise we are expecting a record 582130809Smarcel * marker. 583130809Smarcel */ 584130809Smarcel if (!cd->resid && cd->mpending) { 585130809Smarcel /* 586130809Smarcel * See if there is enough data buffered to 587130809Smarcel * make up a record marker. Make sure we can 588130809Smarcel * handle the case where the record marker is 589130809Smarcel * split across more than one mbuf. 59019370Spst */ 59119370Spst size_t n = 0; 59298948Sobrien uint32_t header; 59319370Spst 59419370Spst m = cd->mpending; 59519370Spst while (n < sizeof(uint32_t) && m) { 59619370Spst n += m->m_len; 59719370Spst m = m->m_next; 598130809Smarcel } 59919370Spst if (n < sizeof(uint32_t)) { 60019370Spst so->so_rcv.sb_lowat = sizeof(uint32_t) - n; 60119370Spst return (FALSE); 60219370Spst } 60398948Sobrien m_copydata(cd->mpending, 0, sizeof(header), 60419370Spst (char *)&header); 60519370Spst header = ntohl(header); 60619370Spst cd->eor = (header & 0x80000000) != 0; 60719370Spst cd->resid = header & 0x7fffffff; 60819370Spst m_adj(cd->mpending, sizeof(uint32_t)); 60919370Spst } 610130809Smarcel 611130809Smarcel /* 612130809Smarcel * Start pulling off mbufs from cd->mpending 61398948Sobrien * until we either have a complete record or 61419370Spst * we run out of data. We use m_split to pull 61519370Spst * data - it will pull as much as possible and 61619370Spst * split the last mbuf if necessary. 61798948Sobrien */ 61898948Sobrien while (cd->mpending && cd->resid) { 61998948Sobrien m = cd->mpending; 62098948Sobrien if (cd->mpending->m_next 62198948Sobrien || cd->mpending->m_len > cd->resid) 62298948Sobrien cd->mpending = m_split(cd->mpending, 62398948Sobrien cd->resid, M_WAITOK); 62498948Sobrien else 62519370Spst cd->mpending = NULL; 62698948Sobrien if (cd->mreq) 62719370Spst m_last(cd->mreq)->m_next = m; 62819370Spst else 62919370Spst cd->mreq = m; 63019370Spst while (m) { 63119370Spst cd->resid -= m->m_len; 63219370Spst m = m->m_next; 63319370Spst } 63419370Spst } 63519370Spst 63619370Spst /* 63798948Sobrien * Block receive upcalls if we have more data pending, 63898948Sobrien * otherwise report our need. 63998948Sobrien */ 64098948Sobrien if (cd->mpending) 64198948Sobrien so->so_rcv.sb_lowat = INT_MAX; 64219370Spst else 64319370Spst so->so_rcv.sb_lowat = 64419370Spst imax(1, imin(cd->resid, so->so_rcv.sb_hiwat / 2)); 64519370Spst return (TRUE); 64619370Spst} 64798948Sobrien 64819370Spststatic bool_t 64919370Spstsvc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg, 65019370Spst struct sockaddr **addrp, struct mbuf **mp) 65119370Spst{ 65219370Spst struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 65319370Spst struct uio uio; 65419370Spst struct mbuf *m; 65519370Spst struct socket* so = xprt->xp_socket; 65619370Spst XDR xdrs; 65798948Sobrien int error, rcvflag; 65819370Spst 65998948Sobrien /* 66019370Spst * Serialise access to the socket and our own record parsing 66198948Sobrien * state. 66219370Spst */ 66398948Sobrien sx_xlock(&xprt->xp_lock); 66498948Sobrien 66598948Sobrien for (;;) { 66619370Spst /* If we have no request ready, check pending queue. */ 66798948Sobrien while (cd->mpending && 66819370Spst (cd->mreq == NULL || cd->resid != 0 || !cd->eor)) { 66919370Spst if (!svc_vc_process_pending(xprt)) 67019370Spst break; 67119370Spst } 67219370Spst 67319370Spst /* Process and return complete request in cd->mreq. */ 67419370Spst if (cd->mreq != NULL && cd->resid == 0 && cd->eor) { 67598948Sobrien 67698948Sobrien xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE); 67719370Spst cd->mreq = NULL; 678130809Smarcel 67919370Spst /* Check for next request in a pending queue. */ 680130809Smarcel svc_vc_process_pending(xprt); 68119370Spst if (cd->mreq == NULL || cd->resid != 0) { 68219370Spst SOCKBUF_LOCK(&so->so_rcv); 68319370Spst if (!soreadable(so)) 68419370Spst xprt_inactive_self(xprt); 68519370Spst SOCKBUF_UNLOCK(&so->so_rcv); 68619370Spst } 68719370Spst 68819370Spst sx_xunlock(&xprt->xp_lock); 68919370Spst 69019370Spst if (! xdr_callmsg(&xdrs, msg)) { 69119370Spst XDR_DESTROY(&xdrs); 69219370Spst return (FALSE); 69319370Spst } 69498948Sobrien 69519370Spst *addrp = NULL; 69619370Spst *mp = xdrmbuf_getall(&xdrs); 69719370Spst XDR_DESTROY(&xdrs); 69819370Spst 69919370Spst return (TRUE); 70019370Spst } 70119370Spst 70219370Spst /* 70319370Spst * The socket upcall calls xprt_active() which will eventually 70419370Spst * cause the server to call us here. We attempt to 70519370Spst * read as much as possible from the socket and put 70619370Spst * the result in cd->mpending. If the read fails, 70719370Spst * we have drained both cd->mpending and the socket so 70819370Spst * we can call xprt_inactive(). 70919370Spst */ 71019370Spst uio.uio_resid = 1000000000; 71119370Spst uio.uio_td = curthread; 71219370Spst m = NULL; 71319370Spst rcvflag = MSG_DONTWAIT; 71419370Spst error = soreceive(so, NULL, &uio, &m, NULL, &rcvflag); 71519370Spst 71619370Spst if (error == EWOULDBLOCK) { 71719370Spst /* 71819370Spst * We must re-test for readability after 71919370Spst * taking the lock to protect us in the case 72019370Spst * where a new packet arrives on the socket 72119370Spst * after our call to soreceive fails with 72219370Spst * EWOULDBLOCK. 72319370Spst */ 72419370Spst SOCKBUF_LOCK(&so->so_rcv); 72519370Spst if (!soreadable(so)) 72619370Spst xprt_inactive_self(xprt); 72719370Spst SOCKBUF_UNLOCK(&so->so_rcv); 72898948Sobrien sx_xunlock(&xprt->xp_lock); 72998948Sobrien return (FALSE); 73019370Spst } 73119370Spst 73219370Spst if (error) { 73319370Spst SOCKBUF_LOCK(&so->so_rcv); 73419370Spst if (xprt->xp_upcallset) { 73546283Sdfr xprt->xp_upcallset = 0; 73619370Spst soupcall_clear(so, SO_RCV); 73719370Spst } 73819370Spst SOCKBUF_UNLOCK(&so->so_rcv); 73919370Spst xprt_inactive_self(xprt); 74019370Spst cd->strm_stat = XPRT_DIED; 74119370Spst sx_xunlock(&xprt->xp_lock); 74219370Spst return (FALSE); 74319370Spst } 74419370Spst 74519370Spst if (!m) { 74619370Spst /* 74719370Spst * EOF - the other end has closed the socket. 74819370Spst */ 74946283Sdfr xprt_inactive_self(xprt); 75019370Spst cd->strm_stat = XPRT_DIED; 75119370Spst sx_xunlock(&xprt->xp_lock); 75219370Spst return (FALSE); 75319370Spst } 75419370Spst 75519370Spst if (cd->mpending) 75619370Spst m_last(cd->mpending)->m_next = m; 75719370Spst else 75819370Spst cd->mpending = m; 75919370Spst } 76019370Spst} 76119370Spst 76219370Spststatic bool_t 76398948Sobriensvc_vc_backchannel_recv(SVCXPRT *xprt, struct rpc_msg *msg, 76419370Spst struct sockaddr **addrp, struct mbuf **mp) 76519370Spst{ 76619370Spst struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 76719370Spst struct ct_data *ct; 76819370Spst struct mbuf *m; 76919370Spst XDR xdrs; 77019370Spst 77119370Spst sx_xlock(&xprt->xp_lock); 77219370Spst ct = (struct ct_data *)xprt->xp_p2; 77319370Spst if (ct == NULL) { 77419370Spst sx_xunlock(&xprt->xp_lock); 77519370Spst return (FALSE); 77698948Sobrien } 77798948Sobrien mtx_lock(&ct->ct_lock); 77898948Sobrien m = cd->mreq; 77998948Sobrien if (m == NULL) { 78098948Sobrien xprt_inactive_self(xprt); 78198948Sobrien mtx_unlock(&ct->ct_lock); 78298948Sobrien sx_xunlock(&xprt->xp_lock); 783130809Smarcel return (FALSE); 784130809Smarcel } 78598948Sobrien cd->mreq = m->m_nextpkt; 78619370Spst mtx_unlock(&ct->ct_lock); 78798948Sobrien sx_xunlock(&xprt->xp_lock); 78898948Sobrien 78998948Sobrien xdrmbuf_create(&xdrs, m, XDR_DECODE); 79098948Sobrien if (! xdr_callmsg(&xdrs, msg)) { 79198948Sobrien XDR_DESTROY(&xdrs); 79298948Sobrien return (FALSE); 79398948Sobrien } 79498948Sobrien *addrp = NULL; 79519370Spst *mp = xdrmbuf_getall(&xdrs); 79698948Sobrien XDR_DESTROY(&xdrs); 79798948Sobrien return (TRUE); 79898948Sobrien} 79998948Sobrien 80098948Sobrienstatic bool_t 80198948Sobriensvc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg, 80298948Sobrien struct sockaddr *addr, struct mbuf *m, uint32_t *seq) 80398948Sobrien{ 80498948Sobrien XDR xdrs; 80519370Spst struct mbuf *mrep; 80646283Sdfr bool_t stat = TRUE; 80746283Sdfr int error, len; 80846283Sdfr 80998948Sobrien /* 81098948Sobrien * Leave space for record mark. 81198948Sobrien */ 81298948Sobrien MGETHDR(mrep, M_WAIT, MT_DATA); 81398948Sobrien mrep->m_len = 0; 81498948Sobrien mrep->m_data += sizeof(uint32_t); 81598948Sobrien 81698948Sobrien xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); 81798948Sobrien 81898948Sobrien if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 81998948Sobrien msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 820130809Smarcel if (!xdr_replymsg(&xdrs, msg)) 82198948Sobrien stat = FALSE; 82219370Spst else 82319370Spst xdrmbuf_append(&xdrs, m); 82419370Spst } else { 82519370Spst stat = xdr_replymsg(&xdrs, msg); 82619370Spst } 82719370Spst 82819370Spst if (stat) { 82998948Sobrien m_fixhdr(mrep); 83019370Spst 83119370Spst /* 83219370Spst * Prepend a record marker containing the reply length. 83398948Sobrien */ 83419370Spst M_PREPEND(mrep, sizeof(uint32_t), M_WAIT); 83519370Spst len = mrep->m_pkthdr.len; 83698948Sobrien *mtod(mrep, uint32_t *) = 83798948Sobrien htonl(0x80000000 | (len - sizeof(uint32_t))); 83898948Sobrien atomic_add_acq_32(&xprt->xp_snd_cnt, len); 83998948Sobrien error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL, 84098948Sobrien 0, curthread); 84198948Sobrien if (!error) { 84298948Sobrien atomic_add_rel_32(&xprt->xp_snt_cnt, len); 84398948Sobrien if (seq) 84498948Sobrien *seq = xprt->xp_snd_cnt; 84598948Sobrien stat = TRUE; 84698948Sobrien } else 84798948Sobrien atomic_subtract_32(&xprt->xp_snd_cnt, len); 84819370Spst } else { 84998948Sobrien m_freem(mrep); 85098948Sobrien } 85198948Sobrien 85298948Sobrien XDR_DESTROY(&xdrs); 85398948Sobrien xprt->xp_p2 = NULL; 85498948Sobrien 85598948Sobrien return (stat); 85698948Sobrien} 85798948Sobrien 85898948Sobrienstatic bool_t 85919370Spstsvc_vc_backchannel_reply(SVCXPRT *xprt, struct rpc_msg *msg, 86098948Sobrien struct sockaddr *addr, struct mbuf *m, uint32_t *seq) 86198948Sobrien{ 86219370Spst struct ct_data *ct; 86398948Sobrien XDR xdrs; 86419370Spst struct mbuf *mrep; 86598948Sobrien bool_t stat = TRUE; 86698948Sobrien int error; 86798948Sobrien 86898948Sobrien /* 86998948Sobrien * Leave space for record mark. 87098948Sobrien */ 87119370Spst MGETHDR(mrep, M_WAITOK, MT_DATA); 87219370Spst mrep->m_len = 0; 87398948Sobrien mrep->m_data += sizeof(uint32_t); 87498948Sobrien 87598948Sobrien xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); 87698948Sobrien 87798948Sobrien if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 87898948Sobrien msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 87998948Sobrien if (!xdr_replymsg(&xdrs, msg)) 88098948Sobrien stat = FALSE; 881130809Smarcel else 882130809Smarcel xdrmbuf_append(&xdrs, m); 883130809Smarcel } else { 884130809Smarcel stat = xdr_replymsg(&xdrs, msg); 885130809Smarcel } 886130809Smarcel 887130809Smarcel if (stat) { 888130809Smarcel m_fixhdr(mrep); 88998948Sobrien 89098948Sobrien /* 89198948Sobrien * Prepend a record marker containing the reply length. 89298948Sobrien */ 893130809Smarcel M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK); 894130809Smarcel *mtod(mrep, uint32_t *) = 895130809Smarcel htonl(0x80000000 | (mrep->m_pkthdr.len 896130809Smarcel - sizeof(uint32_t))); 897130809Smarcel sx_xlock(&xprt->xp_lock); 89898948Sobrien ct = (struct ct_data *)xprt->xp_p2; 89919370Spst if (ct != NULL) 90098948Sobrien error = sosend(ct->ct_socket, NULL, NULL, mrep, NULL, 90119370Spst 0, curthread); 90298948Sobrien else 90398948Sobrien error = EPIPE; 90498948Sobrien sx_xunlock(&xprt->xp_lock); 90598948Sobrien if (!error) { 90698948Sobrien stat = TRUE; 90719370Spst } 90898948Sobrien } else { 90919370Spst m_freem(mrep); 91098948Sobrien } 91198948Sobrien 91298948Sobrien XDR_DESTROY(&xdrs); 91319370Spst 91498948Sobrien return (stat); 91519370Spst} 91698948Sobrien 91798948Sobrienstatic bool_t 91898948Sobriensvc_vc_null() 91919370Spst{ 92098948Sobrien 92198948Sobrien return (FALSE); 92298948Sobrien} 92398948Sobrien 92498948Sobrienstatic int 92598948Sobriensvc_vc_soupcall(struct socket *so, void *arg, int waitflag) 92698948Sobrien{ 92798948Sobrien SVCXPRT *xprt = (SVCXPRT *) arg; 928130809Smarcel 92998948Sobrien if (soreadable(xprt->xp_socket)) 93098948Sobrien xprt_active(xprt); 93198948Sobrien return (SU_OK); 93298948Sobrien} 93398948Sobrien 93498948Sobrien#if 0 93598948Sobrien/* 93698948Sobrien * Get the effective UID of the sending process. Used by rpcbind, keyserv 93798948Sobrien * and rpc.yppasswdd on AF_LOCAL. 93898948Sobrien */ 93998948Sobrienint 94098948Sobrien__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) { 94198948Sobrien int sock, ret; 94298948Sobrien gid_t egid; 94398948Sobrien uid_t euid; 94498948Sobrien struct sockaddr *sa; 945130809Smarcel 94698948Sobrien sock = transp->xp_fd; 94798948Sobrien sa = (struct sockaddr *)transp->xp_rtaddr; 94898948Sobrien if (sa->sa_family == AF_LOCAL) { 94998948Sobrien ret = getpeereid(sock, &euid, &egid); 95098948Sobrien if (ret == 0) 95198948Sobrien *uid = euid; 95298948Sobrien return (ret); 953130809Smarcel } else 954130809Smarcel return (-1); 95598948Sobrien} 95698948Sobrien#endif 95798948Sobrien