Blame m4/mhd_shutdown_socket_trigger.m4

Packit 875988
# SYNOPSIS
Packit 875988
#
Packit 875988
#   MHD_CHECK_SOCKET_SHUTDOWN_TRIGGER([ACTION-IF-TRIGGER], [ACTION-IF-NOT],
Packit 875988
#                                     [ACTION-IF-UNKNOWN])
Packit 875988
#
Packit 875988
# DESCRIPTION
Packit 875988
#
Packit 875988
#   Check whether shutdown of listen socket triggers waiting select().
Packit 875988
#   If cross-compiling, result may be unknown (third action).
Packit 875988
#   Result is cached in $mhd_cv_host_shtdwn_trgr_select variable.
Packit 875988
#
Packit 875988
# LICENSE
Packit 875988
#
Packit 875988
#   Copyright (c) 2017 Karlson2k (Evgeny Grin) <k2k@narod.ru>
Packit 875988
#
Packit 875988
#   Copying and distribution of this file, with or without modification, are
Packit 875988
#   permitted in any medium without royalty provided the copyright notice
Packit 875988
#   and this notice are preserved. This file is offered as-is, without any
Packit 875988
#   warranty.
Packit 875988
Packit 875988
#serial 2
Packit 875988
Packit 875988
AC_DEFUN([MHD_CHECK_SOCKET_SHUTDOWN_TRIGGER],[dnl
Packit 875988
  AC_PREREQ([2.64])dnl
Packit 875988
  AC_REQUIRE([AC_CANONICAL_HOST])dnl
Packit 875988
  AC_REQUIRE([AC_PROG_CC])dnl
Packit 875988
  AC_REQUIRE([AX_PTHREAD])dnl
Packit 875988
  AC_CHECK_HEADERS([sys/time.h],[AC_CHECK_FUNCS([gettimeofday])],[], [AC_INCLUDES_DEFAULT])
Packit 875988
  AC_CHECK_HEADERS([time.h],[AC_CHECK_FUNCS([[nanosleep]])],[], [AC_INCLUDES_DEFAULT])
Packit 875988
  AC_CHECK_HEADERS([unistd.h],[AC_CHECK_FUNCS([usleep])],[], [AC_INCLUDES_DEFAULT])
Packit 875988
  AC_CHECK_HEADERS([string.h sys/types.h sys/socket.h netinet/in.h time.h sys/select.h netinet/tcp.h],[],[], [AC_INCLUDES_DEFAULT])
Packit 875988
  AC_CACHE_CHECK([[whether shutdown of listen socket trigger select()]],
Packit 875988
    [[mhd_cv_host_shtdwn_trgr_select]], [dnl
Packit 875988
    _MHD_OS_KNOWN_SOCKET_SHUTDOWN_TRIGGER([[mhd_cv_host_shtdwn_trgr_select]])
Packit 875988
    AS_VAR_IF([mhd_cv_host_shtdwn_trgr_select], [["maybe"]],
Packit 875988
      [_MHD_RUN_CHECK_SOCKET_SHUTDOWN_TRIGGER([[mhd_cv_host_shtdwn_trgr_select]])])
Packit 875988
    ]
Packit 875988
  )
Packit 875988
  AS_IF([[test "x$mhd_cv_host_shtdwn_trgr_select" = "xyes"]], [$1],
Packit 875988
    [[test "x$mhd_cv_host_shtdwn_trgr_select" = "xno"]], [$2], [$3])
Packit 875988
  ]
Packit 875988
)
Packit 875988
Packit 875988
#
Packit 875988
# _MHD_OS_KNOWN_SOCKET_SHUTDOWN_TRIGGER(VAR)
Packit 875988
#
Packit 875988
# Sets VAR to 'yes', 'no' or 'maybe'.
Packit 875988
Packit 875988
AC_DEFUN([_MHD_OS_KNOWN_SOCKET_SHUTDOWN_TRIGGER],[dnl
Packit 875988
[#] On Linux shutdown of listen socket always trigger select().
Packit 875988
[#] On Windows select() always ignore shutdown of listen socket.
Packit 875988
[#] On other paltforms result may vary depending on platform version.
Packit 875988
  AS_CASE([[$host_os]],
Packit 875988
    [[linux | linux-* | *-linux | *-linux-*]], [$1='yes'],
Packit 875988
    [[mingw*]], [$1='no'],
Packit 875988
    [[cygwin* | msys*]], [$1='no'],
Packit 875988
    [[winnt* | interix*]], [$1='no'],
Packit 875988
    [[mks]], [$1='no'],
Packit 875988
    [[uwin]], [$1='no'],
Packit 875988
    [$1='maybe']
Packit 875988
  )
Packit 875988
  ]
Packit 875988
)
Packit 875988
Packit 875988
#
Packit 875988
# _MHD_RUN_CHECK_SOCKET_SHUTDOWN_TRIGGER(VAR)
Packit 875988
#
Packit 875988
# Sets VAR to 'yes', 'no' or 'guessing no'.
Packit 875988
Packit 875988
AC_DEFUN([_MHD_RUN_CHECK_SOCKET_SHUTDOWN_TRIGGER],[dnl
Packit 875988
  AC_LANG_PUSH([C])
Packit 875988
  MHD_CST_SAVE_CC="$CC"
Packit 875988
  MHD_CST_SAVE_CFLAGS="$CFLAGS"
Packit 875988
  MHD_CST_SAVE_LIBS="$LIBS"
Packit 875988
  CC="$PTHREAD_CC"
Packit 875988
  CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
Packit 875988
  LIBS="$PTHREAD_LIBS $LIBS"
Packit 875988
  AC_RUN_IFELSE([AC_LANG_SOURCE([[
Packit 875988
#include <stdlib.h>
Packit 875988
Packit 875988
#ifdef HAVE_UNISTD_H
Packit 875988
#  include <unistd.h>
Packit 875988
#endif
Packit 875988
#ifdef HAVE_TIME_H
Packit 875988
#  include <time.h>
Packit 875988
#endif
Packit 875988
#ifdef HAVE_STRING_H
Packit 875988
#  include <string.h>
Packit 875988
#endif
Packit 875988
Packit 875988
#if !defined(_WIN32) || defined(__CYGWIN__)
Packit 875988
#  ifdef HAVE_SYS_TYPES_H
Packit 875988
#    include <sys/types.h>
Packit 875988
#  endif
Packit 875988
#  ifdef HAVE_SYS_SOCKET_H
Packit 875988
#    include <sys/socket.h>
Packit 875988
#  endif
Packit 875988
#  ifdef HAVE_NETINET_IN_H
Packit 875988
#    include <netinet/in.h>
Packit 875988
#  endif
Packit 875988
#  ifdef HAVE_SYS_TIME_H
Packit 875988
#    include <sys/time.h>
Packit 875988
#  endif
Packit 875988
#  ifdef HAVE_SYS_SELECT_H
Packit 875988
#    include <sys/select.h>
Packit 875988
#  endif
Packit 875988
#  ifdef HAVE_NETINET_TCP_H
Packit 875988
#    include <netinet/tcp.h>
Packit 875988
#  endif
Packit 875988
   typedef int MHD_socket;
Packit 875988
#  define MHD_INVALID_SOCKET (-1)
Packit 875988
#  define MHD_POSIX_SOCKETS 1
Packit 875988
#else
Packit 875988
#  include <winsock2.h>
Packit 875988
#  include <ws2tcpip.h>
Packit 875988
#  include <windows.h>
Packit 875988
   typedef SOCKET MHD_socket;
Packit 875988
#  define MHD_INVALID_SOCKET (INVALID_SOCKET)
Packit 875988
#  define MHD_WINSOCK_SOCKETS 1
Packit 875988
#endif
Packit 875988
Packit 875988
#include <pthread.h>
Packit 875988
Packit 875988
   #ifndef SHUT_RD
Packit 875988
#  define SHUT_RD 0
Packit 875988
#endif
Packit 875988
#ifndef SHUT_WR
Packit 875988
#  define SHUT_WR 1
Packit 875988
#endif
Packit 875988
#ifndef SHUT_RDWR
Packit 875988
#  define SHUT_RDWR 2
Packit 875988
#endif
Packit 875988
Packit 875988
#ifndef NULL
Packit 875988
#  define NULL ((void*)0)
Packit 875988
#endif
Packit 875988
Packit 875988
#ifdef HAVE_GETTIMEOFDAY
Packit 875988
#  if defined(_WIN32) && !defined(__CYGWIN__)
Packit 875988
#    undef HAVE_GETTIMEOFDAY
Packit 875988
#  endif
Packit 875988
#endif
Packit 875988
Packit 875988
Packit 875988
#ifdef HAVE_NANOSLEEP
Packit 875988
static const struct timespec sm_tmout = {0, 1000};
Packit 875988
#  define short_sleep() nanosleep(&sm_tmout, NULL)
Packit 875988
#elif defined(HAVE_USLEEP)
Packit 875988
#  define short_sleep() usleep(1)
Packit 875988
#else
Packit 875988
#  define short_sleep() (void)0
Packit 875988
#endif
Packit 875988
Packit 875988
static volatile int going_select = 0;
Packit 875988
static volatile int select_ends = 0;
Packit 875988
static volatile int gerror = 0;
Packit 875988
static int timeout_mils;
Packit 875988
Packit 875988
#ifndef HAVE_GETTIMEOFDAY
Packit 875988
static volatile long long select_elapsed_time = 0;
Packit 875988
Packit 875988
static long long time_chk(void)
Packit 875988
{
Packit 875988
  long long ret = time(NULL);
Packit 875988
  if (-1 == ret)
Packit 875988
    gerror = 4;
Packit 875988
  return ret;
Packit 875988
}
Packit 875988
#endif
Packit 875988
Packit 875988
Packit 875988
static void* select_thrd_func(void* param)
Packit 875988
{
Packit 875988
#ifndef HAVE_GETTIMEOFDAY
Packit 875988
  long long start, stop;
Packit 875988
#endif
Packit 875988
  fd_set rs;
Packit 875988
  struct timeval tmot = {0, 0};
Packit 875988
  MHD_socket fd = *((MHD_socket*)param);
Packit 875988
Packit 875988
  FD_ZERO(&rs);
Packit 875988
  FD_SET(fd, &rs);
Packit 875988
  tmot.tv_usec = timeout_mils * 1000;
Packit 875988
#ifndef HAVE_GETTIMEOFDAY
Packit 875988
  start = time_chk();
Packit 875988
#endif
Packit 875988
  going_select = 1;
Packit 875988
  if (0 > select ((int)(fd) + 1, &rs, NULL, NULL, &tmot))
Packit 875988
    gerror = 5;
Packit 875988
#ifndef HAVE_GETTIMEOFDAY
Packit 875988
  stop = time_chk();
Packit 875988
  select_elapsed_time = stop - start;
Packit 875988
#endif
Packit 875988
  select_ends = 1;
Packit 875988
  return NULL;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
static MHD_socket create_socket(void)
Packit 875988
{ return socket (AF_INET, SOCK_STREAM, 0); }
Packit 875988
Packit 875988
static void close_socket(MHD_socket fd)
Packit 875988
{
Packit 875988
#ifdef MHD_POSIX_SOCKETS
Packit 875988
  close(fd);
Packit 875988
#else
Packit 875988
  closesocket(fd);
Packit 875988
#endif
Packit 875988
}
Packit 875988
Packit 875988
static MHD_socket
Packit 875988
create_socket_listen(int port)
Packit 875988
{
Packit 875988
  MHD_socket fd;
Packit 875988
  struct sockaddr_in sock_addr;
Packit 875988
  fd = create_socket();
Packit 875988
  if (MHD_INVALID_SOCKET == fd)
Packit 875988
    return fd;
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(port);
Packit 875988
  sock_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
Packit 875988
Packit 875988
  if (bind (fd, (const struct sockaddr*) &sock_addr, sizeof(sock_addr)) < 0 ||
Packit 875988
      listen(fd, SOMAXCONN) < 0)
Packit 875988
    {
Packit 875988
      close_socket(fd);
Packit 875988
      return MHD_INVALID_SOCKET;
Packit 875988
    }
Packit 875988
  return fd;
Packit 875988
}
Packit 875988
Packit 875988
#ifdef HAVE_GETTIMEOFDAY
Packit 875988
#define diff_time(tv1, tv2) ((long long)(tv1.tv_sec-tv2.tv_sec)*10000 + (long long)(tv1.tv_usec-tv2.tv_usec)/100)
Packit 875988
#else
Packit 875988
#define diff_time(tv1, tv2) ((long long)(tv1-tv2))
Packit 875988
#endif
Packit 875988
Packit 875988
static long long test_run_select(int timeout_millsec, int use_shutdown, long long delay_before_shutdown)
Packit 875988
{
Packit 875988
  pthread_t select_thrd;
Packit 875988
  MHD_socket fd;
Packit 875988
#ifdef HAVE_GETTIMEOFDAY
Packit 875988
  struct timeval start, stop;
Packit 875988
#else
Packit 875988
  long long start;
Packit 875988
#endif
Packit 875988
Packit 875988
  fd = create_socket_listen(0);
Packit 875988
  if (MHD_INVALID_SOCKET == fd)
Packit 875988
    return -7;
Packit 875988
  going_select = 0;
Packit 875988
  select_ends = 0;
Packit 875988
  gerror = 0;
Packit 875988
  timeout_mils = timeout_millsec;
Packit 875988
  if (0 != pthread_create (&select_thrd, NULL, select_thrd_func, (void*)&fd))
Packit 875988
    return -8;
Packit 875988
  while (!going_select) {short_sleep();}
Packit 875988
#ifdef HAVE_GETTIMEOFDAY
Packit 875988
  gettimeofday (&start, NULL);
Packit 875988
#else
Packit 875988
  start = time_chk();
Packit 875988
#endif
Packit 875988
  if (use_shutdown)
Packit 875988
    {
Packit 875988
#ifdef HAVE_GETTIMEOFDAY
Packit 875988
      struct timeval current;
Packit 875988
      do {short_sleep(); gettimeofday(&current, NULL); } while (delay_before_shutdown > diff_time(current, start));
Packit 875988
#else
Packit 875988
      while (delay_before_shutdown > time_chk() - start) {short_sleep();}
Packit 875988
#endif
Packit 875988
      shutdown(fd, SHUT_RDWR);
Packit 875988
    }
Packit 875988
#ifdef HAVE_GETTIMEOFDAY
Packit 875988
  while (!select_ends) {short_sleep();}
Packit 875988
  gettimeofday (&stop, NULL);
Packit 875988
#endif
Packit 875988
  if (0 != pthread_join(select_thrd, NULL))
Packit 875988
    return -9;
Packit 875988
  close_socket(fd);
Packit 875988
  if (gerror)
Packit 875988
    return -10;
Packit 875988
#ifdef HAVE_GETTIMEOFDAY
Packit 875988
  return (long long)diff_time(stop, start);
Packit 875988
#else
Packit 875988
  return select_elapsed_time;
Packit 875988
#endif
Packit 875988
}
Packit 875988
Packit 875988
static int test_it(void)
Packit 875988
{
Packit 875988
  long long duration2;
Packit 875988
#ifdef HAVE_GETTIMEOFDAY
Packit 875988
  long long duration0, duration1;
Packit 875988
  duration0 = test_run_select(0, 0, 0);
Packit 875988
  if (0 > duration0)
Packit 875988
    return -duration0;
Packit 875988
Packit 875988
  duration1 = test_run_select(50, 0, 0);
Packit 875988
  if (0 > duration1)
Packit 875988
    return -duration1 + 20;
Packit 875988
Packit 875988
  duration2 = test_run_select(500, 1, (duration0 + duration1) / 2);
Packit 875988
  if (0 > duration2)
Packit 875988
    return -duration2 + 40;
Packit 875988
Packit 875988
  if (duration1 * 2 > duration2)
Packit 875988
    { /* Check second time to be sure. */
Packit 875988
      duration2 = test_run_select(500, 1, (duration0 + duration1) / 2);
Packit 875988
      if (0 > duration2)
Packit 875988
        return -duration2 + 60;
Packit 875988
      if (duration1 * 2 > duration2)
Packit 875988
        return 0;
Packit 875988
    }
Packit 875988
#else
Packit 875988
  duration2 = test_run_select(5000, 1, 2);
Packit 875988
  if (0 > duration2)
Packit 875988
    return -duration2 + 80;
Packit 875988
Packit 875988
  if (4 > duration2)
Packit 875988
    { /* Check second time to be sure. */
Packit 875988
      duration2 = test_run_select(5000, 1, 2);
Packit 875988
      if (0 > duration2)
Packit 875988
      return -duration2 + 100;
Packit 875988
      if (4 > duration2)
Packit 875988
        return 0;
Packit 875988
    }
Packit 875988
#endif
Packit 875988
  return 1;
Packit 875988
}
Packit 875988
Packit 875988
Packit 875988
static int init(void)
Packit 875988
{
Packit 875988
#ifdef MHD_WINSOCK_SOCKETS
Packit 875988
  WSADATA wsa_data;
Packit 875988
Packit 875988
  if (0 != WSAStartup(MAKEWORD(2, 2), &wsa_data) || MAKEWORD(2, 2) != wsa_data.wVersion)
Packit 875988
    {
Packit 875988
      WSACleanup();
Packit 875988
      return 0;
Packit 875988
    }
Packit 875988
#endif /* MHD_WINSOCK_SOCKETS */
Packit 875988
  return 1;
Packit 875988
}
Packit 875988
Packit 875988
static void cleanup(void)
Packit 875988
{
Packit 875988
#ifdef MHD_WINSOCK_SOCKETS
Packit 875988
  WSACleanup();
Packit 875988
#endif /* MHD_WINSOCK_SOCKETS */
Packit 875988
}
Packit 875988
Packit 875988
int main(void)
Packit 875988
{
Packit 875988
  int res;
Packit 875988
  if (!init())
Packit 875988
    return 19;
Packit 875988
Packit 875988
  res = test_it();
Packit 875988
Packit 875988
  cleanup();
Packit 875988
  if (gerror)
Packit 875988
    return gerror;
Packit 875988
Packit 875988
  return res;
Packit 875988
}
Packit 875988
]])], [$1='yes'], [$1='no'], [$1='guessing no'])
Packit 875988
  CC="$MHD_CST_SAVE_CC"
Packit 875988
  CFLAGS="$MHD_CST_SAVE_CFLAGS"
Packit 875988
  LIBS="$MHD_CST_SAVE_LIBS"
Packit 875988
  AS_UNSET([[MHD_CST_SAVE_CC]])
Packit 875988
  AS_UNSET([[MHD_CST_SAVE_CFLAGS]])
Packit 875988
  AS_UNSET([[MHD_CST_SAVE_LIBS]])
Packit 875988
  AC_LANG_POP([C])
Packit 875988
  ]
Packit 875988
)