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;
101 static unsigned int p2_switch_attempts;
102 static unsigned int p2_switch_success;
103 static unsigned int p2_switch_fail;
105 static unsigned long long bytes_sent_total;
106 static unsigned long long bytes_recv_total;
108 static unsigned long long bytes_sent_after_switch;
109 static unsigned long long bytes_recv_after_switch;
111 static struct GNUNET_TIME_Absolute start_time;
112 static struct GNUNET_TIME_Absolute start_time;
115 * END Testcase specific declarations
119 #define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
121 #define OKPP do { ok++; } while (0)
127 stat_start_attempt_cb (void *cls, const char *subsystem, const char *name,
128 uint64_t value, int is_persistent)
132 p1_switch_attempts++;
133 FPRINTF (stderr, "Peer 1 tries to switch.");
137 p2_switch_attempts++;
138 FPRINTF (stderr, "Peer 2 tries to switch.");
143 if (GNUNET_SCHEDULER_NO_TASK == delayed_end_task)
144 delayed_end_task = GNUNET_SCHEDULER_add_delayed (DELAY, &end, NULL );
150 stat_success_attempt_cb (void *cls, const char *subsystem, const char *name,
151 uint64_t value, int is_persistent)
156 FPRINTF (stderr, "Peer 1 switched successfully.");
161 FPRINTF (stderr, "Peer 2 switched successfully.");
169 stat_fail_attempt_cb (void *cls, const char *subsystem, const char *name,
170 uint64_t value, int is_persistent)
175 FPRINTF (stderr, "Peer 1 failed to switch.");
180 FPRINTF (stderr, "Peer 2 failed to switch.");
190 if (measure_task != GNUNET_SCHEDULER_NO_TASK )
192 GNUNET_SCHEDULER_cancel (measure_task);
193 measure_task = GNUNET_SCHEDULER_NO_TASK;
196 if (delayed_end_task != GNUNET_SCHEDULER_NO_TASK )
198 GNUNET_SCHEDULER_cancel (delayed_end_task);
199 delayed_end_task = GNUNET_SCHEDULER_NO_TASK;
202 if (die_task != GNUNET_SCHEDULER_NO_TASK )
204 GNUNET_SCHEDULER_cancel (die_task);
205 die_task = GNUNET_SCHEDULER_NO_TASK;
210 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
211 "# Attempts to switch addresses", stat_start_attempt_cb, p1);
212 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
213 "# Successful attempts to switch addresses", stat_success_attempt_cb, p1);
214 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
215 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
216 stat_fail_attempt_cb, p1);
217 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
218 "# Failed attempts to switch addresses (failed to send CONNECT)",
219 stat_fail_attempt_cb, p1);
220 GNUNET_STATISTICS_watch_cancel (p1_stat, "transport",
221 "# Failed attempts to switch addresses (no response)",
222 stat_fail_attempt_cb, p1);
223 GNUNET_STATISTICS_destroy (p1_stat, GNUNET_NO);
228 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
229 "# Attempts to switch addresses", stat_start_attempt_cb, p2);
230 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
231 "# Successful attempts to switch addresses", stat_success_attempt_cb, p2);
232 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
233 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
234 stat_fail_attempt_cb, p2);
235 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
236 "# Failed attempts to switch addresses (failed to send CONNECT)",
237 stat_fail_attempt_cb, p2);
238 GNUNET_STATISTICS_watch_cancel (p2_stat, "transport",
239 "# Failed attempts to switch addresses (no response)",
240 stat_fail_attempt_cb, p2);
241 GNUNET_STATISTICS_destroy (p2_stat, GNUNET_NO);
245 if (die_task != GNUNET_SCHEDULER_NO_TASK )
247 GNUNET_SCHEDULER_cancel (die_task);
248 die_task = GNUNET_SCHEDULER_NO_TASK;
253 GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
259 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
265 GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
270 GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
281 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n");
283 delayed_end_task = GNUNET_SCHEDULER_NO_TASK;
284 FPRINTF (stderr, "\n");
285 if (p1_switch_attempts > 0)
287 FPRINTF (stderr, "Peer 1 tried %u times to switch and succeeded %u times, failed %u times\n",
288 p1_switch_attempts, p1_switch_success, p1_switch_fail);
289 if (p1_switch_success != p1_switch_attempts)
292 if (p2_switch_attempts > 0)
294 FPRINTF (stderr, "Peer 2 tried %u times to switch and succeeded %u times, failed %u times\n",
295 p2_switch_attempts, p2_switch_success, p2_switch_fail);
296 if (p2_switch_success != p2_switch_attempts)
300 if ( ((p1_switch_attempts > 0) || (p2_switch_attempts > 0)) &&
301 (bytes_sent_after_switch == 0) )
303 FPRINTF (stderr, "No data sent after switching!\n");
306 if ( ((p1_switch_attempts > 0) || (p2_switch_attempts > 0)) &&
307 (bytes_recv_after_switch == 0) )
309 FPRINTF (stderr, "No data received after switching!\n");
322 die_task = GNUNET_SCHEDULER_NO_TASK;
323 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n");
325 if (test_connected == GNUNET_YES)
326 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Peers got connected\n");
328 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Peers got NOT connected\n");
337 get_size (unsigned int iter)
340 ret = (iter * iter * iter);
341 return sizeof(struct TestMessage) + (ret % 60000);
346 notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
347 const struct GNUNET_MessageHeader *message)
349 const struct TestMessage *hdr;
351 hdr = (const struct TestMessage *) message;
352 if (MTYPE != ntohs (message->type))
355 struct PeerContext *p = cls;
356 char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
358 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
359 "Peer %u (`%s') got message %u of size %u from peer (`%s')\n", p->no, ps,
360 ntohl (hdr->num), ntohs (message->size), GNUNET_i2s (peer));
362 bytes_recv_total += ntohs(hdr->header.size);
363 if ((p1_switch_attempts > 0) || (p2_switch_attempts > 0))
364 bytes_recv_after_switch += ntohs(hdr->header.size);
371 notify_ready (void *cls, size_t size, void *buf)
375 struct TestMessage hdr;
382 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
383 "Timeout occurred while waiting for transmit_ready for message\n");
384 if (GNUNET_SCHEDULER_NO_TASK != die_task)
385 GNUNET_SCHEDULER_cancel (die_task);
386 die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL );
393 GNUNET_assert(size >= s);
394 GNUNET_assert(buf != NULL);
398 hdr.header.size = htons (s);
399 hdr.header.type = htons (MTYPE);
401 memcpy (&cbuf[ret], &hdr, sizeof(struct TestMessage));
402 ret += sizeof(struct TestMessage);
403 memset (&cbuf[ret], n, s - sizeof(struct TestMessage));
404 ret += s - sizeof(struct TestMessage);
409 char *receiver_s = GNUNET_strdup (GNUNET_i2s (&receiver->id));
411 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
412 "Sending message %u of size %u from peer %u (`%4s') -> peer %u (`%s') !\n",
413 n, s, sender->no, GNUNET_i2s (&sender->id), receiver->no, receiver_s);
414 GNUNET_free(receiver_s);
420 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16))
421 break; /* sometimes pack buffer full, sometimes not */
423 while (size - ret >= s);
427 th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, s,
428 TIMEOUT_TRANSMIT, ¬ify_ready, NULL );
434 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
435 "Returning total message block of size %u\n", ret);
437 bytes_sent_total += ret;
438 if ((p1_switch_attempts > 0) || (p2_switch_attempts > 0))
439 bytes_sent_after_switch += ret;
443 FPRINTF (stderr, "%s", "\n");
444 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "All messages sent\n");
451 notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
453 struct PeerContext *p = cls;
454 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') connected to us!\n",
455 p->no, GNUNET_i2s (peer));
460 notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
462 struct PeerContext *p = cls;
463 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') disconnected!\n", p->no,
466 GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
475 start_time = GNUNET_TIME_absolute_get ();
476 th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, get_size (0),
477 TIMEOUT_TRANSMIT, ¬ify_ready, NULL );
482 measure (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
486 measure_task = GNUNET_SCHEDULER_NO_TASK;
489 if ((DURATION.rel_value_us / 1000 / 1000LL) < counter)
491 FPRINTF (stderr, "%s", ".\n");
495 FPRINTF (stderr, "%s", ".");
496 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
503 testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
505 char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
507 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n",
508 p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id));
512 test_connected = GNUNET_YES;
514 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
516 GNUNET_SCHEDULER_add_now (&sendtask, NULL );
521 start_cb (struct PeerContext *p, void *cls)
526 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no,
527 GNUNET_i2s (&p->id));
531 test_connected = GNUNET_NO;
535 char *sender_c = GNUNET_strdup (GNUNET_i2s (&sender->id));
536 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
537 "Test tries to send from %u (%s) -> peer %u (%s)\n", sender->no, sender_c,
538 receiver->no, GNUNET_i2s (&receiver->id));
539 GNUNET_free(sender_c);
540 cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb,
546 run (void *cls, char * const *args, const char *cfgfile,
547 const struct GNUNET_CONFIGURATION_Handle *cfg)
549 die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL );
551 p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1,
552 ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL );
553 p1_stat = GNUNET_STATISTICS_create ("transport", p1->cfg);
554 GNUNET_STATISTICS_watch (p1_stat, "transport",
555 "# Attempts to switch addresses",
556 stat_start_attempt_cb, p1);
557 GNUNET_STATISTICS_watch (p1_stat, "transport",
558 "# Successful attempts to switch addresses",
559 stat_success_attempt_cb, p1);
560 GNUNET_STATISTICS_watch (p1_stat, "transport",
561 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
562 stat_fail_attempt_cb, p1);
563 GNUNET_STATISTICS_watch (p1_stat, "transport",
564 "# Failed attempts to switch addresses (failed to send CONNECT)",
565 stat_fail_attempt_cb, p1);
566 GNUNET_STATISTICS_watch (p1_stat, "transport",
567 "# Failed attempts to switch addresses (no response)",
568 stat_fail_attempt_cb, p1);
570 p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2,
571 ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL );
573 p2_stat = GNUNET_STATISTICS_create ("transport", p2->cfg);
574 GNUNET_STATISTICS_watch (p2_stat, "transport",
575 "# Attempts to switch addresses",
576 stat_start_attempt_cb, p2);
577 GNUNET_STATISTICS_watch (p2_stat, "transport",
578 "# Successful attempts to switch addresses",
579 stat_success_attempt_cb, p2);
580 GNUNET_STATISTICS_watch (p2_stat, "transport",
581 "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
582 stat_fail_attempt_cb, p2);
583 GNUNET_STATISTICS_watch (p2_stat, "transport",
584 "# Failed attempts to switch addresses (failed to send CONNECT)",
585 stat_fail_attempt_cb, p2);
586 GNUNET_STATISTICS_watch (p2_stat, "transport",
587 "# Failed attempts to switch addresses (no response)",
588 stat_fail_attempt_cb, p2);
590 if ((p1 == NULL )|| (p2 == NULL))
592 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
593 if (die_task != GNUNET_SCHEDULER_NO_TASK)
594 GNUNET_SCHEDULER_cancel (die_task);
595 die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
599 if ((p1_stat == NULL )|| (p2_stat == NULL))
601 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not create statistics for peers!\n");
602 if (die_task != GNUNET_SCHEDULER_NO_TASK)
603 GNUNET_SCHEDULER_cancel (die_task);
604 die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
610 main (int argc, char *argv[])
616 static char *argv_new[] = { "test-transport-address-switch", "-c",
617 "test_transport_startonly.conf", NULL };
619 static struct GNUNET_GETOPT_CommandLineOption options[] = {
620 GNUNET_GETOPT_OPTION_END };
622 GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name);
624 GNUNET_log_setup (test_name, "WARNING", NULL );
626 GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source);
627 GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source,
630 tth = GNUNET_TRANSPORT_TESTING_init ();
632 GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1);
633 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Using cfg [%u] : %s \n", 1, cfg_file_p1);
634 GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2);
635 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Using cfg [%u] : %s \n", 2, cfg_file_p2);
637 GNUNET_PROGRAM_run ((sizeof(argv_new) / sizeof(char *)) - 1, argv_new,
638 test_name, "nohelp", options, &run, NULL );
640 GNUNET_free(cfg_file_p1);
641 GNUNET_free(cfg_file_p2);
643 GNUNET_free(test_source);
644 GNUNET_free(test_plugin);
645 GNUNET_free(test_name);
647 GNUNET_TRANSPORT_TESTING_done (tth);
652 /* end of test_transport_address_switch.c */