]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - sunrpc/svc_udp.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / sunrpc / svc_udp.c
index fd129f258187725389859b0da8c7516d5f1e5337..17357c8ced0e567374c9fdf43a1cb5496815656f 100644 (file)
@@ -1,42 +1,53 @@
-/* @(#)svc_udp.c       2.2 88/07/29 4.0 RPCSRC */
 /*
- * 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_udp.c,
+ * Server side for UDP/IP based RPC.  (Does some caching in the hopes of
+ * achieving execute-at-most-once semantics.)
  *
- * 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.
+ * Copyright (C) 2012-2019 Free Software Foundation, Inc.
+ * This file is part of the GNU C Library.
  *
- * 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
+ * <http://www.gnu.org/licenses/>.
  *
- * Sun Microsystems, Inc.
- * 2550 Garcia Avenue
- * Mountain View, California  94043
- */
-#if !defined(lint) && defined(SCCSIDS)
-static char sccsid[] = "@(#)svc_udp.c 1.24 87/08/11 Copyr 1984 Sun Micro";
-#endif
-
-/*
- * svc_udp.c,
- * Server side for UDP/IP based RPC.  (Does some caching in the hopes of
- * achieving execute-at-most-once semantics.)
+ * Copyright (c) 2010, Oracle America, Inc.
  *
- * Copyright (C) 1984, Sun Microsystems, Inc.
+ * 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.
+ *
+ *   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 <stdio.h>
@@ -47,11 +58,14 @@ static char sccsid[] = "@(#)svc_udp.c 1.24 87/08/11 Copyr 1984 Sun Micro";
 #include <errno.h>
 #include <libintl.h>
 
-#ifdef USE_IN_LIBIO
-# include <libio/iolibio.h>
-# define fputs(s, f) _IO_fputs (s, f)
+#ifdef IP_PKTINFO
+#include <sys/uio.h>
 #endif
 
+#include <wchar.h>
+#include <libio/iolibio.h>
+#include <shlib-compat.h>
+
 #define rpc_buffer(xprt) ((xprt)->xp_p1)
 #ifndef MAX
 #define MAX(a, b)     ((a > b) ? a : b)
@@ -105,15 +119,15 @@ struct svcudp_data
  * The routines returns NULL if a problem occurred.
  */
 SVCXPRT *
-svcudp_bufcreate (sock, sendsz, recvsz)
-     int sock;
-     u_int sendsz, recvsz;
+svcudp_bufcreate (int sock, u_int sendsz, u_int recvsz)
 {
   bool_t madesock = FALSE;
   SVCXPRT *xprt;
   struct svcudp_data *su;
   struct sockaddr_in addr;
   socklen_t len = sizeof (struct sockaddr_in);
+  int pad;
+  void *buf;
 
   if (sock == RPC_ANYSOCK)
     {
@@ -124,14 +138,14 @@ svcudp_bufcreate (sock, sendsz, recvsz)
        }
       madesock = TRUE;
     }
-  __bzero ((char *) &addr, sizeof (addr));
+  memset ((char *) &addr, 0, sizeof (addr));
   addr.sin_family = AF_INET;
   if (bindresvport (sock, &addr))
     {
       addr.sin_port = 0;
-      (void) bind (sock, (struct sockaddr *) &addr, len);
+      (void) __bind (sock, (struct sockaddr *) &addr, len);
     }
-  if (getsockname (sock, (struct sockaddr *) &addr, &len) != 0)
+  if (__getsockname (sock, (struct sockaddr *) &addr, &len) != 0)
     {
       perror (_("svcudp_create - cannot getsockname"));
       if (madesock)
@@ -139,23 +153,19 @@ svcudp_bufcreate (sock, sendsz, recvsz)
       return (SVCXPRT *) NULL;
     }
   xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
-  if (xprt == NULL)
-    {
-      (void) fputs (_("svcudp_create: out of memory\n"), stderr);
-      return NULL;
-    }
   su = (struct svcudp_data *) mem_alloc (sizeof (*su));
-  if (su == NULL)
+  buf = mem_alloc (((MAX (sendsz, recvsz) + 3) / 4) * 4);
+  if (xprt == NULL || su == NULL || buf == NULL)
     {
-      (void) fputs (_("svcudp_create: out of memory\n"), stderr);
+      (void) __fxprintf (NULL, "%s: %s",
+                        "svcudp_create",  _("out of memory\n"));
+      mem_free (xprt, sizeof (SVCXPRT));
+      mem_free (su, sizeof (*su));
+      mem_free (buf, ((MAX (sendsz, recvsz) + 3) / 4) * 4);
       return NULL;
     }
   su->su_iosz = ((MAX (sendsz, recvsz) + 3) / 4) * 4;
