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