• Ulrich Drepper's avatar
    flag parameters: paccept · aaca0bdc
    Ulrich Drepper authored
    This patch is by far the most complex in the series.  It adds a new syscall
    paccept.  This syscall differs from accept in that it adds (at the userlevel)
    two additional parameters:
    
    - a signal mask
    - a flags value
    
    The flags parameter can be used to set flag like SOCK_CLOEXEC.  This is
    imlpemented here as well.  Some people argued that this is a property which
    should be inherited from the file desriptor for the server but this is against
    POSIX.  Additionally, we really want the signal mask parameter as well
    (similar to pselect, ppoll, etc).  So an interface change in inevitable.
    
    The flag value is the same as for socket and socketpair.  I think diverging
    here will only create confusion.  Similar to the filesystem interfaces where
    the use of the O_* constants differs, it is acceptable here.
    
    The signal mask is handled as for pselect etc.  The mask is temporarily
    installed for the thread and removed before the call returns.  I modeled the
    code after pselect.  If there is a problem it's likely also in pselect.
    
    For architectures which use socketcall I maintained this interface instead of
    adding a system call.  The symmetry shouldn't be broken.
    
    The following test must be adjusted for architectures other than x86 and
    x86-64 and in case the syscall numbers changed.
    
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    #include <errno.h>
    #include <fcntl.h>
    #include <pthread.h>
    #include <signal.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <netinet/in.h>
    #include <sys/socket.h>
    #include <sys/syscall.h>
    
    #ifndef __NR_paccept
    # ifdef __x86_64__
    #  define __NR_paccept 288
    # elif defined __i386__
    #  define SYS_PACCEPT 18
    #  define USE_SOCKETCALL 1
    # else
    #  error "need __NR_paccept"
    # endif
    #endif
    
    #ifdef USE_SOCKETCALL
    # define paccept(fd, addr, addrlen, mask, flags) \
      ({ long args[6] = { \
           (long) fd, (long) addr, (long) addrlen, (long) mask, 8, (long) flags }; \
         syscall (__NR_socketcall, SYS_PACCEPT, args); })
    #else
    # define paccept(fd, addr, addrlen, mask, flags) \
      syscall (__NR_paccept, fd, addr, addrlen, mask, 8, flags)
    #endif
    
    #define PORT 57392
    
    #define SOCK_CLOEXEC O_CLOEXEC
    
    static pthread_barrier_t b;
    
    static void *
    tf (void *arg)
    {
      pthread_barrier_wait (&b);
      int s = socket (AF_INET, SOCK_STREAM, 0);
      struct sockaddr_in sin;
      sin.sin_family = AF_INET;
      sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
      sin.sin_port = htons (PORT);
      connect (s, (const struct sockaddr *) &sin, sizeof (sin));
      close (s);
    
      pthread_barrier_wait (&b);
      s = socket (AF_INET, SOCK_STREAM, 0);
      sin.sin_port = htons (PORT);
      connect (s, (const struct sockaddr *) &sin, sizeof (sin));
      close (s);
      pthread_barrier_wait (&b);
    
      pthread_barrier_wait (&b);
      sleep (2);
      pthread_kill ((pthread_t) arg, SIGUSR1);
    
      return NULL;
    }
    
    static void
    handler (int s)
    {
    }
    
    int
    main (void)
    {
      pthread_barrier_init (&b, NULL, 2);
    
      struct sockaddr_in sin;
      pthread_t th;
      if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0)
        {
          puts ("pthread_create failed");
          return 1;
        }
    
      int s = socket (AF_INET, SOCK_STREAM, 0);
      int reuse = 1;
      setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof (reuse));
      sin.sin_family = AF_INET;
      sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
      sin.sin_port = htons (PORT);
      bind (s, (struct sockaddr *) &sin, sizeof (sin));
      listen (s, SOMAXCONN);
    
      pthread_barrier_wait (&b);
    
      int s2 = paccept (s, NULL, 0, NULL, 0);
      if (s2 < 0)
        {
          puts ("paccept(0) failed");
          return 1;
        }
    
      int coe = fcntl (s2, F_GETFD);
      if (coe & FD_CLOEXEC)
        {
          puts ("paccept(0) set close-on-exec-flag");
          return 1;
        }
      close (s2);
    
      pthread_barrier_wait (&b);
    
      s2 = paccept (s, NULL, 0, NULL, SOCK_CLOEXEC);
      if (s2 < 0)
        {
          puts ("paccept(SOCK_CLOEXEC) failed");
          return 1;
        }
    
      coe = fcntl (s2, F_GETFD);
      if ((coe & FD_CLOEXEC) == 0)
        {
          puts ("paccept(SOCK_CLOEXEC) does not set close-on-exec flag");
          return 1;
        }
      close (s2);
    
      pthread_barrier_wait (&b);
    
      struct sigaction sa;
      sa.sa_handler = handler;
      sa.sa_flags = 0;
      sigemptyset (&sa.sa_mask);
      sigaction (SIGUSR1, &sa, NULL);
    
      sigset_t ss;
      pthread_sigmask (SIG_SETMASK, NULL, &ss);
      sigaddset (&ss, SIGUSR1);
      pthread_sigmask (SIG_SETMASK, &ss, NULL);
    
      sigdelset (&ss, SIGUSR1);
      alarm (4);
      pthread_barrier_wait (&b);
    
      errno = 0 ;
      s2 = paccept (s, NULL, 0, &ss, 0);
      if (s2 != -1 || errno != EINTR)
        {
          puts ("paccept did not fail with EINTR");
          return 1;
        }
    
      close (s);
    
      puts ("OK");
    
      return 0;
    }
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    [akpm@linux-foundation.org: make it compile]
    [akpm@linux-foundation.org: add sys_ni stub]
    Signed-off-by: default avatarUlrich Drepper <drepper@redhat.com>
    Acked-by: default avatarDavide Libenzi <davidel@xmailserver.org>
    Cc: Michael Kerrisk <mtk.manpages@googlemail.com>
    Cc: <linux-arch@vger.kernel.org>
    Cc: "David S. Miller" <davem@davemloft.net>
    Cc: Roland McGrath <roland@redhat.com>
    Cc: Kyle McMartin <kyle@mcmartin.ca>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    aaca0bdc
compat.c 23.7 KB