-  if ((rpc_buffer (xprt) = mem_alloc (su->su_iosz)) == NULL)
-    {
-      (void) fputs (_("svcudp_create: out of memory\n"), stderr);
-      return NULL;
-    }
+  rpc_buffer (xprt) = buf;
   xdrmem_create (&(su->su_xdrs), rpc_buffer (xprt), su->su_iosz, XDR_DECODE);
   su->su_cache = NULL;
   xprt->xp_p2 = (caddr_t) su;
@@ -163,30 +173,56 @@ svcudp_bufcreate (sock, sendsz, recvsz)
   xprt->xp_ops = &svcudp_op;
   xprt->xp_port = ntohs (addr.sin_port);
   xprt->xp_sock = sock;
+
+#ifdef IP_PKTINFO
+  if ((sizeof (struct iovec) + sizeof (struct msghdr)
+       + sizeof(struct cmsghdr) + sizeof (struct in_pktinfo))
+      > sizeof (xprt->xp_pad))
+    {
+      (void) __fxprintf (NULL,"%s", _("\
+svcudp_create: xp_pad is too small for IP_PKTINFO\n"));
+      return NULL;
+    }
+  pad = 1;
+  if (__setsockopt (sock, SOL_IP, IP_PKTINFO, (void *) &pad,
+                   sizeof (pad)) == 0)
+    /* Set the padding to all 1s. */
+    pad = 0xff;
+  else
+#endif
+    /* Clear the padding. */
+    pad = 0;
+  memset (&xprt->xp_pad [0], pad, sizeof (xprt->xp_pad));
+
   xprt_register (xprt);
   return xprt;
 }
+#ifdef EXPORT_RPC_SYMBOLS
+libc_hidden_def (svcudp_bufcreate)
+#else
+libc_hidden_nolink_sunrpc (svcudp_bufcreate, GLIBC_2_0)
+#endif
 
 SVCXPRT *
-svcudp_create (sock)
-     int sock;
+svcudp_create (int sock)
 {
-
   return svcudp_bufcreate (sock, UDPMSGSIZE, UDPMSGSIZE);
 }
+#ifdef EXPORT_RPC_SYMBOLS
+libc_hidden_def (svcudp_create)
+#else
+libc_hidden_nolink_sunrpc (svcudp_create, GLIBC_2_0)
+#endif
 
 static enum xprt_stat
-svcudp_stat (xprt)
-     SVCXPRT *xprt;
+svcudp_stat (SVCXPRT *xprt)
 {
 
   return XPRT_IDLE;
 }
 
 static bool_t
