aboutsummaryrefslogtreecommitdiff
path: root/src/transport/test_transport_api_reliability.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2010-05-31 07:55:27 +0000
committerChristian Grothoff <christian@grothoff.org>2010-05-31 07:55:27 +0000
commit4a8b0022e6235b9912d02a8e92c020bea1ac1798 (patch)
treea5c5dbaee05c86af33404c9e113c1ff731565084 /src/transport/test_transport_api_reliability.c
parent9c94d4241e499cedfb7696f18793dba8c722e26b (diff)
downloadgnunet-4a8b0022e6235b9912d02a8e92c020bea1ac1798.tar.gz
gnunet-4a8b0022e6235b9912d02a8e92c020bea1ac1798.zip
testcase
Diffstat (limited to 'src/transport/test_transport_api_reliability.c')
-rw-r--r--src/transport/test_transport_api_reliability.c438
1 files changed, 438 insertions, 0 deletions
diff --git a/src/transport/test_transport_api_reliability.c b/src/transport/test_transport_api_reliability.c
new file mode 100644
index 000000000..9b2c167cb
--- /dev/null
+++ b/src/transport/test_transport_api_reliability.c
@@ -0,0 +1,438 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009, 2010 Christian Grothoff (and other contributing authors)
4
5 GNUnet 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 GNUnet 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 GNUnet; 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 * @file transport/test_transport_api_reliability.c
22 * @brief base test case for transport implementations
23 *
24 * This test case serves as a base for tcp and http
25 * transport test cases to check that the transports
26 * achieve reliable message delivery.
27 */
28#include "platform.h"
29#include "gnunet_common.h"
30#include "gnunet_hello_lib.h"
31#include "gnunet_getopt_lib.h"
32#include "gnunet_os_lib.h"
33#include "gnunet_program_lib.h"
34#include "gnunet_scheduler_lib.h"
35#include "gnunet_transport_service.h"
36#include "transport.h"
37
38#define VERBOSE GNUNET_YES
39
40#define VERBOSE_ARM GNUNET_NO
41
42#define START_ARM GNUNET_YES
43
44#define TOTAL_MSGS (60000 * 2)
45
46/**
47 * How long until we give up on transmitting the message?
48 */
49#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300)
50
51#define MTYPE 12345
52
53struct PeerContext
54{
55 struct GNUNET_CONFIGURATION_Handle *cfg;
56 struct GNUNET_TRANSPORT_Handle *th;
57 struct GNUNET_PeerIdentity id;
58#if START_ARM
59 pid_t arm_pid;
60#endif
61};
62
63static struct PeerContext p1;
64
65static struct PeerContext p2;
66
67static struct GNUNET_SCHEDULER_Handle *sched;
68
69static int ok;
70
71static int is_tcp;
72
73static int is_http;
74
75static GNUNET_SCHEDULER_TaskIdentifier die_task;
76
77#if VERBOSE
78#define OKPP do { ok++; fprintf (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
79#else
80#define OKPP do { ok++; } while (0)
81#endif
82
83
84static void
85end ()
86{
87 GNUNET_assert (ok == 6);
88 GNUNET_SCHEDULER_cancel (sched, die_task);
89 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from transports!\n");
90 GNUNET_TRANSPORT_disconnect (p1.th);
91 GNUNET_TRANSPORT_disconnect (p2.th);
92
93 die_task = GNUNET_SCHEDULER_NO_TASK;
94 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
95 "Transports disconnected, returning success!\n");
96 ok = 0;
97}
98
99
100static void
101stop_arm (struct PeerContext *p)
102{
103#if START_ARM
104 if (0 != PLIBC_KILL (p->arm_pid, SIGTERM))
105 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
106 GNUNET_OS_process_wait (p->arm_pid);
107#endif
108 GNUNET_CONFIGURATION_destroy (p->cfg);
109}
110
111
112static void
113end_badly (void *cls,
114 const struct GNUNET_SCHEDULER_TaskContext *tc)
115{
116 GNUNET_break (0);
117 GNUNET_TRANSPORT_disconnect (p1.th);
118 GNUNET_TRANSPORT_disconnect (p2.th);
119 ok = 1;
120}
121
122
123struct TestMessage
124{
125 struct GNUNET_MessageHeader header;
126 uint32_t num;
127};
128
129
130static unsigned int
131get_size (unsigned int iter)
132{
133 unsigned int ret;
134 if (iter < 60000)
135 return iter + sizeof (struct TestMessage);
136 ret = (iter * iter * iter);
137 return sizeof (struct TestMessage) + (ret % 60000);
138}
139
140
141static void
142notify_receive (void *cls,
143 const struct GNUNET_PeerIdentity *peer,
144 const struct GNUNET_MessageHeader *message,
145 struct GNUNET_TIME_Relative latency,
146 uint32_t distance)
147{
148 static int n;
149 unsigned int s;
150 const struct TestMessage *hdr;
151
152 hdr = (const struct TestMessage*) message;
153 s = get_size (n);
154 if (MTYPE != ntohs (message->type))
155 return;
156 if (ntohs (message->size) != s)
157 {
158 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
159 "Expected message %u of size %u, got %u bytes of message %u\n",
160 n, s,
161 ntohs (message->size),
162 ntohl (hdr->num));
163 GNUNET_SCHEDULER_cancel (sched, die_task);
164 die_task = GNUNET_SCHEDULER_add_now (sched, &end_badly, NULL);
165 return;
166 }
167 if (ntohl (hdr->num) != n)
168 {
169 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
170 "Expected message %u of size %u, got %u bytes of message %u\n",
171 n, s,
172 ntohs (message->size),
173 ntohl (hdr->num));
174 GNUNET_SCHEDULER_cancel (sched, die_task);
175 die_task = GNUNET_SCHEDULER_add_now (sched, &end_badly, NULL);
176 return;
177 }
178 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
179 "Got message %u of size %u\n",
180 ntohl (hdr->num),
181 ntohs (message->size));
182 n++;
183 if (n == TOTAL_MSGS)
184 end ();
185}
186
187
188static size_t
189notify_ready (void *cls, size_t size, void *buf)
190{
191 static int n;
192 char *cbuf = buf;
193 struct TestMessage hdr;
194 unsigned int s;
195 unsigned int ret;
196
197 if (buf == NULL)
198 {
199 GNUNET_break (0);
200 ok = 42;
201 return 0;
202 }
203 ret = 0;
204 s = get_size (n);
205 GNUNET_assert (size >= s);
206 GNUNET_assert (buf != NULL);
207 cbuf = buf;
208 do
209 {
210 hdr.header.size = htons (s);
211 hdr.header.type = htons (MTYPE);
212 hdr.num = htonl (n);
213 memcpy (&cbuf[ret], &hdr, sizeof (struct TestMessage));
214 ret += sizeof (struct TestMessage);
215 memset (&cbuf[ret], n, s - sizeof (struct TestMessage));
216 ret += s - sizeof (struct TestMessage);
217 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
218 "Sending message %u of size %u\n",
219 n,
220 s);
221 n++;
222 s = get_size (n);
223 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16))
224 break; /* sometimes pack buffer full, sometimes not */
225 }
226 while (size - ret >= s);
227 if (n < TOTAL_MSGS)
228 GNUNET_TRANSPORT_notify_transmit_ready (p1.th,
229 &p2.id,
230 s, 0, TIMEOUT,
231 &notify_ready,
232 NULL);
233 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
234 "Returning total message block of size %u\n",
235 ret);
236 return ret;
237}
238
239
240static void
241notify_connect (void *cls,
242 const struct GNUNET_PeerIdentity *peer,
243 struct GNUNET_TIME_Relative latency,
244 uint32_t distance)
245{
246 if (cls == &p1)
247 {
248 GNUNET_TRANSPORT_set_quota (p1.th,
249 &p2.id,
250 GNUNET_BANDWIDTH_value_init (1024 * 1024 * 1024),
251 GNUNET_BANDWIDTH_value_init (1024 * 1024 * 1024),
252 GNUNET_TIME_UNIT_FOREVER_REL,
253 NULL, NULL);
254 GNUNET_TRANSPORT_notify_transmit_ready (p1.th,
255 &p2.id,
256 get_size (0), 0, TIMEOUT,
257 &notify_ready,
258 NULL);
259 }
260 else
261 {
262 GNUNET_TRANSPORT_set_quota (p2.th,
263 &p1.id,
264 GNUNET_BANDWIDTH_value_init (1024 * 1024 * 1024),
265 GNUNET_BANDWIDTH_value_init (1024 * 1024 * 1024),
266 GNUNET_TIME_UNIT_FOREVER_REL,
267 NULL, NULL);
268 }
269 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
270 "Peer `%4s' connected to us (%p)!\n", GNUNET_i2s (peer), cls);
271}
272
273
274static void
275notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
276{
277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
278 "Peer `%4s' disconnected (%p)!\n",
279 GNUNET_i2s (peer), cls);
280}
281
282
283static void
284setup_peer (struct PeerContext *p, const char *cfgname)
285{
286 p->cfg = GNUNET_CONFIGURATION_create ();
287#if START_ARM
288 p->arm_pid = GNUNET_OS_start_process (NULL, NULL,
289 "gnunet-service-arm",
290 "gnunet-service-arm",
291#if VERBOSE_ARM
292 "-L", "DEBUG",
293#endif
294 "-c", cfgname, NULL);
295#endif
296 GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
297 p->th = GNUNET_TRANSPORT_connect (sched, p->cfg,
298 p,
299 &notify_receive,
300 &notify_connect,
301 &notify_disconnect);
302 GNUNET_assert (p->th != NULL);
303}
304
305
306static void
307exchange_hello_last (void *cls,
308 const struct GNUNET_MessageHeader *message)
309{
310 struct PeerContext *me = cls;
311
312 GNUNET_TRANSPORT_get_hello_cancel (p2.th, &exchange_hello_last, me);
313 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
314 "Exchanging HELLO with peer (%p)!\n", cls);
315 GNUNET_assert (ok >= 3);
316 OKPP;
317 GNUNET_assert (message != NULL);
318 GNUNET_assert (GNUNET_OK ==
319 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *)
320 message, &me->id));
321 /* both HELLOs exchanged, get ready to test transmission! */
322 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
323 "Finished exchanging HELLOs, now waiting for transmission!\n");
324}
325
326
327static void
328exchange_hello (void *cls,
329 const struct GNUNET_MessageHeader *message)
330{
331 struct PeerContext *me = cls;
332
333 GNUNET_TRANSPORT_get_hello_cancel (p1.th, &exchange_hello, me);
334 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
335 "Exchanging HELLO with peer (%p)!\n", cls);
336 GNUNET_assert (ok >= 2);
337 OKPP;
338 GNUNET_assert (message != NULL);
339 GNUNET_assert (GNUNET_OK ==
340 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *)
341 message, &me->id));
342
343 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
344 "Received HELLO size %d\n", GNUNET_HELLO_size((const struct GNUNET_HELLO_Message *)message));
345
346 GNUNET_TRANSPORT_offer_hello (p2.th, message);
347 GNUNET_TRANSPORT_get_hello (p2.th, &exchange_hello_last, &p2);
348}
349
350
351static void
352run (void *cls,
353 struct GNUNET_SCHEDULER_Handle *s,
354 char *const *args,
355 const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
356{
357 GNUNET_assert (ok == 1);
358 OKPP;
359 sched = s;
360 die_task = GNUNET_SCHEDULER_add_delayed (sched,
361 TIMEOUT,
362 &end_badly,
363 NULL);
364 if (is_tcp)
365 {
366 setup_peer (&p1, "test_transport_api_tcp_peer1.conf");
367 setup_peer (&p2, "test_transport_api_tcp_peer2.conf");
368 }
369 else if (is_http)
370 {
371 setup_peer (&p1, "test_transport_api_http_peer1.conf");
372 setup_peer (&p2, "test_transport_api_http_peer2.conf");
373 }
374 else
375 GNUNET_assert (0);
376 GNUNET_assert(p1.th != NULL);
377 GNUNET_assert(p2.th != NULL);
378 GNUNET_TRANSPORT_get_hello (p1.th, &exchange_hello, &p1);
379}
380
381
382static int
383check ()
384{
385 char *const argv[] = { "test-transport-api-reliability",
386 "-c",
387 "test_transport_api_data.conf",
388#if VERBOSE
389 "-L", "DEBUG",
390#endif
391 NULL
392 };
393 struct GNUNET_GETOPT_CommandLineOption options[] = {
394 GNUNET_GETOPT_OPTION_END
395 };
396
397#if WRITECONFIG
398 setTransportOptions("test_transport_api_data.conf");
399#endif
400 ok = 1;
401 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
402 argv, "test-transport-api", "nohelp",
403 options, &run, &ok);
404 stop_arm (&p1);
405 stop_arm (&p2);
406 return ok;
407}
408
409
410int
411main (int argc, char *argv[])
412{
413 int ret;
414#ifdef MINGW
415 return GNUNET_SYSERR;
416#endif
417 if (strstr(argv[0], "tcp") != NULL)
418 {
419 is_tcp = GNUNET_YES;
420 }
421 else if (strstr(argv[0], "http") != NULL)
422 {
423 is_http = GNUNET_YES;
424 }
425 GNUNET_log_setup ("test-transport-api-reliability",
426#if VERBOSE
427 "DEBUG",
428#else
429 "WARNING",
430#endif
431 NULL);
432 ret = check ();
433 GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-transport-peer-1");
434 GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-transport-peer-2");
435 return ret;
436}
437
438/* end of test_transport_api_reliability.c */