- refactor makefile
[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       GNUNET_MESH_tunnel_destroy (incoming_t);
531     else
532       GNUNET_MESH_tunnel_destroy (t);
533     t = NULL;
534   }
535
536   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
537   {
538     GNUNET_SCHEDULER_cancel (disconnect_task);
539   }
540   disconnect_task =
541         GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers,
542                                       (void *) __LINE__);
543
544   return GNUNET_OK;
545 }
546
547
548 /**
549  * Handlers, for diverse services
550  */
551 static struct GNUNET_MESH_MessageHandler handlers[] = {
552   {&data_callback, 1, sizeof (struct GNUNET_MessageHeader)},
553   {NULL, 0, 0}
554 };
555
556
557 /**
558  * Method called whenever another peer has added us to a tunnel
559  * the other peer initiated.
560  *
561  * @param cls closure
562  * @param tunnel new handle to the tunnel
563  * @param initiator peer that started the tunnel
564  * @param atsi performance information for the tunnel
565  * @return initial tunnel context for the tunnel
566  *         (can be NULL -- that's not an error)
567  */
568 static void *
569 incoming_tunnel (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
570                  const struct GNUNET_PeerIdentity *initiator,
571                  const struct GNUNET_ATS_Information *atsi)
572 {
573   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
574               "Incoming tunnel from %s to peer %d\n",
575               GNUNET_i2s (initiator), (long) cls);
576   ok++;
577   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
578   if ((long) cls == 4L)
579     incoming_t = tunnel;
580   else if ((long) cls == 3L)
581     incoming_t2 = tunnel;
582   else
583   {
584     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
585                 "Incoming tunnel for unknown client %lu\n", (long) cls);
586     GNUNET_break(0);
587   }
588   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
589   {
590     GNUNET_SCHEDULER_cancel (disconnect_task);
591   }
592   disconnect_task =
593         GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers,
594                                       (void *) __LINE__);
595
596   return NULL;
597 }
598
599 /**
600  * Function called whenever an inbound tunnel is destroyed.  Should clean up
601  * any associated state.
602  *
603  * @param cls closure (set from GNUNET_MESH_connect)
604  * @param tunnel connection to the other end (henceforth invalid)
605  * @param tunnel_ctx place where local state associated
606  *                   with the tunnel is stored
607  */
608 static void
609 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel,
610                 void *tunnel_ctx)
611 {
612   long i = (long) cls;
613
614   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
615               "Incoming tunnel disconnected at peer %d\n",
616               i);
617   if (4L == i)
618   {
619     ok++;
620     incoming_t = NULL;
621   }
622   else if (3L == i)
623   {
624     ok++;
625     incoming_t2 = NULL;
626   }
627   else
628     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
629                 "Unknown peer! %d\n", i);
630   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
631   peers_in_tunnel--;
632   if (peers_in_tunnel > 0)
633     return;
634
635   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
636   {
637     GNUNET_SCHEDULER_cancel (disconnect_task);
638   }
639   disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_mesh_peers,
640                                               (void *) __LINE__);
641
642   return;
643 }
644
645
646 /**
647  * Method called whenever a tunnel falls apart.
648  *
649  * @param cls closure
650  * @param peer peer identity the tunnel stopped working with
651  */
652 static void
653 dh (void *cls, const struct GNUNET_PeerIdentity *peer)
654 {
655   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
656               "peer %s disconnected\n",
657               GNUNET_i2s (peer));
658   return;
659 }
660
661
662 /**
663  * Method called whenever a peer connects to a tunnel.
664  *
665  * @param cls closure
666  * @param peer peer identity the tunnel was created to, NULL on timeout
667  * @param atsi performance data for the connection
668  */
669 static void
670 ch (void *cls, const struct GNUNET_PeerIdentity *peer,
671     const struct GNUNET_ATS_Information *atsi)
672 {
673   long i = (long) cls;
674
675   struct GNUNET_PeerIdentity *dest;
676
677   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
678               "%ld peer %s connected\n", i, GNUNET_i2s (peer));
679
680   if (0 == memcmp (p_id[2], peer, sizeof (struct GNUNET_PeerIdentity)) &&
681       i == 0L)
682   {
683     ok++;
684   }
685   if (test == MULTICAST &&
686       0 == memcmp (p_id[1], peer, sizeof (struct GNUNET_PeerIdentity)) &&
687       i == 0L)
688   {
689     ok++;
690   }
691   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
692   switch (test)
693   {
694     case UNICAST:
695     case SPEED:
696     case SPEED_ACK:
697       // incoming_t is NULL unless we send a relevant data packet
698       dest = p_id[2];
699       break;
700     case MULTICAST:
701       peers_in_tunnel++;
702       if (peers_in_tunnel < 2)
703         return;
704       dest = NULL;
705       break;
706     default:
707       GNUNET_assert (0);
708       return;
709   }
710   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
711   {
712     GNUNET_SCHEDULER_cancel (disconnect_task);
713     disconnect_task =
714         GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers,
715                                       (void *) __LINE__);
716     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
717                 "Sending data initializer...\n");
718     peers_responded = 0;
719     data_ack = 0;
720     data_received = 0;
721     data_sent = 0;
722     GNUNET_MESH_notify_transmit_ready (t, GNUNET_NO,
723                                        GNUNET_TIME_UNIT_FOREVER_REL, dest,
724                                            size_payload,
725                                        &tmt_rdy, (void *) 1L);
726   }
727   else
728   {
729     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
730                 "Disconnect already run?\n");
731     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
732                 "Aborting...\n");
733   }
734   return;
735 }
736
737
738 /**
739  * START THE TESTCASE ITSELF, AS WE ARE CONNECTED TO THE MESH SERVICES.
740  * 
741  * Testcase continues when the root receives confirmation of connected peers,
742  * on callback funtion ch.
743  * 
744  * @param cls Closure (unsued).
745  * @param tc Task Context.
746  */
747 static void
748 do_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
749 {
750   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test_task\n");
751   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "add peer 2\n");
752   GNUNET_MESH_peer_request_connect_add (t, p_id[2]);
753
754   if (test == MULTICAST)
755   {
756     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
757                 "add peer 3\n");
758     GNUNET_MESH_peer_request_connect_add (t, p_id[1]);
759   }
760
761   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
762               "schedule timeout in TIMEOUT\n");
763   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
764   {
765     GNUNET_SCHEDULER_cancel (disconnect_task);
766   }
767   disconnect_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
768                                                   &disconnect_mesh_peers,
769                                                   (void *) __LINE__);
770 }
771
772 /**
773  * Callback to be called when the requested peer information is available
774  *
775  * @param cls the closure from GNUNET_TETSBED_peer_get_information()
776  * @param op the operation this callback corresponds to
777  * @param pinfo the result; will be NULL if the operation has failed
778  * @param emsg error message if the operation has failed;
779  *             NULL if the operation is successfull
780  */
781 void
782 pi_cb (void *cls,
783        struct GNUNET_TESTBED_Operation *op,
784        const struct GNUNET_TESTBED_PeerInformation *pinfo,
785        const char *emsg)
786 {
787   long i = (long) cls;
788
789   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "id callback for %ld\n", i);
790   if (NULL == pinfo || NULL != emsg)
791   {
792     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg);
793     abort_test (__LINE__);
794     return;
795   }
796   p_id[i] = pinfo->result.id;
797   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  id: %s\n", GNUNET_i2s (p_id[i]));
798   p_ids++;
799   if ((MULTICAST == test && p_ids < 3) || p_ids < 2)
800     return;
801   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got all IDs, starting test\n");
802   test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
803                                             &do_test, NULL);
804 }
805
806 /**
807  * test main: start test when all peers are connected
808  *
809  * @param cls Closure.
810  * @param ctx Argument to give to GNUNET_MESH_TEST_cleanup on test end.
811  * @param num_peers Number of peers that are running.
812  * @param peers Array of peers.
813  * @param meshes Handle to each of the MESHs of the peers.
814  */
815 static void
816 tmain (void *cls,
817        struct GNUNET_MESH_TEST_Context *ctx,
818        unsigned int num_peers,
819        struct GNUNET_TESTBED_Peer **peers,
820        struct GNUNET_MESH_Handle **meshes)
821 {
822   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test main\n");
823   ok = 0;
824   test_ctx = ctx;
825   peers_running = num_peers;
826   h1 = meshes[0];
827   h2 = meshes[num_peers - 1];
828   t = GNUNET_MESH_tunnel_create (h1, NULL, &ch, &dh, (void *) 0L);
829   if (SPEED_MIN == test)
830   {
831     GNUNET_MESH_tunnel_speed_min(t);
832     test = SPEED;
833   }
834   if (SPEED_NOBUF == test)
835   {
836     GNUNET_MESH_tunnel_buffer(t, GNUNET_NO);
837     test = SPEED;
838   }
839   peers_in_tunnel = 0;
840   disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
841                                                   &disconnect_mesh_peers,
842                                                   (void *) __LINE__);
843   shutdown_handle = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
844                                                   &shutdown_task, NULL);
845   t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0],
846                                                  GNUNET_TESTBED_PIT_IDENTITY,
847                                                  &pi_cb, (void *) 0L);
848   t_op[2] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 1],
849                                                  GNUNET_TESTBED_PIT_IDENTITY,
850                                                  &pi_cb, (void *) 2L);
851   if (MULTICAST == test)
852   {
853     h3 = meshes[num_peers - 2];
854     t_op[1] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 2],
855                                                    GNUNET_TESTBED_PIT_IDENTITY,
856                                                    &pi_cb, (void *) 1L);
857   }
858   else
859   {
860     t_op[1] = NULL;
861   }
862   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n");
863 }
864
865
866 /**
867  * Main: start test
868  */
869 int
870 main (int argc, char *argv[])
871 {
872   initialized = GNUNET_NO;
873
874   GNUNET_log_setup ("test", "DEBUG", NULL);
875   
876   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start\n");
877   if (strstr (argv[0], "test_mesh_small_unicast") != NULL)
878   {
879     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNICAST\n");
880     test = UNICAST;
881     test_name = "unicast";
882     ok_goal = 5;
883   }
884   else if (strstr (argv[0], "test_mesh_small_multicast") != NULL)
885   {
886     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MULTICAST\n");
887     test = MULTICAST;
888     test_name = "multicast";
889     ok_goal = 10;
890   }
891   else if (strstr (argv[0], "test_mesh_small_signal") != NULL)
892   {
893     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SIGNAL\n");
894     test = P2P_SIGNAL;
895     test_name = "signal";
896     ok_goal = 5;
897   }
898   else if (strstr (argv[0], "test_mesh_small_speed_ack") != NULL)
899   {
900    /* Each peer is supposed to generate the following callbacks:
901     * 1 incoming tunnel (@dest)
902     * 1 connected peer (@orig)
903     * TOTAL_PACKETS received data packet (@dest)
904     * TOTAL_PACKETS received data packet (@orig)
905     * 1 received tunnel destroy (@dest)
906     * _________________________________
907     * 5 x ok expected per peer
908     */
909     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n");
910     test = SPEED_ACK;
911     test_name = "speed ack";
912     ok_goal = TOTAL_PACKETS * 2 + 3;
913   }
914   else if (strstr (argv[0], "test_mesh_small_speed") != NULL)
915   {
916    /* Each peer is supposed to generate the following callbacks:
917     * 1 incoming tunnel (@dest)
918     * 1 connected peer (@orig)
919     * 1 initial packet (@dest)
920     * TOTAL_PACKETS received data packet (@dest)
921     * 1 received data packet (@orig)
922     * 1 received tunnel destroy (@dest)
923     * _________________________________
924     */
925     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n");
926     ok_goal = TOTAL_PACKETS + 5;
927     if (strstr (argv[0], "_min") != NULL)
928     {
929       test = SPEED_MIN;
930       test_name = "speed min";
931     }
932     else if (strstr (argv[0], "_nobuf") != NULL)
933     {
934       test = SPEED_NOBUF;
935       test_name = "speed nobuf";
936     }
937     else
938     {
939       test = SPEED;
940       test_name = "speed";
941     }
942   }
943   else
944   {
945     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNKNOWN\n");
946     test = SETUP;
947     ok_goal = 0;
948   }
949
950   if (strstr (argv[0], "backwards") != NULL)
951   {
952     char *aux;
953
954     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "BACKWARDS (LEAF TO ROOT)\n");
955     test_backwards = GNUNET_YES;
956     aux = GNUNET_malloc (32);
957     sprintf (aux, "backwards %s", test_name);
958     test_name = aux;
959   }
960
961   p_ids = 0;
962   GNUNET_MESH_TEST_run ("test_mesh_small",
963                         "test_mesh_small.conf",
964                         5,
965                         &tmain,
966                         NULL,
967                         &incoming_tunnel,
968                         &tunnel_cleaner,
969                         handlers,
970                         NULL);
971
972   if (ok_goal > ok)
973   {
974     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
975                 "FAILED! (%d/%d)\n", ok, ok_goal);
976     return 1;
977   }
978   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n");
979   return 0;
980 }
981
982 /* end of test_mesh_small.c */