libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

mhd_shutdown_socket_trigger.m4 (9013B)


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