The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/rpc/clnt_rc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
    3  * Authors: Doug Rabson <dfr@rabson.org>
    4  * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD: releng/7.3/sys/rpc/clnt_rc.c 182255 2008-08-27 09:43:52Z dfr $");
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/limits.h>
   34 #include <sys/lock.h>
   35 #include <sys/malloc.h>
   36 #include <sys/mbuf.h>
   37 #include <sys/mutex.h>
   38 #include <sys/pcpu.h>
   39 #include <sys/proc.h>
   40 #include <sys/socket.h>
   41 #include <sys/socketvar.h>
   42 #include <sys/time.h>
   43 #include <sys/uio.h>
   44 
   45 #include <rpc/rpc.h>
   46 #include <rpc/rpc_com.h>
   47 
   48 static enum clnt_stat clnt_reconnect_call(CLIENT *, struct rpc_callextra *,
   49     rpcproc_t, xdrproc_t, void *, xdrproc_t, void *, struct timeval);
   50 static void clnt_reconnect_geterr(CLIENT *, struct rpc_err *);
   51 static bool_t clnt_reconnect_freeres(CLIENT *, xdrproc_t, void *);
   52 static void clnt_reconnect_abort(CLIENT *);
   53 static bool_t clnt_reconnect_control(CLIENT *, u_int, void *);
   54 static void clnt_reconnect_destroy(CLIENT *);
   55 
   56 static struct clnt_ops clnt_reconnect_ops = {
   57         .cl_call =      clnt_reconnect_call,
   58         .cl_abort =     clnt_reconnect_abort,
   59         .cl_geterr =    clnt_reconnect_geterr,
   60         .cl_freeres =   clnt_reconnect_freeres,
   61         .cl_destroy =   clnt_reconnect_destroy,
   62         .cl_control =   clnt_reconnect_control
   63 };
   64 
   65 struct rc_data {
   66         struct mtx              rc_lock;
   67         struct sockaddr_storage rc_addr; /* server address */
   68         struct netconfig*       rc_nconf; /* network type */
   69         rpcprog_t               rc_prog;  /* program number */
   70         rpcvers_t               rc_vers;  /* version number */
   71         size_t                  rc_sendsz;
   72         size_t                  rc_recvsz;
   73         struct timeval          rc_timeout;
   74         struct timeval          rc_retry;
   75         int                     rc_retries;
   76         const char              *rc_waitchan;
   77         int                     rc_intr;
   78         int                     rc_connecting;
   79         CLIENT*                 rc_client; /* underlying RPC client */
   80 };
   81 
   82 CLIENT *
   83 clnt_reconnect_create(
   84         struct netconfig *nconf,        /* network type */
   85         struct sockaddr *svcaddr,       /* servers address */
   86         rpcprog_t program,              /* program number */
   87         rpcvers_t version,              /* version number */
   88         size_t sendsz,                  /* buffer recv size */
   89         size_t recvsz)                  /* buffer send size */
   90 {
   91         CLIENT *cl = NULL;              /* client handle */
   92         struct rc_data *rc = NULL;      /* private data */
   93 
   94         if (svcaddr == NULL) {
   95                 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
   96                 return (NULL);
   97         }
   98 
   99         cl = mem_alloc(sizeof (CLIENT));
  100         rc = mem_alloc(sizeof (*rc));
  101         mtx_init(&rc->rc_lock, "rc->rc_lock", NULL, MTX_DEF);
  102         (void) memcpy(&rc->rc_addr, svcaddr, (size_t)svcaddr->sa_len);
  103         rc->rc_nconf = nconf;
  104         rc->rc_prog = program;
  105         rc->rc_vers = version;
  106         rc->rc_sendsz = sendsz;
  107         rc->rc_recvsz = recvsz;
  108         rc->rc_timeout.tv_sec = -1;
  109         rc->rc_timeout.tv_usec = -1;
  110         rc->rc_retry.tv_sec = 3;
  111         rc->rc_retry.tv_usec = 0;
  112         rc->rc_retries = INT_MAX;
  113         rc->rc_waitchan = "rpcrecv";
  114         rc->rc_intr = 0;
  115         rc->rc_connecting = FALSE;
  116         rc->rc_client = NULL;
  117 
  118         cl->cl_refs = 1;
  119         cl->cl_ops = &clnt_reconnect_ops;
  120         cl->cl_private = (caddr_t)(void *)rc;
  121         cl->cl_auth = authnone_create();
  122         cl->cl_tp = NULL;
  123         cl->cl_netid = NULL;
  124         return (cl);
  125 }
  126 
  127 static enum clnt_stat
  128 clnt_reconnect_connect(CLIENT *cl)
  129 {
  130         struct rc_data *rc = (struct rc_data *)cl->cl_private;
  131         struct socket *so;
  132         enum clnt_stat stat;
  133         int error;
  134         int one = 1;
  135 
  136         mtx_lock(&rc->rc_lock);
  137 again:
  138         if (rc->rc_connecting) {
  139                 while (!rc->rc_client) {
  140                         error = msleep(rc, &rc->rc_lock,
  141                             rc->rc_intr ? PCATCH : 0, "rpcrecon", 0);
  142                         if (error) {
  143                                 mtx_unlock(&rc->rc_lock);
  144                                 return (RPC_INTR);
  145                         }
  146                 }
  147                 /*
  148                  * If the other guy failed to connect, we might as
  149                  * well have another go.
  150                  */
  151                 if (!rc->rc_client && !rc->rc_connecting)
  152                         goto again;
  153                 mtx_unlock(&rc->rc_lock);
  154                 return (RPC_SUCCESS);
  155         } else {
  156                 rc->rc_connecting = TRUE;
  157         }
  158         mtx_unlock(&rc->rc_lock);
  159 
  160         so = __rpc_nconf2socket(rc->rc_nconf);
  161         if (!so) {
  162                 stat = rpc_createerr.cf_stat = RPC_TLIERROR;
  163                 rpc_createerr.cf_error.re_errno = 0;
  164                 goto out;
  165         }
  166 
  167         if (rc->rc_nconf->nc_semantics == NC_TPI_CLTS)
  168                 rc->rc_client = clnt_dg_create(so,
  169                     (struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers,
  170                     rc->rc_sendsz, rc->rc_recvsz);
  171         else
  172                 rc->rc_client = clnt_vc_create(so,
  173                     (struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers,
  174                     rc->rc_sendsz, rc->rc_recvsz);
  175 
  176         if (!rc->rc_client) {
  177                 stat = rpc_createerr.cf_stat;
  178                 goto out;
  179         }
  180 
  181         CLNT_CONTROL(rc->rc_client, CLSET_FD_CLOSE, 0);
  182         CLNT_CONTROL(rc->rc_client, CLSET_CONNECT, &one);
  183         CLNT_CONTROL(rc->rc_client, CLSET_TIMEOUT, &rc->rc_timeout);
  184         CLNT_CONTROL(rc->rc_client, CLSET_RETRY_TIMEOUT, &rc->rc_retry);
  185         CLNT_CONTROL(rc->rc_client, CLSET_WAITCHAN, &rc->rc_waitchan);
  186         CLNT_CONTROL(rc->rc_client, CLSET_INTERRUPTIBLE, &rc->rc_intr);
  187         stat = RPC_SUCCESS;
  188 
  189 out:
  190         mtx_lock(&rc->rc_lock);
  191         rc->rc_connecting = FALSE;
  192         wakeup(rc);
  193         mtx_unlock(&rc->rc_lock);
  194 
  195         return (stat);
  196 }
  197 
  198 static enum clnt_stat
  199 clnt_reconnect_call(
  200         CLIENT          *cl,            /* client handle */
  201         struct rpc_callextra *ext,      /* call metadata */
  202         rpcproc_t       proc,           /* procedure number */
  203         xdrproc_t       xargs,          /* xdr routine for args */
  204         void            *argsp,         /* pointer to args */
  205         xdrproc_t       xresults,       /* xdr routine for results */
  206         void            *resultsp,      /* pointer to results */
  207         struct timeval  utimeout)       /* seconds to wait before giving up */
  208 {
  209         struct rc_data *rc = (struct rc_data *)cl->cl_private;
  210         CLIENT *client;
  211         enum clnt_stat stat;
  212         int tries;
  213 
  214         tries = 0;
  215         do {
  216                 if (!rc->rc_client) {
  217                         stat = clnt_reconnect_connect(cl);
  218                         if (stat != RPC_SUCCESS)
  219                                 return (stat);
  220                 }
  221 
  222                 mtx_lock(&rc->rc_lock);
  223                 CLNT_ACQUIRE(rc->rc_client);
  224                 client = rc->rc_client;
  225                 mtx_unlock(&rc->rc_lock);
  226                 stat = CLNT_CALL_EXT(client, ext, proc, xargs, argsp,
  227                     xresults, resultsp, utimeout);
  228 
  229                 CLNT_RELEASE(client);
  230                 if (stat == RPC_TIMEDOUT) {
  231                         /*
  232                          * Check for async send misfeature for NLM
  233                          * protocol.
  234                          */
  235                         if ((rc->rc_timeout.tv_sec == 0
  236                                 && rc->rc_timeout.tv_usec == 0)
  237                             || (rc->rc_timeout.tv_sec == -1
  238                                 && utimeout.tv_sec == 0
  239                                 && utimeout.tv_usec == 0)) {
  240                                 break;
  241                         }
  242                 }
  243 
  244                 if (stat == RPC_INTR)
  245                         break;
  246 
  247                 if (stat != RPC_SUCCESS) {
  248                         tries++;
  249                         if (tries >= rc->rc_retries)
  250                                 break;
  251 
  252                         if (ext && ext->rc_feedback)
  253                                 ext->rc_feedback(FEEDBACK_RECONNECT, proc,
  254                                     ext->rc_feedback_arg);
  255 
  256                         mtx_lock(&rc->rc_lock);
  257                         /*
  258                          * Make sure that someone else hasn't already
  259                          * reconnected.
  260                          */
  261                         if (rc->rc_client == client) {
  262                                 CLNT_RELEASE(rc->rc_client);
  263                                 rc->rc_client = NULL;
  264                         }
  265                         mtx_unlock(&rc->rc_lock);
  266                 }
  267         } while (stat != RPC_SUCCESS);
  268 
  269         return (stat);
  270 }
  271 
  272 static void
  273 clnt_reconnect_geterr(CLIENT *cl, struct rpc_err *errp)
  274 {
  275         struct rc_data *rc = (struct rc_data *)cl->cl_private;
  276 
  277         if (rc->rc_client)
  278                 CLNT_GETERR(rc->rc_client, errp);
  279         else
  280                 memset(errp, 0, sizeof(*errp));
  281 }
  282 
  283 static bool_t
  284 clnt_reconnect_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
  285 {
  286         struct rc_data *rc = (struct rc_data *)cl->cl_private;
  287 
  288         return (CLNT_FREERES(rc->rc_client, xdr_res, res_ptr));
  289 }
  290 
  291 /*ARGSUSED*/
  292 static void
  293 clnt_reconnect_abort(CLIENT *h)
  294 {
  295 }
  296 
  297 static bool_t
  298 clnt_reconnect_control(CLIENT *cl, u_int request, void *info)
  299 {
  300         struct rc_data *rc = (struct rc_data *)cl->cl_private;
  301 
  302         if (info == NULL) {
  303                 return (FALSE);
  304         }
  305         switch (request) {
  306         case CLSET_TIMEOUT:
  307                 rc->rc_timeout = *(struct timeval *)info;
  308                 if (rc->rc_client)
  309                         CLNT_CONTROL(rc->rc_client, request, info);
  310                 break;
  311 
  312         case CLGET_TIMEOUT:
  313                 *(struct timeval *)info = rc->rc_timeout;
  314                 break;
  315 
  316         case CLSET_RETRY_TIMEOUT:
  317                 rc->rc_retry = *(struct timeval *)info;
  318                 if (rc->rc_client)
  319                         CLNT_CONTROL(rc->rc_client, request, info);
  320                 break;
  321 
  322         case CLGET_RETRY_TIMEOUT:
  323                 *(struct timeval *)info = rc->rc_retry;
  324                 break;
  325 
  326         case CLGET_VERS:
  327                 *(uint32_t *)info = rc->rc_vers;
  328                 break;
  329 
  330         case CLSET_VERS:
  331                 rc->rc_vers = *(uint32_t *) info;
  332                 if (rc->rc_client)
  333                         CLNT_CONTROL(rc->rc_client, CLSET_VERS, info);
  334                 break;
  335 
  336         case CLGET_PROG:
  337                 *(uint32_t *)info = rc->rc_prog;
  338                 break;
  339 
  340         case CLSET_PROG:
  341                 rc->rc_prog = *(uint32_t *) info;
  342                 if (rc->rc_client)
  343                         CLNT_CONTROL(rc->rc_client, request, info);
  344                 break;
  345 
  346         case CLSET_WAITCHAN:
  347                 rc->rc_waitchan = *(const char **)info;
  348                 if (rc->rc_client)
  349                         CLNT_CONTROL(rc->rc_client, request, info);
  350                 break;
  351 
  352         case CLGET_WAITCHAN:
  353                 *(const char **) info = rc->rc_waitchan;
  354                 break;
  355 
  356         case CLSET_INTERRUPTIBLE:
  357                 rc->rc_intr = *(int *) info;
  358                 if (rc->rc_client)
  359                         CLNT_CONTROL(rc->rc_client, request, info);
  360                 break;
  361 
  362         case CLGET_INTERRUPTIBLE:
  363                 *(int *) info = rc->rc_intr;
  364                 break;
  365 
  366         case CLSET_RETRIES:
  367                 rc->rc_retries = *(int *) info;
  368                 break;
  369 
  370         case CLGET_RETRIES:
  371                 *(int *) info = rc->rc_retries;
  372                 break;
  373 
  374         default:
  375                 return (FALSE);
  376         }
  377 
  378         return (TRUE);
  379 }
  380 
  381 static void
  382 clnt_reconnect_destroy(CLIENT *cl)
  383 {
  384         struct rc_data *rc = (struct rc_data *)cl->cl_private;
  385 
  386         if (rc->rc_client)
  387                 CLNT_DESTROY(rc->rc_client);
  388         mtx_destroy(&rc->rc_lock);
  389         mem_free(rc, sizeof(*rc));
  390         mem_free(cl, sizeof (CLIENT));
  391 }

Cache object: 5cc26b817a576b3d0f1d056322f8ba6b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.