GNUnet  0.10.x
plugin_namecache_postgres.c
Go to the documentation of this file.
1  /*
2  * This file is part of GNUnet
3  * Copyright (C) 2009-2013, 2016, 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 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 
26 #include "platform.h"
29 #include "gnunet_gnsrecord_lib.h"
30 #include "gnunet_pq_lib.h"
31 #include "namecache.h"
32 
33 
34 #define LOG(kind,...) GNUNET_log_from (kind, "namecache-postgres", __VA_ARGS__)
35 
36 
40 struct Plugin
41 {
42 
43  const struct GNUNET_CONFIGURATION_Handle *cfg;
44 
48  PGconn *dbh;
49 
50 };
51 
52 
61 static int
63 {
64  struct GNUNET_PQ_ExecuteStatement es_temporary =
65  GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS ns096blocks ("
66  " query BYTEA NOT NULL DEFAULT '',"
67  " block BYTEA NOT NULL DEFAULT '',"
68  " expiration_time BIGINT NOT NULL DEFAULT 0"
69  ")"
70  "WITH OIDS");
71  struct GNUNET_PQ_ExecuteStatement es_default =
72  GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS ns096blocks ("
73  " query BYTEA NOT NULL DEFAULT '',"
74  " block BYTEA NOT NULL DEFAULT '',"
75  " expiration_time BIGINT NOT NULL DEFAULT 0"
76  ")"
77  "WITH OIDS");
78  const struct GNUNET_PQ_ExecuteStatement *cr;
79 
80  plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg,
81  "namecache-postgres");
82  if (NULL == plugin->dbh)
83  return GNUNET_SYSERR;
84  if (GNUNET_YES ==
86  "namecache-postgres",
87  "TEMPORARY_TABLE"))
88  {
89  cr = &es_temporary;
90  }
91  else
92  {
93  cr = &es_default;
94  }
95 
96  {
97  struct GNUNET_PQ_ExecuteStatement es[] = {
98  *cr,
99  GNUNET_PQ_make_try_execute ("CREATE INDEX ir_query_hash ON ns096blocks (query,expiration_time)"),
100  GNUNET_PQ_make_try_execute ("CREATE INDEX ir_block_expiration ON ns096blocks (expiration_time)"),
102  };
103 
104  if (GNUNET_OK !=
106  es))
107  {
108  PQfinish (plugin->dbh);
109  plugin->dbh = NULL;
110  return GNUNET_SYSERR;
111  }
112  }
113 
114  {
115  struct GNUNET_PQ_PreparedStatement ps[] = {
116  GNUNET_PQ_make_prepare ("cache_block",
117  "INSERT INTO ns096blocks (query, block, expiration_time) VALUES "
118  "($1, $2, $3)", 3),
119  GNUNET_PQ_make_prepare ("expire_blocks",
120  "DELETE FROM ns096blocks WHERE expiration_time<$1", 1),
121  GNUNET_PQ_make_prepare ("delete_block",
122  "DELETE FROM ns096blocks WHERE query=$1 AND expiration_time<=$2", 2),
123  GNUNET_PQ_make_prepare ("lookup_block",
124  "SELECT block FROM ns096blocks WHERE query=$1"
125  " ORDER BY expiration_time DESC LIMIT 1", 1),
127  };
128 
129  if (GNUNET_OK !=
131  ps))
132  {
133  PQfinish (plugin->dbh);
134  plugin->dbh = NULL;
135  return GNUNET_SYSERR;
136  }
137  }
138 
139  return GNUNET_OK;
140 }
141 
142 
148 static void
150 {
152  struct GNUNET_PQ_QueryParam params[] = {
155  };
157 
159  "expire_blocks",
160  params);
162 }
163 
164 
172 static void
174  const struct GNUNET_HashCode *query,
175  struct GNUNET_TIME_AbsoluteNBO expiration_time)
176 {
177  struct GNUNET_PQ_QueryParam params[] = {
179  GNUNET_PQ_query_param_absolute_time_nbo (&expiration_time),
181  };
183 
185  "delete_block",
186  params);
188 }
189 
190 
198 static int
200  const struct GNUNET_GNSRECORD_Block *block)
201 {
202  struct Plugin *plugin = cls;
203  struct GNUNET_HashCode query;
204  size_t block_size = ntohl (block->purpose.size) +
205  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
206  sizeof (struct GNUNET_CRYPTO_EcdsaSignature);
207  struct GNUNET_PQ_QueryParam params[] = {
209  GNUNET_PQ_query_param_fixed_size (block, block_size),
212  };
214 
217  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
218  &query);
219  if (block_size > 64 * 65536)
220  {
221  GNUNET_break (0);
222  return GNUNET_SYSERR;
223  }
224  delete_old_block (plugin,
225  &query,
226  block->expiration_time);
227 
229  "cache_block",
230  params);
231  if (0 > res)
232  return GNUNET_SYSERR;
233  return GNUNET_OK;
234 }
235 
236 
247 static int
249  const struct GNUNET_HashCode *query,
251  void *iter_cls)
252 {
253  struct Plugin *plugin = cls;
254  size_t bsize;
255  struct GNUNET_GNSRECORD_Block *block;
256  struct GNUNET_PQ_QueryParam params[] = {
259  };
260  struct GNUNET_PQ_ResultSpec rs[] = {
262  (void **) &block,
263  &bsize),
265  };
267 
269  "lookup_block",
270  params,
271  rs);
272  if (0 > res)
273  {
275  "Failing lookup block in namecache (postgres error)\n");
276  return GNUNET_SYSERR;
277  }
279  {
280  /* no result */
282  "Ending iteration (no more results)\n");
283  return GNUNET_NO;
284  }
285  if ( (bsize < sizeof (*block)) ||
286  (bsize != ntohl (block->purpose.size) +
287  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
288  sizeof (struct GNUNET_CRYPTO_EcdsaSignature)) )
289  {
290  GNUNET_break (0);
292  "Failing lookup (corrupt block)\n");
294  return GNUNET_SYSERR;
295  }
296  iter (iter_cls,
297  block);
299  return GNUNET_OK;
300 }
301 
302 
309 static void
311 {
312  PQfinish (plugin->dbh);
313  plugin->dbh = NULL;
314 }
315 
316 
323 void *
325 {
326  static struct Plugin plugin;
327  const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
329 
330  if (NULL != plugin.cfg)
331  return NULL; /* can only initialize once! */
332  memset (&plugin, 0, sizeof (struct Plugin));
333  plugin.cfg = cfg;
334  if (GNUNET_OK != database_setup (&plugin))
335  {
336  database_shutdown (&plugin);
337  return NULL;
338  }
340  api->cls = &plugin;
344  "Postgres namecache plugin running\n");
345  return api;
346 }
347 
348 
355 void *
357 {
359  struct Plugin *plugin = api->cls;
360 
361  database_shutdown (plugin);
362  plugin->cfg = NULL;
363  GNUNET_free (api);
365  "Postgres namecache plugin is finished\n");
366  return NULL;
367 }
368 
369 /* end of plugin_namecache_postgres.c */
void(* GNUNET_NAMECACHE_BlockCallback)(void *cls, const struct GNUNET_GNSRECORD_Block *block)
Function called for matching blocks.
struct GNUNET_TIME_AbsoluteNBO expiration_time
Expiration time of the block.
void * cls
Closure to pass to all plugin functions.
struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_absolute_time_nbo(const struct GNUNET_TIME_AbsoluteNBO *x)
Generate query parameter for an absolute time value.
static int namecache_postgres_lookup_block(void *cls, const struct GNUNET_HashCode *query, GNUNET_NAMECACHE_BlockCallback iter, void *iter_cls)
Get the block for a particular zone and label in the datastore.
static void database_shutdown(struct Plugin *plugin)
Shutdown database connection and associate data structures.
struct GNUNET_PQ_ExecuteStatement GNUNET_PQ_make_execute(const char *sql)
Create a struct GNUNET_PQ_ExecuteStatement where errors are fatal.
Definition: pq_exec.c:37
Information needed to run a list of SQL statements using GNUNET_PQ_exec_statements().
Information needed to prepare a list of SQL statements using GNUNET_PQ_prepare_statements().
const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Description of a DB result cell.
#define GNUNET_NO
Definition: gnunet_common.h:81
struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_absolute_time(const struct GNUNET_TIME_Absolute *x)
Generate query parameter for an absolute time value.
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
enum GNUNET_DB_QueryStatus GNUNET_PQ_eval_prepared_singleton_select(PGconn *connection, const char *statement_name, const struct GNUNET_PQ_QueryParam *params, struct GNUNET_PQ_ResultSpec *rs)
Execute a named prepared statement that is a SELECT statement which must return a single result in co...
Definition: pq_eval.c:241
#define GNUNET_new(type)
Allocate a struct or union of the given type.
enum GNUNET_DB_QueryStatus GNUNET_PQ_eval_prepared_non_select(PGconn *connection, const char *statement_name, const struct GNUNET_PQ_QueryParam *params)
Execute a named prepared statement that is NOT a SELECT statement in connnection using the given para...
Definition: pq_eval.c:151
Information we have in an encrypted block with record data (i.e.
A hard error occurred, retrying will not help.
Definition: gnunet_db_lib.h:39
Time for absolute time used by GNUnet, in microseconds and in network byte order. ...
static int namecache_postgres_cache_block(void *cls, const struct GNUNET_GNSRECORD_Block *block)
Cache a block in the datastore.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
struct GNUNET_BLOCK_PluginFunctions * api
Plugin API.
Definition: block.c:47
int(* cache_block)(void *cls, const struct GNUNET_GNSRECORD_Block *block)
Cache a block in the datastore.
static struct GNUNET_ATS_SolverFunctions * plugin
Our solver.
void * cls
Closure for conv and cleaner.
#define GNUNET_PQ_result_spec_end
End of result parameter specification.
#define GNUNET_PQ_query_param_end
End of query parameter specification.
Definition: gnunet_pq_lib.h:96
int GNUNET_PQ_prepare_statements(PGconn *connection, const struct GNUNET_PQ_PreparedStatement *ps)
Request creation of prepared statements ps from Postgres.
Definition: pq_prepare.c:63
void * libgnunet_plugin_namecache_postgres_done(void *cls)
Exit point from the plugin.
struct GNUNET_PQ_ResultSpec GNUNET_PQ_result_spec_variable_size(const char *name, void **dst, size_t *sptr)
Variable-size result expected.
int(* lookup_block)(void *cls, const struct GNUNET_HashCode *query, GNUNET_NAMECACHE_BlockCallback iter, void *iter_cls)
Get the block for a particular zone and label in the datastore.
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition: crypto_hash.c:44
#define LOG(kind,...)
#define GNUNET_PQ_query_param_auto_from_type(x)
Generate fixed-size query parameter with size determined by variable type.
an ECC signature using ECDSA
void * libgnunet_plugin_namecache_postgres_init(void *cls)
Entry point for the plugin.
uint32_t size
How many bytes does this signature sign? (including this purpose header); in network byte order (!)...
static unsigned int bsize
A 512-bit hashcode.
static int res
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:118
PGconn * GNUNET_PQ_connect_with_cfg(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section)
Connect to a postgres database using the configuration option "CONFIG" in section.
Definition: pq_connect.c:112
#define GNUNET_PQ_PREPARED_STATEMENT_END
Terminator for prepared statement list.
#define GNUNET_SYSERR
Definition: gnunet_common.h:79
helper functions for Postgres DB interactions
void * iter_cls
Iterator cls.
static int database_setup(struct Plugin *plugin)
Initialize the database connections and associated data structures (create tables and indices as need...
int GNUNET_PQ_exec_statements(PGconn *connection, const struct GNUNET_PQ_ExecuteStatement *es)
Request execution of an array of statements es from Postgres.
Definition: pq_exec.c:77
struct returned by the initialization function of the plugin
static void delete_old_block(struct Plugin *plugin, const struct GNUNET_HashCode *query, struct GNUNET_TIME_AbsoluteNBO expiration_time)
Delete older block in the datastore.
static void namecache_postgres_expire_blocks(struct Plugin *plugin)
Removes any expired block.
configuration data
Definition: configuration.c:85
Handle for a plugin.
Definition: block.c:37
PGconn * dbh
Native Postgres database handle.
Public ECC key (always for Curve25519) encoded in a format suitable for network transmission and ECDS...
Description of a DB query parameter.
Definition: gnunet_pq_lib.h:63
struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_fixed_size(const void *ptr, size_t ptr_size)
Generate query parameter for a buffer ptr of ptr_size bytes.
#define GNUNET_PQ_EXECUTE_STATEMENT_END
Terminator for executable statement list.
Time for absolute times used by GNUnet, in microseconds.
#define GNUNET_YES
Definition: gnunet_common.h:80
GNUNET_DB_QueryStatus
Status code returned from functions running database commands.
Definition: gnunet_db_lib.h:34
struct GNUNET_PQ_ExecuteStatement GNUNET_PQ_make_try_execute(const char *sql)
Create a struct GNUNET_PQ_ExecuteStatement where errors should be tolerated.
Definition: pq_exec.c:56
The transaction succeeded, but yielded zero results.
Definition: gnunet_db_lib.h:53
int GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
struct GNUNET_CRYPTO_EccSignaturePurpose purpose
Number of bytes signed; also specifies the number of bytes of encrypted data that follow...
GNUNET_PEERSTORE_Processor iter
Iterator.
common internal definitions for namecache service
struct GNUNET_CRYPTO_EcdsaPublicKey derived_key
Derived key used for signing; hash of this is the query.
struct GNUNET_PQ_PreparedStatement GNUNET_PQ_make_prepare(const char *name, const char *sql, unsigned int num_args)
Create a struct GNUNET_PQ_PreparedStatement.
Definition: pq_prepare.c:39
#define GNUNET_free(ptr)
Wrapper around free.
void GNUNET_PQ_cleanup_result(struct GNUNET_PQ_ResultSpec *rs)
Free all memory that was allocated in rs during GNUNET_PQ_extract_result().
Definition: pq.c:121