2 This file is part of GNUnet.
3 (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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, 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);
337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
340 delayed_end_task = NULL;
341 FPRINTF (stderr, "\n");
342 if (p1_switch_attempts > 0)
345 "Peer 1 tried %u times to switch and succeeded %u times, failed %u times\n",
349 if (p1_switch_success != p1_switch_attempts)
355 else if (p1_addresses_avail > 1)
358 "Peer 1 had %u addresses available, but did not try to switch\n",
361 if (p2_switch_attempts > 0)
364 "Peer 2 tried %u times to switch and succeeded %u times, failed %u times\n",
368 if (p2_switch_success != p2_switch_attempts)
374 else if (p2_addresses_avail > 1)
377 "Peer 2 had %u addresses available, but did not try to switch\n",
381 if ( ((p1_switch_attempts > 0) || (p2_switch_attempts > 0)) &&
382 (bytes_sent_after_switch == 0) )
384 FPRINTF (stderr, "No data sent after switching!\n");
388 if ( ((p1_switch_attempts > 0) || (p2_switch_attempts > 0)) &&
389 (bytes_recv_after_switch == 0) )
391 FPRINTF (stderr, "No data received after switching!\n");
406 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
407 "Fail (timeout)! Stopping peers\n");
408 if (test_connected == GNUNET_YES)
409 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
410 "Peers got connected\n");
412 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
413 "Peers got NOT EVEN connected\n");
420 notify_receive (void *cls,
421 const struct GNUNET_PeerIdentity *peer,
422 const struct GNUNET_MessageHeader *message)
424 const struct TestMessage *hdr;
426 hdr = (const struct TestMessage *) message;
427 if (MTYPE != ntohs (message->type))
430 struct PeerContext *p = cls;
431 char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
433 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
434 "Peer %u (`%s') got message %u of size %u from peer (`%s')\n", p->no, ps,
436 ntohs (message->size),
438 if ( ((p1_switch_attempts >= 1) || (p2_switch_attempts >= 1)) &&
439 (p1_switch_attempts == p1_switch_fail + p1_switch_success) &&
440 (p2_switch_attempts == p2_switch_fail + p2_switch_success) )
442 bytes_recv_after_switch += ntohs(hdr->header.size);
443 if ((bytes_sent_after_switch > 0) && (bytes_recv_after_switch > 0))
445 /* A peer switched addresses and sent and received data after the
446 * switch operations */
456 notify_ready (void *cls, size_t size, void *buf)
458 static uint32_t counter;
460 struct TestMessage hdr;
465 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
466 "Timeout occurred while waiting for transmit_ready for message\n");
467 if (NULL != die_task)
468 GNUNET_SCHEDULER_cancel (die_task);
469 die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
474 GNUNET_assert(size >= MSIZE);
475 GNUNET_assert(buf != NULL);
478 hdr.header.size = htons (MSIZE);
479 hdr.header.type = htons (MTYPE);
480 hdr.num = htonl (counter++);
481 memcpy (&cbuf[0], &hdr, sizeof(struct TestMessage));
482 memset (&cbuf[sizeof(struct TestMessage)], '0', MSIZE - sizeof(struct TestMessage));
484 char *receiver_s = GNUNET_strdup (GNUNET_i2s (&receiver->id));
485 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
486 "Sending message %u of size %u from peer %u (`%4s') -> peer %u (`%s') !\n",
487 (unsigned int) (counter - 1),
490 GNUNET_i2s (&sender->id),
493 GNUNET_free(receiver_s);
496 th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th,
500 ¬ify_ready, NULL);
502 if ( ((p1_switch_attempts >= 1) || (p2_switch_attempts >= 1)) &&
503 (p1_switch_attempts == p1_switch_fail + p1_switch_success) &&
504 (p2_switch_attempts == p2_switch_fail + p2_switch_success) )
506 bytes_sent_after_switch += MSIZE;
513 notify_connect (void *cls,
514 const struct GNUNET_PeerIdentity *peer)
516 struct PeerContext *p = cls;
518 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
519 "Peer %u (`%4s') connected to us!\n",
526 notify_disconnect (void *cls,
527 const struct GNUNET_PeerIdentity *peer)
529 struct PeerContext *p = cls;
533 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
534 "Peer %u (`%4s') disconnected early!\n",
537 GNUNET_SCHEDULER_shutdown ();
541 GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
550 /* Transmit test messages */
551 th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th,
554 ¬ify_ready, NULL);
559 progress_indicator (void *cls,
560 const struct GNUNET_SCHEDULER_TaskContext *tc)
566 if ((DURATION.rel_value_us / 1000 / 1000LL) < counter)
568 FPRINTF (stderr, "%s", ".\n");
572 FPRINTF (stderr, "%s", ".");
573 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
574 &progress_indicator, NULL);
580 testing_connect_cb (struct PeerContext *p1,
581 struct PeerContext *p2,
584 char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
586 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
587 "Peers connected: %u (%s) <-> %u (%s)\n",
588 p1->no, p1_c, p2->no,
589 GNUNET_i2s (&p2->id));
593 test_connected = GNUNET_YES;
595 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
596 "(i:s/+/-) \t i == peer 1/2, s/+/- : switch attempt/switch ok/switch fail\n");
599 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
602 /* Peers are connected, start transmit test messages */
603 GNUNET_SCHEDULER_add_now (&sendtask, NULL);
608 start_cb (struct PeerContext *p, void *cls)
613 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
614 "Peer %u (`%s') started\n",
616 GNUNET_i2s (&p->id));
620 test_connected = GNUNET_NO;
624 char *sender_c = GNUNET_strdup (GNUNET_i2s (&sender->id));
625 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
626 "Test tries to send from %u (%s) -> peer %u (%s)\n",
630 GNUNET_i2s (&receiver->id));
631 GNUNET_free (sender_c);
633 /* Connect the peers */
634 cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2,
644 const struct GNUNET_CONFIGURATION_Handle *cfg)
646 die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
648 p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1,
649 ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL);
651 p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2,
652 ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL);
654 if ((p1 == NULL )|| (p2 == NULL))
656 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
657 GNUNET_SCHEDULER_shutdown ();
661 /* Start to watch statistics for peer 1 */
662 p1_stat = GNUNET_STATISTICS_create ("transport", p1->cfg);
663 GNUNET_STATISTICS_watch (p1_stat, "transport",
664 "# Attempts to switch addresses",
665 stat_start_attempt_cb, p1);
666 GNUNET_STATISTICS_watch (p1_stat, "transport",
667 "# Successful attempts to switch addresses",
668 stat_success_attempt_cb, p1);
669 GNUNET_STATISTICS_watch (p1_stat, "transport",
670 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
671 stat_fail_attempt_cb, p1);
672 GNUNET_STATISTICS_watch (p1_stat, "transport",
673 "# Failed attempts to switch addresses (failed to send CONNECT)",
674 stat_fail_attempt_cb, p1);
675 GNUNET_STATISTICS_watch (p1_stat, "transport",
676 "# Failed attempts to switch addresses (no response)",
677 stat_fail_attempt_cb, p1);
678 GNUNET_STATISTICS_watch (p1_stat, "transport",
679 "# transport addresses",
680 stat_addresses_available, p1);
682 /* Start to watch statistics for peer 2 */
683 p2_stat = GNUNET_STATISTICS_create ("transport", p2->cfg);
684 GNUNET_STATISTICS_watch (p2_stat, "transport",
685 "# Attempts to switch addresses",
686 stat_start_attempt_cb, p2);
687 GNUNET_STATISTICS_watch (p2_stat, "transport",
688 "# Successful attempts to switch addresses",
689 stat_success_attempt_cb, p2);
690 GNUNET_STATISTICS_watch (p2_stat, "transport",
691 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
692 stat_fail_attempt_cb, p2);
693 GNUNET_STATISTICS_watch (p2_stat, "transport",
694 "# Failed attempts to switch addresses (failed to send CONNECT)",
695 stat_fail_attempt_cb, p2);
696 GNUNET_STATISTICS_watch (p2_stat, "transport",
697 "# Failed attempts to switch addresses (no response)",
698 stat_fail_attempt_cb, p2);
699 GNUNET_STATISTICS_watch (p2_stat, "transport",
700 "# transport addresses",
701 stat_addresses_available, p2);
703 if ((p1_stat == NULL )|| (p2_stat == NULL))
705 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
706 "Fail! Could not create statistics for peers!\n");
707 GNUNET_SCHEDULER_shutdown ();
713 main (int argc, char *argv[])
719 static char *argv_new[] = { "test-transport-address-switch", "-c",
720 "test_transport_startonly.conf", NULL };
722 static struct GNUNET_GETOPT_CommandLineOption options[] = {
723 GNUNET_GETOPT_OPTION_END };
725 GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name);
727 GNUNET_log_setup (test_name, "WARNING", NULL );
729 GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source);
730 GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source,
733 tth = GNUNET_TRANSPORT_TESTING_init ();
735 GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1);
736 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Using cfg [%u] : %s \n", 1, cfg_file_p1);
737 GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2);
738 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Using cfg [%u] : %s \n", 2, cfg_file_p2);
740 GNUNET_PROGRAM_run ((sizeof(argv_new) / sizeof(char *)) - 1, argv_new,
741 test_name, "nohelp", options, &run, NULL );
743 GNUNET_free(cfg_file_p1);
744 GNUNET_free(cfg_file_p2);
746 GNUNET_free(test_source);
747 GNUNET_free(test_plugin);
748 GNUNET_free(test_name);
750 GNUNET_TRANSPORT_TESTING_done (tth);
755 /* end of test_transport_address_switch.c */