svc_vc.c revision 269398
1114402Sru/* $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $ */ 2114402Sru 3114402Sru/*- 4114402Sru * Copyright (c) 2009, Sun Microsystems, Inc. 5114402Sru * All rights reserved. 6114402Sru * 7114402Sru * Redistribution and use in source and binary forms, with or without 8114402Sru * modification, are permitted provided that the following conditions are met: 9114402Sru * - Redistributions of source code must retain the above copyright notice, 10114402Sru * this list of conditions and the following disclaimer. 11114402Sru * - Redistributions in binary form must reproduce the above copyright notice, 12114402Sru * this list of conditions and the following disclaimer in the documentation 13151497Sru * and/or other materials provided with the distribution. 14114402Sru * - Neither the name of Sun Microsystems, Inc. nor the names of its 15114402Sru * contributors may be used to endorse or promote products derived 16114402Sru * from this software without specific prior written permission. 17114402Sru * 18114402Sru * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19114402Sru * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20114402Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21114402Sru * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22114402Sru * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23114402Sru * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24114402Sru * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25114402Sru * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26114402Sru * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27114402Sru * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28114402Sru * POSSIBILITY OF SUCH DAMAGE. 29151497Sru */ 30151497Sru 31114402Sru#if defined(LIBC_SCCS) && !defined(lint) 32114402Srustatic char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; 33114402Srustatic char *sccsid = "@(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 34114402Sru#endif 35114402Sru#include <sys/cdefs.h> 36114402Sru__FBSDID("$FreeBSD: stable/10/sys/rpc/svc_vc.c 269398 2014-08-01 21:10:41Z rmacklem $"); 37114402Sru 38114402Sru/* 39114402Sru * svc_vc.c, Server side for Connection Oriented based RPC. 40114402Sru * 41114402Sru * Actually implements two flavors of transporter - 42114402Sru * a tcp rendezvouser (a listner and connection establisher) 43114402Sru * and a record/tcp stream. 44114402Sru */ 45151497Sru 46151497Sru#include <sys/param.h> 47151497Sru#include <sys/lock.h> 48151497Sru#include <sys/kernel.h> 4975584Sru#include <sys/malloc.h> 5075584Sru#include <sys/mbuf.h> 51104862Sru#include <sys/mutex.h> 52151497Sru#include <sys/proc.h> 5375584Sru#include <sys/protosw.h> 54104862Sru#include <sys/queue.h> 55104862Sru#include <sys/socket.h> 56104862Sru#include <sys/socketvar.h> 57104862Sru#include <sys/sx.h> 58104862Sru#include <sys/systm.h> 59104862Sru#include <sys/uio.h> 60104862Sru 61104862Sru#include <net/vnet.h> 62104862Sru 63104862Sru#include <netinet/tcp.h> 64104862Sru 65104862Sru#include <rpc/rpc.h> 66104862Sru 67104862Sru#include <rpc/krpc.h> 68104862Sru#include <rpc/rpc_com.h> 69104862Sru 70104862Sru#include <security/mac/mac_framework.h> 71104862Sru 72114402Srustatic bool_t svc_vc_rendezvous_recv(SVCXPRT *, struct rpc_msg *, 73114402Sru struct sockaddr **, struct mbuf **); 74114402Srustatic enum xprt_stat svc_vc_rendezvous_stat(SVCXPRT *); 75114402Srustatic void svc_vc_rendezvous_destroy(SVCXPRT *); 76114402Srustatic bool_t svc_vc_null(void); 77114402Srustatic void svc_vc_destroy(SVCXPRT *); 78114402Srustatic enum xprt_stat svc_vc_stat(SVCXPRT *); 79114402Srustatic bool_t svc_vc_ack(SVCXPRT *, uint32_t *); 80114402Srustatic bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *, 81114402Sru struct sockaddr **, struct mbuf **); 82114402Srustatic bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *, 83114402Sru struct sockaddr *, struct mbuf *, uint32_t *seq); 84114402Srustatic bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in); 85114402Srustatic bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq, 86114402Sru void *in); 87114402Srustatic void svc_vc_backchannel_destroy(SVCXPRT *); 88114402Srustatic enum xprt_stat svc_vc_backchannel_stat(SVCXPRT *); 89114402Srustatic bool_t svc_vc_backchannel_recv(SVCXPRT *, struct rpc_msg *, 90114402Sru struct sockaddr **, struct mbuf **); 91114402Srustatic bool_t svc_vc_backchannel_reply(SVCXPRT *, struct rpc_msg *, 92114402Sru struct sockaddr *, struct mbuf *, uint32_t *); 93114402Srustatic bool_t svc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, 94114402Sru void *in); 95114402Srustatic SVCXPRT *svc_vc_create_conn(SVCPOOL *pool, struct socket *so, 96114402Sru struct sockaddr *raddr); 97114402Srustatic int svc_vc_accept(struct socket *head, struct socket **sop); 98114402Srustatic int svc_vc_soupcall(struct socket *so, void *arg, int waitflag); 99114402Sru 100114402Srustatic struct xp_ops svc_vc_rendezvous_ops = { 101114402Sru .xp_recv = svc_vc_rendezvous_recv, 102114402Sru .xp_stat = svc_vc_rendezvous_stat, 103114402Sru .xp_reply = (bool_t (*)(SVCXPRT *, struct rpc_msg *, 104114402Sru struct sockaddr *, struct mbuf *, uint32_t *))svc_vc_null, 105114402Sru .xp_destroy = svc_vc_rendezvous_destroy, 106114402Sru .xp_control = svc_vc_rendezvous_control 107114402Sru}; 108114402Sru 109114402Srustatic struct xp_ops svc_vc_ops = { 110114402Sru .xp_recv = svc_vc_recv, 111114402Sru .xp_stat = svc_vc_stat, 112151497Sru .xp_ack = svc_vc_ack, 113151497Sru .xp_reply = svc_vc_reply, 114151497Sru .xp_destroy = svc_vc_destroy, 115151497Sru .xp_control = svc_vc_control 116151497Sru}; 117151497Sru 118151497Srustatic struct xp_ops svc_vc_backchannel_ops = { 119151497Sru .xp_recv = svc_vc_backchannel_recv, 120151497Sru .xp_stat = svc_vc_backchannel_stat, 121151497Sru .xp_reply = svc_vc_backchannel_reply, 122151497Sru .xp_destroy = svc_vc_backchannel_destroy, 123151497Sru .xp_control = svc_vc_backchannel_control 124114402Sru}; 125114402Sru 126114402Sru/* 127114402Sru * Usage: 128104862Sru * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); 129104862Sru * 130104862Sru * Creates, registers, and returns a (rpc) tcp based transporter. 131114402Sru * Once *xprt is initialized, it is registered as a transporter 132114402Sru * see (svc.h, xprt_register). This routine returns 133114402Sru * a NULL if a problem occurred. 134114402Sru * 13575584Sru * The filedescriptor passed in is expected to refer to a bound, but 136114402Sru * not yet connected socket. 137114402Sru * 138114402Sru * Since streams do buffered io similar to stdio, the caller can specify 139114402Sru * how big the send and receive buffers are via the second and third parms; 140114402Sru * 0 => use the system default. 141114402Sru */ 142114402SruSVCXPRT * 143114402Srusvc_vc_create(SVCPOOL *pool, struct socket *so, size_t sendsize, 144114402Sru size_t recvsize) 145114402Sru{ 146114402Sru SVCXPRT *xprt; 147114402Sru struct sockaddr* sa; 148114402Sru int error; 149114402Sru 150114402Sru SOCK_LOCK(so); 151114402Sru if (so->so_state & (SS_ISCONNECTED|SS_ISDISCONNECTED)) { 152114402Sru SOCK_UNLOCK(so); 153114402Sru error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa); 154114402Sru if (error) 155114402Sru return (NULL); 156114402Sru xprt = svc_vc_create_conn(pool, so, sa); 157114402Sru free(sa, M_SONAME); 158114402Sru return (xprt); 159114402Sru } 160114402Sru SOCK_UNLOCK(so); 161114402Sru 162114402Sru xprt = svc_xprt_alloc(); 163114402Sru sx_init(&xprt->xp_lock, "xprt->xp_lock"); 164114402Sru xprt->xp_pool = pool; 165114402Sru xprt->xp_socket = so; 166114402Sru xprt->xp_p1 = NULL; 167114402Sru xprt->xp_p2 = NULL; 168114402Sru xprt->xp_ops = &svc_vc_rendezvous_ops; 169114402Sru 170114402Sru error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 171114402Sru if (error) { 172114402Sru goto cleanup_svc_vc_create; 173114402Sru } 174114402Sru 175114402Sru memcpy(&xprt->xp_ltaddr, sa, sa->sa_len); 176114402Sru free(sa, M_SONAME); 177114402Sru 178114402Sru xprt_register(xprt); 179114402Sru 180114402Sru solisten(so, SOMAXCONN, curthread); 181114402Sru 182114402Sru SOCKBUF_LOCK(&so->so_rcv); 183114402Sru xprt->xp_upcallset = 1; 184114402Sru soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt); 185114402Sru SOCKBUF_UNLOCK(&so->so_rcv); 186114402Sru 187114402Sru return (xprt); 188114402Srucleanup_svc_vc_create: 189114402Sru if (xprt) { 190114402Sru sx_destroy(&xprt->xp_lock); 191114402Sru svc_xprt_free(xprt); 192114402Sru } 193114402Sru return (NULL); 194114402Sru} 195114402Sru 196114402Sru/* 197114402Sru * Create a new transport for a socket optained via soaccept(). 198114402Sru */ 199114402SruSVCXPRT * 200114402Srusvc_vc_create_conn(SVCPOOL *pool, struct socket *so, struct sockaddr *raddr) 201114402Sru{ 202114402Sru SVCXPRT *xprt = NULL; 203114402Sru struct cf_conn *cd = NULL; 204114402Sru struct sockaddr* sa = NULL; 205114402Sru struct sockopt opt; 206114402Sru int one = 1; 207114402Sru int error; 208114402Sru 209114402Sru bzero(&opt, sizeof(struct sockopt)); 210114402Sru opt.sopt_dir = SOPT_SET; 211151497Sru opt.sopt_level = SOL_SOCKET; 212114402Sru opt.sopt_name = SO_KEEPALIVE; 213114402Sru opt.sopt_val = &one; 214114402Sru opt.sopt_valsize = sizeof(one); 215114402Sru error = sosetopt(so, &opt); 216114402Sru if (error) { 217114402Sru return (NULL); 218114402Sru } 219114402Sru 220114402Sru if (so->so_proto->pr_protocol == IPPROTO_TCP) { 221114402Sru bzero(&opt, sizeof(struct sockopt)); 222114402Sru opt.sopt_dir = SOPT_SET; 223114402Sru opt.sopt_level = IPPROTO_TCP; 224114402Sru opt.sopt_name = TCP_NODELAY; 225114402Sru opt.sopt_val = &one; 226114402Sru opt.sopt_valsize = sizeof(one); 227114402Sru error = sosetopt(so, &opt); 228114402Sru if (error) { 229114402Sru return (NULL); 230114402Sru } 231114402Sru } 232114402Sru 233114402Sru cd = mem_alloc(sizeof(*cd)); 234114402Sru cd->strm_stat = XPRT_IDLE; 235114402Sru 236114402Sru xprt = svc_xprt_alloc(); 237114402Sru sx_init(&xprt->xp_lock, "xprt->xp_lock"); 238114402Sru xprt->xp_pool = pool; 239114402Sru xprt->xp_socket = so; 240114402Sru xprt->xp_p1 = cd; 241114402Sru xprt->xp_p2 = NULL; 242114402Sru xprt->xp_ops = &svc_vc_ops; 243114402Sru 244114402Sru /* 245114402Sru * See http://www.connectathon.org/talks96/nfstcp.pdf - client 246114402Sru * has a 5 minute timer, server has a 6 minute timer. 247114402Sru */ 248114402Sru xprt->xp_idletimeout = 6 * 60; 249114402Sru 250114402Sru memcpy(&xprt->xp_rtaddr, raddr, raddr->sa_len); 251114402Sru 252114402Sru error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 253114402Sru if (error) 254114402Sru goto cleanup_svc_vc_create; 255114402Sru 256114402Sru memcpy(&xprt->xp_ltaddr, sa, sa->sa_len); 257114402Sru free(sa, M_SONAME); 258114402Sru 259114402Sru xprt_register(xprt); 260114402Sru 261114402Sru SOCKBUF_LOCK(&so->so_rcv); 262114402Sru xprt->xp_upcallset = 1; 263114402Sru soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt); 264151497Sru SOCKBUF_UNLOCK(&so->so_rcv); 265114402Sru 266104862Sru /* 26775584Sru * Throw the transport into the active list in case it already 26875584Sru * has some data buffered. 26975584Sru */ 270151497Sru sx_xlock(&xprt->xp_lock); 271151497Sru xprt_active(xprt); 272151497Sru sx_xunlock(&xprt->xp_lock); 273151497Sru 274151497Sru return (xprt); 275151497Srucleanup_svc_vc_create: 276151497Sru if (xprt) { 277104862Sru sx_destroy(&xprt->xp_lock); 27875584Sru svc_xprt_free(xprt); 27975584Sru } 280104862Sru if (cd) 281104862Sru mem_free(cd, sizeof(*cd)); 282104862Sru return (NULL); 283104862Sru} 284151497Sru 28575584Sru/* 286151497Sru * Create a new transport for a backchannel on a clnt_vc socket. 287151497Sru */ 288151497SruSVCXPRT * 289151497Srusvc_vc_create_backchannel(SVCPOOL *pool) 290151497Sru{ 291151497Sru SVCXPRT *xprt = NULL; 292151497Sru struct cf_conn *cd = NULL; 293151497Sru 294151497Sru cd = mem_alloc(sizeof(*cd)); 295114402Sru cd->strm_stat = XPRT_IDLE; 296104862Sru 29775584Sru xprt = svc_xprt_alloc(); 298104862Sru sx_init(&xprt->xp_lock, "xprt->xp_lock"); 299104862Sru xprt->xp_pool = pool; 300104862Sru xprt->xp_socket = NULL; 301114402Sru xprt->xp_p1 = cd; 302114402Sru xprt->xp_p2 = NULL; 303104862Sru xprt->xp_ops = &svc_vc_backchannel_ops; 304104862Sru return (xprt); 305104862Sru} 306104862Sru 307104862Sru/* 308114402Sru * This does all of the accept except the final call to soaccept. The 309104862Sru * caller will call soaccept after dropping its locks (soaccept may 310104862Sru * call malloc). 311104862Sru */ 31275584Sruint 31375584Srusvc_vc_accept(struct socket *head, struct socket **sop) 314114402Sru{ 315104862Sru int error = 0; 31675584Sru struct socket *so; 317104862Sru 31875584Sru if ((head->so_options & SO_ACCEPTCONN) == 0) { 31975584Sru error = EINVAL; 320114402Sru goto done; 321114402Sru } 322114402Sru#ifdef MAC 32375584Sru error = mac_socket_check_accept(curthread->td_ucred, head); 32475584Sru if (error != 0) 325151497Sru goto done; 326151497Sru#endif 327151497Sru ACCEPT_LOCK(); 328151497Sru if (TAILQ_EMPTY(&head->so_comp)) { 329114402Sru ACCEPT_UNLOCK(); 330151497Sru error = EWOULDBLOCK; 331151497Sru goto done; 332151497Sru } 333151497Sru so = TAILQ_FIRST(&head->so_comp); 334114402Sru KASSERT(!(so->so_qstate & SQ_INCOMP), ("svc_vc_accept: so SQ_INCOMP")); 335151497Sru KASSERT(so->so_qstate & SQ_COMP, ("svc_vc_accept: so not SQ_COMP")); 336114402Sru 337151497Sru /* 338151497Sru * Before changing the flags on the socket, we have to bump the 339151497Sru * reference count. Otherwise, if the protocol calls sofree(), 340114402Sru * the socket will be released due to a zero refcount. 341114402Sru * XXX might not need soref() since this is simpler than kern_accept. 342114402Sru */ 343151497Sru SOCK_LOCK(so); /* soref() and so_state update */ 344151497Sru soref(so); /* file descriptor reference */ 345151497Sru 346151497Sru TAILQ_REMOVE(&head->so_comp, so, so_list); 347151497Sru head->so_qlen--; 348151497Sru so->so_state |= (head->so_state & SS_NBIO); 349151497Sru so->so_qstate &= ~SQ_COMP; 350151497Sru so->so_head = NULL; 351151497Sru 352151497Sru SOCK_UNLOCK(so); 353151497Sru ACCEPT_UNLOCK(); 354151497Sru 355151497Sru *sop = so; 356151497Sru 357151497Sru /* connection has been removed from the listen queue */ 358151497Sru KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0); 359151497Srudone: 360151497Sru return (error); 361151497Sru} 362151497Sru 363151497Sru/*ARGSUSED*/ 364151497Srustatic bool_t 365151497Srusvc_vc_rendezvous_recv(SVCXPRT *xprt, struct rpc_msg *msg, 366151497Sru struct sockaddr **addrp, struct mbuf **mp) 367151497Sru{ 368151497Sru struct socket *so = NULL; 369114402Sru struct sockaddr *sa = NULL; 370114402Sru int error; 371114402Sru SVCXPRT *new_xprt; 372104862Sru 373114402Sru /* 374104862Sru * The socket upcall calls xprt_active() which will eventually 375104862Sru * cause the server to call us here. We attempt to accept a 376114402Sru * connection from the socket and turn it into a new 377104862Sru * transport. If the accept fails, we have drained all pending 378104862Sru * connections so we call xprt_inactive(). 379114402Sru */ 380104862Sru sx_xlock(&xprt->xp_lock); 381104862Sru 382104862Sru error = svc_vc_accept(xprt->xp_socket, &so); 383104862Sru 384104862Sru if (error == EWOULDBLOCK) { 385104862Sru /* 386104862Sru * We must re-test for new connections after taking 387104862Sru * the lock to protect us in the case where a new 388104862Sru * connection arrives after our call to accept fails 389104862Sru * with EWOULDBLOCK. 390104862Sru */ 391104862Sru ACCEPT_LOCK(); 392104862Sru if (TAILQ_EMPTY(&xprt->xp_socket->so_comp)) 393104862Sru xprt_inactive_self(xprt); 394104862Sru ACCEPT_UNLOCK(); 395104862Sru sx_xunlock(&xprt->xp_lock); 39675584Sru return (FALSE); 397104862Sru } 398104862Sru 399104862Sru if (error) { 400104862Sru SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 40175584Sru if (xprt->xp_upcallset) { 40275584Sru xprt->xp_upcallset = 0; 403151497Sru soupcall_clear(xprt->xp_socket, SO_RCV); 404151497Sru } 405151497Sru SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 406151497Sru xprt_inactive_self(xprt); 407151497Sru sx_xunlock(&xprt->xp_lock); 408151497Sru return (FALSE); 409151497Sru } 410151497Sru 411151497Sru sx_xunlock(&xprt->xp_lock); 412151497Sru 413151497Sru sa = 0; 414151497Sru error = soaccept(so, &sa); 415151497Sru 416151497Sru if (error) { 417151497Sru /* 418151497Sru * XXX not sure if I need to call sofree or soclose here. 419151497Sru */ 420151497Sru if (sa) 421151497Sru free(sa, M_SONAME); 422151497Sru return (FALSE); 423151497Sru } 424151497Sru 425151497Sru /* 426151497Sru * svc_vc_create_conn will call xprt_register - we don't need 427151497Sru * to do anything with the new connection except derefence it. 428151497Sru */ 42975584Sru new_xprt = svc_vc_create_conn(xprt->xp_pool, so, sa); 43075584Sru if (!new_xprt) { 431114402Sru soclose(so); 432104862Sru } else { 433104862Sru SVC_RELEASE(new_xprt); 434104862Sru } 435104862Sru 436104862Sru free(sa, M_SONAME); 437104862Sru 438104862Sru return (FALSE); /* there is never an rpc msg to be processed */ 439114402Sru} 440104862Sru 441104862Sru/*ARGSUSED*/ 442104862Srustatic enum xprt_stat 443104862Srusvc_vc_rendezvous_stat(SVCXPRT *xprt) 444104862Sru{ 445104862Sru 446104862Sru return (XPRT_IDLE); 447104862Sru} 448104862Sru 44975584Srustatic void 450104862Srusvc_vc_destroy_common(SVCXPRT *xprt) 451151497Sru{ 452104862Sru SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 453104862Sru if (xprt->xp_upcallset) { 454151497Sru xprt->xp_upcallset = 0; 455104862Sru soupcall_clear(xprt->xp_socket, SO_RCV); 456151497Sru } 457104862Sru SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 458104862Sru 459104862Sru if (xprt->xp_socket) 460104862Sru (void)soclose(xprt->xp_socket); 461104862Sru 462104862Sru if (xprt->xp_netid) 463104862Sru (void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1); 464151497Sru svc_xprt_free(xprt); 465151497Sru} 46675584Sru 467104862Srustatic void 468104862Srusvc_vc_rendezvous_destroy(SVCXPRT *xprt) 469104862Sru{ 470114402Sru 471104862Sru svc_vc_destroy_common(xprt); 47275584Sru} 473104862Sru 474104862Srustatic void 475104862Srusvc_vc_destroy(SVCXPRT *xprt) 476104862Sru{ 477104862Sru struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1; 478104862Sru 479104862Sru svc_vc_destroy_common(xprt); 480104862Sru 481104862Sru if (cd->mreq) 48275584Sru m_freem(cd->mreq); 483104862Sru if (cd->mpending) 484151497Sru m_freem(cd->mpending); 485104862Sru mem_free(cd, sizeof(*cd)); 486104862Sru} 487151497Sru 488104862Srustatic void 489151497Srusvc_vc_backchannel_destroy(SVCXPRT *xprt) 49075584Sru{ 491104862Sru struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1; 492104862Sru struct mbuf *m, *m2; 493104862Sru 494104862Sru svc_xprt_free(xprt); 495104862Sru m = cd->mreq; 496104862Sru while (m != NULL) { 497104862Sru m2 = m; 498104862Sru m = m->m_nextpkt; 499151497Sru m_freem(m2); 500104862Sru } 501151497Sru mem_free(cd, sizeof(*cd)); 502104862Sru} 50375584Sru 504104862Sru/*ARGSUSED*/ 505151497Srustatic bool_t 506104862Srusvc_vc_control(SVCXPRT *xprt, const u_int rq, void *in) 507151497Sru{ 508151497Sru return (FALSE); 50975584Sru} 51075584Sru 51175584Srustatic bool_t 512104862Srusvc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in) 513104862Sru{ 514114402Sru 515104862Sru return (FALSE); 516104862Sru} 517104862Sru 518104862Srustatic bool_t 51975584Srusvc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, void *in) 520104862Sru{ 521104862Sru 522104862Sru return (FALSE); 523114402Sru} 524114402Sru 525114402Srustatic enum xprt_stat 526104862Srusvc_vc_stat(SVCXPRT *xprt) 527104862Sru{ 528104862Sru struct cf_conn *cd; 529104862Sru 530104862Sru cd = (struct cf_conn *)(xprt->xp_p1); 531151497Sru 532104862Sru if (cd->strm_stat == XPRT_DIED) 533104862Sru return (XPRT_DIED); 534104862Sru 535104862Sru if (cd->mreq != NULL && cd->resid == 0 && cd->eor) 536151497Sru return (XPRT_MOREREQS); 537104862Sru 538151497Sru if (soreadable(xprt->xp_socket)) 539104862Sru return (XPRT_MOREREQS); 540104862Sru 541104862Sru return (XPRT_IDLE); 542104862Sru} 543104862Sru 544104862Srustatic bool_t 545104862Srusvc_vc_ack(SVCXPRT *xprt, uint32_t *ack) 546104862Sru{ 547104862Sru 54875584Sru *ack = atomic_load_acq_32(&xprt->xp_snt_cnt); 549104862Sru *ack -= xprt->xp_socket->so_snd.sb_cc; 550104862Sru return (TRUE); 551104862Sru} 552104862Sru 553104862Srustatic enum xprt_stat 554104862Srusvc_vc_backchannel_stat(SVCXPRT *xprt) 555104862Sru{ 556104862Sru struct cf_conn *cd; 557104862Sru 558104862Sru cd = (struct cf_conn *)(xprt->xp_p1); 559104862Sru 560104862Sru if (cd->mreq != NULL) 561104862Sru return (XPRT_MOREREQS); 562104862Sru 563104862Sru return (XPRT_IDLE); 564104862Sru} 565104862Sru 566104862Sru/* 567104862Sru * If we have an mbuf chain in cd->mpending, try to parse a record from it, 568104862Sru * leaving the result in cd->mreq. If we don't have a complete record, leave 569151497Sru * the partial result in cd->mreq and try to read more from the socket. 570104862Sru */ 571104862Srustatic int 572104862Srusvc_vc_process_pending(SVCXPRT *xprt) 573151497Sru{ 574151497Sru struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 575151497Sru struct socket *so = xprt->xp_socket; 576151497Sru struct mbuf *m; 577151497Sru 578151497Sru /* 579151497Sru * If cd->resid is non-zero, we have part of the 580151497Sru * record already, otherwise we are expecting a record 581151497Sru * marker. 582151497Sru */ 583151497Sru if (!cd->resid && cd->mpending) { 584151497Sru /* 585151497Sru * See if there is enough data buffered to 586151497Sru * make up a record marker. Make sure we can 587151497Sru * handle the case where the record marker is 588151497Sru * split across more than one mbuf. 589151497Sru */ 590151497Sru size_t n = 0; 591151497Sru uint32_t header; 592151497Sru 593151497Sru m = cd->mpending; 594151497Sru while (n < sizeof(uint32_t) && m) { 595151497Sru n += m->m_len; 596151497Sru m = m->m_next; 597151497Sru } 598151497Sru if (n < sizeof(uint32_t)) { 599114402Sru so->so_rcv.sb_lowat = sizeof(uint32_t) - n; 600151497Sru return (FALSE); 601104862Sru } 602104862Sru m_copydata(cd->mpending, 0, sizeof(header), 603104862Sru (char *)&header); 604104862Sru header = ntohl(header); 605151497Sru cd->eor = (header & 0x80000000) != 0; 606151497Sru cd->resid = header & 0x7fffffff; 607151497Sru m_adj(cd->mpending, sizeof(uint32_t)); 608151497Sru } 609151497Sru 610104862Sru /* 611104862Sru * Start pulling off mbufs from cd->mpending 612104862Sru * until we either have a complete record or 613104862Sru * we run out of data. We use m_split to pull 614104862Sru * data - it will pull as much as possible and 615151497Sru * split the last mbuf if necessary. 616151497Sru */ 617151497Sru while (cd->mpending && cd->resid) { 618104862Sru m = cd->mpending; 619151497Sru if (cd->mpending->m_next 620151497Sru || cd->mpending->m_len > cd->resid) 621151497Sru cd->mpending = m_split(cd->mpending, 622151497Sru cd->resid, M_WAITOK); 623151497Sru else 624151497Sru cd->mpending = NULL; 625151497Sru if (cd->mreq) 626151497Sru m_last(cd->mreq)->m_next = m; 627151497Sru else 628151497Sru cd->mreq = m; 629151497Sru while (m) { 630151497Sru cd->resid -= m->m_len; 631151497Sru m = m->m_next; 632151497Sru } 633151497Sru } 634151497Sru 635151497Sru /* 636151497Sru * Block receive upcalls if we have more data pending, 637151497Sru * otherwise report our need. 638151497Sru */ 639151497Sru if (cd->mpending) 640151497Sru so->so_rcv.sb_lowat = INT_MAX; 641104862Sru else 642151497Sru so->so_rcv.sb_lowat = 643151497Sru imax(1, imin(cd->resid, so->so_rcv.sb_hiwat / 2)); 644151497Sru return (TRUE); 645151497Sru} 646151497Sru 647151497Srustatic bool_t 648151497Srusvc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg, 649151497Sru struct sockaddr **addrp, struct mbuf **mp) 650151497Sru{ 651151497Sru struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 652151497Sru struct uio uio; 653151497Sru struct mbuf *m; 654151497Sru struct socket* so = xprt->xp_socket; 655151497Sru XDR xdrs; 656151497Sru int error, rcvflag; 657151497Sru uint32_t xid_plus_direction[2]; 658151497Sru 659151497Sru /* 660151497Sru * Serialise access to the socket and our own record parsing 661151497Sru * state. 662151497Sru */ 663151497Sru sx_xlock(&xprt->xp_lock); 664151497Sru 665151497Sru for (;;) { 666151497Sru /* If we have no request ready, check pending queue. */ 667151497Sru while (cd->mpending && 668151497Sru (cd->mreq == NULL || cd->resid != 0 || !cd->eor)) { 669151497Sru if (!svc_vc_process_pending(xprt)) 670151497Sru break; 671151497Sru } 672151497Sru 673151497Sru /* Process and return complete request in cd->mreq. */ 674151497Sru if (cd->mreq != NULL && cd->resid == 0 && cd->eor) { 675151497Sru 676151497Sru /* 677151497Sru * Now, check for a backchannel reply. 678151497Sru * The XID is in the first uint32_t of the reply 679151497Sru * and the message direction is the second one. 680151497Sru */ 681151497Sru if ((cd->mreq->m_len >= sizeof(xid_plus_direction) || 682151497Sru m_length(cd->mreq, NULL) >= 683151497Sru sizeof(xid_plus_direction)) && 684151497Sru xprt->xp_p2 != NULL) { 685151497Sru m_copydata(cd->mreq, 0, 686151497Sru sizeof(xid_plus_direction), 687151497Sru (char *)xid_plus_direction); 688151497Sru xid_plus_direction[0] = 689151497Sru ntohl(xid_plus_direction[0]); 690151497Sru xid_plus_direction[1] = 691151497Sru ntohl(xid_plus_direction[1]); 692151497Sru /* Check message direction. */ 693151497Sru if (xid_plus_direction[1] == REPLY) { 694151497Sru clnt_bck_svccall(xprt->xp_p2, 695151497Sru cd->mreq, 696151497Sru xid_plus_direction[0]); 697104862Sru cd->mreq = NULL; 698151497Sru continue; 699151497Sru } 700151497Sru } 701104862Sru 702151497Sru xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE); 703151497Sru cd->mreq = NULL; 70475584Sru 705104862Sru /* Check for next request in a pending queue. */ 706151497Sru svc_vc_process_pending(xprt); 707151497Sru if (cd->mreq == NULL || cd->resid != 0) { 708104862Sru SOCKBUF_LOCK(&so->so_rcv); 709104862Sru if (!soreadable(so)) 710151497Sru xprt_inactive_self(xprt); 711151497Sru SOCKBUF_UNLOCK(&so->so_rcv); 712104862Sru } 713104862Sru 714104862Sru sx_xunlock(&xprt->xp_lock); 715104862Sru 716104862Sru if (! xdr_callmsg(&xdrs, msg)) { 717104862Sru XDR_DESTROY(&xdrs); 718151497Sru return (FALSE); 719104862Sru } 720104862Sru 721151497Sru *addrp = NULL; 722151497Sru *mp = xdrmbuf_getall(&xdrs); 723151497Sru XDR_DESTROY(&xdrs); 724104862Sru 725104862Sru return (TRUE); 726104862Sru } 727104862Sru 728104862Sru /* 729104862Sru * The socket upcall calls xprt_active() which will eventually 730104862Sru * cause the server to call us here. We attempt to 731104862Sru * read as much as possible from the socket and put 732104862Sru * the result in cd->mpending. If the read fails, 733104862Sru * we have drained both cd->mpending and the socket so 734104862Sru * we can call xprt_inactive(). 735104862Sru */ 736104862Sru uio.uio_resid = 1000000000; 737151497Sru uio.uio_td = curthread; 738104862Sru m = NULL; 739104862Sru rcvflag = MSG_DONTWAIT; 740151497Sru error = soreceive(so, NULL, &uio, &m, NULL, &rcvflag); 741151497Sru 742151497Sru if (error == EWOULDBLOCK) { 743151497Sru /* 744104862Sru * We must re-test for readability after 745104862Sru * taking the lock to protect us in the case 746104862Sru * where a new packet arrives on the socket 747104862Sru * after our call to soreceive fails with 748104862Sru * EWOULDBLOCK. 749104862Sru */ 750104862Sru SOCKBUF_LOCK(&so->so_rcv); 751104862Sru if (!soreadable(so)) 752104862Sru xprt_inactive_self(xprt); 75375584Sru SOCKBUF_UNLOCK(&so->so_rcv); 754114402Sru sx_xunlock(&xprt->xp_lock); 755104862Sru return (FALSE); 75675584Sru } 757104862Sru 758104862Sru if (error) { 759104862Sru SOCKBUF_LOCK(&so->so_rcv); 760104862Sru if (xprt->xp_upcallset) { 761104862Sru xprt->xp_upcallset = 0; 762104862Sru soupcall_clear(so, SO_RCV); 763104862Sru } 764104862Sru SOCKBUF_UNLOCK(&so->so_rcv); 765104862Sru xprt_inactive_self(xprt); 766104862Sru cd->strm_stat = XPRT_DIED; 767104862Sru sx_xunlock(&xprt->xp_lock); 768104862Sru return (FALSE); 769104862Sru } 770104862Sru 771104862Sru if (!m) { 772104862Sru /* 773104862Sru * EOF - the other end has closed the socket. 774151497Sru */ 77575584Sru xprt_inactive_self(xprt); 776104862Sru cd->strm_stat = XPRT_DIED; 777104862Sru sx_xunlock(&xprt->xp_lock); 778104862Sru return (FALSE); 779104862Sru } 780151497Sru 781104862Sru if (cd->mpending) 782114402Sru m_last(cd->mpending)->m_next = m; 783104862Sru else 78475584Sru cd->mpending = m; 785104862Sru } 786104862Sru} 787104862Sru 788104862Srustatic bool_t 789151497Srusvc_vc_backchannel_recv(SVCXPRT *xprt, struct rpc_msg *msg, 790104862Sru struct sockaddr **addrp, struct mbuf **mp) 791114402Sru{ 792104862Sru struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 793104862Sru struct ct_data *ct; 794151497Sru struct mbuf *m; 795104862Sru XDR xdrs; 796104862Sru 797151497Sru sx_xlock(&xprt->xp_lock); 798104862Sru ct = (struct ct_data *)xprt->xp_p2; 799114402Sru if (ct == NULL) { 800104862Sru sx_xunlock(&xprt->xp_lock); 801104862Sru return (FALSE); 802104862Sru } 803104862Sru mtx_lock(&ct->ct_lock); 804104862Sru m = cd->mreq; 805104862Sru if (m == NULL) { 806151497Sru xprt_inactive_self(xprt); 807104862Sru mtx_unlock(&ct->ct_lock); 808104862Sru sx_xunlock(&xprt->xp_lock); 809104862Sru return (FALSE); 810104862Sru } 811104862Sru cd->mreq = m->m_nextpkt; 812151497Sru mtx_unlock(&ct->ct_lock); 813151497Sru sx_xunlock(&xprt->xp_lock); 814151497Sru 815104862Sru xdrmbuf_create(&xdrs, m, XDR_DECODE); 816114402Sru if (! xdr_callmsg(&xdrs, msg)) { 817104862Sru XDR_DESTROY(&xdrs); 818104862Sru return (FALSE); 819104862Sru } 820151497Sru *addrp = NULL; 821104862Sru *mp = xdrmbuf_getall(&xdrs); 822104862Sru XDR_DESTROY(&xdrs); 823104862Sru return (TRUE); 824104862Sru} 825104862Sru 826104862Srustatic bool_t 827104862Srusvc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg, 828151497Sru struct sockaddr *addr, struct mbuf *m, uint32_t *seq) 829151497Sru{ 830104862Sru XDR xdrs; 831151497Sru struct mbuf *mrep; 832104862Sru bool_t stat = TRUE; 833104862Sru int error, len; 834114402Sru 835151497Sru /* 836114402Sru * Leave space for record mark. 837151497Sru */ 838151497Sru mrep = m_gethdr(M_WAITOK, MT_DATA); 839151497Sru mrep->m_data += sizeof(uint32_t); 840151497Sru 841151497Sru xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); 842151497Sru 843151497Sru if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 844151497Sru msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 845151497Sru if (!xdr_replymsg(&xdrs, msg)) 846151497Sru stat = FALSE; 847151497Sru else 848151497Sru xdrmbuf_append(&xdrs, m); 849151497Sru } else { 850151497Sru stat = xdr_replymsg(&xdrs, msg); 851151497Sru } 852151497Sru 853151497Sru if (stat) { 854151497Sru m_fixhdr(mrep); 855151497Sru 856151497Sru /* 857151497Sru * Prepend a record marker containing the reply length. 858151497Sru */ 859104862Sru M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK); 860151497Sru len = mrep->m_pkthdr.len; 861151497Sru *mtod(mrep, uint32_t *) = 862151497Sru htonl(0x80000000 | (len - sizeof(uint32_t))); 863151497Sru atomic_add_acq_32(&xprt->xp_snd_cnt, len); 864151497Sru error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL, 865151497Sru 0, curthread); 866151497Sru if (!error) { 867151497Sru atomic_add_rel_32(&xprt->xp_snt_cnt, len); 868151497Sru if (seq) 869151497Sru *seq = xprt->xp_snd_cnt; 870151497Sru stat = TRUE; 871104862Sru } else 872151497Sru atomic_subtract_32(&xprt->xp_snd_cnt, len); 873151497Sru } else { 874151497Sru m_freem(mrep); 875151497Sru } 876151497Sru 877151497Sru XDR_DESTROY(&xdrs); 878151497Sru 879151497Sru return (stat); 880151497Sru} 881151497Sru 882151497Srustatic bool_t 883151497Srusvc_vc_backchannel_reply(SVCXPRT *xprt, struct rpc_msg *msg, 884104862Sru struct sockaddr *addr, struct mbuf *m, uint32_t *seq) 885104862Sru{ 886104862Sru struct ct_data *ct; 887151497Sru XDR xdrs; 888151497Sru struct mbuf *mrep; 889151497Sru bool_t stat = TRUE; 890151497Sru int error; 891104862Sru 892104862Sru /* 893104862Sru * Leave space for record mark. 894104862Sru */ 895151497Sru mrep = m_gethdr(M_WAITOK, MT_DATA); 896151497Sru mrep->m_data += sizeof(uint32_t); 897151497Sru 898151497Sru xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); 899104862Sru 900151497Sru if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 901151497Sru msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 902151497Sru if (!xdr_replymsg(&xdrs, msg)) 903151497Sru stat = FALSE; 904151497Sru else 905151497Sru xdrmbuf_append(&xdrs, m); 906151497Sru } else { 907151497Sru stat = xdr_replymsg(&xdrs, msg); 908151497Sru } 909151497Sru 910151497Sru if (stat) { 911151497Sru m_fixhdr(mrep); 912151497Sru 913151497Sru /* 914151497Sru * Prepend a record marker containing the reply length. 915151497Sru */ 916151497Sru M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK); 917151497Sru *mtod(mrep, uint32_t *) = 918114402Sru htonl(0x80000000 | (mrep->m_pkthdr.len 919104862Sru - sizeof(uint32_t))); 920104862Sru sx_xlock(&xprt->xp_lock); 921104862Sru ct = (struct ct_data *)xprt->xp_p2; 922104862Sru if (ct != NULL) 923104862Sru error = sosend(ct->ct_socket, NULL, NULL, mrep, NULL, 924151497Sru 0, curthread); 925151497Sru else 926104862Sru error = EPIPE; 927151497Sru sx_xunlock(&xprt->xp_lock); 92875584Sru if (!error) { 929151497Sru stat = TRUE; 93075584Sru } 93175584Sru } else { 932114402Sru m_freem(mrep); 933104862Sru } 934104862Sru 935104862Sru XDR_DESTROY(&xdrs); 936104862Sru 937104862Sru return (stat); 938104862Sru} 939104862Sru 940104862Srustatic bool_t 941151497Srusvc_vc_null() 942151497Sru{ 94375584Sru 944151497Sru return (FALSE); 945151497Sru} 94675584Sru 947114402Srustatic int 948151497Srusvc_vc_soupcall(struct socket *so, void *arg, int waitflag) 949151497Sru{ 950151497Sru SVCXPRT *xprt = (SVCXPRT *) arg; 951151497Sru 952151497Sru if (soreadable(xprt->xp_socket)) 953151497Sru xprt_active(xprt); 954151497Sru return (SU_OK); 955151497Sru} 956151497Sru 957151497Sru#if 0 958151497Sru/* 959151497Sru * Get the effective UID of the sending process. Used by rpcbind, keyserv 960151497Sru * and rpc.yppasswdd on AF_LOCAL. 961151497Sru */ 962151497Sruint 963151497Sru__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) { 964151497Sru int sock, ret; 965151497Sru gid_t egid; 966151497Sru uid_t euid; 967151497Sru struct sockaddr *sa; 968151497Sru 969151497Sru sock = transp->xp_fd; 970151497Sru sa = (struct sockaddr *)transp->xp_rtaddr; 971151497Sru if (sa->sa_family == AF_LOCAL) { 972151497Sru ret = getpeereid(sock, &euid, &egid); 973151497Sru if (ret == 0) 974151497Sru *uid = euid; 975151497Sru return (ret); 976151497Sru } else 977151497Sru return (-1); 978151497Sru} 979151497Sru#endif 980151497Sru