libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

mhd_shutdown_socket_trigger.m4 (9083B)


      1 # SPDX-License-Identifier: FSFAP
      2 #
      3 # SYNOPSIS
      4 #
      5 #   MHD_CHECK_SOCKET_SHUTDOWN_TRIGGER([ACTION-IF-TRIGGER], [ACTION-IF-NOT],
      6 #                                     [ACTION-IF-UNKNOWN])
      7 #
      8 # DESCRIPTION
      9 #
     10 #   Check whether shutdown of listen socket triggers waiting select().
     11 #   If cross-compiling, result may be unknown (third action).
     12 #   Result is cached in $mhd_cv_host_shtdwn_trgr_select variable.
     13 #
     14 # LICENSE
     15 #
     16 #   Copyright (c) 2017-2023 Karlson2k (Evgeny Grin) <k2k@narod.ru>
     17 #
     18 #   Copying and distribution of this file, with or without modification, are
     19 #   permitted in any medium without royalty provided the copyright notice
     20 #   and this notice are preserved. This file is offered as-is, without any
     21 #   warranty.
     22 
     23 #serial 6
     24 
     25 AC_DEFUN([MHD_CHECK_SOCKET_SHUTDOWN_TRIGGER],[dnl
     26   AC_PREREQ([2.64])dnl
     27   AC_REQUIRE([AC_CANONICAL_HOST])dnl
     28   AC_REQUIRE([AC_PROG_CC])dnl
     29   AC_REQUIRE([AX_PTHREAD])dnl
     30   AC_REQUIRE([MHD_CHECK_FUNC_GETTIMEOFDAY])dnl
     31   MHD_CHECK_FUNC([[usleep]], [[#include <unistd.h>]], [[usleep(100000);]])
     32   MHD_CHECK_FUNC([[nanosleep]], [[#include <time.h>]], [[struct timespec ts2, ts1 = {0, 0}; nanosleep(&ts1, &ts2);]])
     33   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])
     34   AC_CACHE_CHECK([[whether shutdown of listen socket triggers select()]],
     35     [[mhd_cv_host_shtdwn_trgr_select]], [dnl
     36     _MHD_OS_KNOWN_SOCKET_SHUTDOWN_TRIGGER([[mhd_cv_host_shtdwn_trgr_select]])
     37     AS_VAR_IF([mhd_cv_host_shtdwn_trgr_select], [["maybe"]],
     38       [_MHD_RUN_CHECK_SOCKET_SHUTDOWN_TRIGGER([[mhd_cv_host_shtdwn_trgr_select]])])
     39     ]
     40   )
     41   AS_IF([[test "x$mhd_cv_host_shtdwn_trgr_select" = "xyes"]], [$1],
     42     [[test "x$mhd_cv_host_shtdwn_trgr_select" = "xno"]], [$2], [$3])
     43   ]
     44 )
     45 
     46 #
     47 # _MHD_OS_KNOWN_SOCKET_SHUTDOWN_TRIGGER(VAR)
     48 #
     49 # Sets VAR to 'yes', 'no' or 'maybe'.
     50 
     51 AC_DEFUN([_MHD_OS_KNOWN_SOCKET_SHUTDOWN_TRIGGER],[dnl
     52 [#] On Linux shutdown of listen socket always trigger select().
     53 [#] On Windows select() always ignore shutdown of listen socket.
     54 [#] On other paltforms result may vary depending on platform version.
     55   AS_CASE([[$host_os]],
     56     [[linux | linux-* | *-linux | *-linux-*]], [$1='yes'],
     57     [[mingw*]], [$1='no'],
     58     [[cygwin* | msys*]], [$1='no'],
     59     [[winnt* | interix*]], [$1='no'],
     60     [[mks]], [$1='no'],
     61     [[uwin]], [$1='no'],
     62     [$1='maybe']
     63   )
     64   ]
     65 )
     66 
     67 #
     68 # _MHD_RUN_CHECK_SOCKET_SHUTDOWN_TRIGGER(VAR)
     69 #
     70 # Sets VAR to 'yes', 'no' or 'guessing no'.
     71 
     72 AC_DEFUN([_MHD_RUN_CHECK_SOCKET_SHUTDOWN_TRIGGER],[dnl
     73   AC_LANG_PUSH([C])
     74   MHD_CST_SAVE_CC="$CC"
     75   MHD_CST_SAVE_CFLAGS="$CFLAGS"
     76   MHD_CST_SAVE_LIBS="$LIBS"
     77   CC="$PTHREAD_CC"
     78   CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
     79   LIBS="$PTHREAD_LIBS $LIBS"
     80   AC_RUN_IFELSE([AC_LANG_SOURCE([[
     81 #include <stdlib.h>
     82 
     83 #ifdef HAVE_UNISTD_H
     84 #  include <unistd.h>
     85 #endif
     86 #ifdef HAVE_TIME_H
     87 #  include <time.h>
     88 #endif
     89 #ifdef HAVE_STRING_H
     90 #  include <string.h>
     91 #endif
     92 
     93 #if !defined(_WIN32) || defined(__CYGWIN__)
     94 #  ifdef HAVE_SYS_TYPES_H
     95 #    include <sys/types.h>
     96 #  endif
     97 #  ifdef HAVE_SYS_SOCKET_H
     98 #    include <sys/socket.h>
     99 #  endif
    100 #  ifdef HAVE_NETINET_IN_H
    101 #    include <netinet/in.h>
    102 #  endif
    103 #  ifdef HAVE_SYS_TIME_H
    104 #    include <sys/time.h>
    105 #  endif
    106 #  ifdef HAVE_SYS_SELECT_H
    107 #    include <sys/select.h>
    108 #  endif
    109 #  ifdef HAVE_NETINET_TCP_H
    110 #    include <netinet/tcp.h>
    111 #  endif
    112    typedef int MHD_Socket;
    113 #  define MHD_INVALID_SOCKET (-1)
    114 #  define MHD_SOCKETS_KIND_POSIX 1
    115 #else
    116 #  include <winsock2.h>
    117 #  include <ws2tcpip.h>
    118 #  include <windows.h>
    119    typedef SOCKET MHD_Socket;
    120 #  define MHD_INVALID_SOCKET (INVALID_SOCKET)
    121 #  define MHD_SOCKETS_KIND_WINSOCK 1
    122 #endif
    123 
    124 #include <pthread.h>
    125 
    126 #ifndef SHUT_RD
    127 #  define SHUT_RD 0
    128 #endif
    129 #ifndef SHUT_WR
    130 #  define SHUT_WR 1
    131 #endif
    132 #ifndef SHUT_RDWR
    133 #  define SHUT_RDWR 2
    134 #endif
    135 
    136 #ifndef NULL
    137 #  define NULL ((void*)0)
    138 #endif
    139 
    140 #ifdef HAVE_GETTIMEOFDAY
    141 #  if defined(_WIN32) && !defined(__CYGWIN__)
    142 #    undef HAVE_GETTIMEOFDAY
    143 #  endif
    144 #endif
    145 
    146 
    147 #ifdef HAVE_NANOSLEEP
    148 static const struct timespec sm_tmout = {0, 1000};
    149 #  define short_sleep() nanosleep(&sm_tmout, NULL)
    150 #elif defined(HAVE_USLEEP)
    151 #  define short_sleep() usleep(1)
    152 #else
    153 #  define short_sleep() (void)0
    154 #endif
    155 
    156 static volatile int going_select = 0;
    157 static volatile int select_ends = 0;
    158 static volatile int gerror = 0;
    159 static int timeout_mils;
    160 
    161 #ifndef HAVE_GETTIMEOFDAY
    162 static volatile long long select_elapsed_time = 0;
    163 
    164 static long long time_chk(void)
    165 {
    166   long long ret = time(NULL);
    167   if (-1 == ret)
    168     gerror = 4;
    169   return ret;
    170 }
    171 #endif
    172 
    173 
    174 static void* select_thrd_func(void* param)
    175 {
    176 #ifndef HAVE_GETTIMEOFDAY
    177   long long start, stop;
    178 #endif
    179   fd_set rs;
    180   struct timeval tmot = {0, 0};
    181   MHD_Socket fd = *((MHD_Socket*)param);
    182 
    183   FD_ZERO(&rs);
    184   FD_SET(fd, &rs);
    185   tmot.tv_usec = timeout_mils * 1000;
    186 #ifndef HAVE_GETTIMEOFDAY
    187   start = time_chk();
    188 #endif
    189   going_select = 1;
    190   if (0 > select ((int)(fd) + 1, &rs, NULL, NULL, &tmot))
    191     gerror = 5;
    192 #ifndef HAVE_GETTIMEOFDAY
    193   stop = time_chk();
    194   select_elapsed_time = stop - start;
    195 #endif
    196   select_ends = 1;
    197   return NULL;
    198 }
    199 
    200 
    201 static MHD_Socket create_socket(void)
    202 { return socket (AF_INET, SOCK_STREAM, 0); }
    203 
    204 static void close_socket(MHD_Socket fd)
    205 {
    206 #ifdef MHD_SOCKETS_KIND_POSIX
    207   close(fd);
    208 #else
    209   closesocket(fd);
    210 #endif
    211 }
    212 
    213 static MHD_Socket
    214 create_socket_listen(int port)
    215 {
    216   MHD_Socket fd;
    217   struct sockaddr_in sock_addr;
    218   fd = create_socket();
    219   if (MHD_INVALID_SOCKET == fd)
    220     return fd;
    221 
    222   memset (&sock_addr, 0, sizeof (struct sockaddr_in));
    223   sock_addr.sin_family = AF_INET;
    224   sock_addr.sin_port = htons(port);
    225   sock_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    226 
    227   if (bind (fd, (const struct sockaddr*) &sock_addr, sizeof(sock_addr)) < 0 ||
    228       listen(fd, SOMAXCONN) < 0)
    229     {
    230       close_socket(fd);
    231       return MHD_INVALID_SOCKET;
    232     }
    233   return fd;
    234 }
    235 
    236 #ifdef HAVE_GETTIMEOFDAY
    237 #define diff_time(tv1, tv2) ((long long)(tv1.tv_sec-tv2.tv_sec)*10000 + (long long)(tv1.tv_usec-tv2.tv_usec)/100)
    238 #else
    239 #define diff_time(tv1, tv2) ((long long)(tv1-tv2))
    240 #endif
    241 
    242 static long long test_run_select(int timeout_millsec, int use_shutdown, long long delay_before_shutdown)
    243 {
    244   pthread_t select_thrd;
    245   MHD_Socket fd;
    246 #ifdef HAVE_GETTIMEOFDAY
    247   struct timeval start, stop;
    248 #else
    249   long long start;
    250 #endif
    251 
    252   fd = create_socket_listen(0);
    253   if (MHD_INVALID_SOCKET == fd)
    254     return -7;
    255   going_select = 0;
    256   select_ends = 0;
    257   gerror = 0;
    258   timeout_mils = timeout_millsec;
    259   if (0 != pthread_create (&select_thrd, NULL, select_thrd_func, (void*)&fd))
    260     return -8;
    261   while (!going_select) {short_sleep();}
    262 #ifdef HAVE_GETTIMEOFDAY
    263   gettimeofday (&start, NULL);
    264 #else
    265   start = time_chk();
    266 #endif
    267   if (use_shutdown)
    268     {
    269 #ifdef HAVE_GETTIMEOFDAY
    270       struct timeval current;
    271       do {short_sleep(); gettimeofday(&current, NULL); } while (delay_before_shutdown > diff_time(current, start));
    272 #else
    273       while (delay_before_shutdown > time_chk() - start) {short_sleep();}
    274 #endif
    275       shutdown(fd, SHUT_RDWR);
    276     }
    277 #ifdef HAVE_GETTIMEOFDAY
    278   while (!select_ends) {short_sleep();}
    279   gettimeofday (&stop, NULL);
    280 #endif
    281   if (0 != pthread_join(select_thrd, NULL))
    282     return -9;
    283   close_socket(fd);
    284   if (gerror)
    285     return -10;
    286 #ifdef HAVE_GETTIMEOFDAY
    287   return (long long)diff_time(stop, start);
    288 #else
    289   return select_elapsed_time;
    290 #endif
    291 }
    292 
    293 static int test_it(void)
    294 {
    295   long long duration2;
    296 #ifdef HAVE_GETTIMEOFDAY
    297   long long duration0, duration1;
    298   duration0 = test_run_select(0, 0, 0);
    299   if (0 > duration0)
    300     return -duration0;
    301 
    302   duration1 = test_run_select(50, 0, 0);
    303   if (0 > duration1)
    304     return -duration1 + 20;
    305 
    306   duration2 = test_run_select(500, 1, (duration0 + duration1) / 2);
    307   if (0 > duration2)
    308     return -duration2 + 40;
    309 
    310   if (duration1 * 2 > duration2)
    311     { /* Check second time to be sure. */
    312       duration2 = test_run_select(500, 1, (duration0 + duration1) / 2);
    313       if (0 > duration2)
    314         return -duration2 + 60;
    315       if (duration1 * 2 > duration2)
    316         return 0;
    317     }
    318 #else
    319   duration2 = test_run_select(5000, 1, 2);
    320   if (0 > duration2)
    321     return -duration2 + 80;
    322 
    323   if (4 > duration2)
    324     { /* Check second time to be sure. */
    325       duration2 = test_run_select(5000, 1, 2);
    326       if (0 > duration2)
    327       return -duration2 + 100;
    328       if (4 > duration2)
    329         return 0;
    330     }
    331 #endif
    332   return 1;
    333 }
    334 
    335 
    336 static int init(void)
    337 {
    338 #ifdef MHD_SOCKETS_KIND_WINSOCK
    339   WSADATA wsa_data;
    340 
    341   if (0 != WSAStartup(MAKEWORD(2, 2), &wsa_data) || MAKEWORD(2, 2) != wsa_data.wVersion)
    342     {
    343       WSACleanup();
    344       return 0;
    345     }
    346 #endif /* MHD_SOCKETS_KIND_WINSOCK */
    347   return 1;
    348 }
    349 
    350 static void cleanup(void)
    351 {
    352 #ifdef MHD_SOCKETS_KIND_WINSOCK
    353   WSACleanup();
    354 #endif /* MHD_SOCKETS_KIND_WINSOCK */
    355 }
    356 
    357 int main(void)
    358 {
    359   int res;
    360   if (!init())
    361     return 19;
    362 
    363   res = test_it();
    364 
    365   cleanup();
    366   if (gerror)
    367     return gerror;
    368 
    369   return res;
    370 }
    371 ]])], [$1='yes'], [$1='no'], [$1='guessing no'])
    372   CC="$MHD_CST_SAVE_CC"
    373   CFLAGS="$MHD_CST_SAVE_CFLAGS"
    374   LIBS="$MHD_CST_SAVE_LIBS"
    375   AS_UNSET([[MHD_CST_SAVE_CC]])
    376   AS_UNSET([[MHD_CST_SAVE_CFLAGS]])
    377   AS_UNSET([[MHD_CST_SAVE_LIBS]])
    378   AC_LANG_POP([C])
    379   ]
    380 )