svc_vc.c revision 248195
1177633Sdfr/* $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $ */ 2177633Sdfr 3177633Sdfr/* 4177633Sdfr * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 5177633Sdfr * unrestricted use provided that this legend is included on all tape 6177633Sdfr * media and as a part of the software program in whole or part. Users 7177633Sdfr * may copy or modify Sun RPC without charge, but are not authorized 8177633Sdfr * to license or distribute it to anyone else except as part of a product or 9177633Sdfr * program developed by the user. 10177633Sdfr * 11177633Sdfr * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 12177633Sdfr * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 13177633Sdfr * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 14177633Sdfr * 15177633Sdfr * Sun RPC is provided with no support and without any obligation on the 16177633Sdfr * part of Sun Microsystems, Inc. to assist in its use, correction, 17177633Sdfr * modification or enhancement. 18177633Sdfr * 19177633Sdfr * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 20177633Sdfr * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 21177633Sdfr * OR ANY PART THEREOF. 22177633Sdfr * 23177633Sdfr * In no event will Sun Microsystems, Inc. be liable for any lost revenue 24177633Sdfr * or profits or other special, indirect and consequential damages, even if 25177633Sdfr * Sun has been advised of the possibility of such damages. 26177633Sdfr * 27177633Sdfr * Sun Microsystems, Inc. 28177633Sdfr * 2550 Garcia Avenue 29177633Sdfr * Mountain View, California 94043 30177633Sdfr */ 31177633Sdfr 32177633Sdfr#if defined(LIBC_SCCS) && !defined(lint) 33177633Sdfrstatic char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; 34177633Sdfrstatic char *sccsid = "@(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 35177633Sdfr#endif 36177633Sdfr#include <sys/cdefs.h> 37177633Sdfr__FBSDID("$FreeBSD: head/sys/rpc/svc_vc.c 248195 2013-03-12 12:17:19Z glebius $"); 38177633Sdfr 39177633Sdfr/* 40177633Sdfr * svc_vc.c, Server side for Connection Oriented based RPC. 41177633Sdfr * 42177633Sdfr * Actually implements two flavors of transporter - 43177633Sdfr * a tcp rendezvouser (a listner and connection establisher) 44177633Sdfr * and a record/tcp stream. 45177633Sdfr */ 46177633Sdfr 47177633Sdfr#include <sys/param.h> 48177633Sdfr#include <sys/lock.h> 49177633Sdfr#include <sys/kernel.h> 50177633Sdfr#include <sys/malloc.h> 51177633Sdfr#include <sys/mbuf.h> 52177633Sdfr#include <sys/mutex.h> 53193509Srwatson#include <sys/proc.h> 54177633Sdfr#include <sys/protosw.h> 55177633Sdfr#include <sys/queue.h> 56177633Sdfr#include <sys/socket.h> 57177633Sdfr#include <sys/socketvar.h> 58184588Sdfr#include <sys/sx.h> 59177633Sdfr#include <sys/systm.h> 60177633Sdfr#include <sys/uio.h> 61196503Szec 62196503Szec#include <net/vnet.h> 63196503Szec 64177633Sdfr#include <netinet/tcp.h> 65177633Sdfr 66177633Sdfr#include <rpc/rpc.h> 67177633Sdfr 68244008Srmacklem#include <rpc/krpc.h> 69177685Sdfr#include <rpc/rpc_com.h> 70177633Sdfr 71193509Srwatson#include <security/mac/mac_framework.h> 72193509Srwatson 73184588Sdfrstatic bool_t svc_vc_rendezvous_recv(SVCXPRT *, struct rpc_msg *, 74184588Sdfr struct sockaddr **, struct mbuf **); 75177633Sdfrstatic enum xprt_stat svc_vc_rendezvous_stat(SVCXPRT *); 76177633Sdfrstatic void svc_vc_rendezvous_destroy(SVCXPRT *); 77177633Sdfrstatic bool_t svc_vc_null(void); 78177633Sdfrstatic void svc_vc_destroy(SVCXPRT *); 79177633Sdfrstatic enum xprt_stat svc_vc_stat(SVCXPRT *); 80184588Sdfrstatic bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *, 81184588Sdfr struct sockaddr **, struct mbuf **); 82184588Sdfrstatic bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *, 83184588Sdfr struct sockaddr *, struct mbuf *); 84177633Sdfrstatic bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in); 85177633Sdfrstatic bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq, 86177633Sdfr void *in); 87244008Srmacklemstatic void svc_vc_backchannel_destroy(SVCXPRT *); 88244008Srmacklemstatic enum xprt_stat svc_vc_backchannel_stat(SVCXPRT *); 89244008Srmacklemstatic bool_t svc_vc_backchannel_recv(SVCXPRT *, struct rpc_msg *, 90244008Srmacklem struct sockaddr **, struct mbuf **); 91244008Srmacklemstatic bool_t svc_vc_backchannel_reply(SVCXPRT *, struct rpc_msg *, 92244008Srmacklem struct sockaddr *, struct mbuf *); 93244008Srmacklemstatic bool_t svc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, 94244008Srmacklem void *in); 95177633Sdfrstatic SVCXPRT *svc_vc_create_conn(SVCPOOL *pool, struct socket *so, 96177633Sdfr struct sockaddr *raddr); 97177633Sdfrstatic int svc_vc_accept(struct socket *head, struct socket **sop); 98193272Sjhbstatic int svc_vc_soupcall(struct socket *so, void *arg, int waitflag); 99177633Sdfr 100177633Sdfrstatic struct xp_ops svc_vc_rendezvous_ops = { 101177633Sdfr .xp_recv = svc_vc_rendezvous_recv, 102177633Sdfr .xp_stat = svc_vc_rendezvous_stat, 103184588Sdfr .xp_reply = (bool_t (*)(SVCXPRT *, struct rpc_msg *, 104184588Sdfr struct sockaddr *, struct mbuf *))svc_vc_null, 105177633Sdfr .xp_destroy = svc_vc_rendezvous_destroy, 106177633Sdfr .xp_control = svc_vc_rendezvous_control 107177633Sdfr}; 108177633Sdfr 109177633Sdfrstatic struct xp_ops svc_vc_ops = { 110177633Sdfr .xp_recv = svc_vc_recv, 111177633Sdfr .xp_stat = svc_vc_stat, 112177633Sdfr .xp_reply = svc_vc_reply, 113177633Sdfr .xp_destroy = svc_vc_destroy, 114177633Sdfr .xp_control = svc_vc_control 115177633Sdfr}; 116177633Sdfr 117244008Srmacklemstatic struct xp_ops svc_vc_backchannel_ops = { 118244008Srmacklem .xp_recv = svc_vc_backchannel_recv, 119244008Srmacklem .xp_stat = svc_vc_backchannel_stat, 120244008Srmacklem .xp_reply = svc_vc_backchannel_reply, 121244008Srmacklem .xp_destroy = svc_vc_backchannel_destroy, 122244008Srmacklem .xp_control = svc_vc_backchannel_control 123177633Sdfr}; 124177633Sdfr 125177633Sdfr/* 126177633Sdfr * Usage: 127177633Sdfr * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); 128177633Sdfr * 129177633Sdfr * Creates, registers, and returns a (rpc) tcp based transporter. 130177633Sdfr * Once *xprt is initialized, it is registered as a transporter 131177633Sdfr * see (svc.h, xprt_register). This routine returns 132177633Sdfr * a NULL if a problem occurred. 133177633Sdfr * 134177633Sdfr * The filedescriptor passed in is expected to refer to a bound, but 135177633Sdfr * not yet connected socket. 136177633Sdfr * 137177633Sdfr * Since streams do buffered io similar to stdio, the caller can specify 138177633Sdfr * how big the send and receive buffers are via the second and third parms; 139177633Sdfr * 0 => use the system default. 140177633Sdfr */ 141177633SdfrSVCXPRT * 142177633Sdfrsvc_vc_create(SVCPOOL *pool, struct socket *so, size_t sendsize, 143177633Sdfr size_t recvsize) 144177633Sdfr{ 145177633Sdfr SVCXPRT *xprt; 146177633Sdfr struct sockaddr* sa; 147177633Sdfr int error; 148177633Sdfr 149180025Sdfr if (so->so_state & SS_ISCONNECTED) { 150180025Sdfr error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa); 151180025Sdfr if (error) 152180025Sdfr return (NULL); 153180025Sdfr xprt = svc_vc_create_conn(pool, so, sa); 154180025Sdfr free(sa, M_SONAME); 155180025Sdfr return (xprt); 156180025Sdfr } 157180025Sdfr 158184588Sdfr xprt = svc_xprt_alloc(); 159184588Sdfr sx_init(&xprt->xp_lock, "xprt->xp_lock"); 160177633Sdfr xprt->xp_pool = pool; 161177633Sdfr xprt->xp_socket = so; 162177633Sdfr xprt->xp_p1 = NULL; 163177633Sdfr xprt->xp_p2 = NULL; 164177633Sdfr xprt->xp_ops = &svc_vc_rendezvous_ops; 165177633Sdfr 166177633Sdfr error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 167196503Szec if (error) { 168177633Sdfr goto cleanup_svc_vc_create; 169196503Szec } 170177633Sdfr 171184588Sdfr memcpy(&xprt->xp_ltaddr, sa, sa->sa_len); 172177633Sdfr free(sa, M_SONAME); 173177633Sdfr 174177633Sdfr xprt_register(xprt); 175177633Sdfr 176177633Sdfr solisten(so, SOMAXCONN, curthread); 177177633Sdfr 178177633Sdfr SOCKBUF_LOCK(&so->so_rcv); 179193436Srmacklem xprt->xp_upcallset = 1; 180193272Sjhb soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt); 181177633Sdfr SOCKBUF_UNLOCK(&so->so_rcv); 182177633Sdfr 183177633Sdfr return (xprt); 184177633Sdfrcleanup_svc_vc_create: 185177633Sdfr if (xprt) 186184588Sdfr svc_xprt_free(xprt); 187177633Sdfr return (NULL); 188177633Sdfr} 189177633Sdfr 190177633Sdfr/* 191177633Sdfr * Create a new transport for a socket optained via soaccept(). 192177633Sdfr */ 193177633SdfrSVCXPRT * 194177633Sdfrsvc_vc_create_conn(SVCPOOL *pool, struct socket *so, struct sockaddr *raddr) 195177633Sdfr{ 196177633Sdfr SVCXPRT *xprt = NULL; 197177633Sdfr struct cf_conn *cd = NULL; 198177633Sdfr struct sockaddr* sa = NULL; 199180025Sdfr struct sockopt opt; 200180025Sdfr int one = 1; 201177633Sdfr int error; 202177633Sdfr 203180025Sdfr bzero(&opt, sizeof(struct sockopt)); 204180025Sdfr opt.sopt_dir = SOPT_SET; 205180025Sdfr opt.sopt_level = SOL_SOCKET; 206180025Sdfr opt.sopt_name = SO_KEEPALIVE; 207180025Sdfr opt.sopt_val = &one; 208180025Sdfr opt.sopt_valsize = sizeof(one); 209180025Sdfr error = sosetopt(so, &opt); 210196503Szec if (error) { 211180025Sdfr return (NULL); 212196503Szec } 213180025Sdfr 214180025Sdfr if (so->so_proto->pr_protocol == IPPROTO_TCP) { 215180025Sdfr bzero(&opt, sizeof(struct sockopt)); 216180025Sdfr opt.sopt_dir = SOPT_SET; 217180025Sdfr opt.sopt_level = IPPROTO_TCP; 218180025Sdfr opt.sopt_name = TCP_NODELAY; 219180025Sdfr opt.sopt_val = &one; 220180025Sdfr opt.sopt_valsize = sizeof(one); 221180025Sdfr error = sosetopt(so, &opt); 222196503Szec if (error) { 223180025Sdfr return (NULL); 224196503Szec } 225180025Sdfr } 226180025Sdfr 227177633Sdfr cd = mem_alloc(sizeof(*cd)); 228177633Sdfr cd->strm_stat = XPRT_IDLE; 229177633Sdfr 230184588Sdfr xprt = svc_xprt_alloc(); 231184588Sdfr sx_init(&xprt->xp_lock, "xprt->xp_lock"); 232177633Sdfr xprt->xp_pool = pool; 233177633Sdfr xprt->xp_socket = so; 234177633Sdfr xprt->xp_p1 = cd; 235177633Sdfr xprt->xp_p2 = NULL; 236177633Sdfr xprt->xp_ops = &svc_vc_ops; 237177633Sdfr 238184588Sdfr /* 239184588Sdfr * See http://www.connectathon.org/talks96/nfstcp.pdf - client 240184588Sdfr * has a 5 minute timer, server has a 6 minute timer. 241184588Sdfr */ 242184588Sdfr xprt->xp_idletimeout = 6 * 60; 243177633Sdfr 244184588Sdfr memcpy(&xprt->xp_rtaddr, raddr, raddr->sa_len); 245184588Sdfr 246177633Sdfr error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 247177633Sdfr if (error) 248177633Sdfr goto cleanup_svc_vc_create; 249177633Sdfr 250184588Sdfr memcpy(&xprt->xp_ltaddr, sa, sa->sa_len); 251177633Sdfr free(sa, M_SONAME); 252177633Sdfr 253177633Sdfr xprt_register(xprt); 254177633Sdfr 255177633Sdfr SOCKBUF_LOCK(&so->so_rcv); 256193436Srmacklem xprt->xp_upcallset = 1; 257193272Sjhb soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt); 258177633Sdfr SOCKBUF_UNLOCK(&so->so_rcv); 259177633Sdfr 260177633Sdfr /* 261177633Sdfr * Throw the transport into the active list in case it already 262177633Sdfr * has some data buffered. 263177633Sdfr */ 264184588Sdfr sx_xlock(&xprt->xp_lock); 265177633Sdfr xprt_active(xprt); 266184588Sdfr sx_xunlock(&xprt->xp_lock); 267177633Sdfr 268177633Sdfr return (xprt); 269177633Sdfrcleanup_svc_vc_create: 270177633Sdfr if (xprt) { 271177633Sdfr mem_free(xprt, sizeof(*xprt)); 272177633Sdfr } 273177633Sdfr if (cd) 274177633Sdfr mem_free(cd, sizeof(*cd)); 275177633Sdfr return (NULL); 276177633Sdfr} 277177633Sdfr 278177633Sdfr/* 279244008Srmacklem * Create a new transport for a backchannel on a clnt_vc socket. 280244008Srmacklem */ 281244008SrmacklemSVCXPRT * 282244008Srmacklemsvc_vc_create_backchannel(SVCPOOL *pool) 283244008Srmacklem{ 284244008Srmacklem SVCXPRT *xprt = NULL; 285244008Srmacklem struct cf_conn *cd = NULL; 286244008Srmacklem 287244008Srmacklem cd = mem_alloc(sizeof(*cd)); 288244008Srmacklem cd->strm_stat = XPRT_IDLE; 289244008Srmacklem 290244008Srmacklem xprt = svc_xprt_alloc(); 291244008Srmacklem sx_init(&xprt->xp_lock, "xprt->xp_lock"); 292244008Srmacklem xprt->xp_pool = pool; 293244008Srmacklem xprt->xp_socket = NULL; 294244008Srmacklem xprt->xp_p1 = cd; 295244008Srmacklem xprt->xp_p2 = NULL; 296244008Srmacklem xprt->xp_ops = &svc_vc_backchannel_ops; 297244008Srmacklem return (xprt); 298244008Srmacklem} 299244008Srmacklem 300244008Srmacklem/* 301177633Sdfr * This does all of the accept except the final call to soaccept. The 302177633Sdfr * caller will call soaccept after dropping its locks (soaccept may 303177633Sdfr * call malloc). 304177633Sdfr */ 305177633Sdfrint 306177633Sdfrsvc_vc_accept(struct socket *head, struct socket **sop) 307177633Sdfr{ 308177633Sdfr int error = 0; 309177633Sdfr struct socket *so; 310177633Sdfr 311177633Sdfr if ((head->so_options & SO_ACCEPTCONN) == 0) { 312177633Sdfr error = EINVAL; 313177633Sdfr goto done; 314177633Sdfr } 315177633Sdfr#ifdef MAC 316193509Srwatson error = mac_socket_check_accept(curthread->td_ucred, head); 317177633Sdfr if (error != 0) 318177633Sdfr goto done; 319177633Sdfr#endif 320177633Sdfr ACCEPT_LOCK(); 321177633Sdfr if (TAILQ_EMPTY(&head->so_comp)) { 322177633Sdfr ACCEPT_UNLOCK(); 323177633Sdfr error = EWOULDBLOCK; 324177633Sdfr goto done; 325177633Sdfr } 326177633Sdfr so = TAILQ_FIRST(&head->so_comp); 327177633Sdfr KASSERT(!(so->so_qstate & SQ_INCOMP), ("svc_vc_accept: so SQ_INCOMP")); 328177633Sdfr KASSERT(so->so_qstate & SQ_COMP, ("svc_vc_accept: so not SQ_COMP")); 329177633Sdfr 330177633Sdfr /* 331177633Sdfr * Before changing the flags on the socket, we have to bump the 332177633Sdfr * reference count. Otherwise, if the protocol calls sofree(), 333177633Sdfr * the socket will be released due to a zero refcount. 334177633Sdfr * XXX might not need soref() since this is simpler than kern_accept. 335177633Sdfr */ 336177633Sdfr SOCK_LOCK(so); /* soref() and so_state update */ 337177633Sdfr soref(so); /* file descriptor reference */ 338177633Sdfr 339177633Sdfr TAILQ_REMOVE(&head->so_comp, so, so_list); 340177633Sdfr head->so_qlen--; 341177633Sdfr so->so_state |= (head->so_state & SS_NBIO); 342177633Sdfr so->so_qstate &= ~SQ_COMP; 343177633Sdfr so->so_head = NULL; 344177633Sdfr 345177633Sdfr SOCK_UNLOCK(so); 346177633Sdfr ACCEPT_UNLOCK(); 347177633Sdfr 348177633Sdfr *sop = so; 349177633Sdfr 350177633Sdfr /* connection has been removed from the listen queue */ 351177633Sdfr KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0); 352177633Sdfrdone: 353177633Sdfr return (error); 354177633Sdfr} 355177633Sdfr 356177633Sdfr/*ARGSUSED*/ 357177633Sdfrstatic bool_t 358184588Sdfrsvc_vc_rendezvous_recv(SVCXPRT *xprt, struct rpc_msg *msg, 359184588Sdfr struct sockaddr **addrp, struct mbuf **mp) 360177633Sdfr{ 361177633Sdfr struct socket *so = NULL; 362177633Sdfr struct sockaddr *sa = NULL; 363177633Sdfr int error; 364194407Srmacklem SVCXPRT *new_xprt; 365177633Sdfr 366177633Sdfr /* 367177633Sdfr * The socket upcall calls xprt_active() which will eventually 368177633Sdfr * cause the server to call us here. We attempt to accept a 369177633Sdfr * connection from the socket and turn it into a new 370177633Sdfr * transport. If the accept fails, we have drained all pending 371177633Sdfr * connections so we call xprt_inactive(). 372177633Sdfr */ 373184588Sdfr sx_xlock(&xprt->xp_lock); 374177633Sdfr 375177633Sdfr error = svc_vc_accept(xprt->xp_socket, &so); 376177633Sdfr 377177633Sdfr if (error == EWOULDBLOCK) { 378184588Sdfr /* 379184588Sdfr * We must re-test for new connections after taking 380184588Sdfr * the lock to protect us in the case where a new 381184588Sdfr * connection arrives after our call to accept fails 382184588Sdfr * with EWOULDBLOCK. The pool lock protects us from 383184588Sdfr * racing the upcall after our TAILQ_EMPTY() call 384184588Sdfr * returns false. 385184588Sdfr */ 386184588Sdfr ACCEPT_LOCK(); 387184588Sdfr mtx_lock(&xprt->xp_pool->sp_lock); 388184588Sdfr if (TAILQ_EMPTY(&xprt->xp_socket->so_comp)) 389184588Sdfr xprt_inactive_locked(xprt); 390184588Sdfr mtx_unlock(&xprt->xp_pool->sp_lock); 391184588Sdfr ACCEPT_UNLOCK(); 392184588Sdfr sx_xunlock(&xprt->xp_lock); 393177633Sdfr return (FALSE); 394177633Sdfr } 395177633Sdfr 396177633Sdfr if (error) { 397177633Sdfr SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 398193436Srmacklem if (xprt->xp_upcallset) { 399193436Srmacklem xprt->xp_upcallset = 0; 400193436Srmacklem soupcall_clear(xprt->xp_socket, SO_RCV); 401193436Srmacklem } 402177633Sdfr SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 403177633Sdfr xprt_inactive(xprt); 404184588Sdfr sx_xunlock(&xprt->xp_lock); 405177633Sdfr return (FALSE); 406177633Sdfr } 407177633Sdfr 408184588Sdfr sx_xunlock(&xprt->xp_lock); 409177633Sdfr 410177633Sdfr sa = 0; 411177633Sdfr error = soaccept(so, &sa); 412177633Sdfr 413177633Sdfr if (error) { 414177633Sdfr /* 415177633Sdfr * XXX not sure if I need to call sofree or soclose here. 416177633Sdfr */ 417177633Sdfr if (sa) 418177633Sdfr free(sa, M_SONAME); 419177633Sdfr return (FALSE); 420177633Sdfr } 421177633Sdfr 422177633Sdfr /* 423177633Sdfr * svc_vc_create_conn will call xprt_register - we don't need 424194407Srmacklem * to do anything with the new connection except derefence it. 425177633Sdfr */ 426194407Srmacklem new_xprt = svc_vc_create_conn(xprt->xp_pool, so, sa); 427194407Srmacklem if (!new_xprt) { 428180025Sdfr soclose(so); 429194407Srmacklem } else { 430194407Srmacklem SVC_RELEASE(new_xprt); 431194407Srmacklem } 432180025Sdfr 433177633Sdfr free(sa, M_SONAME); 434177633Sdfr 435177633Sdfr return (FALSE); /* there is never an rpc msg to be processed */ 436177633Sdfr} 437177633Sdfr 438177633Sdfr/*ARGSUSED*/ 439177633Sdfrstatic enum xprt_stat 440177633Sdfrsvc_vc_rendezvous_stat(SVCXPRT *xprt) 441177633Sdfr{ 442177633Sdfr 443177633Sdfr return (XPRT_IDLE); 444177633Sdfr} 445177633Sdfr 446177633Sdfrstatic void 447177633Sdfrsvc_vc_destroy_common(SVCXPRT *xprt) 448177633Sdfr{ 449177633Sdfr SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 450193436Srmacklem if (xprt->xp_upcallset) { 451193436Srmacklem xprt->xp_upcallset = 0; 452193436Srmacklem soupcall_clear(xprt->xp_socket, SO_RCV); 453193436Srmacklem } 454177633Sdfr SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 455177633Sdfr 456184588Sdfr sx_destroy(&xprt->xp_lock); 457177633Sdfr if (xprt->xp_socket) 458177633Sdfr (void)soclose(xprt->xp_socket); 459177633Sdfr 460184588Sdfr if (xprt->xp_netid) 461184588Sdfr (void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1); 462184588Sdfr svc_xprt_free(xprt); 463177633Sdfr} 464177633Sdfr 465177633Sdfrstatic void 466177633Sdfrsvc_vc_rendezvous_destroy(SVCXPRT *xprt) 467177633Sdfr{ 468177633Sdfr 469177633Sdfr svc_vc_destroy_common(xprt); 470177633Sdfr} 471177633Sdfr 472177633Sdfrstatic void 473177633Sdfrsvc_vc_destroy(SVCXPRT *xprt) 474177633Sdfr{ 475177633Sdfr struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1; 476177633Sdfr 477177633Sdfr svc_vc_destroy_common(xprt); 478177633Sdfr 479177633Sdfr if (cd->mreq) 480177633Sdfr m_freem(cd->mreq); 481177633Sdfr if (cd->mpending) 482177633Sdfr m_freem(cd->mpending); 483177633Sdfr mem_free(cd, sizeof(*cd)); 484177633Sdfr} 485177633Sdfr 486244008Srmacklemstatic void 487244008Srmacklemsvc_vc_backchannel_destroy(SVCXPRT *xprt) 488244008Srmacklem{ 489244008Srmacklem struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1; 490244008Srmacklem struct mbuf *m, *m2; 491244008Srmacklem 492244008Srmacklem svc_xprt_free(xprt); 493244008Srmacklem m = cd->mreq; 494244008Srmacklem while (m != NULL) { 495244008Srmacklem m2 = m; 496244008Srmacklem m = m->m_nextpkt; 497244008Srmacklem m_freem(m2); 498244008Srmacklem } 499244008Srmacklem mem_free(cd, sizeof(*cd)); 500244008Srmacklem} 501244008Srmacklem 502177633Sdfr/*ARGSUSED*/ 503177633Sdfrstatic bool_t 504177633Sdfrsvc_vc_control(SVCXPRT *xprt, const u_int rq, void *in) 505177633Sdfr{ 506177633Sdfr return (FALSE); 507177633Sdfr} 508177633Sdfr 509177633Sdfrstatic bool_t 510177633Sdfrsvc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in) 511177633Sdfr{ 512177633Sdfr 513177633Sdfr return (FALSE); 514177633Sdfr} 515177633Sdfr 516244008Srmacklemstatic bool_t 517244008Srmacklemsvc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, void *in) 518244008Srmacklem{ 519244008Srmacklem 520244008Srmacklem return (FALSE); 521244008Srmacklem} 522244008Srmacklem 523177633Sdfrstatic enum xprt_stat 524177633Sdfrsvc_vc_stat(SVCXPRT *xprt) 525177633Sdfr{ 526177633Sdfr struct cf_conn *cd; 527177633Sdfr struct mbuf *m; 528177633Sdfr size_t n; 529177633Sdfr 530177633Sdfr cd = (struct cf_conn *)(xprt->xp_p1); 531177633Sdfr 532177633Sdfr if (cd->strm_stat == XPRT_DIED) 533177633Sdfr return (XPRT_DIED); 534177633Sdfr 535177633Sdfr /* 536177633Sdfr * Return XPRT_MOREREQS if we have buffered data and we are 537184588Sdfr * mid-record or if we have enough data for a record 538184588Sdfr * marker. Since this is only a hint, we read mpending and 539184588Sdfr * resid outside the lock. We do need to take the lock if we 540184588Sdfr * have to traverse the mbuf chain. 541177633Sdfr */ 542177633Sdfr if (cd->mpending) { 543177633Sdfr if (cd->resid) 544177633Sdfr return (XPRT_MOREREQS); 545177633Sdfr n = 0; 546184588Sdfr sx_xlock(&xprt->xp_lock); 547177633Sdfr m = cd->mpending; 548177633Sdfr while (m && n < sizeof(uint32_t)) { 549177633Sdfr n += m->m_len; 550177633Sdfr m = m->m_next; 551177633Sdfr } 552184588Sdfr sx_xunlock(&xprt->xp_lock); 553177633Sdfr if (n >= sizeof(uint32_t)) 554177633Sdfr return (XPRT_MOREREQS); 555177633Sdfr } 556177633Sdfr 557184588Sdfr if (soreadable(xprt->xp_socket)) 558184588Sdfr return (XPRT_MOREREQS); 559184588Sdfr 560177633Sdfr return (XPRT_IDLE); 561177633Sdfr} 562177633Sdfr 563244008Srmacklemstatic enum xprt_stat 564244008Srmacklemsvc_vc_backchannel_stat(SVCXPRT *xprt) 565244008Srmacklem{ 566244008Srmacklem struct cf_conn *cd; 567244008Srmacklem 568244008Srmacklem cd = (struct cf_conn *)(xprt->xp_p1); 569244008Srmacklem 570244008Srmacklem if (cd->mreq != NULL) 571244008Srmacklem return (XPRT_MOREREQS); 572244008Srmacklem 573244008Srmacklem return (XPRT_IDLE); 574244008Srmacklem} 575244008Srmacklem 576177633Sdfrstatic bool_t 577184588Sdfrsvc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg, 578184588Sdfr struct sockaddr **addrp, struct mbuf **mp) 579177633Sdfr{ 580177633Sdfr struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 581177633Sdfr struct uio uio; 582177633Sdfr struct mbuf *m; 583184588Sdfr XDR xdrs; 584177633Sdfr int error, rcvflag; 585177633Sdfr 586184588Sdfr /* 587184588Sdfr * Serialise access to the socket and our own record parsing 588184588Sdfr * state. 589184588Sdfr */ 590184588Sdfr sx_xlock(&xprt->xp_lock); 591184588Sdfr 592177633Sdfr for (;;) { 593177633Sdfr /* 594177633Sdfr * If we have an mbuf chain in cd->mpending, try to parse a 595177633Sdfr * record from it, leaving the result in cd->mreq. If we don't 596177633Sdfr * have a complete record, leave the partial result in 597177633Sdfr * cd->mreq and try to read more from the socket. 598177633Sdfr */ 599177633Sdfr if (cd->mpending) { 600177633Sdfr /* 601177633Sdfr * If cd->resid is non-zero, we have part of the 602177633Sdfr * record already, otherwise we are expecting a record 603177633Sdfr * marker. 604177633Sdfr */ 605177633Sdfr if (!cd->resid) { 606177633Sdfr /* 607177633Sdfr * See if there is enough data buffered to 608177633Sdfr * make up a record marker. Make sure we can 609177633Sdfr * handle the case where the record marker is 610177633Sdfr * split across more than one mbuf. 611177633Sdfr */ 612177633Sdfr size_t n = 0; 613177633Sdfr uint32_t header; 614177633Sdfr 615177633Sdfr m = cd->mpending; 616177633Sdfr while (n < sizeof(uint32_t) && m) { 617177633Sdfr n += m->m_len; 618177633Sdfr m = m->m_next; 619177633Sdfr } 620177633Sdfr if (n < sizeof(uint32_t)) 621177633Sdfr goto readmore; 622217242Srmacklem m_copydata(cd->mpending, 0, sizeof(header), 623217242Srmacklem (char *)&header); 624177633Sdfr header = ntohl(header); 625177633Sdfr cd->eor = (header & 0x80000000) != 0; 626177633Sdfr cd->resid = header & 0x7fffffff; 627177633Sdfr m_adj(cd->mpending, sizeof(uint32_t)); 628177633Sdfr } 629177633Sdfr 630177633Sdfr /* 631177633Sdfr * Start pulling off mbufs from cd->mpending 632177633Sdfr * until we either have a complete record or 633177633Sdfr * we run out of data. We use m_split to pull 634177633Sdfr * data - it will pull as much as possible and 635177633Sdfr * split the last mbuf if necessary. 636177633Sdfr */ 637177633Sdfr while (cd->mpending && cd->resid) { 638177633Sdfr m = cd->mpending; 639184588Sdfr if (cd->mpending->m_next 640184588Sdfr || cd->mpending->m_len > cd->resid) 641184588Sdfr cd->mpending = m_split(cd->mpending, 642243882Sglebius cd->resid, M_WAITOK); 643184588Sdfr else 644184588Sdfr cd->mpending = NULL; 645177633Sdfr if (cd->mreq) 646177633Sdfr m_last(cd->mreq)->m_next = m; 647177633Sdfr else 648177633Sdfr cd->mreq = m; 649177633Sdfr while (m) { 650177633Sdfr cd->resid -= m->m_len; 651177633Sdfr m = m->m_next; 652177633Sdfr } 653177633Sdfr } 654177633Sdfr 655177633Sdfr /* 656177633Sdfr * If cd->resid is zero now, we have managed to 657177633Sdfr * receive a record fragment from the stream. Check 658177633Sdfr * for the end-of-record mark to see if we need more. 659177633Sdfr */ 660177633Sdfr if (cd->resid == 0) { 661177633Sdfr if (!cd->eor) 662177633Sdfr continue; 663177633Sdfr 664177633Sdfr /* 665177633Sdfr * Success - we have a complete record in 666177633Sdfr * cd->mreq. 667177633Sdfr */ 668184588Sdfr xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE); 669177633Sdfr cd->mreq = NULL; 670184588Sdfr sx_xunlock(&xprt->xp_lock); 671184588Sdfr 672184588Sdfr if (! xdr_callmsg(&xdrs, msg)) { 673184588Sdfr XDR_DESTROY(&xdrs); 674177633Sdfr return (FALSE); 675177633Sdfr } 676177633Sdfr 677184588Sdfr *addrp = NULL; 678184588Sdfr *mp = xdrmbuf_getall(&xdrs); 679184588Sdfr XDR_DESTROY(&xdrs); 680184588Sdfr 681177633Sdfr return (TRUE); 682177633Sdfr } 683177633Sdfr } 684177633Sdfr 685177633Sdfr readmore: 686177633Sdfr /* 687177633Sdfr * The socket upcall calls xprt_active() which will eventually 688177633Sdfr * cause the server to call us here. We attempt to 689177633Sdfr * read as much as possible from the socket and put 690177633Sdfr * the result in cd->mpending. If the read fails, 691177633Sdfr * we have drained both cd->mpending and the socket so 692177633Sdfr * we can call xprt_inactive(). 693177633Sdfr */ 694177633Sdfr uio.uio_resid = 1000000000; 695177633Sdfr uio.uio_td = curthread; 696177633Sdfr m = NULL; 697177633Sdfr rcvflag = MSG_DONTWAIT; 698177633Sdfr error = soreceive(xprt->xp_socket, NULL, &uio, &m, NULL, 699177633Sdfr &rcvflag); 700177633Sdfr 701177633Sdfr if (error == EWOULDBLOCK) { 702184588Sdfr /* 703184588Sdfr * We must re-test for readability after 704184588Sdfr * taking the lock to protect us in the case 705184588Sdfr * where a new packet arrives on the socket 706184588Sdfr * after our call to soreceive fails with 707184588Sdfr * EWOULDBLOCK. The pool lock protects us from 708184588Sdfr * racing the upcall after our soreadable() 709184588Sdfr * call returns false. 710184588Sdfr */ 711184588Sdfr mtx_lock(&xprt->xp_pool->sp_lock); 712184588Sdfr if (!soreadable(xprt->xp_socket)) 713184588Sdfr xprt_inactive_locked(xprt); 714184588Sdfr mtx_unlock(&xprt->xp_pool->sp_lock); 715184588Sdfr sx_xunlock(&xprt->xp_lock); 716177633Sdfr return (FALSE); 717177633Sdfr } 718177633Sdfr 719177633Sdfr if (error) { 720177633Sdfr SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 721193436Srmacklem if (xprt->xp_upcallset) { 722193436Srmacklem xprt->xp_upcallset = 0; 723193436Srmacklem soupcall_clear(xprt->xp_socket, SO_RCV); 724193436Srmacklem } 725177633Sdfr SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 726177633Sdfr xprt_inactive(xprt); 727177633Sdfr cd->strm_stat = XPRT_DIED; 728184588Sdfr sx_xunlock(&xprt->xp_lock); 729177633Sdfr return (FALSE); 730177633Sdfr } 731177633Sdfr 732177633Sdfr if (!m) { 733177633Sdfr /* 734177633Sdfr * EOF - the other end has closed the socket. 735177633Sdfr */ 736184588Sdfr xprt_inactive(xprt); 737177633Sdfr cd->strm_stat = XPRT_DIED; 738184588Sdfr sx_xunlock(&xprt->xp_lock); 739177633Sdfr return (FALSE); 740177633Sdfr } 741177633Sdfr 742177633Sdfr if (cd->mpending) 743177633Sdfr m_last(cd->mpending)->m_next = m; 744177633Sdfr else 745177633Sdfr cd->mpending = m; 746177633Sdfr } 747177633Sdfr} 748177633Sdfr 749177633Sdfrstatic bool_t 750244008Srmacklemsvc_vc_backchannel_recv(SVCXPRT *xprt, struct rpc_msg *msg, 751244008Srmacklem struct sockaddr **addrp, struct mbuf **mp) 752244008Srmacklem{ 753244008Srmacklem struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 754244008Srmacklem struct ct_data *ct; 755244008Srmacklem struct mbuf *m; 756244008Srmacklem XDR xdrs; 757244008Srmacklem 758244008Srmacklem sx_xlock(&xprt->xp_lock); 759244008Srmacklem ct = (struct ct_data *)xprt->xp_p2; 760244008Srmacklem if (ct == NULL) { 761244008Srmacklem sx_xunlock(&xprt->xp_lock); 762244008Srmacklem return (FALSE); 763244008Srmacklem } 764244008Srmacklem mtx_lock(&ct->ct_lock); 765244008Srmacklem m = cd->mreq; 766244008Srmacklem if (m == NULL) { 767244008Srmacklem xprt_inactive(xprt); 768244008Srmacklem mtx_unlock(&ct->ct_lock); 769244008Srmacklem sx_xunlock(&xprt->xp_lock); 770244008Srmacklem return (FALSE); 771244008Srmacklem } 772244008Srmacklem cd->mreq = m->m_nextpkt; 773244008Srmacklem mtx_unlock(&ct->ct_lock); 774244008Srmacklem sx_xunlock(&xprt->xp_lock); 775244008Srmacklem 776244008Srmacklem xdrmbuf_create(&xdrs, m, XDR_DECODE); 777244008Srmacklem if (! xdr_callmsg(&xdrs, msg)) { 778244008Srmacklem XDR_DESTROY(&xdrs); 779244008Srmacklem return (FALSE); 780244008Srmacklem } 781244008Srmacklem *addrp = NULL; 782244008Srmacklem *mp = xdrmbuf_getall(&xdrs); 783244008Srmacklem XDR_DESTROY(&xdrs); 784244008Srmacklem return (TRUE); 785244008Srmacklem} 786244008Srmacklem 787244008Srmacklemstatic bool_t 788184588Sdfrsvc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg, 789184588Sdfr struct sockaddr *addr, struct mbuf *m) 790177633Sdfr{ 791177633Sdfr XDR xdrs; 792177633Sdfr struct mbuf *mrep; 793184588Sdfr bool_t stat = TRUE; 794177633Sdfr int error; 795177633Sdfr 796177633Sdfr /* 797177633Sdfr * Leave space for record mark. 798177633Sdfr */ 799248195Sglebius mrep = m_gethdr(M_WAITOK, MT_DATA); 800177633Sdfr mrep->m_data += sizeof(uint32_t); 801177633Sdfr 802184588Sdfr xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); 803184588Sdfr 804184588Sdfr if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 805184588Sdfr msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 806184588Sdfr if (!xdr_replymsg(&xdrs, msg)) 807184588Sdfr stat = FALSE; 808184588Sdfr else 809184588Sdfr xdrmbuf_append(&xdrs, m); 810184588Sdfr } else { 811184588Sdfr stat = xdr_replymsg(&xdrs, msg); 812184588Sdfr } 813184588Sdfr 814184588Sdfr if (stat) { 815177633Sdfr m_fixhdr(mrep); 816177633Sdfr 817177633Sdfr /* 818177633Sdfr * Prepend a record marker containing the reply length. 819177633Sdfr */ 820243882Sglebius M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK); 821177633Sdfr *mtod(mrep, uint32_t *) = 822177633Sdfr htonl(0x80000000 | (mrep->m_pkthdr.len 823177633Sdfr - sizeof(uint32_t))); 824177633Sdfr error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL, 825177633Sdfr 0, curthread); 826177633Sdfr if (!error) { 827177633Sdfr stat = TRUE; 828177633Sdfr } 829177633Sdfr } else { 830177633Sdfr m_freem(mrep); 831177633Sdfr } 832177633Sdfr 833184588Sdfr XDR_DESTROY(&xdrs); 834177633Sdfr xprt->xp_p2 = NULL; 835177633Sdfr 836177633Sdfr return (stat); 837177633Sdfr} 838177633Sdfr 839177633Sdfrstatic bool_t 840244008Srmacklemsvc_vc_backchannel_reply(SVCXPRT *xprt, struct rpc_msg *msg, 841244008Srmacklem struct sockaddr *addr, struct mbuf *m) 842244008Srmacklem{ 843244008Srmacklem struct ct_data *ct; 844244008Srmacklem XDR xdrs; 845244008Srmacklem struct mbuf *mrep; 846244008Srmacklem bool_t stat = TRUE; 847244008Srmacklem int error; 848244008Srmacklem 849244008Srmacklem /* 850244008Srmacklem * Leave space for record mark. 851244008Srmacklem */ 852248195Sglebius mrep = m_gethdr(M_WAITOK, MT_DATA); 853244008Srmacklem mrep->m_data += sizeof(uint32_t); 854244008Srmacklem 855244008Srmacklem xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); 856244008Srmacklem 857244008Srmacklem if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 858244008Srmacklem msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 859244008Srmacklem if (!xdr_replymsg(&xdrs, msg)) 860244008Srmacklem stat = FALSE; 861244008Srmacklem else 862244008Srmacklem xdrmbuf_append(&xdrs, m); 863244008Srmacklem } else { 864244008Srmacklem stat = xdr_replymsg(&xdrs, msg); 865244008Srmacklem } 866244008Srmacklem 867244008Srmacklem if (stat) { 868244008Srmacklem m_fixhdr(mrep); 869244008Srmacklem 870244008Srmacklem /* 871244008Srmacklem * Prepend a record marker containing the reply length. 872244008Srmacklem */ 873244008Srmacklem M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK); 874244008Srmacklem *mtod(mrep, uint32_t *) = 875244008Srmacklem htonl(0x80000000 | (mrep->m_pkthdr.len 876244008Srmacklem - sizeof(uint32_t))); 877244008Srmacklem sx_xlock(&xprt->xp_lock); 878244008Srmacklem ct = (struct ct_data *)xprt->xp_p2; 879244008Srmacklem if (ct != NULL) 880244008Srmacklem error = sosend(ct->ct_socket, NULL, NULL, mrep, NULL, 881244008Srmacklem 0, curthread); 882244008Srmacklem else 883244008Srmacklem error = EPIPE; 884244008Srmacklem sx_xunlock(&xprt->xp_lock); 885244008Srmacklem if (!error) { 886244008Srmacklem stat = TRUE; 887244008Srmacklem } 888244008Srmacklem } else { 889244008Srmacklem m_freem(mrep); 890244008Srmacklem } 891244008Srmacklem 892244008Srmacklem XDR_DESTROY(&xdrs); 893244008Srmacklem 894244008Srmacklem return (stat); 895244008Srmacklem} 896244008Srmacklem 897244008Srmacklemstatic bool_t 898177633Sdfrsvc_vc_null() 899177633Sdfr{ 900177633Sdfr 901177633Sdfr return (FALSE); 902177633Sdfr} 903177633Sdfr 904193272Sjhbstatic int 905177633Sdfrsvc_vc_soupcall(struct socket *so, void *arg, int waitflag) 906177633Sdfr{ 907177633Sdfr SVCXPRT *xprt = (SVCXPRT *) arg; 908177633Sdfr 909177633Sdfr 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