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