plugin_peerstore_sqlite.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. /*
  2. * This file is part of GNUnet
  3. * Copyright (C) 2013, 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 peerstore/plugin_peerstore_sqlite.c
  21. * @brief sqlite-based peerstore backend
  22. * @author Omar Tarabai
  23. * @author Christian Grothoff
  24. */
  25. #include "platform.h"
  26. #include "gnunet_peerstore_plugin.h"
  27. #include "gnunet_peerstore_service.h"
  28. #include "gnunet_sq_lib.h"
  29. #include "peerstore.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. "peerstore-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, "peerstore-sqlite", __VA_ARGS__)
  56. /**
  57. * Context for all functions in this plugin.
  58. */
  59. struct Plugin
  60. {
  61. /**
  62. * Configuration handle
  63. */
  64. const struct GNUNET_CONFIGURATION_Handle *cfg;
  65. /**
  66. * Database filename.
  67. */
  68. char *fn;
  69. /**
  70. * Native SQLite database handle.
  71. */
  72. sqlite3 *dbh;
  73. /**
  74. * Precompiled SQL for inserting into peerstoredata
  75. */
  76. sqlite3_stmt *insert_peerstoredata;
  77. /**
  78. * Precompiled SQL for selecting from peerstoredata
  79. */
  80. sqlite3_stmt *select_peerstoredata;
  81. /**
  82. * Precompiled SQL for selecting from peerstoredata
  83. */
  84. sqlite3_stmt *select_peerstoredata_by_pid;
  85. /**
  86. * Precompiled SQL for selecting from peerstoredata
  87. */
  88. sqlite3_stmt *select_peerstoredata_by_key;
  89. /**
  90. * Precompiled SQL for selecting from peerstoredata
  91. */
  92. sqlite3_stmt *select_peerstoredata_by_all;
  93. /**
  94. * Precompiled SQL for deleting expired
  95. * records from peerstoredata
  96. */
  97. sqlite3_stmt *expire_peerstoredata;
  98. /**
  99. * Precompiled SQL for deleting records
  100. * with given key
  101. */
  102. sqlite3_stmt *delete_peerstoredata;
  103. };
  104. /**
  105. * Delete records with the given key
  106. *
  107. * @param cls closure (internal context for the plugin)
  108. * @param sub_system name of sub system
  109. * @param peer Peer identity (can be NULL)
  110. * @param key entry key string (can be NULL)
  111. * @return number of deleted records, #GNUNE_SYSERR on error
  112. */
  113. static int
  114. peerstore_sqlite_delete_records (void *cls,
  115. const char *sub_system,
  116. const struct GNUNET_PeerIdentity *peer,
  117. const char *key)
  118. {
  119. struct Plugin *plugin = cls;
  120. sqlite3_stmt *stmt = plugin->delete_peerstoredata;
  121. struct GNUNET_SQ_QueryParam params[] = {
  122. GNUNET_SQ_query_param_string (sub_system),
  123. GNUNET_SQ_query_param_auto_from_type (peer),
  124. GNUNET_SQ_query_param_string (key),
  125. GNUNET_SQ_query_param_end
  126. };
  127. int ret;
  128. if (GNUNET_OK !=
  129. GNUNET_SQ_bind (stmt,
  130. params))
  131. {
  132. LOG_SQLITE (plugin,
  133. GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  134. "sqlite3_bind");
  135. GNUNET_SQ_reset (plugin->dbh,
  136. stmt);
  137. return GNUNET_SYSERR;
  138. }
  139. if (SQLITE_DONE !=
  140. sqlite3_step (stmt))
  141. {
  142. LOG_SQLITE (plugin,
  143. GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  144. "sqlite3_step");
  145. ret = GNUNET_SYSERR;
  146. }
  147. else
  148. {
  149. ret = sqlite3_changes (plugin->dbh);
  150. }
  151. GNUNET_SQ_reset (plugin->dbh,
  152. stmt);
  153. return ret;
  154. }
  155. /**
  156. * Delete expired records (expiry < now)
  157. *
  158. * @param cls closure (internal context for the plugin)
  159. * @param now time to use as reference
  160. * @param cont continuation called with the number of records expired
  161. * @param cont_cls continuation closure
  162. * @return #GNUNET_OK on success, #GNUNET_SYSERR on error and cont is not
  163. * called
  164. */
  165. static int
  166. peerstore_sqlite_expire_records (void *cls, struct GNUNET_TIME_Absolute now,
  167. GNUNET_PEERSTORE_Continuation cont,
  168. void *cont_cls)
  169. {
  170. struct Plugin *plugin = cls;
  171. sqlite3_stmt *stmt = plugin->expire_peerstoredata;
  172. struct GNUNET_SQ_QueryParam params[] = {
  173. GNUNET_SQ_query_param_absolute_time (&now),
  174. GNUNET_SQ_query_param_end
  175. };
  176. if (GNUNET_OK !=
  177. GNUNET_SQ_bind (stmt,
  178. params))
  179. {
  180. LOG_SQLITE (plugin,
  181. GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  182. "sqlite3_bind");
  183. GNUNET_SQ_reset (plugin->dbh,
  184. stmt);
  185. return GNUNET_SYSERR;
  186. }
  187. if (SQLITE_DONE != sqlite3_step (stmt))
  188. {
  189. LOG_SQLITE (plugin,
  190. GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  191. "sqlite3_step");
  192. GNUNET_SQ_reset (plugin->dbh,
  193. stmt);
  194. return GNUNET_SYSERR;
  195. }
  196. if (NULL != cont)
  197. cont (cont_cls,
  198. sqlite3_changes (plugin->dbh));
  199. GNUNET_SQ_reset (plugin->dbh,
  200. stmt);
  201. return GNUNET_OK;
  202. }
  203. /**
  204. * Iterate over the records given an optional peer id
  205. * and/or key.
  206. *
  207. * @param cls closure (internal context for the plugin)
  208. * @param sub_system name of sub system
  209. * @param peer Peer identity (can be NULL)
  210. * @param key entry key string (can be NULL)
  211. * @param iter function to call asynchronously with the results, terminated
  212. * by a NULL result
  213. * @param iter_cls closure for @a iter
  214. * @return #GNUNET_OK on success, #GNUNET_SYSERR on error and iter is not
  215. * called
  216. */
  217. static int
  218. peerstore_sqlite_iterate_records (void *cls,
  219. const char *sub_system,
  220. const struct GNUNET_PeerIdentity *peer,
  221. const char *key,
  222. GNUNET_PEERSTORE_Processor iter,
  223. void *iter_cls)
  224. {
  225. struct Plugin *plugin = cls;
  226. sqlite3_stmt *stmt;
  227. int err = 0;
  228. int sret;
  229. struct GNUNET_PEERSTORE_Record rec;
  230. LOG (GNUNET_ERROR_TYPE_DEBUG,
  231. "Executing iterate request on sqlite db.\n");
  232. if (NULL == peer)
  233. {
  234. if (NULL == key)
  235. {
  236. struct GNUNET_SQ_QueryParam params[] = {
  237. GNUNET_SQ_query_param_string (sub_system),
  238. GNUNET_SQ_query_param_end
  239. };
  240. stmt = plugin->select_peerstoredata;
  241. err = GNUNET_SQ_bind (stmt,
  242. params);
  243. }
  244. else
  245. {
  246. struct GNUNET_SQ_QueryParam params[] = {
  247. GNUNET_SQ_query_param_string (sub_system),
  248. GNUNET_SQ_query_param_string (key),
  249. GNUNET_SQ_query_param_end
  250. };
  251. stmt = plugin->select_peerstoredata_by_key;
  252. err = GNUNET_SQ_bind (stmt,
  253. params);
  254. }
  255. }
  256. else
  257. {
  258. if (NULL == key)
  259. {
  260. struct GNUNET_SQ_QueryParam params[] = {
  261. GNUNET_SQ_query_param_string (sub_system),
  262. GNUNET_SQ_query_param_auto_from_type (peer),
  263. GNUNET_SQ_query_param_end
  264. };
  265. stmt = plugin->select_peerstoredata_by_pid;
  266. err = GNUNET_SQ_bind (stmt,
  267. params);
  268. }
  269. else
  270. {
  271. struct GNUNET_SQ_QueryParam params[] = {
  272. GNUNET_SQ_query_param_string (sub_system),
  273. GNUNET_SQ_query_param_auto_from_type (peer),
  274. GNUNET_SQ_query_param_string (key),
  275. GNUNET_SQ_query_param_end
  276. };
  277. stmt = plugin->select_peerstoredata_by_all;
  278. err = GNUNET_SQ_bind (stmt,
  279. params);
  280. }
  281. }
  282. if (GNUNET_OK != err)
  283. {
  284. LOG_SQLITE (plugin,
  285. GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  286. "sqlite3_bind_XXXX");
  287. GNUNET_SQ_reset (plugin->dbh,
  288. stmt);
  289. return GNUNET_SYSERR;
  290. }
  291. err = 0;
  292. while (SQLITE_ROW == (sret = sqlite3_step (stmt)))
  293. {
  294. LOG (GNUNET_ERROR_TYPE_DEBUG,
  295. "Returning a matched record.\n");
  296. struct GNUNET_SQ_ResultSpec rs[] = {
  297. GNUNET_SQ_result_spec_string (&rec.sub_system),
  298. GNUNET_SQ_result_spec_auto_from_type (&rec.peer),
  299. GNUNET_SQ_result_spec_string (&rec.key),
  300. GNUNET_SQ_result_spec_variable_size (&rec.value, &rec.value_size),
  301. GNUNET_SQ_result_spec_absolute_time (&rec.expiry),
  302. GNUNET_SQ_result_spec_end
  303. };
  304. if (GNUNET_OK !=
  305. GNUNET_SQ_extract_result (stmt,
  306. rs))
  307. {
  308. GNUNET_break (0);
  309. break;
  310. }
  311. if (NULL != iter)
  312. iter (iter_cls,
  313. &rec,
  314. NULL);
  315. GNUNET_SQ_cleanup_result (rs);
  316. }
  317. if (SQLITE_DONE != sret)
  318. {
  319. LOG_SQLITE (plugin,
  320. GNUNET_ERROR_TYPE_ERROR,
  321. "sqlite_step");
  322. err = 1;
  323. }
  324. GNUNET_SQ_reset (plugin->dbh,
  325. stmt);
  326. if (NULL != iter)
  327. iter (iter_cls,
  328. NULL,
  329. err ? "sqlite error" : NULL);
  330. return GNUNET_OK;
  331. }
  332. /**
  333. * Store a record in the peerstore.
  334. * Key is the combination of sub system and peer identity.
  335. * One key can store multiple values.
  336. *
  337. * @param cls closure (internal context for the plugin)
  338. * @param sub_system name of the GNUnet sub system responsible
  339. * @param peer peer identity
  340. * @param key record key string
  341. * @param value value to be stored
  342. * @param size size of value to be stored
  343. * @param expiry absolute time after which the record is (possibly) deleted
  344. * @param options options related to the store operation
  345. * @param cont continuation called when record is stored
  346. * @param cont_cls continuation closure
  347. * @return #GNUNET_OK on success, else #GNUNET_SYSERR and cont is not called
  348. */
  349. static int
  350. peerstore_sqlite_store_record (void *cls,
  351. const char *sub_system,
  352. const struct GNUNET_PeerIdentity *peer,
  353. const char *key,
  354. const void *value,
  355. size_t size,
  356. struct GNUNET_TIME_Absolute expiry,
  357. enum GNUNET_PEERSTORE_StoreOption options,
  358. GNUNET_PEERSTORE_Continuation cont,
  359. void *cont_cls)
  360. {
  361. struct Plugin *plugin = cls;
  362. sqlite3_stmt *stmt = plugin->insert_peerstoredata;
  363. struct GNUNET_SQ_QueryParam params[] = {
  364. GNUNET_SQ_query_param_string (sub_system),
  365. GNUNET_SQ_query_param_auto_from_type (peer),
  366. GNUNET_SQ_query_param_string (key),
  367. GNUNET_SQ_query_param_fixed_size (value, size),
  368. GNUNET_SQ_query_param_absolute_time (&expiry),
  369. GNUNET_SQ_query_param_end
  370. };
  371. if (GNUNET_PEERSTORE_STOREOPTION_REPLACE == options)
  372. {
  373. peerstore_sqlite_delete_records (cls,
  374. sub_system,
  375. peer,
  376. key);
  377. }
  378. if (GNUNET_OK !=
  379. GNUNET_SQ_bind (stmt,
  380. params))
  381. LOG_SQLITE (plugin,
  382. GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  383. "sqlite3_bind");
  384. else if (SQLITE_DONE != sqlite3_step (stmt))
  385. {
  386. LOG_SQLITE (plugin,
  387. GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
  388. "sqlite3_step");
  389. }
  390. GNUNET_SQ_reset (plugin->dbh,
  391. stmt);
  392. if (NULL != cont)
  393. cont (cont_cls,
  394. GNUNET_OK);
  395. return GNUNET_OK;
  396. }
  397. /**
  398. * @brief Prepare a SQL statement
  399. *
  400. * @param dbh handle to the database
  401. * @param sql SQL statement, UTF-8 encoded
  402. * @return 0 on success
  403. */
  404. static int
  405. sql_exec (sqlite3 *dbh,
  406. const char *sql)
  407. {
  408. int result;
  409. result = sqlite3_exec (dbh,
  410. sql,
  411. NULL,
  412. NULL,
  413. NULL);
  414. LOG (GNUNET_ERROR_TYPE_DEBUG,
  415. "Executed `%s' / %d\n",
  416. sql,
  417. result);
  418. if (SQLITE_OK != result)
  419. LOG (GNUNET_ERROR_TYPE_ERROR,
  420. _ ("Error executing SQL query: %s\n %s\n"),
  421. sqlite3_errmsg (dbh),
  422. sql);
  423. return result;
  424. }
  425. /**
  426. * @brief Prepare a SQL statement
  427. *
  428. * @param dbh handle to the database
  429. * @param sql SQL statement, UTF-8 encoded
  430. * @param stmt set to the prepared statement
  431. * @return 0 on success
  432. */
  433. static int
  434. sql_prepare (sqlite3 *dbh,
  435. const char *sql,
  436. sqlite3_stmt **stmt)
  437. {
  438. char *tail;
  439. int result;
  440. result = sqlite3_prepare_v2 (dbh,
  441. sql,
  442. strlen (sql),
  443. stmt,
  444. (const char **) &tail);
  445. LOG (GNUNET_ERROR_TYPE_DEBUG,
  446. "Prepared `%s' / %p: %d\n",
  447. sql,
  448. *stmt,
  449. result);
  450. if (SQLITE_OK != result)
  451. LOG (GNUNET_ERROR_TYPE_ERROR,
  452. _ ("Error preparing SQL query: %s\n %s\n"),
  453. sqlite3_errmsg (dbh),
  454. sql);
  455. return result;
  456. }
  457. /**
  458. * Initialize the database connections and associated
  459. * data structures (create tables and indices
  460. * as needed as well).
  461. *
  462. * @param plugin the plugin context (state for this module)
  463. * @return #GNUNET_OK on success
  464. */
  465. static int
  466. database_setup (struct Plugin *plugin)
  467. {
  468. char *filename;
  469. if (GNUNET_OK !=
  470. GNUNET_CONFIGURATION_get_value_filename (plugin->cfg,
  471. "peerstore-sqlite",
  472. "FILENAME",
  473. &filename))
  474. {
  475. GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
  476. "peerstore-sqlite",
  477. "FILENAME");
  478. return GNUNET_SYSERR;
  479. }
  480. if (GNUNET_OK != GNUNET_DISK_file_test (filename))
  481. {
  482. if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (filename))
  483. {
  484. GNUNET_break (0);
  485. GNUNET_free (filename);
  486. return GNUNET_SYSERR;
  487. }
  488. }
  489. /* filename should be UTF-8-encoded. If it isn't, it's a bug */
  490. plugin->fn = filename;
  491. /* Open database and precompile statements */
  492. if (SQLITE_OK != sqlite3_open (plugin->fn,
  493. &plugin->dbh))
  494. {
  495. LOG (GNUNET_ERROR_TYPE_ERROR,
  496. _ ("Unable to initialize SQLite: %s.\n"),
  497. sqlite3_errmsg (plugin->dbh));
  498. return GNUNET_SYSERR;
  499. }
  500. sql_exec (plugin->dbh,
  501. "PRAGMA temp_store=MEMORY");
  502. sql_exec (plugin->dbh,
  503. "PRAGMA synchronous=OFF");
  504. sql_exec (plugin->dbh,
  505. "PRAGMA legacy_file_format=OFF");
  506. sql_exec (plugin->dbh,
  507. "PRAGMA auto_vacuum=INCREMENTAL");
  508. sql_exec (plugin->dbh,
  509. "PRAGMA encoding=\"UTF-8\"");
  510. sql_exec (plugin->dbh,
  511. "PRAGMA page_size=4096");
  512. sqlite3_busy_timeout (plugin->dbh,
  513. BUSY_TIMEOUT_MS);
  514. /* Create tables */
  515. sql_exec (plugin->dbh,
  516. "CREATE TABLE IF NOT EXISTS peerstoredata (\n"
  517. " sub_system TEXT NOT NULL,\n"
  518. " peer_id BLOB NOT NULL,\n"
  519. " key TEXT NOT NULL,\n"
  520. " value BLOB NULL,\n"
  521. " expiry INT8 NOT NULL" ");");
  522. /* Create Indices */
  523. if (SQLITE_OK !=
  524. sqlite3_exec (plugin->dbh,
  525. "CREATE INDEX IF NOT EXISTS peerstoredata_key_index ON peerstoredata (sub_system, peer_id, key)",
  526. NULL,
  527. NULL,
  528. NULL))
  529. {
  530. LOG (GNUNET_ERROR_TYPE_ERROR,
  531. _ ("Unable to create indices: %s.\n"),
  532. sqlite3_errmsg (plugin->dbh));
  533. return GNUNET_SYSERR;
  534. }
  535. /* Prepare statements */
  536. sql_prepare (plugin->dbh,
  537. "INSERT INTO peerstoredata (sub_system, peer_id, key, value, expiry)"
  538. " VALUES (?,?,?,?,?);",
  539. &plugin->insert_peerstoredata);
  540. sql_prepare (plugin->dbh,
  541. "SELECT sub_system,peer_id,key,value,expiry FROM peerstoredata"
  542. " WHERE sub_system = ?",
  543. &plugin->select_peerstoredata);
  544. sql_prepare (plugin->dbh,
  545. "SELECT sub_system,peer_id,key,value,expiry FROM peerstoredata"
  546. " WHERE sub_system = ?"
  547. " AND peer_id = ?",
  548. &plugin->select_peerstoredata_by_pid);
  549. sql_prepare (plugin->dbh,
  550. "SELECT sub_system,peer_id,key,value,expiry FROM peerstoredata"
  551. " WHERE sub_system = ?"
  552. " AND key = ?",
  553. &plugin->select_peerstoredata_by_key);
  554. sql_prepare (plugin->dbh,
  555. "SELECT sub_system,peer_id,key,value,expiry FROM peerstoredata"
  556. " WHERE sub_system = ?"
  557. " AND peer_id = ?" " AND key = ?",
  558. &plugin->select_peerstoredata_by_all);
  559. sql_prepare (plugin->dbh,
  560. "DELETE FROM peerstoredata"
  561. " WHERE expiry < ?",
  562. &plugin->expire_peerstoredata);
  563. sql_prepare (plugin->dbh,
  564. "DELETE FROM peerstoredata"
  565. " WHERE sub_system = ?"
  566. " AND peer_id = ?" " AND key = ?",
  567. &plugin->delete_peerstoredata);
  568. return GNUNET_OK;
  569. }
  570. /**
  571. * Shutdown database connection and associate data
  572. * structures.
  573. * @param plugin the plugin context (state for this module)
  574. */
  575. static void
  576. database_shutdown (struct Plugin *plugin)
  577. {
  578. int result;
  579. sqlite3_stmt *stmt;
  580. while (NULL != (stmt = sqlite3_next_stmt (plugin->dbh,
  581. NULL)))
  582. {
  583. result = sqlite3_finalize (stmt);
  584. if (SQLITE_OK != result)
  585. LOG (GNUNET_ERROR_TYPE_WARNING,
  586. "Failed to close statement %p: %d\n",
  587. stmt,
  588. result);
  589. }
  590. if (SQLITE_OK != sqlite3_close (plugin->dbh))
  591. LOG_SQLITE (plugin,
  592. GNUNET_ERROR_TYPE_ERROR,
  593. "sqlite3_close");
  594. GNUNET_free_non_null (plugin->fn);
  595. }
  596. /**
  597. * Entry point for the plugin.
  598. *
  599. * @param cls The struct GNUNET_CONFIGURATION_Handle.
  600. * @return NULL on error, otherwise the plugin context
  601. */
  602. void *
  603. libgnunet_plugin_peerstore_sqlite_init (void *cls)
  604. {
  605. static struct Plugin plugin;
  606. const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
  607. struct GNUNET_PEERSTORE_PluginFunctions *api;
  608. if (NULL != plugin.cfg)
  609. return NULL; /* can only initialize once! */
  610. memset (&plugin,
  611. 0,
  612. sizeof(struct Plugin));
  613. plugin.cfg = cfg;
  614. if (GNUNET_OK != database_setup (&plugin))
  615. {
  616. database_shutdown (&plugin);
  617. return NULL;
  618. }
  619. api = GNUNET_new (struct GNUNET_PEERSTORE_PluginFunctions);
  620. api->cls = &plugin;
  621. api->store_record = &peerstore_sqlite_store_record;
  622. api->iterate_records = &peerstore_sqlite_iterate_records;
  623. api->expire_records = &peerstore_sqlite_expire_records;
  624. LOG (GNUNET_ERROR_TYPE_DEBUG,
  625. "Sqlite plugin is running\n");
  626. return api;
  627. }
  628. /**
  629. * Exit point from the plugin.
  630. *
  631. * @param cls The plugin context (as returned by "init")
  632. * @return Always NULL
  633. */
  634. void *
  635. libgnunet_plugin_peerstore_sqlite_done (void *cls)
  636. {
  637. struct GNUNET_PEERSTORE_PluginFunctions *api = cls;
  638. struct Plugin *plugin = api->cls;
  639. database_shutdown (plugin);
  640. plugin->cfg = NULL;
  641. GNUNET_free (api);
  642. LOG (GNUNET_ERROR_TYPE_DEBUG,
  643. "Sqlite plugin is finished\n");
  644. return NULL;
  645. }
  646. /* end of plugin_peerstore_sqlite.c */