diff options
author | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2016-01-25 14:17:43 +0000 |
---|---|---|
committer | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2016-01-25 14:17:43 +0000 |
commit | 22392ce602ac57b6e77b54d246172d002bcf309f (patch) | |
tree | 4d98991327e91d7008118a5a5c97c11be0f2c13f | |
parent | 3baed95b7d44fb7743e211996db98a9aa6dd9780 (diff) | |
download | libmicrohttpd-22392ce602ac57b6e77b54d246172d002bcf309f.tar.gz libmicrohttpd-22392ce602ac57b6e77b54d246172d002bcf309f.zip |
Added test for checking ability of shutdown() on socket to trigger select()
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | configure.ac | 8 | ||||
-rw-r--r-- | src/microhttpd/Makefile.am | 15 | ||||
-rw-r--r-- | src/microhttpd/test_shutdown_select.c | 299 |
4 files changed, 324 insertions, 2 deletions
@@ -1,3 +1,7 @@ | |||
1 | Mon Jan 25 13:45:50 CET 2016 | ||
2 | Added check test for triggering select() on | ||
3 | listen socket. -EG | ||
4 | |||
1 | Thu Jan 21 19:35:18 CET 2016 | 5 | Thu Jan 21 19:35:18 CET 2016 |
2 | Fixed old bug with making sockets non-blocking on | 6 | Fixed old bug with making sockets non-blocking on |
3 | various platforms so now sockets are really | 7 | various platforms so now sockets are really |
diff --git a/configure.ac b/configure.ac index 4af06b92..fa9bf401 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -141,6 +141,7 @@ AC_MSG_RESULT([[$inln_prfx]]) | |||
141 | CFLAGS="$save_CFLAGS" | 141 | CFLAGS="$save_CFLAGS" |
142 | 142 | ||
143 | # Check system type | 143 | # Check system type |
144 | shutdown_trig_select='no' | ||
144 | AC_MSG_CHECKING([[for target host OS]]) | 145 | AC_MSG_CHECKING([[for target host OS]]) |
145 | case "$host_os" in | 146 | case "$host_os" in |
146 | *darwin* | *rhapsody* | *macosx*) | 147 | *darwin* | *rhapsody* | *macosx*) |
@@ -177,14 +178,14 @@ netbsd*) | |||
177 | ;; | 178 | ;; |
178 | *arm-linux*) | 179 | *arm-linux*) |
179 | AC_DEFINE_UNQUOTED(LINUX,1,[This is a Linux kernel]) | 180 | AC_DEFINE_UNQUOTED(LINUX,1,[This is a Linux kernel]) |
180 | AC_DEFINE_UNQUOTED(HAVE_LISTEN_SHUTDOWN,1,[can use shutdown on listen sockets]) | 181 | shutdown_trig_select='yes' |
181 | mhd_host_os='ARM Linux' | 182 | mhd_host_os='ARM Linux' |
182 | AC_MSG_RESULT([[$mhd_host_os]]) | 183 | AC_MSG_RESULT([[$mhd_host_os]]) |
183 | CFLAGS="-fPIC -pipe $CFLAGS" | 184 | CFLAGS="-fPIC -pipe $CFLAGS" |
184 | ;; | 185 | ;; |
185 | *linux*) | 186 | *linux*) |
186 | AC_DEFINE_UNQUOTED(LINUX,1,[This is a Linux kernel]) | 187 | AC_DEFINE_UNQUOTED(LINUX,1,[This is a Linux kernel]) |
187 | AC_DEFINE_UNQUOTED(HAVE_LISTEN_SHUTDOWN,1,[can use shutdown on listen sockets]) | 188 | shutdown_trig_select='yes' |
188 | mhd_host_os='Linux' | 189 | mhd_host_os='Linux' |
189 | AC_MSG_RESULT([[$mhd_host_os]]) | 190 | AC_MSG_RESULT([[$mhd_host_os]]) |
190 | ;; | 191 | ;; |
@@ -233,6 +234,9 @@ netbsd*) | |||
233 | ;; | 234 | ;; |
234 | esac | 235 | esac |
235 | 236 | ||
237 | AM_CONDITIONAL([HAVE_LISTEN_SHUTDOWN], [test "x$shutdown_trig_select" = "xyes"]) | ||
238 | AS_IF([test "x$shutdown_trig_select" = "xyes"], [AC_DEFINE([HAVE_LISTEN_SHUTDOWN],[1],[can use shutdown on listen sockets])]) | ||
239 | |||
236 | AC_ARG_WITH([threads], | 240 | AC_ARG_WITH([threads], |
237 | [AS_HELP_STRING([--with-threads=LIB],[choose threading library (posix, w32, auto) [auto]])], | 241 | [AS_HELP_STRING([--with-threads=LIB],[choose threading library (posix, w32, auto) [auto]])], |
238 | [], [with_threads='auto']) | 242 | [], [with_threads='auto']) |
diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am index 9b7bc471..58284d17 100644 --- a/src/microhttpd/Makefile.am +++ b/src/microhttpd/Makefile.am | |||
@@ -140,6 +140,7 @@ endif | |||
140 | 140 | ||
141 | 141 | ||
142 | check_PROGRAMS = \ | 142 | check_PROGRAMS = \ |
143 | test_shutdown_select \ | ||
143 | test_daemon | 144 | test_daemon |
144 | 145 | ||
145 | if HAVE_POSTPROCESSOR | 146 | if HAVE_POSTPROCESSOR |
@@ -151,6 +152,11 @@ endif | |||
151 | 152 | ||
152 | TESTS = $(check_PROGRAMS) | 153 | TESTS = $(check_PROGRAMS) |
153 | 154 | ||
155 | if !HAVE_LISTEN_SHUTDOWN | ||
156 | XFAIL_TESTS = \ | ||
157 | test_shutdown_select | ||
158 | endif | ||
159 | |||
154 | test_daemon_SOURCES = \ | 160 | test_daemon_SOURCES = \ |
155 | test_daemon.c | 161 | test_daemon.c |
156 | test_daemon_LDADD = \ | 162 | test_daemon_LDADD = \ |
@@ -178,3 +184,12 @@ test_postprocessor_large_CPPFLAGS = \ | |||
178 | test_postprocessor_large_LDADD = \ | 184 | test_postprocessor_large_LDADD = \ |
179 | $(top_builddir)/src/microhttpd/libmicrohttpd.la \ | 185 | $(top_builddir)/src/microhttpd/libmicrohttpd.la \ |
180 | $(MHD_W32_LIB) | 186 | $(MHD_W32_LIB) |
187 | |||
188 | test_shutdown_select_SOURCES = \ | ||
189 | test_shutdown_select.c | ||
190 | if USE_POSIX_THREADS | ||
191 | test_shutdown_select_CFLAGS = \ | ||
192 | $(AM_CFLAGS) $(PTHREAD_CFLAGS) | ||
193 | test_shutdown_select_LDADD = \ | ||
194 | $(PTHREAD_LIBS) | ||
195 | endif | ||
diff --git a/src/microhttpd/test_shutdown_select.c b/src/microhttpd/test_shutdown_select.c new file mode 100644 index 00000000..1ec0585c --- /dev/null +++ b/src/microhttpd/test_shutdown_select.c | |||
@@ -0,0 +1,299 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | Copyright (C) 2016 Karlson2k (Evgeny Grin) | ||
4 | |||
5 | libmicrohttpd is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | libmicrohttpd is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with libmicrohttpd; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file microhttpd/test_shutdown_select.c | ||
23 | * @brief Test whether shutdown socket triggers select | ||
24 | * @author Karlson2k (Evgeny Grin) | ||
25 | */ | ||
26 | |||
27 | #include "MHD_config.h" | ||
28 | #include "platform_interface.h" | ||
29 | #include "platform.h" | ||
30 | #include <stdlib.h> | ||
31 | #include <stdio.h> | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif /* HAVE_UNISTD_H */ | ||
36 | |||
37 | #ifdef HAVE_TIME_H | ||
38 | #include <time.h> | ||
39 | #endif /* HAVE_TIME_H */ | ||
40 | |||
41 | #if defined(MHD_USE_POSIX_THREADS) | ||
42 | #include <pthread.h> | ||
43 | #endif /* MHD_USE_POSIX_THREADS */ | ||
44 | |||
45 | #if defined(MHD_WINSOCK_SOCKETS) | ||
46 | #include <winsock2.h> | ||
47 | #include <windows.h> | ||
48 | #define sock_errno (WSAGetLastError()) | ||
49 | #elif defined(MHD_POSIX_SOCKETS) | ||
50 | #ifdef HAVE_SYS_TYPES_H | ||
51 | #include <sys/types.h> | ||
52 | #endif /* HAVE_SYS_TYPES_H */ | ||
53 | #ifdef HAVE_SYS_SOCKET_H | ||
54 | #include <sys/socket.h> | ||
55 | #endif /* HAVE_SYS_SOCKET_H */ | ||
56 | #ifdef HAVE_NETINET_IN_H | ||
57 | #include <netinet/in.h> | ||
58 | #endif /* HAVE_NETINET_IN_H */ | ||
59 | #ifdef HAVE_ARPA_INET_H | ||
60 | #include <arpa/inet.h> | ||
61 | #endif /* HAVE_ARPA_INET_H */ | ||
62 | #ifdef HAVE_SYS_SELECT_H | ||
63 | #include <sys/select.h> | ||
64 | #endif /* HAVE_SYS_SELECT_H */ | ||
65 | #define sock_errno (errno) | ||
66 | #endif /* MHD_POSIX_SOCKETS */ | ||
67 | |||
68 | #ifndef SOMAXCONN | ||
69 | #define SOMAXCONN 511 | ||
70 | #endif /* ! SOMAXCONN */ | ||
71 | |||
72 | #if !defined(SHUT_RDWR) && defined(SD_BOTH) | ||
73 | #define SHUT_RDWR SD_BOTH | ||
74 | #endif | ||
75 | |||
76 | |||
77 | static MHD_socket | ||
78 | start_socket_listen(int domain) | ||
79 | { | ||
80 | /* Create sockets similarly to daemon.c */ | ||
81 | MHD_socket fd; | ||
82 | int cloexec_set; | ||
83 | struct sockaddr_in sock_addr; | ||
84 | socklen_t addrlen; | ||
85 | |||
86 | #ifdef MHD_WINSOCK_SOCKETS | ||
87 | unsigned long flags = 1; | ||
88 | #else /* MHD_POSIX_SOCKETS */ | ||
89 | int flags; | ||
90 | #endif /* MHD_POSIX_SOCKETS */ | ||
91 | |||
92 | #if defined(MHD_POSIX_SOCKETS) && defined(SOCK_CLOEXEC) | ||
93 | fd = socket (domain, SOCK_STREAM | SOCK_CLOEXEC, 0); | ||
94 | cloexec_set = 1; | ||
95 | #elif defined(MHD_WINSOCK_SOCKETS) && defined (WSA_FLAG_NO_HANDLE_INHERIT) | ||
96 | fd = WSASocketW (domain, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_NO_HANDLE_INHERIT); | ||
97 | cloexec_set = 1; | ||
98 | #else /* !SOCK_CLOEXEC */ | ||
99 | fd = socket (domain, SOCK_STREAM, 0); | ||
100 | cloexec_set = 0; | ||
101 | #endif /* !SOCK_CLOEXEC */ | ||
102 | if ( (MHD_INVALID_SOCKET == fd) && (cloexec_set) ) | ||
103 | { | ||
104 | fd = socket (domain, SOCK_STREAM, 0); | ||
105 | cloexec_set = 0; | ||
106 | } | ||
107 | if (MHD_INVALID_SOCKET == fd) | ||
108 | { | ||
109 | fprintf (stderr, "Can't create socket: %u\n", | ||
110 | (unsigned)sock_errno); | ||
111 | return MHD_INVALID_SOCKET; | ||
112 | } | ||
113 | |||
114 | if (!cloexec_set) | ||
115 | { | ||
116 | #ifdef MHD_WINSOCK_SOCKETS | ||
117 | if (!SetHandleInformation ((HANDLE)fd, HANDLE_FLAG_INHERIT, 0)) | ||
118 | fprintf (stderr, "Failed to make socket non-inheritable: %u\n", | ||
119 | (unsigned int)GetLastError ()); | ||
120 | #else /* MHD_POSIX_SOCKETS */ | ||
121 | flags = fcntl (fd, F_GETFD); | ||
122 | if ( ( (-1 == flags) || | ||
123 | ( (flags != (flags | FD_CLOEXEC)) && | ||
124 | (0 != fcntl (fd, F_SETFD, flags | FD_CLOEXEC)) ) ) ) | ||
125 | fprintf (stderr, "Failed to make socket non-inheritable: %s\n", | ||
126 | MHD_socket_last_strerr_ ()); | ||
127 | #endif /* MHD_POSIX_SOCKETS */ | ||
128 | } | ||
129 | |||
130 | memset (&sock_addr, 0, sizeof (struct sockaddr_in)); | ||
131 | sock_addr.sin_family = AF_INET; | ||
132 | sock_addr.sin_port = htons (0); | ||
133 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
134 | sock_addr.sin_len = sizeof (struct sockaddr_in); | ||
135 | #endif | ||
136 | addrlen = sizeof (struct sockaddr_in); | ||
137 | |||
138 | if (bind (fd, (const struct sockaddr*) &sock_addr, addrlen) < 0) | ||
139 | { | ||
140 | fprintf (stderr, "Failed to bind socket: %u\n", | ||
141 | (unsigned)sock_errno); | ||
142 | MHD_socket_close_ (fd); | ||
143 | return MHD_INVALID_SOCKET; | ||
144 | } | ||
145 | |||
146 | #ifdef MHD_WINSOCK_SOCKETS | ||
147 | if (0 != ioctlsocket (fd, FIONBIO, &flags)) | ||
148 | { | ||
149 | fprintf (stderr, "Failed to make socket non-blocking: %u\n", | ||
150 | (unsigned)sock_errno); | ||
151 | MHD_socket_close_ (fd); | ||
152 | return MHD_INVALID_SOCKET; | ||
153 | } | ||
154 | #else /* MHD_POSIX_SOCKETS */ | ||
155 | flags = fcntl (fd, F_GETFL); | ||
156 | if ( ( (-1 == flags) || | ||
157 | ( (flags != (flags | O_NONBLOCK)) && | ||
158 | (0 != fcntl (fd, F_SETFL, flags | O_NONBLOCK)) ) ) ) | ||
159 | { | ||
160 | fprintf (stderr, "Failed to make socket non-blocking: %s\n", | ||
161 | MHD_socket_last_strerr_ ()); | ||
162 | MHD_socket_close_ (fd); | ||
163 | return MHD_INVALID_SOCKET; | ||
164 | } | ||
165 | #endif /* MHD_POSIX_SOCKETS */ | ||
166 | |||
167 | if (listen(fd, SOMAXCONN) < 0) | ||
168 | { | ||
169 | fprintf (stderr, "Failed to listen on socket: %u\n", | ||
170 | (unsigned)sock_errno); | ||
171 | MHD_socket_close_ (fd); | ||
172 | return MHD_INVALID_SOCKET; | ||
173 | } | ||
174 | |||
175 | return fd; | ||
176 | } | ||
177 | |||
178 | |||
179 | MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_ | ||
180 | select_thread(void* data) | ||
181 | { | ||
182 | /* use select() like in daemon.c */ | ||
183 | MHD_socket listen_sock = *((MHD_socket*)data); | ||
184 | fd_set rs, ws; | ||
185 | struct timeval timeout; | ||
186 | |||
187 | FD_ZERO(&rs); | ||
188 | FD_ZERO(&ws); | ||
189 | FD_SET(listen_sock, &rs); | ||
190 | timeout.tv_usec = 0; | ||
191 | timeout.tv_sec = 7; | ||
192 | |||
193 | MHD_SYS_select_(listen_sock + 1, &rs, &ws, NULL, &timeout); | ||
194 | |||
195 | return (MHD_THRD_RTRN_TYPE_)0; | ||
196 | } | ||
197 | |||
198 | |||
199 | static void | ||
200 | local_sleep(unsigned seconds) | ||
201 | { | ||
202 | #if defined(_WIN32) && !defined(__CYGWIN__) | ||
203 | Sleep(seconds * 1000); | ||
204 | #else | ||
205 | unsigned seconds_left = seconds; | ||
206 | do | ||
207 | { | ||
208 | seconds_left = sleep(seconds_left); | ||
209 | } while (seconds_left > 0); | ||
210 | #endif | ||
211 | } | ||
212 | |||
213 | |||
214 | int | ||
215 | main (int argc, char *const *argv) | ||
216 | { | ||
217 | int i; | ||
218 | time_t start_t, end_t; | ||
219 | int result = 0; | ||
220 | |||
221 | #ifdef MHD_WINSOCK_SOCKETS | ||
222 | WORD ver_req; | ||
223 | WSADATA wsa_data; | ||
224 | int err; | ||
225 | ver_req = MAKEWORD(2, 2); | ||
226 | |||
227 | err = WSAStartup(ver_req, &wsa_data); | ||
228 | if (err != 0 || MAKEWORD(2, 2) != wsa_data.wVersion) | ||
229 | { | ||
230 | printf("WSAStartup() failed\n"); | ||
231 | WSACleanup(); | ||
232 | return 99; | ||
233 | } | ||
234 | #endif /* MHD_WINSOCK_SOCKETS */ | ||
235 | |||
236 | /* try several times to ensure that accidental incoming connection | ||
237 | * didn't interfere with test results | ||
238 | */ | ||
239 | for (i = 0; i < 5 && result == 0; i++) | ||
240 | { | ||
241 | MHD_thread_handle_ sel_thrd; | ||
242 | /* fprint f(stdout, "Creating, binding and listening socket...\n"); */ | ||
243 | MHD_socket listen_socket = start_socket_listen (AF_INET); | ||
244 | if (MHD_INVALID_SOCKET == listen_socket) | ||
245 | return 99; | ||
246 | |||
247 | /* fprintf (stdout, "Starting select() thread...\n"); */ | ||
248 | #if defined(MHD_USE_POSIX_THREADS) | ||
249 | if (0 != pthread_create (&sel_thrd, NULL, &select_thread, &listen_socket)) | ||
250 | { | ||
251 | MHD_socket_close_ (listen_socket); | ||
252 | fprintf (stderr, "Can't start thread\n"); | ||
253 | return 99; | ||
254 | } | ||
255 | #elif defined(MHD_USE_W32_THREADS) | ||
256 | sel_thrd = (HANDLE)_beginthreadex (NULL, 0, &select_thread, &listen_socket, 0, NULL); | ||
257 | if (0 == (sel_thrd)) | ||
258 | { | ||
259 | MHD_socket_close_ (listen_socket); | ||
260 | fprintf (stderr, "Can't start select() thread\n"); | ||
261 | return 99; | ||
262 | } | ||
263 | #else | ||
264 | #error No threading lib available | ||
265 | #endif | ||
266 | /* fprintf (stdout, "Waiting...\n"); */ | ||
267 | local_sleep(1); /* make sure that select() is started */ | ||
268 | |||
269 | /* fprintf (stdout, "Shutting down socket...\n"); */ | ||
270 | start_t = time (NULL); | ||
271 | shutdown (listen_socket, SHUT_RDWR); | ||
272 | |||
273 | /* fprintf (stdout, "Waiting for thread to finish...\n"); */ | ||
274 | if (0 != MHD_join_thread_(sel_thrd)) | ||
275 | { | ||
276 | MHD_socket_close_(listen_socket); | ||
277 | fprintf (stderr, "Can't join select() thread\n"); | ||
278 | return 99; | ||
279 | } | ||
280 | end_t = time (NULL); | ||
281 | /* fprintf (stdout, "Thread finished.\n"); */ | ||
282 | MHD_socket_close_(listen_socket); | ||
283 | |||
284 | if (start_t == (time_t)-1 || end_t == (time_t)-1) | ||
285 | { | ||
286 | MHD_socket_close_(listen_socket); | ||
287 | fprintf (stderr, "Can't get current time\n"); | ||
288 | return 99; | ||
289 | } | ||
290 | if (end_t - start_t > 3) | ||
291 | result++; | ||
292 | } | ||
293 | |||
294 | #ifdef MHD_WINSOCK_SOCKETS | ||
295 | WSACleanup(); | ||
296 | #endif /* MHD_WINSOCK_SOCKETS */ | ||
297 | |||
298 | return result; | ||
299 | } | ||