2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011, 2016 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, 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 outside,
37 * the test returns "77" (skipped) when no address switching attempt
38 * takes place. It fails if an address switch attempt fails.
40 * NOTE: The test seems largely useless right now, as we simply NEVER
41 * switch addresses under the test conditions. However, it may be a
42 * good starting point for a future test. For now, it always times
43 * out and returns "77" (skipped), so we set the timeout suitably low.
46 #include "gnunet_transport_service.h"
47 #include "gnunet_ats_service.h"
48 #include "transport-testing.h"
51 GNUNET_NETWORK_STRUCT_BEGIN
54 struct GNUNET_MessageHeader header;
55 uint32_t num GNUNET_PACKED;
57 GNUNET_NETWORK_STRUCT_END
60 * Message type for test messages
65 * Message size for test messages
72 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
75 * How long until we give up on transmitting the message?
77 #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
80 static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
82 static struct GNUNET_SCHEDULER_Task *measure_task;
84 static struct GNUNET_TRANSPORT_TransmitHandle *th;
87 * Statistics we track per peer.
91 struct GNUNET_STATISTICS_Handle *stat;
93 unsigned int addresses_avail;
95 unsigned int switch_attempts;
97 unsigned int switch_success;
99 unsigned int switch_fail;
102 static struct PeerStats stats[2];
104 /* Amount of data transfered since last switch attempt */
105 static unsigned long long bytes_sent_after_switch;
107 static unsigned long long bytes_recv_after_switch;
111 stat_start_attempt_cb (void *cls,
112 const char *subsystem,
117 struct PeerStats *stat = cls;
119 stat->switch_attempts++;
120 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
121 "Switch attempted (%p)",
123 bytes_recv_after_switch = 0;
124 bytes_sent_after_switch = 0;
131 stat_success_attempt_cb (void *cls,
132 const char *subsystem,
137 struct PeerStats *stat = cls;
139 stat->switch_success++;
140 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
141 "Switch succeeded (%p)",
148 stat_fail_attempt_cb (void *cls,
149 const char *subsystem,
154 struct PeerStats *stat = cls;
160 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
161 "Switch failed (%p)",
168 stat_addresses_available (void *cls,
169 const char *subsystem,
174 struct PeerStats *stat = cls;
176 stat->addresses_avail++;
182 * List of statistics entries we care about.
184 static struct WatchEntry {
187 * Name of the statistic we watch.
189 const char *stat_name;
192 * Handler to register;
194 GNUNET_STATISTICS_Iterator stat_handler;
196 { "# Attempts to switch addresses", &stat_start_attempt_cb },
197 { "# Successful attempts to switch addresses", &stat_success_attempt_cb },
198 { "# Failed attempts to switch addresses (failed to send CONNECT CONT)", &stat_fail_attempt_cb },
199 { "# Failed attempts to switch addresses (failed to send CONNECT)", &stat_fail_attempt_cb },
200 { "# Failed attempts to switch addresses (no response)", &stat_fail_attempt_cb },
201 { "# transport addresses", &stat_addresses_available },
207 custom_shutdown (void *cls)
211 if (NULL != measure_task)
213 GNUNET_SCHEDULER_cancel (measure_task);
216 if (0 == stats[0].switch_attempts + stats[1].switch_attempts)
218 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
219 "Test did not work, as peers didn't switch (flawed testcase)!\n");
220 ccc->global_ret = 77;
224 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
225 "Fail (timeout)! No transmission after switch! Stopping peers\n");
226 ccc->global_ret = GNUNET_SYSERR;
229 /* stop statistics */
230 for (unsigned int i=0;i<2;i++)
232 if (NULL != stats[i].stat)
234 for (unsigned int j=0;NULL != watches[j].stat_name; j++)
235 GNUNET_STATISTICS_watch_cancel (stats[i].stat,
237 watches[j].stat_name,
238 watches[j].stat_handler,
241 GNUNET_STATISTICS_destroy (stats[i].stat,
243 stats[i].stat = NULL;
248 GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
253 FPRINTF (stderr, "\n");
254 if (stats[0].switch_attempts > 0)
257 "Peer 1 tried %u times to switch and succeeded %u times, failed %u times\n",
258 stats[0].switch_attempts,
259 stats[0].switch_success,
260 stats[0].switch_fail);
261 if (stats[0].switch_success != stats[0].switch_attempts)
267 else if (stats[0].addresses_avail > 1)
270 "Peer 1 had %u addresses available, but did not try to switch\n",
271 stats[0].addresses_avail);
273 if (stats[1].switch_attempts > 0)
276 "Peer 2 tried %u times to switch and succeeded %u times, failed %u times\n",
277 stats[1].switch_attempts,
278 stats[1].switch_success,
279 stats[1].switch_fail);
280 if (stats[1].switch_success != stats[1].switch_attempts)
286 else if (stats[1].addresses_avail > 1)
289 "Peer 2 had %u addresses available, but did not try to switch\n",
290 stats[1].addresses_avail);
293 if ( ((stats[0].switch_attempts > 0) || (stats[1].switch_attempts > 0)) &&
294 (bytes_sent_after_switch == 0) )
296 FPRINTF (stderr, "No data sent after switching!\n");
300 if ( ((stats[0].switch_attempts > 0) || (stats[1].switch_attempts > 0)) &&
301 (bytes_recv_after_switch == 0) )
303 FPRINTF (stderr, "No data received after switching!\n");
308 ccc->global_ret = GNUNET_SYSERR;
313 notify_receive (void *cls,
314 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
315 const struct GNUNET_PeerIdentity *sender,
316 const struct GNUNET_MessageHeader *message)
318 const struct TestMessage *hdr;
320 hdr = (const struct TestMessage *) message;
321 if (MTYPE != ntohs (message->type))
325 char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
327 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
328 "Peer %u (`%s') got message %u of size %u from peer (`%s')\n",
332 ntohs (message->size),
333 GNUNET_i2s (sender));
336 if ( ((stats[0].switch_attempts >= 1) || (stats[1].switch_attempts >= 1)) &&
337 (stats[0].switch_attempts == stats[0].switch_fail + stats[0].switch_success) &&
338 (stats[1].switch_attempts == stats[1].switch_fail + stats[1].switch_success) )
340 bytes_recv_after_switch += ntohs(hdr->header.size);
341 if ((bytes_sent_after_switch > 0) && (bytes_recv_after_switch > 0))
343 /* A peer switched addresses and sent and received data after the
344 * switch operations */
345 GNUNET_SCHEDULER_shutdown ();
352 notify_ready (void *cls, size_t size, void *buf)
354 static uint32_t counter;
356 struct TestMessage hdr;
361 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
362 "Timeout occurred while waiting for transmit_ready for message\n");
363 ccc->global_ret = GNUNET_SYSERR;
364 GNUNET_SCHEDULER_shutdown ();
368 GNUNET_assert(size >= MSIZE);
369 GNUNET_assert(buf != NULL);
372 hdr.header.size = htons (MSIZE);
373 hdr.header.type = htons (MTYPE);
374 hdr.num = htonl (counter++);
375 GNUNET_memcpy (&cbuf[0], &hdr, sizeof(struct TestMessage));
376 memset (&cbuf[sizeof(struct TestMessage)], '0', MSIZE - sizeof(struct TestMessage));
379 char *receiver_s = GNUNET_strdup (GNUNET_i2s (&ccc->p[0]->id));
381 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
382 "Sending message %u of size %u from peer %u (`%4s') -> peer %u (`%s') !\n",
383 (unsigned int) (counter - 1),
386 GNUNET_i2s (&ccc->p[1]->id),
389 GNUNET_free(receiver_s);
393 th = GNUNET_TRANSPORT_notify_transmit_ready (ccc->p[1]->th,
400 if ( ( (stats[0].switch_attempts >= 1) ||
401 (stats[1].switch_attempts >= 1) ) &&
402 (stats[0].switch_attempts == stats[0].switch_fail + stats[0].switch_success) &&
403 (stats[1].switch_attempts == stats[1].switch_fail + stats[1].switch_success) )
405 bytes_sent_after_switch += MSIZE;
412 notify_disconnect (void *cls,
413 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
414 const struct GNUNET_PeerIdentity *other)
418 GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
425 progress_indicator (void *cls)
431 if ((TIMEOUT.rel_value_us / 1000 / 1000LL) < counter)
433 FPRINTF (stderr, "%s", ".\n");
437 FPRINTF (stderr, "%s", ".");
438 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
446 connected_cb (void *cls)
448 for (unsigned int i=0;i<2;i++)
450 stats[i].stat = GNUNET_STATISTICS_create ("transport",
452 if (NULL == stats[i].stat)
454 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
455 "Fail! Could not create statistics for peers!\n");
456 ccc->global_ret = GNUNET_SYSERR;
457 GNUNET_SCHEDULER_shutdown ();
460 for (unsigned int j=0;NULL != watches[j].stat_name; j++)
462 GNUNET_STATISTICS_watch (stats[i].stat,
464 watches[j].stat_name,
465 watches[j].stat_handler,
470 ccc->global_ret = GNUNET_OK;
471 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
474 /* Peers are connected, start transmit test messages */
475 th = GNUNET_TRANSPORT_notify_transmit_ready (ccc->p[1]->th,
476 &ccc->p[0]->id, MSIZE,
478 ¬ify_ready, NULL);
487 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
488 .connect_continuation = &connected_cb,
489 .config_file = "test_transport_api.conf",
490 .rec = ¬ify_receive,
491 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
492 .nd = ¬ify_disconnect,
493 .shutdown_task = &custom_shutdown,
499 ret = GNUNET_TRANSPORT_TESTING_main (2,
500 &GNUNET_TRANSPORT_TESTING_connect_check,
504 if (GNUNET_OK != ret)
508 /* end of test_transport_address_switch.c */