test_communicator_basic.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2019 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_communicator_basic.c
  18. * @brief test the communicators
  19. * @author Julius Bünger
  20. * @author Martin Schanzenbach
  21. */
  22. #include "platform.h"
  23. #include "gnunet_util_lib.h"
  24. #include "transport-testing2.h"
  25. #include "gnunet_ats_transport_service.h"
  26. #include "gnunet_signatures.h"
  27. #include "gnunet_testing_lib.h"
  28. #include "transport.h"
  29. #include <inttypes.h>
  30. #define LOG(kind, ...) GNUNET_log_from (kind, \
  31. "test_transport_communicator", \
  32. __VA_ARGS__)
  33. #define NUM_PEERS 2
  34. static struct GNUNET_SCHEDULER_Task *to_task;
  35. static int queue_est = GNUNET_NO;
  36. static struct GNUNET_PeerIdentity peer_id[NUM_PEERS];
  37. static char *communicator_binary;
  38. static struct
  39. GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_hs[NUM_PEERS];
  40. static struct GNUNET_CONFIGURATION_Handle *cfg_peers[NUM_PEERS];
  41. static char *cfg_peers_name[NUM_PEERS];
  42. static int ret;
  43. static size_t long_message_size;
  44. static struct GNUNET_TIME_Absolute start_short;
  45. static struct GNUNET_TIME_Absolute start_long;
  46. static struct GNUNET_TIME_Absolute timeout;
  47. static struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *my_tc;
  48. #define SHORT_MESSAGE_SIZE 128
  49. #define LONG_MESSAGE_SIZE 32000 /* FIXME */
  50. #define BURST_PACKETS 5000
  51. #define TOTAL_ITERATIONS 1
  52. #define PEER_A 0
  53. #define PEER_B 1
  54. static unsigned int iterations_left = TOTAL_ITERATIONS;
  55. #define SHORT_BURST_WINDOW \
  56. GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,2)
  57. #define LONG_BURST_WINDOW \
  58. GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,2)
  59. enum TestPhase
  60. {
  61. TP_INIT,
  62. TP_BURST_SHORT,
  63. TP_BURST_LONG,
  64. TP_SIZE_CHECK
  65. };
  66. static size_t num_sent = 0;
  67. static uint32_t ack = 0;
  68. static enum TestPhase phase;
  69. static size_t num_received = 0;
  70. static uint64_t avg_latency = 0;
  71. static struct GNUNET_TIME_Relative duration;
  72. static void
  73. communicator_available_cb (void *cls,
  74. struct
  75. GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
  76. *tc_h,
  77. enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc,
  78. char *address_prefix)
  79. {
  80. LOG (GNUNET_ERROR_TYPE_INFO,
  81. "Communicator available. (cc: %u, prefix: %s)\n",
  82. cc,
  83. address_prefix);
  84. }
  85. static void
  86. add_address_cb (void *cls,
  87. struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *
  88. tc_h,
  89. const char *address,
  90. struct GNUNET_TIME_Relative expiration,
  91. uint32_t aid,
  92. enum GNUNET_NetworkType nt)
  93. {
  94. LOG (GNUNET_ERROR_TYPE_DEBUG,
  95. "New address. (addr: %s, expir: %" PRIu32 ", ID: %" PRIu32 ", nt: %u\n",
  96. address,
  97. expiration.rel_value_us,
  98. aid,
  99. nt);
  100. // addresses[1] = GNUNET_strdup (address);
  101. if ((0 == strcmp ((char*) cls, cfg_peers_name[PEER_B])) &&
  102. (GNUNET_NO == queue_est))
  103. {
  104. queue_est = GNUNET_YES;
  105. GNUNET_TRANSPORT_TESTING_transport_communicator_open_queue (tc_hs[PEER_A],
  106. &peer_id[PEER_B],
  107. address);
  108. }
  109. }
  110. /**
  111. * @brief Callback that informs whether the requested queue will be
  112. * established
  113. *
  114. * Implements #GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback.
  115. *
  116. * @param cls Closure - unused
  117. * @param tc_h Communicator handle - unused
  118. * @param will_try #GNUNET_YES if queue will be established
  119. * #GNUNET_NO if queue will not be established (bogous address)
  120. */
  121. static void
  122. queue_create_reply_cb (void *cls,
  123. struct
  124. GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *
  125. tc_h,
  126. int will_try)
  127. {
  128. if (GNUNET_YES == will_try)
  129. LOG (GNUNET_ERROR_TYPE_DEBUG,
  130. "Queue will be established!\n");
  131. else
  132. LOG (GNUNET_ERROR_TYPE_WARNING,
  133. "Queue won't be established (bougus address?)!\n");
  134. }
  135. static struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *
  136. handle_backchannel_cb (void *cls,
  137. struct GNUNET_MessageHeader *msg,
  138. struct GNUNET_PeerIdentity *pid)
  139. {
  140. struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
  141. LOG (GNUNET_ERROR_TYPE_DEBUG, "Handling BC message...\n");
  142. if (0 == memcmp (&peer_id[PEER_A], pid, sizeof (*pid)))
  143. return tc_hs[PEER_A];
  144. else
  145. return tc_hs[PEER_B];
  146. }
  147. static char*
  148. make_payload (size_t payload_size)
  149. {
  150. struct GNUNET_TIME_Absolute ts;
  151. struct GNUNET_TIME_AbsoluteNBO ts_n;
  152. char *payload = GNUNET_malloc (payload_size);
  153. LOG (GNUNET_ERROR_TYPE_DEBUG,
  154. "Making payload of size %lu\n", payload_size);
  155. GNUNET_assert (payload_size >= 8); // So that out timestamp fits
  156. ts = GNUNET_TIME_absolute_get ();
  157. ts_n = GNUNET_TIME_absolute_hton (ts);
  158. memset (payload, 0, payload_size);
  159. memcpy (payload, &ts_n, sizeof (struct GNUNET_TIME_AbsoluteNBO));
  160. return payload;
  161. }
  162. static void
  163. latency_timeout (void *cls)
  164. {
  165. to_task = NULL;
  166. if (GNUNET_TIME_absolute_get_remaining (timeout).rel_value_us > 0)
  167. {
  168. to_task = GNUNET_SCHEDULER_add_at (timeout,
  169. &latency_timeout,
  170. NULL);
  171. return;
  172. }
  173. LOG (GNUNET_ERROR_TYPE_ERROR,
  174. "Latency too high. Test failed. (Phase: %d. Sent: %lu, Received: %lu)\n",
  175. phase, num_sent, num_received);
  176. ret = 2;
  177. GNUNET_SCHEDULER_shutdown ();
  178. }
  179. static void
  180. size_test (void *cls)
  181. {
  182. char *payload;
  183. size_t max_size = 64000;
  184. GNUNET_assert (TP_SIZE_CHECK == phase);
  185. if (LONG_MESSAGE_SIZE != long_message_size)
  186. max_size = long_message_size;
  187. if (ack + 10 > max_size)
  188. return; /* Leave some room for our protocol, so not 2^16 exactly */
  189. ack += 10;
  190. payload = make_payload (ack);
  191. num_sent++;
  192. GNUNET_TRANSPORT_TESTING_transport_communicator_send (my_tc,
  193. (ack < max_size)
  194. ? &size_test
  195. : NULL,
  196. NULL,
  197. payload,
  198. ack);
  199. GNUNET_free (payload);
  200. timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_SECONDS);
  201. }
  202. static void
  203. long_test (void *cls)
  204. {
  205. char *payload;
  206. payload = make_payload (long_message_size);
  207. num_sent++;
  208. GNUNET_TRANSPORT_TESTING_transport_communicator_send (my_tc,
  209. (BURST_PACKETS ==
  210. num_sent)
  211. ? NULL
  212. : &long_test,
  213. NULL,
  214. payload,
  215. long_message_size);
  216. GNUNET_free (payload);
  217. timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_SECONDS);
  218. }
  219. static void
  220. short_test (void *cls)
  221. {
  222. char *payload;
  223. payload = make_payload (SHORT_MESSAGE_SIZE);
  224. num_sent++;
  225. GNUNET_TRANSPORT_TESTING_transport_communicator_send (my_tc,
  226. (BURST_PACKETS ==
  227. num_sent)
  228. ? NULL
  229. : &short_test,
  230. NULL,
  231. payload,
  232. SHORT_MESSAGE_SIZE);
  233. GNUNET_free (payload);
  234. timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_SECONDS);
  235. }
  236. static int test_prepared = GNUNET_NO;
  237. /**
  238. * This helps establishing the backchannel
  239. */
  240. static void
  241. prepare_test (void *cls)
  242. {
  243. char *payload;
  244. if (GNUNET_YES == test_prepared)
  245. {
  246. GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
  247. &short_test,
  248. NULL);
  249. return;
  250. }
  251. test_prepared = GNUNET_YES;
  252. payload = make_payload (SHORT_MESSAGE_SIZE);
  253. GNUNET_TRANSPORT_TESTING_transport_communicator_send (my_tc,
  254. &prepare_test,
  255. NULL,
  256. payload,
  257. SHORT_MESSAGE_SIZE);
  258. GNUNET_free (payload);
  259. }
  260. /**
  261. * @brief Handle opening of queue
  262. *
  263. * Issues sending of test data
  264. *
  265. * Implements #GNUNET_TRANSPORT_TESTING_AddQueueCallback
  266. *
  267. * @param cls Closure
  268. * @param tc_h Communicator handle
  269. * @param tc_queue Handle to newly opened queue
  270. */
  271. static void
  272. add_queue_cb (void *cls,
  273. struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
  274. struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *
  275. tc_queue,
  276. size_t mtu)
  277. {
  278. if (TP_INIT != phase)
  279. return;
  280. if (0 != strcmp ((char*) cls, cfg_peers_name[0]))
  281. return; // TODO?
  282. LOG (GNUNET_ERROR_TYPE_DEBUG,
  283. "Queue established, starting test...\n");
  284. start_short = GNUNET_TIME_absolute_get ();
  285. my_tc = tc_h;
  286. if (0 != mtu)
  287. long_message_size = mtu - 4; /* Dummy message header overhead */
  288. else
  289. long_message_size = LONG_MESSAGE_SIZE;
  290. phase = TP_BURST_SHORT;
  291. timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES);
  292. GNUNET_assert (NULL == to_task);
  293. to_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
  294. &latency_timeout,
  295. NULL);
  296. prepare_test (NULL);
  297. }
  298. static void
  299. update_avg_latency (const char*payload)
  300. {
  301. struct GNUNET_TIME_AbsoluteNBO *ts_n;
  302. struct GNUNET_TIME_Absolute ts;
  303. struct GNUNET_TIME_Relative latency;
  304. ts_n = (struct GNUNET_TIME_AbsoluteNBO *) payload;
  305. ts = GNUNET_TIME_absolute_ntoh (*ts_n);
  306. latency = GNUNET_TIME_absolute_get_duration (ts);
  307. if (1 >= num_received)
  308. avg_latency = latency.rel_value_us;
  309. else
  310. avg_latency = ((avg_latency * (num_received - 1)) + latency.rel_value_us)
  311. / num_received;
  312. }
  313. /**
  314. * @brief Handle an incoming message
  315. *
  316. * Implements #GNUNET_TRANSPORT_TESTING_IncomingMessageCallback
  317. * @param cls Closure
  318. * @param tc_h Handle to the receiving communicator
  319. * @param msg Received message
  320. */
  321. static void
  322. incoming_message_cb (void *cls,
  323. struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
  324. *tc_h,
  325. const char*payload,
  326. size_t payload_len)
  327. {
  328. if (0 != strcmp ((char*) cls, cfg_peers_name[NUM_PEERS - 1]))
  329. {
  330. LOG (GNUNET_ERROR_TYPE_WARNING,
  331. "unexpected receiver...\n");
  332. return;
  333. }
  334. /* Reset timeout */
  335. timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_SECONDS);
  336. switch (phase)
  337. {
  338. case TP_INIT:
  339. GNUNET_break (0);
  340. break;
  341. case TP_BURST_SHORT:
  342. {
  343. GNUNET_assert (SHORT_MESSAGE_SIZE == payload_len);
  344. num_received++;
  345. duration = GNUNET_TIME_absolute_get_duration (start_short);
  346. update_avg_latency (payload);
  347. if (num_received == BURST_PACKETS)
  348. {
  349. LOG (GNUNET_ERROR_TYPE_MESSAGE,
  350. "Short size packet test done.\n");
  351. char *goodput = GNUNET_STRINGS_byte_size_fancy ((SHORT_MESSAGE_SIZE
  352. * num_received * 1000
  353. * 1000)
  354. / duration.rel_value_us);
  355. LOG (GNUNET_ERROR_TYPE_MESSAGE,
  356. "%lu/%lu packets in %llu us (%s/s) -- avg latency: %llu us\n",
  357. (unsigned long) num_received,
  358. (unsigned long) num_sent,
  359. (unsigned long long) duration.rel_value_us,
  360. goodput,
  361. (unsigned long long) avg_latency);
  362. GNUNET_free (goodput);
  363. start_long = GNUNET_TIME_absolute_get ();
  364. phase = TP_BURST_LONG;
  365. num_sent = 0;
  366. avg_latency = 0;
  367. num_received = 0;
  368. long_test (NULL);
  369. }
  370. break;
  371. }
  372. case TP_BURST_LONG:
  373. {
  374. if (long_message_size != payload_len)
  375. {
  376. LOG (GNUNET_ERROR_TYPE_WARNING,
  377. "Ignoring packet with wrong length\n");
  378. return; // Ignore
  379. }
  380. num_received++;
  381. duration = GNUNET_TIME_absolute_get_duration (start_long);
  382. update_avg_latency (payload);
  383. if (num_received == BURST_PACKETS)
  384. {
  385. LOG (GNUNET_ERROR_TYPE_MESSAGE,
  386. "Long size packet test done.\n");
  387. char *goodput = GNUNET_STRINGS_byte_size_fancy ((long_message_size
  388. * num_received * 1000
  389. * 1000)
  390. / duration.rel_value_us);
  391. LOG (GNUNET_ERROR_TYPE_MESSAGE,
  392. "%lu/%lu packets in %llu us (%s/s) -- avg latency: %llu us\n",
  393. (unsigned long) num_received,
  394. (unsigned long) num_sent,
  395. (unsigned long long) duration.rel_value_us,
  396. goodput,
  397. (unsigned long long) avg_latency);
  398. GNUNET_free (goodput);
  399. ack = 0;
  400. phase = TP_SIZE_CHECK;
  401. num_received = 0;
  402. num_sent = 0;
  403. avg_latency = 0;
  404. size_test (NULL);
  405. }
  406. break;
  407. }
  408. case TP_SIZE_CHECK:
  409. {
  410. size_t max_size = 64000;
  411. GNUNET_assert (TP_SIZE_CHECK == phase);
  412. if (LONG_MESSAGE_SIZE != long_message_size)
  413. max_size = long_message_size;
  414. num_received++;
  415. update_avg_latency (payload);
  416. if (num_received >= (max_size) / 10)
  417. {
  418. LOG (GNUNET_ERROR_TYPE_MESSAGE,
  419. "Size packet test done.\n");
  420. LOG (GNUNET_ERROR_TYPE_MESSAGE,
  421. "%lu/%lu packets -- avg latency: %llu us\n",
  422. (unsigned long) num_received,
  423. (unsigned long) num_sent,
  424. (unsigned long long) avg_latency);
  425. num_received = 0;
  426. num_sent = 0;
  427. avg_latency = 0;
  428. iterations_left--;
  429. if (0 != iterations_left)
  430. {
  431. start_short = GNUNET_TIME_absolute_get ();
  432. phase = TP_BURST_SHORT;
  433. short_test (NULL);
  434. break;
  435. }
  436. LOG (GNUNET_ERROR_TYPE_DEBUG,
  437. "Finished\n");
  438. GNUNET_SCHEDULER_shutdown ();
  439. }
  440. break;
  441. }
  442. }
  443. }
  444. static void
  445. do_shutdown (void *cls)
  446. {
  447. if (NULL != to_task)
  448. {
  449. GNUNET_SCHEDULER_cancel (to_task);
  450. to_task = NULL;
  451. }
  452. for (unsigned int i = 0; i < NUM_PEERS; i++)
  453. {
  454. GNUNET_TRANSPORT_TESTING_transport_communicator_service_stop (tc_hs[i]);
  455. }
  456. }
  457. /**
  458. * @brief Main function called by the scheduler
  459. *
  460. * @param cls Closure - Handle to configuration
  461. */
  462. static void
  463. run (void *cls)
  464. {
  465. ret = 0;
  466. num_received = 0;
  467. num_sent = 0;
  468. for (unsigned int i = 0; i < NUM_PEERS; i++)
  469. {
  470. tc_hs[i] = GNUNET_TRANSPORT_TESTING_transport_communicator_service_start (
  471. "transport",
  472. communicator_binary,
  473. cfg_peers_name[i],
  474. &peer_id[i],
  475. &communicator_available_cb,
  476. &add_address_cb,
  477. &queue_create_reply_cb,
  478. &add_queue_cb,
  479. &incoming_message_cb,
  480. &handle_backchannel_cb,
  481. cfg_peers_name[i]); /* cls */
  482. }
  483. GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
  484. NULL);
  485. }
  486. int
  487. main (int argc,
  488. char *const *argv)
  489. {
  490. struct GNUNET_CRYPTO_EddsaPrivateKey *private_key;
  491. char *communicator_name;
  492. char *test_mode;
  493. char *test_name;
  494. char *cfg_peer;
  495. phase = TP_INIT;
  496. ret = 1;
  497. test_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
  498. communicator_name = strchr (test_name, '-');
  499. communicator_name[0] = '\0';
  500. communicator_name++;
  501. test_mode = test_name;
  502. GNUNET_asprintf (&communicator_binary,
  503. "gnunet-communicator-%s",
  504. communicator_name);
  505. if (GNUNET_OK !=
  506. GNUNET_log_setup ("test_communicator_basic",
  507. "DEBUG",
  508. NULL))
  509. {
  510. fprintf (stderr, "Unable to setup log\n");
  511. GNUNET_break (0);
  512. return 2;
  513. }
  514. for (unsigned int i = 0; i < NUM_PEERS; i++)
  515. {
  516. GNUNET_asprintf ((&cfg_peer),
  517. "test_communicator_%s_%s_peer%u.conf",
  518. communicator_name, test_mode, i + 1);
  519. cfg_peers_name[i] = cfg_peer;
  520. cfg_peers[i] = GNUNET_CONFIGURATION_create ();
  521. if (GNUNET_YES ==
  522. GNUNET_DISK_file_test (cfg_peers_name[i]))
  523. {
  524. if (GNUNET_SYSERR ==
  525. GNUNET_CONFIGURATION_load (cfg_peers[i],
  526. cfg_peers_name[i]))
  527. {
  528. fprintf (stderr,
  529. "Malformed configuration file `%s', exiting ...\n",
  530. cfg_peers_name[i]);
  531. return 1;
  532. }
  533. }
  534. else
  535. {
  536. if (GNUNET_SYSERR ==
  537. GNUNET_CONFIGURATION_load (cfg_peers[i],
  538. NULL))
  539. {
  540. fprintf (stderr,
  541. "Configuration file %s does not exist, exiting ...\n",
  542. cfg_peers_name[i]);
  543. return 1;
  544. }
  545. }
  546. private_key =
  547. GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg_peers[i]);
  548. if (NULL == private_key)
  549. {
  550. LOG (GNUNET_ERROR_TYPE_ERROR,
  551. "Unable to get peer ID\n");
  552. return 1;
  553. }
  554. GNUNET_CRYPTO_eddsa_key_get_public (private_key,
  555. &peer_id[i].public_key);
  556. GNUNET_free (private_key);
  557. LOG (GNUNET_ERROR_TYPE_INFO,
  558. "Identity of peer %u is %s\n",
  559. i,
  560. GNUNET_i2s_full (&peer_id[i]));
  561. }
  562. LOG (GNUNET_ERROR_TYPE_MESSAGE, "Starting test...\n");
  563. GNUNET_SCHEDULER_run (&run,
  564. NULL);
  565. return ret;
  566. }