]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - sunrpc/svc.c
Refactor vDSO initialization code
[thirdparty/glibc.git] / sunrpc / svc.c
index 59b902dd63a4a2eab5cf7f6fcb0c9039b536848d..3d35b0234a872440f3611f6c1241bbe0570365ad 100644 (file)
@@ -1,39 +1,55 @@
 /*
- * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
- * unrestricted use provided that this legend is included on all tape
- * media and as a part of the software program in whole or part.  Users
- * may copy or modify Sun RPC without charge, but are not authorized
- * to license or distribute it to anyone else except as part of a product or
- * program developed by the user.
+ * svc.c, Server-side remote procedure call interface.
  *
- * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
- * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * There are two sets of procedures here.  The xprt routines are
+ * for handling transport handles.  The svc routines handle the
+ * list of service routines.
+ *  Copyright (C) 2002-2019 Free Software Foundation, Inc.
+ *  This file is part of the GNU C Library.
+ *  Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
  *
- * Sun RPC is provided with no support and without any obligation on the
- * part of Sun Microsystems, Inc. to assist in its use, correction,
- * modification or enhancement.
+ *  The GNU C Library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
  *
- * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
- * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
- * OR ANY PART THEREOF.
+ *  The GNU C Library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
  *
- * In no event will Sun Microsystems, Inc. be liable for any lost revenue
- * or profits or other special, indirect and consequential damages, even if
- * Sun has been advised of the possibility of such damages.
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with the GNU C Library; if not, see
+ *  <https://www.gnu.org/licenses/>.
  *
- * Sun Microsystems, Inc.
- * 2550 Garcia Avenue
- * Mountain View, California  94043
- */
-/*
- * svc.c, Server-side remote procedure call interface.
+ * Copyright (c) 2010, Oracle America, Inc.
  *
- * There are two sets of procedures here.  The xprt routines are
- * for handling transport handles.  The svc routines handle the
- * list of service routines.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *     * Neither the name of the "Oracle America, Inc." nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
  *
- * Copyright (C) 1984, Sun Microsystems, Inc.
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include <errno.h>
 #include <rpc/svc.h>
 #include <rpc/pmap_clnt.h>
 #include <sys/poll.h>
+#include <time.h>
+#include <shlib-compat.h>
 
-static SVCXPRT **xports;
+#define xports RPC_THREAD_VARIABLE(svc_xports_s)
 
 #define NULL_SVC ((struct svc_callout *)0)
 #define        RQCRED_SIZE     400     /* this size is excessive */
@@ -52,12 +70,14 @@ static SVCXPRT **xports;
    Each entry represents a set of procedures (an rpc program).
    The dispatch routine takes request structs and runs the
    appropriate procedure. */
-static struct svc_callout {
+struct svc_callout {
   struct svc_callout *sc_next;
   rpcprog_t sc_prog;
   rpcvers_t sc_vers;
   void (*sc_dispatch) (struct svc_req *, SVCXPRT *);
-} *svc_head;
+  bool_t sc_mapped;
+};
+#define svc_head RPC_THREAD_VARIABLE(svc_head_s)
 
 /* ***************  SVCXPRT related stuff **************** */
 
@@ -70,13 +90,15 @@ xprt_register (SVCXPRT *xprt)
 
   if (xports == NULL)
     {
-      xports = (SVCXPRT **) malloc (_rpc_dtablesize () * sizeof (SVCXPRT *));
-      if (xports == NULL) /* Donยดt add handle */
+      xports = (SVCXPRT **) calloc (_rpc_dtablesize (), sizeof (SVCXPRT *));
+      if (xports == NULL) /* Don't add handle */
        return;
     }
 
   if (sock < _rpc_dtablesize ())
     {
+      struct pollfd *new_svc_pollfd;
+
       xports[sock] = xprt;
       if (sock < FD_SETSIZE)
        FD_SET (sock, &svc_fdset);
@@ -91,17 +113,20 @@ xprt_register (SVCXPRT *xprt)
            return;
          }
 
-      ++svc_max_pollfd;
-      svc_pollfd = realloc (svc_pollfd,
-                           sizeof (struct pollfd) * svc_max_pollfd);
-      if (svc_pollfd == NULL) /* Out of memory */
+      new_svc_pollfd = (struct pollfd *) realloc (svc_pollfd,
+                                                 sizeof (struct pollfd)
+                                                 * (svc_max_pollfd + 1));
+      if (new_svc_pollfd == NULL) /* Out of memory */
        return;
+      svc_pollfd = new_svc_pollfd;
+      ++svc_max_pollfd;
 
       svc_pollfd[svc_max_pollfd - 1].fd = sock;
       svc_pollfd[svc_max_pollfd - 1].events = (POLLIN | POLLPRI |
                                               POLLRDNORM | POLLRDBAND);
     }
 }
