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