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