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.
 
 
 
 

1961 lines
56 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. * @file psycstore/plugin_psycstore_mysql.c
  21. * @brief mysql-based psycstore backend
  22. * @author Gabor X Toth
  23. * @author Christian Grothoff
  24. * @author Christophe Genevey
  25. */
  26. #include "platform.h"
  27. #include "gnunet_psycstore_plugin.h"
  28. #include "gnunet_psycstore_service.h"
  29. #include "gnunet_multicast_service.h"
  30. #include "gnunet_crypto_lib.h"
  31. #include "gnunet_psyc_util_lib.h"
  32. #include "psycstore.h"
  33. #include "gnunet_my_lib.h"
  34. #include "gnunet_mysql_lib.h"
  35. #include <mysql/mysql.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. /**
  49. * Log an error message at log-level 'level' that indicates
  50. * a failure of the command 'cmd' on file 'filename'
  51. * with the message given by strerror(errno).
  52. */
  53. #define LOG_MYSQL(db, level, cmd, stmt) \
  54. do { \
  55. GNUNET_log_from (level, "psycstore-mysql", \
  56. _("`%s' failed at %s:%d with error: %s\n"), \
  57. cmd, __FILE__, __LINE__, \
  58. mysql_stmt_error (GNUNET_MYSQL_statement_get_stmt(stmt))); \
  59. } while (0)
  60. #define LOG(kind,...) GNUNET_log_from (kind, "psycstore-mysql", __VA_ARGS__)
  61. enum Transactions {
  62. TRANSACTION_NONE = 0,
  63. TRANSACTION_STATE_MODIFY,
  64. TRANSACTION_STATE_SYNC,
  65. };
  66. /**
  67. * Context for all functions in this plugin.
  68. */
  69. struct Plugin
  70. {
  71. const struct GNUNET_CONFIGURATION_Handle *cfg;
  72. /**
  73. * MySQL context.
  74. */
  75. struct GNUNET_MYSQL_Context *mc;
  76. /**
  77. * Current transaction.
  78. */
  79. enum Transactions transaction;
  80. /**
  81. * Precompiled SQL for channel_key_store()
  82. */
  83. struct GNUNET_MYSQL_StatementHandle *insert_channel_key;
  84. /**
  85. * Precompiled SQL for slave_key_store()
  86. */
  87. struct GNUNET_MYSQL_StatementHandle *insert_slave_key;
  88. /**
  89. * Precompiled SQL for membership_store()
  90. */
  91. struct GNUNET_MYSQL_StatementHandle *insert_membership;
  92. /**
  93. * Precompiled SQL for membership_test()
  94. */
  95. struct GNUNET_MYSQL_StatementHandle *select_membership;
  96. /**
  97. * Precompiled SQL for fragment_store()
  98. */
  99. struct GNUNET_MYSQL_StatementHandle *insert_fragment;
  100. /**
  101. * Precompiled SQL for message_add_flags()
  102. */
  103. struct GNUNET_MYSQL_StatementHandle *update_message_flags;
  104. /**
  105. * Precompiled SQL for fragment_get()
  106. */
  107. struct GNUNET_MYSQL_StatementHandle *select_fragments;
  108. /**
  109. * Precompiled SQL for fragment_get()
  110. */
  111. struct GNUNET_MYSQL_StatementHandle *select_latest_fragments;
  112. /**
  113. * Precompiled SQL for message_get()
  114. */
  115. struct GNUNET_MYSQL_StatementHandle *select_messages;
  116. /**
  117. * Precompiled SQL for message_get()
  118. */
  119. struct GNUNET_MYSQL_StatementHandle *select_latest_messages;
  120. /**
  121. * Precompiled SQL for message_get_fragment()
  122. */
  123. struct GNUNET_MYSQL_StatementHandle *select_message_fragment;
  124. /**
  125. * Precompiled SQL for counters_get_message()
  126. */
  127. struct GNUNET_MYSQL_StatementHandle *select_counters_message;
  128. /**
  129. * Precompiled SQL for counters_get_state()
  130. */
  131. struct GNUNET_MYSQL_StatementHandle *select_counters_state;
  132. /**
  133. * Precompiled SQL for state_modify_end()
  134. */
  135. struct GNUNET_MYSQL_StatementHandle *update_state_hash_message_id;
  136. /**
  137. * Precompiled SQL for state_sync_end()
  138. */
  139. struct GNUNET_MYSQL_StatementHandle *update_max_state_message_id;
  140. /**
  141. * Precompiled SQL for state_modify_op()
  142. */
  143. struct GNUNET_MYSQL_StatementHandle *insert_state_current;
  144. /**
  145. * Precompiled SQL for state_modify_end()
  146. */
  147. struct GNUNET_MYSQL_StatementHandle *delete_state_empty;
  148. /**
  149. * Precompiled SQL for state_set_signed()
  150. */
  151. struct GNUNET_MYSQL_StatementHandle *update_state_signed;
  152. /**
  153. * Precompiled SQL for state_sync()
  154. */
  155. struct GNUNET_MYSQL_StatementHandle *insert_state_sync;
  156. /**
  157. * Precompiled SQL for state_sync()
  158. */
  159. struct GNUNET_MYSQL_StatementHandle *delete_state;
  160. /**
  161. * Precompiled SQL for state_sync()
  162. */
  163. struct GNUNET_MYSQL_StatementHandle *insert_state_from_sync;
  164. /**
  165. * Precompiled SQL for state_sync()
  166. */
  167. struct GNUNET_MYSQL_StatementHandle *delete_state_sync;
  168. /**
  169. * Precompiled SQL for state_get_signed()
  170. */
  171. struct GNUNET_MYSQL_StatementHandle *select_state_signed;
  172. /**
  173. * Precompiled SQL for state_get()
  174. */
  175. struct GNUNET_MYSQL_StatementHandle *select_state_one;
  176. /**
  177. * Precompiled SQL for state_get_prefix()
  178. */
  179. struct GNUNET_MYSQL_StatementHandle *select_state_prefix;
  180. };
  181. #if DEBUG_PSYCSTORE
  182. static void
  183. mysql_trace (void *cls, const char *sql)
  184. {
  185. LOG(GNUNET_ERROR_TYPE_DEBUG, "MYSQL query:\n%s\n", sql);
  186. }
  187. #endif
  188. /**
  189. * @brief Prepare a SQL statement
  190. *
  191. * @param dbh handle to the database
  192. * @param sql SQL statement, UTF-8 encoded
  193. * @param stmt set to the prepared statement
  194. * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
  195. */
  196. static int
  197. mysql_prepare (struct GNUNET_MYSQL_Context *mc,
  198. const char *sql,
  199. struct GNUNET_MYSQL_StatementHandle **stmt)
  200. {
  201. *stmt = GNUNET_MYSQL_statement_prepare (mc,
  202. sql);
  203. if (NULL == *stmt)
  204. {
  205. LOG (GNUNET_ERROR_TYPE_ERROR,
  206. _("Error preparing SQL query: %s\n %s\n"),
  207. mysql_stmt_error (GNUNET_MYSQL_statement_get_stmt (*stmt)),
  208. sql);
  209. return GNUNET_SYSERR;
  210. }
  211. LOG (GNUNET_ERROR_TYPE_DEBUG,
  212. "Prepared `%s' / %p\n",
  213. sql,
  214. stmt);
  215. return GNUNET_OK;
  216. }
  217. /**
  218. * Initialize the database connections and associated
  219. * data structures (create tables and indices
  220. * as needed as well).
  221. *
  222. * @param plugin the plugin context (state for this module)
  223. * @return #GNUNET_OK on success
  224. */
  225. static int
  226. database_setup (struct Plugin *plugin)
  227. {
  228. /* Open database and precompile statements */
  229. plugin->mc = GNUNET_MYSQL_context_create (plugin->cfg,
  230. "psycstore-mysql");
  231. if (NULL == plugin->mc)
  232. {
  233. LOG (GNUNET_ERROR_TYPE_ERROR,
  234. _("Unable to initialize Mysql.\n"));
  235. return GNUNET_SYSERR;
  236. }
  237. #define STMT_RUN(sql) \
  238. if (GNUNET_OK != \
  239. GNUNET_MYSQL_statement_run (plugin->mc, \
  240. sql)) \
  241. { \
  242. GNUNET_log (GNUNET_ERROR_TYPE_ERROR, \
  243. _("Failed to run SQL statement `%s'\n"), \
  244. sql); \
  245. return GNUNET_SYSERR; \
  246. }
  247. /* Create tables */
  248. STMT_RUN ("CREATE TABLE IF NOT EXISTS channels (\n"
  249. " id BIGINT UNSIGNED AUTO_INCREMENT,\n"
  250. " pub_key BLOB(32),\n"
  251. " max_state_message_id BIGINT UNSIGNED,\n"
  252. " state_hash_message_id BIGINT UNSIGNED,\n"
  253. " PRIMARY KEY(id),\n"
  254. " UNIQUE KEY(pub_key(32))\n"
  255. ");");
  256. STMT_RUN ("CREATE TABLE IF NOT EXISTS slaves (\n"
  257. " id BIGINT UNSIGNED AUTO_INCREMENT,\n"
  258. " pub_key BLOB(32),\n"
  259. " PRIMARY KEY(id),\n"
  260. " UNIQUE KEY(pub_key(32))\n"
  261. ");");
  262. STMT_RUN ("CREATE TABLE IF NOT EXISTS membership (\n"
  263. " channel_id BIGINT UNSIGNED NOT NULL REFERENCES channels(id),\n"
  264. " slave_id BIGINT UNSIGNED NOT NULL REFERENCES slaves(id),\n"
  265. " did_join TINYINT NOT NULL,\n"
  266. " announced_at BIGINT UNSIGNED NOT NULL,\n"
  267. " effective_since BIGINT UNSIGNED NOT NULL,\n"
  268. " group_generation BIGINT UNSIGNED NOT NULL\n"
  269. ");");
  270. /*** FIX because IF NOT EXISTS doesn't work ***/
  271. GNUNET_MYSQL_statement_run (plugin->mc,
  272. "CREATE INDEX idx_membership_channel_id_slave_id "
  273. "ON membership (channel_id, slave_id);");
  274. /** @todo messages table: add method_name column */
  275. STMT_RUN ("CREATE TABLE IF NOT EXISTS messages (\n"
  276. " channel_id BIGINT UNSIGNED NOT NULL REFERENCES channels(id),\n"
  277. " hop_counter BIGINT UNSIGNED NOT NULL,\n"
  278. " signature BLOB,\n"
  279. " purpose BLOB,\n"
  280. " fragment_id BIGINT UNSIGNED NOT NULL,\n"
  281. " fragment_offset BIGINT UNSIGNED NOT NULL,\n"
  282. " message_id BIGINT UNSIGNED NOT NULL,\n"
  283. " group_generation BIGINT UNSIGNED NOT NULL,\n"
  284. " multicast_flags BIGINT UNSIGNED NOT NULL,\n"
  285. " psycstore_flags BIGINT UNSIGNED NOT NULL,\n"
  286. " data BLOB,\n"
  287. " PRIMARY KEY (channel_id, fragment_id),\n"
  288. " UNIQUE KEY(channel_id, message_id, fragment_offset)\n"
  289. ");");
  290. STMT_RUN ("CREATE TABLE IF NOT EXISTS state (\n"
  291. " channel_id BIGINT UNSIGNED NOT NULL REFERENCES channels(id),\n"
  292. " name TEXT NOT NULL,\n"
  293. " value_current BLOB,\n"
  294. " value_signed BLOB\n"
  295. //" PRIMARY KEY (channel_id, name(255))\n"
  296. ");");
  297. STMT_RUN ("CREATE TABLE IF NOT EXISTS state_sync (\n"
  298. " channel_id BIGINT UNSIGNED NOT NULL REFERENCES channels(id),\n"
  299. " name TEXT NOT NULL,\n"
  300. " value BLOB\n"
  301. //" PRIMARY KEY (channel_id, name(255))\n"
  302. ");");
  303. #undef STMT_RUN
  304. /* Prepare statements */
  305. #define PREP(stmt,handle) \
  306. if (GNUNET_OK != mysql_prepare (plugin->mc, stmt, handle)) \
  307. { \
  308. GNUNET_break (0); \
  309. return GNUNET_SYSERR; \
  310. }
  311. PREP ("INSERT IGNORE INTO channels (pub_key) VALUES (?);",
  312. &plugin->insert_channel_key);
  313. PREP ("INSERT IGNORE INTO slaves (pub_key) VALUES (?);",
  314. &plugin->insert_slave_key);
  315. PREP ("INSERT INTO membership\n"
  316. " (channel_id, slave_id, did_join, announced_at,\n"
  317. " effective_since, group_generation)\n"
  318. "VALUES ((SELECT id FROM channels WHERE pub_key = ?),\n"
  319. " (SELECT id FROM slaves WHERE pub_key = ?),\n"
  320. " ?, ?, ?, ?);",
  321. &plugin->insert_membership);
  322. PREP ("SELECT did_join FROM membership\n"
  323. "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
  324. " AND slave_id = (SELECT id FROM slaves WHERE pub_key = ?)\n"
  325. " AND effective_since <= ? AND did_join = 1\n"
  326. "ORDER BY announced_at DESC LIMIT 1;",
  327. &plugin->select_membership);
  328. PREP ("INSERT IGNORE INTO messages\n"
  329. " (channel_id, hop_counter, signature, purpose,\n"
  330. " fragment_id, fragment_offset, message_id,\n"
  331. " group_generation, multicast_flags, psycstore_flags, data)\n"
  332. "VALUES ((SELECT id FROM channels WHERE pub_key = ?),\n"
  333. " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);",
  334. &plugin->insert_fragment);
  335. PREP ("UPDATE messages\n"
  336. "SET psycstore_flags = psycstore_flags | ?\n"
  337. "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
  338. " AND message_id = ? AND fragment_offset = 0;",
  339. &plugin->update_message_flags);
  340. PREP ("SELECT hop_counter, signature, purpose, fragment_id,\n"
  341. " fragment_offset, message_id, group_generation,\n"
  342. " multicast_flags, psycstore_flags, data\n"
  343. "FROM messages\n"
  344. "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
  345. " AND ? <= fragment_id AND fragment_id <= ? LIMIT 1;",
  346. &plugin->select_fragments);
  347. /** @todo select_messages: add method_prefix filter */
  348. PREP ("SELECT hop_counter, signature, purpose, fragment_id,\n"
  349. " fragment_offset, message_id, group_generation,\n"
  350. " multicast_flags, psycstore_flags, data\n"
  351. "FROM messages\n"
  352. "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
  353. " AND ? <= message_id AND message_id <= ?\n"
  354. "LIMIT ?;",
  355. &plugin->select_messages);
  356. PREP ("SELECT * FROM\n"
  357. "(SELECT hop_counter, signature, purpose, fragment_id,\n"
  358. " fragment_offset, message_id, group_generation,\n"
  359. " multicast_flags, psycstore_flags, data\n"
  360. " FROM messages\n"
  361. " WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
  362. " ORDER BY fragment_id DESC\n"
  363. " LIMIT ?)\n"
  364. "ORDER BY fragment_id;",
  365. &plugin->select_latest_fragments);
  366. /** @todo select_latest_messages: add method_prefix filter */
  367. PREP ("SELECT hop_counter, signature, purpose, fragment_id,\n"
  368. " fragment_offset, message_id, group_generation,\n"
  369. " multicast_flags, psycstore_flags, data\n"
  370. "FROM messages\n"
  371. "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
  372. " AND message_id IN\n"
  373. " (SELECT message_id\n"
  374. " FROM messages\n"
  375. " WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
  376. " GROUP BY message_id\n"
  377. " ORDER BY message_id\n"
  378. " DESC LIMIT ?)\n"
  379. "ORDER BY fragment_id;",
  380. &plugin->select_latest_messages);
  381. PREP ("SELECT hop_counter, signature, purpose, fragment_id,\n"
  382. " fragment_offset, message_id, group_generation,\n"
  383. " multicast_flags, psycstore_flags, data\n"
  384. "FROM messages\n"
  385. "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
  386. " AND message_id = ? AND fragment_offset = ?;",
  387. &plugin->select_message_fragment);
  388. PREP ("SELECT fragment_id, message_id, group_generation\n"
  389. "FROM messages\n"
  390. "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
  391. "ORDER BY fragment_id DESC LIMIT 1;",
  392. &plugin->select_counters_message);
  393. PREP ("SELECT max_state_message_id\n"
  394. "FROM channels\n"
  395. "WHERE pub_key = ? AND max_state_message_id IS NOT NULL;",
  396. &plugin->select_counters_state);
  397. PREP ("UPDATE channels\n"
  398. "SET max_state_message_id = ?\n"
  399. "WHERE pub_key = ?;",
  400. &plugin->update_max_state_message_id);
  401. PREP ("UPDATE channels\n"
  402. "SET state_hash_message_id = ?\n"
  403. "WHERE pub_key = ?;",
  404. &plugin->update_state_hash_message_id);
  405. PREP ("REPLACE INTO state\n"
  406. " (channel_id, name, value_current, value_signed)\n"
  407. "SELECT new.channel_id, new.name, new.value_current, old.value_signed\n"
  408. "FROM (SELECT (SELECT id FROM channels WHERE pub_key = ?) AS channel_id,\n"
  409. " (SELECT ?) AS name,\n"
  410. " (SELECT ?) AS value_current\n"
  411. " ) AS new\n"
  412. "LEFT JOIN (SELECT channel_id, name, value_signed\n"
  413. " FROM state) AS old\n"
  414. "ON new.channel_id = old.channel_id AND new.name = old.name;",
  415. &plugin->insert_state_current);
  416. PREP ("DELETE FROM state\n"
  417. "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
  418. " AND (value_current IS NULL OR length(value_current) = 0)\n"
  419. " AND (value_signed IS NULL OR length(value_signed) = 0);",
  420. &plugin->delete_state_empty);
  421. PREP ("UPDATE state\n"
  422. "SET value_signed = value_current\n"
  423. "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);",
  424. &plugin->update_state_signed);
  425. PREP ("DELETE FROM state\n"
  426. "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);",
  427. &plugin->delete_state);
  428. PREP ("INSERT INTO state_sync (channel_id, name, value)\n"
  429. "VALUES ((SELECT id FROM channels WHERE pub_key = ?), ?, ?);",
  430. &plugin->insert_state_sync);
  431. PREP ("INSERT INTO state\n"
  432. " (channel_id, name, value_current, value_signed)\n"
  433. "SELECT channel_id, name, value, value\n"
  434. "FROM state_sync\n"
  435. "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);",
  436. &plugin->insert_state_from_sync);
  437. PREP ("DELETE FROM state_sync\n"
  438. "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);",
  439. &plugin->delete_state_sync);
  440. PREP ("SELECT value_current\n"
  441. "FROM state\n"
  442. "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
  443. " AND name = ?;",
  444. &plugin->select_state_one);
  445. PREP ("SELECT name, value_current\n"
  446. "FROM state\n"
  447. "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n"
  448. " AND (name = ? OR substr(name, 1, ?) = ?);",
  449. &plugin->select_state_prefix);
  450. PREP ("SELECT name, value_signed\n"
  451. "FROM state\n"
  452. "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)"
  453. " AND value_signed IS NOT NULL;",
  454. &plugin->select_state_signed);
  455. #undef PREP
  456. return GNUNET_OK;
  457. }
  458. /**
  459. * Shutdown database connection and associate data
  460. * structures.
  461. * @param plugin the plugin context (state for this module)
  462. */
  463. static void
  464. database_shutdown (struct Plugin *plugin)
  465. {
  466. GNUNET_MYSQL_context_destroy (plugin->mc);
  467. }
  468. /**
  469. * Execute a prepared statement with a @a channel_key argument.
  470. *
  471. * @param plugin Plugin handle.
  472. * @param stmt Statement to execute.
  473. * @param channel_key Public key of the channel.
  474. *
  475. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  476. */
  477. static int
  478. exec_channel (struct Plugin *plugin, struct GNUNET_MYSQL_StatementHandle *stmt,
  479. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
  480. {
  481. struct GNUNET_MY_QueryParam params[] = {
  482. GNUNET_MY_query_param_auto_from_type (channel_key),
  483. GNUNET_MY_query_param_end
  484. };
  485. if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params))
  486. {
  487. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  488. "mysql exec_channel", stmt);
  489. }
  490. if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
  491. {
  492. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  493. "mysql_stmt_reset", stmt);
  494. return GNUNET_SYSERR;
  495. }
  496. return GNUNET_OK;
  497. }
  498. /**
  499. * Begin a transaction.
  500. */
  501. static int
  502. transaction_begin (struct Plugin *plugin, enum Transactions transaction)
  503. {
  504. if (GNUNET_OK != GNUNET_MYSQL_statement_run (plugin->mc, "BEGIN"))
  505. {
  506. LOG(GNUNET_ERROR_TYPE_ERROR, "transaction_begin failed");
  507. return GNUNET_SYSERR;
  508. }
  509. plugin->transaction = transaction;
  510. return GNUNET_OK;
  511. }
  512. /**
  513. * Commit current transaction.
  514. */
  515. static int
  516. transaction_commit (struct Plugin *plugin)
  517. {
  518. if (GNUNET_OK != GNUNET_MYSQL_statement_run (plugin->mc, "COMMIT"))
  519. {
  520. LOG(GNUNET_ERROR_TYPE_ERROR, "transaction_commit failed");
  521. return GNUNET_SYSERR;
  522. }
  523. plugin->transaction = TRANSACTION_NONE;
  524. return GNUNET_OK;
  525. }
  526. /**
  527. * Roll back current transaction.
  528. */
  529. static int
  530. transaction_rollback (struct Plugin *plugin)
  531. {
  532. if (GNUNET_OK != GNUNET_MYSQL_statement_run (plugin->mc, "ROLLBACK"))
  533. {
  534. LOG(GNUNET_ERROR_TYPE_ERROR, "transaction_rollback failed");
  535. return GNUNET_SYSERR;
  536. }
  537. plugin->transaction = TRANSACTION_NONE;
  538. return GNUNET_OK;
  539. }
  540. static int
  541. channel_key_store (struct Plugin *plugin,
  542. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
  543. {
  544. struct GNUNET_MYSQL_StatementHandle *stmt = plugin->insert_channel_key;
  545. struct GNUNET_MY_QueryParam params[] = {
  546. GNUNET_MY_query_param_auto_from_type (channel_key),
  547. GNUNET_MY_query_param_end
  548. };
  549. if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params))
  550. {
  551. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  552. "mysql exec_prepared", stmt);
  553. return GNUNET_SYSERR;
  554. }
  555. if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
  556. {
  557. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  558. "mysql_stmt_reset", stmt);
  559. return GNUNET_SYSERR;
  560. }
  561. return GNUNET_OK;
  562. }
  563. static int
  564. slave_key_store (struct Plugin *plugin,
  565. const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key)
  566. {
  567. struct GNUNET_MYSQL_StatementHandle *stmt = plugin->insert_slave_key;
  568. struct GNUNET_MY_QueryParam params[] = {
  569. GNUNET_MY_query_param_auto_from_type (slave_key),
  570. GNUNET_MY_query_param_end
  571. };
  572. if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params))
  573. {
  574. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  575. "mysql exec_prepared", stmt);
  576. return GNUNET_SYSERR;
  577. }
  578. if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
  579. {
  580. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  581. "mysql_stmt_reset", stmt);
  582. return GNUNET_SYSERR;
  583. }
  584. return GNUNET_OK;
  585. }
  586. /**
  587. * Store join/leave events for a PSYC channel in order to be able to answer
  588. * membership test queries later.
  589. *
  590. * @see GNUNET_PSYCSTORE_membership_store()
  591. *
  592. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  593. */
  594. static int
  595. mysql_membership_store (void *cls,
  596. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  597. const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
  598. int did_join,
  599. uint64_t announced_at,
  600. uint64_t effective_since,
  601. uint64_t group_generation)
  602. {
  603. struct Plugin *plugin = cls;
  604. uint32_t idid_join = (uint32_t)did_join;
  605. struct GNUNET_MYSQL_StatementHandle *stmt = plugin->insert_membership;
  606. GNUNET_assert (TRANSACTION_NONE == plugin->transaction);
  607. if (announced_at > INT64_MAX ||
  608. effective_since > INT64_MAX ||
  609. group_generation > INT64_MAX)
  610. {
  611. GNUNET_break (0);
  612. return GNUNET_SYSERR;
  613. }
  614. if (GNUNET_OK != channel_key_store (plugin, channel_key)
  615. || GNUNET_OK != slave_key_store (plugin, slave_key))
  616. return GNUNET_SYSERR;
  617. struct GNUNET_MY_QueryParam params[] = {
  618. GNUNET_MY_query_param_auto_from_type (channel_key),
  619. GNUNET_MY_query_param_auto_from_type (slave_key),
  620. GNUNET_MY_query_param_uint32 (&idid_join),
  621. GNUNET_MY_query_param_uint64 (&announced_at),
  622. GNUNET_MY_query_param_uint64 (&effective_since),
  623. GNUNET_MY_query_param_uint64 (&group_generation),
  624. GNUNET_MY_query_param_end
  625. };
  626. if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params))
  627. {
  628. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  629. "mysql exec_prepared", stmt);
  630. return GNUNET_SYSERR;
  631. }
  632. if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
  633. {
  634. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  635. "mysql_stmt_reset", stmt);
  636. return GNUNET_SYSERR;
  637. }
  638. return GNUNET_OK;
  639. }
  640. /**
  641. * Test if a member was admitted to the channel at the given message ID.
  642. *
  643. * @see GNUNET_PSYCSTORE_membership_test()
  644. *
  645. * @return #GNUNET_YES if the member was admitted, #GNUNET_NO if not,
  646. * #GNUNET_SYSERR if there was en error.
  647. */
  648. static int
  649. membership_test (void *cls,
  650. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  651. const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
  652. uint64_t message_id)
  653. {
  654. struct Plugin *plugin = cls;
  655. struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_membership;
  656. uint32_t did_join = 0;
  657. int ret = GNUNET_SYSERR;
  658. struct GNUNET_MY_QueryParam params_select[] = {
  659. GNUNET_MY_query_param_auto_from_type (channel_key),
  660. GNUNET_MY_query_param_auto_from_type (slave_key),
  661. GNUNET_MY_query_param_uint64 (&message_id),
  662. GNUNET_MY_query_param_end
  663. };
  664. if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select))
  665. {
  666. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  667. "mysql execute prepared", stmt);
  668. return GNUNET_SYSERR;
  669. }
  670. struct GNUNET_MY_ResultSpec results_select[] = {
  671. GNUNET_MY_result_spec_uint32 (&did_join),
  672. GNUNET_MY_result_spec_end
  673. };
  674. switch (GNUNET_MY_extract_result (stmt, results_select))
  675. {
  676. case GNUNET_NO:
  677. ret = GNUNET_NO;
  678. break;
  679. case GNUNET_OK:
  680. ret = GNUNET_YES;
  681. break;
  682. default:
  683. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  684. "mysql extract_result", stmt);
  685. return GNUNET_SYSERR;
  686. }
  687. if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
  688. {
  689. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  690. "mysql_stmt_reset", stmt);
  691. return GNUNET_SYSERR;
  692. }
  693. return ret;
  694. }
  695. /**
  696. * Store a message fragment sent to a channel.
  697. *
  698. * @see GNUNET_PSYCSTORE_fragment_store()
  699. *
  700. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  701. */
  702. static int
  703. fragment_store (void *cls,
  704. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  705. const struct GNUNET_MULTICAST_MessageHeader *msg,
  706. uint32_t psycstore_flags)
  707. {
  708. struct Plugin *plugin = cls;
  709. struct GNUNET_MYSQL_StatementHandle *stmt = plugin->insert_fragment;
  710. GNUNET_assert (TRANSACTION_NONE == plugin->transaction);
  711. uint64_t fragment_id = GNUNET_ntohll (msg->fragment_id);
  712. uint64_t fragment_offset = GNUNET_ntohll (msg->fragment_offset);
  713. uint64_t message_id = GNUNET_ntohll (msg->message_id);
  714. uint64_t group_generation = GNUNET_ntohll (msg->group_generation);
  715. uint64_t hop_counter = ntohl(msg->hop_counter);
  716. uint64_t flags = ntohl(msg->flags);
  717. if (fragment_id > INT64_MAX || fragment_offset > INT64_MAX ||
  718. message_id > INT64_MAX || group_generation > INT64_MAX)
  719. {
  720. LOG(GNUNET_ERROR_TYPE_ERROR,
  721. "Tried to store fragment with a field > INT64_MAX: "
  722. "%lu, %lu, %lu, %lu\n", fragment_id, fragment_offset,
  723. message_id, group_generation);
  724. GNUNET_break (0);
  725. return GNUNET_SYSERR;
  726. }
  727. if (GNUNET_OK != channel_key_store (plugin, channel_key))
  728. return GNUNET_SYSERR;
  729. struct GNUNET_MY_QueryParam params_insert[] = {
  730. GNUNET_MY_query_param_auto_from_type (channel_key),
  731. GNUNET_MY_query_param_uint64 (&hop_counter),
  732. GNUNET_MY_query_param_auto_from_type (&msg->signature),
  733. GNUNET_MY_query_param_auto_from_type (&msg->purpose),
  734. GNUNET_MY_query_param_uint64 (&fragment_id),
  735. GNUNET_MY_query_param_uint64 (&fragment_offset),
  736. GNUNET_MY_query_param_uint64 (&message_id),
  737. GNUNET_MY_query_param_uint64 (&group_generation),
  738. GNUNET_MY_query_param_uint64 (&flags),
  739. GNUNET_MY_query_param_uint32 (&psycstore_flags),
  740. GNUNET_MY_query_param_fixed_size (&msg[1], ntohs (msg->header.size)
  741. - sizeof (*msg)),
  742. GNUNET_MY_query_param_end
  743. };
  744. if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_insert))
  745. {
  746. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  747. "mysql execute prepared", stmt);
  748. return GNUNET_SYSERR;
  749. }
  750. if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
  751. {
  752. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  753. "mysql_stmt_reset", stmt);
  754. return GNUNET_SYSERR;
  755. }
  756. return GNUNET_OK;
  757. }
  758. /**
  759. * Set additional flags for a given message.
  760. *
  761. * They are OR'd with any existing flags set.
  762. *
  763. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  764. */
  765. static int
  766. message_add_flags (void *cls,
  767. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  768. uint64_t message_id,
  769. uint32_t psycstore_flags)
  770. {
  771. struct Plugin *plugin = cls;
  772. struct GNUNET_MYSQL_StatementHandle *stmt = plugin->update_message_flags;
  773. int sql_ret;
  774. int ret = GNUNET_SYSERR;
  775. struct GNUNET_MY_QueryParam params_update[] = {
  776. GNUNET_MY_query_param_uint32 (&psycstore_flags),
  777. GNUNET_MY_query_param_auto_from_type (channel_key),
  778. GNUNET_MY_query_param_uint64 (&message_id),
  779. GNUNET_MY_query_param_end
  780. };
  781. sql_ret = GNUNET_MY_exec_prepared (plugin->mc, stmt, params_update);
  782. switch (sql_ret)
  783. {
  784. case GNUNET_OK:
  785. ret = GNUNET_OK;
  786. break;
  787. default:
  788. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  789. "mysql execute prepared", stmt);
  790. }
  791. if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
  792. {
  793. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  794. "mysql_stmt_reset", stmt);
  795. return GNUNET_SYSERR;
  796. }
  797. return ret;
  798. }
  799. static int
  800. fragment_row (struct GNUNET_MYSQL_StatementHandle *stmt,
  801. GNUNET_PSYCSTORE_FragmentCallback cb,
  802. void *cb_cls,
  803. uint64_t *returned_fragments)
  804. {
  805. uint32_t hop_counter;
  806. void *signature = NULL;
  807. void *purpose = NULL;
  808. size_t signature_size;
  809. size_t purpose_size;
  810. uint64_t fragment_id;
  811. uint64_t fragment_offset;
  812. uint64_t message_id;
  813. uint64_t group_generation;
  814. uint64_t flags;
  815. void *buf;
  816. size_t buf_size;
  817. int ret = GNUNET_SYSERR;
  818. int sql_ret;
  819. struct GNUNET_MULTICAST_MessageHeader *mp;
  820. uint64_t msg_flags;
  821. struct GNUNET_MY_ResultSpec results[] = {
  822. GNUNET_MY_result_spec_uint32 (&hop_counter),
  823. GNUNET_MY_result_spec_variable_size (&signature, &signature_size),
  824. GNUNET_MY_result_spec_variable_size (&purpose, &purpose_size),
  825. GNUNET_MY_result_spec_uint64 (&fragment_id),
  826. GNUNET_MY_result_spec_uint64 (&fragment_offset),
  827. GNUNET_MY_result_spec_uint64 (&message_id),
  828. GNUNET_MY_result_spec_uint64 (&group_generation),
  829. GNUNET_MY_result_spec_uint64 (&msg_flags),
  830. GNUNET_MY_result_spec_uint64 (&flags),
  831. GNUNET_MY_result_spec_variable_size (&buf,
  832. &buf_size),
  833. GNUNET_MY_result_spec_end
  834. };
  835. do
  836. {
  837. sql_ret = GNUNET_MY_extract_result (stmt, results);
  838. switch (sql_ret)
  839. {
  840. case GNUNET_NO:
  841. if (ret != GNUNET_YES)
  842. ret = GNUNET_NO;
  843. break;
  844. case GNUNET_YES:
  845. mp = GNUNET_malloc (sizeof (*mp) + buf_size);
  846. mp->header.size = htons (sizeof (*mp) + buf_size);
  847. mp->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE);
  848. mp->hop_counter = htonl (hop_counter);
  849. GNUNET_memcpy (&mp->signature,
  850. signature,
  851. signature_size);
  852. GNUNET_memcpy (&mp->purpose,
  853. purpose,
  854. purpose_size);
  855. mp->fragment_id = GNUNET_htonll (fragment_id);
  856. mp->fragment_offset = GNUNET_htonll (fragment_offset);
  857. mp->message_id = GNUNET_htonll (message_id);
  858. mp->group_generation = GNUNET_htonll (group_generation);
  859. mp->flags = htonl(msg_flags);
  860. GNUNET_memcpy (&mp[1],
  861. buf,
  862. buf_size);
  863. ret = cb (cb_cls, mp, (enum GNUNET_PSYCSTORE_MessageFlags) flags);
  864. if (NULL != returned_fragments)
  865. (*returned_fragments)++;
  866. GNUNET_MY_cleanup_result (results);
  867. break;
  868. default:
  869. LOG_MYSQL (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  870. "mysql extract_result", stmt);
  871. }
  872. }
  873. while (GNUNET_YES == sql_ret);
  874. // for debugging
  875. if (GNUNET_NO == ret)
  876. GNUNET_log (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
  877. "Empty result set\n");
  878. return ret;
  879. }
  880. static int
  881. fragment_select (struct Plugin *plugin,
  882. struct GNUNET_MYSQL_StatementHandle *stmt,
  883. struct GNUNET_MY_QueryParam *params,
  884. uint64_t *returned_fragments,
  885. GNUNET_PSYCSTORE_FragmentCallback cb,
  886. void *cb_cls)
  887. {
  888. int ret = GNUNET_SYSERR;
  889. int sql_ret;
  890. sql_ret = GNUNET_MY_exec_prepared (plugin->mc, stmt, params);
  891. switch (sql_ret)
  892. {
  893. case GNUNET_NO:
  894. if (ret != GNUNET_YES)
  895. ret = GNUNET_NO;
  896. break;
  897. case GNUNET_YES:
  898. ret = fragment_row (stmt, cb, cb_cls, returned_fragments);
  899. break;
  900. default:
  901. LOG_MYSQL (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  902. "mysql exec_prepared", stmt);
  903. }
  904. return ret;
  905. }
  906. /**
  907. * Retrieve a message fragment range by fragment ID.
  908. *
  909. * @see GNUNET_PSYCSTORE_fragment_get()
  910. *
  911. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  912. */
  913. static int
  914. fragment_get (void *cls,
  915. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  916. uint64_t first_fragment_id,
  917. uint64_t last_fragment_id,
  918. uint64_t *returned_fragments,
  919. GNUNET_PSYCSTORE_FragmentCallback cb,
  920. void *cb_cls)
  921. {
  922. struct Plugin *plugin = cls;
  923. struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_fragments;
  924. int ret = GNUNET_SYSERR;
  925. struct GNUNET_MY_QueryParam params_select[] = {
  926. GNUNET_MY_query_param_auto_from_type (channel_key),
  927. GNUNET_MY_query_param_uint64 (&first_fragment_id),
  928. GNUNET_MY_query_param_uint64 (&last_fragment_id),
  929. GNUNET_MY_query_param_end
  930. };
  931. *returned_fragments = 0;
  932. ret = fragment_select (plugin, stmt, params_select, returned_fragments, cb, cb_cls);
  933. if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
  934. {
  935. LOG_MYSQL (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  936. "mysql_stmt_reset", stmt);
  937. return GNUNET_SYSERR;
  938. }
  939. return ret;
  940. }
  941. /**
  942. * Retrieve a message fragment range by fragment ID.
  943. *
  944. * @see GNUNET_PSYCSTORE_fragment_get_latest()
  945. *
  946. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  947. */
  948. static int
  949. fragment_get_latest (void *cls,
  950. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  951. uint64_t fragment_limit,
  952. uint64_t *returned_fragments,
  953. GNUNET_PSYCSTORE_FragmentCallback cb,
  954. void *cb_cls)
  955. {
  956. struct Plugin *plugin = cls;
  957. struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_latest_fragments;
  958. int ret = GNUNET_SYSERR;
  959. *returned_fragments = 0;
  960. struct GNUNET_MY_QueryParam params_select[] = {
  961. GNUNET_MY_query_param_auto_from_type (channel_key),
  962. GNUNET_MY_query_param_uint64 (&fragment_limit),
  963. GNUNET_MY_query_param_end
  964. };
  965. ret = fragment_select (plugin, stmt, params_select, returned_fragments, cb, cb_cls);
  966. if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
  967. {
  968. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  969. "mysql_stmt_reset", stmt);
  970. return GNUNET_SYSERR;
  971. }
  972. return ret;
  973. }
  974. /**
  975. * Retrieve all fragments of a message ID range.
  976. *
  977. * @see GNUNET_PSYCSTORE_message_get()
  978. *
  979. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  980. */
  981. static int
  982. message_get (void *cls,
  983. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  984. uint64_t first_message_id,
  985. uint64_t last_message_id,
  986. uint64_t fragment_limit,
  987. uint64_t *returned_fragments,
  988. GNUNET_PSYCSTORE_FragmentCallback cb,
  989. void *cb_cls)
  990. {
  991. struct Plugin *plugin = cls;
  992. struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_messages;
  993. int ret;
  994. if (0 == fragment_limit)
  995. fragment_limit = UINT64_MAX;
  996. struct GNUNET_MY_QueryParam params_select[] = {
  997. GNUNET_MY_query_param_auto_from_type (channel_key),
  998. GNUNET_MY_query_param_uint64 (&first_message_id),
  999. GNUNET_MY_query_param_uint64 (&last_message_id),
  1000. GNUNET_MY_query_param_uint64 (&fragment_limit),
  1001. GNUNET_MY_query_param_end
  1002. };
  1003. *returned_fragments = 0;
  1004. ret = fragment_select (plugin, stmt, params_select, returned_fragments, cb, cb_cls);
  1005. if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
  1006. {
  1007. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1008. "mysql_stmt_reset", stmt);
  1009. return GNUNET_SYSERR;
  1010. }
  1011. return ret;
  1012. }
  1013. /**
  1014. * Retrieve all fragments of the latest messages.
  1015. *
  1016. * @see GNUNET_PSYCSTORE_message_get_latest()
  1017. *
  1018. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  1019. */
  1020. static int
  1021. message_get_latest (void *cls,
  1022. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  1023. uint64_t message_limit,
  1024. uint64_t *returned_fragments,
  1025. GNUNET_PSYCSTORE_FragmentCallback cb,
  1026. void *cb_cls)
  1027. {
  1028. struct Plugin *plugin = cls;
  1029. struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_latest_messages;
  1030. int ret = GNUNET_SYSERR;
  1031. *returned_fragments = 0;
  1032. struct GNUNET_MY_QueryParam params_select[] = {
  1033. GNUNET_MY_query_param_auto_from_type (channel_key),
  1034. GNUNET_MY_query_param_auto_from_type (channel_key),
  1035. GNUNET_MY_query_param_uint64 (&message_limit),
  1036. GNUNET_MY_query_param_end
  1037. };
  1038. ret = fragment_select (plugin, stmt, params_select, returned_fragments, cb, cb_cls);
  1039. if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
  1040. {
  1041. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1042. "mysql_stmt_reset", stmt);
  1043. return GNUNET_SYSERR;
  1044. }
  1045. return ret;
  1046. }
  1047. /**
  1048. * Retrieve a fragment of message specified by its message ID and fragment
  1049. * offset.
  1050. *
  1051. * @see GNUNET_PSYCSTORE_message_get_fragment()
  1052. *
  1053. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  1054. */
  1055. static int
  1056. message_get_fragment (void *cls,
  1057. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  1058. uint64_t message_id,
  1059. uint64_t fragment_offset,
  1060. GNUNET_PSYCSTORE_FragmentCallback cb,
  1061. void *cb_cls)
  1062. {
  1063. struct Plugin *plugin = cls;
  1064. struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_message_fragment;
  1065. int sql_ret;
  1066. int ret = GNUNET_SYSERR;
  1067. struct GNUNET_MY_QueryParam params_select[] = {
  1068. GNUNET_MY_query_param_auto_from_type (channel_key),
  1069. GNUNET_MY_query_param_uint64 (&message_id),
  1070. GNUNET_MY_query_param_uint64 (&fragment_offset),
  1071. GNUNET_MY_query_param_end
  1072. };
  1073. sql_ret = GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select);
  1074. switch (sql_ret)
  1075. {
  1076. case GNUNET_NO:
  1077. ret = GNUNET_NO;
  1078. break;
  1079. case GNUNET_OK:
  1080. ret = fragment_row (stmt, cb, cb_cls, NULL);
  1081. break;
  1082. default:
  1083. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1084. "mysql execute prepared", stmt);
  1085. }
  1086. if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
  1087. {
  1088. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1089. "mysql_stmt_reset", stmt);
  1090. return GNUNET_SYSERR;
  1091. }
  1092. return ret;
  1093. }
  1094. /**
  1095. * Retrieve the max. values of message counters for a channel.
  1096. *
  1097. * @see GNUNET_PSYCSTORE_counters_get()
  1098. *
  1099. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  1100. */
  1101. static int
  1102. counters_message_get (void *cls,
  1103. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  1104. uint64_t *max_fragment_id,
  1105. uint64_t *max_message_id,
  1106. uint64_t *max_group_generation)
  1107. {
  1108. struct Plugin *plugin = cls;
  1109. struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_counters_message;
  1110. int ret = GNUNET_SYSERR;
  1111. struct GNUNET_MY_QueryParam params_select[] = {
  1112. GNUNET_MY_query_param_auto_from_type (channel_key),
  1113. GNUNET_MY_query_param_end
  1114. };
  1115. if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select))
  1116. {
  1117. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1118. "mysql execute prepared", stmt);
  1119. return GNUNET_SYSERR;
  1120. }
  1121. struct GNUNET_MY_ResultSpec results_select[] = {
  1122. GNUNET_MY_result_spec_uint64 (max_fragment_id),
  1123. GNUNET_MY_result_spec_uint64 (max_message_id),
  1124. GNUNET_MY_result_spec_uint64 (max_group_generation),
  1125. GNUNET_MY_result_spec_end
  1126. };
  1127. ret = GNUNET_MY_extract_result (stmt, results_select);
  1128. if (GNUNET_OK != ret)
  1129. {
  1130. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1131. "mysql extract_result", stmt);
  1132. return GNUNET_SYSERR;
  1133. }
  1134. if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
  1135. {
  1136. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1137. "mysql_stmt_reset", stmt);
  1138. return GNUNET_SYSERR;
  1139. }
  1140. return ret;
  1141. }
  1142. /**
  1143. * Retrieve the max. values of state counters for a channel.
  1144. *
  1145. * @see GNUNET_PSYCSTORE_counters_get()
  1146. *
  1147. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  1148. */
  1149. static int
  1150. counters_state_get (void *cls,
  1151. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  1152. uint64_t *max_state_message_id)
  1153. {
  1154. struct Plugin *plugin = cls;
  1155. struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_counters_state;
  1156. int ret = GNUNET_SYSERR;
  1157. struct GNUNET_MY_QueryParam params_select[] = {
  1158. GNUNET_MY_query_param_auto_from_type (channel_key),
  1159. GNUNET_MY_query_param_end
  1160. };
  1161. if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select))
  1162. {
  1163. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1164. "mysql execute prepared", stmt);
  1165. return GNUNET_SYSERR;
  1166. }
  1167. struct GNUNET_MY_ResultSpec results_select[] = {
  1168. GNUNET_MY_result_spec_uint64 (max_state_message_id),
  1169. GNUNET_MY_result_spec_end
  1170. };
  1171. ret = GNUNET_MY_extract_result (stmt, results_select);
  1172. if (GNUNET_OK != ret)
  1173. {
  1174. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1175. "mysql extract_result", stmt);
  1176. return GNUNET_SYSERR;
  1177. }
  1178. if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
  1179. {
  1180. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1181. "mysql_stmt_reset", stmt);
  1182. return GNUNET_SYSERR;
  1183. }
  1184. return ret;
  1185. }
  1186. /**
  1187. * Assign a value to a state variable.
  1188. *
  1189. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  1190. */
  1191. static int
  1192. state_assign (struct Plugin *plugin, struct GNUNET_MYSQL_StatementHandle *stmt,
  1193. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  1194. const char *name, const void *value, size_t value_size)
  1195. {
  1196. int ret = GNUNET_SYSERR;
  1197. struct GNUNET_MY_QueryParam params[] = {
  1198. GNUNET_MY_query_param_auto_from_type (channel_key),
  1199. GNUNET_MY_query_param_string (name),
  1200. GNUNET_MY_query_param_fixed_size(value, value_size),
  1201. GNUNET_MY_query_param_end
  1202. };
  1203. ret = GNUNET_MY_exec_prepared (plugin->mc, stmt, params);
  1204. if (GNUNET_OK != ret)
  1205. {
  1206. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1207. "mysql exec_prepared", stmt);
  1208. return GNUNET_SYSERR;
  1209. }
  1210. if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
  1211. {
  1212. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1213. "mysql_stmt_reset", stmt);
  1214. return GNUNET_SYSERR;
  1215. }
  1216. return ret;
  1217. }
  1218. static int
  1219. update_message_id (struct Plugin *plugin, struct GNUNET_MYSQL_StatementHandle *stmt,
  1220. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  1221. uint64_t message_id)
  1222. {
  1223. struct GNUNET_MY_QueryParam params[] = {
  1224. GNUNET_MY_query_param_uint64 (&message_id),
  1225. GNUNET_MY_query_param_auto_from_type (channel_key),
  1226. GNUNET_MY_query_param_end
  1227. };
  1228. if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc,
  1229. stmt,
  1230. params))
  1231. {
  1232. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1233. "mysql execute prepared", stmt);
  1234. return GNUNET_SYSERR;
  1235. }
  1236. if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
  1237. {
  1238. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1239. "mysql_stmt_reset", stmt);
  1240. return GNUNET_SYSERR;
  1241. }
  1242. return GNUNET_OK;
  1243. }
  1244. /**
  1245. * Begin modifying current state.
  1246. */
  1247. static int
  1248. state_modify_begin (void *cls,
  1249. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  1250. uint64_t message_id, uint64_t state_delta)
  1251. {
  1252. struct Plugin *plugin = cls;
  1253. if (state_delta > 0)
  1254. {
  1255. /**
  1256. * We can only apply state modifiers in the current message if modifiers in
  1257. * the previous stateful message (message_id - state_delta) were already
  1258. * applied.
  1259. */
  1260. uint64_t max_state_message_id = 0;
  1261. int ret = counters_state_get (plugin, channel_key, &max_state_message_id);
  1262. switch (ret)
  1263. {
  1264. case GNUNET_OK:
  1265. case GNUNET_NO: // no state yet
  1266. ret = GNUNET_OK;
  1267. break;
  1268. default:
  1269. return ret;
  1270. }
  1271. if (max_state_message_id < message_id - state_delta)
  1272. return GNUNET_NO; /* some stateful messages not yet applied */
  1273. else if (message_id - state_delta < max_state_message_id)
  1274. return GNUNET_NO; /* changes already applied */
  1275. }
  1276. if (TRANSACTION_NONE != plugin->transaction)
  1277. {
  1278. /** @todo FIXME: wait for other transaction to finish */
  1279. return GNUNET_SYSERR;
  1280. }
  1281. return transaction_begin (plugin, TRANSACTION_STATE_MODIFY);
  1282. }
  1283. /**
  1284. * Set the current value of state variable.
  1285. *
  1286. * @see GNUNET_PSYCSTORE_state_modify()
  1287. *
  1288. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  1289. */
  1290. static int
  1291. state_modify_op (void *cls,
  1292. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  1293. enum GNUNET_PSYC_Operator op,
  1294. const char *name, const void *value, size_t value_size)
  1295. {
  1296. struct Plugin *plugin = cls;
  1297. GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction);
  1298. switch (op)
  1299. {
  1300. case GNUNET_PSYC_OP_ASSIGN:
  1301. return state_assign (plugin, plugin->insert_state_current,
  1302. channel_key, name, value, value_size);
  1303. default: /** @todo implement more state operations */
  1304. GNUNET_break (0);
  1305. return GNUNET_SYSERR;
  1306. }
  1307. }
  1308. /**
  1309. * End modifying current state.
  1310. */
  1311. static int
  1312. state_modify_end (void *cls,
  1313. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  1314. uint64_t message_id)
  1315. {
  1316. struct Plugin *plugin = cls;
  1317. GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction);
  1318. return
  1319. GNUNET_OK == exec_channel (plugin, plugin->delete_state_empty, channel_key)
  1320. && GNUNET_OK == update_message_id (plugin,
  1321. plugin->update_max_state_message_id,
  1322. channel_key, message_id)
  1323. && GNUNET_OK == transaction_commit (plugin)
  1324. ? GNUNET_OK : GNUNET_SYSERR;
  1325. }
  1326. /**
  1327. * Begin state synchronization.
  1328. */
  1329. static int
  1330. state_sync_begin (void *cls,
  1331. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
  1332. {
  1333. struct Plugin *plugin = cls;
  1334. return exec_channel (plugin, plugin->delete_state_sync, channel_key);
  1335. }
  1336. /**
  1337. * Assign current value of a state variable.
  1338. *
  1339. * @see GNUNET_PSYCSTORE_state_modify()
  1340. *
  1341. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  1342. */
  1343. static int
  1344. state_sync_assign (void *cls,
  1345. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  1346. const char *name, const void *value, size_t value_size)
  1347. {
  1348. struct Plugin *plugin = cls;
  1349. return state_assign (cls, plugin->insert_state_sync,
  1350. channel_key, name, value, value_size);
  1351. }
  1352. /**
  1353. * End modifying current state.
  1354. */
  1355. static int
  1356. state_sync_end (void *cls,
  1357. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  1358. uint64_t max_state_message_id,
  1359. uint64_t state_hash_message_id)
  1360. {
  1361. struct Plugin *plugin = cls;
  1362. int ret = GNUNET_SYSERR;
  1363. if (TRANSACTION_NONE != plugin->transaction)
  1364. {
  1365. /** @todo FIXME: wait for other transaction to finish */
  1366. return GNUNET_SYSERR;
  1367. }
  1368. GNUNET_OK == transaction_begin (plugin, TRANSACTION_STATE_SYNC)
  1369. && GNUNET_OK == exec_channel (plugin, plugin->delete_state, channel_key)
  1370. && GNUNET_OK == exec_channel (plugin, plugin->insert_state_from_sync,
  1371. channel_key)
  1372. && GNUNET_OK == exec_channel (plugin, plugin->delete_state_sync,
  1373. channel_key)
  1374. && GNUNET_OK == update_message_id (plugin,
  1375. plugin->update_state_hash_message_id,
  1376. channel_key, state_hash_message_id)
  1377. && GNUNET_OK == update_message_id (plugin,
  1378. plugin->update_max_state_message_id,
  1379. channel_key, max_state_message_id)
  1380. && GNUNET_OK == transaction_commit (plugin)
  1381. ? ret = GNUNET_OK
  1382. : transaction_rollback (plugin);
  1383. return ret;
  1384. }
  1385. /**
  1386. * Delete the whole state.
  1387. *
  1388. * @see GNUNET_PSYCSTORE_state_reset()
  1389. *
  1390. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  1391. */
  1392. static int
  1393. state_reset (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
  1394. {
  1395. struct Plugin *plugin = cls;
  1396. return exec_channel (plugin, plugin->delete_state, channel_key);
  1397. }
  1398. /**
  1399. * Update signed values of state variables in the state store.
  1400. *
  1401. * @see GNUNET_PSYCSTORE_state_hash_update()
  1402. *
  1403. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  1404. */
  1405. static int
  1406. state_update_signed (void *cls,
  1407. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
  1408. {
  1409. struct Plugin *plugin = cls;
  1410. return exec_channel (plugin, plugin->update_state_signed, channel_key);
  1411. }
  1412. /**
  1413. * Retrieve a state variable by name.
  1414. *
  1415. * @see GNUNET_PSYCSTORE_state_get()
  1416. *
  1417. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  1418. */
  1419. static int
  1420. state_get (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  1421. const char *name, GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls)
  1422. {
  1423. struct Plugin *plugin = cls;
  1424. int ret = GNUNET_SYSERR;
  1425. int sql_ret ;
  1426. struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_state_one;
  1427. struct GNUNET_MY_QueryParam params_select[] = {
  1428. GNUNET_MY_query_param_auto_from_type (channel_key),
  1429. GNUNET_MY_query_param_string (name),
  1430. GNUNET_MY_query_param_end
  1431. };
  1432. void *value_current = NULL;
  1433. size_t value_size = 0;
  1434. struct GNUNET_MY_ResultSpec results[] = {
  1435. GNUNET_MY_result_spec_variable_size (&value_current, &value_size),
  1436. GNUNET_MY_result_spec_end
  1437. };
  1438. if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select))
  1439. {
  1440. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1441. "mysql exec_prepared", stmt);
  1442. }
  1443. else
  1444. {
  1445. sql_ret = GNUNET_MY_extract_result (stmt, results);
  1446. switch (sql_ret)
  1447. {
  1448. case GNUNET_NO:
  1449. ret = GNUNET_NO;
  1450. break;
  1451. case GNUNET_YES:
  1452. ret = cb (cb_cls, name, value_current, value_size);
  1453. break;
  1454. default:
  1455. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1456. "mysql extract_result", stmt);
  1457. }
  1458. }
  1459. if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
  1460. {
  1461. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1462. "mysql_stmt_reset", stmt);
  1463. return GNUNET_SYSERR;
  1464. }
  1465. return ret;
  1466. }
  1467. /**
  1468. * Retrieve all state variables for a channel with the given prefix.
  1469. *
  1470. * @see GNUNET_PSYCSTORE_state_get_prefix()
  1471. *
  1472. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  1473. */
  1474. static int
  1475. state_get_prefix (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  1476. const char *name, GNUNET_PSYCSTORE_StateCallback cb,
  1477. void *cb_cls)
  1478. {
  1479. struct Plugin *plugin = cls;
  1480. int ret = GNUNET_SYSERR;
  1481. struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_state_prefix;
  1482. uint32_t name_len = (uint32_t) strlen (name);
  1483. struct GNUNET_MY_QueryParam params_select[] = {
  1484. GNUNET_MY_query_param_auto_from_type (channel_key),
  1485. GNUNET_MY_query_param_string (name),
  1486. GNUNET_MY_query_param_uint32 (&name_len),
  1487. GNUNET_MY_query_param_string (name),
  1488. GNUNET_MY_query_param_end
  1489. };
  1490. char *name2 = "";
  1491. void *value_current = NULL;
  1492. size_t value_size = 0;
  1493. struct GNUNET_MY_ResultSpec results[] = {
  1494. GNUNET_MY_result_spec_string (&name2),
  1495. GNUNET_MY_result_spec_variable_size (&value_current, &value_size),
  1496. GNUNET_MY_result_spec_end
  1497. };;
  1498. int sql_ret;
  1499. if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select))
  1500. {
  1501. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1502. "mysql exec_prepared", stmt);
  1503. return GNUNET_SYSERR;
  1504. }
  1505. do
  1506. {
  1507. sql_ret = GNUNET_MY_extract_result (stmt, results);
  1508. switch (sql_ret)
  1509. {
  1510. case GNUNET_NO:
  1511. if (ret != GNUNET_YES)
  1512. ret = GNUNET_NO;
  1513. break;
  1514. case GNUNET_YES:
  1515. ret = cb (cb_cls, (const char *) name2, value_current, value_size);
  1516. if (ret != GNUNET_YES)
  1517. sql_ret = GNUNET_NO;
  1518. break;
  1519. default:
  1520. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1521. "mysql extract_result", stmt);
  1522. }
  1523. }
  1524. while (sql_ret == GNUNET_YES);
  1525. if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
  1526. {
  1527. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1528. "mysql_stmt_reset", stmt);
  1529. return GNUNET_SYSERR;
  1530. }
  1531. return ret;
  1532. }
  1533. /**
  1534. * Retrieve all signed state variables for a channel.
  1535. *
  1536. * @see GNUNET_PSYCSTORE_state_get_signed()
  1537. *
  1538. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  1539. */
  1540. static int
  1541. state_get_signed (void *cls,
  1542. const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
  1543. GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls)
  1544. {
  1545. struct Plugin *plugin = cls;
  1546. int ret = GNUNET_SYSERR;
  1547. struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_state_signed;
  1548. struct GNUNET_MY_QueryParam params_select[] = {
  1549. GNUNET_MY_query_param_auto_from_type (channel_key),
  1550. GNUNET_MY_query_param_end
  1551. };
  1552. int sql_ret;
  1553. char *name = "";
  1554. void *value_signed = NULL;
  1555. size_t value_size = 0;
  1556. struct GNUNET_MY_ResultSpec results[] = {
  1557. GNUNET_MY_result_spec_string (&name),
  1558. GNUNET_MY_result_spec_variable_size (&value_signed, &value_size),
  1559. GNUNET_MY_result_spec_end
  1560. };
  1561. if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select))
  1562. {
  1563. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1564. "mysql exec_prepared", stmt);
  1565. return GNUNET_SYSERR;
  1566. }
  1567. do
  1568. {
  1569. sql_ret = GNUNET_MY_extract_result (stmt, results);
  1570. switch (sql_ret)
  1571. {
  1572. case GNUNET_NO:
  1573. if (ret != GNUNET_YES)
  1574. ret = GNUNET_NO;
  1575. break;
  1576. case GNUNET_YES:
  1577. ret = cb (cb_cls, (const char *) name, value_signed, value_size);
  1578. if (ret != GNUNET_YES)
  1579. sql_ret = GNUNET_NO;
  1580. break;
  1581. default:
  1582. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1583. "mysql extract_result", stmt);
  1584. }
  1585. }
  1586. while (sql_ret == GNUNET_YES);
  1587. if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt)))
  1588. {
  1589. LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  1590. "mysql_stmt_reset", stmt);
  1591. return GNUNET_SYSERR;
  1592. }
  1593. return ret;
  1594. }
  1595. /**
  1596. * Entry point for the plugin.
  1597. *
  1598. * @param cls The struct GNUNET_CONFIGURATION_Handle.
  1599. * @return NULL on error, otherwise the plugin context
  1600. */
  1601. void *
  1602. libgnunet_plugin_psycstore_mysql_init (void *cls)
  1603. {
  1604. static struct Plugin plugin;
  1605. const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
  1606. struct GNUNET_PSYCSTORE_PluginFunctions *api;
  1607. if (NULL != plugin.cfg)
  1608. return NULL; /* can only initialize once! */
  1609. memset (&plugin, 0, sizeof (struct Plugin));
  1610. plugin.cfg = cfg;
  1611. if (GNUNET_OK != database_setup (&plugin))
  1612. {
  1613. database_shutdown (&plugin);
  1614. return NULL;
  1615. }
  1616. api = GNUNET_new (struct GNUNET_PSYCSTORE_PluginFunctions);
  1617. api->cls = &plugin;
  1618. api->membership_store = &mysql_membership_store;
  1619. api->membership_test = &membership_test;
  1620. api->fragment_store = &fragment_store;
  1621. api->message_add_flags = &message_add_flags;
  1622. api->fragment_get = &fragment_get;
  1623. api->fragment_get_latest = &fragment_get_latest;
  1624. api->message_get = &message_get;
  1625. api->message_get_latest = &message_get_latest;
  1626. api->message_get_fragment = &message_get_fragment;
  1627. api->counters_message_get = &counters_message_get;
  1628. api->counters_state_get = &counters_state_get;
  1629. api->state_modify_begin = &state_modify_begin;
  1630. api->state_modify_op = &state_modify_op;
  1631. api->state_modify_end = &state_modify_end;
  1632. api->state_sync_begin = &state_sync_begin;
  1633. api->state_sync_assign = &state_sync_assign;
  1634. api->state_sync_end = &state_sync_end;
  1635. api->state_reset = &state_reset;
  1636. api->state_update_signed = &state_update_signed;
  1637. api->state_get = &state_get;
  1638. api->state_get_prefix = &state_get_prefix;
  1639. api->state_get_signed = &state_get_signed;
  1640. LOG (GNUNET_ERROR_TYPE_INFO, _("Mysql database running\n"));
  1641. return api;
  1642. }
  1643. /**
  1644. * Exit point from the plugin.
  1645. *
  1646. * @param cls The plugin context (as returned by "init")
  1647. * @return Always NULL
  1648. */
  1649. void *
  1650. libgnunet_plugin_psycstore_mysql_done (void *cls)
  1651. {
  1652. struct GNUNET_PSYCSTORE_PluginFunctions *api = cls;
  1653. struct Plugin *plugin = api->cls;
  1654. database_shutdown (plugin);
  1655. plugin->cfg = NULL;
  1656. GNUNET_free (api);
  1657. LOG (GNUNET_ERROR_TYPE_DEBUG, "Mysql plugin is finished\n");
  1658. return NULL;
  1659. }
  1660. /* end of plugin_psycstore_mysql.c */