test_core_api_reliability.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2009, 2010, 2015, 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 core/test_core_api_reliability.c
  18. * @brief testcase for core_api.c focusing on reliable transmission (with TCP)
  19. * @author Christian Grothoff
  20. */
  21. #include "platform.h"
  22. #include "gnunet_arm_service.h"
  23. #include "gnunet_core_service.h"
  24. #include "gnunet_util_lib.h"
  25. #include "gnunet_ats_service.h"
  26. #include "gnunet_transport_service.h"
  27. #include "gnunet_transport_hello_service.h"
  28. #include <gauger.h>
  29. /**
  30. * Note that this value must not significantly exceed
  31. * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise
  32. * messages may be dropped even for a reliable transport.
  33. */
  34. #define TOTAL_MSGS (600 * 10)
  35. /**
  36. * How long until we give up on transmitting the message?
  37. */
  38. #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600)
  39. #define MTYPE 12345
  40. static unsigned long long total_bytes;
  41. static struct GNUNET_TIME_Absolute start_time;
  42. static struct GNUNET_SCHEDULER_Task *err_task;
  43. struct PeerContext
  44. {
  45. struct GNUNET_CONFIGURATION_Handle *cfg;
  46. struct GNUNET_CORE_Handle *ch;
  47. struct GNUNET_MQ_Handle *mq;
  48. struct GNUNET_PeerIdentity id;
  49. struct GNUNET_TRANSPORT_OfferHelloHandle *oh;
  50. struct GNUNET_MessageHeader *hello;
  51. struct GNUNET_TRANSPORT_HelloGetHandle *ghh;
  52. struct GNUNET_ATS_ConnectivityHandle *ats;
  53. struct GNUNET_ATS_ConnectivitySuggestHandle *ats_sh;
  54. int connect_status;
  55. struct GNUNET_OS_Process *arm_proc;
  56. };
  57. static struct PeerContext p1;
  58. static struct PeerContext p2;
  59. static int ok;
  60. static int32_t tr_n;
  61. #define OKPP do { ok++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
  62. struct TestMessage
  63. {
  64. struct GNUNET_MessageHeader header;
  65. uint32_t num GNUNET_PACKED;
  66. };
  67. static unsigned int
  68. get_size (unsigned int iter)
  69. {
  70. unsigned int ret;
  71. if (iter < 60000)
  72. return iter + sizeof (struct TestMessage);
  73. ret = (iter * iter * iter);
  74. return sizeof (struct TestMessage) + (ret % 60000);
  75. }
  76. static void
  77. terminate_peer (struct PeerContext *p)
  78. {
  79. if (NULL != p->ch)
  80. {
  81. GNUNET_CORE_disconnect (p->ch);
  82. p->ch = NULL;
  83. }
  84. if (NULL != p->ghh)
  85. {
  86. GNUNET_TRANSPORT_hello_get_cancel (p->ghh);
  87. p->ghh = NULL;
  88. }
  89. if (NULL != p->oh)
  90. {
  91. GNUNET_TRANSPORT_offer_hello_cancel (p->oh);
  92. p->oh = NULL;
  93. }
  94. if (NULL != p->ats_sh)
  95. {
  96. GNUNET_ATS_connectivity_suggest_cancel (p->ats_sh);
  97. p->ats_sh = NULL;
  98. }
  99. if (NULL != p->ats)
  100. {
  101. GNUNET_ATS_connectivity_done (p->ats);
  102. p->ats = NULL;
  103. }
  104. }
  105. static void
  106. terminate_task_error (void *cls)
  107. {
  108. err_task = NULL;
  109. GNUNET_break (0);
  110. GNUNET_SCHEDULER_shutdown ();
  111. ok = 42;
  112. }
  113. static void
  114. do_shutdown (void *cls)
  115. {
  116. unsigned long long delta;
  117. delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value_us;
  118. if (0 == delta)
  119. delta = 1;
  120. FPRINTF (stderr,
  121. "\nThroughput was %llu kb/s\n",
  122. total_bytes * 1000000LL / 1024 / delta);
  123. GAUGER ("CORE",
  124. "Core throughput/s",
  125. total_bytes * 1000000LL / 1024 / delta,
  126. "kb/s");
  127. if (NULL != err_task)
  128. {
  129. GNUNET_SCHEDULER_cancel (err_task);
  130. err_task = NULL;
  131. }
  132. terminate_peer (&p1);
  133. terminate_peer (&p2);
  134. }
  135. static void
  136. send_message (struct GNUNET_MQ_Handle *mq,
  137. int32_t num)
  138. {
  139. struct GNUNET_MQ_Envelope *env;
  140. struct TestMessage *hdr;
  141. unsigned int s;
  142. GNUNET_assert (NULL != mq);
  143. GNUNET_assert (tr_n < TOTAL_MSGS);
  144. s = get_size (tr_n);
  145. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  146. "Sending message %u of size %u\n",
  147. tr_n,
  148. s);
  149. env = GNUNET_MQ_msg_extra (hdr,
  150. s - sizeof (struct TestMessage),
  151. MTYPE);
  152. hdr->num = htonl (tr_n);
  153. memset (&hdr[1],
  154. tr_n,
  155. s - sizeof (struct TestMessage));
  156. tr_n++;
  157. GNUNET_SCHEDULER_cancel (err_task);
  158. err_task =
  159. GNUNET_SCHEDULER_add_delayed (TIMEOUT,
  160. &terminate_task_error,
  161. NULL);
  162. total_bytes += s;
  163. GNUNET_MQ_send (mq,
  164. env);
  165. }
  166. static void *
  167. connect_notify (void *cls,
  168. const struct GNUNET_PeerIdentity *peer,
  169. struct GNUNET_MQ_Handle *mq)
  170. {
  171. struct PeerContext *pc = cls;
  172. if (0 == memcmp (&pc->id,
  173. peer,
  174. sizeof (struct GNUNET_PeerIdentity)))
  175. return (void *) peer;
  176. pc->mq = mq;
  177. GNUNET_assert (0 == pc->connect_status);
  178. pc->connect_status = 1;
  179. if (pc == &p1)
  180. {
  181. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  182. "Encrypted connection established to peer `%s'\n",
  183. GNUNET_i2s (peer));
  184. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  185. "Asking core (1) for transmission to peer `%s'\n",
  186. GNUNET_i2s (&p2.id));
  187. GNUNET_SCHEDULER_cancel (err_task);
  188. err_task =
  189. GNUNET_SCHEDULER_add_delayed (TIMEOUT,
  190. &terminate_task_error,
  191. NULL);
  192. start_time = GNUNET_TIME_absolute_get ();
  193. send_message (mq,
  194. 0);
  195. }
  196. return (void *) peer;
  197. }
  198. static void
  199. disconnect_notify (void *cls,
  200. const struct GNUNET_PeerIdentity *peer,
  201. void *internal_cls)
  202. {
  203. struct PeerContext *pc = cls;
  204. if (0 == memcmp (&pc->id,
  205. peer,
  206. sizeof (struct GNUNET_PeerIdentity)))
  207. return;
  208. pc->mq = NULL;
  209. pc->connect_status = 0;
  210. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  211. "Encrypted connection to `%s' cut\n",
  212. GNUNET_i2s (peer));
  213. }
  214. static int
  215. check_test (void *cls,
  216. const struct TestMessage *hdr)
  217. {
  218. return GNUNET_OK; /* accept all */
  219. }
  220. static void
  221. handle_test (void *cls,
  222. const struct TestMessage *hdr)
  223. {
  224. static int n;
  225. unsigned int s;
  226. s = get_size (n);
  227. if (ntohs (hdr->header.size) != s)
  228. {
  229. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  230. "Expected message %u of size %u, got %u bytes of message %u\n",
  231. n,
  232. s,
  233. ntohs (hdr->header.size),
  234. ntohl (hdr->num));
  235. GNUNET_SCHEDULER_cancel (err_task);
  236. err_task = GNUNET_SCHEDULER_add_now (&terminate_task_error,
  237. NULL);
  238. return;
  239. }
  240. if (ntohl (hdr->num) != n)
  241. {
  242. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  243. "Expected message %u of size %u, got %u bytes of message %u\n",
  244. n,
  245. s,
  246. (unsigned int) ntohs (hdr->header.size),
  247. (unsigned int) ntohl (hdr->num));
  248. GNUNET_SCHEDULER_cancel (err_task);
  249. err_task = GNUNET_SCHEDULER_add_now (&terminate_task_error,
  250. NULL);
  251. return;
  252. }
  253. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  254. "Got message %u of size %u\n",
  255. (unsigned int) ntohl (hdr->num),
  256. (unsigned int) ntohs (hdr->header.size));
  257. n++;
  258. if (0 == (n % (TOTAL_MSGS / 100)))
  259. FPRINTF (stderr,
  260. "%s",
  261. ".");
  262. if (n == TOTAL_MSGS)
  263. {
  264. ok = 0;
  265. GNUNET_SCHEDULER_shutdown ();
  266. }
  267. else
  268. {
  269. if (n == tr_n)
  270. {
  271. send_message (p1.mq,
  272. tr_n);
  273. }
  274. }
  275. }
  276. static void
  277. init_notify (void *cls,
  278. const struct GNUNET_PeerIdentity *my_identity)
  279. {
  280. struct PeerContext *p = cls;
  281. struct GNUNET_MQ_MessageHandler handlers[] = {
  282. GNUNET_MQ_hd_var_size (test,
  283. MTYPE,
  284. struct TestMessage,
  285. NULL),
  286. GNUNET_MQ_handler_end ()
  287. };
  288. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  289. "Connection to CORE service of `%s' established\n",
  290. GNUNET_i2s (my_identity));
  291. p->id = *my_identity;
  292. if (cls == &p1)
  293. {
  294. GNUNET_assert (ok == 2);
  295. OKPP;
  296. /* connect p2 */
  297. GNUNET_assert (NULL !=
  298. (p2.ch = GNUNET_CORE_connect (p2.cfg,
  299. &p2,
  300. &init_notify,
  301. &connect_notify,
  302. &disconnect_notify,
  303. handlers)));
  304. }
  305. else
  306. {
  307. GNUNET_assert (ok == 3);
  308. OKPP;
  309. GNUNET_assert (cls == &p2);
  310. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  311. "Asking transport (1) to connect to peer `%s'\n",
  312. GNUNET_i2s (&p2.id));
  313. p1.ats_sh = GNUNET_ATS_connectivity_suggest (p1.ats,
  314. &p2.id,
  315. 1);
  316. }
  317. }
  318. static void
  319. offer_hello_done (void *cls)
  320. {
  321. struct PeerContext *p = cls;
  322. p->oh = NULL;
  323. }
  324. static void
  325. process_hello (void *cls,
  326. const struct GNUNET_MessageHeader *message)
  327. {
  328. struct PeerContext *p = cls;
  329. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  330. "Received (my) `%s' from transport service\n", "HELLO");
  331. GNUNET_assert (message != NULL);
  332. GNUNET_free_non_null (p->hello);
  333. p->hello = GNUNET_copy_message (message);
  334. if ((p == &p1) && (NULL == p2.oh))
  335. p2.oh = GNUNET_TRANSPORT_offer_hello (p2.cfg,
  336. message,
  337. &offer_hello_done,
  338. &p2);
  339. if ((p == &p2) && (NULL == p1.oh))
  340. p1.oh = GNUNET_TRANSPORT_offer_hello (p1.cfg,
  341. message,
  342. &offer_hello_done,
  343. &p1);
  344. if ((p == &p1) && (p2.hello != NULL) && (NULL == p1.oh) )
  345. p1.oh = GNUNET_TRANSPORT_offer_hello (p1.cfg,
  346. p2.hello,
  347. &offer_hello_done,
  348. &p1);
  349. if ((p == &p2) && (p1.hello != NULL) && (NULL == p2.oh) )
  350. p2.oh = GNUNET_TRANSPORT_offer_hello (p2.cfg,
  351. p1.hello,
  352. &offer_hello_done,
  353. &p2);
  354. }
  355. static void
  356. setup_peer (struct PeerContext *p,
  357. const char *cfgname)
  358. {
  359. char *binary;
  360. binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
  361. p->cfg = GNUNET_CONFIGURATION_create ();
  362. p->arm_proc
  363. = GNUNET_OS_start_process (GNUNET_YES,
  364. GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
  365. NULL, NULL, NULL,
  366. binary,
  367. "gnunet-service-arm",
  368. "-c",
  369. cfgname,
  370. NULL);
  371. GNUNET_assert (GNUNET_OK ==
  372. GNUNET_CONFIGURATION_load (p->cfg,
  373. cfgname));
  374. p->ats = GNUNET_ATS_connectivity_init (p->cfg);
  375. GNUNET_assert (NULL != p->ats);
  376. p->ghh = GNUNET_TRANSPORT_hello_get (p->cfg,
  377. GNUNET_TRANSPORT_AC_ANY,
  378. &process_hello,
  379. p);
  380. GNUNET_free (binary);
  381. }
  382. static void
  383. run (void *cls,
  384. char *const *args,
  385. const char *cfgfile,
  386. const struct GNUNET_CONFIGURATION_Handle *cfg)
  387. {
  388. struct GNUNET_MQ_MessageHandler handlers[] = {
  389. GNUNET_MQ_hd_fixed_size (test,
  390. MTYPE,
  391. struct TestMessage,
  392. NULL),
  393. GNUNET_MQ_handler_end ()
  394. };
  395. GNUNET_assert (ok == 1);
  396. OKPP;
  397. setup_peer (&p1,
  398. "test_core_api_peer1.conf");
  399. setup_peer (&p2,
  400. "test_core_api_peer2.conf");
  401. err_task =
  402. GNUNET_SCHEDULER_add_delayed (TIMEOUT,
  403. &terminate_task_error,
  404. NULL);
  405. GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
  406. NULL);
  407. GNUNET_assert (NULL !=
  408. (p1.ch = GNUNET_CORE_connect (p1.cfg,
  409. &p1,
  410. &init_notify,
  411. &connect_notify,
  412. &disconnect_notify,
  413. handlers)));
  414. }
  415. static void
  416. stop_arm (struct PeerContext *p)
  417. {
  418. if (0 != GNUNET_OS_process_kill (p->arm_proc,
  419. GNUNET_TERM_SIG))
  420. GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
  421. "kill");
  422. if (GNUNET_OK != GNUNET_OS_process_wait (p->arm_proc))
  423. GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
  424. "waitpid");
  425. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  426. "ARM process %u stopped\n",
  427. GNUNET_OS_process_get_pid (p->arm_proc));
  428. GNUNET_OS_process_destroy (p->arm_proc);
  429. p->arm_proc = NULL;
  430. GNUNET_CONFIGURATION_destroy (p->cfg);
  431. }
  432. int
  433. main (int argc,
  434. char *argv1[])
  435. {
  436. char *const argv[] = {
  437. "test-core-api-reliability",
  438. "-c",
  439. "test_core_api_data.conf",
  440. NULL
  441. };
  442. struct GNUNET_GETOPT_CommandLineOption options[] = {
  443. GNUNET_GETOPT_OPTION_END
  444. };
  445. ok = 1;
  446. GNUNET_log_setup ("test-core-api-reliability",
  447. "WARNING",
  448. NULL);
  449. GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
  450. argv,
  451. "test-core-api-reliability",
  452. "nohelp",
  453. options,
  454. &run,
  455. &ok);
  456. stop_arm (&p1);
  457. stop_arm (&p2);
  458. GNUNET_free_non_null (p1.hello);
  459. GNUNET_free_non_null (p2.hello);
  460. GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-1");
  461. GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-2");
  462. return ok;
  463. }
  464. /* end of test_core_api_reliability.c */