glitch in the license text detected by hyazinthe, thank you!
[oweals/gnunet.git] / src / cadet / test_cadet_flow.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 it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14 */
15 /**
16  * @file cadet/test_cadet_flow.c
17  * @author Bart Polot
18  * @author Christian Grothoff
19  * @brief Test for flow control of CADET service
20  */
21 #include <stdio.h>
22 #include "platform.h"
23 #include "cadet_test_lib.h"
24 #include "gnunet_cadet_service.h"
25 #include "gnunet_statistics_service.h"
26 #include <gauger.h>
27
28
29 /**
30  * Ugly workaround to unify data handlers on incoming and outgoing channels.
31  */
32 struct CadetTestChannelWrapper
33 {
34   /**
35    * Channel pointer.
36    */
37   struct GNUNET_CADET_Channel *ch;
38 };
39
40 /**
41  * How many messages to send by default.
42  */
43 #define TOTAL_PACKETS_DEFAULT 500
44
45 /**
46  * How long until we give up on connecting the peers?
47  */
48 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
49
50 /**
51  * Time to wait by default  for stuff that should be rather fast.
52  */
53 #define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20)
54
55 /**
56  * How fast do we send messages?
57  */
58 #define SEND_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 10)
59
60
61 /**
62  * How many packets to send.
63  */
64 static unsigned int total_packets = TOTAL_PACKETS_DEFAULT;
65
66 /**
67  * Time to wait for fast operations.
68  */
69 static struct GNUNET_TIME_Relative short_time;
70
71 /**
72  * Size of each test packet's payload
73  */
74 static size_t size_payload = sizeof (uint32_t);
75
76 /**
77  * Operation to get peer ids.
78  */
79 static struct GNUNET_TESTBED_Operation *t_op[2];
80
81 /**
82  * Peer ids.
83  */
84 static struct GNUNET_PeerIdentity *p_id[2];
85
86 /**
87  * Port ID
88  */
89 static struct GNUNET_HashCode port;
90
91 /**
92  * Peer ids counter.
93  */
94 static unsigned int p_ids;
95
96 /**
97  * Is the setup initialized?
98  */
99 static int initialized;
100
101 /**
102  * Number of payload packes sent.
103  */
104 static int data_sent;
105
106 /**
107  * Number of payload packets received.
108  */
109 static int data_received;
110
111 /**
112  * Number of payload packed acknowledgements sent.
113  */
114 static int ack_sent;
115
116 /**
117  * Number of payload packed explicitly (app level) acknowledged.
118  */
119 static int ack_received;
120
121 /**
122  * Total number of peers asked to run.
123  */
124 static unsigned int peers_requested = 2;
125
126 /**
127  * Number of currently running peers (should be same as @c peers_requested).
128  */
129 static unsigned int peers_running;
130
131 /**
132  * Test context (to shut down).
133  */
134 struct GNUNET_CADET_TEST_Context *test_ctx;
135
136 /**
137  * Task called to disconnect peers.
138  */
139 static struct GNUNET_SCHEDULER_Task *disconnect_task;
140
141 /**
142  * Task To perform tests
143  */
144 static struct GNUNET_SCHEDULER_Task *test_task;
145
146 /**
147  * Task runnining #send_next_msg().
148  */
149 static struct GNUNET_SCHEDULER_Task *send_next_msg_task;
150
151 /**
152  * Cadet handle for the root peer
153  */
154 static struct GNUNET_CADET_Handle *h1;
155
156 /**
157  * Cadet handle for the first leaf peer
158  */
159 static struct GNUNET_CADET_Handle *h2;
160
161 /**
162  * Channel handle for the root peer
163  */
164 static struct GNUNET_CADET_Channel *outgoing_ch;
165
166 /**
167  * Channel handle for the dest peer
168  */
169 static struct GNUNET_CADET_Channel *incoming_ch;
170
171 /**
172  * Time we started the data transmission (after channel has been established
173  * and initilized).
174  */
175 static struct GNUNET_TIME_Absolute start_time;
176
177 /**
178  * Peers handle.
179  */
180 static struct GNUNET_TESTBED_Peer **testbed_peers;
181
182 /**
183  * Statistics operation handle.
184  */
185 static struct GNUNET_TESTBED_Operation *stats_op;
186
187 /**
188  * Keepalives sent.
189  */
190 static unsigned int ka_sent;
191
192 /**
193  * Keepalives received.
194  */
195 static unsigned int ka_received;
196
197 /**
198  * How many messages were dropped by CADET because of full buffers?
199  */
200 static unsigned int msg_dropped;
201
202
203 /**
204  * Show the results of the test (banwidth acheived) and log them to GAUGER
205  */
206 static void
207 show_end_data (void)
208 {
209   static struct GNUNET_TIME_Absolute end_time;
210   static struct GNUNET_TIME_Relative total_time;
211
212   end_time = GNUNET_TIME_absolute_get ();
213   total_time = GNUNET_TIME_absolute_get_difference (start_time, end_time);
214   FPRINTF (stderr,
215            "\nResults of test \"%s\"\n",
216            test_name);
217   FPRINTF (stderr,
218            "Test time %s\n",
219            GNUNET_STRINGS_relative_time_to_string (total_time, GNUNET_YES));
220   FPRINTF (stderr,
221            "Test bandwidth: %f kb/s\n",
222            4 * total_packets * 1.0 / (total_time.rel_value_us / 1000));    // 4bytes * ms
223   FPRINTF (stderr,
224            "Test throughput: %f packets/s\n\n",
225            total_packets * 1000.0 / (total_time.rel_value_us / 1000));     // packets * ms
226   GAUGER ("CADET",
227           test_name,
228           total_packets * 1000.0 / (total_time.rel_value_us / 1000),
229           "packets/s");
230 }
231
232
233 /**
234  * Shut down peergroup, clean up.
235  *
236  * @param cls Closure (unused).
237  * @param tc Task Context.
238  */
239 static void
240 shutdown_task (void *cls)
241 {
242   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
243               "Ending test.\n");
244   if (NULL != send_next_msg_task)
245   {
246     GNUNET_SCHEDULER_cancel (send_next_msg_task);
247     send_next_msg_task = NULL;
248   }
249   if (NULL != test_task)
250   {
251     GNUNET_SCHEDULER_cancel (test_task);
252     test_task = NULL;
253   }
254   for (unsigned int i = 0; i < 2; i++)
255     GNUNET_TESTBED_operation_done (t_op[i]);
256   if (NULL != outgoing_ch)
257   {
258     GNUNET_CADET_channel_destroy (outgoing_ch);
259     outgoing_ch = NULL;
260   }
261   if (NULL != incoming_ch)
262   {
263     GNUNET_CADET_channel_destroy (incoming_ch);
264     incoming_ch = NULL;
265   }
266   GNUNET_CADET_TEST_cleanup (test_ctx);
267 }
268
269
270 /**
271  * Stats callback. Finish the stats testbed operation and when all stats have
272  * been iterated, shutdown the test.
273  *
274  * @param cls Closure (line number from which termination was requested).
275  * @param op the operation that has been finished
276  * @param emsg error message in case the operation has failed; will be NULL if
277  *          operation has executed successfully.
278  */
279 static void
280 stats_cont (void *cls,
281             struct GNUNET_TESTBED_Operation *op,
282             const char *emsg)
283 {
284   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
285               "KA sent: %u, KA received: %u\n",
286               ka_sent,
287               ka_received);
288   if ((KEEPALIVE == test) && ((ka_sent < 2) || (ka_sent > ka_received + 1)))
289   {
290     GNUNET_break (0);
291     ok--;
292   }
293   GNUNET_TESTBED_operation_done (stats_op);
294
295   if (NULL != disconnect_task)
296     GNUNET_SCHEDULER_cancel (disconnect_task);
297   disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
298                                               cls);
299 }
300
301
302 /**
303  * Process statistic values.
304  *
305  * @param cls closure (line number, unused)
306  * @param peer the peer the statistic belong to
307  * @param subsystem name of subsystem that created the statistic
308  * @param name the name of the datum
309  * @param value the current value
310  * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
311  * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
312  */
313 static int
314 stats_iterator (void *cls,
315                 const struct GNUNET_TESTBED_Peer *peer,
316                 const char *subsystem,
317                 const char *name,
318                 uint64_t value,
319                 int is_persistent)
320 {
321   static const char *s_sent = "# keepalives sent";
322   static const char *s_recv = "# keepalives received";
323   static const char *rdrops = "# messages dropped due to full buffer";
324   static const char *cdrops = "# messages dropped due to slow client";
325   uint32_t i;
326
327   i = GNUNET_TESTBED_get_index (peer);
328   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "STATS PEER %u - %s [%s]: %llu\n", i,
329               subsystem, name, (unsigned long long) value);
330   if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i)
331     ka_sent = value;
332   if (0 == strncmp (s_recv, name, strlen (s_recv)) && peers_requested - 1 == i)
333     ka_received = value;
334   if (0 == strncmp (rdrops, name, strlen (rdrops)))
335     msg_dropped += value;
336   if (0 == strncmp (cdrops, name, strlen (cdrops)))
337     msg_dropped += value;
338
339   return GNUNET_OK;
340 }
341
342
343 /**
344  * Task to gather all statistics.
345  *
346  * @param cls Closure (line from which the task was scheduled).
347  */
348 static void
349 gather_stats_and_exit (void *cls)
350 {
351   long l = (long) cls;
352
353   disconnect_task = NULL;
354   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
355               "gathering statistics from line %ld\n",
356               l);
357   if (NULL != outgoing_ch)
358   {
359     GNUNET_CADET_channel_destroy (outgoing_ch);
360     outgoing_ch = NULL;
361   }
362   stats_op = GNUNET_TESTBED_get_statistics (peers_running,
363                                             testbed_peers,
364                                             "cadet",
365                                             NULL,
366                                             &stats_iterator,
367                                             stats_cont,
368                                             cls);
369 }
370
371
372 /**
373  * Abort test: schedule disconnect and shutdown immediately
374  *
375  * @param line Line in the code the abort is requested from (__LINE__).
376  */
377 static void
378 abort_test (long line)
379 {
380   if (NULL != disconnect_task)
381   {
382     GNUNET_SCHEDULER_cancel (disconnect_task);
383     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
384                 "Aborting test from %ld\n",
385                 line);
386     disconnect_task =
387         GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
388                                   (void *) line);
389   }
390 }
391
392
393 /**
394  * Send a message on the channel with the appropriate size and payload.
395  *
396  * Update the appropriate *_sent counter.
397  *
398  * @param channel Channel to send the message on.
399  */
400 static void
401 send_test_message (struct GNUNET_CADET_Channel *channel)
402 {
403   struct GNUNET_MQ_Envelope *env;
404   struct GNUNET_MessageHeader *msg;
405   uint32_t *data;
406   int payload;
407   int size;
408
409   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
410               "Sending test message on channel %p\n",
411               channel);
412   size = size_payload;
413   if (GNUNET_NO == initialized)
414   {
415     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending INITIALIZER\n");
416     size += 1000;
417     payload = data_sent;
418     if (SPEED_ACK == test) // FIXME unify SPEED_ACK with an initializer
419         data_sent++;
420   }
421   else if (SPEED == test || SPEED_ACK == test)
422   {
423     if (get_target_channel() == channel)
424     {
425       payload = ack_sent;
426       size += ack_sent;
427       ack_sent++;
428       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
429                   "Sending ACK %u [%d bytes]\n",
430                   payload, size);
431     }
432     else
433     {
434       payload = data_sent;
435       size += data_sent;
436       data_sent++;
437       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
438                   "Sending DATA %u [%d bytes]\n",
439                   data_sent, size);
440     }
441   }
442   else if (FORWARD == test)
443   {
444     payload = ack_sent;
445   }
446   else if (P2P_SIGNAL == test)
447   {
448     payload = data_sent;
449   }
450   else
451   {
452     GNUNET_assert (0);
453   }
454   env = GNUNET_MQ_msg_extra (msg, size, GNUNET_MESSAGE_TYPE_DUMMY);
455
456   data = (uint32_t *) &msg[1];
457   *data = htonl (payload);
458   GNUNET_MQ_send (GNUNET_CADET_get_mq (channel), env);
459 }
460
461
462 /**
463  * Task to request a new data transmission in a SPEED test, without waiting
464  * for previous messages to be sent/arrrive.
465  *
466  * @param cls Closure (unused).
467  */
468 static void
469 send_next_msg (void *cls)
470 {
471   struct GNUNET_CADET_Channel *channel;
472
473   send_next_msg_task = NULL;
474   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
475               "Sending next message: %d\n",
476               data_sent);
477
478   channel = GNUNET_YES == test_backwards ? incoming_ch : outgoing_ch;
479   GNUNET_assert (NULL != channel);
480   GNUNET_assert (SPEED == test);
481   send_test_message (channel);
482   if (data_sent < total_packets)
483   {
484     /* SPEED test: Send all messages as soon as possible */
485     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
486                 "Scheduling message %d\n",
487                 data_sent + 1);
488     send_next_msg_task =
489       GNUNET_SCHEDULER_add_delayed (SEND_INTERVAL,
490                                       &send_next_msg,
491                                       NULL);
492   }
493 }
494
495
496 /**
497  * Check if payload is sane (size contains payload).
498  *
499  * @param cls should match #ch
500  * @param message The actual message.
501  * @return #GNUNET_OK to keep the channel open,
502  *         #GNUNET_SYSERR to close it (signal serious error).
503  */
504 static int
505 check_data (void *cls,
506             const struct GNUNET_MessageHeader *message)
507 {
508   return GNUNET_OK;             /* all is well-formed */
509 }
510
511
512 /**
513  * Function is called whenever a message is received.
514  *
515  * @param cls closure (set from GNUNET_CADET_connect(), peer number)
516  * @param message the actual message
517  */
518 static void
519 handle_data (void *cls,
520              const struct GNUNET_MessageHeader *message)
521 {
522   struct CadetTestChannelWrapper *ch = cls;
523   struct GNUNET_CADET_Channel *channel = ch->ch;
524   uint32_t *data;
525   uint32_t payload;
526   int *counter;
527
528   GNUNET_CADET_receive_done (channel);
529   counter = get_target_channel () == channel ? &data_received : &ack_received;
530   if (channel == outgoing_ch)
531   {
532     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
533                 "Root client got a message.\n");
534   }
535   else if (channel == incoming_ch)
536   {
537     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
538                 "Leaf client got a message.\n");
539   }
540   else
541   {
542     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
543                 "Unknown channel %p.\n",
544                 channel);
545     GNUNET_assert (0);
546   }
547
548   data = (uint32_t *) &message[1];
549   payload = ntohl (*data);
550   if (payload == *counter)
551   {
552     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
553                 "Payload as expected: %u\n",
554                 payload);
555   }
556   else
557   {
558     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
559                 "Received payload %u, expected: %u\n",
560                 payload, *counter);
561   }
562   (*counter)++;
563   if (get_target_channel () == channel) /* Got "data" */
564   {
565     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
566                 " received data %u\n",
567                 data_received);
568     if (data_received < total_packets)
569       return;
570   }
571   else /* Got "ack" */
572   {
573     if (SPEED_ACK == test || SPEED == test)
574     {
575       GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received ack %u\n", ack_received);
576       /* Send more data */
577       send_test_message (channel);
578       if (ack_received < total_packets && SPEED != test)
579         return;
580       if (ok == 2 && SPEED == test)
581         return;
582       show_end_data ();
583     }
584     if (test == P2P_SIGNAL)
585     {
586       GNUNET_CADET_channel_destroy (incoming_ch);
587       incoming_ch = NULL;
588     }
589     else
590     {
591       GNUNET_CADET_channel_destroy (outgoing_ch);
592       outgoing_ch = NULL;
593     }
594   }
595 }
596
597
598 /**
599  * Method called whenever a peer connects to a port in MQ-based CADET.
600  *
601  * @param cls Closure from #GNUNET_CADET_open_port (peer # as long).
602  * @param channel New handle to the channel.
603  * @param source Peer that started this channel.
604  * @return Closure for the incoming @a channel. It's given to:
605  *         - The #GNUNET_CADET_DisconnectEventHandler (given to
606  *           #GNUNET_CADET_open_port) when the channel dies.
607  *         - Each the #GNUNET_MQ_MessageCallback handlers for each message
608  *           received on the @a channel.
609  */
610 static void *
611 connect_handler (void *cls,
612                  struct GNUNET_CADET_Channel *channel,
613                  const struct GNUNET_PeerIdentity *source)
614 {
615   struct CadetTestChannelWrapper *ch;
616   long peer = (long) cls;
617
618   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
619               "Incoming channel from %s to %ld: %p\n",
620               GNUNET_i2s (source),
621               peer,
622               channel);
623   if (peer == peers_requested - 1)
624   {
625     if (NULL != incoming_ch)
626     {
627       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
628                   "Duplicate incoming channel for client %lu\n",
629                   (long) cls);
630       GNUNET_assert (0);
631     }
632     incoming_ch = channel;
633   }
634   else
635   {
636     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
637                 "Incoming channel for unexpected peer #%lu\n",
638                 (long) cls);
639     GNUNET_assert (0);
640   }
641   ch = GNUNET_new (struct CadetTestChannelWrapper);
642   ch->ch = channel;
643
644   return ch;
645 }
646
647
648 /**
649  * Function called whenever an MQ-channel is destroyed, even if the destruction
650  * was requested by #GNUNET_CADET_channel_destroy.
651  * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
652  *
653  * It should clean up any associated state, including cancelling any pending
654  * transmission on this channel.
655  *
656  * @param cls Channel closure (channel wrapper).
657  * @param channel Connection to the other end (henceforth invalid).
658  */
659 static void
660 disconnect_handler (void *cls,
661                     const struct GNUNET_CADET_Channel *channel)
662 {
663   struct CadetTestChannelWrapper *ch_w = cls;
664
665   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
666               "Channel disconnected at %d\n",
667               ok);
668   GNUNET_assert (ch_w->ch == channel);
669   if (channel == incoming_ch)
670     incoming_ch = NULL;
671   else if (outgoing_ch == channel)
672     outgoing_ch = NULL;
673   else
674     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
675                 "Disconnect on unknown channel %p\n",
676                 channel);
677   if (NULL != disconnect_task)
678     GNUNET_SCHEDULER_cancel (disconnect_task);
679   disconnect_task = GNUNET_SCHEDULER_add_now (&gather_stats_and_exit,
680                                               (void *) __LINE__);
681   GNUNET_free (ch_w);
682 }
683
684
685 /**
686  * Start the testcase, we know the peers and have handles to CADET.
687  *
688  * Testcase continues when the root receives confirmation of connected peers,
689  * on callback function ch.
690  *
691  * @param cls Closure (unused).
692  */
693 static void
694 start_test (void *cls)
695 {
696   struct GNUNET_MQ_MessageHandler handlers[] = {
697     GNUNET_MQ_hd_var_size (data,
698                            GNUNET_MESSAGE_TYPE_DUMMY,
699                            struct GNUNET_MessageHeader,
700                            NULL),
701     GNUNET_MQ_handler_end ()
702   };
703   struct CadetTestChannelWrapper *ch;
704   enum GNUNET_CADET_ChannelOption flags;
705
706   test_task = NULL;
707   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
708               "In start_test\n");
709   start_time = GNUNET_TIME_absolute_get ();
710   ch = GNUNET_new (struct CadetTestChannelWrapper);
711   outgoing_ch = GNUNET_CADET_channel_create (h1,
712                                              ch,
713                                              p_id[1],
714                                              &port,
715                                              flags,
716                                              NULL,
717                                              &disconnect_handler,
718                                              handlers);
719   ch->ch = outgoing_ch;
720   GNUNET_assert (NULL == disconnect_task);
721   disconnect_task
722     = GNUNET_SCHEDULER_add_delayed (short_time,
723                                     &gather_stats_and_exit,
724                                     (void *) __LINE__);
725   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
726               "Sending data initializer on channel %p...\n",
727               outgoing_ch);
728   send_test_message (outgoing_ch);
729 }
730
731
732 /**
733  * Callback to be called when the requested peer information is available
734  *
735  * @param cls the closure from GNUNET_TESTBED_peer_get_information()
736  * @param op the operation this callback corresponds to
737  * @param pinfo the result; will be NULL if the operation has failed
738  * @param emsg error message if the operation has failed;
739  *             NULL if the operation is successfull
740  */
741 static void
742 pi_cb (void *cls,
743        struct GNUNET_TESTBED_Operation *op,
744        const struct GNUNET_TESTBED_PeerInformation *pinfo,
745        const char *emsg)
746 {
747   long i = (long) cls;
748
749   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
750               "ID callback for %ld\n",
751               i);
752   if ( (NULL == pinfo) ||
753        (NULL != emsg) )
754   {
755     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
756                 "pi_cb: %s\n",
757                 emsg);
758     abort_test (__LINE__);
759     return;
760   }
761   p_id[i] = pinfo->result.id;
762   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
763               "id: %s\n",
764               GNUNET_i2s (p_id[i]));
765   p_ids++;
766   if (p_ids < 2)
767     return;
768   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
769               "Got all IDs, starting test\n");
770   test_task = GNUNET_SCHEDULER_add_now (&start_test,
771                                         NULL);
772 }
773
774
775 /**
776  * test main: start test when all peers are connected
777  *
778  * @param cls Closure.
779  * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end.
780  * @param num_peers Number of peers that are running.
781  * @param peers Array of peers.
782  * @param cadets Handle to each of the CADETs of the peers.
783  */
784 static void
785 tmain (void *cls,
786        struct GNUNET_CADET_TEST_Context *ctx,
787        unsigned int num_peers,
788        struct GNUNET_TESTBED_Peer **peers,
789        struct GNUNET_CADET_Handle **cadets)
790 {
791   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
792               "test main\n");
793   test_ctx = ctx;
794   peers_running = num_peers;
795   GNUNET_assert (peers_running == peers_requested);
796   testbed_peers = peers;
797   h1 = cadets[0];
798   h2 = cadets[num_peers - 1];
799   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
800                                  NULL);
801   p_ids = 0;
802   t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0],
803                                                  GNUNET_TESTBED_PIT_IDENTITY,
804                                                  &pi_cb,
805                                                  (void *) 0L);
806   t_op[1] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 1],
807                                                  GNUNET_TESTBED_PIT_IDENTITY,
808                                                  &pi_cb,
809                                                  (void *) 1L);
810   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
811               "requested peer ids\n");
812 }
813
814
815 /**
816  * Main: start test
817  */
818 int
819 main (int argc,
820       char *argv[])
821 {
822   static const struct GNUNET_HashCode *ports[2];
823   struct GNUNET_MQ_MessageHandler handlers[] = {
824     GNUNET_MQ_hd_var_size (data,
825                            GNUNET_MESSAGE_TYPE_DUMMY,
826                            struct GNUNET_MessageHeader,
827                            NULL),
828     GNUNET_MQ_handler_end ()
829   };
830   const char *config_file = "test_cadet.conf";
831   char port_id[] = "test port";
832   struct GNUNET_GETOPT_CommandLineOption options[] = {
833     GNUNET_GETOPT_option_relative_time ('t',
834                                         "time",
835                                         "short_time",
836                                         gettext_noop ("set short timeout"),
837                                         &short_time),
838     GNUNET_GETOPT_option_uint ('m',
839                                "messages",
840                                "NUM_MESSAGES",
841                                gettext_noop ("set number of messages to send"),
842                                &total_packets),
843     GNUNET_GETOPT_option_uint ('p',
844                                "peers",
845                                "NUM_PEERS",
846                                gettext_noop ("number of peers to launch"),
847                                &peers_requested),
848     GNUNET_GETOPT_OPTION_END
849   };
850
851   GNUNET_log_setup ("test-cadet-flow",
852                     "DEBUG",
853                     NULL);
854   total_packets = TOTAL_PACKETS;
855   short_time = SHORT_TIME;
856   if (-1 == GNUNET_GETOPT_run (argv[0],
857                                options,
858                                argc,
859                                argv))
860   {
861     FPRINTF (stderr,
862              "test failed: problem with CLI parameters\n");
863     return 1;
864   }
865   GNUNET_CRYPTO_hash (port_id,
866                       sizeof (port_id),
867                       &port);
868   ports[0] = &port;
869   ports[1] = NULL;
870   GNUNET_CADET_TEST_ruN ("test_cadet_flow",
871                          config_file,
872                          peers_requested,
873                          &tmain,
874                          NULL,        /* tmain cls */
875                          &connect_handler,
876                          NULL,
877                          &disconnect_handler,
878                          handlers,
879                          ports);
880   return 0;
881 }
882
883 /* end of test_cadet_flow.c */