test_transport_address_switch.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  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 transfered 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,
  76. "Switch attempted (%p)",
  77. stat);
  78. bytes_recv_after_switch = 0;
  79. bytes_sent_after_switch = 0;
  80. return GNUNET_OK;
  81. }
  82. static int
  83. stat_success_attempt_cb (void *cls,
  84. const char *subsystem,
  85. const char *name,
  86. uint64_t value,
  87. int is_persistent)
  88. {
  89. struct PeerStats *stat = cls;
  90. stat->switch_success++;
  91. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  92. "Switch succeeded (%p)",
  93. stat);
  94. return GNUNET_OK;
  95. }
  96. static int
  97. stat_fail_attempt_cb (void *cls,
  98. const char *subsystem,
  99. const char *name,
  100. uint64_t value,
  101. int is_persistent)
  102. {
  103. struct PeerStats *stat = cls;
  104. if (value == 0)
  105. return GNUNET_OK;
  106. stat->switch_fail++;
  107. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  108. "Switch failed (%p)",
  109. stat);
  110. return GNUNET_OK;
  111. }
  112. static int
  113. stat_addresses_available (void *cls,
  114. const char *subsystem,
  115. const char *name,
  116. uint64_t value,
  117. int is_persistent)
  118. {
  119. struct PeerStats *stat = cls;
  120. stat->addresses_avail++;
  121. return GNUNET_OK;
  122. }
  123. /**
  124. * List of statistics entries we care about.
  125. */
  126. static struct WatchEntry {
  127. /**
  128. * Name of the statistic we watch.
  129. */
  130. const char *stat_name;
  131. /**
  132. * Handler to register;
  133. */
  134. GNUNET_STATISTICS_Iterator stat_handler;
  135. } watches[] = {
  136. { "# Attempts to switch addresses", &stat_start_attempt_cb },
  137. { "# Successful attempts to switch addresses", &stat_success_attempt_cb },
  138. { "# Failed attempts to switch addresses (failed to send CONNECT CONT)", &stat_fail_attempt_cb },
  139. { "# Failed attempts to switch addresses (failed to send CONNECT)", &stat_fail_attempt_cb },
  140. { "# Failed attempts to switch addresses (no response)", &stat_fail_attempt_cb },
  141. { "# transport addresses", &stat_addresses_available },
  142. { NULL, NULL }
  143. };
  144. static void
  145. custom_shutdown (void *cls)
  146. {
  147. int result;
  148. if (NULL != measure_task)
  149. {
  150. GNUNET_SCHEDULER_cancel (measure_task);
  151. measure_task = NULL;
  152. }
  153. if (0 == stats[0].switch_attempts + stats[1].switch_attempts)
  154. {
  155. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  156. "Test did not work, as peers didn't switch (flawed testcase)!\n");
  157. ccc->global_ret = 77;
  158. }
  159. else
  160. {
  161. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  162. "Fail (timeout)! No transmission after switch! Stopping peers\n");
  163. ccc->global_ret = 77; /* GNUNET_SYSERR; */
  164. }
  165. /* stop statistics */
  166. for (unsigned int i=0;i<2;i++)
  167. {
  168. if (NULL != stats[i].stat)
  169. {
  170. for (unsigned int j=0;NULL != watches[j].stat_name; j++)
  171. GNUNET_STATISTICS_watch_cancel (stats[i].stat,
  172. "transport",
  173. watches[j].stat_name,
  174. watches[j].stat_handler,
  175. &stats[i]);
  176. GNUNET_STATISTICS_destroy (stats[i].stat,
  177. GNUNET_NO);
  178. stats[i].stat = NULL;
  179. }
  180. }
  181. result = 0;
  182. FPRINTF (stderr, "\n");
  183. if (stats[0].switch_attempts > 0)
  184. {
  185. FPRINTF (stderr,
  186. "Peer 1 tried %u times to switch and succeeded %u times, failed %u times\n",
  187. stats[0].switch_attempts,
  188. stats[0].switch_success,
  189. stats[0].switch_fail);
  190. if (stats[0].switch_success != stats[0].switch_attempts)
  191. {
  192. GNUNET_break (0);
  193. result ++;
  194. }
  195. }
  196. else if (stats[0].addresses_avail > 1)
  197. {
  198. FPRINTF (stderr,
  199. "Peer 1 had %u addresses available, but did not try to switch\n",
  200. stats[0].addresses_avail);
  201. }
  202. if (stats[1].switch_attempts > 0)
  203. {
  204. FPRINTF (stderr,
  205. "Peer 2 tried %u times to switch and succeeded %u times, failed %u times\n",
  206. stats[1].switch_attempts,
  207. stats[1].switch_success,
  208. stats[1].switch_fail);
  209. if (stats[1].switch_success != stats[1].switch_attempts)
  210. {
  211. GNUNET_break (0);
  212. result++;
  213. }
  214. }
  215. else if (stats[1].addresses_avail > 1)
  216. {
  217. FPRINTF (stderr,
  218. "Peer 2 had %u addresses available, but did not try to switch\n",
  219. stats[1].addresses_avail);
  220. }
  221. if ( ((stats[0].switch_attempts > 0) || (stats[1].switch_attempts > 0)) &&
  222. (bytes_sent_after_switch == 0) )
  223. {
  224. FPRINTF (stderr,
  225. "No data sent after switching!\n");
  226. GNUNET_break (0);
  227. result++;
  228. }
  229. if ( ((stats[0].switch_attempts > 0) || (stats[1].switch_attempts > 0)) &&
  230. (bytes_recv_after_switch == 0) )
  231. {
  232. FPRINTF (stderr,
  233. "No data received after switching!\n");
  234. GNUNET_break (0);
  235. result++;
  236. }
  237. #if 0
  238. /* This test is not really expected to pass right now... */
  239. if (0 != result)
  240. ccc->global_ret = GNUNET_SYSERR;
  241. #endif
  242. }
  243. static void
  244. notify_receive (void *cls,
  245. struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
  246. const struct GNUNET_PeerIdentity *sender,
  247. const struct GNUNET_TRANSPORT_TESTING_TestMessage *hdr)
  248. {
  249. if (GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE != ntohs (hdr->header.type))
  250. return;
  251. {
  252. char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
  253. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  254. "Peer %u (`%s') got message %u of size %u from peer (`%s')\n",
  255. receiver->no,
  256. ps,
  257. (uint32_t) ntohl (hdr->num),
  258. ntohs (hdr->header.size),
  259. GNUNET_i2s (sender));
  260. GNUNET_free (ps);
  261. }
  262. if ( ((stats[0].switch_attempts >= 1) || (stats[1].switch_attempts >= 1)) &&
  263. (stats[0].switch_attempts == stats[0].switch_fail + stats[0].switch_success) &&
  264. (stats[1].switch_attempts == stats[1].switch_fail + stats[1].switch_success) )
  265. {
  266. bytes_recv_after_switch += ntohs(hdr->header.size);
  267. if ( (bytes_sent_after_switch > 0) &&
  268. (bytes_recv_after_switch > 0) )
  269. {
  270. /* A peer switched addresses and sent and received data after the
  271. * switch operations */
  272. GNUNET_SCHEDULER_shutdown ();
  273. }
  274. }
  275. }
  276. static void
  277. notify_send (void *cls)
  278. {
  279. static uint32_t cnt;
  280. GNUNET_assert (GNUNET_OK ==
  281. GNUNET_TRANSPORT_TESTING_send (ccc->p[1],
  282. ccc->p[0],
  283. GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
  284. GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE,
  285. ++cnt,
  286. &notify_send,
  287. NULL));
  288. if ( ( (stats[0].switch_attempts >= 1) ||
  289. (stats[1].switch_attempts >= 1) ) &&
  290. (stats[0].switch_attempts == stats[0].switch_fail + stats[0].switch_success) &&
  291. (stats[1].switch_attempts == stats[1].switch_fail + stats[1].switch_success) )
  292. {
  293. bytes_sent_after_switch
  294. += GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE;
  295. }
  296. }
  297. static void
  298. progress_indicator (void *cls)
  299. {
  300. static int counter;
  301. measure_task = NULL;
  302. counter++;
  303. if ((TIMEOUT.rel_value_us / 1000 / 1000LL) < counter)
  304. {
  305. FPRINTF (stderr, "%s", ".\n");
  306. }
  307. else
  308. {
  309. FPRINTF (stderr, "%s", ".");
  310. measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
  311. &progress_indicator,
  312. NULL);
  313. }
  314. }
  315. static void
  316. connected_cb (void *cls)
  317. {
  318. for (unsigned int i=0;i<2;i++)
  319. {
  320. stats[i].stat = GNUNET_STATISTICS_create ("transport",
  321. ccc->p[i]->cfg);
  322. if (NULL == stats[i].stat)
  323. {
  324. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  325. "Fail! Could not create statistics for peers!\n");
  326. ccc->global_ret = GNUNET_SYSERR;
  327. GNUNET_SCHEDULER_shutdown ();
  328. return;
  329. }
  330. for (unsigned int j=0;NULL != watches[j].stat_name; j++)
  331. {
  332. GNUNET_STATISTICS_watch (stats[i].stat,
  333. "transport",
  334. watches[j].stat_name,
  335. watches[j].stat_handler,
  336. &stats[i]);
  337. }
  338. }
  339. /* Show progress */
  340. ccc->global_ret = GNUNET_OK;
  341. measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
  342. &progress_indicator,
  343. NULL);
  344. /* Peers are connected, start transmit test messages */
  345. GNUNET_assert (GNUNET_OK ==
  346. GNUNET_TRANSPORT_TESTING_send (ccc->p[1],
  347. ccc->p[0],
  348. GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
  349. GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE,
  350. 0,
  351. &notify_send,
  352. NULL));
  353. }
  354. int
  355. main (int argc,
  356. char *argv[])
  357. {
  358. struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
  359. .connect_continuation = &connected_cb,
  360. .config_file = "test_transport_api_data.conf",
  361. .rec = &notify_receive,
  362. .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
  363. .shutdown_task = &custom_shutdown,
  364. .timeout = TIMEOUT
  365. };
  366. ccc = &my_ccc;
  367. int ret;
  368. ret = GNUNET_TRANSPORT_TESTING_main (2,
  369. &GNUNET_TRANSPORT_TESTING_connect_check,
  370. ccc);
  371. if (77 == ret)
  372. return 77;
  373. if (GNUNET_OK != ret)
  374. return 1;
  375. return 0;
  376. }
  377. /* end of test_transport_address_switch.c */