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