diff options
Diffstat (limited to 'src/namestore/plugin_namestore_postgres.c')
-rw-r--r-- | src/namestore/plugin_namestore_postgres.c | 626 |
1 files changed, 0 insertions, 626 deletions
diff --git a/src/namestore/plugin_namestore_postgres.c b/src/namestore/plugin_namestore_postgres.c deleted file mode 100644 index bdbaf96b3..000000000 --- a/src/namestore/plugin_namestore_postgres.c +++ /dev/null | |||
@@ -1,626 +0,0 @@ | |||
1 | /* | ||
2 | * This file is part of GNUnet | ||
3 | * Copyright (C) 2009-2013, 2016-2018 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 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file namestore/plugin_namestore_postgres.c | ||
23 | * @brief postgres-based namestore backend | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_namestore_plugin.h" | ||
28 | #include "gnunet_namestore_service.h" | ||
29 | #include "gnunet_gnsrecord_lib.h" | ||
30 | #include "gnunet_pq_lib.h" | ||
31 | #include "namestore.h" | ||
32 | |||
33 | |||
34 | #define LOG(kind, ...) GNUNET_log_from (kind, "namestore-postgres", __VA_ARGS__) | ||
35 | |||
36 | |||
37 | /** | ||
38 | * Context for all functions in this plugin. | ||
39 | */ | ||
40 | struct Plugin | ||
41 | { | ||
42 | /** | ||
43 | * Our configuration. | ||
44 | */ | ||
45 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
46 | |||
47 | /** | ||
48 | * Postgres database handle. | ||
49 | */ | ||
50 | struct GNUNET_PQ_Context *dbh; | ||
51 | }; | ||
52 | |||
53 | |||
54 | /** | ||
55 | * Initialize the database connections and associated | ||
56 | * data structures (create tables and indices | ||
57 | * as needed as well). | ||
58 | * | ||
59 | * @param plugin the plugin context (state for this module) | ||
60 | * @return #GNUNET_OK on success | ||
61 | */ | ||
62 | static int | ||
63 | database_setup (struct Plugin *plugin) | ||
64 | { | ||
65 | struct GNUNET_PQ_ExecuteStatement es_temporary = | ||
66 | GNUNET_PQ_make_execute ( | ||
67 | "CREATE TEMPORARY TABLE IF NOT EXISTS ns098records (" | ||
68 | " seq BIGSERIAL PRIMARY KEY," | ||
69 | " zone_private_key BYTEA NOT NULL DEFAULT ''," | ||
70 | " pkey BYTEA DEFAULT ''," | ||
71 | " rvalue BYTEA NOT NULL DEFAULT ''," | ||
72 | " record_count INTEGER NOT NULL DEFAULT 0," | ||
73 | " record_data BYTEA NOT NULL DEFAULT ''," | ||
74 | " label TEXT NOT NULL DEFAULT ''," | ||
75 | " CONSTRAINT zl UNIQUE (zone_private_key,label)" | ||
76 | ")"); | ||
77 | struct GNUNET_PQ_ExecuteStatement es_default = | ||
78 | GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS ns098records (" | ||
79 | " seq BIGSERIAL PRIMARY KEY," | ||
80 | " zone_private_key BYTEA NOT NULL DEFAULT ''," | ||
81 | " pkey BYTEA DEFAULT ''," | ||
82 | " rvalue BYTEA NOT NULL DEFAULT ''," | ||
83 | " record_count INTEGER NOT NULL DEFAULT 0," | ||
84 | " record_data BYTEA NOT NULL DEFAULT ''," | ||
85 | " label TEXT NOT NULL DEFAULT ''," | ||
86 | " CONSTRAINT zl UNIQUE (zone_private_key,label)" | ||
87 | ")"); | ||
88 | const struct GNUNET_PQ_ExecuteStatement *cr; | ||
89 | struct GNUNET_PQ_ExecuteStatement sc = GNUNET_PQ_EXECUTE_STATEMENT_END; | ||
90 | |||
91 | if (GNUNET_YES == | ||
92 | GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg, | ||
93 | "namestore-postgres", | ||
94 | "TEMPORARY_TABLE")) | ||
95 | { | ||
96 | cr = &es_temporary; | ||
97 | } | ||
98 | else | ||
99 | { | ||
100 | cr = &es_default; | ||
101 | } | ||
102 | |||
103 | if (GNUNET_YES == | ||
104 | GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg, | ||
105 | "namestore-postgres", | ||
106 | "ASYNC_COMMIT")) | ||
107 | sc = GNUNET_PQ_make_try_execute ("SET synchronous_commit TO off"); | ||
108 | |||
109 | { | ||
110 | struct GNUNET_PQ_ExecuteStatement es[] = { | ||
111 | *cr, | ||
112 | GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_reverse " | ||
113 | "ON ns098records (zone_private_key,pkey)"), | ||
114 | GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_iter " | ||
115 | "ON ns098records (zone_private_key,seq)"), | ||
116 | GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_label " | ||
117 | "ON ns098records (label)"), | ||
118 | GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS zone_label " | ||
119 | "ON ns098records (zone_private_key,label)"), | ||
120 | sc, | ||
121 | GNUNET_PQ_EXECUTE_STATEMENT_END | ||
122 | }; | ||
123 | struct GNUNET_PQ_PreparedStatement ps[] = { | ||
124 | GNUNET_PQ_make_prepare ("store_records", | ||
125 | "INSERT INTO ns098records" | ||
126 | " (zone_private_key, pkey, rvalue, record_count, record_data, label)" | ||
127 | " VALUES ($1, $2, $3, $4, $5, $6)" | ||
128 | " ON CONFLICT ON CONSTRAINT zl" | ||
129 | " DO UPDATE" | ||
130 | " SET pkey=$2,rvalue=$3,record_count=$4,record_data=$5" | ||
131 | " WHERE ns098records.zone_private_key = $1" | ||
132 | " AND ns098records.label = $6", | ||
133 | 6), | ||
134 | GNUNET_PQ_make_prepare ("delete_records", | ||
135 | "DELETE FROM ns098records " | ||
136 | "WHERE zone_private_key=$1 AND label=$2", | ||
137 | 2), | ||
138 | GNUNET_PQ_make_prepare ("zone_to_name", | ||
139 | "SELECT seq,record_count,record_data,label FROM ns098records" | ||
140 | " WHERE zone_private_key=$1 AND pkey=$2", | ||
141 | 2), | ||
142 | GNUNET_PQ_make_prepare ("iterate_zone", | ||
143 | "SELECT seq,record_count,record_data,label FROM ns098records " | ||
144 | "WHERE zone_private_key=$1 AND seq > $2 ORDER BY seq ASC LIMIT $3", | ||
145 | 3), | ||
146 | GNUNET_PQ_make_prepare ("iterate_all_zones", | ||
147 | "SELECT seq,record_count,record_data,label,zone_private_key" | ||
148 | " FROM ns098records WHERE seq > $1 ORDER BY seq ASC LIMIT $2", | ||
149 | 2), | ||
150 | GNUNET_PQ_make_prepare ("lookup_label", | ||
151 | "SELECT seq,record_count,record_data,label " | ||
152 | "FROM ns098records WHERE zone_private_key=$1 AND label=$2", | ||
153 | 2), | ||
154 | GNUNET_PQ_PREPARED_STATEMENT_END | ||
155 | }; | ||
156 | |||
157 | plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg, | ||
158 | "namestore-postgres", | ||
159 | NULL, | ||
160 | es, | ||
161 | ps); | ||
162 | } | ||
163 | if (NULL == plugin->dbh) | ||
164 | return GNUNET_SYSERR; | ||
165 | return GNUNET_OK; | ||
166 | } | ||
167 | |||
168 | |||
169 | /** | ||
170 | * Store a record in the datastore. Removes any existing record in the | ||
171 | * same zone with the same name. | ||
172 | * | ||
173 | * @param cls closure (internal context for the plugin) | ||
174 | * @param zone_key private key of the zone | ||
175 | * @param label name that is being mapped (at most 255 characters long) | ||
176 | * @param rd_count number of entries in @a rd array | ||
177 | * @param rd array of records with data to store | ||
178 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
179 | */ | ||
180 | static int | ||
181 | namestore_postgres_store_records (void *cls, | ||
182 | const struct | ||
183 | GNUNET_IDENTITY_PrivateKey *zone_key, | ||
184 | const char *label, | ||
185 | unsigned int rd_count, | ||
186 | const struct GNUNET_GNSRECORD_Data *rd) | ||
187 | { | ||
188 | struct Plugin *plugin = cls; | ||
189 | struct GNUNET_IDENTITY_PublicKey pkey; | ||
190 | uint64_t rvalue; | ||
191 | uint32_t rd_count32 = (uint32_t) rd_count; | ||
192 | ssize_t data_size; | ||
193 | |||
194 | memset (&pkey, | ||
195 | 0, | ||
196 | sizeof(pkey)); | ||
197 | for (unsigned int i = 0; i < rd_count; i++) | ||
198 | if (GNUNET_YES == | ||
199 | GNUNET_GNSRECORD_is_zonekey_type (rd[i].record_type)) | ||
200 | { | ||
201 | GNUNET_break (GNUNET_OK == | ||
202 | GNUNET_GNSRECORD_identity_from_data (rd[i].data, | ||
203 | rd[i].data_size, | ||
204 | rd[i].record_type, | ||
205 | &pkey)); | ||
206 | break; | ||
207 | } | ||
208 | rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
209 | UINT64_MAX); | ||
210 | data_size = GNUNET_GNSRECORD_records_get_size (rd_count, | ||
211 | rd); | ||
212 | if (data_size < 0) | ||
213 | { | ||
214 | GNUNET_break (0); | ||
215 | return GNUNET_SYSERR; | ||
216 | } | ||
217 | if (data_size >= UINT16_MAX) | ||
218 | { | ||
219 | GNUNET_break (0); | ||
220 | return GNUNET_SYSERR; | ||
221 | } | ||
222 | /* if record set is empty, delete existing records */ | ||
223 | if (0 == rd_count) | ||
224 | { | ||
225 | struct GNUNET_PQ_QueryParam params[] = { | ||
226 | GNUNET_PQ_query_param_auto_from_type (zone_key), | ||
227 | GNUNET_PQ_query_param_string (label), | ||
228 | GNUNET_PQ_query_param_end | ||
229 | }; | ||
230 | enum GNUNET_DB_QueryStatus res; | ||
231 | |||
232 | res = GNUNET_PQ_eval_prepared_non_select (plugin->dbh, | ||
233 | "delete_records", | ||
234 | params); | ||
235 | if ((GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != res) && | ||
236 | (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != res)) | ||
237 | { | ||
238 | GNUNET_break (0); | ||
239 | return GNUNET_SYSERR; | ||
240 | } | ||
241 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
242 | "postgres", | ||
243 | "Record deleted\n"); | ||
244 | return GNUNET_OK; | ||
245 | } | ||
246 | /* otherwise, UPSERT (i.e. UPDATE if exists, otherwise INSERT) */ | ||
247 | { | ||
248 | char data[data_size]; | ||
249 | struct GNUNET_PQ_QueryParam params[] = { | ||
250 | GNUNET_PQ_query_param_auto_from_type (zone_key), | ||
251 | GNUNET_PQ_query_param_auto_from_type (&pkey), | ||
252 | GNUNET_PQ_query_param_uint64 (&rvalue), | ||
253 | GNUNET_PQ_query_param_uint32 (&rd_count32), | ||
254 | GNUNET_PQ_query_param_fixed_size (data, data_size), | ||
255 | GNUNET_PQ_query_param_string (label), | ||
256 | GNUNET_PQ_query_param_end | ||
257 | }; | ||
258 | enum GNUNET_DB_QueryStatus res; | ||
259 | ssize_t ret; | ||
260 | |||
261 | ret = GNUNET_GNSRECORD_records_serialize (rd_count, | ||
262 | rd, | ||
263 | data_size, | ||
264 | data); | ||
265 | if ((ret < 0) || | ||
266 | (data_size != ret)) | ||
267 | { | ||
268 | GNUNET_break (0); | ||
269 | return GNUNET_SYSERR; | ||
270 | } | ||
271 | |||
272 | res = GNUNET_PQ_eval_prepared_non_select (plugin->dbh, | ||
273 | "store_records", | ||
274 | params); | ||
275 | if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != res) | ||
276 | return GNUNET_SYSERR; | ||
277 | } | ||
278 | return GNUNET_OK; | ||
279 | } | ||
280 | |||
281 | |||
282 | /** | ||
283 | * Closure for #parse_result_call_iterator. | ||
284 | */ | ||
285 | struct ParserContext | ||
286 | { | ||
287 | /** | ||
288 | * Function to call for each result. | ||
289 | */ | ||
290 | GNUNET_NAMESTORE_RecordIterator iter; | ||
291 | |||
292 | /** | ||
293 | * Closure for @e iter. | ||
294 | */ | ||
295 | void *iter_cls; | ||
296 | |||
297 | /** | ||
298 | * Zone key, NULL if part of record. | ||
299 | */ | ||
300 | const struct GNUNET_IDENTITY_PrivateKey *zone_key; | ||
301 | |||
302 | /** | ||
303 | * Number of results still to return (counted down by | ||
304 | * number of results given to iterator). | ||
305 | */ | ||
306 | uint64_t limit; | ||
307 | }; | ||
308 | |||
309 | |||
310 | /** | ||
311 | * A statement has been run. We should evaluate the result, and if possible | ||
312 | * call the @a iter in @a cls with the result. | ||
313 | * | ||
314 | * @param cls closure of type `struct ParserContext *` | ||
315 | * @param result the postgres result | ||
316 | * @param num_result the number of results in @a result | ||
317 | */ | ||
318 | static void | ||
319 | parse_result_call_iterator (void *cls, | ||
320 | PGresult *res, | ||
321 | unsigned int num_results) | ||
322 | { | ||
323 | struct ParserContext *pc = cls; | ||
324 | |||
325 | if (NULL == pc->iter) | ||
326 | return; /* no need to do more work */ | ||
327 | for (unsigned int i = 0; i < num_results; i++) | ||
328 | { | ||
329 | uint64_t serial; | ||
330 | void *data; | ||
331 | size_t data_size; | ||
332 | uint32_t record_count; | ||
333 | char *label; | ||
334 | struct GNUNET_IDENTITY_PrivateKey zk; | ||
335 | struct GNUNET_PQ_ResultSpec rs_with_zone[] = { | ||
336 | GNUNET_PQ_result_spec_uint64 ("seq", &serial), | ||
337 | GNUNET_PQ_result_spec_uint32 ("record_count", &record_count), | ||
338 | GNUNET_PQ_result_spec_variable_size ("record_data", &data, &data_size), | ||
339 | GNUNET_PQ_result_spec_string ("label", &label), | ||
340 | GNUNET_PQ_result_spec_auto_from_type ("zone_private_key", &zk), | ||
341 | GNUNET_PQ_result_spec_end | ||
342 | }; | ||
343 | struct GNUNET_PQ_ResultSpec rs_without_zone[] = { | ||
344 | GNUNET_PQ_result_spec_uint64 ("seq", &serial), | ||
345 | GNUNET_PQ_result_spec_uint32 ("record_count", &record_count), | ||
346 | GNUNET_PQ_result_spec_variable_size ("record_data", &data, &data_size), | ||
347 | GNUNET_PQ_result_spec_string ("label", &label), | ||
348 | GNUNET_PQ_result_spec_end | ||
349 | }; | ||
350 | struct GNUNET_PQ_ResultSpec *rs; | ||
351 | |||
352 | rs = (NULL == pc->zone_key) ? rs_with_zone : rs_without_zone; | ||
353 | if (GNUNET_YES != | ||
354 | GNUNET_PQ_extract_result (res, | ||
355 | rs, | ||
356 | i)) | ||
357 | { | ||
358 | GNUNET_break (0); | ||
359 | return; | ||
360 | } | ||
361 | |||
362 | if (record_count > 64 * 1024) | ||
363 | { | ||
364 | /* sanity check, don't stack allocate far too much just | ||
365 | because database might contain a large value here */ | ||
366 | GNUNET_break (0); | ||
367 | GNUNET_PQ_cleanup_result (rs); | ||
368 | return; | ||
369 | } | ||
370 | |||
371 | { | ||
372 | struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (record_count)]; | ||
373 | |||
374 | GNUNET_assert (0 != serial); | ||
375 | if (GNUNET_OK != | ||
376 | GNUNET_GNSRECORD_records_deserialize (data_size, | ||
377 | data, | ||
378 | record_count, | ||
379 | rd)) | ||
380 | { | ||
381 | GNUNET_break (0); | ||
382 | GNUNET_PQ_cleanup_result (rs); | ||
383 | return; | ||
384 | } | ||
385 | pc->iter (pc->iter_cls, | ||
386 | serial, | ||
387 | (NULL == pc->zone_key) ? &zk : pc->zone_key, | ||
388 | label, | ||
389 | record_count, | ||
390 | rd); | ||
391 | } | ||
392 | GNUNET_PQ_cleanup_result (rs); | ||
393 | } | ||
394 | pc->limit -= num_results; | ||
395 | } | ||
396 | |||
397 | |||
398 | /** | ||
399 | * Lookup records in the datastore for which we are the authority. | ||
400 | * | ||
401 | * @param cls closure (internal context for the plugin) | ||
402 | * @param zone private key of the zone | ||
403 | * @param label name of the record in the zone | ||
404 | * @param iter function to call with the result | ||
405 | * @param iter_cls closure for @a iter | ||
406 | * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR | ||
407 | */ | ||
408 | static int | ||
409 | namestore_postgres_lookup_records (void *cls, | ||
410 | const struct | ||
411 | GNUNET_IDENTITY_PrivateKey *zone, | ||
412 | const char *label, | ||
413 | GNUNET_NAMESTORE_RecordIterator iter, | ||
414 | void *iter_cls) | ||
415 | { | ||
416 | struct Plugin *plugin = cls; | ||
417 | struct GNUNET_PQ_QueryParam params[] = { | ||
418 | GNUNET_PQ_query_param_auto_from_type (zone), | ||
419 | GNUNET_PQ_query_param_string (label), | ||
420 | GNUNET_PQ_query_param_end | ||
421 | }; | ||
422 | struct ParserContext pc; | ||
423 | enum GNUNET_DB_QueryStatus res; | ||
424 | |||
425 | if (NULL == zone) | ||
426 | { | ||
427 | GNUNET_break (0); | ||
428 | return GNUNET_SYSERR; | ||
429 | } | ||
430 | pc.iter = iter; | ||
431 | pc.iter_cls = iter_cls; | ||
432 | pc.zone_key = zone; | ||
433 | res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh, | ||
434 | "lookup_label", | ||
435 | params, | ||
436 | &parse_result_call_iterator, | ||
437 | &pc); | ||
438 | if (res < 0) | ||
439 | return GNUNET_SYSERR; | ||
440 | if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == res) | ||
441 | return GNUNET_NO; | ||
442 | return GNUNET_OK; | ||
443 | } | ||
444 | |||
445 | |||
446 | /** | ||
447 | * Iterate over the results for a particular key and zone in the | ||
448 | * datastore. Will return at most one result to the iterator. | ||
449 | * | ||
450 | * @param cls closure (internal context for the plugin) | ||
451 | * @param zone hash of public key of the zone, NULL to iterate over all zones | ||
452 | * @param serial serial number to exclude in the list of all matching records | ||
453 | * @param limit maximum number of results to fetch | ||
454 | * @param iter function to call with the result | ||
455 | * @param iter_cls closure for @a iter | ||
456 | * @return #GNUNET_OK on success, #GNUNET_NO if there were no more results, #GNUNET_SYSERR on error | ||
457 | */ | ||
458 | static int | ||
459 | namestore_postgres_iterate_records (void *cls, | ||
460 | const struct | ||
461 | GNUNET_IDENTITY_PrivateKey *zone, | ||
462 | uint64_t serial, | ||
463 | uint64_t limit, | ||
464 | GNUNET_NAMESTORE_RecordIterator iter, | ||
465 | void *iter_cls) | ||
466 | { | ||
467 | struct Plugin *plugin = cls; | ||
468 | enum GNUNET_DB_QueryStatus res; | ||
469 | struct ParserContext pc; | ||
470 | |||
471 | pc.iter = iter; | ||
472 | pc.iter_cls = iter_cls; | ||
473 | pc.zone_key = zone; | ||
474 | pc.limit = limit; | ||
475 | if (NULL == zone) | ||
476 | { | ||
477 | struct GNUNET_PQ_QueryParam params_without_zone[] = { | ||
478 | GNUNET_PQ_query_param_uint64 (&serial), | ||
479 | GNUNET_PQ_query_param_uint64 (&limit), | ||
480 | GNUNET_PQ_query_param_end | ||
481 | }; | ||
482 | |||
483 | res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh, | ||
484 | "iterate_all_zones", | ||
485 | params_without_zone, | ||
486 | &parse_result_call_iterator, | ||
487 | &pc); | ||
488 | } | ||
489 | else | ||
490 | { | ||
491 | struct GNUNET_PQ_QueryParam params_with_zone[] = { | ||
492 | GNUNET_PQ_query_param_auto_from_type (zone), | ||
493 | GNUNET_PQ_query_param_uint64 (&serial), | ||
494 | GNUNET_PQ_query_param_uint64 (&limit), | ||
495 | GNUNET_PQ_query_param_end | ||
496 | }; | ||
497 | |||
498 | res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh, | ||
499 | "iterate_zone", | ||
500 | params_with_zone, | ||
501 | &parse_result_call_iterator, | ||
502 | &pc); | ||
503 | } | ||
504 | if (res < 0) | ||
505 | return GNUNET_SYSERR; | ||
506 | |||
507 | if ((GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == res) || | ||
508 | (pc.limit > 0)) | ||
509 | return GNUNET_NO; | ||
510 | return GNUNET_OK; | ||
511 | } | ||
512 | |||
513 | |||
514 | /** | ||
515 | * Look for an existing PKEY delegation record for a given public key. | ||
516 | * Returns at most one result to the iterator. | ||
517 | * | ||
518 | * @param cls closure (internal context for the plugin) | ||
519 | * @param zone private key of the zone to look up in, never NULL | ||
520 | * @param value_zone public key of the target zone (value), never NULL | ||
521 | * @param iter function to call with the result | ||
522 | * @param iter_cls closure for @a iter | ||
523 | * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error | ||
524 | */ | ||
525 | static int | ||
526 | namestore_postgres_zone_to_name (void *cls, | ||
527 | const struct | ||
528 | GNUNET_IDENTITY_PrivateKey *zone, | ||
529 | const struct | ||
530 | GNUNET_IDENTITY_PublicKey *value_zone, | ||
531 | GNUNET_NAMESTORE_RecordIterator iter, | ||
532 | void *iter_cls) | ||
533 | { | ||
534 | struct Plugin *plugin = cls; | ||
535 | struct GNUNET_PQ_QueryParam params[] = { | ||
536 | GNUNET_PQ_query_param_auto_from_type (zone), | ||
537 | GNUNET_PQ_query_param_auto_from_type (value_zone), | ||
538 | GNUNET_PQ_query_param_end | ||
539 | }; | ||
540 | enum GNUNET_DB_QueryStatus res; | ||
541 | struct ParserContext pc; | ||
542 | |||
543 | pc.iter = iter; | ||
544 | pc.iter_cls = iter_cls; | ||
545 | pc.zone_key = zone; | ||
546 | res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh, | ||
547 | "zone_to_name", | ||
548 | params, | ||
549 | &parse_result_call_iterator, | ||
550 | &pc); | ||
551 | if (res < 0) | ||
552 | return GNUNET_SYSERR; | ||
553 | return GNUNET_OK; | ||
554 | } | ||
555 | |||
556 | |||
557 | /** | ||
558 | * Shutdown database connection and associate data | ||
559 | * structures. | ||
560 | * | ||
561 | * @param plugin the plugin context (state for this module) | ||
562 | */ | ||
563 | static void | ||
564 | database_shutdown (struct Plugin *plugin) | ||
565 | { | ||
566 | GNUNET_PQ_disconnect (plugin->dbh); | ||
567 | plugin->dbh = NULL; | ||
568 | } | ||
569 | |||
570 | |||
571 | /** | ||
572 | * Entry point for the plugin. | ||
573 | * | ||
574 | * @param cls the `struct GNUNET_NAMESTORE_PluginEnvironment*` | ||
575 | * @return NULL on error, othrewise the plugin context | ||
576 | */ | ||
577 | void * | ||
578 | libgnunet_plugin_namestore_postgres_init (void *cls) | ||
579 | { | ||
580 | static struct Plugin plugin; | ||
581 | const struct GNUNET_CONFIGURATION_Handle *cfg = cls; | ||
582 | struct GNUNET_NAMESTORE_PluginFunctions *api; | ||
583 | |||
584 | if (NULL != plugin.cfg) | ||
585 | return NULL; /* can only initialize once! */ | ||
586 | memset (&plugin, 0, sizeof(struct Plugin)); | ||
587 | plugin.cfg = cfg; | ||
588 | if (GNUNET_OK != database_setup (&plugin)) | ||
589 | { | ||
590 | database_shutdown (&plugin); | ||
591 | return NULL; | ||
592 | } | ||
593 | api = GNUNET_new (struct GNUNET_NAMESTORE_PluginFunctions); | ||
594 | api->cls = &plugin; | ||
595 | api->store_records = &namestore_postgres_store_records; | ||
596 | api->iterate_records = &namestore_postgres_iterate_records; | ||
597 | api->zone_to_name = &namestore_postgres_zone_to_name; | ||
598 | api->lookup_records = &namestore_postgres_lookup_records; | ||
599 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
600 | "Postgres namestore plugin running\n"); | ||
601 | return api; | ||
602 | } | ||
603 | |||
604 | |||
605 | /** | ||
606 | * Exit point from the plugin. | ||
607 | * | ||
608 | * @param cls the plugin context (as returned by "init") | ||
609 | * @return always NULL | ||
610 | */ | ||
611 | void * | ||
612 | libgnunet_plugin_namestore_postgres_done (void *cls) | ||
613 | { | ||
614 | struct GNUNET_NAMESTORE_PluginFunctions *api = cls; | ||
615 | struct Plugin *plugin = api->cls; | ||
616 | |||
617 | database_shutdown (plugin); | ||
618 | plugin->cfg = NULL; | ||
619 | GNUNET_free (api); | ||
620 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
621 | "Postgres namestore plugin is finished\n"); | ||
622 | return NULL; | ||
623 | } | ||
624 | |||
625 | |||
626 | /* end of plugin_namestore_postgres.c */ | ||