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_vc.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

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

Cache object: 22fc2d19d88752d01b8088971fbe8aa6


[ 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.