1dfdcada3SDoug Rabson /* $NetBSD: clnt_dg.c,v 1.4 2000/07/14 08:40:41 fvdl Exp $ */ 2dfdcada3SDoug Rabson 32e322d37SHiroki Sato /*- 451369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 551369649SPedro F. Giffuni * 62e322d37SHiroki Sato * Copyright (c) 2009, Sun Microsystems, Inc. 72e322d37SHiroki Sato * All rights reserved. 8dfdcada3SDoug Rabson * 92e322d37SHiroki Sato * Redistribution and use in source and binary forms, with or without 102e322d37SHiroki Sato * modification, are permitted provided that the following conditions are met: 112e322d37SHiroki Sato * - Redistributions of source code must retain the above copyright notice, 122e322d37SHiroki Sato * this list of conditions and the following disclaimer. 132e322d37SHiroki Sato * - Redistributions in binary form must reproduce the above copyright notice, 142e322d37SHiroki Sato * this list of conditions and the following disclaimer in the documentation 152e322d37SHiroki Sato * and/or other materials provided with the distribution. 162e322d37SHiroki Sato * - Neither the name of Sun Microsystems, Inc. nor the names of its 172e322d37SHiroki Sato * contributors may be used to endorse or promote products derived 182e322d37SHiroki Sato * from this software without specific prior written permission. 19dfdcada3SDoug Rabson * 202e322d37SHiroki Sato * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 212e322d37SHiroki Sato * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 222e322d37SHiroki Sato * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 232e322d37SHiroki Sato * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 242e322d37SHiroki Sato * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 252e322d37SHiroki Sato * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 262e322d37SHiroki Sato * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 272e322d37SHiroki Sato * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 282e322d37SHiroki Sato * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 292e322d37SHiroki Sato * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 302e322d37SHiroki Sato * POSSIBILITY OF SUCH DAMAGE. 31dfdcada3SDoug Rabson */ 32dfdcada3SDoug Rabson /* 33dfdcada3SDoug Rabson * Copyright (c) 1986-1991 by Sun Microsystems Inc. 34dfdcada3SDoug Rabson */ 35dfdcada3SDoug Rabson 36dfdcada3SDoug Rabson #if defined(LIBC_SCCS) && !defined(lint) 37dfdcada3SDoug Rabson #ident "@(#)clnt_dg.c 1.23 94/04/22 SMI" 38dfdcada3SDoug Rabson static char sccsid[] = "@(#)clnt_dg.c 1.19 89/03/16 Copyr 1988 Sun Micro"; 39dfdcada3SDoug Rabson #endif 40dfdcada3SDoug Rabson #include <sys/cdefs.h> 41dfdcada3SDoug Rabson __FBSDID("$FreeBSD$"); 42dfdcada3SDoug Rabson 43dfdcada3SDoug Rabson /* 44dfdcada3SDoug Rabson * Implements a connectionless client side RPC. 45dfdcada3SDoug Rabson */ 46dfdcada3SDoug Rabson 47dfdcada3SDoug Rabson #include <sys/param.h> 48dfdcada3SDoug Rabson #include <sys/systm.h> 49c675522fSDoug Rabson #include <sys/kernel.h> 50dfdcada3SDoug Rabson #include <sys/lock.h> 51dfdcada3SDoug Rabson #include <sys/malloc.h> 52dfdcada3SDoug Rabson #include <sys/mbuf.h> 53dfdcada3SDoug Rabson #include <sys/mutex.h> 54dfdcada3SDoug Rabson #include <sys/pcpu.h> 55dfdcada3SDoug Rabson #include <sys/proc.h> 56dfdcada3SDoug Rabson #include <sys/socket.h> 57dfdcada3SDoug Rabson #include <sys/socketvar.h> 58dfdcada3SDoug Rabson #include <sys/time.h> 59dfdcada3SDoug Rabson #include <sys/uio.h> 60dfdcada3SDoug Rabson 610348c661SMarko Zec #include <net/vnet.h> 620348c661SMarko Zec 63dfdcada3SDoug Rabson #include <rpc/rpc.h> 64ee31b83aSDoug Rabson #include <rpc/rpc_com.h> 65dfdcada3SDoug Rabson 66dfdcada3SDoug Rabson 67dfdcada3SDoug Rabson #ifdef _FREEFALL_CONFIG 68dfdcada3SDoug Rabson /* 69dfdcada3SDoug Rabson * Disable RPC exponential back-off for FreeBSD.org systems. 70dfdcada3SDoug Rabson */ 71dfdcada3SDoug Rabson #define RPC_MAX_BACKOFF 1 /* second */ 72dfdcada3SDoug Rabson #else 73dfdcada3SDoug Rabson #define RPC_MAX_BACKOFF 30 /* seconds */ 74dfdcada3SDoug Rabson #endif 75dfdcada3SDoug Rabson 76dfdcada3SDoug Rabson static bool_t time_not_ok(struct timeval *); 77c675522fSDoug Rabson static enum clnt_stat clnt_dg_call(CLIENT *, struct rpc_callextra *, 78a9148abdSDoug Rabson rpcproc_t, struct mbuf *, struct mbuf **, struct timeval); 79dfdcada3SDoug Rabson static void clnt_dg_geterr(CLIENT *, struct rpc_err *); 80dfdcada3SDoug Rabson static bool_t clnt_dg_freeres(CLIENT *, xdrproc_t, void *); 81dfdcada3SDoug Rabson static void clnt_dg_abort(CLIENT *); 82dfdcada3SDoug Rabson static bool_t clnt_dg_control(CLIENT *, u_int, void *); 83a9148abdSDoug Rabson static void clnt_dg_close(CLIENT *); 84dfdcada3SDoug Rabson static void clnt_dg_destroy(CLIENT *); 8574fb0ba7SJohn Baldwin static int clnt_dg_soupcall(struct socket *so, void *arg, int waitflag); 86dfdcada3SDoug Rabson 87dfdcada3SDoug Rabson static struct clnt_ops clnt_dg_ops = { 88dfdcada3SDoug Rabson .cl_call = clnt_dg_call, 89dfdcada3SDoug Rabson .cl_abort = clnt_dg_abort, 90dfdcada3SDoug Rabson .cl_geterr = clnt_dg_geterr, 91dfdcada3SDoug Rabson .cl_freeres = clnt_dg_freeres, 92a9148abdSDoug Rabson .cl_close = clnt_dg_close, 93dfdcada3SDoug Rabson .cl_destroy = clnt_dg_destroy, 94dfdcada3SDoug Rabson .cl_control = clnt_dg_control 95dfdcada3SDoug Rabson }; 96dfdcada3SDoug Rabson 97*9c206560SRick Macklem static volatile uint32_t rpc_xid = 0; 98*9c206560SRick Macklem 99dfdcada3SDoug Rabson /* 100c675522fSDoug Rabson * A pending RPC request which awaits a reply. Requests which have 101c675522fSDoug Rabson * received their reply will have cr_xid set to zero and cr_mrep to 102c675522fSDoug Rabson * the mbuf chain of the reply. 103dfdcada3SDoug Rabson */ 104dfdcada3SDoug Rabson struct cu_request { 105dfdcada3SDoug Rabson TAILQ_ENTRY(cu_request) cr_link; 106c675522fSDoug Rabson CLIENT *cr_client; /* owner */ 107dfdcada3SDoug Rabson uint32_t cr_xid; /* XID of request */ 108dfdcada3SDoug Rabson struct mbuf *cr_mrep; /* reply received by upcall */ 109dfdcada3SDoug Rabson int cr_error; /* any error from upcall */ 110a9148abdSDoug Rabson char cr_verf[MAX_AUTH_BYTES]; /* reply verf */ 111dfdcada3SDoug Rabson }; 112dfdcada3SDoug Rabson 113dfdcada3SDoug Rabson TAILQ_HEAD(cu_request_list, cu_request); 114dfdcada3SDoug Rabson 115dfdcada3SDoug Rabson #define MCALL_MSG_SIZE 24 116dfdcada3SDoug Rabson 117dfdcada3SDoug Rabson /* 11874fb0ba7SJohn Baldwin * This structure is pointed to by the socket buffer's sb_upcallarg 119dfdcada3SDoug Rabson * member. It is separate from the client private data to facilitate 120dfdcada3SDoug Rabson * multiple clients sharing the same socket. The cs_lock mutex is used 121dfdcada3SDoug Rabson * to protect all fields of this structure, the socket's receive 122dfdcada3SDoug Rabson * buffer SOCKBUF_LOCK is used to ensure that exactly one of these 123dfdcada3SDoug Rabson * structures is installed on the socket. 124dfdcada3SDoug Rabson */ 125dfdcada3SDoug Rabson struct cu_socket { 126dfdcada3SDoug Rabson struct mtx cs_lock; 127dfdcada3SDoug Rabson int cs_refs; /* Count of clients */ 128dfdcada3SDoug Rabson struct cu_request_list cs_pending; /* Requests awaiting replies */ 1293144f812SRick Macklem int cs_upcallrefs; /* Refcnt of upcalls in prog.*/ 130dfdcada3SDoug Rabson }; 131dfdcada3SDoug Rabson 1323144f812SRick Macklem static void clnt_dg_upcallsdone(struct socket *, struct cu_socket *); 1333144f812SRick Macklem 134dfdcada3SDoug Rabson /* 135dfdcada3SDoug Rabson * Private data kept per client handle 136dfdcada3SDoug Rabson */ 137dfdcada3SDoug Rabson struct cu_data { 138c675522fSDoug Rabson int cu_threads; /* # threads in clnt_vc_call */ 139a9148abdSDoug Rabson bool_t cu_closing; /* TRUE if we are closing */ 140a9148abdSDoug Rabson bool_t cu_closed; /* TRUE if we are closed */ 141dfdcada3SDoug Rabson struct socket *cu_socket; /* connection socket */ 142dfdcada3SDoug Rabson bool_t cu_closeit; /* opened by library */ 143dfdcada3SDoug Rabson struct sockaddr_storage cu_raddr; /* remote address */ 144dfdcada3SDoug Rabson int cu_rlen; 145dfdcada3SDoug Rabson struct timeval cu_wait; /* retransmit interval */ 146dfdcada3SDoug Rabson struct timeval cu_total; /* total time for the call */ 147dfdcada3SDoug Rabson struct rpc_err cu_error; 148dfdcada3SDoug Rabson uint32_t cu_xid; 149dfdcada3SDoug Rabson char cu_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */ 150dfdcada3SDoug Rabson size_t cu_mcalllen; 151dfdcada3SDoug Rabson size_t cu_sendsz; /* send size */ 152dfdcada3SDoug Rabson size_t cu_recvsz; /* recv size */ 153dfdcada3SDoug Rabson int cu_async; 154dfdcada3SDoug Rabson int cu_connect; /* Use connect(). */ 155dfdcada3SDoug Rabson int cu_connected; /* Have done connect(). */ 156dfdcada3SDoug Rabson const char *cu_waitchan; 157dfdcada3SDoug Rabson int cu_waitflag; 158a9148abdSDoug Rabson int cu_cwnd; /* congestion window */ 159a9148abdSDoug Rabson int cu_sent; /* number of in-flight RPCs */ 160a9148abdSDoug Rabson bool_t cu_cwnd_wait; 161dfdcada3SDoug Rabson }; 162dfdcada3SDoug Rabson 163a9148abdSDoug Rabson #define CWNDSCALE 256 164a9148abdSDoug Rabson #define MAXCWND (32 * CWNDSCALE) 165a9148abdSDoug Rabson 166dfdcada3SDoug Rabson /* 167dfdcada3SDoug Rabson * Connection less client creation returns with client handle parameters. 168dfdcada3SDoug Rabson * Default options are set, which the user can change using clnt_control(). 169dfdcada3SDoug Rabson * fd should be open and bound. 170dfdcada3SDoug Rabson * NB: The rpch->cl_auth is initialized to null authentication. 171dfdcada3SDoug Rabson * Caller may wish to set this something more useful. 172dfdcada3SDoug Rabson * 173dfdcada3SDoug Rabson * sendsz and recvsz are the maximum allowable packet sizes that can be 174dfdcada3SDoug Rabson * sent and received. Normally they are the same, but they can be 175dfdcada3SDoug Rabson * changed to improve the program efficiency and buffer allocation. 176dfdcada3SDoug Rabson * If they are 0, use the transport default. 177dfdcada3SDoug Rabson * 178dfdcada3SDoug Rabson * If svcaddr is NULL, returns NULL. 179dfdcada3SDoug Rabson */ 180dfdcada3SDoug Rabson CLIENT * 181dfdcada3SDoug Rabson clnt_dg_create( 182dfdcada3SDoug Rabson struct socket *so, 183dfdcada3SDoug Rabson struct sockaddr *svcaddr, /* servers address */ 184dfdcada3SDoug Rabson rpcprog_t program, /* program number */ 185dfdcada3SDoug Rabson rpcvers_t version, /* version number */ 186dfdcada3SDoug Rabson size_t sendsz, /* buffer recv size */ 187dfdcada3SDoug Rabson size_t recvsz) /* buffer send size */ 188dfdcada3SDoug Rabson { 189dfdcada3SDoug Rabson CLIENT *cl = NULL; /* client handle */ 190dfdcada3SDoug Rabson struct cu_data *cu = NULL; /* private data */ 191dfdcada3SDoug Rabson struct cu_socket *cs = NULL; 19274fb0ba7SJohn Baldwin struct sockbuf *sb; 193dfdcada3SDoug Rabson struct timeval now; 194dfdcada3SDoug Rabson struct rpc_msg call_msg; 195dfdcada3SDoug Rabson struct __rpc_sockinfo si; 196dfdcada3SDoug Rabson XDR xdrs; 197cec077bcSRick Macklem int error; 198*9c206560SRick Macklem uint32_t newxid; 199dfdcada3SDoug Rabson 200dfdcada3SDoug Rabson if (svcaddr == NULL) { 201dfdcada3SDoug Rabson rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 202dfdcada3SDoug Rabson return (NULL); 203dfdcada3SDoug Rabson } 204dfdcada3SDoug Rabson 205dfdcada3SDoug Rabson if (!__rpc_socket2sockinfo(so, &si)) { 206dfdcada3SDoug Rabson rpc_createerr.cf_stat = RPC_TLIERROR; 207dfdcada3SDoug Rabson rpc_createerr.cf_error.re_errno = 0; 208dfdcada3SDoug Rabson return (NULL); 209dfdcada3SDoug Rabson } 210dfdcada3SDoug Rabson 211dfdcada3SDoug Rabson /* 212dfdcada3SDoug Rabson * Find the receive and the send size 213dfdcada3SDoug Rabson */ 214dfdcada3SDoug Rabson sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 215dfdcada3SDoug Rabson recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 216dfdcada3SDoug Rabson if ((sendsz == 0) || (recvsz == 0)) { 217dfdcada3SDoug Rabson rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */ 218dfdcada3SDoug Rabson rpc_createerr.cf_error.re_errno = 0; 219dfdcada3SDoug Rabson return (NULL); 220dfdcada3SDoug Rabson } 221dfdcada3SDoug Rabson 222dfdcada3SDoug Rabson cl = mem_alloc(sizeof (CLIENT)); 223dfdcada3SDoug Rabson 224dfdcada3SDoug Rabson /* 225dfdcada3SDoug Rabson * Should be multiple of 4 for XDR. 226dfdcada3SDoug Rabson */ 2274ed3c0e7SPedro F. Giffuni sendsz = rounddown(sendsz + 3, 4); 2284ed3c0e7SPedro F. Giffuni recvsz = rounddown(recvsz + 3, 4); 229dfdcada3SDoug Rabson cu = mem_alloc(sizeof (*cu)); 230c675522fSDoug Rabson cu->cu_threads = 0; 231c675522fSDoug Rabson cu->cu_closing = FALSE; 232a9148abdSDoug Rabson cu->cu_closed = FALSE; 233dfdcada3SDoug Rabson (void) memcpy(&cu->cu_raddr, svcaddr, (size_t)svcaddr->sa_len); 234dfdcada3SDoug Rabson cu->cu_rlen = svcaddr->sa_len; 235dfdcada3SDoug Rabson /* Other values can also be set through clnt_control() */ 236c675522fSDoug Rabson cu->cu_wait.tv_sec = 3; /* heuristically chosen */ 237dfdcada3SDoug Rabson cu->cu_wait.tv_usec = 0; 238dfdcada3SDoug Rabson cu->cu_total.tv_sec = -1; 239dfdcada3SDoug Rabson cu->cu_total.tv_usec = -1; 240dfdcada3SDoug Rabson cu->cu_sendsz = sendsz; 241dfdcada3SDoug Rabson cu->cu_recvsz = recvsz; 242dfdcada3SDoug Rabson cu->cu_async = FALSE; 243dfdcada3SDoug Rabson cu->cu_connect = FALSE; 244dfdcada3SDoug Rabson cu->cu_connected = FALSE; 245dfdcada3SDoug Rabson cu->cu_waitchan = "rpcrecv"; 246dfdcada3SDoug Rabson cu->cu_waitflag = 0; 247a9148abdSDoug Rabson cu->cu_cwnd = MAXCWND / 2; 248a9148abdSDoug Rabson cu->cu_sent = 0; 249a9148abdSDoug Rabson cu->cu_cwnd_wait = FALSE; 250dfdcada3SDoug Rabson (void) getmicrotime(&now); 251*9c206560SRick Macklem /* Clip at 28bits so that it will not wrap around. */ 252*9c206560SRick Macklem newxid = __RPC_GETXID(&now) & 0xfffffff; 253*9c206560SRick Macklem atomic_cmpset_32(&rpc_xid, 0, newxid); 254*9c206560SRick Macklem call_msg.rm_xid = atomic_fetchadd_32(&rpc_xid, 1); 255dfdcada3SDoug Rabson call_msg.rm_call.cb_prog = program; 256dfdcada3SDoug Rabson call_msg.rm_call.cb_vers = version; 257dfdcada3SDoug Rabson xdrmem_create(&xdrs, cu->cu_mcallc, MCALL_MSG_SIZE, XDR_ENCODE); 258dfdcada3SDoug Rabson if (! xdr_callhdr(&xdrs, &call_msg)) { 259dfdcada3SDoug Rabson rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */ 260dfdcada3SDoug Rabson rpc_createerr.cf_error.re_errno = 0; 261dfdcada3SDoug Rabson goto err2; 262dfdcada3SDoug Rabson } 263c2ede4b3SMartin Blapp cu->cu_mcalllen = XDR_GETPOS(&xdrs); 264dfdcada3SDoug Rabson 265dfdcada3SDoug Rabson /* 266dfdcada3SDoug Rabson * By default, closeit is always FALSE. It is users responsibility 267dfdcada3SDoug Rabson * to do a close on it, else the user may use clnt_control 268dfdcada3SDoug Rabson * to let clnt_destroy do it for him/her. 269dfdcada3SDoug Rabson */ 270dfdcada3SDoug Rabson cu->cu_closeit = FALSE; 271dfdcada3SDoug Rabson cu->cu_socket = so; 272cec077bcSRick Macklem error = soreserve(so, (u_long)sendsz, (u_long)recvsz); 273cec077bcSRick Macklem if (error != 0) { 274cec077bcSRick Macklem rpc_createerr.cf_stat = RPC_FAILED; 275cec077bcSRick Macklem rpc_createerr.cf_error.re_errno = error; 276cec077bcSRick Macklem goto err2; 277cec077bcSRick Macklem } 278dfdcada3SDoug Rabson 27974fb0ba7SJohn Baldwin sb = &so->so_rcv; 280dfdcada3SDoug Rabson SOCKBUF_LOCK(&so->so_rcv); 281dfdcada3SDoug Rabson recheck_socket: 28274fb0ba7SJohn Baldwin if (sb->sb_upcall) { 28374fb0ba7SJohn Baldwin if (sb->sb_upcall != clnt_dg_soupcall) { 284dfdcada3SDoug Rabson SOCKBUF_UNLOCK(&so->so_rcv); 285dfdcada3SDoug Rabson printf("clnt_dg_create(): socket already has an incompatible upcall\n"); 286dfdcada3SDoug Rabson goto err2; 287dfdcada3SDoug Rabson } 28874fb0ba7SJohn Baldwin cs = (struct cu_socket *) sb->sb_upcallarg; 289dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 290dfdcada3SDoug Rabson cs->cs_refs++; 291dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 292dfdcada3SDoug Rabson } else { 293dfdcada3SDoug Rabson /* 294dfdcada3SDoug Rabson * We are the first on this socket - allocate the 295dfdcada3SDoug Rabson * structure and install it in the socket. 296dfdcada3SDoug Rabson */ 29774fb0ba7SJohn Baldwin SOCKBUF_UNLOCK(&so->so_rcv); 298dfdcada3SDoug Rabson cs = mem_alloc(sizeof(*cs)); 29974fb0ba7SJohn Baldwin SOCKBUF_LOCK(&so->so_rcv); 30074fb0ba7SJohn Baldwin if (sb->sb_upcall) { 301dfdcada3SDoug Rabson /* 302dfdcada3SDoug Rabson * We have lost a race with some other client. 303dfdcada3SDoug Rabson */ 304dfdcada3SDoug Rabson mem_free(cs, sizeof(*cs)); 305dfdcada3SDoug Rabson goto recheck_socket; 306dfdcada3SDoug Rabson } 307dfdcada3SDoug Rabson mtx_init(&cs->cs_lock, "cs->cs_lock", NULL, MTX_DEF); 308dfdcada3SDoug Rabson cs->cs_refs = 1; 3093144f812SRick Macklem cs->cs_upcallrefs = 0; 310dfdcada3SDoug Rabson TAILQ_INIT(&cs->cs_pending); 31174fb0ba7SJohn Baldwin soupcall_set(so, SO_RCV, clnt_dg_soupcall, cs); 312dfdcada3SDoug Rabson } 313dfdcada3SDoug Rabson SOCKBUF_UNLOCK(&so->so_rcv); 314dfdcada3SDoug Rabson 315c675522fSDoug Rabson cl->cl_refs = 1; 316dfdcada3SDoug Rabson cl->cl_ops = &clnt_dg_ops; 317dfdcada3SDoug Rabson cl->cl_private = (caddr_t)(void *)cu; 318dfdcada3SDoug Rabson cl->cl_auth = authnone_create(); 319dfdcada3SDoug Rabson cl->cl_tp = NULL; 320dfdcada3SDoug Rabson cl->cl_netid = NULL; 321dfdcada3SDoug Rabson return (cl); 322dfdcada3SDoug Rabson err2: 323dfdcada3SDoug Rabson mem_free(cl, sizeof (CLIENT)); 324dfdcada3SDoug Rabson mem_free(cu, sizeof (*cu)); 325f9952959SEnji Cooper 326dfdcada3SDoug Rabson return (NULL); 327dfdcada3SDoug Rabson } 328dfdcada3SDoug Rabson 329dfdcada3SDoug Rabson static enum clnt_stat 330dfdcada3SDoug Rabson clnt_dg_call( 331dfdcada3SDoug Rabson CLIENT *cl, /* client handle */ 332c675522fSDoug Rabson struct rpc_callextra *ext, /* call metadata */ 333dfdcada3SDoug Rabson rpcproc_t proc, /* procedure number */ 334a9148abdSDoug Rabson struct mbuf *args, /* pointer to args */ 335a9148abdSDoug Rabson struct mbuf **resultsp, /* pointer to results */ 336dfdcada3SDoug Rabson struct timeval utimeout) /* seconds to wait before giving up */ 337dfdcada3SDoug Rabson { 338dfdcada3SDoug Rabson struct cu_data *cu = (struct cu_data *)cl->cl_private; 33974fb0ba7SJohn Baldwin struct cu_socket *cs; 340a9148abdSDoug Rabson struct rpc_timers *rt; 341c675522fSDoug Rabson AUTH *auth; 342a9148abdSDoug Rabson struct rpc_err *errp; 343a9148abdSDoug Rabson enum clnt_stat stat; 344dfdcada3SDoug Rabson XDR xdrs; 345dfdcada3SDoug Rabson struct rpc_msg reply_msg; 346dfdcada3SDoug Rabson bool_t ok; 347c675522fSDoug Rabson int retrans; /* number of re-transmits so far */ 348dfdcada3SDoug Rabson int nrefreshes = 2; /* number of times to refresh cred */ 349c675522fSDoug Rabson struct timeval *tvp; 350c675522fSDoug Rabson int timeout; 351c675522fSDoug Rabson int retransmit_time; 352a9148abdSDoug Rabson int next_sendtime, starttime, rtt, time_waited, tv = 0; 353dfdcada3SDoug Rabson struct sockaddr *sa; 354a9148abdSDoug Rabson uint32_t xid = 0; 355a9148abdSDoug Rabson struct mbuf *mreq = NULL, *results; 356c675522fSDoug Rabson struct cu_request *cr; 357dfdcada3SDoug Rabson int error; 358dfdcada3SDoug Rabson 35974fb0ba7SJohn Baldwin cs = cu->cu_socket->so_rcv.sb_upcallarg; 360c675522fSDoug Rabson cr = malloc(sizeof(struct cu_request), M_RPC, M_WAITOK); 361c675522fSDoug Rabson 362dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 363dfdcada3SDoug Rabson 364a9148abdSDoug Rabson if (cu->cu_closing || cu->cu_closed) { 365c675522fSDoug Rabson mtx_unlock(&cs->cs_lock); 366c675522fSDoug Rabson free(cr, M_RPC); 367c675522fSDoug Rabson return (RPC_CANTSEND); 368c675522fSDoug Rabson } 369c675522fSDoug Rabson cu->cu_threads++; 370c675522fSDoug Rabson 371a9148abdSDoug Rabson if (ext) { 372c675522fSDoug Rabson auth = ext->rc_auth; 373a9148abdSDoug Rabson errp = &ext->rc_err; 374a9148abdSDoug Rabson } else { 375c675522fSDoug Rabson auth = cl->cl_auth; 376a9148abdSDoug Rabson errp = &cu->cu_error; 377a9148abdSDoug Rabson } 378c675522fSDoug Rabson 379c675522fSDoug Rabson cr->cr_client = cl; 380c675522fSDoug Rabson cr->cr_mrep = NULL; 381c675522fSDoug Rabson cr->cr_error = 0; 382dfdcada3SDoug Rabson 383dfdcada3SDoug Rabson if (cu->cu_total.tv_usec == -1) { 384c675522fSDoug Rabson tvp = &utimeout; /* use supplied timeout */ 385dfdcada3SDoug Rabson } else { 386c675522fSDoug Rabson tvp = &cu->cu_total; /* use default timeout */ 387dfdcada3SDoug Rabson } 388c675522fSDoug Rabson if (tvp->tv_sec || tvp->tv_usec) 389c675522fSDoug Rabson timeout = tvtohz(tvp); 390c675522fSDoug Rabson else 391c675522fSDoug Rabson timeout = 0; 392dfdcada3SDoug Rabson 393dfdcada3SDoug Rabson if (cu->cu_connect && !cu->cu_connected) { 394dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 395dfdcada3SDoug Rabson error = soconnect(cu->cu_socket, 396dfdcada3SDoug Rabson (struct sockaddr *)&cu->cu_raddr, curthread); 397dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 398dfdcada3SDoug Rabson if (error) { 399a9148abdSDoug Rabson errp->re_errno = error; 400a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTSEND; 401dfdcada3SDoug Rabson goto out; 402dfdcada3SDoug Rabson } 403dfdcada3SDoug Rabson cu->cu_connected = 1; 404dfdcada3SDoug Rabson } 405151ba793SAlexander Kabaev if (cu->cu_connected) 406dfdcada3SDoug Rabson sa = NULL; 407151ba793SAlexander Kabaev else 408dfdcada3SDoug Rabson sa = (struct sockaddr *)&cu->cu_raddr; 409c675522fSDoug Rabson time_waited = 0; 410c675522fSDoug Rabson retrans = 0; 411a9148abdSDoug Rabson if (ext && ext->rc_timers) { 412a9148abdSDoug Rabson rt = ext->rc_timers; 413a9148abdSDoug Rabson if (!rt->rt_rtxcur) 414a9148abdSDoug Rabson rt->rt_rtxcur = tvtohz(&cu->cu_wait); 415a9148abdSDoug Rabson retransmit_time = next_sendtime = rt->rt_rtxcur; 416a9148abdSDoug Rabson } else { 417a9148abdSDoug Rabson rt = NULL; 418c675522fSDoug Rabson retransmit_time = next_sendtime = tvtohz(&cu->cu_wait); 419a9148abdSDoug Rabson } 420dfdcada3SDoug Rabson 421c675522fSDoug Rabson starttime = ticks; 422dfdcada3SDoug Rabson 423dfdcada3SDoug Rabson call_again: 424dfdcada3SDoug Rabson mtx_assert(&cs->cs_lock, MA_OWNED); 425dfdcada3SDoug Rabson 426*9c206560SRick Macklem xid = atomic_fetchadd_32(&rpc_xid, 1); 427dfdcada3SDoug Rabson 428dfdcada3SDoug Rabson send_again: 429dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 430dfdcada3SDoug Rabson 431bd54830bSGleb Smirnoff mreq = m_gethdr(M_WAITOK, MT_DATA); 432a9148abdSDoug Rabson KASSERT(cu->cu_mcalllen <= MHLEN, ("RPC header too big")); 433a9148abdSDoug Rabson bcopy(cu->cu_mcallc, mreq->m_data, cu->cu_mcalllen); 434a9148abdSDoug Rabson mreq->m_len = cu->cu_mcalllen; 435dfdcada3SDoug Rabson 436dfdcada3SDoug Rabson /* 437dfdcada3SDoug Rabson * The XID is the first thing in the request. 438dfdcada3SDoug Rabson */ 439dfdcada3SDoug Rabson *mtod(mreq, uint32_t *) = htonl(xid); 440dfdcada3SDoug Rabson 441dfdcada3SDoug Rabson xdrmbuf_create(&xdrs, mreq, XDR_ENCODE); 442dfdcada3SDoug Rabson 443a9148abdSDoug Rabson if (cu->cu_async == TRUE && args == NULL) 444dfdcada3SDoug Rabson goto get_reply; 445dfdcada3SDoug Rabson 446dfdcada3SDoug Rabson if ((! XDR_PUTINT32(&xdrs, &proc)) || 447a9148abdSDoug Rabson (! AUTH_MARSHALL(auth, xid, &xdrs, 448a9148abdSDoug Rabson m_copym(args, 0, M_COPYALL, M_WAITOK)))) { 449a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTENCODEARGS; 450dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 451dfdcada3SDoug Rabson goto out; 452dfdcada3SDoug Rabson } 453a9148abdSDoug Rabson mreq->m_pkthdr.len = m_length(mreq, NULL); 454dfdcada3SDoug Rabson 455c675522fSDoug Rabson cr->cr_xid = xid; 456dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 457a9148abdSDoug Rabson 458a9148abdSDoug Rabson /* 459a9148abdSDoug Rabson * Try to get a place in the congestion window. 460a9148abdSDoug Rabson */ 461a9148abdSDoug Rabson while (cu->cu_sent >= cu->cu_cwnd) { 462a9148abdSDoug Rabson cu->cu_cwnd_wait = TRUE; 463a9148abdSDoug Rabson error = msleep(&cu->cu_cwnd_wait, &cs->cs_lock, 464a9148abdSDoug Rabson cu->cu_waitflag, "rpccwnd", 0); 465a9148abdSDoug Rabson if (error) { 466a9148abdSDoug Rabson errp->re_errno = error; 467fa3db771SArtem Belevich if (error == EINTR || error == ERESTART) 468fa3db771SArtem Belevich errp->re_status = stat = RPC_INTR; 469fa3db771SArtem Belevich else 470a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTSEND; 471a9148abdSDoug Rabson goto out; 472a9148abdSDoug Rabson } 473a9148abdSDoug Rabson } 474a9148abdSDoug Rabson cu->cu_sent += CWNDSCALE; 475a9148abdSDoug Rabson 476c675522fSDoug Rabson TAILQ_INSERT_TAIL(&cs->cs_pending, cr, cr_link); 477dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 478dfdcada3SDoug Rabson 479dfdcada3SDoug Rabson /* 480dfdcada3SDoug Rabson * sosend consumes mreq. 481dfdcada3SDoug Rabson */ 482dfdcada3SDoug Rabson error = sosend(cu->cu_socket, sa, NULL, mreq, NULL, 0, curthread); 483dfdcada3SDoug Rabson mreq = NULL; 484dfdcada3SDoug Rabson 485dfdcada3SDoug Rabson /* 486dfdcada3SDoug Rabson * sub-optimal code appears here because we have 487dfdcada3SDoug Rabson * some clock time to spare while the packets are in flight. 488dfdcada3SDoug Rabson * (We assume that this is actually only executed once.) 489dfdcada3SDoug Rabson */ 490a9148abdSDoug Rabson reply_msg.acpted_rply.ar_verf.oa_flavor = AUTH_NULL; 491a9148abdSDoug Rabson reply_msg.acpted_rply.ar_verf.oa_base = cr->cr_verf; 492a9148abdSDoug Rabson reply_msg.acpted_rply.ar_verf.oa_length = 0; 493a9148abdSDoug Rabson reply_msg.acpted_rply.ar_results.where = NULL; 494a9148abdSDoug Rabson reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; 495dfdcada3SDoug Rabson 496dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 497dfdcada3SDoug Rabson if (error) { 498c675522fSDoug Rabson TAILQ_REMOVE(&cs->cs_pending, cr, cr_link); 499a9148abdSDoug Rabson errp->re_errno = error; 500a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTSEND; 501a9148abdSDoug Rabson cu->cu_sent -= CWNDSCALE; 502a9148abdSDoug Rabson if (cu->cu_cwnd_wait) { 503a9148abdSDoug Rabson cu->cu_cwnd_wait = FALSE; 504a9148abdSDoug Rabson wakeup(&cu->cu_cwnd_wait); 505a9148abdSDoug Rabson } 506dfdcada3SDoug Rabson goto out; 507dfdcada3SDoug Rabson } 508dfdcada3SDoug Rabson 509dfdcada3SDoug Rabson /* 510dfdcada3SDoug Rabson * Check to see if we got an upcall while waiting for the 511c675522fSDoug Rabson * lock. 512dfdcada3SDoug Rabson */ 513c675522fSDoug Rabson if (cr->cr_error) { 514c675522fSDoug Rabson TAILQ_REMOVE(&cs->cs_pending, cr, cr_link); 515a9148abdSDoug Rabson errp->re_errno = cr->cr_error; 516a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTRECV; 517a9148abdSDoug Rabson cu->cu_sent -= CWNDSCALE; 518a9148abdSDoug Rabson if (cu->cu_cwnd_wait) { 519a9148abdSDoug Rabson cu->cu_cwnd_wait = FALSE; 520a9148abdSDoug Rabson wakeup(&cu->cu_cwnd_wait); 521a9148abdSDoug Rabson } 522dfdcada3SDoug Rabson goto out; 523dfdcada3SDoug Rabson } 524c675522fSDoug Rabson if (cr->cr_mrep) { 525c675522fSDoug Rabson TAILQ_REMOVE(&cs->cs_pending, cr, cr_link); 526a9148abdSDoug Rabson cu->cu_sent -= CWNDSCALE; 527a9148abdSDoug Rabson if (cu->cu_cwnd_wait) { 528a9148abdSDoug Rabson cu->cu_cwnd_wait = FALSE; 529a9148abdSDoug Rabson wakeup(&cu->cu_cwnd_wait); 530a9148abdSDoug Rabson } 531dfdcada3SDoug Rabson goto got_reply; 532dfdcada3SDoug Rabson } 533dfdcada3SDoug Rabson 534dfdcada3SDoug Rabson /* 535dfdcada3SDoug Rabson * Hack to provide rpc-based message passing 536dfdcada3SDoug Rabson */ 537c675522fSDoug Rabson if (timeout == 0) { 538c675522fSDoug Rabson TAILQ_REMOVE(&cs->cs_pending, cr, cr_link); 539a9148abdSDoug Rabson errp->re_status = stat = RPC_TIMEDOUT; 540a9148abdSDoug Rabson cu->cu_sent -= CWNDSCALE; 541a9148abdSDoug Rabson if (cu->cu_cwnd_wait) { 542a9148abdSDoug Rabson cu->cu_cwnd_wait = FALSE; 543a9148abdSDoug Rabson wakeup(&cu->cu_cwnd_wait); 544a9148abdSDoug Rabson } 545dfdcada3SDoug Rabson goto out; 546dfdcada3SDoug Rabson } 547dfdcada3SDoug Rabson 548dfdcada3SDoug Rabson get_reply: 549dfdcada3SDoug Rabson for (;;) { 550dfdcada3SDoug Rabson /* Decide how long to wait. */ 551c675522fSDoug Rabson if (next_sendtime < timeout) 552dfdcada3SDoug Rabson tv = next_sendtime; 553c675522fSDoug Rabson else 554dfdcada3SDoug Rabson tv = timeout; 555c675522fSDoug Rabson tv -= time_waited; 556dfdcada3SDoug Rabson 557c675522fSDoug Rabson if (tv > 0) { 558b766fabdSRick Macklem if (cu->cu_closing || cu->cu_closed) { 559c675522fSDoug Rabson error = 0; 560b766fabdSRick Macklem cr->cr_error = ESHUTDOWN; 561b766fabdSRick Macklem } else { 562c675522fSDoug Rabson error = msleep(cr, &cs->cs_lock, 563c675522fSDoug Rabson cu->cu_waitflag, cu->cu_waitchan, tv); 564b766fabdSRick Macklem } 565c675522fSDoug Rabson } else { 566c675522fSDoug Rabson error = EWOULDBLOCK; 567c675522fSDoug Rabson } 568c675522fSDoug Rabson 569c675522fSDoug Rabson TAILQ_REMOVE(&cs->cs_pending, cr, cr_link); 570a9148abdSDoug Rabson cu->cu_sent -= CWNDSCALE; 571a9148abdSDoug Rabson if (cu->cu_cwnd_wait) { 572a9148abdSDoug Rabson cu->cu_cwnd_wait = FALSE; 573a9148abdSDoug Rabson wakeup(&cu->cu_cwnd_wait); 574a9148abdSDoug Rabson } 575dfdcada3SDoug Rabson 576dfdcada3SDoug Rabson if (!error) { 577dfdcada3SDoug Rabson /* 578dfdcada3SDoug Rabson * We were woken up by the upcall. If the 579dfdcada3SDoug Rabson * upcall had a receive error, report that, 580dfdcada3SDoug Rabson * otherwise we have a reply. 581dfdcada3SDoug Rabson */ 582c675522fSDoug Rabson if (cr->cr_error) { 583a9148abdSDoug Rabson errp->re_errno = cr->cr_error; 584a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTRECV; 585dfdcada3SDoug Rabson goto out; 586dfdcada3SDoug Rabson } 587a9148abdSDoug Rabson 588a9148abdSDoug Rabson cu->cu_cwnd += (CWNDSCALE * CWNDSCALE 589a9148abdSDoug Rabson + cu->cu_cwnd / 2) / cu->cu_cwnd; 590a9148abdSDoug Rabson if (cu->cu_cwnd > MAXCWND) 591a9148abdSDoug Rabson cu->cu_cwnd = MAXCWND; 592a9148abdSDoug Rabson 593a9148abdSDoug Rabson if (rt) { 594a9148abdSDoug Rabson /* 595a9148abdSDoug Rabson * Add one to the time since a tick 596a9148abdSDoug Rabson * count of N means that the actual 597a9148abdSDoug Rabson * time taken was somewhere between N 598a9148abdSDoug Rabson * and N+1. 599a9148abdSDoug Rabson */ 600a9148abdSDoug Rabson rtt = ticks - starttime + 1; 601a9148abdSDoug Rabson 602a9148abdSDoug Rabson /* 603a9148abdSDoug Rabson * Update our estimate of the round 604a9148abdSDoug Rabson * trip time using roughly the 605a9148abdSDoug Rabson * algorithm described in RFC 606a9148abdSDoug Rabson * 2988. Given an RTT sample R: 607a9148abdSDoug Rabson * 608a9148abdSDoug Rabson * RTTVAR = (1-beta) * RTTVAR + beta * |SRTT-R| 609a9148abdSDoug Rabson * SRTT = (1-alpha) * SRTT + alpha * R 610a9148abdSDoug Rabson * 611a9148abdSDoug Rabson * where alpha = 0.125 and beta = 0.25. 612a9148abdSDoug Rabson * 613a9148abdSDoug Rabson * The initial retransmit timeout is 614a9148abdSDoug Rabson * SRTT + 4*RTTVAR and doubles on each 615a9148abdSDoug Rabson * retransmision. 616a9148abdSDoug Rabson */ 617a9148abdSDoug Rabson if (rt->rt_srtt == 0) { 618a9148abdSDoug Rabson rt->rt_srtt = rtt; 619a9148abdSDoug Rabson rt->rt_deviate = rtt / 2; 620a9148abdSDoug Rabson } else { 621a9148abdSDoug Rabson int32_t error = rtt - rt->rt_srtt; 622a9148abdSDoug Rabson rt->rt_srtt += error / 8; 623a9148abdSDoug Rabson error = abs(error) - rt->rt_deviate; 624a9148abdSDoug Rabson rt->rt_deviate += error / 4; 625a9148abdSDoug Rabson } 626a9148abdSDoug Rabson rt->rt_rtxcur = rt->rt_srtt + 4*rt->rt_deviate; 627a9148abdSDoug Rabson } 628a9148abdSDoug Rabson 629dfdcada3SDoug Rabson break; 630dfdcada3SDoug Rabson } 631dfdcada3SDoug Rabson 632dfdcada3SDoug Rabson /* 633dfdcada3SDoug Rabson * The sleep returned an error so our request is still 634dfdcada3SDoug Rabson * on the list. If we got EWOULDBLOCK, we may want to 635dfdcada3SDoug Rabson * re-send the request. 636dfdcada3SDoug Rabson */ 637dfdcada3SDoug Rabson if (error != EWOULDBLOCK) { 638a9148abdSDoug Rabson errp->re_errno = error; 639fa3db771SArtem Belevich if (error == EINTR || error == ERESTART) 640a9148abdSDoug Rabson errp->re_status = stat = RPC_INTR; 641dfdcada3SDoug Rabson else 642a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTRECV; 643dfdcada3SDoug Rabson goto out; 644dfdcada3SDoug Rabson } 645dfdcada3SDoug Rabson 646c675522fSDoug Rabson time_waited = ticks - starttime; 647dfdcada3SDoug Rabson 648dfdcada3SDoug Rabson /* Check for timeout. */ 649c675522fSDoug Rabson if (time_waited > timeout) { 650a9148abdSDoug Rabson errp->re_errno = EWOULDBLOCK; 651a9148abdSDoug Rabson errp->re_status = stat = RPC_TIMEDOUT; 652dfdcada3SDoug Rabson goto out; 653dfdcada3SDoug Rabson } 654dfdcada3SDoug Rabson 655dfdcada3SDoug Rabson /* Retransmit if necessary. */ 656c675522fSDoug Rabson if (time_waited >= next_sendtime) { 657a9148abdSDoug Rabson cu->cu_cwnd /= 2; 658a9148abdSDoug Rabson if (cu->cu_cwnd < CWNDSCALE) 659a9148abdSDoug Rabson cu->cu_cwnd = CWNDSCALE; 660c675522fSDoug Rabson if (ext && ext->rc_feedback) { 661c675522fSDoug Rabson mtx_unlock(&cs->cs_lock); 662c675522fSDoug Rabson if (retrans == 0) 663c675522fSDoug Rabson ext->rc_feedback(FEEDBACK_REXMIT1, 664c675522fSDoug Rabson proc, ext->rc_feedback_arg); 665c675522fSDoug Rabson else 666c675522fSDoug Rabson ext->rc_feedback(FEEDBACK_REXMIT2, 667c675522fSDoug Rabson proc, ext->rc_feedback_arg); 668c675522fSDoug Rabson mtx_lock(&cs->cs_lock); 669c675522fSDoug Rabson } 670a9148abdSDoug Rabson if (cu->cu_closing || cu->cu_closed) { 671a9148abdSDoug Rabson errp->re_errno = ESHUTDOWN; 672a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTRECV; 673c675522fSDoug Rabson goto out; 674c675522fSDoug Rabson } 675c675522fSDoug Rabson retrans++; 676dfdcada3SDoug Rabson /* update retransmit_time */ 677c675522fSDoug Rabson if (retransmit_time < RPC_MAX_BACKOFF * hz) 678c675522fSDoug Rabson retransmit_time = 2 * retransmit_time; 679c675522fSDoug Rabson next_sendtime += retransmit_time; 680dfdcada3SDoug Rabson goto send_again; 681dfdcada3SDoug Rabson } 682318677adSRick Macklem cu->cu_sent += CWNDSCALE; 683c675522fSDoug Rabson TAILQ_INSERT_TAIL(&cs->cs_pending, cr, cr_link); 684dfdcada3SDoug Rabson } 685dfdcada3SDoug Rabson 686dfdcada3SDoug Rabson got_reply: 687dfdcada3SDoug Rabson /* 688dfdcada3SDoug Rabson * Now decode and validate the response. We need to drop the 689dfdcada3SDoug Rabson * lock since xdr_replymsg may end up sleeping in malloc. 690dfdcada3SDoug Rabson */ 691dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 692dfdcada3SDoug Rabson 693c675522fSDoug Rabson if (ext && ext->rc_feedback) 694c675522fSDoug Rabson ext->rc_feedback(FEEDBACK_OK, proc, ext->rc_feedback_arg); 695c675522fSDoug Rabson 696c675522fSDoug Rabson xdrmbuf_create(&xdrs, cr->cr_mrep, XDR_DECODE); 697dfdcada3SDoug Rabson ok = xdr_replymsg(&xdrs, &reply_msg); 698c675522fSDoug Rabson cr->cr_mrep = NULL; 699dfdcada3SDoug Rabson 700dfdcada3SDoug Rabson if (ok) { 701dfdcada3SDoug Rabson if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && 702dfdcada3SDoug Rabson (reply_msg.acpted_rply.ar_stat == SUCCESS)) 703a9148abdSDoug Rabson errp->re_status = stat = RPC_SUCCESS; 704dfdcada3SDoug Rabson else 705a9148abdSDoug Rabson stat = _seterr_reply(&reply_msg, &(cu->cu_error)); 706dfdcada3SDoug Rabson 707a9148abdSDoug Rabson if (errp->re_status == RPC_SUCCESS) { 708a9148abdSDoug Rabson results = xdrmbuf_getall(&xdrs); 709a9148abdSDoug Rabson if (! AUTH_VALIDATE(auth, xid, 710a9148abdSDoug Rabson &reply_msg.acpted_rply.ar_verf, 711a9148abdSDoug Rabson &results)) { 712a9148abdSDoug Rabson errp->re_status = stat = RPC_AUTHERROR; 713a9148abdSDoug Rabson errp->re_why = AUTH_INVALIDRESP; 714a9148abdSDoug Rabson if (retrans && 715a9148abdSDoug Rabson auth->ah_cred.oa_flavor == RPCSEC_GSS) { 716a9148abdSDoug Rabson /* 717a9148abdSDoug Rabson * If we retransmitted, its 718a9148abdSDoug Rabson * possible that we will 719a9148abdSDoug Rabson * receive a reply for one of 720a9148abdSDoug Rabson * the earlier transmissions 721a9148abdSDoug Rabson * (which will use an older 722a9148abdSDoug Rabson * RPCSEC_GSS sequence 723a9148abdSDoug Rabson * number). In this case, just 724a9148abdSDoug Rabson * go back and listen for a 725a9148abdSDoug Rabson * new reply. We could keep a 726a9148abdSDoug Rabson * record of all the seq 727a9148abdSDoug Rabson * numbers we have transmitted 728a9148abdSDoug Rabson * so far so that we could 729a9148abdSDoug Rabson * accept a reply for any of 730a9148abdSDoug Rabson * them here. 731a9148abdSDoug Rabson */ 732a9148abdSDoug Rabson XDR_DESTROY(&xdrs); 733a9148abdSDoug Rabson mtx_lock(&cs->cs_lock); 734318677adSRick Macklem cu->cu_sent += CWNDSCALE; 735a9148abdSDoug Rabson TAILQ_INSERT_TAIL(&cs->cs_pending, 736a9148abdSDoug Rabson cr, cr_link); 737a9148abdSDoug Rabson cr->cr_mrep = NULL; 738a9148abdSDoug Rabson goto get_reply; 739dfdcada3SDoug Rabson } 740a9148abdSDoug Rabson } else { 741a9148abdSDoug Rabson *resultsp = results; 742dfdcada3SDoug Rabson } 743dfdcada3SDoug Rabson } /* end successful completion */ 744dfdcada3SDoug Rabson /* 7456244c6e7SPedro F. Giffuni * If unsuccessful AND error is an authentication error 746dfdcada3SDoug Rabson * then refresh credentials and try again, else break 747dfdcada3SDoug Rabson */ 748a9148abdSDoug Rabson else if (stat == RPC_AUTHERROR) 749dfdcada3SDoug Rabson /* maybe our credentials need to be refreshed ... */ 750dfdcada3SDoug Rabson if (nrefreshes > 0 && 751a9148abdSDoug Rabson AUTH_REFRESH(auth, &reply_msg)) { 752dfdcada3SDoug Rabson nrefreshes--; 753a9148abdSDoug Rabson XDR_DESTROY(&xdrs); 754a9148abdSDoug Rabson mtx_lock(&cs->cs_lock); 755dfdcada3SDoug Rabson goto call_again; 756dfdcada3SDoug Rabson } 757dfdcada3SDoug Rabson /* end of unsuccessful completion */ 758dfdcada3SDoug Rabson } /* end of valid reply message */ 759dfdcada3SDoug Rabson else { 760a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTDECODERES; 761dfdcada3SDoug Rabson 762dfdcada3SDoug Rabson } 763a9148abdSDoug Rabson XDR_DESTROY(&xdrs); 764a9148abdSDoug Rabson mtx_lock(&cs->cs_lock); 765dfdcada3SDoug Rabson out: 766dfdcada3SDoug Rabson mtx_assert(&cs->cs_lock, MA_OWNED); 767dfdcada3SDoug Rabson 768dfdcada3SDoug Rabson if (mreq) 769dfdcada3SDoug Rabson m_freem(mreq); 770c675522fSDoug Rabson if (cr->cr_mrep) 771c675522fSDoug Rabson m_freem(cr->cr_mrep); 772c675522fSDoug Rabson 773c675522fSDoug Rabson cu->cu_threads--; 774c675522fSDoug Rabson if (cu->cu_closing) 775c675522fSDoug Rabson wakeup(cu); 776dfdcada3SDoug Rabson 777dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 778c675522fSDoug Rabson 779a9148abdSDoug Rabson if (auth && stat != RPC_SUCCESS) 780a9148abdSDoug Rabson AUTH_VALIDATE(auth, xid, NULL, NULL); 781a9148abdSDoug Rabson 782c675522fSDoug Rabson free(cr, M_RPC); 783c675522fSDoug Rabson 784a9148abdSDoug Rabson return (stat); 785dfdcada3SDoug Rabson } 786dfdcada3SDoug Rabson 787dfdcada3SDoug Rabson static void 788dfdcada3SDoug Rabson clnt_dg_geterr(CLIENT *cl, struct rpc_err *errp) 789dfdcada3SDoug Rabson { 790dfdcada3SDoug Rabson struct cu_data *cu = (struct cu_data *)cl->cl_private; 791dfdcada3SDoug Rabson 792dfdcada3SDoug Rabson *errp = cu->cu_error; 793dfdcada3SDoug Rabson } 794dfdcada3SDoug Rabson 795dfdcada3SDoug Rabson static bool_t 796dfdcada3SDoug Rabson clnt_dg_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr) 797dfdcada3SDoug Rabson { 798dfdcada3SDoug Rabson XDR xdrs; 799dfdcada3SDoug Rabson bool_t dummy; 800dfdcada3SDoug Rabson 801dfdcada3SDoug Rabson xdrs.x_op = XDR_FREE; 802dfdcada3SDoug Rabson dummy = (*xdr_res)(&xdrs, res_ptr); 803dfdcada3SDoug Rabson 804dfdcada3SDoug Rabson return (dummy); 805dfdcada3SDoug Rabson } 806dfdcada3SDoug Rabson 807dfdcada3SDoug Rabson /*ARGSUSED*/ 808dfdcada3SDoug Rabson static void 809dfdcada3SDoug Rabson clnt_dg_abort(CLIENT *h) 810dfdcada3SDoug Rabson { 811dfdcada3SDoug Rabson } 812dfdcada3SDoug Rabson 813dfdcada3SDoug Rabson static bool_t 814dfdcada3SDoug Rabson clnt_dg_control(CLIENT *cl, u_int request, void *info) 815dfdcada3SDoug Rabson { 816dfdcada3SDoug Rabson struct cu_data *cu = (struct cu_data *)cl->cl_private; 81774fb0ba7SJohn Baldwin struct cu_socket *cs; 818dfdcada3SDoug Rabson struct sockaddr *addr; 819dfdcada3SDoug Rabson 82074fb0ba7SJohn Baldwin cs = cu->cu_socket->so_rcv.sb_upcallarg; 821dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 822dfdcada3SDoug Rabson 823dfdcada3SDoug Rabson switch (request) { 824dfdcada3SDoug Rabson case CLSET_FD_CLOSE: 825dfdcada3SDoug Rabson cu->cu_closeit = TRUE; 826dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 827dfdcada3SDoug Rabson return (TRUE); 828dfdcada3SDoug Rabson case CLSET_FD_NCLOSE: 829dfdcada3SDoug Rabson cu->cu_closeit = FALSE; 830dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 831dfdcada3SDoug Rabson return (TRUE); 832dfdcada3SDoug Rabson } 833dfdcada3SDoug Rabson 834dfdcada3SDoug Rabson /* for other requests which use info */ 835dfdcada3SDoug Rabson if (info == NULL) { 836dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 837dfdcada3SDoug Rabson return (FALSE); 838dfdcada3SDoug Rabson } 839dfdcada3SDoug Rabson switch (request) { 840dfdcada3SDoug Rabson case CLSET_TIMEOUT: 841dfdcada3SDoug Rabson if (time_not_ok((struct timeval *)info)) { 842dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 843dfdcada3SDoug Rabson return (FALSE); 844dfdcada3SDoug Rabson } 845dfdcada3SDoug Rabson cu->cu_total = *(struct timeval *)info; 846dfdcada3SDoug Rabson break; 847dfdcada3SDoug Rabson case CLGET_TIMEOUT: 848dfdcada3SDoug Rabson *(struct timeval *)info = cu->cu_total; 849dfdcada3SDoug Rabson break; 850dfdcada3SDoug Rabson case CLSET_RETRY_TIMEOUT: 851dfdcada3SDoug Rabson if (time_not_ok((struct timeval *)info)) { 852dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 853dfdcada3SDoug Rabson return (FALSE); 854dfdcada3SDoug Rabson } 855dfdcada3SDoug Rabson cu->cu_wait = *(struct timeval *)info; 856dfdcada3SDoug Rabson break; 857dfdcada3SDoug Rabson case CLGET_RETRY_TIMEOUT: 858dfdcada3SDoug Rabson *(struct timeval *)info = cu->cu_wait; 859dfdcada3SDoug Rabson break; 860dfdcada3SDoug Rabson case CLGET_SVC_ADDR: 861dfdcada3SDoug Rabson /* 862dfdcada3SDoug Rabson * Slightly different semantics to userland - we use 863dfdcada3SDoug Rabson * sockaddr instead of netbuf. 864dfdcada3SDoug Rabson */ 865dfdcada3SDoug Rabson memcpy(info, &cu->cu_raddr, cu->cu_raddr.ss_len); 866dfdcada3SDoug Rabson break; 867dfdcada3SDoug Rabson case CLSET_SVC_ADDR: /* set to new address */ 868dfdcada3SDoug Rabson addr = (struct sockaddr *)info; 869dfdcada3SDoug Rabson (void) memcpy(&cu->cu_raddr, addr, addr->sa_len); 870dfdcada3SDoug Rabson break; 871dfdcada3SDoug Rabson case CLGET_XID: 872*9c206560SRick Macklem *(uint32_t *)info = atomic_load_32(&rpc_xid); 873dfdcada3SDoug Rabson break; 874dfdcada3SDoug Rabson 875dfdcada3SDoug Rabson case CLSET_XID: 876dfdcada3SDoug Rabson /* This will set the xid of the NEXT call */ 877dfdcada3SDoug Rabson /* decrement by 1 as clnt_dg_call() increments once */ 878*9c206560SRick Macklem atomic_store_32(&rpc_xid, *(uint32_t *)info - 1); 879dfdcada3SDoug Rabson break; 880dfdcada3SDoug Rabson 881dfdcada3SDoug Rabson case CLGET_VERS: 882dfdcada3SDoug Rabson /* 883dfdcada3SDoug Rabson * This RELIES on the information that, in the call body, 884dfdcada3SDoug Rabson * the version number field is the fifth field from the 8856244c6e7SPedro F. Giffuni * beginning of the RPC header. MUST be changed if the 886dfdcada3SDoug Rabson * call_struct is changed 887dfdcada3SDoug Rabson */ 888dfdcada3SDoug Rabson *(uint32_t *)info = 889dfdcada3SDoug Rabson ntohl(*(uint32_t *)(void *)(cu->cu_mcallc + 890dfdcada3SDoug Rabson 4 * BYTES_PER_XDR_UNIT)); 891dfdcada3SDoug Rabson break; 892dfdcada3SDoug Rabson 893dfdcada3SDoug Rabson case CLSET_VERS: 894dfdcada3SDoug Rabson *(uint32_t *)(void *)(cu->cu_mcallc + 4 * BYTES_PER_XDR_UNIT) 895dfdcada3SDoug Rabson = htonl(*(uint32_t *)info); 896dfdcada3SDoug Rabson break; 897dfdcada3SDoug Rabson 898dfdcada3SDoug Rabson case CLGET_PROG: 899dfdcada3SDoug Rabson /* 900dfdcada3SDoug Rabson * This RELIES on the information that, in the call body, 901dfdcada3SDoug Rabson * the program number field is the fourth field from the 9026244c6e7SPedro F. Giffuni * beginning of the RPC header. MUST be changed if the 903dfdcada3SDoug Rabson * call_struct is changed 904dfdcada3SDoug Rabson */ 905dfdcada3SDoug Rabson *(uint32_t *)info = 906dfdcada3SDoug Rabson ntohl(*(uint32_t *)(void *)(cu->cu_mcallc + 907dfdcada3SDoug Rabson 3 * BYTES_PER_XDR_UNIT)); 908dfdcada3SDoug Rabson break; 909dfdcada3SDoug Rabson 910dfdcada3SDoug Rabson case CLSET_PROG: 911dfdcada3SDoug Rabson *(uint32_t *)(void *)(cu->cu_mcallc + 3 * BYTES_PER_XDR_UNIT) 912dfdcada3SDoug Rabson = htonl(*(uint32_t *)info); 913dfdcada3SDoug Rabson break; 914dfdcada3SDoug Rabson case CLSET_ASYNC: 915dfdcada3SDoug Rabson cu->cu_async = *(int *)info; 916dfdcada3SDoug Rabson break; 917dfdcada3SDoug Rabson case CLSET_CONNECT: 918dfdcada3SDoug Rabson cu->cu_connect = *(int *)info; 919dfdcada3SDoug Rabson break; 920dfdcada3SDoug Rabson case CLSET_WAITCHAN: 921a9148abdSDoug Rabson cu->cu_waitchan = (const char *)info; 922dfdcada3SDoug Rabson break; 923dfdcada3SDoug Rabson case CLGET_WAITCHAN: 924dfdcada3SDoug Rabson *(const char **) info = cu->cu_waitchan; 925dfdcada3SDoug Rabson break; 926dfdcada3SDoug Rabson case CLSET_INTERRUPTIBLE: 927dfdcada3SDoug Rabson if (*(int *) info) 928dfdcada3SDoug Rabson cu->cu_waitflag = PCATCH; 929dfdcada3SDoug Rabson else 930dfdcada3SDoug Rabson cu->cu_waitflag = 0; 931dfdcada3SDoug Rabson break; 932dfdcada3SDoug Rabson case CLGET_INTERRUPTIBLE: 933dfdcada3SDoug Rabson if (cu->cu_waitflag) 934dfdcada3SDoug Rabson *(int *) info = TRUE; 935dfdcada3SDoug Rabson else 936dfdcada3SDoug Rabson *(int *) info = FALSE; 937dfdcada3SDoug Rabson break; 938dfdcada3SDoug Rabson default: 939dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 940dfdcada3SDoug Rabson return (FALSE); 941dfdcada3SDoug Rabson } 942dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 943dfdcada3SDoug Rabson return (TRUE); 944dfdcada3SDoug Rabson } 945dfdcada3SDoug Rabson 946dfdcada3SDoug Rabson static void 947a9148abdSDoug Rabson clnt_dg_close(CLIENT *cl) 948dfdcada3SDoug Rabson { 949dfdcada3SDoug Rabson struct cu_data *cu = (struct cu_data *)cl->cl_private; 95074fb0ba7SJohn Baldwin struct cu_socket *cs; 951c675522fSDoug Rabson struct cu_request *cr; 952dfdcada3SDoug Rabson 95374fb0ba7SJohn Baldwin cs = cu->cu_socket->so_rcv.sb_upcallarg; 954dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 955c675522fSDoug Rabson 956a9148abdSDoug Rabson if (cu->cu_closed) { 957a9148abdSDoug Rabson mtx_unlock(&cs->cs_lock); 958a9148abdSDoug Rabson return; 959a9148abdSDoug Rabson } 960a9148abdSDoug Rabson 961a9148abdSDoug Rabson if (cu->cu_closing) { 962a9148abdSDoug Rabson while (cu->cu_closing) 963a9148abdSDoug Rabson msleep(cu, &cs->cs_lock, 0, "rpcclose", 0); 964a9148abdSDoug Rabson KASSERT(cu->cu_closed, ("client should be closed")); 965a9148abdSDoug Rabson mtx_unlock(&cs->cs_lock); 966a9148abdSDoug Rabson return; 967a9148abdSDoug Rabson } 968a9148abdSDoug Rabson 969c675522fSDoug Rabson /* 970c675522fSDoug Rabson * Abort any pending requests and wait until everyone 971c675522fSDoug Rabson * has finished with clnt_vc_call. 972c675522fSDoug Rabson */ 973c675522fSDoug Rabson cu->cu_closing = TRUE; 974c675522fSDoug Rabson TAILQ_FOREACH(cr, &cs->cs_pending, cr_link) { 975c675522fSDoug Rabson if (cr->cr_client == cl) { 976c675522fSDoug Rabson cr->cr_xid = 0; 977c675522fSDoug Rabson cr->cr_error = ESHUTDOWN; 978c675522fSDoug Rabson wakeup(cr); 979c675522fSDoug Rabson } 980c675522fSDoug Rabson } 981c675522fSDoug Rabson 982c675522fSDoug Rabson while (cu->cu_threads) 983c675522fSDoug Rabson msleep(cu, &cs->cs_lock, 0, "rpcclose", 0); 984c675522fSDoug Rabson 985a9148abdSDoug Rabson cu->cu_closing = FALSE; 986a9148abdSDoug Rabson cu->cu_closed = TRUE; 987a9148abdSDoug Rabson 988a9148abdSDoug Rabson mtx_unlock(&cs->cs_lock); 989a9148abdSDoug Rabson wakeup(cu); 990a9148abdSDoug Rabson } 991a9148abdSDoug Rabson 992a9148abdSDoug Rabson static void 993a9148abdSDoug Rabson clnt_dg_destroy(CLIENT *cl) 994a9148abdSDoug Rabson { 995a9148abdSDoug Rabson struct cu_data *cu = (struct cu_data *)cl->cl_private; 99674fb0ba7SJohn Baldwin struct cu_socket *cs; 997a9148abdSDoug Rabson struct socket *so = NULL; 998a9148abdSDoug Rabson bool_t lastsocketref; 999a9148abdSDoug Rabson 100074fb0ba7SJohn Baldwin cs = cu->cu_socket->so_rcv.sb_upcallarg; 1001a9148abdSDoug Rabson clnt_dg_close(cl); 1002a9148abdSDoug Rabson 10032ba47632SRick Macklem SOCKBUF_LOCK(&cu->cu_socket->so_rcv); 1004a9148abdSDoug Rabson mtx_lock(&cs->cs_lock); 1005a9148abdSDoug Rabson 1006dfdcada3SDoug Rabson cs->cs_refs--; 1007dfdcada3SDoug Rabson if (cs->cs_refs == 0) { 10083144f812SRick Macklem mtx_unlock(&cs->cs_lock); 100974fb0ba7SJohn Baldwin soupcall_clear(cu->cu_socket, SO_RCV); 10103144f812SRick Macklem clnt_dg_upcallsdone(cu->cu_socket, cs); 1011dfdcada3SDoug Rabson SOCKBUF_UNLOCK(&cu->cu_socket->so_rcv); 10123144f812SRick Macklem mtx_destroy(&cs->cs_lock); 1013dfdcada3SDoug Rabson mem_free(cs, sizeof(*cs)); 1014dfdcada3SDoug Rabson lastsocketref = TRUE; 1015dfdcada3SDoug Rabson } else { 1016dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 10172ba47632SRick Macklem SOCKBUF_UNLOCK(&cu->cu_socket->so_rcv); 1018dfdcada3SDoug Rabson lastsocketref = FALSE; 1019dfdcada3SDoug Rabson } 1020dfdcada3SDoug Rabson 1021c675522fSDoug Rabson if (cu->cu_closeit && lastsocketref) { 1022dfdcada3SDoug Rabson so = cu->cu_socket; 1023dfdcada3SDoug Rabson cu->cu_socket = NULL; 1024dfdcada3SDoug Rabson } 1025dfdcada3SDoug Rabson 1026dfdcada3SDoug Rabson if (so) 1027dfdcada3SDoug Rabson soclose(so); 1028dfdcada3SDoug Rabson 1029dfdcada3SDoug Rabson if (cl->cl_netid && cl->cl_netid[0]) 1030dfdcada3SDoug Rabson mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); 1031dfdcada3SDoug Rabson if (cl->cl_tp && cl->cl_tp[0]) 1032dfdcada3SDoug Rabson mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); 1033dfdcada3SDoug Rabson mem_free(cu, sizeof (*cu)); 1034dfdcada3SDoug Rabson mem_free(cl, sizeof (CLIENT)); 1035dfdcada3SDoug Rabson } 1036dfdcada3SDoug Rabson 1037dfdcada3SDoug Rabson /* 1038dfdcada3SDoug Rabson * Make sure that the time is not garbage. -1 value is allowed. 1039dfdcada3SDoug Rabson */ 1040dfdcada3SDoug Rabson static bool_t 1041dfdcada3SDoug Rabson time_not_ok(struct timeval *t) 1042dfdcada3SDoug Rabson { 1043dfdcada3SDoug Rabson return (t->tv_sec < -1 || t->tv_sec > 100000000 || 1044dfdcada3SDoug Rabson t->tv_usec < -1 || t->tv_usec > 1000000); 1045dfdcada3SDoug Rabson } 1046dfdcada3SDoug Rabson 104774fb0ba7SJohn Baldwin int 1048dfdcada3SDoug Rabson clnt_dg_soupcall(struct socket *so, void *arg, int waitflag) 1049dfdcada3SDoug Rabson { 1050dfdcada3SDoug Rabson struct cu_socket *cs = (struct cu_socket *) arg; 1051dfdcada3SDoug Rabson struct uio uio; 1052dfdcada3SDoug Rabson struct mbuf *m; 1053dfdcada3SDoug Rabson struct mbuf *control; 1054dfdcada3SDoug Rabson struct cu_request *cr; 1055dfdcada3SDoug Rabson int error, rcvflag, foundreq; 1056dfdcada3SDoug Rabson uint32_t xid; 1057dfdcada3SDoug Rabson 10583144f812SRick Macklem cs->cs_upcallrefs++; 1059dfdcada3SDoug Rabson uio.uio_resid = 1000000000; 1060dfdcada3SDoug Rabson uio.uio_td = curthread; 1061dfdcada3SDoug Rabson do { 106274fb0ba7SJohn Baldwin SOCKBUF_UNLOCK(&so->so_rcv); 1063dfdcada3SDoug Rabson m = NULL; 1064dfdcada3SDoug Rabson control = NULL; 1065dfdcada3SDoug Rabson rcvflag = MSG_DONTWAIT; 1066dfdcada3SDoug Rabson error = soreceive(so, NULL, &uio, &m, &control, &rcvflag); 1067dfdcada3SDoug Rabson if (control) 1068dfdcada3SDoug Rabson m_freem(control); 106974fb0ba7SJohn Baldwin SOCKBUF_LOCK(&so->so_rcv); 1070dfdcada3SDoug Rabson 1071dfdcada3SDoug Rabson if (error == EWOULDBLOCK) 1072dfdcada3SDoug Rabson break; 1073dfdcada3SDoug Rabson 1074dfdcada3SDoug Rabson /* 1075dfdcada3SDoug Rabson * If there was an error, wake up all pending 1076dfdcada3SDoug Rabson * requests. 1077dfdcada3SDoug Rabson */ 1078dfdcada3SDoug Rabson if (error) { 1079dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 1080dfdcada3SDoug Rabson TAILQ_FOREACH(cr, &cs->cs_pending, cr_link) { 1081c675522fSDoug Rabson cr->cr_xid = 0; 1082dfdcada3SDoug Rabson cr->cr_error = error; 1083dfdcada3SDoug Rabson wakeup(cr); 1084dfdcada3SDoug Rabson } 1085dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 1086dfdcada3SDoug Rabson break; 1087dfdcada3SDoug Rabson } 1088dfdcada3SDoug Rabson 1089dfdcada3SDoug Rabson /* 1090dfdcada3SDoug Rabson * The XID is in the first uint32_t of the reply. 1091dfdcada3SDoug Rabson */ 10925e8eb3cdSRick Macklem if (m->m_len < sizeof(xid) && m_length(m, NULL) < sizeof(xid)) { 1093c675522fSDoug Rabson /* 1094c675522fSDoug Rabson * Should never happen. 1095c675522fSDoug Rabson */ 10965e8eb3cdSRick Macklem m_freem(m); 1097c675522fSDoug Rabson continue; 10985e8eb3cdSRick Macklem } 1099c675522fSDoug Rabson 11002a1e0fb4SRick Macklem m_copydata(m, 0, sizeof(xid), (char *)&xid); 11012a1e0fb4SRick Macklem xid = ntohl(xid); 1102dfdcada3SDoug Rabson 1103dfdcada3SDoug Rabson /* 1104dfdcada3SDoug Rabson * Attempt to match this reply with a pending request. 1105dfdcada3SDoug Rabson */ 1106dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 1107dfdcada3SDoug Rabson foundreq = 0; 1108dfdcada3SDoug Rabson TAILQ_FOREACH(cr, &cs->cs_pending, cr_link) { 1109dfdcada3SDoug Rabson if (cr->cr_xid == xid) { 1110dfdcada3SDoug Rabson /* 1111c675522fSDoug Rabson * This one matches. We leave the 1112dfdcada3SDoug Rabson * reply mbuf in cr->cr_mrep. Set the 1113c675522fSDoug Rabson * XID to zero so that we will ignore 1114c675522fSDoug Rabson * any duplicated replies that arrive 1115c675522fSDoug Rabson * before clnt_dg_call removes it from 1116c675522fSDoug Rabson * the queue. 1117dfdcada3SDoug Rabson */ 1118dfdcada3SDoug Rabson cr->cr_xid = 0; 1119dfdcada3SDoug Rabson cr->cr_mrep = m; 1120dfdcada3SDoug Rabson cr->cr_error = 0; 1121dfdcada3SDoug Rabson foundreq = 1; 1122dfdcada3SDoug Rabson wakeup(cr); 1123dfdcada3SDoug Rabson break; 1124dfdcada3SDoug Rabson } 1125dfdcada3SDoug Rabson } 1126dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 1127dfdcada3SDoug Rabson 1128dfdcada3SDoug Rabson /* 1129dfdcada3SDoug Rabson * If we didn't find the matching request, just drop 1130dfdcada3SDoug Rabson * it - its probably a repeated reply. 1131dfdcada3SDoug Rabson */ 1132dfdcada3SDoug Rabson if (!foundreq) 1133dfdcada3SDoug Rabson m_freem(m); 1134dfdcada3SDoug Rabson } while (m); 11353144f812SRick Macklem cs->cs_upcallrefs--; 11363144f812SRick Macklem if (cs->cs_upcallrefs < 0) 11373144f812SRick Macklem panic("rpcdg upcall refcnt"); 11383144f812SRick Macklem if (cs->cs_upcallrefs == 0) 11393144f812SRick Macklem wakeup(&cs->cs_upcallrefs); 114074fb0ba7SJohn Baldwin return (SU_OK); 1141dfdcada3SDoug Rabson } 1142dfdcada3SDoug Rabson 11433144f812SRick Macklem /* 11443144f812SRick Macklem * Wait for all upcalls in progress to complete. 11453144f812SRick Macklem */ 11463144f812SRick Macklem static void 11473144f812SRick Macklem clnt_dg_upcallsdone(struct socket *so, struct cu_socket *cs) 11483144f812SRick Macklem { 11493144f812SRick Macklem 11503144f812SRick Macklem SOCKBUF_LOCK_ASSERT(&so->so_rcv); 11513144f812SRick Macklem 11523144f812SRick Macklem while (cs->cs_upcallrefs > 0) 11533144f812SRick Macklem (void) msleep(&cs->cs_upcallrefs, SOCKBUF_MTX(&so->so_rcv), 0, 11543144f812SRick Macklem "rpcdgup", 0); 11553144f812SRick Macklem } 1156