root/maint/gnulib/tests/test-select.h

/* [previous][next][first][last][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. failed
  2. test
  3. open_server_socket
  4. connect_to_socket
  5. do_select
  6. do_select_nowait
  7. do_select_wait
  8. test_tty
  9. do_select_bad_nfd_nowait
  10. test_bad_nfd
  11. do_select_bad_fd
  12. do_select_bad_fd_nowait
  13. test_bad_fd
  14. test_connect_first
  15. test_accept_first
  16. test_pair
  17. test_socket_pair
  18. test_pipe
  19. test_function

   1 /* Test of select() substitute.
   2    Copyright (C) 2008-2021 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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 }

/* [previous][next][first][last][top][bottom][index][help] */