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