-svcudp_recv (xprt, msg)
-     SVCXPRT *xprt;
-     struct rpc_msg *msg;
+svcudp_recv (SVCXPRT *xprt, struct rpc_msg *msg)
 {
   struct svcudp_data *su = su_data (xprt);
   XDR *xdrs = &(su->su_xdrs);
@@ -195,14 +231,70 @@ svcudp_recv (xprt, msg)
   u_long replylen;
   socklen_t len;
 
+  /* It is very tricky when you have IP aliases. We want to make sure
+     that we are sending the packet from the IP address where the
+     incoming packet is addressed to. H.J. */
+#ifdef IP_PKTINFO
+  struct iovec *iovp;
+  struct msghdr *mesgp;
+#endif
+
 again:
   /* FIXME -- should xp_addrlen be a size_t?  */
   len = (socklen_t) sizeof(struct sockaddr_in);
-  rlen = recvfrom (xprt->xp_sock, rpc_buffer (xprt), (int) su->su_iosz, 0,
-                  (struct sockaddr *) &(xprt->xp_raddr), &len);
+#ifdef IP_PKTINFO
+  iovp = (struct iovec *) &xprt->xp_pad [0];
+  mesgp = (struct msghdr *) &xprt->xp_pad [sizeof (struct iovec)];
+  if (mesgp->msg_iovlen)
+    {
+      iovp->iov_base = rpc_buffer (xprt);
+      iovp->iov_len = su->su_iosz;
+      mesgp->msg_iov = iovp;
+      mesgp->msg_iovlen = 1;
+      mesgp->msg_name = &(xprt->xp_raddr);
+      mesgp->msg_namelen = len;
+      mesgp->msg_control = &xprt->xp_pad [sizeof (struct iovec)
+                                         + sizeof (struct msghdr)];
+      mesgp->msg_controllen = sizeof(xprt->xp_pad)
+                             - sizeof (struct iovec) - sizeof (struct msghdr);
+      rlen = __recvmsg (xprt->xp_sock, mesgp, 0);
+      if (rlen >= 0)
+       {
+         struct cmsghdr *cmsg;
+         len = mesgp->msg_namelen;
+         cmsg = CMSG_FIRSTHDR (mesgp);
+         if (cmsg == NULL
+             || CMSG_NXTHDR (mesgp, cmsg) != NULL
+             || cmsg->cmsg_level != SOL_IP
+             || cmsg->cmsg_type != IP_PKTINFO
+             || cmsg->cmsg_len < (sizeof (struct cmsghdr)
+                                  + sizeof (struct in_pktinfo)))
+           {
+             /* Not a simple IP_PKTINFO, ignore it.  */
+             mesgp->msg_control = NULL;
+             mesgp->msg_controllen = 0;
+           }
+         else
+           {
+             /* It was a simple IP_PKTIFO as we expected, discard the
+                interface field.  */
+             struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg);
+             pkti->ipi_ifindex = 0;
+           }
+       }
+    }
+  else
+#endif
+    rlen = __recvfrom (xprt->xp_sock, rpc_buffer (xprt),
+                      (int) su->su_iosz, 0,
+                      (struct sockaddr *) &(xprt->xp_raddr), &len);
   xprt->xp_addrlen = len;
-  if (rlen == -1 && errno == EINTR)
-    goto again;
+  if (rlen == -1)
+    {
+      if (errno == EINTR)
+       goto again;
+      __svc_accept_failed ();
+    }
   if (rlen < 16)               /* < 4 32-bit ints? */
     return FALSE;
   xdrs->x_op = XDR_DECODE;
@@ -214,8 +306,17 @@ again:
     {
       if (cache_get (xprt, msg, &reply, &replylen))
        {
-         (void) sendto (xprt->xp_sock, reply, (int) replylen, 0,
-                        (struct sockaddr *) &xprt->xp_raddr, len);
+#ifdef IP_PKTINFO
+         if (mesgp->msg_iovlen)
+           {
+             iovp->iov_base = reply;
+             iovp->iov_len = replylen;
+             (void) __sendmsg (xprt->xp_sock, mesgp, 0);
+           }
+         else
+#endif
+           (void) __sendto (xprt->xp_sock, reply, (int) replylen, 0,
+                            (struct sockaddr *) &xprt->xp_raddr, len);
          return TRUE;
        }
     }
@@ -223,14 +324,16 @@ again:
 }
 
 static bool_t
