Fixed id counters' cycling
[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, "***************** test: Shutdown of peers failed!\n");
175 #endif
176     ok--;
177   }
178   else
179   {
180 #if VERBOSE
181     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: All peers successfully shut down!\n");
182 #endif
183   }
184 }
185
186
187 static void
188 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
189 {
190 #if VERBOSE
191   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: Ending test.\n");
192 #endif
193
194   if (disconnect_task != GNUNET_SCHEDULER_NO_TASK)
195   {
196     GNUNET_SCHEDULER_cancel (disconnect_task);
197     disconnect_task = GNUNET_SCHEDULER_NO_TASK;
198   }
199
200   if (data_file != NULL)
201     GNUNET_DISK_file_close (data_file);
202   GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
203   GNUNET_CONFIGURATION_destroy (testing_cfg);
204 }
205
206
207 static void
208 disconnect_mesh_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
209 {
210   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
211               "***************** test: disconnecting mesh service of peers\n");
212   disconnect_task = GNUNET_SCHEDULER_NO_TASK;
213   GNUNET_MESH_disconnect(h1);
214   GNUNET_MESH_disconnect(h2);
215   if (test == MULTICAST)
216     GNUNET_MESH_disconnect(h3);
217   if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle)
218   {
219     GNUNET_SCHEDULER_cancel (shutdown_handle);
220     shutdown_handle = GNUNET_SCHEDULER_add_now(&shutdown_task, NULL);
221   }
222 }
223
224
225 /**
226  * Transmit ready callback
227  */
228 size_t
229 tmt_rdy (void *cls, size_t size, void *buf)
230 {
231   struct GNUNET_MessageHeader *msg = buf;
232
233   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test:  tmt_rdy called\n");
234   if (size < sizeof(struct GNUNET_MessageHeader) || NULL == buf)
235     return 0;
236   msg->size = htons (sizeof(struct GNUNET_MessageHeader));
237   msg->type = htons ((long) cls);
238   return sizeof(struct GNUNET_MessageHeader);
239 }
240
241
242 /**
243  * Function is called whenever a message is received.
244  *
245  * @param cls closure (set from GNUNET_MESH_connect)
246  * @param tunnel connection to the other end
247  * @param tunnel_ctx place to store local state associated with the tunnel
248  * @param sender who sent the message
249  * @param message the actual message
250  * @param atsi performance data for the connection
251  * @return GNUNET_OK to keep the connection open,
252  *         GNUNET_SYSERR to close it (signal serious error)
253  */
254 int
255 data_callback (void *cls,
256           struct GNUNET_MESH_Tunnel * tunnel,
257           void **tunnel_ctx,
258           const struct GNUNET_PeerIdentity *sender,
259           const struct GNUNET_MessageHeader *message,
260           const struct GNUNET_ATS_Information *atsi)
261 {
262   long client = (long) cls;
263
264   switch (client)
265   {
266     case 1L:
267       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
268                   "***************** test: Origin client got a response!\n");
269       ok++;
270       peers_responded++;
271       if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
272       {
273         GNUNET_SCHEDULER_cancel (disconnect_task);
274         disconnect_task = GNUNET_SCHEDULER_add_delayed(SHORT_TIME,
275                                                      &disconnect_mesh_peers,
276                                                      NULL);
277       }
278       if (test == MULTICAST && peers_responded < 2)
279         return GNUNET_OK;
280       GNUNET_MESH_tunnel_destroy (tunnel);
281       break;
282     case 2L:
283     case 3L:
284       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
285                   "***************** test: Destination client %u got a message.\n",
286                   client);
287       ok++;
288       GNUNET_MESH_notify_transmit_ready(tunnel,
289                                         GNUNET_NO,
290                                         0,
291                                         GNUNET_TIME_UNIT_FOREVER_REL,
292                                         sender,
293                                         sizeof(struct GNUNET_MessageHeader),
294                                         &tmt_rdy,
295                                         (void *) 1L);
296       if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
297       {
298         GNUNET_SCHEDULER_cancel (disconnect_task);
299         disconnect_task = GNUNET_SCHEDULER_add_delayed(SHORT_TIME,
300                                                       &disconnect_mesh_peers,
301                                                       NULL);
302       }
303       break;
304     default:
305       break;
306   }
307   return GNUNET_OK;
308 }
309
310
311 /**
312  * Handlers, for diverse services
313  */
314 static struct GNUNET_MESH_MessageHandler handlers[] = {
315   {&data_callback, 1, sizeof(struct GNUNET_MessageHeader)},
316   {NULL, 0, 0}
317 };
318
319
320 /**
321  * Method called whenever another peer has added us to a tunnel
322  * the other peer initiated.
323  *
324  * @param cls closure
325  * @param tunnel new handle to the tunnel
326  * @param initiator peer that started the tunnel
327  * @param atsi performance information for the tunnel
328  * @return initial tunnel context for the tunnel
329  *         (can be NULL -- that's not an error)
330  */
331 static void *
332 incoming_tunnel (void *cls,
333                  struct GNUNET_MESH_Tunnel * tunnel,
334                  const struct GNUNET_PeerIdentity * initiator,
335                  const struct GNUNET_ATS_Information * atsi)
336 {
337   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
338               "***************** test: Incoming tunnel from %s to peer %d\n",
339               GNUNET_i2s(initiator),
340               (long) cls);
341   ok++;
342   if ((long) cls == 1L)
343     incoming_t = tunnel;
344   else
345     incoming_t2 = tunnel;
346   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
347   {
348     GNUNET_SCHEDULER_cancel (disconnect_task);
349     disconnect_task = GNUNET_SCHEDULER_add_delayed(SHORT_TIME,
350                                                   &disconnect_mesh_peers,
351                                                   NULL);
352   }
353   return NULL;
354 }
355
356 /**
357  * Function called whenever an inbound tunnel is destroyed.  Should clean up
358  * any associated state.
359  *
360  * @param cls closure (set from GNUNET_MESH_connect)
361  * @param tunnel connection to the other end (henceforth invalid)
362  * @param tunnel_ctx place where local state associated
363  *                   with the tunnel is stored
364  */
365 static void
366 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel,
367                 void *tunnel_ctx)
368 {
369   long i = (long) cls;
370
371   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
372               "***************** test: Incoming tunnel disconnected at peer %d\n",
373               i);
374   if (2L == i)
375     ok++;
376   else if (3L == i)
377     ok++;
378   else
379     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
380               "***************** test: Unknown peer! %d\n",
381               i);
382   peers_in_tunnel--;
383   if (peers_in_tunnel > 0)
384     return;
385
386   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
387   {
388     GNUNET_SCHEDULER_cancel (disconnect_task);
389     disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_mesh_peers, NULL);
390   }
391
392   return;
393 }
394
395
396 /**
397  * Method called whenever a tunnel falls apart.
398  *
399  * @param cls closure
400  * @param peer peer identity the tunnel stopped working with
401  */
402 static void
403 dh (void *cls, const struct GNUNET_PeerIdentity *peer)
404 {
405   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
406               "***************** test: peer %s disconnected\n",
407               GNUNET_i2s(peer));
408   return;
409 }
410
411
412 /**
413  * Method called whenever a peer connects to a tunnel.
414  *
415  * @param cls closure
416  * @param peer peer identity the tunnel was created to, NULL on timeout
417  * @param atsi performance data for the connection
418  */
419 static void
420 ch (void *cls, const struct GNUNET_PeerIdentity *peer,
421     const struct GNUNET_ATS_Information *atsi)
422 {
423   struct GNUNET_PeerIdentity *dest;
424
425   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
426               "***************** test: peer %s connected\n",
427               GNUNET_i2s(peer));
428
429   if (0 == memcmp(&d2->id, peer, sizeof(d2->id)) && (long) cls == 1L)
430     ok++;
431   if (test == MULTICAST &&
432       0 == memcmp(&d3->id, peer, sizeof(d3->id)) &&
433       (long) cls == 1L)
434     ok++;
435   switch (test)
436   {
437     case UNICAST:
438       dest = &d2->id;
439       break;
440     case MULTICAST:
441       peers_in_tunnel++;
442       if (peers_in_tunnel < 2)
443         return;
444       dest = NULL;
445       break;
446     default:
447       return;
448   }
449   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
450   {
451     GNUNET_SCHEDULER_cancel (disconnect_task);
452     disconnect_task = GNUNET_SCHEDULER_add_delayed(SHORT_TIME,
453                                                     &disconnect_mesh_peers,
454                                                     NULL);
455     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
456                 "***************** test: Sending data...\n");
457     peers_responded = 0;
458     GNUNET_MESH_notify_transmit_ready(t,
459                                       GNUNET_NO,
460                                       0,
461                                       GNUNET_TIME_UNIT_FOREVER_REL,
462                                       dest,
463                                       sizeof(struct GNUNET_MessageHeader),
464                                       &tmt_rdy,
465                                       (void *) 1L);
466   }
467   else
468   {
469     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: Disconnect already run?\n");
470     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: Aborting...\n");
471   }
472   return;
473 }
474
475
476 static void
477 do_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
478 {
479   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: test_task\n");
480   if (test == MULTICAST)
481   {
482     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
483                 "***************** test: add peer 3\n");
484     GNUNET_MESH_peer_request_connect_add(t, &d3->id);
485   }
486   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
487               "***************** test: add peer 2\n");
488   GNUNET_MESH_peer_request_connect_add(t, &d2->id);
489   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
490               "***************** test: schedule timeout in 30s\n");
491   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
492   {
493     GNUNET_SCHEDULER_cancel (disconnect_task);
494     disconnect_task = GNUNET_SCHEDULER_add_delayed(
495             GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30),
496             &disconnect_mesh_peers,
497             NULL);
498   }
499 }
500
501
502 /**
503  * Prototype of a callback function indicating that two peers
504  * are currently connected.
505  *
506  * @param cls closure
507  * @param first peer id for first daemon
508  * @param second peer id for the second daemon
509  * @param distance distance between the connected peers
510  * @param emsg error message (NULL on success)
511  */
512 void
513 topo_cb (void *cls,
514          const struct GNUNET_PeerIdentity* first,
515          const struct GNUNET_PeerIdentity* second,
516          const char *emsg)
517 {
518   GNUNET_PEER_Id p1;
519   GNUNET_PEER_Id p2;
520   struct GNUNET_PeerIdentity id;
521
522   GNUNET_PEER_resolve(1, &id);
523   p1 = GNUNET_PEER_search(first);
524   if (p1 == pid1)
525   {
526     p2 = GNUNET_PEER_search(second);
527     if (p2 == 0 || p2 > num_peers)
528     {
529       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
530                   "***************** test: %s is UNKNOWN!? (%u)\n",
531                   GNUNET_i2s(second),
532                   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(second));
539     return;
540   }
541   p1 = GNUNET_PEER_search(second);
542   if (p1 == pid1)
543   {
544     p2 = GNUNET_PEER_search(first);
545     if (p2 == 0 || p2 > num_peers)
546     {
547       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
548                   "***************** test: %s is UNKNOWN!? (%u)\n",
549                   GNUNET_i2s(first),
550                   p2);
551       return;
552     }
553     mesh_peers[p2]++;
554     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
555                 "***************** test: %s IS a neighbor\n",
556                 GNUNET_i2s(first));
557     return;
558   }
559 }
560
561 /**
562  * connect_mesh_service: connect to the mesh service of one of the peers
563  *
564  */
565 static void
566 connect_mesh_service (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
567 {
568   GNUNET_MESH_ApplicationType app;
569   unsigned int i;
570   struct GNUNET_PeerIdentity id;
571
572   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: connect_mesh_service\n");
573
574   for (i = 1; i <= num_peers; i++)
575   {
576     GNUNET_PEER_resolve(i, &id);
577     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
578               "***************** test:   peer %s has %u conns to d1\n",
579               GNUNET_i2s (&id),
580               mesh_peers[i]);
581     if (mesh_peers[i] == 0)
582       break;
583   }
584   GNUNET_assert (i < num_peers);
585   d2 = GNUNET_TESTING_daemon_get_by_id (pg, &id);
586   if (test == MULTICAST)
587   {
588     for (i++; i <= num_peers; i++)
589     {
590       GNUNET_PEER_resolve(i, &id);
591       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
592                 "***************** test:   peer %s has %u conns to d1\n",
593                 GNUNET_i2s (&id),
594                 mesh_peers[i]);
595       if (mesh_peers[i] == 0)
596         break;
597     }
598     GNUNET_assert (i < num_peers);
599     d3 = GNUNET_TESTING_daemon_get_by_id (pg, &id);
600   }
601   app = (GNUNET_MESH_ApplicationType) 0;
602
603 #if VERBOSE
604   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
605               "***************** test: connecting to mesh service of peer %s (%u)\n",
606               GNUNET_i2s (&d1->id),
607               mesh_peers[0]);
608   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
609               "***************** test: connecting to mesh service of peer %s (%u)\n",
610               GNUNET_i2s (&d2->id),
611               i);
612   if (test == MULTICAST)
613   {
614     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
615                 "***************** test: connecting to mesh service of peer %s (%u)\n",
616                 GNUNET_i2s (&d3->id),
617                 i);
618   }
619 #endif
620   h1 = GNUNET_MESH_connect (d1->cfg,
621                             10,
622                             (void *) 1L,
623                             NULL,
624                             &tunnel_cleaner,
625                             handlers,
626                             &app);
627   h2 = GNUNET_MESH_connect (d2->cfg,
628                             10,
629                             (void *) 2L,
630                             &incoming_tunnel,
631                             &tunnel_cleaner,
632                             handlers,
633                             &app);
634   if (test == MULTICAST)
635   {
636     h3 = GNUNET_MESH_connect (d3->cfg,
637                               10,
638                               (void *) 3L,
639                               &incoming_tunnel,
640                               &tunnel_cleaner,
641                               handlers,
642                               &app);
643   }
644   t = GNUNET_MESH_tunnel_create (h1, NULL, &ch, &dh, (void *) 1L);
645   peers_in_tunnel = 0;
646   test_task =
647       GNUNET_SCHEDULER_add_delayed(
648           GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 6),
649           &do_test, NULL);
650 }
651
652
653
654 /**
655  * peergroup_ready: start test when all peers are connected
656  * @param cls closure
657  * @param emsg error message
658  */
659 static void
660 peergroup_ready (void *cls, const char *emsg)
661 {
662   char *buf;
663   int buf_len;
664   unsigned int i;
665
666   if (emsg != NULL)
667   {
668     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
669                 "***************** test: Peergroup callback called with error, aborting test!\n");
670     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
671                 "***************** test: Error from testing: `%s'\n", emsg);
672     ok--;
673     GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
674     return;
675   }
676 #if VERBOSE
677   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
678               "************************************************************\n");
679   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
680               "***************** test: Peer Group started successfully!\n");
681   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
682               "***************** test: Have %u connections\n",
683               total_connections);
684 #endif
685
686   if (data_file != NULL)
687   {
688     buf = NULL;
689     buf_len = GNUNET_asprintf (&buf, "CONNECTIONS_0: %u\n", total_connections);
690     if (buf_len > 0)
691       GNUNET_DISK_file_write (data_file, buf, buf_len);
692     GNUNET_free (buf);
693   }
694   peers_running = GNUNET_TESTING_daemons_running (pg);
695   for (i = 0; i < num_peers; i++)
696   {
697     GNUNET_PEER_Id peer_id;
698
699     d1 = GNUNET_TESTING_daemon_get (pg, i);
700     peer_id = GNUNET_PEER_intern(&d1->id);
701     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
702                 "***************** test:   %u: %s\n",
703                 peer_id,
704                 GNUNET_i2s (&d1->id));
705   }
706   d1 = GNUNET_TESTING_daemon_get (pg, 0);
707   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
708               "***************** test: Peer looking: %s\n",
709               GNUNET_i2s (&d1->id));
710   pid1 = GNUNET_PEER_intern(&d1->id);
711   mesh_peers[pid1] = 100;
712   GNUNET_TESTING_get_topology(pg, &topo_cb, NULL);
713
714   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(
715                                     GNUNET_TIME_UNIT_SECONDS,
716                                     4),
717                                 &connect_mesh_service,
718                                 NULL);
719   disconnect_task =
720       GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_mesh_peers, NULL);
721
722 }
723
724
725 /**
726  * Function that will be called whenever two daemons are connected by
727  * the testing library.
728  *
729  * @param cls closure
730  * @param first peer id for first daemon
731  * @param second peer id for the second daemon
732  * @param distance distance between the connected peers
733  * @param first_cfg config for the first daemon
734  * @param second_cfg config for the second daemon
735  * @param first_daemon handle for the first daemon
736  * @param second_daemon handle for the second daemon
737  * @param emsg error message (NULL on success)
738  */
739 static void
740 connect_cb (void *cls, const struct GNUNET_PeerIdentity *first,
741             const struct GNUNET_PeerIdentity *second, uint32_t distance,
742             const struct GNUNET_CONFIGURATION_Handle *first_cfg,
743             const struct GNUNET_CONFIGURATION_Handle *second_cfg,
744             struct GNUNET_TESTING_Daemon *first_daemon,
745             struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg)
746 {
747   if (emsg == NULL)
748   {
749     total_connections++;
750   }
751   else
752   {
753     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
754                 "***************** test: Problem with new connection (%s)\n",
755                 emsg);
756     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
757                 "***************** test:   (%s)\n",
758                 GNUNET_i2s (first));
759     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
760                 "***************** test:   (%s)\n",
761                 GNUNET_i2s (second));
762   }
763
764 }
765
766
767 /**
768  * run: load configuration options and schedule test to run (start peergroup)
769  * @param cls closure
770  * @param args argv
771  * @param cfgfile configuration file name (can be NULL)
772  * @param cfg configuration handle
773  */
774 static void
775 run (void *cls, char *const *args, const char *cfgfile,
776      const struct GNUNET_CONFIGURATION_Handle *cfg)
777 {
778   char *temp_str;
779   unsigned long long temp_wait;
780   struct GNUNET_TESTING_Host *hosts;
781   char *data_filename;
782
783   ok = 0;
784   testing_cfg = GNUNET_CONFIGURATION_dup (cfg);
785
786   GNUNET_log_setup ("test_mesh_small",
787 #if VERBOSE
788                     "DEBUG",
789 #else
790                     "WARNING",
791 #endif
792                     NULL);
793
794 #if VERBOSE
795   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: Starting daemons.\n");
796   GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing",
797                                          "use_progressbars", "YES");
798 #endif
799
800   if (GNUNET_OK !=
801       GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing",
802                                              "num_peers", &num_peers))
803   {
804     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
805                 "Option TESTING:NUM_PEERS is required!\n");
806     return;
807   }
808
809   mesh_peers = GNUNET_malloc (sizeof(uint16_t) * (num_peers + 1));
810
811   if (GNUNET_OK !=
812       GNUNET_CONFIGURATION_get_value_number (testing_cfg, "test_mesh_small",
813                                              "wait_time", &temp_wait))
814   {
815     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
816                 "Option test_mesh_small:wait_time is required!\n");
817     return;
818   }
819
820   if (GNUNET_OK !=
821       GNUNET_CONFIGURATION_get_value_string (testing_cfg, "testing",
822                                              "topology_output_file",
823                                              &topology_file))
824   {
825     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
826                 "Option test_mesh_small:topology_output_file is required!\n");
827     return;
828   }
829
830   if (GNUNET_OK ==
831       GNUNET_CONFIGURATION_get_value_string (testing_cfg, "test_mesh_small",
832                                              "data_output_file",
833                                              &data_filename))
834   {
835     data_file =
836       GNUNET_DISK_file_open (data_filename,
837                              GNUNET_DISK_OPEN_READWRITE |
838                              GNUNET_DISK_OPEN_CREATE,
839                              GNUNET_DISK_PERM_USER_READ |
840                              GNUNET_DISK_PERM_USER_WRITE);
841     if (data_file == NULL)
842     {
843       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n",
844                   data_filename);
845       GNUNET_free (data_filename);
846     }
847   }
848
849   wait_time =
850       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, temp_wait);
851
852   if (GNUNET_YES ==
853       GNUNET_CONFIGURATION_get_value_string (cfg, "test_mesh_small",
854                                              "output_file", &temp_str))
855   {
856     output_file =
857         GNUNET_DISK_file_open (temp_str,
858                                GNUNET_DISK_OPEN_READWRITE |
859                                GNUNET_DISK_OPEN_CREATE,
860                                GNUNET_DISK_PERM_USER_READ |
861                                GNUNET_DISK_PERM_USER_WRITE);
862     if (output_file == NULL)
863       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n",
864                   temp_str);
865   }
866   GNUNET_free_non_null (temp_str);
867
868   hosts = GNUNET_TESTING_hosts_load (testing_cfg);
869
870   pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT,
871                                        &connect_cb, &peergroup_ready, NULL,
872                                        hosts);
873   GNUNET_assert (pg != NULL);
874   shutdown_handle =
875       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_get_forever (),
876                                     &shutdown_task, NULL);
877 }
878
879
880
881 /**
882  * test_mesh_small command line options
883  */
884 static struct GNUNET_GETOPT_CommandLineOption options[] = {
885   {'V', "verbose", NULL,
886    gettext_noop ("be verbose (print progress information)"),
887    0, &GNUNET_GETOPT_set_one, &verbose},
888   GNUNET_GETOPT_OPTION_END
889 };
890
891
892 /**
893  * Main: start test
894  */
895 int
896 main (int argc, char *argv[])
897 {
898   char *const argv2[] = {
899     argv[0],
900     "-c",
901     "test_mesh_small.conf",
902 #if VERBOSE
903     "-L",
904     "DEBUG",
905 #endif
906     NULL
907   };
908
909   /* Each peer is supposed to generate the following callbacks:
910    * 1 incoming tunnel (@dest)
911    * 1 connected peer (@orig)
912    * 1 received data packet (@dest)
913    * 1 received data packet (@orig)
914    * 1 received tunnel destroy (@dest)
915    * _________________________________
916    * 5 x ok expected per peer
917    */
918   int ok_goal;
919
920   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: Start\n");
921   if (strstr (argv[0], "test_mesh_small_unicast") != NULL)
922   {
923     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: UNICAST\n");
924     test = UNICAST;
925     ok_goal = 5;
926   }
927   else if (strstr (argv[0], "test_mesh_small_multicast") != NULL)
928   {
929     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: MULTICAST\n");
930     test = MULTICAST;
931     ok_goal = 10;
932   }
933   else
934   {
935     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: UNKNOWN\n");
936     test = SETUP;
937     ok_goal = 0;
938   }
939
940   GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
941                       "test_mesh_small",
942                       gettext_noop ("Test mesh in a small network."),
943                       options, &run, NULL);
944 #if REMOVE_DIR
945   GNUNET_DISK_directory_remove ("/tmp/test_mesh_small");
946 #endif
947   if (ok_goal != ok)
948   {
949     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
950                 "***************** test: FAILED! (%d/%d)\n", ok, ok_goal);
951     return 1;
952   }
953   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
954               "***************** test: success\n");
955   return 0;
956 }
957
958 /* end of test_mesh_small.c */