+libc_hidden_nolink_sunrpc (xprt_register, GLIBC_2_0)
 
 /* De-activate a transport handle. */
 void
@@ -122,6 +147,11 @@ xprt_unregister (SVCXPRT *xprt)
          svc_pollfd[i].fd = -1;
     }
 }
+#ifdef EXPORT_RPC_SYMBOLS
+libc_hidden_def (xprt_unregister)
+#else
+libc_hidden_nolink_sunrpc (xprt_unregister, GLIBC_2_0)
+#endif
 
 
 /* ********************** CALLOUT list related stuff ************* */
@@ -170,15 +200,26 @@ svc_register (SVCXPRT * xprt, rpcprog_t prog, rpcvers_t vers,
   s->sc_vers = vers;
   s->sc_dispatch = dispatch;
   s->sc_next = svc_head;
+  s->sc_mapped = FALSE;
   svc_head = s;
 
 pmap_it:
   /* now register the information with the local binder service */
   if (protocol)
-    return pmap_set (prog, vers, protocol, xprt->xp_port);
+    {
+      if (! pmap_set (prog, vers, protocol, xprt->xp_port))
+       return FALSE;
+
+      s->sc_mapped = TRUE;
+    }
 
   return TRUE;
 }
+#ifdef EXPORT_RPC_SYMBOLS
+libc_hidden_def (svc_register)
+#else
+libc_hidden_nolink_sunrpc (svc_register, GLIBC_2_0)
+#endif
 
 /* Remove a service program from the callout list. */
 void
@@ -189,6 +230,7 @@ svc_unregister (rpcprog_t prog, rpcvers_t vers)
 
   if ((s = svc_find (prog, vers, &prev)) == NULL_SVC)
     return;
+  bool is_mapped = s->sc_mapped;
 
   if (prev == NULL_SVC)
     svc_head = s->sc_next;
@@ -198,8 +240,10 @@ svc_unregister (rpcprog_t prog, rpcvers_t vers)
   s->sc_next = NULL_SVC;
   mem_free ((char *) s, (u_int) sizeof (struct svc_callout));
   /* now unregister the information with the local binder service */
-  pmap_unset (prog, vers);
+  if (is_mapped)
+    pmap_unset (prog, vers);
 }
+libc_hidden_nolink_sunrpc (svc_unregister, GLIBC_2_0)
 
 /* ******************* REPLY GENERATION ROUTINES  ************ */
 
@@ -218,6 +262,11 @@ svc_sendreply (register SVCXPRT *xprt, xdrproc_t xdr_results,
   rply.acpted_rply.ar_results.proc = xdr_results;
   return SVC_REPLY (xprt, &rply);
 }
+#ifdef EXPORT_RPC_SYMBOLS
+libc_hidden_def (svc_sendreply)
+#else
+libc_hidden_nolink_sunrpc (svc_sendreply, GLIBC_2_0)
+#endif
 
 /* No procedure error reply */
 void
@@ -231,6 +280,11 @@ svcerr_noproc (register SVCXPRT *xprt)
   rply.acpted_rply.ar_stat = PROC_UNAVAIL;
   SVC_REPLY (xprt, &rply);
 }
+#ifdef EXPORT_RPC_SYMBOLS
+libc_hidden_def (svcerr_noproc)
+#else
+libc_hidden_nolink_sunrpc (svcerr_noproc, GLIBC_2_0)
+#endif
 
 /* Can't decode args error reply */
 void
@@ -244,6 +298,11 @@ svcerr_decode (register SVCXPRT *xprt)
   rply.acpted_rply.ar_stat = GARBAGE_ARGS;
   SVC_REPLY (xprt, &rply);
 }
+#ifdef EXPORT_RPC_SYMBOLS
+libc_hidden_def (svcerr_decode)
+#else
+libc_hidden_nolink_sunrpc (svcerr_decode, GLIBC_2_0)
+#endif
 
 /* Some system error */
 void
@@ -257,6 +316,11 @@ svcerr_systemerr (register SVCXPRT *xprt)
   rply.acpted_rply.ar_stat = SYSTEM_ERR;
   SVC_REPLY (xprt, &rply);
 }
+#ifdef EXPORT_RPC_SYMBOLS
+libc_hidden_def (svcerr_systemerr)
+#else
+libc_hidden_nolink_sunrpc (svcerr_systemerr, GLIBC_2_0)
+#endif
 
 /* Authentication error reply */
 void
@@ -270,6 +334,7 @@ svcerr_auth (SVCXPRT *xprt, enum auth_stat why)
   rply.rjcted_rply.rj_why = why;
   SVC_REPLY (xprt, &rply);
 }
