2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
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.
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.
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.
21 * @file transport/test_transport_address_switch.c
22 * @brief base test case for transport implementations
24 * This test case tests if peers can successfully switch addresses when
25 * connected for plugins supporting multiple addresses by monitoring transport's
28 * This test starts 2 peers and connects them. When connected test messages
29 * are transmitted from peer 2 to peer 1. The test monitors transport's
30 * statistics values for information about address switch attempts.
32 * The test passes with success if one of the peers could successfully switch
33 * addresses in connected state and a test message was successfully transmitted
36 * Since it is not possible to trigger an address switch from
37 * outside, the test still passes when no address switching attempt takes
38 * place. It fails if an address switch attempt fails.
41 #include "gnunet_transport_service.h"
42 #include "gnunet_ats_service.h"
44 #include "transport-testing.h"
47 * Testcase specific declarations
50 GNUNET_NETWORK_STRUCT_BEGIN
53 struct GNUNET_MessageHeader header;
54 uint32_t num GNUNET_PACKED;
56 GNUNET_NETWORK_STRUCT_END
59 * Message type for test messages
64 * Message size for test messages
71 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
74 * How long until we give up on transmitting the message?
76 #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
78 #define DURATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
82 * Timeout task to send messages
84 static struct GNUNET_SCHEDULER_Task *die_task;
87 static struct GNUNET_SCHEDULER_Task *delayed_end_task;
90 * Measurement task to send messages
92 static struct GNUNET_SCHEDULER_Task *measure_task;
95 static struct PeerContext *p1;
96 static char *cfg_file_p1;
97 static struct GNUNET_STATISTICS_Handle *p1_stat;
99 static struct PeerContext *p2;
100 static char *cfg_file_p2;
101 static struct GNUNET_STATISTICS_Handle *p2_stat;
103 static struct PeerContext *sender;
105 static struct PeerContext *receiver;
107 static struct GNUNET_TRANSPORT_TransmitHandle *th;
109 static struct GNUNET_TRANSPORT_TESTING_handle *tth;
111 static GNUNET_TRANSPORT_TESTING_ConnectRequest cc;
113 static int test_connected;
119 * Statistics about peer 1
121 static unsigned int p1_addresses_avail;
122 static unsigned int p1_switch_attempts;
123 static unsigned int p1_switch_success;
124 static unsigned int p1_switch_fail;
128 * Statistics about peer 2
130 static unsigned int p2_switch_attempts;
131 static unsigned int p2_switch_success;
132 static unsigned int p2_switch_fail;
133 static unsigned int p2_addresses_avail;
136 * Transmission statistics
139 /* Amount of data transfered since last switch attempt */
140 static unsigned long long bytes_sent_after_switch;
141 static unsigned long long bytes_recv_after_switch;
145 #define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
147 #define OKPP do { ok++; } while (0)
152 stat_start_attempt_cb (void *cls,
153 const char *subsystem,
160 p1_switch_attempts++;
161 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "(1:s)");
165 p2_switch_attempts++;
166 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "(2:s)");
169 bytes_recv_after_switch = 0;
170 bytes_sent_after_switch = 0;
177 stat_success_attempt_cb (void *cls,
178 const char *subsystem,
186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "(1:+)");
191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "(2:+)");
199 stat_fail_attempt_cb (void *cls,
200 const char *subsystem,
211 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "(1:-)");
216 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "(2:-)");
224 stat_addresses_available (void *cls,
225 const char *subsystem,
232 p1_addresses_avail++;
236 p2_addresses_avail++;
245 if (measure_task != NULL)
247 GNUNET_SCHEDULER_cancel (measure_task);
251 if (delayed_end_task != NULL)
253 GNUNET_SCHEDULER_cancel (delayed_end_task);
254 delayed_end_task = NULL;
257 if (die_task != NULL)
259 GNUNET_SCHEDULER_cancel (die_task);
265 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
266 "# Attempts to switch addresses",
267 stat_start_attempt_cb, p1);
268 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
269 "# Successful attempts to switch addresses",
270 stat_success_attempt_cb, p1);
271 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
272 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
273 stat_fail_attempt_cb, p1);
274 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
275 "# Failed attempts to switch addresses (failed to send CONNECT)",
276 stat_fail_attempt_cb, p1);
277 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
278 "# Failed attempts to switch addresses (no response)",
279 stat_fail_attempt_cb, p1);
280 GNUNET_STATISTICS_watch (p1_stat, "transport",
281 "# transport addresses",
282 stat_addresses_available, p1);
283 GNUNET_STATISTICS_destroy (p1_stat, GNUNET_NO);
288 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
289 "# Attempts to switch addresses", stat_start_attempt_cb, p2);
290 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
291 "# Successful attempts to switch addresses", stat_success_attempt_cb, p2);
292 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
293 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
294 stat_fail_attempt_cb, p2);
295 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
296 "# Failed attempts to switch addresses (failed to send CONNECT)",
297 stat_fail_attempt_cb, p2);
298 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
299 "# Failed attempts to switch addresses (no response)",
300 stat_fail_attempt_cb, p2);
301 GNUNET_STATISTICS_watch (p2_stat, "transport",
302 "# transport addresses",
303 stat_addresses_available, p2);
304 GNUNET_STATISTICS_destroy (p2_stat, GNUNET_NO);
310 GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
315 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
320 GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
325 GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
336 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
339 delayed_end_task = NULL;
340 FPRINTF (stderr, "\n");
341 if (p1_switch_attempts > 0)
344 "Peer 1 tried %u times to switch and succeeded %u times, failed %u times\n",
348 if (p1_switch_success != p1_switch_attempts)
354 else if (p1_addresses_avail > 1)
357 "Peer 1 had %u addresses available, but did not try to switch\n",
360 if (p2_switch_attempts > 0)
363 "Peer 2 tried %u times to switch and succeeded %u times, failed %u times\n",
367 if (p2_switch_success != p2_switch_attempts)
373 else if (p2_addresses_avail > 1)
376 "Peer 2 had %u addresses available, but did not try to switch\n",
380 if ( ((p1_switch_attempts > 0) || (p2_switch_attempts > 0)) &&
381 (bytes_sent_after_switch == 0) )
383 FPRINTF (stderr, "No data sent after switching!\n");
387 if ( ((p1_switch_attempts > 0) || (p2_switch_attempts > 0)) &&
388 (bytes_recv_after_switch == 0) )
390 FPRINTF (stderr, "No data received after switching!\n");
406 if (0 == p1_switch_attempts + p2_switch_attempts)
408 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
409 "Test did not work, as peers didn't switch (flawed testcase)!\n");
414 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
415 "Fail (timeout)! No transmission after switch! Stopping peers\n");
418 if (test_connected == GNUNET_YES)
419 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
420 "Peers got connected\n");
422 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
423 "Peers got NOT EVEN connected\n");
428 notify_receive (void *cls,
429 const struct GNUNET_PeerIdentity *peer,
430 const struct GNUNET_MessageHeader *message)
432 const struct TestMessage *hdr;
434 hdr = (const struct TestMessage *) message;
435 if (MTYPE != ntohs (message->type))
438 struct PeerContext *p = cls;
439 char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
441 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
442 "Peer %u (`%s') got message %u of size %u from peer (`%s')\n", p->no, ps,
444 ntohs (message->size),
446 if ( ((p1_switch_attempts >= 1) || (p2_switch_attempts >= 1)) &&
447 (p1_switch_attempts == p1_switch_fail + p1_switch_success) &&
448 (p2_switch_attempts == p2_switch_fail + p2_switch_success) )
450 bytes_recv_after_switch += ntohs(hdr->header.size);
451 if ((bytes_sent_after_switch > 0) && (bytes_recv_after_switch > 0))
453 /* A peer switched addresses and sent and received data after the
454 * switch operations */
464 notify_ready (void *cls, size_t size, void *buf)
466 static uint32_t counter;
468 struct TestMessage hdr;
473 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
474 "Timeout occurred while waiting for transmit_ready for message\n");
475 if (NULL != die_task)
476 GNUNET_SCHEDULER_cancel (die_task);
477 die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
482 GNUNET_assert(size >= MSIZE);
483 GNUNET_assert(buf != NULL);
486 hdr.header.size = htons (MSIZE);
487 hdr.header.type = htons (MTYPE);
488 hdr.num = htonl (counter++);
489 memcpy (&cbuf[0], &hdr, sizeof(struct TestMessage));
490 memset (&cbuf[sizeof(struct TestMessage)], '0', MSIZE - sizeof(struct TestMessage));
492 char *receiver_s = GNUNET_strdup (GNUNET_i2s (&receiver->id));
493 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
494 "Sending message %u of size %u from peer %u (`%4s') -> peer %u (`%s') !\n",
495 (unsigned int) (counter - 1),
498 GNUNET_i2s (&sender->id),
501 GNUNET_free(receiver_s);
504 th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th,
508 ¬ify_ready, NULL);
510 if ( ((p1_switch_attempts >= 1) || (p2_switch_attempts >= 1)) &&
511 (p1_switch_attempts == p1_switch_fail + p1_switch_success) &&
512 (p2_switch_attempts == p2_switch_fail + p2_switch_success) )
514 bytes_sent_after_switch += MSIZE;
521 notify_connect (void *cls,
522 const struct GNUNET_PeerIdentity *peer)
524 struct PeerContext *p = cls;
526 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
527 "Peer %u (`%4s') connected to us!\n",
534 notify_disconnect (void *cls,
535 const struct GNUNET_PeerIdentity *peer)
537 struct PeerContext *p = cls;
541 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
542 "Peer %u (`%4s') disconnected early!\n",
545 GNUNET_SCHEDULER_shutdown ();
549 GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
558 /* Transmit test messages */
559 th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th,
562 ¬ify_ready, NULL);
567 progress_indicator (void *cls,
568 const struct GNUNET_SCHEDULER_TaskContext *tc)
574 if ((DURATION.rel_value_us / 1000 / 1000LL) < counter)
576 FPRINTF (stderr, "%s", ".\n");
580 FPRINTF (stderr, "%s", ".");
581 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
582 &progress_indicator, NULL);
588 testing_connect_cb (struct PeerContext *p1,
589 struct PeerContext *p2,
592 char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
594 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
595 "Peers connected: %u (%s) <-> %u (%s)\n",
596 p1->no, p1_c, p2->no,
597 GNUNET_i2s (&p2->id));
601 test_connected = GNUNET_YES;
603 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
604 "(i:s/+/-) \t i == peer 1/2, s/+/- : switch attempt/switch ok/switch fail\n");
607 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
610 /* Peers are connected, start transmit test messages */
611 GNUNET_SCHEDULER_add_now (&sendtask, NULL);
616 start_cb (struct PeerContext *p, void *cls)
621 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
622 "Peer %u (`%s') started\n",
624 GNUNET_i2s (&p->id));
628 test_connected = GNUNET_NO;
632 char *sender_c = GNUNET_strdup (GNUNET_i2s (&sender->id));
633 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
634 "Test tries to send from %u (%s) -> peer %u (%s)\n",
638 GNUNET_i2s (&receiver->id));
639 GNUNET_free (sender_c);
641 /* Connect the peers */
642 cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2,
652 const struct GNUNET_CONFIGURATION_Handle *cfg)
654 die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
656 p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1,
657 ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL);
659 p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2,
660 ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL);
662 if ((p1 == NULL )|| (p2 == NULL))
664 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
665 GNUNET_SCHEDULER_shutdown ();
669 /* Start to watch statistics for peer 1 */
670 p1_stat = GNUNET_STATISTICS_create ("transport", p1->cfg);
671 GNUNET_STATISTICS_watch (p1_stat, "transport",
672 "# Attempts to switch addresses",
673 stat_start_attempt_cb, p1);
674 GNUNET_STATISTICS_watch (p1_stat, "transport",
675 "# Successful attempts to switch addresses",
676 stat_success_attempt_cb, p1);
677 GNUNET_STATISTICS_watch (p1_stat, "transport",
678 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
679 stat_fail_attempt_cb, p1);
680 GNUNET_STATISTICS_watch (p1_stat, "transport",
681 "# Failed attempts to switch addresses (failed to send CONNECT)",
682 stat_fail_attempt_cb, p1);
683 GNUNET_STATISTICS_watch (p1_stat, "transport",
684 "# Failed attempts to switch addresses (no response)",
685 stat_fail_attempt_cb, p1);
686 GNUNET_STATISTICS_watch (p1_stat, "transport",
687 "# transport addresses",
688 stat_addresses_available, p1);
690 /* Start to watch statistics for peer 2 */
691 p2_stat = GNUNET_STATISTICS_create ("transport", p2->cfg);
692 GNUNET_STATISTICS_watch (p2_stat, "transport",
693 "# Attempts to switch addresses",
694 stat_start_attempt_cb, p2);
695 GNUNET_STATISTICS_watch (p2_stat, "transport",
696 "# Successful attempts to switch addresses",
697 stat_success_attempt_cb, p2);
698 GNUNET_STATISTICS_watch (p2_stat, "transport",
699 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
700 stat_fail_attempt_cb, p2);
701 GNUNET_STATISTICS_watch (p2_stat, "transport",
702 "# Failed attempts to switch addresses (failed to send CONNECT)",
703 stat_fail_attempt_cb, p2);
704 GNUNET_STATISTICS_watch (p2_stat, "transport",
705 "# Failed attempts to switch addresses (no response)",
706 stat_fail_attempt_cb, p2);
707 GNUNET_STATISTICS_watch (p2_stat, "transport",
708 "# transport addresses",
709 stat_addresses_available, p2);
711 if ((p1_stat == NULL )|| (p2_stat == NULL))
713 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
714 "Fail! Could not create statistics for peers!\n");
715 GNUNET_SCHEDULER_shutdown ();
721 main (int argc, char *argv[])
727 static char *argv_new[] = { "test-transport-address-switch", "-c",
728 "test_transport_startonly.conf", NULL };
730 static struct GNUNET_GETOPT_CommandLineOption options[] = {
731 GNUNET_GETOPT_OPTION_END };
733 GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name);
735 GNUNET_log_setup (test_name, "WARNING", NULL );
737 GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source);
738 GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source,
741 tth = GNUNET_TRANSPORT_TESTING_init ();
743 GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1);
744 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Using cfg [%u] : %s \n", 1, cfg_file_p1);
745 GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2);
746 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Using cfg [%u] : %s \n", 2, cfg_file_p2);
748 GNUNET_PROGRAM_run ((sizeof(argv_new) / sizeof(char *)) - 1, argv_new,
749 test_name, "nohelp", options, &run, NULL );
751 GNUNET_free(cfg_file_p1);
752 GNUNET_free(cfg_file_p2);
754 GNUNET_free(test_source);
755 GNUNET_free(test_plugin);
756 GNUNET_free(test_name);
758 GNUNET_TRANSPORT_TESTING_done (tth);
763 /* end of test_transport_address_switch.c */