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