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