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