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