callback for peergroup shutdown in testing, requisite testcase changes
[oweals/gnunet.git] / src / testing / test_testing_topology.c
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_NO
29
30 /**
31  * How long until we fail the whole testcase?
32  */
33 #define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600)
34
35 /**
36  * How long until we give up on starting the peers?
37  */
38 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 500)
39
40 #define DEFAULT_NUM_PEERS 4
41
42 #define MAX_OUTSTANDING_CONNECTIONS 300
43
44 static float fail_percentage = 0.05;
45
46 static int ok;
47
48 static unsigned long long num_peers;
49
50 static unsigned int total_connections;
51
52 static unsigned int failed_connections;
53
54 static unsigned int total_server_connections;
55
56 static unsigned int total_messages_received;
57
58 static unsigned int expected_messages;
59
60 static unsigned int expected_connections;
61
62 static unsigned long long peers_left;
63
64 static struct GNUNET_TESTING_PeerGroup *pg;
65
66 static struct GNUNET_SCHEDULER_Handle *sched;
67
68 const struct GNUNET_CONFIGURATION_Handle *main_cfg;
69
70 GNUNET_SCHEDULER_TaskIdentifier die_task;
71
72 static char *dotOutFileName;
73
74 static FILE *dotOutFile;
75
76 static char *topology_string;
77
78 static char *blacklist_transports;
79
80 static int transmit_ready_scheduled;
81
82 static int transmit_ready_failed;
83
84 static int transmit_ready_called;
85
86 static enum GNUNET_TESTING_Topology topology;
87
88 static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* Don't do any blacklisting */
89
90 static enum GNUNET_TESTING_Topology connection_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */
91
92 static enum GNUNET_TESTING_TopologyOption connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL;
93
94 static double connect_topology_option_modifier = 0.0;
95
96 static char *test_directory;
97
98 #define MTYPE 12345
99
100 struct GNUNET_TestMessage
101 {
102   /**
103    * Header of the message
104    */
105   struct GNUNET_MessageHeader header;
106
107   /**
108    * Unique identifier for this message.
109    */
110   uint32_t uid;
111 };
112
113 struct TestMessageContext
114 {
115   /* This is a linked list */
116   struct TestMessageContext *next;
117
118   /* Handle to the sending peer core */
119   struct GNUNET_CORE_Handle *peer1handle;
120
121   /* Handle to the receiving peer core */
122   struct GNUNET_CORE_Handle *peer2handle;
123
124   /* Handle to the sending peer daemon */
125   struct GNUNET_TESTING_Daemon *peer1;
126
127   /* Handle to the receiving peer daemon */
128   struct GNUNET_TESTING_Daemon *peer2;
129
130   /* Identifier for this message, so we don't disconnect other peers! */
131   uint32_t uid;
132
133   /* Task for disconnecting cores, allow task to be cancelled on shutdown */
134   GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
135
136 };
137
138 static struct TestMessageContext *test_messages;
139
140 /**
141  * Check whether peers successfully shut down.
142  */
143 void shutdown_callback (void *cls,
144                         const char *emsg)
145 {
146   if (emsg != NULL)
147     {
148 #if VERBOSE
149       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
150                   "Shutdown of peers failed!\n");
151 #endif
152       if (ok == 0)
153         ok = 666;
154     }
155   else
156     {
157 #if VERBOSE
158       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
159                   "All peers successfully shut down!\n");
160 #endif
161     }
162 }
163
164 static void
165 finish_testing ()
166 {
167   GNUNET_assert (pg != NULL);
168   struct TestMessageContext *pos;
169   struct TestMessageContext *free_pos;
170 #if VERBOSE
171   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
172               "Called finish testing, stopping daemons.\n");
173 #endif
174   int count;
175   count = 0;
176   pos = test_messages;
177   while (pos != NULL)
178     {
179       if (pos->peer1handle != NULL)
180         {
181           GNUNET_CORE_disconnect(pos->peer1handle);
182           pos->peer1handle = NULL;
183         }
184       if (pos->peer2handle != NULL)
185         {
186           GNUNET_CORE_disconnect(pos->peer2handle);
187           pos->peer2handle = NULL;
188         }
189       free_pos = pos;
190       pos = pos->next;
191       if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK)
192         {
193           GNUNET_SCHEDULER_cancel(sched, free_pos->disconnect_task);
194         }
195       GNUNET_free(free_pos);
196     }
197 #if VERBOSE
198           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
199                       "transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n", transmit_ready_scheduled, transmit_ready_failed, transmit_ready_called);
200 #endif
201
202 #if VERBOSE
203           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
204                       "Calling daemons_stop\n");
205 #endif
206   GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
207
208   if (dotOutFile != NULL)
209     {
210       fprintf(dotOutFile, "}");
211       fclose(dotOutFile);
212     }
213
214   ok = 0;
215 }
216
217
218 static void
219 disconnect_cores (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
220 {
221   struct TestMessageContext *pos = cls;
222
223   /* Disconnect from the respective cores */
224 #if VERBOSE
225   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
226               "Disconnecting from peer 1 `%4s'\n", GNUNET_i2s (&pos->peer1->id));
227 #endif
228   if (pos->peer1handle != NULL)
229     GNUNET_CORE_disconnect(pos->peer1handle);
230 #if VERBOSE
231   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
232               "Disconnecting from peer 2 `%4s'\n", GNUNET_i2s (&pos->peer2->id));
233 #endif
234   if (pos->peer2handle != NULL)
235     GNUNET_CORE_disconnect(pos->peer2handle);
236   /* Set handles to NULL so test case can be ended properly */
237   pos->peer1handle = NULL;
238   pos->peer2handle = NULL;
239   pos->disconnect_task = GNUNET_SCHEDULER_NO_TASK;
240   /* Decrement total connections so new can be established */
241   total_server_connections -= 2;
242 }
243
244 static int
245 process_mtype (void *cls,
246                const struct GNUNET_PeerIdentity *peer,
247                const struct GNUNET_MessageHeader *message,
248                struct GNUNET_TIME_Relative latency,
249                uint32_t distance)
250 {
251   struct TestMessageContext *pos = cls;
252   struct GNUNET_TestMessage *msg = (struct GNUNET_TestMessage *)message;
253   if (pos->uid != ntohl(msg->uid))
254     return GNUNET_OK;
255
256   total_messages_received++;
257 #if VERBOSE
258   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
259               "Received message from `%4s', type %d.\n", GNUNET_i2s (peer), ntohs(message->type));
260   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
261               "Total messages received %d, expected %d.\n", total_messages_received, expected_messages);
262 #endif
263
264   if (total_messages_received == expected_messages)
265     {
266       GNUNET_SCHEDULER_cancel (sched, die_task);
267       GNUNET_SCHEDULER_add_now (sched, &finish_testing, NULL);
268     }
269   else
270     {
271       pos->disconnect_task = GNUNET_SCHEDULER_add_now(sched, &disconnect_cores, pos);
272     }
273
274   return GNUNET_OK;
275 }
276
277 static void
278 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
279 {
280   char *msg = cls;
281   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
282               "End badly was called (%s)... stopping daemons.\n", msg);
283   struct TestMessageContext *pos;
284   struct TestMessageContext *free_pos;
285
286   pos = test_messages;
287   while (pos != NULL)
288     {
289       if (pos->peer1handle != NULL)
290         {
291           GNUNET_CORE_disconnect(pos->peer1handle);
292           pos->peer1handle = NULL;
293         }
294       if (pos->peer2handle != NULL)
295         {
296           GNUNET_CORE_disconnect(pos->peer2handle);
297           pos->peer2handle = NULL;
298         }
299       free_pos = pos;
300       pos = pos->next;
301       GNUNET_free(free_pos);
302     }
303
304   if (pg != NULL)
305     {
306       GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
307       ok = 7331;                /* Opposite of leet */
308     }
309   else
310     ok = 401;                   /* Never got peers started */
311
312   if (dotOutFile != NULL)
313     {
314       fprintf(dotOutFile, "}");
315       fclose(dotOutFile);
316     }
317 }
318
319 static size_t
320 transmit_ready (void *cls, size_t size, void *buf)
321 {
322   struct GNUNET_TestMessage *m;
323   struct TestMessageContext *pos = cls;
324
325   GNUNET_assert (buf != NULL);
326   m = (struct GNUNET_TestMessage *) buf;
327   m->header.type = htons (MTYPE);
328   m->header.size = htons (sizeof (struct GNUNET_TestMessage));
329   m->uid = htonl(pos->uid);
330   transmit_ready_called++;
331 #if VERBOSE
332   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
333               "transmit ready for peer %s\ntransmit_ready's scheduled %d, transmit_ready's called %d\n", GNUNET_i2s(&pos->peer1->id), transmit_ready_scheduled, transmit_ready_called);
334 #endif
335   return sizeof (struct GNUNET_TestMessage);
336 }
337
338
339 static struct GNUNET_CORE_MessageHandler no_handlers[] = {
340   {NULL, 0, 0}
341 };
342
343 static struct GNUNET_CORE_MessageHandler handlers[] = {
344   {&process_mtype, MTYPE, sizeof (struct GNUNET_TestMessage)},
345   {NULL, 0, 0}
346 };
347
348 static void
349 init_notify_peer2 (void *cls,
350              struct GNUNET_CORE_Handle *server,
351              const struct GNUNET_PeerIdentity *my_identity,
352              const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
353 {
354   struct TestMessageContext *pos = cls;
355
356 #if VERBOSE
357   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
358               "Core connection to `%4s' established, scheduling message send\n",
359               GNUNET_i2s (my_identity));
360 #endif
361   total_server_connections++;
362
363   if (NULL == GNUNET_CORE_notify_transmit_ready (pos->peer1handle,
364                                                  0,
365                                                  TIMEOUT,
366                                                  &pos->peer2->id,
367                                                  sizeof (struct GNUNET_TestMessage),
368                                                  &transmit_ready, pos))
369     {
370       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
371                   "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n",
372                   GNUNET_i2s (&pos->peer2->id));
373       transmit_ready_failed++;
374     }
375   else
376     {
377       transmit_ready_scheduled++;
378     }
379 }
380
381
382 static void
383 init_notify_peer1 (void *cls,
384              struct GNUNET_CORE_Handle *server,
385              const struct GNUNET_PeerIdentity *my_identity,
386              const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
387 {
388   struct TestMessageContext *pos = cls;
389   total_server_connections++;
390
391 #if VERBOSE
392   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
393               "Core connection to `%4s' established, setting up handles\n",
394               GNUNET_i2s (my_identity));
395 #endif
396
397   /*
398    * Connect to the receiving peer
399    */
400   pos->peer2handle = GNUNET_CORE_connect (sched,
401                        pos->peer2->cfg,
402                        TIMEOUT,
403                        pos,
404                        &init_notify_peer2,
405                        NULL,
406                        NULL,
407                        NULL,
408                        GNUNET_YES, NULL, GNUNET_YES, handlers);
409
410 }
411
412
413 static void
414 send_test_messages (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
415 {
416   struct TestMessageContext *pos = cls;
417
418   if ((tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) || (cls == NULL))
419     return;
420
421   if (die_task == GNUNET_SCHEDULER_NO_TASK)
422     {
423       die_task = GNUNET_SCHEDULER_add_delayed (sched,
424                                                TEST_TIMEOUT,
425                                                &end_badly, "from create topology (timeout)");
426     }
427
428   if (total_server_connections >= MAX_OUTSTANDING_CONNECTIONS)
429     {
430       GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1),
431                                     &send_test_messages, pos);
432       return; /* Otherwise we'll double schedule messages here! */
433     }
434
435   /*
436    * Connect to the sending peer
437    */
438   pos->peer1handle = GNUNET_CORE_connect (sched,
439                                           pos->peer1->cfg,
440                                           TIMEOUT,
441                                           pos,
442                                           &init_notify_peer1,
443                                           NULL,
444                                           NULL,
445                                           NULL,
446                                           GNUNET_NO, NULL, GNUNET_NO, no_handlers);
447
448   GNUNET_assert(pos->peer1handle != NULL);
449
450   if (total_server_connections < MAX_OUTSTANDING_CONNECTIONS)
451     {
452       GNUNET_SCHEDULER_add_now (sched,
453                                 &send_test_messages, pos->next);
454     }
455   else
456     {
457       GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1),
458                                     &send_test_messages, pos->next);
459     }
460 }
461
462
463 void
464 topology_callback (void *cls,
465                    const struct GNUNET_PeerIdentity *first,
466                    const struct GNUNET_PeerIdentity *second,
467                    uint32_t distance,
468                    const struct GNUNET_CONFIGURATION_Handle *first_cfg,
469                    const struct GNUNET_CONFIGURATION_Handle *second_cfg,
470                    struct GNUNET_TESTING_Daemon *first_daemon,
471                    struct GNUNET_TESTING_Daemon *second_daemon,
472                    const char *emsg)
473 {
474   struct TestMessageContext *temp_context;
475   if (emsg == NULL)
476     {
477       total_connections++;
478 #if VERBOSE
479       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s\n",
480                first_daemon->shortname,
481                second_daemon->shortname);
482 #endif
483       temp_context = GNUNET_malloc(sizeof(struct TestMessageContext));
484       temp_context->peer1 = first_daemon;
485       temp_context->peer2 = second_daemon;
486       temp_context->next = test_messages;
487       temp_context->uid = total_connections;
488       temp_context->disconnect_task = GNUNET_SCHEDULER_NO_TASK;
489       test_messages = temp_context;
490
491       expected_messages++;
492       if (dotOutFile != NULL)
493         fprintf(dotOutFile, "\tn%s -- n%s;\n", first_daemon->shortname, second_daemon->shortname);
494     }
495 #if VERBOSE
496   else
497     {
498       failed_connections++;
499       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect peer %s to peer %s with error :\n%s\n",
500                first_daemon->shortname,
501                second_daemon->shortname, emsg);
502     }
503 #endif
504
505   if (total_connections == expected_connections)
506     {
507 #if VERBOSE
508       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
509                   "Created %d total connections, which is our target number!  Calling send messages.\n",
510                   total_connections);
511 #endif
512
513       GNUNET_SCHEDULER_cancel (sched, die_task);
514       die_task = GNUNET_SCHEDULER_NO_TASK;
515       GNUNET_SCHEDULER_add_now (sched, &send_test_messages, test_messages);
516       //GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 1), &send_test_messages, test_messages);
517     }
518   else if (total_connections + failed_connections == expected_connections)
519     {
520       if (failed_connections < (unsigned int)(fail_percentage * total_connections))
521         {
522           GNUNET_SCHEDULER_cancel (sched, die_task);
523           die_task = GNUNET_SCHEDULER_NO_TASK;
524           GNUNET_SCHEDULER_add_now (sched, &send_test_messages, test_messages);
525           //GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 1), &send_test_messages, test_messages);
526         }
527       else
528         {
529           GNUNET_SCHEDULER_cancel (sched, die_task);
530           die_task = GNUNET_SCHEDULER_add_now (sched,
531                                                &end_badly, "from topology_callback (too many failed connections)");
532         }
533     }
534   else
535     {
536 #if VERBOSE
537       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
538                   "Have %d total connections, %d failed connections, Want %d (at least %d)\n",
539                   total_connections, failed_connections, expected_connections, expected_connections - (unsigned int)(fail_percentage * expected_connections));
540 #endif
541     }
542 }
543
544 static void
545 connect_topology ()
546 {
547   expected_connections = -1;
548   if ((pg != NULL) && (peers_left == 0))
549     {
550       expected_connections = GNUNET_TESTING_connect_topology (pg, connection_topology, connect_topology_option, connect_topology_option_modifier);
551 #if VERBOSE
552       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
553                   "Have %d expected connections\n", expected_connections);
554 #endif
555     }
556
557   GNUNET_SCHEDULER_cancel (sched, die_task);
558   if (expected_connections == GNUNET_SYSERR)
559     {
560       die_task = GNUNET_SCHEDULER_add_now (sched,
561                                            &end_badly, "from connect topology (bad return)");
562     }
563
564   die_task = GNUNET_SCHEDULER_add_delayed (sched,
565                                            TEST_TIMEOUT,
566                                            &end_badly, "from connect topology (timeout)");
567 }
568
569 static void
570 create_topology ()
571 {
572   peers_left = num_peers; /* Reset counter */
573   if (GNUNET_TESTING_create_topology (pg, topology, blacklist_topology, blacklist_transports) != GNUNET_SYSERR)
574     {
575 #if VERBOSE
576       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
577                   "Topology set up, now starting peers!\n");
578 #endif
579       GNUNET_TESTING_daemons_continue_startup(pg);
580     }
581   else
582     {
583       GNUNET_SCHEDULER_cancel (sched, die_task);
584       die_task = GNUNET_SCHEDULER_add_now (sched,
585                                            &end_badly, "from create topology (bad return)");
586     }
587   GNUNET_SCHEDULER_cancel (sched, die_task);
588   die_task = GNUNET_SCHEDULER_add_delayed (sched,
589                                            TEST_TIMEOUT,
590                                            &end_badly, "from continue startup (timeout)");
591 }
592
593
594 static void
595 peers_started_callback (void *cls,
596        const struct GNUNET_PeerIdentity *id,
597        const struct GNUNET_CONFIGURATION_Handle *cfg,
598        struct GNUNET_TESTING_Daemon *d, const char *emsg)
599 {
600   if (emsg != NULL)
601     {
602       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to start daemon with error: `%s'\n",
603                   emsg);
604       return;
605     }
606   GNUNET_assert (id != NULL);
607 #if VERBOSE
608   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n",
609               (num_peers - peers_left) + 1, num_peers);
610 #endif
611   peers_left--;
612   if (peers_left == 0)
613     {
614 #if VERBOSE
615       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
616                   "All %d daemons started, now creating topology!\n",
617                   num_peers);
618 #endif
619       GNUNET_SCHEDULER_cancel (sched, die_task);
620       /* Set up task in case topology creation doesn't finish
621        * within a reasonable amount of time */
622       die_task = GNUNET_SCHEDULER_add_delayed (sched,
623                                                GNUNET_TIME_relative_multiply
624                                                (GNUNET_TIME_UNIT_MINUTES, 5),
625                                                &end_badly, "from peers_started_callback");
626
627       connect_topology ();
628       ok = 0;
629     }
630 }
631
632 /**
633  * Callback indicating that the hostkey was created for a peer.
634  *
635  * @param cls NULL
636  * @param id the peer identity
637  * @param d the daemon handle (pretty useless at this point, remove?)
638  * @param emsg non-null on failure
639  */
640 void hostkey_callback (void *cls,
641                        const struct GNUNET_PeerIdentity *id,
642                        struct GNUNET_TESTING_Daemon *d,
643                        const char *emsg)
644 {
645   if (emsg != NULL)
646     {
647       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Hostkey callback received error: %s\n", emsg);
648     }
649
650 #if VERBOSE
651     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
652                 "Hostkey created for peer `%s'\n",
653                 GNUNET_i2s(id));
654 #endif
655     peers_left--;
656     if (peers_left == 0)
657       {
658 #if VERBOSE
659         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
660                     "All %d hostkeys created, now creating topology!\n",
661                     num_peers);
662 #endif
663         GNUNET_SCHEDULER_cancel (sched, die_task);
664         /* Set up task in case topology creation doesn't finish
665          * within a reasonable amount of time */
666         die_task = GNUNET_SCHEDULER_add_delayed (sched,
667                                                  GNUNET_TIME_relative_multiply
668                                                  (GNUNET_TIME_UNIT_MINUTES, 5),
669                                                  &end_badly, "from hostkey_callback");
670         GNUNET_SCHEDULER_add_now(sched, &create_topology, NULL);
671         ok = 0;
672       }
673 }
674
675 static void
676 run (void *cls,
677      struct GNUNET_SCHEDULER_Handle *s,
678      char *const *args,
679      const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
680 {
681   char * topology_str;
682   char * connect_topology_str;
683   char * blacklist_topology_str;
684   char * connect_topology_option_str;
685   char * connect_topology_option_modifier_string;
686   sched = s;
687   ok = 1;
688
689   dotOutFile = fopen (dotOutFileName, "w");
690   if (dotOutFile != NULL)
691     {
692       fprintf (dotOutFile, "strict graph G {\n");
693     }
694
695 #if VERBOSE
696   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
697               "Starting daemons based on config file %s\n", cfgfile);
698 #endif
699
700   if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string(cfg, "paths", "servicehome", &test_directory))
701     {
702       ok = 404;
703       return;
704     }
705
706   if ((GNUNET_YES ==
707       GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "topology",
708                                             &topology_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get(&topology, topology_str)))
709     {
710       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
711                   "Invalid topology `%s' given for section %s option %s\n", topology_str, "TESTING", "TOPOLOGY");
712       topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */
713     }
714
715   if ((GNUNET_YES ==
716       GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "connect_topology",
717                                             &connect_topology_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get(&connection_topology, connect_topology_str)))
718     {
719       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
720                   "Invalid connect topology `%s' given for section %s option %s\n", connect_topology_str, "TESTING", "CONNECT_TOPOLOGY");
721     }
722   GNUNET_free_non_null(connect_topology_str);
723   if ((GNUNET_YES ==
724       GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "connect_topology_option",
725                                             &connect_topology_option_str)) && (GNUNET_NO == GNUNET_TESTING_topology_option_get(&connect_topology_option, connect_topology_option_str)))
726     {
727       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
728                   "Invalid connect topology option `%s' given for section %s option %s\n", connect_topology_option_str, "TESTING", "CONNECT_TOPOLOGY_OPTION");
729       connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */
730     }
731   GNUNET_free_non_null(connect_topology_option_str);
732   if (GNUNET_YES ==
733         GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "connect_topology_option_modifier",
734                                                &connect_topology_option_modifier_string))
735     {
736       if (sscanf(connect_topology_option_modifier_string, "%lf", &connect_topology_option_modifier) != 1)
737       {
738         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
739         _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
740         connect_topology_option_modifier_string,
741         "connect_topology_option_modifier",
742         "TESTING");
743       }
744       GNUNET_free (connect_topology_option_modifier_string);
745     }
746
747   if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "blacklist_transports",
748                                          &blacklist_transports))
749     blacklist_transports = NULL;
750
751   if ((GNUNET_YES ==
752       GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "blacklist_topology",
753                                             &blacklist_topology_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get(&blacklist_topology, blacklist_topology_str)))
754     {
755       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
756                   "Invalid topology `%s' given for section %s option %s\n", topology_str, "TESTING", "BLACKLIST_TOPOLOGY");
757     }
758   GNUNET_free_non_null(topology_str);
759   GNUNET_free_non_null(blacklist_topology_str);
760
761   if (GNUNET_SYSERR ==
762       GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers",
763                                              &num_peers))
764     num_peers = DEFAULT_NUM_PEERS;
765
766   main_cfg = cfg;
767
768   peers_left = num_peers;
769
770   /* Set up a task to end testing if peer start fails */
771   die_task = GNUNET_SCHEDULER_add_delayed (sched,
772                                            GNUNET_TIME_relative_multiply
773                                            (GNUNET_TIME_UNIT_MINUTES, 5),
774                                            &end_badly, "didn't start all daemons in reasonable amount of time!!!");
775
776   pg = GNUNET_TESTING_daemons_start (sched, cfg,
777                                      peers_left, TIMEOUT, &hostkey_callback, NULL, &peers_started_callback, NULL,
778                                      &topology_callback, NULL, NULL);
779
780 }
781
782 static int
783 check ()
784 {
785   char *binary_name;
786   char *config_file_name;
787   GNUNET_asprintf(&binary_name, "test-testing-topology-%s", topology_string);
788   GNUNET_asprintf(&config_file_name, "test_testing_data_topology_%s.conf", topology_string);
789   int ret;
790   char *const argv[] = {binary_name,
791     "-c",
792     config_file_name,
793 #if VERBOSE
794     "-L", "DEBUG",
795 #endif
796     NULL
797   };
798   struct GNUNET_GETOPT_CommandLineOption options[] = {
799     GNUNET_GETOPT_OPTION_END
800   };
801   ret = GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
802                       argv, binary_name, "nohelp",
803                       options, &run, &ok);
804   if (ret != GNUNET_OK)
805     {
806       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "`test-testing-topology-%s': Failed with error code %d\n", topology_string, ret);
807     }
808   GNUNET_free(binary_name);
809   GNUNET_free(config_file_name);
810   return ok;
811 }
812
813 int
814 main (int argc, char *argv[])
815 {
816   int ret;
817   char *binary_start_pos;
818   char *our_binary_name;
819
820   binary_start_pos = rindex(argv[0], '/');
821   topology_string = strstr (binary_start_pos,
822                             "_topology");
823   GNUNET_assert (topology_string != NULL);
824   topology_string++;
825   topology_string = strstr (topology_string, "_");
826   GNUNET_assert (topology_string != NULL);
827   topology_string++;
828
829   GNUNET_asprintf(&our_binary_name, "test-testing-topology_%s", topology_string);
830   GNUNET_asprintf(&dotOutFileName, "topology_%s.dot", topology_string);
831
832   GNUNET_log_setup (our_binary_name,
833 #if VERBOSE
834                     "DEBUG",
835 #else
836                     "WARNING",
837 #endif
838                     NULL);
839   ret = check ();
840
841   /**
842    * Need to remove base directory, subdirectories taken care
843    * of by the testing framework.
844    */
845   if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK)
846     {
847       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to remove testing directory %s\n", test_directory);
848     }
849   GNUNET_free(our_binary_name);
850   return ret;
851 }
852
853 /* end of test_testing_topology.c */