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