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