Blame src/microhttpd/test_shutdown_select.c

Packit 875988
/*
Packit 875988
     This file is part of libmicrohttpd
Packit 875988
     Copyright (C) 2016 Karlson2k (Evgeny Grin)
Packit 875988
Packit 875988
     libmicrohttpd is free software; you can redistribute it and/or modify
Packit 875988
     it under the terms of the GNU General Public License as published
Packit 875988
     by the Free Software Foundation; either version 3, or (at your
Packit 875988
     option) any later version.
Packit 875988
Packit 875988
     libmicrohttpd is distributed in the hope that it will be useful, but
Packit 875988
     WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 875988
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 875988
     General Public License for more details.
Packit 875988
Packit 875988
     You should have received a copy of the GNU General Public License
Packit 875988
     along with libmicrohttpd; see the file COPYING.  If not, write to the
Packit 875988
     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Packit 875988
     Boston, MA 02110-1301, USA.
Packit 875988
*/
Packit 875988
Packit 875988
/**
Packit 875988
 * @file microhttpd/test_shutdown_select.c
Packit 875988
 * @brief  Test whether shutdown socket triggers select()/poll()
Packit 875988
 * @details On some platforms shutting down the socket in one thread
Packit 875988
 *          trigger select() or poll() waiting for this socket in
Packit 875988
 *          other thread. libmicrohttpd depend on this behavior on
Packit 875988
 *          those platforms. This program check whether select()
Packit 875988
 *          and poll() (if available) works as expected.
Packit 875988
 * @author Karlson2k (Evgeny Grin)
Packit 875988
 */
