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