svc_vc.c revision 281520
1177633Sdfr/* $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $ */ 2177633Sdfr 3261046Smav/*- 4261046Smav * Copyright (c) 2009, Sun Microsystems, Inc. 5261046Smav * All rights reserved. 6261046Smav * 7261046Smav * Redistribution and use in source and binary forms, with or without 8261046Smav * modification, are permitted provided that the following conditions are met: 9261046Smav * - Redistributions of source code must retain the above copyright notice, 10261046Smav * this list of conditions and the following disclaimer. 11261046Smav * - Redistributions in binary form must reproduce the above copyright notice, 12261046Smav * this list of conditions and the following disclaimer in the documentation 13261046Smav * and/or other materials provided with the distribution. 14261046Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its 15261046Smav * contributors may be used to endorse or promote products derived 16261046Smav * from this software without specific prior written permission. 17177633Sdfr * 18261046Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19261046Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20261046Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21261046Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22261046Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23261046Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24261046Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25261046Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26261046Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27261046Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28261046Smav * POSSIBILITY OF SUCH DAMAGE. 29177633Sdfr */ 30177633Sdfr 31177633Sdfr#if defined(LIBC_SCCS) && !defined(lint) 32177633Sdfrstatic char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; 33177633Sdfrstatic char *sccsid = "@(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 34177633Sdfr#endif 35177633Sdfr#include <sys/cdefs.h> 36177633Sdfr__FBSDID("$FreeBSD: stable/10/sys/rpc/svc_vc.c 281520 2015-04-14 09:58:10Z mav $"); 37177633Sdfr 38177633Sdfr/* 39177633Sdfr * svc_vc.c, Server side for Connection Oriented based RPC. 40177633Sdfr * 41177633Sdfr * Actually implements two flavors of transporter - 42177633Sdfr * a tcp rendezvouser (a listner and connection establisher) 43177633Sdfr * and a record/tcp stream. 44177633Sdfr */ 45177633Sdfr 46177633Sdfr#include <sys/param.h> 47177633Sdfr#include <sys/lock.h> 48177633Sdfr#include <sys/kernel.h> 49177633Sdfr#include <sys/malloc.h> 50177633Sdfr#include <sys/mbuf.h> 51177633Sdfr#include <sys/mutex.h> 52193509Srwatson#include <sys/proc.h> 53177633Sdfr#include <sys/protosw.h> 54177633Sdfr#include <sys/queue.h> 55177633Sdfr#include <sys/socket.h> 56177633Sdfr#include <sys/socketvar.h> 57184588Sdfr#include <sys/sx.h> 58177633Sdfr#include <sys/systm.h> 59177633Sdfr#include <sys/uio.h> 60196503Szec 61196503Szec#include <net/vnet.h> 62196503Szec 63177633Sdfr#include <netinet/tcp.h> 64177633Sdfr 65177633Sdfr#include <rpc/rpc.h> 66177633Sdfr 67244008Srmacklem#include <rpc/krpc.h> 68177685Sdfr#include <rpc/rpc_com.h> 69177633Sdfr 70193509Srwatson#include <security/mac/mac_framework.h> 71193509Srwatson 72184588Sdfrstatic bool_t svc_vc_rendezvous_recv(SVCXPRT *, struct rpc_msg *, 73184588Sdfr struct sockaddr **, struct mbuf **); 74177633Sdfrstatic enum xprt_stat svc_vc_rendezvous_stat(SVCXPRT *); 75177633Sdfrstatic void svc_vc_rendezvous_destroy(SVCXPRT *); 76177633Sdfrstatic bool_t svc_vc_null(void); 77177633Sdfrstatic void svc_vc_destroy(SVCXPRT *); 78177633Sdfrstatic enum xprt_stat svc_vc_stat(SVCXPRT *); 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); 153180025Sdfr error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa); 154180025Sdfr if (error) 155180025Sdfr return (NULL); 156180025Sdfr xprt = svc_vc_create_conn(pool, so, sa); 157180025Sdfr free(sa, M_SONAME); 158180025Sdfr return (xprt); 159180025Sdfr } 160249263Sjhb SOCK_UNLOCK(so); 161180025Sdfr 162184588Sdfr xprt = svc_xprt_alloc(); 163184588Sdfr sx_init(&xprt->xp_lock, "xprt->xp_lock"); 164177633Sdfr xprt->xp_pool = pool; 165177633Sdfr xprt->xp_socket = so; 166177633Sdfr xprt->xp_p1 = NULL; 167177633Sdfr xprt->xp_p2 = NULL; 168177633Sdfr xprt->xp_ops = &svc_vc_rendezvous_ops; 169177633Sdfr 170177633Sdfr error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 171196503Szec if (error) { 172177633Sdfr goto cleanup_svc_vc_create; 173196503Szec } 174177633Sdfr 175184588Sdfr memcpy(&xprt->xp_ltaddr, sa, sa->sa_len); 176177633Sdfr free(sa, M_SONAME); 177177633Sdfr 178177633Sdfr xprt_register(xprt); 179177633Sdfr 180281520Smav solisten(so, -1, curthread); 181177633Sdfr 182177633Sdfr SOCKBUF_LOCK(&so->so_rcv); 183193436Srmacklem xprt->xp_upcallset = 1; 184193272Sjhb soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt); 185177633Sdfr SOCKBUF_UNLOCK(&so->so_rcv); 186177633Sdfr 187177633Sdfr return (xprt); 188177633Sdfrcleanup_svc_vc_create: 189261055Smav if (xprt) { 190261055Smav sx_destroy(&xprt->xp_lock); 191184588Sdfr svc_xprt_free(xprt); 192261055Smav } 193177633Sdfr return (NULL); 194177633Sdfr} 195177633Sdfr 196177633Sdfr/* 197177633Sdfr * Create a new transport for a socket optained via soaccept(). 198177633Sdfr */ 199177633SdfrSVCXPRT * 200177633Sdfrsvc_vc_create_conn(SVCPOOL *pool, struct socket *so, struct sockaddr *raddr) 201177633Sdfr{ 202177633Sdfr SVCXPRT *xprt = NULL; 203177633Sdfr struct cf_conn *cd = NULL; 204177633Sdfr struct sockaddr* sa = NULL; 205180025Sdfr struct sockopt opt; 206180025Sdfr int one = 1; 207177633Sdfr int error; 208177633Sdfr 209180025Sdfr bzero(&opt, sizeof(struct sockopt)); 210180025Sdfr opt.sopt_dir = SOPT_SET; 211180025Sdfr opt.sopt_level = SOL_SOCKET; 212180025Sdfr opt.sopt_name = SO_KEEPALIVE; 213180025Sdfr opt.sopt_val = &one; 214180025Sdfr opt.sopt_valsize = sizeof(one); 215180025Sdfr error = sosetopt(so, &opt); 216196503Szec if (error) { 217180025Sdfr return (NULL); 218196503Szec } 219180025Sdfr 220180025Sdfr if (so->so_proto->pr_protocol == IPPROTO_TCP) { 221180025Sdfr bzero(&opt, sizeof(struct sockopt)); 222180025Sdfr opt.sopt_dir = SOPT_SET; 223180025Sdfr opt.sopt_level = IPPROTO_TCP; 224180025Sdfr opt.sopt_name = TCP_NODELAY; 225180025Sdfr opt.sopt_val = &one; 226180025Sdfr opt.sopt_valsize = sizeof(one); 227180025Sdfr error = sosetopt(so, &opt); 228196503Szec if (error) { 229180025Sdfr return (NULL); 230196503Szec } 231180025Sdfr } 232180025Sdfr 233177633Sdfr cd = mem_alloc(sizeof(*cd)); 234177633Sdfr cd->strm_stat = XPRT_IDLE; 235177633Sdfr 236184588Sdfr xprt = svc_xprt_alloc(); 237184588Sdfr sx_init(&xprt->xp_lock, "xprt->xp_lock"); 238177633Sdfr xprt->xp_pool = pool; 239177633Sdfr xprt->xp_socket = so; 240177633Sdfr xprt->xp_p1 = cd; 241177633Sdfr xprt->xp_p2 = NULL; 242177633Sdfr xprt->xp_ops = &svc_vc_ops; 243177633Sdfr 244184588Sdfr /* 245184588Sdfr * See http://www.connectathon.org/talks96/nfstcp.pdf - client 246184588Sdfr * has a 5 minute timer, server has a 6 minute timer. 247184588Sdfr */ 248184588Sdfr xprt->xp_idletimeout = 6 * 60; 249177633Sdfr 250184588Sdfr memcpy(&xprt->xp_rtaddr, raddr, raddr->sa_len); 251184588Sdfr 252177633Sdfr error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa); 253177633Sdfr if (error) 254177633Sdfr goto cleanup_svc_vc_create; 255177633Sdfr 256184588Sdfr memcpy(&xprt->xp_ltaddr, sa, sa->sa_len); 257177633Sdfr free(sa, M_SONAME); 258177633Sdfr 259177633Sdfr xprt_register(xprt); 260177633Sdfr 261177633Sdfr SOCKBUF_LOCK(&so->so_rcv); 262193436Srmacklem xprt->xp_upcallset = 1; 263193272Sjhb soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt); 264177633Sdfr SOCKBUF_UNLOCK(&so->so_rcv); 265177633Sdfr 266177633Sdfr /* 267177633Sdfr * Throw the transport into the active list in case it already 268177633Sdfr * has some data buffered. 269177633Sdfr */ 270184588Sdfr sx_xlock(&xprt->xp_lock); 271177633Sdfr xprt_active(xprt); 272184588Sdfr sx_xunlock(&xprt->xp_lock); 273177633Sdfr 274177633Sdfr return (xprt); 275177633Sdfrcleanup_svc_vc_create: 276177633Sdfr if (xprt) { 277261055Smav sx_destroy(&xprt->xp_lock); 278261055Smav svc_xprt_free(xprt); 279177633Sdfr } 280177633Sdfr if (cd) 281177633Sdfr mem_free(cd, sizeof(*cd)); 282177633Sdfr return (NULL); 283177633Sdfr} 284177633Sdfr 285177633Sdfr/* 286244008Srmacklem * Create a new transport for a backchannel on a clnt_vc socket. 287244008Srmacklem */ 288244008SrmacklemSVCXPRT * 289244008Srmacklemsvc_vc_create_backchannel(SVCPOOL *pool) 290244008Srmacklem{ 291244008Srmacklem SVCXPRT *xprt = NULL; 292244008Srmacklem struct cf_conn *cd = NULL; 293244008Srmacklem 294244008Srmacklem cd = mem_alloc(sizeof(*cd)); 295244008Srmacklem cd->strm_stat = XPRT_IDLE; 296244008Srmacklem 297244008Srmacklem xprt = svc_xprt_alloc(); 298244008Srmacklem sx_init(&xprt->xp_lock, "xprt->xp_lock"); 299244008Srmacklem xprt->xp_pool = pool; 300244008Srmacklem xprt->xp_socket = NULL; 301244008Srmacklem xprt->xp_p1 = cd; 302244008Srmacklem xprt->xp_p2 = NULL; 303244008Srmacklem xprt->xp_ops = &svc_vc_backchannel_ops; 304244008Srmacklem return (xprt); 305244008Srmacklem} 306244008Srmacklem 307244008Srmacklem/* 308177633Sdfr * This does all of the accept except the final call to soaccept. The 309177633Sdfr * caller will call soaccept after dropping its locks (soaccept may 310177633Sdfr * call malloc). 311177633Sdfr */ 312177633Sdfrint 313177633Sdfrsvc_vc_accept(struct socket *head, struct socket **sop) 314177633Sdfr{ 315177633Sdfr int error = 0; 316177633Sdfr struct socket *so; 317177633Sdfr 318177633Sdfr if ((head->so_options & SO_ACCEPTCONN) == 0) { 319177633Sdfr error = EINVAL; 320177633Sdfr goto done; 321177633Sdfr } 322177633Sdfr#ifdef MAC 323193509Srwatson error = mac_socket_check_accept(curthread->td_ucred, head); 324177633Sdfr if (error != 0) 325177633Sdfr goto done; 326177633Sdfr#endif 327177633Sdfr ACCEPT_LOCK(); 328177633Sdfr if (TAILQ_EMPTY(&head->so_comp)) { 329177633Sdfr ACCEPT_UNLOCK(); 330177633Sdfr error = EWOULDBLOCK; 331177633Sdfr goto done; 332177633Sdfr } 333177633Sdfr so = TAILQ_FIRST(&head->so_comp); 334177633Sdfr KASSERT(!(so->so_qstate & SQ_INCOMP), ("svc_vc_accept: so SQ_INCOMP")); 335177633Sdfr KASSERT(so->so_qstate & SQ_COMP, ("svc_vc_accept: so not SQ_COMP")); 336177633Sdfr 337177633Sdfr /* 338177633Sdfr * Before changing the flags on the socket, we have to bump the 339177633Sdfr * reference count. Otherwise, if the protocol calls sofree(), 340177633Sdfr * the socket will be released due to a zero refcount. 341177633Sdfr * XXX might not need soref() since this is simpler than kern_accept. 342177633Sdfr */ 343177633Sdfr SOCK_LOCK(so); /* soref() and so_state update */ 344177633Sdfr soref(so); /* file descriptor reference */ 345177633Sdfr 346177633Sdfr TAILQ_REMOVE(&head->so_comp, so, so_list); 347177633Sdfr head->so_qlen--; 348177633Sdfr so->so_state |= (head->so_state & SS_NBIO); 349177633Sdfr so->so_qstate &= ~SQ_COMP; 350177633Sdfr so->so_head = NULL; 351177633Sdfr 352177633Sdfr SOCK_UNLOCK(so); 353177633Sdfr ACCEPT_UNLOCK(); 354177633Sdfr 355177633Sdfr *sop = so; 356177633Sdfr 357177633Sdfr /* connection has been removed from the listen queue */ 358177633Sdfr KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0); 359177633Sdfrdone: 360177633Sdfr return (error); 361177633Sdfr} 362177633Sdfr 363177633Sdfr/*ARGSUSED*/ 364177633Sdfrstatic bool_t 365184588Sdfrsvc_vc_rendezvous_recv(SVCXPRT *xprt, struct rpc_msg *msg, 366184588Sdfr struct sockaddr **addrp, struct mbuf **mp) 367177633Sdfr{ 368177633Sdfr struct socket *so = NULL; 369177633Sdfr struct sockaddr *sa = NULL; 370177633Sdfr int error; 371194407Srmacklem SVCXPRT *new_xprt; 372177633Sdfr 373177633Sdfr /* 374177633Sdfr * The socket upcall calls xprt_active() which will eventually 375177633Sdfr * cause the server to call us here. We attempt to accept a 376177633Sdfr * connection from the socket and turn it into a new 377177633Sdfr * transport. If the accept fails, we have drained all pending 378177633Sdfr * connections so we call xprt_inactive(). 379177633Sdfr */ 380184588Sdfr sx_xlock(&xprt->xp_lock); 381177633Sdfr 382177633Sdfr error = svc_vc_accept(xprt->xp_socket, &so); 383177633Sdfr 384177633Sdfr if (error == EWOULDBLOCK) { 385184588Sdfr /* 386184588Sdfr * We must re-test for new connections after taking 387184588Sdfr * the lock to protect us in the case where a new 388184588Sdfr * connection arrives after our call to accept fails 389261047Smav * with EWOULDBLOCK. 390184588Sdfr */ 391184588Sdfr ACCEPT_LOCK(); 392184588Sdfr if (TAILQ_EMPTY(&xprt->xp_socket->so_comp)) 393261053Smav xprt_inactive_self(xprt); 394184588Sdfr ACCEPT_UNLOCK(); 395184588Sdfr sx_xunlock(&xprt->xp_lock); 396177633Sdfr return (FALSE); 397177633Sdfr } 398177633Sdfr 399177633Sdfr if (error) { 400177633Sdfr SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 401193436Srmacklem if (xprt->xp_upcallset) { 402193436Srmacklem xprt->xp_upcallset = 0; 403193436Srmacklem soupcall_clear(xprt->xp_socket, SO_RCV); 404193436Srmacklem } 405177633Sdfr SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 406261053Smav xprt_inactive_self(xprt); 407184588Sdfr sx_xunlock(&xprt->xp_lock); 408177633Sdfr return (FALSE); 409177633Sdfr } 410177633Sdfr 411184588Sdfr sx_xunlock(&xprt->xp_lock); 412177633Sdfr 413177633Sdfr sa = 0; 414177633Sdfr error = soaccept(so, &sa); 415177633Sdfr 416177633Sdfr if (error) { 417177633Sdfr /* 418177633Sdfr * XXX not sure if I need to call sofree or soclose here. 419177633Sdfr */ 420177633Sdfr if (sa) 421177633Sdfr free(sa, M_SONAME); 422177633Sdfr return (FALSE); 423177633Sdfr } 424177633Sdfr 425177633Sdfr /* 426177633Sdfr * svc_vc_create_conn will call xprt_register - we don't need 427194407Srmacklem * to do anything with the new connection except derefence it. 428177633Sdfr */ 429194407Srmacklem new_xprt = svc_vc_create_conn(xprt->xp_pool, so, sa); 430194407Srmacklem if (!new_xprt) { 431180025Sdfr soclose(so); 432194407Srmacklem } else { 433194407Srmacklem SVC_RELEASE(new_xprt); 434194407Srmacklem } 435180025Sdfr 436177633Sdfr free(sa, M_SONAME); 437177633Sdfr 438177633Sdfr return (FALSE); /* there is never an rpc msg to be processed */ 439177633Sdfr} 440177633Sdfr 441177633Sdfr/*ARGSUSED*/ 442177633Sdfrstatic enum xprt_stat 443177633Sdfrsvc_vc_rendezvous_stat(SVCXPRT *xprt) 444177633Sdfr{ 445177633Sdfr 446177633Sdfr return (XPRT_IDLE); 447177633Sdfr} 448177633Sdfr 449177633Sdfrstatic void 450177633Sdfrsvc_vc_destroy_common(SVCXPRT *xprt) 451177633Sdfr{ 452177633Sdfr SOCKBUF_LOCK(&xprt->xp_socket->so_rcv); 453193436Srmacklem if (xprt->xp_upcallset) { 454193436Srmacklem xprt->xp_upcallset = 0; 455193436Srmacklem soupcall_clear(xprt->xp_socket, SO_RCV); 456193436Srmacklem } 457177633Sdfr SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv); 458177633Sdfr 459177633Sdfr if (xprt->xp_socket) 460177633Sdfr (void)soclose(xprt->xp_socket); 461177633Sdfr 462184588Sdfr if (xprt->xp_netid) 463184588Sdfr (void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1); 464184588Sdfr svc_xprt_free(xprt); 465177633Sdfr} 466177633Sdfr 467177633Sdfrstatic void 468177633Sdfrsvc_vc_rendezvous_destroy(SVCXPRT *xprt) 469177633Sdfr{ 470177633Sdfr 471177633Sdfr svc_vc_destroy_common(xprt); 472177633Sdfr} 473177633Sdfr 474177633Sdfrstatic void 475177633Sdfrsvc_vc_destroy(SVCXPRT *xprt) 476177633Sdfr{ 477177633Sdfr struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1; 478177633Sdfr 479177633Sdfr svc_vc_destroy_common(xprt); 480177633Sdfr 481177633Sdfr if (cd->mreq) 482177633Sdfr m_freem(cd->mreq); 483177633Sdfr if (cd->mpending) 484177633Sdfr m_freem(cd->mpending); 485177633Sdfr mem_free(cd, sizeof(*cd)); 486177633Sdfr} 487177633Sdfr 488244008Srmacklemstatic void 489244008Srmacklemsvc_vc_backchannel_destroy(SVCXPRT *xprt) 490244008Srmacklem{ 491244008Srmacklem struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1; 492244008Srmacklem struct mbuf *m, *m2; 493244008Srmacklem 494244008Srmacklem svc_xprt_free(xprt); 495244008Srmacklem m = cd->mreq; 496244008Srmacklem while (m != NULL) { 497244008Srmacklem m2 = m; 498244008Srmacklem m = m->m_nextpkt; 499244008Srmacklem m_freem(m2); 500244008Srmacklem } 501244008Srmacklem mem_free(cd, sizeof(*cd)); 502244008Srmacklem} 503244008Srmacklem 504177633Sdfr/*ARGSUSED*/ 505177633Sdfrstatic bool_t 506177633Sdfrsvc_vc_control(SVCXPRT *xprt, const u_int rq, void *in) 507177633Sdfr{ 508177633Sdfr return (FALSE); 509177633Sdfr} 510177633Sdfr 511177633Sdfrstatic bool_t 512177633Sdfrsvc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in) 513177633Sdfr{ 514177633Sdfr 515177633Sdfr return (FALSE); 516177633Sdfr} 517177633Sdfr 518244008Srmacklemstatic bool_t 519244008Srmacklemsvc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, void *in) 520244008Srmacklem{ 521244008Srmacklem 522244008Srmacklem return (FALSE); 523244008Srmacklem} 524244008Srmacklem 525177633Sdfrstatic enum xprt_stat 526177633Sdfrsvc_vc_stat(SVCXPRT *xprt) 527177633Sdfr{ 528177633Sdfr struct cf_conn *cd; 529177633Sdfr 530177633Sdfr cd = (struct cf_conn *)(xprt->xp_p1); 531177633Sdfr 532177633Sdfr if (cd->strm_stat == XPRT_DIED) 533177633Sdfr return (XPRT_DIED); 534177633Sdfr 535261047Smav if (cd->mreq != NULL && cd->resid == 0 && cd->eor) 536261047Smav return (XPRT_MOREREQS); 537177633Sdfr 538184588Sdfr if (soreadable(xprt->xp_socket)) 539184588Sdfr return (XPRT_MOREREQS); 540184588Sdfr 541177633Sdfr return (XPRT_IDLE); 542177633Sdfr} 543177633Sdfr 544261055Smavstatic bool_t 545261055Smavsvc_vc_ack(SVCXPRT *xprt, uint32_t *ack) 546261055Smav{ 547261055Smav 548261055Smav *ack = atomic_load_acq_32(&xprt->xp_snt_cnt); 549261055Smav *ack -= xprt->xp_socket->so_snd.sb_cc; 550261055Smav return (TRUE); 551261055Smav} 552261055Smav 553244008Srmacklemstatic enum xprt_stat 554244008Srmacklemsvc_vc_backchannel_stat(SVCXPRT *xprt) 555244008Srmacklem{ 556244008Srmacklem struct cf_conn *cd; 557244008Srmacklem 558244008Srmacklem cd = (struct cf_conn *)(xprt->xp_p1); 559244008Srmacklem 560244008Srmacklem if (cd->mreq != NULL) 561244008Srmacklem return (XPRT_MOREREQS); 562244008Srmacklem 563244008Srmacklem return (XPRT_IDLE); 564244008Srmacklem} 565244008Srmacklem 566261047Smav/* 567261047Smav * If we have an mbuf chain in cd->mpending, try to parse a record from it, 568261047Smav * leaving the result in cd->mreq. If we don't have a complete record, leave 569261047Smav * the partial result in cd->mreq and try to read more from the socket. 570261047Smav */ 571261050Smavstatic int 572261047Smavsvc_vc_process_pending(SVCXPRT *xprt) 573261047Smav{ 574261047Smav struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 575261047Smav struct socket *so = xprt->xp_socket; 576261047Smav struct mbuf *m; 577261047Smav 578261047Smav /* 579261047Smav * If cd->resid is non-zero, we have part of the 580261047Smav * record already, otherwise we are expecting a record 581261047Smav * marker. 582261047Smav */ 583261047Smav if (!cd->resid && cd->mpending) { 584261047Smav /* 585261047Smav * See if there is enough data buffered to 586261047Smav * make up a record marker. Make sure we can 587261047Smav * handle the case where the record marker is 588261047Smav * split across more than one mbuf. 589261047Smav */ 590261047Smav size_t n = 0; 591261047Smav uint32_t header; 592261047Smav 593261047Smav m = cd->mpending; 594261047Smav while (n < sizeof(uint32_t) && m) { 595261047Smav n += m->m_len; 596261047Smav m = m->m_next; 597261047Smav } 598261047Smav if (n < sizeof(uint32_t)) { 599261047Smav so->so_rcv.sb_lowat = sizeof(uint32_t) - n; 600261050Smav return (FALSE); 601261047Smav } 602261047Smav m_copydata(cd->mpending, 0, sizeof(header), 603261047Smav (char *)&header); 604261047Smav header = ntohl(header); 605261047Smav cd->eor = (header & 0x80000000) != 0; 606261047Smav cd->resid = header & 0x7fffffff; 607261047Smav m_adj(cd->mpending, sizeof(uint32_t)); 608261047Smav } 609261047Smav 610261047Smav /* 611261047Smav * Start pulling off mbufs from cd->mpending 612261047Smav * until we either have a complete record or 613261047Smav * we run out of data. We use m_split to pull 614261047Smav * data - it will pull as much as possible and 615261047Smav * split the last mbuf if necessary. 616261047Smav */ 617261047Smav while (cd->mpending && cd->resid) { 618261047Smav m = cd->mpending; 619261047Smav if (cd->mpending->m_next 620261047Smav || cd->mpending->m_len > cd->resid) 621261047Smav cd->mpending = m_split(cd->mpending, 622261047Smav cd->resid, M_WAITOK); 623261047Smav else 624261047Smav cd->mpending = NULL; 625261047Smav if (cd->mreq) 626261047Smav m_last(cd->mreq)->m_next = m; 627261047Smav else 628261047Smav cd->mreq = m; 629261047Smav while (m) { 630261047Smav cd->resid -= m->m_len; 631261047Smav m = m->m_next; 632261047Smav } 633261047Smav } 634261047Smav 635261052Smav /* 636261052Smav * Block receive upcalls if we have more data pending, 637261052Smav * otherwise report our need. 638261052Smav */ 639261052Smav if (cd->mpending) 640261052Smav so->so_rcv.sb_lowat = INT_MAX; 641261052Smav else 642261052Smav so->so_rcv.sb_lowat = 643261052Smav imax(1, imin(cd->resid, so->so_rcv.sb_hiwat / 2)); 644261050Smav return (TRUE); 645261047Smav} 646261047Smav 647177633Sdfrstatic bool_t 648184588Sdfrsvc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg, 649184588Sdfr struct sockaddr **addrp, struct mbuf **mp) 650177633Sdfr{ 651177633Sdfr struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 652177633Sdfr struct uio uio; 653177633Sdfr struct mbuf *m; 654261047Smav struct socket* so = xprt->xp_socket; 655184588Sdfr XDR xdrs; 656177633Sdfr int error, rcvflag; 657269398Srmacklem uint32_t xid_plus_direction[2]; 658177633Sdfr 659184588Sdfr /* 660184588Sdfr * Serialise access to the socket and our own record parsing 661184588Sdfr * state. 662184588Sdfr */ 663184588Sdfr sx_xlock(&xprt->xp_lock); 664184588Sdfr 665177633Sdfr for (;;) { 666261047Smav /* If we have no request ready, check pending queue. */ 667261047Smav while (cd->mpending && 668261050Smav (cd->mreq == NULL || cd->resid != 0 || !cd->eor)) { 669261050Smav if (!svc_vc_process_pending(xprt)) 670261050Smav break; 671261050Smav } 672177633Sdfr 673261047Smav /* Process and return complete request in cd->mreq. */ 674261047Smav if (cd->mreq != NULL && cd->resid == 0 && cd->eor) { 675177633Sdfr 676269398Srmacklem /* 677269398Srmacklem * Now, check for a backchannel reply. 678269398Srmacklem * The XID is in the first uint32_t of the reply 679269398Srmacklem * and the message direction is the second one. 680269398Srmacklem */ 681269398Srmacklem if ((cd->mreq->m_len >= sizeof(xid_plus_direction) || 682269398Srmacklem m_length(cd->mreq, NULL) >= 683269398Srmacklem sizeof(xid_plus_direction)) && 684269398Srmacklem xprt->xp_p2 != NULL) { 685269398Srmacklem m_copydata(cd->mreq, 0, 686269398Srmacklem sizeof(xid_plus_direction), 687269398Srmacklem (char *)xid_plus_direction); 688269398Srmacklem xid_plus_direction[0] = 689269398Srmacklem ntohl(xid_plus_direction[0]); 690269398Srmacklem xid_plus_direction[1] = 691269398Srmacklem ntohl(xid_plus_direction[1]); 692269398Srmacklem /* Check message direction. */ 693269398Srmacklem if (xid_plus_direction[1] == REPLY) { 694269398Srmacklem clnt_bck_svccall(xprt->xp_p2, 695269398Srmacklem cd->mreq, 696269398Srmacklem xid_plus_direction[0]); 697269398Srmacklem cd->mreq = NULL; 698269398Srmacklem continue; 699269398Srmacklem } 700269398Srmacklem } 701269398Srmacklem 702261047Smav xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE); 703261047Smav cd->mreq = NULL; 704261047Smav 705261047Smav /* Check for next request in a pending queue. */ 706261047Smav svc_vc_process_pending(xprt); 707261047Smav if (cd->mreq == NULL || cd->resid != 0) { 708261047Smav SOCKBUF_LOCK(&so->so_rcv); 709261047Smav if (!soreadable(so)) 710261053Smav xprt_inactive_self(xprt); 711261047Smav SOCKBUF_UNLOCK(&so->so_rcv); 712177633Sdfr } 713177633Sdfr 714261047Smav sx_xunlock(&xprt->xp_lock); 715177633Sdfr 716261047Smav if (! xdr_callmsg(&xdrs, msg)) { 717261047Smav XDR_DESTROY(&xdrs); 718261047Smav return (FALSE); 719261047Smav } 720184588Sdfr 721261047Smav *addrp = NULL; 722261047Smav *mp = xdrmbuf_getall(&xdrs); 723261047Smav XDR_DESTROY(&xdrs); 724177633Sdfr 725261047Smav return (TRUE); 726177633Sdfr } 727177633Sdfr 728177633Sdfr /* 729177633Sdfr * The socket upcall calls xprt_active() which will eventually 730177633Sdfr * cause the server to call us here. We attempt to 731177633Sdfr * read as much as possible from the socket and put 732177633Sdfr * the result in cd->mpending. If the read fails, 733177633Sdfr * we have drained both cd->mpending and the socket so 734177633Sdfr * we can call xprt_inactive(). 735177633Sdfr */ 736177633Sdfr uio.uio_resid = 1000000000; 737177633Sdfr uio.uio_td = curthread; 738177633Sdfr m = NULL; 739177633Sdfr rcvflag = MSG_DONTWAIT; 740261047Smav error = soreceive(so, NULL, &uio, &m, NULL, &rcvflag); 741177633Sdfr 742177633Sdfr if (error == EWOULDBLOCK) { 743184588Sdfr /* 744184588Sdfr * We must re-test for readability after 745184588Sdfr * taking the lock to protect us in the case 746184588Sdfr * where a new packet arrives on the socket 747184588Sdfr * after our call to soreceive fails with 748261047Smav * EWOULDBLOCK. 749184588Sdfr */ 750261047Smav SOCKBUF_LOCK(&so->so_rcv); 751261047Smav if (!soreadable(so)) 752261053Smav xprt_inactive_self(xprt); 753261047Smav SOCKBUF_UNLOCK(&so->so_rcv); 754184588Sdfr sx_xunlock(&xprt->xp_lock); 755177633Sdfr return (FALSE); 756177633Sdfr } 757177633Sdfr 758177633Sdfr if (error) { 759261047Smav SOCKBUF_LOCK(&so->so_rcv); 760193436Srmacklem if (xprt->xp_upcallset) { 761193436Srmacklem xprt->xp_upcallset = 0; 762261047Smav soupcall_clear(so, SO_RCV); 763193436Srmacklem } 764261047Smav SOCKBUF_UNLOCK(&so->so_rcv); 765261053Smav xprt_inactive_self(xprt); 766177633Sdfr cd->strm_stat = XPRT_DIED; 767184588Sdfr sx_xunlock(&xprt->xp_lock); 768177633Sdfr return (FALSE); 769177633Sdfr } 770177633Sdfr 771177633Sdfr if (!m) { 772177633Sdfr /* 773177633Sdfr * EOF - the other end has closed the socket. 774177633Sdfr */ 775261053Smav xprt_inactive_self(xprt); 776177633Sdfr cd->strm_stat = XPRT_DIED; 777184588Sdfr sx_xunlock(&xprt->xp_lock); 778177633Sdfr return (FALSE); 779177633Sdfr } 780177633Sdfr 781177633Sdfr if (cd->mpending) 782177633Sdfr m_last(cd->mpending)->m_next = m; 783177633Sdfr else 784177633Sdfr cd->mpending = m; 785177633Sdfr } 786177633Sdfr} 787177633Sdfr 788177633Sdfrstatic bool_t 789244008Srmacklemsvc_vc_backchannel_recv(SVCXPRT *xprt, struct rpc_msg *msg, 790244008Srmacklem struct sockaddr **addrp, struct mbuf **mp) 791244008Srmacklem{ 792244008Srmacklem struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1; 793244008Srmacklem struct ct_data *ct; 794244008Srmacklem struct mbuf *m; 795244008Srmacklem XDR xdrs; 796244008Srmacklem 797244008Srmacklem sx_xlock(&xprt->xp_lock); 798244008Srmacklem ct = (struct ct_data *)xprt->xp_p2; 799244008Srmacklem if (ct == NULL) { 800244008Srmacklem sx_xunlock(&xprt->xp_lock); 801244008Srmacklem return (FALSE); 802244008Srmacklem } 803244008Srmacklem mtx_lock(&ct->ct_lock); 804244008Srmacklem m = cd->mreq; 805244008Srmacklem if (m == NULL) { 806261053Smav xprt_inactive_self(xprt); 807244008Srmacklem mtx_unlock(&ct->ct_lock); 808244008Srmacklem sx_xunlock(&xprt->xp_lock); 809244008Srmacklem return (FALSE); 810244008Srmacklem } 811244008Srmacklem cd->mreq = m->m_nextpkt; 812244008Srmacklem mtx_unlock(&ct->ct_lock); 813244008Srmacklem sx_xunlock(&xprt->xp_lock); 814244008Srmacklem 815244008Srmacklem xdrmbuf_create(&xdrs, m, XDR_DECODE); 816244008Srmacklem if (! xdr_callmsg(&xdrs, msg)) { 817244008Srmacklem XDR_DESTROY(&xdrs); 818244008Srmacklem return (FALSE); 819244008Srmacklem } 820244008Srmacklem *addrp = NULL; 821244008Srmacklem *mp = xdrmbuf_getall(&xdrs); 822244008Srmacklem XDR_DESTROY(&xdrs); 823244008Srmacklem return (TRUE); 824244008Srmacklem} 825244008Srmacklem 826244008Srmacklemstatic bool_t 827184588Sdfrsvc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg, 828261055Smav struct sockaddr *addr, struct mbuf *m, uint32_t *seq) 829177633Sdfr{ 830177633Sdfr XDR xdrs; 831177633Sdfr struct mbuf *mrep; 832184588Sdfr bool_t stat = TRUE; 833261055Smav int error, len; 834177633Sdfr 835177633Sdfr /* 836177633Sdfr * Leave space for record mark. 837177633Sdfr */ 838248195Sglebius mrep = m_gethdr(M_WAITOK, MT_DATA); 839177633Sdfr mrep->m_data += sizeof(uint32_t); 840177633Sdfr 841184588Sdfr xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); 842184588Sdfr 843184588Sdfr if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 844184588Sdfr msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 845184588Sdfr if (!xdr_replymsg(&xdrs, msg)) 846184588Sdfr stat = FALSE; 847184588Sdfr else 848184588Sdfr xdrmbuf_append(&xdrs, m); 849184588Sdfr } else { 850184588Sdfr stat = xdr_replymsg(&xdrs, msg); 851184588Sdfr } 852184588Sdfr 853184588Sdfr if (stat) { 854177633Sdfr m_fixhdr(mrep); 855177633Sdfr 856177633Sdfr /* 857177633Sdfr * Prepend a record marker containing the reply length. 858177633Sdfr */ 859243882Sglebius M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK); 860261055Smav len = mrep->m_pkthdr.len; 861177633Sdfr *mtod(mrep, uint32_t *) = 862261055Smav htonl(0x80000000 | (len - sizeof(uint32_t))); 863261055Smav atomic_add_acq_32(&xprt->xp_snd_cnt, len); 864177633Sdfr error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL, 865177633Sdfr 0, curthread); 866177633Sdfr if (!error) { 867261055Smav atomic_add_rel_32(&xprt->xp_snt_cnt, len); 868261055Smav if (seq) 869261055Smav *seq = xprt->xp_snd_cnt; 870177633Sdfr stat = TRUE; 871261055Smav } else 872261055Smav atomic_subtract_32(&xprt->xp_snd_cnt, len); 873177633Sdfr } else { 874177633Sdfr m_freem(mrep); 875177633Sdfr } 876177633Sdfr 877184588Sdfr XDR_DESTROY(&xdrs); 878177633Sdfr 879177633Sdfr return (stat); 880177633Sdfr} 881177633Sdfr 882177633Sdfrstatic bool_t 883244008Srmacklemsvc_vc_backchannel_reply(SVCXPRT *xprt, struct rpc_msg *msg, 884261055Smav struct sockaddr *addr, struct mbuf *m, uint32_t *seq) 885244008Srmacklem{ 886244008Srmacklem struct ct_data *ct; 887244008Srmacklem XDR xdrs; 888244008Srmacklem struct mbuf *mrep; 889244008Srmacklem bool_t stat = TRUE; 890244008Srmacklem int error; 891244008Srmacklem 892244008Srmacklem /* 893244008Srmacklem * Leave space for record mark. 894244008Srmacklem */ 895248195Sglebius mrep = m_gethdr(M_WAITOK, MT_DATA); 896244008Srmacklem mrep->m_data += sizeof(uint32_t); 897244008Srmacklem 898244008Srmacklem xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); 899244008Srmacklem 900244008Srmacklem if (msg->rm_reply.rp_stat == MSG_ACCEPTED && 901244008Srmacklem msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { 902244008Srmacklem if (!xdr_replymsg(&xdrs, msg)) 903244008Srmacklem stat = FALSE; 904244008Srmacklem else 905244008Srmacklem xdrmbuf_append(&xdrs, m); 906244008Srmacklem } else { 907244008Srmacklem stat = xdr_replymsg(&xdrs, msg); 908244008Srmacklem } 909244008Srmacklem 910244008Srmacklem if (stat) { 911244008Srmacklem m_fixhdr(mrep); 912244008Srmacklem 913244008Srmacklem /* 914244008Srmacklem * Prepend a record marker containing the reply length. 915244008Srmacklem */ 916244008Srmacklem M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK); 917244008Srmacklem *mtod(mrep, uint32_t *) = 918244008Srmacklem htonl(0x80000000 | (mrep->m_pkthdr.len 919244008Srmacklem - sizeof(uint32_t))); 920244008Srmacklem sx_xlock(&xprt->xp_lock); 921244008Srmacklem ct = (struct ct_data *)xprt->xp_p2; 922244008Srmacklem if (ct != NULL) 923244008Srmacklem error = sosend(ct->ct_socket, NULL, NULL, mrep, NULL, 924244008Srmacklem 0, curthread); 925244008Srmacklem else 926244008Srmacklem error = EPIPE; 927244008Srmacklem sx_xunlock(&xprt->xp_lock); 928244008Srmacklem if (!error) { 929244008Srmacklem stat = TRUE; 930244008Srmacklem } 931244008Srmacklem } else { 932244008Srmacklem m_freem(mrep); 933244008Srmacklem } 934244008Srmacklem 935244008Srmacklem XDR_DESTROY(&xdrs); 936244008Srmacklem 937244008Srmacklem return (stat); 938244008Srmacklem} 939244008Srmacklem 940244008Srmacklemstatic bool_t 941177633Sdfrsvc_vc_null() 942177633Sdfr{ 943177633Sdfr 944177633Sdfr return (FALSE); 945177633Sdfr} 946177633Sdfr 947193272Sjhbstatic int 948177633Sdfrsvc_vc_soupcall(struct socket *so, void *arg, int waitflag) 949177633Sdfr{ 950177633Sdfr SVCXPRT *xprt = (SVCXPRT *) arg; 951177633Sdfr 952261047Smav if (soreadable(xprt->xp_socket)) 953261047Smav xprt_active(xprt); 954193272Sjhb return (SU_OK); 955177633Sdfr} 956177633Sdfr 957177633Sdfr#if 0 958177633Sdfr/* 959177633Sdfr * Get the effective UID of the sending process. Used by rpcbind, keyserv 960177633Sdfr * and rpc.yppasswdd on AF_LOCAL. 961177633Sdfr */ 962177633Sdfrint 963177633Sdfr__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) { 964177633Sdfr int sock, ret; 965177633Sdfr gid_t egid; 966177633Sdfr uid_t euid; 967177633Sdfr struct sockaddr *sa; 968177633Sdfr 969177633Sdfr sock = transp->xp_fd; 970184588Sdfr sa = (struct sockaddr *)transp->xp_rtaddr; 971177633Sdfr if (sa->sa_family == AF_LOCAL) { 972177633Sdfr ret = getpeereid(sock, &euid, &egid); 973177633Sdfr if (ret == 0) 974177633Sdfr *uid = euid; 975177633Sdfr return (ret); 976177633Sdfr } else 977177633Sdfr return (-1); 978177633Sdfr} 979177633Sdfr#endif 980