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", stat_start_attempt_cb, p1);
232 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
233 "# Successful attempts to switch addresses", stat_success_attempt_cb, p1);
234 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
235 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
236 stat_fail_attempt_cb, p1);
237 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
238 "# Failed attempts to switch addresses (failed to send CONNECT)",
239 stat_fail_attempt_cb, p1);
240 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
241 "# Failed attempts to switch addresses (no response)",
242 stat_fail_attempt_cb, p1);
243 GNUNET_STATISTICS_watch (p1_stat, "transport",
244 "# transport addresses",
245 stat_addresses_available, p1);
246 GNUNET_STATISTICS_destroy (p1_stat, GNUNET_NO);
251 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
252 "# Attempts to switch addresses", stat_start_attempt_cb, p2);
253 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
254 "# Successful attempts to switch addresses", stat_success_attempt_cb, p2);
255 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
256 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
257 stat_fail_attempt_cb, p2);
258 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
259 "# Failed attempts to switch addresses (failed to send CONNECT)",
260 stat_fail_attempt_cb, p2);
261 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
262 "# Failed attempts to switch addresses (no response)",
263 stat_fail_attempt_cb, p2);
264 GNUNET_STATISTICS_watch (p1_stat, "transport",
265 "# transport addresses",
266 stat_addresses_available, p1);
267 GNUNET_STATISTICS_destroy (p2_stat, GNUNET_NO);
271 if (die_task != GNUNET_SCHEDULER_NO_TASK )
273 GNUNET_SCHEDULER_cancel (die_task);
274 die_task = GNUNET_SCHEDULER_NO_TASK;
279 GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
285 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
291 GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
296 GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
307 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n");
309 delayed_end_task = GNUNET_SCHEDULER_NO_TASK;
310 FPRINTF (stderr, "\n");
311 if (p1_switch_attempts > 0)
313 FPRINTF (stderr, "Peer 1 tried %u times to switch and succeeded %u times, failed %u times\n",
314 p1_switch_attempts, p1_switch_success, p1_switch_fail);
315 if (p1_switch_success != p1_switch_attempts)
320 FPRINTF (stderr, "Peer 1 had %u addresses available, but did not try to switch\n",
323 if (p2_switch_attempts > 0)
325 FPRINTF (stderr, "Peer 2 tried %u times to switch and succeeded %u times, failed %u times\n",
326 p2_switch_attempts, p2_switch_success, p2_switch_fail);
327 if (p2_switch_success != p2_switch_attempts)
332 FPRINTF (stderr, "Peer 2 had %u addresses available, but did not try to switch\n",
336 if ( ((p1_switch_attempts > 0) || (p2_switch_attempts > 0)) &&
337 (bytes_sent_after_switch == 0) )
339 FPRINTF (stderr, "No data sent after switching!\n");
342 if ( ((p1_switch_attempts > 0) || (p2_switch_attempts > 0)) &&
343 (bytes_recv_after_switch == 0) )
345 FPRINTF (stderr, "No data received after switching!\n");
358 die_task = GNUNET_SCHEDULER_NO_TASK;
359 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n");
361 FPRINTF (stderr, "Peer 1 had %u addresses available, but did not try to switch\n",
363 FPRINTF (stderr, "Peer 2 had %u addresses available, but did not try to switch\n",
366 if (test_connected == GNUNET_YES)
367 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Peers got connected\n");
369 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Peers got NOT connected\n");
378 get_size (unsigned int iter)
381 ret = (iter * iter * iter);
382 return sizeof(struct TestMessage) + (ret % 60000);
387 notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
388 const struct GNUNET_MessageHeader *message)
390 const struct TestMessage *hdr;
392 hdr = (const struct TestMessage *) message;
393 if (MTYPE != ntohs (message->type))
396 struct PeerContext *p = cls;
397 char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
399 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
400 "Peer %u (`%s') got message %u of size %u from peer (`%s')\n", p->no, ps,
401 ntohl (hdr->num), ntohs (message->size), GNUNET_i2s (peer));
403 bytes_recv_total += ntohs(hdr->header.size);
404 if ((p1_switch_attempts > 0) || (p2_switch_attempts > 0))
405 bytes_recv_after_switch += ntohs(hdr->header.size);
412 notify_ready (void *cls, size_t size, void *buf)
416 struct TestMessage hdr;
423 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
424 "Timeout occurred while waiting for transmit_ready for message\n");
425 if (GNUNET_SCHEDULER_NO_TASK != die_task)
426 GNUNET_SCHEDULER_cancel (die_task);
427 die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL );
434 GNUNET_assert(size >= s);
435 GNUNET_assert(buf != NULL);
439 hdr.header.size = htons (s);
440 hdr.header.type = htons (MTYPE);
442 memcpy (&cbuf[ret], &hdr, sizeof(struct TestMessage));
443 ret += sizeof(struct TestMessage);
444 memset (&cbuf[ret], n, s - sizeof(struct TestMessage));
445 ret += s - sizeof(struct TestMessage);
450 char *receiver_s = GNUNET_strdup (GNUNET_i2s (&receiver->id));
452 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
453 "Sending message %u of size %u from peer %u (`%4s') -> peer %u (`%s') !\n",
454 n, s, sender->no, GNUNET_i2s (&sender->id), receiver->no, receiver_s);
455 GNUNET_free(receiver_s);
461 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16))
462 break; /* sometimes pack buffer full, sometimes not */
464 while (size - ret >= s);
468 th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, s,
469 TIMEOUT_TRANSMIT, ¬ify_ready, NULL );
475 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
476 "Returning total message block of size %u\n", ret);
478 bytes_sent_total += ret;
479 if ((p1_switch_attempts > 0) || (p2_switch_attempts > 0))
480 bytes_sent_after_switch += ret;
484 FPRINTF (stderr, "%s", "\n");
485 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "All messages sent\n");
492 notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
494 struct PeerContext *p = cls;
495 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') connected to us!\n",
496 p->no, GNUNET_i2s (peer));
501 notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
503 struct PeerContext *p = cls;
504 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') disconnected!\n", p->no,
507 GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
516 start_time = GNUNET_TIME_absolute_get ();
517 th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, get_size (0),
518 TIMEOUT_TRANSMIT, ¬ify_ready, NULL );
523 measure (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
527 measure_task = GNUNET_SCHEDULER_NO_TASK;
530 if ((DURATION.rel_value_us / 1000 / 1000LL) < counter)
532 FPRINTF (stderr, "%s", ".\n");
536 FPRINTF (stderr, "%s", ".");
537 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
544 testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
546 char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
548 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n",
549 p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id));
553 test_connected = GNUNET_YES;
555 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
557 GNUNET_SCHEDULER_add_now (&sendtask, NULL );
562 start_cb (struct PeerContext *p, void *cls)
567 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no,
568 GNUNET_i2s (&p->id));
572 test_connected = GNUNET_NO;
576 char *sender_c = GNUNET_strdup (GNUNET_i2s (&sender->id));
577 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
578 "Test tries to send from %u (%s) -> peer %u (%s)\n", sender->no, sender_c,
579 receiver->no, GNUNET_i2s (&receiver->id));
580 GNUNET_free(sender_c);
581 cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb,
587 run (void *cls, char * const *args, const char *cfgfile,
588 const struct GNUNET_CONFIGURATION_Handle *cfg)
590 die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL );
592 p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1,
593 ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL );
594 p1_stat = GNUNET_STATISTICS_create ("transport", p1->cfg);
595 GNUNET_STATISTICS_watch (p1_stat, "transport",
596 "# Attempts to switch addresses",
597 stat_start_attempt_cb, p1);
598 GNUNET_STATISTICS_watch (p1_stat, "transport",
599 "# Successful attempts to switch addresses",
600 stat_success_attempt_cb, p1);
601 GNUNET_STATISTICS_watch (p1_stat, "transport",
602 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
603 stat_fail_attempt_cb, p1);
604 GNUNET_STATISTICS_watch (p1_stat, "transport",
605 "# Failed attempts to switch addresses (failed to send CONNECT)",
606 stat_fail_attempt_cb, p1);
607 GNUNET_STATISTICS_watch (p1_stat, "transport",
608 "# Failed attempts to switch addresses (no response)",
609 stat_fail_attempt_cb, p1);
610 GNUNET_STATISTICS_watch (p1_stat, "transport",
611 "# transport addresses",
612 stat_addresses_available, p1);
614 p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2,
615 ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL );
617 p2_stat = GNUNET_STATISTICS_create ("transport", p2->cfg);
618 GNUNET_STATISTICS_watch (p2_stat, "transport",
619 "# Attempts to switch addresses",
620 stat_start_attempt_cb, p2);
621 GNUNET_STATISTICS_watch (p2_stat, "transport",
622 "# Successful attempts to switch addresses",
623 stat_success_attempt_cb, p2);
624 GNUNET_STATISTICS_watch (p2_stat, "transport",
625 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
626 stat_fail_attempt_cb, p2);
627 GNUNET_STATISTICS_watch (p2_stat, "transport",
628 "# Failed attempts to switch addresses (failed to send CONNECT)",
629 stat_fail_attempt_cb, p2);
630 GNUNET_STATISTICS_watch (p2_stat, "transport",
631 "# Failed attempts to switch addresses (no response)",
632 stat_fail_attempt_cb, p2);
633 GNUNET_STATISTICS_watch (p2_stat, "transport",
634 "# transport addresses",
635 stat_addresses_available, p2);
637 if ((p1 == NULL )|| (p2 == NULL))
639 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
640 if (die_task != GNUNET_SCHEDULER_NO_TASK)
641 GNUNET_SCHEDULER_cancel (die_task);
642 die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
646 if ((p1_stat == NULL )|| (p2_stat == NULL))
648 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not create statistics for peers!\n");
649 if (die_task != GNUNET_SCHEDULER_NO_TASK)
650 GNUNET_SCHEDULER_cancel (die_task);
651 die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
657 main (int argc, char *argv[])
663 static char *argv_new[] = { "test-transport-address-switch", "-c",
664 "test_transport_startonly.conf", NULL };
666 static struct GNUNET_GETOPT_CommandLineOption options[] = {
667 GNUNET_GETOPT_OPTION_END };
669 GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name);
671 GNUNET_log_setup (test_name, "WARNING", NULL );
673 GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source);
674 GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source,
677 tth = GNUNET_TRANSPORT_TESTING_init ();
679 GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1);
680 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Using cfg [%u] : %s \n", 1, cfg_file_p1);
681 GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2);
682 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Using cfg [%u] : %s \n", 2, cfg_file_p2);
684 GNUNET_PROGRAM_run ((sizeof(argv_new) / sizeof(char *)) - 1, argv_new,
685 test_name, "nohelp", options, &run, NULL );
687 GNUNET_free(cfg_file_p1);
688 GNUNET_free(cfg_file_p2);
690 GNUNET_free(test_source);
691 GNUNET_free(test_plugin);
692 GNUNET_free(test_name);
694 GNUNET_TRANSPORT_TESTING_done (tth);
699 /* end of test_transport_address_switch.c */