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: releng/10.3/sys/rpc/svc_vc.c 287338 2015-09-01 01:01:35Z delphij $"); 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 *); 79261055Smavstatic bool_t svc_vc_ack(SVCXPRT *, uint32_t *); 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 *, 83261055Smav struct sockaddr *, struct mbuf *, uint32_t *seq); 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 *, 92261055Smav struct sockaddr *, struct mbuf *, uint32_t *); 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 *, 104261055Smav struct sockaddr *, struct mbuf *, uint32_t *))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, 112261055Smav .xp_ack = svc_vc_ack, 113177633Sdfr .xp_reply = svc_vc_reply, 114177633Sdfr .xp_destroy = svc_vc_destroy, 115177633Sdfr .xp_control = svc_vc_control 116177633Sdfr}; 117177633Sdfr 118244008Srmacklemstatic struct xp_ops svc_vc_backchannel_ops = { 119244008Srmacklem .xp_recv = svc_vc_backchannel_recv, 120244008Srmacklem .xp_stat = svc_vc_backchannel_stat, 121244008Srmacklem .xp_reply = svc_vc_backchannel_reply, 122244008Srmacklem .xp_destroy = svc_vc_backchannel_destroy, 123244008Srmacklem .xp_control = svc_vc_backchannel_control 124177633Sdfr}; 125177633Sdfr 126177633Sdfr/* 127177633Sdfr * Usage: 128177633Sdfr * xprt = svc_vc_create(sock, send_buf_size, recv_buf_size); 129177633Sdfr * 130177633Sdfr * Creates, registers, and returns a (rpc) tcp based transporter. 131177633Sdfr * Once *xprt is initialized, it is registered as a transporter 132177633Sdfr * see (svc.h, xprt_register). This routine returns 133177633Sdfr * a NULL if a problem occurred. 134177633Sdfr * 135177633Sdfr * The filedescriptor passed in is expected to refer to a bound, but 136177633Sdfr * not yet connected socket. 137177633Sdfr * 138177633Sdfr * Since streams do buffered io similar to stdio, the caller can specify 139177633Sdfr * how big the send and receive buffers are via the second and third parms; 140177633Sdfr * 0 => use the system default. 141177633Sdfr */ 142177633SdfrSVCXPRT * 143177633Sdfrsvc_vc_create(SVCPOOL *pool, struct socket *so, size_t sendsize, 144177633Sdfr size_t recvsize) 145177633Sdfr{ 146177633Sdfr SVCXPRT *xprt; 147177633Sdfr struct sockaddr* sa; 148177633Sdfr int error; 149177633Sdfr 150249263Sjhb SOCK_LOCK(so); 151249263Sjhb if (so->so_state & (SS_ISCONNECTED|SS_ISDISCONNECTED)) { 152249263Sjhb SOCK_UNLOCK(so); 153287338Sdelphij CURVNET_SET(so->so_vnet); 154180025Sdfr error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa); 155287338Sdelphij CURVNET_RESTORE(); 156180025Sdfr if (error) 157180025Sdfr return (NULL); 158180025Sdfr xprt = svc_vc_create_conn(pool, so, sa); 159180025Sdfr free(sa, M_SONAME); 160180025Sdfr return (xprt); 161180025Sdfr } 162249263Sjhb SOCK_UNLOCK(so); 163180025Sdfr 164184588Sdfr xprt = svc_xprt_alloc(); 165184588Sdfr sx_init(&xprt->xp_lock, "xprt->xp_lock"); 166177633Sdfr xprt->xp_pool = pool; 167177633Sdfr xprt->xp_socket = so; 168177633Sdfr xprt->xp_p1 = NULL; 169177633Sdfr xprt->xp_p2 = NULL; 170177633Sdfr xprt->xp_ops = &svc_vc_rendezvous_ops; 171177633Sdfr 172287338Sdelphij CURVNET_SET(so->so_vnet); 173177633Sdfr error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 174287338Sdelphij CURVNET_RESTORE(); 175196503Szec if (error) { 176177633Sdfr goto cleanup_svc_vc_create; 177196503Szec } 178177633Sdfr 179184588Sdfr memcpy(&xprt->xp_ltaddr, sa, sa->sa_len); 180177633Sdfr free(sa, M_SONAME); 181177633Sdfr 182177633Sdfr xprt_register(xprt); 183177633Sdfr 184281520Smav solisten(so, -1, curthread); 185177633Sdfr 186177633Sdfr SOCKBUF_LOCK(&so->so_rcv); 187193436Srmacklem xprt->xp_upcallset = 1; 188193272Sjhb soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt); 189177633Sdfr SOCKBUF_UNLOCK(&so->so_rcv); 190177633Sdfr 191177633Sdfr return (xprt); 192177633Sdfrcleanup_svc_vc_create: 193261055Smav if (xprt) { 194261055Smav sx_destroy(&xprt->xp_lock); 195184588Sdfr svc_xprt_free(xprt); 196261055Smav } 197177633Sdfr return (NULL); 198177633Sdfr} 199177633Sdfr 200177633Sdfr/* 201177633Sdfr * Create a new transport for a socket optained via soaccept(). 202177633Sdfr */ 203177633SdfrSVCXPRT * 204177633Sdfrsvc_vc_create_conn(SVCPOOL *pool, struct socket *so, struct sockaddr *raddr) 205177633Sdfr{ 206177633Sdfr SVCXPRT *xprt = NULL; 207177633Sdfr struct cf_conn *cd = NULL; 208177633Sdfr struct sockaddr* sa = NULL; 209180025Sdfr struct sockopt opt; 210180025Sdfr int one = 1; 211177633Sdfr int error; 212177633Sdfr 213180025Sdfr bzero(&opt, sizeof(struct sockopt)); 214180025Sdfr opt.sopt_dir = SOPT_SET; 215180025Sdfr opt.sopt_level = SOL_SOCKET; 216180025Sdfr opt.sopt_name = SO_KEEPALIVE; 217180025Sdfr opt.sopt_val = &one; 218180025Sdfr opt.sopt_valsize = sizeof(one); 219180025Sdfr error = sosetopt(so, &opt); 220196503Szec if (error) { 221180025Sdfr return (NULL); 222196503Szec } 223180025Sdfr 224180025Sdfr if (so->so_proto->pr_protocol == IPPROTO_TCP) { 225180025Sdfr bzero(&opt, sizeof(struct sockopt)); 226180025Sdfr opt.sopt_dir = SOPT_SET; 227180025Sdfr opt.sopt_level = IPPROTO_TCP; 228180025Sdfr opt.sopt_name = TCP_NODELAY; 229180025Sdfr opt.sopt_val = &one; 230180025Sdfr opt.sopt_valsize = sizeof(one); 231180025Sdfr error = sosetopt(so, &opt); 232196503Szec if (error) { 233180025Sdfr return (NULL); 234196503Szec } 235180025Sdfr } 236180025Sdfr 237177633Sdfr cd = mem_alloc(sizeof(*cd)); 238177633Sdfr cd->strm_stat = XPRT_IDLE; 239177633Sdfr 240184588Sdfr xprt = svc_xprt_alloc(); 241184588Sdfr sx_init(&xprt->xp_lock, "xprt->xp_lock"); 242177633Sdfr xprt->xp_pool = pool; 243177633Sdfr xprt->xp_socket = so; 244177633Sdfr xprt->xp_p1 = cd; 245177633Sdfr xprt->xp_p2 = NULL; 246177633Sdfr xprt->xp_ops = &svc_vc_ops; 247177633Sdfr 248184588Sdfr /* 249184588Sdfr * See http://www.connectathon.org/talks96/nfstcp.pdf - client 250184588Sdfr * has a 5 minute timer, server has a 6 minute timer. 251184588Sdfr */ 252184588Sdfr xprt->xp_idletimeout = 6 * 60; 253177633Sdfr 254184588Sdfr memcpy(&xprt->xp_rtaddr, raddr, raddr->sa_len); 255184588Sdfr 256287338Sdelphij CURVNET_SET(so->so_vnet); 257177633Sdfr error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 258287338Sdelphij CURVNET_RESTORE(); 259177633Sdfr if (error) 260177633Sdfr goto cleanup_svc_vc_create; 261177633Sdfr 262184588Sdfr memcpy(&xprt->xp_ltaddr, sa, sa->sa_len); 263177633Sdfr free(sa, M_SONAME); 264177633Sdfr 265177633Sdfr xprt_register(xprt); 266177633Sdfr 267177633Sdfr SOCKBUF_LOCK(&so->so_rcv); 268193436Srmacklem xprt->xp_upcallset = 1; 269193272Sjhb soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt); 270177633Sdfr SOCKBUF_UNLOCK(&so->so_rcv); 271177633Sdfr 272177633Sdfr /* 273177633Sdfr * Throw the transport into the active list in case it already 274177633Sdfr * has some data buffered. 275177633Sdfr */ 276184588Sdfr sx_xlock(&xprt->xp_lock); 277177633Sdfr xprt_active(xprt); 278184588Sdfr sx_xunlock(&xprt->xp_lock); 279177633Sdfr 280177633Sdfr return (xprt); 281177633Sdfrcleanup_svc_vc_create: 282177633Sdfr if (xprt) { 283261055Smav sx_destroy(&xprt->xp_lock); 284261055Smav svc_xprt_free(xprt); 285177633Sdfr } 286177633Sdfr if (cd) 287177633Sdfr mem_free(cd, sizeof(*cd)); 288177633Sdfr return (NULL); 289177633Sdfr} 290177633Sdfr 291177633Sdfr/* 292244008Srmacklem * Create a new transport for a backchannel on a clnt_vc socket. 293244008Srmacklem */ 294244008SrmacklemSVCXPRT * 295244008Srmacklemsvc_vc_create_backchannel(SVCPOOL *pool) 296244008Srmacklem{ 297244008Srmacklem SVCXPRT *xprt = NULL; 298244008Srmacklem struct cf_conn *cd = NULL; 299244008Srmacklem 300244008Srmacklem cd = mem_alloc(sizeof(*cd)); 301244008Srmacklem cd->strm_stat = XPRT_IDLE; 302244008Srmacklem 303244008Srmacklem xprt = svc_xprt_alloc(); 304244008Srmacklem sx_init(&xprt->xp_lock, "xprt->xp_lock"); 305244008Srmacklem xprt->xp_pool = pool; 306244008Srmacklem xprt->xp_socket = NULL; 307244008Srmacklem xprt->xp_p1 = cd; 308244008Srmacklem xprt->xp_p2 = NULL; 309244008Srmacklem xprt->xp_ops = &svc_vc_backchannel_ops; 310244008Srmacklem return (xprt); 311244008Srmacklem} 312244008Srmacklem 313244008Srmacklem/* 314177633Sdfr * This does all of the accept except the final call to soaccept. The 315177633Sdfr * caller will call soaccept after dropping its locks (soaccept may 316177633Sdfr * call malloc). 317177633Sdfr */ 318177633Sdfrint 319177633Sdfrsvc_vc_accept(struct socket *head, struct socket **sop) 320177633Sdfr{ 321177633Sdfr int error = 0; 322177633Sdfr struct socket *so; 323177633Sdfr 324177633Sdfr if ((head->so_options & SO_ACCEPTCONN) == 0) { 325177633Sdfr error = EINVAL; 326177633Sdfr goto done; 327177633Sdfr } 328177633Sdfr#ifdef MAC 329193509Srwatson error = mac_socket_check_accept(curthread->td_ucred, head); 330177633Sdfr if (error != 0) 331177633Sdfr goto done; 332177633Sdfr#endif 333177633Sdfr ACCEPT_LOCK(); 334177633Sdfr if (TAILQ_EMPTY(&head->so_comp)) { 335177633Sdfr ACCEPT_UNLOCK(); 336177633Sdfr error = EWOULDBLOCK; 337177633Sdfr goto done; 338177633Sdfr } 339177633Sdfr so = TAILQ_FIRST(&head->so_comp); 340177633Sdfr KASSERT(!(so->so_qstate & SQ_INCOMP), ("svc_vc_accept: so SQ_INCOMP")); 341177633Sdfr KASSERT(so->so_qstate & SQ_COMP, ("svc_vc_accept: so not SQ_COMP")); 342177633Sdfr 343177633Sdfr /* 344177633Sdfr * Before changing the flags on the socket, we have to bump the 345177633Sdfr * reference count. Otherwise, if the protocol calls sofree(), 346177633Sdfr * the socket will be released due to a zero refcount. 347177633Sdfr * XXX might not need soref() since this is simpler than kern_accept. 348177633Sdfr */ 349177633Sdfr SOCK_LOCK(so); /* soref() and so_state update */ 350177633Sdfr soref(so); /* file descriptor reference */ 351177633Sdfr 352177633Sdfr TAILQ_REMOVE(&head->so_comp, so, so_list); 353177633Sdfr head->so_qlen--; 354177633Sdfr so->so_state |= (head->so_state & SS_NBIO); 355177633Sdfr so->so_qstate &= ~SQ_COMP; 356177633Sdfr so->so_head = NULL; 357177633Sdfr 358177633Sdfr SOCK_UNLOCK(so); 359177633Sdfr ACCEPT_UNLOCK(); 360177633Sdfr 361177633Sdfr *sop = so; 362177633Sdfr 363177633Sdfr /* connection has been removed from the listen queue */ 364177633Sdfr KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0); 365177633Sdfrdone: 366177633Sdfr return (error); 367177633Sdfr} 368177633Sdfr 369177633Sdfr/*ARGSUSED*/ 370177633Sdfrstatic bool_t 371184588Sdfrsvc_vc_rendezvous_recv(SVCXPRT *xprt, struct rpc_msg *msg, 372184588Sdfr struct sockaddr **addrp, struct mbuf **mp) 373177633Sdfr{ 374177633Sdfr struct socket *so = NULL; 375177633Sdfr struct sockaddr *sa = NULL; 376177633Sdfr int error; 377194407Srmacklem SVCXPRT *new_xprt; 378177633Sdfr 379177633Sdfr /* 380177633Sdfr * The socket upcall calls xprt_active() which will eventually 381177633Sdfr * cause the server to call us here. We attempt to accept a 382177633Sdfr * connection from the socket and turn it into a new 383177633Sdfr * transport. If the accept fails, we have drained all pending 384177633Sdfr * connections so we call xprt_inactive(). 385177633Sdfr */ 386184588Sdfr sx_xlock(&xprt->xp_lock); 387177633Sdfr 388177633Sdfr error = svc_vc_accept(xprt->xp_socket, &so); 389177633Sdfr 390177633Sdfr if (error == EWOULDBLOCK) { 391184588Sdfr /* 392184588Sdfr * We must re-test for new connections after taking 393184588Sdfr * the lock to protect us in the case where a new 394184588Sdfr * connection arrives after our call to accept fails 395261047Smav * with EWOULDBLOCK. 396184588Sdfr */ 397184588Sdfr ACCEPT_LOCK(); 398184588Sdfr if (TAILQ_EMPTY(&xprt->xp_socket->so_comp)) 399261053Smav xprt_inactive_self(xprt); 400184588Sdfr ACCEPT_UNLOCK(); 401184588Sdfr sx_xunlock(&xprt->xp_lock); 402177633Sdfr return (FALSE); 403177633Sdfr } 404177633Sdfr 405177633Sdfr if (error) { 406177633Sdfr SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 407193436Srmacklem if (xprt->xp_upcallset) { 408193436Srmacklem xprt->xp_upcallset = 0; 409193436Srmacklem soupcall_clear(xprt->xp_socket, SO_RCV); 410193436Srmacklem } 411177633Sdfr SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 412261053Smav xprt_inactive_self(xprt); 413184588Sdfr sx_xunlock(&xprt->xp_lock); 414177633Sdfr return (FALSE); 415177633Sdfr } 416177633Sdfr 417184588Sdfr sx_xunlock(&xprt->xp_lock); 418177633Sdfr 419177633Sdfr sa = 0; 420177633Sdfr error = soaccept(so, &sa); 421177633Sdfr 422177633Sdfr if (error) { 423177633Sdfr /* 424177633Sdfr * XXX not sure if I need to call sofree or soclose here. 425177633Sdfr */ 426177633Sdfr if (sa) 427177633Sdfr free(sa, M_SONAME); 428177633Sdfr return (FALSE); 429177633Sdfr } 430177633Sdfr 431177633Sdfr /* 432177633Sdfr * svc_vc_create_conn will call xprt_register - we don't need 433194407Srmacklem * to do anything with the new connection except derefence it. 434177633Sdfr */ 435194407Srmacklem new_xprt = svc_vc_create_conn(xprt->xp_pool, so, sa); 436194407Srmacklem if (!new_xprt) { 437180025Sdfr soclose(so); 438194407Srmacklem } else { 439194407Srmacklem SVC_RELEASE(new_xprt); 440194407Srmacklem } 441180025Sdfr 442177633Sdfr free(sa, M_SONAME); 443177633Sdfr 444177633Sdfr return (FALSE); /* there is never an rpc msg to be processed */ 445177633Sdfr} 446177633Sdfr 447177633Sdfr/*ARGSUSED*/ 448177633Sdfrstatic enum xprt_stat 449177633Sdfrsvc_vc_rendezvous_stat(SVCXPRT *xprt) 450177633Sdfr{ 451177633Sdfr 452177633Sdfr return (XPRT_IDLE); 453177633Sdfr} 454177633Sdfr 455177633Sdfrstatic void 456177633Sdfrsvc_vc_destroy_common(SVCXPRT *xprt) 457177633Sdfr{ 458177633Sdfr SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 459193436Srmacklem if (xprt->xp_upcallset) { 460193436Srmacklem xprt->xp_upcallset = 0; 461193436Srmacklem soupcall_clear(xprt->xp_socket, SO_RCV); 462193436Srmacklem } 463177633Sdfr SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 464177633Sdfr 465177633Sdfr if (xprt->xp_socket) 466177633Sdfr (void)soclose(xprt->xp_socket); 467177633Sdfr 468184588Sdfr if (xprt->xp_netid) 469184588Sdfr (void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1); 470184588Sdfr svc_xprt_free(xprt); 471177633Sdfr} 472177633Sdfr 473177633Sdfrstatic void 474177633Sdfrsvc_vc_rendezvous_destroy(SVCXPRT *xprt) 475177633Sdfr{ 476177633Sdfr 477177633Sdfr svc_vc_destroy_common(xprt); 478177633Sdfr} 479177633Sdfr 480177633Sdfrstatic void 481177633Sdfrsvc_vc_destroy(SVCXPRT *xprt) 482177633Sdfr{ 483177633Sdfr struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1; 484177633Sdfr 485177633Sdfr svc_vc_destroy_common(xprt); 486177633Sdfr 487177633Sdfr if (cd->mreq) 488177633Sdfr m_freem(cd->mreq); 489177633Sdfr if (cd->mpending) 490177633Sdfr m_freem(cd->mpending); 491177633Sdfr mem_free(cd, sizeof(*cd)); 492177633Sdfr} 493177633Sdfr 494244008Srmacklemstatic void 495244008Srmacklemsvc_vc_backchannel_destroy(SVCXPRT *xprt) 496244008Srmacklem{ 497244008Srmacklem struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1; 498244008Srmacklem struct mbuf *m, *m2; 499244008Srmacklem 500244008Srmacklem svc_xprt_free(xprt); 501244008Srmacklem m = cd->mreq; 502244008Srmacklem while (m != NULL) { 503244008Srmacklem m2 = m; 504244008Srmacklem m = m->m_nextpkt; 505244008Srmacklem m_freem(m2); 506244008Srmacklem } 507244008Srmacklem mem_free(cd, sizeof(*cd)); 508244008Srmacklem} 509244008Srmacklem 510177633Sdfr/*ARGSUSED*/ 511177633Sdfrstatic bool_t 512177633Sdfrsvc_vc_control(SVCXPRT *xprt, const u_int rq, void *in) 513177633Sdfr{ 514177633Sdfr return (FALSE); 515177633Sdfr} 516177633Sdfr 517177633Sdfrstatic bool_t 518177633Sdfrsvc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in) 519177633Sdfr{ 520177633Sdfr 521177633Sdfr return (FALSE); 522177633Sdfr} 523177633Sdfr 524244008Srmacklemstatic bool_t 525244008Srmacklemsvc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, void *in) 526244008Srmacklem{ 527244008Srmacklem 528244008Srmacklem return (FALSE); 529244008Srmacklem} 530244008Srmacklem 531177633Sdfrstatic enum xprt_stat 532177633Sdfrsvc_vc_stat(SVCXPRT *xprt) 533177633Sdfr{ 534177633Sdfr struct cf_conn *cd; 535177633Sdfr 536177633Sdfr cd = (struct cf_conn *)(xprt->xp_p1); 537177633Sdfr 538177633Sdfr if (cd->strm_stat == XPRT_DIED) 539177633Sdfr return (XPRT_DIED); 540177633Sdfr 541261047Smav if (cd->mreq != NULL && cd->resid == 0 && cd->eor) 542261047Smav return (XPRT_MOREREQS); 543177633Sdfr 544184588Sdfr if (soreadable(xprt->xp_socket)) 545184588Sdfr return (XPRT_MOREREQS); 546184588Sdfr 547177633Sdfr return (XPRT_IDLE); 548177633Sdfr} 549177633Sdfr 550261055Smavstatic bool_t 551261055Smavsvc_vc_ack(SVCXPRT *xprt, uint32_t *ack) 552261055Smav{ 553261055Smav 554261055Smav *ack = atomic_load_acq_32(&xprt->xp_snt_cnt); 555261055Smav *ack -= xprt->xp_socket->so_snd.sb_cc; 556261055Smav return (TRUE); 557261055Smav} 558261055Smav 559244008Srmacklemstatic enum xprt_stat 560244008Srmacklemsvc_vc_backchannel_stat(SVCXPRT *xprt) 561244008Srmacklem{ 562244008Srmacklem struct cf_conn *cd; 563244008Srmacklem 564244008Srmacklem cd = (struct cf_conn *)(xprt->xp_p1); 565244008Srmacklem 566244008Srmacklem if (cd->mreq != NULL) 567244008Srmacklem return (XPRT_MOREREQS); 568244008Srmacklem 569244008Srmacklem return (XPRT_IDLE); 570244008Srmacklem} 571244008Srmacklem 572261047Smav/* 573261047Smav * If we have an mbuf chain in cd->mpending, try to parse a record from it, 574261047Smav * leaving the result in cd->mreq. If we don't have a complete record, leave 575261047Smav * the partial result in cd->mreq and try to read more from the socket. 576261047Smav */ 577261050Smavstatic int 578261047Smavsvc_vc_process_pending(SVCXPRT *xprt) 579261047Smav{ 580261047Smav struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 581261047Smav struct socket *so = xprt->xp_socket; 582261047Smav struct mbuf *m; 583261047Smav 584261047Smav /* 585261047Smav * If cd->resid is non-zero, we have part of the 586261047Smav * record already, otherwise we are expecting a record 587261047Smav * marker. 588261047Smav */ 589261047Smav if (!cd->resid && cd->mpending) { 590261047Smav /* 591261047Smav * See if there is enough data buffered to 592261047Smav * make up a record marker. Make sure we can 593261047Smav * handle the case where the record marker is 594261047Smav * split across more than one mbuf. 595261047Smav */ 596261047Smav size_t n = 0; 597261047Smav uint32_t header; 598261047Smav 599261047Smav m = cd->mpending; 600261047Smav while (n < sizeof(uint32_t) && m) { 601261047Smav n += m->m_len; 602261047Smav m = m->m_next; 603261047Smav } 604261047Smav if (n < sizeof(uint32_t)) { 605261047Smav so->so_rcv.sb_lowat = sizeof(uint32_t) - n; 606261050Smav return (FALSE); 607261047Smav } 608261047Smav m_copydata(cd->mpending, 0, sizeof(header), 609261047Smav (char *)&header); 610261047Smav header = ntohl(header); 611261047Smav cd->eor = (header & 0x80000000) != 0; 612261047Smav cd->resid = header & 0x7fffffff; 613261047Smav m_adj(cd->mpending, sizeof(uint32_t)); 614261047Smav } 615261047Smav 616261047Smav /* 617261047Smav * Start pulling off mbufs from cd->mpending 618261047Smav * until we either have a complete record or 619261047Smav * we run out of data. We use m_split to pull 620261047Smav * data - it will pull as much as possible and 621261047Smav * split the last mbuf if necessary. 622261047Smav */ 623261047Smav while (cd->mpending && cd->resid) { 624261047Smav m = cd->mpending; 625261047Smav if (cd->mpending->m_next 626261047Smav || cd->mpending->m_len > cd->resid) 627261047Smav cd->mpending = m_split(cd->mpending, 628261047Smav cd->resid, M_WAITOK); 629261047Smav else 630261047Smav cd->mpending = NULL; 631261047Smav if (cd->mreq) 632261047Smav m_last(cd->mreq)->m_next = m; 633261047Smav else 634261047Smav cd->mreq = m; 635261047Smav while (m) { 636261047Smav cd->resid -= m->m_len; 637261047Smav m = m->m_next; 638261047Smav } 639261047Smav } 640261047Smav 641261052Smav /* 642261052Smav * Block receive upcalls if we have more data pending, 643261052Smav * otherwise report our need. 644261052Smav */ 645261052Smav if (cd->mpending) 646261052Smav so->so_rcv.sb_lowat = INT_MAX; 647261052Smav else 648261052Smav so->so_rcv.sb_lowat = 649261052Smav imax(1, imin(cd->resid, so->so_rcv.sb_hiwat / 2)); 650261050Smav return (TRUE); 651261047Smav} 652261047Smav 653177633Sdfrstatic bool_t 654184588Sdfrsvc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg, 655184588Sdfr struct sockaddr **addrp, struct mbuf **mp) 656177633Sdfr{ 657177633Sdfr struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 658177633Sdfr struct uio uio; 659177633Sdfr struct mbuf *m; 660261047Smav struct socket* so = xprt->xp_socket; 661184588Sdfr XDR xdrs; 662177633Sdfr int error, rcvflag; 663269398Srmacklem uint32_t xid_plus_direction[2]; 664177633Sdfr 665184588Sdfr /* 666184588Sdfr * Serialise access to the socket and our own record parsing 667184588Sdfr * state. 668184588Sdfr */ 669184588Sdfr sx_xlock(&xprt->xp_lock); 670184588Sdfr 671177633Sdfr for (;;) { 672261047Smav /* If we have no request ready, check pending queue. */ 673261047Smav while (cd->mpending && 674261050Smav (cd->mreq == NULL || cd->resid != 0 || !cd->eor)) { 675261050Smav if (!svc_vc_process_pending(xprt)) 676261050Smav break; 677261050Smav } 678177633Sdfr 679261047Smav /* Process and return complete request in cd->mreq. */ 680261047Smav if (cd->mreq != NULL && cd->resid == 0 && cd->eor) { 681177633Sdfr 682269398Srmacklem /* 683269398Srmacklem * Now, check for a backchannel reply. 684269398Srmacklem * The XID is in the first uint32_t of the reply 685269398Srmacklem * and the message direction is the second one. 686269398Srmacklem */ 687269398Srmacklem if ((cd->mreq->m_len >= sizeof(xid_plus_direction) || 688269398Srmacklem m_length(cd->mreq, NULL) >= 689269398Srmacklem sizeof(xid_plus_direction)) && 690269398Srmacklem xprt->xp_p2 != NULL) { 691269398Srmacklem m_copydata(cd->mreq, 0, 692269398Srmacklem sizeof(xid_plus_direction), 693269398Srmacklem (char *)xid_plus_direction); 694269398Srmacklem xid_plus_direction[0] = 695269398Srmacklem ntohl(xid_plus_direction[0]); 696269398Srmacklem xid_plus_direction[1] = 697269398Srmacklem ntohl(xid_plus_direction[1]); 698269398Srmacklem /* Check message direction. */ 699269398Srmacklem if (xid_plus_direction[1] == REPLY) { 700269398Srmacklem clnt_bck_svccall(xprt->xp_p2, 701269398Srmacklem cd->mreq, 702269398Srmacklem xid_plus_direction[0]); 703269398Srmacklem cd->mreq = NULL; 704269398Srmacklem continue; 705269398Srmacklem } 706269398Srmacklem } 707269398Srmacklem 708261047Smav xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE); 709261047Smav cd->mreq = NULL; 710261047Smav 711261047Smav /* Check for next request in a pending queue. */ 712261047Smav svc_vc_process_pending(xprt); 713261047Smav if (cd->mreq == NULL || cd->resid != 0) { 714261047Smav SOCKBUF_LOCK(&so->so_rcv); 715261047Smav if (!soreadable(so)) 716261053Smav xprt_inactive_self(xprt); 717261047Smav SOCKBUF_UNLOCK(&so->so_rcv); 718177633Sdfr } 719177633Sdfr 720261047Smav sx_xunlock(&xprt->xp_lock); 721177633Sdfr 722261047Smav if (! xdr_callmsg(&xdrs, msg)) { 723261047Smav XDR_DESTROY(&xdrs); 724261047Smav return (FALSE); 725261047Smav } 726184588Sdfr 727261047Smav *addrp = NULL; 728261047Smav *mp = xdrmbuf_getall(&xdrs); 729261047Smav XDR_DESTROY(&xdrs); 730177633Sdfr 731261047Smav return (TRUE); 732177633Sdfr } 733177633Sdfr 734177633Sdfr /* 735177633Sdfr * The socket upcall calls xprt_active() which will eventually 736177633Sdfr * cause the server to call us here. We attempt to 737177633Sdfr * read as much as possible from the socket and put 738177633Sdfr * the result in cd->mpending. If the read fails, 739177633Sdfr * we have drained both cd->mpending and the socket so 740177633Sdfr * we can call xprt_inactive(). 741177633Sdfr */ 742177633Sdfr uio.uio_resid = 1000000000; 743177633Sdfr uio.uio_td = curthread; 744177633Sdfr m = NULL; 745177633Sdfr rcvflag = MSG_DONTWAIT; 746261047Smav error = soreceive(so, NULL, &uio, &m, NULL, &rcvflag); 747177633Sdfr 748177633Sdfr if (error == EWOULDBLOCK) { 749184588Sdfr /* 750184588Sdfr * We must re-test for readability after 751184588Sdfr * taking the lock to protect us in the case 752184588Sdfr * where a new packet arrives on the socket 753184588Sdfr * after our call to soreceive fails with 754261047Smav * EWOULDBLOCK. 755184588Sdfr */ 756261047Smav SOCKBUF_LOCK(&so->so_rcv); 757261047Smav if (!soreadable(so)) 758261053Smav xprt_inactive_self(xprt); 759261047Smav SOCKBUF_UNLOCK(&so->so_rcv); 760184588Sdfr sx_xunlock(&xprt->xp_lock); 761177633Sdfr return (FALSE); 762177633Sdfr } 763177633Sdfr 764177633Sdfr if (error) { 765261047Smav SOCKBUF_LOCK(&so->so_rcv); 766193436Srmacklem if (xprt->xp_upcallset) { 767193436Srmacklem xprt->xp_upcallset = 0; 768261047Smav soupcall_clear(so, SO_RCV); 769193436Srmacklem } 770261047Smav SOCKBUF_UNLOCK(&so->so_rcv); 771261053Smav xprt_inactive_self(xprt); 772177633Sdfr cd->strm_stat = XPRT_DIED; 773184588Sdfr sx_xunlock(&xprt->xp_lock); 774177633Sdfr return (FALSE); 775177633Sdfr } 776177633Sdfr 777177633Sdfr if (!m) { 778177633Sdfr /* 779177633Sdfr * EOF - the other end has closed the socket. 780177633Sdfr */ 781261053Smav xprt_inactive_self(xprt); 782177633Sdfr cd->strm_stat = XPRT_DIED; 783184588Sdfr sx_xunlock(&xprt->xp_lock); 784177633Sdfr return (FALSE); 785177633Sdfr } 786177633Sdfr 787177633Sdfr if (cd->mpending) 788177633Sdfr m_last(cd->mpending)->m_next = m; 789177633Sdfr else 790177633Sdfr cd->mpending = m; 791177633Sdfr } 792177633Sdfr} 793177633Sdfr 794177633Sdfrstatic bool_t 795244008Srmacklemsvc_vc_backchannel_recv(SVCXPRT *xprt, struct rpc_msg *msg, 796244008Srmacklem struct sockaddr **addrp, struct mbuf **mp) 797244008Srmacklem{ 798244008Srmacklem struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 799244008Srmacklem struct ct_data *ct; 800244008Srmacklem struct mbuf *m; 801244008Srmacklem XDR xdrs; 802244008Srmacklem 803244008Srmacklem sx_xlock(&xprt->xp_lock); 804244008Srmacklem ct = (struct ct_data *)xprt->xp_p2; 805244008Srmacklem if (ct == NULL) { 806244008Srmacklem sx_xunlock(&xprt->xp_lock); 807244008Srmacklem return (FALSE); 808244008Srmacklem } 809244008Srmacklem mtx_lock(&ct->ct_lock); 810244008Srmacklem m = cd->mreq; 811244008Srmacklem if (m == NULL) { 812261053Smav xprt_inactive_self(xprt); 813244008Srmacklem mtx_unlock(&ct->ct_lock); 814244008Srmacklem sx_xunlock(&xprt->xp_lock); 815244008Srmacklem return (FALSE); 816244008Srmacklem } 817244008Srmacklem cd->mreq = m->m_nextpkt; 818244008Srmacklem mtx_unlock(&ct->ct_lock); 819244008Srmacklem sx_xunlock(&xprt->xp_lock); 820244008Srmacklem 821244008Srmacklem xdrmbuf_create(&xdrs, m, XDR_DECODE); 822244008Srmacklem if (! xdr_callmsg(&xdrs, msg)) { 823244008Srmacklem XDR_DESTROY(&xdrs); 824244008Srmacklem return (FALSE); 825244008Srmacklem } 826244008Srmacklem *addrp = NULL; 827244008Srmacklem *mp = xdrmbuf_getall(&xdrs); 828244008Srmacklem XDR_DESTROY(&xdrs); 829244008Srmacklem return (TRUE); 830244008Srmacklem} 831244008Srmacklem 832244008Srmacklemstatic bool_t 833184588Sdfrsvc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg, 834261055Smav struct sockaddr *addr, struct mbuf *m, uint32_t *seq) 835177633Sdfr{ 836177633Sdfr XDR xdrs; 837177633Sdfr struct mbuf *mrep; 838184588Sdfr bool_t stat = TRUE; 839261055Smav int error, len; 840177633Sdfr 841177633Sdfr /* 842177633Sdfr * Leave space for record mark. 843177633Sdfr */ 844248195Sglebius mrep = m_gethdr(M_WAITOK, MT_DATA); 845177633Sdfr mrep->m_data += sizeof(uint32_t); 846177633Sdfr 847184588Sdfr xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); 848184588Sdfr 849184588Sdfr if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 850184588Sdfr msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 851184588Sdfr if (!xdr_replymsg(&xdrs, msg)) 852184588Sdfr stat = FALSE; 853184588Sdfr else 854184588Sdfr xdrmbuf_append(&xdrs, m); 855184588Sdfr } else { 856184588Sdfr stat = xdr_replymsg(&xdrs, msg); 857184588Sdfr } 858184588Sdfr 859184588Sdfr if (stat) { 860177633Sdfr m_fixhdr(mrep); 861177633Sdfr 862177633Sdfr /* 863177633Sdfr * Prepend a record marker containing the reply length. 864177633Sdfr */ 865243882Sglebius M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK); 866261055Smav len = mrep->m_pkthdr.len; 867177633Sdfr *mtod(mrep, uint32_t *) = 868261055Smav htonl(0x80000000 | (len - sizeof(uint32_t))); 869261055Smav atomic_add_acq_32(&xprt->xp_snd_cnt, len); 870177633Sdfr error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL, 871177633Sdfr 0, curthread); 872177633Sdfr if (!error) { 873261055Smav atomic_add_rel_32(&xprt->xp_snt_cnt, len); 874261055Smav if (seq) 875261055Smav *seq = xprt->xp_snd_cnt; 876177633Sdfr stat = TRUE; 877261055Smav } else 878261055Smav atomic_subtract_32(&xprt->xp_snd_cnt, len); 879177633Sdfr } else { 880177633Sdfr m_freem(mrep); 881177633Sdfr } 882177633Sdfr 883184588Sdfr XDR_DESTROY(&xdrs); 884177633Sdfr 885177633Sdfr return (stat); 886177633Sdfr} 887177633Sdfr 888177633Sdfrstatic bool_t 889244008Srmacklemsvc_vc_backchannel_reply(SVCXPRT *xprt, struct rpc_msg *msg, 890261055Smav struct sockaddr *addr, struct mbuf *m, uint32_t *seq) 891244008Srmacklem{ 892244008Srmacklem struct ct_data *ct; 893244008Srmacklem XDR xdrs; 894244008Srmacklem struct mbuf *mrep; 895244008Srmacklem bool_t stat = TRUE; 896244008Srmacklem int error; 897244008Srmacklem 898244008Srmacklem /* 899244008Srmacklem * Leave space for record mark. 900244008Srmacklem */ 901248195Sglebius mrep = m_gethdr(M_WAITOK, MT_DATA); 902244008Srmacklem mrep->m_data += sizeof(uint32_t); 903244008Srmacklem 904244008Srmacklem xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); 905244008Srmacklem 906244008Srmacklem if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 907244008Srmacklem msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 908244008Srmacklem if (!xdr_replymsg(&xdrs, msg)) 909244008Srmacklem stat = FALSE; 910244008Srmacklem else 911244008Srmacklem xdrmbuf_append(&xdrs, m); 912244008Srmacklem } else { 913244008Srmacklem stat = xdr_replymsg(&xdrs, msg); 914244008Srmacklem } 915244008Srmacklem 916244008Srmacklem if (stat) { 917244008Srmacklem m_fixhdr(mrep); 918244008Srmacklem 919244008Srmacklem /* 920244008Srmacklem * Prepend a record marker containing the reply length. 921244008Srmacklem */ 922244008Srmacklem M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK); 923244008Srmacklem *mtod(mrep, uint32_t *) = 924244008Srmacklem htonl(0x80000000 | (mrep->m_pkthdr.len 925244008Srmacklem - sizeof(uint32_t))); 926244008Srmacklem sx_xlock(&xprt->xp_lock); 927244008Srmacklem ct = (struct ct_data *)xprt->xp_p2; 928244008Srmacklem if (ct != NULL) 929244008Srmacklem error = sosend(ct->ct_socket, NULL, NULL, mrep, NULL, 930244008Srmacklem 0, curthread); 931244008Srmacklem else 932244008Srmacklem error = EPIPE; 933244008Srmacklem sx_xunlock(&xprt->xp_lock); 934244008Srmacklem if (!error) { 935244008Srmacklem stat = TRUE; 936244008Srmacklem } 937244008Srmacklem } else { 938244008Srmacklem m_freem(mrep); 939244008Srmacklem } 940244008Srmacklem 941244008Srmacklem XDR_DESTROY(&xdrs); 942244008Srmacklem 943244008Srmacklem return (stat); 944244008Srmacklem} 945244008Srmacklem 946244008Srmacklemstatic bool_t 947177633Sdfrsvc_vc_null() 948177633Sdfr{ 949177633Sdfr 950177633Sdfr return (FALSE); 951177633Sdfr} 952177633Sdfr 953193272Sjhbstatic int 954177633Sdfrsvc_vc_soupcall(struct socket *so, void *arg, int waitflag) 955177633Sdfr{ 956177633Sdfr SVCXPRT *xprt = (SVCXPRT *) arg; 957177633Sdfr 958261047Smav if (soreadable(xprt->xp_socket)) 959261047Smav xprt_active(xprt); 960193272Sjhb return (SU_OK); 961177633Sdfr} 962177633Sdfr 963177633Sdfr#if 0 964177633Sdfr/* 965177633Sdfr * Get the effective UID of the sending process. Used by rpcbind, keyserv 966177633Sdfr * and rpc.yppasswdd on AF_LOCAL. 967177633Sdfr */ 968177633Sdfrint 969177633Sdfr__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) { 970177633Sdfr int sock, ret; 971177633Sdfr gid_t egid; 972177633Sdfr uid_t euid; 973177633Sdfr struct sockaddr *sa; 974177633Sdfr 975177633Sdfr sock = transp->xp_fd; 976184588Sdfr sa = (struct sockaddr *)transp->xp_rtaddr; 977177633Sdfr if (sa->sa_family == AF_LOCAL) { 978177633Sdfr ret = getpeereid(sock, &euid, &egid); 979177633Sdfr if (ret == 0) 980177633Sdfr *uid = euid; 981177633Sdfr return (ret); 982177633Sdfr } else 983177633Sdfr return (-1); 984177633Sdfr} 985177633Sdfr#endif 986