svc_vc.c revision 261053
1177633Sdfr/* $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $ */ 2177633Sdfr 3261046Smav/*- 4261046Smav * Copyright (c) 2009, Sun Microsystems, Inc. 5261046Smav * All rights reserved. 6261046Smav * 7261046Smav * Redistribution and use in source and binary forms, with or without 8261046Smav * modification, are permitted provided that the following conditions are met: 9261046Smav * - Redistributions of source code must retain the above copyright notice, 10261046Smav * this list of conditions and the following disclaimer. 11261046Smav * - Redistributions in binary form must reproduce the above copyright notice, 12261046Smav * this list of conditions and the following disclaimer in the documentation 13261046Smav * and/or other materials provided with the distribution. 14261046Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its 15261046Smav * contributors may be used to endorse or promote products derived 16261046Smav * from this software without specific prior written permission. 17177633Sdfr * 18261046Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19261046Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20261046Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21261046Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22261046Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23261046Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24261046Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25261046Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26261046Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27261046Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28261046Smav * POSSIBILITY OF SUCH DAMAGE. 29177633Sdfr */ 30177633Sdfr 31177633Sdfr#if defined(LIBC_SCCS) && !defined(lint) 32177633Sdfrstatic char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; 33177633Sdfrstatic char *sccsid = "@(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 34177633Sdfr#endif 35177633Sdfr#include <sys/cdefs.h> 36177633Sdfr__FBSDID("$FreeBSD: stable/10/sys/rpc/svc_vc.c 261053 2014-01-22 23:51:12Z mav $"); 37177633Sdfr 38177633Sdfr/* 39177633Sdfr * svc_vc.c, Server side for Connection Oriented based RPC. 40177633Sdfr * 41177633Sdfr * Actually implements two flavors of transporter - 42177633Sdfr * a tcp rendezvouser (a listner and connection establisher) 43177633Sdfr * and a record/tcp stream. 44177633Sdfr */ 45177633Sdfr 46177633Sdfr#include <sys/param.h> 47177633Sdfr#include <sys/lock.h> 48177633Sdfr#include <sys/kernel.h> 49177633Sdfr#include <sys/malloc.h> 50177633Sdfr#include <sys/mbuf.h> 51177633Sdfr#include <sys/mutex.h> 52193509Srwatson#include <sys/proc.h> 53177633Sdfr#include <sys/protosw.h> 54177633Sdfr#include <sys/queue.h> 55177633Sdfr#include <sys/socket.h> 56177633Sdfr#include <sys/socketvar.h> 57184588Sdfr#include <sys/sx.h> 58177633Sdfr#include <sys/systm.h> 59177633Sdfr#include <sys/uio.h> 60196503Szec 61196503Szec#include <net/vnet.h> 62196503Szec 63177633Sdfr#include <netinet/tcp.h> 64177633Sdfr 65177633Sdfr#include <rpc/rpc.h> 66177633Sdfr 67244008Srmacklem#include <rpc/krpc.h> 68177685Sdfr#include <rpc/rpc_com.h> 69177633Sdfr 70193509Srwatson#include <security/mac/mac_framework.h> 71193509Srwatson 72184588Sdfrstatic bool_t svc_vc_rendezvous_recv(SVCXPRT *, struct rpc_msg *, 73184588Sdfr struct sockaddr **, struct mbuf **); 74177633Sdfrstatic enum xprt_stat svc_vc_rendezvous_stat(SVCXPRT *); 75177633Sdfrstatic void svc_vc_rendezvous_destroy(SVCXPRT *); 76177633Sdfrstatic bool_t svc_vc_null(void); 77177633Sdfrstatic void svc_vc_destroy(SVCXPRT *); 78177633Sdfrstatic enum xprt_stat svc_vc_stat(SVCXPRT *); 79184588Sdfrstatic bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *, 80184588Sdfr struct sockaddr **, struct mbuf **); 81184588Sdfrstatic bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *, 82184588Sdfr struct sockaddr *, struct mbuf *); 83177633Sdfrstatic bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in); 84177633Sdfrstatic bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq, 85177633Sdfr void *in); 86244008Srmacklemstatic void svc_vc_backchannel_destroy(SVCXPRT *); 87244008Srmacklemstatic enum xprt_stat svc_vc_backchannel_stat(SVCXPRT *); 88244008Srmacklemstatic bool_t svc_vc_backchannel_recv(SVCXPRT *, struct rpc_msg *, 89244008Srmacklem struct sockaddr **, struct mbuf **); 90244008Srmacklemstatic bool_t svc_vc_backchannel_reply(SVCXPRT *, struct rpc_msg *, 91244008Srmacklem struct sockaddr *, struct mbuf *); 92244008Srmacklemstatic bool_t svc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, 93244008Srmacklem void *in); 94177633Sdfrstatic SVCXPRT *svc_vc_create_conn(SVCPOOL *pool, struct socket *so, 95177633Sdfr struct sockaddr *raddr); 96177633Sdfrstatic int svc_vc_accept(struct socket *head, struct socket **sop); 97193272Sjhbstatic int svc_vc_soupcall(struct socket *so, void *arg, int waitflag); 98177633Sdfr 99177633Sdfrstatic struct xp_ops svc_vc_rendezvous_ops = { 100177633Sdfr .xp_recv = svc_vc_rendezvous_recv, 101177633Sdfr .xp_stat = svc_vc_rendezvous_stat, 102184588Sdfr .xp_reply = (bool_t (*)(SVCXPRT *, struct rpc_msg *, 103184588Sdfr struct sockaddr *, struct mbuf *))svc_vc_null, 104177633Sdfr .xp_destroy = svc_vc_rendezvous_destroy, 105177633Sdfr .xp_control = svc_vc_rendezvous_control 106177633Sdfr}; 107177633Sdfr 108177633Sdfrstatic struct xp_ops svc_vc_ops = { 109177633Sdfr .xp_recv = svc_vc_recv, 110177633Sdfr .xp_stat = svc_vc_stat, 111177633Sdfr .xp_reply = svc_vc_reply, 112177633Sdfr .xp_destroy = svc_vc_destroy, 113177633Sdfr .xp_control = svc_vc_control 114177633Sdfr}; 115177633Sdfr 116244008Srmacklemstatic struct xp_ops svc_vc_backchannel_ops = { 117244008Srmacklem .xp_recv = svc_vc_backchannel_recv, 118244008Srmacklem .xp_stat = svc_vc_backchannel_stat, 119244008Srmacklem .xp_reply = svc_vc_backchannel_reply, 120244008Srmacklem .xp_destroy = svc_vc_backchannel_destroy, 121244008Srmacklem .xp_control = svc_vc_backchannel_control 122177633Sdfr}; 123177633Sdfr 124177633Sdfr/* 125177633Sdfr * Usage: 126177633Sdfr * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); 127177633Sdfr * 128177633Sdfr * Creates, registers, and returns a (rpc) tcp based transporter. 129177633Sdfr * Once *xprt is initialized, it is registered as a transporter 130177633Sdfr * see (svc.h, xprt_register). This routine returns 131177633Sdfr * a NULL if a problem occurred. 132177633Sdfr * 133177633Sdfr * The filedescriptor passed in is expected to refer to a bound, but 134177633Sdfr * not yet connected socket. 135177633Sdfr * 136177633Sdfr * Since streams do buffered io similar to stdio, the caller can specify 137177633Sdfr * how big the send and receive buffers are via the second and third parms; 138177633Sdfr * 0 => use the system default. 139177633Sdfr */ 140177633SdfrSVCXPRT * 141177633Sdfrsvc_vc_create(SVCPOOL *pool, struct socket *so, size_t sendsize, 142177633Sdfr size_t recvsize) 143177633Sdfr{ 144177633Sdfr SVCXPRT *xprt; 145177633Sdfr struct sockaddr* sa; 146177633Sdfr int error; 147177633Sdfr 148249263Sjhb SOCK_LOCK(so); 149249263Sjhb if (so->so_state & (SS_ISCONNECTED|SS_ISDISCONNECTED)) { 150249263Sjhb SOCK_UNLOCK(so); 151180025Sdfr error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa); 152180025Sdfr if (error) 153180025Sdfr return (NULL); 154180025Sdfr xprt = svc_vc_create_conn(pool, so, sa); 155180025Sdfr free(sa, M_SONAME); 156180025Sdfr return (xprt); 157180025Sdfr } 158249263Sjhb SOCK_UNLOCK(so); 159180025Sdfr 160184588Sdfr xprt = svc_xprt_alloc(); 161184588Sdfr sx_init(&xprt->xp_lock, "xprt->xp_lock"); 162177633Sdfr xprt->xp_pool = pool; 163177633Sdfr xprt->xp_socket = so; 164177633Sdfr xprt->xp_p1 = NULL; 165177633Sdfr xprt->xp_p2 = NULL; 166177633Sdfr xprt->xp_ops = &svc_vc_rendezvous_ops; 167177633Sdfr 168177633Sdfr error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 169196503Szec if (error) { 170177633Sdfr goto cleanup_svc_vc_create; 171196503Szec } 172177633Sdfr 173184588Sdfr memcpy(&xprt->xp_ltaddr, sa, sa->sa_len); 174177633Sdfr free(sa, M_SONAME); 175177633Sdfr 176177633Sdfr xprt_register(xprt); 177177633Sdfr 178177633Sdfr solisten(so, SOMAXCONN, curthread); 179177633Sdfr 180177633Sdfr SOCKBUF_LOCK(&so->so_rcv); 181193436Srmacklem xprt->xp_upcallset = 1; 182193272Sjhb soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt); 183177633Sdfr SOCKBUF_UNLOCK(&so->so_rcv); 184177633Sdfr 185177633Sdfr return (xprt); 186177633Sdfrcleanup_svc_vc_create: 187177633Sdfr if (xprt) 188184588Sdfr svc_xprt_free(xprt); 189177633Sdfr return (NULL); 190177633Sdfr} 191177633Sdfr 192177633Sdfr/* 193177633Sdfr * Create a new transport for a socket optained via soaccept(). 194177633Sdfr */ 195177633SdfrSVCXPRT * 196177633Sdfrsvc_vc_create_conn(SVCPOOL *pool, struct socket *so, struct sockaddr *raddr) 197177633Sdfr{ 198177633Sdfr SVCXPRT *xprt = NULL; 199177633Sdfr struct cf_conn *cd = NULL; 200177633Sdfr struct sockaddr* sa = NULL; 201180025Sdfr struct sockopt opt; 202180025Sdfr int one = 1; 203177633Sdfr int error; 204177633Sdfr 205180025Sdfr bzero(&opt, sizeof(struct sockopt)); 206180025Sdfr opt.sopt_dir = SOPT_SET; 207180025Sdfr opt.sopt_level = SOL_SOCKET; 208180025Sdfr opt.sopt_name = SO_KEEPALIVE; 209180025Sdfr opt.sopt_val = &one; 210180025Sdfr opt.sopt_valsize = sizeof(one); 211180025Sdfr error = sosetopt(so, &opt); 212196503Szec if (error) { 213180025Sdfr return (NULL); 214196503Szec } 215180025Sdfr 216180025Sdfr if (so->so_proto->pr_protocol == IPPROTO_TCP) { 217180025Sdfr bzero(&opt, sizeof(struct sockopt)); 218180025Sdfr opt.sopt_dir = SOPT_SET; 219180025Sdfr opt.sopt_level = IPPROTO_TCP; 220180025Sdfr opt.sopt_name = TCP_NODELAY; 221180025Sdfr opt.sopt_val = &one; 222180025Sdfr opt.sopt_valsize = sizeof(one); 223180025Sdfr error = sosetopt(so, &opt); 224196503Szec if (error) { 225180025Sdfr return (NULL); 226196503Szec } 227180025Sdfr } 228180025Sdfr 229177633Sdfr cd = mem_alloc(sizeof(*cd)); 230177633Sdfr cd->strm_stat = XPRT_IDLE; 231177633Sdfr 232184588Sdfr xprt = svc_xprt_alloc(); 233184588Sdfr sx_init(&xprt->xp_lock, "xprt->xp_lock"); 234177633Sdfr xprt->xp_pool = pool; 235177633Sdfr xprt->xp_socket = so; 236177633Sdfr xprt->xp_p1 = cd; 237177633Sdfr xprt->xp_p2 = NULL; 238177633Sdfr xprt->xp_ops = &svc_vc_ops; 239177633Sdfr 240184588Sdfr /* 241184588Sdfr * See http://www.connectathon.org/talks96/nfstcp.pdf - client 242184588Sdfr * has a 5 minute timer, server has a 6 minute timer. 243184588Sdfr */ 244184588Sdfr xprt->xp_idletimeout = 6 * 60; 245177633Sdfr 246184588Sdfr memcpy(&xprt->xp_rtaddr, raddr, raddr->sa_len); 247184588Sdfr 248177633Sdfr error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 249177633Sdfr if (error) 250177633Sdfr goto cleanup_svc_vc_create; 251177633Sdfr 252184588Sdfr memcpy(&xprt->xp_ltaddr, sa, sa->sa_len); 253177633Sdfr free(sa, M_SONAME); 254177633Sdfr 255177633Sdfr xprt_register(xprt); 256177633Sdfr 257177633Sdfr SOCKBUF_LOCK(&so->so_rcv); 258193436Srmacklem xprt->xp_upcallset = 1; 259193272Sjhb soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt); 260177633Sdfr SOCKBUF_UNLOCK(&so->so_rcv); 261177633Sdfr 262177633Sdfr /* 263177633Sdfr * Throw the transport into the active list in case it already 264177633Sdfr * has some data buffered. 265177633Sdfr */ 266184588Sdfr sx_xlock(&xprt->xp_lock); 267177633Sdfr xprt_active(xprt); 268184588Sdfr sx_xunlock(&xprt->xp_lock); 269177633Sdfr 270177633Sdfr return (xprt); 271177633Sdfrcleanup_svc_vc_create: 272177633Sdfr if (xprt) { 273177633Sdfr mem_free(xprt, sizeof(*xprt)); 274177633Sdfr } 275177633Sdfr if (cd) 276177633Sdfr mem_free(cd, sizeof(*cd)); 277177633Sdfr return (NULL); 278177633Sdfr} 279177633Sdfr 280177633Sdfr/* 281244008Srmacklem * Create a new transport for a backchannel on a clnt_vc socket. 282244008Srmacklem */ 283244008SrmacklemSVCXPRT * 284244008Srmacklemsvc_vc_create_backchannel(SVCPOOL *pool) 285244008Srmacklem{ 286244008Srmacklem SVCXPRT *xprt = NULL; 287244008Srmacklem struct cf_conn *cd = NULL; 288244008Srmacklem 289244008Srmacklem cd = mem_alloc(sizeof(*cd)); 290244008Srmacklem cd->strm_stat = XPRT_IDLE; 291244008Srmacklem 292244008Srmacklem xprt = svc_xprt_alloc(); 293244008Srmacklem sx_init(&xprt->xp_lock, "xprt->xp_lock"); 294244008Srmacklem xprt->xp_pool = pool; 295244008Srmacklem xprt->xp_socket = NULL; 296244008Srmacklem xprt->xp_p1 = cd; 297244008Srmacklem xprt->xp_p2 = NULL; 298244008Srmacklem xprt->xp_ops = &svc_vc_backchannel_ops; 299244008Srmacklem return (xprt); 300244008Srmacklem} 301244008Srmacklem 302244008Srmacklem/* 303177633Sdfr * This does all of the accept except the final call to soaccept. The 304177633Sdfr * caller will call soaccept after dropping its locks (soaccept may 305177633Sdfr * call malloc). 306177633Sdfr */ 307177633Sdfrint 308177633Sdfrsvc_vc_accept(struct socket *head, struct socket **sop) 309177633Sdfr{ 310177633Sdfr int error = 0; 311177633Sdfr struct socket *so; 312177633Sdfr 313177633Sdfr if ((head->so_options & SO_ACCEPTCONN) == 0) { 314177633Sdfr error = EINVAL; 315177633Sdfr goto done; 316177633Sdfr } 317177633Sdfr#ifdef MAC 318193509Srwatson error = mac_socket_check_accept(curthread->td_ucred, head); 319177633Sdfr if (error != 0) 320177633Sdfr goto done; 321177633Sdfr#endif 322177633Sdfr ACCEPT_LOCK(); 323177633Sdfr if (TAILQ_EMPTY(&head->so_comp)) { 324177633Sdfr ACCEPT_UNLOCK(); 325177633Sdfr error = EWOULDBLOCK; 326177633Sdfr goto done; 327177633Sdfr } 328177633Sdfr so = TAILQ_FIRST(&head->so_comp); 329177633Sdfr KASSERT(!(so->so_qstate & SQ_INCOMP), ("svc_vc_accept: so SQ_INCOMP")); 330177633Sdfr KASSERT(so->so_qstate & SQ_COMP, ("svc_vc_accept: so not SQ_COMP")); 331177633Sdfr 332177633Sdfr /* 333177633Sdfr * Before changing the flags on the socket, we have to bump the 334177633Sdfr * reference count. Otherwise, if the protocol calls sofree(), 335177633Sdfr * the socket will be released due to a zero refcount. 336177633Sdfr * XXX might not need soref() since this is simpler than kern_accept. 337177633Sdfr */ 338177633Sdfr SOCK_LOCK(so); /* soref() and so_state update */ 339177633Sdfr soref(so); /* file descriptor reference */ 340177633Sdfr 341177633Sdfr TAILQ_REMOVE(&head->so_comp, so, so_list); 342177633Sdfr head->so_qlen--; 343177633Sdfr so->so_state |= (head->so_state & SS_NBIO); 344177633Sdfr so->so_qstate &= ~SQ_COMP; 345177633Sdfr so->so_head = NULL; 346177633Sdfr 347177633Sdfr SOCK_UNLOCK(so); 348177633Sdfr ACCEPT_UNLOCK(); 349177633Sdfr 350177633Sdfr *sop = so; 351177633Sdfr 352177633Sdfr /* connection has been removed from the listen queue */ 353177633Sdfr KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0); 354177633Sdfrdone: 355177633Sdfr return (error); 356177633Sdfr} 357177633Sdfr 358177633Sdfr/*ARGSUSED*/ 359177633Sdfrstatic bool_t 360184588Sdfrsvc_vc_rendezvous_recv(SVCXPRT *xprt, struct rpc_msg *msg, 361184588Sdfr struct sockaddr **addrp, struct mbuf **mp) 362177633Sdfr{ 363177633Sdfr struct socket *so = NULL; 364177633Sdfr struct sockaddr *sa = NULL; 365177633Sdfr int error; 366194407Srmacklem SVCXPRT *new_xprt; 367177633Sdfr 368177633Sdfr /* 369177633Sdfr * The socket upcall calls xprt_active() which will eventually 370177633Sdfr * cause the server to call us here. We attempt to accept a 371177633Sdfr * connection from the socket and turn it into a new 372177633Sdfr * transport. If the accept fails, we have drained all pending 373177633Sdfr * connections so we call xprt_inactive(). 374177633Sdfr */ 375184588Sdfr sx_xlock(&xprt->xp_lock); 376177633Sdfr 377177633Sdfr error = svc_vc_accept(xprt->xp_socket, &so); 378177633Sdfr 379177633Sdfr if (error == EWOULDBLOCK) { 380184588Sdfr /* 381184588Sdfr * We must re-test for new connections after taking 382184588Sdfr * the lock to protect us in the case where a new 383184588Sdfr * connection arrives after our call to accept fails 384261047Smav * with EWOULDBLOCK. 385184588Sdfr */ 386184588Sdfr ACCEPT_LOCK(); 387184588Sdfr if (TAILQ_EMPTY(&xprt->xp_socket->so_comp)) 388261053Smav xprt_inactive_self(xprt); 389184588Sdfr ACCEPT_UNLOCK(); 390184588Sdfr sx_xunlock(&xprt->xp_lock); 391177633Sdfr return (FALSE); 392177633Sdfr } 393177633Sdfr 394177633Sdfr if (error) { 395177633Sdfr SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 396193436Srmacklem if (xprt->xp_upcallset) { 397193436Srmacklem xprt->xp_upcallset = 0; 398193436Srmacklem soupcall_clear(xprt->xp_socket, SO_RCV); 399193436Srmacklem } 400177633Sdfr SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 401261053Smav xprt_inactive_self(xprt); 402184588Sdfr sx_xunlock(&xprt->xp_lock); 403177633Sdfr return (FALSE); 404177633Sdfr } 405177633Sdfr 406184588Sdfr sx_xunlock(&xprt->xp_lock); 407177633Sdfr 408177633Sdfr sa = 0; 409177633Sdfr error = soaccept(so, &sa); 410177633Sdfr 411177633Sdfr if (error) { 412177633Sdfr /* 413177633Sdfr * XXX not sure if I need to call sofree or soclose here. 414177633Sdfr */ 415177633Sdfr if (sa) 416177633Sdfr free(sa, M_SONAME); 417177633Sdfr return (FALSE); 418177633Sdfr } 419177633Sdfr 420177633Sdfr /* 421177633Sdfr * svc_vc_create_conn will call xprt_register - we don't need 422194407Srmacklem * to do anything with the new connection except derefence it. 423177633Sdfr */ 424194407Srmacklem new_xprt = svc_vc_create_conn(xprt->xp_pool, so, sa); 425194407Srmacklem if (!new_xprt) { 426180025Sdfr soclose(so); 427194407Srmacklem } else { 428194407Srmacklem SVC_RELEASE(new_xprt); 429194407Srmacklem } 430180025Sdfr 431177633Sdfr free(sa, M_SONAME); 432177633Sdfr 433177633Sdfr return (FALSE); /* there is never an rpc msg to be processed */ 434177633Sdfr} 435177633Sdfr 436177633Sdfr/*ARGSUSED*/ 437177633Sdfrstatic enum xprt_stat 438177633Sdfrsvc_vc_rendezvous_stat(SVCXPRT *xprt) 439177633Sdfr{ 440177633Sdfr 441177633Sdfr return (XPRT_IDLE); 442177633Sdfr} 443177633Sdfr 444177633Sdfrstatic void 445177633Sdfrsvc_vc_destroy_common(SVCXPRT *xprt) 446177633Sdfr{ 447177633Sdfr SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 448193436Srmacklem if (xprt->xp_upcallset) { 449193436Srmacklem xprt->xp_upcallset = 0; 450193436Srmacklem soupcall_clear(xprt->xp_socket, SO_RCV); 451193436Srmacklem } 452177633Sdfr SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 453177633Sdfr 454184588Sdfr sx_destroy(&xprt->xp_lock); 455177633Sdfr if (xprt->xp_socket) 456177633Sdfr (void)soclose(xprt->xp_socket); 457177633Sdfr 458184588Sdfr if (xprt->xp_netid) 459184588Sdfr (void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1); 460184588Sdfr svc_xprt_free(xprt); 461177633Sdfr} 462177633Sdfr 463177633Sdfrstatic void 464177633Sdfrsvc_vc_rendezvous_destroy(SVCXPRT *xprt) 465177633Sdfr{ 466177633Sdfr 467177633Sdfr svc_vc_destroy_common(xprt); 468177633Sdfr} 469177633Sdfr 470177633Sdfrstatic void 471177633Sdfrsvc_vc_destroy(SVCXPRT *xprt) 472177633Sdfr{ 473177633Sdfr struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1; 474177633Sdfr 475177633Sdfr svc_vc_destroy_common(xprt); 476177633Sdfr 477177633Sdfr if (cd->mreq) 478177633Sdfr m_freem(cd->mreq); 479177633Sdfr if (cd->mpending) 480177633Sdfr m_freem(cd->mpending); 481177633Sdfr mem_free(cd, sizeof(*cd)); 482177633Sdfr} 483177633Sdfr 484244008Srmacklemstatic void 485244008Srmacklemsvc_vc_backchannel_destroy(SVCXPRT *xprt) 486244008Srmacklem{ 487244008Srmacklem struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1; 488244008Srmacklem struct mbuf *m, *m2; 489244008Srmacklem 490244008Srmacklem svc_xprt_free(xprt); 491244008Srmacklem m = cd->mreq; 492244008Srmacklem while (m != NULL) { 493244008Srmacklem m2 = m; 494244008Srmacklem m = m->m_nextpkt; 495244008Srmacklem m_freem(m2); 496244008Srmacklem } 497244008Srmacklem mem_free(cd, sizeof(*cd)); 498244008Srmacklem} 499244008Srmacklem 500177633Sdfr/*ARGSUSED*/ 501177633Sdfrstatic bool_t 502177633Sdfrsvc_vc_control(SVCXPRT *xprt, const u_int rq, void *in) 503177633Sdfr{ 504177633Sdfr return (FALSE); 505177633Sdfr} 506177633Sdfr 507177633Sdfrstatic bool_t 508177633Sdfrsvc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in) 509177633Sdfr{ 510177633Sdfr 511177633Sdfr return (FALSE); 512177633Sdfr} 513177633Sdfr 514244008Srmacklemstatic bool_t 515244008Srmacklemsvc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, void *in) 516244008Srmacklem{ 517244008Srmacklem 518244008Srmacklem return (FALSE); 519244008Srmacklem} 520244008Srmacklem 521177633Sdfrstatic enum xprt_stat 522177633Sdfrsvc_vc_stat(SVCXPRT *xprt) 523177633Sdfr{ 524177633Sdfr struct cf_conn *cd; 525177633Sdfr 526177633Sdfr cd = (struct cf_conn *)(xprt->xp_p1); 527177633Sdfr 528177633Sdfr if (cd->strm_stat == XPRT_DIED) 529177633Sdfr return (XPRT_DIED); 530177633Sdfr 531261047Smav if (cd->mreq != NULL && cd->resid == 0 && cd->eor) 532261047Smav return (XPRT_MOREREQS); 533177633Sdfr 534184588Sdfr if (soreadable(xprt->xp_socket)) 535184588Sdfr return (XPRT_MOREREQS); 536184588Sdfr 537177633Sdfr return (XPRT_IDLE); 538177633Sdfr} 539177633Sdfr 540244008Srmacklemstatic enum xprt_stat 541244008Srmacklemsvc_vc_backchannel_stat(SVCXPRT *xprt) 542244008Srmacklem{ 543244008Srmacklem struct cf_conn *cd; 544244008Srmacklem 545244008Srmacklem cd = (struct cf_conn *)(xprt->xp_p1); 546244008Srmacklem 547244008Srmacklem if (cd->mreq != NULL) 548244008Srmacklem return (XPRT_MOREREQS); 549244008Srmacklem 550244008Srmacklem return (XPRT_IDLE); 551244008Srmacklem} 552244008Srmacklem 553261047Smav/* 554261047Smav * If we have an mbuf chain in cd->mpending, try to parse a record from it, 555261047Smav * leaving the result in cd->mreq. If we don't have a complete record, leave 556261047Smav * the partial result in cd->mreq and try to read more from the socket. 557261047Smav */ 558261050Smavstatic int 559261047Smavsvc_vc_process_pending(SVCXPRT *xprt) 560261047Smav{ 561261047Smav struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 562261047Smav struct socket *so = xprt->xp_socket; 563261047Smav struct mbuf *m; 564261047Smav 565261047Smav /* 566261047Smav * If cd->resid is non-zero, we have part of the 567261047Smav * record already, otherwise we are expecting a record 568261047Smav * marker. 569261047Smav */ 570261047Smav if (!cd->resid && cd->mpending) { 571261047Smav /* 572261047Smav * See if there is enough data buffered to 573261047Smav * make up a record marker. Make sure we can 574261047Smav * handle the case where the record marker is 575261047Smav * split across more than one mbuf. 576261047Smav */ 577261047Smav size_t n = 0; 578261047Smav uint32_t header; 579261047Smav 580261047Smav m = cd->mpending; 581261047Smav while (n < sizeof(uint32_t) && m) { 582261047Smav n += m->m_len; 583261047Smav m = m->m_next; 584261047Smav } 585261047Smav if (n < sizeof(uint32_t)) { 586261047Smav so->so_rcv.sb_lowat = sizeof(uint32_t) - n; 587261050Smav return (FALSE); 588261047Smav } 589261047Smav m_copydata(cd->mpending, 0, sizeof(header), 590261047Smav (char *)&header); 591261047Smav header = ntohl(header); 592261047Smav cd->eor = (header & 0x80000000) != 0; 593261047Smav cd->resid = header & 0x7fffffff; 594261047Smav m_adj(cd->mpending, sizeof(uint32_t)); 595261047Smav } 596261047Smav 597261047Smav /* 598261047Smav * Start pulling off mbufs from cd->mpending 599261047Smav * until we either have a complete record or 600261047Smav * we run out of data. We use m_split to pull 601261047Smav * data - it will pull as much as possible and 602261047Smav * split the last mbuf if necessary. 603261047Smav */ 604261047Smav while (cd->mpending && cd->resid) { 605261047Smav m = cd->mpending; 606261047Smav if (cd->mpending->m_next 607261047Smav || cd->mpending->m_len > cd->resid) 608261047Smav cd->mpending = m_split(cd->mpending, 609261047Smav cd->resid, M_WAITOK); 610261047Smav else 611261047Smav cd->mpending = NULL; 612261047Smav if (cd->mreq) 613261047Smav m_last(cd->mreq)->m_next = m; 614261047Smav else 615261047Smav cd->mreq = m; 616261047Smav while (m) { 617261047Smav cd->resid -= m->m_len; 618261047Smav m = m->m_next; 619261047Smav } 620261047Smav } 621261047Smav 622261052Smav /* 623261052Smav * Block receive upcalls if we have more data pending, 624261052Smav * otherwise report our need. 625261052Smav */ 626261052Smav if (cd->mpending) 627261052Smav so->so_rcv.sb_lowat = INT_MAX; 628261052Smav else 629261052Smav so->so_rcv.sb_lowat = 630261052Smav imax(1, imin(cd->resid, so->so_rcv.sb_hiwat / 2)); 631261050Smav return (TRUE); 632261047Smav} 633261047Smav 634177633Sdfrstatic bool_t 635184588Sdfrsvc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg, 636184588Sdfr struct sockaddr **addrp, struct mbuf **mp) 637177633Sdfr{ 638177633Sdfr struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 639177633Sdfr struct uio uio; 640177633Sdfr struct mbuf *m; 641261047Smav struct socket* so = xprt->xp_socket; 642184588Sdfr XDR xdrs; 643177633Sdfr int error, rcvflag; 644177633Sdfr 645184588Sdfr /* 646184588Sdfr * Serialise access to the socket and our own record parsing 647184588Sdfr * state. 648184588Sdfr */ 649184588Sdfr sx_xlock(&xprt->xp_lock); 650184588Sdfr 651177633Sdfr for (;;) { 652261047Smav /* If we have no request ready, check pending queue. */ 653261047Smav while (cd->mpending && 654261050Smav (cd->mreq == NULL || cd->resid != 0 || !cd->eor)) { 655261050Smav if (!svc_vc_process_pending(xprt)) 656261050Smav break; 657261050Smav } 658177633Sdfr 659261047Smav /* Process and return complete request in cd->mreq. */ 660261047Smav if (cd->mreq != NULL && cd->resid == 0 && cd->eor) { 661177633Sdfr 662261047Smav xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE); 663261047Smav cd->mreq = NULL; 664261047Smav 665261047Smav /* Check for next request in a pending queue. */ 666261047Smav svc_vc_process_pending(xprt); 667261047Smav if (cd->mreq == NULL || cd->resid != 0) { 668261047Smav SOCKBUF_LOCK(&so->so_rcv); 669261047Smav if (!soreadable(so)) 670261053Smav xprt_inactive_self(xprt); 671261047Smav SOCKBUF_UNLOCK(&so->so_rcv); 672177633Sdfr } 673177633Sdfr 674261047Smav sx_xunlock(&xprt->xp_lock); 675177633Sdfr 676261047Smav if (! xdr_callmsg(&xdrs, msg)) { 677261047Smav XDR_DESTROY(&xdrs); 678261047Smav return (FALSE); 679261047Smav } 680184588Sdfr 681261047Smav *addrp = NULL; 682261047Smav *mp = xdrmbuf_getall(&xdrs); 683261047Smav XDR_DESTROY(&xdrs); 684177633Sdfr 685261047Smav return (TRUE); 686177633Sdfr } 687177633Sdfr 688177633Sdfr /* 689177633Sdfr * The socket upcall calls xprt_active() which will eventually 690177633Sdfr * cause the server to call us here. We attempt to 691177633Sdfr * read as much as possible from the socket and put 692177633Sdfr * the result in cd->mpending. If the read fails, 693177633Sdfr * we have drained both cd->mpending and the socket so 694177633Sdfr * we can call xprt_inactive(). 695177633Sdfr */ 696177633Sdfr uio.uio_resid = 1000000000; 697177633Sdfr uio.uio_td = curthread; 698177633Sdfr m = NULL; 699177633Sdfr rcvflag = MSG_DONTWAIT; 700261047Smav error = soreceive(so, NULL, &uio, &m, NULL, &rcvflag); 701177633Sdfr 702177633Sdfr if (error == EWOULDBLOCK) { 703184588Sdfr /* 704184588Sdfr * We must re-test for readability after 705184588Sdfr * taking the lock to protect us in the case 706184588Sdfr * where a new packet arrives on the socket 707184588Sdfr * after our call to soreceive fails with 708261047Smav * EWOULDBLOCK. 709184588Sdfr */ 710261047Smav SOCKBUF_LOCK(&so->so_rcv); 711261047Smav if (!soreadable(so)) 712261053Smav xprt_inactive_self(xprt); 713261047Smav SOCKBUF_UNLOCK(&so->so_rcv); 714184588Sdfr sx_xunlock(&xprt->xp_lock); 715177633Sdfr return (FALSE); 716177633Sdfr } 717177633Sdfr 718177633Sdfr if (error) { 719261047Smav SOCKBUF_LOCK(&so->so_rcv); 720193436Srmacklem if (xprt->xp_upcallset) { 721193436Srmacklem xprt->xp_upcallset = 0; 722261047Smav soupcall_clear(so, SO_RCV); 723193436Srmacklem } 724261047Smav SOCKBUF_UNLOCK(&so->so_rcv); 725261053Smav xprt_inactive_self(xprt); 726177633Sdfr cd->strm_stat = XPRT_DIED; 727184588Sdfr sx_xunlock(&xprt->xp_lock); 728177633Sdfr return (FALSE); 729177633Sdfr } 730177633Sdfr 731177633Sdfr if (!m) { 732177633Sdfr /* 733177633Sdfr * EOF - the other end has closed the socket. 734177633Sdfr */ 735261053Smav xprt_inactive_self(xprt); 736177633Sdfr cd->strm_stat = XPRT_DIED; 737184588Sdfr sx_xunlock(&xprt->xp_lock); 738177633Sdfr return (FALSE); 739177633Sdfr } 740177633Sdfr 741177633Sdfr if (cd->mpending) 742177633Sdfr m_last(cd->mpending)->m_next = m; 743177633Sdfr else 744177633Sdfr cd->mpending = m; 745177633Sdfr } 746177633Sdfr} 747177633Sdfr 748177633Sdfrstatic bool_t 749244008Srmacklemsvc_vc_backchannel_recv(SVCXPRT *xprt, struct rpc_msg *msg, 750244008Srmacklem struct sockaddr **addrp, struct mbuf **mp) 751244008Srmacklem{ 752244008Srmacklem struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 753244008Srmacklem struct ct_data *ct; 754244008Srmacklem struct mbuf *m; 755244008Srmacklem XDR xdrs; 756244008Srmacklem 757244008Srmacklem sx_xlock(&xprt->xp_lock); 758244008Srmacklem ct = (struct ct_data *)xprt->xp_p2; 759244008Srmacklem if (ct == NULL) { 760244008Srmacklem sx_xunlock(&xprt->xp_lock); 761244008Srmacklem return (FALSE); 762244008Srmacklem } 763244008Srmacklem mtx_lock(&ct->ct_lock); 764244008Srmacklem m = cd->mreq; 765244008Srmacklem if (m == NULL) { 766261053Smav xprt_inactive_self(xprt); 767244008Srmacklem mtx_unlock(&ct->ct_lock); 768244008Srmacklem sx_xunlock(&xprt->xp_lock); 769244008Srmacklem return (FALSE); 770244008Srmacklem } 771244008Srmacklem cd->mreq = m->m_nextpkt; 772244008Srmacklem mtx_unlock(&ct->ct_lock); 773244008Srmacklem sx_xunlock(&xprt->xp_lock); 774244008Srmacklem 775244008Srmacklem xdrmbuf_create(&xdrs, m, XDR_DECODE); 776244008Srmacklem if (! xdr_callmsg(&xdrs, msg)) { 777244008Srmacklem XDR_DESTROY(&xdrs); 778244008Srmacklem return (FALSE); 779244008Srmacklem } 780244008Srmacklem *addrp = NULL; 781244008Srmacklem *mp = xdrmbuf_getall(&xdrs); 782244008Srmacklem XDR_DESTROY(&xdrs); 783244008Srmacklem return (TRUE); 784244008Srmacklem} 785244008Srmacklem 786244008Srmacklemstatic bool_t 787184588Sdfrsvc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg, 788184588Sdfr struct sockaddr *addr, struct mbuf *m) 789177633Sdfr{ 790177633Sdfr XDR xdrs; 791177633Sdfr struct mbuf *mrep; 792184588Sdfr bool_t stat = TRUE; 793177633Sdfr int error; 794177633Sdfr 795177633Sdfr /* 796177633Sdfr * Leave space for record mark. 797177633Sdfr */ 798248195Sglebius mrep = m_gethdr(M_WAITOK, MT_DATA); 799177633Sdfr mrep->m_data += sizeof(uint32_t); 800177633Sdfr 801184588Sdfr xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); 802184588Sdfr 803184588Sdfr if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 804184588Sdfr msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 805184588Sdfr if (!xdr_replymsg(&xdrs, msg)) 806184588Sdfr stat = FALSE; 807184588Sdfr else 808184588Sdfr xdrmbuf_append(&xdrs, m); 809184588Sdfr } else { 810184588Sdfr stat = xdr_replymsg(&xdrs, msg); 811184588Sdfr } 812184588Sdfr 813184588Sdfr if (stat) { 814177633Sdfr m_fixhdr(mrep); 815177633Sdfr 816177633Sdfr /* 817177633Sdfr * Prepend a record marker containing the reply length. 818177633Sdfr */ 819243882Sglebius M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK); 820177633Sdfr *mtod(mrep, uint32_t *) = 821177633Sdfr htonl(0x80000000 | (mrep->m_pkthdr.len 822177633Sdfr - sizeof(uint32_t))); 823177633Sdfr error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL, 824177633Sdfr 0, curthread); 825177633Sdfr if (!error) { 826177633Sdfr stat = TRUE; 827177633Sdfr } 828177633Sdfr } else { 829177633Sdfr m_freem(mrep); 830177633Sdfr } 831177633Sdfr 832184588Sdfr XDR_DESTROY(&xdrs); 833177633Sdfr xprt->xp_p2 = NULL; 834177633Sdfr 835177633Sdfr return (stat); 836177633Sdfr} 837177633Sdfr 838177633Sdfrstatic bool_t 839244008Srmacklemsvc_vc_backchannel_reply(SVCXPRT *xprt, struct rpc_msg *msg, 840244008Srmacklem struct sockaddr *addr, struct mbuf *m) 841244008Srmacklem{ 842244008Srmacklem struct ct_data *ct; 843244008Srmacklem XDR xdrs; 844244008Srmacklem struct mbuf *mrep; 845244008Srmacklem bool_t stat = TRUE; 846244008Srmacklem int error; 847244008Srmacklem 848244008Srmacklem /* 849244008Srmacklem * Leave space for record mark. 850244008Srmacklem */ 851248195Sglebius mrep = m_gethdr(M_WAITOK, MT_DATA); 852244008Srmacklem mrep->m_data += sizeof(uint32_t); 853244008Srmacklem 854244008Srmacklem xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); 855244008Srmacklem 856244008Srmacklem if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 857244008Srmacklem msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 858244008Srmacklem if (!xdr_replymsg(&xdrs, msg)) 859244008Srmacklem stat = FALSE; 860244008Srmacklem else 861244008Srmacklem xdrmbuf_append(&xdrs, m); 862244008Srmacklem } else { 863244008Srmacklem stat = xdr_replymsg(&xdrs, msg); 864244008Srmacklem } 865244008Srmacklem 866244008Srmacklem if (stat) { 867244008Srmacklem m_fixhdr(mrep); 868244008Srmacklem 869244008Srmacklem /* 870244008Srmacklem * Prepend a record marker containing the reply length. 871244008Srmacklem */ 872244008Srmacklem M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK); 873244008Srmacklem *mtod(mrep, uint32_t *) = 874244008Srmacklem htonl(0x80000000 | (mrep->m_pkthdr.len 875244008Srmacklem - sizeof(uint32_t))); 876244008Srmacklem sx_xlock(&xprt->xp_lock); 877244008Srmacklem ct = (struct ct_data *)xprt->xp_p2; 878244008Srmacklem if (ct != NULL) 879244008Srmacklem error = sosend(ct->ct_socket, NULL, NULL, mrep, NULL, 880244008Srmacklem 0, curthread); 881244008Srmacklem else 882244008Srmacklem error = EPIPE; 883244008Srmacklem sx_xunlock(&xprt->xp_lock); 884244008Srmacklem if (!error) { 885244008Srmacklem stat = TRUE; 886244008Srmacklem } 887244008Srmacklem } else { 888244008Srmacklem m_freem(mrep); 889244008Srmacklem } 890244008Srmacklem 891244008Srmacklem XDR_DESTROY(&xdrs); 892244008Srmacklem 893244008Srmacklem return (stat); 894244008Srmacklem} 895244008Srmacklem 896244008Srmacklemstatic bool_t 897177633Sdfrsvc_vc_null() 898177633Sdfr{ 899177633Sdfr 900177633Sdfr return (FALSE); 901177633Sdfr} 902177633Sdfr 903193272Sjhbstatic int 904177633Sdfrsvc_vc_soupcall(struct socket *so, void *arg, int waitflag) 905177633Sdfr{ 906177633Sdfr SVCXPRT *xprt = (SVCXPRT *) arg; 907177633Sdfr 908261047Smav if (soreadable(xprt->xp_socket)) 909261047Smav xprt_active(xprt); 910193272Sjhb return (SU_OK); 911177633Sdfr} 912177633Sdfr 913177633Sdfr#if 0 914177633Sdfr/* 915177633Sdfr * Get the effective UID of the sending process. Used by rpcbind, keyserv 916177633Sdfr * and rpc.yppasswdd on AF_LOCAL. 917177633Sdfr */ 918177633Sdfrint 919177633Sdfr__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) { 920177633Sdfr int sock, ret; 921177633Sdfr gid_t egid; 922177633Sdfr uid_t euid; 923177633Sdfr struct sockaddr *sa; 924177633Sdfr 925177633Sdfr sock = transp->xp_fd; 926184588Sdfr sa = (struct sockaddr *)transp->xp_rtaddr; 927177633Sdfr if (sa->sa_family == AF_LOCAL) { 928177633Sdfr ret = getpeereid(sock, &euid, &egid); 929177633Sdfr if (ret == 0) 930177633Sdfr *uid = euid; 931177633Sdfr return (ret); 932177633Sdfr } else 933177633Sdfr return (-1); 934177633Sdfr} 935177633Sdfr#endif 936