plugin_namestore_sqlite.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  1. /*
  2. * This file is part of GNUnet
  3. * Copyright (C) 2009-2017 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 namestore/plugin_namestore_sqlite.c
  21. * @brief sqlite-based namestore backend
  22. * @author Christian Grothoff
  23. */
  24. #include "platform.h"
  25. #include "gnunet_namestore_plugin.h"
  26. #include "gnunet_namestore_service.h"
  27. #include "gnunet_gnsrecord_lib.h"
  28. #include "gnunet_sq_lib.h"
  29. #include "namestore.h"
  30. #include <sqlite3.h>
  31. /**
  32. * After how many ms "busy" should a DB operation fail for good? A
  33. * low value makes sure that we are more responsive to requests
  34. * (especially PUTs). A high value guarantees a higher success rate
  35. * (SELECTs in iterate can take several seconds despite LIMIT=1).
  36. *
  37. * The default value of 1s should ensure that users do not experience
  38. * huge latencies while at the same time allowing operations to
  39. * succeed with reasonable probability.
  40. */
  41. #define BUSY_TIMEOUT_MS 1000
  42. /**
  43. * Log an error message at log-level 'level' that indicates
  44. * a failure of the command 'cmd' on file 'filename'
  45. * with the message given by strerror(errno).
  46. */
  47. #define LOG_SQLITE(db, level, cmd) do { GNUNET_log_from (level, \
  48. "namestore-sqlite", _ ( \
  49. "`%s' failed at %s:%d with error: %s\n"), \
  50. cmd, \
  51. __FILE__, __LINE__, \
  52. sqlite3_errmsg ( \
  53. db->dbh)); \
  54. } while (0)
  55. #define LOG(kind, ...) GNUNET_log_from (kind, "namestore-sqlite", __VA_ARGS__)
  56. /**
  57. * Context for all functions in this plugin.
  58. */
  59. struct Plugin
  60. {
  61. const struct GNUNET_CONFIGURATION_Handle *cfg;
  62. /**
  63. * Database filename.
  64. */
  65. char *fn;
  66. /**
  67. * Native SQLite database handle.
  68. */
  69. sqlite3 *dbh;
  70. /**
  71. * Precompiled SQL to store records.
  72. */
  73. sqlite3_stmt *store_records;
  74. /**
  75. * Precompiled SQL to deltete existing records.
  76. */
  77. sqlite3_stmt *delete_records;
  78. /**
  79. * Precompiled SQL for iterate records within a zone.
  80. */
  81. sqlite3_stmt *iterate_zone;
  82. /**
  83. * Precompiled SQL for iterate all records within all zones.
  84. */
  85. sqlite3_stmt *iterate_all_zones;
  86. /**
  87. * Precompiled SQL to for reverse lookup based on PKEY.
  88. */
  89. sqlite3_stmt *zone_to_name;
  90. /**
  91. * Precompiled SQL to lookup records based on label.
  92. */
  93. sqlite3_stmt *lookup_label;
  94. };
  95. /**
  96. * Initialize the database connections and associated
  97. * data structures (create tables and indices
  98. * as needed as well).
  99. *
  100. * @param plugin the plugin context (state for this module)
  101. * @return #GNUNET_OK on success
  102. */
  103. static int
  104. database_setup (struct Plugin *plugin)
  105. {
  106. char *sqlite_filename;
  107. struct GNUNET_SQ_ExecuteStatement es[] = {
  108. GNUNET_SQ_make_try_execute ("PRAGMA temp_store=MEMORY"),
  109. GNUNET_SQ_make_try_execute ("PRAGMA synchronous=NORMAL"),
  110. GNUNET_SQ_make_try_execute ("PRAGMA legacy_file_format=OFF"),
  111. GNUNET_SQ_make_try_execute ("PRAGMA auto_vacuum=INCREMENTAL"),
  112. GNUNET_SQ_make_try_execute ("PRAGMA encoding=\"UTF-8\""),
  113. GNUNET_SQ_make_try_execute ("PRAGMA locking_mode=EXCLUSIVE"),
  114. GNUNET_SQ_make_try_execute ("PRAGMA journal_mode=WAL"),
  115. GNUNET_SQ_make_try_execute ("PRAGMA page_size=4092"),
  116. GNUNET_SQ_make_execute ("CREATE TABLE IF NOT EXISTS ns098records ("
  117. " uid INTEGER PRIMARY KEY,"
  118. " zone_private_key BLOB NOT NULL,"
  119. " pkey BLOB,"
  120. " rvalue INT8 NOT NULL,"
  121. " record_count INT NOT NULL,"
  122. " record_data BLOB NOT NULL,"
  123. " label TEXT NOT NULL"
  124. ")"),
  125. GNUNET_SQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_reverse "
  126. "ON ns098records (zone_private_key,pkey)"),
  127. GNUNET_SQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_iter "
  128. "ON ns098records (zone_private_key,uid)"),
  129. GNUNET_SQ_EXECUTE_STATEMENT_END
  130. };
  131. struct GNUNET_SQ_PrepareStatement ps[] = {
  132. GNUNET_SQ_make_prepare ("INSERT INTO ns098records "
  133. "(zone_private_key,pkey,rvalue,record_count,record_data,label)"
  134. " VALUES (?, ?, ?, ?, ?, ?)",
  135. &plugin->store_records),
  136. GNUNET_SQ_make_prepare ("DELETE FROM ns098records "
  137. "WHERE zone_private_key=? AND label=?",
  138. &plugin->delete_records),
  139. GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label"
  140. " FROM ns098records"
  141. " WHERE zone_private_key=? AND pkey=?",
  142. &plugin->zone_to_name),
  143. GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label"
  144. " FROM ns098records"
  145. " WHERE zone_private_key=? AND uid > ?"
  146. " ORDER BY uid ASC"
  147. " LIMIT ?",
  148. &plugin->iterate_zone),
  149. GNUNET_SQ_make_prepare (
  150. "SELECT uid,record_count,record_data,label,zone_private_key"
  151. " FROM ns098records"
  152. " WHERE uid > ?"
  153. " ORDER BY uid ASC"
  154. " LIMIT ?",
  155. &plugin->iterate_all_zones),
  156. GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label"
  157. " FROM ns098records"
  158. " WHERE zone_private_key=? AND label=?",
  159. &plugin->lookup_label),
  160. GNUNET_SQ_PREPARE_END
  161. };
  162. if (GNUNET_OK !=
  163. GNUNET_CONFIGURATION_get_value_filename (plugin->cfg,
  164. "namestore-sqlite",
  165. "FILENAME",
  166. &sqlite_filename))
  167. {
  168. GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
  169. "namestore-sqlite",
  170. "FILENAME");
  171. return GNUNET_SYSERR;
  172. }
  173. if (GNUNET_OK !=
  174. GNUNET_DISK_file_test (sqlite_filename))
  175. {
  176. if (GNUNET_OK !=
  177. GNUNET_DISK_directory_create_for_file (sqlite_filename))
  178. {
  179. GNUNET_break (0);
  180. GNUNET_free (sqlite_filename);
  181. return GNUNET_SYSERR;
  182. }
  183. }
  184. /* sqlite_filename should be UTF-8-encoded. If it isn't, it's a bug */
  185. plugin->fn = sqlite_filename;
  186. /* Open database and precompile statements */
  187. if (SQLITE_OK !=
  188. sqlite3_open (plugin->fn,
  189. &plugin->dbh))
  190. {
  191. LOG (GNUNET_ERROR_TYPE_ERROR,
  192. _ ("Unable to initialize SQLite: %s.\n"),
  193. sqlite3_errmsg (plugin->dbh));
  194. return GNUNET_SYSERR;
  195. }
  196. GNUNET_break (SQLITE_OK ==
  197. sqlite3_busy_timeout (plugin->dbh,
  198. BUSY_TIMEOUT_MS));
  199. if (GNUNET_OK !=
  200. GNUNET_SQ_exec_statements (plugin->dbh,
  201. es))
  202. {
  203. GNUNET_break (0);
  204. LOG (GNUNET_ERROR_TYPE_ERROR,
  205. _ ("Failed to setup database at `%s'\n"),
  206. plugin->fn);
  207. return GNUNET_SYSERR;
  208. }
  209. if (GNUNET_OK !=
  210. GNUNET_SQ_prepare (plugin->dbh,
  211. ps))
  212. {
  213. GNUNET_break (0);
  214. LOG (GNUNET_ERROR_TYPE_ERROR,
  215. _ ("Failed to setup database at `%s'\n"),
  216. plugin->fn);
  217. return GNUNET_SYSERR;
  218. }
  219. return GNUNET_OK;
  220. }
  221. /**
  222. * Shutdown database connection and associate data
  223. * structures.
  224. * @param plugin the plugin context (state for this module)
  225. */
  226. static void
  227. database_shutdown (struct Plugin *plugin)
  228. {
  229. int result;
  230. sqlite3_stmt *stmt;
  231. if (NULL != plugin->store_records)
  232. sqlite3_finalize (plugin->store_records);
  233. if (NULL != plugin->delete_records)
  234. sqlite3_finalize (plugin->delete_records);
  235. if (NULL != plugin->iterate_zone)
  236. sqlite3_finalize (plugin->iterate_zone);
  237. if (NULL != plugin->iterate_all_zones)
  238. sqlite3_finalize (plugin->iterate_all_zones);
  239. if (NULL != plugin->zone_to_name)
  240. sqlite3_finalize (plugin->zone_to_name);
  241. if (NULL != plugin->lookup_label)
  242. sqlite3_finalize (plugin->lookup_label);
  243. result = sqlite3_close (plugin->dbh);
  244. if (result == SQLITE_BUSY)
  245. {
  246. LOG (GNUNET_ERROR_TYPE_WARNING,
  247. _ (
  248. "Tried to close sqlite without finalizing all prepared statements.\n"));
  249. stmt = sqlite3_next_stmt (plugin->dbh,
  250. NULL);
  251. while (NULL != stmt)
  252. {
  253. GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
  254. "sqlite",
  255. "Closing statement %p\n",
  256. stmt);
  257. result = sqlite3_finalize (stmt);
  258. if (result != SQLITE_OK)
  259. GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
  260. "sqlite",
  261. "Failed to close statement %p: %d\n",
  262. stmt,
  263. result);
  264. stmt = sqlite3_next_stmt (plugin->dbh,
  265. NULL);
  266. }
  267. result = sqlite3_close (plugin->dbh);
  268. }
  269. if (SQLITE_OK != result)
  270. LOG_SQLITE (plugin,
  271. GNUNET_ERROR_TYPE_ERROR,
  272. "sqlite3_close");
  273. GNUNET_free (plugin->fn);
  274. }
  275. /**
  276. * Store a record in the datastore. Removes any existing record in the
  277. * same zone with the same name.
  278. *
  279. * @param cls closure (internal context for the plugin)
  280. * @param zone_key private key of the zone
  281. * @param label name that is being mapped (at most 255 characters long)
  282. * @param rd_count number of entries in @a rd array
  283. * @param rd array of records with data to store
  284. * @return #GNUNET_OK on success, else #GNUNET_SYSERR
  285. */
  286. static int
  287. namestore_sqlite_store_records (void *cls,
  288. const struct
  289. GNUNET_IDENTITY_PrivateKey *zone_key,
  290. const char *label,
  291. unsigned int rd_count,
  292. const struct GNUNET_GNSRECORD_Data *rd)
  293. {
  294. struct Plugin *plugin = cls;
  295. int n;
  296. struct GNUNET_IDENTITY_PublicKey pkey;
  297. uint64_t rvalue;
  298. ssize_t data_size;
  299. memset (&pkey,
  300. 0,
  301. sizeof(pkey));
  302. for (unsigned int i = 0; i < rd_count; i++)
  303. if (GNUNET_YES == GNUNET_GNSRECORD_is_zonekey_type (rd[i].record_type))
  304. {
  305. GNUNET_break (GNUNET_YES ==
  306. GNUNET_GNSRECORD_identity_from_data (rd[i].data,
  307. rd[i].data_size,
  308. rd[i].record_type,
  309. &pkey));
  310. break;
  311. }
  312. rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
  313. UINT64_MAX);
  314. data_size = GNUNET_GNSRECORD_records_get_size (rd_count,
  315. rd);
  316. if (data_size < 0)
  317. {
  318. GNUNET_break (0);
  319. return GNUNET_SYSERR;
  320. }
  321. if (data_size > 64 * 65536)
  322. {
  323. GNUNET_break (0);
  324. return GNUNET_SYSERR;
  325. }
  326. {
  327. /* First delete 'old' records */
  328. char data[data_size];
  329. struct GNUNET_SQ_QueryParam dparams[] = {
  330. GNUNET_SQ_query_param_auto_from_type (zone_key),
  331. GNUNET_SQ_query_param_string (label),
  332. GNUNET_SQ_query_param_end
  333. };
  334. ssize_t ret;
  335. ret = GNUNET_GNSRECORD_records_serialize (rd_count,
  336. rd,
  337. data_size,
  338. data);
  339. if ((ret < 0) ||
  340. (data_size != ret))
  341. {
  342. GNUNET_break (0);
  343. return GNUNET_SYSERR;
  344. }
  345. if (GNUNET_OK !=
  346. GNUNET_SQ_bind (plugin->delete_records,
  347. dparams))
  348. {
  349. LOG_SQLITE (plugin,
  350. GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  351. "sqlite3_bind_XXXX");
  352. GNUNET_SQ_reset (plugin->dbh,
  353. plugin->delete_records);
  354. return GNUNET_SYSERR;
  355. }
  356. n = sqlite3_step (plugin->delete_records);
  357. GNUNET_SQ_reset (plugin->dbh,
  358. plugin->delete_records);
  359. if (0 != rd_count)
  360. {
  361. uint32_t rd_count32 = (uint32_t) rd_count;
  362. struct GNUNET_SQ_QueryParam sparams[] = {
  363. GNUNET_SQ_query_param_auto_from_type (zone_key),
  364. GNUNET_SQ_query_param_auto_from_type (&pkey),
  365. GNUNET_SQ_query_param_uint64 (&rvalue),
  366. GNUNET_SQ_query_param_uint32 (&rd_count32),
  367. GNUNET_SQ_query_param_fixed_size (data, data_size),
  368. GNUNET_SQ_query_param_string (label),
  369. GNUNET_SQ_query_param_end
  370. };
  371. if (GNUNET_OK !=
  372. GNUNET_SQ_bind (plugin->store_records,
  373. sparams))
  374. {
  375. LOG_SQLITE (plugin,
  376. GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  377. "sqlite3_bind_XXXX");
  378. GNUNET_SQ_reset (plugin->dbh,
  379. plugin->store_records);
  380. return GNUNET_SYSERR;
  381. }
  382. n = sqlite3_step (plugin->store_records);
  383. GNUNET_SQ_reset (plugin->dbh,
  384. plugin->store_records);
  385. }
  386. }
  387. switch (n)
  388. {
  389. case SQLITE_DONE:
  390. if (0 != rd_count)
  391. GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
  392. "sqlite",
  393. "Record stored\n");
  394. else
  395. GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
  396. "sqlite",
  397. "Record deleted\n");
  398. return GNUNET_OK;
  399. case SQLITE_BUSY:
  400. LOG_SQLITE (plugin,
  401. GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
  402. "sqlite3_step");
  403. return GNUNET_NO;
  404. default:
  405. LOG_SQLITE (plugin,
  406. GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  407. "sqlite3_step");
  408. return GNUNET_SYSERR;
  409. }
  410. }
  411. /**
  412. * The given 'sqlite' statement has been prepared to be run.
  413. * It will return a record which should be given to the iterator.
  414. * Runs the statement and parses the returned record.
  415. *
  416. * @param plugin plugin context
  417. * @param stmt to run (and then clean up)
  418. * @param zone_key private key of the zone
  419. * @param limit maximum number of results to fetch
  420. * @param iter iterator to call with the result
  421. * @param iter_cls closure for @a iter
  422. * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
  423. */
  424. static int
  425. get_records_and_call_iterator (struct Plugin *plugin,
  426. sqlite3_stmt *stmt,
  427. const struct
  428. GNUNET_IDENTITY_PrivateKey *zone_key,
  429. uint64_t limit,
  430. GNUNET_NAMESTORE_RecordIterator iter,
  431. void *iter_cls)
  432. {
  433. int ret;
  434. int sret;
  435. ret = GNUNET_OK;
  436. for (uint64_t i = 0; i < limit; i++)
  437. {
  438. sret = sqlite3_step (stmt);
  439. if (SQLITE_DONE == sret)
  440. {
  441. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  442. "Iteration done (no results)\n");
  443. ret = GNUNET_NO;
  444. break;
  445. }
  446. if (SQLITE_ROW != sret)
  447. {
  448. LOG_SQLITE (plugin,
  449. GNUNET_ERROR_TYPE_ERROR,
  450. "sqlite_step");
  451. ret = GNUNET_SYSERR;
  452. break;
  453. }
  454. {
  455. uint64_t seq;
  456. uint32_t record_count;
  457. size_t data_size;
  458. void *data;
  459. char *label;
  460. struct GNUNET_IDENTITY_PrivateKey zk;
  461. struct GNUNET_SQ_ResultSpec rs[] = {
  462. GNUNET_SQ_result_spec_uint64 (&seq),
  463. GNUNET_SQ_result_spec_uint32 (&record_count),
  464. GNUNET_SQ_result_spec_variable_size (&data,
  465. &data_size),
  466. GNUNET_SQ_result_spec_string (&label),
  467. GNUNET_SQ_result_spec_end
  468. };
  469. struct GNUNET_SQ_ResultSpec rsx[] = {
  470. GNUNET_SQ_result_spec_uint64 (&seq),
  471. GNUNET_SQ_result_spec_uint32 (&record_count),
  472. GNUNET_SQ_result_spec_variable_size (&data,
  473. &data_size),
  474. GNUNET_SQ_result_spec_string (&label),
  475. GNUNET_SQ_result_spec_auto_from_type (&zk),
  476. GNUNET_SQ_result_spec_end
  477. };
  478. ret = GNUNET_SQ_extract_result (stmt,
  479. (NULL == zone_key)
  480. ? rsx
  481. : rs);
  482. if ((GNUNET_OK != ret) ||
  483. (record_count > 64 * 1024))
  484. {
  485. /* sanity check, don't stack allocate far too much just
  486. because database might contain a large value here */
  487. GNUNET_break (0);
  488. ret = GNUNET_SYSERR;
  489. break;
  490. }
  491. else
  492. {
  493. struct GNUNET_GNSRECORD_Data rd[record_count];
  494. GNUNET_assert (0 != seq);
  495. if (GNUNET_OK !=
  496. GNUNET_GNSRECORD_records_deserialize (data_size,
  497. data,
  498. record_count,
  499. rd))
  500. {
  501. GNUNET_break (0);
  502. ret = GNUNET_SYSERR;
  503. break;
  504. }
  505. else
  506. {
  507. if (NULL != zone_key)
  508. zk = *zone_key;
  509. if (NULL != iter)
  510. iter (iter_cls,
  511. seq,
  512. &zk,
  513. label,
  514. record_count,
  515. rd);
  516. }
  517. }
  518. GNUNET_SQ_cleanup_result (rs);
  519. }
  520. }
  521. GNUNET_SQ_reset (plugin->dbh,
  522. stmt);
  523. return ret;
  524. }
  525. /**
  526. * Lookup records in the datastore for which we are the authority.
  527. *
  528. * @param cls closure (internal context for the plugin)
  529. * @param zone private key of the zone
  530. * @param label name of the record in the zone
  531. * @param iter function to call with the result
  532. * @param iter_cls closure for @a iter
  533. * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR
  534. */
  535. static int
  536. namestore_sqlite_lookup_records (void *cls,
  537. const struct
  538. GNUNET_IDENTITY_PrivateKey *zone,
  539. const char *label,
  540. GNUNET_NAMESTORE_RecordIterator iter,
  541. void *iter_cls)
  542. {
  543. struct Plugin *plugin = cls;
  544. struct GNUNET_SQ_QueryParam params[] = {
  545. GNUNET_SQ_query_param_auto_from_type (zone),
  546. GNUNET_SQ_query_param_string (label),
  547. GNUNET_SQ_query_param_end
  548. };
  549. if (NULL == zone)
  550. {
  551. GNUNET_break (0);
  552. return GNUNET_SYSERR;
  553. }
  554. if (GNUNET_OK !=
  555. GNUNET_SQ_bind (plugin->lookup_label,
  556. params))
  557. {
  558. LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  559. "sqlite3_bind_XXXX");
  560. GNUNET_SQ_reset (plugin->dbh,
  561. plugin->lookup_label);
  562. return GNUNET_SYSERR;
  563. }
  564. return get_records_and_call_iterator (plugin,
  565. plugin->lookup_label,
  566. zone,
  567. 1,
  568. iter,
  569. iter_cls);
  570. }
  571. /**
  572. * Iterate over the results for a particular key and zone in the
  573. * datastore. Will return at most one result to the iterator.
  574. *
  575. * @param cls closure (internal context for the plugin)
  576. * @param zone hash of public key of the zone, NULL to iterate over all zones
  577. * @param serial serial number to exclude in the list of all matching records
  578. * @param limit maximum number of results to return
  579. * @param iter function to call with the result
  580. * @param iter_cls closure for @a iter
  581. * @return #GNUNET_OK on success, #GNUNET_NO if there were no more results, #GNUNET_SYSERR on error
  582. */
  583. static int
  584. namestore_sqlite_iterate_records (void *cls,
  585. const struct
  586. GNUNET_IDENTITY_PrivateKey *zone,
  587. uint64_t serial,
  588. uint64_t limit,
  589. GNUNET_NAMESTORE_RecordIterator iter,
  590. void *iter_cls)
  591. {
  592. struct Plugin *plugin = cls;
  593. sqlite3_stmt *stmt;
  594. int err;
  595. if (NULL == zone)
  596. {
  597. struct GNUNET_SQ_QueryParam params[] = {
  598. GNUNET_SQ_query_param_uint64 (&serial),
  599. GNUNET_SQ_query_param_uint64 (&limit),
  600. GNUNET_SQ_query_param_end
  601. };
  602. stmt = plugin->iterate_all_zones;
  603. err = GNUNET_SQ_bind (stmt,
  604. params);
  605. }
  606. else
  607. {
  608. struct GNUNET_SQ_QueryParam params[] = {
  609. GNUNET_SQ_query_param_auto_from_type (zone),
  610. GNUNET_SQ_query_param_uint64 (&serial),
  611. GNUNET_SQ_query_param_uint64 (&limit),
  612. GNUNET_SQ_query_param_end
  613. };
  614. stmt = plugin->iterate_zone;
  615. err = GNUNET_SQ_bind (stmt,
  616. params);
  617. }
  618. if (GNUNET_OK != err)
  619. {
  620. LOG_SQLITE (plugin,
  621. GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  622. "sqlite3_bind_XXXX");
  623. GNUNET_SQ_reset (plugin->dbh,
  624. stmt);
  625. return GNUNET_SYSERR;
  626. }
  627. return get_records_and_call_iterator (plugin,
  628. stmt,
  629. zone,
  630. limit,
  631. iter,
  632. iter_cls);
  633. }
  634. /**
  635. * Look for an existing PKEY delegation record for a given public key.
  636. * Returns at most one result to the iterator.
  637. *
  638. * @param cls closure (internal context for the plugin)
  639. * @param zone private key of the zone to look up in, never NULL
  640. * @param value_zone public key of the target zone (value), never NULL
  641. * @param iter function to call with the result
  642. * @param iter_cls closure for @a iter
  643. * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
  644. */
  645. static int
  646. namestore_sqlite_zone_to_name (void *cls,
  647. const struct GNUNET_IDENTITY_PrivateKey *zone,
  648. const struct
  649. GNUNET_IDENTITY_PublicKey *value_zone,
  650. GNUNET_NAMESTORE_RecordIterator iter,
  651. void *iter_cls)
  652. {
  653. struct Plugin *plugin = cls;
  654. struct GNUNET_SQ_QueryParam params[] = {
  655. GNUNET_SQ_query_param_auto_from_type (zone),
  656. GNUNET_SQ_query_param_auto_from_type (value_zone),
  657. GNUNET_SQ_query_param_end
  658. };
  659. if (GNUNET_OK !=
  660. GNUNET_SQ_bind (plugin->zone_to_name,
  661. params))
  662. {
  663. LOG_SQLITE (plugin,
  664. GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  665. "sqlite3_bind_XXXX");
  666. GNUNET_SQ_reset (plugin->dbh,
  667. plugin->zone_to_name);
  668. return GNUNET_SYSERR;
  669. }
  670. LOG (GNUNET_ERROR_TYPE_DEBUG,
  671. "Performing reverse lookup for `%s'\n",
  672. GNUNET_GNSRECORD_z2s (value_zone));
  673. return get_records_and_call_iterator (plugin,
  674. plugin->zone_to_name,
  675. zone,
  676. 1,
  677. iter,
  678. iter_cls);
  679. }
  680. /**
  681. * Entry point for the plugin.
  682. *
  683. * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
  684. * @return NULL on error, otherwise the plugin context
  685. */
  686. void *
  687. libgnunet_plugin_namestore_sqlite_init (void *cls)
  688. {
  689. static struct Plugin plugin;
  690. const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
  691. struct GNUNET_NAMESTORE_PluginFunctions *api;
  692. if (NULL != plugin.cfg)
  693. return NULL; /* can only initialize once! */
  694. memset (&plugin,
  695. 0,
  696. sizeof(struct Plugin));
  697. plugin.cfg = cfg;
  698. if (GNUNET_OK != database_setup (&plugin))
  699. {
  700. database_shutdown (&plugin);
  701. return NULL;
  702. }
  703. api = GNUNET_new (struct GNUNET_NAMESTORE_PluginFunctions);
  704. api->cls = &plugin;
  705. api->store_records = &namestore_sqlite_store_records;
  706. api->iterate_records = &namestore_sqlite_iterate_records;
  707. api->zone_to_name = &namestore_sqlite_zone_to_name;
  708. api->lookup_records = &namestore_sqlite_lookup_records;
  709. LOG (GNUNET_ERROR_TYPE_INFO,
  710. _ ("Sqlite database running\n"));
  711. return api;
  712. }
  713. /**
  714. * Exit point from the plugin.
  715. *
  716. * @param cls the plugin context (as returned by "init")
  717. * @return always NULL
  718. */
  719. void *
  720. libgnunet_plugin_namestore_sqlite_done (void *cls)
  721. {
  722. struct GNUNET_NAMESTORE_PluginFunctions *api = cls;
  723. struct Plugin *plugin = api->cls;
  724. database_shutdown (plugin);
  725. plugin->cfg = NULL;
  726. GNUNET_free (api);
  727. LOG (GNUNET_ERROR_TYPE_DEBUG,
  728. "sqlite plugin is finished\n");
  729. return NULL;
  730. }
  731. /* end of plugin_namestore_sqlite.c */