]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Assume that accept4 is always available and works
authorFlorian Weimer <fweimer@redhat.com>
Wed, 19 Apr 2017 05:44:48 +0000 (07:44 +0200)
committerFlorian Weimer <fweimer@redhat.com>
Wed, 19 Apr 2017 05:44:48 +0000 (07:44 +0200)
Simplify the Linux accept4 implementation based on the assumption
that it is available in some way.  __ASSUME_ACCEPT4_SOCKETCALL was
previously unused, so remove it.

For ia64, the accept4 system call (and socket call) were backported
in kernel version 3.2.18.  Reflect this in the installation
instructions.

16 files changed:
ChangeLog
INSTALL
manual/install.texi
nscd/connections.c
socket/Makefile
socket/tst-accept4.c [new file with mode: 0644]
support/Makefile
support/xaccept4.c [new file with mode: 0644]
support/xsocket.h
sysdeps/mach/hurd/kernel-features.h
sysdeps/nacl/kernel-features.h
sysdeps/unix/sysv/linux/accept4.c
sysdeps/unix/sysv/linux/ia64/configure
sysdeps/unix/sysv/linux/ia64/configure.ac
sysdeps/unix/sysv/linux/ia64/kernel-features.h
sysdeps/unix/sysv/linux/kernel-features.h

index fc8c2e4f7b5d5baeb72b15656c406da547262de0..28fcdb24c72e730efab6399be0a3adce0f38e688 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,35 @@
+2017-04-19  Florian Weimer  <fweimer@redhat.com>
+
+       * nscd/connections.c (have_accept4): Removed definition.
+       (nscd_run_worker, main_loop_poll, main_loop_epolll): Assume that
+       accept4 works.
+       * manual/install.texi (Linux): Require at least kernel 3.2.18 for
+       ia64 because that was the first version with accept4 support.
+       * support/Makefile (libsupport-routines): Add xaccept4.
+       * support/xsocket.h (xaccept4): Declare.
+       * support/xaccept4.c: New file.
+       * socket/tst-accept4.c: New file.
+       * socket/Makefile (tests): Add tst-accept4.
+       * sysdeps/mach/hurd/kernel-features.h (__ASSUME_ACCEPT4): Remove
+       definition.
+       * sysdeps/nacl/kernel-features.h (__ASSUME_ACCEPT4): Remove
+       comment.
+       * sysdeps/unix/sysv/linux/accept4.c: Assume that an accept4
+       implementation is available.
+       (accept4): Use the system call if available, otherwise use the
+       socket call.
+       * sysdeps/unix/sysv/linux/ia64/configure.ac (arch_minimum_kernel):
+       Set to 3.2.18.
+       * sysdeps/unix/sysv/linux/ia64/kernel-features.h
+       (__ASSUME_ACCEPT4_SYSCALL, __ASSUME_ACCEPT4): Do not undefine.
+       accept4 is unconditionally available in later 3.2 stable kernels.
+       (__ASSUME_ACCEPT4_SYSCALL): Define.
+       * sysdeps/unix/sysv/linux/kernel-features.h
+       (__ASSUME_ACCEPT4_SOCKETCALL, __ASSUME_ACCEPT4): Remove
+       definitions.
+       * sysdeps/unix/sysv/linux/i386/kernel-features.h
+       (__ASSUME_ACCEPT4_SYSCALL): Define for Linux 4.3 or later.
+
 2017-04-18  Joseph Myers  <joseph@codesourcery.com>
 
        * conform/Makefile (tests-special): Do not make addition of
diff --git a/INSTALL b/INSTALL
index 60f714e0df1510dbf5537c121acfcc8fd653e7ea..920c4df0efb9cf7d8651c71d2a49c80e61fc0ba7 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -501,13 +501,15 @@ Specific advice for GNU/Linux systems
 
 If you are installing the GNU C Library on GNU/Linux systems, you need
 to have the header files from a 3.2 or newer kernel around for
