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)
79 #define DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
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;
144 * END Testcase specific declarations
148 #define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
150 #define OKPP do { ok++; } while (0)
157 stat_start_attempt_cb (void *cls,
158 const char *subsystem,
165 p1_switch_attempts++;
166 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "(1:s)");
170 p2_switch_attempts++;
171 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "(2:s)");
174 bytes_recv_after_switch = 0;
175 bytes_sent_after_switch = 0;
182 stat_success_attempt_cb (void *cls,
183 const char *subsystem,
191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "(1:+)");
196 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "(2:+)");
204 stat_fail_attempt_cb (void *cls,
205 const char *subsystem,
216 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "(1:-)");
221 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "(2:-)");
229 stat_addresses_available (void *cls,
230 const char *subsystem,
237 p1_addresses_avail++;
241 p2_addresses_avail++;
250 if (measure_task != NULL)
252 GNUNET_SCHEDULER_cancel (measure_task);
256 if (delayed_end_task != NULL)
258 GNUNET_SCHEDULER_cancel (delayed_end_task);
259 delayed_end_task = NULL;
262 if (die_task != NULL)
264 GNUNET_SCHEDULER_cancel (die_task);
270 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
271 "# Attempts to switch addresses",
272 stat_start_attempt_cb, p1);
273 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
274 "# Successful attempts to switch addresses",
275 stat_success_attempt_cb, p1);
276 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
277 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
278 stat_fail_attempt_cb, p1);
279 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
280 "# Failed attempts to switch addresses (failed to send CONNECT)",
281 stat_fail_attempt_cb, p1);
282 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
283 "# Failed attempts to switch addresses (no response)",
284 stat_fail_attempt_cb, p1);
285 GNUNET_STATISTICS_watch (p1_stat, "transport",
286 "# transport addresses",
287 stat_addresses_available, p1);
288 GNUNET_STATISTICS_destroy (p1_stat, GNUNET_NO);
293 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
294 "# Attempts to switch addresses", stat_start_attempt_cb, p2);
295 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
296 "# Successful attempts to switch addresses", stat_success_attempt_cb, p2);
297 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
298 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
299 stat_fail_attempt_cb, p2);
300 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
301 "# Failed attempts to switch addresses (failed to send CONNECT)",
302 stat_fail_attempt_cb, p2);
303 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
304 "# Failed attempts to switch addresses (no response)",
305 stat_fail_attempt_cb, p2);
306 GNUNET_STATISTICS_watch (p2_stat, "transport",
307 "# transport addresses",
308 stat_addresses_available, p2);
309 GNUNET_STATISTICS_destroy (p2_stat, GNUNET_NO);
315 GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
320 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
325 GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
330 GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
342 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
345 delayed_end_task = NULL;
346 FPRINTF (stderr, "\n");
347 if (p1_switch_attempts > 0)
349 FPRINTF (stderr, "Peer 1 tried %u times to switch and succeeded %u times, failed %u times\n",
350 p1_switch_attempts, p1_switch_success, p1_switch_fail);
351 if (p1_switch_success != p1_switch_attempts)
357 else if (p1_addresses_avail > 1)
359 FPRINTF (stderr, "Peer 1 had %u addresses available, but did not try to switch\n",
362 if (p2_switch_attempts > 0)
364 FPRINTF (stderr, "Peer 2 tried %u times to switch and succeeded %u times, failed %u times\n",
365 p2_switch_attempts, p2_switch_success, p2_switch_fail);
366 if (p2_switch_success != p2_switch_attempts)
372 else if (p2_addresses_avail > 1)
374 FPRINTF (stderr, "Peer 2 had %u addresses available, but did not try to switch\n",
378 if ( ((p1_switch_attempts > 0) || (p2_switch_attempts > 0)) &&
379 (bytes_sent_after_switch == 0) )
381 FPRINTF (stderr, "No data sent after switching!\n");
385 if ( ((p1_switch_attempts > 0) || (p2_switch_attempts > 0)) &&
386 (bytes_recv_after_switch == 0) )
388 FPRINTF (stderr, "No data received after switching!\n");
403 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
404 "Fail! Stopping peers\n");
406 if (test_connected == GNUNET_YES)
407 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
408 "Peers got connected\n");
410 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
411 "Peers got NOT connected\n");
418 notify_receive (void *cls,
419 const struct GNUNET_PeerIdentity *peer,
420 const struct GNUNET_MessageHeader *message)
422 const struct TestMessage *hdr;
424 hdr = (const struct TestMessage *) message;
425 if (MTYPE != ntohs (message->type))
428 struct PeerContext *p = cls;
429 char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
431 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
432 "Peer %u (`%s') got message %u of size %u from peer (`%s')\n", p->no, ps,
434 ntohs (message->size),
436 if ( ((p1_switch_attempts >= 1) || (p2_switch_attempts >= 1)) &&
437 (p1_switch_attempts == p1_switch_fail + p1_switch_success) &&
438 (p2_switch_attempts == p2_switch_fail + p2_switch_success) )
440 bytes_recv_after_switch += ntohs(hdr->header.size);
441 if ((bytes_sent_after_switch > 0) && (bytes_recv_after_switch > 0))
443 /* A peer switched addresses and sent and received data after the
444 * switch operations */
454 notify_ready (void *cls, size_t size, void *buf)
456 static uint32_t counter;
458 struct TestMessage hdr;
463 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
464 "Timeout occurred while waiting for transmit_ready for message\n");
465 if (NULL != die_task)
466 GNUNET_SCHEDULER_cancel (die_task);
467 die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL );
472 GNUNET_assert(size >= MSIZE);
473 GNUNET_assert(buf != NULL);
476 hdr.header.size = htons (MSIZE);
477 hdr.header.type = htons (MTYPE);
478 hdr.num = htonl (counter++);
479 memcpy (&cbuf[0], &hdr, sizeof(struct TestMessage));
480 memset (&cbuf[sizeof(struct TestMessage)], '0', MSIZE - sizeof(struct TestMessage));
483 char *receiver_s = GNUNET_strdup (GNUNET_i2s (&receiver->id));
484 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
485 "Sending message %u of size %u from peer %u (`%4s') -> peer %u (`%s') !\n",
486 (unsigned int) (counter - 1),
489 GNUNET_i2s (&sender->id),
492 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, const struct GNUNET_PeerIdentity *peer)
515 struct PeerContext *p = cls;
516 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
517 "Peer %u (`%4s') connected to us!\n",
524 notify_disconnect (void *cls,
525 const struct GNUNET_PeerIdentity *peer)
527 struct PeerContext *p = cls;
529 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
530 "Peer %u (`%4s') disconnected!\n",
534 GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
543 /* Transmit test messages */
544 th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th,
547 ¬ify_ready, NULL);
552 progress_indicator (void *cls,
553 const struct GNUNET_SCHEDULER_TaskContext *tc)
559 if ((DURATION.rel_value_us / 1000 / 1000LL) < counter)
561 FPRINTF (stderr, "%s", ".\n");
565 FPRINTF (stderr, "%s", ".");
566 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
567 &progress_indicator, NULL);
573 testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
575 char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
577 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
578 "Peers connected: %u (%s) <-> %u (%s)\n",
579 p1->no, p1_c, p2->no,
580 GNUNET_i2s (&p2->id));
584 test_connected = GNUNET_YES;
586 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
587 "(i:s/+/-) \t i == peer 1/2, s/+/- : switch attempt/switch ok/switch fail\n");
590 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
593 /* Peers are connected, start transmit test messages */
594 GNUNET_SCHEDULER_add_now (&sendtask, NULL);
599 start_cb (struct PeerContext *p, void *cls)
604 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
605 "Peer %u (`%s') started\n",
607 GNUNET_i2s (&p->id));
611 test_connected = GNUNET_NO;
615 char *sender_c = GNUNET_strdup (GNUNET_i2s (&sender->id));
616 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
617 "Test tries to send from %u (%s) -> peer %u (%s)\n",
618 sender->no, sender_c,
619 receiver->no, GNUNET_i2s (&receiver->id));
620 GNUNET_free (sender_c);
622 /* Connect the peers */
623 cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2,
633 const struct GNUNET_CONFIGURATION_Handle *cfg)
635 die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL );
637 p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1,
638 ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL );
640 p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2,
641 ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL );
643 if ((p1 == NULL )|| (p2 == NULL))
645 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
646 if (die_task != NULL)
647 GNUNET_SCHEDULER_cancel (die_task);
648 die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
652 /* Start to watch statistics for peer 1 */
653 p1_stat = GNUNET_STATISTICS_create ("transport", p1->cfg);
654 GNUNET_STATISTICS_watch (p1_stat, "transport",
655 "# Attempts to switch addresses",
656 stat_start_attempt_cb, p1);
657 GNUNET_STATISTICS_watch (p1_stat, "transport",
658 "# Successful attempts to switch addresses",
659 stat_success_attempt_cb, p1);
660 GNUNET_STATISTICS_watch (p1_stat, "transport",
661 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
662 stat_fail_attempt_cb, p1);
663 GNUNET_STATISTICS_watch (p1_stat, "transport",
664 "# Failed attempts to switch addresses (failed to send CONNECT)",
665 stat_fail_attempt_cb, p1);
666 GNUNET_STATISTICS_watch (p1_stat, "transport",
667 "# Failed attempts to switch addresses (no response)",
668 stat_fail_attempt_cb, p1);
669 GNUNET_STATISTICS_watch (p1_stat, "transport",
670 "# transport addresses",
671 stat_addresses_available, p1);
673 /* Start to watch statistics for peer 2 */
674 p2_stat = GNUNET_STATISTICS_create ("transport", p2->cfg);
675 GNUNET_STATISTICS_watch (p2_stat, "transport",
676 "# Attempts to switch addresses",
677 stat_start_attempt_cb, p2);
678 GNUNET_STATISTICS_watch (p2_stat, "transport",
679 "# Successful attempts to switch addresses",
680 stat_success_attempt_cb, p2);
681 GNUNET_STATISTICS_watch (p2_stat, "transport",
682 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
683 stat_fail_attempt_cb, p2);
684 GNUNET_STATISTICS_watch (p2_stat, "transport",
685 "# Failed attempts to switch addresses (failed to send CONNECT)",
686 stat_fail_attempt_cb, p2);
687 GNUNET_STATISTICS_watch (p2_stat, "transport",
688 "# Failed attempts to switch addresses (no response)",
689 stat_fail_attempt_cb, p2);
690 GNUNET_STATISTICS_watch (p2_stat, "transport",
691 "# transport addresses",
692 stat_addresses_available, p2);
694 if ((p1_stat == NULL )|| (p2_stat == NULL))
696 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not create statistics for peers!\n");
697 if (die_task != NULL)
698 GNUNET_SCHEDULER_cancel (die_task);
699 die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
705 main (int argc, char *argv[])
711 static char *argv_new[] = { "test-transport-address-switch", "-c",
712 "test_transport_startonly.conf", NULL };
714 static struct GNUNET_GETOPT_CommandLineOption options[] = {
715 GNUNET_GETOPT_OPTION_END };
717 GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name);
719 GNUNET_log_setup (test_name, "WARNING", NULL );
721 GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source);
722 GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source,
725 tth = GNUNET_TRANSPORT_TESTING_init ();
727 GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1);
728 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Using cfg [%u] : %s \n", 1, cfg_file_p1);
729 GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2);
730 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Using cfg [%u] : %s \n", 2, cfg_file_p2);
732 GNUNET_PROGRAM_run ((sizeof(argv_new) / sizeof(char *)) - 1, argv_new,
733 test_name, "nohelp", options, &run, NULL );
735 GNUNET_free(cfg_file_p1);
736 GNUNET_free(cfg_file_p2);
738 GNUNET_free(test_source);
739 GNUNET_free(test_plugin);
740 GNUNET_free(test_name);
742 GNUNET_TRANSPORT_TESTING_done (tth);
747 /* end of test_transport_address_switch.c */