aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2012-06-11 21:02:30 +0000
committerChristian Grothoff <christian@grothoff.org>2012-06-11 21:02:30 +0000
commit589448a17afcc95ef157678d4e1b2eba0f0c9d7a (patch)
treed9e6c3802d6203680b7b956a60aa0c19dc50a9ff /src
parentd63b9b5f38df2300777e7983af7b0ae210fce626 (diff)
downloadgnunet-589448a17afcc95ef157678d4e1b2eba0f0c9d7a.tar.gz
gnunet-589448a17afcc95ef157678d4e1b2eba0f0c9d7a.zip
-first draft of postgres namestore plugin (#2157)
Diffstat (limited to 'src')
-rw-r--r--src/namestore/Makefile.am34
-rw-r--r--src/namestore/plugin_namestore_postgres.c654
-rw-r--r--src/namestore/plugin_namestore_sqlite.c8
3 files changed, 689 insertions, 7 deletions
diff --git a/src/namestore/Makefile.am b/src/namestore/Makefile.am
index aea857d74..2106ccf76 100644
--- a/src/namestore/Makefile.am
+++ b/src/namestore/Makefile.am
@@ -18,13 +18,18 @@ if USE_COVERAGE
18endif 18endif
19 19
20if HAVE_SQLITE 20if HAVE_SQLITE
21SQLITE_TESTS = \ 21SQLITE_PLUGIN = libgnunet_plugin_namestore_sqlite.la
22 test_plugin_namestore_sqlite 22SQLITE_TESTS = test_plugin_namestore_sqlite
23endif
24if HAVE_POSTGRES
25POSTGRES_TESTS = test_plugin_namestore_postgres
26POSTGRES_PLUGIN = libgnunet_plugin_namestore_postgres.la
23endif 27endif
24 28
25 29
26check_PROGRAMS = \ 30check_PROGRAMS = \
27 $(SQLITE_TESTS) \ 31 $(SQLITE_TESTS) \
32 $(POSTGRES_TESTS) \
28 test_namestore_record_serialization \ 33 test_namestore_record_serialization \
29 test_namestore_api_sign_verify \ 34 test_namestore_api_sign_verify \
30 test_namestore_api \ 35 test_namestore_api \
@@ -87,12 +92,10 @@ gnunet_service_namestore_DEPENDENCIES = \
87 $(top_builddir)/src/util/libgnunetutil.la \ 92 $(top_builddir)/src/util/libgnunetutil.la \
88 libgnunetnamestore.la 93 libgnunetnamestore.la
89 94
90if HAVE_SQLITE
91 SQLITE_PLUGIN = libgnunet_plugin_namestore_sqlite.la
92endif
93 95
94plugin_LTLIBRARIES = \ 96plugin_LTLIBRARIES = \
95 $(SQLITE_PLUGIN) 97 $(SQLITE_PLUGIN) \
98 $(POSTGRES_PLUGIN)
96 99
97libgnunet_plugin_namestore_sqlite_la_SOURCES = \ 100libgnunet_plugin_namestore_sqlite_la_SOURCES = \
98 plugin_namestore_sqlite.c namestore_common.c 101 plugin_namestore_sqlite.c namestore_common.c
@@ -104,6 +107,25 @@ libgnunet_plugin_namestore_sqlite_la_LIBADD = \
104libgnunet_plugin_namestore_sqlite_la_LDFLAGS = \ 107libgnunet_plugin_namestore_sqlite_la_LDFLAGS = \
105 $(GN_PLUGIN_LDFLAGS) 108 $(GN_PLUGIN_LDFLAGS)
106libgnunet_plugin_namestore_sqlite_la_DEPENDENCIES = \ 109libgnunet_plugin_namestore_sqlite_la_DEPENDENCIES = \
110 $(top_builddir)/src/namestore/libgnunetnamestore.la \
111 $(top_builddir)/src/statistics/libgnunetstatistics.la \
112 $(top_builddir)/src/util/libgnunetutil.la \
113 libgnunetnamestore.la
114
115
116libgnunet_plugin_namestore_postgres_la_SOURCES = \
117 plugin_namestore_postgres.c namestore_common.c
118libgnunet_plugin_namestore_postgres_la_LIBADD = \
119 $(top_builddir)/src/namestore/libgnunetnamestore.la \
120 $(top_builddir)/src/postgres/libgnunetpostgres.la \
121 $(top_builddir)/src/statistics/libgnunetstatistics.la \
122 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq \
123 $(LTLIBINTL)
124libgnunet_plugin_namestore_postgres_la_LDFLAGS = \
125 $(GN_PLUGIN_LDFLAGS)
126libgnunet_plugin_namestore_postgres_la_DEPENDENCIES = \
127 $(top_builddir)/src/namestore/libgnunetnamestore.la \
128 $(top_builddir)/src/postgres/libgnunetpostgres.la \
107 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 129 $(top_builddir)/src/statistics/libgnunetstatistics.la \
108 $(top_builddir)/src/util/libgnunetutil.la \ 130 $(top_builddir)/src/util/libgnunetutil.la \
109 libgnunetnamestore.la 131 libgnunetnamestore.la
diff --git a/src/namestore/plugin_namestore_postgres.c b/src/namestore/plugin_namestore_postgres.c
new file mode 100644
index 000000000..a60ed8c0a
--- /dev/null
+++ b/src/namestore/plugin_namestore_postgres.c
@@ -0,0 +1,654 @@
1 /*
2 * This file is part of GNUnet
3 * (C) 2009, 2011, 2012 Christian Grothoff (and other contributing authors)
4 *
5 * GNUnet is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published
7 * by the Free Software Foundation; either version 3, or (at your
8 * 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 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GNUnet; see the file COPYING. If not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 */
20
21/**
22 * @file namestore/plugin_namestore_postgres.c
23 * @brief postgres-based namestore backend
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_namestore_plugin.h"
29#include "gnunet_namestore_service.h"
30#include "gnunet_postgres_lib.h"
31#include "namestore.h"
32
33
34/**
35 * After how many ms "busy" should a DB operation fail for good?
36 * A low value makes sure that we are more responsive to requests
37 * (especially PUTs). A high value guarantees a higher success
38 * rate (SELECTs in iterate can take several seconds despite LIMIT=1).
39 *
40 * The default value of 1s should ensure that users do not experience
41 * huge latencies while at the same time allowing operations to succeed
42 * with reasonable probability.
43 */
44#define BUSY_TIMEOUT_MS 1000
45
46
47/**
48 * Log an error message at log-level 'level' that indicates
49 * a failure of the command 'cmd' on file 'filename'
50 * with the message given by strerror(errno).
51 */
52#define LOG_POSTGRES(db, level, cmd) do { GNUNET_log_from (level, "namestore-postgres", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); } while(0)
53
54#define LOG(kind,...) GNUNET_log_from (kind, "namestore-postgres", __VA_ARGS__)
55
56
57/**
58 * Context for all functions in this plugin.
59 */
60struct Plugin
61{
62
63 const struct GNUNET_CONFIGURATION_Handle *cfg;
64
65 /**
66 * Native Postgres database handle.
67 */
68 PGconn *dbh;
69
70};
71
72
73/**
74 * Create our database indices.
75 *
76 * @param dbh handle to the database
77 */
78static void
79create_indices (PGconn * dbh)
80{
81 /* create indices */
82 if ( (GNUNET_OK !=
83 GNUNET_POSTGRES_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_zone_name_rv ON ns091records (zone_hash,record_name_hash,rvalue)")) ||
84 (GNUNET_OK !=
85 GNUNET_POSTGRES_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_zone_delegation ON ns091records (zone_hash,zone_delegation)")) ||
86 (GNUNET_OK !=
87 GNUNET_POSTGRES_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_zone_rv ON ns091records (zone_hash,rvalue)")) ||
88 (GNUNET_OK !=
89 GNUNET_POSTGRES_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_zone ON ns091records (zone_hash)")) ||
90 (GNUNET_OK !=
91 GNUNET_POSTGRES_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_name_rv ON ns091records (record_name_hash,rvalue)")) ||
92 (GNUNET_OK !=
93 GNUNET_POSTGRES_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_rv ON ns091records (rvalue)")) )
94 LOG (GNUNET_ERROR_TYPE_ERROR,
95 _("Failed to create indices\n"));
96}
97
98
99/**
100 * Initialize the database connections and associated
101 * data structures (create tables and indices
102 * as needed as well).
103 *
104 * @param plugin the plugin context (state for this module)
105 * @return GNUNET_OK on success
106 */
107static int
108database_setup (struct Plugin *plugin)
109{
110 PGresult *res;
111
112 plugin->dbh = GNUNET_POSTGRES_connect (plugin->cfg,
113 "namestore-postgres");
114 if (NULL == plugin->dbh)
115 return GNUNET_SYSERR;
116 res =
117 PQexec (plugin->dbh,
118 "CREATE TABLE ns091records ("
119 " zone_key BLOB NOT NULL DEFAULT '',"
120 " zone_delegation BLOB NOT NULL DEFAULT '',"
121 " zone_hash BLOB NOT NULL DEFAULT '',"
122 " record_count INT NOT NULL DEFAULT 0,"
123 " record_data BLOB NOT NULL DEFAULT '',"
124 " block_expiration_time INT8 NOT NULL DEFAULT 0,"
125 " signature BLOB NOT NULL DEFAULT '',"
126 " record_name TEXT NOT NULL DEFAULT '',"
127 " record_name_hash BLOB NOT NULL DEFAULT '',"
128 " rvalue INT8 NOT NULL DEFAULT ''"
129 ")" "WITH OIDS");
130 if ((NULL == res) || ((PQresultStatus (res) != PGRES_COMMAND_OK) && (0 != strcmp ("42P07", /* duplicate table */
131 PQresultErrorField
132 (res,
133 PG_DIAG_SQLSTATE)))))
134 {
135 (void) GNUNET_POSTGRES_check_result (plugin->dbh, res, PGRES_COMMAND_OK, "CREATE TABLE",
136 "ns091records");
137 PQfinish (plugin->dbh);
138 plugin->dbh = NULL;
139 return GNUNET_SYSERR;
140 }
141 if (PQresultStatus (res) == PGRES_COMMAND_OK)
142 create_indices (plugin->dbh);
143 PQclear (res);
144
145#define ALL "zone_key, record_name, record_count, record_data, block_expiration_time, signature"
146 if ((GNUNET_OK !=
147 GNUNET_POSTGRES_prepare (plugin->dbh,
148 "put_records",
149 "INSERT INTO ns091records (" ALL
150 ", zone_delegation, zone_hash, record_name_hash, rvalue) VALUES "
151 "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", 10)) ||
152 (GNUNET_OK !=
153 GNUNET_POSTGRES_prepare (plugin->dbh,
154 "remove_records",
155 "DELETE FROM ns091records WHERE zone_hash=$1 AND record_name_hash=$2", 2)) ||
156 (GNUNET_OK !=
157 GNUNET_POSTGRES_prepare (plugin->dbh,
158 "iterate_records",
159 "SELECT " ALL
160 " FROM ns091records WHERE zone_hash=$1 AND record_name_hash=$2 ORDER BY rvalue LIMIT 1 OFFSET $3", 3)) ||
161 (GNUNET_OK !=
162 GNUNET_POSTGRES_prepare (plugin->dbh,
163 "iterate_by_zone",
164 "SELECT " ALL
165 " FROM ns091records WHERE zone_hash=$1 ORDER BY rvalue LIMIT 1 OFFSET $2", 2)) ||
166 (GNUNET_OK !=
167 GNUNET_POSTGRES_prepare (plugin->dbh,
168 "iterate_by_name",
169 "SELECT " ALL
170 " FROM ns091records WHERE record_name_hash=$1 ORDER BY rvalue LIMIT 1 OFFSET $2", 2)) ||
171 (GNUNET_OK !=
172 GNUNET_POSTGRES_prepare (plugin->dbh,
173 "iterate_all",
174 "SELECT " ALL
175 " FROM ns091records ORDER BY rvalue LIMIT 1 OFFSET $1", 1)) ||
176 (GNUNET_OK !=
177 GNUNET_POSTGRES_prepare (plugin->dbh,
178 "zone_to_name",
179 "SELECT " ALL
180 " FROM ns091records WHERE zone_hash=$1 AND zone_delegation=$2", 2)) ||
181 (GNUNET_OK !=
182 GNUNET_POSTGRES_prepare (plugin->dbh,
183 "delete_zone",
184 "DELETE FROM ns091records WHERE zone_hash=$1", 1)))
185 {
186 PQfinish (plugin->dbh);
187 plugin->dbh = NULL;
188 return GNUNET_SYSERR;
189 }
190#undef ALL
191 return GNUNET_OK;
192}
193
194
195/**
196 * Removes any existing record in the given zone with the same name.
197 *
198 * @param cls closure (internal context for the plugin)
199 * @param zone hash of the public key of the zone
200 * @param name name to remove (at most 255 characters long)
201 * @return GNUNET_OK on success
202 */
203static int
204namestore_postgres_remove_records (void *cls,
205 const struct GNUNET_CRYPTO_ShortHashCode *zone,
206 const char *name)
207{
208 struct Plugin *plugin = cls;
209 PGresult *ret;
210 struct GNUNET_CRYPTO_ShortHashCode nh;
211 const char *paramValues[] = {
212 (const char *) zone,
213 (const char *) &nh
214 };
215 int paramLengths[] = {
216 sizeof (struct GNUNET_CRYPTO_ShortHashCode),
217 sizeof (struct GNUNET_CRYPTO_ShortHashCode)
218 };
219 const int paramFormats[] = { 1, 1 };
220 size_t name_len;
221
222 name_len = strlen (name);
223 GNUNET_CRYPTO_short_hash (name, name_len, &nh);
224 ret =
225 PQexecPrepared (plugin->dbh, "remove_records", 2, paramValues, paramLengths,
226 paramFormats, 1);
227 if (GNUNET_OK !=
228 GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_COMMAND_OK, "PQexecPrepared", "put"))
229 return GNUNET_SYSERR;
230 PQclear (ret);
231 return GNUNET_OK;
232}
233
234
235/**
236 * Store a record in the datastore. Removes any existing record in the
237 * same zone with the same name.
238 *
239 * @param cls closure (internal context for the plugin)
240 * @param zone_key public key of the zone
241 * @param expire when does the corresponding block in the DHT expire (until
242 * when should we never do a DHT lookup for the same name again)?
243 * @param name name that is being mapped (at most 255 characters long)
244 * @param rd_count number of entries in 'rd' array
245 * @param rd array of records with data to store
246 * @param signature signature of the record block, NULL if signature is unavailable (i.e.
247 * because the user queried for a particular record type only)
248 * @return GNUNET_OK on success, else GNUNET_SYSERR
249 */
250static int
251namestore_postgres_put_records (void *cls,
252 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
253 struct GNUNET_TIME_Absolute expire,
254 const char *name,
255 unsigned int rd_count,
256 const struct GNUNET_NAMESTORE_RecordData *rd,
257 const struct GNUNET_CRYPTO_RsaSignature *signature)
258{
259 struct Plugin *plugin = cls;
260 PGresult *ret;
261 struct GNUNET_CRYPTO_ShortHashCode zone;
262 struct GNUNET_CRYPTO_ShortHashCode zone_delegation;
263 struct GNUNET_CRYPTO_ShortHashCode nh;
264 size_t name_len;
265 uint64_t rvalue;
266 size_t data_size;
267 unsigned int i;
268
269 GNUNET_CRYPTO_short_hash (zone_key,
270 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
271 &zone);
272 (void) namestore_postgres_remove_records (plugin, &zone, name);
273 name_len = strlen (name);
274 GNUNET_CRYPTO_short_hash (name, name_len, &nh);
275 memset (&zone_delegation, 0, sizeof (zone_delegation));
276 for (i=0;i<rd_count;i++)
277 if (rd[i].record_type == GNUNET_NAMESTORE_TYPE_PKEY)
278 {
279 GNUNET_assert (sizeof (struct GNUNET_CRYPTO_ShortHashCode) == rd[i].data_size);
280 memcpy (&zone_delegation,
281 rd[i].data,
282 sizeof (struct GNUNET_CRYPTO_ShortHashCode));
283 break;
284 }
285 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
286 data_size = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
287 if (data_size > 64 * 65536)
288 {
289 GNUNET_break (0);
290 return GNUNET_SYSERR;
291 }
292 {
293 char data[data_size];
294 uint64_t expire_be = GNUNET_htonll (expire.abs_value);
295 uint64_t rvalue_be = GNUNET_htonll (rvalue);
296 uint32_t rd_count_be = htonl ((uint32_t) rd_count);
297 const char *paramValues[] = {
298 (const char *) zone_key,
299 (const char *) name,
300 (const char *) &rd_count_be,
301 (const char *) data,
302 (const char *) &expire_be,
303 (const char *) signature,
304 (const char *) &zone_delegation,
305 (const char *) &zone,
306 (const char *) &nh,
307 (const char *) &rvalue_be
308 };
309 int paramLengths[] = {
310 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
311 name_len + 1,
312 sizeof (uint32_t),
313 data_size,
314 sizeof (uint64_t),
315 sizeof (struct GNUNET_CRYPTO_RsaSignature),
316 sizeof (struct GNUNET_CRYPTO_ShortHashCode),
317 sizeof (struct GNUNET_CRYPTO_ShortHashCode),
318 sizeof (struct GNUNET_CRYPTO_ShortHashCode),
319 sizeof (uint64_t)
320 };
321 const int paramFormats[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
322
323 if (data_size != GNUNET_NAMESTORE_records_serialize (rd_count, rd,
324 data_size, data))
325 {
326 GNUNET_break (0);
327 return GNUNET_SYSERR;
328 }
329 ret =
330 PQexecPrepared (plugin->dbh, "put", 10, paramValues, paramLengths,
331 paramFormats, 1);
332 if (GNUNET_OK !=
333 GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_COMMAND_OK, "PQexecPrepared", "put"))
334 return GNUNET_SYSERR;
335 PQclear (ret);
336 }
337 return GNUNET_OK;
338}
339
340
341/**
342 * The given 'postgres' result was obtained from the database.
343 * Parse the record and give it to the iterator.
344 *
345 * @param plugin plugin context
346 * @param stmt_name name of the prepared statement that was executed
347 * @param res result from postgres to interpret (and then clean up)
348 * @param iter iterator to call with the result
349 * @param iter_cls closure for 'iter'
350 * @return GNUNET_OK on success, GNUNET_NO if there were no results, GNUNET_SYSERR on error
351 */
352static int
353get_record_and_call_iterator (struct Plugin *plugin,
354 const char *stmt_name,
355 PGresult *res,
356 GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
357{
358 unsigned int record_count;
359 size_t data_size;
360 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key;
361 const struct GNUNET_CRYPTO_RsaSignature *sig;
362 struct GNUNET_TIME_Absolute expiration;
363 const char *data;
364 const char *name;
365 unsigned int cnt;
366
367 if (GNUNET_OK !=
368 GNUNET_POSTGRES_check_result (plugin->dbh, res, PGRES_TUPLES_OK, "PQexecPrepared",
369 stmt_name))
370 {
371 LOG (GNUNET_ERROR_TYPE_DEBUG,
372 "Ending iteration (postgres error)\n");
373 return GNUNET_SYSERR;
374 }
375
376 if (0 == (cnt = PQntuples (res)))
377 {
378 /* no result */
379 LOG (GNUNET_ERROR_TYPE_DEBUG,
380 "Ending iteration (no more results)\n");
381 PQclear (res);
382 return GNUNET_NO;
383 }
384 GNUNET_assert (1 == cnt);
385 if ((6 != PQnfields (res)) ||
386 (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) != PQfsize (res, 0)) ||
387 (sizeof (uint32_t) != PQfsize (res, 2)) ||
388 (sizeof (uint64_t) != PQfsize (res, 4)) ||
389 (sizeof (struct GNUNET_CRYPTO_RsaSignature) != PQfsize (res, 5)))
390 {
391 GNUNET_break (0);
392 PQclear (res);
393 return GNUNET_SYSERR;
394 }
395 zone_key = (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *) PQgetvalue (res, 0, 0);
396 name = PQgetvalue (res, 0, 1);
397 if ('\0' != name[PQgetlength (res, 0, 1)-1])
398 {
399 GNUNET_break (0);
400 PQclear (res);
401 return GNUNET_SYSERR;
402 }
403 record_count = ntohl (*(uint32_t *) PQgetvalue (res, 0, 2));
404 data_size = PQgetlength (res, 0, 3);
405 data = PQgetvalue (res, 0, 3);
406 expiration.abs_value =
407 GNUNET_ntohll (*(uint64_t *) PQgetvalue (res, 0, 4));
408 sig = (const struct GNUNET_CRYPTO_RsaSignature*) PQgetvalue (res, 0, 5);
409 if (record_count > 64 * 1024)
410 {
411 /* sanity check, don't stack allocate far too much just
412 because database might contain a large value here */
413 GNUNET_break (0);
414 PQclear (res);
415 return GNUNET_SYSERR;
416 }
417 {
418 struct GNUNET_NAMESTORE_RecordData rd[record_count];
419
420 if (GNUNET_OK !=
421 GNUNET_NAMESTORE_records_deserialize (data_size, data,
422 record_count, rd))
423 {
424 GNUNET_break (0);
425 PQclear (res);
426 return GNUNET_SYSERR;
427 }
428 iter (iter_cls, zone_key, expiration, name,
429 record_count, rd, sig);
430 }
431 PQclear (res);
432 return GNUNET_OK;
433}
434
435
436/**
437 * Iterate over the results for a particular key and zone in the
438 * datastore. Will return at most one result to the iterator.
439 *
440 * @param cls closure (internal context for the plugin)
441 * @param zone hash of public key of the zone, NULL to iterate over all zones
442 * @param name name as string, NULL to iterate over all records of the zone
443 * @param offset offset in the list of all matching records
444 * @param iter function to call with the result
445 * @param iter_cls closure for iter
446 * @return GNUNET_OK on success, GNUNET_NO if there were no results, GNUNET_SYSERR on error
447 */
448static int
449namestore_postgres_iterate_records (void *cls,
450 const struct GNUNET_CRYPTO_ShortHashCode *zone,
451 const char *name,
452 uint64_t offset,
453 GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
454{
455 struct Plugin *plugin = cls;
456 const char *stmt_name;
457 struct GNUNET_CRYPTO_ShortHashCode name_hase;
458 uint64_t offset_be = GNUNET_htonll (offset);
459 const char *paramValues[] = {
460 (const char *) zone,
461 (const char *) &name_hase,
462 (const char *) &offset_be,
463 (const char *) zone,
464 (const char *) &offset_be,
465 };
466 int paramLengths[] = {
467 sizeof (struct GNUNET_CRYPTO_ShortHashCode),
468 sizeof (struct GNUNET_CRYPTO_ShortHashCode),
469 sizeof (uint64_t),
470 sizeof (struct GNUNET_CRYPTO_ShortHashCode),
471 sizeof (uint64_t)
472 };
473 const int paramFormats[] = { 1, 1, 1, 1, 1 };
474 unsigned int num_params;
475 unsigned int first_param;
476 PGresult *res;
477
478 if (NULL == zone)
479 if (NULL == name)
480 {
481 stmt_name = "iterate_all";
482 num_params = 1;
483 first_param = 2;
484 }
485 else
486 {
487 GNUNET_CRYPTO_short_hash (name, strlen(name), &name_hase);
488 stmt_name = "iterate_by_name";
489 num_params = 2;
490 first_param = 1;
491 }
492 else
493 if (NULL == name)
494 {
495 stmt_name = "iterate_by_zone";
496 num_params = 2;
497 first_param = 3;
498 }
499 else
500 {
501 GNUNET_CRYPTO_short_hash (name, strlen(name), &name_hase);
502 stmt_name = "iterate_records";
503 num_params = 3;
504 first_param = 0;
505 }
506 res =
507 PQexecPrepared (plugin->dbh, stmt_name, num_params,
508 &paramValues[first_param],
509 &paramLengths[first_param],
510 &paramFormats[first_param], 1);
511 return get_record_and_call_iterator (plugin, stmt_name, res, iter, iter_cls);
512}
513
514
515/**
516 * Look for an existing PKEY delegation record for a given public key.
517 * Returns at most one result to the iterator.
518 *
519 * @param cls closure (internal context for the plugin)
520 * @param zone hash of public key of the zone to look up in, never NULL
521 * @param value_zone hash of the public key of the target zone (value), never NULL
522 * @param iter function to call with the result
523 * @param iter_cls closure for iter
524 * @return GNUNET_OK on success, GNUNET_NO if there were no results, GNUNET_SYSERR on error
525 */
526static int
527namestore_postgres_zone_to_name (void *cls,
528 const struct GNUNET_CRYPTO_ShortHashCode *zone,
529 const struct GNUNET_CRYPTO_ShortHashCode *value_zone,
530 GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
531{
532 struct Plugin *plugin = cls;
533 const char *paramValues[] = {
534 (const char *) zone,
535 (const char *) value_zone
536 };
537 int paramLengths[] = {
538 sizeof (struct GNUNET_CRYPTO_ShortHashCode),
539 sizeof (struct GNUNET_CRYPTO_ShortHashCode)
540 };
541 const int paramFormats[] = { 1, 1 };
542 PGresult *res;
543
544 res =
545 PQexecPrepared (plugin->dbh, "zone_to_name", 2,
546 paramValues, paramLengths, paramFormats, 1);
547 return get_record_and_call_iterator (plugin, "zone_to_name", res, iter, iter_cls);
548}
549
550
551/**
552 * Delete an entire zone (all records). Not used in normal operation.
553 *
554 * @param cls closure (internal context for the plugin)
555 * @param zone zone to delete
556 */
557static void
558namestore_postgres_delete_zone (void *cls,
559 const struct GNUNET_CRYPTO_ShortHashCode *zone)
560{
561 struct Plugin *plugin = cls;
562 PGresult *ret;
563 const char *paramValues[] = {
564 (const char *) zone,
565 };
566 int paramLengths[] = {
567 sizeof (struct GNUNET_CRYPTO_ShortHashCode)
568 };
569 const int paramFormats[] = { 1 };
570
571 ret =
572 PQexecPrepared (plugin->dbh, "delete_zone", 1, paramValues, paramLengths,
573 paramFormats, 1);
574 if (GNUNET_OK !=
575 GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_COMMAND_OK, "PQexecPrepared", "delete_zone"))
576 {
577 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
578 "Deleting zone failed!\n");
579 return;
580 }
581 PQclear (ret);
582}
583
584
585/**
586 * Shutdown database connection and associate data
587 * structures.
588 *
589 * @param plugin the plugin context (state for this module)
590 */
591static void
592database_shutdown (struct Plugin *plugin)
593{
594 PQfinish (plugin->dbh);
595 plugin->dbh = NULL;
596}
597
598
599/**
600 * Entry point for the plugin.
601 *
602 * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
603 * @return NULL on error, othrewise the plugin context
604 */
605void *
606libgnunet_plugin_namestore_postgres_init (void *cls)
607{
608 static struct Plugin plugin;
609 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
610 struct GNUNET_NAMESTORE_PluginFunctions *api;
611
612 if (NULL != plugin.cfg)
613 return NULL; /* can only initialize once! */
614 memset (&plugin, 0, sizeof (struct Plugin));
615 plugin.cfg = cfg;
616 if (GNUNET_OK != database_setup (&plugin))
617 {
618 database_shutdown (&plugin);
619 return NULL;
620 }
621 api = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_PluginFunctions));
622 api->cls = &plugin;
623 api->put_records = &namestore_postgres_put_records;
624 api->remove_records = &namestore_postgres_remove_records;
625 api->iterate_records = &namestore_postgres_iterate_records;
626 api->zone_to_name = &namestore_postgres_zone_to_name;
627 api->delete_zone = &namestore_postgres_delete_zone;
628 LOG (GNUNET_ERROR_TYPE_INFO,
629 _("Postgres database running\n"));
630 return api;
631}
632
633
634/**
635 * Exit point from the plugin.
636 *
637 * @param cls the plugin context (as returned by "init")
638 * @return always NULL
639 */
640void *
641libgnunet_plugin_namestore_postgres_done (void *cls)
642{
643 struct GNUNET_NAMESTORE_PluginFunctions *api = cls;
644 struct Plugin *plugin = api->cls;
645
646 database_shutdown (plugin);
647 plugin->cfg = NULL;
648 GNUNET_free (api);
649 LOG (GNUNET_ERROR_TYPE_DEBUG,
650 "postgres plugin is finished\n");
651 return NULL;
652}
653
654/* end of plugin_namestore_postgres.c */
diff --git a/src/namestore/plugin_namestore_sqlite.c b/src/namestore/plugin_namestore_sqlite.c
index f6858876e..b3f57033a 100644
--- a/src/namestore/plugin_namestore_sqlite.c
+++ b/src/namestore/plugin_namestore_sqlite.c
@@ -591,6 +591,13 @@ get_record_and_call_iterator (struct Plugin *plugin,
591 GNUNET_break (0); 591 GNUNET_break (0);
592 ret = GNUNET_SYSERR; 592 ret = GNUNET_SYSERR;
593 } 593 }
594 else if (record_count > 64 * 1024)
595 {
596 /* sanity check, don't stack allocate far too much just
597 because database might contain a large value here */
598 GNUNET_break (0);
599 ret = GNUNET_SYSERR;
600 }
594 else 601 else
595 { 602 {
596 struct GNUNET_NAMESTORE_RecordData rd[record_count]; 603 struct GNUNET_NAMESTORE_RecordData rd[record_count];
@@ -601,7 +608,6 @@ get_record_and_call_iterator (struct Plugin *plugin,
601 { 608 {
602 GNUNET_break (0); 609 GNUNET_break (0);
603 ret = GNUNET_SYSERR; 610 ret = GNUNET_SYSERR;
604 record_count = 0;
605 } 611 }
606 else 612 else
607 { 613 {