move GNUNET_TRANSPORT_ATS_ to GNUNET_ATS_
[oweals/gnunet.git] / src / mesh / test_mesh_small_unicast.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_unicast.c
22  *
23  * @brief Test for the mesh service: retransmission of unicast 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, 5)
59
60 #define OK_GOAL 4
61
62 static int ok;
63
64 /**
65  * Be verbose
66  */
67 static int verbose;
68
69 /**
70  * Total number of peers in the test.
71  */
72 static unsigned long long num_peers;
73
74 /**
75  * Global configuration file
76  */
77 static struct GNUNET_CONFIGURATION_Handle *testing_cfg;
78
79 /**
80  * Total number of currently running peers.
81  */
82 static unsigned long long peers_running;
83
84 /**
85  * Total number of connections in the whole network.
86  */
87 static unsigned int total_connections;
88
89 /**
90  * The currently running peer group.
91  */
92 static struct GNUNET_TESTING_PeerGroup *pg;
93
94 /**
95  * File to report results to.
96  */
97 static struct GNUNET_DISK_FileHandle *output_file;
98
99 /**
100  * File to log connection info, statistics to.
101  */
102 static struct GNUNET_DISK_FileHandle *data_file;
103
104 /**
105  * How many data points to capture before triggering next round?
106  */
107 static struct GNUNET_TIME_Relative wait_time;
108
109 /**
110  * Task called to disconnect peers.
111  */
112 static GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
113
114 /**
115  * Task To perform tests
116  */
117 static GNUNET_SCHEDULER_TaskIdentifier test_task;
118
119 /**
120  * Task called to shutdown test.
121  */
122 static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle;
123
124 static char *topology_file;
125
126 static char *data_filename;
127
128 static struct GNUNET_TESTING_Daemon *d1;
129
130 static GNUNET_PEER_Id pid1;
131
132 static struct GNUNET_TESTING_Daemon *d2;
133
134 static struct GNUNET_MESH_Handle *h1;
135
136 static struct GNUNET_MESH_Handle *h2;
137
138 static struct GNUNET_MESH_Tunnel *t;
139
140 static struct GNUNET_MESH_Tunnel *incoming_t;
141
142 static uint16_t *mesh_peers;
143
144 /**
145  * Check whether peers successfully shut down.
146  */
147 static void
148 shutdown_callback (void *cls, const char *emsg)
149 {
150   if (emsg != NULL)
151   {
152 #if VERBOSE
153     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Shutdown of peers failed!\n");
154 #endif
155     ok--;
156   }
157   else
158   {
159 #if VERBOSE
160     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: All peers successfully shut down!\n");
161 #endif
162   }
163 }
164
165
166 static void
167 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
168 {
169 #if VERBOSE
170   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Ending test.\n");
171 #endif
172
173   if (disconnect_task != GNUNET_SCHEDULER_NO_TASK)
174   {
175     GNUNET_SCHEDULER_cancel (disconnect_task);
176     disconnect_task = GNUNET_SCHEDULER_NO_TASK;
177   }
178
179   if (data_file != NULL)
180     GNUNET_DISK_file_close (data_file);
181   GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
182   GNUNET_CONFIGURATION_destroy (testing_cfg);
183 }
184
185
186 static void
187 disconnect_mesh_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
188 {
189   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
190               "test: disconnecting mesh service of peers\n");
191   disconnect_task = GNUNET_SCHEDULER_NO_TASK;
192   GNUNET_MESH_disconnect(h1);
193   GNUNET_MESH_disconnect(h2);
194   GNUNET_SCHEDULER_cancel (shutdown_handle);
195   shutdown_handle = GNUNET_SCHEDULER_add_now(&shutdown_task, NULL);
196 }
197
198
199 /**
200  * Transmit ready callback
201  */
202 size_t
203 tmt_rdy (void *cls, size_t size, void *buf)
204 {
205   struct GNUNET_MessageHeader *msg = buf;
206
207   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test:  tmt_rdy called\n");
208   if (size < sizeof(struct GNUNET_MessageHeader) || NULL == buf)
209     return 0;
210   msg->size = htons (sizeof(struct GNUNET_MessageHeader));
211   msg->type = htons ((long) cls);
212   return sizeof(struct GNUNET_MessageHeader);
213 }
214
215
216 /**
217  * Function is called whenever a message is received.
218  *
219  * @param cls closure (set from GNUNET_MESH_connect)
220  * @param tunnel connection to the other end
221  * @param tunnel_ctx place to store local state associated with the tunnel
222  * @param sender who sent the message
223  * @param message the actual message
224  * @param atsi performance data for the connection
225  * @return GNUNET_OK to keep the connection open,
226  *         GNUNET_SYSERR to close it (signal serious error)
227  */
228 int
229 data_callback (void *cls,
230           struct GNUNET_MESH_Tunnel * tunnel,
231           void **tunnel_ctx,
232           const struct GNUNET_PeerIdentity *sender,
233           const struct GNUNET_MessageHeader *message,
234           const struct GNUNET_ATS_Information *atsi)
235 {
236   long client = (long) cls;
237
238   switch (client)
239   {
240     case 1L:
241       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
242                   "test: Origin client got a response!\n");
243       ok++;
244       GNUNET_SCHEDULER_cancel (disconnect_task);
245       disconnect_task = GNUNET_SCHEDULER_add_now(&disconnect_mesh_peers,
246                                                  NULL);
247       break;
248     case 2L:
249       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
250                   "test: Destination client got a message \n");
251       ok++;
252       GNUNET_MESH_notify_transmit_ready(incoming_t,
253                                         GNUNET_NO,
254                                         0,
255                                         GNUNET_TIME_UNIT_FOREVER_REL,
256                                         sender,
257                                         sizeof(struct GNUNET_MessageHeader),
258                                         &tmt_rdy,
259                                         (void *) 1L);
260       GNUNET_SCHEDULER_cancel (disconnect_task);
261       disconnect_task = GNUNET_SCHEDULER_add_delayed(SHORT_TIME,
262                                                      &disconnect_mesh_peers,
263                                                      NULL);
264       break;
265     default:
266       break;
267   }
268   return GNUNET_OK;
269 }
270
271
272 /**
273  * Handlers, for diverse services
274  */
275 static struct GNUNET_MESH_MessageHandler handlers[] = {
276   {&data_callback, 1, sizeof(struct GNUNET_MessageHeader)},
277   {NULL, 0, 0}
278 };
279
280
281 /**
282  * Method called whenever another peer has added us to a tunnel
283  * the other peer initiated.
284  *
285  * @param cls closure
286  * @param tunnel new handle to the tunnel
287  * @param initiator peer that started the tunnel
288  * @param atsi performance information for the tunnel
289  * @return initial tunnel context for the tunnel
290  *         (can be NULL -- that's not an error)
291  */
292 static void *
293 incoming_tunnel (void *cls,
294                  struct GNUNET_MESH_Tunnel * tunnel,
295                  const struct GNUNET_PeerIdentity * initiator,
296                  const struct GNUNET_ATS_Information * atsi)
297 {
298   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
299               "test: Incoming tunnel from %s\n",
300               GNUNET_i2s(initiator));
301   ok++;
302   incoming_t = tunnel;
303   GNUNET_SCHEDULER_cancel (disconnect_task);
304   disconnect_task = GNUNET_SCHEDULER_add_delayed(SHORT_TIME,
305                                                  &disconnect_mesh_peers,
306                                                  NULL);
307   return NULL;
308 }
309
310 /**
311  * Function called whenever an inbound tunnel is destroyed.  Should clean up
312  * any associated state.
313  *
314  * @param cls closure (set from GNUNET_MESH_connect)
315  * @param tunnel connection to the other end (henceforth invalid)
316  * @param tunnel_ctx place where local state associated
317  *                   with the tunnel is stored
318  */
319 static void
320 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel,
321                 void *tunnel_ctx)
322 {
323 #if VERBOSE
324   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: tunnel disconnected\n");
325 #endif
326   
327   return;
328 }
329
330
331 /**
332  * Method called whenever a tunnel falls apart.
333  *
334  * @param cls closure
335  * @param peer peer identity the tunnel stopped working with
336  */
337 static void
338 dh (void *cls, const struct GNUNET_PeerIdentity *peer)
339 {
340   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
341               "test: peer %s disconnected\n",
342               GNUNET_i2s(peer));
343   return;
344 }
345
346
347 /**
348  * Method called whenever a tunnel is established.
349  *
350  * @param cls closure
351  * @param peer peer identity the tunnel was created to, NULL on timeout
352  * @param atsi performance data for the connection
353  */
354 static void
355 ch (void *cls, const struct GNUNET_PeerIdentity *peer,
356     const struct GNUNET_ATS_Information *atsi)
357 {
358   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
359               "test: peer %s connected\n",
360               GNUNET_i2s(peer));
361   if (0 == memcmp(&d2->id, peer, sizeof(d2->id)) && (long) cls == 1L)
362     ok++;
363   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
364   {
365     GNUNET_SCHEDULER_cancel (disconnect_task);
366     disconnect_task = GNUNET_SCHEDULER_add_delayed(SHORT_TIME,
367                                                     &disconnect_mesh_peers,
368                                                     NULL);
369     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Sending data unicast...\n");
370     GNUNET_MESH_notify_transmit_ready(t,
371                                       GNUNET_NO,
372                                       0,
373                                       GNUNET_TIME_UNIT_FOREVER_REL,
374                                       &d2->id,
375                                       sizeof(struct GNUNET_MessageHeader),
376                                       &tmt_rdy,
377                                       (void *) 1L);
378   }
379   return;
380 }
381
382
383 static void
384 do_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
385 {
386   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: test_task\n");
387   GNUNET_MESH_peer_request_connect_add(t, &d2->id);
388   GNUNET_SCHEDULER_cancel (disconnect_task);
389   disconnect_task = GNUNET_SCHEDULER_add_delayed(
390           GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30),
391                                &disconnect_mesh_peers, NULL);
392 }
393
394
395 /**
396  * Prototype of a callback function indicating that two peers
397  * are currently connected.
398  *
399  * @param cls closure
400  * @param first peer id for first daemon
401  * @param second peer id for the second daemon
402  * @param distance distance between the connected peers
403  * @param emsg error message (NULL on success)
404  */
405 void
406 topo_cb (void *cls,
407          const struct GNUNET_PeerIdentity* first,
408          const struct GNUNET_PeerIdentity* second,
409          const char *emsg)
410 {
411   GNUNET_PEER_Id p1;
412   GNUNET_PEER_Id p2;
413   struct GNUNET_PeerIdentity id;
414
415   GNUNET_PEER_resolve(1, &id);
416   p1 = GNUNET_PEER_search(first);
417   if (p1 == pid1)
418   {
419     p2 = GNUNET_PEER_search(second);
420     GNUNET_assert(p2 < num_peers);
421     GNUNET_assert(p2 > 0);
422     mesh_peers[p2]++;
423     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
424                 "test: %s IS a neighbor\n",
425                 GNUNET_i2s(second));
426     return;
427   }
428   p1 = GNUNET_PEER_search(second);
429   if (p1 == pid1)
430   {
431     p2 = GNUNET_PEER_search(first);
432     GNUNET_assert(p2 < num_peers);
433     GNUNET_assert(p2 > 0);
434     mesh_peers[p2]++;
435     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
436                 "test: %s IS a neighbor\n",
437                 GNUNET_i2s(first));
438     return;
439   }
440 }
441
442 /**
443  * connect_mesh_service: connect to the mesh service of one of the peers
444  *
445  */
446 static void
447 connect_mesh_service (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
448 {
449   GNUNET_MESH_ApplicationType app;
450   unsigned int i;
451   struct GNUNET_PeerIdentity id;
452
453   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: connect_mesh_service\n");
454
455   for (i = 1; i <= num_peers; i++)
456   {
457     GNUNET_PEER_resolve(i, &id);
458     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
459               "test:   peer %s has %u conns to d1\n",
460               GNUNET_i2s (&id),
461               mesh_peers[i]);
462     if (mesh_peers[i] == 0)
463       break;
464   }
465   GNUNET_assert (i < num_peers);
466   d2 = GNUNET_TESTING_daemon_get_by_id (pg, &id);
467   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
468               "test: Peer searched: %s\n",
469               GNUNET_i2s (&d2->id));
470   app = (GNUNET_MESH_ApplicationType) 0;
471
472 #if VERBOSE
473   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
474               "test: connecting to mesh service of peer %s (%u)\n",
475               GNUNET_i2s (&d1->id),
476               mesh_peers[0]);
477   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
478               "test: connecting to mesh service of peer %s (%u)\n",
479               GNUNET_i2s (&d2->id),
480               i);
481 #endif
482   h1 = GNUNET_MESH_connect (d1->cfg,
483                             10,
484                             (void *) 1L,
485                             NULL,
486                             &tunnel_cleaner,
487                             handlers,
488                             &app);
489   h2 = GNUNET_MESH_connect (d2->cfg,
490                             10,
491                             (void *) 2L,
492                             &incoming_tunnel,
493                             &tunnel_cleaner,
494                             handlers,
495                             &app);
496 #if VERBOSE
497   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
498               "test: connected to mesh service of peer %s\n",
499               GNUNET_i2s (&d1->id));
500   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
501               "test: connected to mesh service of peer %s\n",
502               GNUNET_i2s (&d2->id));
503 #endif
504   t = GNUNET_MESH_tunnel_create (h1, NULL, &ch, &dh, (void *) 1L);
505   test_task =
506       GNUNET_SCHEDULER_add_delayed(
507           GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 6),
508           &do_test, NULL);
509 }
510
511
512
513 /**
514  * peergroup_ready: start test when all peers are connected
515  * @param cls closure
516  * @param emsg error message
517  */
518 static void
519 peergroup_ready (void *cls, const char *emsg)
520 {
521   char *buf;
522   int buf_len;
523   unsigned int i;
524
525   if (emsg != NULL)
526   {
527     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
528                 "test: Peergroup callback called with error, aborting test!\n");
529     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
530                 "test: Error from testing: `%s'\n", emsg);
531     ok--;
532     GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
533     return;
534   }
535 #if VERBOSE
536   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
537               "************************************************************\n");
538   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
539               "test: Peer Group started successfully!\n");
540   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
541               "test: Have %u connections\n",
542               total_connections);
543 #endif
544
545   if (data_file != NULL)
546   {
547     buf = NULL;
548     buf_len = GNUNET_asprintf (&buf, "CONNECTIONS_0: %u\n", total_connections);
549     if (buf_len > 0)
550       GNUNET_DISK_file_write (data_file, buf, buf_len);
551     GNUNET_free (buf);
552   }
553   peers_running = GNUNET_TESTING_daemons_running (pg);
554   for (i = 0; i < num_peers; i++)
555   {
556     d1 = GNUNET_TESTING_daemon_get (pg, i);
557     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
558                 "test:   %u: %s\n",
559                 GNUNET_PEER_intern(&d1->id),
560                 GNUNET_i2s (&d1->id));
561   }
562   d1 = GNUNET_TESTING_daemon_get (pg, 0);
563   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
564               "test: Peer looking: %s\n",
565               GNUNET_i2s (&d1->id));
566   pid1 = GNUNET_PEER_intern(&d1->id);
567   mesh_peers[pid1] = 100;
568   GNUNET_TESTING_get_topology(pg, &topo_cb, NULL);
569
570   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(
571                                     GNUNET_TIME_UNIT_SECONDS,
572                                     4),
573                                 &connect_mesh_service,
574                                 NULL);
575   disconnect_task =
576       GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_mesh_peers, NULL);
577
578 }
579
580
581 /**
582  * Function that will be called whenever two daemons are connected by
583  * the testing library.
584  *
585  * @param cls closure
586  * @param first peer id for first daemon
587  * @param second peer id for the second daemon
588  * @param distance distance between the connected peers
589  * @param first_cfg config for the first daemon
590  * @param second_cfg config for the second daemon
591  * @param first_daemon handle for the first daemon
592  * @param second_daemon handle for the second daemon
593  * @param emsg error message (NULL on success)
594  */
595 static void
596 connect_cb (void *cls, const struct GNUNET_PeerIdentity *first,
597             const struct GNUNET_PeerIdentity *second, uint32_t distance,
598             const struct GNUNET_CONFIGURATION_Handle *first_cfg,
599             const struct GNUNET_CONFIGURATION_Handle *second_cfg,
600             struct GNUNET_TESTING_Daemon *first_daemon,
601             struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg)
602 {
603   if (emsg == NULL)
604   {
605     total_connections++;
606   }
607   else
608   {
609     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
610                 "test: Problem with new connection (%s)\n",
611                 emsg);
612   }
613
614 }
615
616
617 /**
618  * run: load configuration options and schedule test to run (start peergroup)
619  * @param cls closure
620  * @param args argv
621  * @param cfgfile configuration file name (can be NULL)
622  * @param cfg configuration handle
623  */
624 static void
625 run (void *cls, char *const *args, const char *cfgfile,
626      const struct GNUNET_CONFIGURATION_Handle *cfg)
627 {
628   char *temp_str;
629   unsigned long long temp_wait;
630   struct GNUNET_TESTING_Host *hosts;
631
632   ok = 0;
633   testing_cfg = GNUNET_CONFIGURATION_dup (cfg);
634
635   GNUNET_log_setup ("test_mesh_small_unicast",
636 #if VERBOSE
637                     "DEBUG",
638 #else
639                     "WARNING",
640 #endif
641                     NULL);
642
643 #if VERBOSE
644   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Starting daemons.\n");
645   GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing",
646                                          "use_progressbars", "YES");
647 #endif
648
649   if (GNUNET_OK !=
650       GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing",
651                                              "num_peers", &num_peers))
652   {
653     GNUNET_assert (GNUNET_OK ==
654                    GNUNET_CONFIGURATION_load (testing_cfg,
655                                               "test_mesh_small.conf"));
656     if (GNUNET_OK !=
657         GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing",
658                                                "num_peers", &num_peers))
659     {
660       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
661                   "Option TESTING:NUM_PEERS is required!\n");
662       return;
663     }
664   }
665
666   mesh_peers = GNUNET_malloc (sizeof(GNUNET_PEER_Id) * (num_peers + 1));
667
668   if (GNUNET_OK !=
669       GNUNET_CONFIGURATION_get_value_number (testing_cfg, "test_mesh_small",
670                                              "wait_time", &temp_wait))
671   {
672     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
673                 "Option test_mesh_small:wait_time is required!\n");
674     return;
675   }
676
677   if (GNUNET_OK !=
678       GNUNET_CONFIGURATION_get_value_string (testing_cfg, "testing",
679                                              "topology_output_file",
680                                              &topology_file))
681   {
682     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
683                 "Option test_mesh_small:topology_output_file is required!\n");
684     return;
685   }
686
687   if (GNUNET_OK !=
688       GNUNET_CONFIGURATION_get_value_string (testing_cfg, "test_mesh_small",
689                                              "data_output_file",
690                                              &data_filename))
691   {
692     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
693                 "Option test_mesh_small:data_output_file is required!\n");
694     return;
695   }
696
697   data_file =
698       GNUNET_DISK_file_open (data_filename,
699                              GNUNET_DISK_OPEN_READWRITE |
700                              GNUNET_DISK_OPEN_CREATE,
701                              GNUNET_DISK_PERM_USER_READ |
702                              GNUNET_DISK_PERM_USER_WRITE);
703   if (data_file == NULL)
704   {
705     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n",
706                 data_filename);
707     GNUNET_free (data_filename);
708   }
709
710   wait_time =
711       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, temp_wait);
712
713   if (GNUNET_YES ==
714       GNUNET_CONFIGURATION_get_value_string (cfg, "test_mesh_small",
715                                              "output_file", &temp_str))
716   {
717     output_file =
718         GNUNET_DISK_file_open (temp_str,
719                                GNUNET_DISK_OPEN_READWRITE |
720                                GNUNET_DISK_OPEN_CREATE,
721                                GNUNET_DISK_PERM_USER_READ |
722                                GNUNET_DISK_PERM_USER_WRITE);
723     if (output_file == NULL)
724       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n",
725                   temp_str);
726   }
727   GNUNET_free_non_null (temp_str);
728
729   hosts = GNUNET_TESTING_hosts_load (testing_cfg);
730
731   pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT,
732                                        &connect_cb, &peergroup_ready, NULL,
733                                        hosts);
734   GNUNET_assert (pg != NULL);
735   shutdown_handle =
736       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_get_forever (),
737                                     &shutdown_task, NULL);
738 }
739
740
741
742 /**
743  * test_mesh_small command line options
744  */
745 static struct GNUNET_GETOPT_CommandLineOption options[] = {
746   {'V', "verbose", NULL,
747    gettext_noop ("be verbose (print progress information)"),
748    0, &GNUNET_GETOPT_set_one, &verbose},
749   GNUNET_GETOPT_OPTION_END
750 };
751
752
753 /**
754  * Main: start test
755  */
756 int
757 main (int argc, char *argv[])
758 {
759   GNUNET_PROGRAM_run (argc, argv, "test_mesh_small_unicast",
760                       gettext_noop ("Test mesh unicast in a small network."),
761                       options, &run, NULL);
762 #if REMOVE_DIR
763   GNUNET_DISK_directory_remove ("/tmp/test_mesh_small_unicast");
764 #endif
765   if (OK_GOAL != ok)
766   {
767     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
768                 "test: FAILED! (%d/%d)\n",
769                 ok, OK_GOAL);
770     return 1;
771   }
772   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: success\n");
773   return 0;
774 }
775
776 /* end of test_mesh_small_unicast.c */