1dfdcada3SDoug Rabson /* $NetBSD: clnt_dg.c,v 1.4 2000/07/14 08:40:41 fvdl Exp $ */ 2dfdcada3SDoug Rabson 3dfdcada3SDoug Rabson /* 4dfdcada3SDoug Rabson * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 5dfdcada3SDoug Rabson * unrestricted use provided that this legend is included on all tape 6dfdcada3SDoug Rabson * media and as a part of the software program in whole or part. Users 7dfdcada3SDoug Rabson * may copy or modify Sun RPC without charge, but are not authorized 8dfdcada3SDoug Rabson * to license or distribute it to anyone else except as part of a product or 9dfdcada3SDoug Rabson * program developed by the user. 10dfdcada3SDoug Rabson * 11dfdcada3SDoug Rabson * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 12dfdcada3SDoug Rabson * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 13dfdcada3SDoug Rabson * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 14dfdcada3SDoug Rabson * 15dfdcada3SDoug Rabson * Sun RPC is provided with no support and without any obligation on the 16dfdcada3SDoug Rabson * part of Sun Microsystems, Inc. to assist in its use, correction, 17dfdcada3SDoug Rabson * modification or enhancement. 18dfdcada3SDoug Rabson * 19dfdcada3SDoug Rabson * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 20dfdcada3SDoug Rabson * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 21dfdcada3SDoug Rabson * OR ANY PART THEREOF. 22dfdcada3SDoug Rabson * 23dfdcada3SDoug Rabson * In no event will Sun Microsystems, Inc. be liable for any lost revenue 24dfdcada3SDoug Rabson * or profits or other special, indirect and consequential damages, even if 25dfdcada3SDoug Rabson * Sun has been advised of the possibility of such damages. 26dfdcada3SDoug Rabson * 27dfdcada3SDoug Rabson * Sun Microsystems, Inc. 28dfdcada3SDoug Rabson * 2550 Garcia Avenue 29dfdcada3SDoug Rabson * Mountain View, California 94043 30dfdcada3SDoug Rabson */ 31dfdcada3SDoug Rabson /* 32dfdcada3SDoug Rabson * Copyright (c) 1986-1991 by Sun Microsystems Inc. 33dfdcada3SDoug Rabson */ 34dfdcada3SDoug Rabson 35dfdcada3SDoug Rabson #if defined(LIBC_SCCS) && !defined(lint) 36dfdcada3SDoug Rabson #ident "@(#)clnt_dg.c 1.23 94/04/22 SMI" 37dfdcada3SDoug Rabson static char sccsid[] = "@(#)clnt_dg.c 1.19 89/03/16 Copyr 1988 Sun Micro"; 38dfdcada3SDoug Rabson #endif 39dfdcada3SDoug Rabson #include <sys/cdefs.h> 40dfdcada3SDoug Rabson __FBSDID("$FreeBSD$"); 41dfdcada3SDoug Rabson 42dfdcada3SDoug Rabson /* 43dfdcada3SDoug Rabson * Implements a connectionless client side RPC. 44dfdcada3SDoug Rabson */ 45dfdcada3SDoug Rabson 46dfdcada3SDoug Rabson #include <sys/param.h> 47dfdcada3SDoug Rabson #include <sys/systm.h> 48c675522fSDoug Rabson #include <sys/kernel.h> 49dfdcada3SDoug Rabson #include <sys/lock.h> 50dfdcada3SDoug Rabson #include <sys/malloc.h> 51dfdcada3SDoug Rabson #include <sys/mbuf.h> 52dfdcada3SDoug Rabson #include <sys/mutex.h> 53dfdcada3SDoug Rabson #include <sys/pcpu.h> 54dfdcada3SDoug Rabson #include <sys/proc.h> 55dfdcada3SDoug Rabson #include <sys/socket.h> 56dfdcada3SDoug Rabson #include <sys/socketvar.h> 57dfdcada3SDoug Rabson #include <sys/time.h> 58dfdcada3SDoug Rabson #include <sys/uio.h> 59dfdcada3SDoug Rabson 600348c661SMarko Zec #include <net/vnet.h> 610348c661SMarko Zec 62dfdcada3SDoug Rabson #include <rpc/rpc.h> 63ee31b83aSDoug Rabson #include <rpc/rpc_com.h> 64dfdcada3SDoug Rabson 65dfdcada3SDoug Rabson 66dfdcada3SDoug Rabson #ifdef _FREEFALL_CONFIG 67dfdcada3SDoug Rabson /* 68dfdcada3SDoug Rabson * Disable RPC exponential back-off for FreeBSD.org systems. 69dfdcada3SDoug Rabson */ 70dfdcada3SDoug Rabson #define RPC_MAX_BACKOFF 1 /* second */ 71dfdcada3SDoug Rabson #else 72dfdcada3SDoug Rabson #define RPC_MAX_BACKOFF 30 /* seconds */ 73dfdcada3SDoug Rabson #endif 74dfdcada3SDoug Rabson 75dfdcada3SDoug Rabson static bool_t time_not_ok(struct timeval *); 76c675522fSDoug Rabson static enum clnt_stat clnt_dg_call(CLIENT *, struct rpc_callextra *, 77a9148abdSDoug Rabson rpcproc_t, struct mbuf *, struct mbuf **, struct timeval); 78dfdcada3SDoug Rabson static void clnt_dg_geterr(CLIENT *, struct rpc_err *); 79dfdcada3SDoug Rabson static bool_t clnt_dg_freeres(CLIENT *, xdrproc_t, void *); 80dfdcada3SDoug Rabson static void clnt_dg_abort(CLIENT *); 81dfdcada3SDoug Rabson static bool_t clnt_dg_control(CLIENT *, u_int, void *); 82a9148abdSDoug Rabson static void clnt_dg_close(CLIENT *); 83dfdcada3SDoug Rabson static void clnt_dg_destroy(CLIENT *); 8474fb0ba7SJohn Baldwin static int clnt_dg_soupcall(struct socket *so, void *arg, int waitflag); 85dfdcada3SDoug Rabson 86dfdcada3SDoug Rabson static struct clnt_ops clnt_dg_ops = { 87dfdcada3SDoug Rabson .cl_call = clnt_dg_call, 88dfdcada3SDoug Rabson .cl_abort = clnt_dg_abort, 89dfdcada3SDoug Rabson .cl_geterr = clnt_dg_geterr, 90dfdcada3SDoug Rabson .cl_freeres = clnt_dg_freeres, 91a9148abdSDoug Rabson .cl_close = clnt_dg_close, 92dfdcada3SDoug Rabson .cl_destroy = clnt_dg_destroy, 93dfdcada3SDoug Rabson .cl_control = clnt_dg_control 94dfdcada3SDoug Rabson }; 95dfdcada3SDoug Rabson 96dfdcada3SDoug Rabson static const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory"; 97dfdcada3SDoug Rabson 98dfdcada3SDoug Rabson /* 99c675522fSDoug Rabson * A pending RPC request which awaits a reply. Requests which have 100c675522fSDoug Rabson * received their reply will have cr_xid set to zero and cr_mrep to 101c675522fSDoug Rabson * the mbuf chain of the reply. 102dfdcada3SDoug Rabson */ 103dfdcada3SDoug Rabson struct cu_request { 104dfdcada3SDoug Rabson TAILQ_ENTRY(cu_request) cr_link; 105c675522fSDoug Rabson CLIENT *cr_client; /* owner */ 106dfdcada3SDoug Rabson uint32_t cr_xid; /* XID of request */ 107dfdcada3SDoug Rabson struct mbuf *cr_mrep; /* reply received by upcall */ 108dfdcada3SDoug Rabson int cr_error; /* any error from upcall */ 109a9148abdSDoug Rabson char cr_verf[MAX_AUTH_BYTES]; /* reply verf */ 110dfdcada3SDoug Rabson }; 111dfdcada3SDoug Rabson 112dfdcada3SDoug Rabson TAILQ_HEAD(cu_request_list, cu_request); 113dfdcada3SDoug Rabson 114dfdcada3SDoug Rabson #define MCALL_MSG_SIZE 24 115dfdcada3SDoug Rabson 116dfdcada3SDoug Rabson /* 11774fb0ba7SJohn Baldwin * This structure is pointed to by the socket buffer's sb_upcallarg 118dfdcada3SDoug Rabson * member. It is separate from the client private data to facilitate 119dfdcada3SDoug Rabson * multiple clients sharing the same socket. The cs_lock mutex is used 120dfdcada3SDoug Rabson * to protect all fields of this structure, the socket's receive 121dfdcada3SDoug Rabson * buffer SOCKBUF_LOCK is used to ensure that exactly one of these 122dfdcada3SDoug Rabson * structures is installed on the socket. 123dfdcada3SDoug Rabson */ 124dfdcada3SDoug Rabson struct cu_socket { 125dfdcada3SDoug Rabson struct mtx cs_lock; 126dfdcada3SDoug Rabson int cs_refs; /* Count of clients */ 127dfdcada3SDoug Rabson struct cu_request_list cs_pending; /* Requests awaiting replies */ 1283144f812SRick Macklem int cs_upcallrefs; /* Refcnt of upcalls in prog.*/ 129dfdcada3SDoug Rabson }; 130dfdcada3SDoug Rabson 1313144f812SRick Macklem static void clnt_dg_upcallsdone(struct socket *, struct cu_socket *); 1323144f812SRick Macklem 133dfdcada3SDoug Rabson /* 134dfdcada3SDoug Rabson * Private data kept per client handle 135dfdcada3SDoug Rabson */ 136dfdcada3SDoug Rabson struct cu_data { 137c675522fSDoug Rabson int cu_threads; /* # threads in clnt_vc_call */ 138a9148abdSDoug Rabson bool_t cu_closing; /* TRUE if we are closing */ 139a9148abdSDoug Rabson bool_t cu_closed; /* TRUE if we are closed */ 140dfdcada3SDoug Rabson struct socket *cu_socket; /* connection socket */ 141dfdcada3SDoug Rabson bool_t cu_closeit; /* opened by library */ 142dfdcada3SDoug Rabson struct sockaddr_storage cu_raddr; /* remote address */ 143dfdcada3SDoug Rabson int cu_rlen; 144dfdcada3SDoug Rabson struct timeval cu_wait; /* retransmit interval */ 145dfdcada3SDoug Rabson struct timeval cu_total; /* total time for the call */ 146dfdcada3SDoug Rabson struct rpc_err cu_error; 147dfdcada3SDoug Rabson uint32_t cu_xid; 148dfdcada3SDoug Rabson char cu_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */ 149dfdcada3SDoug Rabson size_t cu_mcalllen; 150dfdcada3SDoug Rabson size_t cu_sendsz; /* send size */ 151dfdcada3SDoug Rabson size_t cu_recvsz; /* recv size */ 152dfdcada3SDoug Rabson int cu_async; 153dfdcada3SDoug Rabson int cu_connect; /* Use connect(). */ 154dfdcada3SDoug Rabson int cu_connected; /* Have done connect(). */ 155dfdcada3SDoug Rabson const char *cu_waitchan; 156dfdcada3SDoug Rabson int cu_waitflag; 157a9148abdSDoug Rabson int cu_cwnd; /* congestion window */ 158a9148abdSDoug Rabson int cu_sent; /* number of in-flight RPCs */ 159a9148abdSDoug Rabson bool_t cu_cwnd_wait; 160dfdcada3SDoug Rabson }; 161dfdcada3SDoug Rabson 162a9148abdSDoug Rabson #define CWNDSCALE 256 163a9148abdSDoug Rabson #define MAXCWND (32 * CWNDSCALE) 164a9148abdSDoug Rabson 165dfdcada3SDoug Rabson /* 166dfdcada3SDoug Rabson * Connection less client creation returns with client handle parameters. 167dfdcada3SDoug Rabson * Default options are set, which the user can change using clnt_control(). 168dfdcada3SDoug Rabson * fd should be open and bound. 169dfdcada3SDoug Rabson * NB: The rpch->cl_auth is initialized to null authentication. 170dfdcada3SDoug Rabson * Caller may wish to set this something more useful. 171dfdcada3SDoug Rabson * 172dfdcada3SDoug Rabson * sendsz and recvsz are the maximum allowable packet sizes that can be 173dfdcada3SDoug Rabson * sent and received. Normally they are the same, but they can be 174dfdcada3SDoug Rabson * changed to improve the program efficiency and buffer allocation. 175dfdcada3SDoug Rabson * If they are 0, use the transport default. 176dfdcada3SDoug Rabson * 177dfdcada3SDoug Rabson * If svcaddr is NULL, returns NULL. 178dfdcada3SDoug Rabson */ 179dfdcada3SDoug Rabson CLIENT * 180dfdcada3SDoug Rabson clnt_dg_create( 181dfdcada3SDoug Rabson struct socket *so, 182dfdcada3SDoug Rabson struct sockaddr *svcaddr, /* servers address */ 183dfdcada3SDoug Rabson rpcprog_t program, /* program number */ 184dfdcada3SDoug Rabson rpcvers_t version, /* version number */ 185dfdcada3SDoug Rabson size_t sendsz, /* buffer recv size */ 186dfdcada3SDoug Rabson size_t recvsz) /* buffer send size */ 187dfdcada3SDoug Rabson { 188dfdcada3SDoug Rabson CLIENT *cl = NULL; /* client handle */ 189dfdcada3SDoug Rabson struct cu_data *cu = NULL; /* private data */ 190dfdcada3SDoug Rabson struct cu_socket *cs = NULL; 19174fb0ba7SJohn Baldwin struct sockbuf *sb; 192dfdcada3SDoug Rabson struct timeval now; 193dfdcada3SDoug Rabson struct rpc_msg call_msg; 194dfdcada3SDoug Rabson struct __rpc_sockinfo si; 195dfdcada3SDoug Rabson XDR xdrs; 196cec077bcSRick Macklem int error; 197dfdcada3SDoug Rabson 198dfdcada3SDoug Rabson if (svcaddr == NULL) { 199dfdcada3SDoug Rabson rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 200dfdcada3SDoug Rabson return (NULL); 201dfdcada3SDoug Rabson } 202dfdcada3SDoug Rabson 2030348c661SMarko Zec CURVNET_SET(so->so_vnet); 204dfdcada3SDoug Rabson if (!__rpc_socket2sockinfo(so, &si)) { 205dfdcada3SDoug Rabson rpc_createerr.cf_stat = RPC_TLIERROR; 206dfdcada3SDoug Rabson rpc_createerr.cf_error.re_errno = 0; 2070348c661SMarko Zec CURVNET_RESTORE(); 208dfdcada3SDoug Rabson return (NULL); 209dfdcada3SDoug Rabson } 2100348c661SMarko Zec CURVNET_RESTORE(); 211dfdcada3SDoug Rabson 212dfdcada3SDoug Rabson /* 213dfdcada3SDoug Rabson * Find the receive and the send size 214dfdcada3SDoug Rabson */ 215dfdcada3SDoug Rabson sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 216dfdcada3SDoug Rabson recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 217dfdcada3SDoug Rabson if ((sendsz == 0) || (recvsz == 0)) { 218dfdcada3SDoug Rabson rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */ 219dfdcada3SDoug Rabson rpc_createerr.cf_error.re_errno = 0; 220dfdcada3SDoug Rabson return (NULL); 221dfdcada3SDoug Rabson } 222dfdcada3SDoug Rabson 223dfdcada3SDoug Rabson cl = mem_alloc(sizeof (CLIENT)); 224dfdcada3SDoug Rabson 225dfdcada3SDoug Rabson /* 226dfdcada3SDoug Rabson * Should be multiple of 4 for XDR. 227dfdcada3SDoug Rabson */ 228dfdcada3SDoug Rabson sendsz = ((sendsz + 3) / 4) * 4; 229dfdcada3SDoug Rabson recvsz = ((recvsz + 3) / 4) * 4; 230dfdcada3SDoug Rabson cu = mem_alloc(sizeof (*cu)); 231c675522fSDoug Rabson cu->cu_threads = 0; 232c675522fSDoug Rabson cu->cu_closing = FALSE; 233a9148abdSDoug Rabson cu->cu_closed = FALSE; 234dfdcada3SDoug Rabson (void) memcpy(&cu->cu_raddr, svcaddr, (size_t)svcaddr->sa_len); 235dfdcada3SDoug Rabson cu->cu_rlen = svcaddr->sa_len; 236dfdcada3SDoug Rabson /* Other values can also be set through clnt_control() */ 237c675522fSDoug Rabson cu->cu_wait.tv_sec = 3; /* heuristically chosen */ 238dfdcada3SDoug Rabson cu->cu_wait.tv_usec = 0; 239dfdcada3SDoug Rabson cu->cu_total.tv_sec = -1; 240dfdcada3SDoug Rabson cu->cu_total.tv_usec = -1; 241dfdcada3SDoug Rabson cu->cu_sendsz = sendsz; 242dfdcada3SDoug Rabson cu->cu_recvsz = recvsz; 243dfdcada3SDoug Rabson cu->cu_async = FALSE; 244dfdcada3SDoug Rabson cu->cu_connect = FALSE; 245dfdcada3SDoug Rabson cu->cu_connected = FALSE; 246dfdcada3SDoug Rabson cu->cu_waitchan = "rpcrecv"; 247dfdcada3SDoug Rabson cu->cu_waitflag = 0; 248a9148abdSDoug Rabson cu->cu_cwnd = MAXCWND / 2; 249a9148abdSDoug Rabson cu->cu_sent = 0; 250a9148abdSDoug Rabson cu->cu_cwnd_wait = FALSE; 251dfdcada3SDoug Rabson (void) getmicrotime(&now); 252dfdcada3SDoug Rabson cu->cu_xid = __RPC_GETXID(&now); 253dfdcada3SDoug Rabson call_msg.rm_xid = cu->cu_xid; 254dfdcada3SDoug Rabson call_msg.rm_call.cb_prog = program; 255dfdcada3SDoug Rabson call_msg.rm_call.cb_vers = version; 256dfdcada3SDoug Rabson xdrmem_create(&xdrs, cu->cu_mcallc, MCALL_MSG_SIZE, XDR_ENCODE); 257dfdcada3SDoug Rabson if (! xdr_callhdr(&xdrs, &call_msg)) { 258dfdcada3SDoug Rabson rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */ 259dfdcada3SDoug Rabson rpc_createerr.cf_error.re_errno = 0; 260dfdcada3SDoug Rabson goto err2; 261dfdcada3SDoug Rabson } 262c2ede4b3SMartin Blapp cu->cu_mcalllen = XDR_GETPOS(&xdrs); 263dfdcada3SDoug Rabson 264dfdcada3SDoug Rabson /* 265dfdcada3SDoug Rabson * By default, closeit is always FALSE. It is users responsibility 266dfdcada3SDoug Rabson * to do a close on it, else the user may use clnt_control 267dfdcada3SDoug Rabson * to let clnt_destroy do it for him/her. 268dfdcada3SDoug Rabson */ 269dfdcada3SDoug Rabson cu->cu_closeit = FALSE; 270dfdcada3SDoug Rabson cu->cu_socket = so; 271cec077bcSRick Macklem error = soreserve(so, (u_long)sendsz, (u_long)recvsz); 272cec077bcSRick Macklem if (error != 0) { 273cec077bcSRick Macklem rpc_createerr.cf_stat = RPC_FAILED; 274cec077bcSRick Macklem rpc_createerr.cf_error.re_errno = error; 275cec077bcSRick Macklem goto err2; 276cec077bcSRick Macklem } 277dfdcada3SDoug Rabson 27874fb0ba7SJohn Baldwin sb = &so->so_rcv; 279dfdcada3SDoug Rabson SOCKBUF_LOCK(&so->so_rcv); 280dfdcada3SDoug Rabson recheck_socket: 28174fb0ba7SJohn Baldwin if (sb->sb_upcall) { 28274fb0ba7SJohn Baldwin if (sb->sb_upcall != clnt_dg_soupcall) { 283dfdcada3SDoug Rabson SOCKBUF_UNLOCK(&so->so_rcv); 284dfdcada3SDoug Rabson printf("clnt_dg_create(): socket already has an incompatible upcall\n"); 285dfdcada3SDoug Rabson goto err2; 286dfdcada3SDoug Rabson } 28774fb0ba7SJohn Baldwin cs = (struct cu_socket *) sb->sb_upcallarg; 288dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 289dfdcada3SDoug Rabson cs->cs_refs++; 290dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 291dfdcada3SDoug Rabson } else { 292dfdcada3SDoug Rabson /* 293dfdcada3SDoug Rabson * We are the first on this socket - allocate the 294dfdcada3SDoug Rabson * structure and install it in the socket. 295dfdcada3SDoug Rabson */ 29674fb0ba7SJohn Baldwin SOCKBUF_UNLOCK(&so->so_rcv); 297dfdcada3SDoug Rabson cs = mem_alloc(sizeof(*cs)); 29874fb0ba7SJohn Baldwin SOCKBUF_LOCK(&so->so_rcv); 29974fb0ba7SJohn Baldwin if (sb->sb_upcall) { 300dfdcada3SDoug Rabson /* 301dfdcada3SDoug Rabson * We have lost a race with some other client. 302dfdcada3SDoug Rabson */ 303dfdcada3SDoug Rabson mem_free(cs, sizeof(*cs)); 304dfdcada3SDoug Rabson goto recheck_socket; 305dfdcada3SDoug Rabson } 306dfdcada3SDoug Rabson mtx_init(&cs->cs_lock, "cs->cs_lock", NULL, MTX_DEF); 307dfdcada3SDoug Rabson cs->cs_refs = 1; 3083144f812SRick Macklem cs->cs_upcallrefs = 0; 309dfdcada3SDoug Rabson TAILQ_INIT(&cs->cs_pending); 31074fb0ba7SJohn Baldwin soupcall_set(so, SO_RCV, clnt_dg_soupcall, cs); 311dfdcada3SDoug Rabson } 312dfdcada3SDoug Rabson SOCKBUF_UNLOCK(&so->so_rcv); 313dfdcada3SDoug Rabson 314c675522fSDoug Rabson cl->cl_refs = 1; 315dfdcada3SDoug Rabson cl->cl_ops = &clnt_dg_ops; 316dfdcada3SDoug Rabson cl->cl_private = (caddr_t)(void *)cu; 317dfdcada3SDoug Rabson cl->cl_auth = authnone_create(); 318dfdcada3SDoug Rabson cl->cl_tp = NULL; 319dfdcada3SDoug Rabson cl->cl_netid = NULL; 320dfdcada3SDoug Rabson return (cl); 321dfdcada3SDoug Rabson err2: 322dfdcada3SDoug Rabson if (cl) { 323dfdcada3SDoug Rabson mem_free(cl, sizeof (CLIENT)); 324dfdcada3SDoug Rabson if (cu) 325dfdcada3SDoug Rabson mem_free(cu, sizeof (*cu)); 326dfdcada3SDoug Rabson } 327dfdcada3SDoug Rabson return (NULL); 328dfdcada3SDoug Rabson } 329dfdcada3SDoug Rabson 330dfdcada3SDoug Rabson static enum clnt_stat 331dfdcada3SDoug Rabson clnt_dg_call( 332dfdcada3SDoug Rabson CLIENT *cl, /* client handle */ 333c675522fSDoug Rabson struct rpc_callextra *ext, /* call metadata */ 334dfdcada3SDoug Rabson rpcproc_t proc, /* procedure number */ 335a9148abdSDoug Rabson struct mbuf *args, /* pointer to args */ 336a9148abdSDoug Rabson struct mbuf **resultsp, /* pointer to results */ 337dfdcada3SDoug Rabson struct timeval utimeout) /* seconds to wait before giving up */ 338dfdcada3SDoug Rabson { 339dfdcada3SDoug Rabson struct cu_data *cu = (struct cu_data *)cl->cl_private; 34074fb0ba7SJohn Baldwin struct cu_socket *cs; 341a9148abdSDoug Rabson struct rpc_timers *rt; 342c675522fSDoug Rabson AUTH *auth; 343a9148abdSDoug Rabson struct rpc_err *errp; 344a9148abdSDoug Rabson enum clnt_stat stat; 345dfdcada3SDoug Rabson XDR xdrs; 346dfdcada3SDoug Rabson struct rpc_msg reply_msg; 347dfdcada3SDoug Rabson bool_t ok; 348c675522fSDoug Rabson int retrans; /* number of re-transmits so far */ 349dfdcada3SDoug Rabson int nrefreshes = 2; /* number of times to refresh cred */ 350c675522fSDoug Rabson struct timeval *tvp; 351c675522fSDoug Rabson int timeout; 352c675522fSDoug Rabson int retransmit_time; 353a9148abdSDoug Rabson int next_sendtime, starttime, rtt, time_waited, tv = 0; 354dfdcada3SDoug Rabson struct sockaddr *sa; 355dfdcada3SDoug Rabson socklen_t salen; 356a9148abdSDoug Rabson uint32_t xid = 0; 357a9148abdSDoug Rabson struct mbuf *mreq = NULL, *results; 358c675522fSDoug Rabson struct cu_request *cr; 359dfdcada3SDoug Rabson int error; 360dfdcada3SDoug Rabson 36174fb0ba7SJohn Baldwin cs = cu->cu_socket->so_rcv.sb_upcallarg; 362c675522fSDoug Rabson cr = malloc(sizeof(struct cu_request), M_RPC, M_WAITOK); 363c675522fSDoug Rabson 364dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 365dfdcada3SDoug Rabson 366a9148abdSDoug Rabson if (cu->cu_closing || cu->cu_closed) { 367c675522fSDoug Rabson mtx_unlock(&cs->cs_lock); 368c675522fSDoug Rabson free(cr, M_RPC); 369c675522fSDoug Rabson return (RPC_CANTSEND); 370c675522fSDoug Rabson } 371c675522fSDoug Rabson cu->cu_threads++; 372c675522fSDoug Rabson 373a9148abdSDoug Rabson if (ext) { 374c675522fSDoug Rabson auth = ext->rc_auth; 375a9148abdSDoug Rabson errp = &ext->rc_err; 376a9148abdSDoug Rabson } else { 377c675522fSDoug Rabson auth = cl->cl_auth; 378a9148abdSDoug Rabson errp = &cu->cu_error; 379a9148abdSDoug Rabson } 380c675522fSDoug Rabson 381c675522fSDoug Rabson cr->cr_client = cl; 382c675522fSDoug Rabson cr->cr_mrep = NULL; 383c675522fSDoug Rabson cr->cr_error = 0; 384dfdcada3SDoug Rabson 385dfdcada3SDoug Rabson if (cu->cu_total.tv_usec == -1) { 386c675522fSDoug Rabson tvp = &utimeout; /* use supplied timeout */ 387dfdcada3SDoug Rabson } else { 388c675522fSDoug Rabson tvp = &cu->cu_total; /* use default timeout */ 389dfdcada3SDoug Rabson } 390c675522fSDoug Rabson if (tvp->tv_sec || tvp->tv_usec) 391c675522fSDoug Rabson timeout = tvtohz(tvp); 392c675522fSDoug Rabson else 393c675522fSDoug Rabson timeout = 0; 394dfdcada3SDoug Rabson 395dfdcada3SDoug Rabson if (cu->cu_connect && !cu->cu_connected) { 396dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 397dfdcada3SDoug Rabson error = soconnect(cu->cu_socket, 398dfdcada3SDoug Rabson (struct sockaddr *)&cu->cu_raddr, curthread); 399dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 400dfdcada3SDoug Rabson if (error) { 401a9148abdSDoug Rabson errp->re_errno = error; 402a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTSEND; 403dfdcada3SDoug Rabson goto out; 404dfdcada3SDoug Rabson } 405dfdcada3SDoug Rabson cu->cu_connected = 1; 406dfdcada3SDoug Rabson } 407dfdcada3SDoug Rabson if (cu->cu_connected) { 408dfdcada3SDoug Rabson sa = NULL; 409dfdcada3SDoug Rabson salen = 0; 410dfdcada3SDoug Rabson } else { 411dfdcada3SDoug Rabson sa = (struct sockaddr *)&cu->cu_raddr; 412dfdcada3SDoug Rabson salen = cu->cu_rlen; 413dfdcada3SDoug Rabson } 414c675522fSDoug Rabson time_waited = 0; 415c675522fSDoug Rabson retrans = 0; 416a9148abdSDoug Rabson if (ext && ext->rc_timers) { 417a9148abdSDoug Rabson rt = ext->rc_timers; 418a9148abdSDoug Rabson if (!rt->rt_rtxcur) 419a9148abdSDoug Rabson rt->rt_rtxcur = tvtohz(&cu->cu_wait); 420a9148abdSDoug Rabson retransmit_time = next_sendtime = rt->rt_rtxcur; 421a9148abdSDoug Rabson } else { 422a9148abdSDoug Rabson rt = NULL; 423c675522fSDoug Rabson retransmit_time = next_sendtime = tvtohz(&cu->cu_wait); 424a9148abdSDoug Rabson } 425dfdcada3SDoug Rabson 426c675522fSDoug Rabson starttime = ticks; 427dfdcada3SDoug Rabson 428dfdcada3SDoug Rabson call_again: 429dfdcada3SDoug Rabson mtx_assert(&cs->cs_lock, MA_OWNED); 430dfdcada3SDoug Rabson 431dfdcada3SDoug Rabson cu->cu_xid++; 432dfdcada3SDoug Rabson xid = cu->cu_xid; 433dfdcada3SDoug Rabson 434dfdcada3SDoug Rabson send_again: 435dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 436dfdcada3SDoug Rabson 437dfdcada3SDoug Rabson MGETHDR(mreq, M_WAIT, MT_DATA); 438a9148abdSDoug Rabson KASSERT(cu->cu_mcalllen <= MHLEN, ("RPC header too big")); 439a9148abdSDoug Rabson bcopy(cu->cu_mcallc, mreq->m_data, cu->cu_mcalllen); 440a9148abdSDoug Rabson mreq->m_len = cu->cu_mcalllen; 441dfdcada3SDoug Rabson 442dfdcada3SDoug Rabson /* 443dfdcada3SDoug Rabson * The XID is the first thing in the request. 444dfdcada3SDoug Rabson */ 445dfdcada3SDoug Rabson *mtod(mreq, uint32_t *) = htonl(xid); 446dfdcada3SDoug Rabson 447dfdcada3SDoug Rabson xdrmbuf_create(&xdrs, mreq, XDR_ENCODE); 448dfdcada3SDoug Rabson 449a9148abdSDoug Rabson if (cu->cu_async == TRUE && args == NULL) 450dfdcada3SDoug Rabson goto get_reply; 451dfdcada3SDoug Rabson 452dfdcada3SDoug Rabson if ((! XDR_PUTINT32(&xdrs, &proc)) || 453a9148abdSDoug Rabson (! AUTH_MARSHALL(auth, xid, &xdrs, 454a9148abdSDoug Rabson m_copym(args, 0, M_COPYALL, M_WAITOK)))) { 455a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTENCODEARGS; 456dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 457dfdcada3SDoug Rabson goto out; 458dfdcada3SDoug Rabson } 459a9148abdSDoug Rabson mreq->m_pkthdr.len = m_length(mreq, NULL); 460dfdcada3SDoug Rabson 461c675522fSDoug Rabson cr->cr_xid = xid; 462dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 463a9148abdSDoug Rabson 464a9148abdSDoug Rabson /* 465a9148abdSDoug Rabson * Try to get a place in the congestion window. 466a9148abdSDoug Rabson */ 467a9148abdSDoug Rabson while (cu->cu_sent >= cu->cu_cwnd) { 468a9148abdSDoug Rabson cu->cu_cwnd_wait = TRUE; 469a9148abdSDoug Rabson error = msleep(&cu->cu_cwnd_wait, &cs->cs_lock, 470a9148abdSDoug Rabson cu->cu_waitflag, "rpccwnd", 0); 471a9148abdSDoug Rabson if (error) { 472a9148abdSDoug Rabson errp->re_errno = error; 473a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTSEND; 474a9148abdSDoug Rabson goto out; 475a9148abdSDoug Rabson } 476a9148abdSDoug Rabson } 477a9148abdSDoug Rabson cu->cu_sent += CWNDSCALE; 478a9148abdSDoug Rabson 479c675522fSDoug Rabson TAILQ_INSERT_TAIL(&cs->cs_pending, cr, cr_link); 480dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 481dfdcada3SDoug Rabson 482dfdcada3SDoug Rabson /* 483dfdcada3SDoug Rabson * sosend consumes mreq. 484dfdcada3SDoug Rabson */ 485dfdcada3SDoug Rabson error = sosend(cu->cu_socket, sa, NULL, mreq, NULL, 0, curthread); 486dfdcada3SDoug Rabson mreq = NULL; 487dfdcada3SDoug Rabson 488dfdcada3SDoug Rabson /* 489dfdcada3SDoug Rabson * sub-optimal code appears here because we have 490dfdcada3SDoug Rabson * some clock time to spare while the packets are in flight. 491dfdcada3SDoug Rabson * (We assume that this is actually only executed once.) 492dfdcada3SDoug Rabson */ 493a9148abdSDoug Rabson reply_msg.acpted_rply.ar_verf.oa_flavor = AUTH_NULL; 494a9148abdSDoug Rabson reply_msg.acpted_rply.ar_verf.oa_base = cr->cr_verf; 495a9148abdSDoug Rabson reply_msg.acpted_rply.ar_verf.oa_length = 0; 496a9148abdSDoug Rabson reply_msg.acpted_rply.ar_results.where = NULL; 497a9148abdSDoug Rabson reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; 498dfdcada3SDoug Rabson 499dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 500dfdcada3SDoug Rabson if (error) { 501c675522fSDoug Rabson TAILQ_REMOVE(&cs->cs_pending, cr, cr_link); 502a9148abdSDoug Rabson errp->re_errno = error; 503a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTSEND; 504a9148abdSDoug Rabson cu->cu_sent -= CWNDSCALE; 505a9148abdSDoug Rabson if (cu->cu_cwnd_wait) { 506a9148abdSDoug Rabson cu->cu_cwnd_wait = FALSE; 507a9148abdSDoug Rabson wakeup(&cu->cu_cwnd_wait); 508a9148abdSDoug Rabson } 509dfdcada3SDoug Rabson goto out; 510dfdcada3SDoug Rabson } 511dfdcada3SDoug Rabson 512dfdcada3SDoug Rabson /* 513dfdcada3SDoug Rabson * Check to see if we got an upcall while waiting for the 514c675522fSDoug Rabson * lock. 515dfdcada3SDoug Rabson */ 516c675522fSDoug Rabson if (cr->cr_error) { 517c675522fSDoug Rabson TAILQ_REMOVE(&cs->cs_pending, cr, cr_link); 518a9148abdSDoug Rabson errp->re_errno = cr->cr_error; 519a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTRECV; 520a9148abdSDoug Rabson cu->cu_sent -= CWNDSCALE; 521a9148abdSDoug Rabson if (cu->cu_cwnd_wait) { 522a9148abdSDoug Rabson cu->cu_cwnd_wait = FALSE; 523a9148abdSDoug Rabson wakeup(&cu->cu_cwnd_wait); 524a9148abdSDoug Rabson } 525dfdcada3SDoug Rabson goto out; 526dfdcada3SDoug Rabson } 527c675522fSDoug Rabson if (cr->cr_mrep) { 528c675522fSDoug Rabson TAILQ_REMOVE(&cs->cs_pending, cr, cr_link); 529a9148abdSDoug Rabson cu->cu_sent -= CWNDSCALE; 530a9148abdSDoug Rabson if (cu->cu_cwnd_wait) { 531a9148abdSDoug Rabson cu->cu_cwnd_wait = FALSE; 532a9148abdSDoug Rabson wakeup(&cu->cu_cwnd_wait); 533a9148abdSDoug Rabson } 534dfdcada3SDoug Rabson goto got_reply; 535dfdcada3SDoug Rabson } 536dfdcada3SDoug Rabson 537dfdcada3SDoug Rabson /* 538dfdcada3SDoug Rabson * Hack to provide rpc-based message passing 539dfdcada3SDoug Rabson */ 540c675522fSDoug Rabson if (timeout == 0) { 541c675522fSDoug Rabson TAILQ_REMOVE(&cs->cs_pending, cr, cr_link); 542a9148abdSDoug Rabson errp->re_status = stat = RPC_TIMEDOUT; 543a9148abdSDoug Rabson cu->cu_sent -= CWNDSCALE; 544a9148abdSDoug Rabson if (cu->cu_cwnd_wait) { 545a9148abdSDoug Rabson cu->cu_cwnd_wait = FALSE; 546a9148abdSDoug Rabson wakeup(&cu->cu_cwnd_wait); 547a9148abdSDoug Rabson } 548dfdcada3SDoug Rabson goto out; 549dfdcada3SDoug Rabson } 550dfdcada3SDoug Rabson 551dfdcada3SDoug Rabson get_reply: 552dfdcada3SDoug Rabson for (;;) { 553dfdcada3SDoug Rabson /* Decide how long to wait. */ 554c675522fSDoug Rabson if (next_sendtime < timeout) 555dfdcada3SDoug Rabson tv = next_sendtime; 556c675522fSDoug Rabson else 557dfdcada3SDoug Rabson tv = timeout; 558c675522fSDoug Rabson tv -= time_waited; 559dfdcada3SDoug Rabson 560c675522fSDoug Rabson if (tv > 0) { 561b766fabdSRick Macklem if (cu->cu_closing || cu->cu_closed) { 562c675522fSDoug Rabson error = 0; 563b766fabdSRick Macklem cr->cr_error = ESHUTDOWN; 564b766fabdSRick Macklem } else { 565c675522fSDoug Rabson error = msleep(cr, &cs->cs_lock, 566c675522fSDoug Rabson cu->cu_waitflag, cu->cu_waitchan, tv); 567b766fabdSRick Macklem } 568c675522fSDoug Rabson } else { 569c675522fSDoug Rabson error = EWOULDBLOCK; 570c675522fSDoug Rabson } 571c675522fSDoug Rabson 572c675522fSDoug Rabson TAILQ_REMOVE(&cs->cs_pending, cr, cr_link); 573a9148abdSDoug Rabson cu->cu_sent -= CWNDSCALE; 574a9148abdSDoug Rabson if (cu->cu_cwnd_wait) { 575a9148abdSDoug Rabson cu->cu_cwnd_wait = FALSE; 576a9148abdSDoug Rabson wakeup(&cu->cu_cwnd_wait); 577a9148abdSDoug Rabson } 578dfdcada3SDoug Rabson 579dfdcada3SDoug Rabson if (!error) { 580dfdcada3SDoug Rabson /* 581dfdcada3SDoug Rabson * We were woken up by the upcall. If the 582dfdcada3SDoug Rabson * upcall had a receive error, report that, 583dfdcada3SDoug Rabson * otherwise we have a reply. 584dfdcada3SDoug Rabson */ 585c675522fSDoug Rabson if (cr->cr_error) { 586a9148abdSDoug Rabson errp->re_errno = cr->cr_error; 587a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTRECV; 588dfdcada3SDoug Rabson goto out; 589dfdcada3SDoug Rabson } 590a9148abdSDoug Rabson 591a9148abdSDoug Rabson cu->cu_cwnd += (CWNDSCALE * CWNDSCALE 592a9148abdSDoug Rabson + cu->cu_cwnd / 2) / cu->cu_cwnd; 593a9148abdSDoug Rabson if (cu->cu_cwnd > MAXCWND) 594a9148abdSDoug Rabson cu->cu_cwnd = MAXCWND; 595a9148abdSDoug Rabson 596a9148abdSDoug Rabson if (rt) { 597a9148abdSDoug Rabson /* 598a9148abdSDoug Rabson * Add one to the time since a tick 599a9148abdSDoug Rabson * count of N means that the actual 600a9148abdSDoug Rabson * time taken was somewhere between N 601a9148abdSDoug Rabson * and N+1. 602a9148abdSDoug Rabson */ 603a9148abdSDoug Rabson rtt = ticks - starttime + 1; 604a9148abdSDoug Rabson 605a9148abdSDoug Rabson /* 606a9148abdSDoug Rabson * Update our estimate of the round 607a9148abdSDoug Rabson * trip time using roughly the 608a9148abdSDoug Rabson * algorithm described in RFC 609a9148abdSDoug Rabson * 2988. Given an RTT sample R: 610a9148abdSDoug Rabson * 611a9148abdSDoug Rabson * RTTVAR = (1-beta) * RTTVAR + beta * |SRTT-R| 612a9148abdSDoug Rabson * SRTT = (1-alpha) * SRTT + alpha * R 613a9148abdSDoug Rabson * 614a9148abdSDoug Rabson * where alpha = 0.125 and beta = 0.25. 615a9148abdSDoug Rabson * 616a9148abdSDoug Rabson * The initial retransmit timeout is 617a9148abdSDoug Rabson * SRTT + 4*RTTVAR and doubles on each 618a9148abdSDoug Rabson * retransmision. 619a9148abdSDoug Rabson */ 620a9148abdSDoug Rabson if (rt->rt_srtt == 0) { 621a9148abdSDoug Rabson rt->rt_srtt = rtt; 622a9148abdSDoug Rabson rt->rt_deviate = rtt / 2; 623a9148abdSDoug Rabson } else { 624a9148abdSDoug Rabson int32_t error = rtt - rt->rt_srtt; 625a9148abdSDoug Rabson rt->rt_srtt += error / 8; 626a9148abdSDoug Rabson error = abs(error) - rt->rt_deviate; 627a9148abdSDoug Rabson rt->rt_deviate += error / 4; 628a9148abdSDoug Rabson } 629a9148abdSDoug Rabson rt->rt_rtxcur = rt->rt_srtt + 4*rt->rt_deviate; 630a9148abdSDoug Rabson } 631a9148abdSDoug Rabson 632dfdcada3SDoug Rabson break; 633dfdcada3SDoug Rabson } 634dfdcada3SDoug Rabson 635dfdcada3SDoug Rabson /* 636dfdcada3SDoug Rabson * The sleep returned an error so our request is still 637dfdcada3SDoug Rabson * on the list. If we got EWOULDBLOCK, we may want to 638dfdcada3SDoug Rabson * re-send the request. 639dfdcada3SDoug Rabson */ 640dfdcada3SDoug Rabson if (error != EWOULDBLOCK) { 641a9148abdSDoug Rabson errp->re_errno = error; 642dfdcada3SDoug Rabson if (error == EINTR) 643a9148abdSDoug Rabson errp->re_status = stat = RPC_INTR; 644dfdcada3SDoug Rabson else 645a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTRECV; 646dfdcada3SDoug Rabson goto out; 647dfdcada3SDoug Rabson } 648dfdcada3SDoug Rabson 649c675522fSDoug Rabson time_waited = ticks - starttime; 650dfdcada3SDoug Rabson 651dfdcada3SDoug Rabson /* Check for timeout. */ 652c675522fSDoug Rabson if (time_waited > timeout) { 653a9148abdSDoug Rabson errp->re_errno = EWOULDBLOCK; 654a9148abdSDoug Rabson errp->re_status = stat = RPC_TIMEDOUT; 655dfdcada3SDoug Rabson goto out; 656dfdcada3SDoug Rabson } 657dfdcada3SDoug Rabson 658dfdcada3SDoug Rabson /* Retransmit if necessary. */ 659c675522fSDoug Rabson if (time_waited >= next_sendtime) { 660a9148abdSDoug Rabson cu->cu_cwnd /= 2; 661a9148abdSDoug Rabson if (cu->cu_cwnd < CWNDSCALE) 662a9148abdSDoug Rabson cu->cu_cwnd = CWNDSCALE; 663c675522fSDoug Rabson if (ext && ext->rc_feedback) { 664c675522fSDoug Rabson mtx_unlock(&cs->cs_lock); 665c675522fSDoug Rabson if (retrans == 0) 666c675522fSDoug Rabson ext->rc_feedback(FEEDBACK_REXMIT1, 667c675522fSDoug Rabson proc, ext->rc_feedback_arg); 668c675522fSDoug Rabson else 669c675522fSDoug Rabson ext->rc_feedback(FEEDBACK_REXMIT2, 670c675522fSDoug Rabson proc, ext->rc_feedback_arg); 671c675522fSDoug Rabson mtx_lock(&cs->cs_lock); 672c675522fSDoug Rabson } 673a9148abdSDoug Rabson if (cu->cu_closing || cu->cu_closed) { 674a9148abdSDoug Rabson errp->re_errno = ESHUTDOWN; 675a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTRECV; 676c675522fSDoug Rabson goto out; 677c675522fSDoug Rabson } 678c675522fSDoug Rabson retrans++; 679dfdcada3SDoug Rabson /* update retransmit_time */ 680c675522fSDoug Rabson if (retransmit_time < RPC_MAX_BACKOFF * hz) 681c675522fSDoug Rabson retransmit_time = 2 * retransmit_time; 682c675522fSDoug Rabson next_sendtime += retransmit_time; 683dfdcada3SDoug Rabson goto send_again; 684dfdcada3SDoug Rabson } 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); 736a9148abdSDoug Rabson TAILQ_INSERT_TAIL(&cs->cs_pending, 737a9148abdSDoug Rabson cr, cr_link); 738a9148abdSDoug Rabson cr->cr_mrep = NULL; 739a9148abdSDoug Rabson goto get_reply; 740dfdcada3SDoug Rabson } 741a9148abdSDoug Rabson } else { 742a9148abdSDoug Rabson *resultsp = results; 743dfdcada3SDoug Rabson } 744dfdcada3SDoug Rabson } /* end successful completion */ 745dfdcada3SDoug Rabson /* 746dfdcada3SDoug Rabson * If unsuccesful AND error is an authentication error 747dfdcada3SDoug Rabson * then refresh credentials and try again, else break 748dfdcada3SDoug Rabson */ 749a9148abdSDoug Rabson else if (stat == RPC_AUTHERROR) 750dfdcada3SDoug Rabson /* maybe our credentials need to be refreshed ... */ 751dfdcada3SDoug Rabson if (nrefreshes > 0 && 752a9148abdSDoug Rabson AUTH_REFRESH(auth, &reply_msg)) { 753dfdcada3SDoug Rabson nrefreshes--; 754a9148abdSDoug Rabson XDR_DESTROY(&xdrs); 755a9148abdSDoug Rabson mtx_lock(&cs->cs_lock); 756dfdcada3SDoug Rabson goto call_again; 757dfdcada3SDoug Rabson } 758dfdcada3SDoug Rabson /* end of unsuccessful completion */ 759dfdcada3SDoug Rabson } /* end of valid reply message */ 760dfdcada3SDoug Rabson else { 761a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTDECODERES; 762dfdcada3SDoug Rabson 763dfdcada3SDoug Rabson } 764a9148abdSDoug Rabson XDR_DESTROY(&xdrs); 765a9148abdSDoug Rabson mtx_lock(&cs->cs_lock); 766dfdcada3SDoug Rabson out: 767dfdcada3SDoug Rabson mtx_assert(&cs->cs_lock, MA_OWNED); 768dfdcada3SDoug Rabson 769dfdcada3SDoug Rabson if (mreq) 770dfdcada3SDoug Rabson m_freem(mreq); 771c675522fSDoug Rabson if (cr->cr_mrep) 772c675522fSDoug Rabson m_freem(cr->cr_mrep); 773c675522fSDoug Rabson 774c675522fSDoug Rabson cu->cu_threads--; 775c675522fSDoug Rabson if (cu->cu_closing) 776c675522fSDoug Rabson wakeup(cu); 777dfdcada3SDoug Rabson 778dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 779c675522fSDoug Rabson 780a9148abdSDoug Rabson if (auth && stat != RPC_SUCCESS) 781a9148abdSDoug Rabson AUTH_VALIDATE(auth, xid, NULL, NULL); 782a9148abdSDoug Rabson 783c675522fSDoug Rabson free(cr, M_RPC); 784c675522fSDoug Rabson 785a9148abdSDoug Rabson return (stat); 786dfdcada3SDoug Rabson } 787dfdcada3SDoug Rabson 788dfdcada3SDoug Rabson static void 789dfdcada3SDoug Rabson clnt_dg_geterr(CLIENT *cl, struct rpc_err *errp) 790dfdcada3SDoug Rabson { 791dfdcada3SDoug Rabson struct cu_data *cu = (struct cu_data *)cl->cl_private; 792dfdcada3SDoug Rabson 793dfdcada3SDoug Rabson *errp = cu->cu_error; 794dfdcada3SDoug Rabson } 795dfdcada3SDoug Rabson 796dfdcada3SDoug Rabson static bool_t 797dfdcada3SDoug Rabson clnt_dg_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr) 798dfdcada3SDoug Rabson { 799dfdcada3SDoug Rabson XDR xdrs; 800dfdcada3SDoug Rabson bool_t dummy; 801dfdcada3SDoug Rabson 802dfdcada3SDoug Rabson xdrs.x_op = XDR_FREE; 803dfdcada3SDoug Rabson dummy = (*xdr_res)(&xdrs, res_ptr); 804dfdcada3SDoug Rabson 805dfdcada3SDoug Rabson return (dummy); 806dfdcada3SDoug Rabson } 807dfdcada3SDoug Rabson 808dfdcada3SDoug Rabson /*ARGSUSED*/ 809dfdcada3SDoug Rabson static void 810dfdcada3SDoug Rabson clnt_dg_abort(CLIENT *h) 811dfdcada3SDoug Rabson { 812dfdcada3SDoug Rabson } 813dfdcada3SDoug Rabson 814dfdcada3SDoug Rabson static bool_t 815dfdcada3SDoug Rabson clnt_dg_control(CLIENT *cl, u_int request, void *info) 816dfdcada3SDoug Rabson { 817dfdcada3SDoug Rabson struct cu_data *cu = (struct cu_data *)cl->cl_private; 81874fb0ba7SJohn Baldwin struct cu_socket *cs; 819dfdcada3SDoug Rabson struct sockaddr *addr; 820dfdcada3SDoug Rabson 82174fb0ba7SJohn Baldwin cs = cu->cu_socket->so_rcv.sb_upcallarg; 822dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 823dfdcada3SDoug Rabson 824dfdcada3SDoug Rabson switch (request) { 825dfdcada3SDoug Rabson case CLSET_FD_CLOSE: 826dfdcada3SDoug Rabson cu->cu_closeit = TRUE; 827dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 828dfdcada3SDoug Rabson return (TRUE); 829dfdcada3SDoug Rabson case CLSET_FD_NCLOSE: 830dfdcada3SDoug Rabson cu->cu_closeit = FALSE; 831dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 832dfdcada3SDoug Rabson return (TRUE); 833dfdcada3SDoug Rabson } 834dfdcada3SDoug Rabson 835dfdcada3SDoug Rabson /* for other requests which use info */ 836dfdcada3SDoug Rabson if (info == NULL) { 837dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 838dfdcada3SDoug Rabson return (FALSE); 839dfdcada3SDoug Rabson } 840dfdcada3SDoug Rabson switch (request) { 841dfdcada3SDoug Rabson case CLSET_TIMEOUT: 842dfdcada3SDoug Rabson if (time_not_ok((struct timeval *)info)) { 843dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 844dfdcada3SDoug Rabson return (FALSE); 845dfdcada3SDoug Rabson } 846dfdcada3SDoug Rabson cu->cu_total = *(struct timeval *)info; 847dfdcada3SDoug Rabson break; 848dfdcada3SDoug Rabson case CLGET_TIMEOUT: 849dfdcada3SDoug Rabson *(struct timeval *)info = cu->cu_total; 850dfdcada3SDoug Rabson break; 851dfdcada3SDoug Rabson case CLSET_RETRY_TIMEOUT: 852dfdcada3SDoug Rabson if (time_not_ok((struct timeval *)info)) { 853dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 854dfdcada3SDoug Rabson return (FALSE); 855dfdcada3SDoug Rabson } 856dfdcada3SDoug Rabson cu->cu_wait = *(struct timeval *)info; 857dfdcada3SDoug Rabson break; 858dfdcada3SDoug Rabson case CLGET_RETRY_TIMEOUT: 859dfdcada3SDoug Rabson *(struct timeval *)info = cu->cu_wait; 860dfdcada3SDoug Rabson break; 861dfdcada3SDoug Rabson case CLGET_SVC_ADDR: 862dfdcada3SDoug Rabson /* 863dfdcada3SDoug Rabson * Slightly different semantics to userland - we use 864dfdcada3SDoug Rabson * sockaddr instead of netbuf. 865dfdcada3SDoug Rabson */ 866dfdcada3SDoug Rabson memcpy(info, &cu->cu_raddr, cu->cu_raddr.ss_len); 867dfdcada3SDoug Rabson break; 868dfdcada3SDoug Rabson case CLSET_SVC_ADDR: /* set to new address */ 869dfdcada3SDoug Rabson addr = (struct sockaddr *)info; 870dfdcada3SDoug Rabson (void) memcpy(&cu->cu_raddr, addr, addr->sa_len); 871dfdcada3SDoug Rabson break; 872dfdcada3SDoug Rabson case CLGET_XID: 873dfdcada3SDoug Rabson *(uint32_t *)info = cu->cu_xid; 874dfdcada3SDoug Rabson break; 875dfdcada3SDoug Rabson 876dfdcada3SDoug Rabson case CLSET_XID: 877dfdcada3SDoug Rabson /* This will set the xid of the NEXT call */ 878dfdcada3SDoug Rabson /* decrement by 1 as clnt_dg_call() increments once */ 879dfdcada3SDoug Rabson cu->cu_xid = *(uint32_t *)info - 1; 880dfdcada3SDoug Rabson break; 881dfdcada3SDoug Rabson 882dfdcada3SDoug Rabson case CLGET_VERS: 883dfdcada3SDoug Rabson /* 884dfdcada3SDoug Rabson * This RELIES on the information that, in the call body, 885dfdcada3SDoug Rabson * the version number field is the fifth field from the 886dfdcada3SDoug Rabson * begining of the RPC header. MUST be changed if the 887dfdcada3SDoug Rabson * call_struct is changed 888dfdcada3SDoug Rabson */ 889dfdcada3SDoug Rabson *(uint32_t *)info = 890dfdcada3SDoug Rabson ntohl(*(uint32_t *)(void *)(cu->cu_mcallc + 891dfdcada3SDoug Rabson 4 * BYTES_PER_XDR_UNIT)); 892dfdcada3SDoug Rabson break; 893dfdcada3SDoug Rabson 894dfdcada3SDoug Rabson case CLSET_VERS: 895dfdcada3SDoug Rabson *(uint32_t *)(void *)(cu->cu_mcallc + 4 * BYTES_PER_XDR_UNIT) 896dfdcada3SDoug Rabson = htonl(*(uint32_t *)info); 897dfdcada3SDoug Rabson break; 898dfdcada3SDoug Rabson 899dfdcada3SDoug Rabson case CLGET_PROG: 900dfdcada3SDoug Rabson /* 901dfdcada3SDoug Rabson * This RELIES on the information that, in the call body, 902dfdcada3SDoug Rabson * the program number field is the fourth field from the 903dfdcada3SDoug Rabson * begining of the RPC header. MUST be changed if the 904dfdcada3SDoug Rabson * call_struct is changed 905dfdcada3SDoug Rabson */ 906dfdcada3SDoug Rabson *(uint32_t *)info = 907dfdcada3SDoug Rabson ntohl(*(uint32_t *)(void *)(cu->cu_mcallc + 908dfdcada3SDoug Rabson 3 * BYTES_PER_XDR_UNIT)); 909dfdcada3SDoug Rabson break; 910dfdcada3SDoug Rabson 911dfdcada3SDoug Rabson case CLSET_PROG: 912dfdcada3SDoug Rabson *(uint32_t *)(void *)(cu->cu_mcallc + 3 * BYTES_PER_XDR_UNIT) 913dfdcada3SDoug Rabson = htonl(*(uint32_t *)info); 914dfdcada3SDoug Rabson break; 915dfdcada3SDoug Rabson case CLSET_ASYNC: 916dfdcada3SDoug Rabson cu->cu_async = *(int *)info; 917dfdcada3SDoug Rabson break; 918dfdcada3SDoug Rabson case CLSET_CONNECT: 919dfdcada3SDoug Rabson cu->cu_connect = *(int *)info; 920dfdcada3SDoug Rabson break; 921dfdcada3SDoug Rabson case CLSET_WAITCHAN: 922a9148abdSDoug Rabson cu->cu_waitchan = (const char *)info; 923dfdcada3SDoug Rabson break; 924dfdcada3SDoug Rabson case CLGET_WAITCHAN: 925dfdcada3SDoug Rabson *(const char **) info = cu->cu_waitchan; 926dfdcada3SDoug Rabson break; 927dfdcada3SDoug Rabson case CLSET_INTERRUPTIBLE: 928dfdcada3SDoug Rabson if (*(int *) info) 929dfdcada3SDoug Rabson cu->cu_waitflag = PCATCH; 930dfdcada3SDoug Rabson else 931dfdcada3SDoug Rabson cu->cu_waitflag = 0; 932dfdcada3SDoug Rabson break; 933dfdcada3SDoug Rabson case CLGET_INTERRUPTIBLE: 934dfdcada3SDoug Rabson if (cu->cu_waitflag) 935dfdcada3SDoug Rabson *(int *) info = TRUE; 936dfdcada3SDoug Rabson else 937dfdcada3SDoug Rabson *(int *) info = FALSE; 938dfdcada3SDoug Rabson break; 939dfdcada3SDoug Rabson default: 940dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 941dfdcada3SDoug Rabson return (FALSE); 942dfdcada3SDoug Rabson } 943dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 944dfdcada3SDoug Rabson return (TRUE); 945dfdcada3SDoug Rabson } 946dfdcada3SDoug Rabson 947dfdcada3SDoug Rabson static void 948a9148abdSDoug Rabson clnt_dg_close(CLIENT *cl) 949dfdcada3SDoug Rabson { 950dfdcada3SDoug Rabson struct cu_data *cu = (struct cu_data *)cl->cl_private; 95174fb0ba7SJohn Baldwin struct cu_socket *cs; 952c675522fSDoug Rabson struct cu_request *cr; 953dfdcada3SDoug Rabson 95474fb0ba7SJohn Baldwin cs = cu->cu_socket->so_rcv.sb_upcallarg; 955dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 956c675522fSDoug Rabson 957a9148abdSDoug Rabson if (cu->cu_closed) { 958a9148abdSDoug Rabson mtx_unlock(&cs->cs_lock); 959a9148abdSDoug Rabson return; 960a9148abdSDoug Rabson } 961a9148abdSDoug Rabson 962a9148abdSDoug Rabson if (cu->cu_closing) { 963a9148abdSDoug Rabson while (cu->cu_closing) 964a9148abdSDoug Rabson msleep(cu, &cs->cs_lock, 0, "rpcclose", 0); 965a9148abdSDoug Rabson KASSERT(cu->cu_closed, ("client should be closed")); 966a9148abdSDoug Rabson mtx_unlock(&cs->cs_lock); 967a9148abdSDoug Rabson return; 968a9148abdSDoug Rabson } 969a9148abdSDoug Rabson 970c675522fSDoug Rabson /* 971c675522fSDoug Rabson * Abort any pending requests and wait until everyone 972c675522fSDoug Rabson * has finished with clnt_vc_call. 973c675522fSDoug Rabson */ 974c675522fSDoug Rabson cu->cu_closing = TRUE; 975c675522fSDoug Rabson TAILQ_FOREACH(cr, &cs->cs_pending, cr_link) { 976c675522fSDoug Rabson if (cr->cr_client == cl) { 977c675522fSDoug Rabson cr->cr_xid = 0; 978c675522fSDoug Rabson cr->cr_error = ESHUTDOWN; 979c675522fSDoug Rabson wakeup(cr); 980c675522fSDoug Rabson } 981c675522fSDoug Rabson } 982c675522fSDoug Rabson 983c675522fSDoug Rabson while (cu->cu_threads) 984c675522fSDoug Rabson msleep(cu, &cs->cs_lock, 0, "rpcclose", 0); 985c675522fSDoug Rabson 986a9148abdSDoug Rabson cu->cu_closing = FALSE; 987a9148abdSDoug Rabson cu->cu_closed = TRUE; 988a9148abdSDoug Rabson 989a9148abdSDoug Rabson mtx_unlock(&cs->cs_lock); 990a9148abdSDoug Rabson wakeup(cu); 991a9148abdSDoug Rabson } 992a9148abdSDoug Rabson 993a9148abdSDoug Rabson static void 994a9148abdSDoug Rabson clnt_dg_destroy(CLIENT *cl) 995a9148abdSDoug Rabson { 996a9148abdSDoug Rabson struct cu_data *cu = (struct cu_data *)cl->cl_private; 99774fb0ba7SJohn Baldwin struct cu_socket *cs; 998a9148abdSDoug Rabson struct socket *so = NULL; 999a9148abdSDoug Rabson bool_t lastsocketref; 1000a9148abdSDoug Rabson 100174fb0ba7SJohn Baldwin cs = cu->cu_socket->so_rcv.sb_upcallarg; 1002a9148abdSDoug Rabson clnt_dg_close(cl); 1003a9148abdSDoug Rabson 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); 1009c675522fSDoug Rabson SOCKBUF_LOCK(&cu->cu_socket->so_rcv); 101074fb0ba7SJohn Baldwin soupcall_clear(cu->cu_socket, SO_RCV); 10113144f812SRick Macklem clnt_dg_upcallsdone(cu->cu_socket, cs); 1012dfdcada3SDoug Rabson SOCKBUF_UNLOCK(&cu->cu_socket->so_rcv); 10133144f812SRick Macklem mtx_destroy(&cs->cs_lock); 1014dfdcada3SDoug Rabson mem_free(cs, sizeof(*cs)); 1015dfdcada3SDoug Rabson lastsocketref = TRUE; 1016dfdcada3SDoug Rabson } else { 1017dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 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 */ 1092*2a1e0fb4SRick Macklem if (m->m_len < sizeof(xid) && m_length(m, NULL) < sizeof(xid)) 1093c675522fSDoug Rabson /* 1094c675522fSDoug Rabson * Should never happen. 1095c675522fSDoug Rabson */ 1096c675522fSDoug Rabson continue; 1097c675522fSDoug Rabson 1098*2a1e0fb4SRick Macklem m_copydata(m, 0, sizeof(xid), (char *)&xid); 1099*2a1e0fb4SRick Macklem xid = ntohl(xid); 1100dfdcada3SDoug Rabson 1101dfdcada3SDoug Rabson /* 1102dfdcada3SDoug Rabson * Attempt to match this reply with a pending request. 1103dfdcada3SDoug Rabson */ 1104dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 1105dfdcada3SDoug Rabson foundreq = 0; 1106dfdcada3SDoug Rabson TAILQ_FOREACH(cr, &cs->cs_pending, cr_link) { 1107dfdcada3SDoug Rabson if (cr->cr_xid == xid) { 1108dfdcada3SDoug Rabson /* 1109c675522fSDoug Rabson * This one matches. We leave the 1110dfdcada3SDoug Rabson * reply mbuf in cr->cr_mrep. Set the 1111c675522fSDoug Rabson * XID to zero so that we will ignore 1112c675522fSDoug Rabson * any duplicated replies that arrive 1113c675522fSDoug Rabson * before clnt_dg_call removes it from 1114c675522fSDoug Rabson * the queue. 1115dfdcada3SDoug Rabson */ 1116dfdcada3SDoug Rabson cr->cr_xid = 0; 1117dfdcada3SDoug Rabson cr->cr_mrep = m; 1118dfdcada3SDoug Rabson cr->cr_error = 0; 1119dfdcada3SDoug Rabson foundreq = 1; 1120dfdcada3SDoug Rabson wakeup(cr); 1121dfdcada3SDoug Rabson break; 1122dfdcada3SDoug Rabson } 1123dfdcada3SDoug Rabson } 1124dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 1125dfdcada3SDoug Rabson 1126dfdcada3SDoug Rabson /* 1127dfdcada3SDoug Rabson * If we didn't find the matching request, just drop 1128dfdcada3SDoug Rabson * it - its probably a repeated reply. 1129dfdcada3SDoug Rabson */ 1130dfdcada3SDoug Rabson if (!foundreq) 1131dfdcada3SDoug Rabson m_freem(m); 1132dfdcada3SDoug Rabson } while (m); 11333144f812SRick Macklem cs->cs_upcallrefs--; 11343144f812SRick Macklem if (cs->cs_upcallrefs < 0) 11353144f812SRick Macklem panic("rpcdg upcall refcnt"); 11363144f812SRick Macklem if (cs->cs_upcallrefs == 0) 11373144f812SRick Macklem wakeup(&cs->cs_upcallrefs); 113874fb0ba7SJohn Baldwin return (SU_OK); 1139dfdcada3SDoug Rabson } 1140dfdcada3SDoug Rabson 11413144f812SRick Macklem /* 11423144f812SRick Macklem * Wait for all upcalls in progress to complete. 11433144f812SRick Macklem */ 11443144f812SRick Macklem static void 11453144f812SRick Macklem clnt_dg_upcallsdone(struct socket *so, struct cu_socket *cs) 11463144f812SRick Macklem { 11473144f812SRick Macklem 11483144f812SRick Macklem SOCKBUF_LOCK_ASSERT(&so->so_rcv); 11493144f812SRick Macklem 11503144f812SRick Macklem while (cs->cs_upcallrefs > 0) 11513144f812SRick Macklem (void) msleep(&cs->cs_upcallrefs, SOCKBUF_MTX(&so->so_rcv), 0, 11523144f812SRick Macklem "rpcdgup", 0); 11533144f812SRick Macklem } 1154