clnt_rc.c revision 177633
1177633Sdfr/*- 2177633Sdfr * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ 3177633Sdfr * Authors: Doug Rabson <dfr@rabson.org> 4177633Sdfr * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org> 5177633Sdfr * 6177633Sdfr * Redistribution and use in source and binary forms, with or without 7177633Sdfr * modification, are permitted provided that the following conditions 8177633Sdfr * are met: 9177633Sdfr * 1. Redistributions of source code must retain the above copyright 10177633Sdfr * notice, this list of conditions and the following disclaimer. 11177633Sdfr * 2. Redistributions in binary form must reproduce the above copyright 12177633Sdfr * notice, this list of conditions and the following disclaimer in the 13177633Sdfr * documentation and/or other materials provided with the distribution. 14177633Sdfr * 15177633Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16177633Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17177633Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18177633Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19177633Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20177633Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21177633Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22177633Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23177633Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24177633Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25177633Sdfr * SUCH DAMAGE. 26177633Sdfr */ 27177633Sdfr 28177633Sdfr#include <sys/cdefs.h> 29177633Sdfr__FBSDID("$FreeBSD: head/sys/rpc/clnt_rc.c 177633 2008-03-26 15:23:12Z dfr $"); 30177633Sdfr 31177633Sdfr#include <sys/param.h> 32177633Sdfr#include <sys/systm.h> 33177633Sdfr#include <sys/lock.h> 34177633Sdfr#include <sys/malloc.h> 35177633Sdfr#include <sys/mbuf.h> 36177633Sdfr#include <sys/mutex.h> 37177633Sdfr#include <sys/pcpu.h> 38177633Sdfr#include <sys/proc.h> 39177633Sdfr#include <sys/socket.h> 40177633Sdfr#include <sys/socketvar.h> 41177633Sdfr#include <sys/time.h> 42177633Sdfr#include <sys/uio.h> 43177633Sdfr 44177633Sdfr#include <rpc/rpc.h> 45177633Sdfr#include "rpc_com.h" 46177633Sdfr 47177633Sdfrstatic enum clnt_stat clnt_reconnect_call(CLIENT *, rpcproc_t, 48177633Sdfr xdrproc_t, void *, xdrproc_t, void *, struct timeval); 49177633Sdfrstatic void clnt_reconnect_geterr(CLIENT *, struct rpc_err *); 50177633Sdfrstatic bool_t clnt_reconnect_freeres(CLIENT *, xdrproc_t, void *); 51177633Sdfrstatic void clnt_reconnect_abort(CLIENT *); 52177633Sdfrstatic bool_t clnt_reconnect_control(CLIENT *, u_int, void *); 53177633Sdfrstatic void clnt_reconnect_destroy(CLIENT *); 54177633Sdfr 55177633Sdfrstatic struct clnt_ops clnt_reconnect_ops = { 56177633Sdfr .cl_call = clnt_reconnect_call, 57177633Sdfr .cl_abort = clnt_reconnect_abort, 58177633Sdfr .cl_geterr = clnt_reconnect_geterr, 59177633Sdfr .cl_freeres = clnt_reconnect_freeres, 60177633Sdfr .cl_destroy = clnt_reconnect_destroy, 61177633Sdfr .cl_control = clnt_reconnect_control 62177633Sdfr}; 63177633Sdfr 64177633Sdfrstruct rc_data { 65177633Sdfr struct sockaddr_storage rc_addr; /* server address */ 66177633Sdfr struct netconfig* rc_nconf; /* network type */ 67177633Sdfr rpcprog_t rc_prog; /* program number */ 68177633Sdfr rpcvers_t rc_vers; /* version number */ 69177633Sdfr size_t rc_sendsz; 70177633Sdfr size_t rc_recvsz; 71177633Sdfr struct timeval rc_timeout; 72177633Sdfr struct timeval rc_retry; 73177633Sdfr const char *rc_waitchan; 74177633Sdfr int rc_intr; 75177633Sdfr CLIENT* rc_client; /* underlying RPC client */ 76177633Sdfr}; 77177633Sdfr 78177633SdfrCLIENT * 79177633Sdfrclnt_reconnect_create( 80177633Sdfr struct netconfig *nconf, /* network type */ 81177633Sdfr struct sockaddr *svcaddr, /* servers address */ 82177633Sdfr rpcprog_t program, /* program number */ 83177633Sdfr rpcvers_t version, /* version number */ 84177633Sdfr size_t sendsz, /* buffer recv size */ 85177633Sdfr size_t recvsz) /* buffer send size */ 86177633Sdfr{ 87177633Sdfr CLIENT *cl = NULL; /* client handle */ 88177633Sdfr struct rc_data *rc = NULL; /* private data */ 89177633Sdfr 90177633Sdfr if (svcaddr == NULL) { 91177633Sdfr rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 92177633Sdfr return (NULL); 93177633Sdfr } 94177633Sdfr 95177633Sdfr cl = mem_alloc(sizeof (CLIENT)); 96177633Sdfr rc = mem_alloc(sizeof (*rc)); 97177633Sdfr (void) memcpy(&rc->rc_addr, svcaddr, (size_t)svcaddr->sa_len); 98177633Sdfr rc->rc_nconf = nconf; 99177633Sdfr rc->rc_prog = program; 100177633Sdfr rc->rc_vers = version; 101177633Sdfr rc->rc_sendsz = sendsz; 102177633Sdfr rc->rc_recvsz = recvsz; 103177633Sdfr rc->rc_timeout.tv_sec = -1; 104177633Sdfr rc->rc_timeout.tv_usec = -1; 105177633Sdfr rc->rc_retry.tv_sec = 15; 106177633Sdfr rc->rc_retry.tv_usec = 0; 107177633Sdfr rc->rc_waitchan = "rpcrecv"; 108177633Sdfr rc->rc_intr = 0; 109177633Sdfr rc->rc_client = NULL; 110177633Sdfr 111177633Sdfr cl->cl_ops = &clnt_reconnect_ops; 112177633Sdfr cl->cl_private = (caddr_t)(void *)rc; 113177633Sdfr cl->cl_auth = authnone_create(); 114177633Sdfr cl->cl_tp = NULL; 115177633Sdfr cl->cl_netid = NULL; 116177633Sdfr return (cl); 117177633Sdfr} 118177633Sdfr 119177633Sdfrstatic enum clnt_stat 120177633Sdfrclnt_reconnect_connect(CLIENT *cl) 121177633Sdfr{ 122177633Sdfr struct rc_data *rc = (struct rc_data *)cl->cl_private; 123177633Sdfr struct socket *so; 124177633Sdfr int one = 1; 125177633Sdfr 126177633Sdfr so = __rpc_nconf2socket(rc->rc_nconf); 127177633Sdfr if (!so) { 128177633Sdfr rpc_createerr.cf_stat = RPC_TLIERROR; 129177633Sdfr rpc_createerr.cf_error.re_errno = 0; 130177633Sdfr return (RPC_TLIERROR); 131177633Sdfr } 132177633Sdfr 133177633Sdfr if (rc->rc_nconf->nc_semantics == NC_TPI_CLTS) 134177633Sdfr rc->rc_client = clnt_dg_create(so, 135177633Sdfr (struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers, 136177633Sdfr rc->rc_sendsz, rc->rc_recvsz); 137177633Sdfr else 138177633Sdfr rc->rc_client = clnt_vc_create(so, 139177633Sdfr (struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers, 140177633Sdfr rc->rc_sendsz, rc->rc_recvsz); 141177633Sdfr 142177633Sdfr CLNT_CONTROL(rc->rc_client, CLSET_FD_CLOSE, 0); 143177633Sdfr CLNT_CONTROL(rc->rc_client, CLSET_CONNECT, &one); 144177633Sdfr CLNT_CONTROL(rc->rc_client, CLSET_TIMEOUT, &rc->rc_timeout); 145177633Sdfr CLNT_CONTROL(rc->rc_client, CLSET_RETRY_TIMEOUT, &rc->rc_retry); 146177633Sdfr CLNT_CONTROL(rc->rc_client, CLSET_WAITCHAN, &rc->rc_waitchan); 147177633Sdfr CLNT_CONTROL(rc->rc_client, CLSET_INTERRUPTIBLE, &rc->rc_intr); 148177633Sdfr 149177633Sdfr return (RPC_SUCCESS); 150177633Sdfr} 151177633Sdfr 152177633Sdfrstatic enum clnt_stat 153177633Sdfrclnt_reconnect_call( 154177633Sdfr CLIENT *cl, /* client handle */ 155177633Sdfr rpcproc_t proc, /* procedure number */ 156177633Sdfr xdrproc_t xargs, /* xdr routine for args */ 157177633Sdfr void *argsp, /* pointer to args */ 158177633Sdfr xdrproc_t xresults, /* xdr routine for results */ 159177633Sdfr void *resultsp, /* pointer to results */ 160177633Sdfr struct timeval utimeout) /* seconds to wait before giving up */ 161177633Sdfr{ 162177633Sdfr struct rc_data *rc = (struct rc_data *)cl->cl_private; 163177633Sdfr enum clnt_stat stat; 164177633Sdfr 165177633Sdfr do { 166177633Sdfr if (!rc->rc_client) 167177633Sdfr clnt_reconnect_connect(cl); 168177633Sdfr 169177633Sdfr stat = CLNT_CALL(rc->rc_client, proc, xargs, argsp, 170177633Sdfr xresults, resultsp, utimeout); 171177633Sdfr 172177633Sdfr if (stat == RPC_TIMEDOUT) { 173177633Sdfr /* 174177633Sdfr * Check for async send misfeature for NLM 175177633Sdfr * protocol. 176177633Sdfr */ 177177633Sdfr if ((rc->rc_timeout.tv_sec == 0 178177633Sdfr && rc->rc_timeout.tv_usec == 0) 179177633Sdfr || (rc->rc_timeout.tv_sec == -1 180177633Sdfr && utimeout.tv_sec == 0 181177633Sdfr && utimeout.tv_usec == 0)) 182177633Sdfr break; 183177633Sdfr } 184177633Sdfr 185177633Sdfr if (stat == RPC_INTR) 186177633Sdfr break; 187177633Sdfr 188177633Sdfr if (stat != RPC_SUCCESS) { 189177633Sdfr CLNT_DESTROY(rc->rc_client); 190177633Sdfr rc->rc_client = NULL; 191177633Sdfr } 192177633Sdfr } while (stat != RPC_SUCCESS); 193177633Sdfr 194177633Sdfr return (stat); 195177633Sdfr} 196177633Sdfr 197177633Sdfrstatic void 198177633Sdfrclnt_reconnect_geterr(CLIENT *cl, struct rpc_err *errp) 199177633Sdfr{ 200177633Sdfr struct rc_data *rc = (struct rc_data *)cl->cl_private; 201177633Sdfr 202177633Sdfr if (rc->rc_client) 203177633Sdfr CLNT_GETERR(rc->rc_client, errp); 204177633Sdfr else 205177633Sdfr memset(errp, 0, sizeof(*errp)); 206177633Sdfr} 207177633Sdfr 208177633Sdfrstatic bool_t 209177633Sdfrclnt_reconnect_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr) 210177633Sdfr{ 211177633Sdfr struct rc_data *rc = (struct rc_data *)cl->cl_private; 212177633Sdfr 213177633Sdfr return (CLNT_FREERES(rc->rc_client, xdr_res, res_ptr)); 214177633Sdfr} 215177633Sdfr 216177633Sdfr/*ARGSUSED*/ 217177633Sdfrstatic void 218177633Sdfrclnt_reconnect_abort(CLIENT *h) 219177633Sdfr{ 220177633Sdfr} 221177633Sdfr 222177633Sdfrstatic bool_t 223177633Sdfrclnt_reconnect_control(CLIENT *cl, u_int request, void *info) 224177633Sdfr{ 225177633Sdfr struct rc_data *rc = (struct rc_data *)cl->cl_private; 226177633Sdfr 227177633Sdfr if (info == NULL) { 228177633Sdfr return (FALSE); 229177633Sdfr } 230177633Sdfr switch (request) { 231177633Sdfr case CLSET_TIMEOUT: 232177633Sdfr rc->rc_timeout = *(struct timeval *)info; 233177633Sdfr if (rc->rc_client) 234177633Sdfr CLNT_CONTROL(rc->rc_client, request, info); 235177633Sdfr break; 236177633Sdfr 237177633Sdfr case CLGET_TIMEOUT: 238177633Sdfr *(struct timeval *)info = rc->rc_timeout; 239177633Sdfr break; 240177633Sdfr 241177633Sdfr case CLSET_RETRY_TIMEOUT: 242177633Sdfr rc->rc_retry = *(struct timeval *)info; 243177633Sdfr if (rc->rc_client) 244177633Sdfr CLNT_CONTROL(rc->rc_client, request, info); 245177633Sdfr break; 246177633Sdfr 247177633Sdfr case CLGET_RETRY_TIMEOUT: 248177633Sdfr *(struct timeval *)info = rc->rc_retry; 249177633Sdfr break; 250177633Sdfr 251177633Sdfr case CLGET_VERS: 252177633Sdfr *(uint32_t *)info = rc->rc_vers; 253177633Sdfr break; 254177633Sdfr 255177633Sdfr case CLSET_VERS: 256177633Sdfr rc->rc_vers = *(uint32_t *) info; 257177633Sdfr if (rc->rc_client) 258177633Sdfr CLNT_CONTROL(rc->rc_client, CLSET_VERS, info); 259177633Sdfr break; 260177633Sdfr 261177633Sdfr case CLGET_PROG: 262177633Sdfr *(uint32_t *)info = rc->rc_prog; 263177633Sdfr break; 264177633Sdfr 265177633Sdfr case CLSET_PROG: 266177633Sdfr rc->rc_prog = *(uint32_t *) info; 267177633Sdfr if (rc->rc_client) 268177633Sdfr CLNT_CONTROL(rc->rc_client, request, info); 269177633Sdfr break; 270177633Sdfr 271177633Sdfr case CLSET_WAITCHAN: 272177633Sdfr rc->rc_waitchan = *(const char **)info; 273177633Sdfr if (rc->rc_client) 274177633Sdfr CLNT_CONTROL(rc->rc_client, request, info); 275177633Sdfr break; 276177633Sdfr 277177633Sdfr case CLGET_WAITCHAN: 278177633Sdfr *(const char **) info = rc->rc_waitchan; 279177633Sdfr break; 280177633Sdfr 281177633Sdfr case CLSET_INTERRUPTIBLE: 282177633Sdfr rc->rc_intr = *(int *) info; 283177633Sdfr if (rc->rc_client) 284177633Sdfr CLNT_CONTROL(rc->rc_client, request, info); 285177633Sdfr break; 286177633Sdfr 287177633Sdfr case CLGET_INTERRUPTIBLE: 288177633Sdfr *(int *) info = rc->rc_intr; 289177633Sdfr break; 290177633Sdfr 291177633Sdfr default: 292177633Sdfr return (FALSE); 293177633Sdfr } 294177633Sdfr 295177633Sdfr return (TRUE); 296177633Sdfr} 297177633Sdfr 298177633Sdfrstatic void 299177633Sdfrclnt_reconnect_destroy(CLIENT *cl) 300177633Sdfr{ 301177633Sdfr struct rc_data *rc = (struct rc_data *)cl->cl_private; 302177633Sdfr 303177633Sdfr if (rc->rc_client) 304177633Sdfr CLNT_DESTROY(rc->rc_client); 305177633Sdfr mem_free(rc, sizeof(*rc)); 306177633Sdfr mem_free(cl, sizeof (CLIENT)); 307177633Sdfr} 308