test_transport_address_switch.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2009, 2010, 2011, 2016 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file transport/test_transport_address_switch.c
  18. * @brief base test case for transport implementations
  19. *
  20. * This test case tests if peers can successfully switch addresses when
  21. * connected for plugins supporting multiple addresses by monitoring transport's
  22. * statistic values.
  23. *
  24. * This test starts 2 peers and connects them. When connected test messages
  25. * are transmitted from peer 2 to peer 1. The test monitors transport's
  26. * statistics values for information about address switch attempts.
  27. *
  28. * The test passes with success if one of the peers could successfully switch
  29. * addresses in connected state and a test message was successfully transmitted
  30. * after this switch.
  31. *
  32. * Since it is not possible to trigger an address switch from outside,
  33. * the test returns "77" (skipped) when no address switching attempt
  34. * takes place. It fails if an address switch attempt fails.
  35. *
  36. * NOTE: The test seems largely useless right now, as we simply NEVER
  37. * switch addresses under the test conditions. However, it may be a
  38. * good starting point for a future test. For now, it always times
  39. * out and returns "77" (skipped), so we set the timeout suitably low.
  40. */
  41. #include "platform.h"
  42. #include "gnunet_transport_service.h"
  43. #include "gnunet_ats_service.h"
  44. #include "transport-testing.h"
  45. /**
  46. * Testcase timeout (set aggressively as we know this test doesn't work right now)
  47. */
  48. #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
  49. static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
  50. static struct GNUNET_SCHEDULER_Task *measure_task;
  51. /**
  52. * Statistics we track per peer.
  53. */
  54. struct PeerStats
  55. {
  56. struct GNUNET_STATISTICS_Handle *stat;
  57. unsigned int addresses_avail;
  58. unsigned int switch_attempts;
  59. unsigned int switch_success;
  60. unsigned int switch_fail;
  61. };
  62. static struct PeerStats stats[2];
  63. /* Amount of data transferred since last switch attempt */
  64. static unsigned long long bytes_sent_after_switch;
  65. static unsigned long long bytes_recv_after_switch;
  66. static int
  67. stat_start_attempt_cb (void *cls,
  68. const char *subsystem,
  69. const char *name,
  70. uint64_t value,
  71. int is_persistent)
  72. {
  73. struct PeerStats *stat = cls;
  74. stat->switch_attempts++;
  75. GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Switch attempted (%p)", stat);
  76. bytes_recv_after_switch = 0;
  77. bytes_sent_after_switch = 0;
  78. return GNUNET_OK;
  79. }
  80. static int
  81. stat_success_attempt_cb (void *cls,
  82. const char *subsystem,
  83. const char *name,
  84. uint64_t value,
  85. int is_persistent)
  86. {
  87. struct PeerStats *stat = cls;
  88. stat->switch_success++;
  89. GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Switch succeeded (%p)", stat);
  90. return GNUNET_OK;
  91. }
  92. static int
  93. stat_fail_attempt_cb (void *cls,
  94. const char *subsystem,
  95. const char *name,
  96. uint64_t value,
  97. int is_persistent)
  98. {
  99. struct PeerStats *stat = cls;
  100. if (value == 0)
  101. return GNUNET_OK;
  102. stat->switch_fail++;
  103. GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Switch failed (%p)", stat);
  104. return GNUNET_OK;
  105. }
  106. static int
  107. stat_addresses_available (void *cls,
  108. const char *subsystem,
  109. const char *name,
  110. uint64_t value,
  111. int is_persistent)
  112. {
  113. struct PeerStats *stat = cls;
  114. stat->addresses_avail++;
  115. return GNUNET_OK;
  116. }
  117. /**
  118. * List of statistics entries we care about.
  119. */
  120. static struct WatchEntry
  121. {
  122. /**
  123. * Name of the statistic we watch.
  124. */
  125. const char *stat_name;
  126. /**
  127. * Handler to register;
  128. */
  129. GNUNET_STATISTICS_Iterator stat_handler;
  130. } watches[] =
  131. { { "# Attempts to switch addresses", &stat_start_attempt_cb },
  132. { "# Successful attempts to switch addresses", &stat_success_attempt_cb },
  133. { "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
  134. &stat_fail_attempt_cb },
  135. { "# Failed attempts to switch addresses (failed to send CONNECT)",
  136. &stat_fail_attempt_cb },
  137. { "# Failed attempts to switch addresses (no response)",
  138. &stat_fail_attempt_cb },
  139. { "# transport addresses", &stat_addresses_available },
  140. { NULL, NULL } };
  141. static void
  142. custom_shutdown (void *cls)
  143. {
  144. int result;
  145. if (NULL != measure_task)
  146. {
  147. GNUNET_SCHEDULER_cancel (measure_task);
  148. measure_task = NULL;
  149. }
  150. if (0 == stats[0].switch_attempts + stats[1].switch_attempts)
  151. {
  152. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  153. "Test did not work, as peers didn't switch (flawed testcase)!\n");
  154. ccc->global_ret = 77;
  155. }
  156. else
  157. {
  158. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  159. "Fail (timeout)! No transmission after switch! Stopping peers\n");
  160. ccc->global_ret = 77; /* GNUNET_SYSERR; */
  161. }
  162. /* stop statistics */
  163. for (unsigned int i = 0; i < 2; i++)
  164. {
  165. if (NULL != stats[i].stat)
  166. {
  167. for (unsigned int j = 0; NULL != watches[j].stat_name; j++)
  168. GNUNET_assert (GNUNET_OK ==
  169. GNUNET_STATISTICS_watch_cancel (stats[i].stat,
  170. "transport",
  171. watches[j].stat_name,
  172. watches[j].stat_handler,
  173. &stats[i]));
  174. GNUNET_STATISTICS_destroy (stats[i].stat, GNUNET_NO);
  175. stats[i].stat = NULL;
  176. }
  177. }
  178. result = 0;
  179. fprintf (stderr, "\n");
  180. if (stats[0].switch_attempts > 0)
  181. {
  182. fprintf (
  183. stderr,
  184. "Peer 1 tried %u times to switch and succeeded %u times, failed %u times\n",
  185. stats[0].switch_attempts,
  186. stats[0].switch_success,
  187. stats[0].switch_fail);
  188. if (stats[0].switch_success != stats[0].switch_attempts)
  189. {
  190. GNUNET_break (0);
  191. result++;
  192. }
  193. }
  194. else if (stats[0].addresses_avail > 1)
  195. {
  196. fprintf (stderr,
  197. "Peer 1 had %u addresses available, but did not try to switch\n",
  198. stats[0].addresses_avail);
  199. }
  200. if (stats[1].switch_attempts > 0)
  201. {
  202. fprintf (
  203. stderr,
  204. "Peer 2 tried %u times to switch and succeeded %u times, failed %u times\n",
  205. stats[1].switch_attempts,
  206. stats[1].switch_success,
  207. stats[1].switch_fail);
  208. if (stats[1].switch_success != stats[1].switch_attempts)
  209. {
  210. GNUNET_break (0);
  211. result++;
  212. }
  213. }
  214. else if (stats[1].addresses_avail > 1)
  215. {
  216. fprintf (stderr,
  217. "Peer 2 had %u addresses available, but did not try to switch\n",
  218. stats[1].addresses_avail);
  219. }
  220. if (((stats[0].switch_attempts > 0) || (stats[1].switch_attempts > 0)) &&
  221. (bytes_sent_after_switch == 0))
  222. {
  223. fprintf (stderr, "No data sent after switching!\n");
  224. GNUNET_break (0);
  225. result++;
  226. }
  227. if (((stats[0].switch_attempts > 0) || (stats[1].switch_attempts > 0)) &&
  228. (bytes_recv_after_switch == 0))
  229. {
  230. fprintf (stderr, "No data received after switching!\n");
  231. GNUNET_break (0);
  232. result++;
  233. }
  234. #if 0
  235. /* This test is not really expected to pass right now... */
  236. if (0 != result)
  237. ccc->global_ret = GNUNET_SYSERR;
  238. #endif
  239. }
  240. static void
  241. notify_receive (void *cls,
  242. struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
  243. const struct GNUNET_PeerIdentity *sender,
  244. const struct GNUNET_TRANSPORT_TESTING_TestMessage *hdr)
  245. {
  246. if (GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE != ntohs (hdr->header.type))
  247. return;
  248. {
  249. char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
  250. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  251. "Peer %u (`%s') got message %u of size %u from peer (`%s')\n",
  252. receiver->no,
  253. ps,
  254. (uint32_t) ntohl (hdr->num),
  255. ntohs (hdr->header.size),
  256. GNUNET_i2s (sender));
  257. GNUNET_free (ps);
  258. }
  259. if (((stats[0].switch_attempts >= 1) || (stats[1].switch_attempts >= 1)) &&
  260. (stats[0].switch_attempts ==
  261. stats[0].switch_fail + stats[0].switch_success) &&
  262. (stats[1].switch_attempts ==
  263. stats[1].switch_fail + stats[1].switch_success))
  264. {
  265. bytes_recv_after_switch += ntohs (hdr->header.size);
  266. if ((bytes_sent_after_switch > 0) && (bytes_recv_after_switch > 0))
  267. {
  268. /* A peer switched addresses and sent and received data after the
  269. * switch operations */
  270. GNUNET_SCHEDULER_shutdown ();
  271. }
  272. }
  273. }
  274. static void
  275. notify_send (void *cls)
  276. {
  277. static uint32_t cnt;
  278. GNUNET_assert (
  279. GNUNET_OK ==
  280. GNUNET_TRANSPORT_TESTING_send (ccc->p[1],
  281. ccc->p[0],
  282. GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
  283. GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE,
  284. ++cnt,
  285. &notify_send,
  286. NULL));
  287. if (((stats[0].switch_attempts >= 1) || (stats[1].switch_attempts >= 1)) &&
  288. (stats[0].switch_attempts ==
  289. stats[0].switch_fail + stats[0].switch_success) &&
  290. (stats[1].switch_attempts ==
  291. stats[1].switch_fail + stats[1].switch_success))
  292. {
  293. bytes_sent_after_switch += GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE;
  294. }
  295. }
  296. static void
  297. progress_indicator (void *cls)
  298. {
  299. static int counter;
  300. measure_task = NULL;
  301. counter++;
  302. if ((TIMEOUT.rel_value_us / 1000 / 1000LL) < counter)
  303. {
  304. fprintf (stderr, "%s", ".\n");
  305. }
  306. else
  307. {
  308. fprintf (stderr, "%s", ".");
  309. measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
  310. &progress_indicator,
  311. NULL);
  312. }
  313. }
  314. static void
  315. connected_cb (void *cls)
  316. {
  317. for (unsigned int i = 0; i < 2; i++)
  318. {
  319. stats[i].stat = GNUNET_STATISTICS_create ("transport", ccc->p[i]->cfg);
  320. if (NULL == stats[i].stat)
  321. {
  322. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  323. "Fail! Could not create statistics for peers!\n");
  324. ccc->global_ret = GNUNET_SYSERR;
  325. GNUNET_SCHEDULER_shutdown ();
  326. return;
  327. }
  328. for (unsigned int j = 0; NULL != watches[j].stat_name; j++)
  329. {
  330. GNUNET_STATISTICS_watch (stats[i].stat,
  331. "transport",
  332. watches[j].stat_name,
  333. watches[j].stat_handler,
  334. &stats[i]);
  335. }
  336. }
  337. /* Show progress */
  338. ccc->global_ret = GNUNET_OK;
  339. measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
  340. &progress_indicator,
  341. NULL);
  342. /* Peers are connected, start transmit test messages */
  343. GNUNET_assert (
  344. GNUNET_OK ==
  345. GNUNET_TRANSPORT_TESTING_send (ccc->p[1],
  346. ccc->p[0],
  347. GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
  348. GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE,
  349. 0,
  350. &notify_send,
  351. NULL));
  352. }
  353. int
  354. main (int argc, char *argv[])
  355. {
  356. struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc =
  357. { .connect_continuation = &connected_cb,
  358. .config_file = "test_transport_api_data.conf",
  359. .rec = &notify_receive,
  360. .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
  361. .shutdown_task = &custom_shutdown,
  362. .timeout = TIMEOUT };
  363. ccc = &my_ccc;
  364. int ret;
  365. ret = GNUNET_TRANSPORT_TESTING_main (2,
  366. &GNUNET_TRANSPORT_TESTING_connect_check,
  367. ccc);
  368. if (77 == ret)
  369. return 77;
  370. if (GNUNET_OK != ret)
  371. return 1;
  372. return 0;
  373. }
  374. /* end of test_transport_address_switch.c */