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