-svcudp_reply (xprt, msg)
-     SVCXPRT *xprt;
-     struct rpc_msg *msg;
+svcudp_reply (SVCXPRT *xprt, struct rpc_msg *msg)
 {
   struct svcudp_data *su = su_data (xprt);
   XDR *xdrs = &(su->su_xdrs);
-  int slen;
+  int slen, sent;
   bool_t stat = FALSE;
+#ifdef IP_PKTINFO
+  struct iovec *iovp;
+  struct msghdr *mesgp;
+#endif
 
   xdrs->x_op = XDR_ENCODE;
   XDR_SETPOS (xdrs, 0);
@@ -238,9 +341,21 @@ svcudp_reply (xprt, msg)
   if (xdr_replymsg (xdrs, msg))
     {
       slen = (int) XDR_GETPOS (xdrs);
-      if (sendto (xprt->xp_sock, rpc_buffer (xprt), slen, 0,
-                 (struct sockaddr *) &(xprt->xp_raddr), xprt->xp_addrlen)
-         == slen)
+#ifdef IP_PKTINFO
+      mesgp = (struct msghdr *) &xprt->xp_pad [sizeof (struct iovec)];
+      if (mesgp->msg_iovlen)
+       {
+         iovp = (struct iovec *) &xprt->xp_pad [0];
+         iovp->iov_base = rpc_buffer (xprt);
+         iovp->iov_len = slen;
+         sent = __sendmsg (xprt->xp_sock, mesgp, 0);
+       }
+      else
+#endif
+       sent = __sendto (xprt->xp_sock, rpc_buffer (xprt), slen, 0,
+                        (struct sockaddr *) &(xprt->xp_raddr),
+                        xprt->xp_addrlen);
+      if (sent == slen)
        {
          stat = TRUE;
          if (su->su_cache && slen >= 0)
@@ -253,20 +368,14 @@ svcudp_reply (xprt, msg)
 }
 
 static bool_t
-svcudp_getargs (xprt, xdr_args, args_ptr)
-     SVCXPRT *xprt;
-     xdrproc_t xdr_args;
-     caddr_t args_ptr;
+svcudp_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
 {
 
   return (*xdr_args) (&(su_data (xprt)->su_xdrs), args_ptr);
 }
 
 static bool_t
-svcudp_freeargs (xprt, xdr_args, args_ptr)
-     SVCXPRT *xprt;
-     xdrproc_t xdr_args;
-     caddr_t args_ptr;
+svcudp_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
 {
   XDR *xdrs = &(su_data (xprt)->su_xdrs);
 
@@ -275,8 +384,7 @@ svcudp_freeargs (xprt, xdr_args, args_ptr)
 }
 
 static void
-svcudp_destroy (xprt)
-     SVCXPRT *xprt;
+svcudp_destroy (SVCXPRT *xprt)
 {
   struct svcudp_data *su = su_data (xprt);
 
@@ -300,13 +408,13 @@ svcudp_destroy (xprt)
 #define SPARSENESS 4           /* 75% sparse */
 
 #define CACHE_PERROR(msg)      \
-       (void) fprintf(stderr,"%s\n", msg)
+       (void) __fxprintf(NULL, "%s\n", msg)
 
 #define ALLOC(type, size)      \
        (type *) mem_alloc((unsigned) (sizeof(type) * (size)))
 
-#define BZERO(addr, type, size)         \
-       __bzero((char *) addr, sizeof(type) * (int) (size))
+#define CALLOC(type, size)     \
+  (type *) calloc (sizeof (type), size)
 
 /*
  * An entry in the cache
@@ -381,23 +489,25 @@ svcudp_enablecache (SVCXPRT *transp, u_long size)
     }
   uc->uc_size = size;
   uc->uc_nextvictim = 0;
-  uc->uc_entries = ALLOC (cache_ptr, size * SPARSENESS);
+  uc->uc_entries = CALLOC (cache_ptr, size * SPARSENESS);
   if (uc->uc_entries == NULL)
     {
+      mem_free (uc, sizeof (struct udp_cache));
       CACHE_PERROR (_("enablecache: could not allocate cache data"));
       return 0;
     }
-  BZERO (uc->uc_entries, cache_ptr, size * SPARSENESS);
-  uc->uc_fifo = ALLOC (cache_ptr, size);
+  uc->uc_fifo = CALLOC (cache_ptr, size);
   if (uc->uc_fifo == NULL)
     {
+      mem_free (uc->uc_entries, size * SPARSENESS);
+      mem_free (uc, sizeof (struct udp_cache));
       CACHE_PERROR (_("enablecache: could not allocate cache fifo"));
       return 0;
     }
-  BZERO (uc->uc_fifo, cache_ptr, size);
   su->su_cache = (char *) uc;
   return 1;
 }
+libc_hidden_nolink_sunrpc (svcudp_enablecache, GLIBC_2_0)
 
 
 /*
@@ -444,6 +554,7 @@ cache_set (SVCXPRT *xprt, u_long replylen)
       newbuf = mem_alloc (su->su_iosz);
       if (newbuf == NULL)
        {
+         mem_free (victim, sizeof (struct cache_node));
          CACHE_PERROR (_("cache_set: could not allocate new rpc_buffer"));
          return;
        }
@@ -473,11 +584,8 @@ cache_set (SVCXPRT *xprt, u_long replylen)
  * return 1 if found, 0 if not found
  */
 static int
-cache_get (xprt, msg, replyp, replylenp)
-     SVCXPRT *xprt;
-     struct rpc_msg *msg;
-     char **replyp;
-     u_long *replylenp;
+cache_get (SVCXPRT *xprt, struct rpc_msg *msg, char **replyp,
+          u_long *replylenp)
 {
   u_int loc;
   cache_ptr ent;