Allowed to destroy NULL paths
[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     d1 = GNUNET_TESTING_daemon_get (pg, i);
692     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
693                 "***************** test:   %u: %s\n",
694                 GNUNET_PEER_intern(&d1->id),
695                 GNUNET_i2s (&d1->id));
696   }
697   d1 = GNUNET_TESTING_daemon_get (pg, 0);
698   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
699               "***************** test: Peer looking: %s\n",
700               GNUNET_i2s (&d1->id));
701   pid1 = GNUNET_PEER_intern(&d1->id);
702   mesh_peers[pid1] = 100;
703   GNUNET_TESTING_get_topology(pg, &topo_cb, NULL);
704
705   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(
706                                     GNUNET_TIME_UNIT_SECONDS,
707                                     4),
708                                 &connect_mesh_service,
709                                 NULL);
710   disconnect_task =
711       GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_mesh_peers, NULL);
712
713 }
714
715
716 /**
717  * Function that will be called whenever two daemons are connected by
718  * the testing library.
719  *
720  * @param cls closure
721  * @param first peer id for first daemon
722  * @param second peer id for the second daemon
723  * @param distance distance between the connected peers
724  * @param first_cfg config for the first daemon
725  * @param second_cfg config for the second daemon
726  * @param first_daemon handle for the first daemon
727  * @param second_daemon handle for the second daemon
728  * @param emsg error message (NULL on success)
729  */
730 static void
731 connect_cb (void *cls, const struct GNUNET_PeerIdentity *first,
732             const struct GNUNET_PeerIdentity *second, uint32_t distance,
733             const struct GNUNET_CONFIGURATION_Handle *first_cfg,
734             const struct GNUNET_CONFIGURATION_Handle *second_cfg,
735             struct GNUNET_TESTING_Daemon *first_daemon,
736             struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg)
737 {
738   if (emsg == NULL)
739   {
740     total_connections++;
741   }
742   else
743   {
744     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
745                 "***************** test: Problem with new connection (%s)\n",
746                 emsg);
747   }
748
749 }
750
751
752 /**
753  * run: load configuration options and schedule test to run (start peergroup)
754  * @param cls closure
755  * @param args argv
756  * @param cfgfile configuration file name (can be NULL)
757  * @param cfg configuration handle
758  */
759 static void
760 run (void *cls, char *const *args, const char *cfgfile,
761      const struct GNUNET_CONFIGURATION_Handle *cfg)
762 {
763   char *temp_str;
764   unsigned long long temp_wait;
765   struct GNUNET_TESTING_Host *hosts;
766   char *data_filename;
767
768   ok = 0;
769   testing_cfg = GNUNET_CONFIGURATION_dup (cfg);
770
771   GNUNET_log_setup ("test_mesh_small",
772 #if VERBOSE
773                     "DEBUG",
774 #else
775                     "WARNING",
776 #endif
777                     NULL);
778
779 #if VERBOSE
780   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: Starting daemons.\n");
781   GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing",
782                                          "use_progressbars", "YES");
783 #endif
784
785   if (GNUNET_OK !=
786       GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing",
787                                              "num_peers", &num_peers))
788   {
789     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
790                 "Option TESTING:NUM_PEERS is required!\n");
791     return;
792   }
793
794   mesh_peers = GNUNET_malloc (sizeof(GNUNET_PEER_Id) * (num_peers + 1));
795
796   if (GNUNET_OK !=
797       GNUNET_CONFIGURATION_get_value_number (testing_cfg, "test_mesh_small",
798                                              "wait_time", &temp_wait))
799   {
800     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
801                 "Option test_mesh_small:wait_time is required!\n");
802     return;
803   }
804
805   if (GNUNET_OK !=
806       GNUNET_CONFIGURATION_get_value_string (testing_cfg, "testing",
807                                              "topology_output_file",
808                                              &topology_file))
809   {
810     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
811                 "Option test_mesh_small:topology_output_file is required!\n");
812     return;
813   }
814
815   if (GNUNET_OK ==
816       GNUNET_CONFIGURATION_get_value_string (testing_cfg, "test_mesh_small",
817                                              "data_output_file",
818                                              &data_filename))
819   {
820     data_file =
821       GNUNET_DISK_file_open (data_filename,
822                              GNUNET_DISK_OPEN_READWRITE |
823                              GNUNET_DISK_OPEN_CREATE,
824                              GNUNET_DISK_PERM_USER_READ |
825                              GNUNET_DISK_PERM_USER_WRITE);
826     if (data_file == NULL)
827     {
828       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n",
829                   data_filename);
830       GNUNET_free (data_filename);
831     }
832   }
833
834   wait_time =
835       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, temp_wait);
836
837   if (GNUNET_YES ==
838       GNUNET_CONFIGURATION_get_value_string (cfg, "test_mesh_small",
839                                              "output_file", &temp_str))
840   {
841     output_file =
842         GNUNET_DISK_file_open (temp_str,
843                                GNUNET_DISK_OPEN_READWRITE |
844                                GNUNET_DISK_OPEN_CREATE,
845                                GNUNET_DISK_PERM_USER_READ |
846                                GNUNET_DISK_PERM_USER_WRITE);
847     if (output_file == NULL)
848       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n",
849                   temp_str);
850   }
851   GNUNET_free_non_null (temp_str);
852
853   hosts = GNUNET_TESTING_hosts_load (testing_cfg);
854
855   pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT,
856                                        &connect_cb, &peergroup_ready, NULL,
857                                        hosts);
858   GNUNET_assert (pg != NULL);
859   shutdown_handle =
860       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_get_forever (),
861                                     &shutdown_task, NULL);
862 }
863
864
865
866 /**
867  * test_mesh_small command line options
868  */
869 static struct GNUNET_GETOPT_CommandLineOption options[] = {
870   {'V', "verbose", NULL,
871    gettext_noop ("be verbose (print progress information)"),
872    0, &GNUNET_GETOPT_set_one, &verbose},
873   GNUNET_GETOPT_OPTION_END
874 };
875
876
877 /**
878  * Main: start test
879  */
880 int
881 main (int argc, char *argv[])
882 {
883   char *const argv2[] = {
884     argv[0],
885     "-c",
886     "test_mesh_small.conf",
887 #if VERBOSE
888     "-L",
889     "DEBUG",
890 #endif
891     NULL
892   };
893
894   /* Each peer is supposed to generate the following callbacks:
895    * 1 incoming tunnel (@dest)
896    * 1 connected peer (@orig)
897    * 1 received data packet (@dest)
898    * 1 received data packet (@orig)
899    * 1 received tunnel destroy (@dest)
900    * _________________________________
901    * 5 x ok expected per peer
902    */
903   int ok_goal;
904
905   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: Start\n");
906   if (strstr (argv[0], "test_mesh_small_unicast") != NULL)
907   {
908     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: UNICAST\n");
909     test = UNICAST;
910     ok_goal = 5;
911   }
912   else if (strstr (argv[0], "test_mesh_small_multicast") != NULL)
913   {
914     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: MULTICAST\n");
915     test = MULTICAST;
916     ok_goal = 10;
917   }
918   else
919   {
920     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "***************** test: UNKNOWN\n");
921     test = SETUP;
922     ok_goal = 0;
923   }
924
925   GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
926                       "test_mesh_small",
927                       gettext_noop ("Test mesh in a small network."),
928                       options, &run, NULL);
929 #if REMOVE_DIR
930   GNUNET_DISK_directory_remove ("/tmp/test_mesh_small");
931 #endif
932   if (ok_goal != ok)
933   {
934     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
935                 "***************** test: FAILED! (%d/%d)\n", ok, ok_goal);
936     return 1;
937   }
938   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
939               "***************** test: success\n");
940   return 0;
941 }
942
943 /* end of test_mesh_small.c */