mhd_shutdown_socket_trigger.m4 8.8 KB

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