+libc_hidden_nolink_sunrpc (svcerr_auth, GLIBC_2_0)
 
 /* Auth too weak error reply */
 void
@@ -277,6 +342,7 @@ svcerr_weakauth (SVCXPRT *xprt)
 {
   svcerr_auth (xprt, AUTH_TOOWEAK);
 }
+libc_hidden_nolink_sunrpc (svcerr_weakauth, GLIBC_2_0)
 
 /* Program unavailable error reply */
 void
@@ -290,6 +356,7 @@ svcerr_noprog (register SVCXPRT *xprt)
   rply.acpted_rply.ar_stat = PROG_UNAVAIL;
   SVC_REPLY (xprt, &rply);
 }
+libc_hidden_nolink_sunrpc (svcerr_noprog, GLIBC_2_0)
 
 /* Program version mismatch error reply */
 void
@@ -306,6 +373,7 @@ svcerr_progvers (register SVCXPRT *xprt, rpcvers_t low_vers,
   rply.acpted_rply.ar_vers.high = high_vers;
   SVC_REPLY (xprt, &rply);
 }
+libc_hidden_nolink_sunrpc (svcerr_progvers, GLIBC_2_0)
 
 /* ******************* SERVER INPUT STUFF ******************* */
 
@@ -334,45 +402,56 @@ svc_getreq (int rdfds)
   readfds.fds_bits[0] = rdfds;
   svc_getreqset (&readfds);
 }
+libc_hidden_nolink_sunrpc (svc_getreq, GLIBC_2_0)
 
 void
 svc_getreqset (fd_set *readfds)
 {
-  register u_int32_t mask;
-  register u_int32_t *maskp;
+  register fd_mask mask;
+  register fd_mask *maskp;
   register int setsize;
   register int sock;
   register int bit;
 
   setsize = _rpc_dtablesize ();
-  maskp = (u_int32_t *) readfds->fds_bits;
-  for (sock = 0; sock < setsize; sock += 32)
-    for (mask = *maskp++; (bit = ffs (mask)); mask ^= (1 << (bit - 1)))
+  if (setsize > FD_SETSIZE)
+    setsize = FD_SETSIZE;
+  maskp = readfds->fds_bits;
+  for (sock = 0; sock < setsize; sock += NFDBITS)
+    for (mask = *maskp++; (bit = ffsl (mask)); mask ^= (1L << (bit - 1)))
       svc_getreq_common (sock + bit - 1);
 }
+libc_hidden_nolink_sunrpc (svc_getreqset, GLIBC_2_0)
 
 void
 svc_getreq_poll (struct pollfd *pfdp, int pollretval)
 {
-  register int i;
-  register int fds_found;
+  if (pollretval == 0)
+    return;
 
-  for (i = fds_found = 0; i < svc_max_pollfd && fds_found < pollretval; ++i)
+  register int fds_found;
+  for (int i = fds_found = 0; i < svc_max_pollfd; ++i)
     {
       register struct pollfd *p = &pfdp[i];
 
       if (p->fd != -1 && p->revents)
        {
          /* fd has input waiting */
-         ++fds_found;
-
          if (p->revents & POLLNVAL)
-           xprt_unregister (p->fd);
+           xprt_unregister (xports[p->fd]);
          else
            svc_getreq_common (p->fd);
+
+         if (++fds_found >= pollretval)
+           break;
        }
     }
 }
+#ifdef EXPORT_RPC_SYMBOLS
+libc_hidden_def (svc_getreq_poll)
+#else
+libc_hidden_nolink_sunrpc (svc_getreq_poll, GLIBC_2_2)
+#endif
 
 
 void
@@ -464,3 +543,29 @@ svc_getreq_common (const int fd)
     }
   while (stat == XPRT_MOREREQS);
 }
+libc_hidden_nolink_sunrpc (svc_getreq_common, GLIBC_2_2)
+
+/* If there are no file descriptors available, then accept will fail.
+   We want to delay here so the connection request can be dequeued;
+   otherwise we can bounce between polling and accepting, never giving the
+   request a chance to dequeue and eating an enormous amount of cpu time
+   in svc_run if we're polling on many file descriptors.  */
+void
+__svc_accept_failed (void)
+{
+  if (errno == EMFILE)
+    {
+      struct timespec ts = { .tv_sec = 0, .tv_nsec = 50000000 };
+      __nanosleep (&ts, NULL);
+    }
+}
+
+
+void
+__rpc_thread_svc_cleanup (void)
+{
+  struct svc_callout *svcp;
+
+  while ((svcp = svc_head) != NULL)
+    svc_unregister (svcp->sc_prog, svcp->sc_vers);
+}