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