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