clnt_rc.c revision 178112
1125699Spjd/*- 2163872Spjd * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ 3125699Spjd * Authors: Doug Rabson <dfr@rabson.org> 4125699Spjd * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org> 5125699Spjd * 6125699Spjd * Redistribution and use in source and binary forms, with or without 7125699Spjd * modification, are permitted provided that the following conditions 8125699Spjd * are met: 9125699Spjd * 1. Redistributions of source code must retain the above copyright 10125699Spjd * notice, this list of conditions and the following disclaimer. 11125699Spjd * 2. Redistributions in binary form must reproduce the above copyright 12125699Spjd * notice, this list of conditions and the following disclaimer in the 13125699Spjd * documentation and/or other materials provided with the distribution. 14125699Spjd * 15125699Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16125699Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17125699Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18125699Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19125699Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20125699Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21125699Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22125699Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23125699Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24125699Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25125699Spjd * SUCH DAMAGE. 26125699Spjd */ 27163872Spjd 28131689Sru#include <sys/cdefs.h> 29125699Spjd__FBSDID("$FreeBSD: head/sys/rpc/clnt_rc.c 178112 2008-04-11 10:34:59Z dfr $"); 30125699Spjd 31125699Spjd#include <sys/param.h> 32125699Spjd#include <sys/systm.h> 33125714Spjd#include <sys/lock.h> 34125714Spjd#include <sys/malloc.h> 35129381Sle#include <sys/mbuf.h> 36125699Spjd#include <sys/mutex.h> 37125699Spjd#include <sys/pcpu.h> 38125699Spjd#include <sys/proc.h> 39125699Spjd#include <sys/socket.h> 40125699Spjd#include <sys/socketvar.h> 41125699Spjd#include <sys/time.h> 42163872Spjd#include <sys/uio.h> 43163872Spjd 44125699Spjd#include <rpc/rpc.h> 45163872Spjd#include <rpc/rpc_com.h> 46163872Spjd 47125699Spjdstatic enum clnt_stat clnt_reconnect_call(CLIENT *, rpcproc_t, 48125699Spjd xdrproc_t, void *, xdrproc_t, void *, struct timeval); 49125714Spjdstatic void clnt_reconnect_geterr(CLIENT *, struct rpc_err *); 50125714Spjdstatic bool_t clnt_reconnect_freeres(CLIENT *, xdrproc_t, void *); 51125699Spjdstatic void clnt_reconnect_abort(CLIENT *); 52129381Slestatic bool_t clnt_reconnect_control(CLIENT *, u_int, void *); 53131689Srustatic void clnt_reconnect_destroy(CLIENT *); 54129381Sle 55129381Slestatic struct clnt_ops clnt_reconnect_ops = { 56125699Spjd .cl_call = clnt_reconnect_call, 57125699Spjd .cl_abort = clnt_reconnect_abort, 58129381Sle .cl_geterr = clnt_reconnect_geterr, 59125699Spjd .cl_freeres = clnt_reconnect_freeres, 60131689Sru .cl_destroy = clnt_reconnect_destroy, 61125699Spjd .cl_control = clnt_reconnect_control 62129381Sle}; 63125699Spjd 64129381Slestruct rc_data { 65125699Spjd struct sockaddr_storage rc_addr; /* server address */ 66129381Sle struct netconfig* rc_nconf; /* network type */ 67125699Spjd rpcprog_t rc_prog; /* program number */ 68125699Spjd rpcvers_t rc_vers; /* version number */ 69125699Spjd size_t rc_sendsz; 70125699Spjd size_t rc_recvsz; 71125699Spjd struct timeval rc_timeout; 72125699Spjd struct timeval rc_retry; 73129387Sle const char *rc_waitchan; 74125699Spjd int rc_intr; 75125699Spjd CLIENT* rc_client; /* underlying RPC client */ 76125699Spjd}; 77125699Spjd 78163870SpjdCLIENT * 79163873Spjdclnt_reconnect_create( 80125699Spjd struct netconfig *nconf, /* network type */ 81125699Spjd struct sockaddr *svcaddr, /* servers address */ 82125699Spjd rpcprog_t program, /* program number */ 83133142Spjd rpcvers_t version, /* version number */ 84125699Spjd size_t sendsz, /* buffer recv size */ 85125699Spjd size_t recvsz) /* buffer send size */ 86129381Sle{ 87129381Sle CLIENT *cl = NULL; /* client handle */ 88125699Spjd struct rc_data *rc = NULL; /* private data */ 89125699Spjd 90125699Spjd if (svcaddr == NULL) { 91133142Spjd rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 92133142Spjd return (NULL); 93133142Spjd } 94133142Spjd 95133142Spjd cl = mem_alloc(sizeof (CLIENT)); 96133142Spjd rc = mem_alloc(sizeof (*rc)); 97133142Spjd (void) memcpy(&rc->rc_addr, svcaddr, (size_t)svcaddr->sa_len); 98133142Spjd rc->rc_nconf = nconf; 99125699Spjd rc->rc_prog = program; 100131689Sru rc->rc_vers = version; 101131689Sru rc->rc_sendsz = sendsz; 102131689Sru rc->rc_recvsz = recvsz; 103125699Spjd rc->rc_timeout.tv_sec = -1; 104129381Sle rc->rc_timeout.tv_usec = -1; 105125699Spjd rc->rc_retry.tv_sec = 15; 106133142Spjd rc->rc_retry.tv_usec = 0; 107125699Spjd rc->rc_waitchan = "rpcrecv"; 108133142Spjd rc->rc_intr = 0; 109125699Spjd rc->rc_client = NULL; 110133142Spjd 111125699Spjd cl->cl_ops = &clnt_reconnect_ops; 112133142Spjd cl->cl_private = (caddr_t)(void *)rc; 113125699Spjd cl->cl_auth = authnone_create(); 114131689Sru cl->cl_tp = NULL; 115131689Sru cl->cl_netid = NULL; 116131689Sru return (cl); 117125699Spjd} 118125699Spjd 119125699Spjdstatic enum clnt_stat 120131689Sruclnt_reconnect_connect(CLIENT *cl) 121125699Spjd{ 122131689Sru struct rc_data *rc = (struct rc_data *)cl->cl_private; 123125699Spjd struct socket *so; 124125699Spjd int one = 1; 125125699Spjd 126125699Spjd so = __rpc_nconf2socket(rc->rc_nconf); 127125699Spjd if (!so) { 128125699Spjd rpc_createerr.cf_stat = RPC_TLIERROR; 129131689Sru rpc_createerr.cf_error.re_errno = 0; 130131689Sru return (RPC_TLIERROR); 131131689Sru } 132125699Spjd 133131689Sru if (rc->rc_nconf->nc_semantics == NC_TPI_CLTS) 134131689Sru rc->rc_client = clnt_dg_create(so, 135131689Sru (struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers, 136125699Spjd rc->rc_sendsz, rc->rc_recvsz); 137131689Sru else 138131689Sru rc->rc_client = clnt_vc_create(so, 139125699Spjd (struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers, 140125699Spjd rc->rc_sendsz, rc->rc_recvsz); 141125699Spjd 142125699Spjd if (!rc->rc_client) 143125699Spjd return (rpc_createerr.cf_stat); 144125699Spjd 145125699Spjd CLNT_CONTROL(rc->rc_client, CLSET_FD_CLOSE, 0); 146125699Spjd CLNT_CONTROL(rc->rc_client, CLSET_CONNECT, &one); 147163872Spjd CLNT_CONTROL(rc->rc_client, CLSET_TIMEOUT, &rc->rc_timeout); 148163872Spjd CLNT_CONTROL(rc->rc_client, CLSET_RETRY_TIMEOUT, &rc->rc_retry); 149163872Spjd CLNT_CONTROL(rc->rc_client, CLSET_WAITCHAN, &rc->rc_waitchan); 150163872Spjd CLNT_CONTROL(rc->rc_client, CLSET_INTERRUPTIBLE, &rc->rc_intr); 151163872Spjd 152163872Spjd return (RPC_SUCCESS); 153163872Spjd} 154125699Spjd 155125699Spjdstatic enum clnt_stat 156125699Spjdclnt_reconnect_call( 157125699Spjd CLIENT *cl, /* client handle */ 158129381Sle rpcproc_t proc, /* procedure number */ 159125699Spjd xdrproc_t xargs, /* xdr routine for args */ 160129381Sle void *argsp, /* pointer to args */ 161125699Spjd xdrproc_t xresults, /* xdr routine for results */ 162125699Spjd void *resultsp, /* pointer to results */ 163125699Spjd struct timeval utimeout) /* seconds to wait before giving up */ 164125699Spjd{ 165125699Spjd struct rc_data *rc = (struct rc_data *)cl->cl_private; 166125699Spjd enum clnt_stat stat; 167125699Spjd 168129381Sle do { 169125699Spjd if (!rc->rc_client) { 170125699Spjd stat = clnt_reconnect_connect(cl); 171125699Spjd if (stat != RPC_SUCCESS) 172129381Sle return (stat); 173129381Sle } 174129381Sle 175125699Spjd stat = CLNT_CALL(rc->rc_client, proc, xargs, argsp, 176125699Spjd xresults, resultsp, utimeout); 177125699Spjd 178125699Spjd if (stat == RPC_TIMEDOUT) { 179125699Spjd /* 180125699Spjd * Check for async send misfeature for NLM 181125699Spjd * protocol. 182129381Sle */ 183125699Spjd if ((rc->rc_timeout.tv_sec == 0 184125699Spjd && rc->rc_timeout.tv_usec == 0) 185125699Spjd || (rc->rc_timeout.tv_sec == -1 186125699Spjd && utimeout.tv_sec == 0 187125699Spjd && utimeout.tv_usec == 0)) 188125699Spjd break; 189125699Spjd } 190163872Spjd 191163872Spjd if (stat == RPC_INTR) 192163872Spjd break; 193163872Spjd 194163872Spjd if (stat != RPC_SUCCESS) { 195163872Spjd CLNT_DESTROY(rc->rc_client); 196163872Spjd rc->rc_client = NULL; 197125699Spjd } 198125699Spjd } while (stat != RPC_SUCCESS); 199129381Sle 200125699Spjd return (stat); 201125699Spjd} 202125714Spjd 203125714Spjdstatic void 204125714Spjdclnt_reconnect_geterr(CLIENT *cl, struct rpc_err *errp) 205129381Sle{ 206125714Spjd struct rc_data *rc = (struct rc_data *)cl->cl_private; 207129381Sle 208129381Sle if (rc->rc_client) 209129381Sle CLNT_GETERR(rc->rc_client, errp); 210129381Sle else 211129381Sle memset(errp, 0, sizeof(*errp)); 212129381Sle} 213129381Sle 214129381Slestatic bool_t 215131689Sruclnt_reconnect_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr) 216131689Sru{ 217131689Sru struct rc_data *rc = (struct rc_data *)cl->cl_private; 218125699Spjd 219125699Spjd return (CLNT_FREERES(rc->rc_client, xdr_res, res_ptr)); 220131689Sru} 221125699Spjd 222125699Spjd/*ARGSUSED*/ 223131689Srustatic void 224125699Spjdclnt_reconnect_abort(CLIENT *h) 225125699Spjd{ 226125699Spjd} 227125699Spjd 228125699Spjdstatic bool_t 229125699Spjdclnt_reconnect_control(CLIENT *cl, u_int request, void *info) 230125699Spjd{ 231125699Spjd struct rc_data *rc = (struct rc_data *)cl->cl_private; 232125699Spjd 233125699Spjd if (info == NULL) { 234125699Spjd return (FALSE); 235125714Spjd } 236169308Swkoszek switch (request) { 237125714Spjd case CLSET_TIMEOUT: 238125714Spjd rc->rc_timeout = *(struct timeval *)info; 239125699Spjd if (rc->rc_client) 240125699Spjd CLNT_CONTROL(rc->rc_client, request, info); 241125699Spjd break; 242125699Spjd 243125699Spjd case CLGET_TIMEOUT: 244125699Spjd *(struct timeval *)info = rc->rc_timeout; 245125699Spjd break; 246125699Spjd 247125699Spjd case CLSET_RETRY_TIMEOUT: 248125699Spjd rc->rc_retry = *(struct timeval *)info; 249125699Spjd if (rc->rc_client) 250125699Spjd CLNT_CONTROL(rc->rc_client, request, info); 251125699Spjd break; 252125699Spjd 253125699Spjd case CLGET_RETRY_TIMEOUT: 254125699Spjd *(struct timeval *)info = rc->rc_retry; 255125699Spjd break; 256125699Spjd 257125699Spjd case CLGET_VERS: 258125699Spjd *(uint32_t *)info = rc->rc_vers; 259125699Spjd break; 260125699Spjd 261125699Spjd case CLSET_VERS: 262125699Spjd rc->rc_vers = *(uint32_t *) info; 263131594Sru if (rc->rc_client) 264125699Spjd CLNT_CONTROL(rc->rc_client, CLSET_VERS, info); 265126861Spjd break; 266125699Spjd 267125699Spjd case CLGET_PROG: 268125699Spjd *(uint32_t *)info = rc->rc_prog; 269125699Spjd break; 270125699Spjd 271125699Spjd case CLSET_PROG: 272125699Spjd rc->rc_prog = *(uint32_t *) info; 273125699Spjd if (rc->rc_client) 274125699Spjd CLNT_CONTROL(rc->rc_client, request, info); 275125699Spjd break; 276125699Spjd 277125699Spjd case CLSET_WAITCHAN: 278 rc->rc_waitchan = *(const char **)info; 279 if (rc->rc_client) 280 CLNT_CONTROL(rc->rc_client, request, info); 281 break; 282 283 case CLGET_WAITCHAN: 284 *(const char **) info = rc->rc_waitchan; 285 break; 286 287 case CLSET_INTERRUPTIBLE: 288 rc->rc_intr = *(int *) info; 289 if (rc->rc_client) 290 CLNT_CONTROL(rc->rc_client, request, info); 291 break; 292 293 case CLGET_INTERRUPTIBLE: 294 *(int *) info = rc->rc_intr; 295 break; 296 297 default: 298 return (FALSE); 299 } 300 301 return (TRUE); 302} 303 304static void 305clnt_reconnect_destroy(CLIENT *cl) 306{ 307 struct rc_data *rc = (struct rc_data *)cl->cl_private; 308 309 if (rc->rc_client) 310 CLNT_DESTROY(rc->rc_client); 311 mem_free(rc, sizeof(*rc)); 312 mem_free(cl, sizeof (CLIENT)); 313} 314