(root)/
glibc-2.38/
socket/
tst-accept4.c
       1  /* Test the accept4 function with differing flags arguments.
       2     Copyright (C) 2017-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <arpa/inet.h>
      20  #include <errno.h>
      21  #include <fcntl.h>
      22  #include <stdbool.h>
      23  #include <support/check.h>
      24  #include <support/xsocket.h>
      25  #include <support/xunistd.h>
      26  #include <sys/socket.h>
      27  
      28  static bool
      29  is_nonblocking (int fd)
      30  {
      31    int status = fcntl (fd, F_GETFL);
      32    if (status < 0)
      33      FAIL_EXIT1 ("fcntl (F_GETFL): %m");
      34    return status & O_NONBLOCK;
      35  }
      36  
      37  static bool
      38  is_cloexec (int fd)
      39  {
      40    int status = fcntl (fd, F_GETFD);
      41    if (status < 0)
      42      FAIL_EXIT1 ("fcntl (F_GETFD): %m");
      43    return status & FD_CLOEXEC;
      44  }
      45  
      46  struct client
      47  {
      48    int socket;
      49    struct sockaddr_in address;
      50  };
      51  
      52  /* Perform a non-blocking connect to *SERVER_ADDRESS.  */
      53  static struct client
      54  client_connect (const struct sockaddr_in *server_address)
      55  {
      56    struct client result;
      57    result.socket = xsocket (AF_INET,
      58                             SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
      59    TEST_VERIFY (is_nonblocking (result.socket));
      60    TEST_VERIFY (is_cloexec (result.socket));
      61    int ret = connect (result.socket, (const struct sockaddr *) server_address,
      62                       sizeof (*server_address));
      63    if (ret < 0 && errno != EINPROGRESS)
      64      FAIL_EXIT1 ("client connect: %m");
      65    socklen_t sa_len = sizeof (result.address);
      66    xgetsockname (result.socket, (struct sockaddr *) &result.address,
      67                  &sa_len);
      68    TEST_VERIFY (sa_len == sizeof (result.address));
      69    return result;
      70  }
      71  
      72  static void
      73  check_same_address (const struct sockaddr_in *left,
      74                      const struct sockaddr_in *right)
      75  {
      76    TEST_VERIFY (left->sin_family == AF_INET);
      77    TEST_VERIFY (right->sin_family == AF_INET);
      78    TEST_VERIFY (left->sin_addr.s_addr == right->sin_addr.s_addr);
      79    TEST_VERIFY (left->sin_port == right->sin_port);
      80  }
      81  
      82  static int
      83  do_test (void)
      84  {
      85    /* Create server socket.  */
      86    int server_socket = xsocket (AF_INET, SOCK_STREAM, 0);
      87    TEST_VERIFY (!is_nonblocking (server_socket));
      88    TEST_VERIFY (!is_cloexec (server_socket));
      89    struct sockaddr_in server_address =
      90      {
      91        .sin_family = AF_INET,
      92        .sin_addr = {.s_addr = htonl (INADDR_LOOPBACK) },
      93      };
      94    xbind (server_socket,
      95           (struct sockaddr *) &server_address, sizeof (server_address));
      96    {
      97      socklen_t sa_len = sizeof (server_address);
      98      xgetsockname (server_socket, (struct sockaddr *) &server_address,
      99                    &sa_len);
     100      TEST_VERIFY (sa_len == sizeof (server_address));
     101    }
     102    xlisten (server_socket, 5);
     103  
     104    for (int do_nonblock = 0; do_nonblock < 2; ++do_nonblock)
     105      for (int do_cloexec = 0; do_cloexec < 2; ++do_cloexec)
     106        {
     107          int sockflags = 0;
     108          if (do_nonblock)
     109            sockflags |= SOCK_NONBLOCK;
     110          if (do_cloexec)
     111            sockflags |= SOCK_CLOEXEC;
     112  
     113          struct client client = client_connect (&server_address);
     114          struct sockaddr_in client_address;
     115          socklen_t sa_len = sizeof (client_address);
     116          int client_socket = xaccept4 (server_socket,
     117                                        (struct sockaddr *) &client_address,
     118                                        &sa_len, sockflags);
     119          TEST_VERIFY (sa_len == sizeof (client_address));
     120          TEST_VERIFY (is_nonblocking (client_socket) == do_nonblock);
     121          TEST_VERIFY (is_cloexec (client_socket) == do_cloexec);
     122          check_same_address (&client.address, &client_address);
     123          xclose (client_socket);
     124          xclose (client.socket);
     125        }
     126  
     127    xclose (server_socket);
     128    return 0;
     129  }
     130  
     131  #include <support/test-driver.c>