diff options
author | Christian Grothoff <christian@grothoff.org> | 2020-10-22 11:48:57 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2020-10-22 11:48:57 +0200 |
commit | dd9aadce4ccb6517fac420b241e19834bec84174 (patch) | |
tree | 0955c6fad4fa662c6e3e84c740a83880551d6e7f | |
parent | c43779a4bed4d372153e12ba94b9c4c6520050ef (diff) | |
parent | 276535e5ec0fc9eb13d6821cdacf6c297fdd8c09 (diff) | |
download | libmicrohttpd-dd9aadce4ccb6517fac420b241e19834bec84174.tar.gz libmicrohttpd-dd9aadce4ccb6517fac420b241e19834bec84174.zip |
Merge branch 'master' of git+ssh://gnunet.org/libmicrohttpd
-rw-r--r-- | configure.ac | 17 | ||||
-rw-r--r-- | src/microhttpd/daemon.c | 27 | ||||
-rw-r--r-- | src/microhttpd/mhd_send.c | 2 | ||||
-rw-r--r-- | src/testcurl/.gitignore | 3 | ||||
-rw-r--r-- | src/testcurl/Makefile.am | 14 | ||||
-rw-r--r-- | src/testcurl/test_add_conn.c | 1040 |
6 files changed, 1098 insertions, 5 deletions
diff --git a/configure.ac b/configure.ac index a3596813..b874ee68 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -866,6 +866,23 @@ AX_CHECK_LINK_FLAG([-fno-strict-aliasing], | |||
866 | 866 | ||
867 | AC_C_BIGENDIAN | 867 | AC_C_BIGENDIAN |
868 | AC_C_VARARRAYS | 868 | AC_C_VARARRAYS |
869 | |||
870 | AC_CACHE_CHECK([[whether __func__ magic-macro is available]], | ||
871 | [[mhd_cv_macro___func___avail]], [dnl | ||
872 | AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <stddef.h>]],[[const char *funcname = __func__ ; if (NULL == funcname) return 1;]])], | ||
873 | [[mhd_cv_macro___func___avail="yes"]],[[mhd_cv_macro___func___avail="no"]]) | ||
874 | ]) | ||
875 | AS_VAR_IF([mhd_cv_macro___func___avail], ["yes"], | ||
876 | [AC_DEFINE([HAVE___FUNC__], [1], [Define to 1 if your compiler supports __func__ magic-macro.])], | ||
877 | [ | ||
878 | AC_CACHE_CHECK([[whether __FUNCTION__ magic-macro is available]], | ||
879 | [[mhd_cv_macro___function___avail]], [dnl | ||
880 | AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <stddef.h>]],[[const char *funcname = __FUNCTION__ ; if (NULL == funcname) return 1;]])], | ||
881 | [[mhd_cv_macro___function___avail="yes"]],[[mhd_cv_macro___function___avail="no"]]) | ||
882 | ]) | ||
883 | AC_DEFINE([HAVE___FUNCTION__], [1], [Define to 1 if your compiler supports __FUNCTION__ magic-macro.]) | ||
884 | ] | ||
885 | ) | ||
869 | AC_CACHE_CHECK([[whether __builtin_bswap32() is available]], | 886 | AC_CACHE_CHECK([[whether __builtin_bswap32() is available]], |
870 | [[mhd_cv_func___builtin_bswap32_avail]], [dnl | 887 | [[mhd_cv_func___builtin_bswap32_avail]], [dnl |
871 | AC_TRY_LINK([#include<stdint.h>],[uint32_t a = 1; uint32_t b = __builtin_bswap32(a); a = b;], | 888 | AC_TRY_LINK([#include<stdint.h>],[uint32_t a = 1; uint32_t b = __builtin_bswap32(a); a = b;], |
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index 710ba55b..b18885f0 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c | |||
@@ -6018,7 +6018,7 @@ MHD_start_daemon_va (unsigned int flags, | |||
6018 | #ifdef HAVE_LISTEN_SHUTDOWN | 6018 | #ifdef HAVE_LISTEN_SHUTDOWN |
6019 | if (0 != (*pflags & MHD_USE_NO_LISTEN_SOCKET)) | 6019 | if (0 != (*pflags & MHD_USE_NO_LISTEN_SOCKET)) |
6020 | #endif | 6020 | #endif |
6021 | *pflags |= MHD_USE_ITC; /* yes, must use ITC to signal thread */ | 6021 | *pflags |= MHD_USE_ITC; /* yes, must use ITC to signal thread */ |
6022 | } | 6022 | } |
6023 | #ifdef DAUTH_SUPPORT | 6023 | #ifdef DAUTH_SUPPORT |
6024 | daemon->digest_auth_rand_size = 0; | 6024 | daemon->digest_auth_rand_size = 0; |
@@ -6594,10 +6594,21 @@ MHD_start_daemon_va (unsigned int flags, | |||
6594 | } | 6594 | } |
6595 | #endif /* HTTPS_SUPPORT */ | 6595 | #endif /* HTTPS_SUPPORT */ |
6596 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) | 6596 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) |
6597 | if ( (0 != (*pflags & MHD_USE_INTERNAL_POLLING_THREAD)) && | 6597 | /* Start threads if requested by parameters */ |
6598 | ( (0 == (*pflags & MHD_USE_NO_LISTEN_SOCKET)) || | 6598 | if (0 != (*pflags & MHD_USE_INTERNAL_POLLING_THREAD)) |
6599 | (MHD_ITC_IS_VALID_ (daemon->itc)) ) ) | ||
6600 | { | 6599 | { |
6600 | /* Internal thread (or threads) is used. | ||
6601 | * Make sure that MHD will be able to communicate with threads. */ | ||
6602 | /* If using a thread pool ITC will be initialised later | ||
6603 | * for each individual worker thread. */ | ||
6604 | #ifdef HAVE_LISTEN_SHUTDOWN | ||
6605 | mhd_assert ((1 < daemon->worker_pool_size) || \ | ||
6606 | (MHD_ITC_IS_VALID_ (daemon->itc)) || \ | ||
6607 | (MHD_INVALID_SOCKET != daemon->listen_fd)); | ||
6608 | #else /* ! HAVE_LISTEN_SHUTDOWN */ | ||
6609 | mhd_assert ((1 < daemon->worker_pool_size) || \ | ||
6610 | (MHD_ITC_IS_VALID_ (daemon->itc))); | ||
6611 | #endif /* ! HAVE_LISTEN_SHUTDOWN */ | ||
6601 | if (0 == daemon->worker_pool_size) | 6612 | if (0 == daemon->worker_pool_size) |
6602 | { | 6613 | { |
6603 | if (! MHD_create_named_thread_ (&daemon->pid, | 6614 | if (! MHD_create_named_thread_ (&daemon->pid, |
@@ -6630,6 +6641,7 @@ MHD_start_daemon_va (unsigned int flags, | |||
6630 | unsigned int leftover_conns = daemon->connection_limit | 6641 | unsigned int leftover_conns = daemon->connection_limit |
6631 | % daemon->worker_pool_size; | 6642 | % daemon->worker_pool_size; |
6632 | 6643 | ||
6644 | mhd_assert (2 <= daemon->worker_pool_size); | ||
6633 | i = 0; /* we need this in case fcntl or malloc fails */ | 6645 | i = 0; /* we need this in case fcntl or malloc fails */ |
6634 | 6646 | ||
6635 | /* Allocate memory for pooled objects */ | 6647 | /* Allocate memory for pooled objects */ |
@@ -6680,6 +6692,13 @@ MHD_start_daemon_va (unsigned int flags, | |||
6680 | else | 6692 | else |
6681 | MHD_itc_set_invalid_ (d->itc); | 6693 | MHD_itc_set_invalid_ (d->itc); |
6682 | 6694 | ||
6695 | #ifdef HAVE_LISTEN_SHUTDOWN | ||
6696 | mhd_assert ((MHD_ITC_IS_VALID_ (d->itc)) || \ | ||
6697 | (MHD_INVALID_SOCKET != d->listen_fd)); | ||
6698 | #else /* ! HAVE_LISTEN_SHUTDOWN */ | ||
6699 | mhd_assert (MHD_ITC_IS_VALID_ (d->itc)); | ||
6700 | #endif /* ! HAVE_LISTEN_SHUTDOWN */ | ||
6701 | |||
6683 | /* Divide available connections evenly amongst the threads. | 6702 | /* Divide available connections evenly amongst the threads. |
6684 | * Thread indexes in [0, leftover_conns) each get one of the | 6703 | * Thread indexes in [0, leftover_conns) each get one of the |
6685 | * leftover connections. */ | 6704 | * leftover connections. */ |
diff --git a/src/microhttpd/mhd_send.c b/src/microhttpd/mhd_send.c index 50fa5483..006525d2 100644 --- a/src/microhttpd/mhd_send.c +++ b/src/microhttpd/mhd_send.c | |||
@@ -36,6 +36,7 @@ | |||
36 | * and every place where sendfile(), sendfile64(), setsockopt() | 36 | * and every place where sendfile(), sendfile64(), setsockopt() |
37 | * are used. */ | 37 | * are used. */ |
38 | 38 | ||
39 | #include "mhd_send.h" | ||
39 | #ifdef MHD_LINUX_SOLARIS_SENDFILE | 40 | #ifdef MHD_LINUX_SOLARIS_SENDFILE |
40 | #include <sys/sendfile.h> | 41 | #include <sys/sendfile.h> |
41 | #endif /* MHD_LINUX_SOLARIS_SENDFILE */ | 42 | #endif /* MHD_LINUX_SOLARIS_SENDFILE */ |
@@ -48,7 +49,6 @@ | |||
48 | /* For FreeBSD version identification */ | 49 | /* For FreeBSD version identification */ |
49 | #include <sys/param.h> | 50 | #include <sys/param.h> |
50 | #endif /* HAVE_SYS_PARAM_H */ | 51 | #endif /* HAVE_SYS_PARAM_H */ |
51 | #include "mhd_send.h" | ||
52 | 52 | ||
53 | 53 | ||
54 | /** | 54 | /** |
diff --git a/src/testcurl/.gitignore b/src/testcurl/.gitignore index e3ec49c0..4c1c7f03 100644 --- a/src/testcurl/.gitignore +++ b/src/testcurl/.gitignore | |||
@@ -111,3 +111,6 @@ perf_get_concurrent11 | |||
111 | test_get_empty | 111 | test_get_empty |
112 | test_patch | 112 | test_patch |
113 | test_patch11 | 113 | test_patch11 |
114 | /test_add_conn | ||
115 | /test_add_conn_nolisten | ||
116 | core | ||
diff --git a/src/testcurl/Makefile.am b/src/testcurl/Makefile.am index 687b77bf..f45f13d3 100644 --- a/src/testcurl/Makefile.am +++ b/src/testcurl/Makefile.am | |||
@@ -56,6 +56,8 @@ check_PROGRAMS = \ | |||
56 | test_delete \ | 56 | test_delete \ |
57 | test_patch \ | 57 | test_patch \ |
58 | test_put \ | 58 | test_put \ |
59 | test_add_conn \ | ||
60 | test_add_conn_nolisten \ | ||
59 | test_process_headers \ | 61 | test_process_headers \ |
60 | test_process_arguments \ | 62 | test_process_arguments \ |
61 | test_parse_cookies \ | 63 | test_parse_cookies \ |
@@ -271,6 +273,18 @@ test_put_chunked_SOURCES = \ | |||
271 | test_put_chunked_LDADD = \ | 273 | test_put_chunked_LDADD = \ |
272 | $(top_builddir)/src/microhttpd/libmicrohttpd.la \ | 274 | $(top_builddir)/src/microhttpd/libmicrohttpd.la \ |
273 | @LIBCURL@ | 275 | @LIBCURL@ |
276 | |||
277 | test_add_conn_SOURCES = \ | ||
278 | test_add_conn.c $(top_srcdir)/src/microhttpd/test_helpers.h | ||
279 | test_add_conn_LDADD = \ | ||
280 | $(top_builddir)/src/microhttpd/libmicrohttpd.la \ | ||
281 | @LIBCURL@ | ||
282 | |||
283 | test_add_conn_nolisten_SOURCES = \ | ||
284 | test_add_conn.c $(top_srcdir)/src/microhttpd/test_helpers.h | ||
285 | test_add_conn_nolisten_LDADD = \ | ||
286 | $(top_builddir)/src/microhttpd/libmicrohttpd.la \ | ||
287 | @LIBCURL@ | ||
274 | 288 | ||
275 | test_get11_SOURCES = \ | 289 | test_get11_SOURCES = \ |
276 | test_get.c | 290 | test_get.c |
diff --git a/src/testcurl/test_add_conn.c b/src/testcurl/test_add_conn.c new file mode 100644 index 00000000..52aa2831 --- /dev/null +++ b/src/testcurl/test_add_conn.c | |||
@@ -0,0 +1,1040 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | Copyright (C) 2007, 2009, 2011 Christian Grothoff | ||
4 | Copyright (C) 2020 Karlson2k (Evgeny Grin) - large rework, multithreading. | ||
5 | |||
6 | libmicrohttpd is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published | ||
8 | by the Free Software Foundation; either version 2, or (at your | ||
9 | option) any later version. | ||
10 | |||
11 | libmicrohttpd is distributed in the hope that it will be useful, but | ||
12 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with libmicrohttpd; see the file COPYING. If not, write to the | ||
18 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
19 | Boston, MA 02110-1301, USA. | ||
20 | */ | ||
21 | /** | ||
22 | * @file test_add_conn.c | ||
23 | * @brief Testcase for libmicrohttpd GET operations | ||
24 | * @author Christian Grothoff | ||
25 | * @author Karlson2k (Evgeny Grin) | ||
26 | */ | ||
27 | #include "MHD_config.h" | ||
28 | #include "platform.h" | ||
29 | #include <curl/curl.h> | ||
30 | #include <microhttpd.h> | ||
31 | #include <stdlib.h> | ||
32 | #include <string.h> | ||
33 | #include <time.h> | ||
34 | #include "test_helpers.h" | ||
35 | #include "mhd_sockets.h" /* only macros used */ | ||
36 | |||
37 | |||
38 | #ifdef _WIN32 | ||
39 | #ifndef WIN32_LEAN_AND_MEAN | ||
40 | #define WIN32_LEAN_AND_MEAN 1 | ||
41 | #endif /* !WIN32_LEAN_AND_MEAN */ | ||
42 | #include <windows.h> | ||
43 | #endif | ||
44 | |||
45 | #ifndef WINDOWS | ||
46 | #include <unistd.h> | ||
47 | #include <sys/socket.h> | ||
48 | #endif | ||
49 | |||
50 | #ifdef HAVE_PTHREAD_H | ||
51 | #include <pthread.h> | ||
52 | #endif /* HAVE_PTHREAD_H */ | ||
53 | |||
54 | #if defined(CPU_COUNT) && (CPU_COUNT + 0) < 2 | ||
55 | #undef CPU_COUNT | ||
56 | #endif | ||
57 | #if ! defined(CPU_COUNT) | ||
58 | #define CPU_COUNT 2 | ||
59 | #endif | ||
60 | |||
61 | /* Could be increased to facilitate debugging */ | ||
62 | #define TIMEOUTS_VAL 5 | ||
63 | |||
64 | #define EXPECTED_URI_BASE_PATH "/hello_world" | ||
65 | #define EXPECTED_URI_QUERY "a=%26&b=c" | ||
66 | #define EXPECTED_URI_FULL_PATH EXPECTED_URI_BASE_PATH "?" EXPECTED_URI_QUERY | ||
67 | |||
68 | static int oneone; | ||
69 | static int no_listen; | ||
70 | static int global_port; | ||
71 | |||
72 | struct CBC | ||
73 | { | ||
74 | char *buf; | ||
75 | size_t pos; | ||
76 | size_t size; | ||
77 | }; | ||
78 | |||
79 | |||
80 | static size_t | ||
81 | copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) | ||
82 | { | ||
83 | struct CBC *cbc = ctx; | ||
84 | |||
85 | if (cbc->pos + size * nmemb > cbc->size) | ||
86 | return 0; /* overflow */ | ||
87 | memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); | ||
88 | cbc->pos += size * nmemb; | ||
89 | return size * nmemb; | ||
90 | } | ||
91 | |||
92 | |||
93 | static void * | ||
94 | log_cb (void *cls, | ||
95 | const char *uri, | ||
96 | struct MHD_Connection *con) | ||
97 | { | ||
98 | (void) cls; | ||
99 | (void) con; | ||
100 | if (0 != strcmp (uri, | ||
101 | EXPECTED_URI_FULL_PATH)) | ||
102 | { | ||
103 | fprintf (stderr, | ||
104 | "Wrong URI: `%s'\n", | ||
105 | uri); | ||
106 | _exit (22); | ||
107 | } | ||
108 | return NULL; | ||
109 | } | ||
110 | |||
111 | |||
112 | static enum MHD_Result | ||
113 | ahc_echo (void *cls, | ||
114 | struct MHD_Connection *connection, | ||
115 | const char *url, | ||
116 | const char *method, | ||
117 | const char *version, | ||
118 | const char *upload_data, size_t *upload_data_size, | ||
119 | void **unused) | ||
120 | { | ||
121 | static int ptr; | ||
122 | const char *me = cls; | ||
123 | struct MHD_Response *response; | ||
124 | enum MHD_Result ret; | ||
125 | const char *v; | ||
126 | (void) version; | ||
127 | (void) upload_data; | ||
128 | (void) upload_data_size; /* Unused. Silence compiler warning. */ | ||
129 | |||
130 | if (0 != strcasecmp (me, method)) | ||
131 | return MHD_NO; /* unexpected method */ | ||
132 | if (&ptr != *unused) | ||
133 | { | ||
134 | *unused = &ptr; | ||
135 | return MHD_YES; | ||
136 | } | ||
137 | *unused = NULL; | ||
138 | v = MHD_lookup_connection_value (connection, | ||
139 | MHD_GET_ARGUMENT_KIND, | ||
140 | "a"); | ||
141 | if ( (NULL == v) || | ||
142 | (0 != strcmp ("&", | ||
143 | v)) ) | ||
144 | { | ||
145 | fprintf (stderr, "Found while looking for 'a=&': 'a=%s'\n", | ||
146 | NULL == v ? "NULL" : v); | ||
147 | _exit (17); | ||
148 | } | ||
149 | v = NULL; | ||
150 | if (MHD_YES != MHD_lookup_connection_value_n (connection, | ||
151 | MHD_GET_ARGUMENT_KIND, | ||
152 | "b", | ||
153 | 1, | ||
154 | &v, | ||
155 | NULL)) | ||
156 | { | ||
157 | fprintf (stderr, "Not found 'b' GET argument.\n"); | ||
158 | _exit (18); | ||
159 | } | ||
160 | if ( (NULL == v) || | ||
161 | (0 != strcmp ("c", | ||
162 | v)) ) | ||
163 | { | ||
164 | fprintf (stderr, "Found while looking for 'b=c': 'b=%s'\n", | ||
165 | NULL == v ? "NULL" : v); | ||
166 | _exit (19); | ||
167 | } | ||
168 | response = MHD_create_response_from_buffer (strlen (url), | ||
169 | (void *) url, | ||
170 | MHD_RESPMEM_MUST_COPY); | ||
171 | ret = MHD_queue_response (connection, | ||
172 | MHD_HTTP_OK, | ||
173 | response); | ||
174 | MHD_destroy_response (response); | ||
175 | if (ret == MHD_NO) | ||
176 | { | ||
177 | fprintf (stderr, "Failed to queue response.\n"); | ||
178 | _exit (19); | ||
179 | } | ||
180 | return ret; | ||
181 | } | ||
182 | |||
183 | |||
184 | static void | ||
185 | _externalErrorExit_func (const char *errDesc, const char *funcName, int lineNum) | ||
186 | { | ||
187 | if ((NULL != errDesc) && (0 != errDesc[0])) | ||
188 | fprintf (stderr, "%s", errDesc); | ||
189 | else | ||
190 | fprintf (stderr, "System or external library call failed"); | ||
191 | if ((NULL != funcName) && (0 != funcName[0])) | ||
192 | fprintf (stderr, " in %s", funcName); | ||
193 | if (0 < lineNum) | ||
194 | fprintf (stderr, " at line %d", lineNum); | ||
195 | |||
196 | fprintf (stderr, ".\nLast errno value: %d\n", (int) errno); | ||
197 | #ifdef MHD_WINSOCK_SOCKETS | ||
198 | fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); | ||
199 | #endif /* MHD_WINSOCK_SOCKETS */ | ||
200 | fflush (stderr); | ||
201 | _exit (99); | ||
202 | } | ||
203 | |||
204 | |||
205 | #if defined(HAVE___FUNC__) | ||
206 | #define externalErrorExit(ignore) \ | ||
207 | _externalErrorExit_func(NULL, __func__, __LINE__) | ||
208 | #define externalErrorExitDesc(errDesc) \ | ||
209 | _externalErrorExit_func(errDesc, __func__, __LINE__) | ||
210 | #elif defined(HAVE___FUNCTION__) | ||
211 | #define externalErrorExit(ignore) \ | ||
212 | _externalErrorExit_func(NULL, __FUNCTION__, __LINE__) | ||
213 | #define externalErrorExitDesc(errDesc) \ | ||
214 | _externalErrorExit_func(errDesc, __FUNCTION__, __LINE__) | ||
215 | #else | ||
216 | #define externalErrorExit(ignore) _externalErrorExit_func(NULL, NULL, __LINE__) | ||
217 | #define externalErrorExitDesc(errDesc) \ | ||
218 | _externalErrorExit_func(errDesc, NULL, __LINE__) | ||
219 | #endif | ||
220 | |||
221 | |||
222 | /* Static const value, indicates that result value was not set yet */ | ||
223 | static const int eMarker = 0xCE; | ||
224 | |||
225 | |||
226 | static MHD_socket | ||
227 | createListeningSocket (int *pport) | ||
228 | { | ||
229 | MHD_socket skt; | ||
230 | static const int on = 1; | ||
231 | struct sockaddr_in sin; | ||
232 | socklen_t sin_len; | ||
233 | |||
234 | skt = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); | ||
235 | if (MHD_INVALID_SOCKET == skt) | ||
236 | externalErrorExitDesc ("socket() failed"); | ||
237 | |||
238 | #ifdef MHD_POSIX_SOCKETS | ||
239 | setsockopt (skt, SOL_SOCKET, SO_REUSEADDR, (void*) &on, sizeof (on)); | ||
240 | /* Ignore possible error */ | ||
241 | #endif /* MHD_POSIX_SOCKETS */ | ||
242 | |||
243 | memset (&sin, 0, sizeof(sin)); | ||
244 | sin.sin_family = AF_INET; | ||
245 | sin.sin_port = htons (*pport); | ||
246 | sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | ||
247 | if (0 != bind (skt, (struct sockaddr*) &sin, sizeof(sin))) | ||
248 | externalErrorExitDesc ("bind() failed"); | ||
249 | |||
250 | if (0 != listen (skt, SOMAXCONN)) | ||
251 | externalErrorExitDesc ("listen() failed"); | ||
252 | |||
253 | if (0 == *pport) | ||
254 | { | ||
255 | memset (&sin, 0, sizeof(sin)); | ||
256 | sin_len = sizeof(sin); | ||
257 | if (0 != getsockname (skt, (struct sockaddr *) &sin, &sin_len)) | ||
258 | externalErrorExitDesc ("getsockname() failed"); | ||
259 | |||
260 | if (sizeof(sin) < sin_len) | ||
261 | externalErrorExitDesc ("getsockname() failed"); | ||
262 | |||
263 | if (AF_INET != sin.sin_family) | ||
264 | externalErrorExitDesc ("getsockname() returned wrong socket family"); | ||
265 | |||
266 | *pport = (int) ntohs (sin.sin_port); | ||
267 | } | ||
268 | |||
269 | return skt; | ||
270 | } | ||
271 | |||
272 | |||
273 | static MHD_socket | ||
274 | acceptTimeLimited (MHD_socket lstn_sk, struct sockaddr *paddr, | ||
275 | socklen_t *paddr_len) | ||
276 | { | ||
277 | fd_set rs; | ||
278 | struct timeval timeoutval; | ||
279 | MHD_socket accepted; | ||
280 | |||
281 | FD_ZERO (&rs); | ||
282 | FD_SET (lstn_sk, &rs); | ||
283 | timeoutval.tv_sec = TIMEOUTS_VAL; | ||
284 | timeoutval.tv_usec = 0; | ||
285 | if (1 != select (((int) lstn_sk) + 1, &rs, NULL, NULL, &timeoutval)) | ||
286 | externalErrorExitDesc ("select() failed"); | ||
287 | |||
288 | accepted = accept (lstn_sk, paddr, paddr_len); | ||
289 | if (MHD_INVALID_SOCKET == accepted) | ||
290 | externalErrorExitDesc ("accept() failed"); | ||
291 | |||
292 | return accepted; | ||
293 | } | ||
294 | |||
295 | |||
296 | struct addConnParam | ||
297 | { | ||
298 | struct MHD_Daemon *d; | ||
299 | |||
300 | MHD_socket lstn_sk; | ||
301 | |||
302 | /* Non-zero indicate error */ | ||
303 | volatile int result; | ||
304 | |||
305 | #ifdef HAVE_PTHREAD_H | ||
306 | pthread_t addConnThread; | ||
307 | #endif /* HAVE_PTHREAD_H */ | ||
308 | }; | ||
309 | |||
310 | static int | ||
311 | doAcceptAndAddConnInThread (struct addConnParam *p) | ||
312 | { | ||
313 | MHD_socket newConn; | ||
314 | struct sockaddr addr; | ||
315 | socklen_t addr_len = sizeof(addr); | ||
316 | |||
317 | newConn = acceptTimeLimited (p->lstn_sk, &addr, &addr_len); | ||
318 | |||
319 | p->result = (MHD_YES == MHD_add_connection (p->d, newConn, &addr, addr_len)) ? | ||
320 | 0 : 1; | ||
321 | if (p->result) | ||
322 | fprintf (stderr, "MHD_add_connection() failed, errno=%d.\n", errno); | ||
323 | return p->result; | ||
324 | } | ||
325 | |||
326 | |||
327 | #ifdef HAVE_PTHREAD_H | ||
328 | static void * | ||
329 | doAcceptAndAddConn (void *param) | ||
330 | { | ||
331 | struct addConnParam *p = param; | ||
332 | |||
333 | (void) doAcceptAndAddConnInThread (p); | ||
334 | |||
335 | return (void*) p; | ||
336 | } | ||
337 | |||
338 | |||
339 | static void | ||
340 | startThreadAddConn (struct addConnParam *param) | ||
341 | { | ||
342 | /* thread must reset this value to zero if succeed */ | ||
343 | param->result = eMarker; | ||
344 | |||
345 | if (0 != pthread_create (¶m->addConnThread, NULL, &doAcceptAndAddConn, | ||
346 | (void*) param)) | ||
347 | externalErrorExitDesc ("pthread_create() failed"); | ||
348 | } | ||
349 | |||
350 | |||
351 | static int | ||
352 | finishThreadAddConn (struct addConnParam *param) | ||
353 | { | ||
354 | struct addConnParam *result; | ||
355 | |||
356 | if (0 != pthread_join (param->addConnThread, (void**) &result)) | ||
357 | externalErrorExitDesc ("pthread_join() failed"); | ||
358 | |||
359 | if (param != result) | ||
360 | abort (); /* Test used in a wrong way */ | ||
361 | |||
362 | if (eMarker == param->result) | ||
363 | abort (); /* Test used in a wrong way */ | ||
364 | |||
365 | return result->result; | ||
366 | } | ||
367 | |||
368 | |||
369 | #endif /* HAVE_PTHREAD_H */ | ||
370 | |||
371 | |||
372 | struct curlQueryParams | ||
373 | { | ||
374 | /* Destination path for CURL query */ | ||
375 | const char *queryPath; | ||
376 | |||
377 | /* Destination port for CURL query */ | ||
378 | int queryPort; | ||
379 | |||
380 | /* CURL query result error flag */ | ||
381 | volatile int queryError; | ||
382 | |||
383 | #ifdef HAVE_PTHREAD_H | ||
384 | pthread_t queryThread; | ||
385 | #endif /* HAVE_PTHREAD_H */ | ||
386 | }; | ||
387 | |||
388 | static CURL * | ||
389 | curlEasyInitForTest (const char *queryPath, int port, struct CBC *pcbc) | ||
390 | { | ||
391 | CURL *c; | ||
392 | |||
393 | c = curl_easy_init (); | ||
394 | if (NULL == c) | ||
395 | { | ||
396 | fprintf (stderr, "curl_easy_init() failed.\n"); | ||
397 | _exit (99); | ||
398 | } | ||
399 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); | ||
400 | curl_easy_setopt (c, CURLOPT_URL, queryPath); | ||
401 | curl_easy_setopt (c, CURLOPT_PORT, (long) port); | ||
402 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | ||
403 | curl_easy_setopt (c, CURLOPT_WRITEDATA, pcbc); | ||
404 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, (long) TIMEOUTS_VAL); | ||
405 | curl_easy_setopt (c, CURLOPT_TIMEOUT, (long) TIMEOUTS_VAL); | ||
406 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); | ||
407 | if (oneone) | ||
408 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); | ||
409 | else | ||
410 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); | ||
411 | |||
412 | return c; | ||
413 | } | ||
414 | |||
415 | |||
416 | static int | ||
417 | doCurlQueryInThread (struct curlQueryParams *p) | ||
418 | { | ||
419 | CURL *c; | ||
420 | char buf[2048]; | ||
421 | struct CBC cbc; | ||
422 | CURLcode errornum; | ||
423 | |||
424 | if (NULL == p->queryPath) | ||
425 | abort (); | ||
426 | |||
427 | if (0 == p->queryPort) | ||
428 | abort (); | ||
429 | |||
430 | cbc.buf = buf; | ||
431 | cbc.size = sizeof(buf); | ||
432 | cbc.pos = 0; | ||
433 | |||
434 | c = curlEasyInitForTest (p->queryPath, p->queryPort, &cbc); | ||
435 | |||
436 | errornum = curl_easy_perform (c); | ||
437 | if (CURLE_OK != errornum) | ||
438 | { | ||
439 | fprintf (stderr, | ||
440 | "curl_easy_perform failed: `%s'\n", | ||
441 | curl_easy_strerror (errornum)); | ||
442 | p->queryError = 2; | ||
443 | } | ||
444 | else | ||
445 | { | ||
446 | if (cbc.pos != strlen (EXPECTED_URI_BASE_PATH)) | ||
447 | { | ||
448 | fprintf (stderr, "curl reports wrong size of MHD reply body data.\n"); | ||
449 | p->queryError = 4; | ||
450 | } | ||
451 | else if (0 != strncmp (EXPECTED_URI_BASE_PATH, cbc.buf, | ||
452 | strlen (EXPECTED_URI_BASE_PATH))) | ||
453 | { | ||
454 | fprintf (stderr, "curl reports wrong MHD reply body data.\n"); | ||
455 | p->queryError = 4; | ||
456 | } | ||
457 | else | ||
458 | p->queryError = 0; | ||
459 | } | ||
460 | curl_easy_cleanup (c); | ||
461 | |||
462 | return p->queryError; | ||
463 | } | ||
464 | |||
465 | |||
466 | #ifdef HAVE_PTHREAD_H | ||
467 | static void * | ||
468 | doCurlQuery (void *param) | ||
469 | { | ||
470 | struct curlQueryParams *p = (struct curlQueryParams*) param; | ||
471 | |||
472 | (void) doCurlQueryInThread (p); | ||
473 | |||
474 | return param; | ||
475 | } | ||
476 | |||
477 | |||
478 | static void | ||
479 | startThreadCurlQuery (struct curlQueryParams *param) | ||
480 | { | ||
481 | /* thread must reset this value to zero if succeed */ | ||
482 | param->queryError = eMarker; | ||
483 | |||
484 | if (0 != pthread_create (¶m->queryThread, NULL, &doCurlQuery, | ||
485 | (void*) param)) | ||
486 | externalErrorExitDesc ("pthread_create() failed"); | ||
487 | } | ||
488 | |||
489 | |||
490 | static int | ||
491 | finishThreadCurlQuery (struct curlQueryParams *param) | ||
492 | { | ||
493 | struct curlQueryParams *result; | ||
494 | |||
495 | if (0 != pthread_join (param->queryThread, (void**) &result)) | ||
496 | externalErrorExitDesc ("pthread_join() failed"); | ||
497 | |||
498 | if (param != result) | ||
499 | abort (); /* Test used in wrong way */ | ||
500 | |||
501 | if (eMarker == param->queryError) | ||
502 | abort (); /* Test used in wrong way */ | ||
503 | |||
504 | return result->queryError; | ||
505 | } | ||
506 | |||
507 | |||
508 | /* Perform test queries and shut down MHD daemon */ | ||
509 | static int | ||
510 | performTestQueries (struct MHD_Daemon *d, int d_port) | ||
511 | { | ||
512 | struct curlQueryParams qParam; | ||
513 | struct addConnParam aParam; | ||
514 | int a_port = 0; /* Additional listening socket port */ | ||
515 | int ret = 0; /* Return value */ | ||
516 | |||
517 | qParam.queryPath = "http://127.0.0.1" EXPECTED_URI_FULL_PATH; | ||
518 | qParam.queryPort = 0; /* autoassign */ | ||
519 | |||
520 | aParam.d = d; | ||
521 | aParam.lstn_sk = createListeningSocket (&a_port); /* Sets a_port */ | ||
522 | |||
523 | /* Test of adding connection in the same thread */ | ||
524 | qParam.queryError = eMarker; /* to be zeroed in new thread */ | ||
525 | qParam.queryPort = a_port; /* Connect to additional socket */ | ||
526 | startThreadCurlQuery (&qParam); | ||
527 | ret |= doAcceptAndAddConnInThread (&aParam); | ||
528 | ret |= finishThreadCurlQuery (&qParam); | ||
529 | |||
530 | if (! no_listen) | ||
531 | { | ||
532 | /* Test of the daemon itself can accept and process new connection. */ | ||
533 | ret <<= 3; /* Remember errors for each step */ | ||
534 | qParam.queryPort = d_port; /* Connect to the daemon */ | ||
535 | ret |= doCurlQueryInThread (&qParam); | ||
536 | } | ||
537 | |||
538 | /* Test of adding connection in an external thread */ | ||
539 | ret <<= 3; /* Remember errors for each step */ | ||
540 | aParam.result = eMarker; /* to be zeroed in new thread */ | ||
541 | qParam.queryPort = a_port; /* Connect to the daemon */ | ||
542 | startThreadAddConn (&aParam); | ||
543 | ret |= doCurlQueryInThread (&qParam); | ||
544 | ret |= finishThreadAddConn (&aParam); | ||
545 | |||
546 | (void) MHD_socket_close_ (aParam.lstn_sk); | ||
547 | MHD_stop_daemon (d); | ||
548 | |||
549 | return ret; | ||
550 | } | ||
551 | |||
552 | |||
553 | #endif /* HAVE_PTHREAD_H */ | ||
554 | |||
555 | enum testMhdThreadsType | ||
556 | { | ||
557 | testMhdThreadExternal = 0, | ||
558 | testMhdThreadInternal = MHD_USE_INTERNAL_POLLING_THREAD, | ||
559 | testMhdThreadInternalPerConnection = MHD_USE_THREAD_PER_CONNECTION | ||
560 | | MHD_USE_INTERNAL_POLLING_THREAD, | ||
561 | testMhdThreadInternalPool | ||
562 | }; | ||
563 | |||
564 | enum testMhdPollType | ||
565 | { | ||
566 | testMhdPollBySelect = 0, | ||
567 | testMhdPollByPoll = MHD_USE_POLL, | ||
568 | testMhdPollByEpoll = MHD_USE_EPOLL, | ||
569 | testMhdPollAuto = MHD_USE_AUTO | ||
570 | }; | ||
571 | |||
572 | static struct MHD_Daemon * | ||
573 | startTestMhdDaemon (enum testMhdThreadsType thrType, | ||
574 | enum testMhdPollType pollType, int *pport) | ||
575 | { | ||
576 | struct MHD_Daemon *d; | ||
577 | const union MHD_DaemonInfo *dinfo; | ||
578 | |||
579 | if ( (0 == *pport) && | ||
580 | (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) ) | ||
581 | *pport = oneone ? 1550 : 1570; | ||
582 | |||
583 | if (testMhdThreadInternalPool != thrType) | ||
584 | d = MHD_start_daemon (((int) thrType) | ((int) pollType) | ||
585 | | (thrType == testMhdThreadExternal ? | ||
586 | 0 : MHD_USE_ITC) | ||
587 | | (no_listen ? MHD_USE_NO_LISTEN_SOCKET : 0) | ||
588 | | MHD_USE_ERROR_LOG, | ||
589 | *pport, NULL, NULL, | ||
590 | &ahc_echo, "GET", | ||
591 | MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL, | ||
592 | MHD_OPTION_END); | ||
593 | else | ||
594 | d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | ((int) pollType) | ||
595 | | MHD_USE_ITC | ||
596 | | (no_listen ? MHD_USE_NO_LISTEN_SOCKET : 0) | ||
597 | | MHD_USE_ERROR_LOG, | ||
598 | *pport, NULL, NULL, | ||
599 | &ahc_echo, "GET", | ||
600 | MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT, | ||
601 | MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL, | ||
602 | MHD_OPTION_END); | ||
603 | |||
604 | if (NULL == d) | ||
605 | { | ||
606 | fprintf (stderr, "Failed to start MHD daemon, errno=%d.\n", errno); | ||
607 | abort (); | ||
608 | } | ||
609 | |||
610 | if ((! no_listen) && (0 == *pport)) | ||
611 | { | ||
612 | dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); | ||
613 | if ((NULL == dinfo) || (0 == dinfo->port) ) | ||
614 | { | ||
615 | fprintf (stderr, "MHD_get_daemon_info() failed.\n"); | ||
616 | abort (); | ||
617 | } | ||
618 | *pport = (int) dinfo->port; | ||
619 | } | ||
620 | |||
621 | return d; | ||
622 | } | ||
623 | |||
624 | |||
625 | /* Test runners */ | ||
626 | |||
627 | |||
628 | static int | ||
629 | testExternalGet (void) | ||
630 | { | ||
631 | struct MHD_Daemon *d; | ||
632 | CURL *c_d; | ||
633 | char buf_d[2048]; | ||
634 | struct CBC cbc_d; | ||
635 | CURL *c_a; | ||
636 | char buf_a[2048]; | ||
637 | struct CBC cbc_a; | ||
638 | CURLM *multi; | ||
639 | time_t start; | ||
640 | struct timeval tv; | ||
641 | int d_port = global_port; /* Daemon's port */ | ||
642 | int a_port = 0; /* Additional listening socket port */ | ||
643 | struct addConnParam aParam; | ||
644 | int ret = 0; /* Return value of the test */ | ||
645 | |||
646 | d = startTestMhdDaemon (testMhdThreadExternal, testMhdPollBySelect, &d_port); | ||
647 | |||
648 | aParam.d = d; | ||
649 | aParam.lstn_sk = createListeningSocket (&a_port); | ||
650 | |||
651 | multi = NULL; | ||
652 | cbc_d.buf = buf_d; | ||
653 | cbc_d.size = sizeof(buf_d); | ||
654 | cbc_d.pos = 0; | ||
655 | cbc_a.buf = buf_a; | ||
656 | cbc_a.size = sizeof(buf_a); | ||
657 | cbc_a.pos = 0; | ||
658 | |||
659 | if (! no_listen) | ||
660 | c_d = curlEasyInitForTest ("http://127.0.0.1" EXPECTED_URI_FULL_PATH, | ||
661 | d_port, &cbc_d); | ||
662 | |||
663 | c_a = curlEasyInitForTest ("http://127.0.0.1" EXPECTED_URI_FULL_PATH, | ||
664 | a_port, &cbc_a); | ||
665 | |||
666 | multi = curl_multi_init (); | ||
667 | if (multi == NULL) | ||
668 | { | ||
669 | fprintf (stderr, "curl_multi_init() failed.\n"); | ||
670 | _exit (99); | ||
671 | } | ||
672 | if (! no_listen) | ||
673 | { | ||
674 | if (CURLM_OK != curl_multi_add_handle (multi, c_d)) | ||
675 | { | ||
676 | fprintf (stderr, "curl_multi_add_handle() failed.\n"); | ||
677 | _exit (99); | ||
678 | } | ||
679 | } | ||
680 | |||
681 | if (CURLM_OK != curl_multi_add_handle (multi, c_a)) | ||
682 | { | ||
683 | fprintf (stderr, "curl_multi_add_handle() failed.\n"); | ||
684 | _exit (99); | ||
685 | } | ||
686 | |||
687 | start = time (NULL); | ||
688 | while (time (NULL) - start <= TIMEOUTS_VAL) | ||
689 | { | ||
690 | fd_set rs; | ||
691 | fd_set ws; | ||
692 | fd_set es; | ||
693 | MHD_socket maxMhdSk; | ||
694 | int maxCurlSk; | ||
695 | int running; | ||
696 | |||
697 | maxMhdSk = MHD_INVALID_SOCKET; | ||
698 | maxCurlSk = -1; | ||
699 | FD_ZERO (&rs); | ||
700 | FD_ZERO (&ws); | ||
701 | FD_ZERO (&es); | ||
702 | curl_multi_perform (multi, &running); | ||
703 | if (0 == running) | ||
704 | { | ||
705 | struct CURLMsg *msg; | ||
706 | int msgLeft; | ||
707 | int totalMsgs = 0; | ||
708 | do | ||
709 | { | ||
710 | msg = curl_multi_info_read (multi, &msgLeft); | ||
711 | if (NULL == msg) | ||
712 | { | ||
713 | fprintf (stderr, "curl_multi_info_read failed, NULL returned.\n"); | ||
714 | _exit (99); | ||
715 | } | ||
716 | totalMsgs++; | ||
717 | if (CURLMSG_DONE == msg->msg) | ||
718 | { | ||
719 | if (CURLE_OK != msg->data.result) | ||
720 | { | ||
721 | fprintf (stderr, "curl_multi_info_read failed, error: '%s'\n", | ||
722 | curl_easy_strerror (msg->data.result)); | ||
723 | ret |= 2; | ||
724 | } | ||
725 | } | ||
726 | } while (msgLeft > 0); | ||
727 | if ((no_listen ? 1 : 2) != totalMsgs) | ||
728 | { | ||
729 | fprintf (stderr, | ||
730 | "curl_multi_info_read returned wrong " | ||
731 | "number of results (%d).\n", | ||
732 | totalMsgs); | ||
733 | _exit (99); | ||
734 | } | ||
735 | break; /* All transfers have finished. */ | ||
736 | } | ||
737 | if (CURLM_OK != curl_multi_fdset (multi, &rs, &ws, &es, &maxCurlSk)) | ||
738 | { | ||
739 | fprintf (stderr, "curl_multi_fdset() failed.\n"); | ||
740 | _exit (99); | ||
741 | } | ||
742 | if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxMhdSk)) | ||
743 | { | ||
744 | ret |= 8; | ||
745 | break; | ||
746 | } | ||
747 | FD_SET (aParam.lstn_sk, &rs); | ||
748 | if (maxMhdSk < aParam.lstn_sk) | ||
749 | maxMhdSk = aParam.lstn_sk; | ||
750 | tv.tv_sec = 0; | ||
751 | tv.tv_usec = 1000; | ||
752 | #ifdef MHD_POSIX_SOCKETS | ||
753 | if (maxMhdSk > maxCurlSk) | ||
754 | maxCurlSk = maxMhdSk; | ||
755 | #endif /* MHD_POSIX_SOCKETS */ | ||
756 | if (-1 == select (maxCurlSk + 1, &rs, &ws, &es, &tv)) | ||
757 | { | ||
758 | #ifdef MHD_POSIX_SOCKETS | ||
759 | if (EINTR != errno) | ||
760 | externalErrorExitDesc ("select() failed"); | ||
761 | #else | ||
762 | if ((WSAEINVAL != WSAGetLastError ()) || (0 != rs.fd_count) || (0 != | ||
763 | ws. | ||
764 | fd_count) | ||
765 | || (0 != es.fd_count) ) | ||
766 | externalErrorExitDesc ("select() failed"); | ||
767 | Sleep (1000); | ||
768 | #endif | ||
769 | } | ||
770 | if (FD_ISSET (aParam.lstn_sk, &rs)) | ||
771 | ret |= doAcceptAndAddConnInThread (&aParam); | ||
772 | |||
773 | if (MHD_YES != MHD_run_from_select (d, &rs, &ws, &es)) | ||
774 | { | ||
775 | fprintf (stderr, "MHD_run_from_select() failed.\n"); | ||
776 | ret |= 1; | ||
777 | break; | ||
778 | } | ||
779 | } | ||
780 | |||
781 | MHD_stop_daemon (d); | ||
782 | (void) MHD_socket_close_ (aParam.lstn_sk); | ||
783 | |||
784 | if (! no_listen) | ||
785 | { | ||
786 | curl_multi_remove_handle (multi, c_d); | ||
787 | curl_easy_cleanup (c_d); | ||
788 | if (cbc_d.pos != strlen ("/hello_world")) | ||
789 | { | ||
790 | fprintf (stderr, | ||
791 | "curl reports wrong size of MHD reply body data at line %d.\n", | ||
792 | __LINE__); | ||
793 | ret |= 4; | ||
794 | } | ||
795 | if (0 != strncmp ("/hello_world", cbc_d.buf, strlen ("/hello_world"))) | ||
796 | { | ||
797 | fprintf (stderr, "curl reports wrong MHD reply body data at line %d.\n", | ||
798 | __LINE__); | ||
799 | ret |= 4; | ||
800 | } | ||
801 | } | ||
802 | curl_multi_remove_handle (multi, c_a); | ||
803 | curl_easy_cleanup (c_a); | ||
804 | curl_multi_cleanup (multi); | ||
805 | if (cbc_a.pos != strlen ("/hello_world")) | ||
806 | { | ||
807 | fprintf (stderr, | ||
808 | "curl reports wrong size of MHD reply body data at line %d.\n", | ||
809 | __LINE__); | ||
810 | ret |= 4; | ||
811 | } | ||
812 | if (0 != strncmp ("/hello_world", cbc_a.buf, strlen ("/hello_world"))) | ||
813 | { | ||
814 | fprintf (stderr, "curl reports wrong MHD reply body data at line %d.\n", | ||
815 | __LINE__); | ||
816 | ret |= 4; | ||
817 | } | ||
818 | return ret; | ||
819 | } | ||
820 | |||
821 | |||
822 | #ifdef HAVE_PTHREAD_H | ||
823 | static int | ||
824 | testInternalGet (enum testMhdPollType pollType) | ||
825 | { | ||
826 | struct MHD_Daemon *d; | ||
827 | int d_port = global_port; /* Daemon's port */ | ||
828 | |||
829 | d = startTestMhdDaemon (testMhdThreadInternal, pollType, | ||
830 | &d_port); | ||
831 | |||
832 | return performTestQueries (d, d_port); | ||
833 | } | ||
834 | |||
835 | |||
836 | static int | ||
837 | testMultithreadedGet (enum testMhdPollType pollType) | ||
838 | { | ||
839 | struct MHD_Daemon *d; | ||
840 | int d_port = global_port; /* Daemon's port */ | ||
841 | |||
842 | d = startTestMhdDaemon (testMhdThreadInternalPerConnection, pollType, | ||
843 | &d_port); | ||
844 | |||
845 | return performTestQueries (d, d_port); | ||
846 | } | ||
847 | |||
848 | |||
849 | static int | ||
850 | testMultithreadedPoolGet (enum testMhdPollType pollType) | ||
851 | { | ||
852 | struct MHD_Daemon *d; | ||
853 | int d_port = global_port; /* Daemon's port */ | ||
854 | |||
855 | d = startTestMhdDaemon (testMhdThreadInternalPool, pollType, | ||
856 | &d_port); | ||
857 | |||
858 | return performTestQueries (d, d_port); | ||
859 | } | ||
860 | |||
861 | |||
862 | static int | ||
863 | testStopRace (enum testMhdPollType pollType) | ||
864 | { | ||
865 | struct MHD_Daemon *d; | ||
866 | int d_port = global_port; /* Daemon's port */ | ||
867 | int a_port = 0; /* Additional listening socket port */ | ||
868 | struct sockaddr_in sin; | ||
869 | MHD_socket fd1; | ||
870 | MHD_socket fd2; | ||
871 | struct addConnParam aParam; | ||
872 | int ret = 0; /* Return value of the test */ | ||
873 | |||
874 | d = startTestMhdDaemon (testMhdThreadInternal, pollType, | ||
875 | &d_port); | ||
876 | |||
877 | if (! no_listen) | ||
878 | { | ||
879 | fd1 = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); | ||
880 | if (MHD_INVALID_SOCKET == fd1) | ||
881 | externalErrorExitDesc ("socket() failed"); | ||
882 | |||
883 | memset (&sin, 0, sizeof(sin)); | ||
884 | sin.sin_family = AF_INET; | ||
885 | sin.sin_port = htons (d_port); | ||
886 | sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | ||
887 | if (connect (fd1, (struct sockaddr *) (&sin), sizeof(sin)) < 0) | ||
888 | externalErrorExitDesc ("socket() failed"); | ||
889 | } | ||
890 | |||
891 | aParam.d = d; | ||
892 | aParam.lstn_sk = createListeningSocket (&a_port); /* Sets a_port */ | ||
893 | startThreadAddConn (&aParam); | ||
894 | |||
895 | fd2 = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); | ||
896 | if (MHD_INVALID_SOCKET == fd2) | ||
897 | externalErrorExitDesc ("socket() failed"); | ||
898 | memset (&sin, 0, sizeof(sin)); | ||
899 | sin.sin_family = AF_INET; | ||
900 | sin.sin_port = htons (a_port); | ||
901 | sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | ||
902 | if (connect (fd2, (struct sockaddr *) (&sin), sizeof(sin)) < 0) | ||
903 | externalErrorExitDesc ("socket() failed"); | ||
904 | ret |= finishThreadAddConn (&aParam); | ||
905 | |||
906 | /* Let the thread get going. */ | ||
907 | usleep (500000); | ||
908 | |||
909 | MHD_stop_daemon (d); | ||
910 | |||
911 | if (! no_listen) | ||
912 | (void) MHD_socket_close_ (fd1); | ||
913 | (void) MHD_socket_close_ (aParam.lstn_sk); | ||
914 | (void) MHD_socket_close_ (fd2); | ||
915 | |||
916 | return ret; | ||
917 | } | ||
918 | |||
919 | |||
920 | #endif /* HAVE_PTHREAD_H */ | ||
921 | |||
922 | |||
923 | int | ||
924 | main (int argc, char *const *argv) | ||
925 | { | ||
926 | unsigned int errorCount = 0; | ||
927 | unsigned int test_result = 0; | ||
928 | int verbose = 0; | ||
929 | |||
930 | if ((NULL == argv) || (0 == argv[0])) | ||
931 | return 99; | ||
932 | oneone = has_in_name (argv[0], "11"); | ||
933 | no_listen = has_in_name (argv[0], "_nolisten"); | ||
934 | verbose = ! has_param (argc, argv, "-q") || has_param (argc, argv, "--quiet"); | ||
935 | if (0 != curl_global_init (CURL_GLOBAL_WIN32)) | ||
936 | return 2; | ||
937 | /* Could be set to non-zero value to enforce using specific port | ||
938 | * in the test */ | ||
939 | global_port = 0; | ||
940 | test_result = testExternalGet (); | ||
941 | if (test_result) | ||
942 | fprintf (stderr, "FAILED: testExternalGet () - %u.\n", test_result); | ||
943 | else if (verbose) | ||
944 | printf ("PASSED: testExternalGet ().\n"); | ||
945 | errorCount += test_result; | ||
946 | #ifdef HAVE_PTHREAD_H | ||
947 | if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS)) | ||
948 | { | ||
949 | test_result = testInternalGet (testMhdPollBySelect); | ||
950 | if (test_result) | ||
951 | fprintf (stderr, "FAILED: testInternalGet (testMhdPollBySelect) - %u.\n", | ||
952 | test_result); | ||
953 | else if (verbose) | ||
954 | printf ("PASSED: testInternalGet (testMhdPollBySelect).\n"); | ||
955 | errorCount += test_result; | ||
956 | test_result = testMultithreadedGet (testMhdPollBySelect); | ||
957 | if (test_result) | ||
958 | fprintf (stderr, | ||
959 | "FAILED: testMultithreadedGet (testMhdPollBySelect) - %u.\n", | ||
960 | test_result); | ||
961 | else if (verbose) | ||
962 | printf ("PASSED: testMultithreadedGet (testMhdPollBySelect).\n"); | ||
963 | errorCount += test_result; | ||
964 | test_result = testMultithreadedPoolGet (testMhdPollBySelect); | ||
965 | if (test_result) | ||
966 | fprintf (stderr, | ||
967 | "FAILED: testMultithreadedPoolGet (testMhdPollBySelect) - %u.\n", | ||
968 | test_result); | ||
969 | else if (verbose) | ||
970 | printf ("PASSED: testMultithreadedPoolGet (testMhdPollBySelect).\n"); | ||
971 | errorCount += test_result; | ||
972 | test_result = testStopRace (testMhdPollBySelect); | ||
973 | if (test_result) | ||
974 | fprintf (stderr, "FAILED: testStopRace (testMhdPollBySelect) - %u.\n", | ||
975 | test_result); | ||
976 | else if (verbose) | ||
977 | printf ("PASSED: testStopRace (testMhdPollBySelect).\n"); | ||
978 | errorCount += test_result; | ||
979 | if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_POLL)) | ||
980 | { | ||
981 | test_result = testInternalGet (testMhdPollByPoll); | ||
982 | if (test_result) | ||
983 | fprintf (stderr, "FAILED: testInternalGet (testMhdPollByPoll) - %u.\n", | ||
984 | test_result); | ||
985 | else if (verbose) | ||
986 | printf ("PASSED: testInternalGet (testMhdPollByPoll).\n"); | ||
987 | errorCount += test_result; | ||
988 | test_result = testMultithreadedGet (testMhdPollByPoll); | ||
989 | if (test_result) | ||
990 | fprintf (stderr, | ||
991 | "FAILED: testMultithreadedGet (testMhdPollByPoll) - %u.\n", | ||
992 | test_result); | ||
993 | else if (verbose) | ||
994 | printf ("PASSED: testMultithreadedGet (testMhdPollByPoll).\n"); | ||
995 | errorCount += test_result; | ||
996 | test_result = testMultithreadedPoolGet (testMhdPollByPoll); | ||
997 | if (test_result) | ||
998 | fprintf (stderr, | ||
999 | "FAILED: testMultithreadedPoolGet (testMhdPollByPoll) - %u.\n", | ||
1000 | test_result); | ||
1001 | else if (verbose) | ||
1002 | printf ("PASSED: testMultithreadedPoolGet (testMhdPollByPoll).\n"); | ||
1003 | errorCount += test_result; | ||
1004 | test_result = testStopRace (testMhdPollByPoll); | ||
1005 | if (test_result) | ||
1006 | fprintf (stderr, "FAILED: testStopRace (testMhdPollByPoll) - %u.\n", | ||
1007 | test_result); | ||
1008 | else if (verbose) | ||
1009 | printf ("PASSED: testStopRace (testMhdPollByPoll).\n"); | ||
1010 | errorCount += test_result; | ||
1011 | } | ||
1012 | if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_EPOLL)) | ||
1013 | { | ||
1014 | test_result = testInternalGet (testMhdPollByEpoll); | ||
1015 | if (test_result) | ||
1016 | fprintf (stderr, "FAILED: testInternalGet (testMhdPollByEpoll) - %u.\n", | ||
1017 | test_result); | ||
1018 | else if (verbose) | ||
1019 | printf ("PASSED: testInternalGet (testMhdPollByEpoll).\n"); | ||
1020 | errorCount += test_result; | ||
1021 | test_result = testMultithreadedPoolGet (testMhdPollByEpoll); | ||
1022 | if (test_result) | ||
1023 | fprintf (stderr, | ||
1024 | "FAILED: testMultithreadedPoolGet (testMhdPollByEpoll) - %u.\n", | ||
1025 | test_result); | ||
1026 | else if (verbose) | ||
1027 | printf ("PASSED: testMultithreadedPoolGet (testMhdPollByEpoll).\n"); | ||
1028 | errorCount += test_result; | ||
1029 | } | ||
1030 | } | ||
1031 | #endif /* HAVE_PTHREAD_H */ | ||
1032 | if (0 != errorCount) | ||
1033 | fprintf (stderr, | ||
1034 | "Error (code: %u)\n", | ||
1035 | errorCount); | ||
1036 | else if (verbose) | ||
1037 | printf ("All tests passed.\n"); | ||
1038 | curl_global_cleanup (); | ||
1039 | return (errorCount == 0) ? 0 : 1; /* 0 == pass */ | ||
1040 | } | ||