aboutsummaryrefslogtreecommitdiff
path: root/src/testing/test_testing_topology.c
diff options
context:
space:
mode:
authorNathan S. Evans <evans@in.tum.de>2010-02-26 10:44:15 +0000
committerNathan S. Evans <evans@in.tum.de>2010-02-26 10:44:15 +0000
commiteb98ca5b7a3d2377f2422d453b5b0fe445cf6329 (patch)
tree235d47d54d8abe7763d363f71627f22f2955b848 /src/testing/test_testing_topology.c
parentbd668ec4112fa46c3ce69ebebc9457d43dee7fa5 (diff)
downloadgnunet-eb98ca5b7a3d2377f2422d453b5b0fe445cf6329.tar.gz
gnunet-eb98ca5b7a3d2377f2422d453b5b0fe445cf6329.zip
towards better topology testing, still a kink or two
Diffstat (limited to 'src/testing/test_testing_topology.c')
-rw-r--r--src/testing/test_testing_topology.c664
1 files changed, 664 insertions, 0 deletions
diff --git a/src/testing/test_testing_topology.c b/src/testing/test_testing_topology.c
new file mode 100644
index 000000000..a8d1a4a8c
--- /dev/null
+++ b/src/testing/test_testing_topology.c
@@ -0,0 +1,664 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009 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 testing/test_testing_topology.c
22 * @brief base testcase for testing all the topologies provided
23 */
24#include "platform.h"
25#include "gnunet_testing_lib.h"
26#include "gnunet_core_service.h"
27
28#define VERBOSE GNUNET_YES
29
30/**
31 * How long until we give up on connecting the peers?
32 */
33#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
34
35#define DEFAULT_NUM_PEERS 4;
36
37static int ok;
38
39static unsigned long long num_peers;
40
41static unsigned int total_connections;
42
43static unsigned int total_server_connections;
44
45static unsigned int total_messages_received;
46
47static unsigned int expected_messages;
48
49static unsigned int expected_connections;
50
51static int peers_left;
52
53static struct GNUNET_TESTING_PeerGroup *pg;
54
55static struct GNUNET_SCHEDULER_Handle *sched;
56
57const struct GNUNET_CONFIGURATION_Handle *main_cfg;
58
59GNUNET_SCHEDULER_TaskIdentifier die_task;
60
61static char *dotOutFileName = "topology.dot";
62
63static FILE *dotOutFile;
64
65static char *topology_string;
66
67static int transmit_ready_scheduled;
68
69static int transmit_ready_called;
70
71struct TestMessageContext *global_pos;
72
73#define MTYPE 12345
74
75struct TestMessageContext
76{
77 /* This is a linked list */
78 struct TestMessageContext *next;
79
80 /* Handle to the sending peer core */
81 struct GNUNET_CORE_Handle *peer1handle;
82
83 /* Handle to the receiving peer core */
84 struct GNUNET_CORE_Handle *peer2handle;
85
86 /* Handle to the sending peer daemon */
87 struct GNUNET_TESTING_Daemon *peer1;
88
89 /* Handle to the receiving peer daemon */
90 struct GNUNET_TESTING_Daemon *peer2;
91
92 /* Maintain some state */
93 int first_step_done;
94
95};
96
97struct Connection
98{
99 struct Connection *next;
100 struct GNUNET_TESTING_Daemon *peer;
101 struct GNUNET_CORE_Handle *server;
102};
103
104static struct Connection *global_connections;
105
106static struct TestMessageContext *test_messages;
107
108static void
109finish_testing ()
110{
111 GNUNET_assert (pg != NULL);
112 struct Connection *pos;
113#if VERBOSE
114 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
115 "Called finish testing, stopping daemons.\n");
116#endif
117 int count;
118 count = 0;
119 pos = global_connections;
120 while (pos != NULL)
121 {
122 if (pos->server != NULL)
123 {
124 GNUNET_CORE_disconnect(pos->server);
125 pos->server = NULL;
126 }
127 pos = pos->next;
128 }
129#if VERBOSE
130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
131 "transmit_ready's scheduled %d, transmit_ready's called %d\n", transmit_ready_scheduled, transmit_ready_called);
132#endif
133 sleep(1);
134#if VERBOSE
135 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
136 "Calling daemons_stop\n");
137#endif
138 GNUNET_TESTING_daemons_stop (pg);
139#if VERBOSE
140 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
141 "daemons_stop finished\n");
142#endif
143 if (dotOutFile != NULL)
144 {
145 fprintf(dotOutFile, "}");
146 fclose(dotOutFile);
147 }
148
149 ok = 0;
150}
151
152static int
153process_mtype (void *cls,
154 const struct GNUNET_PeerIdentity *peer,
155 const struct GNUNET_MessageHeader *message,
156 struct GNUNET_TIME_Relative latency,
157 uint32_t distance)
158{
159 total_messages_received++;
160#if VERBOSE
161 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
162 "Received message from `%4s', type %d.\n", GNUNET_i2s (peer), ntohs(message->type));
163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
164 "Total messages received %d, expected %d.\n", total_messages_received, expected_messages);
165#endif
166
167 if (total_messages_received == expected_messages)
168 {
169 GNUNET_SCHEDULER_cancel (sched, die_task);
170 GNUNET_SCHEDULER_add_now (sched, &finish_testing, NULL);
171 }
172 return GNUNET_OK;
173}
174
175static void
176end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
177{
178#if VERBOSE
179 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
180 "End badly was called... stopping daemons.\n");
181#endif
182 struct Connection *pos;
183
184 pos = global_connections;
185 while (pos != NULL)
186 {
187 if (pos->server != NULL)
188 {
189 GNUNET_CORE_disconnect(pos->server);
190 pos->server = NULL;
191 }
192 pos = pos->next;
193 }
194
195 if (pg != NULL)
196 {
197 GNUNET_TESTING_daemons_stop (pg);
198 ok = 7331; /* Opposite of leet */
199 }
200 else
201 ok = 401; /* Never got peers started */
202
203 if (dotOutFile != NULL)
204 {
205 fprintf(dotOutFile, "}");
206 fclose(dotOutFile);
207 }
208}
209
210
211/**
212 * Forward declaration.
213 */
214static size_t
215transmit_ready (void *cls, size_t size, void *buf);
216
217static void
218schedule_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
219{
220
221 if (global_pos != NULL)
222 {
223 if (NULL == GNUNET_CORE_notify_transmit_ready (global_pos->peer1handle,
224 0,
225 TIMEOUT,
226 &global_pos->peer2->id,
227 sizeof (struct GNUNET_MessageHeader),
228 &transmit_ready, &global_pos->peer1->id))
229 {
230 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
231 "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n",
232 GNUNET_i2s (&global_pos->peer2->id));
233 }
234 else
235 {
236 transmit_ready_scheduled++;
237 }
238 global_pos = global_pos->next;
239 }
240 else
241 {
242 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
243 "Transmit ready scheduled on %d messages\n",
244 transmit_ready_scheduled);
245 }
246
247}
248
249static size_t
250transmit_ready (void *cls, size_t size, void *buf)
251{
252 struct GNUNET_MessageHeader *m;
253 struct GNUNET_PeerIdentity *peer = cls;
254 GNUNET_assert (buf != NULL);
255 m = (struct GNUNET_MessageHeader *) buf;
256 m->type = htons (MTYPE);
257 m->size = htons (sizeof (struct GNUNET_MessageHeader));
258
259 transmit_ready_called++;
260#if VERBOSE
261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
262 "transmit ready for peer %s\ntransmit_ready's scheduled %d, transmit_ready's called %d\n", GNUNET_i2s(peer), transmit_ready_scheduled, transmit_ready_called);
263#endif
264 GNUNET_SCHEDULER_add_now(sched, &schedule_transmission, NULL);
265 return sizeof (struct GNUNET_MessageHeader);
266}
267
268
269static struct GNUNET_CORE_MessageHandler handlers[] = {
270 {&process_mtype, MTYPE, sizeof (struct GNUNET_MessageHeader)},
271 {NULL, 0, 0}
272};
273
274
275
276static void
277send_test_messages ()
278{
279 struct TestMessageContext *pos;
280 struct Connection *conn_pos;
281 die_task = GNUNET_SCHEDULER_add_delayed (sched,
282 TIMEOUT,
283 &end_badly, "from send test messages");
284
285 int count = 0;
286 int conn_count = 0;
287 pos = test_messages;
288 while (pos != NULL)
289 {
290 conn_pos = global_connections;
291 conn_count = 0;
292 while (conn_pos != NULL)
293 {
294 if (conn_pos->peer == pos->peer1)
295 {
296 pos->peer1handle = conn_pos->server;
297 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
298 "Peer matched conn_count %d\n",
299 conn_count);
300 break;
301 }
302 conn_count++;
303 conn_pos = conn_pos->next;
304 }
305 GNUNET_assert(pos->peer1handle != NULL);
306
307 /*
308 if (NULL == GNUNET_CORE_notify_transmit_ready (pos->peer1handle,
309 0,
310 TIMEOUT,
311 &pos->peer2->id,
312 sizeof (struct GNUNET_MessageHeader),
313 &transmit_ready, &pos->peer1->id))
314 {
315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
316 "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n",
317 GNUNET_i2s (&pos->peer2->id));
318 }
319 else
320 {
321 transmit_ready_scheduled++;
322 }
323 */
324 pos = pos->next;
325 count++;
326 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
327 "Prepared %d messages\n",
328 count);
329 }
330
331 global_pos = test_messages;
332
333 GNUNET_SCHEDULER_add_now(sched, &schedule_transmission, NULL);
334}
335
336
337
338static void
339init_notify (void *cls,
340 struct GNUNET_CORE_Handle *server,
341 const struct GNUNET_PeerIdentity *my_identity,
342 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
343{
344 struct Connection *connection = cls;
345
346#if VERBOSE
347 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
348 "Core connection to `%4s' established, setting up handles\n",
349 GNUNET_i2s (my_identity));
350#endif
351 connection->server = server;
352 total_server_connections++;
353
354 if (total_server_connections == num_peers)
355 {
356 GNUNET_SCHEDULER_cancel(sched, die_task);
357 GNUNET_SCHEDULER_add_now(sched, &send_test_messages, NULL);
358 }
359#if OLD
360 if (context->first_step_done == GNUNET_NO)
361 {
362 context->peer1handle = server;
363#if VERBOSE
364 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting core to peer 2\n");
365#endif
366 context->first_step_done = GNUNET_YES;
367 /* connect p2 */
368 GNUNET_CORE_connect (sched,
369 context->peer2->cfg,
370 TIMEOUT,
371 context,
372 &init_notify,
373 NULL,
374 NULL,
375 NULL,
376 NULL,
377 GNUNET_YES,
378 NULL, GNUNET_YES, handlers);
379
380 }
381 else
382 {
383 context->peer2handle = server;
384#if VERBOSE
385 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
386 "Asking core (1) for transmission to peer `%4s'\n",
387 GNUNET_i2s (&context->peer2->id));
388#endif
389 transmit_ready_scheduled++;
390 if (NULL == GNUNET_CORE_notify_transmit_ready (context->peer1->server,
391 0,
392 TIMEOUT,
393 &context->peer2->id,
394 sizeof (struct GNUNET_MessageHeader),
395 &transmit_ready, NULL))
396 {
397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
398 "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n",
399 GNUNET_i2s (&context->peer2->id));
400 }
401 }
402#endif
403}
404
405
406static void
407setup_handlers ()
408{
409 int i;
410 struct Connection *new_connection;
411
412 struct GNUNET_TESTING_Daemon *temp_daemon;
413 die_task = GNUNET_SCHEDULER_add_delayed (sched,
414 TIMEOUT,
415 &end_badly, "from setup_handlers");
416
417
418 /**
419 * Set up a single handler for each peer
420 */
421 for (i = 0; i < num_peers; i++)
422 {
423 new_connection = GNUNET_malloc(sizeof(struct Connection));
424 temp_daemon = GNUNET_TESTING_daemon_get(pg, i);
425 new_connection->peer = temp_daemon;
426 new_connection->server = NULL;
427 new_connection->next = global_connections;
428 global_connections = new_connection;
429
430 GNUNET_CORE_connect (sched,
431 temp_daemon->cfg,
432 TIMEOUT,
433 new_connection,
434 &init_notify,
435 NULL,
436 NULL,
437 NULL,
438 NULL,
439 GNUNET_YES, NULL, GNUNET_YES, handlers);
440 }
441}
442
443
444
445void
446topology_callback (void *cls,
447 const struct GNUNET_PeerIdentity *first,
448 const struct GNUNET_PeerIdentity *second,
449 const struct GNUNET_CONFIGURATION_Handle *first_cfg,
450 const struct GNUNET_CONFIGURATION_Handle *second_cfg,
451 struct GNUNET_TESTING_Daemon *first_daemon,
452 struct GNUNET_TESTING_Daemon *second_daemon,
453 const char *emsg)
454{
455 struct TestMessageContext *temp_context;
456 if (emsg == NULL)
457 {
458 total_connections++;
459#if VERBOSE
460 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s\n",
461 first_daemon->shortname,
462 second_daemon->shortname);
463#endif
464 temp_context = GNUNET_malloc(sizeof(struct TestMessageContext));
465 temp_context->first_step_done = 0;
466 temp_context->peer1handle = NULL;
467 temp_context->peer1 = first_daemon;
468 temp_context->peer2 = second_daemon;
469 temp_context->peer2handle = NULL;
470 temp_context->next = test_messages;
471 test_messages = temp_context;
472
473 expected_messages++;
474 if (dotOutFile != NULL)
475 fprintf(dotOutFile, "\tn%s -- n%s;\n", first_daemon->shortname, second_daemon->shortname);
476 }
477#if VERBOSE
478 else
479 {
480
481 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect peer %s to peer %s with error %s\n",
482 first_daemon->shortname,
483 second_daemon->shortname, emsg);
484 }
485#endif
486
487 if (total_connections == expected_connections)
488 {
489#if VERBOSE
490 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
491 "Created %d total connections, which is our target number! Calling send messages.\n",
492 total_connections);
493#endif
494
495 GNUNET_SCHEDULER_cancel (sched, die_task);
496 die_task = GNUNET_SCHEDULER_add_now (sched, &setup_handlers, NULL);
497 }
498 else
499 {
500#if VERBOSE
501 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
502 "Have %d total connections, Need %d\n",
503 total_connections, expected_connections);
504#endif
505 }
506}
507
508
509static void
510create_topology ()
511{
512 expected_connections = -1;
513 if ((pg != NULL) && (peers_left == 0))
514 {
515 /* create_topology will read the topology information from
516 the config already contained in the peer group, so should
517 we have create_topology called from start peers? I think
518 maybe this way is best so that the client can know both
519 when peers are started, and when they are connected.
520 */
521 expected_connections = GNUNET_TESTING_create_topology (pg);
522#if VERBOSE
523 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
524 "Have %d expected connections\n", expected_connections);
525#endif
526 }
527
528 GNUNET_SCHEDULER_cancel (sched, die_task);
529 if (expected_connections == GNUNET_SYSERR)
530 {
531 die_task = GNUNET_SCHEDULER_add_now (sched,
532 &end_badly, NULL);
533 }
534 die_task = GNUNET_SCHEDULER_add_delayed (sched,
535 TIMEOUT,
536 &end_badly, NULL);
537}
538
539
540static void
541my_cb (void *cls,
542 const struct GNUNET_PeerIdentity *id,
543 const struct GNUNET_CONFIGURATION_Handle *cfg,
544 struct GNUNET_TESTING_Daemon *d, const char *emsg)
545{
546 GNUNET_assert (id != NULL);
547#if VERBOSE
548 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %d out of %d\n",
549 (num_peers - peers_left) + 1, num_peers);
550#endif
551 peers_left--;
552 if (peers_left == 0)
553 {
554#if VERBOSE
555 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
556 "All %d daemons started, now creating topology!\n",
557 num_peers);
558#endif
559 GNUNET_SCHEDULER_cancel (sched, die_task);
560 /* Set up task in case topology creation doesn't finish
561 * within a reasonable amount of time */
562 die_task = GNUNET_SCHEDULER_add_delayed (sched,
563 GNUNET_TIME_relative_multiply
564 (GNUNET_TIME_UNIT_MINUTES, 5),
565 &end_badly, NULL);
566 create_topology ();
567 ok = 0;
568 }
569}
570
571
572static void
573run (void *cls,
574 struct GNUNET_SCHEDULER_Handle *s,
575 char *const *args,
576 const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
577{
578 sched = s;
579 ok = 1;
580
581 dotOutFile = fopen (dotOutFileName, "w");
582 if (dotOutFile != NULL)
583 {
584 fprintf (dotOutFile, "strict graph G {\n");
585 }
586
587#if VERBOSE
588 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
589 "Starting daemons based on config file %s\n", cfgfile);
590#endif
591 if (GNUNET_SYSERR ==
592 GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers",
593 &num_peers))
594 num_peers = DEFAULT_NUM_PEERS;
595
596 main_cfg = cfg;
597
598 peers_left = num_peers;
599
600 /* Set up a task to end testing if peer start fails */
601 die_task = GNUNET_SCHEDULER_add_delayed (sched,
602 GNUNET_TIME_relative_multiply
603 (GNUNET_TIME_UNIT_MINUTES, 5),
604 &end_badly, NULL);
605
606 pg = GNUNET_TESTING_daemons_start (sched, cfg,
607 peers_left, &my_cb, NULL,
608 &topology_callback, NULL, NULL);
609
610}
611
612static int
613check ()
614{
615 char *binary_name;
616 char *config_file_name;
617 GNUNET_asprintf(&binary_name, "test-testing-topology-%s", topology_string);
618 GNUNET_asprintf(&config_file_name, "test_testing_data_topology_%s.conf", topology_string);
619 char *const argv[] = {binary_name,
620 "-c",
621 config_file_name,
622#if VERBOSE
623 "-L", "DEBUG",
624#endif
625 NULL
626 };
627 struct GNUNET_GETOPT_CommandLineOption options[] = {
628 GNUNET_GETOPT_OPTION_END
629 };
630 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
631 argv, binary_name, "nohelp",
632 options, &run, &ok);
633 return ok;
634}
635
636int
637main (int argc, char *argv[])
638{
639 int ret;
640 char *binary_start_pos;
641 char *our_binary_name;
642 binary_start_pos = rindex(argv[0], '/');
643 if (strstr(binary_start_pos, "test_testing_topology_") == NULL)
644 {
645 return GNUNET_SYSERR;
646 }
647
648 topology_string = &binary_start_pos[23];
649
650 GNUNET_asprintf(&our_binary_name, "test-testing-topology_%s", topology_string);
651 GNUNET_log_setup (our_binary_name,
652#if VERBOSE
653 "DEBUG",
654#else
655 "WARNING",
656#endif
657 NULL);
658 ret = check ();
659 sleep (1);
660 GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing");
661 return ret;
662}
663
664/* end of test_testing_group.c */