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.
 
 
 
 

1531 lines
51 KiB

  1. /*
  2. * This file is part of GNUnet
  3. * Copyright (C) 2016 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. * @file psycstore/plugin_psycstore_postgres.c
  21. * @brief PostgresQL-based psycstore backend
  22. * @author Daniel Golle
  23. * @author Gabor X Toth
  24. * @author Christian Grothoff
  25. * @author Christophe Genevey
  26. * @author Jeffrey Burdges
  27. */
  28. #include "platform.h"
  29. #include "gnunet_psycstore_plugin.h"
  30. #include "gnunet_psycstore_service.h"
  31. #include "gnunet_multicast_service.h"
  32. #include "gnunet_crypto_lib.h"
  33. #include "gnunet_psyc_util_lib.h"
  34. #include "psycstore.h"
  35. #include "gnunet_pq_lib.h"
  36. /**
  37. * After how many ms "busy" should a DB operation fail for good? A
  38. * low value makes sure that we are more responsive to requests
  39. * (especially PUTs). A high value guarantees a higher success rate
  40. * (SELECTs in iterate can take several seconds despite LIMIT=1).
  41. *
  42. * The default value of 1s should ensure that users do not experience
  43. * huge latencies while at the same time allowing operations to
  44. * succeed with reasonable probability.
  45. */
  46. #define BUSY_TIMEOUT_MS 1000
  47. #define DEBUG_PSYCSTORE GNUNET_EXTRA_LOGGING
  48. #define LOG(kind,...) GNUNET_log_from (kind, "psycstore-postgres", __VA_ARGS__)
  49. enum Transactions {
  50. TRANSACTION_NONE = 0,
  51. TRANSACTION_STATE_MODIFY,
  52. TRANSACTION_STATE_SYNC,
  53. };
  54. /**
  55. * Context for all functions in this plugin.
  56. */
  57. struct Plugin
  58. {
  59. const struct GNUNET_CONFIGURATION_Handle *cfg;
  60. /**
  61. * Native Postgres database handle.
  62. */
  63. PGconn *dbh;
  64. enum Transactions transaction;
  65. void *cls;
  66. };
  67. /**
  68. * Initialize the database connections and associated
  69. * data structures (create tables and indices
  70. * as needed as well).
  71. *
  72. * @param plugin the plugin context (state for this module)
  73. * @return #GNUNET_OK on success
  74. */
  75. static int
  76. database_setup (struct Plugin *plugin)
  77. {
  78. struct GNUNET_PQ_ExecuteStatement es[] = {
  79. GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS channels (\n"
  80. " id SERIAL,\n"
  81. " pub_key BYTEA NOT NULL CHECK (LENGTH(pub_key)=32),\n"
  82. " max_state_message_id BIGINT,\n"
  83. " state_hash_message_id BIGINT,\n"
  84. " PRIMARY KEY(id)\n"
  85. ")"
  86. "WITH OIDS"),
  87. GNUNET_PQ_make_execute ("CREATE UNIQUE INDEX IF NOT EXISTS channel_pub_key_idx \n"
  88. " ON channels (pub_key)"),
  89. GNUNET_PQ_make_execute ("CREATE OR REPLACE FUNCTION get_chan_id(BYTEA) RETURNS INTEGER AS \n"
  90. " 'SELECT id FROM channels WHERE pub_key=$1;' LANGUAGE SQL STABLE \n"
  91. "RETURNS NULL ON NULL INPUT"),
  92. GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS slaves (\n"
  93. " id SERIAL,\n"
  94. " pub_key BYTEA NOT NULL CHECK (LENGTH(pub_key)=32),\n"
  95. " PRIMARY KEY(id)\n"
  96. ")"
  97. "WITH OIDS"),
  98. GNUNET_PQ_make_execute ("CREATE UNIQUE INDEX IF NOT EXISTS slaves_pub_key_idx \n"
  99. " ON slaves (pub_key)"),
  100. GNUNET_PQ_make_execute ("CREATE OR REPLACE FUNCTION get_slave_id(BYTEA) RETURNS INTEGER AS \n"
  101. " 'SELECT id FROM slaves WHERE pub_key=$1;' LANGUAGE SQL STABLE \n"
  102. "RETURNS NULL ON NULL INPUT"),
  103. GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS membership (\n"
  104. " channel_id BIGINT NOT NULL REFERENCES channels(id),\n"
  105. " slave_id BIGINT NOT NULL REFERENCES slaves(id),\n"
  106. " did_join INT NOT NULL,\n"
  107. " announced_at BIGINT NOT NULL,\n"
  108. " effective_since BIGINT NOT NULL,\n"
  109. " group_generation BIGINT NOT NULL\n"
  110. ")"
  111. "WITH OIDS"),
  112. GNUNET_PQ_make_execute ("CREATE INDEX IF NOT EXISTS idx_membership_channel_id_slave_id "
  113. "ON membership (channel_id, slave_id)"),
  114. /** @todo messages table: add method_name column */
  115. GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS messages (\n"
  116. " channel_id BIGINT NOT NULL REFERENCES channels(id),\n"
  117. " hop_counter INT NOT NULL,\n"
  118. " signature BYTEA CHECK (LENGTH(signature)=64),\n"
  119. " purpose BYTEA CHECK (LENGTH(purpose)=8),\n"
  120. " fragment_id BIGINT NOT NULL,\n"
  121. " fragment_offset BIGINT NOT NULL,\n"
  122. " message_id BIGINT NOT NULL,\n"
  123. " group_generation BIGINT NOT NULL,\n"
  124. " multicast_flags INT NOT NULL,\n"
  125. " psycstore_flags INT NOT NULL,\n"
  126. " data BYTEA,\n"
  127. " PRIMARY KEY (channel_id, fragment_id),\n"
  128. " UNIQUE (channel_id, message_id, fragment_offset)\n"
  129. ")"
  130. "WITH OIDS"),
  131. GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS state (\n"
  132. " channel_id BIGINT NOT NULL REFERENCES channels(id),\n"
  133. " name TEXT NOT NULL,\n"
  134. " value_current BYTEA,\n"
  135. " value_signed BYTEA,\n"
  136. " PRIMARY KEY (channel_id, name)\n"
  137. ")"
  138. "WITH OIDS"),
  139. GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS state_sync (\n"
  140. " channel_id BIGINT NOT NULL REFERENCES channels(id),\n"
  141. " name TEXT NOT NULL,\n"
  142. " value BYTEA,\n"
  143. " PRIMARY KEY (channel_id, name)\n"
  144. ")"
  145. "WITH OIDS"),
  146. GNUNET_PQ_EXECUTE_STATEMENT_END
  147. };
  148. /* Open database and precompile statements */
  149. plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg,
  150. "psycstore-postgres");
  151. if (NULL == plugin->dbh)
  152. return GNUNET_SYSERR;
  153. if (GNUNET_OK !=
  154. GNUNET_PQ_exec_statements (plugin->dbh,
  155. es))
  156. {
  157. PQfinish (plugin->dbh);
  158. plugin->dbh = NULL;
  159. return GNUNET_SYSERR;
  160. }
  161. /* Prepare statements */
  162. {
  163. struct GNUNET_PQ_PreparedStatement ps[] = {
  164. GNUNET_PQ_make_prepare ("transaction_begin",
  165. "BEGIN", 0),
  166. GNUNET_PQ_make_prepare ("transaction_commit",
  167. "COMMIT", 0),
  168. GNUNET_PQ_make_prepare ("transaction_rollback",
  169. "ROLLBACK", 0),
  170. GNUNET_PQ_make_prepare ("insert_channel_key",
  171. "INSERT INTO channels (pub_key) VALUES ($1)"
  172. " ON CONFLICT DO NOTHING", 1),
  173. GNUNET_PQ_make_prepare ("insert_slave_key",
  174. "INSERT INTO slaves (pub_key) VALUES ($1)"
  175. " ON CONFLICT DO NOTHING", 1),
  176. GNUNET_PQ_make_prepare ("insert_membership",
  177. "INSERT INTO membership\n"
  178. " (channel_id, slave_id, did_join, announced_at,\n"
  179. " effective_since, group_generation)\n"
  180. "VALUES (get_chan_id($1),\n"
  181. " get_slave_id($2),\n"
  182. " $3, $4, $5, $6)", 6),
  183. GNUNET_PQ_make_prepare ("select_membership",
  184. "SELECT did_join FROM membership\n"
  185. "WHERE channel_id = get_chan_id($1)\n"
  186. " AND slave_id = get_slave_id($2)\n"
  187. " AND effective_since <= $3 AND did_join = 1\n"
  188. "ORDER BY announced_at DESC LIMIT 1", 3),
  189. GNUNET_PQ_make_prepare ("insert_fragment",
  190. "INSERT INTO messages\n"
  191. " (channel_id, hop_counter, signature, purpose,\n"
  192. " fragment_id, fragment_offset, message_id,\n"
  193. " group_generation, multicast_flags, psycstore_flags, data)\n"
  194. "VALUES (get_chan_id($1),\n"
  195. " $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)"
  196. "ON CONFLICT DO NOTHING", 11),
  197. GNUNET_PQ_make_prepare ("update_message_flags",
  198. "UPDATE messages\n"
  199. "SET psycstore_flags = psycstore_flags | $1\n"
  200. "WHERE channel_id = get_chan_id($2) \n"
  201. " AND message_id = $3 AND fragment_offset = 0", 3),
  202. GNUNET_PQ_make_prepare ("select_fragments",
  203. "SELECT hop_counter, signature, purpose, fragment_id,\n"
  204. " fragment_offset, message_id, group_generation,\n"
  205. " multicast_flags, psycstore_flags, data\n"
  206. "FROM messages\n"
  207. "WHERE channel_id = get_chan_id($1) \n"
  208. " AND $2 <= fragment_id AND fragment_id <= $3", 3),
  209. /** @todo select_messages: add method_prefix filter */
  210. GNUNET_PQ_make_prepare ("select_messages",
  211. "SELECT hop_counter, signature, purpose, fragment_id,\n"
  212. " fragment_offset, message_id, group_generation,\n"
  213. " multicast_flags, psycstore_flags, data\n"
  214. "FROM messages\n"
  215. "WHERE channel_id = get_chan_id($1) \n"
  216. " AND $2 <= message_id AND message_id <= $3\n"
  217. "LIMIT $4;", 4),
  218. /** @todo select_latest_messages: add method_prefix filter */
  219. GNUNET_PQ_make_prepare ("select_latest_fragments",
  220. "SELECT rev.hop_counter AS hop_counter,\n"
  221. " rev.signature AS signature,\n"
  222. " rev.purpose AS purpose,\n"
  223. " rev.fragment_id AS fragment_id,\n"
  224. " rev.fragment_offset AS fragment_offset,\n"
  225. " rev.message_id AS message_id,\n"
  226. " rev.group_generation AS group_generation,\n"
  227. " rev.multicast_flags AS multicast_flags,\n"
  228. " rev.psycstore_flags AS psycstore_flags,\n"
  229. " rev.data AS data\n"
  230. " FROM\n"
  231. " (SELECT hop_counter, signature, purpose, fragment_id,\n"
  232. " fragment_offset, message_id, group_generation,\n"
  233. " multicast_flags, psycstore_flags, data \n"
  234. " FROM messages\n"
  235. " WHERE channel_id = get_chan_id($1) \n"
  236. " ORDER BY fragment_id DESC\n"
  237. " LIMIT $2) AS rev\n"
  238. " ORDER BY rev.fragment_id;", 2),
  239. GNUNET_PQ_make_prepare ("select_latest_messages",
  240. "SELECT hop_counter, signature, purpose, fragment_id,\n"
  241. " fragment_offset, message_id, group_generation,\n"
  242. " multicast_flags, psycstore_flags, data\n"
  243. "FROM messages\n"
  244. "WHERE channel_id = get_chan_id($1)\n"
  245. " AND message_id IN\n"
  246. " (SELECT message_id\n"
  247. " FROM messages\n"
  248. " WHERE channel_id = get_chan_id($2) \n"
  249. " GROUP BY message_id\n"
  250. " ORDER BY message_id\n"
  251. " DESC LIMIT $3)\n"
  252. "ORDER BY fragment_id", 3),
  253. GNUNET_PQ_make_prepare ("select_message_fragment",
  254. "SELECT hop_counter, signature, purpose, fragment_id,\n"
  255. " fragment_offset, message_id, group_generation,\n"
  256. " multicast_flags, psycstore_flags, data\n"
  257. "FROM messages\n"
  258. "WHERE channel_id = get_chan_id($1) \n"
  259. " AND message_id = $2 AND fragment_offset = $3", 3),
  260. GNUNET_PQ_make_prepare ("select_counters_message",
  261. "SELECT fragment_id, message_id, group_generation\n"
  262. "FROM messages\n"
  263. "WHERE channel_id = get_chan_id($1)\n"
  264. "ORDER BY fragment_id DESC LIMIT 1", 1),
  265. GNUNET_PQ_make_prepare ("select_counters_state",
  266. "SELECT max_state_message_id\n"
  267. "FROM channels\n"
  268. "WHERE pub_key = $1 AND max_state_message_id IS NOT NULL", 1),
  269. GNUNET_PQ_make_prepare ("update_max_state_message_id",
  270. "UPDATE channels\n"
  271. "SET max_state_message_id = $1\n"
  272. "WHERE pub_key = $2", 2),
  273. GNUNET_PQ_make_prepare ("update_state_hash_message_id",
  274. "UPDATE channels\n"
  275. "SET state_hash_message_id = $1\n"
  276. "WHERE pub_key = $2", 2),
  277. GNUNET_PQ_make_prepare ("insert_state_current",
  278. "INSERT INTO state\n"
  279. " (channel_id, name, value_current, value_signed)\n"
  280. "SELECT new.channel_id, new.name,\n"
  281. " new.value_current, old.value_signed\n"
  282. "FROM (SELECT get_chan_id($1) AS channel_id,\n"
  283. " $2::TEXT AS name, $3::BYTEA AS value_current) AS new\n"
  284. "LEFT JOIN (SELECT channel_id, name, value_signed\n"
  285. " FROM state) AS old\n"
  286. "ON new.channel_id = old.channel_id AND new.name = old.name\n"
  287. "ON CONFLICT (channel_id, name)\n"
  288. " DO UPDATE SET value_current = EXCLUDED.value_current,\n"
  289. " value_signed = EXCLUDED.value_signed", 3),
  290. GNUNET_PQ_make_prepare ("delete_state_empty",
  291. "DELETE FROM state\n"
  292. "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = $1)\n"
  293. " AND (value_current IS NULL OR length(value_current) = 0)\n"
  294. " AND (value_signed IS NULL OR length(value_signed) = 0)", 1),
  295. GNUNET_PQ_make_prepare ("update_state_signed",
  296. "UPDATE state\n"
  297. "SET value_signed = value_current\n"
  298. "WHERE channel_id = get_chan_id($1) ", 1),
  299. GNUNET_PQ_make_prepare ("delete_state",
  300. "DELETE FROM state\n"
  301. "WHERE channel_id = get_chan_id($1) ", 1),
  302. GNUNET_PQ_make_prepare ("insert_state_sync",
  303. "INSERT INTO state_sync (channel_id, name, value)\n"
  304. "VALUES (get_chan_id($1), $2, $3)", 3),
  305. GNUNET_PQ_make_prepare ("insert_state_from_sync",
  306. "INSERT INTO state\n"
  307. " (channel_id, name, value_current, value_signed)\n"
  308. "SELECT channel_id, name, value, value\n"
  309. "FROM state_sync\n"
  310. "WHERE channel_id = get_chan_id($1)", 1),
  311. GNUNET_PQ_make_prepare ("delete_state_sync",
  312. "DELETE FROM state_sync\n"
  313. "WHERE channel_id = get_chan_id($1)", 1),
  314. GNUNET_PQ_make_prepare ("select_state_one",
  315. "SELECT value_current\n"
  316. "FROM state\n"
  317. "WHERE channel_id = get_chan_id($1)\n"
  318. " AND name = $2", 2),
  319. GNUNET_PQ_make_prepare ("select_state_prefix",
  320. "SELECT name, value_current\n"
  321. "FROM state\n"
  322. "WHERE channel_id = get_chan_id($1)\n"
  323. " AND (name = $2 OR substr(name, 1, $3) = $4)", 4),
  324. GNUNET_PQ_make_prepare ("select_state_signed",
  325. "SELECT name, value_signed\n"
  326. "FROM state\n"
  327. "WHERE channel_id = get_chan_id($1)\n"
  328. " AND value_signed IS NOT NULL", 1),
  329. GNUNET_PQ_PREPARED_STATEMENT_END
  330. };
  331. if (GNUNET_OK !=
  332. GNUNET_PQ_prepare_statements (plugin->dbh,
  333. ps))
  334. {
  335. PQfinish (plugin->dbh);
  336. plugin->dbh = NULL;
  337. return GNUNET_SYSERR;
  338. }
  339. }
  340. return GNUNET_OK;
  341. }
  342. /**
  343. * Shutdown database connection and associate data
  344. * structures.
  345. * @param plugin the plugin context (state for this module)
  346. */
  347. static void
  348. database_shutdown (struct Plugin *plugin)
  349. {
  350. PQfinish (plugin->dbh);
  351. plugin->dbh = NULL;
  352. }
  353. /**
  354. * Execute a prepared statement with a @a channel_key argument.
  355. *
  356. * @param plugin Plugin handle.
  357. * @param stmt Statement to execute.
  358. * @param channel_key Public key of the channel.
  359. *
  360. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  361. */
  362. static int
  363. exec_channel (struct Plugin *plugin, const char *stmt,
  364. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
  365. {
  366. struct GNUNET_PQ_QueryParam params[] = {
  367. GNUNET_PQ_query_param_auto_from_type (channel_key),
  368. GNUNET_PQ_query_param_end
  369. };
  370. if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
  371. GNUNET_PQ_eval_prepared_non_select (plugin->dbh, stmt, params))
  372. return GNUNET_SYSERR;
  373. return GNUNET_OK;
  374. }
  375. /**
  376. * Begin a transaction.
  377. */
  378. static int
  379. transaction_begin (struct Plugin *plugin, enum Transactions transaction)
  380. {
  381. struct GNUNET_PQ_QueryParam params[] = {
  382. GNUNET_PQ_query_param_end
  383. };
  384. if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
  385. GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "transaction_begin", params))
  386. return GNUNET_SYSERR;
  387. plugin->transaction = transaction;
  388. return GNUNET_OK;
  389. }
  390. /**
  391. * Commit current transaction.
  392. */
  393. static int
  394. transaction_commit (struct Plugin *plugin)
  395. {
  396. struct GNUNET_PQ_QueryParam params[] = {
  397. GNUNET_PQ_query_param_end
  398. };
  399. if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
  400. GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "transaction_commit", params))
  401. return GNUNET_SYSERR;
  402. plugin->transaction = TRANSACTION_NONE;
  403. return GNUNET_OK;
  404. }
  405. /**
  406. * Roll back current transaction.
  407. */
  408. static int
  409. transaction_rollback (struct Plugin *plugin)
  410. {
  411. struct GNUNET_PQ_QueryParam params[] = {
  412. GNUNET_PQ_query_param_end
  413. };
  414. if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
  415. GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "transaction_rollback", params))
  416. return GNUNET_SYSERR;
  417. plugin->transaction = TRANSACTION_NONE;
  418. return GNUNET_OK;
  419. }
  420. static int
  421. channel_key_store (struct Plugin *plugin,
  422. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
  423. {
  424. struct GNUNET_PQ_QueryParam params[] = {
  425. GNUNET_PQ_query_param_auto_from_type (channel_key),
  426. GNUNET_PQ_query_param_end
  427. };
  428. if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
  429. GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
  430. "insert_channel_key",
  431. params))
  432. return GNUNET_SYSERR;
  433. return GNUNET_OK;
  434. }
  435. static int
  436. slave_key_store (struct Plugin *plugin,
  437. const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key)
  438. {
  439. struct GNUNET_PQ_QueryParam params[] = {
  440. GNUNET_PQ_query_param_auto_from_type (slave_key),
  441. GNUNET_PQ_query_param_end
  442. };
  443. if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
  444. GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "insert_slave_key", params))
  445. return GNUNET_SYSERR;
  446. return GNUNET_OK;
  447. }
  448. /**
  449. * Store join/leave events for a PSYC channel in order to be able to answer
  450. * membership test queries later.
  451. *
  452. * @see GNUNET_PSYCSTORE_membership_store()
  453. *
  454. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  455. */
  456. static int
  457. postgres_membership_store (void *cls,
  458. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  459. const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
  460. int did_join,
  461. uint64_t announced_at,
  462. uint64_t effective_since,
  463. uint64_t group_generation)
  464. {
  465. struct Plugin *plugin = cls;
  466. uint32_t idid_join = (uint32_t) did_join;
  467. GNUNET_assert (TRANSACTION_NONE == plugin->transaction);
  468. if ( (announced_at > INT64_MAX) ||
  469. (effective_since > INT64_MAX) ||
  470. (group_generation > INT64_MAX) )
  471. {
  472. GNUNET_break (0);
  473. return GNUNET_SYSERR;
  474. }
  475. if ( (GNUNET_OK !=
  476. channel_key_store (plugin, channel_key)) ||
  477. (GNUNET_OK !=
  478. slave_key_store (plugin, slave_key)) )
  479. return GNUNET_SYSERR;
  480. struct GNUNET_PQ_QueryParam params[] = {
  481. GNUNET_PQ_query_param_auto_from_type (channel_key),
  482. GNUNET_PQ_query_param_auto_from_type (slave_key),
  483. GNUNET_PQ_query_param_uint32 (&idid_join),
  484. GNUNET_PQ_query_param_uint64 (&announced_at),
  485. GNUNET_PQ_query_param_uint64 (&effective_since),
  486. GNUNET_PQ_query_param_uint64 (&group_generation),
  487. GNUNET_PQ_query_param_end
  488. };
  489. if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
  490. GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
  491. "insert_membership",
  492. params))
  493. return GNUNET_SYSERR;
  494. return GNUNET_OK;
  495. }
  496. /**
  497. * Test if a member was admitted to the channel at the given message ID.
  498. *
  499. * @see GNUNET_PSYCSTORE_membership_test()
  500. *
  501. * @return #GNUNET_YES if the member was admitted, #GNUNET_NO if not,
  502. * #GNUNET_SYSERR if there was en error.
  503. */
  504. static int
  505. membership_test (void *cls,
  506. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  507. const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
  508. uint64_t message_id)
  509. {
  510. struct Plugin *plugin = cls;
  511. uint32_t did_join = 0;
  512. struct GNUNET_PQ_QueryParam params_select[] = {
  513. GNUNET_PQ_query_param_auto_from_type (channel_key),
  514. GNUNET_PQ_query_param_auto_from_type (slave_key),
  515. GNUNET_PQ_query_param_uint64 (&message_id),
  516. GNUNET_PQ_query_param_end
  517. };
  518. struct GNUNET_PQ_ResultSpec results_select[] = {
  519. GNUNET_PQ_result_spec_uint32 ("did_join", &did_join),
  520. GNUNET_PQ_result_spec_end
  521. };
  522. if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
  523. GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, "select_membership",
  524. params_select, results_select))
  525. return GNUNET_SYSERR;
  526. return GNUNET_OK;
  527. }
  528. /**
  529. * Store a message fragment sent to a channel.
  530. *
  531. * @see GNUNET_PSYCSTORE_fragment_store()
  532. *
  533. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  534. */
  535. static int
  536. fragment_store (void *cls,
  537. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  538. const struct GNUNET_MULTICAST_MessageHeader *msg,
  539. uint32_t psycstore_flags)
  540. {
  541. struct Plugin *plugin = cls;
  542. GNUNET_assert (TRANSACTION_NONE == plugin->transaction);
  543. uint64_t fragment_id = GNUNET_ntohll (msg->fragment_id);
  544. uint64_t fragment_offset = GNUNET_ntohll (msg->fragment_offset);
  545. uint64_t message_id = GNUNET_ntohll (msg->message_id);
  546. uint64_t group_generation = GNUNET_ntohll (msg->group_generation);
  547. uint32_t hop_counter = ntohl(msg->hop_counter);
  548. uint32_t flags = ntohl(msg->flags);
  549. if (fragment_id > INT64_MAX || fragment_offset > INT64_MAX ||
  550. message_id > INT64_MAX || group_generation > INT64_MAX)
  551. {
  552. LOG(GNUNET_ERROR_TYPE_ERROR,
  553. "Tried to store fragment with a field > INT64_MAX: "
  554. "%lu, %lu, %lu, %lu\n", fragment_id, fragment_offset,
  555. message_id, group_generation);
  556. GNUNET_break (0);
  557. return GNUNET_SYSERR;
  558. }
  559. if (GNUNET_OK != channel_key_store (plugin, channel_key))
  560. return GNUNET_SYSERR;
  561. struct GNUNET_PQ_QueryParam params_insert[] = {
  562. GNUNET_PQ_query_param_auto_from_type (channel_key),
  563. GNUNET_PQ_query_param_uint32 (&hop_counter),
  564. GNUNET_PQ_query_param_auto_from_type (&msg->signature),
  565. GNUNET_PQ_query_param_auto_from_type (&msg->purpose),
  566. GNUNET_PQ_query_param_uint64 (&fragment_id),
  567. GNUNET_PQ_query_param_uint64 (&fragment_offset),
  568. GNUNET_PQ_query_param_uint64 (&message_id),
  569. GNUNET_PQ_query_param_uint64 (&group_generation),
  570. GNUNET_PQ_query_param_uint32 (&flags),
  571. GNUNET_PQ_query_param_uint32 (&psycstore_flags),
  572. GNUNET_PQ_query_param_fixed_size (&msg[1], ntohs (msg->header.size) - sizeof (*msg)),
  573. GNUNET_PQ_query_param_end
  574. };
  575. if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
  576. GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "insert_fragment", params_insert))
  577. return GNUNET_SYSERR;
  578. return GNUNET_OK;
  579. }
  580. /**
  581. * Set additional flags for a given message.
  582. *
  583. * They are OR'd with any existing flags set.
  584. *
  585. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  586. */
  587. static int
  588. message_add_flags (void *cls,
  589. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  590. uint64_t message_id,
  591. uint32_t psycstore_flags)
  592. {
  593. struct Plugin *plugin = cls;
  594. struct GNUNET_PQ_QueryParam params_update[] = {
  595. GNUNET_PQ_query_param_uint32 (&psycstore_flags),
  596. GNUNET_PQ_query_param_auto_from_type (channel_key),
  597. GNUNET_PQ_query_param_uint64 (&message_id),
  598. GNUNET_PQ_query_param_end
  599. };
  600. if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
  601. GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "update_message_flags", params_update))
  602. return GNUNET_SYSERR;
  603. return GNUNET_OK;
  604. }
  605. /**
  606. * Closure for #fragment_rows.
  607. */
  608. struct FragmentRowsContext {
  609. GNUNET_PSYCSTORE_FragmentCallback cb;
  610. void *cb_cls;
  611. uint64_t *returned_fragments;
  612. /* I preserved this but I do not see the point since
  613. * it cannot stop the loop early and gets overwritten ?? */
  614. int ret;
  615. };
  616. /**
  617. * Callback that retrieves the results of a SELECT statement
  618. * reading form the messages table.
  619. *
  620. * Only passed to GNUNET_PQ_eval_prepared_multi_select and
  621. * has type GNUNET_PQ_PostgresResultHandler.
  622. *
  623. * @param cls closure
  624. * @param result the postgres result
  625. * @param num_result the number of results in @a result
  626. */
  627. void fragment_rows (void *cls,
  628. PGresult *res,
  629. unsigned int num_results)
  630. {
  631. struct FragmentRowsContext *c = cls;
  632. for (unsigned int i=0;i<num_results;i++)
  633. {
  634. uint32_t hop_counter;
  635. void *signature = NULL;
  636. void *purpose = NULL;
  637. size_t signature_size;
  638. size_t purpose_size;
  639. uint64_t fragment_id;
  640. uint64_t fragment_offset;
  641. uint64_t message_id;
  642. uint64_t group_generation;
  643. uint32_t flags;
  644. void *buf;
  645. size_t buf_size;
  646. uint32_t msg_flags;
  647. struct GNUNET_PQ_ResultSpec results[] = {
  648. GNUNET_PQ_result_spec_uint32 ("hop_counter", &hop_counter),
  649. GNUNET_PQ_result_spec_variable_size ("signature", &signature, &signature_size),
  650. GNUNET_PQ_result_spec_variable_size ("purpose", &purpose, &purpose_size),
  651. GNUNET_PQ_result_spec_uint64 ("fragment_id", &fragment_id),
  652. GNUNET_PQ_result_spec_uint64 ("fragment_offset", &fragment_offset),
  653. GNUNET_PQ_result_spec_uint64 ("message_id", &message_id),
  654. GNUNET_PQ_result_spec_uint64 ("group_generation", &group_generation),
  655. GNUNET_PQ_result_spec_uint32 ("multicast_flags", &msg_flags),
  656. GNUNET_PQ_result_spec_uint32 ("psycstore_flags", &flags),
  657. GNUNET_PQ_result_spec_variable_size ("data", &buf, &buf_size),
  658. GNUNET_PQ_result_spec_end
  659. };
  660. struct GNUNET_MULTICAST_MessageHeader *mp;
  661. if (GNUNET_YES != GNUNET_PQ_extract_result (res, results, i))
  662. {
  663. GNUNET_PQ_cleanup_result(results); /* missing previously, a memory leak?? */
  664. break; /* nothing more?? */
  665. }
  666. mp = GNUNET_malloc (sizeof (*mp) + buf_size);
  667. mp->header.size = htons (sizeof (*mp) + buf_size);
  668. mp->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE);
  669. mp->hop_counter = htonl (hop_counter);
  670. GNUNET_memcpy (&mp->signature,
  671. signature, signature_size);
  672. GNUNET_memcpy (&mp->purpose,
  673. purpose, purpose_size);
  674. mp->fragment_id = GNUNET_htonll (fragment_id);
  675. mp->fragment_offset = GNUNET_htonll (fragment_offset);
  676. mp->message_id = GNUNET_htonll (message_id);
  677. mp->group_generation = GNUNET_htonll (group_generation);
  678. mp->flags = htonl(msg_flags);
  679. GNUNET_memcpy (&mp[1],
  680. buf, buf_size);
  681. GNUNET_PQ_cleanup_result(results);
  682. c->ret = c->cb (c->cb_cls, mp, (enum GNUNET_PSYCSTORE_MessageFlags) flags);
  683. if (NULL != c->returned_fragments)
  684. (*c->returned_fragments)++;
  685. }
  686. }
  687. static int
  688. fragment_select (struct Plugin *plugin,
  689. const char *stmt,
  690. struct GNUNET_PQ_QueryParam *params,
  691. uint64_t *returned_fragments,
  692. GNUNET_PSYCSTORE_FragmentCallback cb,
  693. void *cb_cls)
  694. {
  695. /* Stack based closure */
  696. struct FragmentRowsContext frc = {
  697. .cb = cb,
  698. .cb_cls = cb_cls,
  699. .returned_fragments = returned_fragments,
  700. .ret = GNUNET_SYSERR
  701. };
  702. if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
  703. stmt, params,
  704. &fragment_rows, &frc))
  705. return GNUNET_SYSERR;
  706. return frc.ret; /* GNUNET_OK ?? */
  707. }
  708. /**
  709. * Retrieve a message fragment range by fragment ID.
  710. *
  711. * @see GNUNET_PSYCSTORE_fragment_get()
  712. *
  713. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  714. */
  715. static int
  716. fragment_get (void *cls,
  717. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  718. uint64_t first_fragment_id,
  719. uint64_t last_fragment_id,
  720. uint64_t *returned_fragments,
  721. GNUNET_PSYCSTORE_FragmentCallback cb,
  722. void *cb_cls)
  723. {
  724. struct Plugin *plugin = cls;
  725. struct GNUNET_PQ_QueryParam params_select[] = {
  726. GNUNET_PQ_query_param_auto_from_type (channel_key),
  727. GNUNET_PQ_query_param_uint64 (&first_fragment_id),
  728. GNUNET_PQ_query_param_uint64 (&last_fragment_id),
  729. GNUNET_PQ_query_param_end
  730. };
  731. *returned_fragments = 0;
  732. return fragment_select (plugin,
  733. "select_fragments",
  734. params_select,
  735. returned_fragments,
  736. cb, cb_cls);
  737. }
  738. /**
  739. * Retrieve a message fragment range by fragment ID.
  740. *
  741. * @see GNUNET_PSYCSTORE_fragment_get_latest()
  742. *
  743. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  744. */
  745. static int
  746. fragment_get_latest (void *cls,
  747. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  748. uint64_t fragment_limit,
  749. uint64_t *returned_fragments,
  750. GNUNET_PSYCSTORE_FragmentCallback cb,
  751. void *cb_cls)
  752. {
  753. struct Plugin *plugin = cls;
  754. *returned_fragments = 0;
  755. struct GNUNET_PQ_QueryParam params_select[] = {
  756. GNUNET_PQ_query_param_auto_from_type (channel_key),
  757. GNUNET_PQ_query_param_uint64 (&fragment_limit),
  758. GNUNET_PQ_query_param_end
  759. };
  760. return fragment_select (plugin,
  761. "select_latest_fragments",
  762. params_select,
  763. returned_fragments,
  764. cb, cb_cls);
  765. }
  766. /**
  767. * Retrieve all fragments of a message ID range.
  768. *
  769. * @see GNUNET_PSYCSTORE_message_get()
  770. *
  771. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  772. */
  773. static int
  774. message_get (void *cls,
  775. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  776. uint64_t first_message_id,
  777. uint64_t last_message_id,
  778. uint64_t fragment_limit,
  779. uint64_t *returned_fragments,
  780. GNUNET_PSYCSTORE_FragmentCallback cb,
  781. void *cb_cls)
  782. {
  783. struct Plugin *plugin = cls;
  784. struct GNUNET_PQ_QueryParam params_select[] = {
  785. GNUNET_PQ_query_param_auto_from_type (channel_key),
  786. GNUNET_PQ_query_param_uint64 (&first_message_id),
  787. GNUNET_PQ_query_param_uint64 (&last_message_id),
  788. GNUNET_PQ_query_param_uint64 (&fragment_limit),
  789. GNUNET_PQ_query_param_end
  790. };
  791. if (0 == fragment_limit)
  792. fragment_limit = INT64_MAX;
  793. *returned_fragments = 0;
  794. return fragment_select (plugin,
  795. "select_messages",
  796. params_select,
  797. returned_fragments,
  798. cb, cb_cls);
  799. }
  800. /**
  801. * Retrieve all fragments of the latest messages.
  802. *
  803. * @see GNUNET_PSYCSTORE_message_get_latest()
  804. *
  805. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  806. */
  807. static int
  808. message_get_latest (void *cls,
  809. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  810. uint64_t message_limit,
  811. uint64_t *returned_fragments,
  812. GNUNET_PSYCSTORE_FragmentCallback cb,
  813. void *cb_cls)
  814. {
  815. struct Plugin *plugin = cls;
  816. struct GNUNET_PQ_QueryParam params_select[] = {
  817. GNUNET_PQ_query_param_auto_from_type (channel_key),
  818. GNUNET_PQ_query_param_auto_from_type (channel_key),
  819. GNUNET_PQ_query_param_uint64 (&message_limit),
  820. GNUNET_PQ_query_param_end
  821. };
  822. *returned_fragments = 0;
  823. return fragment_select (plugin,
  824. "select_latest_messages",
  825. params_select,
  826. returned_fragments,
  827. cb, cb_cls);
  828. }
  829. /**
  830. * Retrieve a fragment of message specified by its message ID and fragment
  831. * offset.
  832. *
  833. * @see GNUNET_PSYCSTORE_message_get_fragment()
  834. *
  835. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  836. */
  837. static int
  838. message_get_fragment (void *cls,
  839. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  840. uint64_t message_id,
  841. uint64_t fragment_offset,
  842. GNUNET_PSYCSTORE_FragmentCallback cb,
  843. void *cb_cls)
  844. {
  845. struct Plugin *plugin = cls;
  846. const char *stmt = "select_message_fragment";
  847. struct GNUNET_PQ_QueryParam params_select[] = {
  848. GNUNET_PQ_query_param_auto_from_type (channel_key),
  849. GNUNET_PQ_query_param_uint64 (&message_id),
  850. GNUNET_PQ_query_param_uint64 (&fragment_offset),
  851. GNUNET_PQ_query_param_end
  852. };
  853. /* Stack based closure */
  854. struct FragmentRowsContext frc = {
  855. .cb = cb,
  856. .cb_cls = cb_cls,
  857. .returned_fragments = NULL,
  858. .ret = GNUNET_SYSERR
  859. };
  860. if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
  861. stmt, params_select,
  862. &fragment_rows, &frc))
  863. return GNUNET_SYSERR;
  864. return frc.ret; /* GNUNET_OK ?? */
  865. }
  866. /**
  867. * Retrieve the max. values of message counters for a channel.
  868. *
  869. * @see GNUNET_PSYCSTORE_counters_get()
  870. *
  871. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  872. */
  873. static int
  874. counters_message_get (void *cls,
  875. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  876. uint64_t *max_fragment_id,
  877. uint64_t *max_message_id,
  878. uint64_t *max_group_generation)
  879. {
  880. struct Plugin *plugin = cls;
  881. const char *stmt = "select_counters_message";
  882. struct GNUNET_PQ_QueryParam params_select[] = {
  883. GNUNET_PQ_query_param_auto_from_type (channel_key),
  884. GNUNET_PQ_query_param_end
  885. };
  886. struct GNUNET_PQ_ResultSpec results_select[] = {
  887. GNUNET_PQ_result_spec_uint64 ("fragment_id", max_fragment_id),
  888. GNUNET_PQ_result_spec_uint64 ("message_id", max_message_id),
  889. GNUNET_PQ_result_spec_uint64 ("group_generation", max_group_generation),
  890. GNUNET_PQ_result_spec_end
  891. };
  892. if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
  893. GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, stmt,
  894. params_select, results_select))
  895. return GNUNET_SYSERR;
  896. return GNUNET_OK;
  897. }
  898. /**
  899. * Retrieve the max. values of state counters for a channel.
  900. *
  901. * @see GNUNET_PSYCSTORE_counters_get()
  902. *
  903. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  904. */
  905. static int
  906. counters_state_get (void *cls,
  907. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  908. uint64_t *max_state_message_id)
  909. {
  910. struct Plugin *plugin = cls;
  911. const char *stmt = "select_counters_state";
  912. struct GNUNET_PQ_QueryParam params_select[] = {
  913. GNUNET_PQ_query_param_auto_from_type (channel_key),
  914. GNUNET_PQ_query_param_end
  915. };
  916. struct GNUNET_PQ_ResultSpec results_select[] = {
  917. GNUNET_PQ_result_spec_uint64 ("max_state_message_id", max_state_message_id),
  918. GNUNET_PQ_result_spec_end
  919. };
  920. if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
  921. GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, stmt,
  922. params_select, results_select))
  923. return GNUNET_SYSERR;
  924. return GNUNET_OK;
  925. }
  926. /**
  927. * Assign a value to a state variable.
  928. *
  929. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  930. */
  931. static int
  932. state_assign (struct Plugin *plugin, const char *stmt,
  933. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  934. const char *name, const void *value, size_t value_size)
  935. {
  936. struct GNUNET_PQ_QueryParam params[] = {
  937. GNUNET_PQ_query_param_auto_from_type (channel_key),
  938. GNUNET_PQ_query_param_string (name),
  939. GNUNET_PQ_query_param_fixed_size (value, value_size),
  940. GNUNET_PQ_query_param_end
  941. };
  942. if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
  943. GNUNET_PQ_eval_prepared_non_select (plugin->dbh, stmt, params))
  944. return GNUNET_SYSERR;
  945. return GNUNET_OK;
  946. }
  947. static int
  948. update_message_id (struct Plugin *plugin,
  949. const char *stmt,
  950. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  951. uint64_t message_id)
  952. {
  953. struct GNUNET_PQ_QueryParam params[] = {
  954. GNUNET_PQ_query_param_uint64 (&message_id),
  955. GNUNET_PQ_query_param_auto_from_type (channel_key),
  956. GNUNET_PQ_query_param_end
  957. };
  958. if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
  959. GNUNET_PQ_eval_prepared_non_select (plugin->dbh, stmt, params))
  960. return GNUNET_SYSERR;
  961. return GNUNET_OK;
  962. }
  963. /**
  964. * Begin modifying current state.
  965. */
  966. static int
  967. state_modify_begin (void *cls,
  968. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  969. uint64_t message_id, uint64_t state_delta)
  970. {
  971. struct Plugin *plugin = cls;
  972. if (state_delta > 0)
  973. {
  974. /**
  975. * We can only apply state modifiers in the current message if modifiers in
  976. * the previous stateful message (message_id - state_delta) were already
  977. * applied.
  978. */
  979. uint64_t max_state_message_id = 0;
  980. int ret = counters_state_get (plugin, channel_key, &max_state_message_id);
  981. switch (ret)
  982. {
  983. case GNUNET_OK:
  984. case GNUNET_NO: // no state yet
  985. ret = GNUNET_OK;
  986. break;
  987. default:
  988. return ret;
  989. }
  990. if (max_state_message_id < message_id - state_delta)
  991. return GNUNET_NO; /* some stateful messages not yet applied */
  992. else if (message_id - state_delta < max_state_message_id)
  993. return GNUNET_NO; /* changes already applied */
  994. }
  995. if (TRANSACTION_NONE != plugin->transaction)
  996. {
  997. /** @todo FIXME: wait for other transaction to finish */
  998. return GNUNET_SYSERR;
  999. }
  1000. return transaction_begin (plugin, TRANSACTION_STATE_MODIFY);
  1001. }
  1002. /**
  1003. * Set the current value of state variable.
  1004. *
  1005. * @see GNUNET_PSYCSTORE_state_modify()
  1006. *
  1007. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  1008. */
  1009. static int
  1010. state_modify_op (void *cls,
  1011. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  1012. enum GNUNET_PSYC_Operator op,
  1013. const char *name, const void *value, size_t value_size)
  1014. {
  1015. struct Plugin *plugin = cls;
  1016. GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction);
  1017. switch (op)
  1018. {
  1019. case GNUNET_PSYC_OP_ASSIGN:
  1020. return state_assign (plugin, "insert_state_current",
  1021. channel_key, name, value, value_size);
  1022. default: /** @todo implement more state operations */
  1023. GNUNET_break (0);
  1024. return GNUNET_SYSERR;
  1025. }
  1026. }
  1027. /**
  1028. * End modifying current state.
  1029. */
  1030. static int
  1031. state_modify_end (void *cls,
  1032. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  1033. uint64_t message_id)
  1034. {
  1035. struct Plugin *plugin = cls;
  1036. GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction);
  1037. return
  1038. GNUNET_OK == exec_channel (plugin, "delete_state_empty", channel_key)
  1039. && GNUNET_OK == update_message_id (plugin,
  1040. "update_max_state_message_id",
  1041. channel_key, message_id)
  1042. && GNUNET_OK == transaction_commit (plugin)
  1043. ? GNUNET_OK : GNUNET_SYSERR;
  1044. }
  1045. /**
  1046. * Begin state synchronization.
  1047. */
  1048. static int
  1049. state_sync_begin (void *cls,
  1050. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
  1051. {
  1052. struct Plugin *plugin = cls;
  1053. return exec_channel (plugin, "delete_state_sync", channel_key);
  1054. }
  1055. /**
  1056. * Assign current value of a state variable.
  1057. *
  1058. * @see GNUNET_PSYCSTORE_state_modify()
  1059. *
  1060. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  1061. */
  1062. static int
  1063. state_sync_assign (void *cls,
  1064. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  1065. const char *name, const void *value, size_t value_size)
  1066. {
  1067. struct Plugin *plugin = cls;
  1068. return state_assign (plugin, "insert_state_sync",
  1069. channel_key, name, value, value_size);
  1070. }
  1071. /**
  1072. * End modifying current state.
  1073. */
  1074. static int
  1075. state_sync_end (void *cls,
  1076. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  1077. uint64_t max_state_message_id,
  1078. uint64_t state_hash_message_id)
  1079. {
  1080. struct Plugin *plugin = cls;
  1081. int ret = GNUNET_SYSERR;
  1082. if (TRANSACTION_NONE != plugin->transaction)
  1083. {
  1084. /** @todo FIXME: wait for other transaction to finish */
  1085. return GNUNET_SYSERR;
  1086. }
  1087. GNUNET_OK == transaction_begin (plugin, TRANSACTION_STATE_SYNC)
  1088. && GNUNET_OK == exec_channel (plugin, "delete_state", channel_key)
  1089. && GNUNET_OK == exec_channel (plugin, "insert_state_from_sync",
  1090. channel_key)
  1091. && GNUNET_OK == exec_channel (plugin, "delete_state_sync",
  1092. channel_key)
  1093. && GNUNET_OK == update_message_id (plugin,
  1094. "update_state_hash_message_id",
  1095. channel_key, state_hash_message_id)
  1096. && GNUNET_OK == update_message_id (plugin,
  1097. "update_max_state_message_id",
  1098. channel_key, max_state_message_id)
  1099. && GNUNET_OK == transaction_commit (plugin)
  1100. ? ret = GNUNET_OK
  1101. : transaction_rollback (plugin);
  1102. return ret;
  1103. }
  1104. /**
  1105. * Delete the whole state.
  1106. *
  1107. * @see GNUNET_PSYCSTORE_state_reset()
  1108. *
  1109. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  1110. */
  1111. static int
  1112. state_reset (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
  1113. {
  1114. struct Plugin *plugin = cls;
  1115. return exec_channel (plugin, "delete_state", channel_key);
  1116. }
  1117. /**
  1118. * Update signed values of state variables in the state store.
  1119. *
  1120. * @see GNUNET_PSYCSTORE_state_hash_update()
  1121. *
  1122. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  1123. */
  1124. static int
  1125. state_update_signed (void *cls,
  1126. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
  1127. {
  1128. struct Plugin *plugin = cls;
  1129. return exec_channel (plugin, "update_state_signed", channel_key);
  1130. }
  1131. /**
  1132. * Retrieve a state variable by name.
  1133. *
  1134. * @see GNUNET_PSYCSTORE_state_get()
  1135. *
  1136. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  1137. */
  1138. static int
  1139. state_get (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  1140. const char *name, GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls)
  1141. {
  1142. struct Plugin *plugin = cls;
  1143. const char *stmt = "select_state_one";
  1144. struct GNUNET_PQ_QueryParam params_select[] = {
  1145. GNUNET_PQ_query_param_auto_from_type (channel_key),
  1146. GNUNET_PQ_query_param_string (name),
  1147. GNUNET_PQ_query_param_end
  1148. };
  1149. void *value_current = NULL;
  1150. size_t value_size = 0;
  1151. struct GNUNET_PQ_ResultSpec results_select[] = {
  1152. GNUNET_PQ_result_spec_variable_size ("value_current", &value_current, &value_size),
  1153. GNUNET_PQ_result_spec_end
  1154. };
  1155. if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
  1156. GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, stmt,
  1157. params_select, results_select))
  1158. return GNUNET_SYSERR;
  1159. return cb (cb_cls, name, value_current,
  1160. value_size);
  1161. }
  1162. /**
  1163. * Closure for #get_state_cb.
  1164. */
  1165. struct GetStateContext {
  1166. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key;
  1167. // const char *name,
  1168. GNUNET_PSYCSTORE_StateCallback cb;
  1169. void *cb_cls;
  1170. const char *value_id;
  1171. /* I preserved this but I do not see the point since
  1172. * it cannot stop the loop early and gets overwritten ?? */
  1173. int ret;
  1174. };
  1175. /**
  1176. * Callback that retrieves the results of a SELECT statement
  1177. * reading form the state table.
  1178. *
  1179. * Only passed to GNUNET_PQ_eval_prepared_multi_select and
  1180. * has type GNUNET_PQ_PostgresResultHandler.
  1181. *
  1182. * @param cls closure
  1183. * @param result the postgres result
  1184. * @param num_result the number of results in @a result
  1185. */
  1186. static void
  1187. get_state_cb (void *cls,
  1188. PGresult *res,
  1189. unsigned int num_results)
  1190. {
  1191. struct GetStateContext *c = cls;
  1192. for (unsigned int i=0;i<num_results;i++)
  1193. {
  1194. char *name = "";
  1195. void *value = NULL;
  1196. size_t value_size = 0;
  1197. struct GNUNET_PQ_ResultSpec results[] = {
  1198. GNUNET_PQ_result_spec_string ("name", &name),
  1199. GNUNET_PQ_result_spec_variable_size (c->value_id, &value, &value_size),
  1200. GNUNET_PQ_result_spec_end
  1201. };
  1202. if (GNUNET_YES != GNUNET_PQ_extract_result (res, results, i))
  1203. {
  1204. GNUNET_PQ_cleanup_result(results); /* previously invoked via PQclear?? */
  1205. break; /* nothing more?? */
  1206. }
  1207. c->ret = c->cb (c->cb_cls, (const char *) name, value, value_size);
  1208. GNUNET_PQ_cleanup_result(results);
  1209. }
  1210. }
  1211. /**
  1212. * Retrieve all state variables for a channel with the given prefix.
  1213. *
  1214. * @see GNUNET_PSYCSTORE_state_get_prefix()
  1215. *
  1216. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  1217. */
  1218. static int
  1219. state_get_prefix (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  1220. const char *name, GNUNET_PSYCSTORE_StateCallback cb,
  1221. void *cb_cls)
  1222. {
  1223. struct Plugin *plugin = cls;
  1224. const char *stmt = "select_state_prefix";
  1225. uint32_t name_len = (uint32_t) strlen (name);
  1226. struct GNUNET_PQ_QueryParam params_select[] = {
  1227. GNUNET_PQ_query_param_auto_from_type (channel_key),
  1228. GNUNET_PQ_query_param_string (name),
  1229. GNUNET_PQ_query_param_uint32 (&name_len),
  1230. GNUNET_PQ_query_param_string (name),
  1231. GNUNET_PQ_query_param_end
  1232. };
  1233. struct GetStateContext gsc = {
  1234. .cb = cb,
  1235. .cb_cls = cb_cls,
  1236. .value_id = "value_current",
  1237. .ret = GNUNET_NO
  1238. };
  1239. if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
  1240. stmt, params_select,
  1241. &get_state_cb, &gsc))
  1242. return GNUNET_SYSERR;
  1243. return gsc.ret; /* GNUNET_OK ?? */
  1244. }
  1245. /**
  1246. * Retrieve all signed state variables for a channel.
  1247. *
  1248. * @see GNUNET_PSYCSTORE_state_get_signed()
  1249. *
  1250. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  1251. */
  1252. static int
  1253. state_get_signed (void *cls,
  1254. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  1255. GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls)
  1256. {
  1257. struct Plugin *plugin = cls;
  1258. const char *stmt = "select_state_signed";
  1259. struct GNUNET_PQ_QueryParam params_select[] = {
  1260. GNUNET_PQ_query_param_auto_from_type (channel_key),
  1261. GNUNET_PQ_query_param_end
  1262. };
  1263. struct GetStateContext gsc = {
  1264. .cb = cb,
  1265. .cb_cls = cb_cls,
  1266. .value_id = "value_signed",
  1267. .ret = GNUNET_NO
  1268. };
  1269. if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
  1270. stmt, params_select,
  1271. &get_state_cb, &gsc))
  1272. return GNUNET_SYSERR;
  1273. return gsc.ret; /* GNUNET_OK ?? */
  1274. }
  1275. /**
  1276. * Entry point for the plugin.
  1277. *
  1278. * @param cls The struct GNUNET_CONFIGURATION_Handle.
  1279. * @return NULL on error, otherwise the plugin context
  1280. */
  1281. void *
  1282. libgnunet_plugin_psycstore_postgres_init (void *cls)
  1283. {
  1284. static struct Plugin plugin;
  1285. const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
  1286. struct GNUNET_PSYCSTORE_PluginFunctions *api;
  1287. if (NULL != plugin.cfg)
  1288. return NULL; /* can only initialize once! */
  1289. memset (&plugin, 0, sizeof (struct Plugin));
  1290. plugin.cfg = cfg;
  1291. if (GNUNET_OK != database_setup (&plugin))
  1292. {
  1293. database_shutdown (&plugin);
  1294. return NULL;
  1295. }
  1296. api = GNUNET_new (struct GNUNET_PSYCSTORE_PluginFunctions);
  1297. api->cls = &plugin;
  1298. api->membership_store = &postgres_membership_store;
  1299. api->membership_test = &membership_test;
  1300. api->fragment_store = &fragment_store;
  1301. api->message_add_flags = &message_add_flags;
  1302. api->fragment_get = &fragment_get;
  1303. api->fragment_get_latest = &fragment_get_latest;
  1304. api->message_get = &message_get;
  1305. api->message_get_latest = &message_get_latest;
  1306. api->message_get_fragment = &message_get_fragment;
  1307. api->counters_message_get = &counters_message_get;
  1308. api->counters_state_get = &counters_state_get;
  1309. api->state_modify_begin = &state_modify_begin;
  1310. api->state_modify_op = &state_modify_op;
  1311. api->state_modify_end = &state_modify_end;
  1312. api->state_sync_begin = &state_sync_begin;
  1313. api->state_sync_assign = &state_sync_assign;
  1314. api->state_sync_end = &state_sync_end;
  1315. api->state_reset = &state_reset;
  1316. api->state_update_signed = &state_update_signed;
  1317. api->state_get = &state_get;
  1318. api->state_get_prefix = &state_get_prefix;
  1319. api->state_get_signed = &state_get_signed;
  1320. LOG (GNUNET_ERROR_TYPE_INFO, _("Postgres database running\n"));
  1321. return api;
  1322. }
  1323. /**
  1324. * Exit point from the plugin.
  1325. *
  1326. * @param cls The plugin context (as returned by "init")
  1327. * @return Always NULL
  1328. */
  1329. void *
  1330. libgnunet_plugin_psycstore_postgres_done (void *cls)
  1331. {
  1332. struct GNUNET_PSYCSTORE_PluginFunctions *api = cls;
  1333. struct Plugin *plugin = api->cls;
  1334. database_shutdown (plugin);
  1335. plugin->cfg = NULL;
  1336. GNUNET_free (api);
  1337. LOG (GNUNET_ERROR_TYPE_DEBUG, "Postgres plugin has finished\n");
  1338. return NULL;
  1339. }
  1340. /* end of plugin_psycstore_postgres.c */