/*
* This file is part of GNUnet
- * (C) 2009-2013 Christian Grothoff (and other contributing authors)
+ * Copyright (C) 2009-2013, 2016 GNUnet e.V.
*
* GNUnet is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
*
* You should have received a copy of the GNU General Public License
* along with GNUnet; see the file COPYING. If not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
/**
#include "platform.h"
#include "gnunet_namestore_plugin.h"
#include "gnunet_namestore_service.h"
+#include "gnunet_gnsrecord_lib.h"
#include "gnunet_postgres_lib.h"
+#include "gnunet_pq_lib.h"
#include "namestore.h"
struct Plugin
{
+ /**
+ * Our configuration.
+ */
const struct GNUNET_CONFIGURATION_Handle *cfg;
/**
{
/* create indices */
if ( (GNUNET_OK !=
- GNUNET_POSTGRES_exec (dbh,
- "CREATE INDEX ir_query_hash ON ns096blocks (query,expiration_time)")) ||
- (GNUNET_OK !=
- GNUNET_POSTGRES_exec (dbh,
- "CREATE INDEX ir_block_expiration ON ns096blocks (expiration_time)")) ||
- (GNUNET_OK !=
GNUNET_POSTGRES_exec (dbh,
"CREATE INDEX ir_pkey_reverse ON ns097records (zone_private_key,pkey)")) ||
(GNUNET_OK !=
GNUNET_POSTGRES_exec (dbh,
"CREATE INDEX ir_pkey_iter ON ns097records (zone_private_key,rvalue)")) ||
(GNUNET_OK !=
- GNUNET_POSTGRES_exec (dbh,
- "CREATE INDEX it_iter ON ns097records (rvalue)")) )
+ GNUNET_POSTGRES_exec (dbh, "CREATE INDEX it_iter ON ns097records (rvalue)")) ||
+ (GNUNET_OK !=
+ GNUNET_POSTGRES_exec (dbh, "CREATE INDEX ir_label ON ns097records (label)")) )
LOG (GNUNET_ERROR_TYPE_ERROR,
_("Failed to create indices\n"));
}
* as needed as well).
*
* @param plugin the plugin context (state for this module)
- * @return GNUNET_OK on success
+ * @return #GNUNET_OK on success
*/
static int
database_setup (struct Plugin *plugin)
plugin->dbh = NULL;
return GNUNET_SYSERR;
}
-
-
- if (GNUNET_YES ==
- GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg,
- "namestore-postgres",
- "TEMPORARY_TABLE"))
- {
- res =
- PQexec (plugin->dbh,
- "CREATE TEMPORARY TABLE ns096blocks ("
- " query BYTEA NOT NULL DEFAULT '',"
- " block BYTEA NOT NULL DEFAULT '',"
- " expiration_time BIGINT NOT NULL DEFAULT 0"
- ")" "WITH OIDS");
- }
- else
- {
- res =
- PQexec (plugin->dbh,
- "CREATE TABLE ns096blocks ("
- " query BYTEA NOT NULL DEFAULT '',"
- " block BYTEA NOT NULL DEFAULT '',"
- " expiration_time BIGINT NOT NULL DEFAULT 0"
- ")" "WITH OIDS");
- }
- if ( (NULL == res) ||
- ((PQresultStatus (res) != PGRES_COMMAND_OK) &&
- (0 != strcmp ("42P07", /* duplicate table */
- PQresultErrorField
- (res,
- PG_DIAG_SQLSTATE)))))
- {
- (void) GNUNET_POSTGRES_check_result (plugin->dbh, res,
- PGRES_COMMAND_OK, "CREATE TABLE",
- "ns096blocks");
- PQfinish (plugin->dbh);
- plugin->dbh = NULL;
- return GNUNET_SYSERR;
- }
- if (PQresultStatus (res) == PGRES_COMMAND_OK)
- create_indices (plugin->dbh);
- PQclear (res);
+ create_indices (plugin->dbh);
if ((GNUNET_OK !=
- GNUNET_POSTGRES_prepare (plugin->dbh,
- "cache_block",
- "INSERT INTO ns096blocks (query, block, expiration_time) VALUES "
- "($1, $2, $3)", 3)) ||
- (GNUNET_OK !=
- GNUNET_POSTGRES_prepare (plugin->dbh,
- "expire_blocks",
- "DELETE FROM ns096blocks WHERE expiration_time<$1", 1)) ||
- (GNUNET_OK !=
- GNUNET_POSTGRES_prepare (plugin->dbh,
- "delete_block",
- "DELETE FROM ns096blocks WHERE query=$1 AND expiration_time<=$2", 2)) ||
- (GNUNET_OK !=
- GNUNET_POSTGRES_prepare (plugin->dbh,
- "lookup_block",
- "SELECT block FROM ns096blocks WHERE query=$1"
- " ORDER BY expiration_time DESC LIMIT 1", 1)) ||
- (GNUNET_OK !=
GNUNET_POSTGRES_prepare (plugin->dbh,
"store_records",
- "INSERT INTO ns097records (zone_private_key, pkey, value, record_count, record_data, label) VALUES "
+ "INSERT INTO ns097records (zone_private_key, pkey, rvalue, record_count, record_data, label) VALUES "
"($1, $2, $3, $4, $5, $6)", 6)) ||
(GNUNET_OK !=
GNUNET_POSTGRES_prepare (plugin->dbh,
(GNUNET_OK !=
GNUNET_POSTGRES_prepare (plugin->dbh,
"iterate_zone",
- "SELECT record_count, record_data, label FROM ns097records"
+ "SELECT record_count,record_data,label FROM ns097records"
" WHERE zone_private_key=$1 ORDER BY rvalue LIMIT 1 OFFSET $2", 2)) ||
(GNUNET_OK !=
GNUNET_POSTGRES_prepare (plugin->dbh,
"iterate_all_zones",
"SELECT record_count,record_data,label,zone_private_key"
- " FROM ns097records ORDER BY rvalue LIMIT 1 OFFSET $1", 1)))
+ " FROM ns097records ORDER BY rvalue LIMIT 1 OFFSET $1", 1)) ||
+ (GNUNET_OK !=
+ GNUNET_POSTGRES_prepare (plugin->dbh,
+ "lookup_label",
+ "SELECT record_count,record_data,label"
+ " FROM ns097records WHERE zone_private_key=$1 AND label=$2", 2)))
{
PQfinish (plugin->dbh);
plugin->dbh = NULL;
}
-/**
- * Removes any expired block.
- *
- * @param plugin the plugin
- */
-static void
-namestore_postgres_expire_blocks (struct Plugin *plugin)
-{
- struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
- struct GNUNET_TIME_AbsoluteNBO now_be = GNUNET_TIME_absolute_hton (now);
- const char *paramValues[] = {
- (const char *) &now_be
- };
- int paramLengths[] = {
- sizeof (now_be)
- };
- const int paramFormats[] = { 1 };
- PGresult *res;
-
- res =
- PQexecPrepared (plugin->dbh, "expire_blocks", 1,
- paramValues, paramLengths, paramFormats, 1);
- if (GNUNET_OK !=
- GNUNET_POSTGRES_check_result (plugin->dbh,
- res,
- PGRES_COMMAND_OK,
- "PQexecPrepared",
- "expire_blocks"))
- return;
- PQclear (res);
-}
-
-
-/**
- * Delete older block in the datastore.
- *
- * @param the plugin
- * @param query query for the block
- * @param expiration time how old does the block have to be for deletion
- * @return #GNUNET_OK on success, else #GNUNET_SYSERR
- */
-static void
-delete_old_block (struct Plugin *plugin,
- const struct GNUNET_HashCode *query,
- struct GNUNET_TIME_AbsoluteNBO expiration_time)
-{
- const char *paramValues[] = {
- (const char *) query,
- (const char *) &expiration_time
- };
- int paramLengths[] = {
- sizeof (*query),
- sizeof (expiration_time)
- };
- const int paramFormats[] = { 1, 1 };
- PGresult *res;
-
- res =
- PQexecPrepared (plugin->dbh, "delete_block", 2,
- paramValues, paramLengths, paramFormats, 1);
- if (GNUNET_OK !=
- GNUNET_POSTGRES_check_result (plugin->dbh,
- res,
- PGRES_COMMAND_OK,
- "PQexecPrepared",
- "delete_block"))
- return;
- PQclear (res);
-}
-
-
-/**
- * Cache a block in the datastore.
- *
- * @param cls closure (internal context for the plugin)
- * @param block block to cache
- * @return #GNUNET_OK on success, else #GNUNET_SYSERR
- */
-static int
-namestore_postgres_cache_block (void *cls,
- const struct GNUNET_NAMESTORE_Block *block)
-{
- struct Plugin *plugin = cls;
- struct GNUNET_HashCode query;
- size_t block_size = ntohl (block->purpose.size) +
- sizeof (struct GNUNET_CRYPTO_EccPublicSignKey) +
- sizeof (struct GNUNET_CRYPTO_EccSignature);
- const char *paramValues[] = {
- (const char *) &query,
- (const char *) block,
- (const char *) &block->expiration_time
- };
- int paramLengths[] = {
- sizeof (query),
- (int) block_size,
- sizeof (block->expiration_time)
- };
- const int paramFormats[] = { 1, 1, 1 };
- PGresult *res;
-
- namestore_postgres_expire_blocks (plugin);
- GNUNET_CRYPTO_hash (&block->derived_key,
- sizeof (struct GNUNET_CRYPTO_EccPublicSignKey),
- &query);
- if (block_size > 64 * 65536)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- delete_old_block (plugin, &query, block->expiration_time);
-
- res =
- PQexecPrepared (plugin->dbh, "cache_block", 3,
- paramValues, paramLengths, paramFormats, 1);
- if (GNUNET_OK !=
- GNUNET_POSTGRES_check_result (plugin->dbh,
- res,
- PGRES_COMMAND_OK,
- "PQexecPrepared",
- "cache_block"))
- return GNUNET_SYSERR;
- PQclear (res);
- return GNUNET_OK;
-}
-
-
-/**
- * Get the block for a particular zone and label in the
- * datastore. Will return at most one result to the iterator.
- *
- * @param cls closure (internal context for the plugin)
- * @param query hash of public key derived from the zone and the label
- * @param iter function to call with the result
- * @param iter_cls closure for @a iter
- * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
- */
-static int
-namestore_postgres_lookup_block (void *cls,
- const struct GNUNET_HashCode *query,
- GNUNET_NAMESTORE_BlockCallback iter, void *iter_cls)
-{
- struct Plugin *plugin = cls;
- const char *paramValues[] = {
- (const char *) query
- };
- int paramLengths[] = {
- sizeof (*query)
- };
- const int paramFormats[] = { 1 };
- PGresult *res;
- unsigned int cnt;
- size_t bsize;
- const struct GNUNET_NAMESTORE_Block *block;
-
- res = PQexecPrepared (plugin->dbh,
- "lookup_block", 1,
- paramValues, paramLengths, paramFormats,
- 1);
- if (GNUNET_OK !=
- GNUNET_POSTGRES_check_result (plugin->dbh, res, PGRES_TUPLES_OK,
- "PQexecPrepared",
- "lookup_block"))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Failing lookup (postgres error)\n");
- return GNUNET_SYSERR;
- }
- if (0 == (cnt = PQntuples (res)))
- {
- /* no result */
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Ending iteration (no more results)\n");
- PQclear (res);
- return GNUNET_NO;
- }
- GNUNET_assert (1 == cnt);
- GNUNET_assert (1 != PQnfields (res));
- bsize = PQgetlength (res, 0, 0);
- block = (const struct GNUNET_NAMESTORE_Block *) PQgetvalue (res, 0, 0);
- if ( (bsize < sizeof (*block)) ||
- (bsize != ntohl (block->purpose.size) +
- sizeof (struct GNUNET_CRYPTO_EccPublicSignKey) +
- sizeof (struct GNUNET_CRYPTO_EccSignature)) )
- {
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Failing lookup (corrupt block)\n");
- PQclear (res);
- return GNUNET_SYSERR;
- }
- iter (iter_cls, block);
- PQclear (res);
- return GNUNET_OK;
-}
-
-
/**
* Store a record in the datastore. Removes any existing record in the
* same zone with the same name.
*/
static int
namestore_postgres_store_records (void *cls,
- const struct GNUNET_CRYPTO_EccPrivateKey *zone_key,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
const char *label,
unsigned int rd_count,
- const struct GNUNET_NAMESTORE_RecordData *rd)
+ const struct GNUNET_GNSRECORD_Data *rd)
{
struct Plugin *plugin = cls;
- struct GNUNET_CRYPTO_EccPublicSignKey pkey;
+ struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
uint64_t rvalue;
uint32_t rd_count_nbo = htonl ((uint32_t) rd_count);
size_t data_size;
memset (&pkey, 0, sizeof (pkey));
for (i=0;i<rd_count;i++)
- if (GNUNET_NAMESTORE_TYPE_PKEY == rd[i].record_type)
+ if (GNUNET_GNSRECORD_TYPE_PKEY == rd[i].record_type)
{
- GNUNET_break (sizeof (struct GNUNET_CRYPTO_EccPublicSignKey) == rd[i].data_size);
+ GNUNET_break (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) == rd[i].data_size);
memcpy (&pkey,
rd[i].data,
rd[i].data_size);
break;
}
rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
- data_size = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
+ data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
if (data_size > 64 * 65536)
{
GNUNET_break (0);
}
{
char data[data_size];
+ // FIXME: use libgnunetpq!
const char *paramValues[] = {
(const char *) zone_key,
(const char *) &pkey,
const int paramFormats[] = { 1, 1, 1, 1, 1, 1 };
PGresult *res;
- if (data_size != GNUNET_NAMESTORE_records_serialize (rd_count, rd,
+ if (data_size != GNUNET_GNSRECORD_records_serialize (rd_count, rd,
data_size, data))
{
GNUNET_break (0);
static int
get_record_and_call_iterator (struct Plugin *plugin,
PGresult *res,
- const struct GNUNET_CRYPTO_EccPrivateKey *zone_key,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
{
const char *data;
GNUNET_assert (3 + ((NULL == zone_key) ? 1 : 0) == PQnfields (res));
if (NULL == zone_key)
{
- if (sizeof (struct GNUNET_CRYPTO_EccPrivateKey) != PQgetlength (res, 0, 3))
+ if (sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey) != PQgetlength (res, 0, 3))
{
GNUNET_break (0);
PQclear (res);
return GNUNET_SYSERR;
}
- zone_key = (const struct GNUNET_CRYPTO_EccPrivateKey *) PQgetvalue (res, 0, 3);
+ zone_key = (const struct GNUNET_CRYPTO_EcdsaPrivateKey *) PQgetvalue (res, 0, 3);
}
if (sizeof (uint32_t) != PQfsize (res, 0))
{
return GNUNET_SYSERR;
}
{
- struct GNUNET_NAMESTORE_RecordData rd[record_count];
+ struct GNUNET_GNSRECORD_Data rd[record_count];
char buf[label_len + 1];
memcpy (buf, label, label_len);
buf[label_len] = '\0';
if (GNUNET_OK !=
- GNUNET_NAMESTORE_records_deserialize (data_size, data,
+ GNUNET_GNSRECORD_records_deserialize (data_size, data,
record_count, rd))
{
GNUNET_break (0);
}
+/**
+ * Lookup records in the datastore for which we are the authority.
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param zone private key of the zone
+ * @param label name of the record in the zone
+ * @param iter function to call with the result
+ * @param iter_cls closure for @a iter
+ * @return #GNUNET_OK on success, else #GNUNET_SYSERR
+ */
+static int
+namestore_postgres_lookup_records (void *cls,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+ const char *label,
+ GNUNET_NAMESTORE_RecordIterator iter,
+ void *iter_cls)
+{
+ struct Plugin *plugin = cls;
+ const char *paramValues[] = {
+ (const char *) zone,
+ label
+ };
+ int paramLengths[] = {
+ sizeof (*zone),
+ strlen (label)
+ };
+ const int paramFormats[] = { 1, 1 };
+ PGresult *res;
+
+ res = PQexecPrepared (plugin->dbh,
+ "lookup_label", 2,
+ paramValues, paramLengths, paramFormats,
+ 1);
+ return get_record_and_call_iterator (plugin,
+ res,
+ zone,
+ iter, iter_cls);
+}
+
+
/**
* Iterate over the results for a particular key and zone in the
* datastore. Will return at most one result to the iterator.
*/
static int
namestore_postgres_iterate_records (void *cls,
- const struct GNUNET_CRYPTO_EccPrivateKey *zone,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
uint64_t offset,
GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
{
*/
static int
namestore_postgres_zone_to_name (void *cls,
- const struct GNUNET_CRYPTO_EccPrivateKey *zone,
- const struct GNUNET_CRYPTO_EccPublicSignKey *value_zone,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey *value_zone,
GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
{
struct Plugin *plugin = cls;
/**
* Entry point for the plugin.
*
- * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*"
+ * @param cls the `struct GNUNET_NAMESTORE_PluginEnvironment*`
* @return NULL on error, othrewise the plugin context
*/
void *
}
api = GNUNET_new (struct GNUNET_NAMESTORE_PluginFunctions);
api->cls = &plugin;
- api->cache_block = &namestore_postgres_cache_block;
- api->lookup_block = &namestore_postgres_lookup_block;
api->store_records = &namestore_postgres_store_records;
api->iterate_records = &namestore_postgres_iterate_records;
api->zone_to_name = &namestore_postgres_zone_to_name;
+ api->lookup_records = &namestore_postgres_lookup_records;
LOG (GNUNET_ERROR_TYPE_INFO,
_("Postgres database running\n"));
return api;