You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

533 lines
17 KiB

  1. /*
  2. * This file is part of GNUnet
  3. * Copyright (C) 2013 GNUnet e.V.
  4. *
  5. * GNUnet is free software: you can redistribute it and/or modify it
  6. * under the terms of the GNU Affero General Public License as published
  7. * by the Free Software Foundation, either version 3 of the License,
  8. * or (at your option) any later version.
  9. *
  10. * GNUnet is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. SPDX-License-Identifier: AGPL3.0-or-later
  18. */
  19. /**
  20. * @author Gabor X Toth
  21. * @author Christian Grothoff
  22. *
  23. * @file
  24. * Test for the PSYCstore plugins.
  25. */
  26. #include <inttypes.h>
  27. #include "platform.h"
  28. #include "gnunet_util_lib.h"
  29. #include "gnunet_testing_lib.h"
  30. #include "gnunet_psycstore_plugin.h"
  31. #include "gnunet_psycstore_service.h"
  32. #include "gnunet_multicast_service.h"
  33. #define DEBUG_PSYCSTORE GNUNET_EXTRA_LOGGING
  34. #if DEBUG_PSYCSTORE
  35. # define LOG_LEVEL "DEBUG"
  36. #else
  37. # define LOG_LEVEL "WARNING"
  38. #endif
  39. #define C2ARG(str) str, (sizeof (str) - 1)
  40. #define LOG(kind,...) \
  41. GNUNET_log_from (kind, "test-plugin-psycstore", __VA_ARGS__)
  42. static int ok;
  43. /**
  44. * Name of plugin under test.
  45. */
  46. static const char *plugin_name;
  47. static struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key;
  48. static struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key;
  49. static struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key;
  50. static struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key;
  51. /**
  52. * Function called when the service shuts down. Unloads our psycstore
  53. * plugin.
  54. *
  55. * @param api api to unload
  56. */
  57. static void
  58. unload_plugin (struct GNUNET_PSYCSTORE_PluginFunctions *api)
  59. {
  60. char *libname;
  61. GNUNET_asprintf (&libname, "libgnunet_plugin_psycstore_%s", plugin_name);
  62. GNUNET_break (NULL == GNUNET_PLUGIN_unload (libname, api));
  63. GNUNET_free (libname);
  64. }
  65. /**
  66. * Load the psycstore plugin.
  67. *
  68. * @param cfg configuration to pass
  69. * @return NULL on error
  70. */
  71. static struct GNUNET_PSYCSTORE_PluginFunctions *
  72. load_plugin (const struct GNUNET_CONFIGURATION_Handle *cfg)
  73. {
  74. struct GNUNET_PSYCSTORE_PluginFunctions *ret;
  75. char *libname;
  76. GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Loading `%s' psycstore plugin\n"),
  77. plugin_name);
  78. GNUNET_asprintf (&libname, "libgnunet_plugin_psycstore_%s", plugin_name);
  79. if (NULL == (ret = GNUNET_PLUGIN_load (libname, (void*) cfg)))
  80. {
  81. FPRINTF (stderr, "Failed to load plugin `%s'!\n", plugin_name);
  82. return NULL;
  83. }
  84. GNUNET_free (libname);
  85. return ret;
  86. }
  87. #define MAX_MSG 16
  88. struct FragmentClosure
  89. {
  90. uint8_t n;
  91. uint64_t flags[MAX_MSG];
  92. struct GNUNET_MULTICAST_MessageHeader *msg[MAX_MSG];
  93. };
  94. static int
  95. fragment_cb (void *cls, struct GNUNET_MULTICAST_MessageHeader *msg2,
  96. enum GNUNET_PSYCSTORE_MessageFlags flags)
  97. {
  98. struct FragmentClosure *fcls = cls;
  99. struct GNUNET_MULTICAST_MessageHeader *msg1;
  100. uint64_t flags1;
  101. int ret;
  102. if (fcls->n >= MAX_MSG)
  103. {
  104. GNUNET_break (0);
  105. return GNUNET_SYSERR;
  106. }
  107. msg1 = fcls->msg[fcls->n];
  108. flags1 = fcls->flags[fcls->n++];
  109. if (NULL == msg1)
  110. {
  111. GNUNET_break (0);
  112. return GNUNET_SYSERR;
  113. }
  114. if (flags1 == flags && msg1->header.size == msg2->header.size
  115. && 0 == memcmp (msg1, msg2, ntohs (msg1->header.size)))
  116. {
  117. LOG (GNUNET_ERROR_TYPE_DEBUG, "Fragment %llu matches\n",
  118. GNUNET_ntohll (msg1->fragment_id));
  119. ret = GNUNET_YES;
  120. }
  121. else
  122. {
  123. LOG (GNUNET_ERROR_TYPE_ERROR, "Fragment %llu differs\n",
  124. GNUNET_ntohll (msg1->fragment_id));
  125. ret = GNUNET_SYSERR;
  126. }
  127. GNUNET_free (msg2);
  128. return ret;
  129. }
  130. struct StateClosure {
  131. size_t n;
  132. char *name[16];
  133. void *value[16];
  134. size_t value_size[16];
  135. };
  136. static int
  137. state_cb (void *cls, const char *name, const void *value, uint32_t value_size)
  138. {
  139. struct StateClosure *scls = cls;
  140. const void *val = scls->value[scls->n]; // FIXME: check for n out-of-bounds FIRST!
  141. size_t val_size = scls->value_size[scls->n++];
  142. /* FIXME: check name */
  143. LOG (GNUNET_ERROR_TYPE_DEBUG,
  144. " name = %s, value_size = %u\n",
  145. name, value_size);
  146. return GNUNET_YES;
  147. return value_size == val_size && 0 == memcmp (value, val, val_size)
  148. ? GNUNET_YES
  149. : GNUNET_SYSERR;
  150. }
  151. static void
  152. run (void *cls, char *const *args, const char *cfgfile,
  153. const struct GNUNET_CONFIGURATION_Handle *cfg)
  154. {
  155. struct GNUNET_PSYCSTORE_PluginFunctions *db;
  156. ok = 1;
  157. db = load_plugin (cfg);
  158. if (NULL == db)
  159. {
  160. FPRINTF (stderr,
  161. "%s",
  162. "Failed to initialize PSYCstore. "
  163. "Database likely not setup, skipping test.\n");
  164. ok = 77;
  165. return;
  166. }
  167. /* Store & test membership */
  168. LOG (GNUNET_ERROR_TYPE_INFO, "MEMBERSHIP\n");
  169. channel_key = GNUNET_CRYPTO_eddsa_key_create ();
  170. slave_key = GNUNET_CRYPTO_ecdsa_key_create ();
  171. GNUNET_CRYPTO_eddsa_key_get_public (channel_key,
  172. &channel_pub_key);
  173. GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key);
  174. LOG (GNUNET_ERROR_TYPE_INFO, "membership_store()\n");
  175. GNUNET_assert (GNUNET_OK == db->membership_store (db->cls, &channel_pub_key,
  176. &slave_pub_key, GNUNET_YES,
  177. 4, 2, 1));
  178. LOG (GNUNET_ERROR_TYPE_INFO, "membership_test()\n");
  179. GNUNET_assert (GNUNET_YES == db->membership_test (db->cls, &channel_pub_key,
  180. &slave_pub_key, 4));
  181. GNUNET_assert (GNUNET_YES == db->membership_test (db->cls, &channel_pub_key,
  182. &slave_pub_key, 2));
  183. GNUNET_assert (GNUNET_NO == db->membership_test (db->cls, &channel_pub_key,
  184. &slave_pub_key, 1));
  185. /* Store & get messages */
  186. LOG (GNUNET_ERROR_TYPE_INFO, "MESSAGES\n");
  187. struct GNUNET_MULTICAST_MessageHeader *msg
  188. = GNUNET_malloc (sizeof (*msg) + sizeof (channel_pub_key));
  189. GNUNET_assert (msg != NULL);
  190. msg->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE);
  191. msg->header.size = htons (sizeof (*msg) + sizeof (channel_pub_key));
  192. uint64_t fragment_id = INT64_MAX - 1;
  193. msg->fragment_id = GNUNET_htonll (fragment_id);
  194. uint64_t message_id = INT64_MAX - 10;
  195. msg->message_id = GNUNET_htonll (message_id);
  196. uint64_t group_generation = INT64_MAX - 3;
  197. msg->group_generation = GNUNET_htonll (group_generation);
  198. msg->hop_counter = htonl (9);
  199. msg->fragment_offset = GNUNET_htonll (0);
  200. msg->flags = htonl (GNUNET_MULTICAST_MESSAGE_LAST_FRAGMENT);
  201. GNUNET_memcpy (&msg[1], &channel_pub_key, sizeof (channel_pub_key));
  202. msg->purpose.size = htonl (ntohs (msg->header.size)
  203. - sizeof (msg->header)
  204. - sizeof (msg->hop_counter)
  205. - sizeof (msg->signature));
  206. msg->purpose.purpose = htonl (234);
  207. GNUNET_assert (GNUNET_OK ==
  208. GNUNET_CRYPTO_eddsa_sign (channel_key, &msg->purpose, &msg->signature));
  209. LOG (GNUNET_ERROR_TYPE_INFO, "fragment_store()\n");
  210. struct FragmentClosure fcls = { 0 };
  211. fcls.n = 0;
  212. fcls.msg[0] = msg;
  213. fcls.flags[0] = GNUNET_PSYCSTORE_MESSAGE_STATE;
  214. GNUNET_assert (
  215. GNUNET_OK == db->fragment_store (db->cls, &channel_pub_key, msg,
  216. fcls.flags[0]));
  217. LOG (GNUNET_ERROR_TYPE_INFO, "fragment_get(%" PRIu64 ")\n", fragment_id);
  218. uint64_t ret_frags = 0;
  219. GNUNET_assert (
  220. GNUNET_OK == db->fragment_get (db->cls, &channel_pub_key,
  221. fragment_id, fragment_id,
  222. &ret_frags, fragment_cb, &fcls));
  223. GNUNET_assert (fcls.n == 1);
  224. LOG (GNUNET_ERROR_TYPE_INFO, "message_get_fragment()\n");
  225. fcls.n = 0;
  226. GNUNET_assert (
  227. GNUNET_OK == db->message_get_fragment (db->cls, &channel_pub_key,
  228. GNUNET_ntohll (msg->message_id),
  229. GNUNET_ntohll (msg->fragment_offset),
  230. fragment_cb, &fcls));
  231. GNUNET_assert (fcls.n == 1);
  232. LOG (GNUNET_ERROR_TYPE_INFO, "message_add_flags()\n");
  233. GNUNET_assert (
  234. GNUNET_OK == db->message_add_flags (db->cls, &channel_pub_key,
  235. GNUNET_ntohll (msg->message_id),
  236. GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED));
  237. LOG (GNUNET_ERROR_TYPE_INFO, "fragment_get(%" PRIu64 ")\n", fragment_id);
  238. fcls.n = 0;
  239. fcls.flags[0] |= GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED;
  240. GNUNET_assert (
  241. GNUNET_OK == db->fragment_get (db->cls, &channel_pub_key,
  242. fragment_id, fragment_id,
  243. &ret_frags, fragment_cb, &fcls));
  244. GNUNET_assert (fcls.n == 1);
  245. LOG (GNUNET_ERROR_TYPE_INFO, "fragment_store()\n");
  246. struct GNUNET_MULTICAST_MessageHeader *msg1
  247. = GNUNET_malloc (sizeof (*msg1) + sizeof (channel_pub_key));
  248. GNUNET_memcpy (msg1, msg, sizeof (*msg1) + sizeof (channel_pub_key));
  249. msg1->fragment_id = GNUNET_htonll (INT64_MAX);
  250. msg1->fragment_offset = GNUNET_htonll (32768);
  251. fcls.n = 0;
  252. fcls.msg[1] = msg1;
  253. fcls.flags[1] = GNUNET_PSYCSTORE_MESSAGE_STATE_HASH;
  254. GNUNET_assert (GNUNET_OK == db->fragment_store (db->cls, &channel_pub_key, msg1,
  255. fcls.flags[1]));
  256. LOG (GNUNET_ERROR_TYPE_INFO, "message_get()\n");
  257. GNUNET_assert (
  258. GNUNET_OK == db->message_get (db->cls, &channel_pub_key,
  259. message_id, message_id, 0,
  260. &ret_frags, fragment_cb, &fcls));
  261. GNUNET_assert (fcls.n == 2 && ret_frags == 2);
  262. /* Message counters */
  263. LOG (GNUNET_ERROR_TYPE_INFO, "counters_message_get()\n");
  264. fragment_id = 0;
  265. message_id = 0;
  266. group_generation = 0;
  267. GNUNET_assert (
  268. GNUNET_OK == db->counters_message_get (db->cls, &channel_pub_key,
  269. &fragment_id, &message_id,
  270. &group_generation)
  271. && fragment_id == GNUNET_ntohll (msg1->fragment_id)
  272. && message_id == GNUNET_ntohll (msg1->message_id)
  273. && group_generation == GNUNET_ntohll (msg1->group_generation));
  274. /* Modify state */
  275. LOG (GNUNET_ERROR_TYPE_INFO, "STATE\n");
  276. LOG (GNUNET_ERROR_TYPE_INFO, "state_modify_*()\n");
  277. message_id = GNUNET_ntohll (fcls.msg[0]->message_id) + 1;
  278. GNUNET_assert (GNUNET_OK == db->state_modify_begin (db->cls, &channel_pub_key,
  279. message_id, 0));
  280. GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key,
  281. GNUNET_PSYC_OP_ASSIGN,
  282. "_foo",
  283. C2ARG("one two three")));
  284. GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key,
  285. GNUNET_PSYC_OP_ASSIGN,
  286. "_foo_bar", slave_key,
  287. sizeof (*slave_key)));
  288. GNUNET_assert (GNUNET_OK == db->state_modify_end (db->cls, &channel_pub_key,
  289. message_id));
  290. LOG (GNUNET_ERROR_TYPE_INFO, "state_get()\n");
  291. struct StateClosure scls = { 0 };
  292. scls.n = 0;
  293. scls.value[0] = "one two three";
  294. scls.value_size[0] = strlen ("one two three");
  295. GNUNET_assert (GNUNET_OK == db->state_get (db->cls, &channel_pub_key, "_foo",
  296. state_cb, &scls));
  297. GNUNET_assert (scls.n == 1);
  298. LOG (GNUNET_ERROR_TYPE_INFO, "state_get_prefix()\n");
  299. scls.n = 0;
  300. scls.value[1] = slave_key;
  301. scls.value_size[1] = sizeof (*slave_key);
  302. GNUNET_assert (GNUNET_OK == db->state_get_prefix (db->cls, &channel_pub_key,
  303. "_foo", state_cb, &scls));
  304. GNUNET_assert (scls.n == 2);
  305. LOG (GNUNET_ERROR_TYPE_INFO, "state_get_signed()\n");
  306. scls.n = 0;
  307. GNUNET_assert (GNUNET_NO == db->state_get_signed (db->cls, &channel_pub_key,
  308. state_cb, &scls));
  309. GNUNET_assert (scls.n == 0);
  310. LOG (GNUNET_ERROR_TYPE_INFO, "state_update_signed()\n");
  311. GNUNET_assert (GNUNET_OK == db->state_update_signed (db->cls,
  312. &channel_pub_key));
  313. LOG (GNUNET_ERROR_TYPE_INFO, "state_get_signed()\n");
  314. scls.n = 0;
  315. GNUNET_assert (GNUNET_YES == db->state_get_signed (db->cls, &channel_pub_key,
  316. state_cb, &scls));
  317. GNUNET_assert (scls.n == 2);
  318. /* State counters */
  319. LOG (GNUNET_ERROR_TYPE_INFO, "counters_state_get()\n");
  320. uint64_t max_state_msg_id = 0;
  321. GNUNET_assert (GNUNET_OK == db->counters_state_get (db->cls, &channel_pub_key,
  322. &max_state_msg_id)
  323. && max_state_msg_id == message_id);
  324. /* State sync */
  325. LOG (GNUNET_ERROR_TYPE_INFO, "state_sync_*()\n");
  326. scls.n = 0;
  327. scls.value[0] = channel_key;
  328. scls.value_size[0] = sizeof (*channel_key);
  329. scls.value[1] = "three two one";
  330. scls.value_size[1] = strlen ("three two one");
  331. GNUNET_assert (GNUNET_OK == db->state_sync_begin (db->cls, &channel_pub_key));
  332. GNUNET_assert (GNUNET_OK == db->state_sync_assign (db->cls, &channel_pub_key,
  333. "_sync_bar", scls.value[0],
  334. scls.value_size[0]));
  335. GNUNET_assert (GNUNET_OK == db->state_sync_assign (db->cls, &channel_pub_key,
  336. "_sync_foo", scls.value[1],
  337. scls.value_size[1]));
  338. GNUNET_assert (GNUNET_OK == db->state_sync_end (db->cls, &channel_pub_key,
  339. max_state_msg_id,
  340. INT64_MAX - 5));
  341. GNUNET_assert (GNUNET_NO == db->state_get_prefix (db->cls, &channel_pub_key,
  342. "_foo", state_cb, &scls));
  343. GNUNET_assert (scls.n == 0);
  344. GNUNET_assert (GNUNET_OK == db->state_get_prefix (db->cls, &channel_pub_key,
  345. "_sync", state_cb, &scls));
  346. GNUNET_assert (scls.n == 2);
  347. scls.n = 0;
  348. GNUNET_assert (GNUNET_OK == db->state_get_signed (db->cls, &channel_pub_key,
  349. state_cb, &scls));
  350. GNUNET_assert (scls.n == 2);
  351. /* Modify state after sync */
  352. LOG (GNUNET_ERROR_TYPE_INFO, "state_modify_*()\n");
  353. message_id = GNUNET_ntohll (fcls.msg[0]->message_id) + 6;
  354. GNUNET_assert (GNUNET_OK == db->state_modify_begin (db->cls, &channel_pub_key,
  355. message_id,
  356. message_id - max_state_msg_id));
  357. GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key,
  358. GNUNET_PSYC_OP_ASSIGN,
  359. "_sync_foo",
  360. C2ARG("five six seven")));
  361. GNUNET_assert (GNUNET_OK == db->state_modify_end (db->cls, &channel_pub_key,
  362. message_id));
  363. /* Reset state */
  364. LOG (GNUNET_ERROR_TYPE_INFO, "state_reset()\n");
  365. scls.n = 0;
  366. GNUNET_assert (GNUNET_OK == db->state_reset (db->cls, &channel_pub_key));
  367. GNUNET_assert (scls.n == 0);
  368. ok = 0;
  369. if (NULL != channel_key)
  370. {
  371. GNUNET_free (channel_key);
  372. channel_key = NULL;
  373. }
  374. if (NULL != slave_key)
  375. {
  376. GNUNET_free (slave_key);
  377. slave_key = NULL;
  378. }
  379. unload_plugin (db);
  380. }
  381. int
  382. main (int argc, char *argv[])
  383. {
  384. char cfg_name[128];
  385. char *const xargv[] = {
  386. "test-plugin-psycstore",
  387. "-c", cfg_name,
  388. "-L", LOG_LEVEL,
  389. NULL
  390. };
  391. struct GNUNET_GETOPT_CommandLineOption options[] = {
  392. GNUNET_GETOPT_OPTION_END
  393. };
  394. GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-psycstore-sqlite");
  395. GNUNET_log_setup ("test-plugin-psycstore", LOG_LEVEL, NULL);
  396. plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
  397. GNUNET_snprintf (cfg_name, sizeof (cfg_name), "test_plugin_psycstore_%s.conf",
  398. plugin_name);
  399. GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1, xargv,
  400. "test-plugin-psycstore", "nohelp", options, &run, NULL);
  401. if ( (0 != ok) &&
  402. (77 != ok) )
  403. FPRINTF (stderr, "Missed some testcases: %d\n", ok);
  404. #if ! DEBUG_PSYCSTORE
  405. GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-psycstore-sqlite");
  406. #endif
  407. return ok;
  408. }
  409. /* end of test_plugin_psycstore.c */