2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
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.
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.
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.
21 * @file testing/test_testing_topology.c
22 * @brief base testcase for testing all the topologies provided
25 #include "gnunet_testing_lib.h"
26 #include "gnunet_core_service.h"
28 #define VERBOSE GNUNET_NO
31 #define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 360)
33 * How long until we give up on connecting the peers?
35 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
37 #define DEFAULT_NUM_PEERS 4;
41 static unsigned long long num_peers;
43 static unsigned int total_connections;
45 static unsigned int total_server_connections;
47 static unsigned int total_messages_received;
49 static unsigned int expected_messages;
51 static unsigned int expected_connections;
53 static int peers_left;
55 static struct GNUNET_TESTING_PeerGroup *pg;
57 static struct GNUNET_SCHEDULER_Handle *sched;
59 const struct GNUNET_CONFIGURATION_Handle *main_cfg;
61 GNUNET_SCHEDULER_TaskIdentifier die_task;
63 static char *dotOutFileName = "topology.dot";
65 static FILE *dotOutFile;
67 static char *topology_string;
69 static int transmit_ready_scheduled;
71 static int transmit_ready_called;
73 struct TestMessageContext *global_pos;
77 struct TestMessageContext
79 /* This is a linked list */
80 struct TestMessageContext *next;
82 /* Handle to the sending peer core */
83 struct GNUNET_CORE_Handle *peer1handle;
85 /* Handle to the receiving peer core */
86 struct GNUNET_CORE_Handle *peer2handle;
88 /* Handle to the sending peer daemon */
89 struct GNUNET_TESTING_Daemon *peer1;
91 /* Handle to the receiving peer daemon */
92 struct GNUNET_TESTING_Daemon *peer2;
94 /* Maintain some state */
101 struct Connection *next;
102 struct GNUNET_TESTING_Daemon *peer;
103 struct GNUNET_CORE_Handle *server;
106 static struct Connection *global_connections;
108 static struct TestMessageContext *test_messages;
113 GNUNET_assert (pg != NULL);
114 struct Connection *pos;
116 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
117 "Called finish testing, stopping daemons.\n");
121 pos = global_connections;
124 if (pos->server != NULL)
126 GNUNET_CORE_disconnect(pos->server);
132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
133 "transmit_ready's scheduled %d, transmit_ready's called %d\n", transmit_ready_scheduled, transmit_ready_called);
137 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
138 "Calling daemons_stop\n");
140 GNUNET_TESTING_daemons_stop (pg);
142 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
143 "daemons_stop finished\n");
145 if (dotOutFile != NULL)
147 fprintf(dotOutFile, "}");
155 process_mtype (void *cls,
156 const struct GNUNET_PeerIdentity *peer,
157 const struct GNUNET_MessageHeader *message,
158 struct GNUNET_TIME_Relative latency,
161 total_messages_received++;
163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
164 "Received message from `%4s', type %d.\n", GNUNET_i2s (peer), ntohs(message->type));
165 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
166 "Total messages received %d, expected %d.\n", total_messages_received, expected_messages);
169 if (total_messages_received == expected_messages)
171 GNUNET_SCHEDULER_cancel (sched, die_task);
172 GNUNET_SCHEDULER_add_now (sched, &finish_testing, NULL);
178 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
182 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
183 "End badly was called (%s)... stopping daemons.\n", msg);
185 struct Connection *pos;
187 pos = global_connections;
190 if (pos->server != NULL)
192 GNUNET_CORE_disconnect(pos->server);
200 GNUNET_TESTING_daemons_stop (pg);
201 ok = 7331; /* Opposite of leet */
204 ok = 401; /* Never got peers started */
206 if (dotOutFile != NULL)
208 fprintf(dotOutFile, "}");
215 * Forward declaration.
218 transmit_ready (void *cls, size_t size, void *buf);
221 schedule_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
224 if (global_pos != NULL)
226 if (NULL == GNUNET_CORE_notify_transmit_ready (global_pos->peer1handle,
229 &global_pos->peer2->id,
230 sizeof (struct GNUNET_MessageHeader),
231 &transmit_ready, &global_pos->peer1->id))
233 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
234 "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n",
235 GNUNET_i2s (&global_pos->peer2->id));
239 transmit_ready_scheduled++;
241 global_pos = global_pos->next;
245 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
246 "Transmit ready scheduled on %d messages\n",
247 transmit_ready_scheduled);
253 transmit_ready (void *cls, size_t size, void *buf)
255 struct GNUNET_MessageHeader *m;
257 struct GNUNET_PeerIdentity *peer = cls;
259 GNUNET_assert (buf != NULL);
260 m = (struct GNUNET_MessageHeader *) buf;
261 m->type = htons (MTYPE);
262 m->size = htons (sizeof (struct GNUNET_MessageHeader));
264 transmit_ready_called++;
266 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
267 "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);
269 GNUNET_SCHEDULER_add_now(sched, &schedule_transmission, NULL);
270 return sizeof (struct GNUNET_MessageHeader);
274 static struct GNUNET_CORE_MessageHandler handlers[] = {
275 {&process_mtype, MTYPE, sizeof (struct GNUNET_MessageHeader)},
282 send_test_messages ()
284 struct TestMessageContext *pos;
285 struct Connection *conn_pos;
286 die_task = GNUNET_SCHEDULER_add_delayed (sched,
288 &end_badly, "from send test messages");
295 conn_pos = global_connections;
297 while (conn_pos != NULL)
299 if (conn_pos->peer == pos->peer1)
301 pos->peer1handle = conn_pos->server;
302 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
303 "Peer matched conn_count %d\n",
308 conn_pos = conn_pos->next;
310 GNUNET_assert(pos->peer1handle != NULL);
313 if (NULL == GNUNET_CORE_notify_transmit_ready (pos->peer1handle,
317 sizeof (struct GNUNET_MessageHeader),
318 &transmit_ready, &pos->peer1->id))
320 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
321 "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n",
322 GNUNET_i2s (&pos->peer2->id));
326 transmit_ready_scheduled++;
331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
332 "Prepared %d messages\n",
336 global_pos = test_messages;
338 GNUNET_SCHEDULER_add_now(sched, &schedule_transmission, NULL);
344 init_notify (void *cls,
345 struct GNUNET_CORE_Handle *server,
346 const struct GNUNET_PeerIdentity *my_identity,
347 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
349 struct Connection *connection = cls;
352 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
353 "Core connection to `%4s' established, setting up handles\n",
354 GNUNET_i2s (my_identity));
356 connection->server = server;
357 total_server_connections++;
359 if (total_server_connections == num_peers)
361 GNUNET_SCHEDULER_cancel(sched, die_task);
362 GNUNET_SCHEDULER_add_now(sched, &send_test_messages, NULL);
371 struct Connection *new_connection;
373 struct GNUNET_TESTING_Daemon *temp_daemon;
374 die_task = GNUNET_SCHEDULER_add_delayed (sched,
376 &end_badly, "from setup_handlers");
380 * Set up a single handler for each peer
382 for (i = 0; i < num_peers; i++)
384 new_connection = GNUNET_malloc(sizeof(struct Connection));
385 temp_daemon = GNUNET_TESTING_daemon_get(pg, i);
386 new_connection->peer = temp_daemon;
387 new_connection->server = NULL;
388 new_connection->next = global_connections;
389 global_connections = new_connection;
391 GNUNET_CORE_connect (sched,
400 GNUNET_YES, NULL, GNUNET_YES, handlers);
407 topology_callback (void *cls,
408 const struct GNUNET_PeerIdentity *first,
409 const struct GNUNET_PeerIdentity *second,
410 const struct GNUNET_CONFIGURATION_Handle *first_cfg,
411 const struct GNUNET_CONFIGURATION_Handle *second_cfg,
412 struct GNUNET_TESTING_Daemon *first_daemon,
413 struct GNUNET_TESTING_Daemon *second_daemon,
416 struct TestMessageContext *temp_context;
421 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s\n",
422 first_daemon->shortname,
423 second_daemon->shortname);
425 temp_context = GNUNET_malloc(sizeof(struct TestMessageContext));
426 temp_context->first_step_done = 0;
427 temp_context->peer1handle = NULL;
428 temp_context->peer1 = first_daemon;
429 temp_context->peer2 = second_daemon;
430 temp_context->peer2handle = NULL;
431 temp_context->next = test_messages;
432 test_messages = temp_context;
435 if (dotOutFile != NULL)
436 fprintf(dotOutFile, "\tn%s -- n%s;\n", first_daemon->shortname, second_daemon->shortname);
441 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect peer %s to peer %s with error %s\n",
442 first_daemon->shortname,
443 second_daemon->shortname, emsg);
447 if (total_connections == expected_connections)
450 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
451 "Created %d total connections, which is our target number! Calling send messages.\n",
455 GNUNET_SCHEDULER_cancel (sched, die_task);
456 /* die_task = GNUNET_SCHEDULER_add_now (sched, &setup_handlers, NULL); */
457 die_task = GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 1), &setup_handlers, NULL);
462 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
463 "Have %d total connections, Need %d\n",
464 total_connections, expected_connections);
473 expected_connections = -1;
474 if ((pg != NULL) && (peers_left == 0))
476 /* create_topology will read the topology information from
477 the config already contained in the peer group, so should
478 we have create_topology called from start peers? I think
479 maybe this way is best so that the client can know both
480 when peers are started, and when they are connected.
482 expected_connections = GNUNET_TESTING_create_topology (pg);
484 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
485 "Have %d expected connections\n", expected_connections);
489 GNUNET_SCHEDULER_cancel (sched, die_task);
490 if (expected_connections == GNUNET_SYSERR)
492 die_task = GNUNET_SCHEDULER_add_now (sched,
493 &end_badly, "from create topology (bad return)");
495 die_task = GNUNET_SCHEDULER_add_delayed (sched,
497 &end_badly, "from create topology (timeout)");
503 const struct GNUNET_PeerIdentity *id,
504 const struct GNUNET_CONFIGURATION_Handle *cfg,
505 struct GNUNET_TESTING_Daemon *d, const char *emsg)
507 GNUNET_assert (id != NULL);
509 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %d out of %d\n",
510 (num_peers - peers_left) + 1, num_peers);
516 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
517 "All %d daemons started, now creating topology!\n",
520 GNUNET_SCHEDULER_cancel (sched, die_task);
521 /* Set up task in case topology creation doesn't finish
522 * within a reasonable amount of time */
523 die_task = GNUNET_SCHEDULER_add_delayed (sched,
524 GNUNET_TIME_relative_multiply
525 (GNUNET_TIME_UNIT_MINUTES, 5),
535 struct GNUNET_SCHEDULER_Handle *s,
537 const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
542 dotOutFile = fopen (dotOutFileName, "w");
543 if (dotOutFile != NULL)
545 fprintf (dotOutFile, "strict graph G {\n");
549 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
550 "Starting daemons based on config file %s\n", cfgfile);
553 GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers",
555 num_peers = DEFAULT_NUM_PEERS;
559 peers_left = num_peers;
561 /* Set up a task to end testing if peer start fails */
562 die_task = GNUNET_SCHEDULER_add_delayed (sched,
563 GNUNET_TIME_relative_multiply
564 (GNUNET_TIME_UNIT_MINUTES, 5),
567 pg = GNUNET_TESTING_daemons_start (sched, cfg,
568 peers_left, &my_cb, NULL,
569 &topology_callback, NULL, NULL);
577 char *config_file_name;
578 GNUNET_asprintf(&binary_name, "test-testing-topology-%s", topology_string);
579 GNUNET_asprintf(&config_file_name, "test_testing_data_topology_%s.conf", topology_string);
580 char *const argv[] = {binary_name,
588 struct GNUNET_GETOPT_CommandLineOption options[] = {
589 GNUNET_GETOPT_OPTION_END
591 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
592 argv, binary_name, "nohelp",
594 GNUNET_free(binary_name);
595 GNUNET_free(config_file_name);
600 main (int argc, char *argv[])
603 char *binary_start_pos;
604 char *our_binary_name;
605 binary_start_pos = rindex(argv[0], '/');
606 if (strstr(binary_start_pos, "test_testing_topology_") == NULL)
608 return GNUNET_SYSERR;
611 topology_string = &binary_start_pos[23];
613 GNUNET_asprintf(&our_binary_name, "test-testing-topology_%s", topology_string);
614 GNUNET_log_setup (our_binary_name,
623 GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing");
624 GNUNET_free(our_binary_name);
628 /* end of test_testing_group.c */