Adapted timeout for slower buildbots
[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, 30)
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 30s\n");
479   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
480   {
481     GNUNET_SCHEDULER_cancel (disconnect_task);
482     disconnect_task =
483         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
484                                       (GNUNET_TIME_UNIT_SECONDS, 30),
485                                       &disconnect_mesh_peers, NULL);
486   }
487 }
488
489
490 /**
491  * Prototype of a callback function indicating that two peers
492  * are currently connected.
493  *
494  * @param cls closure
495  * @param first peer id for first daemon
496  * @param second peer id for the second daemon
497  * @param distance distance between the connected peers
498  * @param emsg error message (NULL on success)
499  */
500 void
501 topo_cb (void *cls, const struct GNUNET_PeerIdentity *first,
502          const struct GNUNET_PeerIdentity *second, const char *emsg)
503 {
504   GNUNET_PEER_Id p1;
505   GNUNET_PEER_Id p2;
506   struct GNUNET_PeerIdentity id;
507
508   GNUNET_PEER_resolve (1, &id);
509   p1 = GNUNET_PEER_search (first);
510   if (p1 == pid1)
511   {
512     p2 = GNUNET_PEER_search (second);
513     if (p2 == 0 || p2 > num_peers)
514     {
515       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
516                   "***************** test: %s is UNKNOWN!? (%u)\n",
517                   GNUNET_i2s (second), p2);
518       return;
519     }
520     mesh_peers[p2]++;
521     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
522                 "***************** test: %s IS a neighbor\n",
523                 GNUNET_i2s (second));
524     return;
525   }
526   p1 = GNUNET_PEER_search (second);
527   if (p1 == pid1)
528   {
529     p2 = GNUNET_PEER_search (first);
530     if (p2 == 0 || p2 > num_peers)
531     {
532       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
533                   "***************** test: %s is UNKNOWN!? (%u)\n",
534                   GNUNET_i2s (first), p2);
535       return;
536     }
537     mesh_peers[p2]++;
538     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
539                 "***************** test: %s IS a neighbor\n",
540                 GNUNET_i2s (first));
541     return;
542   }
543 }
544
545 /**
546  * connect_mesh_service: connect to the mesh service of one of the peers
547  *
548  */
549 static void
550 connect_mesh_service (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
551 {
552   GNUNET_MESH_ApplicationType app;
553   unsigned int i;
554   struct GNUNET_PeerIdentity id;
555
556   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
557               "***************** test: connect_mesh_service\n");
558
559   for (i = 1; i <= num_peers; i++)
560   {
561     GNUNET_PEER_resolve (i, &id);
562     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
563                 "***************** test:   peer %s has %u conns to d1\n",
564                 GNUNET_i2s (&id), mesh_peers[i]);
565     if (mesh_peers[i] == 0)
566       break;
567   }
568   GNUNET_assert (i < num_peers);
569   d2 = GNUNET_TESTING_daemon_get_by_id (pg, &id);
570   if (test == MULTICAST)
571   {
572     for (i++; i <= num_peers; i++)
573     {
574       GNUNET_PEER_resolve (i, &id);
575       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
576                   "***************** test:   peer %s has %u conns to d1\n",
577                   GNUNET_i2s (&id), mesh_peers[i]);
578       if (mesh_peers[i] == 0)
579         break;
580     }
581     GNUNET_assert (i < num_peers);
582     d3 = GNUNET_TESTING_daemon_get_by_id (pg, &id);
583   }
584   app = (GNUNET_MESH_ApplicationType) 0;
585
586 #if VERBOSE
587   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
588               "***************** test: connecting to mesh service of peer %s (%u)\n",
589               GNUNET_i2s (&d1->id), mesh_peers[0]);
590   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
591               "***************** test: connecting to mesh service of peer %s (%u)\n",
592               GNUNET_i2s (&d2->id), i);
593   if (test == MULTICAST)
594   {
595     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
596                 "***************** test: connecting to mesh service of peer %s (%u)\n",
597                 GNUNET_i2s (&d3->id), i);
598   }
599 #endif
600   h1 = GNUNET_MESH_connect (d1->cfg, 10, (void *) 1L, NULL, &tunnel_cleaner,
601                             handlers, &app);
602   h2 = GNUNET_MESH_connect (d2->cfg, 10, (void *) 2L, &incoming_tunnel,
603                             &tunnel_cleaner, handlers, &app);
604   if (test == MULTICAST)
605   {
606     h3 = GNUNET_MESH_connect (d3->cfg, 10, (void *) 3L, &incoming_tunnel,
607                               &tunnel_cleaner, handlers, &app);
608   }
609   t = GNUNET_MESH_tunnel_create (h1, NULL, &ch, &dh, (void *) 1L);
610   peers_in_tunnel = 0;
611   test_task =
612       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
613                                     (GNUNET_TIME_UNIT_SECONDS, 6), &do_test,
614                                     NULL);
615 }
616
617
618
619 /**
620  * peergroup_ready: start test when all peers are connected
621  * @param cls closure
622  * @param emsg error message
623  */
624 static void
625 peergroup_ready (void *cls, const char *emsg)
626 {
627   char *buf;
628   int buf_len;
629   unsigned int i;
630
631   if (emsg != NULL)
632   {
633     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
634                 "***************** test: Peergroup callback called with error, aborting test!\n");
635     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
636                 "***************** test: Error from testing: `%s'\n", emsg);
637     ok--;
638     GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
639     return;
640   }
641 #if VERBOSE
642   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
643               "************************************************************\n");
644   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
645               "***************** test: Peer Group started successfully!\n");
646   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
647               "***************** test: Have %u connections\n",
648               total_connections);
649 #endif
650
651   if (data_file != NULL)
652   {
653     buf = NULL;
654     buf_len = GNUNET_asprintf (&buf, "CONNECTIONS_0: %u\n", total_connections);
655     if (buf_len > 0)
656       GNUNET_DISK_file_write (data_file, buf, buf_len);
657     GNUNET_free (buf);
658   }
659   peers_running = GNUNET_TESTING_daemons_running (pg);
660   for (i = 0; i < num_peers; i++)
661   {
662     GNUNET_PEER_Id peer_id;
663
664     d1 = GNUNET_TESTING_daemon_get (pg, i);
665     peer_id = GNUNET_PEER_intern (&d1->id);
666     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test:   %u: %s\n",
667                 peer_id, GNUNET_i2s (&d1->id));
668   }
669   d1 = GNUNET_TESTING_daemon_get (pg, 0);
670   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
671               "***************** test: Peer looking: %s\n",
672               GNUNET_i2s (&d1->id));
673   pid1 = GNUNET_PEER_intern (&d1->id);
674   mesh_peers[pid1] = 100;
675   GNUNET_TESTING_get_topology (pg, &topo_cb, NULL);
676
677   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
678                                 (GNUNET_TIME_UNIT_SECONDS, 4),
679                                 &connect_mesh_service, NULL);
680   disconnect_task =
681       GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_mesh_peers, NULL);
682
683 }
684
685
686 /**
687  * Function that will be called whenever two daemons are connected by
688  * the testing library.
689  *
690  * @param cls closure
691  * @param first peer id for first daemon
692  * @param second peer id for the second daemon
693  * @param distance distance between the connected peers
694  * @param first_cfg config for the first daemon
695  * @param second_cfg config for the second daemon
696  * @param first_daemon handle for the first daemon
697  * @param second_daemon handle for the second daemon
698  * @param emsg error message (NULL on success)
699  */
700 static void
701 connect_cb (void *cls, const struct GNUNET_PeerIdentity *first,
702             const struct GNUNET_PeerIdentity *second, uint32_t distance,
703             const struct GNUNET_CONFIGURATION_Handle *first_cfg,
704             const struct GNUNET_CONFIGURATION_Handle *second_cfg,
705             struct GNUNET_TESTING_Daemon *first_daemon,
706             struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg)
707 {
708   if (emsg == NULL)
709   {
710     total_connections++;
711   }
712   else
713   {
714     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
715                 "***************** test: Problem with new connection (%s)\n",
716                 emsg);
717     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test:   (%s)\n",
718                 GNUNET_i2s (first));
719     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test:   (%s)\n",
720                 GNUNET_i2s (second));
721   }
722
723 }
724
725
726 /**
727  * run: load configuration options and schedule test to run (start peergroup)
728  * @param cls closure
729  * @param args argv
730  * @param cfgfile configuration file name (can be NULL)
731  * @param cfg configuration handle
732  */
733 static void
734 run (void *cls, char *const *args, const char *cfgfile,
735      const struct GNUNET_CONFIGURATION_Handle *cfg)
736 {
737   char *temp_str;
738   unsigned long long temp_wait;
739   struct GNUNET_TESTING_Host *hosts;
740   char *data_filename;
741
742   ok = 0;
743   testing_cfg = GNUNET_CONFIGURATION_dup (cfg);
744
745   GNUNET_log_setup ("test_mesh_small",
746 #if VERBOSE
747                     "DEBUG",
748 #else
749                     "WARNING",
750 #endif
751                     NULL);
752
753 #if VERBOSE
754   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
755               "***************** test: Starting daemons.\n");
756   GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing",
757                                          "use_progressbars", "YES");
758 #endif
759
760   if (GNUNET_OK !=
761       GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing",
762                                              "num_peers", &num_peers))
763   {
764     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
765                 "Option TESTING:NUM_PEERS is required!\n");
766     return;
767   }
768
769   mesh_peers = GNUNET_malloc (sizeof (uint16_t) * (num_peers + 1));
770
771   if (GNUNET_OK !=
772       GNUNET_CONFIGURATION_get_value_number (testing_cfg, "test_mesh_small",
773                                              "wait_time", &temp_wait))
774   {
775     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
776                 "Option test_mesh_small:wait_time is required!\n");
777     return;
778   }
779
780   if (GNUNET_OK !=
781       GNUNET_CONFIGURATION_get_value_string (testing_cfg, "testing",
782                                              "topology_output_file",
783                                              &topology_file))
784   {
785     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
786                 "Option test_mesh_small:topology_output_file is required!\n");
787     return;
788   }
789
790   if (GNUNET_OK ==
791       GNUNET_CONFIGURATION_get_value_string (testing_cfg, "test_mesh_small",
792                                              "data_output_file",
793                                              &data_filename))
794   {
795     data_file =
796         GNUNET_DISK_file_open (data_filename,
797                                GNUNET_DISK_OPEN_READWRITE |
798                                GNUNET_DISK_OPEN_CREATE,
799                                GNUNET_DISK_PERM_USER_READ |
800                                GNUNET_DISK_PERM_USER_WRITE);
801     if (data_file == NULL)
802     {
803       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n",
804                   data_filename);
805       GNUNET_free (data_filename);
806     }
807   }
808
809   wait_time =
810       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, temp_wait);
811
812   if (GNUNET_YES ==
813       GNUNET_CONFIGURATION_get_value_string (cfg, "test_mesh_small",
814                                              "output_file", &temp_str))
815   {
816     output_file =
817         GNUNET_DISK_file_open (temp_str,
818                                GNUNET_DISK_OPEN_READWRITE |
819                                GNUNET_DISK_OPEN_CREATE,
820                                GNUNET_DISK_PERM_USER_READ |
821                                GNUNET_DISK_PERM_USER_WRITE);
822     if (output_file == NULL)
823       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n",
824                   temp_str);
825   }
826   GNUNET_free_non_null (temp_str);
827
828   hosts = GNUNET_TESTING_hosts_load (testing_cfg);
829
830   pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT,
831                                        &connect_cb, &peergroup_ready, NULL,
832                                        hosts);
833   GNUNET_assert (pg != NULL);
834   shutdown_handle =
835       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_get_forever (),
836                                     &shutdown_task, NULL);
837 }
838
839
840
841 /**
842  * test_mesh_small command line options
843  */
844 static struct GNUNET_GETOPT_CommandLineOption options[] = {
845   {'V', "verbose", NULL,
846    gettext_noop ("be verbose (print progress information)"),
847    0, &GNUNET_GETOPT_set_one, &verbose},
848   GNUNET_GETOPT_OPTION_END
849 };
850
851
852 /**
853  * Main: start test
854  */
855 int
856 main (int argc, char *argv[])
857 {
858   char *const argv2[] = {
859     argv[0],
860     "-c",
861     "test_mesh_small.conf",
862 #if VERBOSE
863     "-L",
864     "DEBUG",
865 #endif
866     NULL
867   };
868
869   /* Each peer is supposed to generate the following callbacks:
870    * 1 incoming tunnel (@dest)
871    * 1 connected peer (@orig)
872    * 1 received data packet (@dest)
873    * 1 received data packet (@orig)
874    * 1 received tunnel destroy (@dest)
875    * _________________________________
876    * 5 x ok expected per peer
877    */
878   int ok_goal;
879
880   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: Start\n");
881   if (strstr (argv[0], "test_mesh_small_unicast") != NULL)
882   {
883     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: UNICAST\n");
884     test = UNICAST;
885     ok_goal = 5;
886   }
887   else if (strstr (argv[0], "test_mesh_small_multicast") != NULL)
888   {
889     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: MULTICAST\n");
890     test = MULTICAST;
891     ok_goal = 10;
892   }
893   else
894   {
895     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: UNKNOWN\n");
896     test = SETUP;
897     ok_goal = 0;
898   }
899
900   GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
901                       "test_mesh_small",
902                       gettext_noop ("Test mesh in a small network."), options,
903                       &run, NULL);
904 #if REMOVE_DIR
905   GNUNET_DISK_directory_remove ("/tmp/test_mesh_small");
906 #endif
907   if (ok_goal != ok)
908   {
909     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
910                 "***************** test: FAILED! (%d/%d)\n", ok, ok_goal);
911     return 1;
912   }
913   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: success\n");
914   return 0;
915 }
916
917 /* end of test_mesh_small.c */