1177633Sdfr/* $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 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 = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro"; 33177633Sdfrstatic char *sccsid = "@(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 34177633Sdfrstatic char sccsid3[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro"; 35177633Sdfr#endif 36177633Sdfr#include <sys/cdefs.h> 37177633Sdfr__FBSDID("$FreeBSD: stable/10/sys/rpc/clnt_vc.c 318675 2017-05-22 19:57:20Z rmacklem $"); 38177633Sdfr 39177633Sdfr/* 40177633Sdfr * clnt_tcp.c, Implements a TCP/IP based, client side RPC. 41177633Sdfr * 42177633Sdfr * Copyright (C) 1984, Sun Microsystems, Inc. 43177633Sdfr * 44177633Sdfr * TCP based RPC supports 'batched calls'. 45177633Sdfr * A sequence of calls may be batched-up in a send buffer. The rpc call 46177633Sdfr * return immediately to the client even though the call was not necessarily 47177633Sdfr * sent. The batching occurs if the results' xdr routine is NULL (0) AND 48177633Sdfr * the rpc timeout value is zero (see clnt.h, rpc). 49177633Sdfr * 50177633Sdfr * Clients should NOT casually batch calls that in fact return results; that is, 51177633Sdfr * the server side should be aware that a call is batched and not produce any 52177633Sdfr * return message. Batched calls that produce many result messages can 53177633Sdfr * deadlock (netlock) the client and the server.... 54177633Sdfr * 55177633Sdfr * Now go hang yourself. 56177633Sdfr */ 57177633Sdfr 58177633Sdfr#include <sys/param.h> 59177633Sdfr#include <sys/systm.h> 60318675Srmacklem#include <sys/kernel.h> 61177633Sdfr#include <sys/lock.h> 62177633Sdfr#include <sys/malloc.h> 63177633Sdfr#include <sys/mbuf.h> 64177633Sdfr#include <sys/mutex.h> 65177633Sdfr#include <sys/pcpu.h> 66177633Sdfr#include <sys/proc.h> 67184588Sdfr#include <sys/protosw.h> 68177633Sdfr#include <sys/socket.h> 69177633Sdfr#include <sys/socketvar.h> 70244008Srmacklem#include <sys/sx.h> 71177633Sdfr#include <sys/syslog.h> 72177633Sdfr#include <sys/time.h> 73177633Sdfr#include <sys/uio.h> 74196503Szec 75196503Szec#include <net/vnet.h> 76196503Szec 77184588Sdfr#include <netinet/tcp.h> 78177633Sdfr 79177633Sdfr#include <rpc/rpc.h> 80177685Sdfr#include <rpc/rpc_com.h> 81244008Srmacklem#include <rpc/krpc.h> 82177633Sdfr 83177633Sdfrstruct cmessage { 84177633Sdfr struct cmsghdr cmsg; 85177633Sdfr struct cmsgcred cmcred; 86177633Sdfr}; 87177633Sdfr 88180025Sdfrstatic enum clnt_stat clnt_vc_call(CLIENT *, struct rpc_callextra *, 89184588Sdfr rpcproc_t, struct mbuf *, struct mbuf **, struct timeval); 90177633Sdfrstatic void clnt_vc_geterr(CLIENT *, struct rpc_err *); 91177633Sdfrstatic bool_t clnt_vc_freeres(CLIENT *, xdrproc_t, void *); 92177633Sdfrstatic void clnt_vc_abort(CLIENT *); 93177633Sdfrstatic bool_t clnt_vc_control(CLIENT *, u_int, void *); 94184588Sdfrstatic void clnt_vc_close(CLIENT *); 95177633Sdfrstatic void clnt_vc_destroy(CLIENT *); 96177633Sdfrstatic bool_t time_not_ok(struct timeval *); 97193272Sjhbstatic int clnt_vc_soupcall(struct socket *so, void *arg, int waitflag); 98177633Sdfr 99177633Sdfrstatic struct clnt_ops clnt_vc_ops = { 100177633Sdfr .cl_call = clnt_vc_call, 101177633Sdfr .cl_abort = clnt_vc_abort, 102177633Sdfr .cl_geterr = clnt_vc_geterr, 103177633Sdfr .cl_freeres = clnt_vc_freeres, 104184588Sdfr .cl_close = clnt_vc_close, 105177633Sdfr .cl_destroy = clnt_vc_destroy, 106177633Sdfr .cl_control = clnt_vc_control 107177633Sdfr}; 108177633Sdfr 109193437Srmacklemstatic void clnt_vc_upcallsdone(struct ct_data *); 110193437Srmacklem 111318675Srmacklemstatic int fake_wchan; 112318675Srmacklem 113177633Sdfr/* 114177633Sdfr * Create a client handle for a connection. 115177633Sdfr * Default options are set, which the user can change using clnt_control()'s. 116177633Sdfr * The rpc/vc package does buffering similar to stdio, so the client 117177633Sdfr * must pick send and receive buffer sizes, 0 => use the default. 118177633Sdfr * NB: fd is copied into a private area. 119177633Sdfr * NB: The rpch->cl_auth is set null authentication. Caller may wish to 120177633Sdfr * set this something more useful. 121177633Sdfr * 122177633Sdfr * fd should be an open socket 123177633Sdfr */ 124177633SdfrCLIENT * 125177633Sdfrclnt_vc_create( 126177633Sdfr struct socket *so, /* open file descriptor */ 127177633Sdfr struct sockaddr *raddr, /* servers address */ 128177633Sdfr const rpcprog_t prog, /* program number */ 129177633Sdfr const rpcvers_t vers, /* version number */ 130177633Sdfr size_t sendsz, /* buffer recv size */ 131221127Srmacklem size_t recvsz, /* buffer send size */ 132221127Srmacklem int intrflag) /* interruptible */ 133177633Sdfr{ 134177633Sdfr CLIENT *cl; /* client handle */ 135177633Sdfr struct ct_data *ct = NULL; /* client handle */ 136177633Sdfr struct timeval now; 137177633Sdfr struct rpc_msg call_msg; 138177633Sdfr static uint32_t disrupt; 139177633Sdfr struct __rpc_sockinfo si; 140177633Sdfr XDR xdrs; 141221127Srmacklem int error, interrupted, one = 1, sleep_flag; 142184588Sdfr struct sockopt sopt; 143177633Sdfr 144177633Sdfr if (disrupt == 0) 145177633Sdfr disrupt = (uint32_t)(long)raddr; 146177633Sdfr 147177633Sdfr cl = (CLIENT *)mem_alloc(sizeof (*cl)); 148177633Sdfr ct = (struct ct_data *)mem_alloc(sizeof (*ct)); 149177633Sdfr 150177633Sdfr mtx_init(&ct->ct_lock, "ct->ct_lock", NULL, MTX_DEF); 151180025Sdfr ct->ct_threads = 0; 152180025Sdfr ct->ct_closing = FALSE; 153184588Sdfr ct->ct_closed = FALSE; 154193437Srmacklem ct->ct_upcallrefs = 0; 155177633Sdfr 156177633Sdfr if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) { 157177633Sdfr error = soconnect(so, raddr, curthread); 158180025Sdfr SOCK_LOCK(so); 159180025Sdfr interrupted = 0; 160221127Srmacklem sleep_flag = PSOCK; 161221127Srmacklem if (intrflag != 0) 162248255Sjhb sleep_flag |= PCATCH; 163180025Sdfr while ((so->so_state & SS_ISCONNECTING) 164180025Sdfr && so->so_error == 0) { 165180025Sdfr error = msleep(&so->so_timeo, SOCK_MTX(so), 166221127Srmacklem sleep_flag, "connec", 0); 167180025Sdfr if (error) { 168180025Sdfr if (error == EINTR || error == ERESTART) 169180025Sdfr interrupted = 1; 170180025Sdfr break; 171180025Sdfr } 172180025Sdfr } 173180025Sdfr if (error == 0) { 174180025Sdfr error = so->so_error; 175180025Sdfr so->so_error = 0; 176180025Sdfr } 177180025Sdfr SOCK_UNLOCK(so); 178177633Sdfr if (error) { 179180025Sdfr if (!interrupted) 180180025Sdfr so->so_state &= ~SS_ISCONNECTING; 181177633Sdfr rpc_createerr.cf_stat = RPC_SYSTEMERROR; 182177633Sdfr rpc_createerr.cf_error.re_errno = error; 183177633Sdfr goto err; 184177633Sdfr } 185177633Sdfr } 186177633Sdfr 187196503Szec if (!__rpc_socket2sockinfo(so, &si)) { 188177633Sdfr goto err; 189196503Szec } 190177633Sdfr 191184588Sdfr if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 192184588Sdfr bzero(&sopt, sizeof(sopt)); 193184588Sdfr sopt.sopt_dir = SOPT_SET; 194184588Sdfr sopt.sopt_level = SOL_SOCKET; 195184588Sdfr sopt.sopt_name = SO_KEEPALIVE; 196184588Sdfr sopt.sopt_val = &one; 197184588Sdfr sopt.sopt_valsize = sizeof(one); 198184588Sdfr sosetopt(so, &sopt); 199184588Sdfr } 200184588Sdfr 201184588Sdfr if (so->so_proto->pr_protocol == IPPROTO_TCP) { 202184588Sdfr bzero(&sopt, sizeof(sopt)); 203184588Sdfr sopt.sopt_dir = SOPT_SET; 204184588Sdfr sopt.sopt_level = IPPROTO_TCP; 205184588Sdfr sopt.sopt_name = TCP_NODELAY; 206184588Sdfr sopt.sopt_val = &one; 207184588Sdfr sopt.sopt_valsize = sizeof(one); 208184588Sdfr sosetopt(so, &sopt); 209184588Sdfr } 210184588Sdfr 211177633Sdfr ct->ct_closeit = FALSE; 212177633Sdfr 213177633Sdfr /* 214177633Sdfr * Set up private data struct 215177633Sdfr */ 216177633Sdfr ct->ct_socket = so; 217177633Sdfr ct->ct_wait.tv_sec = -1; 218177633Sdfr ct->ct_wait.tv_usec = -1; 219177633Sdfr memcpy(&ct->ct_addr, raddr, raddr->sa_len); 220177633Sdfr 221177633Sdfr /* 222177633Sdfr * Initialize call message 223177633Sdfr */ 224177633Sdfr getmicrotime(&now); 225177633Sdfr ct->ct_xid = ((uint32_t)++disrupt) ^ __RPC_GETXID(&now); 226177633Sdfr call_msg.rm_xid = ct->ct_xid; 227177633Sdfr call_msg.rm_direction = CALL; 228177633Sdfr call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 229177633Sdfr call_msg.rm_call.cb_prog = (uint32_t)prog; 230177633Sdfr call_msg.rm_call.cb_vers = (uint32_t)vers; 231177633Sdfr 232177633Sdfr /* 233177633Sdfr * pre-serialize the static part of the call msg and stash it away 234177633Sdfr */ 235177633Sdfr xdrmem_create(&xdrs, ct->ct_mcallc, MCALL_MSG_SIZE, 236177633Sdfr XDR_ENCODE); 237177633Sdfr if (! xdr_callhdr(&xdrs, &call_msg)) { 238177633Sdfr if (ct->ct_closeit) { 239177633Sdfr soclose(ct->ct_socket); 240177633Sdfr } 241177633Sdfr goto err; 242177633Sdfr } 243177633Sdfr ct->ct_mpos = XDR_GETPOS(&xdrs); 244177633Sdfr XDR_DESTROY(&xdrs); 245177633Sdfr ct->ct_waitchan = "rpcrecv"; 246177633Sdfr ct->ct_waitflag = 0; 247177633Sdfr 248177633Sdfr /* 249177633Sdfr * Create a client handle which uses xdrrec for serialization 250177633Sdfr * and authnone for authentication. 251177633Sdfr */ 252213756Srmacklem sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 253213756Srmacklem recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 254213756Srmacklem error = soreserve(ct->ct_socket, sendsz, recvsz); 255213756Srmacklem if (error != 0) { 256213756Srmacklem if (ct->ct_closeit) { 257213756Srmacklem soclose(ct->ct_socket); 258213756Srmacklem } 259213756Srmacklem goto err; 260213756Srmacklem } 261180025Sdfr cl->cl_refs = 1; 262177633Sdfr cl->cl_ops = &clnt_vc_ops; 263177633Sdfr cl->cl_private = ct; 264177633Sdfr cl->cl_auth = authnone_create(); 265177633Sdfr 266177633Sdfr SOCKBUF_LOCK(&ct->ct_socket->so_rcv); 267193272Sjhb soupcall_set(ct->ct_socket, SO_RCV, clnt_vc_soupcall, ct); 268177633Sdfr SOCKBUF_UNLOCK(&ct->ct_socket->so_rcv); 269177633Sdfr 270177633Sdfr ct->ct_record = NULL; 271177633Sdfr ct->ct_record_resid = 0; 272177633Sdfr TAILQ_INIT(&ct->ct_pending); 273177633Sdfr return (cl); 274177633Sdfr 275177633Sdfrerr: 276303692Sngie mtx_destroy(&ct->ct_lock); 277303692Sngie mem_free(ct, sizeof (struct ct_data)); 278303692Sngie mem_free(cl, sizeof (CLIENT)); 279303692Sngie 280177633Sdfr return ((CLIENT *)NULL); 281177633Sdfr} 282177633Sdfr 283177633Sdfrstatic enum clnt_stat 284177633Sdfrclnt_vc_call( 285184588Sdfr CLIENT *cl, /* client handle */ 286184588Sdfr struct rpc_callextra *ext, /* call metadata */ 287184588Sdfr rpcproc_t proc, /* procedure number */ 288184588Sdfr struct mbuf *args, /* pointer to args */ 289184588Sdfr struct mbuf **resultsp, /* pointer to results */ 290184588Sdfr struct timeval utimeout) 291177633Sdfr{ 292177633Sdfr struct ct_data *ct = (struct ct_data *) cl->cl_private; 293180025Sdfr AUTH *auth; 294184588Sdfr struct rpc_err *errp; 295184588Sdfr enum clnt_stat stat; 296177633Sdfr XDR xdrs; 297177633Sdfr struct rpc_msg reply_msg; 298177633Sdfr bool_t ok; 299177633Sdfr int nrefreshes = 2; /* number of times to refresh cred */ 300177633Sdfr struct timeval timeout; 301177633Sdfr uint32_t xid; 302184588Sdfr struct mbuf *mreq = NULL, *results; 303180025Sdfr struct ct_request *cr; 304318675Srmacklem int error, trycnt; 305177633Sdfr 306180025Sdfr cr = malloc(sizeof(struct ct_request), M_RPC, M_WAITOK); 307180025Sdfr 308177633Sdfr mtx_lock(&ct->ct_lock); 309177633Sdfr 310184588Sdfr if (ct->ct_closing || ct->ct_closed) { 311180025Sdfr mtx_unlock(&ct->ct_lock); 312180025Sdfr free(cr, M_RPC); 313180025Sdfr return (RPC_CANTSEND); 314180025Sdfr } 315180025Sdfr ct->ct_threads++; 316177633Sdfr 317184588Sdfr if (ext) { 318180025Sdfr auth = ext->rc_auth; 319184588Sdfr errp = &ext->rc_err; 320184588Sdfr } else { 321180025Sdfr auth = cl->cl_auth; 322184588Sdfr errp = &ct->ct_error; 323184588Sdfr } 324180025Sdfr 325180025Sdfr cr->cr_mrep = NULL; 326180025Sdfr cr->cr_error = 0; 327180025Sdfr 328177633Sdfr if (ct->ct_wait.tv_usec == -1) { 329177633Sdfr timeout = utimeout; /* use supplied timeout */ 330177633Sdfr } else { 331177633Sdfr timeout = ct->ct_wait; /* use default timeout */ 332177633Sdfr } 333177633Sdfr 334318675Srmacklem /* 335318675Srmacklem * After 15sec of looping, allow it to return RPC_CANTSEND, which will 336318675Srmacklem * cause the clnt_reconnect layer to create a new TCP connection. 337318675Srmacklem */ 338318675Srmacklem trycnt = 15 * hz; 339177633Sdfrcall_again: 340177633Sdfr mtx_assert(&ct->ct_lock, MA_OWNED); 341318675Srmacklem if (ct->ct_closing || ct->ct_closed) { 342318675Srmacklem ct->ct_threads--; 343318675Srmacklem wakeup(ct); 344318675Srmacklem mtx_unlock(&ct->ct_lock); 345318675Srmacklem free(cr, M_RPC); 346318675Srmacklem return (RPC_CANTSEND); 347318675Srmacklem } 348177633Sdfr 349177633Sdfr ct->ct_xid++; 350177633Sdfr xid = ct->ct_xid; 351177633Sdfr 352177633Sdfr mtx_unlock(&ct->ct_lock); 353177633Sdfr 354177633Sdfr /* 355177633Sdfr * Leave space to pre-pend the record mark. 356177633Sdfr */ 357248195Sglebius mreq = m_gethdr(M_WAITOK, MT_DATA); 358177633Sdfr mreq->m_data += sizeof(uint32_t); 359184588Sdfr KASSERT(ct->ct_mpos + sizeof(uint32_t) <= MHLEN, 360184588Sdfr ("RPC header too big")); 361184588Sdfr bcopy(ct->ct_mcallc, mreq->m_data, ct->ct_mpos); 362184588Sdfr mreq->m_len = ct->ct_mpos; 363177633Sdfr 364177633Sdfr /* 365177633Sdfr * The XID is the first thing in the request. 366177633Sdfr */ 367177633Sdfr *mtod(mreq, uint32_t *) = htonl(xid); 368177633Sdfr 369177633Sdfr xdrmbuf_create(&xdrs, mreq, XDR_ENCODE); 370177633Sdfr 371184588Sdfr errp->re_status = stat = RPC_SUCCESS; 372177633Sdfr 373177633Sdfr if ((! XDR_PUTINT32(&xdrs, &proc)) || 374184588Sdfr (! AUTH_MARSHALL(auth, xid, &xdrs, 375184588Sdfr m_copym(args, 0, M_COPYALL, M_WAITOK)))) { 376184588Sdfr errp->re_status = stat = RPC_CANTENCODEARGS; 377180025Sdfr mtx_lock(&ct->ct_lock); 378180025Sdfr goto out; 379177633Sdfr } 380184588Sdfr mreq->m_pkthdr.len = m_length(mreq, NULL); 381177633Sdfr 382177633Sdfr /* 383177633Sdfr * Prepend a record marker containing the packet length. 384177633Sdfr */ 385243882Sglebius M_PREPEND(mreq, sizeof(uint32_t), M_WAITOK); 386177633Sdfr *mtod(mreq, uint32_t *) = 387177633Sdfr htonl(0x80000000 | (mreq->m_pkthdr.len - sizeof(uint32_t))); 388177633Sdfr 389180025Sdfr cr->cr_xid = xid; 390177633Sdfr mtx_lock(&ct->ct_lock); 391199053Srmacklem /* 392199053Srmacklem * Check to see if the other end has already started to close down 393199053Srmacklem * the connection. The upcall will have set ct_error.re_status 394199053Srmacklem * to RPC_CANTRECV if this is the case. 395199053Srmacklem * If the other end starts to close down the connection after this 396199053Srmacklem * point, it will be detected later when cr_error is checked, 397199053Srmacklem * since the request is in the ct_pending queue. 398199053Srmacklem */ 399199053Srmacklem if (ct->ct_error.re_status == RPC_CANTRECV) { 400199053Srmacklem if (errp != &ct->ct_error) { 401199053Srmacklem errp->re_errno = ct->ct_error.re_errno; 402199053Srmacklem errp->re_status = RPC_CANTRECV; 403199053Srmacklem } 404199053Srmacklem stat = RPC_CANTRECV; 405199053Srmacklem goto out; 406199053Srmacklem } 407180025Sdfr TAILQ_INSERT_TAIL(&ct->ct_pending, cr, cr_link); 408177633Sdfr mtx_unlock(&ct->ct_lock); 409177633Sdfr 410177633Sdfr /* 411177633Sdfr * sosend consumes mreq. 412177633Sdfr */ 413177633Sdfr error = sosend(ct->ct_socket, NULL, NULL, mreq, NULL, 0, curthread); 414177633Sdfr mreq = NULL; 415318675Srmacklem if (error == EMSGSIZE || (error == ERESTART && 416318675Srmacklem (ct->ct_waitflag & PCATCH) == 0 && trycnt-- > 0)) { 417184588Sdfr SOCKBUF_LOCK(&ct->ct_socket->so_snd); 418184588Sdfr sbwait(&ct->ct_socket->so_snd); 419184588Sdfr SOCKBUF_UNLOCK(&ct->ct_socket->so_snd); 420184588Sdfr AUTH_VALIDATE(auth, xid, NULL, NULL); 421184588Sdfr mtx_lock(&ct->ct_lock); 422184588Sdfr TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 423318675Srmacklem /* Sleep for 1 clock tick before trying the sosend() again. */ 424318675Srmacklem msleep(&fake_wchan, &ct->ct_lock, 0, "rpclpsnd", 1); 425184588Sdfr goto call_again; 426184588Sdfr } 427177633Sdfr 428184588Sdfr reply_msg.acpted_rply.ar_verf.oa_flavor = AUTH_NULL; 429184588Sdfr reply_msg.acpted_rply.ar_verf.oa_base = cr->cr_verf; 430184588Sdfr reply_msg.acpted_rply.ar_verf.oa_length = 0; 431184588Sdfr reply_msg.acpted_rply.ar_results.where = NULL; 432184588Sdfr reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; 433177633Sdfr 434177633Sdfr mtx_lock(&ct->ct_lock); 435177633Sdfr if (error) { 436180025Sdfr TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 437184588Sdfr errp->re_errno = error; 438184588Sdfr errp->re_status = stat = RPC_CANTSEND; 439177633Sdfr goto out; 440177633Sdfr } 441177633Sdfr 442177633Sdfr /* 443177633Sdfr * Check to see if we got an upcall while waiting for the 444177633Sdfr * lock. In both these cases, the request has been removed 445177633Sdfr * from ct->ct_pending. 446177633Sdfr */ 447180025Sdfr if (cr->cr_error) { 448180025Sdfr TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 449184588Sdfr errp->re_errno = cr->cr_error; 450184588Sdfr errp->re_status = stat = RPC_CANTRECV; 451177633Sdfr goto out; 452177633Sdfr } 453180025Sdfr if (cr->cr_mrep) { 454180025Sdfr TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 455177633Sdfr goto got_reply; 456177633Sdfr } 457177633Sdfr 458177633Sdfr /* 459177633Sdfr * Hack to provide rpc-based message passing 460177633Sdfr */ 461177633Sdfr if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 462180025Sdfr TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 463184588Sdfr errp->re_status = stat = RPC_TIMEDOUT; 464177633Sdfr goto out; 465177633Sdfr } 466177633Sdfr 467180025Sdfr error = msleep(cr, &ct->ct_lock, ct->ct_waitflag, ct->ct_waitchan, 468177633Sdfr tvtohz(&timeout)); 469177633Sdfr 470180025Sdfr TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 471180025Sdfr 472177633Sdfr if (error) { 473177633Sdfr /* 474177633Sdfr * The sleep returned an error so our request is still 475177633Sdfr * on the list. Turn the error code into an 476177633Sdfr * appropriate client status. 477177633Sdfr */ 478184588Sdfr errp->re_errno = error; 479177633Sdfr switch (error) { 480177633Sdfr case EINTR: 481184588Sdfr stat = RPC_INTR; 482177633Sdfr break; 483177633Sdfr case EWOULDBLOCK: 484184588Sdfr stat = RPC_TIMEDOUT; 485177633Sdfr break; 486177633Sdfr default: 487184588Sdfr stat = RPC_CANTRECV; 488177633Sdfr } 489184588Sdfr errp->re_status = stat; 490177633Sdfr goto out; 491177633Sdfr } else { 492177633Sdfr /* 493177633Sdfr * We were woken up by the upcall. If the 494177633Sdfr * upcall had a receive error, report that, 495177633Sdfr * otherwise we have a reply. 496177633Sdfr */ 497180025Sdfr if (cr->cr_error) { 498184588Sdfr errp->re_errno = cr->cr_error; 499184588Sdfr errp->re_status = stat = RPC_CANTRECV; 500177633Sdfr goto out; 501177633Sdfr } 502177633Sdfr } 503177633Sdfr 504177633Sdfrgot_reply: 505177633Sdfr /* 506177633Sdfr * Now decode and validate the response. We need to drop the 507177633Sdfr * lock since xdr_replymsg may end up sleeping in malloc. 508177633Sdfr */ 509177633Sdfr mtx_unlock(&ct->ct_lock); 510177633Sdfr 511184588Sdfr if (ext && ext->rc_feedback) 512184588Sdfr ext->rc_feedback(FEEDBACK_OK, proc, ext->rc_feedback_arg); 513184588Sdfr 514180025Sdfr xdrmbuf_create(&xdrs, cr->cr_mrep, XDR_DECODE); 515177633Sdfr ok = xdr_replymsg(&xdrs, &reply_msg); 516180025Sdfr cr->cr_mrep = NULL; 517177633Sdfr 518177633Sdfr if (ok) { 519177633Sdfr if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && 520184588Sdfr (reply_msg.acpted_rply.ar_stat == SUCCESS)) 521184588Sdfr errp->re_status = stat = RPC_SUCCESS; 522177633Sdfr else 523184588Sdfr stat = _seterr_reply(&reply_msg, errp); 524177633Sdfr 525184588Sdfr if (stat == RPC_SUCCESS) { 526184588Sdfr results = xdrmbuf_getall(&xdrs); 527184588Sdfr if (!AUTH_VALIDATE(auth, xid, 528184588Sdfr &reply_msg.acpted_rply.ar_verf, 529184588Sdfr &results)) { 530184588Sdfr errp->re_status = stat = RPC_AUTHERROR; 531184588Sdfr errp->re_why = AUTH_INVALIDRESP; 532184588Sdfr } else { 533184588Sdfr KASSERT(results, 534184588Sdfr ("auth validated but no result")); 535184588Sdfr *resultsp = results; 536177633Sdfr } 537177633Sdfr } /* end successful completion */ 538177633Sdfr /* 539177633Sdfr * If unsuccesful AND error is an authentication error 540177633Sdfr * then refresh credentials and try again, else break 541177633Sdfr */ 542184588Sdfr else if (stat == RPC_AUTHERROR) 543177633Sdfr /* maybe our credentials need to be refreshed ... */ 544177633Sdfr if (nrefreshes > 0 && 545184588Sdfr AUTH_REFRESH(auth, &reply_msg)) { 546177633Sdfr nrefreshes--; 547184588Sdfr XDR_DESTROY(&xdrs); 548184588Sdfr mtx_lock(&ct->ct_lock); 549177633Sdfr goto call_again; 550177633Sdfr } 551177633Sdfr /* end of unsuccessful completion */ 552177633Sdfr } /* end of valid reply message */ 553177633Sdfr else { 554184588Sdfr errp->re_status = stat = RPC_CANTDECODERES; 555177633Sdfr } 556184588Sdfr XDR_DESTROY(&xdrs); 557184588Sdfr mtx_lock(&ct->ct_lock); 558177633Sdfrout: 559177633Sdfr mtx_assert(&ct->ct_lock, MA_OWNED); 560177633Sdfr 561184588Sdfr KASSERT(stat != RPC_SUCCESS || *resultsp, 562184588Sdfr ("RPC_SUCCESS without reply")); 563184588Sdfr 564177633Sdfr if (mreq) 565177633Sdfr m_freem(mreq); 566180025Sdfr if (cr->cr_mrep) 567180025Sdfr m_freem(cr->cr_mrep); 568177633Sdfr 569180025Sdfr ct->ct_threads--; 570180025Sdfr if (ct->ct_closing) 571180025Sdfr wakeup(ct); 572180025Sdfr 573177633Sdfr mtx_unlock(&ct->ct_lock); 574180025Sdfr 575184588Sdfr if (auth && stat != RPC_SUCCESS) 576184588Sdfr AUTH_VALIDATE(auth, xid, NULL, NULL); 577184588Sdfr 578180025Sdfr free(cr, M_RPC); 579180025Sdfr 580184588Sdfr return (stat); 581177633Sdfr} 582177633Sdfr 583177633Sdfrstatic void 584177633Sdfrclnt_vc_geterr(CLIENT *cl, struct rpc_err *errp) 585177633Sdfr{ 586177633Sdfr struct ct_data *ct = (struct ct_data *) cl->cl_private; 587177633Sdfr 588177633Sdfr *errp = ct->ct_error; 589177633Sdfr} 590177633Sdfr 591177633Sdfrstatic bool_t 592177633Sdfrclnt_vc_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr) 593177633Sdfr{ 594177633Sdfr XDR xdrs; 595177633Sdfr bool_t dummy; 596177633Sdfr 597177633Sdfr xdrs.x_op = XDR_FREE; 598177633Sdfr dummy = (*xdr_res)(&xdrs, res_ptr); 599177633Sdfr 600177633Sdfr return (dummy); 601177633Sdfr} 602177633Sdfr 603177633Sdfr/*ARGSUSED*/ 604177633Sdfrstatic void 605177633Sdfrclnt_vc_abort(CLIENT *cl) 606177633Sdfr{ 607177633Sdfr} 608177633Sdfr 609177633Sdfrstatic bool_t 610177633Sdfrclnt_vc_control(CLIENT *cl, u_int request, void *info) 611177633Sdfr{ 612177633Sdfr struct ct_data *ct = (struct ct_data *)cl->cl_private; 613177633Sdfr void *infop = info; 614244008Srmacklem SVCXPRT *xprt; 615177633Sdfr 616177633Sdfr mtx_lock(&ct->ct_lock); 617177633Sdfr 618177633Sdfr switch (request) { 619177633Sdfr case CLSET_FD_CLOSE: 620177633Sdfr ct->ct_closeit = TRUE; 621177633Sdfr mtx_unlock(&ct->ct_lock); 622177633Sdfr return (TRUE); 623177633Sdfr case CLSET_FD_NCLOSE: 624177633Sdfr ct->ct_closeit = FALSE; 625177633Sdfr mtx_unlock(&ct->ct_lock); 626177633Sdfr return (TRUE); 627177633Sdfr default: 628177633Sdfr break; 629177633Sdfr } 630177633Sdfr 631177633Sdfr /* for other requests which use info */ 632177633Sdfr if (info == NULL) { 633177633Sdfr mtx_unlock(&ct->ct_lock); 634177633Sdfr return (FALSE); 635177633Sdfr } 636177633Sdfr switch (request) { 637177633Sdfr case CLSET_TIMEOUT: 638177633Sdfr if (time_not_ok((struct timeval *)info)) { 639177633Sdfr mtx_unlock(&ct->ct_lock); 640177633Sdfr return (FALSE); 641177633Sdfr } 642177633Sdfr ct->ct_wait = *(struct timeval *)infop; 643177633Sdfr break; 644177633Sdfr case CLGET_TIMEOUT: 645177633Sdfr *(struct timeval *)infop = ct->ct_wait; 646177633Sdfr break; 647177633Sdfr case CLGET_SERVER_ADDR: 648177633Sdfr (void) memcpy(info, &ct->ct_addr, (size_t)ct->ct_addr.ss_len); 649177633Sdfr break; 650177633Sdfr case CLGET_SVC_ADDR: 651177633Sdfr /* 652177633Sdfr * Slightly different semantics to userland - we use 653177633Sdfr * sockaddr instead of netbuf. 654177633Sdfr */ 655177633Sdfr memcpy(info, &ct->ct_addr, ct->ct_addr.ss_len); 656177633Sdfr break; 657177633Sdfr case CLSET_SVC_ADDR: /* set to new address */ 658177633Sdfr mtx_unlock(&ct->ct_lock); 659177633Sdfr return (FALSE); 660177633Sdfr case CLGET_XID: 661177633Sdfr *(uint32_t *)info = ct->ct_xid; 662177633Sdfr break; 663177633Sdfr case CLSET_XID: 664177633Sdfr /* This will set the xid of the NEXT call */ 665177633Sdfr /* decrement by 1 as clnt_vc_call() increments once */ 666177633Sdfr ct->ct_xid = *(uint32_t *)info - 1; 667177633Sdfr break; 668177633Sdfr case CLGET_VERS: 669177633Sdfr /* 670177633Sdfr * This RELIES on the information that, in the call body, 671177633Sdfr * the version number field is the fifth field from the 672177633Sdfr * begining of the RPC header. MUST be changed if the 673177633Sdfr * call_struct is changed 674177633Sdfr */ 675177633Sdfr *(uint32_t *)info = 676177633Sdfr ntohl(*(uint32_t *)(void *)(ct->ct_mcallc + 677177633Sdfr 4 * BYTES_PER_XDR_UNIT)); 678177633Sdfr break; 679177633Sdfr 680177633Sdfr case CLSET_VERS: 681177633Sdfr *(uint32_t *)(void *)(ct->ct_mcallc + 682177633Sdfr 4 * BYTES_PER_XDR_UNIT) = 683177633Sdfr htonl(*(uint32_t *)info); 684177633Sdfr break; 685177633Sdfr 686177633Sdfr case CLGET_PROG: 687177633Sdfr /* 688177633Sdfr * This RELIES on the information that, in the call body, 689177633Sdfr * the program number field is the fourth field from the 690177633Sdfr * begining of the RPC header. MUST be changed if the 691177633Sdfr * call_struct is changed 692177633Sdfr */ 693177633Sdfr *(uint32_t *)info = 694177633Sdfr ntohl(*(uint32_t *)(void *)(ct->ct_mcallc + 695177633Sdfr 3 * BYTES_PER_XDR_UNIT)); 696177633Sdfr break; 697177633Sdfr 698177633Sdfr case CLSET_PROG: 699177633Sdfr *(uint32_t *)(void *)(ct->ct_mcallc + 700177633Sdfr 3 * BYTES_PER_XDR_UNIT) = 701177633Sdfr htonl(*(uint32_t *)info); 702177633Sdfr break; 703177633Sdfr 704177633Sdfr case CLSET_WAITCHAN: 705184588Sdfr ct->ct_waitchan = (const char *)info; 706177633Sdfr break; 707177633Sdfr 708177633Sdfr case CLGET_WAITCHAN: 709177633Sdfr *(const char **) info = ct->ct_waitchan; 710177633Sdfr break; 711177633Sdfr 712177633Sdfr case CLSET_INTERRUPTIBLE: 713177633Sdfr if (*(int *) info) 714248255Sjhb ct->ct_waitflag = PCATCH; 715177633Sdfr else 716177633Sdfr ct->ct_waitflag = 0; 717177633Sdfr break; 718177633Sdfr 719177633Sdfr case CLGET_INTERRUPTIBLE: 720177633Sdfr if (ct->ct_waitflag) 721177633Sdfr *(int *) info = TRUE; 722177633Sdfr else 723177633Sdfr *(int *) info = FALSE; 724177633Sdfr break; 725177633Sdfr 726244008Srmacklem case CLSET_BACKCHANNEL: 727244008Srmacklem xprt = (SVCXPRT *)info; 728244008Srmacklem if (ct->ct_backchannelxprt == NULL) { 729244008Srmacklem xprt->xp_p2 = ct; 730244008Srmacklem ct->ct_backchannelxprt = xprt; 731244008Srmacklem } 732244008Srmacklem break; 733244008Srmacklem 734177633Sdfr default: 735177633Sdfr mtx_unlock(&ct->ct_lock); 736177633Sdfr return (FALSE); 737177633Sdfr } 738177633Sdfr 739177633Sdfr mtx_unlock(&ct->ct_lock); 740177633Sdfr return (TRUE); 741177633Sdfr} 742177633Sdfr 743177633Sdfrstatic void 744184588Sdfrclnt_vc_close(CLIENT *cl) 745177633Sdfr{ 746177633Sdfr struct ct_data *ct = (struct ct_data *) cl->cl_private; 747180025Sdfr struct ct_request *cr; 748177633Sdfr 749177633Sdfr mtx_lock(&ct->ct_lock); 750177633Sdfr 751184588Sdfr if (ct->ct_closed) { 752184588Sdfr mtx_unlock(&ct->ct_lock); 753184588Sdfr return; 754184588Sdfr } 755184588Sdfr 756184588Sdfr if (ct->ct_closing) { 757184588Sdfr while (ct->ct_closing) 758184588Sdfr msleep(ct, &ct->ct_lock, 0, "rpcclose", 0); 759184588Sdfr KASSERT(ct->ct_closed, ("client should be closed")); 760184588Sdfr mtx_unlock(&ct->ct_lock); 761184588Sdfr return; 762184588Sdfr } 763184588Sdfr 764177633Sdfr if (ct->ct_socket) { 765193272Sjhb ct->ct_closing = TRUE; 766193272Sjhb mtx_unlock(&ct->ct_lock); 767193272Sjhb 768177633Sdfr SOCKBUF_LOCK(&ct->ct_socket->so_rcv); 769193272Sjhb soupcall_clear(ct->ct_socket, SO_RCV); 770193437Srmacklem clnt_vc_upcallsdone(ct); 771177633Sdfr SOCKBUF_UNLOCK(&ct->ct_socket->so_rcv); 772177633Sdfr 773180025Sdfr /* 774180025Sdfr * Abort any pending requests and wait until everyone 775180025Sdfr * has finished with clnt_vc_call. 776180025Sdfr */ 777193272Sjhb mtx_lock(&ct->ct_lock); 778180025Sdfr TAILQ_FOREACH(cr, &ct->ct_pending, cr_link) { 779180025Sdfr cr->cr_xid = 0; 780180025Sdfr cr->cr_error = ESHUTDOWN; 781180025Sdfr wakeup(cr); 782180025Sdfr } 783177633Sdfr 784180025Sdfr while (ct->ct_threads) 785180025Sdfr msleep(ct, &ct->ct_lock, 0, "rpcclose", 0); 786184588Sdfr } 787180025Sdfr 788184588Sdfr ct->ct_closing = FALSE; 789184588Sdfr ct->ct_closed = TRUE; 790184588Sdfr mtx_unlock(&ct->ct_lock); 791184588Sdfr wakeup(ct); 792184588Sdfr} 793184588Sdfr 794184588Sdfrstatic void 795184588Sdfrclnt_vc_destroy(CLIENT *cl) 796184588Sdfr{ 797184588Sdfr struct ct_data *ct = (struct ct_data *) cl->cl_private; 798184588Sdfr struct socket *so = NULL; 799244008Srmacklem SVCXPRT *xprt; 800184588Sdfr 801184588Sdfr clnt_vc_close(cl); 802184588Sdfr 803184588Sdfr mtx_lock(&ct->ct_lock); 804244008Srmacklem xprt = ct->ct_backchannelxprt; 805244008Srmacklem ct->ct_backchannelxprt = NULL; 806244008Srmacklem if (xprt != NULL) { 807244008Srmacklem mtx_unlock(&ct->ct_lock); /* To avoid a LOR. */ 808244008Srmacklem sx_xlock(&xprt->xp_lock); 809244008Srmacklem mtx_lock(&ct->ct_lock); 810244008Srmacklem xprt->xp_p2 = NULL; 811317473Srmacklem sx_xunlock(&xprt->xp_lock); 812244008Srmacklem } 813184588Sdfr 814184588Sdfr if (ct->ct_socket) { 815177633Sdfr if (ct->ct_closeit) { 816177633Sdfr so = ct->ct_socket; 817177633Sdfr } 818177633Sdfr } 819177633Sdfr 820177633Sdfr mtx_unlock(&ct->ct_lock); 821177633Sdfr 822177633Sdfr mtx_destroy(&ct->ct_lock); 823177633Sdfr if (so) { 824177633Sdfr soshutdown(so, SHUT_WR); 825177633Sdfr soclose(so); 826177633Sdfr } 827177633Sdfr mem_free(ct, sizeof(struct ct_data)); 828241143Spfg if (cl->cl_netid && cl->cl_netid[0]) 829241143Spfg mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); 830241143Spfg if (cl->cl_tp && cl->cl_tp[0]) 831241143Spfg mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); 832177633Sdfr mem_free(cl, sizeof(CLIENT)); 833177633Sdfr} 834177633Sdfr 835177633Sdfr/* 836177633Sdfr * Make sure that the time is not garbage. -1 value is disallowed. 837177633Sdfr * Note this is different from time_not_ok in clnt_dg.c 838177633Sdfr */ 839177633Sdfrstatic bool_t 840177633Sdfrtime_not_ok(struct timeval *t) 841177633Sdfr{ 842177633Sdfr return (t->tv_sec <= -1 || t->tv_sec > 100000000 || 843177633Sdfr t->tv_usec <= -1 || t->tv_usec > 1000000); 844177633Sdfr} 845177633Sdfr 846193272Sjhbint 847177633Sdfrclnt_vc_soupcall(struct socket *so, void *arg, int waitflag) 848177633Sdfr{ 849177633Sdfr struct ct_data *ct = (struct ct_data *) arg; 850177633Sdfr struct uio uio; 851244008Srmacklem struct mbuf *m, *m2; 852177633Sdfr struct ct_request *cr; 853177633Sdfr int error, rcvflag, foundreq; 854244008Srmacklem uint32_t xid_plus_direction[2], header; 855184588Sdfr bool_t do_read; 856244008Srmacklem SVCXPRT *xprt; 857244008Srmacklem struct cf_conn *cd; 858177633Sdfr 859244008Srmacklem CTASSERT(sizeof(xid_plus_direction) == 2 * sizeof(uint32_t)); 860193437Srmacklem ct->ct_upcallrefs++; 861177633Sdfr uio.uio_td = curthread; 862177633Sdfr do { 863177633Sdfr /* 864177633Sdfr * If ct_record_resid is zero, we are waiting for a 865177633Sdfr * record mark. 866177633Sdfr */ 867177633Sdfr if (ct->ct_record_resid == 0) { 868177633Sdfr 869177633Sdfr /* 870177633Sdfr * Make sure there is either a whole record 871177633Sdfr * mark in the buffer or there is some other 872177633Sdfr * error condition 873177633Sdfr */ 874177633Sdfr do_read = FALSE; 875177633Sdfr if (so->so_rcv.sb_cc >= sizeof(uint32_t) 876177633Sdfr || (so->so_rcv.sb_state & SBS_CANTRCVMORE) 877177633Sdfr || so->so_error) 878177633Sdfr do_read = TRUE; 879177633Sdfr 880177633Sdfr if (!do_read) 881193437Srmacklem break; 882177633Sdfr 883193272Sjhb SOCKBUF_UNLOCK(&so->so_rcv); 884177633Sdfr uio.uio_resid = sizeof(uint32_t); 885177633Sdfr m = NULL; 886177633Sdfr rcvflag = MSG_DONTWAIT | MSG_SOCALLBCK; 887177633Sdfr error = soreceive(so, NULL, &uio, &m, NULL, &rcvflag); 888193272Sjhb SOCKBUF_LOCK(&so->so_rcv); 889177633Sdfr 890177633Sdfr if (error == EWOULDBLOCK) 891177633Sdfr break; 892177633Sdfr 893177633Sdfr /* 894177633Sdfr * If there was an error, wake up all pending 895177633Sdfr * requests. 896177633Sdfr */ 897177633Sdfr if (error || uio.uio_resid > 0) { 898177633Sdfr wakeup_all: 899177633Sdfr mtx_lock(&ct->ct_lock); 900177633Sdfr if (!error) { 901177633Sdfr /* 902177633Sdfr * We must have got EOF trying 903177633Sdfr * to read from the stream. 904177633Sdfr */ 905177633Sdfr error = ECONNRESET; 906177633Sdfr } 907177633Sdfr ct->ct_error.re_status = RPC_CANTRECV; 908177633Sdfr ct->ct_error.re_errno = error; 909177633Sdfr TAILQ_FOREACH(cr, &ct->ct_pending, cr_link) { 910177633Sdfr cr->cr_error = error; 911177633Sdfr wakeup(cr); 912177633Sdfr } 913177633Sdfr mtx_unlock(&ct->ct_lock); 914177633Sdfr break; 915177633Sdfr } 916217242Srmacklem m_copydata(m, 0, sizeof(uint32_t), (char *)&header); 917177633Sdfr header = ntohl(header); 918177633Sdfr ct->ct_record = NULL; 919177633Sdfr ct->ct_record_resid = header & 0x7fffffff; 920177633Sdfr ct->ct_record_eor = ((header & 0x80000000) != 0); 921177633Sdfr m_freem(m); 922177633Sdfr } else { 923177633Sdfr /* 924184588Sdfr * Wait until the socket has the whole record 925184588Sdfr * buffered. 926184588Sdfr */ 927184588Sdfr do_read = FALSE; 928184588Sdfr if (so->so_rcv.sb_cc >= ct->ct_record_resid 929184588Sdfr || (so->so_rcv.sb_state & SBS_CANTRCVMORE) 930184588Sdfr || so->so_error) 931184588Sdfr do_read = TRUE; 932184588Sdfr 933184588Sdfr if (!do_read) 934193437Srmacklem break; 935184588Sdfr 936184588Sdfr /* 937177633Sdfr * We have the record mark. Read as much as 938177633Sdfr * the socket has buffered up to the end of 939177633Sdfr * this record. 940177633Sdfr */ 941193272Sjhb SOCKBUF_UNLOCK(&so->so_rcv); 942177633Sdfr uio.uio_resid = ct->ct_record_resid; 943177633Sdfr m = NULL; 944177633Sdfr rcvflag = MSG_DONTWAIT | MSG_SOCALLBCK; 945177633Sdfr error = soreceive(so, NULL, &uio, &m, NULL, &rcvflag); 946193272Sjhb SOCKBUF_LOCK(&so->so_rcv); 947177633Sdfr 948177633Sdfr if (error == EWOULDBLOCK) 949177633Sdfr break; 950177633Sdfr 951177633Sdfr if (error || uio.uio_resid == ct->ct_record_resid) 952177633Sdfr goto wakeup_all; 953177633Sdfr 954177633Sdfr /* 955177633Sdfr * If we have part of the record already, 956177633Sdfr * chain this bit onto the end. 957177633Sdfr */ 958177633Sdfr if (ct->ct_record) 959177633Sdfr m_last(ct->ct_record)->m_next = m; 960177633Sdfr else 961177633Sdfr ct->ct_record = m; 962177633Sdfr 963177633Sdfr ct->ct_record_resid = uio.uio_resid; 964177633Sdfr 965177633Sdfr /* 966177633Sdfr * If we have the entire record, see if we can 967177633Sdfr * match it to a request. 968177633Sdfr */ 969177633Sdfr if (ct->ct_record_resid == 0 970177633Sdfr && ct->ct_record_eor) { 971177633Sdfr /* 972177633Sdfr * The XID is in the first uint32_t of 973244008Srmacklem * the reply and the message direction 974244008Srmacklem * is the second one. 975177633Sdfr */ 976244008Srmacklem if (ct->ct_record->m_len < 977244008Srmacklem sizeof(xid_plus_direction) && 978220585Srmacklem m_length(ct->ct_record, NULL) < 979244008Srmacklem sizeof(xid_plus_direction)) { 980220585Srmacklem m_freem(ct->ct_record); 981177633Sdfr break; 982220585Srmacklem } 983244008Srmacklem m_copydata(ct->ct_record, 0, 984244008Srmacklem sizeof(xid_plus_direction), 985244008Srmacklem (char *)xid_plus_direction); 986244008Srmacklem xid_plus_direction[0] = 987244008Srmacklem ntohl(xid_plus_direction[0]); 988244008Srmacklem xid_plus_direction[1] = 989244008Srmacklem ntohl(xid_plus_direction[1]); 990244008Srmacklem /* Check message direction. */ 991244008Srmacklem if (xid_plus_direction[1] == CALL) { 992244008Srmacklem /* This is a backchannel request. */ 993244008Srmacklem mtx_lock(&ct->ct_lock); 994244008Srmacklem xprt = ct->ct_backchannelxprt; 995244008Srmacklem if (xprt == NULL) { 996244008Srmacklem mtx_unlock(&ct->ct_lock); 997244008Srmacklem /* Just throw it away. */ 998244008Srmacklem m_freem(ct->ct_record); 999244008Srmacklem ct->ct_record = NULL; 1000244008Srmacklem } else { 1001244008Srmacklem cd = (struct cf_conn *) 1002244008Srmacklem xprt->xp_p1; 1003244008Srmacklem m2 = cd->mreq; 1004177633Sdfr /* 1005244008Srmacklem * The requests are chained 1006244008Srmacklem * in the m_nextpkt list. 1007177633Sdfr */ 1008244008Srmacklem while (m2 != NULL && 1009244008Srmacklem m2->m_nextpkt != NULL) 1010244008Srmacklem /* Find end of list. */ 1011244008Srmacklem m2 = m2->m_nextpkt; 1012244008Srmacklem if (m2 != NULL) 1013244008Srmacklem m2->m_nextpkt = 1014244008Srmacklem ct->ct_record; 1015244008Srmacklem else 1016244008Srmacklem cd->mreq = 1017244008Srmacklem ct->ct_record; 1018244008Srmacklem ct->ct_record->m_nextpkt = 1019244008Srmacklem NULL; 1020244008Srmacklem ct->ct_record = NULL; 1021244008Srmacklem xprt_active(xprt); 1022244008Srmacklem mtx_unlock(&ct->ct_lock); 1023177633Sdfr } 1024244008Srmacklem } else { 1025244008Srmacklem mtx_lock(&ct->ct_lock); 1026244008Srmacklem foundreq = 0; 1027244008Srmacklem TAILQ_FOREACH(cr, &ct->ct_pending, 1028244008Srmacklem cr_link) { 1029244008Srmacklem if (cr->cr_xid == 1030244008Srmacklem xid_plus_direction[0]) { 1031244008Srmacklem /* 1032244008Srmacklem * This one 1033244008Srmacklem * matches. We leave 1034244008Srmacklem * the reply mbuf in 1035244008Srmacklem * cr->cr_mrep. Set 1036244008Srmacklem * the XID to zero so 1037244008Srmacklem * that we will ignore 1038244008Srmacklem * any duplicated 1039244008Srmacklem * replies. 1040244008Srmacklem */ 1041244008Srmacklem cr->cr_xid = 0; 1042244008Srmacklem cr->cr_mrep = 1043244008Srmacklem ct->ct_record; 1044244008Srmacklem cr->cr_error = 0; 1045244008Srmacklem foundreq = 1; 1046244008Srmacklem wakeup(cr); 1047244008Srmacklem break; 1048244008Srmacklem } 1049244008Srmacklem } 1050244008Srmacklem mtx_unlock(&ct->ct_lock); 1051244008Srmacklem 1052244008Srmacklem if (!foundreq) 1053244008Srmacklem m_freem(ct->ct_record); 1054244008Srmacklem ct->ct_record = NULL; 1055177633Sdfr } 1056177633Sdfr } 1057177633Sdfr } 1058177633Sdfr } while (m); 1059193437Srmacklem ct->ct_upcallrefs--; 1060193437Srmacklem if (ct->ct_upcallrefs < 0) 1061193437Srmacklem panic("rpcvc upcall refcnt"); 1062193437Srmacklem if (ct->ct_upcallrefs == 0) 1063193437Srmacklem wakeup(&ct->ct_upcallrefs); 1064193272Sjhb return (SU_OK); 1065177633Sdfr} 1066193437Srmacklem 1067193437Srmacklem/* 1068193437Srmacklem * Wait for all upcalls in progress to complete. 1069193437Srmacklem */ 1070193437Srmacklemstatic void 1071193437Srmacklemclnt_vc_upcallsdone(struct ct_data *ct) 1072193437Srmacklem{ 1073193437Srmacklem 1074193437Srmacklem SOCKBUF_LOCK_ASSERT(&ct->ct_socket->so_rcv); 1075193437Srmacklem 1076193437Srmacklem while (ct->ct_upcallrefs > 0) 1077193437Srmacklem (void) msleep(&ct->ct_upcallrefs, 1078193437Srmacklem SOCKBUF_MTX(&ct->ct_socket->so_rcv), 0, "rpcvcup", 0); 1079193437Srmacklem} 1080