2
0

mhd_shutdown_socket_trigger.m4 9.1 KB

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