transport_api_cmd_start_peer.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. /*
  2. This file is part of GNUnet
  3. Copyright (C) 2021 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 testing_api_cmd_start_peer.c
  18. * @brief cmd to start a peer.
  19. * @author t3sserakt
  20. */
  21. #include "platform.h"
  22. #include "gnunet_util_lib.h"
  23. #include "gnunet_testing_ng_lib.h"
  24. #include "gnunet_peerstore_service.h"
  25. #include "gnunet_transport_core_service.h"
  26. #include "gnunet_transport_application_service.h"
  27. #include "transport-testing-cmds.h"
  28. /**
  29. * Generic logging shortcut
  30. */
  31. #define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
  32. static void
  33. retrieve_hello (void *cls);
  34. /**
  35. * Callback delivering the hello of this peer from peerstore.
  36. *
  37. */
  38. static void
  39. hello_iter_cb (void *cb_cls,
  40. const struct GNUNET_PEERSTORE_Record *record,
  41. const char *emsg)
  42. {
  43. struct StartPeerState *sps = cb_cls;
  44. if (NULL == record)
  45. {
  46. sps->pic = NULL;
  47. sps->rh_task = GNUNET_SCHEDULER_add_now (retrieve_hello, sps);
  48. return;
  49. }
  50. // Check record type et al?
  51. sps->hello_size = record->value_size;
  52. sps->hello = GNUNET_malloc (sps->hello_size);
  53. memcpy (sps->hello, record->value, sps->hello_size);
  54. sps->hello[sps->hello_size - 1] = '\0';
  55. GNUNET_PEERSTORE_iterate_cancel (sps->pic);
  56. sps->pic = NULL;
  57. sps->finished = GNUNET_YES;
  58. }
  59. /**
  60. * Function to start the retrieval task to retrieve the hello of this peer
  61. * from the peerstore.
  62. *
  63. */
  64. static void
  65. retrieve_hello (void *cls)
  66. {
  67. struct StartPeerState *sps = cls;
  68. sps->rh_task = NULL;
  69. sps->pic = GNUNET_PEERSTORE_iterate (sps->ph,
  70. "transport",
  71. &sps->id,
  72. GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
  73. hello_iter_cb,
  74. sps);
  75. }
  76. /**
  77. * This function checks StartPeerState#finished, which is set when the hello was retrieved.
  78. *
  79. */
  80. static int
  81. start_peer_finish (void *cls,
  82. GNUNET_SCHEDULER_TaskCallback cont,
  83. void *cont_cls)
  84. {
  85. struct StartPeerState *sps = cls;
  86. if (GNUNET_YES == sps->finished)
  87. {
  88. cont (cont_cls);
  89. }
  90. return sps->finished;
  91. }
  92. /**
  93. * Disconnect callback for the connection to the core service.
  94. *
  95. */
  96. static void
  97. notify_disconnect (void *cls,
  98. const struct GNUNET_PeerIdentity *peer,
  99. void *handler_cls)
  100. {
  101. struct StartPeerState *sps = cls;
  102. LOG (GNUNET_ERROR_TYPE_DEBUG,
  103. "Peer %s disconnected from peer %u (`%s')\n",
  104. GNUNET_i2s (peer),
  105. sps->no,
  106. GNUNET_i2s (&sps->id));
  107. }
  108. /**
  109. * Connect callback for the connection to the core service.
  110. *
  111. */
  112. static void *
  113. notify_connect (void *cls,
  114. const struct GNUNET_PeerIdentity *peer,
  115. struct GNUNET_MQ_Handle *mq)
  116. {
  117. struct StartPeerState *sps = cls;
  118. struct GNUNET_ShortHashCode *key = GNUNET_new (struct GNUNET_ShortHashCode);
  119. struct GNUNET_HashCode hc;
  120. int node_number;
  121. void *ret = NULL;
  122. LOG (GNUNET_ERROR_TYPE_DEBUG,
  123. "Peer %s connected to peer %u (`%s')\n",
  124. GNUNET_i2s (peer),
  125. sps->no,
  126. GNUNET_i2s (&sps->id));
  127. // TODO we need to store with a key identifying the netns node in the future. For now we have only one connecting node.
  128. node_number = 1;
  129. GNUNET_CRYPTO_hash (&node_number, sizeof(node_number), &hc);
  130. memcpy (key,
  131. &hc,
  132. sizeof (*key));
  133. GNUNET_CONTAINER_multishortmap_put (sps->connected_peers_map,
  134. key,
  135. mq,
  136. GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
  137. GNUNET_free (key);
  138. // TODO what does the handler function need?
  139. return ret;
  140. }
  141. /**
  142. * The run method of this cmd will start all services of a peer to test the transport service.
  143. *
  144. */
  145. static void
  146. start_peer_run (void *cls,
  147. const struct GNUNET_TESTING_Command *cmd,
  148. struct GNUNET_TESTING_Interpreter *is)
  149. {
  150. struct StartPeerState *sps = cls;
  151. char *emsg = NULL;
  152. struct GNUNET_PeerIdentity dummy;
  153. const struct GNUNET_TESTING_Command *system_cmd;
  154. struct GNUNET_TESTING_System *tl_system;
  155. char *home;
  156. char *transport_unix_path;
  157. char *communicator_unix_path;
  158. char *bindto;
  159. if (GNUNET_NO == GNUNET_DISK_file_test (sps->cfgname))
  160. {
  161. LOG (GNUNET_ERROR_TYPE_ERROR,
  162. "File not found: `%s'\n",
  163. sps->cfgname);
  164. GNUNET_TESTING_interpreter_fail ();
  165. return;
  166. }
  167. sps->cfg = GNUNET_CONFIGURATION_create ();
  168. GNUNET_assert (GNUNET_OK ==
  169. GNUNET_CONFIGURATION_load (sps->cfg, sps->cfgname));
  170. GNUNET_asprintf (&home,
  171. "$GNUNET_TMP/test-transport/api-tcp-p%u",
  172. sps->no);
  173. GNUNET_asprintf (&transport_unix_path,
  174. "$GNUNET_RUNTIME_DIR/tng-p%u.sock",
  175. sps->no);
  176. GNUNET_asprintf (&communicator_unix_path,
  177. "$GNUNET_RUNTIME_DIR/tcp-comm-p%u.sock",
  178. sps->no);
  179. GNUNET_asprintf (&bindto,
  180. "%s:60002",
  181. sps->node_ip);
  182. GNUNET_CONFIGURATION_set_value_string (sps->cfg, "PATHS", "GNUNET_TEST_HOME",
  183. home);
  184. GNUNET_CONFIGURATION_set_value_string (sps->cfg, "transport", "UNIXPATH",
  185. transport_unix_path);
  186. GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-tcp",
  187. "BINDTO",
  188. bindto);
  189. GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-tcp",
  190. "UNIXPATH",
  191. communicator_unix_path);
  192. system_cmd = GNUNET_TESTING_interpreter_lookup_command (sps->system_label);
  193. GNUNET_TESTING_get_trait_test_system (system_cmd,
  194. &tl_system);
  195. sps->tl_system = tl_system;
  196. if (GNUNET_SYSERR ==
  197. GNUNET_TESTING_configuration_create (tl_system,
  198. sps->cfg))
  199. {
  200. LOG (GNUNET_ERROR_TYPE_ERROR,
  201. "Testing library failed to create unique configuration based on `%s'\n",
  202. sps->cfgname);
  203. GNUNET_CONFIGURATION_destroy (sps->cfg);
  204. GNUNET_TESTING_interpreter_fail ();
  205. return;
  206. }
  207. sps->peer = GNUNET_TESTING_peer_configure (sps->tl_system,
  208. sps->cfg,
  209. sps->no,
  210. NULL,
  211. &emsg);
  212. if (NULL == sps->peer)
  213. {
  214. LOG (GNUNET_ERROR_TYPE_ERROR,
  215. "Testing library failed to create unique configuration based on `%s': `%s'\n",
  216. sps->cfgname,
  217. emsg);
  218. GNUNET_free (emsg);
  219. GNUNET_TESTING_interpreter_fail ();
  220. return;
  221. }
  222. if (GNUNET_OK != GNUNET_TESTING_peer_start (sps->peer))
  223. {
  224. LOG (GNUNET_ERROR_TYPE_ERROR,
  225. "Testing library failed to create unique configuration based on `%s'\n",
  226. sps->cfgname);
  227. GNUNET_free (emsg);
  228. GNUNET_TESTING_interpreter_fail ();
  229. return;
  230. }
  231. memset (&dummy,
  232. '\0',
  233. sizeof(dummy));
  234. GNUNET_TESTING_peer_get_identity (sps->peer,
  235. &sps->id);
  236. if (0 == memcmp (&dummy,
  237. &sps->id,
  238. sizeof(struct GNUNET_PeerIdentity)))
  239. {
  240. LOG (GNUNET_ERROR_TYPE_ERROR,
  241. "Testing library failed to obtain peer identity for peer %u\n",
  242. sps->no);
  243. GNUNET_free (emsg);
  244. GNUNET_TESTING_interpreter_fail ();
  245. return;
  246. }
  247. LOG (GNUNET_ERROR_TYPE_DEBUG,
  248. "Peer %u configured with identity `%s'\n",
  249. sps->no,
  250. GNUNET_i2s_full (&sps->id));
  251. sps->th = GNUNET_TRANSPORT_core_connect (sps->cfg,
  252. NULL,
  253. sps->handlers,
  254. sps,
  255. &notify_connect,
  256. &notify_disconnect);
  257. if (NULL == sps->th)
  258. {
  259. LOG (GNUNET_ERROR_TYPE_ERROR,
  260. "Failed to connect to transport service for peer `%s': `%s'\n",
  261. sps->cfgname,
  262. emsg);
  263. GNUNET_free (emsg);
  264. GNUNET_TESTING_interpreter_fail ();
  265. return;
  266. }
  267. sps->ph = GNUNET_PEERSTORE_connect (sps->cfg);
  268. if (NULL == sps->th)
  269. {
  270. LOG (GNUNET_ERROR_TYPE_ERROR,
  271. "Failed to connect to peerstore service for peer `%s': `%s'\n",
  272. sps->cfgname,
  273. emsg);
  274. GNUNET_free (emsg);
  275. GNUNET_TESTING_interpreter_fail ();
  276. return;
  277. }
  278. sps->ah = GNUNET_TRANSPORT_application_init (sps->cfg);
  279. if (NULL == sps->ah)
  280. {
  281. LOG (GNUNET_ERROR_TYPE_ERROR,
  282. "Failed to initialize the TRANSPORT application suggestion client handle for peer `%s': `%s'\n",
  283. sps->cfgname,
  284. emsg);
  285. GNUNET_free (emsg);
  286. GNUNET_TESTING_interpreter_fail ();
  287. return;
  288. }
  289. sps->rh_task = GNUNET_SCHEDULER_add_now (retrieve_hello, sps);
  290. }
  291. /**
  292. * The cleanup function of this cmd frees resources the cmd allocated.
  293. *
  294. */
  295. static void
  296. start_peer_cleanup (void *cls,
  297. const struct GNUNET_TESTING_Command *cmd)
  298. {
  299. struct StartPeerState *sps = cls;
  300. if (NULL != sps->handlers)
  301. {
  302. GNUNET_free (sps->handlers);
  303. sps->handlers = NULL;
  304. }
  305. if (NULL != sps->cfg)
  306. {
  307. GNUNET_CONFIGURATION_destroy (sps->cfg);
  308. sps->cfg = NULL;
  309. }
  310. GNUNET_free (sps->hello);
  311. GNUNET_free (sps->connected_peers_map);
  312. GNUNET_free (sps);
  313. }
  314. /**
  315. * This function prepares an array with traits.
  316. *
  317. */
  318. static int
  319. start_peer_traits (void *cls,
  320. const void **ret,
  321. const char *trait,
  322. unsigned int index)
  323. {
  324. struct StartPeerState *sps = cls;
  325. struct GNUNET_TRANSPORT_ApplicationHandle *ah = sps->ah;
  326. struct GNUNET_PeerIdentity *id = &sps->id;
  327. struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map =
  328. sps->connected_peers_map;
  329. char *hello = sps->hello;
  330. size_t hello_size = sps->hello_size;
  331. struct GNUNET_TESTING_Trait traits[] = {
  332. {
  333. .index = 0,
  334. .trait_name = "application_handle",
  335. .ptr = (const void *) ah,
  336. },
  337. {
  338. .index = 1,
  339. .trait_name = "peer_id",
  340. .ptr = (const void *) id,
  341. },
  342. {
  343. .index = 2,
  344. .trait_name = "connected_peers_map",
  345. .ptr = (const void *) connected_peers_map,
  346. },
  347. {
  348. .index = 3,
  349. .trait_name = "hello",
  350. .ptr = (const void *) hello,
  351. },
  352. {
  353. .index = 4,
  354. .trait_name = "hello_size",
  355. .ptr = (const void *) hello_size,
  356. },
  357. {
  358. .index = 5,
  359. .trait_name = "state",
  360. .ptr = (const void *) sps,
  361. },
  362. GNUNET_TESTING_trait_end ()
  363. };
  364. return GNUNET_TESTING_get_trait (traits,
  365. ret,
  366. trait,
  367. index);
  368. }
  369. /**
  370. * Function to get the trait with the struct StartPeerState.
  371. *
  372. * @param[out] sps struct StartPeerState.
  373. * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
  374. *
  375. */
  376. int
  377. GNUNET_TRANSPORT_get_trait_state (const struct
  378. GNUNET_TESTING_Command
  379. *cmd,
  380. struct StartPeerState **sps)
  381. {
  382. return cmd->traits (cmd->cls,
  383. (const void **) sps,
  384. "state",
  385. (unsigned int) 5);
  386. }
  387. /**
  388. * Function to get the trait with the size of the hello.
  389. *
  390. * @param[out] hello_size size of hello.
  391. * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
  392. *
  393. */
  394. int
  395. GNUNET_TRANSPORT_get_trait_hello_size (const struct
  396. GNUNET_TESTING_Command
  397. *cmd,
  398. size_t **hello_size)
  399. {
  400. return cmd->traits (cmd->cls,
  401. (const void **) hello_size,
  402. "hello_size",
  403. (unsigned int) 4);
  404. }
  405. /**
  406. * Function to get the trait with the hello.
  407. *
  408. * @param[out] hello The hello for the peer.
  409. * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
  410. *
  411. */
  412. int
  413. GNUNET_TRANSPORT_get_trait_hello (const struct
  414. GNUNET_TESTING_Command
  415. *cmd,
  416. char **hello)
  417. {
  418. return cmd->traits (cmd->cls,
  419. (const void **) hello,
  420. "hello",
  421. (unsigned int) 3);
  422. }
  423. /**
  424. * Function to get the trait with the map of connected peers.
  425. *
  426. * @param[out] connected_peers_map The map with connected peers.
  427. * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
  428. *
  429. */
  430. int
  431. GNUNET_TRANSPORT_get_trait_connected_peers_map (const struct
  432. GNUNET_TESTING_Command
  433. *cmd,
  434. struct
  435. GNUNET_CONTAINER_MultiShortmap *
  436. *
  437. connected_peers_map)
  438. {
  439. return cmd->traits (cmd->cls,
  440. (const void **) connected_peers_map,
  441. "connected_peers_map",
  442. (unsigned int) 2);
  443. }
  444. /**
  445. * Function to get the trait with the transport application handle.
  446. *
  447. * @param[out] ah The application handle.
  448. * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
  449. */
  450. int
  451. GNUNET_TRANSPORT_get_trait_application_handle (const struct
  452. GNUNET_TESTING_Command *cmd,
  453. struct
  454. GNUNET_TRANSPORT_ApplicationHandle
  455. **ah)
  456. {
  457. return cmd->traits (cmd->cls,
  458. (const void **) ah,
  459. "application_handle",
  460. (unsigned int) 0);
  461. }
  462. /**
  463. * Function to get the trait with the peer id.
  464. *
  465. * @param[out] id The peer id.
  466. * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
  467. */
  468. int
  469. GNUNET_TRANSPORT_get_trait_peer_id (const struct
  470. GNUNET_TESTING_Command *cmd,
  471. struct GNUNET_PeerIdentity **id)
  472. {
  473. return cmd->traits (cmd->cls,
  474. (const void **) id,
  475. "peer_id",
  476. (unsigned int) 1);
  477. }
  478. /**
  479. * Create command.
  480. *
  481. * @param label name for command.
  482. * @param system_label Label of the cmd to setup a test environment.
  483. * @param m The number of the local node of the actual network namespace.
  484. * @param n The number of the actual namespace.
  485. * @param local_m Number of local nodes in each namespace.
  486. * @param handlers Handler for messages received by this peer.
  487. * @param cfgname Configuration file name for this peer.
  488. * @return command.
  489. */
  490. struct GNUNET_TESTING_Command
  491. GNUNET_TRANSPORT_cmd_start_peer (const char *label,
  492. const char *system_label,
  493. char *m,
  494. char *n,
  495. char *local_m,
  496. char *node_ip,
  497. struct GNUNET_MQ_MessageHandler *handlers,
  498. const char *cfgname)
  499. {
  500. struct StartPeerState *sps;
  501. struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map =
  502. GNUNET_CONTAINER_multishortmap_create (1,GNUNET_NO);
  503. unsigned int i;
  504. sps = GNUNET_new (struct StartPeerState);
  505. sps->m = m;
  506. sps->n = n;
  507. sps->local_m = local_m;
  508. sps->no = (atoi (n) - 1) * atoi (sps->local_m) + atoi (m);
  509. sps->system_label = system_label;
  510. sps->connected_peers_map = connected_peers_map;
  511. sps->cfgname = cfgname;
  512. sps->node_ip = node_ip;
  513. if (NULL != handlers)
  514. {
  515. for (i = 0; NULL != handlers[i].cb; i++)
  516. ;
  517. sps->handlers = GNUNET_new_array (i + 1,
  518. struct GNUNET_MQ_MessageHandler);
  519. GNUNET_memcpy (sps->handlers,
  520. handlers,
  521. i * sizeof(struct GNUNET_MQ_MessageHandler));
  522. }
  523. struct GNUNET_TESTING_Command cmd = {
  524. .cls = sps,
  525. .label = label,
  526. .run = &start_peer_run,
  527. .finish = &start_peer_finish,
  528. .cleanup = &start_peer_cleanup,
  529. .traits = &start_peer_traits
  530. };
  531. return cmd;
  532. }