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