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