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(¤t, 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 )