-reference.  These headers must be installed using 'make
-headers_install'; the headers present in the kernel source directory are
-not suitable for direct use by the GNU C Library.  You do not need to
-use that kernel, just have its headers installed where the GNU C Library
-can access them, referred to here as INSTALL-DIRECTORY.  The easiest way
-to do this is to unpack it in a directory such as
-'/usr/src/linux-VERSION'.  In that directory, run 'make headers_install
+reference.  (For the ia64 architecture, you need version 3.2.18 or newer
+because this is the first version with support for the 'accept4' system
+call.)  These headers must be installed using 'make headers_install';
+the headers present in the kernel source directory are not suitable for
+direct use by the GNU C Library.  You do not need to use that kernel,
+just have its headers installed where the GNU C Library can access them,
+referred to here as INSTALL-DIRECTORY.  The easiest way to do this is to
+unpack it in a directory such as '/usr/src/linux-VERSION'.  In that
+directory, run 'make headers_install
 INSTALL_HDR_PATH=INSTALL-DIRECTORY'.  Finally, configure the GNU C
 Library with the option '--with-headers=INSTALL-DIRECTORY/include'.  Use
 the most recent kernel you can get your hands on.  (If you are
index 99397c2ee0b046d73f40fcd55f33b9d3be066bb7..d39d2daacd0f227e3941e9d973e799e5fd48c219 100644 (file)
@@ -566,6 +566,8 @@ patches, although we try to avoid this.
 
 If you are installing @theglibc{} on @gnulinuxsystems{}, you need to have
 the header files from a 3.2 or newer kernel around for reference.
+(For the ia64 architecture, you need version 3.2.18 or newer because this
+is the first version with support for the @code{accept4} system call.)
 These headers must be installed using @samp{make headers_install}; the
 headers present in the kernel source directory are not suitable for
 direct use by @theglibc{}.  You do not need to use that kernel, just have
index a5ca57aea58788a222097fe48273a748f491660e..cc1ed72077640a8b45b8d70f3abc13814a0e8faf 100644 (file)
@@ -257,10 +257,6 @@ int inotify_fd = -1;
 static int nl_status_fd = -1;
 #endif
 
-#ifndef __ASSUME_ACCEPT4
-static int have_accept4;
-#endif
-
 /* Number of times clients had to wait.  */
 unsigned long int client_queued;
 
@@ -1650,16 +1646,6 @@ nscd_run_worker (void *p)
       /* We are done with the list.  */
       pthread_mutex_unlock (&readylist_lock);
 
-#ifndef __ASSUME_ACCEPT4
-      if (have_accept4 < 0)
-       {
-         /* We do not want to block on a short read or so.  */
-         int fl = fcntl (fd, F_GETFL);
-         if (fl == -1 || fcntl (fd, F_SETFL, fl | O_NONBLOCK) == -1)
-           goto close_and_out;
-       }
-#endif
-
       /* Now read the request.  */
       request_header req;
       if (__builtin_expect (TEMP_FAILURE_RETRY (read (fd, &req, sizeof (req)))
@@ -2099,24 +2085,8 @@ main_loop_poll (void)
          if (conns[0].revents != 0)
            {
              /* We have a new incoming connection.  Accept the connection.  */
-             int fd;
-
-#ifndef __ASSUME_ACCEPT4
-             fd = -1;
-             if (have_accept4 >= 0)
-#endif
-               {
-                 fd = TEMP_FAILURE_RETRY (accept4 (sock, NULL, NULL,
+             int fd = TEMP_FAILURE_RETRY (accept4 (sock, NULL, NULL,
                                                    SOCK_NONBLOCK));
-#ifndef __ASSUME_ACCEPT4
-                 if (have_accept4 == 0)
-                   have_accept4 = fd != -1 || errno != ENOSYS ? 1 : -1;
-#endif
-               }
-#ifndef __ASSUME_ACCEPT4
-             if (have_accept4 < 0)
-               fd = TEMP_FAILURE_RETRY (accept (sock, NULL, NULL));
-#endif
 
              /* Use the descriptor if we have not reached the limit.  */
              if (fd >= 0)
@@ -2284,24 +2254,8 @@ main_loop_epoll (int efd)
        if (revs[cnt].data.fd == sock)
          {
            /* A new connection.  */
-           int fd;
-
-# ifndef __ASSUME_ACCEPT4
-           fd = -1;
-           if (have_accept4 >= 0)
-# endif
-             {
-               fd = TEMP_FAILURE_RETRY (accept4 (sock, NULL, NULL,
+           int fd = TEMP_FAILURE_RETRY (accept4 (sock, NULL, NULL,
                                                  SOCK_NONBLOCK));
-# ifndef __ASSUME_ACCEPT4
-               if (have_accept4 == 0)
-                 have_accept4 = fd != -1 || errno != ENOSYS ? 1 : -1;
-# endif
-             }
-# ifndef __ASSUME_ACCEPT4
-           if (have_accept4 < 0)
-             fd = TEMP_FAILURE_RETRY (accept (sock, NULL, NULL));
-# endif
 
            /* Use the descriptor if we have not reached the limit.  */
            if (fd >= 0)
index 25d4f6857863adca7f7992761033d90dffaa12fb..1e2555d66d41b252d148b4918111aa4fa7ccd336 100644 (file)
@@ -31,6 +31,8 @@ routines := accept bind connect getpeername getsockname getsockopt    \
            setsockopt shutdown socket socketpair isfdtype opensock     \
            sockatmark accept4 recvmmsg sendmmsg
 
+tests := tst-accept4
+
 aux     := sa_len
 
 include ../Rules
diff --git a/socket/tst-accept4.c b/socket/tst-accept4.c
new file mode 100644 (file)
index 0000000..a5cf3a2
--- /dev/null
@@ -0,0 +1,131 @@
+/* Test the accept4 function with differing flags arguments.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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.
+
+   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.
+
+   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/>.  */
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <support/check.h>
+#include <support/xsocket.h>
+#include <support/xunistd.h>
+#include <sys/socket.h>
+
+static bool
+is_nonblocking (int fd)
+{
+  int status = fcntl (fd, F_GETFL);
+  if (status < 0)
+    FAIL_EXIT1 ("fcntl (F_GETFL): %m");
+  return status & O_NONBLOCK;
+}
+
+static bool
+is_cloexec (int fd)
+{
+  int status = fcntl (fd, F_GETFD);
+  if (status < 0)
+    FAIL_EXIT1 ("fcntl (F_GETFD): %m");
+  return status & FD_CLOEXEC;
+}
+
+struct client
+{
+  int socket;
+  struct sockaddr_in address;
+};
+
+/* Perform a non-blocking connect to *SERVER_ADDRESS.  */
+static struct client
+client_connect (const struct sockaddr_in *server_address)
+{
+  struct client result;
+  result.socket = xsocket (AF_INET,
+                           SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
+  TEST_VERIFY (is_nonblocking (result.socket));
+  TEST_VERIFY (is_cloexec (result.socket));
+  int ret = connect (result.socket, (const struct sockaddr *) server_address,
+                     sizeof (*server_address));
+  if (ret < 0 && errno != EINPROGRESS)
+    FAIL_EXIT1 ("client connect: %m");
+  socklen_t sa_len = sizeof (result.address);
+  xgetsockname (result.socket, (struct sockaddr *) &result.address,
+                &sa_len);
+  TEST_VERIFY (sa_len == sizeof (result.address));
+  return result;
+}
+
+static void
+check_same_address (const struct sockaddr_in *left,
+                    const struct sockaddr_in *right)
+{
+  TEST_VERIFY (left->sin_family == AF_INET);
+  TEST_VERIFY (right->sin_family == AF_INET);
+  TEST_VERIFY (left->sin_addr.s_addr == right->sin_addr.s_addr);
+  TEST_VERIFY (left->sin_port == right->sin_port);
+}
+
+static int
+do_test (void)
+{
+  /* Create server socket.  */
+  int server_socket = xsocket (AF_INET, SOCK_STREAM, 0);
+  TEST_VERIFY (!is_nonblocking (server_socket));
+  TEST_VERIFY (!is_cloexec (server_socket));
+  struct sockaddr_in server_address =
+    {
+      .sin_family = AF_INET,
+      .sin_addr = {.s_addr = htonl (INADDR_LOOPBACK) },
+    };
+  xbind (server_socket,
+         (struct sockaddr *) &server_address, sizeof (server_address));
+  {
+    socklen_t sa_len = sizeof (server_address);
+    xgetsockname (server_socket, (struct sockaddr *) &server_address,
+                  &sa_len);
+    TEST_VERIFY (sa_len == sizeof (server_address));
+  }
+  xlisten (server_socket, 5);
+
+  for (int do_nonblock = 0; do_nonblock < 2; ++do_nonblock)
+    for (int do_cloexec = 0; do_cloexec < 2; ++do_cloexec)
+      {
+        int sockflags = 0;
+        if (do_nonblock)
+          sockflags |= SOCK_NONBLOCK;
+        if (do_cloexec)
+          sockflags |= SOCK_CLOEXEC;
+
+        struct client client = client_connect (&server_address);
+        struct sockaddr_in client_address;
+        socklen_t sa_len = sizeof (client_address);
+        int client_socket = xaccept4 (server_socket,
+                                      (struct sockaddr *) &client_address,
+                                      &sa_len, sockflags);
+        TEST_VERIFY (sa_len == sizeof (client_address));
+        TEST_VERIFY (is_nonblocking (client_socket) == do_nonblock);
+        TEST_VERIFY (is_cloexec (client_socket) == do_cloexec);
+        check_same_address (&client.address, &client_address);
+        xclose (client_socket);
+        xclose (client.socket);
+      }
+
+  xclose (server_socket);
+  return 0;
+}
+
+#include <support/test-driver.c>
index 1f33fa0c74bd4952f490ab71955fa1eb3574dcfc..38dbd832e9fe757122906139d1db709fa47c45a0 100644 (file)
@@ -50,6 +50,7 @@ libsupport-routines = \
   temp_file \
   write_message \
   xaccept \
+  xaccept4 \
   xasprintf \
   xbind \
   xcalloc \
diff --git a/support/xaccept4.c b/support/xaccept4.c
new file mode 100644 (file)
index 0000000..67dd95e
--- /dev/null
@@ -0,0 +1,32 @@
+/* accept4 with error checking.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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.
+
+   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.
+
+   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/>.  */
+
+#include <support/xsocket.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+int
+xaccept4 (int fd, struct sockaddr *sa, socklen_t *salen, int flags)
+{
+  int clientfd = accept4 (fd, sa, salen, flags);
+  if (clientfd < 0)
+    FAIL_EXIT1 ("accept4 (%d, 0x%x): %m", fd, flags);
+  return clientfd;
+}
index 0dbf13ace9d1b3f6b79318bffe35761a8f877d6d..d6724948d8a1f58a4c61c95162bc005d744ee722 100644 (file)
@@ -30,6 +30,7 @@ void xconnect (int, const struct sockaddr *, socklen_t);
 void xbind (int, const struct sockaddr *, socklen_t);
 void xlisten (int, int);
 int xaccept (int, struct sockaddr *, socklen_t *);
+int xaccept4 (int, struct sockaddr *, socklen_t *, int);
 void xsendto (int, const void *, size_t, int,
               const struct sockaddr *, socklen_t);
 size_t xrecvfrom (int, void *, size_t, int, struct sockaddr *, socklen_t *);
index 20cb3ba7bfb5cdaed74bc97bf27265bdfe15a886..196638829f5ca3b0e4b66362f53a96f1c8b39511 100644 (file)
@@ -19,5 +19,3 @@
 /* This file can define __ASSUME_* macros checked by certain source files.
    Almost none of these are used outside of sysdeps/unix/sysv/linux code.
    But those referring to POSIX-level features like O_* flags can be.  */
-
-#define __ASSUME_ACCEPT4       1
index 32834fd79279fb4e8f0b5215602ad60b950304b0..ba315b66388742c7b533688acb56db3607726235 100644 (file)
@@ -19,7 +19,3 @@
 /* This file can define __ASSUME_* macros checked by certain source files.
    Almost none of these are used outside of sysdeps/unix/sysv/linux code.
    But those referring to POSIX-level features like O_* flags can be.  */
-
-/*
-#define __ASSUME_ACCEPT4       1
-*/
index 53afd7a5100360f41e884abbed595ed0ec09a2b5..0592f43dd65b181e45afb2202de8a994cd04f4dd 100644 (file)
 
 #include <sysdep-cancel.h>
 #include <sys/syscall.h>
+#include <socketcall.h>
 #include <kernel-features.h>
 
+int
+accept4 (int fd, __SOCKADDR_ARG addr, socklen_t *addr_len, int flags)
+{
 /* Do not use the accept4 syscall on socketcall architectures unless
    it was added at the same time as the socketcall support or can be
    assumed to be present.  */
 #if defined __ASSUME_SOCKETCALL \
     && !defined __ASSUME_ACCEPT4_SYSCALL_WITH_SOCKETCALL \
     && !defined __ASSUME_ACCEPT4_SYSCALL
-# undef __NR_accept4
-#endif
-
-#ifdef __NR_accept4
-int
-accept4 (int fd, __SOCKADDR_ARG addr, socklen_t *addr_len, int flags)
-{
-  return SYSCALL_CANCEL (accept4, fd, addr.__sockaddr__, addr_len, flags);
-}
-#elif defined __NR_socketcall
-# include <socketcall.h>
-# ifdef __ASSUME_ACCEPT4_SOCKETCALL
-int
-accept4 (int fd, __SOCKADDR_ARG addr, socklen_t *addr_len, int flags)
-{
   return SOCKETCALL_CANCEL (accept4, fd, addr.__sockaddr__, addr_len, flags);
-}
-# else
-static int have_accept4;
-
-int
-accept4 (int fd, __SOCKADDR_ARG addr, socklen_t *addr_len, int flags)
-{
-  if (__glibc_likely (have_accept4 >= 0))
-    {
-      int ret = SOCKETCALL_CANCEL (accept4, fd, addr.__sockaddr__, addr_len,
-                                  flags);
-      /* The kernel returns -EINVAL for unknown socket operations.
-        We need to convert that error to an ENOSYS error.  */
-      if (__builtin_expect (ret < 0, 0)
-         && have_accept4 == 0
-         && errno == EINVAL)
-       {
-         /* Try another call, this time with the FLAGS parameter
-            cleared and an invalid file descriptor.  This call will not
-            cause any harm and it will return immediately.  */
-         ret = SOCKETCALL_CANCEL (invalid, -1);
-         if (errno == EINVAL)
-           {
-             have_accept4 = -1;
-             __set_errno (ENOSYS);
-           }
-         else
-           {
-             have_accept4 = 1;
-             __set_errno (EINVAL);
-           }
-         return -1;
-       }
-      return ret;
-    }
-  __set_errno (ENOSYS);
-  return -1;
-}
-# endif /* __ASSUME_ACCEPT4_SOCKETCALL  */
-#else /* __NR_socketcall   */
-int
-accept4 (int fd, __SOCKADDR_ARG addr, socklen_t *addr_len, int flags)
-{
-  __set_errno (ENOSYS);
-  return -1;
-}
-stub_warning (accept4)
+#else
+  return SYSCALL_CANCEL (accept4, fd, addr.__sockaddr__, addr_len, flags);
 #endif
+}
index 1d4e5d18d639b2fbbd4b3d0aa4d6ad567d5c8b32..3cf72371ef8acdf0522d1c1661202b680a84c483 100644 (file)
@@ -2,3 +2,7 @@
  # Local configure fragment for sysdeps/unix/sysv/linux/ia64
 
 ldd_rewrite_script=$dir/ldd-rewrite.sed
+
+# First version with support for the accept4 system call.
+# Linux 3.3 includes it as well.
+arch_minimum_kernel=3.2.18
index 4fb564721b858a1fe735a524101a11b98455ac2c..94a578c12dfe89bea52eeefb84c1ed4d51b98057 100644 (file)
@@ -2,3 +2,7 @@ GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory.
 # Local configure fragment for sysdeps/unix/sysv/linux/ia64
 
 ldd_rewrite_script=$dir/ldd-rewrite.sed
+
+# First version with support for the accept4 system call.
+# Linux 3.3 includes it as well.
+arch_minimum_kernel=3.2.18
index ac9403e869dcc52eb8a6f6b1c84f0b03b8df1461..cda0ad61501a562129ad5cc6f34abe9ba3850623 100644 (file)
 
 #include_next <kernel-features.h>
 
-/* Support for the accept4 syscall was added in 3.3.  */
-#if __LINUX_KERNEL_VERSION < 0x030300
-# undef __ASSUME_ACCEPT4_SYSCALL
-# undef __ASSUME_ACCEPT4
-#endif
-
 #define __ASSUME_RECV_SYSCALL          1
 #define __ASSUME_SEND_SYSCALL          1
+#define __ASSUME_ACCEPT4_SYSCALL       1
 
 #endif /* _KERNEL_FEATURES_H */
index fd936c5366fc8445aa3e9681930ec5d80cd490c9..b981466f3445244be9a4037f5f309b5946449763 100644 (file)
    architectures using a separate syscall rather than socketcall that
    syscall was only added later, and some architectures first had
    socketcall support then a separate syscall.  Define
-   __ASSUME_ACCEPT4_SOCKETCALL if glibc uses socketcall on this
-   architecture and accept4 is available through socketcall,
    __ASSUME_ACCEPT4_SYSCALL if it is available through a separate
-   syscall, __ASSUME_ACCEPT4_SYSCALL_WITH_SOCKETCALL if it became
+   syscall, and __ASSUME_ACCEPT4_SYSCALL_WITH_SOCKETCALL if it became
    available through a separate syscall at the same time as through
-   socketcall, and __ASSUME_ACCEPT4 if the accept4 function is known
-   to work.  */
-#ifdef __ASSUME_SOCKETCALL
-# define __ASSUME_ACCEPT4_SOCKETCALL   1
-#endif
+   socketcall.  */
 #define __ASSUME_ACCEPT4_SYSCALL       1
-#define __ASSUME_ACCEPT4       1
 
 /* Support for the FUTEX_CLOCK_REALTIME flag was added in 2.6.29.  */
 #define __ASSUME_FUTEX_CLOCK_REALTIME  1