Merge branch 'master' of ssh://gnunet.org/gnunet
[oweals/gnunet.git] / src / cadet / test_cadet.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2011, 2017 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20 /**
21  * @file cadet/test_cadet.c
22  * @author Bart Polot
23  * @author Christian Grothoff
24  * @brief Test for the cadet service: retransmission of traffic.
25  */
26 #include <stdio.h>
27 #include "platform.h"
28 #include "cadet_test_lib.h"
29 #include "gnunet_cadet_service.h"
30 #include "gnunet_statistics_service.h"
31 #include <gauger.h>
32
33
34 /**
35  * How many messages to send
36  */
37 #define TOTAL_PACKETS 500 /* Cannot exceed 64k! */
38
39 /**
40  * How long until we give up on connecting the peers?
41  */
42 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
43
44 /**
45  * Time to wait for stuff that should be rather fast
46  */
47 #define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20)
48
49 /**
50  * DIFFERENT TESTS TO RUN
51  */
52 #define SETUP 0
53 #define FORWARD 1
54 #define KEEPALIVE 2
55 #define SPEED 3
56 #define SPEED_ACK 4
57 #define SPEED_REL 8
58 #define P2P_SIGNAL 10
59
60 /**
61  * Which test are we running?
62  */
63 static int test;
64
65 /**
66  * String with test name
67  */
68 static char *test_name;
69
70 /**
71  * Flag to send traffic leaf->root in speed tests to test BCK_ACK logic.
72  */
73 static int test_backwards = GNUNET_NO;
74
75 /**
76  * How many events have happened
77  */
78 static int ok;
79
80 /**
81  * Number of events expected to conclude the test successfully.
82  */
83 static int ok_goal;
84
85 /**
86  * Size of each test packet
87  */
88 static size_t size_payload = sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t);
89
90 /**
91  * Operation to get peer ids.
92  */
93 static struct GNUNET_TESTBED_Operation *t_op[2];
94
95 /**
96  * Peer ids.
97  */
98 static struct GNUNET_PeerIdentity *p_id[2];
99
100 /**
101  * Port ID
102  */
103 static struct GNUNET_HashCode port;
104
105 /**
106  * Peer ids counter.
107  */
108 static unsigned int p_ids;
109
110 /**
111  * Is the setup initialized?
112  */
113 static int initialized;
114
115 /**
116  * Number of payload packes sent.
117  */
118 static int data_sent;
119
120 /**
121  * Number of payload packets received.
122  */
123 static int data_received;
124
125 /**
126  * Number of payload packed acknowledgements sent.
127  */
128 static int ack_sent;
129
130 /**
131  * Number of payload packed explicitly (app level) acknowledged.
132  */
133 static int ack_received;
134
135 /**
136  * Total number of peers asked to run.
137  */
138 static unsigned long long peers_requested;
139
140 /**
141  * Number of currently running peers (should be same as @c peers_requested).
142  */
143 static unsigned long long peers_running;
144
145 /**
146  * Test context (to shut down).
147  */
148 struct GNUNET_CADET_TEST_Context *test_ctx;
149
150 /**
151  * Task called to disconnect peers.
152  */
153 static struct GNUNET_SCHEDULER_Task *disconnect_task;
154
155 /**
156  * Task To perform tests
157  */
158 static struct GNUNET_SCHEDULER_Task *test_task;
159
160 /**
161  * Task runnining #data_task().
162  */
163 static struct GNUNET_SCHEDULER_Task *data_job;
164
165 /**
166  * Cadet handle for the root peer
167  */
168 static struct GNUNET_CADET_Handle *h1;
169
170 /**
171  * Cadet handle for the first leaf peer
172  */
173 static struct GNUNET_CADET_Handle *h2;
174
175 /**
176  * Channel handle for the root peer
177  */
178 static struct GNUNET_CADET_Channel *ch;
179
180 /**
181  * Channel handle for the dest peer
182  */
183 static struct GNUNET_CADET_Channel *incoming_ch;
184
185 /**
186  * Transmit handle for root data calls
187  */
188 static struct GNUNET_CADET_TransmitHandle *th;
189
190 /**
191  * Transmit handle for root data calls
192  */
193 static struct GNUNET_CADET_TransmitHandle *incoming_th;
194
195
196 /**
197  * Time we started the data transmission (after channel has been established
198  * and initilized).
199  */
200 static struct GNUNET_TIME_Absolute start_time;
201
202 /**
203  * Peers handle.
204  */
205 static struct GNUNET_TESTBED_Peer **testbed_peers;
206
207 /**
208  * Statistics operation handle.
209  */
210 static struct GNUNET_TESTBED_Operation *stats_op;
211
212 /**
213  * Keepalives sent.
214  */
215 static unsigned int ka_sent;
216
217 /**
218  * Keepalives received.
219  */
220 static unsigned int ka_received;
221
222 /**
223  * How many messages were dropped by CADET because of full buffers?
224  */
225 static unsigned int msg_dropped;
226
227
228 /**
229  * Get the client number considered as the "target" or "receiver", depending on
230  * the test type and size.
231  *
232  * @return Peer # of the target client, either 0 (for backward tests) or
233  *         the last peer in the line (for other tests).
234  */
235 static unsigned int
236 get_expected_target ()
237 {
238   if (SPEED == test && GNUNET_YES == test_backwards)
239     return 0;
240   else
241     return peers_requested - 1;
242 }
243
244
245 /**
246  * Show the results of the test (banwidth acheived) and log them to GAUGER
247  */
248 static void
249 show_end_data (void)
250 {
251   static struct GNUNET_TIME_Absolute end_time;
252   static struct GNUNET_TIME_Relative total_time;
253
254   end_time = GNUNET_TIME_absolute_get();
255   total_time = GNUNET_TIME_absolute_get_difference(start_time, end_time);
256   FPRINTF (stderr, "\nResults of test \"%s\"\n", test_name);
257   FPRINTF (stderr, "Test time %s\n",
258            GNUNET_STRINGS_relative_time_to_string (total_time,
259                                                    GNUNET_YES));
260   FPRINTF (stderr, "Test bandwidth: %f kb/s\n",
261            4 * TOTAL_PACKETS * 1.0 / (total_time.rel_value_us / 1000)); // 4bytes * ms
262   FPRINTF (stderr, "Test throughput: %f packets/s\n\n",
263            TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000)); // packets * ms
264   GAUGER ("CADET", test_name,
265           TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000),
266           "packets/s");
267 }
268
269
270 /**
271  * Disconnect from cadet services af all peers, call shutdown.
272  *
273  * @param cls Closure (line number from which termination was requested).
274  * @param tc Task Context.
275  */
276 static void
277 disconnect_cadet_peers (void *cls)
278 {
279   long line = (long) cls;
280   unsigned int i;
281
282   disconnect_task = NULL;
283   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
284               "disconnecting cadet service of peers, called from line %ld\n",
285               line);
286   for (i = 0; i < 2; i++)
287   {
288     GNUNET_TESTBED_operation_done (t_op[i]);
289   }
290   if (NULL != ch)
291   {
292     if (NULL != th)
293     {
294       GNUNET_CADET_notify_transmit_ready_cancel (th);
295       th = NULL;
296     }
297     GNUNET_CADET_channel_destroy (ch);
298     ch = NULL;
299   }
300   if (NULL != incoming_ch)
301   {
302     if (NULL != incoming_th)
303     {
304       GNUNET_CADET_notify_transmit_ready_cancel (incoming_th);
305       incoming_th = NULL;
306     }
307     GNUNET_CADET_channel_destroy (incoming_ch);
308     incoming_ch = NULL;
309   }
310   GNUNET_CADET_TEST_cleanup (test_ctx);
311   GNUNET_SCHEDULER_shutdown ();
312 }
313
314
315 /**
316  * Shut down peergroup, clean up.
317  *
318  * @param cls Closure (unused).
319  * @param tc Task Context.
320  */
321 static void
322 shutdown_task (void *cls)
323 {
324   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n");
325   if (NULL != data_job)
326   {
327     GNUNET_SCHEDULER_cancel (data_job);
328     data_job = NULL;
329   }
330   if (NULL != test_task)
331   {
332     GNUNET_SCHEDULER_cancel (test_task);
333     test_task = NULL;
334   }
335   if (NULL != disconnect_task)
336   {
337     GNUNET_SCHEDULER_cancel (disconnect_task);
338     disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
339                                                 (void *) __LINE__);
340   }
341 }
342
343
344 /**
345  * Stats callback. Finish the stats testbed operation and when all stats have
346  * been iterated, shutdown the test.
347  *
348  * @param cls Closure (line number from which termination was requested).
349  * @param op the operation that has been finished
350  * @param emsg error message in case the operation has failed; will be NULL if
351  *          operation has executed successfully.
352  */
353 static void
354 stats_cont (void *cls,
355             struct GNUNET_TESTBED_Operation *op,
356             const char *emsg)
357 {
358   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
359               " KA sent: %u, KA received: %u\n",
360               ka_sent,
361               ka_received);
362   if ( (KEEPALIVE == test) &&
363        ( (ka_sent < 2) ||
364          (ka_sent > ka_received + 1)) )
365   {
366     GNUNET_break (0);
367     ok--;
368   }
369   GNUNET_TESTBED_operation_done (stats_op);
370
371   if (NULL != disconnect_task)
372     GNUNET_SCHEDULER_cancel (disconnect_task);
373   disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
374                                               cls);
375 }
376
377
378 /**
379  * Process statistic values.
380  *
381  * @param cls closure (line number, unused)
382  * @param peer the peer the statistic belong to
383  * @param subsystem name of subsystem that created the statistic
384  * @param name the name of the datum
385  * @param value the current value
386  * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
387  * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
388  */
389 static int
390 stats_iterator (void *cls,
391                 const struct GNUNET_TESTBED_Peer *peer,
392                 const char *subsystem,
393                 const char *name,
394                 uint64_t value,
395                 int is_persistent)
396 {
397   static const char *s_sent = "# keepalives sent";
398   static const char *s_recv = "# keepalives received";
399   static const char *rdrops = "# messages dropped due to full buffer";
400   static const char *cdrops = "# messages dropped due to slow client";
401   uint32_t i;
402
403   i = GNUNET_TESTBED_get_index (peer);
404   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
405               "STATS PEER %u - %s [%s]: %llu\n",
406               i,
407               subsystem,
408               name,
409               (unsigned long long) value);
410   if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i)
411     ka_sent = value;
412   if (0 == strncmp(s_recv, name, strlen (s_recv)) && peers_requested - 1 == i)
413     ka_received = value;
414   if (0 == strncmp(rdrops, name, strlen (rdrops)))
415     msg_dropped += value;
416   if (0 == strncmp(cdrops, name, strlen (cdrops)))
417     msg_dropped += value;
418
419   return GNUNET_OK;
420 }
421
422
423 /**
424  * Task to gather all statistics.
425  *
426  * @param cls Closure (NULL).
427  */
428 static void
429 gather_stats_and_exit (void *cls)
430 {
431   long l = (long) cls;
432
433   disconnect_task = NULL;
434   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
435               "gathering statistics from line %d\n",
436               (int) l);
437   if (NULL != ch)
438   {
439     if (NULL != th)
440     {
441       GNUNET_CADET_notify_transmit_ready_cancel (th);
442       th = NULL;
443     }
444     GNUNET_CADET_channel_destroy (ch);
445     ch = NULL;
446   }
447   stats_op = GNUNET_TESTBED_get_statistics (peers_running, testbed_peers,
448                                             "cadet", NULL,
449                                             &stats_iterator, stats_cont, cls);
450 }
451
452
453
454 /**
455  * Abort test: schedule disconnect and shutdown immediately
456  *
457  * @param line Line in the code the abort is requested from (__LINE__).
458  */
459 static void
460 abort_test (long line)
461 {
462   if (NULL != disconnect_task)
463   {
464     GNUNET_SCHEDULER_cancel (disconnect_task);
465     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
466                 "Aborting test from %ld\n", line);
467     disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
468                                                 (void *) line);
469   }
470 }
471
472 /**
473  * Transmit ready callback.
474  *
475  * @param cls Closure (message type).
476  * @param size Size of the tranmist buffer.
477  * @param buf Pointer to the beginning of the buffer.
478  *
479  * @return Number of bytes written to buf.
480  */
481 static size_t
482 tmt_rdy (void *cls, size_t size, void *buf);
483
484
485 /**
486  * Task to request a new data transmission.
487  *
488  * @param cls Closure (peer #).
489  */
490 static void
491 data_task (void *cls)
492 {
493   struct GNUNET_CADET_Channel *channel;
494   static struct GNUNET_CADET_TransmitHandle **pth;
495   long src;
496
497   data_job = NULL;
498   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data task\n");
499   if (GNUNET_YES == test_backwards)
500   {
501     channel = incoming_ch;
502     pth = &incoming_th;
503     src = peers_requested - 1;
504   }
505   else
506   {
507     channel = ch;
508     pth = &th;
509     src = 0;
510   }
511
512   GNUNET_assert (NULL != channel);
513   GNUNET_assert (NULL == *pth);
514
515   *pth = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
516                                              GNUNET_TIME_UNIT_FOREVER_REL,
517                                              size_payload + data_sent,
518                                              &tmt_rdy, (void *) src);
519   if (NULL == *pth)
520   {
521     unsigned long i = (unsigned long) cls;
522
523     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Retransmission\n");
524     if (0 == i)
525     {
526       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "  in 1 ms\n");
527       data_job = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
528                                                &data_task, (void *) 1L);
529     }
530     else
531     {
532       i++;
533       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
534                   "in %llu ms\n",
535                   (unsigned long long) i);
536       data_job = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
537                                                                               i),
538                                                &data_task, (void *) i);
539     }
540   }
541 }
542
543
544 /**
545  * Transmit ready callback
546  *
547  * @param cls Closure (peer # which is sending the data).
548  * @param size Size of the buffer we have.
549  * @param buf Buffer to copy data to.
550  */
551 static size_t
552 tmt_rdy (void *cls, size_t size, void *buf)
553 {
554   struct GNUNET_MessageHeader *msg = buf;
555   size_t msg_size;
556   uint32_t *data;
557   long id = (long) cls;
558   unsigned int counter;
559
560   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
561               "tmt_rdy on %ld, filling buffer\n",
562               id);
563   if (0 == id)
564     th = NULL;
565   else if ((peers_requested - 1) == id)
566     incoming_th = NULL;
567   else
568     GNUNET_assert (0);
569   counter = get_expected_target () == id ? ack_sent : data_sent;
570   msg_size = size_payload + counter;
571   GNUNET_assert (msg_size > sizeof (struct GNUNET_MessageHeader));
572   if ( (size < msg_size) ||
573        (NULL == buf) )
574   {
575     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
576                 "size %u, buf %p, data_sent %u, ack_received %u\n",
577                 (unsigned int) size,
578                 buf,
579                 data_sent,
580                 ack_received);
581     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ok %u, ok goal %u\n", ok, ok_goal);
582     GNUNET_break (ok >= ok_goal - 2);
583
584     return 0;
585   }
586   msg->size = htons (msg_size);
587   msg->type = htons (GNUNET_MESSAGE_TYPE_DUMMY);
588   data = (uint32_t *) &msg[1];
589   *data = htonl (counter);
590   if (GNUNET_NO == initialized)
591   {
592     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
593                 "sending initializer\n");
594     msg_size = size_payload + 1000;
595     msg->size = htons (msg_size);
596     if (SPEED_ACK == test)
597         data_sent++;
598   }
599   else if ( (SPEED == test) ||
600             (SPEED_ACK == test) )
601   {
602     if (get_expected_target() == id)
603       ack_sent++;
604     else
605       data_sent++;
606     counter++;
607     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
608                 " Sent message %u size %u\n",
609                 counter,
610                 (unsigned int) msg_size);
611     if ( (data_sent < TOTAL_PACKETS) &&
612          (SPEED == test) )
613     {
614       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
615                   " Scheduling message %d\n",
616                   counter + 1);
617       data_job = GNUNET_SCHEDULER_add_now (&data_task, NULL);
618     }
619   }
620
621   return msg_size;
622 }
623
624
625 /**
626  * Function is called whenever a message is received.
627  *
628  * @param cls closure (set from GNUNET_CADET_connect(), peer number)
629  * @param channel connection to the other end
630  * @param channel_ctx place to store local state associated with the channel
631  * @param message the actual message
632  * @return #GNUNET_OK to keep the connection open,
633  *         #GNUNET_SYSERR to close it (signal serious error)
634  */
635 static int
636 data_callback (void *cls,
637                struct GNUNET_CADET_Channel *channel,
638                void **channel_ctx,
639                const struct GNUNET_MessageHeader *message)
640 {
641   struct GNUNET_CADET_TransmitHandle **pth;
642   long client = (long) cls;
643   long expected_target_client;
644   uint32_t *data;
645   uint32_t payload;
646   unsigned int counter;
647
648   ok++;
649   counter = get_expected_target () == client ? data_received : ack_received;
650
651   GNUNET_CADET_receive_done (channel);
652
653   if ((ok % 10) == 0)
654   {
655     if (NULL != disconnect_task)
656     {
657       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
658                   " reschedule timeout\n");
659       GNUNET_SCHEDULER_cancel (disconnect_task);
660       disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
661                                                       &gather_stats_and_exit,
662                                                       (void *) __LINE__);
663     }
664   }
665
666   switch (client)
667   {
668   case 0L:
669     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message!\n");
670     GNUNET_assert (channel == ch);
671     pth = &th;
672     break;
673   case 1L:
674   case 4L:
675     GNUNET_assert (client == peers_requested - 1);
676     GNUNET_assert (channel == incoming_ch);
677     pth = &incoming_th;
678     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Leaf client %ld got a message.\n",
679                 client);
680     break;
681   default:
682     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Client %ld not valid.\n", client);
683     GNUNET_assert (0);
684   }
685   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: (%d/%d)\n", ok, ok_goal);
686   data = (uint32_t *) &message[1];
687   payload = ntohl (*data);
688   if (payload == counter)
689   {
690     GNUNET_log (GNUNET_ERROR_TYPE_INFO, " payload as expected: %u\n", payload);
691   }
692   else
693   {
694     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " payload %u, expected: %u\n",
695                 payload, counter);
696   }
697   expected_target_client = get_expected_target ();
698
699   if (GNUNET_NO == initialized)
700   {
701     initialized = GNUNET_YES;
702     start_time = GNUNET_TIME_absolute_get ();
703     if (SPEED == test)
704     {
705       GNUNET_assert (peers_requested - 1 == client);
706       data_job = GNUNET_SCHEDULER_add_now (&data_task, NULL);
707       return GNUNET_OK;
708     }
709   }
710
711   counter++;
712   if (client == expected_target_client) /* Normally 4 */
713   {
714     data_received++;
715     GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received data %u\n", data_received);
716     if (SPEED != test || (ok_goal - 2) == ok)
717     {
718       /* Send ACK */
719       GNUNET_assert (NULL == *pth);
720       *pth = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
721                                                  GNUNET_TIME_UNIT_FOREVER_REL,
722                                                  size_payload + ack_sent,
723                                                  &tmt_rdy, (void *) client);
724       return GNUNET_OK;
725     }
726     else
727     {
728       if (data_received < TOTAL_PACKETS)
729         return GNUNET_OK;
730     }
731   }
732   else /* Normally 0 */
733   {
734     if (SPEED_ACK == test || SPEED == test)
735     {
736       ack_received++;
737       GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received ack %u\n", ack_received);
738       /* send more data */
739       GNUNET_assert (NULL == *pth);
740       *pth = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
741                                                  GNUNET_TIME_UNIT_FOREVER_REL,
742                                                  size_payload + data_sent,
743                                                  &tmt_rdy, (void *) client);
744       if (ack_received < TOTAL_PACKETS && SPEED != test)
745         return GNUNET_OK;
746       if (ok == 2 && SPEED == test)
747         return GNUNET_OK;
748       show_end_data();
749     }
750     if (test == P2P_SIGNAL)
751     {
752       if (NULL != incoming_th)
753       {
754         GNUNET_CADET_notify_transmit_ready_cancel (incoming_th);
755         incoming_th = NULL;
756       }
757       GNUNET_CADET_channel_destroy (incoming_ch);
758       incoming_ch = NULL;
759     }
760     else
761     {
762       if (NULL != th)
763       {
764         GNUNET_CADET_notify_transmit_ready_cancel (th);
765         th = NULL;
766       }
767       GNUNET_CADET_channel_destroy (ch);
768       ch = NULL;
769     }
770   }
771
772   return GNUNET_OK;
773 }
774
775
776 /**
777  * Data handlers for every message type of CADET's payload.
778  * {callback_function, message_type, size_expected}
779  */
780 static struct GNUNET_CADET_MessageHandler handlers[] = {
781   {&data_callback,
782    GNUNET_MESSAGE_TYPE_DUMMY,
783    sizeof (struct GNUNET_MessageHeader)},
784   {NULL, 0, 0}
785 };
786
787
788 /**
789  * Method called whenever another peer has added us to a channel
790  * the other peer initiated.
791  *
792  * @param cls Closure.
793  * @param channel New handle to the channel.
794  * @param initiator Peer that started the channel.
795  * @param port Port this channel is connected to.
796  * @param options channel option flags
797  * @return Initial channel context for the channel
798  *         (can be NULL -- that's not an error).
799  */
800 static void *
801 incoming_channel (void *cls,
802                   struct GNUNET_CADET_Channel *channel,
803                   const struct GNUNET_PeerIdentity *initiator,
804                   const struct GNUNET_HashCode *port,
805                   enum GNUNET_CADET_ChannelOption options)
806 {
807   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
808               "Incoming channel from %s to peer %d:%s\n",
809               GNUNET_i2s (initiator),
810               (int) (long) cls, GNUNET_h2s (port));
811   ok++;
812   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
813   if ((long) cls == peers_requested - 1)
814   {
815     if (NULL != incoming_ch)
816     {
817       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
818                   "Duplicate incoming channel for client %lu\n",
819                   (long) cls);
820       GNUNET_break(0);
821     }
822     incoming_ch = channel;
823   }
824   else
825   {
826     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
827                 "Incoming channel for unexpected peer #%lu\n",
828                 (long) cls);
829     GNUNET_break (0);
830   }
831   if (NULL != disconnect_task)
832   {
833     GNUNET_SCHEDULER_cancel (disconnect_task);
834     disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
835                                                     &gather_stats_and_exit,
836                                                     (void *) __LINE__);
837   }
838
839   return NULL;
840 }
841
842
843 /**
844  * Function called whenever an inbound channel is destroyed.  Should clean up
845  * any associated state.
846  *
847  * @param cls closure (set from GNUNET_CADET_connect, peer number)
848  * @param channel connection to the other end (henceforth invalid)
849  * @param channel_ctx place where local state associated
850  *                   with the channel is stored
851  */
852 static void
853 channel_cleaner (void *cls,
854                  const struct GNUNET_CADET_Channel *channel,
855                  void *channel_ctx)
856 {
857   long i = (long) cls;
858
859   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
860               "Incoming channel disconnected at peer %ld\n",
861               i);
862   if (peers_running - 1 == i)
863   {
864     ok++;
865     GNUNET_break (channel == incoming_ch);
866     incoming_ch = NULL;
867   }
868   else if (0L == i)
869   {
870     if (P2P_SIGNAL == test)
871     {
872       ok++;
873     }
874     GNUNET_break (channel == ch);
875     ch = NULL;
876   }
877   else
878     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
879                 "Unknown peer! %d\n",
880                 (int) i);
881   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
882
883   if (NULL != disconnect_task)
884   {
885     GNUNET_SCHEDULER_cancel (disconnect_task);
886     disconnect_task = GNUNET_SCHEDULER_add_now (&gather_stats_and_exit,
887                                                 (void *) __LINE__);
888   }
889 }
890
891
892 /**
893  * START THE TESTCASE ITSELF, AS WE ARE CONNECTED TO THE CADET SERVICES.
894  *
895  * Testcase continues when the root receives confirmation of connected peers,
896  * on callback function ch.
897  *
898  * @param cls Closure (unused).
899  */
900 static void
901 do_test (void *cls)
902 {
903   enum GNUNET_CADET_ChannelOption flags;
904
905   test_task = NULL;
906   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
907               "do_test\n");
908   if (NULL != disconnect_task)
909   {
910     GNUNET_SCHEDULER_cancel (disconnect_task);
911     disconnect_task = NULL;
912   }
913
914   flags = GNUNET_CADET_OPTION_DEFAULT;
915   if (SPEED_REL == test)
916   {
917     test = SPEED;
918     flags |= GNUNET_CADET_OPTION_RELIABLE;
919   }
920
921   ch = GNUNET_CADET_channel_create (h1,
922                                     NULL,
923                                     p_id[1],
924                                     &port,
925                                     flags);
926
927   disconnect_task
928     = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
929                                     &gather_stats_and_exit,
930                                     (void *) __LINE__);
931   if (KEEPALIVE == test)
932     return; /* Don't send any data. */
933
934   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
935               "Sending data initializer...\n");
936   data_received = 0;
937   data_sent = 0;
938   ack_received = 0;
939   ack_sent = 0;
940   th = GNUNET_CADET_notify_transmit_ready (ch,
941                                            GNUNET_NO,
942                                            GNUNET_TIME_UNIT_FOREVER_REL,
943                                            size_payload + 1000,
944                                            &tmt_rdy, (void *) 0L);
945 }
946
947
948 /**
949  * Callback to be called when the requested peer information is available
950  *
951  * @param cls the closure from GNUNET_TESTBED_peer_get_information()
952  * @param op the operation this callback corresponds to
953  * @param pinfo the result; will be NULL if the operation has failed
954  * @param emsg error message if the operation has failed;
955  *             NULL if the operation is successfull
956  */
957 static void
958 pi_cb (void *cls,
959        struct GNUNET_TESTBED_Operation *op,
960        const struct GNUNET_TESTBED_PeerInformation *pinfo,
961        const char *emsg)
962 {
963   long i = (long) cls;
964
965   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
966               "id callback for %ld\n", i);
967
968   if ( (NULL == pinfo) ||
969        (NULL != emsg) )
970   {
971     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
972                 "pi_cb: %s\n", emsg);
973     abort_test (__LINE__);
974     return;
975   }
976   p_id[i] = pinfo->result.id;
977   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
978               "  id: %s\n", GNUNET_i2s (p_id[i]));
979   p_ids++;
980   if (p_ids < 2)
981     return;
982   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
983               "Got all IDs, starting test\n");
984   test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
985                                             &do_test,
986                                             NULL);
987 }
988
989
990 /**
991  * test main: start test when all peers are connected
992  *
993  * @param cls Closure.
994  * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end.
995  * @param num_peers Number of peers that are running.
996  * @param peers Array of peers.
997  * @param cadetes Handle to each of the CADETs of the peers.
998  */
999 static void
1000 tmain (void *cls,
1001        struct GNUNET_CADET_TEST_Context *ctx,
1002        unsigned int num_peers,
1003        struct GNUNET_TESTBED_Peer **peers,
1004        struct GNUNET_CADET_Handle **cadets)
1005 {
1006   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test main\n");
1007   ok = 0;
1008   test_ctx = ctx;
1009   peers_running = num_peers;
1010   GNUNET_assert (peers_running == peers_requested);
1011   testbed_peers = peers;
1012   h1 = cadets[0];
1013   h2 = cadets[num_peers - 1];
1014   disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
1015                                                   &disconnect_cadet_peers,
1016                                                   (void *) __LINE__);
1017   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
1018   t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0],
1019                                                  GNUNET_TESTBED_PIT_IDENTITY,
1020                                                  &pi_cb, (void *) 0L);
1021   t_op[1] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 1],
1022                                                  GNUNET_TESTBED_PIT_IDENTITY,
1023                                                  &pi_cb, (void *) 1L);
1024   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n");
1025 }
1026
1027
1028 /**
1029  * Main: start test
1030  */
1031 int
1032 main (int argc, char *argv[])
1033 {
1034   initialized = GNUNET_NO;
1035   static const struct GNUNET_HashCode *ports[2];
1036   const char *config_file;
1037   char port_id[] = "test port";
1038   GNUNET_CRYPTO_hash (port_id, sizeof (port_id), &port);
1039
1040   GNUNET_log_setup ("test", "DEBUG", NULL);
1041   config_file = "test_cadet.conf";
1042
1043   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start\n");
1044
1045   /* Find out requested size */
1046   if (strstr (argv[0], "_2_") != NULL)
1047   {
1048     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "DIRECT CONNECTIONs\n");
1049     peers_requested = 2;
1050   }
1051   else if (strstr (argv[0], "_5_") != NULL)
1052   {
1053     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "5 PEER LINE\n");
1054     peers_requested = 5;
1055   }
1056   else
1057   {
1058     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "SIZE UNKNOWN, USING 2\n");
1059     peers_requested = 2;
1060   }
1061
1062   /* Find out requested test */
1063   if (strstr (argv[0], "_forward") != NULL)
1064   {
1065     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "FORWARD\n");
1066     test = FORWARD;
1067     test_name = "unicast";
1068     ok_goal = 4;
1069   }
1070   else if (strstr (argv[0], "_signal") != NULL)
1071   {
1072     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SIGNAL\n");
1073     test = P2P_SIGNAL;
1074     test_name = "signal";
1075     ok_goal = 4;
1076   }
1077   else if (strstr (argv[0], "_speed_ack") != NULL)
1078   {
1079     /* Test is supposed to generate the following callbacks:
1080      * 1 incoming channel (@dest)
1081      * TOTAL_PACKETS received data packet (@dest)
1082      * TOTAL_PACKETS received data packet (@orig)
1083      * 1 received channel destroy (@dest)
1084      */
1085     ok_goal = TOTAL_PACKETS * 2 + 2;
1086     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n");
1087     test = SPEED_ACK;
1088     test_name = "speed ack";
1089   }
1090   else if (strstr (argv[0], "_speed") != NULL)
1091   {
1092     /* Test is supposed to generate the following callbacks:
1093      * 1 incoming channel (@dest)
1094      * 1 initial packet (@dest)
1095      * TOTAL_PACKETS received data packet (@dest)
1096      * 1 received data packet (@orig)
1097      * 1 received channel destroy (@dest)
1098      */
1099     ok_goal = TOTAL_PACKETS + 4;
1100     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n");
1101     if (strstr (argv[0], "_reliable") != NULL)
1102     {
1103       test = SPEED_REL;
1104       test_name = "speed reliable";
1105       config_file = "test_cadet_drop.conf";
1106     }
1107     else
1108     {
1109       test = SPEED;
1110       test_name = "speed";
1111     }
1112   }
1113   else if (strstr (argv[0], "_keepalive") != NULL)
1114   {
1115     test = KEEPALIVE;
1116     /* Test is supposed to generate the following callbacks:
1117      * 1 incoming channel (@dest)
1118      * [wait]
1119      * 1 received channel destroy (@dest)
1120      */
1121     ok_goal = 2;
1122   }
1123   else
1124   {
1125     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNKNOWN\n");
1126     test = SETUP;
1127     ok_goal = 0;
1128   }
1129
1130   if (strstr (argv[0], "backwards") != NULL)
1131   {
1132     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "BACKWARDS (LEAF TO ROOT)\n");
1133     test_backwards = GNUNET_YES;
1134     GNUNET_asprintf (&test_name, "backwards %s", test_name);
1135   }
1136
1137   p_ids = 0;
1138   ports[0] = &port;
1139   ports[1] = NULL;
1140   GNUNET_CADET_TEST_run ("test_cadet_small",
1141                         config_file,
1142                         peers_requested,
1143                         &tmain,
1144                         NULL, /* tmain cls */
1145                         &incoming_channel,
1146                         &channel_cleaner,
1147                         handlers,
1148                         ports);
1149   if (NULL != strstr (argv[0], "_reliable"))
1150     msg_dropped = 0; /* dropped should be retransmitted */
1151
1152   if (ok_goal > ok - msg_dropped)
1153   {
1154     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1155                 "FAILED! (%d/%d)\n", ok, ok_goal);
1156     return 1;
1157   }
1158   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n");
1159   return 0;
1160 }
1161
1162 /* end of test_cadet.c */