(root)/
findutils-4.9.0/
gnulib-tests/
test-select.h
       1  /* Test of select() substitute.
       2     Copyright (C) 2008-2022 Free Software Foundation, Inc.
       3  
       4     This program is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU General Public License as published by
       6     the Free Software Foundation, either version 3 of the License, or
       7     (at your option) any later version.
       8  
       9     This program is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU General Public License for more details.
      13  
      14     You should have received a copy of the GNU General Public License
      15     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  /* Written by Paolo Bonzini, 2008.  */
      18  
      19  #include <stdio.h>
      20  #include <string.h>
      21  #include <sys/socket.h>
      22  #include <netinet/in.h>
      23  #include <arpa/inet.h>
      24  #include <unistd.h>
      25  #include <fcntl.h>
      26  #include <stdlib.h>
      27  #include <stdbool.h>
      28  #include <sys/ioctl.h>
      29  #include <errno.h>
      30  
      31  #include "macros.h"
      32  
      33  #if defined _WIN32 && ! defined __CYGWIN__
      34  # define WINDOWS_NATIVE
      35  #endif
      36  
      37  #ifdef HAVE_SYS_WAIT_H
      38  # include <sys/wait.h>
      39  #endif
      40  
      41  #define TEST_PORT       12345
      42  
      43  
      44  typedef int (*select_fn) (int, fd_set *, fd_set *, fd_set *, struct timeval *);
      45  
      46  
      47  /* Minimal testing infrastructure.  */
      48  
      49  static int failures;
      50  
      51  static void
      52  failed (const char *reason)
      53  {
      54    if (++failures > 1)
      55      printf ("  ");
      56    printf ("failed (%s)\n", reason);
      57  }
      58  
      59  static int
      60  test (void (*fn) (select_fn), select_fn my_select, const char *msg)
      61  {
      62    failures = 0;
      63    printf ("%s... ", msg);
      64    fflush (stdout);
      65    fn (my_select);
      66  
      67    if (!failures)
      68      printf ("passed\n");
      69  
      70    return failures;
      71  }
      72  
      73  
      74  /* Funny socket code.  */
      75  
      76  static int
      77  open_server_socket (void)
      78  {
      79    int s, x;
      80    struct sockaddr_in ia;
      81  
      82    s = socket (AF_INET, SOCK_STREAM, 0);
      83  
      84    x = 1;
      85    setsockopt (s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof (x));
      86  
      87    memset (&ia, 0, sizeof (ia));
      88    ia.sin_family = AF_INET;
      89    inet_pton (AF_INET, "127.0.0.1", &ia.sin_addr);
      90    ia.sin_port = htons (TEST_PORT);
      91    if (bind (s, (struct sockaddr *) &ia, sizeof (ia)) < 0)
      92      {
      93        perror ("bind");
      94        exit (77);
      95      }
      96  
      97    if (listen (s, 1) < 0)
      98      {
      99        perror ("listen");
     100        exit (77);
     101      }
     102  
     103    return s;
     104  }
     105  
     106  static int
     107  connect_to_socket (bool blocking)
     108  {
     109    int s;
     110    struct sockaddr_in ia;
     111  
     112    s = socket (AF_INET, SOCK_STREAM, 0);
     113  
     114    memset (&ia, 0, sizeof (ia));
     115    ia.sin_family = AF_INET;
     116    inet_pton (AF_INET, "127.0.0.1", &ia.sin_addr);
     117    ia.sin_port = htons (TEST_PORT);
     118  
     119    if (!blocking)
     120      {
     121  #ifdef WINDOWS_NATIVE
     122        unsigned long iMode = 1;
     123        ioctl (s, FIONBIO, (char *) &iMode);
     124  
     125  #elif defined F_GETFL
     126        int oldflags = fcntl (s, F_GETFL, NULL);
     127  
     128        if (!(oldflags & O_NONBLOCK))
     129          fcntl (s, F_SETFL, oldflags | O_NONBLOCK);
     130  #endif
     131      }
     132  
     133    if (connect (s, (struct sockaddr *) &ia, sizeof (ia)) < 0
     134        && (blocking || errno != EINPROGRESS))
     135      {
     136        perror ("connect");
     137        exit (77);
     138      }
     139  
     140    return s;
     141  }
     142  
     143  
     144  /* A slightly more convenient interface to select(2).
     145     Waits until a specific event occurs on a file descriptor FD.
     146     EV is a bit mask of events to look for:
     147       SEL_IN - input can be polled without blocking,
     148       SEL_OUT - output can be provided without blocking,
     149       SEL_EXC - an exception occurred,
     150     A maximum wait time is specified by TIMEOUT.
     151     *TIMEOUT = { 0, 0 } means to return immediately,
     152     TIMEOUT = NULL means to wait indefinitely.  */
     153  
     154  enum { SEL_IN = 1, SEL_OUT = 2, SEL_EXC = 4 };
     155  
     156  static int
     157  do_select (int fd, int ev, struct timeval *timeout, select_fn my_select)
     158  {
     159    fd_set rfds, wfds, xfds;
     160    int r, rev;
     161  
     162    FD_ZERO (&rfds);
     163    FD_ZERO (&wfds);
     164    FD_ZERO (&xfds);
     165    if (ev & SEL_IN)
     166      FD_SET (fd, &rfds);
     167    if (ev & SEL_OUT)
     168      FD_SET (fd, &wfds);
     169    if (ev & SEL_EXC)
     170      FD_SET (fd, &xfds);
     171    r = my_select (fd + 1, &rfds, &wfds, &xfds, timeout);
     172    if (r < 0)
     173      return r;
     174  
     175    rev = 0;
     176    if (FD_ISSET (fd, &rfds))
     177      rev |= SEL_IN;
     178    if (FD_ISSET (fd, &wfds))
     179      rev |= SEL_OUT;
     180    if (FD_ISSET (fd, &xfds))
     181      rev |= SEL_EXC;
     182    if (rev && r == 0)
     183      failed ("select returned 0");
     184    if (rev & ~ev)
     185      failed ("select returned unrequested events");
     186  
     187    return rev;
     188  }
     189  
     190  static int
     191  do_select_nowait (int fd, int ev, select_fn my_select)
     192  {
     193    struct timeval tv0;
     194    tv0.tv_sec = 0;
     195    tv0.tv_usec = 0;
     196    return do_select (fd, ev, &tv0, my_select);
     197  }
     198  
     199  static int
     200  do_select_wait (int fd, int ev, select_fn my_select)
     201  {
     202    return do_select (fd, ev, NULL, my_select);
     203  }
     204  
     205  
     206  /* Test select(2) for TTYs.  */
     207  
     208  #ifdef INTERACTIVE
     209  static void
     210  test_tty (select_fn my_select)
     211  {
     212    if (do_select_nowait (0, SEL_IN, my_select) != 0)
     213      failed ("can read");
     214    if (do_select_nowait (0, SEL_OUT, my_select) == 0)
     215      failed ("cannot write");
     216  
     217    if (do_select_wait (0, SEL_IN, my_select) == 0)
     218      failed ("return with infinite timeout");
     219  
     220    getchar ();
     221    if (do_select_nowait (0, SEL_IN, my_select) != 0)
     222      failed ("can read after getc");
     223  }
     224  #endif
     225  
     226  
     227  static int
     228  do_select_bad_nfd_nowait (int nfd, select_fn my_select)
     229  {
     230    struct timeval tv0;
     231    tv0.tv_sec = 0;
     232    tv0.tv_usec = 0;
     233    errno = 0;
     234    return my_select (nfd, NULL, NULL, NULL, &tv0);
     235  }
     236  
     237  static void
     238  test_bad_nfd (select_fn my_select)
     239  {
     240    if (do_select_bad_nfd_nowait (-1, my_select) != -1 || errno != EINVAL)
     241      failed ("invalid errno after negative nfds");
     242    /* Can't test FD_SETSIZE + 1 for EINVAL, since some systems allow
     243       dynamically larger set size by redefining FD_SETSIZE anywhere up
     244       to the actual maximum fd.  */
     245  #if 0
     246    if (do_select_bad_nfd_nowait (FD_SETSIZE + 1, my_select) != -1
     247        || errno != EINVAL)
     248      failed ("invalid errno after bogus nfds");
     249  #endif
     250  }
     251  
     252  /* Test select(2) on invalid file descriptors.  */
     253  
     254  static int
     255  do_select_bad_fd (int fd, int ev, struct timeval *timeout, select_fn my_select)
     256  {
     257    fd_set rfds, wfds, xfds;
     258  
     259    FD_ZERO (&rfds);
     260    FD_ZERO (&wfds);
     261    FD_ZERO (&xfds);
     262    if (ev & SEL_IN)
     263      FD_SET (fd, &rfds);
     264    if (ev & SEL_OUT)
     265      FD_SET (fd, &wfds);
     266    if (ev & SEL_EXC)
     267      FD_SET (fd, &xfds);
     268    errno = 0;
     269    return my_select (fd + 1, &rfds, &wfds, &xfds, timeout);
     270    /* In this case, when fd is invalid, on some platforms, the bit for fd
     271       is left alone in the fd_set, whereas on other platforms it is cleared.
     272       So, don't check the bit for fd here.  */
     273  }
     274  
     275  static int
     276  do_select_bad_fd_nowait (int fd, int ev, select_fn my_select)
     277  {
     278    struct timeval tv0;
     279    tv0.tv_sec = 0;
     280    tv0.tv_usec = 0;
     281    return do_select_bad_fd (fd, ev, &tv0, my_select);
     282  }
     283  
     284  static void
     285  test_bad_fd (select_fn my_select)
     286  {
     287    /* This tests fails on OSF/1 and native Windows, even with fd = 16.  */
     288  #if !(defined __osf__ || defined WINDOWS_NATIVE)
     289    int fd;
     290  
     291    /* On Linux, Mac OS X, *BSD, values of fd like 99 or 399 are discarded
     292       by the kernel early and therefore do *not* lead to EBADF, as required
     293       by POSIX.  */
     294  # if defined __linux__ || (defined __APPLE__ && defined __MACH__) || (defined __FreeBSD__ || defined __DragonFly__) || defined __OpenBSD__ || defined __NetBSD__
     295    fd = 14;
     296  # else
     297    fd = 99;
     298  # endif
     299    /* Even on the best POSIX compliant platforms, values of fd >= FD_SETSIZE
     300       require an nfds argument that is > FD_SETSIZE and thus may lead to EINVAL,
     301       not EBADF.  */
     302    if (fd >= FD_SETSIZE)
     303      fd = FD_SETSIZE - 1;
     304    close (fd);
     305  
     306    if (do_select_bad_fd_nowait (fd, SEL_IN, my_select) == 0 || errno != EBADF)
     307      failed ("invalid fd among rfds");
     308    if (do_select_bad_fd_nowait (fd, SEL_OUT, my_select) == 0 || errno != EBADF)
     309      failed ("invalid fd among wfds");
     310    if (do_select_bad_fd_nowait (fd, SEL_EXC, my_select) == 0 || errno != EBADF)
     311      failed ("invalid fd among xfds");
     312  #endif
     313  }
     314  
     315  
     316  /* Test select(2) for unconnected nonblocking sockets.  */
     317  
     318  static void
     319  test_connect_first (select_fn my_select)
     320  {
     321    int s = open_server_socket ();
     322    struct sockaddr_in ia;
     323    socklen_t addrlen;
     324  
     325    int c1, c2;
     326  
     327    if (do_select_nowait (s, SEL_IN | SEL_EXC, my_select) != 0)
     328      failed ("can read, socket not connected");
     329  
     330    c1 = connect_to_socket (false);
     331  
     332    if (do_select_wait (s, SEL_IN | SEL_EXC, my_select) != SEL_IN)
     333      failed ("expecting readability on passive socket");
     334    if (do_select_nowait (s, SEL_IN | SEL_EXC, my_select) != SEL_IN)
     335      failed ("expecting readability on passive socket");
     336  
     337    addrlen = sizeof (ia);
     338    c2 = accept (s, (struct sockaddr *) &ia, &addrlen);
     339    ASSERT (close (s) == 0);
     340    ASSERT (close (c1) == 0);
     341    ASSERT (close (c2) == 0);
     342  }
     343  
     344  
     345  /* Test select(2) for unconnected blocking sockets.  */
     346  
     347  static void
     348  test_accept_first (select_fn my_select)
     349  {
     350  #ifndef WINDOWS_NATIVE
     351    int s = open_server_socket ();
     352    struct sockaddr_in ia;
     353    socklen_t addrlen;
     354    char buf[3];
     355    int c, pid;
     356  
     357    pid = fork ();
     358    if (pid < 0)
     359      return;
     360  
     361    if (pid == 0)
     362      {
     363        addrlen = sizeof (ia);
     364        c = accept (s, (struct sockaddr *) &ia, &addrlen);
     365        ASSERT (close (s) == 0);
     366        ASSERT (write (c, "foo", 3) == 3);
     367        ASSERT (read (c, buf, 3) == 3);
     368        shutdown (c, SHUT_RD);
     369        ASSERT (close (c) == 0);
     370        exit (0);
     371      }
     372    else
     373      {
     374        ASSERT (close (s) == 0);
     375        c = connect_to_socket (true);
     376        if (do_select_nowait (c, SEL_OUT, my_select) != SEL_OUT)
     377          failed ("cannot write after blocking connect");
     378        ASSERT (write (c, "foo", 3) == 3);
     379        wait (&pid);
     380        if (do_select_wait (c, SEL_IN, my_select) != SEL_IN)
     381          failed ("cannot read data left in the socket by closed process");
     382        ASSERT (read (c, buf, 3) == 3);
     383        ASSERT (write (c, "foo", 3) == 3);
     384        (void) close (c); /* may fail with errno = ECONNRESET */
     385      }
     386  #endif
     387  }
     388  
     389  
     390  /* Common code for pipes and connected sockets.  */
     391  
     392  static void
     393  test_pair (int rd, int wd, select_fn my_select)
     394  {
     395    char buf[3];
     396    if (do_select_wait (wd, SEL_IN | SEL_OUT | SEL_EXC, my_select) != SEL_OUT)
     397      failed ("expecting writability before writing");
     398    if (do_select_nowait (wd, SEL_IN | SEL_OUT | SEL_EXC, my_select) != SEL_OUT)
     399      failed ("expecting writability before writing");
     400  
     401    ASSERT (write (wd, "foo", 3) == 3);
     402    if (do_select_wait (rd, SEL_IN, my_select) != SEL_IN)
     403      failed ("expecting readability after writing");
     404    if (do_select_nowait (rd, SEL_IN, my_select) != SEL_IN)
     405      failed ("expecting readability after writing");
     406  
     407    ASSERT (read (rd, buf, 3) == 3);
     408  }
     409  
     410  
     411  /* Test select(2) on connected sockets.  */
     412  
     413  static void
     414  test_socket_pair (select_fn my_select)
     415  {
     416    struct sockaddr_in ia;
     417  
     418    socklen_t addrlen = sizeof (ia);
     419    int s = open_server_socket ();
     420    int c1 = connect_to_socket (false);
     421    int c2 = accept (s, (struct sockaddr *) &ia, &addrlen);
     422  
     423    ASSERT (close (s) == 0);
     424  
     425    test_pair (c1, c2, my_select);
     426    ASSERT (close (c1) == 0);
     427    ASSERT (write (c2, "foo", 3) == 3);
     428    (void) close (c2); /* may fail with errno = ECONNRESET */
     429  }
     430  
     431  
     432  /* Test select(2) on pipes.  */
     433  
     434  static void
     435  test_pipe (select_fn my_select)
     436  {
     437    int fd[2];
     438  
     439    ASSERT (pipe (fd) == 0);
     440    test_pair (fd[0], fd[1], my_select);
     441    ASSERT (close (fd[0]) == 0);
     442    ASSERT (close (fd[1]) == 0);
     443  }
     444  
     445  
     446  /* Do them all.  */
     447  
     448  static int
     449  test_function (select_fn my_select)
     450  {
     451    int result = 0;
     452  
     453  #ifdef INTERACTIVE
     454    printf ("Please press Enter\n");
     455    test (test_tty, "TTY", my_select);
     456  #endif
     457  
     458    result += test (test_bad_nfd, my_select, "Invalid nfd test");
     459    result += test (test_bad_fd, my_select, "Invalid fd test");
     460    result += test (test_connect_first, my_select, "Unconnected socket test");
     461    result += test (test_socket_pair, my_select, "Connected sockets test");
     462    result += test (test_accept_first, my_select, "General socket test with fork");
     463    result += test (test_pipe, my_select, "Pipe test");
     464  
     465    return result;
     466  }