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 address when connected
28 #include "gnunet_transport_service.h"
29 #include "gnunet_ats_service.h"
31 #include "transport-testing.h"
34 * Testcase specific declarations
37 GNUNET_NETWORK_STRUCT_BEGIN
40 struct GNUNET_MessageHeader header;
43 GNUNET_NETWORK_STRUCT_END
46 * Note that this value must not significantly exceed
47 * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise
48 * messages may be dropped even for a reliable transport.
50 #define TOTAL_MSGS (4096 * 2)
53 * Message type for test messages
60 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
63 * How long until we give up on transmitting the message?
65 #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
67 #define DURATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
68 #define DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
70 static GNUNET_SCHEDULER_TaskIdentifier die_task;
72 static GNUNET_SCHEDULER_TaskIdentifier delayed_end_task;
74 static GNUNET_SCHEDULER_TaskIdentifier measure_task;
76 struct PeerContext *p1;
78 struct GNUNET_STATISTICS_Handle *p1_stat;
80 struct PeerContext *p2;
82 struct GNUNET_STATISTICS_Handle *p2_stat;
84 struct PeerContext *sender;
86 struct PeerContext *receiver;
88 struct GNUNET_TRANSPORT_TransmitHandle *th;
90 static int test_connected;
93 struct GNUNET_TRANSPORT_TESTING_handle *tth;
95 static GNUNET_TRANSPORT_TESTING_ConnectRequest cc;
97 static unsigned int p1_switch_attempts;
98 static unsigned int p1_switch_success;
99 static unsigned int p1_switch_fail;
100 static unsigned int p1_addresses_avail;
102 static unsigned int p2_switch_attempts;
103 static unsigned int p2_switch_success;
104 static unsigned int p2_switch_fail;
105 static unsigned int p2_addresses_avail;
107 static unsigned long long bytes_sent_total;
108 static unsigned long long bytes_recv_total;
110 static unsigned long long bytes_sent_after_switch;
111 static unsigned long long bytes_recv_after_switch;
113 static struct GNUNET_TIME_Absolute start_time;
114 static struct GNUNET_TIME_Absolute start_time;
117 * END Testcase specific declarations
121 #define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
123 #define OKPP do { ok++; } while (0)
129 stat_start_attempt_cb (void *cls, const char *subsystem, const char *name,
130 uint64_t value, int is_persistent)
134 p1_switch_attempts++;
135 FPRINTF (stderr, "Peer 1 tries to switch.");
139 p2_switch_attempts++;
140 FPRINTF (stderr, "Peer 2 tries to switch.");
145 if (GNUNET_SCHEDULER_NO_TASK == delayed_end_task)
146 delayed_end_task = GNUNET_SCHEDULER_add_delayed (DELAY, &end, NULL );
152 stat_success_attempt_cb (void *cls, const char *subsystem, const char *name,
153 uint64_t value, int is_persistent)
158 FPRINTF (stderr, "Peer 1 switched successfully.");
163 FPRINTF (stderr, "Peer 2 switched successfully.");
171 stat_fail_attempt_cb (void *cls, const char *subsystem, const char *name,
172 uint64_t value, int is_persistent)
180 FPRINTF (stderr, "Peer 1 failed to switch.");
185 FPRINTF (stderr, "Peer 2 failed to switch.");
192 stat_addresses_available (void *cls, const char *subsystem, const char *name,
193 uint64_t value, int is_persistent)
197 p1_addresses_avail++;
201 p2_addresses_avail++;
210 if (measure_task != GNUNET_SCHEDULER_NO_TASK )
212 GNUNET_SCHEDULER_cancel (measure_task);
213 measure_task = GNUNET_SCHEDULER_NO_TASK;
216 if (delayed_end_task != GNUNET_SCHEDULER_NO_TASK )
218 GNUNET_SCHEDULER_cancel (delayed_end_task);
219 delayed_end_task = GNUNET_SCHEDULER_NO_TASK;
222 if (die_task != GNUNET_SCHEDULER_NO_TASK )
224 GNUNET_SCHEDULER_cancel (die_task);
225 die_task = GNUNET_SCHEDULER_NO_TASK;
230 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
231 "# Attempts to switch addresses",
232 stat_start_attempt_cb, p1);
233 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
234 "# Successful attempts to switch addresses",
235 stat_success_attempt_cb, p1);
236 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
237 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
238 stat_fail_attempt_cb, p1);
239 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
240 "# Failed attempts to switch addresses (failed to send CONNECT)",
241 stat_fail_attempt_cb, p1);
242 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
243 "# Failed attempts to switch addresses (no response)",
244 stat_fail_attempt_cb, p1);
245 GNUNET_STATISTICS_watch (p1_stat, "transport",
246 "# transport addresses",
247 stat_addresses_available, p1);
248 GNUNET_STATISTICS_destroy (p1_stat, GNUNET_NO);
253 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
254 "# Attempts to switch addresses", stat_start_attempt_cb, p2);
255 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
256 "# Successful attempts to switch addresses", stat_success_attempt_cb, p2);
257 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
258 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
259 stat_fail_attempt_cb, p2);
260 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
261 "# Failed attempts to switch addresses (failed to send CONNECT)",
262 stat_fail_attempt_cb, p2);
263 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
264 "# Failed attempts to switch addresses (no response)",
265 stat_fail_attempt_cb, p2);
266 GNUNET_STATISTICS_watch (p2_stat, "transport",
267 "# transport addresses",
268 stat_addresses_available, p2);
269 GNUNET_STATISTICS_destroy (p2_stat, GNUNET_NO);
273 if (die_task != GNUNET_SCHEDULER_NO_TASK )
275 GNUNET_SCHEDULER_cancel (die_task);
276 die_task = GNUNET_SCHEDULER_NO_TASK;
281 GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
287 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
293 GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
298 GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
309 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n");
311 delayed_end_task = GNUNET_SCHEDULER_NO_TASK;
312 FPRINTF (stderr, "\n");
313 if (p1_switch_attempts > 0)
315 FPRINTF (stderr, "Peer 1 tried %u times to switch and succeeded %u times, failed %u times\n",
316 p1_switch_attempts, p1_switch_success, p1_switch_fail);
317 if (p1_switch_success != p1_switch_attempts)
325 FPRINTF (stderr, "Peer 1 had %u addresses available, but did not try to switch\n",
328 if (p2_switch_attempts > 0)
330 FPRINTF (stderr, "Peer 2 tried %u times to switch and succeeded %u times, failed %u times\n",
331 p2_switch_attempts, p2_switch_success, p2_switch_fail);
332 if (p2_switch_success != p2_switch_attempts)
340 FPRINTF (stderr, "Peer 2 had %u addresses available, but did not try to switch\n",
344 if ( ((p1_switch_attempts > 0) || (p2_switch_attempts > 0)) &&
345 (bytes_sent_after_switch == 0) )
347 FPRINTF (stderr, "No data sent after switching!\n");
351 if ( ((p1_switch_attempts > 0) || (p2_switch_attempts > 0)) &&
352 (bytes_recv_after_switch == 0) )
354 FPRINTF (stderr, "No data received after switching!\n");
368 die_task = GNUNET_SCHEDULER_NO_TASK;
369 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n");
371 FPRINTF (stderr, "Peer 1 had %u addresses available, but did not try to switch\n",
373 FPRINTF (stderr, "Peer 2 had %u addresses available, but did not try to switch\n",
376 if (test_connected == GNUNET_YES)
377 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Peers got connected\n");
379 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Peers got NOT connected\n");
388 get_size (unsigned int iter)
391 ret = (iter * iter * iter);
392 return sizeof(struct TestMessage) + (ret % 60000);
397 notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
398 const struct GNUNET_MessageHeader *message)
400 const struct TestMessage *hdr;
402 hdr = (const struct TestMessage *) message;
403 if (MTYPE != ntohs (message->type))
406 struct PeerContext *p = cls;
407 char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
409 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
410 "Peer %u (`%s') got message %u of size %u from peer (`%s')\n", p->no, ps,
411 ntohl (hdr->num), ntohs (message->size), GNUNET_i2s (peer));
413 bytes_recv_total += ntohs(hdr->header.size);
414 if ((p1_switch_attempts > 0) || (p2_switch_attempts > 0))
415 bytes_recv_after_switch += ntohs(hdr->header.size);
422 notify_ready (void *cls, size_t size, void *buf)
426 struct TestMessage hdr;
433 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
434 "Timeout occurred while waiting for transmit_ready for message\n");
435 if (GNUNET_SCHEDULER_NO_TASK != die_task)
436 GNUNET_SCHEDULER_cancel (die_task);
437 die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL );
444 GNUNET_assert(size >= s);
445 GNUNET_assert(buf != NULL);
449 hdr.header.size = htons (s);
450 hdr.header.type = htons (MTYPE);
452 memcpy (&cbuf[ret], &hdr, sizeof(struct TestMessage));
453 ret += sizeof(struct TestMessage);
454 memset (&cbuf[ret], n, s - sizeof(struct TestMessage));
455 ret += s - sizeof(struct TestMessage);
460 char *receiver_s = GNUNET_strdup (GNUNET_i2s (&receiver->id));
462 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
463 "Sending message %u of size %u from peer %u (`%4s') -> peer %u (`%s') !\n",
464 n, s, sender->no, GNUNET_i2s (&sender->id), receiver->no, receiver_s);
465 GNUNET_free(receiver_s);
471 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16))
472 break; /* sometimes pack buffer full, sometimes not */
474 while (size - ret >= s);
478 th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, s,
479 TIMEOUT_TRANSMIT, ¬ify_ready, NULL );
485 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
486 "Returning total message block of size %u\n", ret);
488 bytes_sent_total += ret;
489 if ((p1_switch_attempts > 0) || (p2_switch_attempts > 0))
490 bytes_sent_after_switch += ret;
494 FPRINTF (stderr, "%s", "\n");
495 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "All messages sent\n");
502 notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
504 struct PeerContext *p = cls;
505 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') connected to us!\n",
506 p->no, GNUNET_i2s (peer));
511 notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
513 struct PeerContext *p = cls;
514 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') disconnected!\n", p->no,
517 GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
526 start_time = GNUNET_TIME_absolute_get ();
527 th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, get_size (0),
528 TIMEOUT_TRANSMIT, ¬ify_ready, NULL );
533 measure (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
537 measure_task = GNUNET_SCHEDULER_NO_TASK;
540 if ((DURATION.rel_value_us / 1000 / 1000LL) < counter)
542 FPRINTF (stderr, "%s", ".\n");
546 FPRINTF (stderr, "%s", ".");
547 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
554 testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
556 char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
558 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n",
559 p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id));
563 test_connected = GNUNET_YES;
565 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
567 GNUNET_SCHEDULER_add_now (&sendtask, NULL );
572 start_cb (struct PeerContext *p, void *cls)
577 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no,
578 GNUNET_i2s (&p->id));
582 test_connected = GNUNET_NO;
586 char *sender_c = GNUNET_strdup (GNUNET_i2s (&sender->id));
587 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
588 "Test tries to send from %u (%s) -> peer %u (%s)\n", sender->no, sender_c,
589 receiver->no, GNUNET_i2s (&receiver->id));
590 GNUNET_free(sender_c);
591 cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb,
597 run (void *cls, char * const *args, const char *cfgfile,
598 const struct GNUNET_CONFIGURATION_Handle *cfg)
600 die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL );
602 p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1,
603 ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL );
605 p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2,
606 ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL );
608 if ((p1 == NULL )|| (p2 == NULL))
610 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
611 if (die_task != GNUNET_SCHEDULER_NO_TASK)
612 GNUNET_SCHEDULER_cancel (die_task);
613 die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
617 p1_stat = GNUNET_STATISTICS_create ("transport", p1->cfg);
618 GNUNET_STATISTICS_watch (p1_stat, "transport",
619 "# Attempts to switch addresses",
620 stat_start_attempt_cb, p1);
621 GNUNET_STATISTICS_watch (p1_stat, "transport",
622 "# Successful attempts to switch addresses",
623 stat_success_attempt_cb, p1);
624 GNUNET_STATISTICS_watch (p1_stat, "transport",
625 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
626 stat_fail_attempt_cb, p1);
627 GNUNET_STATISTICS_watch (p1_stat, "transport",
628 "# Failed attempts to switch addresses (failed to send CONNECT)",
629 stat_fail_attempt_cb, p1);
630 GNUNET_STATISTICS_watch (p1_stat, "transport",
631 "# Failed attempts to switch addresses (no response)",
632 stat_fail_attempt_cb, p1);
633 GNUNET_STATISTICS_watch (p1_stat, "transport",
634 "# transport addresses",
635 stat_addresses_available, p1);
637 p2_stat = GNUNET_STATISTICS_create ("transport", p2->cfg);
638 GNUNET_STATISTICS_watch (p2_stat, "transport",
639 "# Attempts to switch addresses",
640 stat_start_attempt_cb, p2);
641 GNUNET_STATISTICS_watch (p2_stat, "transport",
642 "# Successful attempts to switch addresses",
643 stat_success_attempt_cb, p2);
644 GNUNET_STATISTICS_watch (p2_stat, "transport",
645 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
646 stat_fail_attempt_cb, p2);
647 GNUNET_STATISTICS_watch (p2_stat, "transport",
648 "# Failed attempts to switch addresses (failed to send CONNECT)",
649 stat_fail_attempt_cb, p2);
650 GNUNET_STATISTICS_watch (p2_stat, "transport",
651 "# Failed attempts to switch addresses (no response)",
652 stat_fail_attempt_cb, p2);
653 GNUNET_STATISTICS_watch (p2_stat, "transport",
654 "# transport addresses",
655 stat_addresses_available, p2);
657 if ((p1_stat == NULL )|| (p2_stat == NULL))
659 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not create statistics for peers!\n");
660 if (die_task != GNUNET_SCHEDULER_NO_TASK)
661 GNUNET_SCHEDULER_cancel (die_task);
662 die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
668 main (int argc, char *argv[])
674 static char *argv_new[] = { "test-transport-address-switch", "-c",
675 "test_transport_startonly.conf", NULL };
677 static struct GNUNET_GETOPT_CommandLineOption options[] = {
678 GNUNET_GETOPT_OPTION_END };
680 GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name);
682 GNUNET_log_setup (test_name, "WARNING", NULL );
684 GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source);
685 GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source,
688 tth = GNUNET_TRANSPORT_TESTING_init ();
690 GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1);
691 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Using cfg [%u] : %s \n", 1, cfg_file_p1);
692 GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2);
693 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Using cfg [%u] : %s \n", 2, cfg_file_p2);
695 GNUNET_PROGRAM_run ((sizeof(argv_new) / sizeof(char *)) - 1, argv_new,
696 test_name, "nohelp", options, &run, NULL );
698 GNUNET_free(cfg_file_p1);
699 GNUNET_free(cfg_file_p2);
701 GNUNET_free(test_source);
702 GNUNET_free(test_plugin);
703 GNUNET_free(test_name);
705 GNUNET_TRANSPORT_TESTING_done (tth);
710 /* end of test_transport_address_switch.c */