1dfdcada3SDoug Rabson /* $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 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 #if defined(LIBC_SCCS) && !defined(lint) 33dfdcada3SDoug Rabson static char *sccsid2 = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro"; 34dfdcada3SDoug Rabson static char *sccsid = "@(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC"; 35dfdcada3SDoug Rabson static char sccsid3[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro"; 36dfdcada3SDoug Rabson #endif 37dfdcada3SDoug Rabson #include <sys/cdefs.h> 38dfdcada3SDoug Rabson __FBSDID("$FreeBSD$"); 39dfdcada3SDoug Rabson 40dfdcada3SDoug Rabson /* 41dfdcada3SDoug Rabson * clnt_tcp.c, Implements a TCP/IP based, client side RPC. 42dfdcada3SDoug Rabson * 43dfdcada3SDoug Rabson * Copyright (C) 1984, Sun Microsystems, Inc. 44dfdcada3SDoug Rabson * 45dfdcada3SDoug Rabson * TCP based RPC supports 'batched calls'. 46dfdcada3SDoug Rabson * A sequence of calls may be batched-up in a send buffer. The rpc call 47dfdcada3SDoug Rabson * return immediately to the client even though the call was not necessarily 48dfdcada3SDoug Rabson * sent. The batching occurs if the results' xdr routine is NULL (0) AND 49dfdcada3SDoug Rabson * the rpc timeout value is zero (see clnt.h, rpc). 50dfdcada3SDoug Rabson * 51dfdcada3SDoug Rabson * Clients should NOT casually batch calls that in fact return results; that is, 52dfdcada3SDoug Rabson * the server side should be aware that a call is batched and not produce any 53dfdcada3SDoug Rabson * return message. Batched calls that produce many result messages can 54dfdcada3SDoug Rabson * deadlock (netlock) the client and the server.... 55dfdcada3SDoug Rabson * 56dfdcada3SDoug Rabson * Now go hang yourself. 57dfdcada3SDoug Rabson */ 58dfdcada3SDoug Rabson 59dfdcada3SDoug Rabson #include <sys/param.h> 60dfdcada3SDoug Rabson #include <sys/systm.h> 61dfdcada3SDoug Rabson #include <sys/lock.h> 62dfdcada3SDoug Rabson #include <sys/malloc.h> 63dfdcada3SDoug Rabson #include <sys/mbuf.h> 64dfdcada3SDoug Rabson #include <sys/mutex.h> 65dfdcada3SDoug Rabson #include <sys/pcpu.h> 66dfdcada3SDoug Rabson #include <sys/proc.h> 67a9148abdSDoug Rabson #include <sys/protosw.h> 68dfdcada3SDoug Rabson #include <sys/socket.h> 69dfdcada3SDoug Rabson #include <sys/socketvar.h> 70dfdcada3SDoug Rabson #include <sys/syslog.h> 71dfdcada3SDoug Rabson #include <sys/time.h> 72dfdcada3SDoug Rabson #include <sys/uio.h> 73a9148abdSDoug Rabson #include <netinet/tcp.h> 74dfdcada3SDoug Rabson 75dfdcada3SDoug Rabson #include <rpc/rpc.h> 76ee31b83aSDoug Rabson #include <rpc/rpc_com.h> 77dfdcada3SDoug Rabson 78dfdcada3SDoug Rabson #define MCALL_MSG_SIZE 24 79dfdcada3SDoug Rabson 80dfdcada3SDoug Rabson struct cmessage { 81dfdcada3SDoug Rabson struct cmsghdr cmsg; 82dfdcada3SDoug Rabson struct cmsgcred cmcred; 83dfdcada3SDoug Rabson }; 84dfdcada3SDoug Rabson 85c675522fSDoug Rabson static enum clnt_stat clnt_vc_call(CLIENT *, struct rpc_callextra *, 86a9148abdSDoug Rabson rpcproc_t, struct mbuf *, struct mbuf **, struct timeval); 87dfdcada3SDoug Rabson static void clnt_vc_geterr(CLIENT *, struct rpc_err *); 88dfdcada3SDoug Rabson static bool_t clnt_vc_freeres(CLIENT *, xdrproc_t, void *); 89dfdcada3SDoug Rabson static void clnt_vc_abort(CLIENT *); 90dfdcada3SDoug Rabson static bool_t clnt_vc_control(CLIENT *, u_int, void *); 91a9148abdSDoug Rabson static void clnt_vc_close(CLIENT *); 92dfdcada3SDoug Rabson static void clnt_vc_destroy(CLIENT *); 93dfdcada3SDoug Rabson static bool_t time_not_ok(struct timeval *); 94dfdcada3SDoug Rabson static void clnt_vc_soupcall(struct socket *so, void *arg, int waitflag); 95dfdcada3SDoug Rabson 96dfdcada3SDoug Rabson static struct clnt_ops clnt_vc_ops = { 97dfdcada3SDoug Rabson .cl_call = clnt_vc_call, 98dfdcada3SDoug Rabson .cl_abort = clnt_vc_abort, 99dfdcada3SDoug Rabson .cl_geterr = clnt_vc_geterr, 100dfdcada3SDoug Rabson .cl_freeres = clnt_vc_freeres, 101a9148abdSDoug Rabson .cl_close = clnt_vc_close, 102dfdcada3SDoug Rabson .cl_destroy = clnt_vc_destroy, 103dfdcada3SDoug Rabson .cl_control = clnt_vc_control 104dfdcada3SDoug Rabson }; 105dfdcada3SDoug Rabson 106dfdcada3SDoug Rabson /* 107c675522fSDoug Rabson * A pending RPC request which awaits a reply. Requests which have 108c675522fSDoug Rabson * received their reply will have cr_xid set to zero and cr_mrep to 109c675522fSDoug Rabson * the mbuf chain of the reply. 110dfdcada3SDoug Rabson */ 111dfdcada3SDoug Rabson struct ct_request { 112dfdcada3SDoug Rabson TAILQ_ENTRY(ct_request) cr_link; 113dfdcada3SDoug Rabson uint32_t cr_xid; /* XID of request */ 114dfdcada3SDoug Rabson struct mbuf *cr_mrep; /* reply received by upcall */ 115dfdcada3SDoug Rabson int cr_error; /* any error from upcall */ 116a9148abdSDoug Rabson char cr_verf[MAX_AUTH_BYTES]; /* reply verf */ 117dfdcada3SDoug Rabson }; 118dfdcada3SDoug Rabson 119dfdcada3SDoug Rabson TAILQ_HEAD(ct_request_list, ct_request); 120dfdcada3SDoug Rabson 121dfdcada3SDoug Rabson struct ct_data { 122dfdcada3SDoug Rabson struct mtx ct_lock; 123c675522fSDoug Rabson int ct_threads; /* number of threads in clnt_vc_call */ 124a9148abdSDoug Rabson bool_t ct_closing; /* TRUE if we are closing */ 125a9148abdSDoug Rabson bool_t ct_closed; /* TRUE if we are closed */ 126dfdcada3SDoug Rabson struct socket *ct_socket; /* connection socket */ 127dfdcada3SDoug Rabson bool_t ct_closeit; /* close it on destroy */ 128dfdcada3SDoug Rabson struct timeval ct_wait; /* wait interval in milliseconds */ 129dfdcada3SDoug Rabson struct sockaddr_storage ct_addr; /* remote addr */ 130dfdcada3SDoug Rabson struct rpc_err ct_error; 131dfdcada3SDoug Rabson uint32_t ct_xid; 132dfdcada3SDoug Rabson char ct_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */ 133dfdcada3SDoug Rabson size_t ct_mpos; /* pos after marshal */ 134dfdcada3SDoug Rabson const char *ct_waitchan; 135dfdcada3SDoug Rabson int ct_waitflag; 136dfdcada3SDoug Rabson struct mbuf *ct_record; /* current reply record */ 137dfdcada3SDoug Rabson size_t ct_record_resid; /* how much left of reply to read */ 138dfdcada3SDoug Rabson bool_t ct_record_eor; /* true if reading last fragment */ 139dfdcada3SDoug Rabson struct ct_request_list ct_pending; 140dfdcada3SDoug Rabson }; 141dfdcada3SDoug Rabson 142dfdcada3SDoug Rabson static const char clnt_vc_errstr[] = "%s : %s"; 143dfdcada3SDoug Rabson static const char clnt_vc_str[] = "clnt_vc_create"; 144dfdcada3SDoug Rabson static const char clnt_read_vc_str[] = "read_vc"; 145dfdcada3SDoug Rabson static const char __no_mem_str[] = "out of memory"; 146dfdcada3SDoug Rabson 147dfdcada3SDoug Rabson /* 148dfdcada3SDoug Rabson * Create a client handle for a connection. 149dfdcada3SDoug Rabson * Default options are set, which the user can change using clnt_control()'s. 150dfdcada3SDoug Rabson * The rpc/vc package does buffering similar to stdio, so the client 151dfdcada3SDoug Rabson * must pick send and receive buffer sizes, 0 => use the default. 152dfdcada3SDoug Rabson * NB: fd is copied into a private area. 153dfdcada3SDoug Rabson * NB: The rpch->cl_auth is set null authentication. Caller may wish to 154dfdcada3SDoug Rabson * set this something more useful. 155dfdcada3SDoug Rabson * 156dfdcada3SDoug Rabson * fd should be an open socket 157dfdcada3SDoug Rabson */ 158dfdcada3SDoug Rabson CLIENT * 159dfdcada3SDoug Rabson clnt_vc_create( 160dfdcada3SDoug Rabson struct socket *so, /* open file descriptor */ 161dfdcada3SDoug Rabson struct sockaddr *raddr, /* servers address */ 162dfdcada3SDoug Rabson const rpcprog_t prog, /* program number */ 163dfdcada3SDoug Rabson const rpcvers_t vers, /* version number */ 164dfdcada3SDoug Rabson size_t sendsz, /* buffer recv size */ 165dfdcada3SDoug Rabson size_t recvsz) /* buffer send size */ 166dfdcada3SDoug Rabson { 167dfdcada3SDoug Rabson CLIENT *cl; /* client handle */ 168dfdcada3SDoug Rabson struct ct_data *ct = NULL; /* client handle */ 169dfdcada3SDoug Rabson struct timeval now; 170dfdcada3SDoug Rabson struct rpc_msg call_msg; 171dfdcada3SDoug Rabson static uint32_t disrupt; 172dfdcada3SDoug Rabson struct __rpc_sockinfo si; 173dfdcada3SDoug Rabson XDR xdrs; 174a9148abdSDoug Rabson int error, interrupted, one = 1; 175a9148abdSDoug Rabson struct sockopt sopt; 176dfdcada3SDoug Rabson 177dfdcada3SDoug Rabson if (disrupt == 0) 178dfdcada3SDoug Rabson disrupt = (uint32_t)(long)raddr; 179dfdcada3SDoug Rabson 180dfdcada3SDoug Rabson cl = (CLIENT *)mem_alloc(sizeof (*cl)); 181dfdcada3SDoug Rabson ct = (struct ct_data *)mem_alloc(sizeof (*ct)); 182dfdcada3SDoug Rabson 183dfdcada3SDoug Rabson mtx_init(&ct->ct_lock, "ct->ct_lock", NULL, MTX_DEF); 184c675522fSDoug Rabson ct->ct_threads = 0; 185c675522fSDoug Rabson ct->ct_closing = FALSE; 186a9148abdSDoug Rabson ct->ct_closed = FALSE; 187dfdcada3SDoug Rabson 188dfdcada3SDoug Rabson if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) { 189dfdcada3SDoug Rabson error = soconnect(so, raddr, curthread); 190c675522fSDoug Rabson SOCK_LOCK(so); 191c675522fSDoug Rabson interrupted = 0; 192c675522fSDoug Rabson while ((so->so_state & SS_ISCONNECTING) 193c675522fSDoug Rabson && so->so_error == 0) { 194c675522fSDoug Rabson error = msleep(&so->so_timeo, SOCK_MTX(so), 195c675522fSDoug Rabson PSOCK | PCATCH, "connec", 0); 196dfdcada3SDoug Rabson if (error) { 197c675522fSDoug Rabson if (error == EINTR || error == ERESTART) 198c675522fSDoug Rabson interrupted = 1; 199c675522fSDoug Rabson break; 200c675522fSDoug Rabson } 201c675522fSDoug Rabson } 202c675522fSDoug Rabson if (error == 0) { 203c675522fSDoug Rabson error = so->so_error; 204c675522fSDoug Rabson so->so_error = 0; 205c675522fSDoug Rabson } 206c675522fSDoug Rabson SOCK_UNLOCK(so); 207c675522fSDoug Rabson if (error) { 208c675522fSDoug Rabson if (!interrupted) 209c675522fSDoug Rabson so->so_state &= ~SS_ISCONNECTING; 210dfdcada3SDoug Rabson rpc_createerr.cf_stat = RPC_SYSTEMERROR; 211dfdcada3SDoug Rabson rpc_createerr.cf_error.re_errno = error; 212dfdcada3SDoug Rabson goto err; 213dfdcada3SDoug Rabson } 214dfdcada3SDoug Rabson } 215dfdcada3SDoug Rabson 216dfdcada3SDoug Rabson if (!__rpc_socket2sockinfo(so, &si)) 217dfdcada3SDoug Rabson goto err; 218dfdcada3SDoug Rabson 219a9148abdSDoug Rabson if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 220a9148abdSDoug Rabson bzero(&sopt, sizeof(sopt)); 221a9148abdSDoug Rabson sopt.sopt_dir = SOPT_SET; 222a9148abdSDoug Rabson sopt.sopt_level = SOL_SOCKET; 223a9148abdSDoug Rabson sopt.sopt_name = SO_KEEPALIVE; 224a9148abdSDoug Rabson sopt.sopt_val = &one; 225a9148abdSDoug Rabson sopt.sopt_valsize = sizeof(one); 226a9148abdSDoug Rabson sosetopt(so, &sopt); 227a9148abdSDoug Rabson } 228a9148abdSDoug Rabson 229a9148abdSDoug Rabson if (so->so_proto->pr_protocol == IPPROTO_TCP) { 230a9148abdSDoug Rabson bzero(&sopt, sizeof(sopt)); 231a9148abdSDoug Rabson sopt.sopt_dir = SOPT_SET; 232a9148abdSDoug Rabson sopt.sopt_level = IPPROTO_TCP; 233a9148abdSDoug Rabson sopt.sopt_name = TCP_NODELAY; 234a9148abdSDoug Rabson sopt.sopt_val = &one; 235a9148abdSDoug Rabson sopt.sopt_valsize = sizeof(one); 236a9148abdSDoug Rabson sosetopt(so, &sopt); 237a9148abdSDoug Rabson } 238a9148abdSDoug Rabson 239dfdcada3SDoug Rabson ct->ct_closeit = FALSE; 240dfdcada3SDoug Rabson 241dfdcada3SDoug Rabson /* 242dfdcada3SDoug Rabson * Set up private data struct 243dfdcada3SDoug Rabson */ 244dfdcada3SDoug Rabson ct->ct_socket = so; 245dfdcada3SDoug Rabson ct->ct_wait.tv_sec = -1; 246dfdcada3SDoug Rabson ct->ct_wait.tv_usec = -1; 247dfdcada3SDoug Rabson memcpy(&ct->ct_addr, raddr, raddr->sa_len); 248dfdcada3SDoug Rabson 249dfdcada3SDoug Rabson /* 250dfdcada3SDoug Rabson * Initialize call message 251dfdcada3SDoug Rabson */ 252dfdcada3SDoug Rabson getmicrotime(&now); 253dfdcada3SDoug Rabson ct->ct_xid = ((uint32_t)++disrupt) ^ __RPC_GETXID(&now); 254dfdcada3SDoug Rabson call_msg.rm_xid = ct->ct_xid; 255dfdcada3SDoug Rabson call_msg.rm_direction = CALL; 256dfdcada3SDoug Rabson call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 257dfdcada3SDoug Rabson call_msg.rm_call.cb_prog = (uint32_t)prog; 258dfdcada3SDoug Rabson call_msg.rm_call.cb_vers = (uint32_t)vers; 259dfdcada3SDoug Rabson 260dfdcada3SDoug Rabson /* 261dfdcada3SDoug Rabson * pre-serialize the static part of the call msg and stash it away 262dfdcada3SDoug Rabson */ 263dfdcada3SDoug Rabson xdrmem_create(&xdrs, ct->ct_mcallc, MCALL_MSG_SIZE, 264dfdcada3SDoug Rabson XDR_ENCODE); 265dfdcada3SDoug Rabson if (! xdr_callhdr(&xdrs, &call_msg)) { 266dfdcada3SDoug Rabson if (ct->ct_closeit) { 267dfdcada3SDoug Rabson soclose(ct->ct_socket); 268dfdcada3SDoug Rabson } 269dfdcada3SDoug Rabson goto err; 270dfdcada3SDoug Rabson } 271dfdcada3SDoug Rabson ct->ct_mpos = XDR_GETPOS(&xdrs); 272dfdcada3SDoug Rabson XDR_DESTROY(&xdrs); 273dfdcada3SDoug Rabson ct->ct_waitchan = "rpcrecv"; 274dfdcada3SDoug Rabson ct->ct_waitflag = 0; 275dfdcada3SDoug Rabson 276dfdcada3SDoug Rabson /* 277dfdcada3SDoug Rabson * Create a client handle which uses xdrrec for serialization 278dfdcada3SDoug Rabson * and authnone for authentication. 279dfdcada3SDoug Rabson */ 280c675522fSDoug Rabson cl->cl_refs = 1; 281dfdcada3SDoug Rabson cl->cl_ops = &clnt_vc_ops; 282dfdcada3SDoug Rabson cl->cl_private = ct; 283dfdcada3SDoug Rabson cl->cl_auth = authnone_create(); 284dfdcada3SDoug Rabson sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); 285dfdcada3SDoug Rabson recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); 286a9148abdSDoug Rabson soreserve(ct->ct_socket, sendsz, recvsz); 287dfdcada3SDoug Rabson 288dfdcada3SDoug Rabson SOCKBUF_LOCK(&ct->ct_socket->so_rcv); 289dfdcada3SDoug Rabson ct->ct_socket->so_upcallarg = ct; 290dfdcada3SDoug Rabson ct->ct_socket->so_upcall = clnt_vc_soupcall; 291dfdcada3SDoug Rabson ct->ct_socket->so_rcv.sb_flags |= SB_UPCALL; 292dfdcada3SDoug Rabson SOCKBUF_UNLOCK(&ct->ct_socket->so_rcv); 293dfdcada3SDoug Rabson 294dfdcada3SDoug Rabson ct->ct_record = NULL; 295dfdcada3SDoug Rabson ct->ct_record_resid = 0; 296dfdcada3SDoug Rabson TAILQ_INIT(&ct->ct_pending); 297dfdcada3SDoug Rabson return (cl); 298dfdcada3SDoug Rabson 299dfdcada3SDoug Rabson err: 300dfdcada3SDoug Rabson if (cl) { 301dfdcada3SDoug Rabson if (ct) { 302dfdcada3SDoug Rabson mem_free(ct, sizeof (struct ct_data)); 303dfdcada3SDoug Rabson } 304dfdcada3SDoug Rabson if (cl) 305dfdcada3SDoug Rabson mem_free(cl, sizeof (CLIENT)); 306dfdcada3SDoug Rabson } 307dfdcada3SDoug Rabson return ((CLIENT *)NULL); 308dfdcada3SDoug Rabson } 309dfdcada3SDoug Rabson 310dfdcada3SDoug Rabson static enum clnt_stat 311dfdcada3SDoug Rabson clnt_vc_call( 312a9148abdSDoug Rabson CLIENT *cl, /* client handle */ 313a9148abdSDoug Rabson struct rpc_callextra *ext, /* call metadata */ 314a9148abdSDoug Rabson rpcproc_t proc, /* procedure number */ 315a9148abdSDoug Rabson struct mbuf *args, /* pointer to args */ 316a9148abdSDoug Rabson struct mbuf **resultsp, /* pointer to results */ 317dfdcada3SDoug Rabson struct timeval utimeout) 318dfdcada3SDoug Rabson { 319dfdcada3SDoug Rabson struct ct_data *ct = (struct ct_data *) cl->cl_private; 320c675522fSDoug Rabson AUTH *auth; 321a9148abdSDoug Rabson struct rpc_err *errp; 322a9148abdSDoug Rabson enum clnt_stat stat; 323dfdcada3SDoug Rabson XDR xdrs; 324dfdcada3SDoug Rabson struct rpc_msg reply_msg; 325dfdcada3SDoug Rabson bool_t ok; 326dfdcada3SDoug Rabson int nrefreshes = 2; /* number of times to refresh cred */ 327dfdcada3SDoug Rabson struct timeval timeout; 328dfdcada3SDoug Rabson uint32_t xid; 329a9148abdSDoug Rabson struct mbuf *mreq = NULL, *results; 330c675522fSDoug Rabson struct ct_request *cr; 331dfdcada3SDoug Rabson int error; 332dfdcada3SDoug Rabson 333c675522fSDoug Rabson cr = malloc(sizeof(struct ct_request), M_RPC, M_WAITOK); 334c675522fSDoug Rabson 335dfdcada3SDoug Rabson mtx_lock(&ct->ct_lock); 336dfdcada3SDoug Rabson 337a9148abdSDoug Rabson if (ct->ct_closing || ct->ct_closed) { 338c675522fSDoug Rabson mtx_unlock(&ct->ct_lock); 339c675522fSDoug Rabson free(cr, M_RPC); 340c675522fSDoug Rabson return (RPC_CANTSEND); 341c675522fSDoug Rabson } 342c675522fSDoug Rabson ct->ct_threads++; 343c675522fSDoug Rabson 344a9148abdSDoug Rabson if (ext) { 345c675522fSDoug Rabson auth = ext->rc_auth; 346a9148abdSDoug Rabson errp = &ext->rc_err; 347a9148abdSDoug Rabson } else { 348c675522fSDoug Rabson auth = cl->cl_auth; 349a9148abdSDoug Rabson errp = &ct->ct_error; 350a9148abdSDoug Rabson } 351c675522fSDoug Rabson 352c675522fSDoug Rabson cr->cr_mrep = NULL; 353c675522fSDoug Rabson cr->cr_error = 0; 354dfdcada3SDoug Rabson 355dfdcada3SDoug Rabson if (ct->ct_wait.tv_usec == -1) { 356dfdcada3SDoug Rabson timeout = utimeout; /* use supplied timeout */ 357dfdcada3SDoug Rabson } else { 358dfdcada3SDoug Rabson timeout = ct->ct_wait; /* use default timeout */ 359dfdcada3SDoug Rabson } 360dfdcada3SDoug Rabson 361dfdcada3SDoug Rabson call_again: 362dfdcada3SDoug Rabson mtx_assert(&ct->ct_lock, MA_OWNED); 363dfdcada3SDoug Rabson 364dfdcada3SDoug Rabson ct->ct_xid++; 365dfdcada3SDoug Rabson xid = ct->ct_xid; 366dfdcada3SDoug Rabson 367dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 368dfdcada3SDoug Rabson 369dfdcada3SDoug Rabson /* 370dfdcada3SDoug Rabson * Leave space to pre-pend the record mark. 371dfdcada3SDoug Rabson */ 372dfdcada3SDoug Rabson MGETHDR(mreq, M_WAIT, MT_DATA); 373dfdcada3SDoug Rabson mreq->m_data += sizeof(uint32_t); 374a9148abdSDoug Rabson KASSERT(ct->ct_mpos + sizeof(uint32_t) <= MHLEN, 375a9148abdSDoug Rabson ("RPC header too big")); 376a9148abdSDoug Rabson bcopy(ct->ct_mcallc, mreq->m_data, ct->ct_mpos); 377a9148abdSDoug Rabson mreq->m_len = ct->ct_mpos; 378dfdcada3SDoug Rabson 379dfdcada3SDoug Rabson /* 380dfdcada3SDoug Rabson * The XID is the first thing in the request. 381dfdcada3SDoug Rabson */ 382dfdcada3SDoug Rabson *mtod(mreq, uint32_t *) = htonl(xid); 383dfdcada3SDoug Rabson 384dfdcada3SDoug Rabson xdrmbuf_create(&xdrs, mreq, XDR_ENCODE); 385dfdcada3SDoug Rabson 386a9148abdSDoug Rabson errp->re_status = stat = RPC_SUCCESS; 387dfdcada3SDoug Rabson 388dfdcada3SDoug Rabson if ((! XDR_PUTINT32(&xdrs, &proc)) || 389a9148abdSDoug Rabson (! AUTH_MARSHALL(auth, xid, &xdrs, 390a9148abdSDoug Rabson m_copym(args, 0, M_COPYALL, M_WAITOK)))) { 391a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTENCODEARGS; 392c675522fSDoug Rabson mtx_lock(&ct->ct_lock); 393c675522fSDoug Rabson goto out; 394dfdcada3SDoug Rabson } 395a9148abdSDoug Rabson mreq->m_pkthdr.len = m_length(mreq, NULL); 396dfdcada3SDoug Rabson 397dfdcada3SDoug Rabson /* 398dfdcada3SDoug Rabson * Prepend a record marker containing the packet length. 399dfdcada3SDoug Rabson */ 400dfdcada3SDoug Rabson M_PREPEND(mreq, sizeof(uint32_t), M_WAIT); 401dfdcada3SDoug Rabson *mtod(mreq, uint32_t *) = 402dfdcada3SDoug Rabson htonl(0x80000000 | (mreq->m_pkthdr.len - sizeof(uint32_t))); 403dfdcada3SDoug Rabson 404c675522fSDoug Rabson cr->cr_xid = xid; 405dfdcada3SDoug Rabson mtx_lock(&ct->ct_lock); 406c675522fSDoug Rabson TAILQ_INSERT_TAIL(&ct->ct_pending, cr, cr_link); 407dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 408dfdcada3SDoug Rabson 409dfdcada3SDoug Rabson /* 410dfdcada3SDoug Rabson * sosend consumes mreq. 411dfdcada3SDoug Rabson */ 412dfdcada3SDoug Rabson error = sosend(ct->ct_socket, NULL, NULL, mreq, NULL, 0, curthread); 413dfdcada3SDoug Rabson mreq = NULL; 414a9148abdSDoug Rabson if (error == EMSGSIZE) { 415a9148abdSDoug Rabson SOCKBUF_LOCK(&ct->ct_socket->so_snd); 416a9148abdSDoug Rabson sbwait(&ct->ct_socket->so_snd); 417a9148abdSDoug Rabson SOCKBUF_UNLOCK(&ct->ct_socket->so_snd); 418a9148abdSDoug Rabson AUTH_VALIDATE(auth, xid, NULL, NULL); 419a9148abdSDoug Rabson mtx_lock(&ct->ct_lock); 420a9148abdSDoug Rabson TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 421a9148abdSDoug Rabson goto call_again; 422a9148abdSDoug Rabson } 423dfdcada3SDoug Rabson 424a9148abdSDoug Rabson reply_msg.acpted_rply.ar_verf.oa_flavor = AUTH_NULL; 425a9148abdSDoug Rabson reply_msg.acpted_rply.ar_verf.oa_base = cr->cr_verf; 426a9148abdSDoug Rabson reply_msg.acpted_rply.ar_verf.oa_length = 0; 427a9148abdSDoug Rabson reply_msg.acpted_rply.ar_results.where = NULL; 428a9148abdSDoug Rabson reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; 429dfdcada3SDoug Rabson 430dfdcada3SDoug Rabson mtx_lock(&ct->ct_lock); 431dfdcada3SDoug Rabson if (error) { 432c675522fSDoug Rabson TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 433a9148abdSDoug Rabson errp->re_errno = error; 434a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTSEND; 435dfdcada3SDoug Rabson goto out; 436dfdcada3SDoug Rabson } 437dfdcada3SDoug Rabson 438dfdcada3SDoug Rabson /* 439dfdcada3SDoug Rabson * Check to see if we got an upcall while waiting for the 440dfdcada3SDoug Rabson * lock. In both these cases, the request has been removed 441dfdcada3SDoug Rabson * from ct->ct_pending. 442dfdcada3SDoug Rabson */ 443c675522fSDoug Rabson if (cr->cr_error) { 444c675522fSDoug Rabson TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 445a9148abdSDoug Rabson errp->re_errno = cr->cr_error; 446a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTRECV; 447dfdcada3SDoug Rabson goto out; 448dfdcada3SDoug Rabson } 449c675522fSDoug Rabson if (cr->cr_mrep) { 450c675522fSDoug Rabson TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 451dfdcada3SDoug Rabson goto got_reply; 452dfdcada3SDoug Rabson } 453dfdcada3SDoug Rabson 454dfdcada3SDoug Rabson /* 455dfdcada3SDoug Rabson * Hack to provide rpc-based message passing 456dfdcada3SDoug Rabson */ 457dfdcada3SDoug Rabson if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 458c675522fSDoug Rabson TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 459a9148abdSDoug Rabson errp->re_status = stat = RPC_TIMEDOUT; 460dfdcada3SDoug Rabson goto out; 461dfdcada3SDoug Rabson } 462dfdcada3SDoug Rabson 463c675522fSDoug Rabson error = msleep(cr, &ct->ct_lock, ct->ct_waitflag, ct->ct_waitchan, 464dfdcada3SDoug Rabson tvtohz(&timeout)); 465dfdcada3SDoug Rabson 466c675522fSDoug Rabson TAILQ_REMOVE(&ct->ct_pending, cr, cr_link); 467c675522fSDoug Rabson 468dfdcada3SDoug Rabson if (error) { 469dfdcada3SDoug Rabson /* 470dfdcada3SDoug Rabson * The sleep returned an error so our request is still 471dfdcada3SDoug Rabson * on the list. Turn the error code into an 472dfdcada3SDoug Rabson * appropriate client status. 473dfdcada3SDoug Rabson */ 474a9148abdSDoug Rabson errp->re_errno = error; 475dfdcada3SDoug Rabson switch (error) { 476dfdcada3SDoug Rabson case EINTR: 477a9148abdSDoug Rabson stat = RPC_INTR; 478dfdcada3SDoug Rabson break; 479dfdcada3SDoug Rabson case EWOULDBLOCK: 480a9148abdSDoug Rabson stat = RPC_TIMEDOUT; 481dfdcada3SDoug Rabson break; 482dfdcada3SDoug Rabson default: 483a9148abdSDoug Rabson stat = RPC_CANTRECV; 484dfdcada3SDoug Rabson } 485a9148abdSDoug Rabson errp->re_status = stat; 486dfdcada3SDoug Rabson goto out; 487dfdcada3SDoug Rabson } else { 488dfdcada3SDoug Rabson /* 489dfdcada3SDoug Rabson * We were woken up by the upcall. If the 490dfdcada3SDoug Rabson * upcall had a receive error, report that, 491dfdcada3SDoug Rabson * otherwise we have a reply. 492dfdcada3SDoug Rabson */ 493c675522fSDoug Rabson if (cr->cr_error) { 494a9148abdSDoug Rabson errp->re_errno = cr->cr_error; 495a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTRECV; 496dfdcada3SDoug Rabson goto out; 497dfdcada3SDoug Rabson } 498dfdcada3SDoug Rabson } 499dfdcada3SDoug Rabson 500dfdcada3SDoug Rabson got_reply: 501dfdcada3SDoug Rabson /* 502dfdcada3SDoug Rabson * Now decode and validate the response. We need to drop the 503dfdcada3SDoug Rabson * lock since xdr_replymsg may end up sleeping in malloc. 504dfdcada3SDoug Rabson */ 505dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 506dfdcada3SDoug Rabson 507a9148abdSDoug Rabson if (ext && ext->rc_feedback) 508a9148abdSDoug Rabson ext->rc_feedback(FEEDBACK_OK, proc, ext->rc_feedback_arg); 509a9148abdSDoug Rabson 510c675522fSDoug Rabson xdrmbuf_create(&xdrs, cr->cr_mrep, XDR_DECODE); 511dfdcada3SDoug Rabson ok = xdr_replymsg(&xdrs, &reply_msg); 512c675522fSDoug Rabson cr->cr_mrep = NULL; 513dfdcada3SDoug Rabson 514dfdcada3SDoug Rabson if (ok) { 515dfdcada3SDoug Rabson if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && 516dfdcada3SDoug Rabson (reply_msg.acpted_rply.ar_stat == SUCCESS)) 517a9148abdSDoug Rabson errp->re_status = stat = RPC_SUCCESS; 518dfdcada3SDoug Rabson else 519a9148abdSDoug Rabson stat = _seterr_reply(&reply_msg, errp); 520dfdcada3SDoug Rabson 521a9148abdSDoug Rabson if (stat == RPC_SUCCESS) { 522a9148abdSDoug Rabson results = xdrmbuf_getall(&xdrs); 523a9148abdSDoug Rabson if (!AUTH_VALIDATE(auth, xid, 524a9148abdSDoug Rabson &reply_msg.acpted_rply.ar_verf, 525a9148abdSDoug Rabson &results)) { 526a9148abdSDoug Rabson errp->re_status = stat = RPC_AUTHERROR; 527a9148abdSDoug Rabson errp->re_why = AUTH_INVALIDRESP; 528a9148abdSDoug Rabson } else { 529a9148abdSDoug Rabson KASSERT(results, 530a9148abdSDoug Rabson ("auth validated but no result")); 531a9148abdSDoug Rabson *resultsp = results; 532dfdcada3SDoug Rabson } 533dfdcada3SDoug Rabson } /* end successful completion */ 534dfdcada3SDoug Rabson /* 535dfdcada3SDoug Rabson * If unsuccesful AND error is an authentication error 536dfdcada3SDoug Rabson * then refresh credentials and try again, else break 537dfdcada3SDoug Rabson */ 538a9148abdSDoug Rabson else if (stat == RPC_AUTHERROR) 539dfdcada3SDoug Rabson /* maybe our credentials need to be refreshed ... */ 540dfdcada3SDoug Rabson if (nrefreshes > 0 && 541a9148abdSDoug Rabson AUTH_REFRESH(auth, &reply_msg)) { 542dfdcada3SDoug Rabson nrefreshes--; 543a9148abdSDoug Rabson XDR_DESTROY(&xdrs); 544a9148abdSDoug Rabson mtx_lock(&ct->ct_lock); 545dfdcada3SDoug Rabson goto call_again; 546dfdcada3SDoug Rabson } 547dfdcada3SDoug Rabson /* end of unsuccessful completion */ 548dfdcada3SDoug Rabson } /* end of valid reply message */ 549dfdcada3SDoug Rabson else { 550a9148abdSDoug Rabson errp->re_status = stat = RPC_CANTDECODERES; 551dfdcada3SDoug Rabson } 552a9148abdSDoug Rabson XDR_DESTROY(&xdrs); 553a9148abdSDoug Rabson mtx_lock(&ct->ct_lock); 554dfdcada3SDoug Rabson out: 555dfdcada3SDoug Rabson mtx_assert(&ct->ct_lock, MA_OWNED); 556dfdcada3SDoug Rabson 557a9148abdSDoug Rabson KASSERT(stat != RPC_SUCCESS || *resultsp, 558a9148abdSDoug Rabson ("RPC_SUCCESS without reply")); 559a9148abdSDoug Rabson 560dfdcada3SDoug Rabson if (mreq) 561dfdcada3SDoug Rabson m_freem(mreq); 562c675522fSDoug Rabson if (cr->cr_mrep) 563c675522fSDoug Rabson m_freem(cr->cr_mrep); 564c675522fSDoug Rabson 565c675522fSDoug Rabson ct->ct_threads--; 566c675522fSDoug Rabson if (ct->ct_closing) 567c675522fSDoug Rabson wakeup(ct); 568dfdcada3SDoug Rabson 569dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 570c675522fSDoug Rabson 571a9148abdSDoug Rabson if (auth && stat != RPC_SUCCESS) 572a9148abdSDoug Rabson AUTH_VALIDATE(auth, xid, NULL, NULL); 573a9148abdSDoug Rabson 574c675522fSDoug Rabson free(cr, M_RPC); 575c675522fSDoug Rabson 576a9148abdSDoug Rabson return (stat); 577dfdcada3SDoug Rabson } 578dfdcada3SDoug Rabson 579dfdcada3SDoug Rabson static void 580dfdcada3SDoug Rabson clnt_vc_geterr(CLIENT *cl, struct rpc_err *errp) 581dfdcada3SDoug Rabson { 582dfdcada3SDoug Rabson struct ct_data *ct = (struct ct_data *) cl->cl_private; 583dfdcada3SDoug Rabson 584dfdcada3SDoug Rabson *errp = ct->ct_error; 585dfdcada3SDoug Rabson } 586dfdcada3SDoug Rabson 587dfdcada3SDoug Rabson static bool_t 588dfdcada3SDoug Rabson clnt_vc_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr) 589dfdcada3SDoug Rabson { 590dfdcada3SDoug Rabson XDR xdrs; 591dfdcada3SDoug Rabson bool_t dummy; 592dfdcada3SDoug Rabson 593dfdcada3SDoug Rabson xdrs.x_op = XDR_FREE; 594dfdcada3SDoug Rabson dummy = (*xdr_res)(&xdrs, res_ptr); 595dfdcada3SDoug Rabson 596dfdcada3SDoug Rabson return (dummy); 597dfdcada3SDoug Rabson } 598dfdcada3SDoug Rabson 599dfdcada3SDoug Rabson /*ARGSUSED*/ 600dfdcada3SDoug Rabson static void 601dfdcada3SDoug Rabson clnt_vc_abort(CLIENT *cl) 602dfdcada3SDoug Rabson { 603dfdcada3SDoug Rabson } 604dfdcada3SDoug Rabson 605dfdcada3SDoug Rabson static bool_t 606dfdcada3SDoug Rabson clnt_vc_control(CLIENT *cl, u_int request, void *info) 607dfdcada3SDoug Rabson { 608dfdcada3SDoug Rabson struct ct_data *ct = (struct ct_data *)cl->cl_private; 609dfdcada3SDoug Rabson void *infop = info; 610dfdcada3SDoug Rabson 611dfdcada3SDoug Rabson mtx_lock(&ct->ct_lock); 612dfdcada3SDoug Rabson 613dfdcada3SDoug Rabson switch (request) { 614dfdcada3SDoug Rabson case CLSET_FD_CLOSE: 615dfdcada3SDoug Rabson ct->ct_closeit = TRUE; 616dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 617dfdcada3SDoug Rabson return (TRUE); 618dfdcada3SDoug Rabson case CLSET_FD_NCLOSE: 619dfdcada3SDoug Rabson ct->ct_closeit = FALSE; 620dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 621dfdcada3SDoug Rabson return (TRUE); 622dfdcada3SDoug Rabson default: 623dfdcada3SDoug Rabson break; 624dfdcada3SDoug Rabson } 625dfdcada3SDoug Rabson 626dfdcada3SDoug Rabson /* for other requests which use info */ 627dfdcada3SDoug Rabson if (info == NULL) { 628dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 629dfdcada3SDoug Rabson return (FALSE); 630dfdcada3SDoug Rabson } 631dfdcada3SDoug Rabson switch (request) { 632dfdcada3SDoug Rabson case CLSET_TIMEOUT: 633dfdcada3SDoug Rabson if (time_not_ok((struct timeval *)info)) { 634dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 635dfdcada3SDoug Rabson return (FALSE); 636dfdcada3SDoug Rabson } 637dfdcada3SDoug Rabson ct->ct_wait = *(struct timeval *)infop; 638dfdcada3SDoug Rabson break; 639dfdcada3SDoug Rabson case CLGET_TIMEOUT: 640dfdcada3SDoug Rabson *(struct timeval *)infop = ct->ct_wait; 641dfdcada3SDoug Rabson break; 642dfdcada3SDoug Rabson case CLGET_SERVER_ADDR: 643dfdcada3SDoug Rabson (void) memcpy(info, &ct->ct_addr, (size_t)ct->ct_addr.ss_len); 644dfdcada3SDoug Rabson break; 645dfdcada3SDoug Rabson case CLGET_SVC_ADDR: 646dfdcada3SDoug Rabson /* 647dfdcada3SDoug Rabson * Slightly different semantics to userland - we use 648dfdcada3SDoug Rabson * sockaddr instead of netbuf. 649dfdcada3SDoug Rabson */ 650dfdcada3SDoug Rabson memcpy(info, &ct->ct_addr, ct->ct_addr.ss_len); 651dfdcada3SDoug Rabson break; 652dfdcada3SDoug Rabson case CLSET_SVC_ADDR: /* set to new address */ 653dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 654dfdcada3SDoug Rabson return (FALSE); 655dfdcada3SDoug Rabson case CLGET_XID: 656dfdcada3SDoug Rabson *(uint32_t *)info = ct->ct_xid; 657dfdcada3SDoug Rabson break; 658dfdcada3SDoug Rabson case CLSET_XID: 659dfdcada3SDoug Rabson /* This will set the xid of the NEXT call */ 660dfdcada3SDoug Rabson /* decrement by 1 as clnt_vc_call() increments once */ 661dfdcada3SDoug Rabson ct->ct_xid = *(uint32_t *)info - 1; 662dfdcada3SDoug Rabson break; 663dfdcada3SDoug Rabson case CLGET_VERS: 664dfdcada3SDoug Rabson /* 665dfdcada3SDoug Rabson * This RELIES on the information that, in the call body, 666dfdcada3SDoug Rabson * the version number field is the fifth field from the 667dfdcada3SDoug Rabson * begining of the RPC header. MUST be changed if the 668dfdcada3SDoug Rabson * call_struct is changed 669dfdcada3SDoug Rabson */ 670dfdcada3SDoug Rabson *(uint32_t *)info = 671dfdcada3SDoug Rabson ntohl(*(uint32_t *)(void *)(ct->ct_mcallc + 672dfdcada3SDoug Rabson 4 * BYTES_PER_XDR_UNIT)); 673dfdcada3SDoug Rabson break; 674dfdcada3SDoug Rabson 675dfdcada3SDoug Rabson case CLSET_VERS: 676dfdcada3SDoug Rabson *(uint32_t *)(void *)(ct->ct_mcallc + 677dfdcada3SDoug Rabson 4 * BYTES_PER_XDR_UNIT) = 678dfdcada3SDoug Rabson htonl(*(uint32_t *)info); 679dfdcada3SDoug Rabson break; 680dfdcada3SDoug Rabson 681dfdcada3SDoug Rabson case CLGET_PROG: 682dfdcada3SDoug Rabson /* 683dfdcada3SDoug Rabson * This RELIES on the information that, in the call body, 684dfdcada3SDoug Rabson * the program number field is the fourth field from the 685dfdcada3SDoug Rabson * begining of the RPC header. MUST be changed if the 686dfdcada3SDoug Rabson * call_struct is changed 687dfdcada3SDoug Rabson */ 688dfdcada3SDoug Rabson *(uint32_t *)info = 689dfdcada3SDoug Rabson ntohl(*(uint32_t *)(void *)(ct->ct_mcallc + 690dfdcada3SDoug Rabson 3 * BYTES_PER_XDR_UNIT)); 691dfdcada3SDoug Rabson break; 692dfdcada3SDoug Rabson 693dfdcada3SDoug Rabson case CLSET_PROG: 694dfdcada3SDoug Rabson *(uint32_t *)(void *)(ct->ct_mcallc + 695dfdcada3SDoug Rabson 3 * BYTES_PER_XDR_UNIT) = 696dfdcada3SDoug Rabson htonl(*(uint32_t *)info); 697dfdcada3SDoug Rabson break; 698dfdcada3SDoug Rabson 699dfdcada3SDoug Rabson case CLSET_WAITCHAN: 700a9148abdSDoug Rabson ct->ct_waitchan = (const char *)info; 701dfdcada3SDoug Rabson break; 702dfdcada3SDoug Rabson 703dfdcada3SDoug Rabson case CLGET_WAITCHAN: 704dfdcada3SDoug Rabson *(const char **) info = ct->ct_waitchan; 705dfdcada3SDoug Rabson break; 706dfdcada3SDoug Rabson 707dfdcada3SDoug Rabson case CLSET_INTERRUPTIBLE: 708dfdcada3SDoug Rabson if (*(int *) info) 709dfdcada3SDoug Rabson ct->ct_waitflag = PCATCH; 710dfdcada3SDoug Rabson else 711dfdcada3SDoug Rabson ct->ct_waitflag = 0; 712dfdcada3SDoug Rabson break; 713dfdcada3SDoug Rabson 714dfdcada3SDoug Rabson case CLGET_INTERRUPTIBLE: 715dfdcada3SDoug Rabson if (ct->ct_waitflag) 716dfdcada3SDoug Rabson *(int *) info = TRUE; 717dfdcada3SDoug Rabson else 718dfdcada3SDoug Rabson *(int *) info = FALSE; 719dfdcada3SDoug Rabson break; 720dfdcada3SDoug Rabson 721dfdcada3SDoug Rabson default: 722dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 723dfdcada3SDoug Rabson return (FALSE); 724dfdcada3SDoug Rabson } 725dfdcada3SDoug Rabson 726dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 727dfdcada3SDoug Rabson return (TRUE); 728dfdcada3SDoug Rabson } 729dfdcada3SDoug Rabson 730dfdcada3SDoug Rabson static void 731a9148abdSDoug Rabson clnt_vc_close(CLIENT *cl) 732dfdcada3SDoug Rabson { 733dfdcada3SDoug Rabson struct ct_data *ct = (struct ct_data *) cl->cl_private; 734c675522fSDoug Rabson struct ct_request *cr; 735dfdcada3SDoug Rabson 736dfdcada3SDoug Rabson mtx_lock(&ct->ct_lock); 737dfdcada3SDoug Rabson 738a9148abdSDoug Rabson if (ct->ct_closed) { 739a9148abdSDoug Rabson mtx_unlock(&ct->ct_lock); 740a9148abdSDoug Rabson return; 741a9148abdSDoug Rabson } 742a9148abdSDoug Rabson 743a9148abdSDoug Rabson if (ct->ct_closing) { 744a9148abdSDoug Rabson while (ct->ct_closing) 745a9148abdSDoug Rabson msleep(ct, &ct->ct_lock, 0, "rpcclose", 0); 746a9148abdSDoug Rabson KASSERT(ct->ct_closed, ("client should be closed")); 747a9148abdSDoug Rabson mtx_unlock(&ct->ct_lock); 748a9148abdSDoug Rabson return; 749a9148abdSDoug Rabson } 750a9148abdSDoug Rabson 751dfdcada3SDoug Rabson if (ct->ct_socket) { 752dfdcada3SDoug Rabson SOCKBUF_LOCK(&ct->ct_socket->so_rcv); 753dfdcada3SDoug Rabson ct->ct_socket->so_upcallarg = NULL; 754dfdcada3SDoug Rabson ct->ct_socket->so_upcall = NULL; 755dfdcada3SDoug Rabson ct->ct_socket->so_rcv.sb_flags &= ~SB_UPCALL; 756dfdcada3SDoug Rabson SOCKBUF_UNLOCK(&ct->ct_socket->so_rcv); 757dfdcada3SDoug Rabson 758c675522fSDoug Rabson /* 759c675522fSDoug Rabson * Abort any pending requests and wait until everyone 760c675522fSDoug Rabson * has finished with clnt_vc_call. 761c675522fSDoug Rabson */ 762c675522fSDoug Rabson ct->ct_closing = TRUE; 763c675522fSDoug Rabson TAILQ_FOREACH(cr, &ct->ct_pending, cr_link) { 764c675522fSDoug Rabson cr->cr_xid = 0; 765c675522fSDoug Rabson cr->cr_error = ESHUTDOWN; 766c675522fSDoug Rabson wakeup(cr); 767c675522fSDoug Rabson } 768c675522fSDoug Rabson 769c675522fSDoug Rabson while (ct->ct_threads) 770c675522fSDoug Rabson msleep(ct, &ct->ct_lock, 0, "rpcclose", 0); 771a9148abdSDoug Rabson } 772dfdcada3SDoug Rabson 773a9148abdSDoug Rabson ct->ct_closing = FALSE; 774a9148abdSDoug Rabson ct->ct_closed = TRUE; 775a9148abdSDoug Rabson mtx_unlock(&ct->ct_lock); 776a9148abdSDoug Rabson wakeup(ct); 777a9148abdSDoug Rabson } 778a9148abdSDoug Rabson 779a9148abdSDoug Rabson static void 780a9148abdSDoug Rabson clnt_vc_destroy(CLIENT *cl) 781a9148abdSDoug Rabson { 782a9148abdSDoug Rabson struct ct_data *ct = (struct ct_data *) cl->cl_private; 783a9148abdSDoug Rabson struct socket *so = NULL; 784a9148abdSDoug Rabson 785a9148abdSDoug Rabson clnt_vc_close(cl); 786a9148abdSDoug Rabson 787a9148abdSDoug Rabson mtx_lock(&ct->ct_lock); 788a9148abdSDoug Rabson 789a9148abdSDoug Rabson if (ct->ct_socket) { 790dfdcada3SDoug Rabson if (ct->ct_closeit) { 791dfdcada3SDoug Rabson so = ct->ct_socket; 792dfdcada3SDoug Rabson } 793dfdcada3SDoug Rabson } 794dfdcada3SDoug Rabson 795dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 796dfdcada3SDoug Rabson 797dfdcada3SDoug Rabson mtx_destroy(&ct->ct_lock); 798dfdcada3SDoug Rabson if (so) { 799dfdcada3SDoug Rabson soshutdown(so, SHUT_WR); 800dfdcada3SDoug Rabson soclose(so); 801dfdcada3SDoug Rabson } 802dfdcada3SDoug Rabson mem_free(ct, sizeof(struct ct_data)); 803dfdcada3SDoug Rabson mem_free(cl, sizeof(CLIENT)); 804dfdcada3SDoug Rabson } 805dfdcada3SDoug Rabson 806dfdcada3SDoug Rabson /* 807dfdcada3SDoug Rabson * Make sure that the time is not garbage. -1 value is disallowed. 808dfdcada3SDoug Rabson * Note this is different from time_not_ok in clnt_dg.c 809dfdcada3SDoug Rabson */ 810dfdcada3SDoug Rabson static bool_t 811dfdcada3SDoug Rabson time_not_ok(struct timeval *t) 812dfdcada3SDoug Rabson { 813dfdcada3SDoug Rabson return (t->tv_sec <= -1 || t->tv_sec > 100000000 || 814dfdcada3SDoug Rabson t->tv_usec <= -1 || t->tv_usec > 1000000); 815dfdcada3SDoug Rabson } 816dfdcada3SDoug Rabson 817dfdcada3SDoug Rabson void 818dfdcada3SDoug Rabson clnt_vc_soupcall(struct socket *so, void *arg, int waitflag) 819dfdcada3SDoug Rabson { 820dfdcada3SDoug Rabson struct ct_data *ct = (struct ct_data *) arg; 821dfdcada3SDoug Rabson struct uio uio; 822dfdcada3SDoug Rabson struct mbuf *m; 823dfdcada3SDoug Rabson struct ct_request *cr; 824dfdcada3SDoug Rabson int error, rcvflag, foundreq; 825dfdcada3SDoug Rabson uint32_t xid, header; 826a9148abdSDoug Rabson bool_t do_read; 827dfdcada3SDoug Rabson 828dfdcada3SDoug Rabson uio.uio_td = curthread; 829dfdcada3SDoug Rabson do { 830dfdcada3SDoug Rabson /* 831dfdcada3SDoug Rabson * If ct_record_resid is zero, we are waiting for a 832dfdcada3SDoug Rabson * record mark. 833dfdcada3SDoug Rabson */ 834dfdcada3SDoug Rabson if (ct->ct_record_resid == 0) { 835dfdcada3SDoug Rabson 836dfdcada3SDoug Rabson /* 837dfdcada3SDoug Rabson * Make sure there is either a whole record 838dfdcada3SDoug Rabson * mark in the buffer or there is some other 839dfdcada3SDoug Rabson * error condition 840dfdcada3SDoug Rabson */ 841dfdcada3SDoug Rabson do_read = FALSE; 842dfdcada3SDoug Rabson SOCKBUF_LOCK(&so->so_rcv); 843dfdcada3SDoug Rabson if (so->so_rcv.sb_cc >= sizeof(uint32_t) 844dfdcada3SDoug Rabson || (so->so_rcv.sb_state & SBS_CANTRCVMORE) 845dfdcada3SDoug Rabson || so->so_error) 846dfdcada3SDoug Rabson do_read = TRUE; 847dfdcada3SDoug Rabson SOCKBUF_UNLOCK(&so->so_rcv); 848dfdcada3SDoug Rabson 849dfdcada3SDoug Rabson if (!do_read) 850dfdcada3SDoug Rabson return; 851dfdcada3SDoug Rabson 852dfdcada3SDoug Rabson uio.uio_resid = sizeof(uint32_t); 853dfdcada3SDoug Rabson m = NULL; 854dfdcada3SDoug Rabson rcvflag = MSG_DONTWAIT | MSG_SOCALLBCK; 855dfdcada3SDoug Rabson error = soreceive(so, NULL, &uio, &m, NULL, &rcvflag); 856dfdcada3SDoug Rabson 857dfdcada3SDoug Rabson if (error == EWOULDBLOCK) 858dfdcada3SDoug Rabson break; 859dfdcada3SDoug Rabson 860dfdcada3SDoug Rabson /* 861dfdcada3SDoug Rabson * If there was an error, wake up all pending 862dfdcada3SDoug Rabson * requests. 863dfdcada3SDoug Rabson */ 864dfdcada3SDoug Rabson if (error || uio.uio_resid > 0) { 865dfdcada3SDoug Rabson wakeup_all: 866dfdcada3SDoug Rabson mtx_lock(&ct->ct_lock); 867dfdcada3SDoug Rabson if (!error) { 868dfdcada3SDoug Rabson /* 869dfdcada3SDoug Rabson * We must have got EOF trying 870dfdcada3SDoug Rabson * to read from the stream. 871dfdcada3SDoug Rabson */ 872dfdcada3SDoug Rabson error = ECONNRESET; 873dfdcada3SDoug Rabson } 874dfdcada3SDoug Rabson ct->ct_error.re_status = RPC_CANTRECV; 875dfdcada3SDoug Rabson ct->ct_error.re_errno = error; 876dfdcada3SDoug Rabson TAILQ_FOREACH(cr, &ct->ct_pending, cr_link) { 877dfdcada3SDoug Rabson cr->cr_error = error; 878dfdcada3SDoug Rabson wakeup(cr); 879dfdcada3SDoug Rabson } 880dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 881dfdcada3SDoug Rabson break; 882dfdcada3SDoug Rabson } 883a9148abdSDoug Rabson bcopy(mtod(m, uint32_t *), &header, sizeof(uint32_t)); 884dfdcada3SDoug Rabson header = ntohl(header); 885dfdcada3SDoug Rabson ct->ct_record = NULL; 886dfdcada3SDoug Rabson ct->ct_record_resid = header & 0x7fffffff; 887dfdcada3SDoug Rabson ct->ct_record_eor = ((header & 0x80000000) != 0); 888dfdcada3SDoug Rabson m_freem(m); 889dfdcada3SDoug Rabson } else { 890dfdcada3SDoug Rabson /* 891a9148abdSDoug Rabson * Wait until the socket has the whole record 892a9148abdSDoug Rabson * buffered. 893a9148abdSDoug Rabson */ 894a9148abdSDoug Rabson do_read = FALSE; 895a9148abdSDoug Rabson SOCKBUF_LOCK(&so->so_rcv); 896a9148abdSDoug Rabson if (so->so_rcv.sb_cc >= ct->ct_record_resid 897a9148abdSDoug Rabson || (so->so_rcv.sb_state & SBS_CANTRCVMORE) 898a9148abdSDoug Rabson || so->so_error) 899a9148abdSDoug Rabson do_read = TRUE; 900a9148abdSDoug Rabson SOCKBUF_UNLOCK(&so->so_rcv); 901a9148abdSDoug Rabson 902a9148abdSDoug Rabson if (!do_read) 903a9148abdSDoug Rabson return; 904a9148abdSDoug Rabson 905a9148abdSDoug Rabson /* 906dfdcada3SDoug Rabson * We have the record mark. Read as much as 907dfdcada3SDoug Rabson * the socket has buffered up to the end of 908dfdcada3SDoug Rabson * this record. 909dfdcada3SDoug Rabson */ 910dfdcada3SDoug Rabson uio.uio_resid = ct->ct_record_resid; 911dfdcada3SDoug Rabson m = NULL; 912dfdcada3SDoug Rabson rcvflag = MSG_DONTWAIT | MSG_SOCALLBCK; 913dfdcada3SDoug Rabson error = soreceive(so, NULL, &uio, &m, NULL, &rcvflag); 914dfdcada3SDoug Rabson 915dfdcada3SDoug Rabson if (error == EWOULDBLOCK) 916dfdcada3SDoug Rabson break; 917dfdcada3SDoug Rabson 918dfdcada3SDoug Rabson if (error || uio.uio_resid == ct->ct_record_resid) 919dfdcada3SDoug Rabson goto wakeup_all; 920dfdcada3SDoug Rabson 921dfdcada3SDoug Rabson /* 922dfdcada3SDoug Rabson * If we have part of the record already, 923dfdcada3SDoug Rabson * chain this bit onto the end. 924dfdcada3SDoug Rabson */ 925dfdcada3SDoug Rabson if (ct->ct_record) 926dfdcada3SDoug Rabson m_last(ct->ct_record)->m_next = m; 927dfdcada3SDoug Rabson else 928dfdcada3SDoug Rabson ct->ct_record = m; 929dfdcada3SDoug Rabson 930dfdcada3SDoug Rabson ct->ct_record_resid = uio.uio_resid; 931dfdcada3SDoug Rabson 932dfdcada3SDoug Rabson /* 933dfdcada3SDoug Rabson * If we have the entire record, see if we can 934dfdcada3SDoug Rabson * match it to a request. 935dfdcada3SDoug Rabson */ 936dfdcada3SDoug Rabson if (ct->ct_record_resid == 0 937dfdcada3SDoug Rabson && ct->ct_record_eor) { 938dfdcada3SDoug Rabson /* 939dfdcada3SDoug Rabson * The XID is in the first uint32_t of 940dfdcada3SDoug Rabson * the reply. 941dfdcada3SDoug Rabson */ 942a9148abdSDoug Rabson if (ct->ct_record->m_len < sizeof(xid)) 943dfdcada3SDoug Rabson ct->ct_record = 944a9148abdSDoug Rabson m_pullup(ct->ct_record, 945a9148abdSDoug Rabson sizeof(xid)); 946dfdcada3SDoug Rabson if (!ct->ct_record) 947dfdcada3SDoug Rabson break; 948a9148abdSDoug Rabson bcopy(mtod(ct->ct_record, uint32_t *), 949a9148abdSDoug Rabson &xid, sizeof(uint32_t)); 950dfdcada3SDoug Rabson xid = ntohl(xid); 951dfdcada3SDoug Rabson 952dfdcada3SDoug Rabson mtx_lock(&ct->ct_lock); 953dfdcada3SDoug Rabson foundreq = 0; 954dfdcada3SDoug Rabson TAILQ_FOREACH(cr, &ct->ct_pending, cr_link) { 955dfdcada3SDoug Rabson if (cr->cr_xid == xid) { 956dfdcada3SDoug Rabson /* 957dfdcada3SDoug Rabson * This one 958c675522fSDoug Rabson * matches. We leave 959c675522fSDoug Rabson * the reply mbuf in 960dfdcada3SDoug Rabson * cr->cr_mrep. Set 961dfdcada3SDoug Rabson * the XID to zero so 962c675522fSDoug Rabson * that we will ignore 963c675522fSDoug Rabson * any duplicaed 964c675522fSDoug Rabson * replies. 965dfdcada3SDoug Rabson */ 966dfdcada3SDoug Rabson cr->cr_xid = 0; 967dfdcada3SDoug Rabson cr->cr_mrep = ct->ct_record; 968dfdcada3SDoug Rabson cr->cr_error = 0; 969dfdcada3SDoug Rabson foundreq = 1; 970dfdcada3SDoug Rabson wakeup(cr); 971dfdcada3SDoug Rabson break; 972dfdcada3SDoug Rabson } 973dfdcada3SDoug Rabson } 974dfdcada3SDoug Rabson mtx_unlock(&ct->ct_lock); 975dfdcada3SDoug Rabson 976dfdcada3SDoug Rabson if (!foundreq) 977dfdcada3SDoug Rabson m_freem(ct->ct_record); 978dfdcada3SDoug Rabson ct->ct_record = NULL; 979dfdcada3SDoug Rabson } 980dfdcada3SDoug Rabson } 981dfdcada3SDoug Rabson } while (m); 982dfdcada3SDoug Rabson } 983