mhd_shutdown_socket_trigger.m4 9.0 KB

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