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