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