move GNUNET_TRANSPORT_ATS_ to GNUNET_ATS_
[oweals/gnunet.git] / src / testing / test_testing_large_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 3, 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 #include "gnunet_os_lib.h"
28
29 #define VERBOSE GNUNET_YES
30
31 #define DELAY_FOR_LOGGING GNUNET_NO
32
33 #define SECONDS_PER_PEER_START 120
34
35 #define DEFAULT_NUM_PEERS 4
36
37 #define MAX_OUTSTANDING_CONNECTIONS 100
38
39 static float fail_percentage = 0.05;
40
41 static int ok;
42
43 struct GNUNET_TIME_Relative connect_timeout;
44
45 static unsigned long long connect_attempts;
46
47 static unsigned long long num_peers;
48
49 static unsigned int topology_connections;
50
51 static unsigned int total_connections;
52
53 static unsigned int failed_connections;
54
55 static unsigned int total_server_connections;
56
57 static unsigned int total_messages_received;
58
59 static unsigned int expected_messages;
60
61 static unsigned int expected_connections;
62
63 static unsigned long long peers_left;
64
65 static struct GNUNET_TESTING_PeerGroup *pg;
66
67 const struct GNUNET_CONFIGURATION_Handle *main_cfg;
68
69 GNUNET_SCHEDULER_TaskIdentifier die_task;
70
71 static char *dotOutFileName;
72
73 static struct GNUNET_TIME_Relative settle_time;
74
75 static FILE *dotOutFile;
76
77 static char *topology_string;
78
79 static char *blacklist_transports;
80
81 static int transmit_ready_scheduled;
82
83 static int transmit_ready_failed;
84
85 static int transmit_ready_called;
86
87 struct GNUNET_TIME_Relative test_timeout;
88
89 struct GNUNET_TIME_Relative timeout;
90
91 static unsigned int modnum;
92
93 static unsigned int dotnum;
94
95 static enum GNUNET_TESTING_Topology topology;
96
97 static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_NONE;  /* Don't do any blacklisting */
98
99 static enum GNUNET_TESTING_Topology connection_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */
100
101 static enum GNUNET_TESTING_TopologyOption connect_topology_option =
102     GNUNET_TESTING_TOPOLOGY_OPTION_ALL;
103
104 static double connect_topology_option_modifier = 0.0;
105
106 static char *test_directory;
107
108 #define MTYPE 12345
109
110 struct GNUNET_TestMessage
111 {
112   /**
113    * Header of the message
114    */
115   struct GNUNET_MessageHeader header;
116
117   /**
118    * Unique identifier for this message.
119    */
120   uint32_t uid;
121 };
122
123 struct TestMessageContext
124 {
125   /* This is a linked list */
126   struct TestMessageContext *next;
127
128   /* Handle to the sending peer core */
129   struct GNUNET_CORE_Handle *peer1handle;
130
131   /* Handle to the receiving peer core */
132   struct GNUNET_CORE_Handle *peer2handle;
133
134   /* Handle to the sending peer daemon */
135   struct GNUNET_TESTING_Daemon *peer1;
136
137   /* Handle to the receiving peer daemon */
138   struct GNUNET_TESTING_Daemon *peer2;
139
140   /* Identifier for this message, so we don't disconnect other peers! */
141   uint32_t uid;
142
143   /* Has peer1 been notified already of a connection to peer2? */
144   int peer1notified;
145
146   /* Has the core of peer2 been connected already? */
147   int peer2connected;
148
149   /* Task for disconnecting cores, allow task to be cancelled on shutdown */
150   GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
151
152 };
153
154 static struct TestMessageContext *test_messages;
155
156 /**
157  * Check whether peers successfully shut down.
158  */
159 void
160 shutdown_callback (void *cls, const char *emsg)
161 {
162   if (emsg != NULL)
163   {
164 #if VERBOSE
165     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n");
166 #endif
167     if (ok == 0)
168       ok = 666;
169   }
170   else
171   {
172 #if VERBOSE
173     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n");
174 #endif
175   }
176 }
177
178 #if DELAY_FOR_LOGGING
179 static void
180 gather_log_data ()
181 {
182   char *peer_number;
183   char *connect_number;
184   struct GNUNET_OS_Process *mem_process;
185
186   GNUNET_asprintf (&peer_number, "%llu", num_peers);
187   GNUNET_asprintf (&connect_number, "%llu", expected_connections);
188   mem_process =
189       GNUNET_OS_start_process (NULL, NULL, "./memsize.pl", "memsize.pl",
190                                "totals.txt", peer_number, connect_number, NULL);
191   GNUNET_OS_process_wait (mem_process);
192   GNUNET_OS_process_close (mem_process);
193   mem_process = NULL;
194 }
195
196 #endif
197
198 static void
199 finish_testing ()
200 {
201   GNUNET_assert (pg != NULL);
202   struct TestMessageContext *pos;
203   struct TestMessageContext *free_pos;
204
205 #if VERBOSE
206   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
207               "Called finish testing, stopping daemons.\n");
208 #endif
209
210   pos = test_messages;
211   while (pos != NULL)
212   {
213     if (pos->peer1handle != NULL)
214     {
215       GNUNET_CORE_disconnect (pos->peer1handle);
216       pos->peer1handle = NULL;
217     }
218     if (pos->peer2handle != NULL)
219     {
220       GNUNET_CORE_disconnect (pos->peer2handle);
221       pos->peer2handle = NULL;
222     }
223     free_pos = pos;
224     pos = pos->next;
225     if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK)
226     {
227       GNUNET_SCHEDULER_cancel (free_pos->disconnect_task);
228     }
229     GNUNET_free (free_pos);
230   }
231 #if VERBOSE
232   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
233               "Transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n",
234               transmit_ready_scheduled, transmit_ready_failed,
235               transmit_ready_called);
236 #endif
237
238 #if VERBOSE
239   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n");
240 #endif
241   GNUNET_TESTING_daemons_stop (pg, timeout, &shutdown_callback, NULL);
242
243   if (dotOutFile != NULL)
244   {
245     fprintf (dotOutFile, "}");
246     fclose (dotOutFile);
247   }
248
249   ok = 0;
250 }
251
252
253 static void
254 disconnect_cores (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
255 {
256   struct TestMessageContext *pos = cls;
257
258   /* Disconnect from the respective cores */
259 #if VERBOSE > 1
260   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 1 `%4s'\n",
261               GNUNET_i2s (&pos->peer1->id));
262 #endif
263   if (pos->peer1handle != NULL)
264     GNUNET_CORE_disconnect (pos->peer1handle);
265 #if VERBOSE > 1
266   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 2 `%4s'\n",
267               GNUNET_i2s (&pos->peer2->id));
268 #endif
269   if (pos->peer2handle != NULL)
270     GNUNET_CORE_disconnect (pos->peer2handle);
271   /* Set handles to NULL so test case can be ended properly */
272   pos->peer1handle = NULL;
273   pos->peer2handle = NULL;
274   pos->disconnect_task = GNUNET_SCHEDULER_NO_TASK;
275   /* Decrement total connections so new can be established */
276   total_server_connections -= 2;
277 }
278
279
280 static void
281 topology_cb (void *cls, const struct GNUNET_PeerIdentity *first,
282              const struct GNUNET_PeerIdentity *second, const char *emsg)
283 {
284   FILE *outfile = cls;
285
286   if (first != NULL)
287   {
288     if (outfile != NULL)
289     {
290       fprintf (outfile, "\t\"%s\" -- ", GNUNET_i2s (first));
291       fprintf (outfile, "\"%s\";\n", GNUNET_i2s (second));
292     }
293     topology_connections++;
294   }
295   else
296   {
297     fprintf (stderr,
298              "Finished iterating over topology, %d total connections!\n",
299              topology_connections);
300     if (outfile != NULL)
301     {
302       fprintf (outfile, "}\n");
303       fclose (outfile);
304       GNUNET_SCHEDULER_add_now (&finish_testing, NULL);
305     }
306   }
307 }
308
309 static int
310 process_mtype (void *cls, const struct GNUNET_PeerIdentity *peer,
311                const struct GNUNET_MessageHeader *message,
312                const struct GNUNET_ATS_Information *atsi)
313 {
314   char *dotOutFileNameFinished;
315   FILE *dotOutFileFinished;
316   struct TestMessageContext *pos = cls;
317   struct GNUNET_TestMessage *msg = (struct GNUNET_TestMessage *) message;
318
319   if (pos->uid != ntohl (msg->uid))
320     return GNUNET_OK;
321
322 #if VERBOSE
323   if ((total_messages_received) % modnum == 0)
324   {
325     if (total_messages_received == 0)
326       fprintf (stdout, "0%%");
327     else
328       fprintf (stdout, "%d%%",
329                (int) (((float) total_messages_received / expected_messages) *
330                       100));
331
332   }
333   else if (total_messages_received % dotnum == 0)
334   {
335     fprintf (stdout, ".");
336   }
337   fflush (stdout);
338 #endif
339
340   total_messages_received++;
341
342 #if VERBOSE > 1
343   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
344               "Received message from `%4s', type %d.\n", GNUNET_i2s (peer),
345               ntohs (message->type));
346   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
347               "Total messages received %d, expected %d.\n",
348               total_messages_received, expected_messages);
349 #endif
350
351   if (total_messages_received == expected_messages)
352   {
353 #if VERBOSE
354     fprintf (stdout, "100%%]\n");
355 #endif
356     GNUNET_SCHEDULER_cancel (die_task);
357     GNUNET_asprintf (&dotOutFileNameFinished, "%s.dot", "final_topology");
358     dotOutFileFinished = fopen (dotOutFileNameFinished, "w");
359     GNUNET_free (dotOutFileNameFinished);
360     if (dotOutFileFinished != NULL)
361     {
362       fprintf (dotOutFileFinished, "strict graph G {\n");
363     }
364     topology_connections = 0;
365     GNUNET_TESTING_get_topology (pg, &topology_cb, dotOutFileFinished);
366     //GNUNET_SCHEDULER_add_now (&finish_testing, NULL);
367   }
368   else
369   {
370     pos->disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cores, pos);
371   }
372
373   return GNUNET_OK;
374 }
375
376 static void
377 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
378 {
379   char *msg = cls;
380
381   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
382               "End badly was called (%s)... stopping daemons.\n", msg);
383   struct TestMessageContext *pos;
384   struct TestMessageContext *free_pos;
385
386   pos = test_messages;
387   while (pos != NULL)
388   {
389     if (pos->peer1handle != NULL)
390     {
391       GNUNET_CORE_disconnect (pos->peer1handle);
392       pos->peer1handle = NULL;
393     }
394     if (pos->peer2handle != NULL)
395     {
396       GNUNET_CORE_disconnect (pos->peer2handle);
397       pos->peer2handle = NULL;
398     }
399     free_pos = pos;
400     pos = pos->next;
401     GNUNET_free (free_pos);
402   }
403
404 #if VERBOSE
405   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
406               "Transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n",
407               transmit_ready_scheduled, transmit_ready_failed,
408               transmit_ready_called);
409   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
410               "Total messages received %d, expected %d.\n",
411               total_messages_received, expected_messages);
412 #endif
413
414   if (pg != NULL)
415   {
416     GNUNET_TESTING_daemons_stop (pg, timeout, &shutdown_callback, NULL);
417     ok = 7331;                  /* Opposite of leet */
418   }
419   else
420     ok = 401;                   /* Never got peers started */
421
422   if (dotOutFile != NULL)
423   {
424     fprintf (dotOutFile, "}");
425     fclose (dotOutFile);
426   }
427 }
428
429 static size_t
430 transmit_ready (void *cls, size_t size, void *buf)
431 {
432   struct GNUNET_TestMessage *m;
433   struct TestMessageContext *pos = cls;
434
435   GNUNET_assert (buf != NULL);
436   m = (struct GNUNET_TestMessage *) buf;
437   m->header.type = htons (MTYPE);
438   m->header.size = htons (sizeof (struct GNUNET_TestMessage));
439   m->uid = htonl (pos->uid);
440   transmit_ready_called++;
441 #if VERBOSE > 1
442   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
443               "transmit ready for peer %s\ntransmit_ready's scheduled %d, transmit_ready's called %d\n",
444               GNUNET_i2s (&pos->peer1->id), transmit_ready_scheduled,
445               transmit_ready_called);
446 #endif
447   return sizeof (struct GNUNET_TestMessage);
448 }
449
450
451 static struct GNUNET_CORE_MessageHandler no_handlers[] = {
452   {NULL, 0, 0}
453 };
454
455 static struct GNUNET_CORE_MessageHandler handlers[] = {
456   {&process_mtype, MTYPE, sizeof (struct GNUNET_TestMessage)},
457   {NULL, 0, 0}
458 };
459
460 static void
461 init_notify_peer2 (void *cls, struct GNUNET_CORE_Handle *server,
462                    const struct GNUNET_PeerIdentity *my_identity)
463 {
464   struct TestMessageContext *pos = cls;
465
466   total_server_connections++;
467
468   pos->peer2connected = GNUNET_YES;
469   if (pos->peer1notified == GNUNET_YES) /* Peer 1 has been notified of connection to peer 2 */
470   {
471 #if VERBOSE > 1
472     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
473                 "Scheduling message send to peer `%s' from peer `%s' (init_notify_peer2)\n",
474                 GNUNET_i2s (my_identity),
475                 GNUNET_h2s (&pos->peer1->id.hashPubKey));
476 #endif
477     if (NULL ==
478         GNUNET_CORE_notify_transmit_ready (pos->peer1handle, 0, timeout,
479                                            &pos->peer2->id,
480                                            sizeof (struct GNUNET_TestMessage),
481                                            &transmit_ready, pos))
482     {
483       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
484                   "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n",
485                   GNUNET_i2s (&pos->peer2->id));
486       transmit_ready_failed++;
487     }
488     else
489     {
490       transmit_ready_scheduled++;
491     }
492   }
493 }
494
495 /**
496  * Method called whenever a given peer connects.
497  *
498  * @param cls closure
499  * @param peer peer identity this notification is about
500  * @param atsi performance data for the connection
501  */
502 static void
503 connect_notify_peers (void *cls, const struct GNUNET_PeerIdentity *peer,
504                       const struct GNUNET_ATS_Information *atsi)
505 {
506   struct TestMessageContext *pos = cls;
507
508   if (0 == memcmp (peer, &pos->peer2->id, sizeof (struct GNUNET_PeerIdentity)))
509   {
510     pos->peer1notified = GNUNET_YES;
511 #if VERBOSE > 1
512     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
513                 "Peer `%s' notified of connection to peer `%s'\n",
514                 GNUNET_i2s (&pos->peer1->id), GNUNET_h2s (&peer->hashPubKey));
515 #endif
516   }
517   else
518     return;
519
520   if (pos->peer2connected == GNUNET_YES)        /* Already connected and notified of connection, send message! */
521   {
522 #if VERBOSE > 1
523     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
524                 "Scheduling message send to peer `%s' from peer `%s' (init_notify_peer2)\n",
525                 GNUNET_i2s (&pos->peer2->id),
526                 GNUNET_h2s (&pos->peer1->id.hashPubKey));
527 #endif
528     if (NULL ==
529         GNUNET_CORE_notify_transmit_ready (pos->peer1handle, 0, timeout,
530                                            &pos->peer2->id,
531                                            sizeof (struct GNUNET_TestMessage),
532                                            &transmit_ready, pos))
533     {
534       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
535                   "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n",
536                   GNUNET_i2s (&pos->peer2->id));
537       transmit_ready_failed++;
538     }
539     else
540     {
541       transmit_ready_scheduled++;
542     }
543   }
544 }
545
546 static void
547 init_notify_peer1 (void *cls, struct GNUNET_CORE_Handle *server,
548                    const struct GNUNET_PeerIdentity *my_identity)
549 {
550   struct TestMessageContext *pos = cls;
551
552   total_server_connections++;
553
554 #if VERBOSE > 1
555   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
556               "Core connection to `%4s' established, setting up handles\n",
557               GNUNET_i2s (my_identity));
558 #endif
559
560   /*
561    * Connect to the receiving peer
562    */
563   pos->peer2handle =
564       GNUNET_CORE_connect (pos->peer2->cfg, 1, pos, &init_notify_peer2, NULL,
565                            NULL, NULL, NULL, GNUNET_YES, NULL, GNUNET_YES,
566                            handlers);
567
568 }
569
570
571 static void
572 send_test_messages (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
573 {
574   struct TestMessageContext *pos = cls;
575
576   if ((pos == test_messages) && (settle_time.rel_value > 0))
577   {
578     topology_connections = 0;
579     GNUNET_TESTING_get_topology (pg, &topology_cb, NULL);
580   }
581   if (((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) || (cls == NULL))
582     return;
583
584   if (die_task == GNUNET_SCHEDULER_NO_TASK)
585   {
586     die_task =
587         GNUNET_SCHEDULER_add_delayed (test_timeout, &end_badly,
588                                       "from send test messages (timeout)");
589   }
590
591   if (total_server_connections >= MAX_OUTSTANDING_CONNECTIONS)
592   {
593     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
594                                   (GNUNET_TIME_UNIT_SECONDS, 1),
595                                   &send_test_messages, pos);
596     return;                     /* Otherwise we'll double schedule messages here! */
597   }
598
599   /*
600    * Connect to the sending peer
601    */
602   pos->peer1handle =
603       GNUNET_CORE_connect (pos->peer1->cfg, 1, pos, &init_notify_peer1,
604                            &connect_notify_peers, NULL, NULL, NULL, GNUNET_NO,
605                            NULL, GNUNET_NO, no_handlers);
606
607   GNUNET_assert (pos->peer1handle != NULL);
608
609   if (total_server_connections < MAX_OUTSTANDING_CONNECTIONS)
610   {
611     GNUNET_SCHEDULER_add_now (&send_test_messages, pos->next);
612   }
613   else
614   {
615     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
616                                   (GNUNET_TIME_UNIT_SECONDS, 1),
617                                   &send_test_messages, pos->next);
618   }
619 }
620
621
622 void
623 topology_callback (void *cls, const struct GNUNET_PeerIdentity *first,
624                    const struct GNUNET_PeerIdentity *second, uint32_t distance,
625                    const struct GNUNET_CONFIGURATION_Handle *first_cfg,
626                    const struct GNUNET_CONFIGURATION_Handle *second_cfg,
627                    struct GNUNET_TESTING_Daemon *first_daemon,
628                    struct GNUNET_TESTING_Daemon *second_daemon,
629                    const char *emsg)
630 {
631   struct TestMessageContext *temp_context;
632
633   if (emsg == NULL)
634   {
635 #if VERBOSE
636     if ((total_connections) % modnum == 0)
637     {
638       if (total_connections == 0)
639         fprintf (stdout, "0%%");
640       else
641         fprintf (stdout, "%d%%",
642                  (int) (((float) total_connections / expected_connections) *
643                         100));
644
645     }
646     else if (total_connections % dotnum == 0)
647     {
648       fprintf (stdout, ".");
649     }
650     fflush (stdout);
651 #endif
652     total_connections++;
653 #if VERBOSE > 1
654     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "connected peer %s to peer %s\n",
655                 first_daemon->shortname, second_daemon->shortname);
656 #endif
657     temp_context = GNUNET_malloc (sizeof (struct TestMessageContext));
658     temp_context->peer1 = first_daemon;
659     temp_context->peer2 = second_daemon;
660     temp_context->next = test_messages;
661     temp_context->uid = total_connections;
662     temp_context->disconnect_task = GNUNET_SCHEDULER_NO_TASK;
663     test_messages = temp_context;
664
665     expected_messages++;
666     if (dotOutFile != NULL)
667       fprintf (dotOutFile, "\tn%s -- n%s;\n", first_daemon->shortname,
668                second_daemon->shortname);
669   }
670 #if VERBOSE
671   else
672   {
673     failed_connections++;
674     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
675                 "Failed to connect peer %s to peer %s with error :\n%s\n",
676                 first_daemon->shortname, second_daemon->shortname, emsg);
677   }
678 #endif
679
680   if (total_connections == expected_connections)
681   {
682 #if VERBOSE
683     fprintf (stdout, "100%%]\n");
684 #endif
685 #if VERBOSE
686     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
687                 "Created %d total connections, which is our target number!  Calling send messages.\n",
688                 total_connections);
689 #endif
690     modnum = expected_messages / 4;
691     dotnum = (expected_messages / 50) + 1;
692     GNUNET_SCHEDULER_cancel (die_task);
693     die_task = GNUNET_SCHEDULER_NO_TASK;
694 #if DELAY_FOR_LOGGING
695     fprintf (stdout, "Sending test messages in 10 seconds.\n");
696     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
697                                   (GNUNET_TIME_UNIT_SECONDS, 10),
698                                   &send_test_messages, test_messages);
699     gather_log_data ();
700 #else
701     if (settle_time.rel_value > 0)
702     {
703       GNUNET_TESTING_get_topology (pg, &topology_cb, NULL);
704     }
705     GNUNET_SCHEDULER_add_delayed (settle_time, &send_test_messages,
706                                   test_messages);
707 #endif
708 #if VERBOSE
709     fprintf (stdout, "Test message progress: [");
710 #endif
711
712   }
713   else if (total_connections + failed_connections == expected_connections)
714   {
715     if (failed_connections <
716         (unsigned int) (fail_percentage * total_connections))
717     {
718       GNUNET_SCHEDULER_cancel (die_task);
719       die_task = GNUNET_SCHEDULER_NO_TASK;
720       GNUNET_SCHEDULER_add_now (&send_test_messages, test_messages);
721     }
722     else
723     {
724       GNUNET_SCHEDULER_cancel (die_task);
725       die_task =
726           GNUNET_SCHEDULER_add_now (&end_badly,
727                                     "from topology_callback (too many failed connections)");
728     }
729   }
730   else
731   {
732 #if VERBOSE > 1
733     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
734                 "Have %d total connections, %d failed connections, Want %d (at least %d)\n",
735                 total_connections, failed_connections, expected_connections,
736                 expected_connections -
737                 (unsigned int) (fail_percentage * expected_connections));
738 #endif
739   }
740 }
741
742 static void
743 topology_creation_finished (void *cls, const char *emsg)
744 {
745 #if VERBOSE
746   if (emsg == NULL)
747     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
748                 "All topology connections created successfully!\n");
749 #endif
750 }
751
752 static void
753 connect_topology ()
754 {
755   expected_connections = -1;
756   if ((pg != NULL) && (peers_left == 0))
757   {
758     expected_connections =
759         GNUNET_TESTING_connect_topology (pg, connection_topology,
760                                          connect_topology_option,
761                                          connect_topology_option_modifier,
762                                          connect_timeout, connect_attempts,
763                                          &topology_creation_finished, NULL);
764 #if VERBOSE > 1
765     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n",
766                 expected_connections);
767 #endif
768   }
769
770   GNUNET_SCHEDULER_cancel (die_task);
771   if (expected_connections == GNUNET_SYSERR)
772   {
773     die_task =
774         GNUNET_SCHEDULER_add_now (&end_badly,
775                                   "from connect topology (bad return)");
776   }
777
778   die_task =
779       GNUNET_SCHEDULER_add_delayed (test_timeout, &end_badly,
780                                     "from connect topology (timeout)");
781   modnum = expected_connections / 4;
782   dotnum = (expected_connections / 50) + 1;
783 #if VERBOSE
784   fprintf (stdout, "Peer connection progress: [");
785 #endif
786 }
787
788 static void
789 create_topology ()
790 {
791   peers_left = num_peers;       /* Reset counter */
792   if (GNUNET_TESTING_create_topology
793       (pg, topology, blacklist_topology, blacklist_transports) != GNUNET_SYSERR)
794   {
795 #if VERBOSE
796     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
797                 "Topology set up, now starting peers!\n");
798     fprintf (stdout, "Daemon start progress [");
799 #endif
800     GNUNET_TESTING_daemons_continue_startup (pg);
801   }
802   else
803   {
804     GNUNET_SCHEDULER_cancel (die_task);
805     die_task =
806         GNUNET_SCHEDULER_add_now (&end_badly,
807                                   "from create topology (bad return)");
808   }
809   GNUNET_SCHEDULER_cancel (die_task);
810   die_task =
811       GNUNET_SCHEDULER_add_delayed (test_timeout, &end_badly,
812                                     "from continue startup (timeout)");
813 }
814
815
816 static void
817 peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id,
818                         const struct GNUNET_CONFIGURATION_Handle *cfg,
819                         struct GNUNET_TESTING_Daemon *d, const char *emsg)
820 {
821   if (emsg != NULL)
822   {
823     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
824                 "Failed to start daemon with error: `%s'\n", emsg);
825     return;
826   }
827   GNUNET_assert (id != NULL);
828 #if VERBOSE > 1
829   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n",
830               (num_peers - peers_left) + 1, num_peers);
831 #endif
832 #if VERBOSE
833   if ((num_peers - peers_left) % modnum == 0)
834   {
835     if (num_peers - peers_left == 0)
836       fprintf (stdout, "0%%");
837     else
838       fprintf (stdout, "%d%%",
839                (int) (((float) (num_peers - peers_left) / num_peers) * 100));
840
841   }
842   else if ((num_peers - peers_left) % dotnum == 0)
843   {
844     fprintf (stdout, ".");
845   }
846   fflush (stdout);
847 #endif
848   peers_left--;
849   if (peers_left == 0)
850   {
851 #if VERBOSE
852     fprintf (stdout, "100%%]\n");
853 #endif
854 #if VERBOSE
855     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
856                 "All %d daemons started, now connecting peers!\n", num_peers);
857 #endif
858     GNUNET_SCHEDULER_cancel (die_task);
859     /* Set up task in case topology creation doesn't finish
860      * within a reasonable amount of time */
861     die_task =
862         GNUNET_SCHEDULER_add_delayed (timeout, &end_badly,
863                                       "from peers_started_callback");
864 #if DELAY_FOR_LOGGING
865     fprintf (stdout, "Connecting topology in 10 seconds\n");
866     gather_log_data ();
867     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
868                                   (GNUNET_TIME_UNIT_SECONDS, 10),
869                                   &connect_topology, NULL);
870 #else
871     connect_topology ();
872 #endif
873     ok = 0;
874   }
875 }
876
877 /**
878  * Callback indicating that the hostkey was created for a peer.
879  *
880  * @param cls NULL
881  * @param id the peer identity
882  * @param d the daemon handle (pretty useless at this point, remove?)
883  * @param emsg non-null on failure
884  */
885 void
886 hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id,
887                   struct GNUNET_TESTING_Daemon *d, const char *emsg)
888 {
889   if (emsg != NULL)
890   {
891     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
892                 "Hostkey callback received error: %s\n", emsg);
893   }
894
895 #if VERBOSE > 1
896   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
897               "Hostkey (%d/%d) created for peer `%s'\n", num_peers - peers_left,
898               num_peers, GNUNET_i2s (id));
899 #endif
900
901 #if VERBOSE
902   if ((num_peers - peers_left) % modnum == 0)
903   {
904     if (num_peers - peers_left == 0)
905       fprintf (stdout, "0%%");
906     else
907       fprintf (stdout, "%d%%",
908                (int) (((float) (num_peers - peers_left) / num_peers) * 100));
909
910   }
911   else if ((num_peers - peers_left) % dotnum == 0)
912   {
913     fprintf (stdout, ".");
914   }
915   fflush (stdout);
916 #endif
917   peers_left--;
918   if (peers_left == 0)
919   {
920 #if VERBOSE
921     fprintf (stdout, "100%%]\n");
922     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
923                 "All %d hostkeys created, now creating topology!\n", num_peers);
924 #endif
925     GNUNET_SCHEDULER_cancel (die_task);
926     /* Set up task in case topology creation doesn't finish
927      * within a reasonable amount of time */
928     die_task =
929         GNUNET_SCHEDULER_add_delayed (test_timeout, &end_badly,
930                                       "from create_topology");
931     GNUNET_SCHEDULER_add_now (&create_topology, NULL);
932     ok = 0;
933   }
934 }
935
936 static void
937 run (void *cls, char *const *args, const char *cfgfile,
938      const struct GNUNET_CONFIGURATION_Handle *cfg)
939 {
940   char *topology_str;
941   char *connect_topology_str;
942   char *blacklist_topology_str;
943   char *connect_topology_option_str;
944   char *connect_topology_option_modifier_string;
945   unsigned long long temp_settle;
946
947   ok = 1;
948
949   dotOutFile = fopen (dotOutFileName, "w");
950   if (dotOutFile != NULL)
951   {
952     fprintf (dotOutFile, "strict graph G {\n");
953   }
954
955 #if VERBOSE
956   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
957               "Starting daemons based on config file %s\n", cfgfile);
958 #endif
959
960   if (GNUNET_YES !=
961       GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome",
962                                              &test_directory))
963   {
964     ok = 404;
965     return;
966   }
967
968   if ((GNUNET_YES ==
969        GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "topology",
970                                               &topology_str)) &&
971       (GNUNET_NO == GNUNET_TESTING_topology_get (&topology, topology_str)))
972   {
973     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
974                 "Invalid topology `%s' given for section %s option %s\n",
975                 topology_str, "TESTING", "TOPOLOGY");
976     topology = GNUNET_TESTING_TOPOLOGY_CLIQUE;  /* Defaults to NONE, so set better default here */
977   }
978
979   if ((GNUNET_YES ==
980        GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
981                                               "connect_topology",
982                                               &connect_topology_str)) &&
983       (GNUNET_NO ==
984        GNUNET_TESTING_topology_get (&connection_topology,
985                                     connect_topology_str)))
986   {
987     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
988                 "Invalid connect topology `%s' given for section %s option %s\n",
989                 connect_topology_str, "TESTING", "CONNECT_TOPOLOGY");
990   }
991   GNUNET_free_non_null (connect_topology_str);
992   if ((GNUNET_YES ==
993        GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
994                                               "connect_topology_option",
995                                               &connect_topology_option_str)) &&
996       (GNUNET_NO ==
997        GNUNET_TESTING_topology_option_get (&connect_topology_option,
998                                            connect_topology_option_str)))
999   {
1000     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1001                 "Invalid connect topology option `%s' given for section %s option %s\n",
1002                 connect_topology_option_str, "TESTING",
1003                 "CONNECT_TOPOLOGY_OPTION");
1004     connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL;       /* Defaults to NONE, set to ALL */
1005   }
1006   GNUNET_free_non_null (connect_topology_option_str);
1007   if (GNUNET_YES ==
1008       GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
1009                                              "connect_topology_option_modifier",
1010                                              &connect_topology_option_modifier_string))
1011   {
1012     if (sscanf
1013         (connect_topology_option_modifier_string, "%lf",
1014          &connect_topology_option_modifier) != 1)
1015     {
1016       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1017                   _
1018                   ("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
1019                   connect_topology_option_modifier_string,
1020                   "connect_topology_option_modifier", "TESTING");
1021     }
1022     GNUNET_free (connect_topology_option_modifier_string);
1023   }
1024
1025   if (GNUNET_YES !=
1026       GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
1027                                              "blacklist_transports",
1028                                              &blacklist_transports))
1029     blacklist_transports = NULL;
1030
1031   if ((GNUNET_YES ==
1032        GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
1033                                               "blacklist_topology",
1034                                               &blacklist_topology_str)) &&
1035       (GNUNET_NO ==
1036        GNUNET_TESTING_topology_get (&blacklist_topology,
1037                                     blacklist_topology_str)))
1038   {
1039     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1040                 "Invalid topology `%s' given for section %s option %s\n",
1041                 topology_str, "TESTING", "BLACKLIST_TOPOLOGY");
1042   }
1043   GNUNET_free_non_null (topology_str);
1044   GNUNET_free_non_null (blacklist_topology_str);
1045
1046   if (GNUNET_OK ==
1047       GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "settle_time",
1048                                              &temp_settle))
1049     settle_time =
1050         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, temp_settle);
1051
1052   if (GNUNET_SYSERR ==
1053       GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers",
1054                                              &num_peers))
1055     num_peers = DEFAULT_NUM_PEERS;
1056
1057   if (GNUNET_OK ==
1058       GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_timeout",
1059                                              &temp_settle))
1060     connect_timeout =
1061         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, temp_settle);
1062   else
1063   {
1064     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
1065                 "testing", "connect_timeout");
1066     return;
1067   }
1068
1069
1070   if (GNUNET_OK !=
1071       GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts",
1072                                              &connect_attempts))
1073   {
1074     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
1075                 "testing", "connect_attempts");
1076     return;
1077   }
1078
1079   main_cfg = cfg;
1080
1081   peers_left = num_peers;
1082
1083   /**
1084    * How long until we fail the whole testcase?
1085    */
1086   test_timeout =
1087       GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_multiply
1088                                      (GNUNET_TIME_UNIT_SECONDS,
1089                                       SECONDS_PER_PEER_START), num_peers * 2);
1090
1091   /**
1092    * How long until we give up on starting the peers?
1093    */
1094   timeout =
1095       GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_multiply
1096                                      (GNUNET_TIME_UNIT_SECONDS,
1097                                       SECONDS_PER_PEER_START), num_peers);
1098
1099   modnum = num_peers / 4;
1100   dotnum = (num_peers / 50) + 1;
1101 #if VERBOSE
1102   fprintf (stdout, "Hostkey generation progress: [");
1103 #endif
1104   /* Set up a task to end testing if peer start fails */
1105   die_task =
1106       GNUNET_SCHEDULER_add_delayed (timeout, &end_badly,
1107                                     "didn't generate all hostkeys within a reasonable amount of time!!!");
1108
1109   GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1);
1110   pg = GNUNET_TESTING_daemons_start (cfg, peers_left, peers_left / 2,
1111                                      peers_left, timeout, &hostkey_callback,
1112                                      NULL, &peers_started_callback, NULL,
1113                                      &topology_callback, NULL, NULL);
1114
1115 }
1116
1117 static int
1118 check ()
1119 {
1120   char *binary_name;
1121   char *config_file_name;
1122
1123   GNUNET_asprintf (&binary_name, "test-testing-topology-%s", topology_string);
1124   GNUNET_asprintf (&config_file_name, "test_testing_data_topology_%s.conf",
1125                    topology_string);
1126   int ret;
1127
1128   char *const argv[] = { binary_name,
1129     "-c",
1130     config_file_name,
1131 #if VERBOSE
1132     "-L", "DEBUG",
1133 #endif
1134     NULL
1135   };
1136   struct GNUNET_GETOPT_CommandLineOption options[] = {
1137     GNUNET_GETOPT_OPTION_END
1138   };
1139   ret =
1140       GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv,
1141                           binary_name, "nohelp", options, &run, &ok);
1142   if (ret != GNUNET_OK)
1143   {
1144     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1145                 "`test-testing-topology-%s': Failed with error code %d\n",
1146                 topology_string, ret);
1147   }
1148   GNUNET_free (binary_name);
1149   GNUNET_free (config_file_name);
1150   return ok;
1151 }
1152
1153 int
1154 main (int argc, char *argv[])
1155 {
1156   int ret;
1157   char *binary_start_pos;
1158   char *our_binary_name;
1159
1160   binary_start_pos = rindex (argv[0], '/');
1161   GNUNET_assert (binary_start_pos != NULL);
1162   topology_string = strstr (binary_start_pos, "_topology");
1163   GNUNET_assert (topology_string != NULL);
1164   topology_string++;
1165   topology_string = strstr (topology_string, "_");
1166   GNUNET_assert (topology_string != NULL);
1167   topology_string++;
1168
1169   GNUNET_asprintf (&our_binary_name, "test-testing-large-topology_%s",
1170                    topology_string);
1171   GNUNET_asprintf (&dotOutFileName, "large_topology_%s.dot", topology_string);
1172
1173   GNUNET_log_setup (our_binary_name,
1174 #if VERBOSE
1175                     "DEBUG",
1176 #else
1177                     "WARNING",
1178 #endif
1179                     NULL);
1180   ret = check ();
1181
1182   /**
1183    * Need to remove base directory, subdirectories taken care
1184    * of by the testing framework.
1185    */
1186   if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK)
1187   {
1188     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1189                 "Failed to remove testing directory %s\n", test_directory);
1190   }
1191   GNUNET_free (our_binary_name);
1192   return ret;
1193 }
1194
1195 /* end of test_testing_topology.c */