- not necessarilly a bug
[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 "mesh_test_lib.h"
28 #include "gnunet_mesh_service.h"
29 #include <gauger.h>
30
31
32 /**
33  * How namy messages to send
34  */
35 #define TOTAL_PACKETS 1000
36
37 /**
38  * How long until we give up on connecting the peers?
39  */
40 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
41
42 /**
43  * Time to wait for stuff that should be rather fast
44  */
45 #define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20)
46
47 /**
48  * DIFFERENT TESTS TO RUN
49  */
50 #define SETUP 0
51 #define UNICAST 1
52 #define MULTICAST 2
53 #define SPEED 3
54 #define SPEED_ACK 4
55 #define SPEED_MIN 5
56 #define SPEED_NOBUF 6
57 #define P2P_SIGNAL 10
58
59 /**
60  * Which test are we running?
61  */
62 static int test;
63
64 /**
65  * String with test name
66  */
67 char *test_name;
68
69 /**
70  * Flag to send traffic leaf->root in speed tests to test BCK_ACK logic.
71  */
72 static int test_backwards = GNUNET_NO;
73
74 /**
75  * How many events have happened
76  */
77 static int ok;
78
79  /**
80   * Each peer is supposed to generate the following callbacks:
81   * 1 incoming tunnel (@dest)
82   * 1 connected peer (@orig)
83   * 1 received data packet (@dest)
84   * 1 received data packet (@orig)
85   * 1 received tunnel destroy (@dest)
86   * _________________________________
87   * 5 x ok expected per peer
88   */
89 int ok_goal;
90
91
92 /**
93  * Size of each test packet
94  */
95 size_t size_payload = sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t);
96
97 /**
98  * Operation to get peer ids.
99  */
100 struct GNUNET_TESTBED_Operation *t_op[3];
101
102 /**
103  * Peer ids.
104  */
105 struct GNUNET_PeerIdentity *p_id[3];
106
107 /**
108  * Peer ids counter.
109  */
110 unsigned int p_ids;
111
112 /**
113  * Is the setup initialized?
114  */
115 static int initialized;
116
117 /**
118  * Peers that have been connected
119  */
120 static int peers_in_tunnel;
121
122 /**
123  * Peers that have responded
124  */
125 static int peers_responded;
126
127 /**
128  * Number of payload packes sent
129  */
130 static int data_sent;
131
132 /**
133  * Number of payload packets received
134  */
135 static int data_received;
136
137 /**
138  * Number of payload packed explicitly (app level) acknowledged
139  */
140 static int data_ack;
141
142 /**
143  * Total number of currently running peers.
144  */
145 static unsigned long long peers_running;
146
147 /**
148  * Test context (to shut down).
149  */
150 struct GNUNET_MESH_TEST_Context *test_ctx;
151
152 /**
153  * Task called to disconnect peers.
154  */
155 static GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
156
157 /**
158  * Task To perform tests
159  */
160 static GNUNET_SCHEDULER_TaskIdentifier test_task;
161
162 /**
163  * Task called to shutdown test.
164  */
165 static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle;
166
167 /**
168  * Mesh handle for the root peer
169  */
170 static struct GNUNET_MESH_Handle *h1;
171
172 /**
173  * Mesh handle for the first leaf peer
174  */
175 static struct GNUNET_MESH_Handle *h2;
176
177 /**
178  * Mesh handle for the second leaf peer
179  */
180 static struct GNUNET_MESH_Handle *h3;
181
182 /**
183  * Tunnel handle for the root peer
184  */
185 static struct GNUNET_MESH_Tunnel *t;
186
187 /**
188  * Tunnel handle for the first leaf peer
189  */
190 static struct GNUNET_MESH_Tunnel *incoming_t;
191
192 /**
193  * Tunnel handle for the second leaf peer
194  */
195 static struct GNUNET_MESH_Tunnel *incoming_t2;
196
197 /**
198  * Time we started the data transmission (after tunnel has been established
199  * and initilized).
200  */
201 static struct GNUNET_TIME_Absolute start_time;
202
203
204 /**
205  * Show the results of the test (banwidth acheived) and log them to GAUGER
206  */
207 static void
208 show_end_data (void)
209 {
210   static struct GNUNET_TIME_Absolute end_time;
211   static struct GNUNET_TIME_Relative total_time;
212
213   end_time = GNUNET_TIME_absolute_get();
214   total_time = GNUNET_TIME_absolute_get_difference(start_time, end_time);
215   FPRINTF (stderr, "\nResults of test \"%s\"\n", test_name);
216   FPRINTF (stderr, "Test time %llu ms\n",
217             (unsigned long long) total_time.rel_value);
218   FPRINTF (stderr, "Test bandwidth: %f kb/s\n",
219             4 * TOTAL_PACKETS * 1.0 / total_time.rel_value); // 4bytes * ms
220   FPRINTF (stderr, "Test throughput: %f packets/s\n\n",
221             TOTAL_PACKETS * 1000.0 / total_time.rel_value); // packets * ms
222   GAUGER ("MESH", test_name,
223           TOTAL_PACKETS * 1000.0 / total_time.rel_value,
224           "packets/s");
225 }
226
227
228 /**
229  * Shut down peergroup, clean up.
230  * 
231  * @param cls Closure (unused).
232  * @param tc Task Context.
233  */
234 static void
235 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
236 {
237   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n");
238   shutdown_handle = GNUNET_SCHEDULER_NO_TASK;
239 }
240
241
242 /**
243  * Disconnect from mesh services af all peers, call shutdown.
244  * 
245  * @param cls Closure (unused).
246  * @param tc Task Context.
247  */
248 static void
249 disconnect_mesh_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
250 {
251   long line = (long) cls;
252   unsigned int i;
253
254   for (i = 0; i < 3; i++)
255     if (NULL != t_op[i])
256     {
257       GNUNET_TESTBED_operation_done (t_op[i]);
258       t_op[i] = NULL;
259     }
260   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
261               "disconnecting mesh service of peers, called from line %ld\n",
262               line);
263   disconnect_task = GNUNET_SCHEDULER_NO_TASK;
264   if (NULL != t)
265   {
266     GNUNET_MESH_tunnel_destroy (t);
267     t = NULL;
268   }
269   if (NULL != incoming_t)
270   {
271     GNUNET_MESH_tunnel_destroy (incoming_t);
272     incoming_t = NULL;
273   }
274   if (NULL != incoming_t2)
275   {
276     GNUNET_MESH_tunnel_destroy (incoming_t2);
277     incoming_t2 = NULL;
278   }
279   GNUNET_MESH_TEST_cleanup (test_ctx);
280   if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle)
281   {
282     GNUNET_SCHEDULER_cancel (shutdown_handle);
283   }
284   shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
285 }
286
287
288 void
289 abort_test (long line)
290 {
291   if (disconnect_task != GNUNET_SCHEDULER_NO_TASK)
292   {
293     GNUNET_SCHEDULER_cancel (disconnect_task);
294   }
295     disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
296                                                     &disconnect_mesh_peers,
297                                                     (void *) line);
298 }
299
300 /**
301  * Transmit ready callback.
302  * 
303  * @param cls Closure (message type).
304  * @param size Size of the tranmist buffer.
305  * @param buf Pointer to the beginning of the buffer.
306  * 
307  * @return Number of bytes written to buf.
308  */
309 static size_t
310 tmt_rdy (void *cls, size_t size, void *buf);
311
312
313 /**
314  * Task to schedule a new data transmission.
315  * 
316  * @param cls Closure (peer #).
317  * @param tc Task Context.
318  */
319 static void
320 data_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
321 {
322   struct GNUNET_MESH_TransmitHandle *th;
323   struct GNUNET_MESH_Tunnel *tunnel;
324   struct GNUNET_PeerIdentity *destination;
325
326   if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
327     return;
328
329   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data task\n");
330   if (GNUNET_YES == test_backwards)
331   {
332     tunnel = incoming_t;
333     destination = p_id[0];
334   }
335   else
336   {
337     tunnel = t;
338     destination = p_id[2];
339   }
340   th = GNUNET_MESH_notify_transmit_ready (tunnel, GNUNET_NO,
341                                           GNUNET_TIME_UNIT_FOREVER_REL,
342                                           destination,
343                                           size_payload,
344                                           &tmt_rdy, (void *) 1L);
345   if (NULL == th)
346   {
347     unsigned long i = (unsigned long) cls;
348
349     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Retransmission\n");
350     if (0 == i)
351     {
352       GNUNET_log (GNUNET_ERROR_TYPE_INFO, "  in 1 ms\n");
353       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
354                                     &data_task, (void *)1UL);
355     }
356     else
357     {
358       i++;
359       GNUNET_log (GNUNET_ERROR_TYPE_INFO, "in %u ms\n", i);
360       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(
361                                       GNUNET_TIME_UNIT_MILLISECONDS,
362                                       i),
363                                     &data_task, (void *)i);
364     }
365   }
366 }
367
368
369 /**
370  * Transmit ready callback
371  *
372  * @param cls Closure (message type).
373  * @param size Size of the buffer we have.
374  * @param buf Buffer to copy data to.
375  */
376 size_t
377 tmt_rdy (void *cls, size_t size, void *buf)
378 {
379   struct GNUNET_MessageHeader *msg = buf;
380   uint32_t *data;
381
382   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
383               " tmt_rdy called\n");
384   if (size < size_payload || NULL == buf)
385   {
386     GNUNET_break (0);
387     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
388                 "size %u, buf %p, data_sent %u, data_received %u\n",
389                 size,
390                 buf,
391                 data_sent,
392                 data_received);
393     return 0;
394   }
395   msg->size = htons (size);
396   msg->type = htons ((long) cls);
397   data = (uint32_t *) &msg[1];
398   *data = htonl (data_sent);
399   if (SPEED == test && GNUNET_YES == initialized)
400   {
401     data_sent++;
402     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
403               " Sent packet %d\n", data_sent);
404     if (data_sent < TOTAL_PACKETS)
405     {
406       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
407               " Scheduling packet %d\n", data_sent + 1);
408       GNUNET_SCHEDULER_add_now(&data_task, NULL);
409     }
410   }
411   return size_payload;
412 }
413
414
415 /**
416  * Function is called whenever a message is received.
417  *
418  * @param cls closure (set from GNUNET_MESH_connect)
419  * @param tunnel connection to the other end
420  * @param tunnel_ctx place to store local state associated with the tunnel
421  * @param sender who sent the message
422  * @param message the actual message
423  * @param atsi performance data for the connection
424  * @return GNUNET_OK to keep the connection open,
425  *         GNUNET_SYSERR to close it (signal serious error)
426  */
427 int
428 data_callback (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx,
429                const struct GNUNET_PeerIdentity *sender,
430                const struct GNUNET_MessageHeader *message,
431                const struct GNUNET_ATS_Information *atsi)
432 {
433   long client = (long) cls;
434   long expected_target_client;
435   uint32_t *data;
436
437   ok++;
438
439   if ((ok % 20) == 0)
440   {
441     if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
442     {
443       GNUNET_SCHEDULER_cancel (disconnect_task);
444     }
445     disconnect_task =
446               GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers,
447                                             (void *) __LINE__);
448   }
449
450   switch (client)
451   {
452   case 0L:
453     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message!\n");
454     peers_responded++;
455     if (test == MULTICAST && peers_responded < 2)
456       return GNUNET_OK;
457     break;
458   case 3L:
459   case 4L:
460     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
461                 "Leaf client %li got a message.\n",
462                 client);
463     client = 4L;
464     break;
465   default:
466     GNUNET_assert (0);
467     break;
468   }
469   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: (%d/%d)\n", ok, ok_goal);
470   data = (uint32_t *) &message[1];
471   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " payload: (%u)\n", ntohl (*data));
472   if (SPEED == test && GNUNET_YES == test_backwards)
473   {
474     expected_target_client = 0L;
475   }
476   else
477   {
478     expected_target_client = 4L;
479   }
480
481   if (GNUNET_NO == initialized)
482   {
483     initialized = GNUNET_YES;
484     start_time = GNUNET_TIME_absolute_get ();
485     if (SPEED == test)
486     {
487       GNUNET_assert (4L == client);
488       GNUNET_SCHEDULER_add_now (&data_task, NULL);
489       return GNUNET_OK;
490     }
491   }
492
493   if (client == expected_target_client) // Normally 3 or 4
494   {
495     data_received++;
496     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
497                 " received data %u\n", data_received);
498     if (SPEED != test || (ok_goal - 2) == ok)
499     {
500       GNUNET_MESH_notify_transmit_ready (tunnel, GNUNET_NO,
501                                         GNUNET_TIME_UNIT_FOREVER_REL, sender,
502                                                size_payload,
503                                         &tmt_rdy, (void *) 1L);
504       return GNUNET_OK;
505     }
506     else
507     {
508       if (data_received < TOTAL_PACKETS)
509         return GNUNET_OK;
510     }
511   }
512   else // Normally 0
513   {
514     if (test == SPEED_ACK || test == SPEED)
515     {
516       data_ack++;
517       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
518               " received ack %u\n", data_ack);
519       GNUNET_MESH_notify_transmit_ready (tunnel, GNUNET_NO,
520                                         GNUNET_TIME_UNIT_FOREVER_REL, sender,
521                                                size_payload,
522                                         &tmt_rdy, (void *) 1L);
523       if (data_ack < TOTAL_PACKETS && SPEED != test)
524         return GNUNET_OK;
525       if (ok == 2 && SPEED == test)
526         return GNUNET_OK;
527       show_end_data();
528     }
529     if (test == P2P_SIGNAL)
530     {
531       GNUNET_MESH_tunnel_destroy (incoming_t);
532       incoming_t = NULL;
533     }
534     else
535     {
536       GNUNET_MESH_tunnel_destroy (t);
537       t = NULL;
538     }
539   }
540
541   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
542   {
543     GNUNET_SCHEDULER_cancel (disconnect_task);
544   }
545   disconnect_task =
546         GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers,
547                                       (void *) __LINE__);
548
549   return GNUNET_OK;
550 }
551
552
553 /**
554  * Handlers, for diverse services
555  */
556 static struct GNUNET_MESH_MessageHandler handlers[] = {
557   {&data_callback, 1, sizeof (struct GNUNET_MessageHeader)},
558   {NULL, 0, 0}
559 };
560
561
562 /**
563  * Method called whenever another peer has added us to a tunnel
564  * the other peer initiated.
565  *
566  * @param cls closure
567  * @param tunnel new handle to the tunnel
568  * @param initiator peer that started the tunnel
569  * @param atsi performance information for the tunnel
570  * @return initial tunnel context for the tunnel
571  *         (can be NULL -- that's not an error)
572  */
573 static void *
574 incoming_tunnel (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
575                  const struct GNUNET_PeerIdentity *initiator,
576                  const struct GNUNET_ATS_Information *atsi)
577 {
578   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
579               "Incoming tunnel from %s to peer %d\n",
580               GNUNET_i2s (initiator), (long) cls);
581   ok++;
582   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
583   if ((long) cls == 4L)
584     incoming_t = tunnel;
585   else if ((long) cls == 3L)
586     incoming_t2 = tunnel;
587   else
588   {
589     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
590                 "Incoming tunnel for unknown client %lu\n", (long) cls);
591     GNUNET_break(0);
592   }
593   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
594   {
595     GNUNET_SCHEDULER_cancel (disconnect_task);
596   }
597   disconnect_task =
598         GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers,
599                                       (void *) __LINE__);
600
601   return NULL;
602 }
603
604 /**
605  * Function called whenever an inbound tunnel is destroyed.  Should clean up
606  * any associated state.
607  *
608  * @param cls closure (set from GNUNET_MESH_connect)
609  * @param tunnel connection to the other end (henceforth invalid)
610  * @param tunnel_ctx place where local state associated
611  *                   with the tunnel is stored
612  */
613 static void
614 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel,
615                 void *tunnel_ctx)
616 {
617   long i = (long) cls;
618
619   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
620               "Incoming tunnel disconnected at peer %d\n",
621               i);
622   if (4L == i)
623   {
624     ok++;
625     incoming_t = NULL;
626   }
627   else if (3L == i)
628   {
629     ok++;
630     incoming_t2 = NULL;
631   }
632   else
633     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
634                 "Unknown peer! %d\n", i);
635   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
636   peers_in_tunnel--;
637   if (peers_in_tunnel > 0)
638     return;
639
640   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
641   {
642     GNUNET_SCHEDULER_cancel (disconnect_task);
643   }
644   disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_mesh_peers,
645                                               (void *) __LINE__);
646
647   return;
648 }
649
650
651 /**
652  * Method called whenever a tunnel falls apart.
653  *
654  * @param cls closure
655  * @param peer peer identity the tunnel stopped working with
656  */
657 static void
658 dh (void *cls, const struct GNUNET_PeerIdentity *peer)
659 {
660   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
661               "peer %s disconnected\n",
662               GNUNET_i2s (peer));
663   return;
664 }
665
666
667 /**
668  * Method called whenever a peer connects to a tunnel.
669  *
670  * @param cls closure
671  * @param peer peer identity the tunnel was created to, NULL on timeout
672  * @param atsi performance data for the connection
673  */
674 static void
675 ch (void *cls, const struct GNUNET_PeerIdentity *peer,
676     const struct GNUNET_ATS_Information *atsi)
677 {
678   long i = (long) cls;
679
680   struct GNUNET_PeerIdentity *dest;
681
682   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
683               "%ld peer %s connected\n", i, GNUNET_i2s (peer));
684
685   if (0 == memcmp (p_id[2], peer, sizeof (struct GNUNET_PeerIdentity)) &&
686       i == 0L)
687   {
688     ok++;
689   }
690   if (test == MULTICAST &&
691       0 == memcmp (p_id[1], peer, sizeof (struct GNUNET_PeerIdentity)) &&
692       i == 0L)
693   {
694     ok++;
695   }
696   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
697   switch (test)
698   {
699     case UNICAST:
700     case P2P_SIGNAL:
701     case SPEED:
702     case SPEED_ACK:
703       // incoming_t is NULL unless we send a relevant data packet
704       dest = p_id[2];
705       break;
706     case MULTICAST:
707       peers_in_tunnel++;
708       if (peers_in_tunnel < 2)
709         return;
710       dest = NULL;
711       break;
712     default:
713       GNUNET_assert (0);
714       return;
715   }
716   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
717   {
718     GNUNET_SCHEDULER_cancel (disconnect_task);
719     disconnect_task =
720         GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers,
721                                       (void *) __LINE__);
722     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
723                 "Sending data initializer...\n");
724     peers_responded = 0;
725     data_ack = 0;
726     data_received = 0;
727     data_sent = 0;
728     GNUNET_MESH_notify_transmit_ready (t, GNUNET_NO,
729                                        GNUNET_TIME_UNIT_FOREVER_REL, dest,
730                                            size_payload,
731                                        &tmt_rdy, (void *) 1L);
732   }
733   else
734   {
735     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
736                 "Disconnect already run?\n");
737     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
738                 "Aborting...\n");
739   }
740   return;
741 }
742
743
744 /**
745  * START THE TESTCASE ITSELF, AS WE ARE CONNECTED TO THE MESH SERVICES.
746  * 
747  * Testcase continues when the root receives confirmation of connected peers,
748  * on callback funtion ch.
749  * 
750  * @param cls Closure (unsued).
751  * @param tc Task Context.
752  */
753 static void
754 do_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
755 {
756   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test_task\n");
757   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "add peer 2\n");
758   GNUNET_MESH_peer_request_connect_add (t, p_id[2]);
759
760   if (test == MULTICAST)
761   {
762     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
763                 "add peer 3\n");
764     GNUNET_MESH_peer_request_connect_add (t, p_id[1]);
765   }
766
767   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
768               "schedule timeout in TIMEOUT\n");
769   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
770   {
771     GNUNET_SCHEDULER_cancel (disconnect_task);
772   }
773   disconnect_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
774                                                   &disconnect_mesh_peers,
775                                                   (void *) __LINE__);
776 }
777
778 /**
779  * Callback to be called when the requested peer information is available
780  *
781  * @param cls the closure from GNUNET_TETSBED_peer_get_information()
782  * @param op the operation this callback corresponds to
783  * @param pinfo the result; will be NULL if the operation has failed
784  * @param emsg error message if the operation has failed;
785  *             NULL if the operation is successfull
786  */
787 void
788 pi_cb (void *cls,
789        struct GNUNET_TESTBED_Operation *op,
790        const struct GNUNET_TESTBED_PeerInformation *pinfo,
791        const char *emsg)
792 {
793   long i = (long) cls;
794
795   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "id callback for %ld\n", i);
796   if (NULL == pinfo || NULL != emsg)
797   {
798     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg);
799     abort_test (__LINE__);
800     return;
801   }
802   p_id[i] = pinfo->result.id;
803   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  id: %s\n", GNUNET_i2s (p_id[i]));
804   p_ids++;
805   if ((MULTICAST == test && p_ids < 3) || p_ids < 2)
806     return;
807   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got all IDs, starting test\n");
808   test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
809                                             &do_test, NULL);
810 }
811
812 /**
813  * test main: start test when all peers are connected
814  *
815  * @param cls Closure.
816  * @param ctx Argument to give to GNUNET_MESH_TEST_cleanup on test end.
817  * @param num_peers Number of peers that are running.
818  * @param peers Array of peers.
819  * @param meshes Handle to each of the MESHs of the peers.
820  */
821 static void
822 tmain (void *cls,
823        struct GNUNET_MESH_TEST_Context *ctx,
824        unsigned int num_peers,
825        struct GNUNET_TESTBED_Peer **peers,
826        struct GNUNET_MESH_Handle **meshes)
827 {
828   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test main\n");
829   ok = 0;
830   test_ctx = ctx;
831   peers_running = num_peers;
832   h1 = meshes[0];
833   h2 = meshes[num_peers - 1];
834   t = GNUNET_MESH_tunnel_create (h1, NULL, &ch, &dh, (void *) 0L);
835   if (SPEED_MIN == test)
836   {
837     GNUNET_MESH_tunnel_speed_min(t);
838     test = SPEED;
839   }
840   if (SPEED_NOBUF == test)
841   {
842     GNUNET_MESH_tunnel_buffer(t, GNUNET_NO);
843     test = SPEED;
844   }
845   peers_in_tunnel = 0;
846   disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
847                                                   &disconnect_mesh_peers,
848                                                   (void *) __LINE__);
849   shutdown_handle = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
850                                                   &shutdown_task, NULL);
851   t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0],
852                                                  GNUNET_TESTBED_PIT_IDENTITY,
853                                                  &pi_cb, (void *) 0L);
854   t_op[2] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 1],
855                                                  GNUNET_TESTBED_PIT_IDENTITY,
856                                                  &pi_cb, (void *) 2L);
857   if (MULTICAST == test)
858   {
859     h3 = meshes[num_peers - 2];
860     t_op[1] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 2],
861                                                    GNUNET_TESTBED_PIT_IDENTITY,
862                                                    &pi_cb, (void *) 1L);
863   }
864   else
865   {
866     t_op[1] = NULL;
867   }
868   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n");
869 }
870
871
872 /**
873  * Main: start test
874  */
875 int
876 main (int argc, char *argv[])
877 {
878   initialized = GNUNET_NO;
879
880   GNUNET_log_setup ("test", "DEBUG", NULL);
881   
882   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start\n");
883   if (strstr (argv[0], "test_mesh_small_unicast") != NULL)
884   {
885     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNICAST\n");
886     test = UNICAST;
887     test_name = "unicast";
888     ok_goal = 5;
889   }
890   else if (strstr (argv[0], "test_mesh_small_multicast") != NULL)
891   {
892     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MULTICAST\n");
893     test = MULTICAST;
894     test_name = "multicast";
895     ok_goal = 10;
896   }
897   else if (strstr (argv[0], "test_mesh_small_signal") != NULL)
898   {
899     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SIGNAL\n");
900     test = P2P_SIGNAL;
901     test_name = "signal";
902     ok_goal = 5;
903   }
904   else if (strstr (argv[0], "test_mesh_small_speed_ack") != NULL)
905   {
906    /* Each peer is supposed to generate the following callbacks:
907     * 1 incoming tunnel (@dest)
908     * 1 connected peer (@orig)
909     * TOTAL_PACKETS received data packet (@dest)
910     * TOTAL_PACKETS received data packet (@orig)
911     * 1 received tunnel destroy (@dest)
912     * _________________________________
913     * 5 x ok expected per peer
914     */
915     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n");
916     test = SPEED_ACK;
917     test_name = "speed ack";
918     ok_goal = TOTAL_PACKETS * 2 + 3;
919   }
920   else if (strstr (argv[0], "test_mesh_small_speed") != NULL)
921   {
922    /* Each peer is supposed to generate the following callbacks:
923     * 1 incoming tunnel (@dest)
924     * 1 connected peer (@orig)
925     * 1 initial packet (@dest)
926     * TOTAL_PACKETS received data packet (@dest)
927     * 1 received data packet (@orig)
928     * 1 received tunnel destroy (@dest)
929     * _________________________________
930     */
931     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n");
932     ok_goal = TOTAL_PACKETS + 5;
933     if (strstr (argv[0], "_min") != NULL)
934     {
935       test = SPEED_MIN;
936       test_name = "speed min";
937     }
938     else if (strstr (argv[0], "_nobuf") != NULL)
939     {
940       test = SPEED_NOBUF;
941       test_name = "speed nobuf";
942     }
943     else
944     {
945       test = SPEED;
946       test_name = "speed";
947     }
948   }
949   else
950   {
951     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNKNOWN\n");
952     test = SETUP;
953     ok_goal = 0;
954   }
955
956   if (strstr (argv[0], "backwards") != NULL)
957   {
958     char *aux;
959
960     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "BACKWARDS (LEAF TO ROOT)\n");
961     test_backwards = GNUNET_YES;
962     aux = GNUNET_malloc (32);
963     sprintf (aux, "backwards %s", test_name);
964     test_name = aux;
965   }
966
967   p_ids = 0;
968   GNUNET_MESH_TEST_run ("test_mesh_small",
969                         "test_mesh_small.conf",
970                         5,
971                         &tmain,
972                         NULL,
973                         &incoming_tunnel,
974                         &tunnel_cleaner,
975                         handlers,
976                         NULL);
977
978   if (ok_goal > ok)
979   {
980     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
981                 "FAILED! (%d/%d)\n", ok, ok_goal);
982     return 1;
983   }
984   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n");
985   return 0;
986 }
987
988 /* end of test_mesh_small.c */