added ATS addresstype information to unix
[oweals/gnunet.git] / src / mesh / test_mesh_small.c
1 /*
2      This file is part of GNUnet.
3      (C) 2011 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 mesh/test_mesh_small.c
22  *
23  * @brief Test for the mesh service: retransmission of traffic.
24  */
25 #include "platform.h"
26 #include "gnunet_testing_lib.h"
27 #include "gnunet_mesh_service.h"
28
29 #define VERBOSE GNUNET_YES
30 #define REMOVE_DIR GNUNET_YES
31
32 struct MeshPeer
33 {
34   struct MeshPeer *prev;
35
36   struct MeshPeer *next;
37
38   struct GNUNET_TESTING_Daemon *daemon;
39
40   struct GNUNET_MESH_Handle *mesh_handle;
41 };
42
43
44 struct StatsContext
45 {
46   unsigned long long total_mesh_bytes;
47 };
48
49
50 /**
51  * How long until we give up on connecting the peers?
52  */
53 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500)
54
55 /**
56  * Time to wait for stuff that should be rather fast
57  */
58 #define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300)
59
60 /**
61  * DIFFERENT TESTS TO RUN
62  */
63 #define SETUP 0
64 #define UNICAST 1
65 #define MULTICAST 2
66
67 /**
68  * Which test are we running?
69  */
70 static int test;
71
72 /**
73  * How many events have happened
74  */
75 static int ok;
76
77 static int peers_in_tunnel;
78
79 static int peers_responded;
80
81 /**
82  * Be verbose
83  */
84 static int verbose;
85
86 /**
87  * Total number of peers in the test.
88  */
89 static unsigned long long num_peers;
90
91 /**
92  * Global configuration file
93  */
94 static struct GNUNET_CONFIGURATION_Handle *testing_cfg;
95
96 /**
97  * Total number of currently running peers.
98  */
99 static unsigned long long peers_running;
100
101 /**
102  * Total number of connections in the whole network.
103  */
104 static unsigned int total_connections;
105
106 /**
107  * The currently running peer group.
108  */
109 static struct GNUNET_TESTING_PeerGroup *pg;
110
111 /**
112  * File to report results to.
113  */
114 static struct GNUNET_DISK_FileHandle *output_file;
115
116 /**
117  * File to log connection info, statistics to.
118  */
119 static struct GNUNET_DISK_FileHandle *data_file;
120
121 /**
122  * How many data points to capture before triggering next round?
123  */
124 static struct GNUNET_TIME_Relative wait_time;
125
126 /**
127  * Task called to disconnect peers.
128  */
129 static GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
130
131 /**
132  * Task To perform tests
133  */
134 static GNUNET_SCHEDULER_TaskIdentifier test_task;
135
136 /**
137  * Task called to shutdown test.
138  */
139 static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle;
140
141 static char *topology_file;
142
143 static struct GNUNET_TESTING_Daemon *d1;
144
145 static GNUNET_PEER_Id pid1;
146
147 static struct GNUNET_TESTING_Daemon *d2;
148
149 static struct GNUNET_TESTING_Daemon *d3;
150
151 static struct GNUNET_MESH_Handle *h1;
152
153 static struct GNUNET_MESH_Handle *h2;
154
155 static struct GNUNET_MESH_Handle *h3;
156
157 static struct GNUNET_MESH_Tunnel *t;
158
159 static struct GNUNET_MESH_Tunnel *incoming_t;
160
161 static struct GNUNET_MESH_Tunnel *incoming_t2;
162
163 static uint16_t *mesh_peers;
164
165 /**
166  * Check whether peers successfully shut down.
167  */
168 static void
169 shutdown_callback (void *cls, const char *emsg)
170 {
171   if (emsg != NULL)
172   {
173 #if VERBOSE
174     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
175                 "***************** test: Shutdown of peers failed!\n");
176 #endif
177     ok--;
178   }
179   else
180   {
181 #if VERBOSE
182     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
183                 "***************** test: All peers successfully shut down!\n");
184 #endif
185   }
186 }
187
188
189 static void
190 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
191 {
192 #if VERBOSE
193   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
194               "***************** test: Ending test.\n");
195 #endif
196
197   if (disconnect_task != GNUNET_SCHEDULER_NO_TASK)
198   {
199     GNUNET_SCHEDULER_cancel (disconnect_task);
200     disconnect_task = GNUNET_SCHEDULER_NO_TASK;
201   }
202
203   if (data_file != NULL)
204     GNUNET_DISK_file_close (data_file);
205   GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
206   GNUNET_CONFIGURATION_destroy (testing_cfg);
207 }
208
209
210 static void
211 disconnect_mesh_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
212 {
213   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
214               "***************** test: disconnecting mesh service of peers\n");
215   disconnect_task = GNUNET_SCHEDULER_NO_TASK;
216   GNUNET_MESH_disconnect (h1);
217   GNUNET_MESH_disconnect (h2);
218   if (test == MULTICAST)
219     GNUNET_MESH_disconnect (h3);
220   if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle)
221   {
222     GNUNET_SCHEDULER_cancel (shutdown_handle);
223     shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
224   }
225 }
226
227
228 /**
229  * Transmit ready callback
230  */
231 size_t
232 tmt_rdy (void *cls, size_t size, void *buf)
233 {
234   struct GNUNET_MessageHeader *msg = buf;
235
236   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
237               "***************** test:  tmt_rdy called\n");
238   if (size < sizeof (struct GNUNET_MessageHeader) || NULL == buf)
239     return 0;
240   msg->size = htons (sizeof (struct GNUNET_MessageHeader));
241   msg->type = htons ((long) cls);
242   return sizeof (struct GNUNET_MessageHeader);
243 }
244
245
246 /**
247  * Function is called whenever a message is received.
248  *
249  * @param cls closure (set from GNUNET_MESH_connect)
250  * @param tunnel connection to the other end
251  * @param tunnel_ctx place to store local state associated with the tunnel
252  * @param sender who sent the message
253  * @param message the actual message
254  * @param atsi performance data for the connection
255  * @return GNUNET_OK to keep the connection open,
256  *         GNUNET_SYSERR to close it (signal serious error)
257  */
258 int
259 data_callback (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx,
260                const struct GNUNET_PeerIdentity *sender,
261                const struct GNUNET_MessageHeader *message,
262                const struct GNUNET_ATS_Information *atsi)
263 {
264   long client = (long) cls;
265
266   switch (client)
267   {
268   case 1L:
269     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
270                 "***************** test: Origin client got a response!\n");
271     ok++;
272     peers_responded++;
273     if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
274     {
275       GNUNET_SCHEDULER_cancel (disconnect_task);
276       disconnect_task =
277           GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers,
278                                         NULL);
279     }
280     if (test == MULTICAST && peers_responded < 2)
281       return GNUNET_OK;
282     GNUNET_MESH_tunnel_destroy (tunnel);
283     break;
284   case 2L:
285   case 3L:
286     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
287                 "***************** test: Destination client %u got a message.\n",
288                 client);
289     ok++;
290     GNUNET_MESH_notify_transmit_ready (tunnel, GNUNET_NO, 0,
291                                        GNUNET_TIME_UNIT_FOREVER_REL, sender,
292                                        sizeof (struct GNUNET_MessageHeader),
293                                        &tmt_rdy, (void *) 1L);
294     if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
295     {
296       GNUNET_SCHEDULER_cancel (disconnect_task);
297       disconnect_task =
298           GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers,
299                                         NULL);
300     }
301     break;
302   default:
303     break;
304   }
305   return GNUNET_OK;
306 }
307
308
309 /**
310  * Handlers, for diverse services
311  */
312 static struct GNUNET_MESH_MessageHandler handlers[] = {
313   {&data_callback, 1, sizeof (struct GNUNET_MessageHeader)},
314   {NULL, 0, 0}
315 };
316
317
318 /**
319  * Method called whenever another peer has added us to a tunnel
320  * the other peer initiated.
321  *
322  * @param cls closure
323  * @param tunnel new handle to the tunnel
324  * @param initiator peer that started the tunnel
325  * @param atsi performance information for the tunnel
326  * @return initial tunnel context for the tunnel
327  *         (can be NULL -- that's not an error)
328  */
329 static void *
330 incoming_tunnel (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
331                  const struct GNUNET_PeerIdentity *initiator,
332                  const struct GNUNET_ATS_Information *atsi)
333 {
334   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
335               "***************** test: Incoming tunnel from %s to peer %d\n",
336               GNUNET_i2s (initiator), (long) cls);
337   ok++;
338   if ((long) cls == 1L)
339     incoming_t = tunnel;
340   else
341     incoming_t2 = tunnel;
342   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
343   {
344     GNUNET_SCHEDULER_cancel (disconnect_task);
345     disconnect_task =
346         GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers, NULL);
347   }
348   return NULL;
349 }
350
351 /**
352  * Function called whenever an inbound tunnel is destroyed.  Should clean up
353  * any associated state.
354  *
355  * @param cls closure (set from GNUNET_MESH_connect)
356  * @param tunnel connection to the other end (henceforth invalid)
357  * @param tunnel_ctx place where local state associated
358  *                   with the tunnel is stored
359  */
360 static void
361 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel,
362                 void *tunnel_ctx)
363 {
364   long i = (long) cls;
365
366   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
367               "***************** test: Incoming tunnel disconnected at peer %d\n",
368               i);
369   if (2L == i)
370     ok++;
371   else if (3L == i)
372     ok++;
373   else
374     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
375                 "***************** test: Unknown peer! %d\n", i);
376   peers_in_tunnel--;
377   if (peers_in_tunnel > 0)
378     return;
379
380   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
381   {
382     GNUNET_SCHEDULER_cancel (disconnect_task);
383     disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_mesh_peers, NULL);
384   }
385
386   return;
387 }
388
389
390 /**
391  * Method called whenever a tunnel falls apart.
392  *
393  * @param cls closure
394  * @param peer peer identity the tunnel stopped working with
395  */
396 static void
397 dh (void *cls, const struct GNUNET_PeerIdentity *peer)
398 {
399   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
400               "***************** test: peer %s disconnected\n",
401               GNUNET_i2s (peer));
402   return;
403 }
404
405
406 /**
407  * Method called whenever a peer connects to a tunnel.
408  *
409  * @param cls closure
410  * @param peer peer identity the tunnel was created to, NULL on timeout
411  * @param atsi performance data for the connection
412  */
413 static void
414 ch (void *cls, const struct GNUNET_PeerIdentity *peer,
415     const struct GNUNET_ATS_Information *atsi)
416 {
417   struct GNUNET_PeerIdentity *dest;
418
419   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
420               "***************** test: peer %s connected\n", GNUNET_i2s (peer));
421
422   if (0 == memcmp (&d2->id, peer, sizeof (d2->id)) && (long) cls == 1L)
423     ok++;
424   if (test == MULTICAST && 0 == memcmp (&d3->id, peer, sizeof (d3->id)) &&
425       (long) cls == 1L)
426     ok++;
427   switch (test)
428   {
429   case UNICAST:
430     dest = &d2->id;
431     break;
432   case MULTICAST:
433     peers_in_tunnel++;
434     if (peers_in_tunnel < 2)
435       return;
436     dest = NULL;
437     break;
438   default:
439     return;
440   }
441   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
442   {
443     GNUNET_SCHEDULER_cancel (disconnect_task);
444     disconnect_task =
445         GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers, NULL);
446     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
447                 "***************** test: Sending data...\n");
448     peers_responded = 0;
449     GNUNET_MESH_notify_transmit_ready (t, GNUNET_NO, 0,
450                                        GNUNET_TIME_UNIT_FOREVER_REL, dest,
451                                        sizeof (struct GNUNET_MessageHeader),
452                                        &tmt_rdy, (void *) 1L);
453   }
454   else
455   {
456     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
457                 "***************** test: Disconnect already run?\n");
458     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
459                 "***************** test: Aborting...\n");
460   }
461   return;
462 }
463
464
465 static void
466 do_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
467 {
468   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: test_task\n");
469   if (test == MULTICAST)
470   {
471     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
472                 "***************** test: add peer 3\n");
473     GNUNET_MESH_peer_request_connect_add (t, &d3->id);
474   }
475   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: add peer 2\n");
476   GNUNET_MESH_peer_request_connect_add (t, &d2->id);
477   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
478               "***************** test: schedule timeout in 90s\n");
479   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
480   {
481     GNUNET_SCHEDULER_cancel (disconnect_task);
482     disconnect_task =
483         GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers, NULL);
484   }
485 }
486
487
488 /**
489  * Prototype of a callback function indicating that two peers
490  * are currently connected.
491  *
492  * @param cls closure
493  * @param first peer id for first daemon
494  * @param second peer id for the second daemon
495  * @param distance distance between the connected peers
496  * @param emsg error message (NULL on success)
497  */
498 void
499 topo_cb (void *cls, const struct GNUNET_PeerIdentity *first,
500          const struct GNUNET_PeerIdentity *second, const char *emsg)
501 {
502   GNUNET_PEER_Id p1;
503   GNUNET_PEER_Id p2;
504   struct GNUNET_PeerIdentity id;
505
506   GNUNET_PEER_resolve (1, &id);
507   p1 = GNUNET_PEER_search (first);
508   if (p1 == pid1)
509   {
510     p2 = GNUNET_PEER_search (second);
511     if (p2 == 0 || p2 > num_peers)
512     {
513       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
514                   "***************** test: %s is UNKNOWN!? (%u)\n",
515                   GNUNET_i2s (second), p2);
516       return;
517     }
518     mesh_peers[p2]++;
519     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
520                 "***************** test: %s IS a neighbor\n",
521                 GNUNET_i2s (second));
522     return;
523   }
524   p1 = GNUNET_PEER_search (second);
525   if (p1 == pid1)
526   {
527     p2 = GNUNET_PEER_search (first);
528     if (p2 == 0 || p2 > num_peers)
529     {
530       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
531                   "***************** test: %s is UNKNOWN!? (%u)\n",
532                   GNUNET_i2s (first), p2);
533       return;
534     }
535     mesh_peers[p2]++;
536     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
537                 "***************** test: %s IS a neighbor\n",
538                 GNUNET_i2s (first));
539     return;
540   }
541 }
542
543 /**
544  * connect_mesh_service: connect to the mesh service of one of the peers
545  *
546  */
547 static void
548 connect_mesh_service (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
549 {
550   GNUNET_MESH_ApplicationType app;
551   unsigned int i;
552   struct GNUNET_PeerIdentity id;
553
554   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
555               "***************** test: connect_mesh_service\n");
556
557   for (i = 1; i <= num_peers; i++)
558   {
559     GNUNET_PEER_resolve (i, &id);
560     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
561                 "***************** test:   peer %s has %u conns to d1\n",
562                 GNUNET_i2s (&id), mesh_peers[i]);
563     if (mesh_peers[i] == 0)
564       break;
565   }
566   GNUNET_assert (i < num_peers);
567   d2 = GNUNET_TESTING_daemon_get_by_id (pg, &id);
568   if (test == MULTICAST)
569   {
570     for (i++; i <= num_peers; i++)
571     {
572       GNUNET_PEER_resolve (i, &id);
573       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
574                   "***************** test:   peer %s has %u conns to d1\n",
575                   GNUNET_i2s (&id), mesh_peers[i]);
576       if (mesh_peers[i] == 0)
577         break;
578     }
579     GNUNET_assert (i < num_peers);
580     d3 = GNUNET_TESTING_daemon_get_by_id (pg, &id);
581   }
582   app = (GNUNET_MESH_ApplicationType) 0;
583
584 #if VERBOSE
585   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
586               "***************** test: connecting to mesh service of peer %s (%u)\n",
587               GNUNET_i2s (&d1->id), mesh_peers[0]);
588   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
589               "***************** test: connecting to mesh service of peer %s (%u)\n",
590               GNUNET_i2s (&d2->id), i);
591   if (test == MULTICAST)
592   {
593     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
594                 "***************** test: connecting to mesh service of peer %s (%u)\n",
595                 GNUNET_i2s (&d3->id), i);
596   }
597 #endif
598   h1 = GNUNET_MESH_connect (d1->cfg, 10, (void *) 1L, NULL, &tunnel_cleaner,
599                             handlers, &app);
600   h2 = GNUNET_MESH_connect (d2->cfg, 10, (void *) 2L, &incoming_tunnel,
601                             &tunnel_cleaner, handlers, &app);
602   if (test == MULTICAST)
603   {
604     h3 = GNUNET_MESH_connect (d3->cfg, 10, (void *) 3L, &incoming_tunnel,
605                               &tunnel_cleaner, handlers, &app);
606   }
607   t = GNUNET_MESH_tunnel_create (h1, NULL, &ch, &dh, (void *) 1L);
608   peers_in_tunnel = 0;
609   test_task =
610       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
611                                     (GNUNET_TIME_UNIT_SECONDS, 6), &do_test,
612                                     NULL);
613 }
614
615
616
617 /**
618  * peergroup_ready: start test when all peers are connected
619  * @param cls closure
620  * @param emsg error message
621  */
622 static void
623 peergroup_ready (void *cls, const char *emsg)
624 {
625   char *buf;
626   int buf_len;
627   unsigned int i;
628
629   if (emsg != NULL)
630   {
631     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
632                 "***************** test: Peergroup callback called with error, aborting test!\n");
633     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
634                 "***************** test: Error from testing: `%s'\n", emsg);
635     ok--;
636     GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
637     return;
638   }
639 #if VERBOSE
640   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
641               "************************************************************\n");
642   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
643               "***************** test: Peer Group started successfully!\n");
644   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
645               "***************** test: Have %u connections\n",
646               total_connections);
647 #endif
648
649   if (data_file != NULL)
650   {
651     buf = NULL;
652     buf_len = GNUNET_asprintf (&buf, "CONNECTIONS_0: %u\n", total_connections);
653     if (buf_len > 0)
654       GNUNET_DISK_file_write (data_file, buf, buf_len);
655     GNUNET_free (buf);
656   }
657   peers_running = GNUNET_TESTING_daemons_running (pg);
658   for (i = 0; i < num_peers; i++)
659   {
660     GNUNET_PEER_Id peer_id;
661
662     d1 = GNUNET_TESTING_daemon_get (pg, i);
663     peer_id = GNUNET_PEER_intern (&d1->id);
664     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test:   %u: %s\n",
665                 peer_id, GNUNET_i2s (&d1->id));
666   }
667   d1 = GNUNET_TESTING_daemon_get (pg, 0);
668   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
669               "***************** test: Peer looking: %s\n",
670               GNUNET_i2s (&d1->id));
671   pid1 = GNUNET_PEER_intern (&d1->id);
672   mesh_peers[pid1] = 100;
673   GNUNET_TESTING_get_topology (pg, &topo_cb, NULL);
674
675   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
676                                 (GNUNET_TIME_UNIT_SECONDS, 4),
677                                 &connect_mesh_service, NULL);
678   disconnect_task =
679       GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_mesh_peers, NULL);
680
681 }
682
683
684 /**
685  * Function that will be called whenever two daemons are connected by
686  * the testing library.
687  *
688  * @param cls closure
689  * @param first peer id for first daemon
690  * @param second peer id for the second daemon
691  * @param distance distance between the connected peers
692  * @param first_cfg config for the first daemon
693  * @param second_cfg config for the second daemon
694  * @param first_daemon handle for the first daemon
695  * @param second_daemon handle for the second daemon
696  * @param emsg error message (NULL on success)
697  */
698 static void
699 connect_cb (void *cls, const struct GNUNET_PeerIdentity *first,
700             const struct GNUNET_PeerIdentity *second, uint32_t distance,
701             const struct GNUNET_CONFIGURATION_Handle *first_cfg,
702             const struct GNUNET_CONFIGURATION_Handle *second_cfg,
703             struct GNUNET_TESTING_Daemon *first_daemon,
704             struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg)
705 {
706   if (emsg == NULL)
707   {
708     total_connections++;
709   }
710   else
711   {
712     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
713                 "***************** test: Problem with new connection (%s)\n",
714                 emsg);
715     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test:   (%s)\n",
716                 GNUNET_i2s (first));
717     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test:   (%s)\n",
718                 GNUNET_i2s (second));
719   }
720
721 }
722
723
724 /**
725  * run: load configuration options and schedule test to run (start peergroup)
726  * @param cls closure
727  * @param args argv
728  * @param cfgfile configuration file name (can be NULL)
729  * @param cfg configuration handle
730  */
731 static void
732 run (void *cls, char *const *args, const char *cfgfile,
733      const struct GNUNET_CONFIGURATION_Handle *cfg)
734 {
735   char *temp_str;
736   struct GNUNET_TESTING_Host *hosts;
737   char *data_filename;
738
739   ok = 0;
740   testing_cfg = GNUNET_CONFIGURATION_dup (cfg);
741
742   GNUNET_log_setup ("test_mesh_small",
743 #if VERBOSE
744                     "DEBUG",
745 #else
746                     "WARNING",
747 #endif
748                     NULL);
749
750 #if VERBOSE
751   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
752               "***************** test: Starting daemons.\n");
753   GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing",
754                                          "use_progressbars", "YES");
755 #endif
756
757   if (GNUNET_OK !=
758       GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing",
759                                              "num_peers", &num_peers))
760   {
761     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
762                 "Option TESTING:NUM_PEERS is required!\n");
763     return;
764   }
765
766   mesh_peers = GNUNET_malloc (sizeof (uint16_t) * (num_peers + 1));
767
768   if (GNUNET_OK !=
769       GNUNET_CONFIGURATION_get_value_time (testing_cfg, "test_mesh_small",
770                                            "WAIT_TIME", &wait_time))
771   {
772     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
773                 "Option test_mesh_small:wait_time is required!\n");
774     return;
775   }
776
777   if (GNUNET_OK !=
778       GNUNET_CONFIGURATION_get_value_string (testing_cfg, "testing",
779                                              "topology_output_file",
780                                              &topology_file))
781   {
782     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
783                 "Option test_mesh_small:topology_output_file is required!\n");
784     return;
785   }
786
787   if (GNUNET_OK ==
788       GNUNET_CONFIGURATION_get_value_string (testing_cfg, "test_mesh_small",
789                                              "data_output_file",
790                                              &data_filename))
791   {
792     data_file =
793         GNUNET_DISK_file_open (data_filename,
794                                GNUNET_DISK_OPEN_READWRITE |
795                                GNUNET_DISK_OPEN_CREATE,
796                                GNUNET_DISK_PERM_USER_READ |
797                                GNUNET_DISK_PERM_USER_WRITE);
798     if (data_file == NULL)
799     {
800       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n",
801                   data_filename);
802       GNUNET_free (data_filename);
803     }
804   }
805
806   if (GNUNET_YES ==
807       GNUNET_CONFIGURATION_get_value_string (cfg, "test_mesh_small",
808                                              "output_file", &temp_str))
809   {
810     output_file =
811         GNUNET_DISK_file_open (temp_str,
812                                GNUNET_DISK_OPEN_READWRITE |
813                                GNUNET_DISK_OPEN_CREATE,
814                                GNUNET_DISK_PERM_USER_READ |
815                                GNUNET_DISK_PERM_USER_WRITE);
816     if (output_file == NULL)
817       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n",
818                   temp_str);
819   }
820   GNUNET_free_non_null (temp_str);
821
822   hosts = GNUNET_TESTING_hosts_load (testing_cfg);
823
824   pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT,
825                                        &connect_cb, &peergroup_ready, NULL,
826                                        hosts);
827   GNUNET_assert (pg != NULL);
828   shutdown_handle =
829       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_get_forever (),
830                                     &shutdown_task, NULL);
831 }
832
833
834
835 /**
836  * test_mesh_small command line options
837  */
838 static struct GNUNET_GETOPT_CommandLineOption options[] = {
839   {'V', "verbose", NULL,
840    gettext_noop ("be verbose (print progress information)"),
841    0, &GNUNET_GETOPT_set_one, &verbose},
842   GNUNET_GETOPT_OPTION_END
843 };
844
845
846 /**
847  * Main: start test
848  */
849 int
850 main (int argc, char *argv[])
851 {
852   char *const argv2[] = {
853     argv[0],
854     "-c",
855     "test_mesh_small.conf",
856 #if VERBOSE
857     "-L",
858     "DEBUG",
859 #endif
860     NULL
861   };
862
863   /* Each peer is supposed to generate the following callbacks:
864    * 1 incoming tunnel (@dest)
865    * 1 connected peer (@orig)
866    * 1 received data packet (@dest)
867    * 1 received data packet (@orig)
868    * 1 received tunnel destroy (@dest)
869    * _________________________________
870    * 5 x ok expected per peer
871    */
872   int ok_goal;
873
874   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: Start\n");
875   if (strstr (argv[0], "test_mesh_small_unicast") != NULL)
876   {
877     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: UNICAST\n");
878     test = UNICAST;
879     ok_goal = 5;
880   }
881   else if (strstr (argv[0], "test_mesh_small_multicast") != NULL)
882   {
883     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: MULTICAST\n");
884     test = MULTICAST;
885     ok_goal = 10;
886   }
887   else
888   {
889     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: UNKNOWN\n");
890     test = SETUP;
891     ok_goal = 0;
892   }
893
894   GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
895                       "test_mesh_small",
896                       gettext_noop ("Test mesh in a small network."), options,
897                       &run, NULL);
898 #if REMOVE_DIR
899   GNUNET_DISK_directory_remove ("/tmp/test_mesh_small");
900 #endif
901   if (ok_goal > ok)
902   {
903     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
904                 "***************** test: FAILED! (%d/%d)\n", ok, ok_goal);
905     return 1;
906   }
907   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: success\n");
908   return 0;
909 }
910
911 /* end of test_mesh_small.c */