- distribute peers equally among island nodes on SuperMUC
[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 /**
289  * Abort test: schedule disconnect and shutdown immediately
290  * 
291  * @param line Line in the code the abort is requested from (__LINE__).
292  */
293 void
294 abort_test (long line)
295 {
296   if (disconnect_task != GNUNET_SCHEDULER_NO_TASK)
297   {
298     GNUNET_SCHEDULER_cancel (disconnect_task);
299   }
300   disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
301                                                   &disconnect_mesh_peers,
302                                                   (void *) line);
303 }
304
305 /**
306  * Transmit ready callback.
307  * 
308  * @param cls Closure (message type).
309  * @param size Size of the tranmist buffer.
310  * @param buf Pointer to the beginning of the buffer.
311  * 
312  * @return Number of bytes written to buf.
313  */
314 static size_t
315 tmt_rdy (void *cls, size_t size, void *buf);
316
317
318 /**
319  * Task to schedule a new data transmission.
320  * 
321  * @param cls Closure (peer #).
322  * @param tc Task Context.
323  */
324 static void
325 data_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
326 {
327   struct GNUNET_MESH_TransmitHandle *th;
328   struct GNUNET_MESH_Tunnel *tunnel;
329   struct GNUNET_PeerIdentity *destination;
330
331   if ((GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason) != 0)
332     return;
333
334   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data task\n");
335   if (GNUNET_YES == test_backwards)
336   {
337     tunnel = incoming_t;
338     destination = p_id[0];
339   }
340   else
341   {
342     tunnel = t;
343     destination = p_id[2];
344   }
345   th = GNUNET_MESH_notify_transmit_ready (tunnel, GNUNET_NO,
346                                           GNUNET_TIME_UNIT_FOREVER_REL,
347                                           destination,
348                                           size_payload,
349                                           &tmt_rdy, (void *) 1L);
350   if (NULL == th)
351   {
352     unsigned long i = (unsigned long) cls;
353
354     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Retransmission\n");
355     if (0 == i)
356     {
357       GNUNET_log (GNUNET_ERROR_TYPE_INFO, "  in 1 ms\n");
358       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
359                                     &data_task, (void *)1UL);
360     }
361     else
362     {
363       i++;
364       GNUNET_log (GNUNET_ERROR_TYPE_INFO, "in %u ms\n", i);
365       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(
366                                       GNUNET_TIME_UNIT_MILLISECONDS,
367                                       i),
368                                     &data_task, (void *)i);
369     }
370   }
371 }
372
373
374 /**
375  * Transmit ready callback
376  *
377  * @param cls Closure (message type).
378  * @param size Size of the buffer we have.
379  * @param buf Buffer to copy data to.
380  */
381 size_t
382 tmt_rdy (void *cls, size_t size, void *buf)
383 {
384   struct GNUNET_MessageHeader *msg = buf;
385   uint32_t *data;
386
387   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
388               " tmt_rdy called\n");
389   if (size < size_payload || NULL == buf)
390   {
391     GNUNET_break (0);
392     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
393                 "size %u, buf %p, data_sent %u, data_received %u\n",
394                 size,
395                 buf,
396                 data_sent,
397                 data_received);
398     return 0;
399   }
400   msg->size = htons (size);
401   msg->type = htons ((long) cls);
402   data = (uint32_t *) &msg[1];
403   *data = htonl (data_sent);
404   if (SPEED == test && GNUNET_YES == initialized)
405   {
406     data_sent++;
407     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
408               " Sent packet %d\n", data_sent);
409     if (data_sent < TOTAL_PACKETS)
410     {
411       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
412               " Scheduling packet %d\n", data_sent + 1);
413       GNUNET_SCHEDULER_add_now(&data_task, NULL);
414     }
415   }
416   return size_payload;
417 }
418
419
420 /**
421  * Function is called whenever a message is received.
422  *
423  * @param cls closure (set from GNUNET_MESH_connect)
424  * @param tunnel connection to the other end
425  * @param tunnel_ctx place to store local state associated with the tunnel
426  * @param sender who sent the message
427  * @param message the actual message
428  * @param atsi performance data for the connection
429  * @return GNUNET_OK to keep the connection open,
430  *         GNUNET_SYSERR to close it (signal serious error)
431  */
432 int
433 data_callback (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx,
434                const struct GNUNET_PeerIdentity *sender,
435                const struct GNUNET_MessageHeader *message,
436                const struct GNUNET_ATS_Information *atsi)
437 {
438   long client = (long) cls;
439   long expected_target_client;
440   uint32_t *data;
441
442   ok++;
443
444   if ((ok % 20) == 0)
445   {
446     if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
447     {
448       GNUNET_SCHEDULER_cancel (disconnect_task);
449     }
450     disconnect_task =
451               GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers,
452                                             (void *) __LINE__);
453   }
454
455   switch (client)
456   {
457   case 0L:
458     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message!\n");
459     peers_responded++;
460     if (test == MULTICAST && peers_responded < 2)
461       return GNUNET_OK;
462     break;
463   case 3L:
464   case 4L:
465     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
466                 "Leaf client %li got a message.\n",
467                 client);
468     client = 4L;
469     break;
470   default:
471     GNUNET_assert (0);
472     break;
473   }
474   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: (%d/%d)\n", ok, ok_goal);
475   data = (uint32_t *) &message[1];
476   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " payload: (%u)\n", ntohl (*data));
477   if (SPEED == test && GNUNET_YES == test_backwards)
478   {
479     expected_target_client = 0L;
480   }
481   else
482   {
483     expected_target_client = 4L;
484   }
485
486   if (GNUNET_NO == initialized)
487   {
488     initialized = GNUNET_YES;
489     start_time = GNUNET_TIME_absolute_get ();
490     if (SPEED == test)
491     {
492       GNUNET_assert (4L == client);
493       GNUNET_SCHEDULER_add_now (&data_task, NULL);
494       return GNUNET_OK;
495     }
496   }
497
498   if (client == expected_target_client) // Normally 3 or 4
499   {
500     data_received++;
501     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
502                 " received data %u\n", data_received);
503     if (SPEED != test || (ok_goal - 2) == ok)
504     {
505       GNUNET_MESH_notify_transmit_ready (tunnel, GNUNET_NO,
506                                         GNUNET_TIME_UNIT_FOREVER_REL, sender,
507                                                size_payload,
508                                         &tmt_rdy, (void *) 1L);
509       return GNUNET_OK;
510     }
511     else
512     {
513       if (data_received < TOTAL_PACKETS)
514         return GNUNET_OK;
515     }
516   }
517   else // Normally 0
518   {
519     if (test == SPEED_ACK || test == SPEED)
520     {
521       data_ack++;
522       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
523               " received ack %u\n", data_ack);
524       GNUNET_MESH_notify_transmit_ready (tunnel, GNUNET_NO,
525                                         GNUNET_TIME_UNIT_FOREVER_REL, sender,
526                                                size_payload,
527                                         &tmt_rdy, (void *) 1L);
528       if (data_ack < TOTAL_PACKETS && SPEED != test)
529         return GNUNET_OK;
530       if (ok == 2 && SPEED == test)
531         return GNUNET_OK;
532       show_end_data();
533     }
534     if (test == P2P_SIGNAL)
535     {
536       GNUNET_MESH_tunnel_destroy (incoming_t);
537       incoming_t = NULL;
538     }
539     else
540     {
541       GNUNET_MESH_tunnel_destroy (t);
542       t = NULL;
543     }
544   }
545
546   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
547   {
548     GNUNET_SCHEDULER_cancel (disconnect_task);
549   }
550   disconnect_task =
551         GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers,
552                                       (void *) __LINE__);
553
554   return GNUNET_OK;
555 }
556
557
558 /**
559  * Handlers, for diverse services
560  */
561 static struct GNUNET_MESH_MessageHandler handlers[] = {
562   {&data_callback, 1, sizeof (struct GNUNET_MessageHeader)},
563   {NULL, 0, 0}
564 };
565
566
567 /**
568  * Method called whenever another peer has added us to a tunnel
569  * the other peer initiated.
570  *
571  * @param cls closure
572  * @param tunnel new handle to the tunnel
573  * @param initiator peer that started the tunnel
574  * @param atsi performance information for the tunnel
575  * @return initial tunnel context for the tunnel
576  *         (can be NULL -- that's not an error)
577  */
578 static void *
579 incoming_tunnel (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
580                  const struct GNUNET_PeerIdentity *initiator,
581                  const struct GNUNET_ATS_Information *atsi)
582 {
583   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
584               "Incoming tunnel from %s to peer %d\n",
585               GNUNET_i2s (initiator), (long) cls);
586   ok++;
587   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
588   if ((long) cls == 4L)
589     incoming_t = tunnel;
590   else if ((long) cls == 3L)
591     incoming_t2 = tunnel;
592   else
593   {
594     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
595                 "Incoming tunnel for unknown client %lu\n", (long) cls);
596     GNUNET_break(0);
597   }
598   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
599   {
600     GNUNET_SCHEDULER_cancel (disconnect_task);
601   }
602   disconnect_task =
603         GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers,
604                                       (void *) __LINE__);
605
606   return NULL;
607 }
608
609 /**
610  * Function called whenever an inbound tunnel is destroyed.  Should clean up
611  * any associated state.
612  *
613  * @param cls closure (set from GNUNET_MESH_connect)
614  * @param tunnel connection to the other end (henceforth invalid)
615  * @param tunnel_ctx place where local state associated
616  *                   with the tunnel is stored
617  */
618 static void
619 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel,
620                 void *tunnel_ctx)
621 {
622   long i = (long) cls;
623
624   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
625               "Incoming tunnel disconnected at peer %d\n",
626               i);
627   if (4L == i)
628   {
629     ok++;
630     incoming_t = NULL;
631   }
632   else if (3L == i)
633   {
634     ok++;
635     incoming_t2 = NULL;
636   }
637   else
638     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
639                 "Unknown peer! %d\n", i);
640   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
641   peers_in_tunnel--;
642   if (peers_in_tunnel > 0)
643     return;
644
645   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
646   {
647     GNUNET_SCHEDULER_cancel (disconnect_task);
648   }
649   disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_mesh_peers,
650                                               (void *) __LINE__);
651
652   return;
653 }
654
655
656 /**
657  * Method called whenever a tunnel falls apart.
658  *
659  * @param cls closure
660  * @param peer peer identity the tunnel stopped working with
661  */
662 static void
663 dh (void *cls, const struct GNUNET_PeerIdentity *peer)
664 {
665   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
666               "peer %s disconnected\n",
667               GNUNET_i2s (peer));
668   if (P2P_SIGNAL == test)
669   {
670     ok ++;
671     if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
672     {
673       GNUNET_SCHEDULER_cancel (disconnect_task);
674     }
675     disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_mesh_peers,
676                                                 (void *) __LINE__);
677   }
678   return;
679 }
680
681
682 /**
683  * Method called whenever a peer connects to a tunnel.
684  *
685  * @param cls closure
686  * @param peer peer identity the tunnel was created to, NULL on timeout
687  * @param atsi performance data for the connection
688  */
689 static void
690 ch (void *cls, const struct GNUNET_PeerIdentity *peer,
691     const struct GNUNET_ATS_Information *atsi)
692 {
693   long i = (long) cls;
694
695   struct GNUNET_PeerIdentity *dest;
696
697   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
698               "%ld peer %s connected\n", i, GNUNET_i2s (peer));
699
700   if (0 == memcmp (p_id[2], peer, sizeof (struct GNUNET_PeerIdentity)) &&
701       i == 0L)
702   {
703     ok++;
704   }
705   if (test == MULTICAST &&
706       0 == memcmp (p_id[1], peer, sizeof (struct GNUNET_PeerIdentity)) &&
707       i == 0L)
708   {
709     ok++;
710   }
711   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
712   switch (test)
713   {
714     case UNICAST:
715     case P2P_SIGNAL:
716     case SPEED:
717     case SPEED_ACK:
718       // incoming_t is NULL unless we send a relevant data packet
719       dest = p_id[2];
720       break;
721     case MULTICAST:
722       peers_in_tunnel++;
723       if (peers_in_tunnel < 2)
724         return;
725       dest = NULL;
726       break;
727     default:
728       GNUNET_assert (0);
729       return;
730   }
731   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
732   {
733     GNUNET_SCHEDULER_cancel (disconnect_task);
734     disconnect_task =
735         GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_mesh_peers,
736                                       (void *) __LINE__);
737     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
738                 "Sending data initializer...\n");
739     peers_responded = 0;
740     data_ack = 0;
741     data_received = 0;
742     data_sent = 0;
743     GNUNET_MESH_notify_transmit_ready (t, GNUNET_NO,
744                                        GNUNET_TIME_UNIT_FOREVER_REL, dest,
745                                            size_payload,
746                                        &tmt_rdy, (void *) 1L);
747   }
748   else
749   {
750     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
751                 "Disconnect already run?\n");
752     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
753                 "Aborting...\n");
754   }
755   return;
756 }
757
758
759 /**
760  * START THE TESTCASE ITSELF, AS WE ARE CONNECTED TO THE MESH SERVICES.
761  * 
762  * Testcase continues when the root receives confirmation of connected peers,
763  * on callback funtion ch.
764  * 
765  * @param cls Closure (unsued).
766  * @param tc Task Context.
767  */
768 static void
769 do_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
770 {
771   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test_task\n");
772   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "add peer 2\n");
773   GNUNET_MESH_peer_request_connect_add (t, p_id[2]);
774
775   if (test == MULTICAST)
776   {
777     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
778                 "add peer 3\n");
779     GNUNET_MESH_peer_request_connect_add (t, p_id[1]);
780   }
781
782   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
783               "schedule timeout in TIMEOUT\n");
784   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
785   {
786     GNUNET_SCHEDULER_cancel (disconnect_task);
787   }
788   disconnect_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
789                                                   &disconnect_mesh_peers,
790                                                   (void *) __LINE__);
791 }
792
793 /**
794  * Callback to be called when the requested peer information is available
795  *
796  * @param cls the closure from GNUNET_TETSBED_peer_get_information()
797  * @param op the operation this callback corresponds to
798  * @param pinfo the result; will be NULL if the operation has failed
799  * @param emsg error message if the operation has failed;
800  *             NULL if the operation is successfull
801  */
802 void
803 pi_cb (void *cls,
804        struct GNUNET_TESTBED_Operation *op,
805        const struct GNUNET_TESTBED_PeerInformation *pinfo,
806        const char *emsg)
807 {
808   long i = (long) cls;
809
810   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "id callback for %ld\n", i);
811   if (NULL == pinfo || NULL != emsg)
812   {
813     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg);
814     abort_test (__LINE__);
815     return;
816   }
817   p_id[i] = pinfo->result.id;
818   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  id: %s\n", GNUNET_i2s (p_id[i]));
819   p_ids++;
820   if ((MULTICAST == test && p_ids < 3) || p_ids < 2)
821     return;
822   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got all IDs, starting test\n");
823   test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
824                                             &do_test, NULL);
825 }
826
827 /**
828  * test main: start test when all peers are connected
829  *
830  * @param cls Closure.
831  * @param ctx Argument to give to GNUNET_MESH_TEST_cleanup on test end.
832  * @param num_peers Number of peers that are running.
833  * @param peers Array of peers.
834  * @param meshes Handle to each of the MESHs of the peers.
835  */
836 static void
837 tmain (void *cls,
838        struct GNUNET_MESH_TEST_Context *ctx,
839        unsigned int num_peers,
840        struct GNUNET_TESTBED_Peer **peers,
841        struct GNUNET_MESH_Handle **meshes)
842 {
843   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test main\n");
844   ok = 0;
845   test_ctx = ctx;
846   peers_running = num_peers;
847   h1 = meshes[0];
848   h2 = meshes[num_peers - 1];
849   t = GNUNET_MESH_tunnel_create (h1, NULL, &ch, &dh, (void *) 0L);
850   if (SPEED_MIN == test)
851   {
852     GNUNET_MESH_tunnel_speed_min(t);
853     test = SPEED;
854   }
855   if (SPEED_NOBUF == test)
856   {
857     GNUNET_MESH_tunnel_buffer(t, GNUNET_NO);
858     test = SPEED;
859   }
860   peers_in_tunnel = 0;
861   disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
862                                                   &disconnect_mesh_peers,
863                                                   (void *) __LINE__);
864   shutdown_handle = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
865                                                   &shutdown_task, NULL);
866   t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0],
867                                                  GNUNET_TESTBED_PIT_IDENTITY,
868                                                  &pi_cb, (void *) 0L);
869   t_op[2] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 1],
870                                                  GNUNET_TESTBED_PIT_IDENTITY,
871                                                  &pi_cb, (void *) 2L);
872   if (MULTICAST == test)
873   {
874     h3 = meshes[num_peers - 2];
875     t_op[1] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 2],
876                                                    GNUNET_TESTBED_PIT_IDENTITY,
877                                                    &pi_cb, (void *) 1L);
878   }
879   else
880   {
881     t_op[1] = NULL;
882   }
883   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n");
884 }
885
886
887 /**
888  * Main: start test
889  */
890 int
891 main (int argc, char *argv[])
892 {
893   initialized = GNUNET_NO;
894
895   GNUNET_log_setup ("test", "DEBUG", NULL);
896   
897   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start\n");
898   if (strstr (argv[0], "test_mesh_small_unicast") != NULL)
899   {
900     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNICAST\n");
901     test = UNICAST;
902     test_name = "unicast";
903     ok_goal = 5;
904   }
905   else if (strstr (argv[0], "test_mesh_small_multicast") != NULL)
906   {
907     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MULTICAST\n");
908     test = MULTICAST;
909     test_name = "multicast";
910     ok_goal = 10;
911   }
912   else if (strstr (argv[0], "test_mesh_small_signal") != NULL)
913   {
914     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SIGNAL\n");
915     test = P2P_SIGNAL;
916     test_name = "signal";
917     ok_goal = 5;
918   }
919   else if (strstr (argv[0], "test_mesh_small_speed_ack") != NULL)
920   {
921    /* Each peer is supposed to generate the following callbacks:
922     * 1 incoming tunnel (@dest)
923     * 1 connected peer (@orig)
924     * TOTAL_PACKETS received data packet (@dest)
925     * TOTAL_PACKETS received data packet (@orig)
926     * 1 received tunnel destroy (@dest)
927     * _________________________________
928     * 5 x ok expected per peer
929     */
930     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n");
931     test = SPEED_ACK;
932     test_name = "speed ack";
933     ok_goal = TOTAL_PACKETS * 2 + 3;
934   }
935   else if (strstr (argv[0], "test_mesh_small_speed") != NULL)
936   {
937    /* Each peer is supposed to generate the following callbacks:
938     * 1 incoming tunnel (@dest)
939     * 1 connected peer (@orig)
940     * 1 initial packet (@dest)
941     * TOTAL_PACKETS received data packet (@dest)
942     * 1 received data packet (@orig)
943     * 1 received tunnel destroy (@dest)
944     * _________________________________
945     */
946     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n");
947     ok_goal = TOTAL_PACKETS + 5;
948     if (strstr (argv[0], "_min") != NULL)
949     {
950       test = SPEED_MIN;
951       test_name = "speed min";
952     }
953     else if (strstr (argv[0], "_nobuf") != NULL)
954     {
955       test = SPEED_NOBUF;
956       test_name = "speed nobuf";
957     }
958     else
959     {
960       test = SPEED;
961       test_name = "speed";
962     }
963   }
964   else
965   {
966     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNKNOWN\n");
967     test = SETUP;
968     ok_goal = 0;
969   }
970
971   if (strstr (argv[0], "backwards") != NULL)
972   {
973     char *aux;
974
975     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "BACKWARDS (LEAF TO ROOT)\n");
976     test_backwards = GNUNET_YES;
977     aux = GNUNET_malloc (32);
978     sprintf (aux, "backwards %s", test_name);
979     test_name = aux;
980   }
981
982   p_ids = 0;
983   GNUNET_MESH_TEST_run ("test_mesh_small",
984                         "test_mesh_small.conf",
985                         5,
986                         &tmain,
987                         NULL,
988                         &incoming_tunnel,
989                         &tunnel_cleaner,
990                         handlers,
991                         NULL);
992
993   if (ok_goal > ok)
994   {
995     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
996                 "FAILED! (%d/%d)\n", ok, ok_goal);
997     return 1;
998   }
999   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n");
1000   return 0;
1001 }
1002
1003 /* end of test_mesh_small.c */