2
0

test_shutdown_select.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. /*
  2. This file is part of libmicrohttpd
  3. Copyright (C) 2016 Karlson2k (Evgeny Grin)
  4. libmicrohttpd is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. option) any later version.
  8. libmicrohttpd is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with libmicrohttpd; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  15. Boston, MA 02110-1301, USA.
  16. */
  17. /**
  18. * @file microhttpd/test_shutdown_select.c
  19. * @brief Test whether shutdown socket triggers select()/poll()
  20. * @details On some platforms shutting down the socket in one thread
  21. * trigger select() or poll() waiting for this socket in
  22. * other thread. libmicrohttpd depend on this behavior on
  23. * those platforms. This program check whether select()
  24. * and poll() (if available) works as expected.
  25. * @author Karlson2k (Evgeny Grin)
  26. */
  27. #include "MHD_config.h"
  28. #include "platform.h"
  29. #include "mhd_sockets.h"
  30. #include <stdlib.h>
  31. #include <stdio.h>
  32. #ifdef HAVE_UNISTD_H
  33. #include <unistd.h>
  34. #endif /* HAVE_UNISTD_H */
  35. #ifdef HAVE_TIME_H
  36. #include <time.h>
  37. #endif /* HAVE_TIME_H */
  38. #if defined(MHD_USE_POSIX_THREADS)
  39. #include <pthread.h>
  40. #endif /* MHD_USE_POSIX_THREADS */
  41. #if defined(MHD_WINSOCK_SOCKETS)
  42. #include <winsock2.h>
  43. #include <windows.h>
  44. #define sock_errno (WSAGetLastError())
  45. #elif defined(MHD_POSIX_SOCKETS)
  46. #ifdef HAVE_SYS_TYPES_H
  47. #include <sys/types.h>
  48. #endif /* HAVE_SYS_TYPES_H */
  49. #ifdef HAVE_SYS_SOCKET_H
  50. #include <sys/socket.h>
  51. #endif /* HAVE_SYS_SOCKET_H */
  52. #ifdef HAVE_NETINET_IN_H
  53. #include <netinet/in.h>
  54. #endif /* HAVE_NETINET_IN_H */
  55. #ifdef HAVE_ARPA_INET_H
  56. #include <arpa/inet.h>
  57. #endif /* HAVE_ARPA_INET_H */
  58. #ifdef HAVE_SYS_SELECT_H
  59. #include <sys/select.h>
  60. #endif /* HAVE_SYS_SELECT_H */
  61. #if defined(HAVE_POLL) && defined(HAVE_POLL_H)
  62. #include <poll.h>
  63. #endif /* HAVE_POLL && HAVE_POLL_H */
  64. #define sock_errno (errno)
  65. #endif /* MHD_POSIX_SOCKETS */
  66. #ifdef HAVE_STDBOOL_H
  67. #include <stdbool.h>
  68. #endif /* HAVE_STDBOOL_H */
  69. #include "mhd_threads.h"
  70. #ifndef SOMAXCONN
  71. #define SOMAXCONN 511
  72. #endif /* ! SOMAXCONN */
  73. #if !defined(SHUT_RDWR) && defined(SD_BOTH)
  74. #define SHUT_RDWR SD_BOTH
  75. #endif
  76. static _MHD_bool check_err;
  77. static _MHD_bool
  78. has_in_name(const char *prog_name, const char *marker)
  79. {
  80. size_t name_pos;
  81. size_t pos;
  82. if (!prog_name || !marker)
  83. return 0;
  84. pos = 0;
  85. name_pos = 0;
  86. while (prog_name[pos])
  87. {
  88. if ('/' == prog_name[pos])
  89. name_pos = pos + 1;
  90. #ifdef _WIN32
  91. else if ('\\' == prog_name[pos])
  92. name_pos = pos + 1;
  93. #endif /* _WIN32 */
  94. pos++;
  95. }
  96. if (name_pos == pos)
  97. return !0;
  98. return strstr(prog_name + name_pos, marker) != NULL;
  99. }
  100. static MHD_socket
  101. start_socket_listen(int domain)
  102. {
  103. /* Create sockets similarly to daemon.c */
  104. MHD_socket fd;
  105. int cloexec_set;
  106. struct sockaddr_in sock_addr;
  107. socklen_t addrlen;
  108. #ifdef MHD_WINSOCK_SOCKETS
  109. unsigned long flags = 1;
  110. #else /* MHD_POSIX_SOCKETS */
  111. int flags;
  112. #endif /* MHD_POSIX_SOCKETS */
  113. #if defined(MHD_POSIX_SOCKETS) && defined(SOCK_CLOEXEC)
  114. fd = socket (domain, SOCK_STREAM | SOCK_CLOEXEC, 0);
  115. cloexec_set = 1;
  116. #elif defined(MHD_WINSOCK_SOCKETS) && defined (WSA_FLAG_NO_HANDLE_INHERIT)
  117. fd = WSASocketW (domain, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_NO_HANDLE_INHERIT);
  118. cloexec_set = 1;
  119. #else /* !SOCK_CLOEXEC */
  120. fd = socket (domain, SOCK_STREAM, 0);
  121. cloexec_set = 0;
  122. #endif /* !SOCK_CLOEXEC */
  123. if ( (MHD_INVALID_SOCKET == fd) && (cloexec_set) )
  124. {
  125. fd = socket (domain, SOCK_STREAM, 0);
  126. cloexec_set = 0;
  127. }
  128. if (MHD_INVALID_SOCKET == fd)
  129. {
  130. fprintf (stderr, "Can't create socket: %u\n",
  131. (unsigned)sock_errno);
  132. return MHD_INVALID_SOCKET;
  133. }
  134. if (!cloexec_set)
  135. {
  136. #ifdef MHD_WINSOCK_SOCKETS
  137. if (!SetHandleInformation ((HANDLE)fd, HANDLE_FLAG_INHERIT, 0))
  138. fprintf (stderr, "Failed to make socket non-inheritable: %u\n",
  139. (unsigned int)GetLastError ());
  140. #else /* MHD_POSIX_SOCKETS */
  141. flags = fcntl (fd, F_GETFD);
  142. if ( ( (-1 == flags) ||
  143. ( (flags != (flags | FD_CLOEXEC)) &&
  144. (0 != fcntl (fd, F_SETFD, flags | FD_CLOEXEC)) ) ) )
  145. fprintf (stderr, "Failed to make socket non-inheritable: %s\n",
  146. MHD_socket_last_strerr_ ());
  147. #endif /* MHD_POSIX_SOCKETS */
  148. }
  149. memset (&sock_addr, 0, sizeof (struct sockaddr_in));
  150. sock_addr.sin_family = AF_INET;
  151. sock_addr.sin_port = htons (0);
  152. #if HAVE_SOCKADDR_IN_SIN_LEN
  153. sock_addr.sin_len = sizeof (struct sockaddr_in);
  154. #endif
  155. addrlen = sizeof (struct sockaddr_in);
  156. if (bind (fd, (const struct sockaddr*) &sock_addr, addrlen) < 0)
  157. {
  158. fprintf (stderr, "Failed to bind socket: %u\n",
  159. (unsigned)sock_errno);
  160. MHD_socket_close_chk_ (fd);
  161. return MHD_INVALID_SOCKET;
  162. }
  163. #ifdef MHD_WINSOCK_SOCKETS
  164. if (0 != ioctlsocket (fd, FIONBIO, &flags))
  165. {
  166. fprintf (stderr, "Failed to make socket non-blocking: %u\n",
  167. (unsigned)sock_errno);
  168. MHD_socket_close_chk_ (fd);
  169. return MHD_INVALID_SOCKET;
  170. }
  171. #else /* MHD_POSIX_SOCKETS */
  172. flags = fcntl (fd, F_GETFL);
  173. if ( ( (-1 == flags) ||
  174. ( (flags != (flags | O_NONBLOCK)) &&
  175. (0 != fcntl (fd, F_SETFL, flags | O_NONBLOCK)) ) ) )
  176. {
  177. fprintf (stderr, "Failed to make socket non-blocking: %s\n",
  178. MHD_socket_last_strerr_ ());
  179. MHD_socket_close_chk_ (fd);
  180. return MHD_INVALID_SOCKET;
  181. }
  182. #endif /* MHD_POSIX_SOCKETS */
  183. if (listen(fd, SOMAXCONN) < 0)
  184. {
  185. fprintf (stderr, "Failed to listen on socket: %u\n",
  186. (unsigned)sock_errno);
  187. MHD_socket_close_chk_ (fd);
  188. return MHD_INVALID_SOCKET;
  189. }
  190. return fd;
  191. }
  192. MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
  193. select_thread(void* data)
  194. {
  195. /* use select() like in daemon.c */
  196. MHD_socket listen_sock = *((MHD_socket*)data);
  197. fd_set rs, ws;
  198. struct timeval timeout;
  199. FD_ZERO(&rs);
  200. FD_ZERO(&ws);
  201. FD_SET(listen_sock, &rs);
  202. timeout.tv_usec = 0;
  203. timeout.tv_sec = 7;
  204. check_err = (0 > MHD_SYS_select_(listen_sock + 1, &rs, &ws, NULL, &timeout));
  205. return (MHD_THRD_RTRN_TYPE_)0;
  206. }
  207. #ifdef HAVE_POLL
  208. MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
  209. poll_thread(void* data)
  210. {
  211. /* use poll() like in daemon.c */
  212. struct pollfd p[1];
  213. MHD_socket listen_sock = *((MHD_socket*)data);
  214. p[0].fd = listen_sock;
  215. p[0].events = POLLIN;
  216. p[0].revents = 0;
  217. check_err = (0 > MHD_sys_poll_ (p, 1, 7000));
  218. return (MHD_THRD_RTRN_TYPE_)0;
  219. }
  220. #endif /* HAVE_POLL */
  221. static void
  222. local_sleep(unsigned seconds)
  223. {
  224. #if defined(_WIN32) && !defined(__CYGWIN__)
  225. Sleep(seconds * 1000);
  226. #else
  227. unsigned seconds_left = seconds;
  228. do
  229. {
  230. seconds_left = sleep(seconds_left);
  231. } while (seconds_left > 0);
  232. #endif
  233. }
  234. int
  235. main (int argc, char *const *argv)
  236. {
  237. int i;
  238. time_t start_t, end_t;
  239. int result = 0;
  240. MHD_THRD_RTRN_TYPE_ (MHD_THRD_CALL_SPEC_ *test_func)(void* data);
  241. #ifdef MHD_WINSOCK_SOCKETS
  242. WORD ver_req;
  243. WSADATA wsa_data;
  244. int err;
  245. #endif /* MHD_WINSOCK_SOCKETS */
  246. _MHD_bool test_poll;
  247. test_poll = has_in_name(argv[0], "_poll");
  248. if (!test_poll)
  249. test_func = &select_thread;
  250. else
  251. {
  252. #ifndef HAVE_POLL
  253. return 77;
  254. #else /* ! HAVE_POLL */
  255. test_func = &poll_thread;
  256. #endif /* ! HAVE_POLL */
  257. }
  258. #ifdef MHD_WINSOCK_SOCKETS
  259. ver_req = MAKEWORD(2, 2);
  260. err = WSAStartup(ver_req, &wsa_data);
  261. if (err != 0 || MAKEWORD(2, 2) != wsa_data.wVersion)
  262. {
  263. printf("WSAStartup() failed\n");
  264. WSACleanup();
  265. return 99;
  266. }
  267. #endif /* MHD_WINSOCK_SOCKETS */
  268. /* try several times to ensure that accidental incoming connection
  269. * didn't interfere with test results
  270. */
  271. for (i = 0; i < 5 && result == 0; i++)
  272. {
  273. MHD_thread_handle_ sel_thrd;
  274. /* fprintf(stdout, "Creating, binding and listening socket...\n"); */
  275. MHD_socket listen_socket = start_socket_listen (AF_INET);
  276. if (MHD_INVALID_SOCKET == listen_socket)
  277. return 99;
  278. check_err = !0;
  279. /* fprintf (stdout, "Starting select() thread...\n"); */
  280. #if defined(MHD_USE_POSIX_THREADS)
  281. if (0 != pthread_create (&sel_thrd, NULL, test_func, &listen_socket))
  282. {
  283. MHD_socket_close_chk_ (listen_socket);
  284. fprintf (stderr, "Can't start thread\n");
  285. return 99;
  286. }
  287. #elif defined(MHD_USE_W32_THREADS)
  288. sel_thrd = (HANDLE)_beginthreadex (NULL, 0, test_func, &listen_socket, 0, NULL);
  289. if (0 == (sel_thrd))
  290. {
  291. MHD_socket_close_chk_ (listen_socket);
  292. fprintf (stderr, "Can't start select() thread\n");
  293. return 99;
  294. }
  295. #else
  296. #error No threading lib available
  297. #endif
  298. /* fprintf (stdout, "Waiting...\n"); */
  299. local_sleep(1); /* make sure that select() is started */
  300. /* fprintf (stdout, "Shutting down socket...\n"); */
  301. start_t = time (NULL);
  302. shutdown (listen_socket, SHUT_RDWR);
  303. /* fprintf (stdout, "Waiting for thread to finish...\n"); */
  304. if (!MHD_join_thread_(sel_thrd))
  305. {
  306. MHD_socket_close_chk_(listen_socket);
  307. fprintf (stderr, "Can't join select() thread\n");
  308. return 99;
  309. }
  310. if (check_err)
  311. {
  312. MHD_socket_close_chk_(listen_socket);
  313. fprintf (stderr, "Error in waiting thread\n");
  314. return 99;
  315. }
  316. end_t = time (NULL);
  317. /* fprintf (stdout, "Thread finished.\n"); */
  318. MHD_socket_close_chk_(listen_socket);
  319. if (start_t == (time_t)-1 || end_t == (time_t)-1)
  320. {
  321. MHD_socket_close_chk_(listen_socket);
  322. fprintf (stderr, "Can't get current time\n");
  323. return 99;
  324. }
  325. if (end_t - start_t > 3)
  326. result++;
  327. }
  328. #ifdef MHD_WINSOCK_SOCKETS
  329. WSACleanup();
  330. #endif /* MHD_WINSOCK_SOCKETS */
  331. return result;
  332. }