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> 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 59dfdcada3SDoug Rabson #include <rpc/rpc.h> 60dfdcada3SDoug Rabson #include "rpc_com.h" 61dfdcada3SDoug Rabson 62dfdcada3SDoug Rabson 63dfdcada3SDoug Rabson #ifdef _FREEFALL_CONFIG 64dfdcada3SDoug Rabson /* 65dfdcada3SDoug Rabson * Disable RPC exponential back-off for FreeBSD.org systems. 66dfdcada3SDoug Rabson */ 67dfdcada3SDoug Rabson #define RPC_MAX_BACKOFF 1 /* second */ 68dfdcada3SDoug Rabson #else 69dfdcada3SDoug Rabson #define RPC_MAX_BACKOFF 30 /* seconds */ 70dfdcada3SDoug Rabson #endif 71dfdcada3SDoug Rabson 72dfdcada3SDoug Rabson static bool_t time_not_ok(struct timeval *); 73dfdcada3SDoug Rabson static enum clnt_stat clnt_dg_call(CLIENT *, rpcproc_t, xdrproc_t, void *, 74dfdcada3SDoug Rabson xdrproc_t, void *, struct timeval); 75dfdcada3SDoug Rabson static void clnt_dg_geterr(CLIENT *, struct rpc_err *); 76dfdcada3SDoug Rabson static bool_t clnt_dg_freeres(CLIENT *, xdrproc_t, void *); 77dfdcada3SDoug Rabson static void clnt_dg_abort(CLIENT *); 78dfdcada3SDoug Rabson static bool_t clnt_dg_control(CLIENT *, u_int, void *); 79dfdcada3SDoug Rabson static void clnt_dg_destroy(CLIENT *); 80dfdcada3SDoug Rabson static void clnt_dg_soupcall(struct socket *so, void *arg, int waitflag); 81dfdcada3SDoug Rabson 82dfdcada3SDoug Rabson static struct clnt_ops clnt_dg_ops = { 83dfdcada3SDoug Rabson .cl_call = clnt_dg_call, 84dfdcada3SDoug Rabson .cl_abort = clnt_dg_abort, 85dfdcada3SDoug Rabson .cl_geterr = clnt_dg_geterr, 86dfdcada3SDoug Rabson .cl_freeres = clnt_dg_freeres, 87dfdcada3SDoug Rabson .cl_destroy = clnt_dg_destroy, 88dfdcada3SDoug Rabson .cl_control = clnt_dg_control 89dfdcada3SDoug Rabson }; 90dfdcada3SDoug Rabson 91dfdcada3SDoug Rabson static const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory"; 92dfdcada3SDoug Rabson 93dfdcada3SDoug Rabson /* 94dfdcada3SDoug Rabson * A pending RPC request which awaits a reply. 95dfdcada3SDoug Rabson */ 96dfdcada3SDoug Rabson struct cu_request { 97dfdcada3SDoug Rabson TAILQ_ENTRY(cu_request) cr_link; 98dfdcada3SDoug Rabson uint32_t cr_xid; /* XID of request */ 99dfdcada3SDoug Rabson struct mbuf *cr_mrep; /* reply received by upcall */ 100dfdcada3SDoug Rabson int cr_error; /* any error from upcall */ 101dfdcada3SDoug Rabson }; 102dfdcada3SDoug Rabson 103dfdcada3SDoug Rabson TAILQ_HEAD(cu_request_list, cu_request); 104dfdcada3SDoug Rabson 105dfdcada3SDoug Rabson #define MCALL_MSG_SIZE 24 106dfdcada3SDoug Rabson 107dfdcada3SDoug Rabson /* 108dfdcada3SDoug Rabson * This structure is pointed to by the socket's so_upcallarg 109dfdcada3SDoug Rabson * member. It is separate from the client private data to facilitate 110dfdcada3SDoug Rabson * multiple clients sharing the same socket. The cs_lock mutex is used 111dfdcada3SDoug Rabson * to protect all fields of this structure, the socket's receive 112dfdcada3SDoug Rabson * buffer SOCKBUF_LOCK is used to ensure that exactly one of these 113dfdcada3SDoug Rabson * structures is installed on the socket. 114dfdcada3SDoug Rabson */ 115dfdcada3SDoug Rabson struct cu_socket { 116dfdcada3SDoug Rabson struct mtx cs_lock; 117dfdcada3SDoug Rabson int cs_refs; /* Count of clients */ 118dfdcada3SDoug Rabson struct cu_request_list cs_pending; /* Requests awaiting replies */ 119dfdcada3SDoug Rabson 120dfdcada3SDoug Rabson }; 121dfdcada3SDoug Rabson 122dfdcada3SDoug Rabson /* 123dfdcada3SDoug Rabson * Private data kept per client handle 124dfdcada3SDoug Rabson */ 125dfdcada3SDoug Rabson struct cu_data { 126dfdcada3SDoug Rabson struct socket *cu_socket; /* connection socket */ 127dfdcada3SDoug Rabson bool_t cu_closeit; /* opened by library */ 128dfdcada3SDoug Rabson struct sockaddr_storage cu_raddr; /* remote address */ 129dfdcada3SDoug Rabson int cu_rlen; 130dfdcada3SDoug Rabson struct timeval cu_wait; /* retransmit interval */ 131dfdcada3SDoug Rabson struct timeval cu_total; /* total time for the call */ 132dfdcada3SDoug Rabson struct rpc_err cu_error; 133dfdcada3SDoug Rabson uint32_t cu_xid; 134dfdcada3SDoug Rabson char cu_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */ 135dfdcada3SDoug Rabson size_t cu_mcalllen; 136dfdcada3SDoug Rabson size_t cu_sendsz; /* send size */ 137dfdcada3SDoug Rabson size_t cu_recvsz; /* recv size */ 138dfdcada3SDoug Rabson int cu_async; 139dfdcada3SDoug Rabson int cu_connect; /* Use connect(). */ 140dfdcada3SDoug Rabson int cu_connected; /* Have done connect(). */ 141dfdcada3SDoug Rabson const char *cu_waitchan; 142dfdcada3SDoug Rabson int cu_waitflag; 143dfdcada3SDoug Rabson }; 144dfdcada3SDoug Rabson 145dfdcada3SDoug Rabson /* 146dfdcada3SDoug Rabson * Connection less client creation returns with client handle parameters. 147dfdcada3SDoug Rabson * Default options are set, which the user can change using clnt_control(). 148dfdcada3SDoug Rabson * fd should be open and bound. 149dfdcada3SDoug Rabson * NB: The rpch->cl_auth is initialized to null authentication. 150dfdcada3SDoug Rabson * Caller may wish to set this something more useful. 151dfdcada3SDoug Rabson * 152dfdcada3SDoug Rabson * sendsz and recvsz are the maximum allowable packet sizes that can be 153dfdcada3SDoug Rabson * sent and received. Normally they are the same, but they can be 154dfdcada3SDoug Rabson * changed to improve the program efficiency and buffer allocation. 155dfdcada3SDoug Rabson * If they are 0, use the transport default. 156dfdcada3SDoug Rabson * 157dfdcada3SDoug Rabson * If svcaddr is NULL, returns NULL. 158dfdcada3SDoug Rabson */ 159dfdcada3SDoug Rabson CLIENT * 160dfdcada3SDoug Rabson clnt_dg_create( 161dfdcada3SDoug Rabson struct socket *so, 162dfdcada3SDoug Rabson struct sockaddr *svcaddr, /* servers address */ 163dfdcada3SDoug Rabson rpcprog_t program, /* program number */ 164dfdcada3SDoug Rabson rpcvers_t version, /* version number */ 165dfdcada3SDoug Rabson size_t sendsz, /* buffer recv size */ 166dfdcada3SDoug Rabson size_t recvsz) /* buffer send size */ 167dfdcada3SDoug Rabson { 168dfdcada3SDoug Rabson CLIENT *cl = NULL; /* client handle */ 169dfdcada3SDoug Rabson struct cu_data *cu = NULL; /* private data */ 170dfdcada3SDoug Rabson struct cu_socket *cs = NULL; 171dfdcada3SDoug Rabson struct timeval now; 172dfdcada3SDoug Rabson struct rpc_msg call_msg; 173dfdcada3SDoug Rabson struct __rpc_sockinfo si; 174dfdcada3SDoug Rabson XDR xdrs; 175dfdcada3SDoug Rabson 176dfdcada3SDoug Rabson if (svcaddr == NULL) { 177dfdcada3SDoug Rabson rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 178dfdcada3SDoug Rabson return (NULL); 179dfdcada3SDoug Rabson } 180dfdcada3SDoug Rabson 181dfdcada3SDoug Rabson if (!__rpc_socket2sockinfo(so, &si)) { 182dfdcada3SDoug Rabson rpc_createerr.cf_stat = RPC_TLIERROR; 183dfdcada3SDoug Rabson rpc_createerr.cf_error.re_errno = 0; 184dfdcada3SDoug Rabson return (NULL); 185dfdcada3SDoug Rabson } 186dfdcada3SDoug Rabson 187dfdcada3SDoug Rabson /* 188dfdcada3SDoug Rabson * Find the receive and the send size 189dfdcada3SDoug Rabson */ 190dfdcada3SDoug Rabson sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 191dfdcada3SDoug Rabson recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 192dfdcada3SDoug Rabson if ((sendsz == 0) || (recvsz == 0)) { 193dfdcada3SDoug Rabson rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */ 194dfdcada3SDoug Rabson rpc_createerr.cf_error.re_errno = 0; 195dfdcada3SDoug Rabson return (NULL); 196dfdcada3SDoug Rabson } 197dfdcada3SDoug Rabson 198dfdcada3SDoug Rabson cl = mem_alloc(sizeof (CLIENT)); 199dfdcada3SDoug Rabson 200dfdcada3SDoug Rabson /* 201dfdcada3SDoug Rabson * Should be multiple of 4 for XDR. 202dfdcada3SDoug Rabson */ 203dfdcada3SDoug Rabson sendsz = ((sendsz + 3) / 4) * 4; 204dfdcada3SDoug Rabson recvsz = ((recvsz + 3) / 4) * 4; 205dfdcada3SDoug Rabson cu = mem_alloc(sizeof (*cu)); 206dfdcada3SDoug Rabson (void) memcpy(&cu->cu_raddr, svcaddr, (size_t)svcaddr->sa_len); 207dfdcada3SDoug Rabson cu->cu_rlen = svcaddr->sa_len; 208dfdcada3SDoug Rabson /* Other values can also be set through clnt_control() */ 209dfdcada3SDoug Rabson cu->cu_wait.tv_sec = 15; /* heuristically chosen */ 210dfdcada3SDoug Rabson cu->cu_wait.tv_usec = 0; 211dfdcada3SDoug Rabson cu->cu_total.tv_sec = -1; 212dfdcada3SDoug Rabson cu->cu_total.tv_usec = -1; 213dfdcada3SDoug Rabson cu->cu_sendsz = sendsz; 214dfdcada3SDoug Rabson cu->cu_recvsz = recvsz; 215dfdcada3SDoug Rabson cu->cu_async = FALSE; 216dfdcada3SDoug Rabson cu->cu_connect = FALSE; 217dfdcada3SDoug Rabson cu->cu_connected = FALSE; 218dfdcada3SDoug Rabson cu->cu_waitchan = "rpcrecv"; 219dfdcada3SDoug Rabson cu->cu_waitflag = 0; 220dfdcada3SDoug Rabson (void) getmicrotime(&now); 221dfdcada3SDoug Rabson cu->cu_xid = __RPC_GETXID(&now); 222dfdcada3SDoug Rabson call_msg.rm_xid = cu->cu_xid; 223dfdcada3SDoug Rabson call_msg.rm_call.cb_prog = program; 224dfdcada3SDoug Rabson call_msg.rm_call.cb_vers = version; 225dfdcada3SDoug Rabson xdrmem_create(&xdrs, cu->cu_mcallc, MCALL_MSG_SIZE, XDR_ENCODE); 226dfdcada3SDoug Rabson if (! xdr_callhdr(&xdrs, &call_msg)) { 227dfdcada3SDoug Rabson rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */ 228dfdcada3SDoug Rabson rpc_createerr.cf_error.re_errno = 0; 229dfdcada3SDoug Rabson goto err2; 230dfdcada3SDoug Rabson } 231dfdcada3SDoug Rabson cu->cu_mcalllen = XDR_GETPOS(&xdrs);; 232dfdcada3SDoug Rabson 233dfdcada3SDoug Rabson /* 234dfdcada3SDoug Rabson * By default, closeit is always FALSE. It is users responsibility 235dfdcada3SDoug Rabson * to do a close on it, else the user may use clnt_control 236dfdcada3SDoug Rabson * to let clnt_destroy do it for him/her. 237dfdcada3SDoug Rabson */ 238dfdcada3SDoug Rabson cu->cu_closeit = FALSE; 239dfdcada3SDoug Rabson cu->cu_socket = so; 240dfdcada3SDoug Rabson 241dfdcada3SDoug Rabson SOCKBUF_LOCK(&so->so_rcv); 242dfdcada3SDoug Rabson recheck_socket: 243dfdcada3SDoug Rabson if (so->so_upcall) { 244dfdcada3SDoug Rabson if (so->so_upcall != clnt_dg_soupcall) { 245dfdcada3SDoug Rabson SOCKBUF_UNLOCK(&so->so_rcv); 246dfdcada3SDoug Rabson printf("clnt_dg_create(): socket already has an incompatible upcall\n"); 247dfdcada3SDoug Rabson goto err2; 248dfdcada3SDoug Rabson } 249dfdcada3SDoug Rabson cs = (struct cu_socket *) so->so_upcallarg; 250dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 251dfdcada3SDoug Rabson cs->cs_refs++; 252dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 253dfdcada3SDoug Rabson } else { 254dfdcada3SDoug Rabson /* 255dfdcada3SDoug Rabson * We are the first on this socket - allocate the 256dfdcada3SDoug Rabson * structure and install it in the socket. 257dfdcada3SDoug Rabson */ 258dfdcada3SDoug Rabson SOCKBUF_UNLOCK(&cu->cu_socket->so_rcv); 259dfdcada3SDoug Rabson cs = mem_alloc(sizeof(*cs)); 260dfdcada3SDoug Rabson SOCKBUF_LOCK(&cu->cu_socket->so_rcv); 261dfdcada3SDoug Rabson if (so->so_upcall) { 262dfdcada3SDoug Rabson /* 263dfdcada3SDoug Rabson * We have lost a race with some other client. 264dfdcada3SDoug Rabson */ 265dfdcada3SDoug Rabson mem_free(cs, sizeof(*cs)); 266dfdcada3SDoug Rabson goto recheck_socket; 267dfdcada3SDoug Rabson } 268dfdcada3SDoug Rabson mtx_init(&cs->cs_lock, "cs->cs_lock", NULL, MTX_DEF); 269dfdcada3SDoug Rabson cs->cs_refs = 1; 270dfdcada3SDoug Rabson TAILQ_INIT(&cs->cs_pending); 271dfdcada3SDoug Rabson so->so_upcallarg = cs; 272dfdcada3SDoug Rabson so->so_upcall = clnt_dg_soupcall; 273dfdcada3SDoug Rabson so->so_rcv.sb_flags |= SB_UPCALL; 274dfdcada3SDoug Rabson } 275dfdcada3SDoug Rabson SOCKBUF_UNLOCK(&so->so_rcv); 276dfdcada3SDoug Rabson 277dfdcada3SDoug Rabson cl->cl_ops = &clnt_dg_ops; 278dfdcada3SDoug Rabson cl->cl_private = (caddr_t)(void *)cu; 279dfdcada3SDoug Rabson cl->cl_auth = authnone_create(); 280dfdcada3SDoug Rabson cl->cl_tp = NULL; 281dfdcada3SDoug Rabson cl->cl_netid = NULL; 282dfdcada3SDoug Rabson return (cl); 283dfdcada3SDoug Rabson err2: 284dfdcada3SDoug Rabson if (cl) { 285dfdcada3SDoug Rabson mem_free(cl, sizeof (CLIENT)); 286dfdcada3SDoug Rabson if (cu) 287dfdcada3SDoug Rabson mem_free(cu, sizeof (*cu)); 288dfdcada3SDoug Rabson } 289dfdcada3SDoug Rabson return (NULL); 290dfdcada3SDoug Rabson } 291dfdcada3SDoug Rabson 292dfdcada3SDoug Rabson static enum clnt_stat 293dfdcada3SDoug Rabson clnt_dg_call( 294dfdcada3SDoug Rabson CLIENT *cl, /* client handle */ 295dfdcada3SDoug Rabson rpcproc_t proc, /* procedure number */ 296dfdcada3SDoug Rabson xdrproc_t xargs, /* xdr routine for args */ 297dfdcada3SDoug Rabson void *argsp, /* pointer to args */ 298dfdcada3SDoug Rabson xdrproc_t xresults, /* xdr routine for results */ 299dfdcada3SDoug Rabson void *resultsp, /* pointer to results */ 300dfdcada3SDoug Rabson struct timeval utimeout) /* seconds to wait before giving up */ 301dfdcada3SDoug Rabson { 302dfdcada3SDoug Rabson struct cu_data *cu = (struct cu_data *)cl->cl_private; 303dfdcada3SDoug Rabson struct cu_socket *cs = (struct cu_socket *) cu->cu_socket->so_upcallarg; 304dfdcada3SDoug Rabson XDR xdrs; 305dfdcada3SDoug Rabson struct rpc_msg reply_msg; 306dfdcada3SDoug Rabson bool_t ok; 307dfdcada3SDoug Rabson int nrefreshes = 2; /* number of times to refresh cred */ 308dfdcada3SDoug Rabson struct timeval timeout; 309dfdcada3SDoug Rabson struct timeval retransmit_time; 310dfdcada3SDoug Rabson struct timeval next_sendtime, starttime, time_waited, tv; 311dfdcada3SDoug Rabson struct sockaddr *sa; 312dfdcada3SDoug Rabson socklen_t salen; 313dfdcada3SDoug Rabson uint32_t xid; 314dfdcada3SDoug Rabson struct mbuf *mreq = NULL; 315dfdcada3SDoug Rabson struct cu_request cr; 316dfdcada3SDoug Rabson int error; 317dfdcada3SDoug Rabson 318dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 319dfdcada3SDoug Rabson 320dfdcada3SDoug Rabson cr.cr_mrep = NULL; 321dfdcada3SDoug Rabson cr.cr_error = 0; 322dfdcada3SDoug Rabson 323dfdcada3SDoug Rabson if (cu->cu_total.tv_usec == -1) { 324dfdcada3SDoug Rabson timeout = utimeout; /* use supplied timeout */ 325dfdcada3SDoug Rabson } else { 326dfdcada3SDoug Rabson timeout = cu->cu_total; /* use default timeout */ 327dfdcada3SDoug Rabson } 328dfdcada3SDoug Rabson 329dfdcada3SDoug Rabson if (cu->cu_connect && !cu->cu_connected) { 330dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 331dfdcada3SDoug Rabson error = soconnect(cu->cu_socket, 332dfdcada3SDoug Rabson (struct sockaddr *)&cu->cu_raddr, curthread); 333dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 334dfdcada3SDoug Rabson if (error) { 335dfdcada3SDoug Rabson cu->cu_error.re_errno = error; 336dfdcada3SDoug Rabson cu->cu_error.re_status = RPC_CANTSEND; 337dfdcada3SDoug Rabson goto out; 338dfdcada3SDoug Rabson } 339dfdcada3SDoug Rabson cu->cu_connected = 1; 340dfdcada3SDoug Rabson } 341dfdcada3SDoug Rabson if (cu->cu_connected) { 342dfdcada3SDoug Rabson sa = NULL; 343dfdcada3SDoug Rabson salen = 0; 344dfdcada3SDoug Rabson } else { 345dfdcada3SDoug Rabson sa = (struct sockaddr *)&cu->cu_raddr; 346dfdcada3SDoug Rabson salen = cu->cu_rlen; 347dfdcada3SDoug Rabson } 348dfdcada3SDoug Rabson time_waited.tv_sec = 0; 349dfdcada3SDoug Rabson time_waited.tv_usec = 0; 350dfdcada3SDoug Rabson retransmit_time = next_sendtime = cu->cu_wait; 351dfdcada3SDoug Rabson 352dfdcada3SDoug Rabson getmicrotime(&starttime); 353dfdcada3SDoug Rabson 354dfdcada3SDoug Rabson call_again: 355dfdcada3SDoug Rabson mtx_assert(&cs->cs_lock, MA_OWNED); 356dfdcada3SDoug Rabson 357dfdcada3SDoug Rabson cu->cu_xid++; 358dfdcada3SDoug Rabson xid = cu->cu_xid; 359dfdcada3SDoug Rabson 360dfdcada3SDoug Rabson send_again: 361dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 362dfdcada3SDoug Rabson 363dfdcada3SDoug Rabson MGETHDR(mreq, M_WAIT, MT_DATA); 364dfdcada3SDoug Rabson MCLGET(mreq, M_WAIT); 365dfdcada3SDoug Rabson mreq->m_len = 0; 366dfdcada3SDoug Rabson m_append(mreq, cu->cu_mcalllen, cu->cu_mcallc); 367dfdcada3SDoug Rabson 368dfdcada3SDoug Rabson /* 369dfdcada3SDoug Rabson * The XID is the first thing in the request. 370dfdcada3SDoug Rabson */ 371dfdcada3SDoug Rabson *mtod(mreq, uint32_t *) = htonl(xid); 372dfdcada3SDoug Rabson 373dfdcada3SDoug Rabson xdrmbuf_create(&xdrs, mreq, XDR_ENCODE); 374dfdcada3SDoug Rabson 375dfdcada3SDoug Rabson if (cu->cu_async == TRUE && xargs == NULL) 376dfdcada3SDoug Rabson goto get_reply; 377dfdcada3SDoug Rabson 378dfdcada3SDoug Rabson if ((! XDR_PUTINT32(&xdrs, &proc)) || 379dfdcada3SDoug Rabson (! AUTH_MARSHALL(cl->cl_auth, &xdrs)) || 380dfdcada3SDoug Rabson (! (*xargs)(&xdrs, argsp))) { 381dfdcada3SDoug Rabson cu->cu_error.re_status = RPC_CANTENCODEARGS; 382dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 383dfdcada3SDoug Rabson goto out; 384dfdcada3SDoug Rabson } 385dfdcada3SDoug Rabson m_fixhdr(mreq); 386dfdcada3SDoug Rabson 387dfdcada3SDoug Rabson cr.cr_xid = xid; 388dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 389dfdcada3SDoug Rabson TAILQ_INSERT_TAIL(&cs->cs_pending, &cr, cr_link); 390dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 391dfdcada3SDoug Rabson 392dfdcada3SDoug Rabson /* 393dfdcada3SDoug Rabson * sosend consumes mreq. 394dfdcada3SDoug Rabson */ 395dfdcada3SDoug Rabson error = sosend(cu->cu_socket, sa, NULL, mreq, NULL, 0, curthread); 396dfdcada3SDoug Rabson mreq = NULL; 397dfdcada3SDoug Rabson 398dfdcada3SDoug Rabson /* 399dfdcada3SDoug Rabson * sub-optimal code appears here because we have 400dfdcada3SDoug Rabson * some clock time to spare while the packets are in flight. 401dfdcada3SDoug Rabson * (We assume that this is actually only executed once.) 402dfdcada3SDoug Rabson */ 403dfdcada3SDoug Rabson reply_msg.acpted_rply.ar_verf = _null_auth; 404dfdcada3SDoug Rabson reply_msg.acpted_rply.ar_results.where = resultsp; 405dfdcada3SDoug Rabson reply_msg.acpted_rply.ar_results.proc = xresults; 406dfdcada3SDoug Rabson 407dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 408dfdcada3SDoug Rabson if (error) { 409dfdcada3SDoug Rabson TAILQ_REMOVE(&cs->cs_pending, &cr, cr_link); 410dfdcada3SDoug Rabson 411dfdcada3SDoug Rabson cu->cu_error.re_errno = error; 412dfdcada3SDoug Rabson cu->cu_error.re_status = RPC_CANTSEND; 413dfdcada3SDoug Rabson goto out; 414dfdcada3SDoug Rabson } 415dfdcada3SDoug Rabson 416dfdcada3SDoug Rabson /* 417dfdcada3SDoug Rabson * Check to see if we got an upcall while waiting for the 418dfdcada3SDoug Rabson * lock. In both these cases, the request has been removed 419dfdcada3SDoug Rabson * from cs->cs_pending. 420dfdcada3SDoug Rabson */ 421dfdcada3SDoug Rabson if (cr.cr_error) { 422dfdcada3SDoug Rabson cu->cu_error.re_errno = cr.cr_error; 423dfdcada3SDoug Rabson cu->cu_error.re_status = RPC_CANTRECV; 424dfdcada3SDoug Rabson goto out; 425dfdcada3SDoug Rabson } 426dfdcada3SDoug Rabson if (cr.cr_mrep) { 427dfdcada3SDoug Rabson goto got_reply; 428dfdcada3SDoug Rabson } 429dfdcada3SDoug Rabson 430dfdcada3SDoug Rabson /* 431dfdcada3SDoug Rabson * Hack to provide rpc-based message passing 432dfdcada3SDoug Rabson */ 433dfdcada3SDoug Rabson if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 434dfdcada3SDoug Rabson if (cr.cr_xid) 435dfdcada3SDoug Rabson TAILQ_REMOVE(&cs->cs_pending, &cr, cr_link); 436dfdcada3SDoug Rabson cu->cu_error.re_status = RPC_TIMEDOUT; 437dfdcada3SDoug Rabson goto out; 438dfdcada3SDoug Rabson } 439dfdcada3SDoug Rabson 440dfdcada3SDoug Rabson get_reply: 441dfdcada3SDoug Rabson for (;;) { 442dfdcada3SDoug Rabson /* Decide how long to wait. */ 443dfdcada3SDoug Rabson if (timevalcmp(&next_sendtime, &timeout, <)) { 444dfdcada3SDoug Rabson tv = next_sendtime; 445dfdcada3SDoug Rabson } else { 446dfdcada3SDoug Rabson tv = timeout; 447dfdcada3SDoug Rabson } 448dfdcada3SDoug Rabson timevalsub(&tv, &time_waited); 449dfdcada3SDoug Rabson if (tv.tv_sec < 0 || tv.tv_usec < 0) 450dfdcada3SDoug Rabson tv.tv_sec = tv.tv_usec = 0; 451dfdcada3SDoug Rabson 452dfdcada3SDoug Rabson error = msleep(&cr, &cs->cs_lock, cu->cu_waitflag, 453dfdcada3SDoug Rabson cu->cu_waitchan, tvtohz(&tv)); 454dfdcada3SDoug Rabson 455dfdcada3SDoug Rabson if (!error) { 456dfdcada3SDoug Rabson /* 457dfdcada3SDoug Rabson * We were woken up by the upcall. If the 458dfdcada3SDoug Rabson * upcall had a receive error, report that, 459dfdcada3SDoug Rabson * otherwise we have a reply. 460dfdcada3SDoug Rabson */ 461dfdcada3SDoug Rabson if (cr.cr_error) { 462dfdcada3SDoug Rabson cu->cu_error.re_errno = cr.cr_error; 463dfdcada3SDoug Rabson cu->cu_error.re_status = RPC_CANTRECV; 464dfdcada3SDoug Rabson goto out; 465dfdcada3SDoug Rabson } 466dfdcada3SDoug Rabson break; 467dfdcada3SDoug Rabson } 468dfdcada3SDoug Rabson 469dfdcada3SDoug Rabson /* 470dfdcada3SDoug Rabson * The sleep returned an error so our request is still 471dfdcada3SDoug Rabson * on the list. If we got EWOULDBLOCK, we may want to 472dfdcada3SDoug Rabson * re-send the request. 473dfdcada3SDoug Rabson */ 474dfdcada3SDoug Rabson if (error != EWOULDBLOCK) { 475dfdcada3SDoug Rabson if (cr.cr_xid) 476dfdcada3SDoug Rabson TAILQ_REMOVE(&cs->cs_pending, &cr, cr_link); 477dfdcada3SDoug Rabson cu->cu_error.re_errno = error; 478dfdcada3SDoug Rabson if (error == EINTR) 479dfdcada3SDoug Rabson cu->cu_error.re_status = RPC_INTR; 480dfdcada3SDoug Rabson else 481dfdcada3SDoug Rabson cu->cu_error.re_status = RPC_CANTRECV; 482dfdcada3SDoug Rabson goto out; 483dfdcada3SDoug Rabson } 484dfdcada3SDoug Rabson 485dfdcada3SDoug Rabson getmicrotime(&tv); 486dfdcada3SDoug Rabson time_waited = tv; 487dfdcada3SDoug Rabson timevalsub(&time_waited, &starttime); 488dfdcada3SDoug Rabson 489dfdcada3SDoug Rabson /* Check for timeout. */ 490dfdcada3SDoug Rabson if (timevalcmp(&time_waited, &timeout, >)) { 491dfdcada3SDoug Rabson if (cr.cr_xid) 492dfdcada3SDoug Rabson TAILQ_REMOVE(&cs->cs_pending, &cr, cr_link); 493dfdcada3SDoug Rabson cu->cu_error.re_errno = EWOULDBLOCK; 494dfdcada3SDoug Rabson cu->cu_error.re_status = RPC_TIMEDOUT; 495dfdcada3SDoug Rabson goto out; 496dfdcada3SDoug Rabson } 497dfdcada3SDoug Rabson 498dfdcada3SDoug Rabson /* Retransmit if necessary. */ 499dfdcada3SDoug Rabson if (timevalcmp(&time_waited, &next_sendtime, >)) { 500dfdcada3SDoug Rabson if (cr.cr_xid) 501dfdcada3SDoug Rabson TAILQ_REMOVE(&cs->cs_pending, &cr, cr_link); 502dfdcada3SDoug Rabson /* update retransmit_time */ 503dfdcada3SDoug Rabson if (retransmit_time.tv_sec < RPC_MAX_BACKOFF) 504dfdcada3SDoug Rabson timevaladd(&retransmit_time, &retransmit_time); 505dfdcada3SDoug Rabson timevaladd(&next_sendtime, &retransmit_time); 506dfdcada3SDoug Rabson goto send_again; 507dfdcada3SDoug Rabson } 508dfdcada3SDoug Rabson } 509dfdcada3SDoug Rabson 510dfdcada3SDoug Rabson got_reply: 511dfdcada3SDoug Rabson /* 512dfdcada3SDoug Rabson * Now decode and validate the response. We need to drop the 513dfdcada3SDoug Rabson * lock since xdr_replymsg may end up sleeping in malloc. 514dfdcada3SDoug Rabson */ 515dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 516dfdcada3SDoug Rabson 517dfdcada3SDoug Rabson xdrmbuf_create(&xdrs, cr.cr_mrep, XDR_DECODE); 518dfdcada3SDoug Rabson ok = xdr_replymsg(&xdrs, &reply_msg); 519dfdcada3SDoug Rabson XDR_DESTROY(&xdrs); 520dfdcada3SDoug Rabson cr.cr_mrep = NULL; 521dfdcada3SDoug Rabson 522dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 523dfdcada3SDoug Rabson 524dfdcada3SDoug Rabson if (ok) { 525dfdcada3SDoug Rabson if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && 526dfdcada3SDoug Rabson (reply_msg.acpted_rply.ar_stat == SUCCESS)) 527dfdcada3SDoug Rabson cu->cu_error.re_status = RPC_SUCCESS; 528dfdcada3SDoug Rabson else 529dfdcada3SDoug Rabson _seterr_reply(&reply_msg, &(cu->cu_error)); 530dfdcada3SDoug Rabson 531dfdcada3SDoug Rabson if (cu->cu_error.re_status == RPC_SUCCESS) { 532dfdcada3SDoug Rabson if (! AUTH_VALIDATE(cl->cl_auth, 533dfdcada3SDoug Rabson &reply_msg.acpted_rply.ar_verf)) { 534dfdcada3SDoug Rabson cu->cu_error.re_status = RPC_AUTHERROR; 535dfdcada3SDoug Rabson cu->cu_error.re_why = AUTH_INVALIDRESP; 536dfdcada3SDoug Rabson } 537dfdcada3SDoug Rabson if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 538dfdcada3SDoug Rabson xdrs.x_op = XDR_FREE; 539dfdcada3SDoug Rabson (void) xdr_opaque_auth(&xdrs, 540dfdcada3SDoug Rabson &(reply_msg.acpted_rply.ar_verf)); 541dfdcada3SDoug Rabson } 542dfdcada3SDoug Rabson } /* end successful completion */ 543dfdcada3SDoug Rabson /* 544dfdcada3SDoug Rabson * If unsuccesful AND error is an authentication error 545dfdcada3SDoug Rabson * then refresh credentials and try again, else break 546dfdcada3SDoug Rabson */ 547dfdcada3SDoug Rabson else if (cu->cu_error.re_status == RPC_AUTHERROR) 548dfdcada3SDoug Rabson /* maybe our credentials need to be refreshed ... */ 549dfdcada3SDoug Rabson if (nrefreshes > 0 && 550dfdcada3SDoug Rabson AUTH_REFRESH(cl->cl_auth, &reply_msg)) { 551dfdcada3SDoug Rabson nrefreshes--; 552dfdcada3SDoug Rabson goto call_again; 553dfdcada3SDoug Rabson } 554dfdcada3SDoug Rabson /* end of unsuccessful completion */ 555dfdcada3SDoug Rabson } /* end of valid reply message */ 556dfdcada3SDoug Rabson else { 557dfdcada3SDoug Rabson cu->cu_error.re_status = RPC_CANTDECODERES; 558dfdcada3SDoug Rabson 559dfdcada3SDoug Rabson } 560dfdcada3SDoug Rabson out: 561dfdcada3SDoug Rabson mtx_assert(&cs->cs_lock, MA_OWNED); 562dfdcada3SDoug Rabson 563dfdcada3SDoug Rabson if (mreq) 564dfdcada3SDoug Rabson m_freem(mreq); 565dfdcada3SDoug Rabson if (cr.cr_mrep) 566dfdcada3SDoug Rabson m_freem(cr.cr_mrep); 567dfdcada3SDoug Rabson 568dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 569dfdcada3SDoug Rabson return (cu->cu_error.re_status); 570dfdcada3SDoug Rabson } 571dfdcada3SDoug Rabson 572dfdcada3SDoug Rabson static void 573dfdcada3SDoug Rabson clnt_dg_geterr(CLIENT *cl, struct rpc_err *errp) 574dfdcada3SDoug Rabson { 575dfdcada3SDoug Rabson struct cu_data *cu = (struct cu_data *)cl->cl_private; 576dfdcada3SDoug Rabson 577dfdcada3SDoug Rabson *errp = cu->cu_error; 578dfdcada3SDoug Rabson } 579dfdcada3SDoug Rabson 580dfdcada3SDoug Rabson static bool_t 581dfdcada3SDoug Rabson clnt_dg_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr) 582dfdcada3SDoug Rabson { 583dfdcada3SDoug Rabson XDR xdrs; 584dfdcada3SDoug Rabson bool_t dummy; 585dfdcada3SDoug Rabson 586dfdcada3SDoug Rabson xdrs.x_op = XDR_FREE; 587dfdcada3SDoug Rabson dummy = (*xdr_res)(&xdrs, res_ptr); 588dfdcada3SDoug Rabson 589dfdcada3SDoug Rabson return (dummy); 590dfdcada3SDoug Rabson } 591dfdcada3SDoug Rabson 592dfdcada3SDoug Rabson /*ARGSUSED*/ 593dfdcada3SDoug Rabson static void 594dfdcada3SDoug Rabson clnt_dg_abort(CLIENT *h) 595dfdcada3SDoug Rabson { 596dfdcada3SDoug Rabson } 597dfdcada3SDoug Rabson 598dfdcada3SDoug Rabson static bool_t 599dfdcada3SDoug Rabson clnt_dg_control(CLIENT *cl, u_int request, void *info) 600dfdcada3SDoug Rabson { 601dfdcada3SDoug Rabson struct cu_data *cu = (struct cu_data *)cl->cl_private; 602dfdcada3SDoug Rabson struct cu_socket *cs = (struct cu_socket *) cu->cu_socket->so_upcallarg; 603dfdcada3SDoug Rabson struct sockaddr *addr; 604dfdcada3SDoug Rabson 605dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 606dfdcada3SDoug Rabson 607dfdcada3SDoug Rabson switch (request) { 608dfdcada3SDoug Rabson case CLSET_FD_CLOSE: 609dfdcada3SDoug Rabson cu->cu_closeit = TRUE; 610dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 611dfdcada3SDoug Rabson return (TRUE); 612dfdcada3SDoug Rabson case CLSET_FD_NCLOSE: 613dfdcada3SDoug Rabson cu->cu_closeit = FALSE; 614dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 615dfdcada3SDoug Rabson return (TRUE); 616dfdcada3SDoug Rabson } 617dfdcada3SDoug Rabson 618dfdcada3SDoug Rabson /* for other requests which use info */ 619dfdcada3SDoug Rabson if (info == NULL) { 620dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 621dfdcada3SDoug Rabson return (FALSE); 622dfdcada3SDoug Rabson } 623dfdcada3SDoug Rabson switch (request) { 624dfdcada3SDoug Rabson case CLSET_TIMEOUT: 625dfdcada3SDoug Rabson if (time_not_ok((struct timeval *)info)) { 626dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 627dfdcada3SDoug Rabson return (FALSE); 628dfdcada3SDoug Rabson } 629dfdcada3SDoug Rabson cu->cu_total = *(struct timeval *)info; 630dfdcada3SDoug Rabson break; 631dfdcada3SDoug Rabson case CLGET_TIMEOUT: 632dfdcada3SDoug Rabson *(struct timeval *)info = cu->cu_total; 633dfdcada3SDoug Rabson break; 634dfdcada3SDoug Rabson case CLSET_RETRY_TIMEOUT: 635dfdcada3SDoug Rabson if (time_not_ok((struct timeval *)info)) { 636dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 637dfdcada3SDoug Rabson return (FALSE); 638dfdcada3SDoug Rabson } 639dfdcada3SDoug Rabson cu->cu_wait = *(struct timeval *)info; 640dfdcada3SDoug Rabson break; 641dfdcada3SDoug Rabson case CLGET_RETRY_TIMEOUT: 642dfdcada3SDoug Rabson *(struct timeval *)info = cu->cu_wait; 643dfdcada3SDoug Rabson break; 644dfdcada3SDoug Rabson case CLGET_SVC_ADDR: 645dfdcada3SDoug Rabson /* 646dfdcada3SDoug Rabson * Slightly different semantics to userland - we use 647dfdcada3SDoug Rabson * sockaddr instead of netbuf. 648dfdcada3SDoug Rabson */ 649dfdcada3SDoug Rabson memcpy(info, &cu->cu_raddr, cu->cu_raddr.ss_len); 650dfdcada3SDoug Rabson break; 651dfdcada3SDoug Rabson case CLSET_SVC_ADDR: /* set to new address */ 652dfdcada3SDoug Rabson addr = (struct sockaddr *)info; 653dfdcada3SDoug Rabson (void) memcpy(&cu->cu_raddr, addr, addr->sa_len); 654dfdcada3SDoug Rabson break; 655dfdcada3SDoug Rabson case CLGET_XID: 656dfdcada3SDoug Rabson *(uint32_t *)info = cu->cu_xid; 657dfdcada3SDoug Rabson break; 658dfdcada3SDoug Rabson 659dfdcada3SDoug Rabson case CLSET_XID: 660dfdcada3SDoug Rabson /* This will set the xid of the NEXT call */ 661dfdcada3SDoug Rabson /* decrement by 1 as clnt_dg_call() increments once */ 662dfdcada3SDoug Rabson cu->cu_xid = *(uint32_t *)info - 1; 663dfdcada3SDoug Rabson break; 664dfdcada3SDoug Rabson 665dfdcada3SDoug Rabson case CLGET_VERS: 666dfdcada3SDoug Rabson /* 667dfdcada3SDoug Rabson * This RELIES on the information that, in the call body, 668dfdcada3SDoug Rabson * the version number field is the fifth field from the 669dfdcada3SDoug Rabson * begining of the RPC header. MUST be changed if the 670dfdcada3SDoug Rabson * call_struct is changed 671dfdcada3SDoug Rabson */ 672dfdcada3SDoug Rabson *(uint32_t *)info = 673dfdcada3SDoug Rabson ntohl(*(uint32_t *)(void *)(cu->cu_mcallc + 674dfdcada3SDoug Rabson 4 * BYTES_PER_XDR_UNIT)); 675dfdcada3SDoug Rabson break; 676dfdcada3SDoug Rabson 677dfdcada3SDoug Rabson case CLSET_VERS: 678dfdcada3SDoug Rabson *(uint32_t *)(void *)(cu->cu_mcallc + 4 * BYTES_PER_XDR_UNIT) 679dfdcada3SDoug Rabson = htonl(*(uint32_t *)info); 680dfdcada3SDoug Rabson break; 681dfdcada3SDoug Rabson 682dfdcada3SDoug Rabson case CLGET_PROG: 683dfdcada3SDoug Rabson /* 684dfdcada3SDoug Rabson * This RELIES on the information that, in the call body, 685dfdcada3SDoug Rabson * the program number field is the fourth field from the 686dfdcada3SDoug Rabson * begining of the RPC header. MUST be changed if the 687dfdcada3SDoug Rabson * call_struct is changed 688dfdcada3SDoug Rabson */ 689dfdcada3SDoug Rabson *(uint32_t *)info = 690dfdcada3SDoug Rabson ntohl(*(uint32_t *)(void *)(cu->cu_mcallc + 691dfdcada3SDoug Rabson 3 * BYTES_PER_XDR_UNIT)); 692dfdcada3SDoug Rabson break; 693dfdcada3SDoug Rabson 694dfdcada3SDoug Rabson case CLSET_PROG: 695dfdcada3SDoug Rabson *(uint32_t *)(void *)(cu->cu_mcallc + 3 * BYTES_PER_XDR_UNIT) 696dfdcada3SDoug Rabson = htonl(*(uint32_t *)info); 697dfdcada3SDoug Rabson break; 698dfdcada3SDoug Rabson case CLSET_ASYNC: 699dfdcada3SDoug Rabson cu->cu_async = *(int *)info; 700dfdcada3SDoug Rabson break; 701dfdcada3SDoug Rabson case CLSET_CONNECT: 702dfdcada3SDoug Rabson cu->cu_connect = *(int *)info; 703dfdcada3SDoug Rabson break; 704dfdcada3SDoug Rabson case CLSET_WAITCHAN: 705dfdcada3SDoug Rabson cu->cu_waitchan = *(const char **)info; 706dfdcada3SDoug Rabson break; 707dfdcada3SDoug Rabson case CLGET_WAITCHAN: 708dfdcada3SDoug Rabson *(const char **) info = cu->cu_waitchan; 709dfdcada3SDoug Rabson break; 710dfdcada3SDoug Rabson case CLSET_INTERRUPTIBLE: 711dfdcada3SDoug Rabson if (*(int *) info) 712dfdcada3SDoug Rabson cu->cu_waitflag = PCATCH; 713dfdcada3SDoug Rabson else 714dfdcada3SDoug Rabson cu->cu_waitflag = 0; 715dfdcada3SDoug Rabson break; 716dfdcada3SDoug Rabson case CLGET_INTERRUPTIBLE: 717dfdcada3SDoug Rabson if (cu->cu_waitflag) 718dfdcada3SDoug Rabson *(int *) info = TRUE; 719dfdcada3SDoug Rabson else 720dfdcada3SDoug Rabson *(int *) info = FALSE; 721dfdcada3SDoug Rabson break; 722dfdcada3SDoug Rabson default: 723dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 724dfdcada3SDoug Rabson return (FALSE); 725dfdcada3SDoug Rabson } 726dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 727dfdcada3SDoug Rabson return (TRUE); 728dfdcada3SDoug Rabson } 729dfdcada3SDoug Rabson 730dfdcada3SDoug Rabson static void 731dfdcada3SDoug Rabson clnt_dg_destroy(CLIENT *cl) 732dfdcada3SDoug Rabson { 733dfdcada3SDoug Rabson struct cu_data *cu = (struct cu_data *)cl->cl_private; 734dfdcada3SDoug Rabson struct cu_socket *cs = (struct cu_socket *) cu->cu_socket->so_upcallarg; 735dfdcada3SDoug Rabson struct socket *so = NULL; 736dfdcada3SDoug Rabson bool_t lastsocketref; 737dfdcada3SDoug Rabson 738dfdcada3SDoug Rabson SOCKBUF_LOCK(&cu->cu_socket->so_rcv); 739dfdcada3SDoug Rabson 740dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 741dfdcada3SDoug Rabson cs->cs_refs--; 742dfdcada3SDoug Rabson if (cs->cs_refs == 0) { 743dfdcada3SDoug Rabson cu->cu_socket->so_upcallarg = NULL; 744dfdcada3SDoug Rabson cu->cu_socket->so_upcall = NULL; 745dfdcada3SDoug Rabson cu->cu_socket->so_rcv.sb_flags &= ~SB_UPCALL; 746dfdcada3SDoug Rabson mtx_destroy(&cs->cs_lock); 747dfdcada3SDoug Rabson SOCKBUF_UNLOCK(&cu->cu_socket->so_rcv); 748dfdcada3SDoug Rabson mem_free(cs, sizeof(*cs)); 749dfdcada3SDoug Rabson lastsocketref = TRUE; 750dfdcada3SDoug Rabson } else { 751dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 752dfdcada3SDoug Rabson SOCKBUF_UNLOCK(&cu->cu_socket->so_rcv); 753dfdcada3SDoug Rabson lastsocketref = FALSE; 754dfdcada3SDoug Rabson } 755dfdcada3SDoug Rabson 756dfdcada3SDoug Rabson if (cu->cu_closeit) { 757dfdcada3SDoug Rabson KASSERT(lastsocketref, ("clnt_dg_destroy(): closing a socket " 758dfdcada3SDoug Rabson "shared with other clients")); 759dfdcada3SDoug Rabson so = cu->cu_socket; 760dfdcada3SDoug Rabson cu->cu_socket = NULL; 761dfdcada3SDoug Rabson } 762dfdcada3SDoug Rabson 763dfdcada3SDoug Rabson if (so) 764dfdcada3SDoug Rabson soclose(so); 765dfdcada3SDoug Rabson 766dfdcada3SDoug Rabson if (cl->cl_netid && cl->cl_netid[0]) 767dfdcada3SDoug Rabson mem_free(cl->cl_netid, strlen(cl->cl_netid) +1); 768dfdcada3SDoug Rabson if (cl->cl_tp && cl->cl_tp[0]) 769dfdcada3SDoug Rabson mem_free(cl->cl_tp, strlen(cl->cl_tp) +1); 770dfdcada3SDoug Rabson mem_free(cu, sizeof (*cu)); 771dfdcada3SDoug Rabson mem_free(cl, sizeof (CLIENT)); 772dfdcada3SDoug Rabson } 773dfdcada3SDoug Rabson 774dfdcada3SDoug Rabson /* 775dfdcada3SDoug Rabson * Make sure that the time is not garbage. -1 value is allowed. 776dfdcada3SDoug Rabson */ 777dfdcada3SDoug Rabson static bool_t 778dfdcada3SDoug Rabson time_not_ok(struct timeval *t) 779dfdcada3SDoug Rabson { 780dfdcada3SDoug Rabson return (t->tv_sec < -1 || t->tv_sec > 100000000 || 781dfdcada3SDoug Rabson t->tv_usec < -1 || t->tv_usec > 1000000); 782dfdcada3SDoug Rabson } 783dfdcada3SDoug Rabson 784dfdcada3SDoug Rabson void 785dfdcada3SDoug Rabson clnt_dg_soupcall(struct socket *so, void *arg, int waitflag) 786dfdcada3SDoug Rabson { 787dfdcada3SDoug Rabson struct cu_socket *cs = (struct cu_socket *) arg; 788dfdcada3SDoug Rabson struct uio uio; 789dfdcada3SDoug Rabson struct mbuf *m; 790dfdcada3SDoug Rabson struct mbuf *control; 791dfdcada3SDoug Rabson struct cu_request *cr; 792dfdcada3SDoug Rabson int error, rcvflag, foundreq; 793dfdcada3SDoug Rabson uint32_t xid; 794dfdcada3SDoug Rabson 795dfdcada3SDoug Rabson uio.uio_resid = 1000000000; 796dfdcada3SDoug Rabson uio.uio_td = curthread; 797dfdcada3SDoug Rabson do { 798dfdcada3SDoug Rabson m = NULL; 799dfdcada3SDoug Rabson control = NULL; 800dfdcada3SDoug Rabson rcvflag = MSG_DONTWAIT; 801dfdcada3SDoug Rabson error = soreceive(so, NULL, &uio, &m, &control, &rcvflag); 802dfdcada3SDoug Rabson if (control) 803dfdcada3SDoug Rabson m_freem(control); 804dfdcada3SDoug Rabson 805dfdcada3SDoug Rabson if (error == EWOULDBLOCK) 806dfdcada3SDoug Rabson break; 807dfdcada3SDoug Rabson 808dfdcada3SDoug Rabson /* 809dfdcada3SDoug Rabson * If there was an error, wake up all pending 810dfdcada3SDoug Rabson * requests. 811dfdcada3SDoug Rabson */ 812dfdcada3SDoug Rabson if (error) { 813dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 814dfdcada3SDoug Rabson TAILQ_FOREACH(cr, &cs->cs_pending, cr_link) { 815dfdcada3SDoug Rabson cr->cr_error = error; 816dfdcada3SDoug Rabson wakeup(cr); 817dfdcada3SDoug Rabson } 818dfdcada3SDoug Rabson TAILQ_INIT(&cs->cs_pending); 819dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 820dfdcada3SDoug Rabson break; 821dfdcada3SDoug Rabson } 822dfdcada3SDoug Rabson 823dfdcada3SDoug Rabson /* 824dfdcada3SDoug Rabson * The XID is in the first uint32_t of the reply. 825dfdcada3SDoug Rabson */ 826dfdcada3SDoug Rabson m = m_pullup(m, sizeof(xid)); 827dfdcada3SDoug Rabson if (!m) 828dfdcada3SDoug Rabson break; 829dfdcada3SDoug Rabson xid = ntohl(*mtod(m, uint32_t *)); 830dfdcada3SDoug Rabson 831dfdcada3SDoug Rabson /* 832dfdcada3SDoug Rabson * Attempt to match this reply with a pending request. 833dfdcada3SDoug Rabson */ 834dfdcada3SDoug Rabson mtx_lock(&cs->cs_lock); 835dfdcada3SDoug Rabson foundreq = 0; 836dfdcada3SDoug Rabson TAILQ_FOREACH(cr, &cs->cs_pending, cr_link) { 837dfdcada3SDoug Rabson if (cr->cr_xid == xid) { 838dfdcada3SDoug Rabson /* 839dfdcada3SDoug Rabson * This one matches. We snip it out of 840dfdcada3SDoug Rabson * the pending list and leave the 841dfdcada3SDoug Rabson * reply mbuf in cr->cr_mrep. Set the 842dfdcada3SDoug Rabson * XID to zero so that clnt_dg_call 843dfdcada3SDoug Rabson * can know not to repeat the 844dfdcada3SDoug Rabson * TAILQ_REMOVE. 845dfdcada3SDoug Rabson */ 846dfdcada3SDoug Rabson TAILQ_REMOVE(&cs->cs_pending, cr, cr_link); 847dfdcada3SDoug Rabson cr->cr_xid = 0; 848dfdcada3SDoug Rabson cr->cr_mrep = m; 849dfdcada3SDoug Rabson cr->cr_error = 0; 850dfdcada3SDoug Rabson foundreq = 1; 851dfdcada3SDoug Rabson wakeup(cr); 852dfdcada3SDoug Rabson break; 853dfdcada3SDoug Rabson } 854dfdcada3SDoug Rabson } 855dfdcada3SDoug Rabson mtx_unlock(&cs->cs_lock); 856dfdcada3SDoug Rabson 857dfdcada3SDoug Rabson /* 858dfdcada3SDoug Rabson * If we didn't find the matching request, just drop 859dfdcada3SDoug Rabson * it - its probably a repeated reply. 860dfdcada3SDoug Rabson */ 861dfdcada3SDoug Rabson if (!foundreq) 862dfdcada3SDoug Rabson m_freem(m); 863dfdcada3SDoug Rabson } while (m); 864dfdcada3SDoug Rabson } 865dfdcada3SDoug Rabson 866