aboutsummaryrefslogtreecommitdiff
path: root/m4
diff options
context:
space:
mode:
authorEvgeny Grin (Karlson2k) <k2k@narod.ru>2017-03-20 00:54:22 +0300
committerEvgeny Grin (Karlson2k) <k2k@narod.ru>2017-03-20 00:56:19 +0300
commitf3dd2a630369473fe3bc0ac86983e59f64457a97 (patch)
tree48ba9f31505361374c28386486e5cf48ccc9a491 /m4
parente3ce8fdf5739928c5250863bb2132f041d4cab64 (diff)
downloadlibmicrohttpd-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.m4338
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
23AC_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
49AC_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
70AC_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
145static 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
153static volatile int going_select = 0;
154static volatile int select_ends = 0;
155static volatile int gerror = 0;
156static int timeout_mils;
157
158static 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
175static MHD_socket create_socket(void)
176{
177 return socket (AF_INET, SOCK_STREAM, 0);
178}
179
180static void close_socket(MHD_socket fd)
181{
182#ifdef MHD_POSIX_SOCKETS
183 close(fd);
184#else
185 closesocket(fd);
186#endif
187}
188
189static MHD_socket
190create_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
218static 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(&current, 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
271static 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
294static 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
308static void cleanup(void)
309{
310#ifdef MHD_WINSOCK_SOCKETS
311 WSACleanup();
312#endif /* MHD_WINSOCK_SOCKETS */
313}
314
315int 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)