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