svc_vc.c revision 194407
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 194407 2009-06-17 22:50:26Z rmacklem $"); 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> 61177633Sdfr#include <netinet/tcp.h> 62177633Sdfr 63177633Sdfr#include <rpc/rpc.h> 64177633Sdfr 65177685Sdfr#include <rpc/rpc_com.h> 66177633Sdfr 67193509Srwatson#include <security/mac/mac_framework.h> 68193509Srwatson 69184588Sdfrstatic bool_t svc_vc_rendezvous_recv(SVCXPRT *, struct rpc_msg *, 70184588Sdfr struct sockaddr **, struct mbuf **); 71177633Sdfrstatic enum xprt_stat svc_vc_rendezvous_stat(SVCXPRT *); 72177633Sdfrstatic void svc_vc_rendezvous_destroy(SVCXPRT *); 73177633Sdfrstatic bool_t svc_vc_null(void); 74177633Sdfrstatic void svc_vc_destroy(SVCXPRT *); 75177633Sdfrstatic enum xprt_stat svc_vc_stat(SVCXPRT *); 76184588Sdfrstatic bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *, 77184588Sdfr struct sockaddr **, struct mbuf **); 78184588Sdfrstatic bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *, 79184588Sdfr struct sockaddr *, struct mbuf *); 80177633Sdfrstatic bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in); 81177633Sdfrstatic bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq, 82177633Sdfr void *in); 83177633Sdfrstatic SVCXPRT *svc_vc_create_conn(SVCPOOL *pool, struct socket *so, 84177633Sdfr struct sockaddr *raddr); 85177633Sdfrstatic int svc_vc_accept(struct socket *head, struct socket **sop); 86193272Sjhbstatic int svc_vc_soupcall(struct socket *so, void *arg, int waitflag); 87177633Sdfr 88177633Sdfrstatic struct xp_ops svc_vc_rendezvous_ops = { 89177633Sdfr .xp_recv = svc_vc_rendezvous_recv, 90177633Sdfr .xp_stat = svc_vc_rendezvous_stat, 91184588Sdfr .xp_reply = (bool_t (*)(SVCXPRT *, struct rpc_msg *, 92184588Sdfr struct sockaddr *, struct mbuf *))svc_vc_null, 93177633Sdfr .xp_destroy = svc_vc_rendezvous_destroy, 94177633Sdfr .xp_control = svc_vc_rendezvous_control 95177633Sdfr}; 96177633Sdfr 97177633Sdfrstatic struct xp_ops svc_vc_ops = { 98177633Sdfr .xp_recv = svc_vc_recv, 99177633Sdfr .xp_stat = svc_vc_stat, 100177633Sdfr .xp_reply = svc_vc_reply, 101177633Sdfr .xp_destroy = svc_vc_destroy, 102177633Sdfr .xp_control = svc_vc_control 103177633Sdfr}; 104177633Sdfr 105177633Sdfrstruct cf_conn { /* kept in xprt->xp_p1 for actual connection */ 106177633Sdfr enum xprt_stat strm_stat; 107177633Sdfr struct mbuf *mpending; /* unparsed data read from the socket */ 108177633Sdfr struct mbuf *mreq; /* current record being built from mpending */ 109177633Sdfr uint32_t resid; /* number of bytes needed for fragment */ 110177633Sdfr bool_t eor; /* reading last fragment of current record */ 111177633Sdfr}; 112177633Sdfr 113177633Sdfr/* 114177633Sdfr * Usage: 115177633Sdfr * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); 116177633Sdfr * 117177633Sdfr * Creates, registers, and returns a (rpc) tcp based transporter. 118177633Sdfr * Once *xprt is initialized, it is registered as a transporter 119177633Sdfr * see (svc.h, xprt_register). This routine returns 120177633Sdfr * a NULL if a problem occurred. 121177633Sdfr * 122177633Sdfr * The filedescriptor passed in is expected to refer to a bound, but 123177633Sdfr * not yet connected socket. 124177633Sdfr * 125177633Sdfr * Since streams do buffered io similar to stdio, the caller can specify 126177633Sdfr * how big the send and receive buffers are via the second and third parms; 127177633Sdfr * 0 => use the system default. 128177633Sdfr */ 129177633SdfrSVCXPRT * 130177633Sdfrsvc_vc_create(SVCPOOL *pool, struct socket *so, size_t sendsize, 131177633Sdfr size_t recvsize) 132177633Sdfr{ 133177633Sdfr SVCXPRT *xprt; 134177633Sdfr struct sockaddr* sa; 135177633Sdfr int error; 136177633Sdfr 137180025Sdfr if (so->so_state & SS_ISCONNECTED) { 138180025Sdfr error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa); 139180025Sdfr if (error) 140180025Sdfr return (NULL); 141180025Sdfr xprt = svc_vc_create_conn(pool, so, sa); 142180025Sdfr free(sa, M_SONAME); 143180025Sdfr return (xprt); 144180025Sdfr } 145180025Sdfr 146184588Sdfr xprt = svc_xprt_alloc(); 147184588Sdfr sx_init(&xprt->xp_lock, "xprt->xp_lock"); 148177633Sdfr xprt->xp_pool = pool; 149177633Sdfr xprt->xp_socket = so; 150177633Sdfr xprt->xp_p1 = NULL; 151177633Sdfr xprt->xp_p2 = NULL; 152177633Sdfr xprt->xp_ops = &svc_vc_rendezvous_ops; 153177633Sdfr 154177633Sdfr error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 155177633Sdfr if (error) 156177633Sdfr goto cleanup_svc_vc_create; 157177633Sdfr 158184588Sdfr memcpy(&xprt->xp_ltaddr, sa, sa->sa_len); 159177633Sdfr free(sa, M_SONAME); 160177633Sdfr 161177633Sdfr xprt_register(xprt); 162177633Sdfr 163177633Sdfr solisten(so, SOMAXCONN, curthread); 164177633Sdfr 165177633Sdfr SOCKBUF_LOCK(&so->so_rcv); 166193436Srmacklem xprt->xp_upcallset = 1; 167193272Sjhb soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt); 168177633Sdfr SOCKBUF_UNLOCK(&so->so_rcv); 169177633Sdfr 170177633Sdfr return (xprt); 171177633Sdfrcleanup_svc_vc_create: 172177633Sdfr if (xprt) 173184588Sdfr svc_xprt_free(xprt); 174177633Sdfr return (NULL); 175177633Sdfr} 176177633Sdfr 177177633Sdfr/* 178177633Sdfr * Create a new transport for a socket optained via soaccept(). 179177633Sdfr */ 180177633SdfrSVCXPRT * 181177633Sdfrsvc_vc_create_conn(SVCPOOL *pool, struct socket *so, struct sockaddr *raddr) 182177633Sdfr{ 183177633Sdfr SVCXPRT *xprt = NULL; 184177633Sdfr struct cf_conn *cd = NULL; 185177633Sdfr struct sockaddr* sa = NULL; 186180025Sdfr struct sockopt opt; 187180025Sdfr int one = 1; 188177633Sdfr int error; 189177633Sdfr 190180025Sdfr bzero(&opt, sizeof(struct sockopt)); 191180025Sdfr opt.sopt_dir = SOPT_SET; 192180025Sdfr opt.sopt_level = SOL_SOCKET; 193180025Sdfr opt.sopt_name = SO_KEEPALIVE; 194180025Sdfr opt.sopt_val = &one; 195180025Sdfr opt.sopt_valsize = sizeof(one); 196180025Sdfr error = sosetopt(so, &opt); 197180025Sdfr if (error) 198180025Sdfr return (NULL); 199180025Sdfr 200180025Sdfr if (so->so_proto->pr_protocol == IPPROTO_TCP) { 201180025Sdfr bzero(&opt, sizeof(struct sockopt)); 202180025Sdfr opt.sopt_dir = SOPT_SET; 203180025Sdfr opt.sopt_level = IPPROTO_TCP; 204180025Sdfr opt.sopt_name = TCP_NODELAY; 205180025Sdfr opt.sopt_val = &one; 206180025Sdfr opt.sopt_valsize = sizeof(one); 207180025Sdfr error = sosetopt(so, &opt); 208180025Sdfr if (error) 209180025Sdfr return (NULL); 210180025Sdfr } 211180025Sdfr 212177633Sdfr cd = mem_alloc(sizeof(*cd)); 213177633Sdfr cd->strm_stat = XPRT_IDLE; 214177633Sdfr 215184588Sdfr xprt = svc_xprt_alloc(); 216184588Sdfr sx_init(&xprt->xp_lock, "xprt->xp_lock"); 217177633Sdfr xprt->xp_pool = pool; 218177633Sdfr xprt->xp_socket = so; 219177633Sdfr xprt->xp_p1 = cd; 220177633Sdfr xprt->xp_p2 = NULL; 221177633Sdfr xprt->xp_ops = &svc_vc_ops; 222177633Sdfr 223184588Sdfr /* 224184588Sdfr * See http://www.connectathon.org/talks96/nfstcp.pdf - client 225184588Sdfr * has a 5 minute timer, server has a 6 minute timer. 226184588Sdfr */ 227184588Sdfr xprt->xp_idletimeout = 6 * 60; 228177633Sdfr 229184588Sdfr memcpy(&xprt->xp_rtaddr, raddr, raddr->sa_len); 230184588Sdfr 231177633Sdfr error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 232177633Sdfr if (error) 233177633Sdfr goto cleanup_svc_vc_create; 234177633Sdfr 235184588Sdfr memcpy(&xprt->xp_ltaddr, sa, sa->sa_len); 236177633Sdfr free(sa, M_SONAME); 237177633Sdfr 238177633Sdfr xprt_register(xprt); 239177633Sdfr 240177633Sdfr SOCKBUF_LOCK(&so->so_rcv); 241193436Srmacklem xprt->xp_upcallset = 1; 242193272Sjhb soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt); 243177633Sdfr SOCKBUF_UNLOCK(&so->so_rcv); 244177633Sdfr 245177633Sdfr /* 246177633Sdfr * Throw the transport into the active list in case it already 247177633Sdfr * has some data buffered. 248177633Sdfr */ 249184588Sdfr sx_xlock(&xprt->xp_lock); 250177633Sdfr xprt_active(xprt); 251184588Sdfr sx_xunlock(&xprt->xp_lock); 252177633Sdfr 253177633Sdfr return (xprt); 254177633Sdfrcleanup_svc_vc_create: 255177633Sdfr if (xprt) { 256177633Sdfr mem_free(xprt, sizeof(*xprt)); 257177633Sdfr } 258177633Sdfr if (cd) 259177633Sdfr mem_free(cd, sizeof(*cd)); 260177633Sdfr return (NULL); 261177633Sdfr} 262177633Sdfr 263177633Sdfr/* 264177633Sdfr * This does all of the accept except the final call to soaccept. The 265177633Sdfr * caller will call soaccept after dropping its locks (soaccept may 266177633Sdfr * call malloc). 267177633Sdfr */ 268177633Sdfrint 269177633Sdfrsvc_vc_accept(struct socket *head, struct socket **sop) 270177633Sdfr{ 271177633Sdfr int error = 0; 272177633Sdfr struct socket *so; 273177633Sdfr 274177633Sdfr if ((head->so_options & SO_ACCEPTCONN) == 0) { 275177633Sdfr error = EINVAL; 276177633Sdfr goto done; 277177633Sdfr } 278177633Sdfr#ifdef MAC 279193509Srwatson error = mac_socket_check_accept(curthread->td_ucred, head); 280177633Sdfr if (error != 0) 281177633Sdfr goto done; 282177633Sdfr#endif 283177633Sdfr ACCEPT_LOCK(); 284177633Sdfr if (TAILQ_EMPTY(&head->so_comp)) { 285177633Sdfr ACCEPT_UNLOCK(); 286177633Sdfr error = EWOULDBLOCK; 287177633Sdfr goto done; 288177633Sdfr } 289177633Sdfr so = TAILQ_FIRST(&head->so_comp); 290177633Sdfr KASSERT(!(so->so_qstate & SQ_INCOMP), ("svc_vc_accept: so SQ_INCOMP")); 291177633Sdfr KASSERT(so->so_qstate & SQ_COMP, ("svc_vc_accept: so not SQ_COMP")); 292177633Sdfr 293177633Sdfr /* 294177633Sdfr * Before changing the flags on the socket, we have to bump the 295177633Sdfr * reference count. Otherwise, if the protocol calls sofree(), 296177633Sdfr * the socket will be released due to a zero refcount. 297177633Sdfr * XXX might not need soref() since this is simpler than kern_accept. 298177633Sdfr */ 299177633Sdfr SOCK_LOCK(so); /* soref() and so_state update */ 300177633Sdfr soref(so); /* file descriptor reference */ 301177633Sdfr 302177633Sdfr TAILQ_REMOVE(&head->so_comp, so, so_list); 303177633Sdfr head->so_qlen--; 304177633Sdfr so->so_state |= (head->so_state & SS_NBIO); 305177633Sdfr so->so_qstate &= ~SQ_COMP; 306177633Sdfr so->so_head = NULL; 307177633Sdfr 308177633Sdfr SOCK_UNLOCK(so); 309177633Sdfr ACCEPT_UNLOCK(); 310177633Sdfr 311177633Sdfr *sop = so; 312177633Sdfr 313177633Sdfr /* connection has been removed from the listen queue */ 314177633Sdfr KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0); 315177633Sdfrdone: 316177633Sdfr return (error); 317177633Sdfr} 318177633Sdfr 319177633Sdfr/*ARGSUSED*/ 320177633Sdfrstatic bool_t 321184588Sdfrsvc_vc_rendezvous_recv(SVCXPRT *xprt, struct rpc_msg *msg, 322184588Sdfr struct sockaddr **addrp, struct mbuf **mp) 323177633Sdfr{ 324177633Sdfr struct socket *so = NULL; 325177633Sdfr struct sockaddr *sa = NULL; 326177633Sdfr int error; 327194407Srmacklem SVCXPRT *new_xprt; 328177633Sdfr 329177633Sdfr /* 330177633Sdfr * The socket upcall calls xprt_active() which will eventually 331177633Sdfr * cause the server to call us here. We attempt to accept a 332177633Sdfr * connection from the socket and turn it into a new 333177633Sdfr * transport. If the accept fails, we have drained all pending 334177633Sdfr * connections so we call xprt_inactive(). 335177633Sdfr */ 336184588Sdfr sx_xlock(&xprt->xp_lock); 337177633Sdfr 338177633Sdfr error = svc_vc_accept(xprt->xp_socket, &so); 339177633Sdfr 340177633Sdfr if (error == EWOULDBLOCK) { 341184588Sdfr /* 342184588Sdfr * We must re-test for new connections after taking 343184588Sdfr * the lock to protect us in the case where a new 344184588Sdfr * connection arrives after our call to accept fails 345184588Sdfr * with EWOULDBLOCK. The pool lock protects us from 346184588Sdfr * racing the upcall after our TAILQ_EMPTY() call 347184588Sdfr * returns false. 348184588Sdfr */ 349184588Sdfr ACCEPT_LOCK(); 350184588Sdfr mtx_lock(&xprt->xp_pool->sp_lock); 351184588Sdfr if (TAILQ_EMPTY(&xprt->xp_socket->so_comp)) 352184588Sdfr xprt_inactive_locked(xprt); 353184588Sdfr mtx_unlock(&xprt->xp_pool->sp_lock); 354184588Sdfr ACCEPT_UNLOCK(); 355184588Sdfr sx_xunlock(&xprt->xp_lock); 356177633Sdfr return (FALSE); 357177633Sdfr } 358177633Sdfr 359177633Sdfr if (error) { 360177633Sdfr SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 361193436Srmacklem if (xprt->xp_upcallset) { 362193436Srmacklem xprt->xp_upcallset = 0; 363193436Srmacklem soupcall_clear(xprt->xp_socket, SO_RCV); 364193436Srmacklem } 365177633Sdfr SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 366177633Sdfr xprt_inactive(xprt); 367184588Sdfr sx_xunlock(&xprt->xp_lock); 368177633Sdfr return (FALSE); 369177633Sdfr } 370177633Sdfr 371184588Sdfr sx_xunlock(&xprt->xp_lock); 372177633Sdfr 373177633Sdfr sa = 0; 374177633Sdfr error = soaccept(so, &sa); 375177633Sdfr 376177633Sdfr if (error) { 377177633Sdfr /* 378177633Sdfr * XXX not sure if I need to call sofree or soclose here. 379177633Sdfr */ 380177633Sdfr if (sa) 381177633Sdfr free(sa, M_SONAME); 382177633Sdfr return (FALSE); 383177633Sdfr } 384177633Sdfr 385177633Sdfr /* 386177633Sdfr * svc_vc_create_conn will call xprt_register - we don't need 387194407Srmacklem * to do anything with the new connection except derefence it. 388177633Sdfr */ 389194407Srmacklem new_xprt = svc_vc_create_conn(xprt->xp_pool, so, sa); 390194407Srmacklem if (!new_xprt) { 391180025Sdfr soclose(so); 392194407Srmacklem } else { 393194407Srmacklem SVC_RELEASE(new_xprt); 394194407Srmacklem } 395180025Sdfr 396177633Sdfr free(sa, M_SONAME); 397177633Sdfr 398177633Sdfr return (FALSE); /* there is never an rpc msg to be processed */ 399177633Sdfr} 400177633Sdfr 401177633Sdfr/*ARGSUSED*/ 402177633Sdfrstatic enum xprt_stat 403177633Sdfrsvc_vc_rendezvous_stat(SVCXPRT *xprt) 404177633Sdfr{ 405177633Sdfr 406177633Sdfr return (XPRT_IDLE); 407177633Sdfr} 408177633Sdfr 409177633Sdfrstatic void 410177633Sdfrsvc_vc_destroy_common(SVCXPRT *xprt) 411177633Sdfr{ 412177633Sdfr SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 413193436Srmacklem if (xprt->xp_upcallset) { 414193436Srmacklem xprt->xp_upcallset = 0; 415193436Srmacklem soupcall_clear(xprt->xp_socket, SO_RCV); 416193436Srmacklem } 417177633Sdfr SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 418177633Sdfr 419184588Sdfr sx_destroy(&xprt->xp_lock); 420177633Sdfr if (xprt->xp_socket) 421177633Sdfr (void)soclose(xprt->xp_socket); 422177633Sdfr 423184588Sdfr if (xprt->xp_netid) 424184588Sdfr (void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1); 425184588Sdfr svc_xprt_free(xprt); 426177633Sdfr} 427177633Sdfr 428177633Sdfrstatic void 429177633Sdfrsvc_vc_rendezvous_destroy(SVCXPRT *xprt) 430177633Sdfr{ 431177633Sdfr 432177633Sdfr svc_vc_destroy_common(xprt); 433177633Sdfr} 434177633Sdfr 435177633Sdfrstatic void 436177633Sdfrsvc_vc_destroy(SVCXPRT *xprt) 437177633Sdfr{ 438177633Sdfr struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1; 439177633Sdfr 440177633Sdfr svc_vc_destroy_common(xprt); 441177633Sdfr 442177633Sdfr if (cd->mreq) 443177633Sdfr m_freem(cd->mreq); 444177633Sdfr if (cd->mpending) 445177633Sdfr m_freem(cd->mpending); 446177633Sdfr mem_free(cd, sizeof(*cd)); 447177633Sdfr} 448177633Sdfr 449177633Sdfr/*ARGSUSED*/ 450177633Sdfrstatic bool_t 451177633Sdfrsvc_vc_control(SVCXPRT *xprt, const u_int rq, void *in) 452177633Sdfr{ 453177633Sdfr return (FALSE); 454177633Sdfr} 455177633Sdfr 456177633Sdfrstatic bool_t 457177633Sdfrsvc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in) 458177633Sdfr{ 459177633Sdfr 460177633Sdfr return (FALSE); 461177633Sdfr} 462177633Sdfr 463177633Sdfrstatic enum xprt_stat 464177633Sdfrsvc_vc_stat(SVCXPRT *xprt) 465177633Sdfr{ 466177633Sdfr struct cf_conn *cd; 467177633Sdfr struct mbuf *m; 468177633Sdfr size_t n; 469177633Sdfr 470177633Sdfr cd = (struct cf_conn *)(xprt->xp_p1); 471177633Sdfr 472177633Sdfr if (cd->strm_stat == XPRT_DIED) 473177633Sdfr return (XPRT_DIED); 474177633Sdfr 475177633Sdfr /* 476177633Sdfr * Return XPRT_MOREREQS if we have buffered data and we are 477184588Sdfr * mid-record or if we have enough data for a record 478184588Sdfr * marker. Since this is only a hint, we read mpending and 479184588Sdfr * resid outside the lock. We do need to take the lock if we 480184588Sdfr * have to traverse the mbuf chain. 481177633Sdfr */ 482177633Sdfr if (cd->mpending) { 483177633Sdfr if (cd->resid) 484177633Sdfr return (XPRT_MOREREQS); 485177633Sdfr n = 0; 486184588Sdfr sx_xlock(&xprt->xp_lock); 487177633Sdfr m = cd->mpending; 488177633Sdfr while (m && n < sizeof(uint32_t)) { 489177633Sdfr n += m->m_len; 490177633Sdfr m = m->m_next; 491177633Sdfr } 492184588Sdfr sx_xunlock(&xprt->xp_lock); 493177633Sdfr if (n >= sizeof(uint32_t)) 494177633Sdfr return (XPRT_MOREREQS); 495177633Sdfr } 496177633Sdfr 497184588Sdfr if (soreadable(xprt->xp_socket)) 498184588Sdfr return (XPRT_MOREREQS); 499184588Sdfr 500177633Sdfr return (XPRT_IDLE); 501177633Sdfr} 502177633Sdfr 503177633Sdfrstatic bool_t 504184588Sdfrsvc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg, 505184588Sdfr struct sockaddr **addrp, struct mbuf **mp) 506177633Sdfr{ 507177633Sdfr struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 508177633Sdfr struct uio uio; 509177633Sdfr struct mbuf *m; 510184588Sdfr XDR xdrs; 511177633Sdfr int error, rcvflag; 512177633Sdfr 513184588Sdfr /* 514184588Sdfr * Serialise access to the socket and our own record parsing 515184588Sdfr * state. 516184588Sdfr */ 517184588Sdfr sx_xlock(&xprt->xp_lock); 518184588Sdfr 519177633Sdfr for (;;) { 520177633Sdfr /* 521177633Sdfr * If we have an mbuf chain in cd->mpending, try to parse a 522177633Sdfr * record from it, leaving the result in cd->mreq. If we don't 523177633Sdfr * have a complete record, leave the partial result in 524177633Sdfr * cd->mreq and try to read more from the socket. 525177633Sdfr */ 526177633Sdfr if (cd->mpending) { 527177633Sdfr /* 528177633Sdfr * If cd->resid is non-zero, we have part of the 529177633Sdfr * record already, otherwise we are expecting a record 530177633Sdfr * marker. 531177633Sdfr */ 532177633Sdfr if (!cd->resid) { 533177633Sdfr /* 534177633Sdfr * See if there is enough data buffered to 535177633Sdfr * make up a record marker. Make sure we can 536177633Sdfr * handle the case where the record marker is 537177633Sdfr * split across more than one mbuf. 538177633Sdfr */ 539177633Sdfr size_t n = 0; 540177633Sdfr uint32_t header; 541177633Sdfr 542177633Sdfr m = cd->mpending; 543177633Sdfr while (n < sizeof(uint32_t) && m) { 544177633Sdfr n += m->m_len; 545177633Sdfr m = m->m_next; 546177633Sdfr } 547177633Sdfr if (n < sizeof(uint32_t)) 548177633Sdfr goto readmore; 549184588Sdfr if (cd->mpending->m_len < sizeof(uint32_t)) 550184588Sdfr cd->mpending = m_pullup(cd->mpending, 551184588Sdfr sizeof(uint32_t)); 552177633Sdfr memcpy(&header, mtod(cd->mpending, uint32_t *), 553177633Sdfr sizeof(header)); 554177633Sdfr header = ntohl(header); 555177633Sdfr cd->eor = (header & 0x80000000) != 0; 556177633Sdfr cd->resid = header & 0x7fffffff; 557177633Sdfr m_adj(cd->mpending, sizeof(uint32_t)); 558177633Sdfr } 559177633Sdfr 560177633Sdfr /* 561177633Sdfr * Start pulling off mbufs from cd->mpending 562177633Sdfr * until we either have a complete record or 563177633Sdfr * we run out of data. We use m_split to pull 564177633Sdfr * data - it will pull as much as possible and 565177633Sdfr * split the last mbuf if necessary. 566177633Sdfr */ 567177633Sdfr while (cd->mpending && cd->resid) { 568177633Sdfr m = cd->mpending; 569184588Sdfr if (cd->mpending->m_next 570184588Sdfr || cd->mpending->m_len > cd->resid) 571184588Sdfr cd->mpending = m_split(cd->mpending, 572184588Sdfr cd->resid, M_WAIT); 573184588Sdfr else 574184588Sdfr cd->mpending = NULL; 575177633Sdfr if (cd->mreq) 576177633Sdfr m_last(cd->mreq)->m_next = m; 577177633Sdfr else 578177633Sdfr cd->mreq = m; 579177633Sdfr while (m) { 580177633Sdfr cd->resid -= m->m_len; 581177633Sdfr m = m->m_next; 582177633Sdfr } 583177633Sdfr } 584177633Sdfr 585177633Sdfr /* 586177633Sdfr * If cd->resid is zero now, we have managed to 587177633Sdfr * receive a record fragment from the stream. Check 588177633Sdfr * for the end-of-record mark to see if we need more. 589177633Sdfr */ 590177633Sdfr if (cd->resid == 0) { 591177633Sdfr if (!cd->eor) 592177633Sdfr continue; 593177633Sdfr 594177633Sdfr /* 595177633Sdfr * Success - we have a complete record in 596177633Sdfr * cd->mreq. 597177633Sdfr */ 598184588Sdfr xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE); 599177633Sdfr cd->mreq = NULL; 600184588Sdfr sx_xunlock(&xprt->xp_lock); 601184588Sdfr 602184588Sdfr if (! xdr_callmsg(&xdrs, msg)) { 603184588Sdfr XDR_DESTROY(&xdrs); 604177633Sdfr return (FALSE); 605177633Sdfr } 606177633Sdfr 607184588Sdfr *addrp = NULL; 608184588Sdfr *mp = xdrmbuf_getall(&xdrs); 609184588Sdfr XDR_DESTROY(&xdrs); 610184588Sdfr 611177633Sdfr return (TRUE); 612177633Sdfr } 613177633Sdfr } 614177633Sdfr 615177633Sdfr readmore: 616177633Sdfr /* 617177633Sdfr * The socket upcall calls xprt_active() which will eventually 618177633Sdfr * cause the server to call us here. We attempt to 619177633Sdfr * read as much as possible from the socket and put 620177633Sdfr * the result in cd->mpending. If the read fails, 621177633Sdfr * we have drained both cd->mpending and the socket so 622177633Sdfr * we can call xprt_inactive(). 623177633Sdfr */ 624177633Sdfr uio.uio_resid = 1000000000; 625177633Sdfr uio.uio_td = curthread; 626177633Sdfr m = NULL; 627177633Sdfr rcvflag = MSG_DONTWAIT; 628177633Sdfr error = soreceive(xprt->xp_socket, NULL, &uio, &m, NULL, 629177633Sdfr &rcvflag); 630177633Sdfr 631177633Sdfr if (error == EWOULDBLOCK) { 632184588Sdfr /* 633184588Sdfr * We must re-test for readability after 634184588Sdfr * taking the lock to protect us in the case 635184588Sdfr * where a new packet arrives on the socket 636184588Sdfr * after our call to soreceive fails with 637184588Sdfr * EWOULDBLOCK. The pool lock protects us from 638184588Sdfr * racing the upcall after our soreadable() 639184588Sdfr * call returns false. 640184588Sdfr */ 641184588Sdfr mtx_lock(&xprt->xp_pool->sp_lock); 642184588Sdfr if (!soreadable(xprt->xp_socket)) 643184588Sdfr xprt_inactive_locked(xprt); 644184588Sdfr mtx_unlock(&xprt->xp_pool->sp_lock); 645184588Sdfr sx_xunlock(&xprt->xp_lock); 646177633Sdfr return (FALSE); 647177633Sdfr } 648177633Sdfr 649177633Sdfr if (error) { 650177633Sdfr SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 651193436Srmacklem if (xprt->xp_upcallset) { 652193436Srmacklem xprt->xp_upcallset = 0; 653193436Srmacklem soupcall_clear(xprt->xp_socket, SO_RCV); 654193436Srmacklem } 655177633Sdfr SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 656177633Sdfr xprt_inactive(xprt); 657177633Sdfr cd->strm_stat = XPRT_DIED; 658184588Sdfr sx_xunlock(&xprt->xp_lock); 659177633Sdfr return (FALSE); 660177633Sdfr } 661177633Sdfr 662177633Sdfr if (!m) { 663177633Sdfr /* 664177633Sdfr * EOF - the other end has closed the socket. 665177633Sdfr */ 666184588Sdfr xprt_inactive(xprt); 667177633Sdfr cd->strm_stat = XPRT_DIED; 668184588Sdfr sx_xunlock(&xprt->xp_lock); 669177633Sdfr return (FALSE); 670177633Sdfr } 671177633Sdfr 672177633Sdfr if (cd->mpending) 673177633Sdfr m_last(cd->mpending)->m_next = m; 674177633Sdfr else 675177633Sdfr cd->mpending = m; 676177633Sdfr } 677177633Sdfr} 678177633Sdfr 679177633Sdfrstatic bool_t 680184588Sdfrsvc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg, 681184588Sdfr struct sockaddr *addr, struct mbuf *m) 682177633Sdfr{ 683177633Sdfr XDR xdrs; 684177633Sdfr struct mbuf *mrep; 685184588Sdfr bool_t stat = TRUE; 686177633Sdfr int error; 687177633Sdfr 688177633Sdfr /* 689177633Sdfr * Leave space for record mark. 690177633Sdfr */ 691177633Sdfr MGETHDR(mrep, M_WAIT, MT_DATA); 692177633Sdfr mrep->m_len = 0; 693177633Sdfr mrep->m_data += sizeof(uint32_t); 694177633Sdfr 695184588Sdfr xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); 696184588Sdfr 697184588Sdfr if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 698184588Sdfr msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 699184588Sdfr if (!xdr_replymsg(&xdrs, msg)) 700184588Sdfr stat = FALSE; 701184588Sdfr else 702184588Sdfr xdrmbuf_append(&xdrs, m); 703184588Sdfr } else { 704184588Sdfr stat = xdr_replymsg(&xdrs, msg); 705184588Sdfr } 706184588Sdfr 707184588Sdfr if (stat) { 708177633Sdfr m_fixhdr(mrep); 709177633Sdfr 710177633Sdfr /* 711177633Sdfr * Prepend a record marker containing the reply length. 712177633Sdfr */ 713177633Sdfr M_PREPEND(mrep, sizeof(uint32_t), M_WAIT); 714177633Sdfr *mtod(mrep, uint32_t *) = 715177633Sdfr htonl(0x80000000 | (mrep->m_pkthdr.len 716177633Sdfr - sizeof(uint32_t))); 717177633Sdfr error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL, 718177633Sdfr 0, curthread); 719177633Sdfr if (!error) { 720177633Sdfr stat = TRUE; 721177633Sdfr } 722177633Sdfr } else { 723177633Sdfr m_freem(mrep); 724177633Sdfr } 725177633Sdfr 726184588Sdfr XDR_DESTROY(&xdrs); 727177633Sdfr xprt->xp_p2 = NULL; 728177633Sdfr 729177633Sdfr return (stat); 730177633Sdfr} 731177633Sdfr 732177633Sdfrstatic bool_t 733177633Sdfrsvc_vc_null() 734177633Sdfr{ 735177633Sdfr 736177633Sdfr return (FALSE); 737177633Sdfr} 738177633Sdfr 739193272Sjhbstatic int 740177633Sdfrsvc_vc_soupcall(struct socket *so, void *arg, int waitflag) 741177633Sdfr{ 742177633Sdfr SVCXPRT *xprt = (SVCXPRT *) arg; 743177633Sdfr 744177633Sdfr xprt_active(xprt); 745193272Sjhb return (SU_OK); 746177633Sdfr} 747177633Sdfr 748177633Sdfr#if 0 749177633Sdfr/* 750177633Sdfr * Get the effective UID of the sending process. Used by rpcbind, keyserv 751177633Sdfr * and rpc.yppasswdd on AF_LOCAL. 752177633Sdfr */ 753177633Sdfrint 754177633Sdfr__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) { 755177633Sdfr int sock, ret; 756177633Sdfr gid_t egid; 757177633Sdfr uid_t euid; 758177633Sdfr struct sockaddr *sa; 759177633Sdfr 760177633Sdfr sock = transp->xp_fd; 761184588Sdfr sa = (struct sockaddr *)transp->xp_rtaddr; 762177633Sdfr if (sa->sa_family == AF_LOCAL) { 763177633Sdfr ret = getpeereid(sock, &euid, &egid); 764177633Sdfr if (ret == 0) 765177633Sdfr *uid = euid; 766177633Sdfr return (ret); 767177633Sdfr } else 768177633Sdfr return (-1); 769177633Sdfr} 770177633Sdfr#endif 771