aboutsummaryrefslogtreecommitdiff
path: root/src/testzzuf
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2008-04-13 02:28:23 +0000
committerChristian Grothoff <christian@grothoff.org>2008-04-13 02:28:23 +0000
commit2369ddff276508b0387443ff4cbdd4986f513a3e (patch)
treef72d9dd67b4814d128dd84555bb9110f61ede1d3 /src/testzzuf
parentec8aedc77bbaa293dc76d2aba98fc8ce1243cf68 (diff)
downloadlibmicrohttpd-2369ddff276508b0387443ff4cbdd4986f513a3e.tar.gz
libmicrohttpd-2369ddff276508b0387443ff4cbdd4986f513a3e.zip
socat-ing get'
'
Diffstat (limited to 'src/testzzuf')
-rw-r--r--src/testzzuf/Makefile.am2
-rw-r--r--src/testzzuf/README13
-rw-r--r--src/testzzuf/daemontest_get.c298
-rw-r--r--src/testzzuf/socat.c99
4 files changed, 258 insertions, 154 deletions
diff --git a/src/testzzuf/Makefile.am b/src/testzzuf/Makefile.am
index 0ebaf893..9e9d27a3 100644
--- a/src/testzzuf/Makefile.am
+++ b/src/testzzuf/Makefile.am
@@ -2,6 +2,8 @@ SUBDIRS = .
2 2
3INCLUDES = -I$(top_srcdir)/src/include 3INCLUDES = -I$(top_srcdir)/src/include
4 4
5EXTRA_DIST = README socat.c
6
5check_PROGRAMS = \ 7check_PROGRAMS = \
6 daemontest_get \ 8 daemontest_get \
7 daemontest_post \ 9 daemontest_post \
diff --git a/src/testzzuf/README b/src/testzzuf/README
new file mode 100644
index 00000000..5ee15698
--- /dev/null
+++ b/src/testzzuf/README
@@ -0,0 +1,13 @@
1Testcases in this directory require zzuf and socat.
2
3zzuf is used to randomly mess with the TCP connection between the CURL
4clients and the MHD server. The goal is to expose problems in MHD's
5error handling (by introducing random syntax errors). socat is
6used to listen on port 11081 and forward the randomzied stream to
7port 11080 where MHD is waiting.
8
9As a result, the testcases in this directory do NOT check that
10whatever CURL returns is what was expected -- random modifications to
11the TCP stream can have random effects ;-). Testcases "fail" if the
12code crashes or hangs indefinitely.
13
diff --git a/src/testzzuf/daemontest_get.c b/src/testzzuf/daemontest_get.c
index 2d5729c1..d7b11f3e 100644
--- a/src/testzzuf/daemontest_get.c
+++ b/src/testzzuf/daemontest_get.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of libmicrohttpd 2 This file is part of libmicrohttpd
3 (C) 2007 Christian Grothoff 3 (C) 2007, 2008 Christian Grothoff
4 4
5 libmicrohttpd is free software; you can redistribute it and/or modify 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 6 it under the terms of the GNU General Public License as published
@@ -21,7 +21,6 @@
21/** 21/**
22 * @file daemontest_get.c 22 * @file daemontest_get.c
23 * @brief Testcase for libmicrohttpd GET operations 23 * @brief Testcase for libmicrohttpd GET operations
24 * TODO: test parsing of query
25 * @author Christian Grothoff 24 * @author Christian Grothoff
26 */ 25 */
27 26
@@ -36,6 +35,18 @@
36#include <unistd.h> 35#include <unistd.h>
37#endif 36#endif
38 37
38#include "socat.c"
39
40/**
41 * A larger loop count will run more random tests --
42 * which would be good, except that it may take too
43 * long for most user's patience. So this small
44 * value is the default.
45 */
46#define LOOP_COUNT 10
47
48#define CURL_TIMEOUT 50L
49
39static int oneone; 50static int oneone;
40 51
41struct CBC 52struct CBC
@@ -96,45 +107,39 @@ testInternalGet ()
96 CURL *c; 107 CURL *c;
97 char buf[2048]; 108 char buf[2048];
98 struct CBC cbc; 109 struct CBC cbc;
99 CURLcode errornum; 110 int i;
100 111
101 cbc.buf = buf; 112 cbc.buf = buf;
102 cbc.size = 2048; 113 cbc.size = 2048;
103 cbc.pos = 0; 114 cbc.pos = 0;
104 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, 115 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */,
105 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); 116 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
106 if (d == NULL) 117 if (d == NULL)
107 return 1; 118 return 1;
108 c = curl_easy_init (); 119 zzuf_socat_start();
109 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11080/hello_world"); 120 for (i=0;i<LOOP_COUNT;i++) {
110 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer); 121 fprintf(stderr, ".");
111 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 122 c = curl_easy_init ();
112 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); 123 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world");
113 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 124 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
114 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); 125 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
115 if (oneone) 126 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
116 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 127 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
117 else 128 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
118 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 129 if (oneone)
119 // NOTE: use of CONNECTTIMEOUT without also 130 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
120 // setting NOSIGNAL results in really weird 131 else
121 // crashes on my system! 132 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
122 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); 133 // NOTE: use of CONNECTTIMEOUT without also
123 if (CURLE_OK != (errornum = curl_easy_perform (c))) 134 // setting NOSIGNAL results in really weird
124 { 135 // crashes on my system!
125 fprintf (stderr, 136 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
126 "curl_easy_perform failed: `%s'\n", 137 curl_easy_perform (c);
127 curl_easy_strerror (errornum)); 138 curl_easy_cleanup (c);
128 curl_easy_cleanup (c); 139 }
129 MHD_stop_daemon (d); 140 fprintf(stderr, "\n");
130 return 2; 141 zzuf_socat_stop();
131 }
132 curl_easy_cleanup (c);
133 MHD_stop_daemon (d); 142 MHD_stop_daemon (d);
134 if (cbc.pos != strlen ("/hello_world"))
135 return 4;
136 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
137 return 8;
138 return 0; 143 return 0;
139} 144}
140 145
@@ -145,45 +150,39 @@ testMultithreadedGet ()
145 CURL *c; 150 CURL *c;
146 char buf[2048]; 151 char buf[2048];
147 struct CBC cbc; 152 struct CBC cbc;
148 CURLcode errornum; 153 int i;
149 154
150 cbc.buf = buf; 155 cbc.buf = buf;
151 cbc.size = 2048; 156 cbc.size = 2048;
152 cbc.pos = 0; 157 cbc.pos = 0;
153 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, 158 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION /* | MHD_USE_DEBUG */,
154 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); 159 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
155 if (d == NULL) 160 if (d == NULL)
156 return 16; 161 return 16;
157 c = curl_easy_init (); 162 zzuf_socat_start();
158 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world"); 163 for (i=0;i<LOOP_COUNT;i++) {
159 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer); 164 fprintf(stderr, ".");
160 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); 165 c = curl_easy_init ();
161 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); 166 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world");
162 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 167 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
163 if (oneone) 168 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
164 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 169 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
165 else 170 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
166 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 171 if (oneone)
167 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); 172 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
168 // NOTE: use of CONNECTTIMEOUT without also 173 else
169 // setting NOSIGNAL results in really weird 174 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
170 // crashes on my system! 175 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
171 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); 176 // NOTE: use of CONNECTTIMEOUT without also
172 if (CURLE_OK != (errornum = curl_easy_perform (c))) 177 // setting NOSIGNAL results in really weird
173 { 178 // crashes on my system!
174 fprintf (stderr, 179 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
175 "curl_easy_perform failed: `%s'\n", 180 curl_easy_perform (c);
176 curl_easy_strerror (errornum)); 181 curl_easy_cleanup (c);
177 curl_easy_cleanup (c); 182 }
178 MHD_stop_daemon (d); 183 fprintf(stderr, "\n");
179 return 32; 184 zzuf_socat_stop();
180 }
181 curl_easy_cleanup (c);
182 MHD_stop_daemon (d); 185 MHD_stop_daemon (d);
183 if (cbc.pos != strlen ("/hello_world"))
184 return 64;
185 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
186 return 128;
187 return 0; 186 return 0;
188} 187}
189 188
@@ -202,35 +201,18 @@ testExternalGet ()
202 fd_set es; 201 fd_set es;
203 int max; 202 int max;
204 int running; 203 int running;
205 struct CURLMsg *msg;
206 time_t start; 204 time_t start;
207 struct timeval tv; 205 struct timeval tv;
206 int i;
208 207
209 multi = NULL; 208 multi = NULL;
210 cbc.buf = buf; 209 cbc.buf = buf;
211 cbc.size = 2048; 210 cbc.size = 2048;
212 cbc.pos = 0; 211 cbc.pos = 0;
213 d = MHD_start_daemon (MHD_USE_DEBUG, 212 d = MHD_start_daemon (MHD_NO_FLAG /* | MHD_USE_DEBUG*/,
214 1082, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); 213 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
215 if (d == NULL) 214 if (d == NULL)
216 return 256; 215 return 256;
217 c = curl_easy_init ();
218 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1082/hello_world");
219 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
220 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
221 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
222 if (oneone)
223 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
224 else
225 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
226 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
227 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
228 // NOTE: use of CONNECTTIMEOUT without also
229 // setting NOSIGNAL results in really weird
230 // crashes on my system!
231 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
232
233
234 multi = curl_multi_init (); 216 multi = curl_multi_init ();
235 if (multi == NULL) 217 if (multi == NULL)
236 { 218 {
@@ -238,75 +220,83 @@ testExternalGet ()
238 MHD_stop_daemon (d); 220 MHD_stop_daemon (d);
239 return 512; 221 return 512;
240 } 222 }
241 mret = curl_multi_add_handle (multi, c); 223 zzuf_socat_start();
242 if (mret != CURLM_OK) 224 for (i=0;i<LOOP_COUNT;i++) {
243 { 225 fprintf(stderr, ".");
244 curl_multi_cleanup (multi); 226 c = curl_easy_init ();
245 curl_easy_cleanup (c); 227 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world");
246 MHD_stop_daemon (d); 228 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
247 return 1024; 229 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
248 } 230 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
249 start = time (NULL); 231 if (oneone)
250 while ((time (NULL) - start < 5) && (multi != NULL)) 232 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
251 { 233 else
252 max = 0; 234 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
253 FD_ZERO (&rs); 235 curl_easy_setopt (c, CURLOPT_TIMEOUT_MS, CURL_TIMEOUT);
254 FD_ZERO (&ws); 236 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT_MS, CURL_TIMEOUT);
255 FD_ZERO (&es); 237 // NOTE: use of CONNECTTIMEOUT without also
256 curl_multi_perform (multi, &running); 238 // setting NOSIGNAL results in really weird
257 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); 239 // crashes on my system!
258 if (mret != CURLM_OK) 240 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
259 { 241 mret = curl_multi_add_handle (multi, c);
260 curl_multi_remove_handle (multi, c); 242 if (mret != CURLM_OK)
261 curl_multi_cleanup (multi); 243 {
262 curl_easy_cleanup (c); 244 curl_multi_cleanup (multi);
263 MHD_stop_daemon (d); 245 curl_easy_cleanup (c);
264 return 2048; 246 zzuf_socat_stop();
265 } 247 MHD_stop_daemon (d);
266 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) 248 return 1024;
267 { 249 }
268 curl_multi_remove_handle (multi, c); 250 start = time (NULL);
269 curl_multi_cleanup (multi); 251 while ((time (NULL) - start < 5) && (c != NULL))
270 curl_easy_cleanup (c); 252 {
271 MHD_stop_daemon (d); 253 max = 0;
272 return 4096; 254 FD_ZERO (&rs);
273 } 255 FD_ZERO (&ws);
274 tv.tv_sec = 0; 256 FD_ZERO (&es);
275 tv.tv_usec = 1000; 257 curl_multi_perform (multi, &running);
276 select (max + 1, &rs, &ws, &es, &tv); 258 mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
277 curl_multi_perform (multi, &running); 259 if (mret != CURLM_OK)
278 if (running == 0) 260 {
279 { 261 curl_multi_remove_handle (multi, c);
280 msg = curl_multi_info_read (multi, &running); 262 curl_multi_cleanup (multi);
281 if (msg == NULL) 263 curl_easy_cleanup (c);
282 break; 264 zzuf_socat_stop();
283 if (msg->msg == CURLMSG_DONE) 265 MHD_stop_daemon (d);
284 { 266 return 2048;
285 if (msg->data.result != CURLE_OK) 267 }
286 printf ("%s failed at %s:%d: `%s'\n", 268 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
287 "curl_multi_perform", 269 {
288 __FILE__, 270 curl_multi_remove_handle (multi, c);
289 __LINE__, curl_easy_strerror (msg->data.result)); 271 curl_multi_cleanup (multi);
290 curl_multi_remove_handle (multi, c); 272 curl_easy_cleanup (c);
291 curl_multi_cleanup (multi); 273 zzuf_socat_stop();
292 curl_easy_cleanup (c); 274 MHD_stop_daemon (d);
293 c = NULL; 275 return 4096;
294 multi = NULL; 276 }
295 } 277 tv.tv_sec = 0;
296 } 278 tv.tv_usec = 1000;
297 MHD_run (d); 279 select (max + 1, &rs, &ws, &es, &tv);
298 } 280 curl_multi_perform (multi, &running);
299 if (multi != NULL) 281 if (running == 0)
300 { 282 {
301 curl_multi_remove_handle (multi, c); 283 curl_multi_info_read (multi, &running);
302 curl_easy_cleanup (c); 284 curl_multi_remove_handle (multi, c);
303 curl_multi_cleanup (multi); 285 curl_easy_cleanup (c);
304 } 286 c = NULL;
287 }
288 MHD_run (d);
289 }
290 if (c != NULL)
291 {
292 curl_multi_remove_handle (multi, c);
293 curl_easy_cleanup (c);
294 }
295 }
296 fprintf(stderr, "\n");
297 curl_multi_cleanup (multi);
298 zzuf_socat_stop();
305 MHD_stop_daemon (d); 299 MHD_stop_daemon (d);
306 if (cbc.pos != strlen ("/hello_world"))
307 return 8192;
308 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
309 return 16384;
310 return 0; 300 return 0;
311} 301}
312 302
@@ -322,7 +312,7 @@ main (int argc, char *const *argv)
322 return 2; 312 return 2;
323 errorCount += testInternalGet (); 313 errorCount += testInternalGet ();
324 errorCount += testMultithreadedGet (); 314 errorCount += testMultithreadedGet ();
325 errorCount += testExternalGet (); 315 errorCount += testExternalGet ();
326 if (errorCount != 0) 316 if (errorCount != 0)
327 fprintf (stderr, "Error (code: %u)\n", errorCount); 317 fprintf (stderr, "Error (code: %u)\n", errorCount);
328 curl_global_cleanup (); 318 curl_global_cleanup ();
diff --git a/src/testzzuf/socat.c b/src/testzzuf/socat.c
new file mode 100644
index 00000000..b8948575
--- /dev/null
+++ b/src/testzzuf/socat.c
@@ -0,0 +1,99 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2008 Christian Grothoff
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 2, 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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file socat.c
23 * @brief Code to fork-exec zzuf and start the socat process
24 * @author Christian Grothoff
25 */
26
27#include <errno.h>
28#include <sys/types.h>
29#include <sys/wait.h>
30#include <signal.h>
31
32
33static pid_t zzuf_pid;
34
35static void
36zzuf_socat_start() {
37 int status;
38 char * const args[] = {
39 "zzuf",
40 "--ratio=0.0:0.75",
41 "-n",
42 "-A",
43 "socat",
44 "TCP4-LISTEN:11081,reuseaddr,fork",
45 "TCP4:127.0.0.1:11080",
46 NULL,
47 };
48 zzuf_pid = fork();
49 if (zzuf_pid == -1) {
50 fprintf(stderr,
51 "fork failed: %s\n",
52 strerror(errno));
53 exit(1);
54 }
55 if (zzuf_pid != 0)
56 {
57 sleep(1); /* allow zzuf and socat to start */
58 status = 0;
59 if (0 < waitpid(zzuf_pid, &status, WNOHANG))
60 {
61 if (WIFEXITED(status))
62 fprintf(stderr,
63 "zzuf died with status code %d!\n",
64 WEXITSTATUS(status));
65 if (WIFSIGNALED(status))
66 fprintf(stderr,
67 "zzuf died from signal %d!\n",
68 WTERMSIG(status));
69 exit(1);
70 }
71 return;
72 }
73 setpgrp();
74 execvp("zzuf",
75 args);
76 fprintf(stderr,
77 "execution of `zzuf' failed: %s\n",
78 strerror(errno));
79 zzuf_pid = 0; /* fork failed */
80 exit(1);
81}
82
83
84static void
85zzuf_socat_stop() {
86 int status;
87 if (zzuf_pid != 0)
88 {
89 if (0 != killpg(zzuf_pid, SIGINT))
90 fprintf(stderr,
91 "Failed to killpg: %s\n",
92 strerror(errno));
93 kill(zzuf_pid, SIGINT);
94 waitpid(zzuf_pid, &status, 0);
95 sleep(1); /* allow socat to also die in peace */
96 }
97}
98
99/* end of socat.c */