Packit 875988
Packit 875988
#include "MHD_config.h"
Packit 875988
#include "platform.h"
Packit 875988
#include "mhd_sockets.h"
Packit 875988
#include <stdlib.h>
Packit 875988
#include <stdio.h>
Packit 875988
Packit 875988
#ifdef HAVE_UNISTD_H
Packit 875988
#include <unistd.h>
Packit 875988
#endif /* HAVE_UNISTD_H */
Packit 875988
Packit 875988
#ifdef HAVE_TIME_H
Packit 875988
#include <time.h>
Packit 875988
#endif /* HAVE_TIME_H */
Packit 875988
Packit 875988
#if defined(MHD_USE_POSIX_THREADS)
Packit 875988
#include <pthread.h>
Packit 875988
#endif /* MHD_USE_POSIX_THREADS */
Packit 875988
Packit 875988
#if defined(MHD_WINSOCK_SOCKETS)
Packit 875988
#include <winsock2.h>
Packit 875988
#include <windows.h>
Packit 875988
#define sock_errno (WSAGetLastError())
Packit 875988
#elif defined(MHD_POSIX_SOCKETS)
Packit 875988
#ifdef HAVE_SYS_TYPES_H
Packit 875988
#include <sys/types.h>
Packit 875988
#endif /* HAVE_SYS_TYPES_H */
Packit 875988
#ifdef HAVE_SYS_SOCKET_H
Packit 875988
#include <sys/socket.h>
Packit 875988
#endif /* HAVE_SYS_SOCKET_H */
Packit 875988
#ifdef HAVE_NETINET_IN_H
Packit 875988
#include <netinet/in.h>
Packit 875988
#endif /* HAVE_NETINET_IN_H */
Packit 875988
#ifdef HAVE_ARPA_INET_H
Packit 875988
#include <arpa/inet.h>
Packit 875988
#endif /* HAVE_ARPA_INET_H */
Packit 875988
#ifdef HAVE_SYS_SELECT_H
Packit 875988
#include <sys/select.h>
Packit 875988
#endif /* HAVE_SYS_SELECT_H */
Packit 875988
#if defined(HAVE_POLL) && defined(HAVE_POLL_H)
Packit 875988
#include <poll.h>
Packit 875988
#endif /* HAVE_POLL && HAVE_POLL_H */
Packit 875988
#define sock_errno (errno)
Packit 875988
#endif /* MHD_POSIX_SOCKETS */
Packit 875988
Packit 875988
#ifdef HAVE_STDBOOL_H
Packit 875988
#include <stdbool.h>
Packit 875988
#endif /* HAVE_STDBOOL_H */
Packit 875988
Packit 875988
#include "mhd_threads.h"
Packit 875988
Packit 875988
#ifndef SOMAXCONN
Packit 875988
#define SOMAXCONN 511
Packit 875988
#endif /* ! SOMAXCONN */
Packit 875988
Packit 875988
#if !defined(SHUT_RDWR) && defined(SD_BOTH)
Packit 875988
#define SHUT_RDWR SD_BOTH
Packit 875988
#endif
Packit 875988
Packit 875988
static bool check_err;
Packit 875988
Packit 875988
Packit 875988
static bool
Packit 875988
has_in_name(const char *prog_name, const char *marker)
Packit 875988
{
Packit 875988
  size_t name_pos;
Packit 875988
  size_t pos;
Packit 875988
Packit 875988
  if (!prog_name || !marker)
Packit 875988
    return 0;
Packit 875988
Packit 875988
  pos = 0;
Packit 875988
  name_pos = 0;
Packit 875988
  while (prog_name[pos])
Packit 875988
    {
Packit 875988
      if ('/' == prog_name[pos])
Packit 875988
        name_pos = pos + 1;
Packit 875988
#if defined(_WIN32) || defined(__CYGWIN__)
Packit 875988
      else if ('\\' == prog_name[pos])
Packit 875988
        name_pos = pos + 1;
Packit 875988
#endif /* _WIN32 || __CYGWIN__ */
Packit 875988
      pos++;
Packit 875988
    }
Packit 875988
  if (name_pos == pos)
Packit 875988
    return true;
Packit 875988
  return strstr(prog_name + name_pos, marker) != NULL;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
static MHD_socket
Packit 875988
start_socket_listen(int domain)
Packit 875988
{
Packit 875988
/* Create sockets similarly to daemon.c */
Packit 875988
  MHD_socket fd;
Packit 875988
  int cloexec_set;
Packit 875988
  struct sockaddr_in sock_addr;
Packit 875988
  socklen_t addrlen;
Packit 875988
Packit 875988
#ifdef MHD_WINSOCK_SOCKETS
Packit 875988
  unsigned long flags = 1;
Packit 875988
#else  /* MHD_POSIX_SOCKETS */
Packit 875988
  int flags;
Packit 875988
#endif /* MHD_POSIX_SOCKETS */
Packit 875988
Packit 875988
#if defined(MHD_POSIX_SOCKETS) && defined(SOCK_CLOEXEC)
Packit 875988
  fd = socket (domain, SOCK_STREAM | SOCK_CLOEXEC, 0);
Packit 875988
  cloexec_set = 1;
Packit 875988
#elif defined(MHD_WINSOCK_SOCKETS) && defined (WSA_FLAG_NO_HANDLE_INHERIT)
Packit 875988
  fd = WSASocketW (domain, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_NO_HANDLE_INHERIT);
Packit 875988
  cloexec_set = 1;
Packit 875988
#else  /* !SOCK_CLOEXEC */
Packit 875988
  fd = socket (domain, SOCK_STREAM, 0);
Packit 875988
  cloexec_set = 0;
Packit 875988
#endif /* !SOCK_CLOEXEC */
Packit 875988
  if ( (MHD_INVALID_SOCKET == fd) && (cloexec_set) )
Packit 875988
    {
Packit 875988
      fd = socket (domain, SOCK_STREAM, 0);
Packit 875988
      cloexec_set = 0;
Packit 875988
    }
Packit 875988
  if (MHD_INVALID_SOCKET == fd)
Packit 875988
    {
Packit 875988
      fprintf (stderr, "Can't create socket: %u\n",
Packit 875988
               (unsigned)sock_errno);
Packit 875988
      return MHD_INVALID_SOCKET;
Packit 875988
    }
Packit 875988
Packit 875988
  if (!cloexec_set)
Packit 875988
    {
Packit 875988
#ifdef MHD_WINSOCK_SOCKETS
Packit 875988
    if (!SetHandleInformation ((HANDLE)fd, HANDLE_FLAG_INHERIT, 0))
Packit 875988
      fprintf (stderr, "Failed to make socket non-inheritable: %u\n",
Packit 875988
               (unsigned int)GetLastError ());
Packit 875988
#else  /* MHD_POSIX_SOCKETS */
Packit 875988
    flags = fcntl (fd, F_GETFD);
Packit 875988
    if ( ( (-1 == flags) ||
Packit 875988
           ( (flags != (flags | FD_CLOEXEC)) &&
Packit 875988
             (0 != fcntl (fd, F_SETFD, flags | FD_CLOEXEC)) ) ) )
Packit 875988
      fprintf (stderr, "Failed to make socket non-inheritable: %s\n",
Packit 875988
               MHD_socket_last_strerr_ ());
Packit 875988
#endif /* MHD_POSIX_SOCKETS */
Packit 875988
    }
Packit 875988
Packit 875988
  memset (&sock_addr, 0, sizeof (struct sockaddr_in));
Packit 875988
  sock_addr.sin_family = AF_INET;
Packit 875988
  sock_addr.sin_port = htons (0);
Packit 875988
#if HAVE_SOCKADDR_IN_SIN_LEN
Packit 875988
  sock_addr.sin_len = sizeof (struct sockaddr_in);
Packit 875988
#endif
Packit 875988
  addrlen = sizeof (struct sockaddr_in);
Packit 875988
Packit 875988
  if (bind (fd, (const struct sockaddr*) &sock_addr, addrlen) < 0)
Packit 875988
    {
Packit 875988
      fprintf (stderr, "Failed to bind socket: %u\n",
Packit 875988
               (unsigned)sock_errno);
Packit 875988
      MHD_socket_close_chk_ (fd);
Packit 875988
      return MHD_INVALID_SOCKET;
Packit 875988
    }
Packit 875988
Packit 875988
#ifdef MHD_WINSOCK_SOCKETS
Packit 875988
  if (0 != ioctlsocket (fd, FIONBIO, &flags))
Packit 875988
    {
Packit 875988
      fprintf (stderr, "Failed to make socket non-blocking: %u\n",
Packit 875988
               (unsigned)sock_errno);
Packit 875988
      MHD_socket_close_chk_ (fd);
Packit 875988
      return MHD_INVALID_SOCKET;
Packit 875988
    }
Packit 875988
#else  /* MHD_POSIX_SOCKETS */
Packit 875988
  flags = fcntl (fd, F_GETFL);
Packit 875988
  if ( ( (-1 == flags) ||
Packit 875988
         ( (flags != (flags | O_NONBLOCK)) &&
Packit 875988
           (0 != fcntl (fd, F_SETFL, flags | O_NONBLOCK)) ) ) )
Packit 875988
    {
Packit 875988
      fprintf (stderr, "Failed to make socket non-blocking: %s\n",
Packit 875988
              MHD_socket_last_strerr_ ());
Packit 875988
      MHD_socket_close_chk_ (fd);
Packit 875988
      return MHD_INVALID_SOCKET;
Packit 875988
    }
Packit 875988
#endif /* MHD_POSIX_SOCKETS */
Packit 875988
Packit 875988
  if (listen(fd, SOMAXCONN) < 0)
Packit 875988
    {
Packit 875988
      fprintf (stderr, "Failed to listen on socket: %u\n",
Packit 875988
               (unsigned)sock_errno);
Packit 875988
      MHD_socket_close_chk_ (fd);
Packit 875988
      return MHD_INVALID_SOCKET;
Packit 875988
    }
Packit 875988
Packit 875988
  return fd;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
Packit 875988
select_thread(void* data)
Packit 875988
{
Packit 875988
  /* use select() like in daemon.c */
Packit 875988
  MHD_socket listen_sock = *((MHD_socket*)data);
Packit 875988
  fd_set rs, ws;
Packit 875988
  struct timeval timeout;
Packit 875988
Packit 875988
  FD_ZERO(&rs);
Packit 875988
  FD_ZERO(&ws);
Packit 875988
  FD_SET(listen_sock, &rs);
Packit 875988
  timeout.tv_usec = 0;
Packit 875988
  timeout.tv_sec = 7;
Packit 875988
Packit 875988
  check_err = (0 > MHD_SYS_select_(listen_sock + 1, &rs, &ws, NULL, &timeout));
Packit 875988
Packit 875988
  return (MHD_THRD_RTRN_TYPE_)0;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
#ifdef HAVE_POLL
Packit 875988
MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
Packit 875988
poll_thread(void* data)
Packit 875988
{
Packit 875988
  /* use poll() like in daemon.c */
Packit 875988
  struct pollfd p[1];
Packit 875988
  MHD_socket listen_sock = *((MHD_socket*)data);
Packit 875988
Packit 875988
  p[0].fd = listen_sock;
Packit 875988
  p[0].events = POLLIN;
Packit 875988
  p[0].revents = 0;
Packit 875988
Packit 875988
  check_err = (0 > MHD_sys_poll_ (p, 1, 7000));
Packit 875988
Packit 875988
  return (MHD_THRD_RTRN_TYPE_)0;
Packit 875988
}
Packit 875988
#endif /* HAVE_POLL */
Packit 875988
Packit 875988
Packit 875988
static void
Packit 875988
local_sleep(unsigned seconds)
Packit 875988
{
Packit 875988
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit 875988
  Sleep(seconds * 1000);
Packit 875988
#else
Packit 875988
  unsigned seconds_left = seconds;
Packit 875988
  do
Packit 875988
    {
Packit 875988
      seconds_left = sleep(seconds_left);
Packit 875988
    } while (seconds_left > 0);
Packit 875988
#endif
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
int
Packit 875988
main (int argc, char *const *argv)
Packit 875988
{
Packit 875988
  int i;
Packit 875988
  time_t start_t, end_t;
Packit 875988
  int result = 0;
Packit 875988
  MHD_THRD_RTRN_TYPE_ (MHD_THRD_CALL_SPEC_ *test_func)(void* data);
Packit 875988
#ifdef MHD_WINSOCK_SOCKETS
Packit 875988
  WORD ver_req;
Packit 875988
  WSADATA wsa_data;
Packit 875988
  int err;
Packit 875988
#endif /* MHD_WINSOCK_SOCKETS */
Packit 875988
  bool test_poll;
Packit 875988
  bool must_ignore;
Packit 875988
  (void)argc; /* Unused. Silent compiler warning. */
Packit 875988
Packit 875988
  test_poll = has_in_name(argv[0], "_poll");
Packit 875988
  must_ignore = has_in_name(argv[0], "_ignore");
Packit 875988
  if (! test_poll)
Packit 875988
    test_func = &select_thread;
Packit 875988
  else
Packit 875988
    {
Packit 875988
#ifndef HAVE_POLL
Packit 875988
      return 77;
Packit 875988
#else  /* ! HAVE_POLL */
Packit 875988
      test_func = &poll_thread;
Packit 875988
#endif /* ! HAVE_POLL */
Packit 875988
    }
Packit 875988
Packit 875988
#ifdef MHD_WINSOCK_SOCKETS
Packit 875988
  ver_req = MAKEWORD(2, 2);
Packit 875988
Packit 875988
  err = WSAStartup(ver_req, &wsa_data);
Packit 875988
  if (err != 0 || MAKEWORD(2, 2) != wsa_data.wVersion)
Packit 875988
    {
Packit 875988
      printf("WSAStartup() failed\n");
Packit 875988
      WSACleanup();
Packit 875988
      return 99;
Packit 875988
    }
Packit 875988
#endif /* MHD_WINSOCK_SOCKETS */
Packit 875988
Packit 875988
  /* try several times to ensure that accidental incoming connection
Packit 875988
   * didn't interfere with test results
Packit 875988
   */
Packit 875988
  for (i = 0; i < 5 && result == 0; i++)
Packit 875988
    {
Packit 875988
      MHD_thread_handle_ sel_thrd;
Packit 875988
      /* fprintf(stdout, "Creating, binding and listening socket...\n"); */
Packit 875988
      MHD_socket listen_socket = start_socket_listen (AF_INET);
Packit 875988
      if (MHD_INVALID_SOCKET == listen_socket)
Packit 875988
        return 99;
Packit 875988
Packit 875988
      check_err = true;
Packit 875988
      /* fprintf (stdout, "Starting select() thread...\n"); */
Packit 875988
#if defined(MHD_USE_POSIX_THREADS)
Packit 875988
      if (0 != pthread_create (&sel_thrd, NULL, test_func, &listen_socket))
Packit 875988
        {
Packit 875988
          MHD_socket_close_chk_ (listen_socket);
Packit 875988
          fprintf (stderr, "Can't start thread\n");
Packit 875988
          return 99;
Packit 875988
        }
Packit 875988
#elif defined(MHD_USE_W32_THREADS)
Packit 875988
      sel_thrd = (HANDLE)_beginthreadex (NULL, 0, test_func, &listen_socket, 0, NULL);
Packit 875988
      if (0 == (sel_thrd))
Packit 875988
        {
Packit 875988
          MHD_socket_close_chk_ (listen_socket);
Packit 875988
          fprintf (stderr, "Can't start select() thread\n");
Packit 875988
          return 99;
Packit 875988
        }
Packit 875988
#else
Packit 875988
#error No threading lib available
Packit 875988
#endif
Packit 875988
      /* fprintf (stdout, "Waiting...\n"); */
Packit 875988
      local_sleep(1); /* make sure that select() is started */
Packit 875988
Packit 875988
      /* fprintf (stdout, "Shutting down socket...\n"); */
Packit 875988
      start_t = time (NULL);
Packit 875988
      shutdown (listen_socket, SHUT_RDWR);
Packit 875988
Packit 875988
      /* fprintf (stdout, "Waiting for thread to finish...\n"); */
Packit 875988
      if (!MHD_join_thread_(sel_thrd))
Packit 875988
        {
Packit 875988
          MHD_socket_close_chk_(listen_socket);
Packit 875988
          fprintf (stderr, "Can't join select() thread\n");
Packit 875988
          return 99;
Packit 875988
        }
Packit 875988
      if (check_err)
Packit 875988
        {
Packit 875988
          MHD_socket_close_chk_(listen_socket);
Packit 875988
          fprintf (stderr, "Error in waiting thread\n");
Packit 875988
          return 99;
Packit 875988
        }
Packit 875988
      end_t = time (NULL);
Packit 875988
      /* fprintf (stdout, "Thread finished.\n"); */
Packit 875988
      MHD_socket_close_chk_(listen_socket);
Packit 875988
Packit 875988
      if (start_t == (time_t)-1 || end_t == (time_t)-1)
Packit 875988
        {
Packit 875988
          MHD_socket_close_chk_(listen_socket);
Packit 875988
          fprintf (stderr, "Can't get current time\n");
Packit 875988
          return 99;
Packit 875988
        }
Packit 875988
      if (end_t - start_t > 3)
Packit 875988
        result++;
Packit 875988
    }
Packit 875988
Packit 875988
#ifdef MHD_WINSOCK_SOCKETS
Packit 875988
  WSACleanup();
Packit 875988
#endif /* MHD_WINSOCK_SOCKETS */
Packit 875988
Packit 875988
  return must_ignore ? (!result) : (result);
Packit 875988
}