aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeny Grin (Karlson2k) <k2k@narod.ru>2016-01-25 14:17:43 +0000
committerEvgeny Grin (Karlson2k) <k2k@narod.ru>2016-01-25 14:17:43 +0000
commit22392ce602ac57b6e77b54d246172d002bcf309f (patch)
tree4d98991327e91d7008118a5a5c97c11be0f2c13f
parent3baed95b7d44fb7743e211996db98a9aa6dd9780 (diff)
downloadlibmicrohttpd-22392ce602ac57b6e77b54d246172d002bcf309f.tar.gz
libmicrohttpd-22392ce602ac57b6e77b54d246172d002bcf309f.zip
Added test for checking ability of shutdown() on socket to trigger select()
-rw-r--r--ChangeLog4
-rw-r--r--configure.ac8
-rw-r--r--src/microhttpd/Makefile.am15
-rw-r--r--src/microhttpd/test_shutdown_select.c299
4 files changed, 324 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 7b24960f..2302cff3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
1Mon Jan 25 13:45:50 CET 2016
2 Added check test for triggering select() on
3 listen socket. -EG
4
1Thu Jan 21 19:35:18 CET 2016 5Thu 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]])
141CFLAGS="$save_CFLAGS" 141CFLAGS="$save_CFLAGS"
142 142
143# Check system type 143# Check system type
144shutdown_trig_select='no'
144AC_MSG_CHECKING([[for target host OS]]) 145AC_MSG_CHECKING([[for target host OS]])
145case "$host_os" in 146case "$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;;
234esac 235esac
235 236
237AM_CONDITIONAL([HAVE_LISTEN_SHUTDOWN], [test "x$shutdown_trig_select" = "xyes"])
238AS_IF([test "x$shutdown_trig_select" = "xyes"], [AC_DEFINE([HAVE_LISTEN_SHUTDOWN],[1],[can use shutdown on listen sockets])])
239
236AC_ARG_WITH([threads], 240AC_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
142check_PROGRAMS = \ 142check_PROGRAMS = \
143 test_shutdown_select \
143 test_daemon 144 test_daemon
144 145
145if HAVE_POSTPROCESSOR 146if HAVE_POSTPROCESSOR
@@ -151,6 +152,11 @@ endif
151 152
152TESTS = $(check_PROGRAMS) 153TESTS = $(check_PROGRAMS)
153 154
155if !HAVE_LISTEN_SHUTDOWN
156XFAIL_TESTS = \
157 test_shutdown_select
158endif
159
154test_daemon_SOURCES = \ 160test_daemon_SOURCES = \
155 test_daemon.c 161 test_daemon.c
156test_daemon_LDADD = \ 162test_daemon_LDADD = \
@@ -178,3 +184,12 @@ test_postprocessor_large_CPPFLAGS = \
178test_postprocessor_large_LDADD = \ 184test_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
188test_shutdown_select_SOURCES = \
189 test_shutdown_select.c
190if USE_POSIX_THREADS
191test_shutdown_select_CFLAGS = \
192 $(AM_CFLAGS) $(PTHREAD_CFLAGS)
193test_shutdown_select_LDADD = \
194 $(PTHREAD_LIBS)
195endif
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
77static MHD_socket
78start_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
179MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
180select_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
199static void
200local_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
214int
215main (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}