aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSchanzenbach, Martin <mschanzenbach@posteo.de>2017-06-23 20:39:27 +0200
committerSchanzenbach, Martin <mschanzenbach@posteo.de>2017-06-23 20:39:27 +0200
commit2d81d6d8217b9aa08139bd66d14c597705568920 (patch)
tree197017d2b8498a79700ef6e00160b80ae749222e /src
parentad5b64d8ef992d7281501297b547095569d8f0fb (diff)
parentd7547ab18052726a69ee088876389a18798e03a8 (diff)
downloadgnunet-2d81d6d8217b9aa08139bd66d14c597705568920.tar.gz
gnunet-2d81d6d8217b9aa08139bd66d14c597705568920.zip
Merge remote-tracking branch 'origin/master' into credentials
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/consensus/gnunet-service-consensus.c47
-rw-r--r--src/consensus/test_consensus.conf2
-rw-r--r--src/conversation/test_conversation.conf2
-rw-r--r--src/datacache/Makefile.am2
-rw-r--r--src/datacache/plugin_datacache_postgres.c750
-rw-r--r--src/datastore/Makefile.am1
-rw-r--r--src/datastore/plugin_datastore_postgres.c834
-rw-r--r--src/datastore/plugin_datastore_sqlite.c54
-rw-r--r--src/gns/gnunet-gns-import.c39
-rw-r--r--src/include/Makefile.am2
-rw-r--r--src/include/gnunet_db_lib.h61
-rw-r--r--src/include/gnunet_postgres_lib.h178
-rw-r--r--src/include/gnunet_pq_lib.h268
-rw-r--r--src/include/gnunet_protocols.h7
-rw-r--r--src/include/gnunet_strings_lib.h4
-rw-r--r--src/multicast/Makefile.am2
-rw-r--r--src/multicast/gnunet-service-multicast.c9
-rw-r--r--src/multicast/test_multicast.conf45
-rw-r--r--src/multicast/test_multicast_multipeer.c93
-rw-r--r--src/namecache/Makefile.am1
-rw-r--r--src/namecache/plugin_namecache_postgres.c280
-rw-r--r--src/namestore/Makefile.am1
-rw-r--r--src/namestore/gnunet-service-namestore.c7
-rw-r--r--src/namestore/namestore_api.c13
-rw-r--r--src/namestore/plugin_namestore_postgres.c566
-rw-r--r--src/postgres/Makefile.am24
-rw-r--r--src/postgres/postgres.c247
-rw-r--r--src/pq/Makefile.am4
-rw-r--r--src/pq/pq_connect.c127
-rw-r--r--src/pq/pq_eval.c281
-rw-r--r--src/pq/pq_exec.c106
-rw-r--r--src/pq/pq_prepare.c93
-rw-r--r--src/psycstore/Makefile.am1
-rw-r--r--src/psycstore/plugin_psycstore_postgres.c1198
-rw-r--r--src/set/gnunet-service-set.c8
-rw-r--r--src/set/gnunet-service-set_union.c89
-rw-r--r--src/set/gnunet-service-set_union.h10
-rw-r--r--src/set/set_api.c2
-rw-r--r--src/social/gnunet-social.c7
-rw-r--r--src/transport/Makefile.am4
-rw-r--r--src/transport/plugin_transport_http_server.c30
-rw-r--r--src/util/crypto_hash.c4
-rw-r--r--src/util/gnunet-ecc.c66
-rw-r--r--src/util/service.c3
-rw-r--r--src/zonemaster/gnunet-service-zonemaster.c3
46 files changed, 2942 insertions, 2637 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 4a1d909ed..e4d7d8924 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -11,9 +11,9 @@ endif
11 11
12if HAVE_EXPERIMENTAL 12if HAVE_EXPERIMENTAL
13 EXP_DIR = \ 13 EXP_DIR = \
14 dv \
15 rps 14 rps
16endif 15endif
16# dv (FTBFS)
17 17
18if HAVE_JSON 18if HAVE_JSON
19if HAVE_MHD 19if HAVE_MHD
@@ -49,7 +49,7 @@ if HAVE_MYSQL
49endif 49endif
50 50
51if HAVE_POSTGRESQL 51if HAVE_POSTGRESQL
52 POSTGRES_DIR = pq postgres 52 POSTGRES_DIR = pq
53endif 53endif
54 54
55if HAVE_MHD 55if HAVE_MHD
diff --git a/src/consensus/gnunet-service-consensus.c b/src/consensus/gnunet-service-consensus.c
index 4af7199aa..84b1cbe55 100644
--- a/src/consensus/gnunet-service-consensus.c
+++ b/src/consensus/gnunet-service-consensus.c
@@ -693,7 +693,7 @@ send_to_client_iter (void *cls,
693 GNUNET_assert (GNUNET_BLOCK_TYPE_CONSENSUS_ELEMENT == element->element_type); 693 GNUNET_assert (GNUNET_BLOCK_TYPE_CONSENSUS_ELEMENT == element->element_type);
694 ce = element->data; 694 ce = element->data;
695 695
696 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "marker is %u\n", (unsigned) ce->marker); 696 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "marker is %u\n", (unsigned) ce->marker);
697 697
698 if (0 != ce->marker) 698 if (0 != ce->marker)
699 return GNUNET_YES; 699 return GNUNET_YES;
@@ -988,7 +988,7 @@ set_result_cb (void *cls,
988 988
989 if ( (NULL != consensus_element) && (0 != consensus_element->marker) ) 989 if ( (NULL != consensus_element) && (0 != consensus_element->marker) )
990 { 990 {
991 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 991 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
992 "P%u: got some marker\n", 992 "P%u: got some marker\n",
993 session->local_peer_idx); 993 session->local_peer_idx);
994 if ( (GNUNET_YES == setop->transceive_contested) && 994 if ( (GNUNET_YES == setop->transceive_contested) &&
@@ -1002,7 +1002,7 @@ set_result_cb (void *cls,
1002 if (CONSENSUS_MARKER_SIZE == consensus_element->marker) 1002 if (CONSENSUS_MARKER_SIZE == consensus_element->marker)
1003 { 1003 {
1004 1004
1005 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1005 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1006 "P%u: got size marker\n", 1006 "P%u: got size marker\n",
1007 session->local_peer_idx); 1007 session->local_peer_idx);
1008 1008
@@ -1018,7 +1018,7 @@ set_result_cb (void *cls,
1018 uint64_t *copy = GNUNET_memdup (session->first_sizes_received, sizeof (uint64_t) * session->num_peers); 1018 uint64_t *copy = GNUNET_memdup (session->first_sizes_received, sizeof (uint64_t) * session->num_peers);
1019 qsort (copy, session->num_peers, sizeof (uint64_t), cmp_uint64_t); 1019 qsort (copy, session->num_peers, sizeof (uint64_t), cmp_uint64_t);
1020 session->lower_bound = copy[session->num_peers / 3 + 1]; 1020 session->lower_bound = copy[session->num_peers / 3 + 1];
1021 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1021 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1022 "P%u: lower bound %llu\n", 1022 "P%u: lower bound %llu\n",
1023 session->local_peer_idx, 1023 session->local_peer_idx,
1024 (long long) session->lower_bound); 1024 (long long) session->lower_bound);
@@ -1045,7 +1045,7 @@ set_result_cb (void *cls,
1045 NULL, 1045 NULL,
1046 NULL); 1046 NULL);
1047#ifdef GNUNET_EXTRA_LOGGING 1047#ifdef GNUNET_EXTRA_LOGGING
1048 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1048 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1049 "P%u: adding element %s into set {%s} of task {%s}\n", 1049 "P%u: adding element %s into set {%s} of task {%s}\n",
1050 session->local_peer_idx, 1050 session->local_peer_idx,
1051 debug_str_element (element), 1051 debug_str_element (element),
@@ -1057,7 +1057,7 @@ set_result_cb (void *cls,
1057 { 1057 {
1058 diff_insert (output_diff, 1, element); 1058 diff_insert (output_diff, 1, element);
1059#ifdef GNUNET_EXTRA_LOGGING 1059#ifdef GNUNET_EXTRA_LOGGING
1060 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1060 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1061 "P%u: adding element %s into diff {%s} of task {%s}\n", 1061 "P%u: adding element %s into diff {%s} of task {%s}\n",
1062 session->local_peer_idx, 1062 session->local_peer_idx,
1063 debug_str_element (element), 1063 debug_str_element (element),
@@ -1069,7 +1069,7 @@ set_result_cb (void *cls,
1069 { 1069 {
1070 rfn_vote (output_rfn, task_other_peer (task), VOTE_ADD, element); 1070 rfn_vote (output_rfn, task_other_peer (task), VOTE_ADD, element);
1071#ifdef GNUNET_EXTRA_LOGGING 1071#ifdef GNUNET_EXTRA_LOGGING
1072 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1072 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1073 "P%u: adding element %s into rfn {%s} of task {%s}\n", 1073 "P%u: adding element %s into rfn {%s} of task {%s}\n",
1074 session->local_peer_idx, 1074 session->local_peer_idx,
1075 debug_str_element (element), 1075 debug_str_element (element),
@@ -1096,7 +1096,7 @@ set_result_cb (void *cls,
1096 NULL, 1096 NULL,
1097 NULL); 1097 NULL);
1098#ifdef GNUNET_EXTRA_LOGGING 1098#ifdef GNUNET_EXTRA_LOGGING
1099 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1099 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1100 "P%u: removing element %s from set {%s} of task {%s}\n", 1100 "P%u: removing element %s from set {%s} of task {%s}\n",
1101 session->local_peer_idx, 1101 session->local_peer_idx,
1102 debug_str_element (element), 1102 debug_str_element (element),
@@ -1108,7 +1108,7 @@ set_result_cb (void *cls,
1108 { 1108 {
1109 diff_insert (output_diff, -1, element); 1109 diff_insert (output_diff, -1, element);
1110#ifdef GNUNET_EXTRA_LOGGING 1110#ifdef GNUNET_EXTRA_LOGGING
1111 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1111 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1112 "P%u: removing element %s from diff {%s} of task {%s}\n", 1112 "P%u: removing element %s from diff {%s} of task {%s}\n",
1113 session->local_peer_idx, 1113 session->local_peer_idx,
1114 debug_str_element (element), 1114 debug_str_element (element),
@@ -1120,7 +1120,7 @@ set_result_cb (void *cls,
1120 { 1120 {
1121 rfn_vote (output_rfn, task_other_peer (task), VOTE_REMOVE, element); 1121 rfn_vote (output_rfn, task_other_peer (task), VOTE_REMOVE, element);
1122#ifdef GNUNET_EXTRA_LOGGING 1122#ifdef GNUNET_EXTRA_LOGGING
1123 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1124 "P%u: removing element %s from rfn {%s} of task {%s}\n", 1124 "P%u: removing element %s from rfn {%s} of task {%s}\n",
1125 session->local_peer_idx, 1125 session->local_peer_idx,
1126 debug_str_element (element), 1126 debug_str_element (element),
@@ -1133,8 +1133,11 @@ set_result_cb (void *cls,
1133 // XXX: check first if any changes to the underlying 1133 // XXX: check first if any changes to the underlying
1134 // set are still pending 1134 // set are still pending
1135 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1135 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1136 "Finishing setop in Task {%s}\n", 1136 "P%u: Finishing setop in Task {%s} (%u/%u)\n",
1137 debug_str_task_key (&task->key)); 1137 session->local_peer_idx,
1138 debug_str_task_key (&task->key),
1139 (unsigned int) task->step->finished_tasks,
1140 (unsigned int) task->step->tasks_len);
1138 if (NULL != output_rfn) 1141 if (NULL != output_rfn)
1139 { 1142 {
1140 rfn_commit (output_rfn, task_other_peer (task)); 1143 rfn_commit (output_rfn, task_other_peer (task));
@@ -1345,7 +1348,7 @@ commit_set (struct ConsensusSession *session,
1345 .size = 0, 1348 .size = 0,
1346 .sender_index = 0 1349 .sender_index = 0
1347 }; 1350 };
1348 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "inserting size marker\n"); 1351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "inserting size marker\n");
1349 cse.ce.marker = CONSENSUS_MARKER_SIZE; 1352 cse.ce.marker = CONSENSUS_MARKER_SIZE;
1350 cse.size = GNUNET_htonll (session->first_size); 1353 cse.size = GNUNET_htonll (session->first_size);
1351 cse.sender_index = session->local_peer_idx; 1354 cse.sender_index = session->local_peer_idx;
@@ -1421,7 +1424,7 @@ commit_set (struct ConsensusSession *session,
1421 } 1424 }
1422 GNUNET_SET_add_element (set->h, &element, NULL, NULL); 1425 GNUNET_SET_add_element (set->h, &element, NULL, NULL);
1423#ifdef GNUNET_EXTRA_LOGGING 1426#ifdef GNUNET_EXTRA_LOGGING
1424 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1427 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1425 "P%u: evil peer: cramming element %s into set {%s} of task {%s}\n", 1428 "P%u: evil peer: cramming element %s into set {%s} of task {%s}\n",
1426 session->local_peer_idx, 1429 session->local_peer_idx,
1427 debug_str_element (&element), 1430 debug_str_element (&element),
@@ -1436,7 +1439,7 @@ commit_set (struct ConsensusSession *session,
1436 GNUNET_SET_commit (setop->op, set->h); 1439 GNUNET_SET_commit (setop->op, set->h);
1437 break; 1440 break;
1438 case EVILNESS_SLACK: 1441 case EVILNESS_SLACK:
1439 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1442 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1440 "P%u: evil peer: slacking\n", 1443 "P%u: evil peer: slacking\n",
1441 (unsigned int) session->local_peer_idx); 1444 (unsigned int) session->local_peer_idx);
1442 /* Do nothing. */ 1445 /* Do nothing. */
@@ -1470,6 +1473,7 @@ commit_set (struct ConsensusSession *session,
1470 peers to wait. */ 1473 peers to wait. */
1471 GNUNET_SET_operation_cancel (setop->op); 1474 GNUNET_SET_operation_cancel (setop->op);
1472 setop->op = NULL; 1475 setop->op = NULL;
1476 finish_task (task);
1473 } 1477 }
1474#endif 1478#endif
1475} 1479}
@@ -1891,7 +1895,7 @@ task_start_apply_round (struct TaskEntry *task)
1891 ri->element, 1895 ri->element,
1892 &set_mutation_done, 1896 &set_mutation_done,
1893 progress_cls)); 1897 progress_cls));
1894 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1898 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1895 "P%u: apply round: adding element %s with %u-majority.\n", 1899 "P%u: apply round: adding element %s with %u-majority.\n",
1896 session->local_peer_idx, 1900 session->local_peer_idx,
1897 debug_str_element (ri->element), majority_num); 1901 debug_str_element (ri->element), majority_num);
@@ -1903,13 +1907,13 @@ task_start_apply_round (struct TaskEntry *task)
1903 ri->element, 1907 ri->element,
1904 &set_mutation_done, 1908 &set_mutation_done,
1905 progress_cls)); 1909 progress_cls));
1906 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1910 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1907 "P%u: apply round: deleting element %s with %u-majority.\n", 1911 "P%u: apply round: deleting element %s with %u-majority.\n",
1908 session->local_peer_idx, 1912 session->local_peer_idx,
1909 debug_str_element (ri->element), majority_num); 1913 debug_str_element (ri->element), majority_num);
1910 break; 1914 break;
1911 case VOTE_STAY: 1915 case VOTE_STAY:
1912 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1916 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1913 "P%u: apply round: keeping element %s with %u-majority.\n", 1917 "P%u: apply round: keeping element %s with %u-majority.\n",
1914 session->local_peer_idx, 1918 session->local_peer_idx,
1915 debug_str_element (ri->element), majority_num); 1919 debug_str_element (ri->element), majority_num);
@@ -2378,6 +2382,13 @@ finish_task (struct TaskEntry *task)
2378 2382
2379 task->step->finished_tasks++; 2383 task->step->finished_tasks++;
2380 2384
2385 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2386 "P%u: Finishing Task {%s} (now %u/%u tasks finished in step)\n",
2387 task->step->session->local_peer_idx,
2388 debug_str_task_key (&task->key),
2389 (unsigned int) task->step->finished_tasks,
2390 (unsigned int) task->step->tasks_len);
2391
2381 if (task->step->finished_tasks == task->step->tasks_len) 2392 if (task->step->finished_tasks == task->step->tasks_len)
2382 finish_step (task->step); 2393 finish_step (task->step);
2383} 2394}
diff --git a/src/consensus/test_consensus.conf b/src/consensus/test_consensus.conf
index 881251a66..f78b77d09 100644
--- a/src/consensus/test_consensus.conf
+++ b/src/consensus/test_consensus.conf
@@ -5,7 +5,7 @@ GNUNET_TEST_HOME = /tmp/test-consensus/
5#OPTIONS = -L INFO 5#OPTIONS = -L INFO
6BINARY = gnunet-service-evil-consensus 6BINARY = gnunet-service-evil-consensus
7 7
8PREFIX = valgrind 8#PREFIX = valgrind
9 9
10#EVIL_SPEC = 0;cram-all;noreplace;5 10#EVIL_SPEC = 0;cram-all;noreplace;5
11#EVIL_SPEC = 0;cram;5/1;cram;5 11#EVIL_SPEC = 0;cram;5/1;cram;5
diff --git a/src/conversation/test_conversation.conf b/src/conversation/test_conversation.conf
index e0fd8200c..87c4b8f07 100644
--- a/src/conversation/test_conversation.conf
+++ b/src/conversation/test_conversation.conf
@@ -2,7 +2,7 @@
2 2
3[conversation] 3[conversation]
4LINE=1 4LINE=1
5PREFIX = valgrind 5#PREFIX = valgrind
6 6
7[nse] 7[nse]
8WORKBITS = 0 8WORKBITS = 0
diff --git a/src/datacache/Makefile.am b/src/datacache/Makefile.am
index 670a64926..898b51563 100644
--- a/src/datacache/Makefile.am
+++ b/src/datacache/Makefile.am
@@ -71,7 +71,7 @@ libgnunet_plugin_datacache_heap_la_LDFLAGS = \
71libgnunet_plugin_datacache_postgres_la_SOURCES = \ 71libgnunet_plugin_datacache_postgres_la_SOURCES = \
72 plugin_datacache_postgres.c 72 plugin_datacache_postgres.c
73libgnunet_plugin_datacache_postgres_la_LIBADD = \ 73libgnunet_plugin_datacache_postgres_la_LIBADD = \
74 $(top_builddir)/src/postgres/libgnunetpostgres.la \ 74 $(top_builddir)/src/pq/libgnunetpq.la \
75 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 75 $(top_builddir)/src/statistics/libgnunetstatistics.la \
76 $(top_builddir)/src/util/libgnunetutil.la \ 76 $(top_builddir)/src/util/libgnunetutil.la \
77 $(GN_PLUGIN_LDFLAGS) -lpq 77 $(GN_PLUGIN_LDFLAGS) -lpq
diff --git a/src/datacache/plugin_datacache_postgres.c b/src/datacache/plugin_datacache_postgres.c
index 13c2c26a2..5c497cdf8 100644
--- a/src/datacache/plugin_datacache_postgres.c
+++ b/src/datacache/plugin_datacache_postgres.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet 2 This file is part of GNUnet
3 Copyright (C) 2006, 2009, 2010, 2012, 2015 GNUnet e.V. 3 Copyright (C) 2006, 2009, 2010, 2012, 2015, 2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 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 6 it under the terms of the GNU General Public License as published
@@ -25,7 +25,7 @@
25 */ 25 */
26#include "platform.h" 26#include "platform.h"
27#include "gnunet_util_lib.h" 27#include "gnunet_util_lib.h"
28#include "gnunet_postgres_lib.h" 28#include "gnunet_pq_lib.h"
29#include "gnunet_datacache_plugin.h" 29#include "gnunet_datacache_plugin.h"
30 30
31#define LOG(kind,...) GNUNET_log_from (kind, "datacache-postgres", __VA_ARGS__) 31#define LOG(kind,...) GNUNET_log_from (kind, "datacache-postgres", __VA_ARGS__)
@@ -66,115 +66,67 @@ struct Plugin
66static int 66static int
67init_connection (struct Plugin *plugin) 67init_connection (struct Plugin *plugin)
68{ 68{
69 PGresult *ret; 69 struct GNUNET_PQ_ExecuteStatement es[] = {
70 GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS gn090dc ("
71 " type INTEGER NOT NULL DEFAULT 0,"
72 " discard_time BIGINT NOT NULL DEFAULT 0,"
73 " key BYTEA NOT NULL DEFAULT '',"
74 " value BYTEA NOT NULL DEFAULT '',"
75 " path BYTEA DEFAULT '')"
76 "WITH OIDS"),
77 GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS idx_key ON gn090dc (key)"),
78 GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS idx_dt ON gn090dc (discard_time)"),
79 GNUNET_PQ_make_execute ("ALTER TABLE gn090dc ALTER value SET STORAGE EXTERNAL"),
80 GNUNET_PQ_make_execute ("ALTER TABLE gn090dc ALTER key SET STORAGE PLAIN"),
81 GNUNET_PQ_EXECUTE_STATEMENT_END
82 };
83 struct GNUNET_PQ_PreparedStatement ps[] = {
84 GNUNET_PQ_make_prepare ("getkt",
85 "SELECT discard_time,type,value,path FROM gn090dc "
86 "WHERE key=$1 AND type=$2",
87 2),
88 GNUNET_PQ_make_prepare ("getk",
89 "SELECT discard_time,type,value,path FROM gn090dc "
90 "WHERE key=$1",
91 1),
92 GNUNET_PQ_make_prepare ("getm",
93 "SELECT length(value) AS len,oid,key FROM gn090dc "
94 "ORDER BY discard_time ASC LIMIT 1",
95 0),
96 GNUNET_PQ_make_prepare ("get_random",
97 "SELECT discard_time,type,value,path,key FROM gn090dc "
98 "ORDER BY key ASC LIMIT 1 OFFSET $1",
99 1),
100 GNUNET_PQ_make_prepare ("get_closest",
101 "SELECT discard_time,type,value,path,key FROM gn090dc "
102 "WHERE key>=$1 ORDER BY key ASC LIMIT $2",
103 1),
104 GNUNET_PQ_make_prepare ("delrow",
105 "DELETE FROM gn090dc WHERE oid=$1",
106 1),
107 GNUNET_PQ_make_prepare ("put",
108 "INSERT INTO gn090dc (type, discard_time, key, value, path) "
109 "VALUES ($1, $2, $3, $4, $5)",
110 5),
111 GNUNET_PQ_PREPARED_STATEMENT_END
112 };
70 113
71 plugin->dbh = GNUNET_POSTGRES_connect (plugin->env->cfg, 114 plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->env->cfg,
72 "datacache-postgres"); 115 "datacache-postgres");
73 if (NULL == plugin->dbh) 116 if (NULL == plugin->dbh)
74 return GNUNET_SYSERR; 117 return GNUNET_SYSERR;
75 ret =
76 PQexec (plugin->dbh,
77 "CREATE TEMPORARY TABLE IF NOT EXISTS gn090dc ("
78 " type INTEGER NOT NULL DEFAULT 0,"
79 " discard_time BIGINT NOT NULL DEFAULT 0,"
80 " key BYTEA NOT NULL DEFAULT '',"
81 " value BYTEA NOT NULL DEFAULT '',"
82 " path BYTEA DEFAULT '')"
83 "WITH OIDS");
84 if ( (ret == NULL) ||
85 ((PQresultStatus (ret) != PGRES_COMMAND_OK) &&
86 (0 != strcmp ("42P07", /* duplicate table */
87 PQresultErrorField
88 (ret,
89 PG_DIAG_SQLSTATE)))))
90 {
91 (void) GNUNET_POSTGRES_check_result (plugin->dbh, ret,
92 PGRES_COMMAND_OK,
93 "CREATE TABLE",
94 "gn090dc");
95 PQfinish (plugin->dbh);
96 plugin->dbh = NULL;
97 return GNUNET_SYSERR;
98 }
99 if (PQresultStatus (ret) == PGRES_COMMAND_OK)
100 {
101 if ((GNUNET_OK !=
102 GNUNET_POSTGRES_exec (plugin->dbh,
103 "CREATE INDEX IF NOT EXISTS idx_key ON gn090dc (key)")) ||
104 (GNUNET_OK !=
105 GNUNET_POSTGRES_exec (plugin->dbh,
106 "CREATE INDEX IF NOT EXISTS idx_dt ON gn090dc (discard_time)")))
107 {
108 PQclear (ret);
109 PQfinish (plugin->dbh);
110 plugin->dbh = NULL;
111 return GNUNET_SYSERR;
112 }
113 }
114 PQclear (ret);
115 ret =
116 PQexec (plugin->dbh,
117 "ALTER TABLE gn090dc ALTER value SET STORAGE EXTERNAL");
118 if (GNUNET_OK != 118 if (GNUNET_OK !=
119 GNUNET_POSTGRES_check_result (plugin->dbh, 119 GNUNET_PQ_exec_statements (plugin->dbh,
120 ret, 120 es))
121 PGRES_COMMAND_OK,
122 "ALTER TABLE",
123 "gn090dc"))
124 { 121 {
125 PQfinish (plugin->dbh); 122 PQfinish (plugin->dbh);
126 plugin->dbh = NULL; 123 plugin->dbh = NULL;
127 return GNUNET_SYSERR; 124 return GNUNET_SYSERR;
128 } 125 }
129 PQclear (ret); 126
130 ret = PQexec (plugin->dbh,
131 "ALTER TABLE gn090dc ALTER key SET STORAGE PLAIN");
132 if (GNUNET_OK != 127 if (GNUNET_OK !=
133 GNUNET_POSTGRES_check_result (plugin->dbh, 128 GNUNET_PQ_prepare_statements (plugin->dbh,
134 ret, 129 ps))
135 PGRES_COMMAND_OK,
136 "ALTER TABLE",
137 "gn090dc"))
138 {
139 PQfinish (plugin->dbh);
140 plugin->dbh = NULL;
141 return GNUNET_SYSERR;
142 }
143 PQclear (ret);
144 if ((GNUNET_OK !=
145 GNUNET_POSTGRES_prepare (plugin->dbh,
146 "getkt",
147 "SELECT discard_time,type,value,path FROM gn090dc "
148 "WHERE key=$1 AND type=$2 ", 2)) ||
149 (GNUNET_OK !=
150 GNUNET_POSTGRES_prepare (plugin->dbh,
151 "getk",
152 "SELECT discard_time,type,value,path FROM gn090dc "
153 "WHERE key=$1", 1)) ||
154 (GNUNET_OK !=
155 GNUNET_POSTGRES_prepare (plugin->dbh,
156 "getm",
157 "SELECT length(value),oid,key FROM gn090dc "
158 "ORDER BY discard_time ASC LIMIT 1", 0)) ||
159 (GNUNET_OK !=
160 GNUNET_POSTGRES_prepare (plugin->dbh,
161 "get_random",
162 "SELECT discard_time,type,value,path,key FROM gn090dc "
163 "ORDER BY key ASC LIMIT 1 OFFSET $1", 1)) ||
164 (GNUNET_OK !=
165 GNUNET_POSTGRES_prepare (plugin->dbh,
166 "get_closest",
167 "SELECT discard_time,type,value,path,key FROM gn090dc "
168 "WHERE key>=$1 ORDER BY key ASC LIMIT $2", 1)) ||
169 (GNUNET_OK !=
170 GNUNET_POSTGRES_prepare (plugin->dbh,
171 "delrow",
172 "DELETE FROM gn090dc WHERE oid=$1", 1)) ||
173 (GNUNET_OK !=
174 GNUNET_POSTGRES_prepare (plugin->dbh,
175 "put",
176 "INSERT INTO gn090dc (type, discard_time, key, value, path) "
177 "VALUES ($1, $2, $3, $4, $5)", 5)))
178 { 130 {
179 PQfinish (plugin->dbh); 131 PQfinish (plugin->dbh);
180 plugin->dbh = NULL; 132 plugin->dbh = NULL;
@@ -189,7 +141,7 @@ init_connection (struct Plugin *plugin)
189 * 141 *
190 * @param cls closure (our `struct Plugin`) 142 * @param cls closure (our `struct Plugin`)
191 * @param key key to store @a data under 143 * @param key key to store @a data under
192 * @param size number of bytes in @a data 144 * @param data_size number of bytes in @a data
193 * @param data data to store 145 * @param data data to store
194 * @param type type of the value 146 * @param type type of the value
195 * @param discard_time when to discard the value in any case 147 * @param discard_time when to discard the value in any case
@@ -200,7 +152,7 @@ init_connection (struct Plugin *plugin)
200static ssize_t 152static ssize_t
201postgres_plugin_put (void *cls, 153postgres_plugin_put (void *cls,
202 const struct GNUNET_HashCode *key, 154 const struct GNUNET_HashCode *key,
203 size_t size, 155 size_t data_size,
204 const char *data, 156 const char *data,
205 enum GNUNET_BLOCK_Type type, 157 enum GNUNET_BLOCK_Type type,
206 struct GNUNET_TIME_Absolute discard_time, 158 struct GNUNET_TIME_Absolute discard_time,
@@ -208,36 +160,125 @@ postgres_plugin_put (void *cls,
208 const struct GNUNET_PeerIdentity *path_info) 160 const struct GNUNET_PeerIdentity *path_info)
209{ 161{
210 struct Plugin *plugin = cls; 162 struct Plugin *plugin = cls;
211 PGresult *ret; 163 uint32_t type32 = (uint32_t) type;
212 uint32_t btype = htonl (type); 164 struct GNUNET_PQ_QueryParam params[] = {
213 uint64_t bexpi = GNUNET_TIME_absolute_hton (discard_time).abs_value_us__; 165 GNUNET_PQ_query_param_uint32 (&type32),
214 166 GNUNET_PQ_query_param_absolute_time (&discard_time),
215 const char *paramValues[] = { 167 GNUNET_PQ_query_param_auto_from_type (key),
216 (const char *) &btype, 168 GNUNET_PQ_query_param_fixed_size (data, data_size),
217 (const char *) &bexpi, 169 GNUNET_PQ_query_param_fixed_size (path_info,
218 (const char *) key, 170 path_info_len * sizeof (struct GNUNET_PeerIdentity)),
219 (const char *) data, 171 GNUNET_PQ_query_param_end
220 (const char *) path_info
221 };
222 int paramLengths[] = {
223 sizeof (btype),
224 sizeof (bexpi),
225 sizeof (struct GNUNET_HashCode),
226 size,
227 path_info_len * sizeof (struct GNUNET_PeerIdentity)
228 }; 172 };
229 const int paramFormats[] = { 1, 1, 1, 1, 1 }; 173 enum GNUNET_DB_QueryStatus ret;
230 174
231 ret = 175 ret = GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
232 PQexecPrepared (plugin->dbh, "put", 5, paramValues, paramLengths, 176 "put",
233 paramFormats, 1); 177 params);
234 if (GNUNET_OK != 178 if (0 > ret)
235 GNUNET_POSTGRES_check_result (plugin->dbh, ret,
236 PGRES_COMMAND_OK, "PQexecPrepared", "put"))
237 return -1; 179 return -1;
238 plugin->num_items++; 180 plugin->num_items++;
239 PQclear (ret); 181 return data_size + OVERHEAD;
240 return size + OVERHEAD; 182}
183
184
185/**
186 * Closure for #handle_results.
187 */
188struct HandleResultContext
189{
190
191 /**
192 * Function to call on each result, may be NULL.
193 */
194 GNUNET_DATACACHE_Iterator iter;
195
196 /**
197 * Closure for @e iter.
198 */
199 void *iter_cls;
200
201 /**
202 * Key used.
203 */
204 const struct GNUNET_HashCode *key;
205};
206
207
208/**
209 * Function to be called with the results of a SELECT statement
210 * that has returned @a num_results results. Parse the result
211 * and call the callback given in @a cls
212 *
213 * @param cls closure of type `struct HandleResultContext`
214 * @param result the postgres result
215 * @param num_result the number of results in @a result
216 */
217static void
218handle_results (void *cls,
219 PGresult *result,
220 unsigned int num_results)
221{
222 struct HandleResultContext *hrc = cls;
223
224 for (unsigned int i=0;i<num_results;i++)
225 {
226 struct GNUNET_TIME_Absolute expiration_time;
227 uint32_t type;
228 void *data;
229 size_t data_size;
230 struct GNUNET_PeerIdentity *path;
231 size_t path_len;
232 struct GNUNET_PQ_ResultSpec rs[] = {
233 GNUNET_PQ_result_spec_absolute_time ("discard_time",
234 &expiration_time),
235 GNUNET_PQ_result_spec_uint32 ("type",
236 &type),
237 GNUNET_PQ_result_spec_variable_size ("value",
238 &data,
239 &data_size),
240 GNUNET_PQ_result_spec_variable_size ("path",
241 (void **) &path,
242 &path_len),
243 GNUNET_PQ_result_spec_end
244 };
245
246 if (GNUNET_YES !=
247 GNUNET_PQ_extract_result (result,
248 rs,
249 i))
250 {
251 GNUNET_break (0);
252 return;
253 }
254 if (0 != (path_len % sizeof (struct GNUNET_PeerIdentity)))
255 {
256 GNUNET_break (0);
257 path_len = 0;
258 }
259 path_len %= sizeof (struct GNUNET_PeerIdentity);
260 LOG (GNUNET_ERROR_TYPE_DEBUG,
261 "Found result of size %u bytes and type %u in database\n",
262 (unsigned int) data_size,
263 (unsigned int) type);
264 if ( (NULL != hrc->iter) &&
265 (GNUNET_SYSERR ==
266 hrc->iter (hrc->iter_cls,
267 hrc->key,
268 data_size,
269 data,
270 (enum GNUNET_BLOCK_Type) type,
271 expiration_time,
272 path_len,
273 path)) )
274 {
275 LOG (GNUNET_ERROR_TYPE_DEBUG,
276 "Ending iteration (client error)\n");
277 GNUNET_PQ_cleanup_result (rs);
278 return;
279 }
280 GNUNET_PQ_cleanup_result (rs);
281 }
241} 282}
242 283
243 284
@@ -260,94 +301,30 @@ postgres_plugin_get (void *cls,
260 void *iter_cls) 301 void *iter_cls)
261{ 302{
262 struct Plugin *plugin = cls; 303 struct Plugin *plugin = cls;
263 uint32_t btype = htonl (type); 304 uint32_t type32 = (uint32_t) type;
264 305 struct GNUNET_PQ_QueryParam paramk[] = {
265 const char *paramValues[] = { 306 GNUNET_PQ_query_param_auto_from_type (key),
266 (const char *) key, 307 GNUNET_PQ_query_param_end
267 (const char *) &btype
268 }; 308 };
269 int paramLengths[] = { 309 struct GNUNET_PQ_QueryParam paramkt[] = {
270 sizeof (struct GNUNET_HashCode), 310 GNUNET_PQ_query_param_auto_from_type (key),
271 sizeof (btype) 311 GNUNET_PQ_query_param_uint32 (&type32),
312 GNUNET_PQ_query_param_end
272 }; 313 };
273 const int paramFormats[] = { 1, 1 }; 314 enum GNUNET_DB_QueryStatus res;
274 struct GNUNET_TIME_Absolute expiration_time; 315 struct HandleResultContext hr_ctx;
275 uint32_t size; 316
276 unsigned int cnt; 317 hr_ctx.iter = iter;
277 unsigned int i; 318 hr_ctx.iter_cls = iter_cls;
278 unsigned int path_len; 319 hr_ctx.key = key;
279 const struct GNUNET_PeerIdentity *path; 320 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
280 PGresult *res; 321 (0 == type) ? "getk" : "getkt",
281 322 (0 == type) ? paramk : paramkt,
282 res = 323 &handle_results,
283 PQexecPrepared (plugin->dbh, (type == 0) ? "getk" : "getkt", 324 &hr_ctx);
284 (type == 0) ? 1 : 2, paramValues, paramLengths, 325 if (res < 0)
285 paramFormats, 1);
286 if (GNUNET_OK !=
287 GNUNET_POSTGRES_check_result (plugin->dbh,
288 res,
289 PGRES_TUPLES_OK,
290 "PQexecPrepared",
291 (type == 0) ? "getk" : "getkt"))
292 {
293 LOG (GNUNET_ERROR_TYPE_DEBUG,
294 "Ending iteration (postgres error)\n");
295 return 0; 326 return 0;
296 } 327 return res;
297
298 if (0 == (cnt = PQntuples (res)))
299 {
300 /* no result */
301 LOG (GNUNET_ERROR_TYPE_DEBUG,
302 "Ending iteration (no more results)\n");
303 PQclear (res);
304 return 0;
305 }
306 if (iter == NULL)
307 {
308 PQclear (res);
309 return cnt;
310 }
311 if ( (4 != PQnfields (res)) ||
312 (sizeof (uint64_t) != PQfsize (res, 0)) ||
313 (sizeof (uint32_t) != PQfsize (res, 1)))
314 {
315 GNUNET_break (0);
316 PQclear (res);
317 return 0;
318 }
319 for (i = 0; i < cnt; i++)
320 {
321 expiration_time.abs_value_us =
322 GNUNET_ntohll (*(uint64_t *) PQgetvalue (res, i, 0));
323 type = ntohl (*(uint32_t *) PQgetvalue (res, i, 1));
324 size = PQgetlength (res, i, 2);
325 path_len = PQgetlength (res, i, 3);
326 if (0 != (path_len % sizeof (struct GNUNET_PeerIdentity)))
327 {
328 GNUNET_break (0);
329 path_len = 0;
330 }
331 path_len %= sizeof (struct GNUNET_PeerIdentity);
332 path = (const struct GNUNET_PeerIdentity *) PQgetvalue (res, i, 3);
333 LOG (GNUNET_ERROR_TYPE_DEBUG,
334 "Found result of size %u bytes and type %u in database\n",
335 (unsigned int) size, (unsigned int) type);
336 if (GNUNET_SYSERR ==
337 iter (iter_cls, key, size, PQgetvalue (res, i, 2),
338 (enum GNUNET_BLOCK_Type) type,
339 expiration_time,
340 path_len,
341 path))
342 {
343 LOG (GNUNET_ERROR_TYPE_DEBUG,
344 "Ending iteration (client error)\n");
345 PQclear (res);
346 return cnt;
347 }
348 }
349 PQclear (res);
350 return cnt;
351} 328}
352 329
353 330
@@ -362,54 +339,53 @@ static int
362postgres_plugin_del (void *cls) 339postgres_plugin_del (void *cls)
363{ 340{
364 struct Plugin *plugin = cls; 341 struct Plugin *plugin = cls;
342 struct GNUNET_PQ_QueryParam pempty[] = {
343 GNUNET_PQ_query_param_end
344 };
365 uint32_t size; 345 uint32_t size;
366 uint32_t oid; 346 uint32_t oid;
367 struct GNUNET_HashCode key; 347 struct GNUNET_HashCode key;
368 PGresult *res; 348 struct GNUNET_PQ_ResultSpec rs[] = {
349 GNUNET_PQ_result_spec_uint32 ("len",
350 &size),
351 GNUNET_PQ_result_spec_uint32 ("oid",
352 &oid),
353 GNUNET_PQ_result_spec_auto_from_type ("key",
354 &key),
355 GNUNET_PQ_result_spec_end
356 };
357 enum GNUNET_DB_QueryStatus res;
358 struct GNUNET_PQ_QueryParam dparam[] = {
359 GNUNET_PQ_query_param_uint32 (&oid),
360 GNUNET_PQ_query_param_end
361 };
369 362
370 res = PQexecPrepared (plugin->dbh, 363 res = GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh,
371 "getm", 364 "getm",
372 0, NULL, NULL, NULL, 1); 365 pempty,
373 if (GNUNET_OK != 366 rs);
374 GNUNET_POSTGRES_check_result (plugin->dbh, 367 if (0 > res)
375 res, 368 return GNUNET_SYSERR;
376 PGRES_TUPLES_OK, 369 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == res)
377 "PQexecPrepared",
378 "getm"))
379 {
380 LOG (GNUNET_ERROR_TYPE_DEBUG,
381 "Ending iteration (postgres error)\n");
382 return 0;
383 }
384 if (0 == PQntuples (res))
385 { 370 {
386 /* no result */ 371 /* no result */
387 LOG (GNUNET_ERROR_TYPE_DEBUG, 372 LOG (GNUNET_ERROR_TYPE_DEBUG,
388 "Ending iteration (no more results)\n"); 373 "Ending iteration (no more results)\n");
389 PQclear (res);
390 return GNUNET_SYSERR;
391 }
392 if ((3 != PQnfields (res)) || (sizeof (size) != PQfsize (res, 0)) ||
393 (sizeof (oid) != PQfsize (res, 1)) ||
394 (sizeof (struct GNUNET_HashCode) != PQgetlength (res, 0, 2)))
395 {
396 GNUNET_break (0);
397 PQclear (res);
398 return 0; 374 return 0;
399 } 375 }
400 size = ntohl (*(uint32_t *) PQgetvalue (res, 0, 0)); 376 res = GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
401 oid = ntohl (*(uint32_t *) PQgetvalue (res, 0, 1)); 377 "delrow",
402 GNUNET_memcpy (&key, PQgetvalue (res, 0, 2), sizeof (struct GNUNET_HashCode)); 378 dparam);
403 PQclear (res); 379 if (0 > res)
404 if (GNUNET_OK != 380 {
405 GNUNET_POSTGRES_delete_by_rowid (plugin->dbh, 381 GNUNET_PQ_cleanup_result (rs);
406 "delrow",
407 oid))
408 return GNUNET_SYSERR; 382 return GNUNET_SYSERR;
383 }
409 plugin->num_items--; 384 plugin->num_items--;
410 plugin->env->delete_notify (plugin->env->cls, 385 plugin->env->delete_notify (plugin->env->cls,
411 &key, 386 &key,
412 size + OVERHEAD); 387 size + OVERHEAD);
388 GNUNET_PQ_cleanup_result (rs);
413 return GNUNET_OK; 389 return GNUNET_OK;
414} 390}
415 391
@@ -428,22 +404,34 @@ postgres_plugin_get_random (void *cls,
428 void *iter_cls) 404 void *iter_cls)
429{ 405{
430 struct Plugin *plugin = cls; 406 struct Plugin *plugin = cls;
431 unsigned int off; 407 uint32_t off;
432 uint32_t off_be;
433 struct GNUNET_TIME_Absolute expiration_time; 408 struct GNUNET_TIME_Absolute expiration_time;
434 uint32_t size; 409 size_t data_size;
435 unsigned int path_len; 410 void *data;
436 const struct GNUNET_PeerIdentity *path; 411 size_t path_len;
437 const struct GNUNET_HashCode *key; 412 struct GNUNET_PeerIdentity *path;
438 unsigned int type; 413 struct GNUNET_HashCode key;
439 PGresult *res; 414 uint32_t type;
440 const char *paramValues[] = { 415 enum GNUNET_DB_QueryStatus res;
441 (const char *) &off_be 416 struct GNUNET_PQ_QueryParam params[] = {
417 GNUNET_PQ_query_param_uint32 (&off),
418 GNUNET_PQ_query_param_end
442 }; 419 };
443 int paramLengths[] = { 420 struct GNUNET_PQ_ResultSpec rs[] = {
444 sizeof (off_be) 421 GNUNET_PQ_result_spec_absolute_time ("discard_time",
422 &expiration_time),
423 GNUNET_PQ_result_spec_uint32 ("type",
424 &type),
425 GNUNET_PQ_result_spec_variable_size ("value",
426 &data,
427 &data_size),
428 GNUNET_PQ_result_spec_variable_size ("path",
429 (void **) &path,
430 &path_len),
431 GNUNET_PQ_result_spec_auto_from_type ("key",
432 &key),
433 GNUNET_PQ_result_spec_end
445 }; 434 };
446 const int paramFormats[] = { 1 };
447 435
448 if (0 == plugin->num_items) 436 if (0 == plugin->num_items)
449 return 0; 437 return 0;
@@ -451,67 +439,136 @@ postgres_plugin_get_random (void *cls,
451 return 1; 439 return 1;
452 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, 440 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
453 plugin->num_items); 441 plugin->num_items);
454 off_be = htonl (off); 442 res = GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh,
455 res = 443 "get_random",
456 PQexecPrepared (plugin->dbh, "get_random", 444 params,
457 1, paramValues, paramLengths, paramFormats, 445 rs);
458 1); 446 if (0 > res)
459 if (GNUNET_OK !=
460 GNUNET_POSTGRES_check_result (plugin->dbh,
461 res,
462 PGRES_TUPLES_OK,
463 "PQexecPrepared",
464 "get_random"))
465 { 447 {
466 GNUNET_break (0); 448 GNUNET_break (0);
467 return 0; 449 return 0;
468 } 450 }
469 if (0 == PQntuples (res)) 451 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == res)
470 { 452 {
471 GNUNET_break (0); 453 GNUNET_break (0);
472 return 0; 454 return 0;
473 } 455 }
474 if ( (5 != PQnfields (res)) ||
475 (sizeof (uint64_t) != PQfsize (res, 0)) ||
476 (sizeof (uint32_t) != PQfsize (res, 1)) ||
477 (sizeof (struct GNUNET_HashCode) != PQfsize (res, 4)) )
478 {
479 GNUNET_break (0);
480 PQclear (res);
481 return 0;
482 }
483 expiration_time.abs_value_us =
484 GNUNET_ntohll (*(uint64_t *) PQgetvalue (res, 0, 0));
485 type = ntohl (*(uint32_t *) PQgetvalue (res, 0, 1));
486 size = PQgetlength (res, 0, 2);
487 path_len = PQgetlength (res, 0, 3);
488 if (0 != (path_len % sizeof (struct GNUNET_PeerIdentity))) 456 if (0 != (path_len % sizeof (struct GNUNET_PeerIdentity)))
489 { 457 {
490 GNUNET_break (0); 458 GNUNET_break (0);
491 path_len = 0; 459 path_len = 0;
492 } 460 }
493 path_len %= sizeof (struct GNUNET_PeerIdentity); 461 path_len %= sizeof (struct GNUNET_PeerIdentity);
494 path = (const struct GNUNET_PeerIdentity *) PQgetvalue (res, 0, 3);
495 key = (const struct GNUNET_HashCode *) PQgetvalue (res, 0, 4);
496 LOG (GNUNET_ERROR_TYPE_DEBUG, 462 LOG (GNUNET_ERROR_TYPE_DEBUG,
497 "Found random value with key %s of size %u bytes and type %u in database\n", 463 "Found random value with key %s of size %u bytes and type %u in database\n",
498 GNUNET_h2s (key), 464 GNUNET_h2s (&key),
499 (unsigned int) size, 465 (unsigned int) data_size,
500 (unsigned int) type); 466 (unsigned int) type);
501 (void) iter (iter_cls, 467 (void) iter (iter_cls,
502 key, 468 &key,
503 size, 469 data_size,
504 PQgetvalue (res, 0, 2), 470 data,
505 (enum GNUNET_BLOCK_Type) type, 471 (enum GNUNET_BLOCK_Type) type,
506 expiration_time, 472 expiration_time,
507 path_len, 473 path_len,
508 path); 474 path);
509 PQclear (res); 475 GNUNET_PQ_cleanup_result (rs);
510 return 1; 476 return 1;
511} 477}
512 478
513 479
514/** 480/**
481 * Closure for #extract_result_cb.
482 */
483struct ExtractResultContext
484{
485 /**
486 * Function to call for each result found.
487 */
488 GNUNET_DATACACHE_Iterator iter;
489
490 /**
491 * Closure for @e iter.
492 */
493 void *iter_cls;
494
495};
496
497
498/**
499 * Function to be called with the results of a SELECT statement
500 * that has returned @a num_results results. Calls the `iter`
501 * from @a cls for each result.
502 *
503 * @param cls closure with the `struct ExtractResultContext`
504 * @param result the postgres result
505 * @param num_result the number of results in @a result
506 */
507static void
508extract_result_cb (void *cls,
509 PGresult *result,
510 unsigned int num_results)
511{
512 struct ExtractResultContext *erc = cls;
513
514 if (NULL == erc->iter)
515 return;
516 for (unsigned int i=0;i<num_results;i++)
517 {
518 struct GNUNET_TIME_Absolute expiration_time;
519 uint32_t type;
520 void *data;
521 size_t data_size;
522 struct GNUNET_PeerIdentity *path;
523 size_t path_len;
524 struct GNUNET_HashCode key;
525 struct GNUNET_PQ_ResultSpec rs[] = {
526 GNUNET_PQ_result_spec_absolute_time ("",
527 &expiration_time),
528 GNUNET_PQ_result_spec_uint32 ("type",
529 &type),
530 GNUNET_PQ_result_spec_variable_size ("value",
531 &data,
532 &data_size),
533 GNUNET_PQ_result_spec_variable_size ("path",
534 (void **) &path,
535 &path_len),
536 GNUNET_PQ_result_spec_auto_from_type ("key",
537 &key),
538 GNUNET_PQ_result_spec_end
539 };
540
541 if (0 != (path_len % sizeof (struct GNUNET_PeerIdentity)))
542 {
543 GNUNET_break (0);
544 path_len = 0;
545 }
546 path_len %= sizeof (struct GNUNET_PeerIdentity);
547 LOG (GNUNET_ERROR_TYPE_DEBUG,
548 "Found result of size %u bytes and type %u in database\n",
549 (unsigned int) data_size,
550 (unsigned int) type);
551 if (GNUNET_SYSERR ==
552 erc->iter (erc->iter_cls,
553 &key,
554 data_size,
555 data,
556 (enum GNUNET_BLOCK_Type) type,
557 expiration_time,
558 path_len,
559 path))
560 {
561 LOG (GNUNET_ERROR_TYPE_DEBUG,
562 "Ending iteration (client error)\n");
563 GNUNET_PQ_cleanup_result (rs);
564 break;
565 }
566 GNUNET_PQ_cleanup_result (rs);
567 }
568}
569
570
571/**
515 * Iterate over the results that are "close" to a particular key in 572 * Iterate over the results that are "close" to a particular key in
516 * the datacache. "close" is defined as numerically larger than @a 573 * the datacache. "close" is defined as numerically larger than @a
517 * key (when interpreted as a circular address space), with small 574 * key (when interpreted as a circular address space), with small
@@ -532,105 +589,36 @@ postgres_plugin_get_closest (void *cls,
532 void *iter_cls) 589 void *iter_cls)
533{ 590{
534 struct Plugin *plugin = cls; 591 struct Plugin *plugin = cls;
535 uint32_t nbo_limit = htonl (num_results); 592 uint32_t num_results32 = (uint32_t) num_results;
536 const char *paramValues[] = { 593 struct GNUNET_PQ_QueryParam params[] = {
537 (const char *) key, 594 GNUNET_PQ_query_param_auto_from_type (key),
538 (const char *) &nbo_limit, 595 GNUNET_PQ_query_param_uint32 (&num_results32),
596 GNUNET_PQ_query_param_end
539 }; 597 };
540 int paramLengths[] = { 598 enum GNUNET_DB_QueryStatus res;
541 sizeof (struct GNUNET_HashCode), 599 struct ExtractResultContext erc;
542 sizeof (nbo_limit) 600
543 601 erc.iter = iter;
544 }; 602 erc.iter_cls = iter_cls;
545 const int paramFormats[] = { 1, 1 }; 603 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
546 struct GNUNET_TIME_Absolute expiration_time; 604 "get_closest",
547 uint32_t size; 605 params,
548 unsigned int type; 606 &extract_result_cb,
549 unsigned int cnt; 607 &erc);
550 unsigned int i; 608 if (0 > res)
551 unsigned int path_len;
552 const struct GNUNET_PeerIdentity *path;
553 PGresult *res;
554
555 res =
556 PQexecPrepared (plugin->dbh,
557 "get_closest",
558 2,
559 paramValues,
560 paramLengths,
561 paramFormats,
562 1);
563 if (GNUNET_OK !=
564 GNUNET_POSTGRES_check_result (plugin->dbh,
565 res,
566 PGRES_TUPLES_OK,
567 "PQexecPrepared",
568 "get_closest"))
569 { 609 {
570 LOG (GNUNET_ERROR_TYPE_DEBUG, 610 LOG (GNUNET_ERROR_TYPE_DEBUG,
571 "Ending iteration (postgres error)\n"); 611 "Ending iteration (postgres error)\n");
572 return 0; 612 return 0;
573 } 613 }
574 614 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == res)
575 if (0 == (cnt = PQntuples (res)))
576 { 615 {
577 /* no result */ 616 /* no result */
578 LOG (GNUNET_ERROR_TYPE_DEBUG, 617 LOG (GNUNET_ERROR_TYPE_DEBUG,
579 "Ending iteration (no more results)\n"); 618 "Ending iteration (no more results)\n");
580 PQclear (res);
581 return 0; 619 return 0;
582 } 620 }
583 if (NULL == iter) 621 return res;
584 {
585 PQclear (res);
586 return cnt;
587 }
588 if ( (5 != PQnfields (res)) ||
589 (sizeof (uint64_t) != PQfsize (res, 0)) ||
590 (sizeof (uint32_t) != PQfsize (res, 1)) ||
591 (sizeof (struct GNUNET_HashCode) != PQfsize (res, 4)) )
592 {
593 GNUNET_break (0);
594 PQclear (res);
595 return 0;
596 }
597 for (i = 0; i < cnt; i++)
598 {
599 expiration_time.abs_value_us =
600 GNUNET_ntohll (*(uint64_t *) PQgetvalue (res, i, 0));
601 type = ntohl (*(uint32_t *) PQgetvalue (res, i, 1));
602 size = PQgetlength (res, i, 2);
603 path_len = PQgetlength (res, i, 3);
604 if (0 != (path_len % sizeof (struct GNUNET_PeerIdentity)))
605 {
606 GNUNET_break (0);
607 path_len = 0;
608 }
609 path_len %= sizeof (struct GNUNET_PeerIdentity);
610 path = (const struct GNUNET_PeerIdentity *) PQgetvalue (res, i, 3);
611 key = (const struct GNUNET_HashCode *) PQgetvalue (res, i, 4);
612 LOG (GNUNET_ERROR_TYPE_DEBUG,
613 "Found result of size %u bytes and type %u in database\n",
614 (unsigned int) size,
615 (unsigned int) type);
616 if (GNUNET_SYSERR ==
617 iter (iter_cls,
618 key,
619 size,
620 PQgetvalue (res, i, 2),
621 (enum GNUNET_BLOCK_Type) type,
622 expiration_time,
623 path_len,
624 path))
625 {
626 LOG (GNUNET_ERROR_TYPE_DEBUG,
627 "Ending iteration (client error)\n");
628 PQclear (res);
629 return cnt;
630 }
631 }
632 PQclear (res);
633 return cnt;
634} 622}
635 623
636 624
diff --git a/src/datastore/Makefile.am b/src/datastore/Makefile.am
index 9b8cf365f..240abbc67 100644
--- a/src/datastore/Makefile.am
+++ b/src/datastore/Makefile.am
@@ -148,7 +148,6 @@ libgnunet_plugin_datastore_postgres_la_SOURCES = \
148 plugin_datastore_postgres.c 148 plugin_datastore_postgres.c
149libgnunet_plugin_datastore_postgres_la_LIBADD = \ 149libgnunet_plugin_datastore_postgres_la_LIBADD = \
150 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 150 $(top_builddir)/src/statistics/libgnunetstatistics.la \
151 $(top_builddir)/src/postgres/libgnunetpostgres.la \
152 $(top_builddir)/src/pq/libgnunetpq.la \ 151 $(top_builddir)/src/pq/libgnunetpq.la \
153 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq 152 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq
154libgnunet_plugin_datastore_postgres_la_LDFLAGS = \ 153libgnunet_plugin_datastore_postgres_la_LDFLAGS = \
diff --git a/src/datastore/plugin_datastore_postgres.c b/src/datastore/plugin_datastore_postgres.c
index b6aeb0be6..fd1a533bb 100644
--- a/src/datastore/plugin_datastore_postgres.c
+++ b/src/datastore/plugin_datastore_postgres.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet 2 This file is part of GNUnet
3 Copyright (C) 2009-2016 GNUnet e.V. 3 Copyright (C) 2009-2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify 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 6 it under the terms of the GNU General Public License as published
@@ -23,10 +23,8 @@
23 * @brief postgres-based datastore backend 23 * @brief postgres-based datastore backend
24 * @author Christian Grothoff 24 * @author Christian Grothoff
25 */ 25 */
26
27#include "platform.h" 26#include "platform.h"
28#include "gnunet_datastore_plugin.h" 27#include "gnunet_datastore_plugin.h"
29#include "gnunet_postgres_lib.h"
30#include "gnunet_pq_lib.h" 28#include "gnunet_pq_lib.h"
31 29
32 30
@@ -70,160 +68,106 @@ struct Plugin
70static int 68static int
71init_connection (struct Plugin *plugin) 69init_connection (struct Plugin *plugin)
72{ 70{
73 PGresult *ret; 71 struct GNUNET_PQ_ExecuteStatement es[] = {
72 /* FIXME: PostgreSQL does not have unsigned integers! This is ok for the type column because
73 * we only test equality on it and can cast it to/from uint32_t. For repl, prio, and anonLevel
74 * we do math or inequality tests, so we can't handle the entire range of uint32_t.
75 * This will also cause problems for expiration times after 294247-01-10-04:00:54 UTC.
76 * PostgreSQL also recommends against using WITH OIDS.
77 */
78 GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS gn090 ("
79 " repl INTEGER NOT NULL DEFAULT 0,"
80 " type INTEGER NOT NULL DEFAULT 0,"
81 " prio INTEGER NOT NULL DEFAULT 0,"
82 " anonLevel INTEGER NOT NULL DEFAULT 0,"
83 " expire BIGINT NOT NULL DEFAULT 0,"
84 " rvalue BIGINT NOT NULL DEFAULT 0,"
85 " hash BYTEA NOT NULL DEFAULT '',"
86 " vhash BYTEA NOT NULL DEFAULT '',"
87 " value BYTEA NOT NULL DEFAULT '')"
88 "WITH OIDS"),
89 GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS idx_hash ON gn090 (hash)"),
90 GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS idx_prio ON gn090 (prio)"),
91 GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS idx_expire ON gn090 (expire)"),
92 GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS idx_prio_anon ON gn090 (prio,anonLevel)"),
93 GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS idx_prio_hash_anon ON gn090 (prio,hash,anonLevel)"),
94 GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS idx_repl_rvalue ON gn090 (repl,rvalue)"),
95 GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS idx_expire_hash ON gn090 (expire,hash)"),
96 GNUNET_PQ_make_execute ("ALTER TABLE gn090 ALTER value SET STORAGE EXTERNAL"),
97 GNUNET_PQ_make_execute ("ALTER TABLE gn090 ALTER hash SET STORAGE PLAIN"),
98 GNUNET_PQ_make_execute ("ALTER TABLE gn090 ALTER vhash SET STORAGE PLAIN"),
99 GNUNET_PQ_EXECUTE_STATEMENT_END
100 };
101#define RESULT_COLUMNS "repl, type, prio, anonLevel, expire, hash, value, oid"
102 struct GNUNET_PQ_PreparedStatement ps[] = {
103 GNUNET_PQ_make_prepare ("get",
104 "SELECT " RESULT_COLUMNS " FROM gn090 "
105 "WHERE oid >= $1::bigint AND "
106 "(rvalue >= $2 OR 0 = $3::smallint) AND "
107 "(hash = $4 OR 0 = $5::smallint) AND "
108 "(type = $6 OR 0 = $7::smallint) "
109 "ORDER BY oid ASC LIMIT 1",
110 7),
111 GNUNET_PQ_make_prepare ("put",
112 "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) "
113 "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
114 9),
115 GNUNET_PQ_make_prepare ("update",
116 "UPDATE gn090 "
117 "SET prio = prio + $1, "
118 "repl = repl + $2, "
119 "expire = GREATEST(expire, $3) "
120 "WHERE hash = $4 AND vhash = $5",
121 5),
122 GNUNET_PQ_make_prepare ("decrepl",
123 "UPDATE gn090 SET repl = GREATEST (repl - 1, 0) "
124 "WHERE oid = $1",
125 1),
126 GNUNET_PQ_make_prepare ("select_non_anonymous",
127 "SELECT " RESULT_COLUMNS " FROM gn090 "
128 "WHERE anonLevel = 0 AND type = $1 AND oid >= $2::bigint "
129 "ORDER BY oid ASC LIMIT 1",
130 2),
131 GNUNET_PQ_make_prepare ("select_expiration_order",
132 "(SELECT " RESULT_COLUMNS " FROM gn090 "
133 "WHERE expire < $1 ORDER BY prio ASC LIMIT 1) "
134 "UNION "
135 "(SELECT " RESULT_COLUMNS " FROM gn090 "
136 "ORDER BY prio ASC LIMIT 1) "
137 "ORDER BY expire ASC LIMIT 1",
138 1),
139 GNUNET_PQ_make_prepare ("select_replication_order",
140 "SELECT " RESULT_COLUMNS " FROM gn090 "
141 "ORDER BY repl DESC,RANDOM() LIMIT 1",
142 0),
143 GNUNET_PQ_make_prepare ("delrow",
144 "DELETE FROM gn090 " "WHERE oid=$1",
145 1),
146 GNUNET_PQ_make_prepare ("remove", "DELETE FROM gn090 "
147 "WHERE hash = $1 AND "
148 "value = $2",
149 2),
150 GNUNET_PQ_make_prepare ("get_keys",
151 "SELECT hash FROM gn090",
152 0),
153 GNUNET_PQ_make_prepare ("estimate_size",
154 "SELECT SUM(LENGTH(value))+256*COUNT(*) AS total FROM gn090",
155 0),
156 GNUNET_PQ_PREPARED_STATEMENT_END
157 };
158#undef RESULT_COLUMNS
74 159
75 plugin->dbh = GNUNET_POSTGRES_connect (plugin->env->cfg, "datastore-postgres"); 160 plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->env->cfg,
161 "datastore-postgres");
76 if (NULL == plugin->dbh) 162 if (NULL == plugin->dbh)
77 return GNUNET_SYSERR; 163 return GNUNET_SYSERR;
78 164
79 /* FIXME: PostgreSQL does not have unsigned integers! This is ok for the type column because 165 if ( (GNUNET_OK !=
80 * we only test equality on it and can cast it to/from uint32_t. For repl, prio, and anonLevel 166 GNUNET_PQ_exec_statements (plugin->dbh,
81 * we do math or inequality tests, so we can't handle the entire range of uint32_t. 167 es)) ||
82 * This will also cause problems for expiration times after 294247-01-10-04:00:54 UTC. 168 (GNUNET_OK !=
83 * PostgreSQL also recommends against using WITH OIDS. 169 GNUNET_PQ_prepare_statements (plugin->dbh,
84 */ 170 ps)) )
85 ret =
86 PQexec (plugin->dbh,
87 "CREATE TABLE IF NOT EXISTS gn090 ("
88 " repl INTEGER NOT NULL DEFAULT 0,"
89 " type INTEGER NOT NULL DEFAULT 0,"
90 " prio INTEGER NOT NULL DEFAULT 0,"
91 " anonLevel INTEGER NOT NULL DEFAULT 0,"
92 " expire BIGINT NOT NULL DEFAULT 0,"
93 " rvalue BIGINT NOT NULL DEFAULT 0,"
94 " hash BYTEA NOT NULL DEFAULT '',"
95 " vhash BYTEA NOT NULL DEFAULT '',"
96 " value BYTEA NOT NULL DEFAULT '')"
97 "WITH OIDS");
98 if ( (NULL == ret) ||
99 ((PQresultStatus (ret) != PGRES_COMMAND_OK) &&
100 (0 != strcmp ("42P07", /* duplicate table */
101 PQresultErrorField
102 (ret,
103 PG_DIAG_SQLSTATE)))))
104 {
105 (void) GNUNET_POSTGRES_check_result (plugin->dbh,
106 ret,
107 PGRES_COMMAND_OK,
108 "CREATE TABLE",
109 "gn090");
110 PQfinish (plugin->dbh);
111 plugin->dbh = NULL;
112 return GNUNET_SYSERR;
113 }
114
115 if (PQresultStatus (ret) == PGRES_COMMAND_OK)
116 {
117 if ((GNUNET_OK !=
118 GNUNET_POSTGRES_exec (plugin->dbh,
119 "CREATE INDEX IF NOT EXISTS idx_hash ON gn090 (hash)")) ||
120 (GNUNET_OK !=
121 GNUNET_POSTGRES_exec (plugin->dbh,
122 "CREATE INDEX IF NOT EXISTS idx_prio ON gn090 (prio)")) ||
123 (GNUNET_OK !=
124 GNUNET_POSTGRES_exec (plugin->dbh,
125 "CREATE INDEX IF NOT EXISTS idx_expire ON gn090 (expire)")) ||
126 (GNUNET_OK !=
127 GNUNET_POSTGRES_exec (plugin->dbh,
128 "CREATE INDEX IF NOT EXISTS idx_prio_anon ON gn090 (prio,anonLevel)")) ||
129 (GNUNET_OK !=
130 GNUNET_POSTGRES_exec (plugin->dbh,
131 "CREATE INDEX IF NOT EXISTS idx_prio_hash_anon ON gn090 (prio,hash,anonLevel)")) ||
132 (GNUNET_OK !=
133 GNUNET_POSTGRES_exec (plugin->dbh,
134 "CREATE INDEX IF NOT EXISTS idx_repl_rvalue ON gn090 (repl,rvalue)")) ||
135 (GNUNET_OK !=
136 GNUNET_POSTGRES_exec (plugin->dbh,
137 "CREATE INDEX IF NOT EXISTS idx_expire_hash ON gn090 (expire,hash)")))
138 {
139 PQclear (ret);
140 PQfinish (plugin->dbh);
141 plugin->dbh = NULL;
142 return GNUNET_SYSERR;
143 }
144 }
145 PQclear (ret);
146
147 ret =
148 PQexec (plugin->dbh,
149 "ALTER TABLE gn090 ALTER value SET STORAGE EXTERNAL");
150 if (GNUNET_OK !=
151 GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_COMMAND_OK, "ALTER TABLE", "gn090"))
152 {
153 PQfinish (plugin->dbh);
154 plugin->dbh = NULL;
155 return GNUNET_SYSERR;
156 }
157 PQclear (ret);
158 ret = PQexec (plugin->dbh, "ALTER TABLE gn090 ALTER hash SET STORAGE PLAIN");
159 if (GNUNET_OK !=
160 GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_COMMAND_OK, "ALTER TABLE", "gn090"))
161 {
162 PQfinish (plugin->dbh);
163 plugin->dbh = NULL;
164 return GNUNET_SYSERR;
165 }
166 PQclear (ret);
167 ret = PQexec (plugin->dbh, "ALTER TABLE gn090 ALTER vhash SET STORAGE PLAIN");
168 if (GNUNET_OK !=
169 GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_COMMAND_OK, "ALTER TABLE", "gn090"))
170 {
171 PQfinish (plugin->dbh);
172 plugin->dbh = NULL;
173 return GNUNET_SYSERR;
174 }
175 PQclear (ret);
176#define RESULT_COLUMNS "repl, type, prio, anonLevel, expire, hash, value, oid"
177 if ((GNUNET_OK !=
178 GNUNET_POSTGRES_prepare (plugin->dbh, "get",
179 "SELECT " RESULT_COLUMNS " FROM gn090 "
180 "WHERE oid >= $1::bigint AND "
181 "(rvalue >= $2 OR 0 = $3::smallint) AND "
182 "(hash = $4 OR 0 = $5::smallint) AND "
183 "(type = $6 OR 0 = $7::smallint) "
184 "ORDER BY oid ASC LIMIT 1", 7)) ||
185 (GNUNET_OK !=
186 GNUNET_POSTGRES_prepare (plugin->dbh, "put",
187 "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) "
188 "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", 9)) ||
189 (GNUNET_OK !=
190 GNUNET_POSTGRES_prepare (plugin->dbh, "update",
191 "UPDATE gn090 "
192 "SET prio = prio + $1, "
193 "repl = repl + $2, "
194 "expire = GREATEST(expire, $3) "
195 "WHERE hash = $4 AND vhash = $5", 5)) ||
196 (GNUNET_OK !=
197 GNUNET_POSTGRES_prepare (plugin->dbh, "decrepl",
198 "UPDATE gn090 SET repl = GREATEST (repl - 1, 0) "
199 "WHERE oid = $1", 1)) ||
200 (GNUNET_OK !=
201 GNUNET_POSTGRES_prepare (plugin->dbh, "select_non_anonymous",
202 "SELECT " RESULT_COLUMNS " FROM gn090 "
203 "WHERE anonLevel = 0 AND type = $1 AND oid >= $2::bigint "
204 "ORDER BY oid ASC LIMIT 1",
205 2)) ||
206 (GNUNET_OK !=
207 GNUNET_POSTGRES_prepare (plugin->dbh, "select_expiration_order",
208 "(SELECT " RESULT_COLUMNS " FROM gn090 "
209 "WHERE expire < $1 ORDER BY prio ASC LIMIT 1) "
210 "UNION "
211 "(SELECT " RESULT_COLUMNS " FROM gn090 "
212 "ORDER BY prio ASC LIMIT 1) "
213 "ORDER BY expire ASC LIMIT 1",
214 1)) ||
215 (GNUNET_OK !=
216 GNUNET_POSTGRES_prepare (plugin->dbh, "select_replication_order",
217 "SELECT " RESULT_COLUMNS " FROM gn090 "
218 "ORDER BY repl DESC,RANDOM() LIMIT 1", 0)) ||
219 (GNUNET_OK !=
220 GNUNET_POSTGRES_prepare (plugin->dbh, "delrow", "DELETE FROM gn090 " "WHERE oid=$1", 1)) ||
221 (GNUNET_OK !=
222 GNUNET_POSTGRES_prepare (plugin->dbh, "remove", "DELETE FROM gn090 "
223 "WHERE hash = $1 AND "
224 "value = $2", 2)) ||
225 (GNUNET_OK !=
226 GNUNET_POSTGRES_prepare (plugin->dbh, "get_keys", "SELECT hash FROM gn090", 0)))
227 { 171 {
228 PQfinish (plugin->dbh); 172 PQfinish (plugin->dbh);
229 plugin->dbh = NULL; 173 plugin->dbh = NULL;
@@ -241,44 +185,32 @@ init_connection (struct Plugin *plugin)
241 * @return number of bytes used on disk 185 * @return number of bytes used on disk
242 */ 186 */
243static void 187static void
244postgres_plugin_estimate_size (void *cls, unsigned long long *estimate) 188postgres_plugin_estimate_size (void *cls,
189 unsigned long long *estimate)
245{ 190{
246 struct Plugin *plugin = cls; 191 struct Plugin *plugin = cls;
247 unsigned long long total; 192 uint64_t total;
248 PGresult *ret; 193 struct GNUNET_PQ_QueryParam params[] = {
194 GNUNET_PQ_query_param_end
195 };
196 struct GNUNET_PQ_ResultSpec rs[] = {
197 GNUNET_PQ_result_spec_uint64 ("total",
198 &total),
199 GNUNET_PQ_result_spec_end
200 };
201 enum GNUNET_DB_QueryStatus ret;
249 202
250 if (NULL == estimate) 203 if (NULL == estimate)
251 return; 204 return;
252 ret = 205 ret = GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh,
253 PQexecParams (plugin->dbh, 206 "estimate_size",
254 "SELECT SUM(LENGTH(value))+256*COUNT(*) FROM gn090", 0, 207 params,
255 NULL, NULL, NULL, NULL, 1); 208 rs);
256 if (GNUNET_OK != 209 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != ret)
257 GNUNET_POSTGRES_check_result (plugin->dbh,
258 ret,
259 PGRES_TUPLES_OK,
260 "PQexecParams",
261 "get_size"))
262 {
263 *estimate = 0;
264 return;
265 }
266 if ((PQntuples (ret) != 1) || (PQnfields (ret) != 1) )
267 {
268 GNUNET_break (0);
269 PQclear (ret);
270 *estimate = 0;
271 return;
272 }
273 if (PQgetlength (ret, 0, 0) != sizeof (unsigned long long))
274 { 210 {
275 GNUNET_break (0 == PQgetlength (ret, 0, 0)); 211 *estimate = 0LL;
276 PQclear (ret);
277 *estimate = 0;
278 return; 212 return;
279 } 213 }
280 total = GNUNET_ntohll (*(const unsigned long long *) PQgetvalue (ret, 0, 0));
281 PQclear (ret);
282 *estimate = total; 214 *estimate = total;
283} 215}
284 216
@@ -315,13 +247,12 @@ postgres_plugin_put (void *cls,
315{ 247{
316 struct Plugin *plugin = cls; 248 struct Plugin *plugin = cls;
317 struct GNUNET_HashCode vhash; 249 struct GNUNET_HashCode vhash;
318 PGresult *ret; 250 enum GNUNET_DB_QueryStatus ret;
319 251
320 GNUNET_CRYPTO_hash (data, 252 GNUNET_CRYPTO_hash (data,
321 size, 253 size,
322 &vhash); 254 &vhash);
323 255 if (! absent)
324 if (!absent)
325 { 256 {
326 struct GNUNET_PQ_QueryParam params[] = { 257 struct GNUNET_PQ_QueryParam params[] = {
327 GNUNET_PQ_query_param_uint32 (&priority), 258 GNUNET_PQ_query_param_uint32 (&priority),
@@ -331,15 +262,10 @@ postgres_plugin_put (void *cls,
331 GNUNET_PQ_query_param_auto_from_type (&vhash), 262 GNUNET_PQ_query_param_auto_from_type (&vhash),
332 GNUNET_PQ_query_param_end 263 GNUNET_PQ_query_param_end
333 }; 264 };
334 ret = GNUNET_PQ_exec_prepared (plugin->dbh, 265 ret = GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
335 "update", 266 "update",
336 params); 267 params);
337 if (GNUNET_OK != 268 if (0 > ret)
338 GNUNET_POSTGRES_check_result (plugin->dbh,
339 ret,
340 PGRES_COMMAND_OK,
341 "PQexecPrepared",
342 "update"))
343 { 269 {
344 cont (cont_cls, 270 cont (cont_cls,
345 key, 271 key,
@@ -348,9 +274,7 @@ postgres_plugin_put (void *cls,
348 _("Postgress exec failure")); 274 _("Postgress exec failure"));
349 return; 275 return;
350 } 276 }
351 /* What an awful API, this function really does return a string */ 277 bool affected = (0 != ret);
352 bool affected = 0 != strcmp ("0", PQcmdTuples (ret));
353 PQclear (ret);
354 if (affected) 278 if (affected)
355 { 279 {
356 cont (cont_cls, 280 cont (cont_cls,
@@ -362,177 +286,195 @@ postgres_plugin_put (void *cls,
362 } 286 }
363 } 287 }
364 288
365 uint32_t utype = type;
366 uint64_t rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
367 UINT64_MAX);
368 struct GNUNET_PQ_QueryParam params[] = {
369 GNUNET_PQ_query_param_uint32 (&replication),
370 GNUNET_PQ_query_param_uint32 (&utype),
371 GNUNET_PQ_query_param_uint32 (&priority),
372 GNUNET_PQ_query_param_uint32 (&anonymity),
373 GNUNET_PQ_query_param_absolute_time (&expiration),
374 GNUNET_PQ_query_param_uint64 (&rvalue),
375 GNUNET_PQ_query_param_auto_from_type (key),
376 GNUNET_PQ_query_param_auto_from_type (&vhash),
377 GNUNET_PQ_query_param_fixed_size (data, size),
378 GNUNET_PQ_query_param_end
379 };
380
381 ret = GNUNET_PQ_exec_prepared (plugin->dbh,
382 "put",
383 params);
384 if (GNUNET_OK !=
385 GNUNET_POSTGRES_check_result (plugin->dbh,
386 ret,
387 PGRES_COMMAND_OK,
388 "PQexecPrepared", "put"))
389 { 289 {
390 cont (cont_cls, key, size, 290 uint32_t utype = (uint32_t) type;
391 GNUNET_SYSERR, 291 uint64_t rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
392 _("Postgress exec failure")); 292 UINT64_MAX);
393 return; 293 struct GNUNET_PQ_QueryParam params[] = {
294 GNUNET_PQ_query_param_uint32 (&replication),
295 GNUNET_PQ_query_param_uint32 (&utype),
296 GNUNET_PQ_query_param_uint32 (&priority),
297 GNUNET_PQ_query_param_uint32 (&anonymity),
298 GNUNET_PQ_query_param_absolute_time (&expiration),
299 GNUNET_PQ_query_param_uint64 (&rvalue),
300 GNUNET_PQ_query_param_auto_from_type (key),
301 GNUNET_PQ_query_param_auto_from_type (&vhash),
302 GNUNET_PQ_query_param_fixed_size (data, size),
303 GNUNET_PQ_query_param_end
304 };
305
306 ret = GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
307 "put",
308 params);
309 if (0 > ret)
310 {
311 cont (cont_cls,
312 key,
313 size,
314 GNUNET_SYSERR,
315 "Postgress exec failure");
316 return;
317 }
394 } 318 }
395 PQclear (ret);
396 plugin->env->duc (plugin->env->cls, 319 plugin->env->duc (plugin->env->cls,
397 size + GNUNET_DATASTORE_ENTRY_OVERHEAD); 320 size + GNUNET_DATASTORE_ENTRY_OVERHEAD);
398 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 321 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
399 "datastore-postgres", 322 "datastore-postgres",
400 "Stored %u bytes in database\n", 323 "Stored %u bytes in database\n",
401 (unsigned int) size); 324 (unsigned int) size);
402 cont (cont_cls, key, size, GNUNET_OK, NULL); 325 cont (cont_cls,
326 key,
327 size,
328 GNUNET_OK,
329 NULL);
403} 330}
404 331
405 332
406/** 333/**
407 * Function invoked to process the result and call the processor. 334 * Closure for #process_result.
335 */
336struct ProcessResultContext
337{
338
339 /**
340 * The plugin handle.
341 */
342 struct Plugin *plugin;
343
344 /**
345 * Function to call on each result.
346 */
347 PluginDatumProcessor proc;
348
349 /**
350 * Closure for @e proc.
351 */
352 void *proc_cls;
353
354};
355
356
357/**
358 * Function invoked to process the result and call the processor of @a
359 * cls.
408 * 360 *
409 * @param plugin global plugin data 361 * @param cls our `struct ProcessResultContext`
410 * @param proc function to call the value (once only).
411 * @param proc_cls closure for proc
412 * @param res result from exec 362 * @param res result from exec
413 * @param filename filename for error messages 363 * @param num_results number of results in @a res
414 * @param line line number for error messages
415 */ 364 */
416static void 365static void
417process_result (struct Plugin *plugin, 366process_result (void *cls,
418 PluginDatumProcessor proc, 367 PGresult *res,
419 void *proc_cls, 368 unsigned int num_results)
420 PGresult * res,
421 const char *filename, int line)
422{ 369{
423 int iret; 370 struct ProcessResultContext *prc = cls;
424 uint32_t rowid; 371 struct Plugin *plugin = prc->plugin;
425 uint32_t utype;
426 uint32_t anonymity;
427 uint32_t replication;
428 uint32_t priority;
429 size_t size;
430 void *data;
431 struct GNUNET_TIME_Absolute expiration_time;
432 struct GNUNET_HashCode key;
433 struct GNUNET_PQ_ResultSpec rs[] = {
434 GNUNET_PQ_result_spec_uint32 ("repl", &replication),
435 GNUNET_PQ_result_spec_uint32 ("type", &utype),
436 GNUNET_PQ_result_spec_uint32 ("prio", &priority),
437 GNUNET_PQ_result_spec_uint32 ("anonLevel", &anonymity),
438 GNUNET_PQ_result_spec_absolute_time ("expire", &expiration_time),
439 GNUNET_PQ_result_spec_auto_from_type ("hash", &key),
440 GNUNET_PQ_result_spec_variable_size ("value", &data, &size),
441 GNUNET_PQ_result_spec_uint32 ("oid", &rowid),
442 GNUNET_PQ_result_spec_end
443 };
444 372
445 if (GNUNET_OK != 373 if (0 == num_results)
446 GNUNET_POSTGRES_check_result_ (plugin->dbh,
447 res,
448 PGRES_TUPLES_OK,
449 "PQexecPrepared",
450 "select",
451 filename, line))
452 {
453 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
454 "datastore-postgres",
455 "Ending iteration (postgres error)\n");
456 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
457 return;
458 }
459
460 if (0 == PQntuples (res))
461 { 374 {
462 /* no result */ 375 /* no result */
463 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 376 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
464 "datastore-postgres", 377 "datastore-postgres",
465 "Ending iteration (no more results)\n"); 378 "Ending iteration (no more results)\n");
466 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 379 prc->proc (prc->proc_cls, NULL, 0, NULL, 0, 0, 0, 0,
467 PQclear (res); 380 GNUNET_TIME_UNIT_ZERO_ABS, 0);
468 return; 381 return;
469 } 382 }
470 if (1 != PQntuples (res)) 383 if (1 != num_results)
471 { 384 {
472 GNUNET_break (0); 385 GNUNET_break (0);
473 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 386 prc->proc (prc->proc_cls, NULL, 0, NULL, 0, 0, 0, 0,
474 PQclear (res); 387 GNUNET_TIME_UNIT_ZERO_ABS, 0);
475 return; 388 return;
476 } 389 }
477 if (GNUNET_OK != 390 /* Technically we don't need the loop here, but nicer in case
478 GNUNET_PQ_extract_result (res, 391 we ever relax the condition above. */
479 rs, 392 for (unsigned int i=0;i<num_results;i++)
480 0))
481 { 393 {
482 GNUNET_break (0); 394 int iret;
483 PQclear (res); 395 uint32_t rowid;
484 GNUNET_POSTGRES_delete_by_rowid (plugin->dbh, 396 uint32_t utype;
485 "delrow", 397 uint32_t anonymity;
486 rowid); 398 uint32_t replication;
487 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); 399 uint32_t priority;
488 return; 400 size_t size;
489 } 401 void *data;
402 struct GNUNET_TIME_Absolute expiration_time;
403 struct GNUNET_HashCode key;
404 struct GNUNET_PQ_ResultSpec rs[] = {
405 GNUNET_PQ_result_spec_uint32 ("repl", &replication),
406 GNUNET_PQ_result_spec_uint32 ("type", &utype),
407 GNUNET_PQ_result_spec_uint32 ("prio", &priority),
408 GNUNET_PQ_result_spec_uint32 ("anonLevel", &anonymity),
409 GNUNET_PQ_result_spec_absolute_time ("expire", &expiration_time),
410 GNUNET_PQ_result_spec_auto_from_type ("hash", &key),
411 GNUNET_PQ_result_spec_variable_size ("value", &data, &size),
412 GNUNET_PQ_result_spec_uint32 ("oid", &rowid),
413 GNUNET_PQ_result_spec_end
414 };
490 415
491 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 416 if (GNUNET_OK !=
492 "datastore-postgres", 417 GNUNET_PQ_extract_result (res,
493 "Found result of size %u bytes and type %u in database\n", 418 rs,
494 (unsigned int) size, 419 i))
495 (unsigned int) utype);
496 iret = proc (proc_cls,
497 &key,
498 size,
499 data,
500 (enum GNUNET_BLOCK_Type) utype,
501 priority,
502 anonymity,
503 replication,
504 expiration_time,
505 rowid);
506 PQclear (res);
507 if (iret == GNUNET_NO)
508 {
509 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
510 "Processor asked for item %u to be removed.\n",
511 (unsigned int) rowid);
512 if (GNUNET_OK ==
513 GNUNET_POSTGRES_delete_by_rowid (plugin->dbh,
514 "delrow",
515 rowid))
516 { 420 {
517 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 421 GNUNET_break (0);
518 "datastore-postgres", 422 prc->proc (prc->proc_cls, NULL, 0, NULL, 0, 0, 0, 0,
519 "Deleting %u bytes from database\n", 423 GNUNET_TIME_UNIT_ZERO_ABS, 0);
520 (unsigned int) size); 424 return;
521 plugin->env->duc (plugin->env->cls,
522 - (size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
523 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
524 "datastore-postgres",
525 "Deleted %u bytes from database\n",
526 (unsigned int) size);
527 } 425 }
528 } 426
427 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
428 "datastore-postgres",
429 "Found result of size %u bytes and type %u in database\n",
430 (unsigned int) size,
431 (unsigned int) utype);
432 iret = prc->proc (prc->proc_cls,
433 &key,
434 size,
435 data,
436 (enum GNUNET_BLOCK_Type) utype,
437 priority,
438 anonymity,
439 replication,
440 expiration_time,
441 rowid);
442 if (iret == GNUNET_NO)
443 {
444 struct GNUNET_PQ_QueryParam param[] = {
445 GNUNET_PQ_query_param_uint32 (&rowid),
446 GNUNET_PQ_query_param_end
447 };
448
449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
450 "Processor asked for item %u to be removed.\n",
451 (unsigned int) rowid);
452 if (0 <
453 GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
454 "delrow",
455 param))
456 {
457 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
458 "datastore-postgres",
459 "Deleting %u bytes from database\n",
460 (unsigned int) size);
461 plugin->env->duc (plugin->env->cls,
462 - (size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
463 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
464 "datastore-postgres",
465 "Deleted %u bytes from database\n",
466 (unsigned int) size);
467 }
468 }
469 GNUNET_PQ_cleanup_result (rs);
470 } /* for (i) */
529} 471}
530 472
531 473
532/** 474/**
533 * Get one of the results for a particular key in the datastore. 475 * Get one of the results for a particular key in the datastore.
534 * 476 *
535 * @param cls closure with the 'struct Plugin' 477 * @param cls closure with the `struct Plugin`
536 * @param next_uid return the result with lowest uid >= next_uid 478 * @param next_uid return the result with lowest uid >= next_uid
537 * @param random if true, return a random result instead of using next_uid 479 * @param random if true, return a random result instead of using next_uid
538 * @param key maybe NULL (to match all entries) 480 * @param key maybe NULL (to match all entries)
@@ -567,7 +509,8 @@ postgres_plugin_get_key (void *cls,
567 GNUNET_PQ_query_param_uint16 (&use_type), 509 GNUNET_PQ_query_param_uint16 (&use_type),
568 GNUNET_PQ_query_param_end 510 GNUNET_PQ_query_param_end
569 }; 511 };
570 PGresult *ret; 512 struct ProcessResultContext prc;
513 enum GNUNET_DB_QueryStatus res;
571 514
572 if (random) 515 if (random)
573 { 516 {
@@ -576,16 +519,21 @@ postgres_plugin_get_key (void *cls,
576 next_uid = 0; 519 next_uid = 0;
577 } 520 }
578 else 521 else
522 {
579 rvalue = 0; 523 rvalue = 0;
580 524 }
581 ret = GNUNET_PQ_exec_prepared (plugin->dbh, 525 prc.plugin = plugin;
582 "get", 526 prc.proc = proc;
583 params); 527 prc.proc_cls = proc_cls;
584 process_result (plugin, 528
585 proc, 529 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
586 proc_cls, 530 "get",
587 ret, 531 params,
588 __FILE__, __LINE__); 532 &process_result,
533 &prc);
534 if (0 > res)
535 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0,
536 GNUNET_TIME_UNIT_ZERO_ABS, 0);
589} 537}
590 538
591 539
@@ -615,16 +563,20 @@ postgres_plugin_get_zero_anonymity (void *cls,
615 GNUNET_PQ_query_param_uint64 (&next_uid), 563 GNUNET_PQ_query_param_uint64 (&next_uid),
616 GNUNET_PQ_query_param_end 564 GNUNET_PQ_query_param_end
617 }; 565 };
618 PGresult *ret; 566 struct ProcessResultContext prc;
619 567 enum GNUNET_DB_QueryStatus res;
620 ret = GNUNET_PQ_exec_prepared (plugin->dbh, 568
621 "select_non_anonymous", 569 prc.plugin = plugin;
622 params); 570 prc.proc = proc;
623 571 prc.proc_cls = proc_cls;
624 process_result (plugin, 572 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
625 proc, proc_cls, 573 "select_non_anonymous",
626 ret, 574 params,
627 __FILE__, __LINE__); 575 &process_result,
576 &prc);
577 if (0 > res)
578 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0,
579 GNUNET_TIME_UNIT_ZERO_ABS, 0);
628} 580}
629 581
630 582
@@ -692,7 +644,7 @@ repl_proc (void *cls,
692 GNUNET_PQ_query_param_uint32 (&oid), 644 GNUNET_PQ_query_param_uint32 (&oid),
693 GNUNET_PQ_query_param_end 645 GNUNET_PQ_query_param_end
694 }; 646 };
695 PGresult *qret; 647 enum GNUNET_DB_QueryStatus qret;
696 648
697 ret = rc->proc (rc->proc_cls, 649 ret = rc->proc (rc->proc_cls,
698 key, 650 key,
@@ -706,17 +658,11 @@ repl_proc (void *cls,
706 uid); 658 uid);
707 if (NULL == key) 659 if (NULL == key)
708 return ret; 660 return ret;
709 qret = GNUNET_PQ_exec_prepared (plugin->dbh, 661 qret = GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
710 "decrepl", 662 "decrepl",
711 params); 663 params);
712 if (GNUNET_OK != 664 if (0 > qret)
713 GNUNET_POSTGRES_check_result (plugin->dbh,
714 qret,
715 PGRES_COMMAND_OK,
716 "PQexecPrepared",
717 "decrepl"))
718 return GNUNET_SYSERR; 665 return GNUNET_SYSERR;
719 PQclear (qret);
720 return ret; 666 return ret;
721} 667}
722 668
@@ -738,20 +684,27 @@ postgres_plugin_get_replication (void *cls,
738 void *proc_cls) 684 void *proc_cls)
739{ 685{
740 struct Plugin *plugin = cls; 686 struct Plugin *plugin = cls;
687 struct GNUNET_PQ_QueryParam params[] = {
688 GNUNET_PQ_query_param_end
689 };
741 struct ReplCtx rc; 690 struct ReplCtx rc;
742 PGresult *ret; 691 struct ProcessResultContext prc;
692 enum GNUNET_DB_QueryStatus res;
743 693
744 rc.plugin = plugin; 694 rc.plugin = plugin;
745 rc.proc = proc; 695 rc.proc = proc;
746 rc.proc_cls = proc_cls; 696 rc.proc_cls = proc_cls;
747 ret = PQexecPrepared (plugin->dbh, 697 prc.plugin = plugin;
748 "select_replication_order", 0, NULL, NULL, 698 prc.proc = &repl_proc;
749 NULL, 1); 699 prc.proc_cls = &rc;
750 process_result (plugin, 700 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
751 &repl_proc, 701 "select_replication_order",
752 &rc, 702 params,
753 ret, 703 &process_result,
754 __FILE__, __LINE__); 704 &prc);
705 if (0 > res)
706 proc (proc_cls, NULL, 0, NULL, 0, 0, 0, 0,
707 GNUNET_TIME_UNIT_ZERO_ABS, 0);
755} 708}
756 709
757 710
@@ -774,16 +727,75 @@ postgres_plugin_get_expiration (void *cls,
774 GNUNET_PQ_query_param_absolute_time (&now), 727 GNUNET_PQ_query_param_absolute_time (&now),
775 GNUNET_PQ_query_param_end 728 GNUNET_PQ_query_param_end
776 }; 729 };
777 PGresult *ret; 730 struct ProcessResultContext prc;
778 731
779 now = GNUNET_TIME_absolute_get (); 732 now = GNUNET_TIME_absolute_get ();
780 ret = GNUNET_PQ_exec_prepared (plugin->dbh, 733 prc.plugin = plugin;
781 "select_expiration_order", 734 prc.proc = proc;
782 params); 735 prc.proc_cls = proc_cls;
783 process_result (plugin, 736 (void) GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
784 proc, proc_cls, 737 "select_expiration_order",
785 ret, 738 params,
786 __FILE__, __LINE__); 739 &process_result,
740 &prc);
741}
742
743
744/**
745 * Closure for #process_keys.
746 */
747struct ProcessKeysContext
748{
749
750 /**
751 * Function to call for each key.
752 */
753 PluginKeyProcessor proc;
754
755 /**
756 * Closure for @e proc.
757 */
758 void *proc_cls;
759};
760
761
762/**
763 * Function to be called with the results of a SELECT statement
764 * that has returned @a num_results results.
765 *
766 * @param cls closure with a `struct ProcessKeysContext`
767 * @param result the postgres result
768 * @param num_result the number of results in @a result
769 */
770static void
771process_keys (void *cls,
772 PGresult *result,
773 unsigned int num_results)
774{
775 struct ProcessKeysContext *pkc = cls;
776
777 for (unsigned i=0;i<num_results;i++)
778 {
779 struct GNUNET_HashCode key;
780 struct GNUNET_PQ_ResultSpec rs[] = {
781 GNUNET_PQ_result_spec_auto_from_type ("hash",
782 &key),
783 GNUNET_PQ_result_spec_end
784 };
785
786 if (GNUNET_OK !=
787 GNUNET_PQ_extract_result (result,
788 rs,
789 i))
790 {
791 GNUNET_break (0);
792 continue;
793 }
794 pkc->proc (pkc->proc_cls,
795 &key,
796 1);
797 GNUNET_PQ_cleanup_result (rs);
798 }
787} 799}
788 800
789 801
@@ -800,28 +812,21 @@ postgres_plugin_get_keys (void *cls,
800 void *proc_cls) 812 void *proc_cls)
801{ 813{
802 struct Plugin *plugin = cls; 814 struct Plugin *plugin = cls;
803 int ret; 815 struct GNUNET_PQ_QueryParam params[] = {
804 int i; 816 GNUNET_PQ_query_param_end
805 struct GNUNET_HashCode key; 817 };
806 PGresult * res; 818 struct ProcessKeysContext pkc;
807 819
808 res = PQexecPrepared (plugin->dbh, 820 pkc.proc = proc;
809 "get_keys", 821 pkc.proc_cls = proc_cls;
810 0, NULL, NULL, NULL, 1); 822 (void) GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
811 ret = PQntuples (res); 823 "get_keys",
812 for (i=0;i<ret;i++) 824 params,
813 { 825 &process_keys,
814 if (sizeof (struct GNUNET_HashCode) != 826 &pkc);
815 PQgetlength (res, i, 0)) 827 proc (proc_cls,
816 { 828 NULL,
817 GNUNET_memcpy (&key, 829 0);
818 PQgetvalue (res, i, 0),
819 sizeof (struct GNUNET_HashCode));
820 proc (proc_cls, &key, 1);
821 }
822 }
823 PQclear (res);
824 proc (proc_cls, NULL, 0);
825} 830}
826 831
827 832
@@ -834,10 +839,14 @@ static void
834postgres_plugin_drop (void *cls) 839postgres_plugin_drop (void *cls)
835{ 840{
836 struct Plugin *plugin = cls; 841 struct Plugin *plugin = cls;
842 struct GNUNET_PQ_ExecuteStatement es[] = {
843 GNUNET_PQ_make_execute ("DROP TABLE gn090"),
844 GNUNET_PQ_EXECUTE_STATEMENT_END
845 };
837 846
838 if (GNUNET_OK != 847 if (GNUNET_OK !=
839 GNUNET_POSTGRES_exec (plugin->dbh, 848 GNUNET_PQ_exec_statements (plugin->dbh,
840 "DROP TABLE gn090")) 849 es))
841 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, 850 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
842 "postgres", 851 "postgres",
843 _("Failed to drop table from database.\n")); 852 _("Failed to drop table from database.\n"));
@@ -863,21 +872,17 @@ postgres_plugin_remove_key (void *cls,
863 void *cont_cls) 872 void *cont_cls)
864{ 873{
865 struct Plugin *plugin = cls; 874 struct Plugin *plugin = cls;
866 PGresult *ret; 875 enum GNUNET_DB_QueryStatus ret;
867 struct GNUNET_PQ_QueryParam params[] = { 876 struct GNUNET_PQ_QueryParam params[] = {
868 GNUNET_PQ_query_param_auto_from_type (key), 877 GNUNET_PQ_query_param_auto_from_type (key),
869 GNUNET_PQ_query_param_fixed_size (data, size), 878 GNUNET_PQ_query_param_fixed_size (data, size),
870 GNUNET_PQ_query_param_end 879 GNUNET_PQ_query_param_end
871 }; 880 };
872 ret = GNUNET_PQ_exec_prepared (plugin->dbh, 881
873 "remove", 882 ret = GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
874 params); 883 "remove",
875 if (GNUNET_OK != 884 params);
876 GNUNET_POSTGRES_check_result (plugin->dbh, 885 if (0 > ret)
877 ret,
878 PGRES_COMMAND_OK,
879 "PQexecPrepared",
880 "remove"))
881 { 886 {
882 cont (cont_cls, 887 cont (cont_cls,
883 key, 888 key,
@@ -886,10 +891,7 @@ postgres_plugin_remove_key (void *cls,
886 _("Postgress exec failure")); 891 _("Postgress exec failure"));
887 return; 892 return;
888 } 893 }
889 /* What an awful API, this function really does return a string */ 894 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == ret)
890 bool affected = 0 != strcmp ("0", PQcmdTuples (ret));
891 PQclear (ret);
892 if (!affected)
893 { 895 {
894 cont (cont_cls, 896 cont (cont_cls,
895 key, 897 key,
diff --git a/src/datastore/plugin_datastore_sqlite.c b/src/datastore/plugin_datastore_sqlite.c
index 323c03856..77b8409cd 100644
--- a/src/datastore/plugin_datastore_sqlite.c
+++ b/src/datastore/plugin_datastore_sqlite.c
@@ -186,31 +186,19 @@ create_indices (sqlite3 * dbh)
186{ 186{
187 /* create indices */ 187 /* create indices */
188 if ((SQLITE_OK != 188 if ((SQLITE_OK !=
189 sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS idx_hash ON gn090 (hash)", 189 sqlite3_exec (dbh, "CREATE INDEX IF NOT EXISTS idx_hash ON gn091 (hash)",
190 NULL, NULL, NULL)) || 190 NULL, NULL, NULL)) ||
191 (SQLITE_OK != 191 (SQLITE_OK !=
192 sqlite3_exec (dbh, 192 sqlite3_exec (dbh,
193 "CREATE INDEX IF NOT EXISTS idx_expire_repl ON gn090 (expire ASC,repl DESC)", 193 "CREATE INDEX IF NOT EXISTS idx_anon_type ON gn091 (anonLevel ASC,type)",
194 NULL, NULL, NULL)) || 194 NULL, NULL, NULL)) ||
195 (SQLITE_OK != 195 (SQLITE_OK !=
196 sqlite3_exec (dbh, 196 sqlite3_exec (dbh,
197 "CREATE INDEX IF NOT EXISTS idx_comb ON gn090 (anonLevel ASC,expire ASC,prio,type,hash)", 197 "CREATE INDEX IF NOT EXISTS idx_expire ON gn091 (expire ASC)",
198 NULL, NULL, NULL)) || 198 NULL, NULL, NULL)) ||
199 (SQLITE_OK != 199 (SQLITE_OK !=
200 sqlite3_exec (dbh, 200 sqlite3_exec (dbh,
201 "CREATE INDEX IF NOT EXISTS idx_anon_type_hash ON gn090 (anonLevel ASC,type,hash)", 201 "CREATE INDEX IF NOT EXISTS idx_repl_rvalue ON gn091 (repl,rvalue)",
202 NULL, NULL, NULL)) ||
203 (SQLITE_OK !=
204 sqlite3_exec (dbh,
205 "CREATE INDEX IF NOT EXISTS idx_expire ON gn090 (expire ASC)",
206 NULL, NULL, NULL)) ||
207 (SQLITE_OK !=
208 sqlite3_exec (dbh,
209 "CREATE INDEX IF NOT EXISTS idx_repl_rvalue ON gn090 (repl,rvalue)",
210 NULL, NULL, NULL)) ||
211 (SQLITE_OK !=
212 sqlite3_exec (dbh,
213 "CREATE INDEX IF NOT EXISTS idx_repl ON gn090 (repl DESC)",
214 NULL, NULL, NULL))) 202 NULL, NULL, NULL)))
215 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "sqlite", 203 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "sqlite",
216 "Failed to create indices: %s\n", sqlite3_errmsg (dbh)); 204 "Failed to create indices: %s\n", sqlite3_errmsg (dbh));
@@ -305,7 +293,7 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
305 ENULL)); 293 ENULL));
306 CHECK (SQLITE_OK == 294 CHECK (SQLITE_OK ==
307 sqlite3_exec (plugin->dbh, 295 sqlite3_exec (plugin->dbh,
308 "PRAGMA page_size=4092", NULL, NULL, 296 "PRAGMA page_size=4096", NULL, NULL,
309 ENULL)); 297 ENULL));
310 298
311 CHECK (SQLITE_OK == 299 CHECK (SQLITE_OK ==
@@ -315,7 +303,7 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
315 /* We have to do it here, because otherwise precompiling SQL might fail */ 303 /* We have to do it here, because otherwise precompiling SQL might fail */
316 CHECK (SQLITE_OK == 304 CHECK (SQLITE_OK ==
317 sq_prepare (plugin->dbh, 305 sq_prepare (plugin->dbh,
318 "SELECT 1 FROM sqlite_master WHERE tbl_name = 'gn090'", 306 "SELECT 1 FROM sqlite_master WHERE tbl_name = 'gn091'",
319 &stmt)); 307 &stmt));
320 308
321 /* FIXME: SQLite does not have unsigned integers! This is ok for the type column because 309 /* FIXME: SQLite does not have unsigned integers! This is ok for the type column because
@@ -327,7 +315,7 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
327 sqlite3_step (stmt)) && 315 sqlite3_step (stmt)) &&
328 (SQLITE_OK != 316 (SQLITE_OK !=
329 sqlite3_exec (plugin->dbh, 317 sqlite3_exec (plugin->dbh,
330 "CREATE TABLE gn090 (" 318 "CREATE TABLE gn091 ("
331 " repl INT4 NOT NULL DEFAULT 0," 319 " repl INT4 NOT NULL DEFAULT 0,"
332 " type INT4 NOT NULL DEFAULT 0," 320 " type INT4 NOT NULL DEFAULT 0,"
333 " prio INT4 NOT NULL DEFAULT 0," 321 " prio INT4 NOT NULL DEFAULT 0,"
@@ -353,7 +341,7 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
353#define RESULT_COLUMNS "repl, type, prio, anonLevel, expire, hash, value, _ROWID_" 341#define RESULT_COLUMNS "repl, type, prio, anonLevel, expire, hash, value, _ROWID_"
354 if ( (SQLITE_OK != 342 if ( (SQLITE_OK !=
355 sq_prepare (plugin->dbh, 343 sq_prepare (plugin->dbh,
356 "UPDATE gn090 " 344 "UPDATE gn091 "
357 "SET prio = prio + ?, " 345 "SET prio = prio + ?, "
358 "repl = repl + ?, " 346 "repl = repl + ?, "
359 "expire = MAX(expire, ?) " 347 "expire = MAX(expire, ?) "
@@ -361,16 +349,16 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
361 &plugin->update)) || 349 &plugin->update)) ||
362 (SQLITE_OK != 350 (SQLITE_OK !=
363 sq_prepare (plugin->dbh, 351 sq_prepare (plugin->dbh,
364 "UPDATE gn090 " "SET repl = MAX (0, repl - 1) WHERE _ROWID_ = ?", 352 "UPDATE gn091 " "SET repl = MAX (0, repl - 1) WHERE _ROWID_ = ?",
365 &plugin->updRepl)) || 353 &plugin->updRepl)) ||
366 (SQLITE_OK != 354 (SQLITE_OK !=
367 sq_prepare (plugin->dbh, 355 sq_prepare (plugin->dbh,
368 "SELECT " RESULT_COLUMNS " FROM gn090 " 356 "SELECT " RESULT_COLUMNS " FROM gn091 "
369#if SQLITE_VERSION_NUMBER >= 3007000 357#if SQLITE_VERSION_NUMBER >= 3007000
370 "INDEXED BY idx_repl_rvalue " 358 "INDEXED BY idx_repl_rvalue "
371#endif 359#endif
372 "WHERE repl=?2 AND " " (rvalue>=?1 OR " 360 "WHERE repl=?2 AND " " (rvalue>=?1 OR "
373 " NOT EXISTS (SELECT 1 FROM gn090 " 361 " NOT EXISTS (SELECT 1 FROM gn091 "
374#if SQLITE_VERSION_NUMBER >= 3007000 362#if SQLITE_VERSION_NUMBER >= 3007000
375 "INDEXED BY idx_repl_rvalue " 363 "INDEXED BY idx_repl_rvalue "
376#endif 364#endif
@@ -379,7 +367,7 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
379 &plugin->selRepl)) || 367 &plugin->selRepl)) ||
380 (SQLITE_OK != 368 (SQLITE_OK !=
381 sq_prepare (plugin->dbh, 369 sq_prepare (plugin->dbh,
382 "SELECT MAX(repl) FROM gn090" 370 "SELECT MAX(repl) FROM gn091"
383#if SQLITE_VERSION_NUMBER >= 3007000 371#if SQLITE_VERSION_NUMBER >= 3007000
384 " INDEXED BY idx_repl_rvalue" 372 " INDEXED BY idx_repl_rvalue"
385#endif 373#endif
@@ -387,18 +375,18 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
387 &plugin->maxRepl)) || 375 &plugin->maxRepl)) ||
388 (SQLITE_OK != 376 (SQLITE_OK !=
389 sq_prepare (plugin->dbh, 377 sq_prepare (plugin->dbh,
390 "SELECT " RESULT_COLUMNS " FROM gn090 " 378 "SELECT " RESULT_COLUMNS " FROM gn091 "
391#if SQLITE_VERSION_NUMBER >= 3007000 379#if SQLITE_VERSION_NUMBER >= 3007000
392 "INDEXED BY idx_expire " 380 "INDEXED BY idx_expire "
393#endif 381#endif
394 "WHERE NOT EXISTS (SELECT 1 FROM gn090 WHERE expire < ?1 LIMIT 1) OR (expire < ?1) " 382 "WHERE NOT EXISTS (SELECT 1 FROM gn091 WHERE expire < ?1 LIMIT 1) OR (expire < ?1) "
395 "ORDER BY expire ASC LIMIT 1", 383 "ORDER BY expire ASC LIMIT 1",
396 &plugin->selExpi)) || 384 &plugin->selExpi)) ||
397 (SQLITE_OK != 385 (SQLITE_OK !=
398 sq_prepare (plugin->dbh, 386 sq_prepare (plugin->dbh,
399 "SELECT " RESULT_COLUMNS " FROM gn090 " 387 "SELECT " RESULT_COLUMNS " FROM gn091 "
400#if SQLITE_VERSION_NUMBER >= 3007000 388#if SQLITE_VERSION_NUMBER >= 3007000
401 "INDEXED BY idx_anon_type_hash " 389 "INDEXED BY idx_anon_type "
402#endif 390#endif
403 "WHERE _ROWID_ >= ? AND " 391 "WHERE _ROWID_ >= ? AND "
404 "anonLevel = 0 AND " 392 "anonLevel = 0 AND "
@@ -407,12 +395,12 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
407 &plugin->selZeroAnon)) || 395 &plugin->selZeroAnon)) ||
408 (SQLITE_OK != 396 (SQLITE_OK !=
409 sq_prepare (plugin->dbh, 397 sq_prepare (plugin->dbh,
410 "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) " 398 "INSERT INTO gn091 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) "
411 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", 399 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
412 &plugin->insertContent)) || 400 &plugin->insertContent)) ||
413 (SQLITE_OK != 401 (SQLITE_OK !=
414 sq_prepare (plugin->dbh, 402 sq_prepare (plugin->dbh,
415 "SELECT " RESULT_COLUMNS " FROM gn090 " 403 "SELECT " RESULT_COLUMNS " FROM gn091 "
416 "WHERE _ROWID_ >= ? AND " 404 "WHERE _ROWID_ >= ? AND "
417 "(rvalue >= ? OR 0 = ?) AND " 405 "(rvalue >= ? OR 0 = ?) AND "
418 "(hash = ? OR 0 = ?) AND " 406 "(hash = ? OR 0 = ?) AND "
@@ -421,11 +409,11 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
421 &plugin->get)) || 409 &plugin->get)) ||
422 (SQLITE_OK != 410 (SQLITE_OK !=
423 sq_prepare (plugin->dbh, 411 sq_prepare (plugin->dbh,
424 "DELETE FROM gn090 WHERE _ROWID_ = ?", 412 "DELETE FROM gn091 WHERE _ROWID_ = ?",
425 &plugin->delRow)) || 413 &plugin->delRow)) ||
426 (SQLITE_OK != 414 (SQLITE_OK !=
427 sq_prepare (plugin->dbh, 415 sq_prepare (plugin->dbh,
428 "DELETE FROM gn090 " 416 "DELETE FROM gn091 "
429 "WHERE hash = ? AND " 417 "WHERE hash = ? AND "
430 "value = ? ", 418 "value = ? ",
431 &plugin->remove)) || 419 &plugin->remove)) ||
@@ -1137,7 +1125,7 @@ sqlite_plugin_get_keys (void *cls,
1137 GNUNET_assert (NULL != proc); 1125 GNUNET_assert (NULL != proc);
1138 if (SQLITE_OK != 1126 if (SQLITE_OK !=
1139 sq_prepare (plugin->dbh, 1127 sq_prepare (plugin->dbh,
1140 "SELECT hash FROM gn090", 1128 "SELECT hash FROM gn091",
1141 &stmt)) 1129 &stmt))
1142 { 1130 {
1143 LOG_SQLITE (plugin, 1131 LOG_SQLITE (plugin,
diff --git a/src/gns/gnunet-gns-import.c b/src/gns/gnunet-gns-import.c
index 49f6e495f..3b9b0a081 100644
--- a/src/gns/gnunet-gns-import.c
+++ b/src/gns/gnunet-gns-import.c
@@ -60,11 +60,6 @@ static char *master_zone_pkey;
60static struct GNUNET_CRYPTO_EcdsaPrivateKey master_pk; 60static struct GNUNET_CRYPTO_EcdsaPrivateKey master_pk;
61 61
62/** 62/**
63 * String version of PKEY for short-zone.
64 */
65static char *short_zone_pkey;
66
67/**
68 * String version of PKEY for private-zone. 63 * String version of PKEY for private-zone.
69 */ 64 */
70static char *private_zone_pkey; 65static char *private_zone_pkey;
@@ -80,11 +75,6 @@ static char *pin_zone_pkey = "72QC35CO20UJN1E91KPJFNT9TG4CLKAPB4VK9S3Q758S9MLBRK
80static int found_private_rec = GNUNET_NO; 75static int found_private_rec = GNUNET_NO;
81 76
82/** 77/**
83 * Set to GNUNET_YES if short record was found;
84 */
85static int found_short_rec = GNUNET_NO;
86
87/**
88 * Set to GNUNET_YES if pin record was found; 78 * Set to GNUNET_YES if pin record was found;
89 */ 79 */
90static int found_pin_rec = GNUNET_NO; 80static int found_pin_rec = GNUNET_NO;
@@ -219,8 +209,6 @@ zone_iterator (void *cls,
219 { 209 {
220 if (0 == strcmp (rname, "private")) 210 if (0 == strcmp (rname, "private"))
221 check_pkey (rd_len, rd, private_zone_pkey, &found_private_rec); 211 check_pkey (rd_len, rd, private_zone_pkey, &found_private_rec);
222 else if (0 == strcmp (rname, "short"))
223 check_pkey (rd_len, rd, short_zone_pkey, &found_short_rec);
224 else if (0 == strcmp (rname, "pin")) 212 else if (0 == strcmp (rname, "pin"))
225 check_pkey (rd_len, rd, pin_zone_pkey, &found_pin_rec); 213 check_pkey (rd_len, rd, pin_zone_pkey, &found_pin_rec);
226 } 214 }
@@ -242,16 +230,6 @@ zone_iteration_error (void *cls)
242 return; 230 return;
243 } 231 }
244 } 232 }
245 if (!found_short_rec)
246 {
247 if (0 != run_process_and_wait (GNUNET_NO, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, &st, &code,
248 "gnunet-namestore",
249 "gnunet-namestore", "-z", "master-zone", "-a", "-e", "never", "-n", "short", "-p", "-t", "PKEY", "-V", short_zone_pkey, NULL))
250 {
251 ret = 9;
252 return;
253 }
254 }
255 if (!found_pin_rec) 233 if (!found_pin_rec)
256 { 234 {
257 if (0 != run_process_and_wait (GNUNET_NO, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, &st, &code, 235 if (0 != run_process_and_wait (GNUNET_NO, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, &st, &code,
@@ -274,7 +252,7 @@ zone_iteration_finished (void *cls)
274 252
275 253
276/** 254/**
277 * Get master-zone, short-zone and private-zone keys. 255 * Get master-zone and private-zone keys.
278 * 256 *
279 * This function is initially called for all egos and then again 257 * This function is initially called for all egos and then again
280 * whenever a ego's identifier changes or if it is deleted. At the 258 * whenever a ego's identifier changes or if it is deleted. At the
@@ -316,7 +294,6 @@ get_ego (void *cls,
316 if (NULL == ego) 294 if (NULL == ego)
317 { 295 {
318 if (NULL == master_zone_pkey || 296 if (NULL == master_zone_pkey ||
319 NULL == short_zone_pkey ||
320 NULL == private_zone_pkey) 297 NULL == private_zone_pkey)
321 { 298 {
322 ret = 11; 299 ret = 11;
@@ -340,8 +317,6 @@ get_ego (void *cls,
340 master_zone_pkey = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk); 317 master_zone_pkey = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
341 master_pk = *GNUNET_IDENTITY_ego_get_private_key (ego); 318 master_pk = *GNUNET_IDENTITY_ego_get_private_key (ego);
342 } 319 }
343 else if (NULL == short_zone_pkey && 0 == strcmp ("short-zone", identifier))
344 short_zone_pkey = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
345 else if (NULL == private_zone_pkey && 0 == strcmp ("private-zone", identifier)) 320 else if (NULL == private_zone_pkey && 0 == strcmp ("private-zone", identifier))
346 private_zone_pkey = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk); 321 private_zone_pkey = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
347 } 322 }
@@ -357,8 +332,6 @@ shutdown_task (void *cls)
357{ 332{
358 GNUNET_free_non_null (master_zone_pkey); 333 GNUNET_free_non_null (master_zone_pkey);
359 master_zone_pkey = NULL; 334 master_zone_pkey = NULL;
360 GNUNET_free_non_null (short_zone_pkey);
361 short_zone_pkey = NULL;
362 GNUNET_free_non_null (private_zone_pkey); 335 GNUNET_free_non_null (private_zone_pkey);
363 private_zone_pkey = NULL; 336 private_zone_pkey = NULL;
364 if (NULL != list_it) 337 if (NULL != list_it)
@@ -411,11 +384,6 @@ run (void *cls, char *const *args, const char *cfgfile,
411 384
412 if (0 != run_process_and_wait (GNUNET_NO, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, &st, &code, 385 if (0 != run_process_and_wait (GNUNET_NO, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, &st, &code,
413 "gnunet-identity", 386 "gnunet-identity",
414 "gnunet-identity", "-C", "short-zone", NULL))
415 return;
416
417 if (0 != run_process_and_wait (GNUNET_NO, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, &st, &code,
418 "gnunet-identity",
419 "gnunet-identity", "-C", "private-zone", NULL)) 387 "gnunet-identity", "-C", "private-zone", NULL))
420 return; 388 return;
421 389
@@ -426,11 +394,6 @@ run (void *cls, char *const *args, const char *cfgfile,
426 394
427 if (0 != run_process_and_wait (GNUNET_NO, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, &st, &code, 395 if (0 != run_process_and_wait (GNUNET_NO, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, &st, &code,
428 "gnunet-identity", 396 "gnunet-identity",
429 "gnunet-identity", "-e", "short-zone", "-s", "gns-short", NULL))
430 return;
431
432 if (0 != run_process_and_wait (GNUNET_NO, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, &st, &code,
433 "gnunet-identity",
434 "gnunet-identity", "-e", "master-zone", "-s", "gns-master", NULL)) 397 "gnunet-identity", "-e", "master-zone", "-s", "gns-master", NULL))
435 return; 398 return;
436 399
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
index b745da125..e5abec416 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -48,6 +48,7 @@ gnunetinclude_HEADERS = \
48 gnunet_datacache_plugin.h \ 48 gnunet_datacache_plugin.h \
49 gnunet_datastore_service.h \ 49 gnunet_datastore_service.h \
50 gnunet_datastore_plugin.h \ 50 gnunet_datastore_plugin.h \
51 gnunet_db_lib.h \
51 gnunet_dht_service.h \ 52 gnunet_dht_service.h \
52 gnunet_disk_lib.h \ 53 gnunet_disk_lib.h \
53 gnunet_dnsparser_lib.h \ 54 gnunet_dnsparser_lib.h \
@@ -90,7 +91,6 @@ gnunetinclude_HEADERS = \
90 gnunet_peerstore_service.h \ 91 gnunet_peerstore_service.h \
91 gnunet_plugin_lib.h \ 92 gnunet_plugin_lib.h \
92 gnunet_pq_lib.h \ 93 gnunet_pq_lib.h \
93 gnunet_postgres_lib.h \
94 gnunet_psycstore_plugin.h \ 94 gnunet_psycstore_plugin.h \
95 gnunet_psycstore_service.h \ 95 gnunet_psycstore_service.h \
96 gnunet_psyc_service.h \ 96 gnunet_psyc_service.h \
diff --git a/src/include/gnunet_db_lib.h b/src/include/gnunet_db_lib.h
new file mode 100644
index 000000000..9356f66cb
--- /dev/null
+++ b/src/include/gnunet_db_lib.h
@@ -0,0 +1,61 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3, or (at your option) any later version.
8
9 GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along with
14 GNUnet; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
15*/
16/**
17 * @file include/gnunet_db_lib.h
18 * @brief shared defintions for transactional databases
19 * @author Christian Grothoff
20 */
21#ifndef GNUNET_DB_LIB_H
22#define GNUNET_DB_LIB_H
23
24
25/**
26 * Status code returned from functions running database commands.
27 * Can be combined with a function that returns the number
28 * of results, so all non-negative values indicate success.
29 */
30enum GNUNET_DB_QueryStatus
31{
32 /**
33 * A hard error occurred, retrying will not help.
34 */
35 GNUNET_DB_STATUS_HARD_ERROR = -2,
36
37 /**
38 * A soft error occurred, retrying the transaction may succeed.
39 * Includes DEADLOCKS and SERIALIZATION errors.
40 */
41 GNUNET_DB_STATUS_SOFT_ERROR = -1,
42
43 /**
44 * The transaction succeeded, but yielded zero results.
45 * May include the case where an INSERT failed with UNIQUE
46 * violation (i.e. row already exists) or where DELETE
47 * failed to remove anything (i.e. nothing matched).
48 */
49 GNUNET_DB_STATUS_SUCCESS_NO_RESULTS = 0,
50
51 /**
52 * The transaction succeeded, and yielded one result.
53 */
54 GNUNET_DB_STATUS_SUCCESS_ONE_RESULT = 1
55
56 /* Larger values may be returned for SELECT statements
57 that returned more than one result. */
58
59};
60
61#endif
diff --git a/src/include/gnunet_postgres_lib.h b/src/include/gnunet_postgres_lib.h
deleted file mode 100644
index 66fc2a5df..000000000
--- a/src/include/gnunet_postgres_lib.h
+++ /dev/null
@@ -1,178 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2012 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @author Christian Grothoff
22 *
23 * @file
24 * Helper library to access a PostgreSQL database
25 *
26 * @defgroup postgres PostgreSQL library
27 * Helper library to access a PostgreSQL database.
28 * @{
29 */
30#ifndef GNUNET_POSTGRES_LIB_H
31#define GNUNET_POSTGRES_LIB_H
32
33#include "gnunet_util_lib.h"
34#include <libpq-fe.h>
35
36#ifdef __cplusplus
37extern "C"
38{
39#if 0 /* keep Emacsens' auto-indent happy */
40}
41#endif
42#endif
43
44
45/**
46 * Check if the result obtained from Postgres has
47 * the desired status code. If not, log an error, clear the
48 * result and return #GNUNET_SYSERR.
49 *
50 * @param dbh database handle
51 * @param ret return value from database operation to check
52 * @param expected_status desired status
53 * @param command description of the command that was run
54 * @param args arguments given to the command
55 * @param filename name of the source file where the command was run
56 * @param line line number in the source file
57 * @return #GNUNET_OK if the result is acceptable
58 */
59int
60GNUNET_POSTGRES_check_result_ (PGconn *dbh,
61 PGresult *ret,
62 int expected_status,
63 const char *command,
64 const char *args,
65 const char *filename,
66 int line);
67
68
69/**
70 * Check if the result obtained from Postgres has
71 * the desired status code. If not, log an error, clear the
72 * result and return #GNUNET_SYSERR.
73 *
74 * @param dbh database handle
75 * @param ret return value from database operation to check
76 * @param expected_status desired status
77 * @param command description of the command that was run
78 * @param args arguments given to the command
79 * @return #GNUNET_OK if the result is acceptable
80 */
81#define GNUNET_POSTGRES_check_result(dbh,ret,expected_status,command,args) GNUNET_POSTGRES_check_result_(dbh,ret,expected_status,command,args,__FILE__,__LINE__)
82
83
84/**
85 * Run simple SQL statement (without results).
86 *
87 * @param dbh database handle
88 * @param sql statement to run
89 * @param filename filename for error reporting
90 * @param line code line for error reporting
91 * @return #GNUNET_OK on success
92 */
93int
94GNUNET_POSTGRES_exec_ (PGconn *dbh,
95 const char *sql,
96 const char *filename,
97 int line);
98
99
100/**
101 * Run simple SQL statement (without results).
102 *
103 * @param dbh database handle
104 * @param sql statement to run
105 * @return #GNUNET_OK on success
106 */
107#define GNUNET_POSTGRES_exec(dbh,sql) GNUNET_POSTGRES_exec_(dbh,sql,__FILE__,__LINE__)
108
109
110/**
111 * Prepare SQL statement.
112 *
113 * @param dbh database handle
114 * @param name name for the prepared SQL statement
115 * @param sql SQL code to prepare
116 * @param nparams number of parameters in sql
117 * @param filename filename for error reporting
118 * @param line code line for error reporting
119 * @return #GNUNET_OK on success
120 */
121int
122GNUNET_POSTGRES_prepare_ (PGconn *dbh,
123 const char *name,
124 const char *sql,
125 int nparams,
126 const char *filename,
127 int line);
128
129
130/**
131 * Prepare SQL statement.
132 *
133 * @param dbh database handle
134 * @param name name for the prepared SQL statement
135 * @param sql SQL code to prepare
136 * @param nparams number of parameters in sql
137 * @return #GNUNET_OK on success
138 */
139#define GNUNET_POSTGRES_prepare(dbh,name,sql,nparams) GNUNET_POSTGRES_prepare_(dbh,name,sql,nparams,__FILE__,__LINE__)
140
141
142/**
143 * Connect to a postgres database
144 *
145 * @param cfg configuration
146 * @param section configuration section to use to get Postgres configuration options
147 * @return the postgres handle
148 */
149PGconn *
150GNUNET_POSTGRES_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
151 const char *section);
152
153
154/**
155 * Delete the row identified by the given rowid (qid
156 * in postgres).
157 *
158 * @param dbh database handle
159 * @param stmt name of the prepared statement
160 * @param rowid which row to delete
161 * @return #GNUNET_OK on success
162 */
163int
164GNUNET_POSTGRES_delete_by_rowid (PGconn *dbh,
165 const char *stmt,
166 uint32_t rowid);
167
168
169#if 0 /* keep Emacsens' auto-indent happy */
170{
171#endif
172#ifdef __cplusplus
173}
174#endif
175
176#endif
177
178/** @} */ /* end of group */
diff --git a/src/include/gnunet_pq_lib.h b/src/include/gnunet_pq_lib.h
index 756370b74..ed295b500 100644
--- a/src/include/gnunet_pq_lib.h
+++ b/src/include/gnunet_pq_lib.h
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet 2 This file is part of GNUnet
3 Copyright (C) 2016 GNUnet e.V. 3 Copyright (C) 2016, 2017 GNUnet e.V.
4 4
5 GNUnet is free software; you can redistribute it and/or modify it under the 5 GNUnet is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software 6 terms of the GNU General Public License as published by the Free Software
@@ -23,6 +23,9 @@
23 23
24#include <libpq-fe.h> 24#include <libpq-fe.h>
25#include "gnunet_util_lib.h" 25#include "gnunet_util_lib.h"
26#include "gnunet_db_lib.h"
27
28/* ************************* pq_query_helper.c functions ************************ */
26 29
27 30
28/** 31/**
@@ -188,6 +191,9 @@ struct GNUNET_PQ_QueryParam
188GNUNET_PQ_query_param_uint64 (const uint64_t *x); 191GNUNET_PQ_query_param_uint64 (const uint64_t *x);
189 192
190 193
194/* ************************* pq_result_helper.c functions ************************ */
195
196
191/** 197/**
192 * Extract data from a Postgres database @a result at row @a row. 198 * Extract data from a Postgres database @a result at row @a row.
193 * 199 *
@@ -412,6 +418,8 @@ GNUNET_PQ_result_spec_uint64 (const char *name,
412 uint64_t *u64); 418 uint64_t *u64);
413 419
414 420
421/* ************************* pq.c functions ************************ */
422
415/** 423/**
416 * Execute a prepared statement. 424 * Execute a prepared statement.
417 * 425 *
@@ -419,6 +427,7 @@ GNUNET_PQ_result_spec_uint64 (const char *name,
419 * @param name name of the prepared statement 427 * @param name name of the prepared statement
420 * @param params parameters to the statement 428 * @param params parameters to the statement
421 * @return postgres result 429 * @return postgres result
430 * @deprecated (should become an internal API)
422 */ 431 */
423PGresult * 432PGresult *
424GNUNET_PQ_exec_prepared (PGconn *db_conn, 433GNUNET_PQ_exec_prepared (PGconn *db_conn,
@@ -435,6 +444,7 @@ GNUNET_PQ_exec_prepared (PGconn *db_conn,
435 * @return 444 * @return
436 * #GNUNET_YES if all results could be extracted 445 * #GNUNET_YES if all results could be extracted
437 * #GNUNET_SYSERR if a result was invalid (non-existing field) 446 * #GNUNET_SYSERR if a result was invalid (non-existing field)
447 * @deprecated (should become an internal API)
438 */ 448 */
439int 449int
440GNUNET_PQ_extract_result (PGresult *result, 450GNUNET_PQ_extract_result (PGresult *result,
@@ -452,6 +462,262 @@ void
452GNUNET_PQ_cleanup_result (struct GNUNET_PQ_ResultSpec *rs); 462GNUNET_PQ_cleanup_result (struct GNUNET_PQ_ResultSpec *rs);
453 463
454 464
465/* ******************** pq_eval.c functions ************** */
466
467
468/**
469 * Check the @a result's error code to see what happened.
470 * Also logs errors.
471 *
472 * @param connection connection to execute the statement in
473 * @param statement_name name of the statement that created @a result
474 * @param result result to check
475 * @return status code from the result, mapping PQ status
476 * codes to `enum GNUNET_DB_QueryStatus`. Never
477 * returns positive values as this function does
478 * not look at the result set.
479 * @deprecated (low level, let's see if we can do with just the high-level functions)
480 */
481enum GNUNET_DB_QueryStatus
482GNUNET_PQ_eval_result (PGconn *connection,
483 const char *statement_name,
484 PGresult *result);
485
486
487/**
488 * Execute a named prepared @a statement that is NOT a SELECT
489 * statement in @a connnection using the given @a params. Returns the
490 * resulting session state.
491 *
492 * @param connection connection to execute the statement in
493 * @param statement_name name of the statement
494 * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated)
495 * @return status code from the result, mapping PQ status
496 * codes to `enum GNUNET_DB_QueryStatus`. If the
497 * statement was a DELETE or UPDATE statement, the
498 * number of affected rows is returned; if the
499 * statment was an INSERT statement, and no row
500 * was added due to a UNIQUE violation, we return
501 * zero; if INSERT was successful, we return one.
502 */
503enum GNUNET_DB_QueryStatus
504GNUNET_PQ_eval_prepared_non_select (PGconn *connection,
505 const char *statement_name,
506 const struct GNUNET_PQ_QueryParam *params);
507
508
509/**
510 * Function to be called with the results of a SELECT statement
511 * that has returned @a num_results results.
512 *
513 * @param cls closure
514 * @param result the postgres result
515 * @param num_result the number of results in @a result
516 */
517typedef void
518(*GNUNET_PQ_PostgresResultHandler)(void *cls,
519 PGresult *result,
520 unsigned int num_results);
521
522
523/**
524 * Execute a named prepared @a statement that is a SELECT statement
525 * which may return multiple results in @a connection using the given
526 * @a params. Call @a rh with the results. Returns the query
527 * status including the number of results given to @a rh (possibly zero).
528 * @a rh will not have been called if the return value is negative.
529 *
530 * @param connection connection to execute the statement in
531 * @param statement_name name of the statement
532 * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated)
533 * @param rh function to call with the result set, NULL to ignore
534 * @param rh_cls closure to pass to @a rh
535 * @return status code from the result, mapping PQ status
536 * codes to `enum GNUNET_DB_QueryStatus`.
537 */
538enum GNUNET_DB_QueryStatus
539GNUNET_PQ_eval_prepared_multi_select (PGconn *connection,
540 const char *statement_name,
541 const struct GNUNET_PQ_QueryParam *params,
542 GNUNET_PQ_PostgresResultHandler rh,
543 void *rh_cls);
544
545
546/**
547 * Execute a named prepared @a statement that is a SELECT statement
548 * which must return a single result in @a connection using the given
549 * @a params. Stores the result (if any) in @a rs, which the caller
550 * must then clean up using #GNUNET_PQ_cleanup_result() if the return
551 * value was #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT. Returns the
552 * resulting session status.
553 *
554 * @param connection connection to execute the statement in
555 * @param statement_name name of the statement
556 * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated)
557 * @param[in,out] rs result specification to use for storing the result of the query
558 * @return status code from the result, mapping PQ status
559 * codes to `enum GNUNET_DB_QueryStatus`.
560 */
561enum GNUNET_DB_QueryStatus
562GNUNET_PQ_eval_prepared_singleton_select (PGconn *connection,
563 const char *statement_name,
564 const struct GNUNET_PQ_QueryParam *params,
565 struct GNUNET_PQ_ResultSpec *rs);
566
567
568/* ******************** pq_prepare.c functions ************** */
569
570
571/**
572 * Information needed to prepare a list of SQL statements using
573 * #GNUNET_PQ_prepare_statements().
574 */
575struct GNUNET_PQ_PreparedStatement {
576
577 /**
578 * Name of the statement.
579 */
580 const char *name;
581
582 /**
583 * Actual SQL statement.
584 */
585 const char *sql;
586
587 /**
588 * Number of arguments included in @e sql.
589 */
590 unsigned int num_arguments;
591
592};
593
594
595/**
596 * Terminator for prepared statement list.
597 */
598#define GNUNET_PQ_PREPARED_STATEMENT_END { NULL, NULL, 0 }
599
600
601/**
602 * Create a `struct GNUNET_PQ_PreparedStatement`.
603 *
604 * @param name name of the statement
605 * @param sql actual SQL statement
606 * @param num_args number of arguments in the statement
607 * @return initialized struct
608 */
609struct GNUNET_PQ_PreparedStatement
610GNUNET_PQ_make_prepare (const char *name,
611 const char *sql,
612 unsigned int num_args);
613
614
615/**
616 * Request creation of prepared statements @a ps from Postgres.
617 *
618 * @param connection connection to prepare the statements for
619 * @param ps #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared
620 * statements.
621 * @return #GNUNET_OK on success,
622 * #GNUNET_SYSERR on error
623 */
624int
625GNUNET_PQ_prepare_statements (PGconn *connection,
626 const struct GNUNET_PQ_PreparedStatement *ps);
627
628
629/* ******************** pq_exec.c functions ************** */
630
631
632/**
633 * Information needed to run a list of SQL statements using
634 * #GNUNET_PQ_exec_statements().
635 */
636struct GNUNET_PQ_ExecuteStatement {
637
638 /**
639 * Actual SQL statement.
640 */
641 const char *sql;
642
643 /**
644 * Should we ignore errors?
645 */
646 int ignore_errors;
647
648};
649
650
651/**
652 * Terminator for executable statement list.
653 */
654#define GNUNET_PQ_EXECUTE_STATEMENT_END { NULL, GNUNET_SYSERR }
655
656
657/**
658 * Create a `struct GNUNET_PQ_ExecuteStatement` where errors are fatal.
659 *
660 * @param sql actual SQL statement
661 * @return initialized struct
662 */
663struct GNUNET_PQ_ExecuteStatement
664GNUNET_PQ_make_execute (const char *sql);
665
666
667/**
668 * Create a `struct GNUNET_PQ_ExecuteStatement` where errors should
669 * be tolerated.
670 *
671 * @param sql actual SQL statement
672 * @return initialized struct
673 */
674struct GNUNET_PQ_ExecuteStatement
675GNUNET_PQ_make_try_execute (const char *sql);
676
677
678/**
679 * Request execution of an array of statements @a es from Postgres.
680 *
681 * @param connection connection to execute the statements over
682 * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared
683 * statements.
684 * @return #GNUNET_OK on success (modulo statements where errors can be ignored)
685 * #GNUNET_SYSERR on error
686 */
687int
688GNUNET_PQ_exec_statements (PGconn *connection,
689 const struct GNUNET_PQ_ExecuteStatement *es);
690
691
692/* ******************** pq_connect.c functions ************** */
693
694
695/**
696 * Create a connection to the Postgres database using @a config_str
697 * for the configuration. Initialize logging via GNUnet's log
698 * routines and disable Postgres's logger.
699 *
700 * @param config_str configuration to use
701 * @return NULL on error
702 */
703PGconn *
704GNUNET_PQ_connect (const char *config_str);
705
706
707/**
708 * Connect to a postgres database using the configuration
709 * option "CONFIG" in @a section.
710 *
711 * @param cfg configuration
712 * @param section configuration section to use to get Postgres configuration options
713 * @return the postgres handle, NULL on error
714 */
715PGconn *
716GNUNET_PQ_connect_with_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg,
717 const char *section);
718
719
720
455#endif /* GNUNET_PQ_LIB_H_ */ 721#endif /* GNUNET_PQ_LIB_H_ */
456 722
457/* end of include/gnunet_pq_lib.h */ 723/* end of include/gnunet_pq_lib.h */
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h
index 1d8049593..455a8292b 100644
--- a/src/include/gnunet_protocols.h
+++ b/src/include/gnunet_protocols.h
@@ -1814,6 +1814,13 @@ extern "C"
1814 */ 1814 */
1815#define GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT 598 1815#define GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT 598
1816 1816
1817/**
1818 * Request all missing elements from the other peer,
1819 * based on their sets and the elements we previously sent
1820 * with #GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS.
1821 */
1822#define GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OVER 599
1823
1817 1824
1818/******************************************************************************* 1825/*******************************************************************************
1819 * TESTBED LOGGER message types 1826 * TESTBED LOGGER message types
diff --git a/src/include/gnunet_strings_lib.h b/src/include/gnunet_strings_lib.h
index 144780c82..897f9f161 100644
--- a/src/include/gnunet_strings_lib.h
+++ b/src/include/gnunet_strings_lib.h
@@ -281,7 +281,7 @@ GNUNET_STRINGS_get_short_name (const char *filename);
281 281
282 282
283/** 283/**
284 * Convert binary data to ASCII encoding using Base32Hex (RFC 4648). 284 * Convert binary data to ASCII encoding using CrockfordBase32.
285 * Does not append 0-terminator, but returns a pointer to the place where 285 * Does not append 0-terminator, but returns a pointer to the place where
286 * it should be placed, if needed. 286 * it should be placed, if needed.
287 * 287 *
@@ -315,7 +315,7 @@ GNUNET_STRINGS_data_to_string_alloc (const void *buf,
315 315
316 316
317/** 317/**
318 * Convert Base32hex encoding back to data. 318 * Convert CrockfordBase32 encoding back to data.
319 * @a out_size must match exactly the size of the data before it was encoded. 319 * @a out_size must match exactly the size of the data before it was encoded.
320 * 320 *
321 * @param enc the encoding 321 * @param enc the encoding
diff --git a/src/multicast/Makefile.am b/src/multicast/Makefile.am
index 8a754d3db..a4054f5f6 100644
--- a/src/multicast/Makefile.am
+++ b/src/multicast/Makefile.am
@@ -51,7 +51,7 @@ gnunet_service_multicast_LDADD = \
51 $(GN_LIBINTL) 51 $(GN_LIBINTL)
52 52
53check_PROGRAMS = \ 53check_PROGRAMS = \
54 test_multicast_multipeer 54 test_multicast_multipeer
55# test_multicast 55# test_multicast
56# test_multicast_2peers 56# test_multicast_2peers
57 57
diff --git a/src/multicast/gnunet-service-multicast.c b/src/multicast/gnunet-service-multicast.c
index 9683efcff..39623e7b1 100644
--- a/src/multicast/gnunet-service-multicast.c
+++ b/src/multicast/gnunet-service-multicast.c
@@ -1504,13 +1504,12 @@ handle_client_member_join (void *cls,
1504 cl->client = client; 1504 cl->client = client;
1505 GNUNET_CONTAINER_DLL_insert (grp->clients_head, grp->clients_tail, cl); 1505 GNUNET_CONTAINER_DLL_insert (grp->clients_head, grp->clients_tail, cl);
1506 1506
1507 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1508 "%p Client connected to group %s..\n",
1509 mem, GNUNET_h2s (&grp->pub_key_hash));
1510 char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&mem->pub_key); 1507 char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&mem->pub_key);
1511 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1508 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1512 "%p ..as member %s (%s).\n", 1509 "Client connected to group %s as member %s (%s).\n",
1513 mem, GNUNET_h2s (&mem->pub_key_hash), str); 1510 GNUNET_h2s (&grp->pub_key_hash),
1511 GNUNET_h2s (&mem->pub_key_hash),
1512 str);
1514 GNUNET_free (str); 1513 GNUNET_free (str);
1515 1514
1516 if (NULL != mem->join_dcsn) 1515 if (NULL != mem->join_dcsn)
diff --git a/src/multicast/test_multicast.conf b/src/multicast/test_multicast.conf
index 3081aeecc..3dc96adbb 100644
--- a/src/multicast/test_multicast.conf
+++ b/src/multicast/test_multicast.conf
@@ -1,12 +1,55 @@
1[testbed] 1[testbed]
2HOSTNAME = localhost 2HOSTNAME = localhost
3#OVERLAY_TOPOLOGY = LINE
3 4
4[arm] 5[arm]
5GLOBAL_POSTFIX=-L ERROR 6GLOBAL_POSTFIX=-L ERROR
6 7
8[hostlist]
9SERVERS = http://localhost:8080/
10
7[multicast] 11[multicast]
8#PREFIX = xterm -T peer -e gdb --args 12#PREFIX = tmux split-window -v gdb -x ./cmd.gdb --args
9UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock 13UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock
10 14
11[vpn] 15[vpn]
12AUTOSTART = NO 16AUTOSTART = NO
17
18[peerinfo]
19# Do not use shipped gnunet HELLOs
20USE_INCLUDED_HELLOS = NO
21
22# Option to disable all disk IO; only useful for testbed runs
23# (large-scale experiments); disables persistence of HELLOs!
24NO_IO = YES
25
26[nat]
27ENABLE_UPNP = NO
28
29[fs]
30FORCESTART = NO
31AUTOSTART = NO
32
33[vpn]
34FORCESTART = NO
35AUTOSTART = NO
36
37[revocation]
38FORCESTART = NO
39AUTOSTART = NO
40
41[gns]
42FORCESTART = NO
43AUTOSTART = NO
44
45[namestore]
46FORCESTART = NO
47AUTOSTART = NO
48
49[namecache]
50FORCESTART = NO
51AUTOSTART = NO
52
53[topology]
54FORCESTART = NO
55AUTOSTART = NO
diff --git a/src/multicast/test_multicast_multipeer.c b/src/multicast/test_multicast_multipeer.c
index c2078abf9..5c3664f35 100644
--- a/src/multicast/test_multicast_multipeer.c
+++ b/src/multicast/test_multicast_multipeer.c
@@ -33,14 +33,15 @@
33#include "gnunet_testbed_service.h" 33#include "gnunet_testbed_service.h"
34#include "gnunet_multicast_service.h" 34#include "gnunet_multicast_service.h"
35 35
36#define NUM_PEERS 3 36#define NUM_PEERS 2
37 37
38struct multicast_peer 38struct multicast_peer
39{ 39{
40 int peer; /* peer number */ 40 int peer; /* peer number */
41 const struct GNUNET_PeerIdentity *id;
41 struct GNUNET_TESTBED_Operation *op; /* not yet in use */ 42 struct GNUNET_TESTBED_Operation *op; /* not yet in use */
42 struct GNUNET_TESTBED_Operation *pi_op; /* not yet in use */ 43 struct GNUNET_TESTBED_Operation *pi_op; /* not yet in use */
43 uint8_t test_ok; 44 int test_ok;
44}; 45};
45 46
46static void service_connect (void *cls, 47static void service_connect (void *cls,
@@ -54,7 +55,6 @@ static struct GNUNET_TESTBED_Peer **peers;
54// FIXME: refactor 55// FIXME: refactor
55static struct GNUNET_TESTBED_Operation *op[NUM_PEERS]; 56static struct GNUNET_TESTBED_Operation *op[NUM_PEERS];
56static struct GNUNET_TESTBED_Operation *pi_op[NUM_PEERS]; 57static struct GNUNET_TESTBED_Operation *pi_op[NUM_PEERS];
57static const struct GNUNET_PeerIdentity *peer_id[NUM_PEERS];
58 58
59static struct GNUNET_MULTICAST_Origin *origin; 59static struct GNUNET_MULTICAST_Origin *origin;
60static struct GNUNET_MULTICAST_Member *member[NUM_PEERS]; /* first element always empty */ 60static struct GNUNET_MULTICAST_Member *member[NUM_PEERS]; /* first element always empty */
@@ -80,16 +80,6 @@ static int result;
80static void 80static void
81shutdown_task (void *cls) 81shutdown_task (void *cls)
82{ 82{
83 if (NULL != mc_peers)
84 {
85 for (int i=0; i < NUM_PEERS; i++)
86 {
87 GNUNET_free (mc_peers[i]);
88 mc_peers[i] = NULL;
89 }
90 GNUNET_free (mc_peers);
91 }
92
93 for (int i=0;i<NUM_PEERS;i++) 83 for (int i=0;i<NUM_PEERS;i++)
94 { 84 {
95 if (NULL != op[i]) 85 if (NULL != op[i])
@@ -104,6 +94,16 @@ shutdown_task (void *cls)
104 } 94 }
105 } 95 }
106 96
97 if (NULL != mc_peers)
98 {
99 for (int i=0; i < NUM_PEERS; i++)
100 {
101 GNUNET_free (mc_peers[i]);
102 mc_peers[i] = NULL;
103 }
104 GNUNET_free (mc_peers);
105 }
106
107 if (NULL != timeout_tid) 107 if (NULL != timeout_tid)
108 { 108 {
109 GNUNET_SCHEDULER_cancel (timeout_tid); 109 GNUNET_SCHEDULER_cancel (timeout_tid);
@@ -130,8 +130,9 @@ member_join_request (void *cls,
130{ 130{
131 struct multicast_peer *mc_peer = (struct multicast_peer*)cls; 131 struct multicast_peer *mc_peer = (struct multicast_peer*)cls;
132 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 132 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
133 "Peer #%u sent a join request.\n", mc_peer->peer); 133 "Peer #%u (%s) sent a join request.\n",
134 134 mc_peer->peer,
135 GNUNET_i2s (mc_peers[mc_peer->peer]->id));
135} 136}
136 137
137 138
@@ -165,7 +166,10 @@ member_join_decision (void *cls,
165 struct GNUNET_MULTICAST_MemberTransmitHandle *req; 166 struct GNUNET_MULTICAST_MemberTransmitHandle *req;
166 167
167 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 168 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
168 "Peer #%u received a decision from origin: %s\n", mc_peer->peer, (GNUNET_YES == is_admitted)?"accepted":"rejected"); 169 "Peer #%u (%s) received a decision from origin: %s\n",
170 mc_peer->peer,
171 GNUNET_i2s (mc_peers[mc_peer->peer]->id),
172 (GNUNET_YES == is_admitted)?"accepted":"rejected");
169 173
170 if (GNUNET_YES == is_admitted) 174 if (GNUNET_YES == is_admitted)
171 { 175 {
@@ -203,29 +207,30 @@ member_message (void *cls,
203 if (0 != strncmp ("pong", (char *)&msg[1], 4)) 207 if (0 != strncmp ("pong", (char *)&msg[1], 4))
204 { 208 {
205 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 209 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
206 "peer #%i did not receive pong\n", 210 "peer #%i (%s) did not receive pong\n",
207 mc_peer->peer); 211 mc_peer->peer,
212 GNUNET_i2s (mc_peers[mc_peer->peer]->id));
208 213
209 result = GNUNET_SYSERR; 214 result = GNUNET_SYSERR;
210 GNUNET_SCHEDULER_shutdown (); 215 GNUNET_SCHEDULER_shutdown ();
211 } 216 }
212 217
213 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 218 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
214 "peer #%i receives: %s\n", 219 "peer #%i (%s) receives: %s\n",
215 mc_peer->peer, 220 mc_peer->peer,
221 GNUNET_i2s (mc_peers[mc_peer->peer]->id),
216 (char *)&msg[1]); 222 (char *)&msg[1]);
217 223
218 mc_peer->test_ok = GNUNET_OK; 224 mc_peer->test_ok = GNUNET_OK;
219 225
220 // FIXME: ugly test function 226 // FIXME: ugly test function
221 /* 227 // (we start with 1 because 0 is origin)
222 for (int i=1; i<NUM_PEERS; i++) 228 for (int i=1; i<NUM_PEERS; i++)
223 if (!mc_peers[i]->test_ok) 229 if (GNUNET_NO == mc_peers[i]->test_ok)
224 return; 230 return;
225 231
226 result = GNUNET_YES; 232 result = GNUNET_YES;
227 GNUNET_SCHEDULER_shutdown(); 233 GNUNET_SCHEDULER_shutdown();
228 */
229} 234}
230 235
231 236
@@ -345,7 +350,9 @@ multicast_da (void *cls,
345 else 350 else
346 { 351 {
347 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 352 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
348 "peer #%u parting from multicast group\n", mc_peer->peer); 353 "peer #%u (%s) parting from multicast group\n",
354 mc_peer->peer,
355 GNUNET_i2s (mc_peers[mc_peer->peer]->id));
349 356
350 GNUNET_MULTICAST_member_part (member[mc_peer->peer], NULL, cls); 357 GNUNET_MULTICAST_member_part (member[mc_peer->peer], NULL, cls);
351 } 358 }
@@ -381,9 +388,12 @@ multicast_ca (void *cls,
381 // Get members keys 388 // Get members keys
382 member_pub_key[mc_peer->peer] = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey); 389 member_pub_key[mc_peer->peer] = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
383 member_key[mc_peer->peer] = GNUNET_CRYPTO_ecdsa_key_create (); 390 member_key[mc_peer->peer] = GNUNET_CRYPTO_ecdsa_key_create ();
384 GNUNET_CRYPTO_ecdsa_key_get_public (member_key[mc_peer->peer], member_pub_key[mc_peer->peer]); 391 GNUNET_CRYPTO_ecdsa_key_get_public (member_key[mc_peer->peer],
392 member_pub_key[mc_peer->peer]);
385 393
386 sprintf(data, "Hi, I am peer #%u. Can I enter?", mc_peer->peer); 394 sprintf(data, "Hi, I am peer #%u (%s). Can I enter?",
395 mc_peer->peer,
396 GNUNET_i2s (mc_peers[mc_peer->peer]->id));
387 uint8_t data_size = strlen (data) + 1; 397 uint8_t data_size = strlen (data) + 1;
388 join_msg = GNUNET_malloc (sizeof (join_msg) + data_size); 398 join_msg = GNUNET_malloc (sizeof (join_msg) + data_size);
389 join_msg->size = htons (sizeof (join_msg) + data_size); 399 join_msg->size = htons (sizeof (join_msg) + data_size);
@@ -391,12 +401,14 @@ multicast_ca (void *cls,
391 GNUNET_memcpy (&join_msg[1], data, data_size); 401 GNUNET_memcpy (&join_msg[1], data, data_size);
392 402
393 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 403 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
394 "Peer #%u tries to join multicast group\n", mc_peer->peer); 404 "Peer #%u (%s) tries to join multicast group\n",
405 mc_peer->peer,
406 GNUNET_i2s (mc_peers[mc_peer->peer]->id));
395 407
396 return GNUNET_MULTICAST_member_join (cfg, 408 return GNUNET_MULTICAST_member_join (cfg,
397 group_pub_key, 409 group_pub_key,
398 member_key[mc_peer->peer], 410 member_key[mc_peer->peer],
399 peer_id[0], 411 mc_peers[0]->id,
400 0, 412 0,
401 NULL, 413 NULL,
402 join_msg, /* join message */ 414 join_msg, /* join message */
@@ -424,13 +436,17 @@ peer_information_cb (void *cls,
424 GNUNET_SCHEDULER_shutdown (); 436 GNUNET_SCHEDULER_shutdown ();
425 } 437 }
426 438
427 peer_id[mc_peer->peer] = pinfo->result.id; 439 mc_peers[mc_peer->peer]->id = pinfo->result.id;
428 440
429 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 441 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
430 "Got peer information of %s (%s)\n", (0==mc_peer->peer)?"origin":"member" ,GNUNET_i2s(pinfo->result.id)); 442 "Got peer information of %s (%s)\n",
443 (0 == mc_peer->peer)? "origin" : "member",
444 GNUNET_i2s (pinfo->result.id));
431 445
432 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 446 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
433 "Create peer #%u\n", mc_peer->peer); 447 "Create peer #%u (%s)\n",
448 mc_peer->peer,
449 GNUNET_i2s (mc_peers[mc_peer->peer]->id));
434 450
435 if (0 != mc_peer->peer) 451 if (0 != mc_peer->peer)
436 { 452 {
@@ -461,13 +477,18 @@ service_connect (void *cls,
461 if (NULL == ca_result) 477 if (NULL == ca_result)
462 { 478 {
463 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 479 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
464 "Connection adapter not created for peer #%u\n", mc_peer->peer); 480 "Connection adapter not created for peer #%u (%s)\n",
481 mc_peer->peer,
482 GNUNET_i2s (mc_peers[mc_peer->peer]->id));
483
465 result = GNUNET_SYSERR; 484 result = GNUNET_SYSERR;
466 GNUNET_SCHEDULER_shutdown(); 485 GNUNET_SCHEDULER_shutdown();
467 } 486 }
468 487
469 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 488 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
470 "Connected to multicast service of peer #%u\n", mc_peer->peer); 489 "Connected to multicast service of peer #%u (%s)\n",
490 mc_peer->peer,
491 GNUNET_i2s (mc_peers[mc_peer->peer]->id));
471 492
472 if (0 == mc_peer->peer) 493 if (0 == mc_peer->peer)
473 { 494 {
@@ -525,9 +546,6 @@ testbed_master (void *cls,
525 546
526 peers = p; 547 peers = p;
527 548
528 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
529 "Create origin peer\n");
530
531 mc_peers = GNUNET_new_array (NUM_PEERS, struct multicast_peer*); 549 mc_peers = GNUNET_new_array (NUM_PEERS, struct multicast_peer*);
532 550
533 // Create test contexts for members 551 // Create test contexts for members
@@ -538,6 +556,9 @@ testbed_master (void *cls,
538 mc_peers[i]->test_ok = GNUNET_NO; 556 mc_peers[i]->test_ok = GNUNET_NO;
539 } 557 }
540 558
559 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
560 "Create origin peer\n");
561
541 op[0] = GNUNET_TESTBED_service_connect (NULL, /* Closure for operation */ 562 op[0] = GNUNET_TESTBED_service_connect (NULL, /* Closure for operation */
542 peers[0], /* The peer whose service to connect to */ 563 peers[0], /* The peer whose service to connect to */
543 "multicast", /* The name of the service */ 564 "multicast", /* The name of the service */
@@ -553,7 +574,7 @@ testbed_master (void *cls,
553 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); /* Schedule a new task on shutdown */ 574 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); /* Schedule a new task on shutdown */
554 575
555 /* Schedule the shutdown task with a delay of a few Seconds */ 576 /* Schedule the shutdown task with a delay of a few Seconds */
556 timeout_tid = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 80), 577 timeout_tid = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 400),
557 &timeout_task, NULL); 578 &timeout_task, NULL);
558} 579}
559 580
diff --git a/src/namecache/Makefile.am b/src/namecache/Makefile.am
index d379b2602..c62ca6a2b 100644
--- a/src/namecache/Makefile.am
+++ b/src/namecache/Makefile.am
@@ -133,7 +133,6 @@ libgnunet_plugin_namecache_postgres_la_SOURCES = \
133 plugin_namecache_postgres.c 133 plugin_namecache_postgres.c
134libgnunet_plugin_namecache_postgres_la_LIBADD = \ 134libgnunet_plugin_namecache_postgres_la_LIBADD = \
135 libgnunetnamecache.la \ 135 libgnunetnamecache.la \
136 $(top_builddir)/src/postgres/libgnunetpostgres.la \
137 $(top_builddir)/src/pq/libgnunetpq.la \ 136 $(top_builddir)/src/pq/libgnunetpq.la \
138 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 137 $(top_builddir)/src/statistics/libgnunetstatistics.la \
139 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq \ 138 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq \
diff --git a/src/namecache/plugin_namecache_postgres.c b/src/namecache/plugin_namecache_postgres.c
index bec8bffd2..d943b0cd8 100644
--- a/src/namecache/plugin_namecache_postgres.c
+++ b/src/namecache/plugin_namecache_postgres.c
@@ -1,6 +1,6 @@
1 /* 1 /*
2 * This file is part of GNUnet 2 * This file is part of GNUnet
3 * Copyright (C) 2009-2013, 2016 GNUnet e.V. 3 * Copyright (C) 2009-2013, 2016, 2017 GNUnet e.V.
4 * 4 *
5 * GNUnet is free software; you can redistribute it and/or modify 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 6 * it under the terms of the GNU General Public License as published
@@ -27,31 +27,10 @@
27#include "gnunet_namecache_plugin.h" 27#include "gnunet_namecache_plugin.h"
28#include "gnunet_namecache_service.h" 28#include "gnunet_namecache_service.h"
29#include "gnunet_gnsrecord_lib.h" 29#include "gnunet_gnsrecord_lib.h"
30#include "gnunet_postgres_lib.h"
31#include "gnunet_pq_lib.h" 30#include "gnunet_pq_lib.h"
32#include "namecache.h" 31#include "namecache.h"
33 32
34 33
35/**
36 * After how many ms "busy" should a DB operation fail for good?
37 * A low value makes sure that we are more responsive to requests
38 * (especially PUTs). A high value guarantees a higher success
39 * rate (SELECTs in iterate can take several seconds despite LIMIT=1).
40 *
41 * The default value of 1s should ensure that users do not experience
42 * huge latencies while at the same time allowing operations to succeed
43 * with reasonable probability.
44 */
45#define BUSY_TIMEOUT_MS 1000
46
47
48/**
49 * Log an error message at log-level 'level' that indicates
50 * a failure of the command 'cmd' on file 'filename'
51 * with the message given by strerror(errno).
52 */
53#define LOG_POSTGRES(db, level, cmd) do { GNUNET_log_from (level, "namecache-postgres", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); } while(0)
54
55#define LOG(kind,...) GNUNET_log_from (kind, "namecache-postgres", __VA_ARGS__) 34#define LOG(kind,...) GNUNET_log_from (kind, "namecache-postgres", __VA_ARGS__)
56 35
57 36
@@ -72,40 +51,34 @@ struct Plugin
72 51
73 52
74/** 53/**
75 * Create our database indices.
76 *
77 * @param dbh handle to the database
78 */
79static void
80create_indices (PGconn * dbh)
81{
82 /* create indices */
83 if ( (GNUNET_OK !=
84 GNUNET_POSTGRES_exec (dbh,
85 "CREATE INDEX ir_query_hash ON ns096blocks (query,expiration_time)")) ||
86 (GNUNET_OK !=
87 GNUNET_POSTGRES_exec (dbh,
88 "CREATE INDEX ir_block_expiration ON ns096blocks (expiration_time)")) )
89 LOG (GNUNET_ERROR_TYPE_ERROR,
90 _("Failed to create indices\n"));
91}
92
93
94/**
95 * Initialize the database connections and associated 54 * Initialize the database connections and associated
96 * data structures (create tables and indices 55 * data structures (create tables and indices
97 * as needed as well). 56 * as needed as well).
98 * 57 *
99 * @param plugin the plugin context (state for this module) 58 * @param plugin the plugin context (state for this module)
100 * @return GNUNET_OK on success 59 * @return #GNUNET_OK on success
101 */ 60 */
102static int 61static int
103database_setup (struct Plugin *plugin) 62database_setup (struct Plugin *plugin)
104{ 63{
105 PGresult *res; 64 struct GNUNET_PQ_ExecuteStatement es_temporary =
106 65 GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS ns096blocks ("
107 plugin->dbh = GNUNET_POSTGRES_connect (plugin->cfg, 66 " query BYTEA NOT NULL DEFAULT '',"
108 "namecache-postgres"); 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");
109 if (NULL == plugin->dbh) 82 if (NULL == plugin->dbh)
110 return GNUNET_SYSERR; 83 return GNUNET_SYSERR;
111 if (GNUNET_YES == 84 if (GNUNET_YES ==
@@ -113,65 +86,56 @@ database_setup (struct Plugin *plugin)
113 "namecache-postgres", 86 "namecache-postgres",
114 "TEMPORARY_TABLE")) 87 "TEMPORARY_TABLE"))
115 { 88 {
116 res = 89 cr = &es_temporary;
117 PQexec (plugin->dbh,
118 "CREATE TEMPORARY TABLE ns096blocks ("
119 " query BYTEA NOT NULL DEFAULT '',"
120 " block BYTEA NOT NULL DEFAULT '',"
121 " expiration_time BIGINT NOT NULL DEFAULT 0"
122 ")" "WITH OIDS");
123 } 90 }
124 else 91 else
125 { 92 {
126 res = 93 cr = &es_default;
127 PQexec (plugin->dbh,
128 "CREATE TABLE ns096blocks ("
129 " query BYTEA NOT NULL DEFAULT '',"
130 " block BYTEA NOT NULL DEFAULT '',"
131 " expiration_time BIGINT NOT NULL DEFAULT 0"
132 ")" "WITH OIDS");
133 } 94 }
134 if ( (NULL == res) || 95
135 ((PQresultStatus (res) != PGRES_COMMAND_OK) &&
136 (0 != strcmp ("42P07", /* duplicate table */
137 PQresultErrorField
138 (res,
139 PG_DIAG_SQLSTATE)))))
140 { 96 {
141 (void) GNUNET_POSTGRES_check_result (plugin->dbh, res, 97 struct GNUNET_PQ_ExecuteStatement es[] = {
142 PGRES_COMMAND_OK, "CREATE TABLE", 98 *cr,
143 "ns096blocks"); 99 GNUNET_PQ_make_try_execute ("CREATE INDEX ir_query_hash ON ns096blocks (query,expiration_time)"),
144 PQfinish (plugin->dbh); 100 GNUNET_PQ_make_try_execute ("CREATE INDEX ir_block_expiration ON ns096blocks (expiration_time)"),
145 plugin->dbh = NULL; 101 GNUNET_PQ_EXECUTE_STATEMENT_END
146 return GNUNET_SYSERR; 102 };
103
104 if (GNUNET_OK !=
105 GNUNET_PQ_exec_statements (plugin->dbh,
106 es))
107 {
108 PQfinish (plugin->dbh);
109 plugin->dbh = NULL;
110 return GNUNET_SYSERR;
111 }
147 } 112 }
148 if (PQresultStatus (res) == PGRES_COMMAND_OK) 113
149 create_indices (plugin->dbh);
150 PQclear (res);
151
152 if ((GNUNET_OK !=
153 GNUNET_POSTGRES_prepare (plugin->dbh,
154 "cache_block",
155 "INSERT INTO ns096blocks (query, block, expiration_time) VALUES "
156 "($1, $2, $3)", 3)) ||
157 (GNUNET_OK !=
158 GNUNET_POSTGRES_prepare (plugin->dbh,
159 "expire_blocks",
160 "DELETE FROM ns096blocks WHERE expiration_time<$1", 1)) ||
161 (GNUNET_OK !=
162 GNUNET_POSTGRES_prepare (plugin->dbh,
163 "delete_block",
164 "DELETE FROM ns096blocks WHERE query=$1 AND expiration_time<=$2", 2)) ||
165 (GNUNET_OK !=
166 GNUNET_POSTGRES_prepare (plugin->dbh,
167 "lookup_block",
168 "SELECT block FROM ns096blocks WHERE query=$1"
169 " ORDER BY expiration_time DESC LIMIT 1", 1)))
170 { 114 {
171 PQfinish (plugin->dbh); 115 struct GNUNET_PQ_PreparedStatement ps[] = {
172 plugin->dbh = NULL; 116 GNUNET_PQ_make_prepare ("cache_block",
173 return GNUNET_SYSERR; 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),
126 GNUNET_PQ_PREPARED_STATEMENT_END
127 };
128
129 if (GNUNET_OK !=
130 GNUNET_PQ_prepare_statements (plugin->dbh,
131 ps))
132 {
133 PQfinish (plugin->dbh);
134 plugin->dbh = NULL;
135 return GNUNET_SYSERR;
136 }
174 } 137 }
138
175 return GNUNET_OK; 139 return GNUNET_OK;
176} 140}
177 141
@@ -185,23 +149,16 @@ static void
185namecache_postgres_expire_blocks (struct Plugin *plugin) 149namecache_postgres_expire_blocks (struct Plugin *plugin)
186{ 150{
187 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); 151 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
188 struct GNUNET_PQ_QueryParam params[] = { 152 struct GNUNET_PQ_QueryParam params[] = {
189 GNUNET_PQ_query_param_absolute_time (&now), 153 GNUNET_PQ_query_param_absolute_time (&now),
190 GNUNET_PQ_query_param_end 154 GNUNET_PQ_query_param_end
191 }; 155 };
192 PGresult *res; 156 enum GNUNET_DB_QueryStatus res;
193 157
194 res = GNUNET_PQ_exec_prepared (plugin->dbh, 158 res = GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
195 "expire_blocks", 159 "expire_blocks",
196 params); 160 params);
197 if (GNUNET_OK != 161 GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != res);
198 GNUNET_POSTGRES_check_result (plugin->dbh,
199 res,
200 PGRES_COMMAND_OK,
201 "PQexecPrepared",
202 "expire_blocks"))
203 return;
204 PQclear (res);
205} 162}
206 163
207 164
@@ -217,24 +174,17 @@ delete_old_block (struct Plugin *plugin,
217 const struct GNUNET_HashCode *query, 174 const struct GNUNET_HashCode *query,
218 struct GNUNET_TIME_AbsoluteNBO expiration_time) 175 struct GNUNET_TIME_AbsoluteNBO expiration_time)
219{ 176{
220 struct GNUNET_PQ_QueryParam params[] = { 177 struct GNUNET_PQ_QueryParam params[] = {
221 GNUNET_PQ_query_param_auto_from_type (query), 178 GNUNET_PQ_query_param_auto_from_type (query),
222 GNUNET_PQ_query_param_absolute_time_nbo (&expiration_time), 179 GNUNET_PQ_query_param_absolute_time_nbo (&expiration_time),
223 GNUNET_PQ_query_param_end 180 GNUNET_PQ_query_param_end
224 }; 181 };
225 PGresult *res; 182 enum GNUNET_DB_QueryStatus res;
226 183
227 res = GNUNET_PQ_exec_prepared (plugin->dbh, 184 res = GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
228 "delete_block", 185 "delete_block",
229 params); 186 params);
230 if (GNUNET_OK != 187 GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != res);
231 GNUNET_POSTGRES_check_result (plugin->dbh,
232 res,
233 PGRES_COMMAND_OK,
234 "PQexecPrepared",
235 "delete_block"))
236 return;
237 PQclear (res);
238} 188}
239 189
240 190
@@ -254,13 +204,13 @@ namecache_postgres_cache_block (void *cls,
254 size_t block_size = ntohl (block->purpose.size) + 204 size_t block_size = ntohl (block->purpose.size) +
255 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) + 205 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
256 sizeof (struct GNUNET_CRYPTO_EcdsaSignature); 206 sizeof (struct GNUNET_CRYPTO_EcdsaSignature);
257 struct GNUNET_PQ_QueryParam params[] = { 207 struct GNUNET_PQ_QueryParam params[] = {
258 GNUNET_PQ_query_param_auto_from_type (&query), 208 GNUNET_PQ_query_param_auto_from_type (&query),
259 GNUNET_PQ_query_param_fixed_size (block, block_size), 209 GNUNET_PQ_query_param_fixed_size (block, block_size),
260 GNUNET_PQ_query_param_absolute_time_nbo (&block->expiration_time), 210 GNUNET_PQ_query_param_absolute_time_nbo (&block->expiration_time),
261 GNUNET_PQ_query_param_end 211 GNUNET_PQ_query_param_end
262 }; 212 };
263 PGresult *res; 213 enum GNUNET_DB_QueryStatus res;
264 214
265 namecache_postgres_expire_blocks (plugin); 215 namecache_postgres_expire_blocks (plugin);
266 GNUNET_CRYPTO_hash (&block->derived_key, 216 GNUNET_CRYPTO_hash (&block->derived_key,
@@ -271,19 +221,15 @@ namecache_postgres_cache_block (void *cls,
271 GNUNET_break (0); 221 GNUNET_break (0);
272 return GNUNET_SYSERR; 222 return GNUNET_SYSERR;
273 } 223 }
274 delete_old_block (plugin, &query, block->expiration_time); 224 delete_old_block (plugin,
275 225 &query,
276 res = GNUNET_PQ_exec_prepared (plugin->dbh, 226 block->expiration_time);
277 "cache_block", 227
278 params); 228 res = GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
279 if (GNUNET_OK != 229 "cache_block",
280 GNUNET_POSTGRES_check_result (plugin->dbh, 230 params);
281 res, 231 if (0 > res)
282 PGRES_COMMAND_OK,
283 "PQexecPrepared",
284 "cache_block"))
285 return GNUNET_SYSERR; 232 return GNUNET_SYSERR;
286 PQclear (res);
287 return GNUNET_OK; 233 return GNUNET_OK;
288} 234}
289 235
@@ -301,42 +247,41 @@ namecache_postgres_cache_block (void *cls,
301static int 247static int
302namecache_postgres_lookup_block (void *cls, 248namecache_postgres_lookup_block (void *cls,
303 const struct GNUNET_HashCode *query, 249 const struct GNUNET_HashCode *query,
304 GNUNET_NAMECACHE_BlockCallback iter, void *iter_cls) 250 GNUNET_NAMECACHE_BlockCallback iter,
251 void *iter_cls)
305{ 252{
306 struct Plugin *plugin = cls; 253 struct Plugin *plugin = cls;
307 struct GNUNET_PQ_QueryParam params[] = { 254 size_t bsize;
255 struct GNUNET_GNSRECORD_Block *block;
256 struct GNUNET_PQ_QueryParam params[] = {
308 GNUNET_PQ_query_param_auto_from_type (query), 257 GNUNET_PQ_query_param_auto_from_type (query),
309 GNUNET_PQ_query_param_end 258 GNUNET_PQ_query_param_end
310 }; 259 };
311 PGresult *res; 260 struct GNUNET_PQ_ResultSpec rs[] = {
312 unsigned int cnt; 261 GNUNET_PQ_result_spec_variable_size ("block",
313 size_t bsize; 262 (void **) &block,
314 const struct GNUNET_GNSRECORD_Block *block; 263 &bsize),
315 264 GNUNET_PQ_result_spec_end
316 res = GNUNET_PQ_exec_prepared (plugin->dbh, 265 };
317 "lookup_block", 266 enum GNUNET_DB_QueryStatus res;
318 params); 267
319 if (GNUNET_OK != 268 res = GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh,
320 GNUNET_POSTGRES_check_result (plugin->dbh, res, PGRES_TUPLES_OK, 269 "lookup_block",
321 "PQexecPrepared", 270 params,
322 "lookup_block")) 271 rs);
272 if (0 > res)
323 { 273 {
324 LOG (GNUNET_ERROR_TYPE_DEBUG, 274 LOG (GNUNET_ERROR_TYPE_WARNING,
325 "Failing lookup (postgres error)\n"); 275 "Failing lookup block in namecache (postgres error)\n");
326 return GNUNET_SYSERR; 276 return GNUNET_SYSERR;
327 } 277 }
328 if (0 == (cnt = PQntuples (res))) 278 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == res)
329 { 279 {
330 /* no result */ 280 /* no result */
331 LOG (GNUNET_ERROR_TYPE_DEBUG, 281 LOG (GNUNET_ERROR_TYPE_DEBUG,
332 "Ending iteration (no more results)\n"); 282 "Ending iteration (no more results)\n");
333 PQclear (res);
334 return GNUNET_NO; 283 return GNUNET_NO;
335 } 284 }
336 GNUNET_assert (1 == cnt);
337 GNUNET_assert (1 != PQnfields (res));
338 bsize = PQgetlength (res, 0, 0);
339 block = (const struct GNUNET_GNSRECORD_Block *) PQgetvalue (res, 0, 0);
340 if ( (bsize < sizeof (*block)) || 285 if ( (bsize < sizeof (*block)) ||
341 (bsize != ntohl (block->purpose.size) + 286 (bsize != ntohl (block->purpose.size) +
342 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) + 287 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
@@ -345,11 +290,12 @@ namecache_postgres_lookup_block (void *cls,
345 GNUNET_break (0); 290 GNUNET_break (0);
346 LOG (GNUNET_ERROR_TYPE_DEBUG, 291 LOG (GNUNET_ERROR_TYPE_DEBUG,
347 "Failing lookup (corrupt block)\n"); 292 "Failing lookup (corrupt block)\n");
348 PQclear (res); 293 GNUNET_PQ_cleanup_result (rs);
349 return GNUNET_SYSERR; 294 return GNUNET_SYSERR;
350 } 295 }
351 iter (iter_cls, block); 296 iter (iter_cls,
352 PQclear (res); 297 block);
298 GNUNET_PQ_cleanup_result (rs);
353 return GNUNET_OK; 299 return GNUNET_OK;
354} 300}
355 301
@@ -395,7 +341,7 @@ libgnunet_plugin_namecache_postgres_init (void *cls)
395 api->cache_block = &namecache_postgres_cache_block; 341 api->cache_block = &namecache_postgres_cache_block;
396 api->lookup_block = &namecache_postgres_lookup_block; 342 api->lookup_block = &namecache_postgres_lookup_block;
397 LOG (GNUNET_ERROR_TYPE_INFO, 343 LOG (GNUNET_ERROR_TYPE_INFO,
398 _("Postgres database running\n")); 344 "Postgres namecache plugin running\n");
399 return api; 345 return api;
400} 346}
401 347
@@ -416,7 +362,7 @@ libgnunet_plugin_namecache_postgres_done (void *cls)
416 plugin->cfg = NULL; 362 plugin->cfg = NULL;
417 GNUNET_free (api); 363 GNUNET_free (api);
418 LOG (GNUNET_ERROR_TYPE_DEBUG, 364 LOG (GNUNET_ERROR_TYPE_DEBUG,
419 "postgres plugin is finished\n"); 365 "Postgres namecache plugin is finished\n");
420 return NULL; 366 return NULL;
421} 367}
422 368
diff --git a/src/namestore/Makefile.am b/src/namestore/Makefile.am
index 1b99fcc45..4f710e116 100644
--- a/src/namestore/Makefile.am
+++ b/src/namestore/Makefile.am
@@ -199,7 +199,6 @@ libgnunet_plugin_namestore_postgres_la_SOURCES = \
199 plugin_namestore_postgres.c 199 plugin_namestore_postgres.c
200libgnunet_plugin_namestore_postgres_la_LIBADD = \ 200libgnunet_plugin_namestore_postgres_la_LIBADD = \
201 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ 201 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
202 $(top_builddir)/src/postgres/libgnunetpostgres.la \
203 $(top_builddir)/src/pq/libgnunetpq.la \ 202 $(top_builddir)/src/pq/libgnunetpq.la \
204 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 203 $(top_builddir)/src/statistics/libgnunetstatistics.la \
205 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq \ 204 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq \
diff --git a/src/namestore/gnunet-service-namestore.c b/src/namestore/gnunet-service-namestore.c
index 6cb4290a0..b27cfb732 100644
--- a/src/namestore/gnunet-service-namestore.c
+++ b/src/namestore/gnunet-service-namestore.c
@@ -414,9 +414,12 @@ get_nick_record (const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone)
414 struct GNUNET_GNSRECORD_Data *nick; 414 struct GNUNET_GNSRECORD_Data *nick;
415 int res; 415 int res;
416 416
417 res = GSN_database->lookup_records (GSN_database->cls, zone, 417 nick = NULL;
418 res = GSN_database->lookup_records (GSN_database->cls,
419 zone,
418 GNUNET_GNS_MASTERZONE_STR, 420 GNUNET_GNS_MASTERZONE_STR,
419 &lookup_nick_it, &nick); 421 &lookup_nick_it,
422 &nick);
420 if ( (GNUNET_OK != res) || 423 if ( (GNUNET_OK != res) ||
421 (NULL == nick) ) 424 (NULL == nick) )
422 { 425 {
diff --git a/src/namestore/namestore_api.c b/src/namestore/namestore_api.c
index 933ba7b95..92068cc01 100644
--- a/src/namestore/namestore_api.c
+++ b/src/namestore/namestore_api.c
@@ -1303,11 +1303,14 @@ GNUNET_NAMESTORE_zone_iteration_stop (struct GNUNET_NAMESTORE_ZoneIterator *it)
1303 1303
1304 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1304 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1305 "Sending ZONE_ITERATION_STOP message\n"); 1305 "Sending ZONE_ITERATION_STOP message\n");
1306 env = GNUNET_MQ_msg (msg, 1306 if (NULL != h->mq)
1307 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP); 1307 {
1308 msg->gns_header.r_id = htonl (it->op_id); 1308 env = GNUNET_MQ_msg (msg,
1309 GNUNET_MQ_send (h->mq, 1309 GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP);
1310 env); 1310 msg->gns_header.r_id = htonl (it->op_id);
1311 GNUNET_MQ_send (h->mq,
1312 env);
1313 }
1311 free_ze (it); 1314 free_ze (it);
1312} 1315}
1313 1316
diff --git a/src/namestore/plugin_namestore_postgres.c b/src/namestore/plugin_namestore_postgres.c
index 01dbf9e61..491cec1cb 100644
--- a/src/namestore/plugin_namestore_postgres.c
+++ b/src/namestore/plugin_namestore_postgres.c
@@ -1,6 +1,6 @@
1 /* 1 /*
2 * This file is part of GNUnet 2 * This file is part of GNUnet
3 * Copyright (C) 2009-2013, 2016 GNUnet e.V. 3 * Copyright (C) 2009-2013, 2016, 2017 GNUnet e.V.
4 * 4 *
5 * GNUnet is free software; you can redistribute it and/or modify 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 6 * it under the terms of the GNU General Public License as published
@@ -27,31 +27,10 @@
27#include "gnunet_namestore_plugin.h" 27#include "gnunet_namestore_plugin.h"
28#include "gnunet_namestore_service.h" 28#include "gnunet_namestore_service.h"
29#include "gnunet_gnsrecord_lib.h" 29#include "gnunet_gnsrecord_lib.h"
30#include "gnunet_postgres_lib.h"
31#include "gnunet_pq_lib.h" 30#include "gnunet_pq_lib.h"
32#include "namestore.h" 31#include "namestore.h"
33 32
34 33
35/**
36 * After how many ms "busy" should a DB operation fail for good?
37 * A low value makes sure that we are more responsive to requests
38 * (especially PUTs). A high value guarantees a higher success
39 * rate (SELECTs in iterate can take several seconds despite LIMIT=1).
40 *
41 * The default value of 1s should ensure that users do not experience
42 * huge latencies while at the same time allowing operations to succeed
43 * with reasonable probability.
44 */
45#define BUSY_TIMEOUT_MS 1000
46
47
48/**
49 * Log an error message at log-level 'level' that indicates
50 * a failure of the command 'cmd' on file 'filename'
51 * with the message given by strerror(errno).
52 */
53#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)
54
55#define LOG(kind,...) GNUNET_log_from (kind, "namestore-postgres", __VA_ARGS__) 34#define LOG(kind,...) GNUNET_log_from (kind, "namestore-postgres", __VA_ARGS__)
56 35
57 36
@@ -75,30 +54,6 @@ struct Plugin
75 54
76 55
77/** 56/**
78 * Create our database indices.
79 *
80 * @param dbh handle to the database
81 */
82static void
83create_indices (PGconn * dbh)
84{
85 /* create indices */
86 if ( (GNUNET_OK !=
87 GNUNET_POSTGRES_exec (dbh,
88 "CREATE INDEX IF NOT EXISTS ir_pkey_reverse ON ns097records (zone_private_key,pkey)")) ||
89 (GNUNET_OK !=
90 GNUNET_POSTGRES_exec (dbh,
91 "CREATE INDEX IF NOT EXISTS ir_pkey_iter ON ns097records (zone_private_key,rvalue)")) ||
92 (GNUNET_OK !=
93 GNUNET_POSTGRES_exec (dbh, "CREATE INDEX IF NOT EXISTS it_iter ON ns097records (rvalue)")) ||
94 (GNUNET_OK !=
95 GNUNET_POSTGRES_exec (dbh, "CREATE INDEX IF NOT EXISTS ir_label ON ns097records (label)")) )
96 LOG (GNUNET_ERROR_TYPE_ERROR,
97 _("Failed to create indices\n"));
98}
99
100
101/**
102 * Initialize the database connections and associated 57 * Initialize the database connections and associated
103 * data structures (create tables and indices 58 * data structures (create tables and indices
104 * as needed as well). 59 * as needed as well).
@@ -109,10 +64,30 @@ create_indices (PGconn * dbh)
109static int 64static int
110database_setup (struct Plugin *plugin) 65database_setup (struct Plugin *plugin)
111{ 66{
112 PGresult *res; 67 struct GNUNET_PQ_ExecuteStatement es_temporary =
113 68 GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS ns097records ("
114 plugin->dbh = GNUNET_POSTGRES_connect (plugin->cfg, 69 " zone_private_key BYTEA NOT NULL DEFAULT '',"
115 "namestore-postgres"); 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 ")"
76 "WITH OIDS");
77 struct GNUNET_PQ_ExecuteStatement es_default =
78 GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS ns097records ("
79 " zone_private_key BYTEA NOT NULL DEFAULT '',"
80 " pkey BYTEA DEFAULT '',"
81 " rvalue BYTEA NOT NULL DEFAULT '',"
82 " record_count INTEGER NOT NULL DEFAULT 0,"
83 " record_data BYTEA NOT NULL DEFAULT '',"
84 " label TEXT NOT NULL DEFAULT ''"
85 ")"
86 "WITH OIDS");
87 const struct GNUNET_PQ_ExecuteStatement *cr;
88
89 plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg,
90 "namestore-postgres");
116 if (NULL == plugin->dbh) 91 if (NULL == plugin->dbh)
117 return GNUNET_SYSERR; 92 return GNUNET_SYSERR;
118 if (GNUNET_YES == 93 if (GNUNET_YES ==
@@ -120,80 +95,70 @@ database_setup (struct Plugin *plugin)
120 "namestore-postgres", 95 "namestore-postgres",
121 "TEMPORARY_TABLE")) 96 "TEMPORARY_TABLE"))
122 { 97 {
123 res = 98 cr = &es_temporary;
124 PQexec (plugin->dbh,
125 "CREATE TEMPORARY TABLE IF NOT EXISTS ns097records ("
126 " zone_private_key BYTEA NOT NULL DEFAULT '',"
127 " pkey BYTEA DEFAULT '',"
128 " rvalue BYTEA NOT NULL DEFAULT '',"
129 " record_count INTEGER NOT NULL DEFAULT 0,"
130 " record_data BYTEA NOT NULL DEFAULT '',"
131 " label TEXT NOT NULL DEFAULT ''"
132 ")" "WITH OIDS");
133 } 99 }
134 else 100 else
135 { 101 {
136 res = 102 cr = &es_default;
137 PQexec (plugin->dbh,
138 "CREATE TABLE IF NOT EXISTS ns097records ("
139 " zone_private_key BYTEA NOT NULL DEFAULT '',"
140 " pkey BYTEA DEFAULT '',"
141 " rvalue BYTEA NOT NULL DEFAULT '',"
142 " record_count INTEGER NOT NULL DEFAULT 0,"
143 " record_data BYTEA NOT NULL DEFAULT '',"
144 " label TEXT NOT NULL DEFAULT ''"
145 ")" "WITH OIDS");
146 } 103 }
147 if ( (NULL == res) || 104
148 ((PQresultStatus (res) != PGRES_COMMAND_OK) &&
149 (0 != strcmp ("42P07", /* duplicate table */
150 PQresultErrorField
151 (res,
152 PG_DIAG_SQLSTATE)))))
153 { 105 {
154 (void) GNUNET_POSTGRES_check_result (plugin->dbh, res, 106 struct GNUNET_PQ_ExecuteStatement es[] = {
155 PGRES_COMMAND_OK, "CREATE TABLE", 107 *cr,
156 "ns097records"); 108 GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_reverse "
157 PQfinish (plugin->dbh); 109 "ON ns097records (zone_private_key,pkey)"),
158 plugin->dbh = NULL; 110 GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_pkey_iter "
159 return GNUNET_SYSERR; 111 "ON ns097records (zone_private_key,rvalue)"),
112 GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS it_iter "
113 "ON ns097records (rvalue)"),
114 GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS ir_label "
115 "ON ns097records (label)"),
116 GNUNET_PQ_EXECUTE_STATEMENT_END
117 };
118
119 if (GNUNET_OK !=
120 GNUNET_PQ_exec_statements (plugin->dbh,
121 es))
122 {
123 PQfinish (plugin->dbh);
124 plugin->dbh = NULL;
125 return GNUNET_SYSERR;
126 }
160 } 127 }
161 create_indices (plugin->dbh); 128
162
163 if ((GNUNET_OK !=
164 GNUNET_POSTGRES_prepare (plugin->dbh,
165 "store_records",
166 "INSERT INTO ns097records (zone_private_key, pkey, rvalue, record_count, record_data, label) VALUES "
167 "($1, $2, $3, $4, $5, $6)", 6)) ||
168 (GNUNET_OK !=
169 GNUNET_POSTGRES_prepare (plugin->dbh,
170 "delete_records",
171 "DELETE FROM ns097records WHERE zone_private_key=$1 AND label=$2", 2)) ||
172 (GNUNET_OK !=
173 GNUNET_POSTGRES_prepare (plugin->dbh,
174 "zone_to_name",
175 "SELECT record_count,record_data,label FROM ns097records"
176 " WHERE zone_private_key=$1 AND pkey=$2", 2)) ||
177 (GNUNET_OK !=
178 GNUNET_POSTGRES_prepare (plugin->dbh,
179 "iterate_zone",
180 "SELECT record_count,record_data,label FROM ns097records"
181 " WHERE zone_private_key=$1 ORDER BY rvalue LIMIT 1 OFFSET $2", 2)) ||
182 (GNUNET_OK !=
183 GNUNET_POSTGRES_prepare (plugin->dbh,
184 "iterate_all_zones",
185 "SELECT record_count,record_data,label,zone_private_key"
186 " FROM ns097records ORDER BY rvalue LIMIT 1 OFFSET $1", 1)) ||
187 (GNUNET_OK !=
188 GNUNET_POSTGRES_prepare (plugin->dbh,
189 "lookup_label",
190 "SELECT record_count,record_data,label"
191 " FROM ns097records WHERE zone_private_key=$1 AND label=$2", 2)))
192 { 129 {
193 PQfinish (plugin->dbh); 130 struct GNUNET_PQ_PreparedStatement ps[] = {
194 plugin->dbh = NULL; 131 GNUNET_PQ_make_prepare ("store_records",
195 return GNUNET_SYSERR; 132 "INSERT INTO ns097records (zone_private_key, pkey, rvalue, record_count, record_data, label) VALUES "
133 "($1, $2, $3, $4, $5, $6)", 6),
134 GNUNET_PQ_make_prepare ("delete_records",
135 "DELETE FROM ns097records "
136 "WHERE zone_private_key=$1 AND label=$2", 2),
137 GNUNET_PQ_make_prepare ("zone_to_name",
138 "SELECT record_count,record_data,label FROM ns097records"
139 " WHERE zone_private_key=$1 AND pkey=$2", 2),
140 GNUNET_PQ_make_prepare ("iterate_zone",
141 "SELECT record_count,record_data,label FROM ns097records "
142 "WHERE zone_private_key=$1 ORDER BY rvalue LIMIT 1 OFFSET $2", 2),
143 GNUNET_PQ_make_prepare ("iterate_all_zones",
144 "SELECT record_count,record_data,label,zone_private_key"
145 " FROM ns097records ORDER BY rvalue LIMIT 1 OFFSET $1", 1),
146 GNUNET_PQ_make_prepare ("lookup_label",
147 "SELECT record_count,record_data,label "
148 "FROM ns097records WHERE zone_private_key=$1 AND label=$2", 2),
149 GNUNET_PQ_PREPARED_STATEMENT_END
150 };
151
152 if (GNUNET_OK !=
153 GNUNET_PQ_prepare_statements (plugin->dbh,
154 ps))
155 {
156 PQfinish (plugin->dbh);
157 plugin->dbh = NULL;
158 return GNUNET_SYSERR;
159 }
196 } 160 }
161
197 return GNUNET_OK; 162 return GNUNET_OK;
198} 163}
199 164
@@ -219,21 +184,21 @@ namestore_postgres_store_records (void *cls,
219 struct Plugin *plugin = cls; 184 struct Plugin *plugin = cls;
220 struct GNUNET_CRYPTO_EcdsaPublicKey pkey; 185 struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
221 uint64_t rvalue; 186 uint64_t rvalue;
222 uint32_t rd_count_nbo = htonl ((uint32_t) rd_count); 187 uint32_t rd_count32 = (uint32_t) rd_count;
223 size_t data_size; 188 size_t data_size;
224 unsigned int i;
225 189
226 memset (&pkey, 0, sizeof (pkey)); 190 memset (&pkey, 0, sizeof (pkey));
227 for (i=0;i<rd_count;i++) 191 for (unsigned int i=0;i<rd_count;i++)
228 if (GNUNET_GNSRECORD_TYPE_PKEY == rd[i].record_type) 192 if (GNUNET_GNSRECORD_TYPE_PKEY == rd[i].record_type)
229 { 193 {
230 GNUNET_break (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) == rd[i].data_size); 194 GNUNET_break (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) == rd[i].data_size);
231 GNUNET_memcpy (&pkey, 195 GNUNET_memcpy (&pkey,
232 rd[i].data, 196 rd[i].data,
233 rd[i].data_size); 197 rd[i].data_size);
234 break; 198 break;
235 } 199 }
236 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); 200 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
201 UINT64_MAX);
237 data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd); 202 data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
238 if (data_size > 64 * 65536) 203 if (data_size > 64 * 65536)
239 { 204 {
@@ -242,141 +207,134 @@ namestore_postgres_store_records (void *cls,
242 } 207 }
243 { 208 {
244 char data[data_size]; 209 char data[data_size];
245 // FIXME: use libgnunetpq! 210 struct GNUNET_PQ_QueryParam params[] = {
246 const char *paramValues[] = { 211 GNUNET_PQ_query_param_auto_from_type (zone_key),
247 (const char *) zone_key, 212 GNUNET_PQ_query_param_auto_from_type (&pkey),
248 (const char *) &pkey, 213 GNUNET_PQ_query_param_uint64 (&rvalue),
249 (const char *) &rvalue, 214 GNUNET_PQ_query_param_uint32 (&rd_count32),
250 (const char *) &rd_count_nbo, 215 GNUNET_PQ_query_param_fixed_size (data, data_size),
251 (const char *) data, 216 GNUNET_PQ_query_param_string (label),
252 label 217 GNUNET_PQ_query_param_end
253 };
254 int paramLengths[] = {
255 sizeof (*zone_key),
256 sizeof (pkey),
257 sizeof (rvalue),
258 sizeof (rd_count_nbo),
259 data_size,
260 strlen (label)
261 }; 218 };
262 const int paramFormats[] = { 1, 1, 1, 1, 1, 1 }; 219 enum GNUNET_DB_QueryStatus res;
263 PGresult *res;
264 220
265 if (data_size != GNUNET_GNSRECORD_records_serialize (rd_count, rd, 221 if (data_size !=
266 data_size, data)) 222 GNUNET_GNSRECORD_records_serialize (rd_count, rd,
223 data_size, data))
267 { 224 {
268 GNUNET_break (0); 225 GNUNET_break (0);
269 return GNUNET_SYSERR; 226 return GNUNET_SYSERR;
270 } 227 }
271 228
272 res = 229 res = GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
273 PQexecPrepared (plugin->dbh, "store_records", 6, 230 "store_records",
274 paramValues, paramLengths, paramFormats, 1); 231 params);
275 if (GNUNET_OK != 232 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != res)
276 GNUNET_POSTGRES_check_result (plugin->dbh,
277 res,
278 PGRES_COMMAND_OK,
279 "PQexecPrepared",
280 "store_records"))
281 return GNUNET_SYSERR; 233 return GNUNET_SYSERR;
282 PQclear (res);
283 return GNUNET_OK;
284 } 234 }
235 return GNUNET_OK;
285} 236}
286 237
287 238
288/** 239/**
240 * Closure for #parse_result_call_iterator.
241 */
242struct ParserContext
243{
244 /**
245 * Function to call for each result.
246 */
247 GNUNET_NAMESTORE_RecordIterator iter;
248
249 /**
250 * Closure for @e iter.
251 */
252 void *iter_cls;
253
254 /**
255 * Zone key, NULL if part of record.
256 */
257 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key;
258};
259
260
261/**
289 * A statement has been run. We should evaluate the result, and if possible 262 * A statement has been run. We should evaluate the result, and if possible
290 * call the given @a iter with the result. 263 * call the @a iter in @a cls with the result.
291 * 264 *
292 * @param plugin plugin context 265 * @param cls closure of type `struct ParserContext *`
293 * @param res result from the statement that was run (to be cleaned up) 266 * @param result the postgres result
294 * @param zone_key private key of the zone, could be NULL, in which case we should 267 * @param num_result the number of results in @a result
295 * get the zone from @a res
296 * @param iter iterator to call with the result
297 * @param iter_cls closure for @a iter
298 * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
299 */ 268 */
300static int 269static void
301get_record_and_call_iterator (struct Plugin *plugin, 270parse_result_call_iterator (void *cls,
302 PGresult *res, 271 PGresult *res,
303 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key, 272 unsigned int num_results)
304 GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
305{ 273{
306 const char *data; 274 struct ParserContext *pc = cls;
307 size_t data_size; 275
308 uint32_t record_count; 276 for (unsigned int i=0;i<num_results;i++)
309 const char *label;
310 size_t label_len;
311 unsigned int cnt;
312
313 if (GNUNET_OK !=
314 GNUNET_POSTGRES_check_result (plugin->dbh, res, PGRES_TUPLES_OK,
315 "PQexecPrepared",
316 "iteration"))
317 {
318 LOG (GNUNET_ERROR_TYPE_DEBUG,
319 "Failing lookup (postgres error)\n");
320 return GNUNET_SYSERR;
321 }
322 if (0 == (cnt = PQntuples (res)))
323 {
324 /* no result */
325 LOG (GNUNET_ERROR_TYPE_DEBUG,
326 "Ending iteration (no more results)\n");
327 PQclear (res);
328 return GNUNET_NO;
329 }
330 GNUNET_assert (1 == cnt);
331 GNUNET_assert (3 + ((NULL == zone_key) ? 1 : 0) == PQnfields (res));
332 if (NULL == zone_key)
333 { 277 {
334 if (sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey) != PQgetlength (res, 0, 3)) 278 void *data;
279 size_t data_size;
280 uint32_t record_count;
281 char *label;
282 struct GNUNET_CRYPTO_EcdsaPrivateKey zk;
283 struct GNUNET_PQ_ResultSpec rs_with_zone[] = {
284 GNUNET_PQ_result_spec_uint32 ("record_count", &record_count),
285 GNUNET_PQ_result_spec_variable_size ("record_data", &data, &data_size),
286 GNUNET_PQ_result_spec_string ("label", &label),
287 GNUNET_PQ_result_spec_auto_from_type ("zone_private_key", &zk),
288 GNUNET_PQ_result_spec_end
289 };
290 struct GNUNET_PQ_ResultSpec rs_without_zone[] = {
291 GNUNET_PQ_result_spec_uint32 ("record_count", &record_count),
292 GNUNET_PQ_result_spec_variable_size ("record_data", &data, &data_size),
293 GNUNET_PQ_result_spec_string ("label", &label),
294 GNUNET_PQ_result_spec_end
295 };
296 struct GNUNET_PQ_ResultSpec *rs;
297
298 rs = (NULL == pc->zone_key) ? rs_with_zone : rs_without_zone;
299 if (GNUNET_YES !=
300 GNUNET_PQ_extract_result (res,
301 rs,
302 i))
335 { 303 {
336 GNUNET_break (0); 304 GNUNET_break (0);
337 PQclear (res); 305 return;
338 return GNUNET_SYSERR;
339 } 306 }
340 zone_key = (const struct GNUNET_CRYPTO_EcdsaPrivateKey *) PQgetvalue (res, 0, 3);
341 }
342 if (sizeof (uint32_t) != PQfsize (res, 0))
343 {
344 GNUNET_break (0);
345 PQclear (res);
346 return GNUNET_SYSERR;
347 }
348 307
349 record_count = ntohl (*(uint32_t *) PQgetvalue (res, 0, 0)); 308 if (record_count > 64 * 1024)
350 data = PQgetvalue (res, 0, 1);
351 data_size = PQgetlength (res, 0, 1);
352 label = PQgetvalue (res, 0, 2);
353 label_len = PQgetlength (res, 0, 1);
354 if (record_count > 64 * 1024)
355 {
356 /* sanity check, don't stack allocate far too much just
357 because database might contain a large value here */
358 GNUNET_break (0);
359 PQclear (res);
360 return GNUNET_SYSERR;
361 }
362 {
363 struct GNUNET_GNSRECORD_Data rd[record_count];
364 char buf[label_len + 1];
365
366 GNUNET_memcpy (buf, label, label_len);
367 buf[label_len] = '\0';
368 if (GNUNET_OK !=
369 GNUNET_GNSRECORD_records_deserialize (data_size, data,
370 record_count, rd))
371 { 309 {
310 /* sanity check, don't stack allocate far too much just
311 because database might contain a large value here */
372 GNUNET_break (0); 312 GNUNET_break (0);
373 PQclear (res); 313 GNUNET_PQ_cleanup_result (rs);
374 return GNUNET_SYSERR; 314 return;
315 }
316
317 {
318 struct GNUNET_GNSRECORD_Data rd[record_count];
319
320 if (GNUNET_OK !=
321 GNUNET_GNSRECORD_records_deserialize (data_size,
322 data,
323 record_count,
324 rd))
325 {
326 GNUNET_break (0);
327 GNUNET_PQ_cleanup_result (rs);
328 return;
329 }
330 pc->iter (pc->iter_cls,
331 (NULL == pc->zone_key) ? &zk : pc->zone_key,
332 label,
333 record_count,
334 rd);
375 } 335 }
376 iter (iter_cls, zone_key, buf, record_count, rd); 336 GNUNET_PQ_cleanup_result (rs);
377 } 337 }
378 PQclear (res);
379 return GNUNET_OK;
380} 338}
381 339
382 340
@@ -398,25 +356,25 @@ namestore_postgres_lookup_records (void *cls,
398 void *iter_cls) 356 void *iter_cls)
399{ 357{
400 struct Plugin *plugin = cls; 358 struct Plugin *plugin = cls;
401 const char *paramValues[] = { 359 struct GNUNET_PQ_QueryParam params[] = {
402 (const char *) zone, 360 GNUNET_PQ_query_param_auto_from_type (zone),
403 label 361 GNUNET_PQ_query_param_string (label),
362 GNUNET_PQ_query_param_end
404 }; 363 };
405 int paramLengths[] = { 364 struct ParserContext pc;
406 sizeof (*zone), 365 enum GNUNET_DB_QueryStatus res;
407 strlen (label) 366
408 }; 367 pc.iter = iter;
409 const int paramFormats[] = { 1, 1 }; 368 pc.iter_cls = iter_cls;
410 PGresult *res; 369 pc.zone_key = NULL;
411 370 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
412 res = PQexecPrepared (plugin->dbh, 371 "lookup_label",
413 "lookup_label", 2, 372 params,
414 paramValues, paramLengths, paramFormats, 373 &parse_result_call_iterator,
415 1); 374 &pc);
416 return get_record_and_call_iterator (plugin, 375 if (res <= 0)
417 res, 376 return GNUNET_SYSERR;
418 zone, 377 return GNUNET_OK;
419 iter, iter_cls);
420} 378}
421 379
422 380
@@ -435,53 +393,50 @@ static int
435namestore_postgres_iterate_records (void *cls, 393namestore_postgres_iterate_records (void *cls,
436 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, 394 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
437 uint64_t offset, 395 uint64_t offset,
438 GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls) 396 GNUNET_NAMESTORE_RecordIterator iter,
397 void *iter_cls)
439{ 398{
440 struct Plugin *plugin = cls; 399 struct Plugin *plugin = cls;
441 uint64_t offset_be = GNUNET_htonll (offset); 400 enum GNUNET_DB_QueryStatus res;
401 struct ParserContext pc;
442 402
403 pc.iter = iter;
404 pc.iter_cls = iter_cls;
405 pc.zone_key = zone;
443 if (NULL == zone) 406 if (NULL == zone)
444 { 407 {
445 const char *paramValues[] = { 408 struct GNUNET_PQ_QueryParam params_without_zone[] = {
446 (const char *) &offset_be 409 GNUNET_PQ_query_param_uint64 (&offset),
410 GNUNET_PQ_query_param_end
447 }; 411 };
448 int paramLengths[] = { 412
449 sizeof (offset_be) 413 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
450 }; 414 "iterate_all_zones",
451 const int paramFormats[] = { 1 }; 415 params_without_zone,
452 PGresult *res; 416 &parse_result_call_iterator,
453 417 &pc);
454 res = PQexecPrepared (plugin->dbh,
455 "iterate_all_zones", 1,
456 paramValues, paramLengths, paramFormats,
457 1);
458 return get_record_and_call_iterator (plugin,
459 res,
460 NULL,
461 iter, iter_cls);
462 } 418 }
463 else 419 else
464 { 420 {
465 const char *paramValues[] = { 421 struct GNUNET_PQ_QueryParam params_with_zone[] = {
466 (const char *) zone, 422 GNUNET_PQ_query_param_auto_from_type (zone),
467 (const char *) &offset_be 423 GNUNET_PQ_query_param_uint64 (&offset),
468 }; 424 GNUNET_PQ_query_param_end
469 int paramLengths[] = {
470 sizeof (*zone),
471 sizeof (offset_be)
472 }; 425 };
473 const int paramFormats[] = { 1, 1 }; 426
474 PGresult *res; 427 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
475 428 "iterate_zone",
476 res = PQexecPrepared (plugin->dbh, 429 params_with_zone,
477 "iterate_zone", 2, 430 &parse_result_call_iterator,
478 paramValues, paramLengths, paramFormats, 431 &pc);
479 1);
480 return get_record_and_call_iterator (plugin,
481 res,
482 zone,
483 iter, iter_cls);
484 } 432 }
433 if (res < 0)
434 return GNUNET_SYSERR;
435
436 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == res)
437 return GNUNET_NO;
438
439 return GNUNET_OK;
485} 440}
486 441
487 442
@@ -503,25 +458,26 @@ namestore_postgres_zone_to_name (void *cls,
503 GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls) 458 GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
504{ 459{
505 struct Plugin *plugin = cls; 460 struct Plugin *plugin = cls;
506 const char *paramValues[] = { 461 struct GNUNET_PQ_QueryParam params[] = {
507 (const char *) zone, 462 GNUNET_PQ_query_param_auto_from_type (zone),
508 (const char *) value_zone 463 GNUNET_PQ_query_param_auto_from_type (value_zone),
464 GNUNET_PQ_query_param_end
509 }; 465 };
510 int paramLengths[] = { 466 enum GNUNET_DB_QueryStatus res;
511 sizeof (*zone), 467 struct ParserContext pc;
512 sizeof (*value_zone) 468
513 }; 469 pc.iter = iter;
514 const int paramFormats[] = { 1, 1 }; 470 pc.iter_cls = iter_cls;
515 PGresult *res; 471 pc.zone_key = zone;
516 472
517 res = PQexecPrepared (plugin->dbh, 473 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
518 "zone_to_name", 2, 474 "zone_to_name",
519 paramValues, paramLengths, paramFormats, 475 params,
520 1); 476 &parse_result_call_iterator,
521 return get_record_and_call_iterator (plugin, 477 &pc);
522 res, 478 if (res < 0)
523 zone, 479 return GNUNET_SYSERR;
524 iter, iter_cls); 480 return GNUNET_OK;
525} 481}
526 482
527 483
@@ -568,7 +524,7 @@ libgnunet_plugin_namestore_postgres_init (void *cls)
568 api->zone_to_name = &namestore_postgres_zone_to_name; 524 api->zone_to_name = &namestore_postgres_zone_to_name;
569 api->lookup_records = &namestore_postgres_lookup_records; 525 api->lookup_records = &namestore_postgres_lookup_records;
570 LOG (GNUNET_ERROR_TYPE_INFO, 526 LOG (GNUNET_ERROR_TYPE_INFO,
571 _("Postgres database running\n")); 527 "Postgres namestore plugin running\n");
572 return api; 528 return api;
573} 529}
574 530
@@ -589,7 +545,7 @@ libgnunet_plugin_namestore_postgres_done (void *cls)
589 plugin->cfg = NULL; 545 plugin->cfg = NULL;
590 GNUNET_free (api); 546 GNUNET_free (api);
591 LOG (GNUNET_ERROR_TYPE_DEBUG, 547 LOG (GNUNET_ERROR_TYPE_DEBUG,
592 "postgres plugin is finished\n"); 548 "Postgres namestore plugin is finished\n");
593 return NULL; 549 return NULL;
594} 550}
595 551
diff --git a/src/postgres/Makefile.am b/src/postgres/Makefile.am
deleted file mode 100644
index 6f37e1918..000000000
--- a/src/postgres/Makefile.am
+++ /dev/null
@@ -1,24 +0,0 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include $(POSTGRESQL_CPPFLAGS)
3
4if MINGW
5 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
6endif
7
8if USE_COVERAGE
9 AM_CFLAGS = --coverage
10endif
11
12if HAVE_POSTGRESQL
13lib_LTLIBRARIES = libgnunetpostgres.la
14endif
15
16libgnunetpostgres_la_SOURCES = \
17 postgres.c
18libgnunetpostgres_la_LIBADD = -lpq \
19 $(top_builddir)/src/util/libgnunetutil.la
20libgnunetpostgres_la_LDFLAGS = \
21 $(POSTGRESQL_LDFLAGS) \
22 $(GN_LIB_LDFLAGS) \
23 -version-info 0:0:0
24
diff --git a/src/postgres/postgres.c b/src/postgres/postgres.c
deleted file mode 100644
index 14095c5a4..000000000
--- a/src/postgres/postgres.c
+++ /dev/null
@@ -1,247 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2009, 2010, 2012 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file postgres/postgres.c
22 * @brief library to help with access to a Postgres database
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_postgres_lib.h"
27
28
29/**
30 * Check if the result obtained from Postgres has
31 * the desired status code. If not, log an error, clear the
32 * result and return GNUNET_SYSERR.
33 *
34 * @param dbh database handle
35 * @param ret return value from database operation to check
36 * @param expected_status desired status
37 * @param command description of the command that was run
38 * @param args arguments given to the command
39 * @param filename name of the source file where the command was run
40 * @param line line number in the source file
41 * @return #GNUNET_OK if the result is acceptable
42 */
43int
44GNUNET_POSTGRES_check_result_ (PGconn *dbh,
45 PGresult *ret,
46 int expected_status,
47 const char *command,
48 const char *args,
49 const char *filename,
50 int line)
51{
52 if (ret == NULL)
53 {
54 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
55 "postgres",
56 "Postgres failed to allocate result for `%s:%s' at %s:%d\n",
57 command,
58 args,
59 filename,
60 line);
61 return GNUNET_SYSERR;
62 }
63 if (PQresultStatus (ret) != expected_status)
64 {
65 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
66 "postgres",
67 _("`%s:%s' failed at %s:%d with error: %s\n"),
68 command,
69 args,
70 filename,
71 line,
72 PQerrorMessage (dbh));
73 PQclear (ret);
74 return GNUNET_SYSERR;
75 }
76 return GNUNET_OK;
77}
78
79
80/**
81 * Run simple SQL statement (without results).
82 *
83 * @param dbh database handle
84 * @param sql statement to run
85 * @param filename filename for error reporting
86 * @param line code line for error reporting
87 * @return #GNUNET_OK on success
88 */
89int
90GNUNET_POSTGRES_exec_ (PGconn * dbh,
91 const char *sql,
92 const char *filename,
93 int line)
94{
95 PGresult *ret;
96
97 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
98 "Executing SQL statement `%s' at %s:%d\n",
99 sql,
100 filename,
101 line);
102 ret = PQexec (dbh,
103 sql);
104 if (GNUNET_OK !=
105 GNUNET_POSTGRES_check_result_ (dbh,
106 ret,
107 PGRES_COMMAND_OK,
108 "PQexec",
109 sql,
110 filename,
111 line))
112 return GNUNET_SYSERR;
113 PQclear (ret);
114 return GNUNET_OK;
115}
116
117
118/**
119 * Prepare SQL statement.
120 *
121 * @param dbh database handle
122 * @param name name for the prepared SQL statement
123 * @param sql SQL code to prepare
124 * @param nparams number of parameters in sql
125 * @param filename filename for error reporting
126 * @param line code line for error reporting
127 * @return #GNUNET_OK on success
128 */
129int
130GNUNET_POSTGRES_prepare_ (PGconn *dbh,
131 const char *name,
132 const char *sql,
133 int nparams,
134 const char *filename,
135 int line)
136{
137 PGresult *ret;
138
139 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
140 "Preparing SQL statement `%s' as `%s' at %s:%d\n",
141 sql,
142 name,
143 filename,
144 line);
145 ret = PQprepare (dbh,
146 name,
147 sql,
148 nparams, NULL);
149 if (GNUNET_OK !=
150 GNUNET_POSTGRES_check_result_ (dbh,
151 ret,
152 PGRES_COMMAND_OK,
153 "PQprepare",
154 sql,
155 filename,
156 line))
157 return GNUNET_SYSERR;
158 PQclear (ret);
159 return GNUNET_OK;
160}
161
162
163/**
164 * Connect to a postgres database
165 *
166 * @param cfg configuration
167 * @param section configuration section to use to get Postgres configuration options
168 * @return the postgres handle
169 */
170PGconn *
171GNUNET_POSTGRES_connect (const struct GNUNET_CONFIGURATION_Handle * cfg,
172 const char *section)
173{
174 PGconn *dbh;
175 char *conninfo;
176
177 /* Open database and precompile statements */
178 if (GNUNET_OK !=
179 GNUNET_CONFIGURATION_get_value_string (cfg,
180 section,
181 "CONFIG",
182 &conninfo))
183 conninfo = NULL;
184 dbh = PQconnectdb (conninfo == NULL ? "" : conninfo);
185
186 if (NULL != dbh)
187 {
188 if (PQstatus (dbh) != CONNECTION_OK)
189 {
190 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
191 "postgres",
192 _("Unable to connect to Postgres database '%s': %s\n"),
193 conninfo,
194 PQerrorMessage (dbh));
195 PQfinish (dbh);
196 dbh = NULL;
197 }
198 }
199 // FIXME: warn about out-of-memory when dbh is NULL?
200 GNUNET_free_non_null (conninfo);
201 return dbh;
202}
203
204
205/**
206 * Delete the row identified by the given rowid (qid
207 * in postgres).
208 *
209 * @param dbh database handle
210 * @param stmt name of the prepared statement
211 * @param rowid which row to delete
212 * @return #GNUNET_OK on success
213 */
214int
215GNUNET_POSTGRES_delete_by_rowid (PGconn * dbh,
216 const char *stmt,
217 uint32_t rowid)
218{
219 uint32_t brow = htonl (rowid);
220 const char *paramValues[] = { (const char *) &brow };
221 int paramLengths[] = { sizeof (brow) };
222 const int paramFormats[] = { 1 };
223 PGresult *ret;
224
225 ret = PQexecPrepared (dbh,
226 stmt,
227 1,
228 paramValues,
229 paramLengths,
230 paramFormats,
231 1);
232 if (GNUNET_OK !=
233 GNUNET_POSTGRES_check_result_ (dbh, ret,
234 PGRES_COMMAND_OK,
235 "PQexecPrepared",
236 "delrow",
237 __FILE__,
238 __LINE__))
239 {
240 return GNUNET_SYSERR;
241 }
242 PQclear (ret);
243 return GNUNET_OK;
244}
245
246
247/* end of postgres.c */
diff --git a/src/pq/Makefile.am b/src/pq/Makefile.am
index 8bb0a0132..d0c71703b 100644
--- a/src/pq/Makefile.am
+++ b/src/pq/Makefile.am
@@ -15,6 +15,10 @@ endif
15 15
16libgnunetpq_la_SOURCES = \ 16libgnunetpq_la_SOURCES = \
17 pq.c \ 17 pq.c \
18 pq_connect.c \
19 pq_eval.c \
20 pq_exec.c \
21 pq_prepare.c \
18 pq_query_helper.c \ 22 pq_query_helper.c \
19 pq_result_helper.c 23 pq_result_helper.c
20libgnunetpq_la_LIBADD = -lpq \ 24libgnunetpq_la_LIBADD = -lpq \
diff --git a/src/pq/pq_connect.c b/src/pq/pq_connect.c
new file mode 100644
index 000000000..99ad06485
--- /dev/null
+++ b/src/pq/pq_connect.c
@@ -0,0 +1,127 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3, or (at your option) any later version.
8
9 GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along with
14 GNUnet; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
15*/
16/**
17 * @file pq/pq_connect.c
18 * @brief functions to connect to libpq (PostGres)
19 * @author Christian Grothoff
20 */
21#include "platform.h"
22#include "gnunet_util_lib.h"
23#include "gnunet_pq_lib.h"
24
25
26/**
27 * Function called by libpq whenever it wants to log something.
28 * We already log whenever we care, so this function does nothing
29 * and merely exists to silence the libpq logging.
30 *
31 * @param arg the SQL connection that was used
32 * @param res information about some libpq event
33 */
34static void
35pq_notice_receiver_cb (void *arg,
36 const PGresult *res)
37{
38 /* do nothing, intentionally */
39}
40
41
42/**
43 * Function called by libpq whenever it wants to log something.
44 * We log those using the Taler logger.
45 *
46 * @param arg the SQL connection that was used
47 * @param message information about some libpq event
48 */
49static void
50pq_notice_processor_cb (void *arg,
51 const char *message)
52{
53 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
54 "pq",
55 "%s",
56 message);
57}
58
59
60/**
61 * Create a connection to the Postgres database using @a config_str
62 * for the configuration. Initialize logging via GNUnet's log
63 * routines and disable Postgres's logger.
64 *
65 * @param config_str configuration to use
66 * @return NULL on error
67 */
68PGconn *
69GNUNET_PQ_connect (const char *config_str)
70{
71 PGconn *conn;
72
73 conn = PQconnectdb (config_str);
74 if ( (NULL == conn) ||
75 (CONNECTION_OK !=
76 PQstatus (conn)) )
77 {
78 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
79 "pq",
80 "Database connection to '%s' failed: %s\n",
81 config_str,
82 (NULL != conn) ?
83 PQerrorMessage (conn)
84 : "PQconnectdb returned NULL");
85 if (NULL != conn)
86 PQfinish (conn);
87 return NULL;
88 }
89 PQsetNoticeReceiver (conn,
90 &pq_notice_receiver_cb,
91 conn);
92 PQsetNoticeProcessor (conn,
93 &pq_notice_processor_cb,
94 conn);
95 return conn;
96}
97
98
99/**
100 * Connect to a postgres database using the configuration
101 * option "CONFIG" in @a section.
102 *
103 * @param cfg configuration
104 * @param section configuration section to use to get Postgres configuration options
105 * @return the postgres handle, NULL on error
106 */
107PGconn *
108GNUNET_PQ_connect_with_cfg (const struct GNUNET_CONFIGURATION_Handle * cfg,
109 const char *section)
110{
111 PGconn *dbh;
112 char *conninfo;
113
114 /* Open database and precompile statements */
115 if (GNUNET_OK !=
116 GNUNET_CONFIGURATION_get_value_string (cfg,
117 section,
118 "CONFIG",
119 &conninfo))
120 conninfo = NULL;
121 dbh = GNUNET_PQ_connect (conninfo == NULL ? "" : conninfo);
122 GNUNET_free_non_null (conninfo);
123 return dbh;
124}
125
126
127/* end of pq/pq_connect.c */
diff --git a/src/pq/pq_eval.c b/src/pq/pq_eval.c
new file mode 100644
index 000000000..0f28aec7e
--- /dev/null
+++ b/src/pq/pq_eval.c
@@ -0,0 +1,281 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3, or (at your option) any later version.
8
9 GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along with
14 GNUnet; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
15*/
16/**
17 * @file pq/pq_eval.c
18 * @brief functions to execute SQL statements with arguments and/or results (PostGres)
19 * @author Christian Grothoff
20 */
21#include "platform.h"
22#include "gnunet_util_lib.h"
23#include "gnunet_pq_lib.h"
24
25
26/**
27 * Error code returned by Postgres for deadlock.
28 */
29#define PQ_DIAG_SQLSTATE_DEADLOCK "40P01"
30
31/**
32 * Error code returned by Postgres for uniqueness violation.
33 */
34#define PQ_DIAG_SQLSTATE_UNIQUE_VIOLATION "23505"
35
36/**
37 * Error code returned by Postgres on serialization failure.
38 */
39#define PQ_DIAG_SQLSTATE_SERIALIZATION_FAILURE "40001"
40
41
42/**
43 * Check the @a result's error code to see what happened.
44 * Also logs errors.
45 *
46 * @param connection connection to execute the statement in
47 * @param statement_name name of the statement that created @a result
48 * @param result result to check
49 * @return status code from the result, mapping PQ status
50 * codes to `enum GNUNET_DB_QueryStatus`. Never
51 * returns positive values as this function does
52 * not look at the result set.
53 * @deprecated (low level, let's see if we can do with just the high-level functions)
54 */
55enum GNUNET_DB_QueryStatus
56GNUNET_PQ_eval_result (PGconn *connection,
57 const char *statement_name,
58 PGresult *result)
59{
60 ExecStatusType est;
61
62 est = PQresultStatus (result);
63 if ( (PGRES_COMMAND_OK != est) &&
64 (PGRES_TUPLES_OK != est) )
65 {
66 const char *sqlstate;
67
68 sqlstate = PQresultErrorField (result,
69 PG_DIAG_SQLSTATE);
70 if (NULL == sqlstate)
71 {
72 /* very unexpected... */
73 GNUNET_break (0);
74 return GNUNET_DB_STATUS_HARD_ERROR;
75 }
76 if ( (0 == strcmp (sqlstate,
77 PQ_DIAG_SQLSTATE_DEADLOCK)) ||
78 (0 == strcmp (sqlstate,
79 PQ_DIAG_SQLSTATE_SERIALIZATION_FAILURE)) )
80 {
81 /* These two can be retried and have a fair chance of working
82 the next time */
83 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
84 "pq",
85 "Query `%s' failed with result: %s/%s/%s/%s/%s\n",
86 statement_name,
87 PQresultErrorField (result,
88 PG_DIAG_MESSAGE_PRIMARY),
89 PQresultErrorField (result,
90 PG_DIAG_MESSAGE_DETAIL),
91 PQresultErrorMessage (result),
92 PQresStatus (PQresultStatus (result)),
93 PQerrorMessage (connection));
94 return GNUNET_DB_STATUS_SOFT_ERROR;
95 }
96 if (0 == strcmp (sqlstate,
97 PQ_DIAG_SQLSTATE_UNIQUE_VIOLATION))
98 {
99 /* Likely no need to retry, INSERT of "same" data. */
100 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
101 "pq",
102 "Query `%s' failed with unique violation: %s/%s/%s/%s/%s\n",
103 statement_name,
104 PQresultErrorField (result,
105 PG_DIAG_MESSAGE_PRIMARY),
106 PQresultErrorField (result,
107 PG_DIAG_MESSAGE_DETAIL),
108 PQresultErrorMessage (result),
109 PQresStatus (PQresultStatus (result)),
110 PQerrorMessage (connection));
111 return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
112 }
113 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
114 "pq",
115 "Query `%s' failed with result: %s/%s/%s/%s/%s\n",
116 statement_name,
117 PQresultErrorField (result,
118 PG_DIAG_MESSAGE_PRIMARY),
119 PQresultErrorField (result,
120 PG_DIAG_MESSAGE_DETAIL),
121 PQresultErrorMessage (result),
122 PQresStatus (PQresultStatus (result)),
123 PQerrorMessage (connection));
124 return GNUNET_DB_STATUS_HARD_ERROR;
125 }
126 return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
127}
128
129
130/**
131 * Execute a named prepared @a statement that is NOT a SELECT
132 * statement in @a connnection using the given @a params. Returns the
133 * resulting session state.
134 *
135 * @param connection connection to execute the statement in
136 * @param statement_name name of the statement
137 * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated)
138 * @return status code from the result, mapping PQ status
139 * codes to `enum GNUNET_DB_QueryStatus`. If the
140 * statement was a DELETE or UPDATE statement, the
141 * number of affected rows is returned.; if the
142 * statment was an INSERT statement, and no row
143 * was added due to a UNIQUE violation, we return
144 * zero; if INSERT was successful, we return one.
145 */
146enum GNUNET_DB_QueryStatus
147GNUNET_PQ_eval_prepared_non_select (PGconn *connection,
148 const char *statement_name,
149 const struct GNUNET_PQ_QueryParam *params)
150{
151 PGresult *result;
152 enum GNUNET_DB_QueryStatus qs;
153
154 result = GNUNET_PQ_exec_prepared (connection,
155 statement_name,
156 params);
157 qs = GNUNET_PQ_eval_result (connection,
158 statement_name,
159 result);
160 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
161 {
162 const char *tuples;
163
164 /* What an awful API, this function really does return a string */
165 tuples = PQcmdTuples (result);
166 if (NULL != tuples)
167 qs = strtol (tuples, NULL, 10);
168 }
169 PQclear (result);
170 return qs;
171}
172
173
174/**
175 * Execute a named prepared @a statement that is a SELECT statement
176 * which may return multiple results in @a connection using the given
177 * @a params. Call @a rh with the results. Returns the query
178 * status including the number of results given to @a rh (possibly zero).
179 * @a rh will not have been called if the return value is negative.
180 *
181 * @param connection connection to execute the statement in
182 * @param statement_name name of the statement
183 * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated)
184 * @param rh function to call with the result set, NULL to ignore
185 * @param rh_cls closure to pass to @a rh
186 * @return status code from the result, mapping PQ status
187 * codes to `enum GNUNET_DB_QueryStatus`.
188 */
189enum GNUNET_DB_QueryStatus
190GNUNET_PQ_eval_prepared_multi_select (PGconn *connection,
191 const char *statement_name,
192 const struct GNUNET_PQ_QueryParam *params,
193 GNUNET_PQ_PostgresResultHandler rh,
194 void *rh_cls)
195{
196 PGresult *result;
197 enum GNUNET_DB_QueryStatus qs;
198 unsigned int ret;
199
200 result = GNUNET_PQ_exec_prepared (connection,
201 statement_name,
202 params);
203 qs = GNUNET_PQ_eval_result (connection,
204 statement_name,
205 result);
206 if (qs < 0)
207 {
208 PQclear (result);
209 return qs;
210 }
211 ret = PQntuples (result);
212 if (NULL != rh)
213 rh (rh_cls,
214 result,
215 ret);
216 PQclear (result);
217 return ret;
218}
219
220
221/**
222 * Execute a named prepared @a statement that is a SELECT statement
223 * which must return a single result in @a connection using the given
224 * @a params. Stores the result (if any) in @a rs, which the caller
225 * must then clean up using #GNUNET_PQ_cleanup_result() if the return
226 * value was #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT. Returns the
227 * resulting session status.
228 *
229 * @param connection connection to execute the statement in
230 * @param statement_name name of the statement
231 * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated)
232 * @param[in,out] rs result specification to use for storing the result of the query
233 * @return status code from the result, mapping PQ status
234 * codes to `enum GNUNET_DB_QueryStatus`.
235 */
236enum GNUNET_DB_QueryStatus
237GNUNET_PQ_eval_prepared_singleton_select (PGconn *connection,
238 const char *statement_name,
239 const struct GNUNET_PQ_QueryParam *params,
240 struct GNUNET_PQ_ResultSpec *rs)
241{
242 PGresult *result;
243 enum GNUNET_DB_QueryStatus qs;
244
245 result = GNUNET_PQ_exec_prepared (connection,
246 statement_name,
247 params);
248 qs = GNUNET_PQ_eval_result (connection,
249 statement_name,
250 result);
251 if (qs < 0)
252 {
253 PQclear (result);
254 return qs;
255 }
256 if (0 == PQntuples (result))
257 {
258 PQclear (result);
259 return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
260 }
261 if (1 != PQntuples (result))
262 {
263 /* more than one result, but there must be at most one */
264 GNUNET_break (0);
265 PQclear (result);
266 return GNUNET_DB_STATUS_HARD_ERROR;
267 }
268 if (GNUNET_OK !=
269 GNUNET_PQ_extract_result (result,
270 rs,
271 0))
272 {
273 PQclear (result);
274 return GNUNET_DB_STATUS_HARD_ERROR;
275 }
276 PQclear (result);
277 return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
278}
279
280
281/* end of pq/pq_eval.c */
diff --git a/src/pq/pq_exec.c b/src/pq/pq_exec.c
new file mode 100644
index 000000000..1e5e4eb76
--- /dev/null
+++ b/src/pq/pq_exec.c
@@ -0,0 +1,106 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3, or (at your option) any later version.
8
9 GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along with
14 GNUnet; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
15*/
16/**
17 * @file pq/pq_exec.c
18 * @brief functions to execute plain SQL statements (PostGres)
19 * @author Christian Grothoff
20 */
21#include "platform.h"
22#include "gnunet_util_lib.h"
23#include "gnunet_pq_lib.h"
24
25
26/**
27 * Create a `struct GNUNET_PQ_ExecuteStatement` where errors are fatal.
28 *
29 * @param sql actual SQL statement
30 * @return initialized struct
31 */
32struct GNUNET_PQ_ExecuteStatement
33GNUNET_PQ_make_execute (const char *sql)
34{
35 struct GNUNET_PQ_ExecuteStatement es = {
36 .sql = sql,
37 .ignore_errors = GNUNET_NO
38 };
39
40 return es;
41}
42
43
44/**
45 * Create a `struct GNUNET_PQ_ExecuteStatement` where errors should
46 * be tolerated.
47 *
48 * @param sql actual SQL statement
49 * @return initialized struct
50 */
51struct GNUNET_PQ_ExecuteStatement
52GNUNET_PQ_make_try_execute (const char *sql)
53{
54 struct GNUNET_PQ_ExecuteStatement es = {
55 .sql = sql,
56 .ignore_errors = GNUNET_YES
57 };
58
59 return es;
60}
61
62
63/**
64 * Request execution of an array of statements @a es from Postgres.
65 *
66 * @param connection connection to execute the statements over
67 * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared
68 * statements.
69 * @return #GNUNET_OK on success (modulo statements where errors can be ignored)
70 * #GNUNET_SYSERR on error
71 */
72int
73GNUNET_PQ_exec_statements (PGconn *connection,
74 const struct GNUNET_PQ_ExecuteStatement *es)
75{
76 for (unsigned int i=0; NULL != es[i].sql; i++)
77 {
78 PGresult *result;
79
80 result = PQexec (connection,
81 es[i].sql);
82
83 if ( (GNUNET_NO == es[i].ignore_errors) &&
84 (PGRES_COMMAND_OK != PQresultStatus (result)) )
85 {
86 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
87 "pq",
88 "Failed to execute `%s': %s/%s/%s/%s/%s",
89 es[i].sql,
90 PQresultErrorField (result,
91 PG_DIAG_MESSAGE_PRIMARY),
92 PQresultErrorField (result,
93 PG_DIAG_MESSAGE_DETAIL),
94 PQresultErrorMessage (result),
95 PQresStatus (PQresultStatus (result)),
96 PQerrorMessage (connection));
97 PQclear (result);
98 return GNUNET_SYSERR;
99 }
100 PQclear (result);
101 }
102 return GNUNET_OK;
103}
104
105
106/* end of pq/pq_exec.c */
diff --git a/src/pq/pq_prepare.c b/src/pq/pq_prepare.c
new file mode 100644
index 000000000..612d6df7c
--- /dev/null
+++ b/src/pq/pq_prepare.c
@@ -0,0 +1,93 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2017 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3, or (at your option) any later version.
8
9 GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along with
14 GNUnet; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
15*/
16/**
17 * @file pq/pq_prepare.c
18 * @brief functions to connect to libpq (PostGres)
19 * @author Christian Grothoff
20 */
21#include "platform.h"
22#include "gnunet_util_lib.h"
23#include "gnunet_pq_lib.h"
24
25
26/**
27 * Create a `struct GNUNET_PQ_PreparedStatement`.
28 *
29 * @param name name of the statement
30 * @param sql actual SQL statement
31 * @param num_args number of arguments in the statement
32 * @return initialized struct
33 */
34struct GNUNET_PQ_PreparedStatement
35GNUNET_PQ_make_prepare (const char *name,
36 const char *sql,
37 unsigned int num_args)
38{
39 struct GNUNET_PQ_PreparedStatement ps = {
40 .name = name,
41 .sql = sql,
42 .num_arguments = num_args
43 };
44
45 return ps;
46}
47
48
49/**
50 * Request creation of prepared statements @a ps from Postgres.
51 *
52 * @param connection connection to prepare the statements for
53 * @param ps #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared
54 * statements.
55 * @return #GNUNET_OK on success,
56 * #GNUNET_SYSERR on error
57 */
58int
59GNUNET_PQ_prepare_statements (PGconn *connection,
60 const struct GNUNET_PQ_PreparedStatement *ps)
61{
62 for (unsigned int i=0;NULL != ps[i].name;i++)
63 {
64 PGresult *ret;
65
66 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
67 "pq",
68 "Preparing SQL statement `%s' as `%s'\n",
69 ps[i].sql,
70 ps[i].name);
71 ret = PQprepare (connection,
72 ps[i].name,
73 ps[i].sql,
74 ps[i].num_arguments,
75 NULL);
76 if (PGRES_COMMAND_OK != PQresultStatus (ret))
77 {
78 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
79 "pq",
80 _("PQprepare (`%s' as `%s') failed with error: %s\n"),
81 ps[i].sql,
82 ps[i].name,
83 PQerrorMessage (connection));
84 PQclear (ret);
85 return GNUNET_SYSERR;
86 }
87 PQclear (ret);
88 }
89 return GNUNET_OK;
90}
91
92
93/* end of pq/pq_prepare.c */
diff --git a/src/psycstore/Makefile.am b/src/psycstore/Makefile.am
index a342c06e6..557bb42b5 100644
--- a/src/psycstore/Makefile.am
+++ b/src/psycstore/Makefile.am
@@ -88,7 +88,6 @@ libgnunet_plugin_psycstore_postgres_la_SOURCES = \
88 plugin_psycstore_postgres.c 88 plugin_psycstore_postgres.c
89libgnunet_plugin_psycstore_postgres_la_LIBADD = \ 89libgnunet_plugin_psycstore_postgres_la_LIBADD = \
90 libgnunetpsycstore.la \ 90 libgnunetpsycstore.la \
91 $(top_builddir)/src/postgres/libgnunetpostgres.la \
92 $(top_builddir)/src/pq/libgnunetpq.la \ 91 $(top_builddir)/src/pq/libgnunetpq.la \
93 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 92 $(top_builddir)/src/statistics/libgnunetstatistics.la \
94 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq \ 93 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq \
diff --git a/src/psycstore/plugin_psycstore_postgres.c b/src/psycstore/plugin_psycstore_postgres.c
index 273ab4e80..b8010af0a 100644
--- a/src/psycstore/plugin_psycstore_postgres.c
+++ b/src/psycstore/plugin_psycstore_postgres.c
@@ -25,6 +25,7 @@
25 * @author Gabor X Toth 25 * @author Gabor X Toth
26 * @author Christian Grothoff 26 * @author Christian Grothoff
27 * @author Christophe Genevey 27 * @author Christophe Genevey
28 * @author Jeffrey Burdges
28 */ 29 */
29 30
30#include "platform.h" 31#include "platform.h"
@@ -34,7 +35,6 @@
34#include "gnunet_crypto_lib.h" 35#include "gnunet_crypto_lib.h"
35#include "gnunet_psyc_util_lib.h" 36#include "gnunet_psyc_util_lib.h"
36#include "psycstore.h" 37#include "psycstore.h"
37#include "gnunet_postgres_lib.h"
38#include "gnunet_pq_lib.h" 38#include "gnunet_pq_lib.h"
39 39
40/** 40/**
@@ -84,342 +84,276 @@ struct Plugin
84 * as needed as well). 84 * as needed as well).
85 * 85 *
86 * @param plugin the plugin context (state for this module) 86 * @param plugin the plugin context (state for this module)
87 * @return GNUNET_OK on success 87 * @return #GNUNET_OK on success
88 */ 88 */
89static int 89static int
90database_setup (struct Plugin *plugin) 90database_setup (struct Plugin *plugin)
91{ 91{
92 struct GNUNET_PQ_ExecuteStatement es[] = {
93 GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS channels (\n"
94 " id SERIAL,\n"
95 " pub_key BYTEA NOT NULL CHECK (LENGTH(pub_key)=32),\n"
96 " max_state_message_id BIGINT,\n"
97 " state_hash_message_id BIGINT,\n"
98 " PRIMARY KEY(id)\n"
99 ")"
100 "WITH OIDS"),
101 GNUNET_PQ_make_execute ("CREATE UNIQUE INDEX IF NOT EXISTS channel_pub_key_idx \n"
102 " ON channels (pub_key)"),
103 GNUNET_PQ_make_execute ("CREATE OR REPLACE FUNCTION get_chan_id(BYTEA) RETURNS INTEGER AS \n"
104 " 'SELECT id FROM channels WHERE pub_key=$1;' LANGUAGE SQL STABLE \n"
105 "RETURNS NULL ON NULL INPUT"),
106 GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS slaves (\n"
107 " id SERIAL,\n"
108 " pub_key BYTEA NOT NULL CHECK (LENGTH(pub_key)=32),\n"
109 " PRIMARY KEY(id)\n"
110 ")"
111 "WITH OIDS"),
112 GNUNET_PQ_make_execute ("CREATE UNIQUE INDEX IF NOT EXISTS slaves_pub_key_idx \n"
113 " ON slaves (pub_key)"),
114 GNUNET_PQ_make_execute ("CREATE OR REPLACE FUNCTION get_slave_id(BYTEA) RETURNS INTEGER AS \n"
115 " 'SELECT id FROM slaves WHERE pub_key=$1;' LANGUAGE SQL STABLE \n"
116 "RETURNS NULL ON NULL INPUT"),
117 GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS membership (\n"
118 " channel_id BIGINT NOT NULL REFERENCES channels(id),\n"
119 " slave_id BIGINT NOT NULL REFERENCES slaves(id),\n"
120 " did_join INT NOT NULL,\n"
121 " announced_at BIGINT NOT NULL,\n"
122 " effective_since BIGINT NOT NULL,\n"
123 " group_generation BIGINT NOT NULL\n"
124 ")"
125 "WITH OIDS"),
126 GNUNET_PQ_make_execute ("CREATE INDEX IF NOT EXISTS idx_membership_channel_id_slave_id "
127 "ON membership (channel_id, slave_id)"),
128 /** @todo messages table: add method_name column */
129 GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS messages (\n"
130 " channel_id BIGINT NOT NULL REFERENCES channels(id),\n"
131 " hop_counter INT NOT NULL,\n"
132 " signature BYTEA CHECK (LENGTH(signature)=64),\n"
133 " purpose BYTEA CHECK (LENGTH(purpose)=8),\n"
134 " fragment_id BIGINT NOT NULL,\n"
135 " fragment_offset BIGINT NOT NULL,\n"
136 " message_id BIGINT NOT NULL,\n"
137 " group_generation BIGINT NOT NULL,\n"
138 " multicast_flags INT NOT NULL,\n"
139 " psycstore_flags INT NOT NULL,\n"
140 " data BYTEA,\n"
141 " PRIMARY KEY (channel_id, fragment_id),\n"
142 " UNIQUE (channel_id, message_id, fragment_offset)\n"
143 ")"
144 "WITH OIDS"),
145 GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS state (\n"
146 " channel_id BIGINT NOT NULL REFERENCES channels(id),\n"
147 " name TEXT NOT NULL,\n"
148 " value_current BYTEA,\n"
149 " value_signed BYTEA,\n"
150 " PRIMARY KEY (channel_id, name)\n"
151 ")"
152 "WITH OIDS"),
153 GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS state_sync (\n"
154 " channel_id BIGINT NOT NULL REFERENCES channels(id),\n"
155 " name TEXT NOT NULL,\n"
156 " value BYTEA,\n"
157 " PRIMARY KEY (channel_id, name)\n"
158 ")"
159 "WITH OIDS"),
160 GNUNET_PQ_EXECUTE_STATEMENT_END
161 };
162
92 /* Open database and precompile statements */ 163 /* Open database and precompile statements */
93 plugin->dbh = GNUNET_POSTGRES_connect (plugin->cfg, 164 plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg,
94 "psycstore-postgres"); 165 "psycstore-postgres");
95 if (NULL == plugin->dbh) 166 if (NULL == plugin->dbh)
96 return GNUNET_SYSERR; 167 return GNUNET_SYSERR;
97 168 if (GNUNET_OK !=
98 /* Create tables */ 169 GNUNET_PQ_exec_statements (plugin->dbh,
99 if ((GNUNET_OK != 170 es))
100 GNUNET_POSTGRES_exec(plugin->dbh,
101 "CREATE TABLE IF NOT EXISTS channels (\n"
102 " id SERIAL,\n"
103 " pub_key BYTEA NOT NULL CHECK (LENGTH(pub_key)=32),\n"
104 " max_state_message_id BIGINT,\n"
105 " state_hash_message_id BIGINT,\n"
106 " PRIMARY KEY(id)\n"
107 ")" "WITH OIDS")) ||
108
109 (GNUNET_OK !=
110 GNUNET_POSTGRES_exec(plugin->dbh,
111 "CREATE UNIQUE INDEX IF NOT EXISTS channel_pub_key_idx \n"
112 " ON channels (pub_key)")) ||
113
114 (GNUNET_OK !=
115 GNUNET_POSTGRES_exec(plugin->dbh,
116 "CREATE OR REPLACE FUNCTION get_chan_id(BYTEA) RETURNS INTEGER AS \n"
117 " 'SELECT id FROM channels WHERE pub_key=$1;' LANGUAGE SQL STABLE \n"
118 "RETURNS NULL ON NULL INPUT")) ||
119
120 (GNUNET_OK !=
121 GNUNET_POSTGRES_exec(plugin->dbh,
122 "CREATE TABLE IF NOT EXISTS slaves (\n"
123 " id SERIAL,\n"
124 " pub_key BYTEA NOT NULL CHECK (LENGTH(pub_key)=32),\n"
125 " PRIMARY KEY(id)\n"
126 ")" "WITH OIDS")) ||
127
128 (GNUNET_OK !=
129 GNUNET_POSTGRES_exec(plugin->dbh,
130 "CREATE UNIQUE INDEX IF NOT EXISTS slaves_pub_key_idx \n"
131 " ON slaves (pub_key)")) ||
132
133 (GNUNET_OK !=
134 GNUNET_POSTGRES_exec(plugin->dbh,
135 "CREATE OR REPLACE FUNCTION get_slave_id(BYTEA) RETURNS INTEGER AS \n"
136 " 'SELECT id FROM slaves WHERE pub_key=$1;' LANGUAGE SQL STABLE \n"
137 "RETURNS NULL ON NULL INPUT")) ||
138
139 (GNUNET_OK !=
140 GNUNET_POSTGRES_exec(plugin->dbh,
141 "CREATE TABLE IF NOT EXISTS membership (\n"
142 " channel_id BIGINT NOT NULL REFERENCES channels(id),\n"
143 " slave_id BIGINT NOT NULL REFERENCES slaves(id),\n"
144 " did_join INT NOT NULL,\n"
145 " announced_at BIGINT NOT NULL,\n"
146 " effective_since BIGINT NOT NULL,\n"
147 " group_generation BIGINT NOT NULL\n"
148 ")" "WITH OIDS")) ||
149
150 (GNUNET_OK !=
151 GNUNET_POSTGRES_exec(plugin->dbh,
152 "CREATE INDEX IF NOT EXISTS idx_membership_channel_id_slave_id "
153 "ON membership (channel_id, slave_id)")) ||
154
155 /** @todo messages table: add method_name column */
156 (GNUNET_OK !=
157 GNUNET_POSTGRES_exec(plugin->dbh,
158 "CREATE TABLE IF NOT EXISTS messages (\n"
159 " channel_id BIGINT NOT NULL REFERENCES channels(id),\n"
160 " hop_counter INT NOT NULL,\n"
161 " signature BYTEA CHECK (LENGTH(signature)=64),\n"
162 " purpose BYTEA CHECK (LENGTH(purpose)=8),\n"
163 " fragment_id BIGINT NOT NULL,\n"
164 " fragment_offset BIGINT NOT NULL,\n"
165 " message_id BIGINT NOT NULL,\n"
166 " group_generation BIGINT NOT NULL,\n"
167 " multicast_flags INT NOT NULL,\n"
168 " psycstore_flags INT NOT NULL,\n"
169 " data BYTEA,\n"
170 " PRIMARY KEY (channel_id, fragment_id),\n"
171 " UNIQUE (channel_id, message_id, fragment_offset)\n"
172 ")" "WITH OIDS")) ||
173
174 (GNUNET_OK !=
175 GNUNET_POSTGRES_exec(plugin->dbh,
176 "CREATE TABLE IF NOT EXISTS state (\n"
177 " channel_id BIGINT NOT NULL REFERENCES channels(id),\n"
178 " name TEXT NOT NULL,\n"
179 " value_current BYTEA,\n"
180 " value_signed BYTEA,\n"
181 " PRIMARY KEY (channel_id, name)\n"
182 ")" "WITH OIDS")) ||
183 (GNUNET_OK !=
184 GNUNET_POSTGRES_exec(plugin->dbh,
185 "CREATE TABLE IF NOT EXISTS state_sync (\n"
186 " channel_id BIGINT NOT NULL REFERENCES channels(id),\n"
187 " name TEXT NOT NULL,\n"
188 " value BYTEA,\n"
189 " PRIMARY KEY (channel_id, name)\n"
190 ")" "WITH OIDS")))
191 { 171 {
192 PQfinish (plugin->dbh); 172 PQfinish (plugin->dbh);
193 plugin->dbh = NULL; 173 plugin->dbh = NULL;
194 return GNUNET_SYSERR; 174 return GNUNET_SYSERR;
195 } 175 }
196 176
197
198 /* Prepare statements */ 177 /* Prepare statements */
199 if ((GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 178 {
200 "transaction_begin", 179 struct GNUNET_PQ_PreparedStatement ps[] = {
201 "BEGIN", 0)) || 180 GNUNET_PQ_make_prepare ("transaction_begin",
202 181 "BEGIN", 0),
203 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 182 GNUNET_PQ_make_prepare ("transaction_commit",
204 "transaction_commit", 183 "COMMIT", 0),
205 "COMMIT", 0)) || 184 GNUNET_PQ_make_prepare ("transaction_rollback",
206 185 "ROLLBACK", 0),
207 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 186 GNUNET_PQ_make_prepare ("insert_channel_key",
208 "transaction_rollback", 187 "INSERT INTO channels (pub_key) VALUES ($1)"
209 "ROLLBACK", 0)) || 188 " ON CONFLICT DO NOTHING", 1),
210 189 GNUNET_PQ_make_prepare ("insert_slave_key",
211 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 190 "INSERT INTO slaves (pub_key) VALUES ($1)"
212 "insert_channel_key", 191 " ON CONFLICT DO NOTHING", 1),
213 "INSERT INTO channels (pub_key) VALUES ($1)" 192 GNUNET_PQ_make_prepare ("insert_membership",
214 " ON CONFLICT DO NOTHING", 1)) || 193 "INSERT INTO membership\n"
215 194 " (channel_id, slave_id, did_join, announced_at,\n"
216 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 195 " effective_since, group_generation)\n"
217 "insert_slave_key", 196 "VALUES (get_chan_id($1),\n"
218 "INSERT INTO slaves (pub_key) VALUES ($1)" 197 " get_slave_id($2),\n"
219 " ON CONFLICT DO NOTHING", 1)) || 198 " $3, $4, $5, $6)", 6),
220 199 GNUNET_PQ_make_prepare ("select_membership",
221 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 200 "SELECT did_join FROM membership\n"
222 "insert_membership", 201 "WHERE channel_id = get_chan_id($1)\n"
223 "INSERT INTO membership\n" 202 " AND slave_id = get_slave_id($2)\n"
224 " (channel_id, slave_id, did_join, announced_at,\n" 203 " AND effective_since <= $3 AND did_join = 1\n"
225 " effective_since, group_generation)\n" 204 "ORDER BY announced_at DESC LIMIT 1", 3),
226 "VALUES (get_chan_id($1),\n" 205 GNUNET_PQ_make_prepare ("insert_fragment",
227 " get_slave_id($2),\n" 206 "INSERT INTO messages\n"
228 " $3, $4, $5, $6)", 6)) || 207 " (channel_id, hop_counter, signature, purpose,\n"
229 208 " fragment_id, fragment_offset, message_id,\n"
230 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 209 " group_generation, multicast_flags, psycstore_flags, data)\n"
231 "select_membership", 210 "VALUES (get_chan_id($1),\n"
232 "SELECT did_join FROM membership\n" 211 " $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)"
233 "WHERE channel_id = get_chan_id($1)\n" 212 "ON CONFLICT DO NOTHING", 11),
234 " AND slave_id = get_slave_id($2)\n" 213 GNUNET_PQ_make_prepare ("update_message_flags",
235 " AND effective_since <= $3 AND did_join = 1\n" 214 "UPDATE messages\n"
236 "ORDER BY announced_at DESC LIMIT 1", 3)) || 215 "SET psycstore_flags = psycstore_flags | $1\n"
237 216 "WHERE channel_id = get_chan_id($2) \n"
238 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 217 " AND message_id = $3 AND fragment_offset = 0", 3),
239 "insert_fragment", 218 GNUNET_PQ_make_prepare ("select_fragments",
240 "INSERT INTO messages\n" 219 "SELECT hop_counter, signature, purpose, fragment_id,\n"
241 " (channel_id, hop_counter, signature, purpose,\n" 220 " fragment_offset, message_id, group_generation,\n"
242 " fragment_id, fragment_offset, message_id,\n" 221 " multicast_flags, psycstore_flags, data\n"
243 " group_generation, multicast_flags, psycstore_flags, data)\n" 222 "FROM messages\n"
244 "VALUES (get_chan_id($1),\n" 223 "WHERE channel_id = get_chan_id($1) \n"
245 " $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)" 224 " AND $2 <= fragment_id AND fragment_id <= $3", 3),
246 "ON CONFLICT DO NOTHING", 11)) ||
247
248 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh,
249 "update_message_flags",
250 "UPDATE messages\n"
251 "SET psycstore_flags = psycstore_flags | $1\n"
252 "WHERE channel_id = get_chan_id($2) \n"
253 " AND message_id = $3 AND fragment_offset = 0", 3)) ||
254
255 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh,
256 "select_fragments",
257 "SELECT hop_counter, signature, purpose, fragment_id,\n"
258 " fragment_offset, message_id, group_generation,\n"
259 " multicast_flags, psycstore_flags, data\n"
260 "FROM messages\n"
261 "WHERE channel_id = get_chan_id($1) \n"
262 " AND $2 <= fragment_id AND fragment_id <= $3", 3)) ||
263
264 /** @todo select_messages: add method_prefix filter */ 225 /** @todo select_messages: add method_prefix filter */
265 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 226 GNUNET_PQ_make_prepare ("select_messages",
266 "select_messages", 227 "SELECT hop_counter, signature, purpose, fragment_id,\n"
267 "SELECT hop_counter, signature, purpose, fragment_id,\n" 228 " fragment_offset, message_id, group_generation,\n"
268 " fragment_offset, message_id, group_generation,\n" 229 " multicast_flags, psycstore_flags, data\n"
269 " multicast_flags, psycstore_flags, data\n" 230 "FROM messages\n"
270 "FROM messages\n" 231 "WHERE channel_id = get_chan_id($1) \n"
271 "WHERE channel_id = get_chan_id($1) \n" 232 " AND $2 <= message_id AND message_id <= $3\n"
272 " AND $2 <= message_id AND message_id <= $3\n" 233 "LIMIT $4;", 4),
273 "LIMIT $4;", 4)) ||
274
275 /** @todo select_latest_messages: add method_prefix filter */ 234 /** @todo select_latest_messages: add method_prefix filter */
276 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 235 GNUNET_PQ_make_prepare ("select_latest_fragments",
277 "select_latest_fragments", 236 "SELECT rev.hop_counter AS hop_counter,\n"
278 "SELECT rev.hop_counter AS hop_counter,\n" 237 " rev.signature AS signature,\n"
279 " rev.signature AS signature,\n" 238 " rev.purpose AS purpose,\n"
280 " rev.purpose AS purpose,\n" 239 " rev.fragment_id AS fragment_id,\n"
281 " rev.fragment_id AS fragment_id,\n" 240 " rev.fragment_offset AS fragment_offset,\n"
282 " rev.fragment_offset AS fragment_offset,\n" 241 " rev.message_id AS message_id,\n"
283 " rev.message_id AS message_id,\n" 242 " rev.group_generation AS group_generation,\n"
284 " rev.group_generation AS group_generation,\n" 243 " rev.multicast_flags AS multicast_flags,\n"
285 " rev.multicast_flags AS multicast_flags,\n" 244 " rev.psycstore_flags AS psycstore_flags,\n"
286 " rev.psycstore_flags AS psycstore_flags,\n" 245 " rev.data AS data\n"
287 " rev.data AS data\n" 246 " FROM\n"
288 " FROM\n" 247 " (SELECT hop_counter, signature, purpose, fragment_id,\n"
289 " (SELECT hop_counter, signature, purpose, fragment_id,\n" 248 " fragment_offset, message_id, group_generation,\n"
290 " fragment_offset, message_id, group_generation,\n" 249 " multicast_flags, psycstore_flags, data \n"
291 " multicast_flags, psycstore_flags, data \n" 250 " FROM messages\n"
292 " FROM messages\n" 251 " WHERE channel_id = get_chan_id($1) \n"
293 " WHERE channel_id = get_chan_id($1) \n" 252 " ORDER BY fragment_id DESC\n"
294 " ORDER BY fragment_id DESC\n" 253 " LIMIT $2) AS rev\n"
295 " LIMIT $2) AS rev\n" 254 " ORDER BY rev.fragment_id;", 2),
296 " ORDER BY rev.fragment_id;", 2)) || 255 GNUNET_PQ_make_prepare ("select_latest_messages",
297 256 "SELECT hop_counter, signature, purpose, fragment_id,\n"
298 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 257 " fragment_offset, message_id, group_generation,\n"
299 "select_latest_messages", 258 " multicast_flags, psycstore_flags, data\n"
300 "SELECT hop_counter, signature, purpose, fragment_id,\n" 259 "FROM messages\n"
301 " fragment_offset, message_id, group_generation,\n" 260 "WHERE channel_id = get_chan_id($1)\n"
302 " multicast_flags, psycstore_flags, data\n" 261 " AND message_id IN\n"
303 "FROM messages\n" 262 " (SELECT message_id\n"
304 "WHERE channel_id = get_chan_id($1)\n" 263 " FROM messages\n"
305 " AND message_id IN\n" 264 " WHERE channel_id = get_chan_id($2) \n"
306 " (SELECT message_id\n" 265 " GROUP BY message_id\n"
307 " FROM messages\n" 266 " ORDER BY message_id\n"
308 " WHERE channel_id = get_chan_id($2) \n" 267 " DESC LIMIT $3)\n"
309 " GROUP BY message_id\n" 268 "ORDER BY fragment_id", 3),
310 " ORDER BY message_id\n" 269 GNUNET_PQ_make_prepare ("select_message_fragment",
311 " DESC LIMIT $3)\n" 270 "SELECT hop_counter, signature, purpose, fragment_id,\n"
312 "ORDER BY fragment_id", 3)) || 271 " fragment_offset, message_id, group_generation,\n"
313 272 " multicast_flags, psycstore_flags, data\n"
314 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 273 "FROM messages\n"
315 "select_message_fragment", 274 "WHERE channel_id = get_chan_id($1) \n"
316 "SELECT hop_counter, signature, purpose, fragment_id,\n" 275 " AND message_id = $2 AND fragment_offset = $3", 3),
317 " fragment_offset, message_id, group_generation,\n" 276 GNUNET_PQ_make_prepare ("select_counters_message",
318 " multicast_flags, psycstore_flags, data\n" 277 "SELECT fragment_id, message_id, group_generation\n"
319 "FROM messages\n" 278 "FROM messages\n"
320 "WHERE channel_id = get_chan_id($1) \n" 279 "WHERE channel_id = get_chan_id($1)\n"
321 " AND message_id = $2 AND fragment_offset = $3", 3)) || 280 "ORDER BY fragment_id DESC LIMIT 1", 1),
322 281 GNUNET_PQ_make_prepare ("select_counters_state",
323 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 282 "SELECT max_state_message_id\n"
324 "select_counters_message", 283 "FROM channels\n"
325 "SELECT fragment_id, message_id, group_generation\n" 284 "WHERE pub_key = $1 AND max_state_message_id IS NOT NULL", 1),
326 "FROM messages\n" 285 GNUNET_PQ_make_prepare ("update_max_state_message_id",
327 "WHERE channel_id = get_chan_id($1)\n" 286 "UPDATE channels\n"
328 "ORDER BY fragment_id DESC LIMIT 1", 1)) || 287 "SET max_state_message_id = $1\n"
329 288 "WHERE pub_key = $2", 2),
330 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 289
331 "select_counters_state", 290 GNUNET_PQ_make_prepare ("update_state_hash_message_id",
332 "SELECT max_state_message_id\n" 291 "UPDATE channels\n"
333 "FROM channels\n" 292 "SET state_hash_message_id = $1\n"
334 "WHERE pub_key = $1 AND max_state_message_id IS NOT NULL", 1)) || 293 "WHERE pub_key = $2", 2),
335 294 GNUNET_PQ_make_prepare ("insert_state_current",
336 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 295 "INSERT INTO state\n"
337 "update_max_state_message_id", 296 " (channel_id, name, value_current, value_signed)\n"
338 "UPDATE channels\n" 297 "SELECT new.channel_id, new.name,\n"
339 "SET max_state_message_id = $1\n" 298 " new.value_current, old.value_signed\n"
340 "WHERE pub_key = $2", 2)) || 299 "FROM (SELECT get_chan_id($1) AS channel_id,\n"
341 300 " $2::TEXT AS name, $3::BYTEA AS value_current) AS new\n"
342 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 301 "LEFT JOIN (SELECT channel_id, name, value_signed\n"
343 "update_state_hash_message_id", 302 " FROM state) AS old\n"
344 "UPDATE channels\n" 303 "ON new.channel_id = old.channel_id AND new.name = old.name\n"
345 "SET state_hash_message_id = $1\n" 304 "ON CONFLICT (channel_id, name)\n"
346 "WHERE pub_key = $2", 2)) || 305 " DO UPDATE SET value_current = EXCLUDED.value_current,\n"
347 306 " value_signed = EXCLUDED.value_signed", 3),
348 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 307 GNUNET_PQ_make_prepare ("delete_state_empty",
349 "insert_state_current", 308 "DELETE FROM state\n"
350 "INSERT INTO state\n" 309 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = $1)\n"
351 " (channel_id, name, value_current, value_signed)\n" 310 " AND (value_current IS NULL OR length(value_current) = 0)\n"
352 "SELECT new.channel_id, new.name,\n" 311 " AND (value_signed IS NULL OR length(value_signed) = 0)", 1),
353 " new.value_current, old.value_signed\n" 312 GNUNET_PQ_make_prepare ("update_state_signed",
354 "FROM (SELECT get_chan_id($1) AS channel_id,\n" 313 "UPDATE state\n"
355 " $2::TEXT AS name, $3::BYTEA AS value_current) AS new\n" 314 "SET value_signed = value_current\n"
356 "LEFT JOIN (SELECT channel_id, name, value_signed\n" 315 "WHERE channel_id = get_chan_id($1) ", 1),
357 " FROM state) AS old\n" 316 GNUNET_PQ_make_prepare ("delete_state",
358 "ON new.channel_id = old.channel_id AND new.name = old.name\n" 317 "DELETE FROM state\n"
359 "ON CONFLICT (channel_id, name)\n" 318 "WHERE channel_id = get_chan_id($1) ", 1),
360 " DO UPDATE SET value_current = EXCLUDED.value_current,\n" 319 GNUNET_PQ_make_prepare ("insert_state_sync",
361 " value_signed = EXCLUDED.value_signed", 3)) || 320 "INSERT INTO state_sync (channel_id, name, value)\n"
362 321 "VALUES (get_chan_id($1), $2, $3)", 3),
363 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 322 GNUNET_PQ_make_prepare ("insert_state_from_sync",
364 "delete_state_empty", 323 "INSERT INTO state\n"
365 "DELETE FROM state\n" 324 " (channel_id, name, value_current, value_signed)\n"
366 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = $1)\n" 325 "SELECT channel_id, name, value, value\n"
367 " AND (value_current IS NULL OR length(value_current) = 0)\n" 326 "FROM state_sync\n"
368 " AND (value_signed IS NULL OR length(value_signed) = 0)", 1)) || 327 "WHERE channel_id = get_chan_id($1)", 1),
369 328 GNUNET_PQ_make_prepare ("delete_state_sync",
370 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 329 "DELETE FROM state_sync\n"
371 "update_state_signed", 330 "WHERE channel_id = get_chan_id($1)", 1),
372 "UPDATE state\n" 331 GNUNET_PQ_make_prepare ("select_state_one",
373 "SET value_signed = value_current\n" 332 "SELECT value_current\n"
374 "WHERE channel_id = get_chan_id($1) ", 1)) || 333 "FROM state\n"
375 334 "WHERE channel_id = get_chan_id($1)\n"
376 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 335 " AND name = $2", 2),
377 "delete_state", 336 GNUNET_PQ_make_prepare ("select_state_prefix",
378 "DELETE FROM state\n" 337 "SELECT name, value_current\n"
379 "WHERE channel_id = get_chan_id($1) ", 1)) || 338 "FROM state\n"
380 339 "WHERE channel_id = get_chan_id($1)\n"
381 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 340 " AND (name = $2 OR substr(name, 1, $3) = $4)", 4),
382 "insert_state_sync", 341 GNUNET_PQ_make_prepare ("select_state_signed",
383 "INSERT INTO state_sync (channel_id, name, value)\n" 342 "SELECT name, value_signed\n"
384 "VALUES (get_chan_id($1), $2, $3)", 3)) || 343 "FROM state\n"
385 344 "WHERE channel_id = get_chan_id($1)\n"
386 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 345 " AND value_signed IS NOT NULL", 1),
387 "insert_state_from_sync", 346 GNUNET_PQ_PREPARED_STATEMENT_END
388 "INSERT INTO state\n" 347 };
389 " (channel_id, name, value_current, value_signed)\n" 348
390 "SELECT channel_id, name, value, value\n" 349 if (GNUNET_OK !=
391 "FROM state_sync\n" 350 GNUNET_PQ_prepare_statements (plugin->dbh,
392 "WHERE channel_id = get_chan_id($1)", 1)) || 351 ps))
393 352 {
394 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh, 353 PQfinish (plugin->dbh);
395 "delete_state_sync", 354 plugin->dbh = NULL;
396 "DELETE FROM state_sync\n" 355 return GNUNET_SYSERR;
397 "WHERE channel_id = get_chan_id($1)", 1)) || 356 }
398
399 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh,
400 "select_state_one",
401 "SELECT value_current\n"
402 "FROM state\n"
403 "WHERE channel_id = get_chan_id($1)\n"
404 " AND name = $2", 2)) ||
405
406 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh,
407 "select_state_prefix",
408 "SELECT name, value_current\n"
409 "FROM state\n"
410 "WHERE channel_id = get_chan_id($1)\n"
411 " AND (name = $2 OR substr(name, 1, $3) = $4)", 4)) ||
412
413 (GNUNET_OK != GNUNET_POSTGRES_prepare (plugin->dbh,
414 "select_state_signed",
415 "SELECT name, value_signed\n"
416 "FROM state\n"
417 "WHERE channel_id = get_chan_id($1)\n"
418 " AND value_signed IS NOT NULL", 1)))
419 {
420 PQfinish (plugin->dbh);
421 plugin->dbh = NULL;
422 return GNUNET_SYSERR;
423 } 357 }
424 358
425 return GNUNET_OK; 359 return GNUNET_OK;
@@ -452,22 +386,15 @@ static int
452exec_channel (struct Plugin *plugin, const char *stmt, 386exec_channel (struct Plugin *plugin, const char *stmt,
453 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) 387 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
454{ 388{
455 PGresult *ret;
456 struct GNUNET_PQ_QueryParam params[] = { 389 struct GNUNET_PQ_QueryParam params[] = {
457 GNUNET_PQ_query_param_auto_from_type (channel_key), 390 GNUNET_PQ_query_param_auto_from_type (channel_key),
458 GNUNET_PQ_query_param_end 391 GNUNET_PQ_query_param_end
459 }; 392 };
460 393
461 ret = GNUNET_PQ_exec_prepared (plugin->dbh, stmt, params); 394 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
462 if (GNUNET_OK != 395 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, stmt, params))
463 GNUNET_POSTGRES_check_result (plugin->dbh,
464 ret,
465 PGRES_COMMAND_OK,
466 "PQexecPrepared", stmt))
467 return GNUNET_SYSERR; 396 return GNUNET_SYSERR;
468 397
469 PQclear (ret);
470
471 return GNUNET_OK; 398 return GNUNET_OK;
472} 399}
473 400
@@ -478,23 +405,15 @@ exec_channel (struct Plugin *plugin, const char *stmt,
478static int 405static int
479transaction_begin (struct Plugin *plugin, enum Transactions transaction) 406transaction_begin (struct Plugin *plugin, enum Transactions transaction)
480{ 407{
481 PGresult *ret;
482 struct GNUNET_PQ_QueryParam params[] = { 408 struct GNUNET_PQ_QueryParam params[] = {
483 GNUNET_PQ_query_param_end 409 GNUNET_PQ_query_param_end
484 }; 410 };
485 411
486 ret = GNUNET_PQ_exec_prepared (plugin->dbh, "transaction_begin", params); 412 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
487 if (GNUNET_OK != 413 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "transaction_begin", params))
488 GNUNET_POSTGRES_check_result (plugin->dbh,
489 ret,
490 PGRES_COMMAND_OK,
491 "PQexecPrepared", "transaction_begin"))
492 {
493 return GNUNET_SYSERR; 414 return GNUNET_SYSERR;
494 }
495 415
496 plugin->transaction = transaction; 416 plugin->transaction = transaction;
497 PQclear (ret);
498 return GNUNET_OK; 417 return GNUNET_OK;
499} 418}
500 419
@@ -505,23 +424,14 @@ transaction_begin (struct Plugin *plugin, enum Transactions transaction)
505static int 424static int
506transaction_commit (struct Plugin *plugin) 425transaction_commit (struct Plugin *plugin)
507{ 426{
508 PGresult *ret;
509
510 struct GNUNET_PQ_QueryParam params[] = { 427 struct GNUNET_PQ_QueryParam params[] = {
511 GNUNET_PQ_query_param_end 428 GNUNET_PQ_query_param_end
512 }; 429 };
513 430
514 ret = GNUNET_PQ_exec_prepared (plugin->dbh, "transaction_commit", params); 431 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
515 if (GNUNET_OK != 432 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "transaction_commit", params))
516 GNUNET_POSTGRES_check_result (plugin->dbh,
517 ret,
518 PGRES_COMMAND_OK,
519 "PQexecPrepared", "transaction_commit"))
520 {
521 return GNUNET_SYSERR; 433 return GNUNET_SYSERR;
522 }
523 434
524 PQclear (ret);
525 plugin->transaction = TRANSACTION_NONE; 435 plugin->transaction = TRANSACTION_NONE;
526 return GNUNET_OK; 436 return GNUNET_OK;
527} 437}
@@ -533,23 +443,14 @@ transaction_commit (struct Plugin *plugin)
533static int 443static int
534transaction_rollback (struct Plugin *plugin) 444transaction_rollback (struct Plugin *plugin)
535{ 445{
536 PGresult *ret;
537
538 struct GNUNET_PQ_QueryParam params[] = { 446 struct GNUNET_PQ_QueryParam params[] = {
539 GNUNET_PQ_query_param_end 447 GNUNET_PQ_query_param_end
540 }; 448 };
541 449
542 ret = GNUNET_PQ_exec_prepared (plugin->dbh, "transaction_rollback", params); 450 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
543 if (GNUNET_OK != 451 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "transaction_rollback", params))
544 GNUNET_POSTGRES_check_result (plugin->dbh,
545 ret,
546 PGRES_COMMAND_OK,
547 "PQexecPrepared", "transaction_rollback"))
548 {
549 return GNUNET_SYSERR; 452 return GNUNET_SYSERR;
550 }
551 453
552 PQclear (ret);
553 plugin->transaction = TRANSACTION_NONE; 454 plugin->transaction = TRANSACTION_NONE;
554 return GNUNET_OK; 455 return GNUNET_OK;
555} 456}
@@ -559,24 +460,15 @@ static int
559channel_key_store (struct Plugin *plugin, 460channel_key_store (struct Plugin *plugin,
560 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) 461 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
561{ 462{
562 PGresult *ret;
563
564 struct GNUNET_PQ_QueryParam params[] = { 463 struct GNUNET_PQ_QueryParam params[] = {
565 GNUNET_PQ_query_param_auto_from_type (channel_key), 464 GNUNET_PQ_query_param_auto_from_type (channel_key),
566 GNUNET_PQ_query_param_end 465 GNUNET_PQ_query_param_end
567 }; 466 };
568 467
569 ret = GNUNET_PQ_exec_prepared (plugin->dbh, "insert_channel_key", params); 468 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
570 if (GNUNET_OK != 469 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "insert_channel_key", params))
571 GNUNET_POSTGRES_check_result (plugin->dbh,
572 ret,
573 PGRES_COMMAND_OK,
574 "PQexecPrepared", "insert_channel_key"))
575 {
576 return GNUNET_SYSERR; 470 return GNUNET_SYSERR;
577 }
578 471
579 PQclear (ret);
580 return GNUNET_OK; 472 return GNUNET_OK;
581} 473}
582 474
@@ -585,24 +477,15 @@ static int
585slave_key_store (struct Plugin *plugin, 477slave_key_store (struct Plugin *plugin,
586 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key) 478 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key)
587{ 479{
588 PGresult *ret;
589
590 struct GNUNET_PQ_QueryParam params[] = { 480 struct GNUNET_PQ_QueryParam params[] = {
591 GNUNET_PQ_query_param_auto_from_type (slave_key), 481 GNUNET_PQ_query_param_auto_from_type (slave_key),
592 GNUNET_PQ_query_param_end 482 GNUNET_PQ_query_param_end
593 }; 483 };
594 484
595 ret = GNUNET_PQ_exec_prepared (plugin->dbh, "insert_slave_key", params); 485 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
596 if (GNUNET_OK != 486 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "insert_slave_key", params))
597 GNUNET_POSTGRES_check_result (plugin->dbh,
598 ret,
599 PGRES_COMMAND_OK,
600 "PQexecPrepared", "insert_slave_key"))
601 {
602 return GNUNET_SYSERR; 487 return GNUNET_SYSERR;
603 }
604 488
605 PQclear (ret);
606 return GNUNET_OK; 489 return GNUNET_OK;
607} 490}
608 491
@@ -624,7 +507,6 @@ postgres_membership_store (void *cls,
624 uint64_t effective_since, 507 uint64_t effective_since,
625 uint64_t group_generation) 508 uint64_t group_generation)
626{ 509{
627 PGresult *ret;
628 struct Plugin *plugin = cls; 510 struct Plugin *plugin = cls;
629 511
630 uint32_t idid_join = (uint32_t)did_join; 512 uint32_t idid_join = (uint32_t)did_join;
@@ -653,17 +535,10 @@ postgres_membership_store (void *cls,
653 GNUNET_PQ_query_param_end 535 GNUNET_PQ_query_param_end
654 }; 536 };
655 537
656 ret = GNUNET_PQ_exec_prepared (plugin->dbh, "insert_membership", params); 538 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
657 if (GNUNET_OK != 539 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "insert_membership", params))
658 GNUNET_POSTGRES_check_result (plugin->dbh,
659 ret,
660 PGRES_COMMAND_OK,
661 "PQexecPrepared", "insert_membership"))
662 {
663 return GNUNET_SYSERR; 540 return GNUNET_SYSERR;
664 }
665 541
666 PQclear (ret);
667 return GNUNET_OK; 542 return GNUNET_OK;
668} 543}
669 544
@@ -681,13 +556,10 @@ membership_test (void *cls,
681 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, 556 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
682 uint64_t message_id) 557 uint64_t message_id)
683{ 558{
684 PGresult *res;
685 struct Plugin *plugin = cls; 559 struct Plugin *plugin = cls;
686 560
687 uint32_t did_join = 0; 561 uint32_t did_join = 0;
688 562
689 int ret = GNUNET_SYSERR;
690
691 struct GNUNET_PQ_QueryParam params_select[] = { 563 struct GNUNET_PQ_QueryParam params_select[] = {
692 GNUNET_PQ_query_param_auto_from_type (channel_key), 564 GNUNET_PQ_query_param_auto_from_type (channel_key),
693 GNUNET_PQ_query_param_auto_from_type (slave_key), 565 GNUNET_PQ_query_param_auto_from_type (slave_key),
@@ -695,35 +567,17 @@ membership_test (void *cls,
695 GNUNET_PQ_query_param_end 567 GNUNET_PQ_query_param_end
696 }; 568 };
697 569
698 res = GNUNET_PQ_exec_prepared (plugin->dbh, "select_membership", params_select);
699 if (GNUNET_OK !=
700 GNUNET_POSTGRES_check_result (plugin->dbh,
701 res,
702 PGRES_TUPLES_OK,
703 "PQexecPrepared", "select_membership"))
704 {
705 return GNUNET_SYSERR;
706 }
707
708 struct GNUNET_PQ_ResultSpec results_select[] = { 570 struct GNUNET_PQ_ResultSpec results_select[] = {
709 GNUNET_PQ_result_spec_uint32 ("did_join", &did_join), 571 GNUNET_PQ_result_spec_uint32 ("did_join", &did_join),
710 GNUNET_PQ_result_spec_end 572 GNUNET_PQ_result_spec_end
711 }; 573 };
712 574
713 switch (GNUNET_PQ_extract_result (res, results_select, 0)) 575 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
714 { 576 GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, "select_membership",
715 case GNUNET_OK: 577 params_select, results_select))
716 ret = GNUNET_YES; 578 return GNUNET_SYSERR;
717 break;
718
719 default:
720 ret = GNUNET_NO;
721 break;
722 }
723 579
724 PQclear (res); 580 return GNUNET_OK;
725
726 return ret;
727} 581}
728 582
729/** 583/**
@@ -739,7 +593,6 @@ fragment_store (void *cls,
739 const struct GNUNET_MULTICAST_MessageHeader *msg, 593 const struct GNUNET_MULTICAST_MessageHeader *msg,
740 uint32_t psycstore_flags) 594 uint32_t psycstore_flags)
741{ 595{
742 PGresult *res;
743 struct Plugin *plugin = cls; 596 struct Plugin *plugin = cls;
744 597
745 GNUNET_assert (TRANSACTION_NONE == plugin->transaction); 598 GNUNET_assert (TRANSACTION_NONE == plugin->transaction);
@@ -782,15 +635,10 @@ fragment_store (void *cls,
782 GNUNET_PQ_query_param_end 635 GNUNET_PQ_query_param_end
783 }; 636 };
784 637
785 res = GNUNET_PQ_exec_prepared (plugin->dbh, "insert_fragment", params_insert); 638 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
786 if (GNUNET_OK != 639 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "insert_fragment", params_insert))
787 GNUNET_POSTGRES_check_result (plugin->dbh,
788 res,
789 PGRES_COMMAND_OK,
790 "PQexecPrepared", "insert_fragment"))
791 return GNUNET_SYSERR; 640 return GNUNET_SYSERR;
792 641
793 PQclear (res);
794 return GNUNET_OK; 642 return GNUNET_OK;
795} 643}
796 644
@@ -807,7 +655,6 @@ message_add_flags (void *cls,
807 uint64_t message_id, 655 uint64_t message_id,
808 uint32_t psycstore_flags) 656 uint32_t psycstore_flags)
809{ 657{
810 PGresult *res;
811 struct Plugin *plugin = cls; 658 struct Plugin *plugin = cls;
812 659
813 struct GNUNET_PQ_QueryParam params_update[] = { 660 struct GNUNET_PQ_QueryParam params_update[] = {
@@ -817,74 +664,80 @@ message_add_flags (void *cls,
817 GNUNET_PQ_query_param_end 664 GNUNET_PQ_query_param_end
818 }; 665 };
819 666
820 res = GNUNET_PQ_exec_prepared (plugin->dbh, "update_message_flags", params_update); 667 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
821 if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh, 668 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "update_message_flags", params_update))
822 res,
823 PGRES_COMMAND_OK,
824 "PQexecPrepared","update_message_flags"))
825 return GNUNET_SYSERR; 669 return GNUNET_SYSERR;
826 670
827 PQclear (res);
828 return GNUNET_OK; 671 return GNUNET_OK;
829} 672}
830 673
831 674
832static int 675/**
833fragment_row (struct Plugin *plugin, 676 * Closure for #fragment_rows.
834 const char *stmt, 677 */
835 PGresult *res, 678struct FragmentRowsContext {
836 GNUNET_PSYCSTORE_FragmentCallback cb, 679 GNUNET_PSYCSTORE_FragmentCallback cb;
837 void *cb_cls, 680 void *cb_cls;
838 uint64_t *returned_fragments)
839{
840 uint32_t hop_counter;
841 void *signature = NULL;
842 void *purpose = NULL;
843 size_t signature_size;
844 size_t purpose_size;
845
846 uint64_t fragment_id;
847 uint64_t fragment_offset;
848 uint64_t message_id;
849 uint64_t group_generation;
850 uint32_t flags;
851 void *buf;
852 size_t buf_size;
853 int ret = GNUNET_SYSERR;
854 struct GNUNET_MULTICAST_MessageHeader *mp;
855
856 uint32_t msg_flags;
857
858 struct GNUNET_PQ_ResultSpec results[] = {
859 GNUNET_PQ_result_spec_uint32 ("hop_counter", &hop_counter),
860 GNUNET_PQ_result_spec_variable_size ("signature", &signature, &signature_size),
861 GNUNET_PQ_result_spec_variable_size ("purpose", &purpose, &purpose_size),
862 GNUNET_PQ_result_spec_uint64 ("fragment_id", &fragment_id),
863 GNUNET_PQ_result_spec_uint64 ("fragment_offset", &fragment_offset),
864 GNUNET_PQ_result_spec_uint64 ("message_id", &message_id),
865 GNUNET_PQ_result_spec_uint64 ("group_generation", &group_generation),
866 GNUNET_PQ_result_spec_uint32 ("multicast_flags", &msg_flags),
867 GNUNET_PQ_result_spec_uint32 ("psycstore_flags", &flags),
868 GNUNET_PQ_result_spec_variable_size ("data", &buf, &buf_size),
869 GNUNET_PQ_result_spec_end
870 };
871 681
872 if (GNUNET_OK != 682 uint64_t *returned_fragments;
873 GNUNET_POSTGRES_check_result (plugin->dbh, res, PGRES_TUPLES_OK,
874 "PQexecPrepared",
875 stmt))
876 {
877 LOG (GNUNET_ERROR_TYPE_DEBUG,
878 "Failing fragment lookup (postgres error)\n");
879 return GNUNET_SYSERR;
880 }
881 683
882 int nrows = PQntuples (res); 684 /* I preserved this but I do not see the point since
883 for (int row = 0; row < nrows; row++) 685 * it cannot stop the loop early and gets overwritten ?? */
686 int ret;
687};
688
689
690/**
691 * Callback that retrieves the results of a SELECT statement
692 * reading form the messages table.
693 *
694 * Only passed to GNUNET_PQ_eval_prepared_multi_select and
695 * has type GNUNET_PQ_PostgresResultHandler.
696 *
697 * @param cls closure
698 * @param result the postgres result
699 * @param num_result the number of results in @a result
700 */
701void fragment_rows (void *cls,
702 PGresult *res,
703 unsigned int num_results)
704{
705 struct FragmentRowsContext *c = cls;
706
707 for (unsigned int i=0;i<num_results;i++)
884 { 708 {
885 if (GNUNET_OK != GNUNET_PQ_extract_result (res, results, row)) 709 uint32_t hop_counter;
710 void *signature = NULL;
711 void *purpose = NULL;
712 size_t signature_size;
713 size_t purpose_size;
714 uint64_t fragment_id;
715 uint64_t fragment_offset;
716 uint64_t message_id;
717 uint64_t group_generation;
718 uint32_t flags;
719 void *buf;
720 size_t buf_size;
721 uint32_t msg_flags;
722 struct GNUNET_PQ_ResultSpec results[] = {
723 GNUNET_PQ_result_spec_uint32 ("hop_counter", &hop_counter),
724 GNUNET_PQ_result_spec_variable_size ("signature", &signature, &signature_size),
725 GNUNET_PQ_result_spec_variable_size ("purpose", &purpose, &purpose_size),
726 GNUNET_PQ_result_spec_uint64 ("fragment_id", &fragment_id),
727 GNUNET_PQ_result_spec_uint64 ("fragment_offset", &fragment_offset),
728 GNUNET_PQ_result_spec_uint64 ("message_id", &message_id),
729 GNUNET_PQ_result_spec_uint64 ("group_generation", &group_generation),
730 GNUNET_PQ_result_spec_uint32 ("multicast_flags", &msg_flags),
731 GNUNET_PQ_result_spec_uint32 ("psycstore_flags", &flags),
732 GNUNET_PQ_result_spec_variable_size ("data", &buf, &buf_size),
733 GNUNET_PQ_result_spec_end
734 };
735 struct GNUNET_MULTICAST_MessageHeader *mp;
736
737 if (GNUNET_YES != GNUNET_PQ_extract_result (res, results, i))
886 { 738 {
887 break; 739 GNUNET_PQ_cleanup_result(results); /* missing previously, a memory leak?? */
740 break; /* nothing more?? */
888 } 741 }
889 742
890 mp = GNUNET_malloc (sizeof (*mp) + buf_size); 743 mp = GNUNET_malloc (sizeof (*mp) + buf_size);
@@ -893,11 +746,9 @@ fragment_row (struct Plugin *plugin,
893 mp->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE); 746 mp->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE);
894 mp->hop_counter = htonl (hop_counter); 747 mp->hop_counter = htonl (hop_counter);
895 GNUNET_memcpy (&mp->signature, 748 GNUNET_memcpy (&mp->signature,
896 signature, 749 signature, signature_size);
897 signature_size);
898 GNUNET_memcpy (&mp->purpose, 750 GNUNET_memcpy (&mp->purpose,
899 purpose, 751 purpose, purpose_size);
900 purpose_size);
901 mp->fragment_id = GNUNET_htonll (fragment_id); 752 mp->fragment_id = GNUNET_htonll (fragment_id);
902 mp->fragment_offset = GNUNET_htonll (fragment_offset); 753 mp->fragment_offset = GNUNET_htonll (fragment_offset);
903 mp->message_id = GNUNET_htonll (message_id); 754 mp->message_id = GNUNET_htonll (message_id);
@@ -905,15 +756,12 @@ fragment_row (struct Plugin *plugin,
905 mp->flags = htonl(msg_flags); 756 mp->flags = htonl(msg_flags);
906 757
907 GNUNET_memcpy (&mp[1], 758 GNUNET_memcpy (&mp[1],
908 buf, 759 buf, buf_size);
909 buf_size);
910 GNUNET_PQ_cleanup_result(results); 760 GNUNET_PQ_cleanup_result(results);
911 ret = cb (cb_cls, mp, (enum GNUNET_PSYCSTORE_MessageFlags) flags); 761 c->ret = c->cb (c->cb_cls, mp, (enum GNUNET_PSYCSTORE_MessageFlags) flags);
912 if (NULL != returned_fragments) 762 if (NULL != c->returned_fragments)
913 (*returned_fragments)++; 763 (*c->returned_fragments)++;
914 } 764 }
915
916 return ret;
917} 765}
918 766
919 767
@@ -925,26 +773,19 @@ fragment_select (struct Plugin *plugin,
925 GNUNET_PSYCSTORE_FragmentCallback cb, 773 GNUNET_PSYCSTORE_FragmentCallback cb,
926 void *cb_cls) 774 void *cb_cls)
927{ 775{
928 PGresult *res; 776 /* Stack based closure */
929 int ret = GNUNET_SYSERR; 777 struct FragmentRowsContext frc = {
930 778 .cb = cb,
931 res = GNUNET_PQ_exec_prepared (plugin->dbh, stmt, params); 779 .cb_cls = cb_cls,
932 if (GNUNET_YES == 780 .returned_fragments = returned_fragments,
933 GNUNET_POSTGRES_check_result (plugin->dbh, 781 .ret = GNUNET_SYSERR
934 res, 782 };
935 PGRES_TUPLES_OK,
936 "PQexecPrepared", stmt))
937 {
938 if (PQntuples (res) == 0)
939 ret = GNUNET_NO;
940 else
941 {
942 ret = fragment_row (plugin, stmt, res, cb, cb_cls, returned_fragments);
943 }
944 PQclear (res);
945 }
946 783
947 return ret; 784 if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
785 stmt, params,
786 &fragment_rows, &frc))
787 return GNUNET_SYSERR;
788 return frc.ret; /* GNUNET_OK ?? */
948} 789}
949 790
950/** 791/**
@@ -964,8 +805,6 @@ fragment_get (void *cls,
964 void *cb_cls) 805 void *cb_cls)
965{ 806{
966 struct Plugin *plugin = cls; 807 struct Plugin *plugin = cls;
967 *returned_fragments = 0;
968
969 struct GNUNET_PQ_QueryParam params_select[] = { 808 struct GNUNET_PQ_QueryParam params_select[] = {
970 GNUNET_PQ_query_param_auto_from_type (channel_key), 809 GNUNET_PQ_query_param_auto_from_type (channel_key),
971 GNUNET_PQ_query_param_uint64 (&first_fragment_id), 810 GNUNET_PQ_query_param_uint64 (&first_fragment_id),
@@ -973,7 +812,12 @@ fragment_get (void *cls,
973 GNUNET_PQ_query_param_end 812 GNUNET_PQ_query_param_end
974 }; 813 };
975 814
976 return fragment_select (plugin, "select_fragments", params_select, returned_fragments, cb, cb_cls); 815 *returned_fragments = 0;
816 return fragment_select (plugin,
817 "select_fragments",
818 params_select,
819 returned_fragments,
820 cb, cb_cls);
977} 821}
978 822
979 823
@@ -1002,7 +846,11 @@ fragment_get_latest (void *cls,
1002 GNUNET_PQ_query_param_end 846 GNUNET_PQ_query_param_end
1003 }; 847 };
1004 848
1005 return fragment_select (plugin, "select_latest_fragments", params_select, returned_fragments, cb, cb_cls); 849 return fragment_select (plugin,
850 "select_latest_fragments",
851 params_select,
852 returned_fragments,
853 cb, cb_cls);
1006} 854}
1007 855
1008 856
@@ -1024,11 +872,6 @@ message_get (void *cls,
1024 void *cb_cls) 872 void *cb_cls)
1025{ 873{
1026 struct Plugin *plugin = cls; 874 struct Plugin *plugin = cls;
1027 *returned_fragments = 0;
1028
1029 if (0 == fragment_limit)
1030 fragment_limit = INT64_MAX;
1031
1032 struct GNUNET_PQ_QueryParam params_select[] = { 875 struct GNUNET_PQ_QueryParam params_select[] = {
1033 GNUNET_PQ_query_param_auto_from_type (channel_key), 876 GNUNET_PQ_query_param_auto_from_type (channel_key),
1034 GNUNET_PQ_query_param_uint64 (&first_message_id), 877 GNUNET_PQ_query_param_uint64 (&first_message_id),
@@ -1037,7 +880,14 @@ message_get (void *cls,
1037 GNUNET_PQ_query_param_end 880 GNUNET_PQ_query_param_end
1038 }; 881 };
1039 882
1040 return fragment_select (plugin, "select_messages", params_select, returned_fragments, cb, cb_cls); 883 if (0 == fragment_limit)
884 fragment_limit = INT64_MAX;
885 *returned_fragments = 0;
886 return fragment_select (plugin,
887 "select_messages",
888 params_select,
889 returned_fragments,
890 cb, cb_cls);
1041} 891}
1042 892
1043 893
@@ -1057,8 +907,6 @@ message_get_latest (void *cls,
1057 void *cb_cls) 907 void *cb_cls)
1058{ 908{
1059 struct Plugin *plugin = cls; 909 struct Plugin *plugin = cls;
1060 *returned_fragments = 0;
1061
1062 struct GNUNET_PQ_QueryParam params_select[] = { 910 struct GNUNET_PQ_QueryParam params_select[] = {
1063 GNUNET_PQ_query_param_auto_from_type (channel_key), 911 GNUNET_PQ_query_param_auto_from_type (channel_key),
1064 GNUNET_PQ_query_param_auto_from_type (channel_key), 912 GNUNET_PQ_query_param_auto_from_type (channel_key),
@@ -1066,7 +914,12 @@ message_get_latest (void *cls,
1066 GNUNET_PQ_query_param_end 914 GNUNET_PQ_query_param_end
1067 }; 915 };
1068 916
1069 return fragment_select (plugin, "select_latest_messages", params_select, returned_fragments, cb, cb_cls); 917 *returned_fragments = 0;
918 return fragment_select (plugin,
919 "select_latest_messages",
920 params_select,
921 returned_fragments,
922 cb, cb_cls);
1070} 923}
1071 924
1072 925
@@ -1086,9 +939,7 @@ message_get_fragment (void *cls,
1086 GNUNET_PSYCSTORE_FragmentCallback cb, 939 GNUNET_PSYCSTORE_FragmentCallback cb,
1087 void *cb_cls) 940 void *cb_cls)
1088{ 941{
1089 PGresult *res;
1090 struct Plugin *plugin = cls; 942 struct Plugin *plugin = cls;
1091 int ret = GNUNET_SYSERR;
1092 const char *stmt = "select_message_fragment"; 943 const char *stmt = "select_message_fragment";
1093 944
1094 struct GNUNET_PQ_QueryParam params_select[] = { 945 struct GNUNET_PQ_QueryParam params_select[] = {
@@ -1098,21 +949,19 @@ message_get_fragment (void *cls,
1098 GNUNET_PQ_query_param_end 949 GNUNET_PQ_query_param_end
1099 }; 950 };
1100 951
1101 res = GNUNET_PQ_exec_prepared (plugin->dbh, stmt, params_select); 952 /* Stack based closure */
1102 if (GNUNET_OK == GNUNET_POSTGRES_check_result (plugin->dbh, 953 struct FragmentRowsContext frc = {
1103 res, 954 .cb = cb,
1104 PGRES_TUPLES_OK, 955 .cb_cls = cb_cls,
1105 "PQexecPrepared", stmt)) 956 .returned_fragments = NULL,
1106 { 957 .ret = GNUNET_SYSERR
1107 if (PQntuples (res) == 0) 958 };
1108 ret = GNUNET_NO;
1109 else
1110 ret = fragment_row (plugin, stmt, res, cb, cb_cls, NULL);
1111
1112 PQclear (res);
1113 }
1114 959
1115 return ret; 960 if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
961 stmt, params_select,
962 &fragment_rows, &frc))
963 return GNUNET_SYSERR;
964 return frc.ret; /* GNUNET_OK ?? */
1116} 965}
1117 966
1118/** 967/**
@@ -1129,7 +978,6 @@ counters_message_get (void *cls,
1129 uint64_t *max_message_id, 978 uint64_t *max_message_id,
1130 uint64_t *max_group_generation) 979 uint64_t *max_group_generation)
1131{ 980{
1132 PGresult *res;
1133 struct Plugin *plugin = cls; 981 struct Plugin *plugin = cls;
1134 982
1135 const char *stmt = "select_counters_message"; 983 const char *stmt = "select_counters_message";
@@ -1139,15 +987,6 @@ counters_message_get (void *cls,
1139 GNUNET_PQ_query_param_end 987 GNUNET_PQ_query_param_end
1140 }; 988 };
1141 989
1142 res = GNUNET_PQ_exec_prepared (plugin->dbh, stmt, params_select);
1143 if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh,
1144 res,
1145 PGRES_TUPLES_OK,
1146 "PQexecPrepared", stmt))
1147 {
1148 return GNUNET_SYSERR;
1149 }
1150
1151 struct GNUNET_PQ_ResultSpec results_select[] = { 990 struct GNUNET_PQ_ResultSpec results_select[] = {
1152 GNUNET_PQ_result_spec_uint64 ("fragment_id", max_fragment_id), 991 GNUNET_PQ_result_spec_uint64 ("fragment_id", max_fragment_id),
1153 GNUNET_PQ_result_spec_uint64 ("message_id", max_message_id), 992 GNUNET_PQ_result_spec_uint64 ("message_id", max_message_id),
@@ -1155,14 +994,10 @@ counters_message_get (void *cls,
1155 GNUNET_PQ_result_spec_end 994 GNUNET_PQ_result_spec_end
1156 }; 995 };
1157 996
1158 if (GNUNET_OK != GNUNET_PQ_extract_result (res, results_select, 0)) 997 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
1159 { 998 GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, stmt,
1160 PQclear (res); 999 params_select, results_select))
1161 return GNUNET_SYSERR; 1000 return GNUNET_SYSERR;
1162 }
1163
1164 GNUNET_PQ_cleanup_result(results_select);
1165 PQclear (res);
1166 1001
1167 return GNUNET_OK; 1002 return GNUNET_OK;
1168} 1003}
@@ -1179,44 +1014,26 @@ counters_state_get (void *cls,
1179 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, 1014 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1180 uint64_t *max_state_message_id) 1015 uint64_t *max_state_message_id)
1181{ 1016{
1182 PGresult *res;
1183 struct Plugin *plugin = cls; 1017 struct Plugin *plugin = cls;
1184 1018
1185 const char *stmt = "select_counters_state"; 1019 const char *stmt = "select_counters_state";
1186 1020
1187 int ret = GNUNET_SYSERR;
1188
1189 struct GNUNET_PQ_QueryParam params_select[] = { 1021 struct GNUNET_PQ_QueryParam params_select[] = {
1190 GNUNET_PQ_query_param_auto_from_type (channel_key), 1022 GNUNET_PQ_query_param_auto_from_type (channel_key),
1191 GNUNET_PQ_query_param_end 1023 GNUNET_PQ_query_param_end
1192 }; 1024 };
1193 1025
1194 res = GNUNET_PQ_exec_prepared (plugin->dbh, stmt, params_select);
1195 if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh,
1196 res,
1197 PGRES_TUPLES_OK,
1198 "PQexecPrepared", stmt))
1199 {
1200 return GNUNET_SYSERR;
1201 }
1202
1203 struct GNUNET_PQ_ResultSpec results_select[] = { 1026 struct GNUNET_PQ_ResultSpec results_select[] = {
1204 GNUNET_PQ_result_spec_uint64 ("max_state_message_id", max_state_message_id), 1027 GNUNET_PQ_result_spec_uint64 ("max_state_message_id", max_state_message_id),
1205 GNUNET_PQ_result_spec_end 1028 GNUNET_PQ_result_spec_end
1206 }; 1029 };
1207 1030
1208 ret = GNUNET_PQ_extract_result (res, results_select, 0); 1031 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
1209 1032 GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, stmt,
1210 if (GNUNET_OK != ret) 1033 params_select, results_select))
1211 { 1034 return GNUNET_SYSERR;
1212 PQclear (res);
1213 return GNUNET_SYSERR;
1214 }
1215
1216 GNUNET_PQ_cleanup_result(results_select);
1217 PQclear (res);
1218 1035
1219 return ret; 1036 return GNUNET_OK;
1220} 1037}
1221 1038
1222 1039
@@ -1230,8 +1047,6 @@ state_assign (struct Plugin *plugin, const char *stmt,
1230 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, 1047 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1231 const char *name, const void *value, size_t value_size) 1048 const char *name, const void *value, size_t value_size)
1232{ 1049{
1233 PGresult *res;
1234
1235 struct GNUNET_PQ_QueryParam params[] = { 1050 struct GNUNET_PQ_QueryParam params[] = {
1236 GNUNET_PQ_query_param_auto_from_type (channel_key), 1051 GNUNET_PQ_query_param_auto_from_type (channel_key),
1237 GNUNET_PQ_query_param_string (name), 1052 GNUNET_PQ_query_param_string (name),
@@ -1239,44 +1054,29 @@ state_assign (struct Plugin *plugin, const char *stmt,
1239 GNUNET_PQ_query_param_end 1054 GNUNET_PQ_query_param_end
1240 }; 1055 };
1241 1056
1242 res = GNUNET_PQ_exec_prepared (plugin->dbh, stmt, params); 1057 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
1243 if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh, 1058 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, stmt, params))
1244 res,
1245 PGRES_COMMAND_OK,
1246 "PQexecPrepared", stmt))
1247 {
1248 return GNUNET_SYSERR; 1059 return GNUNET_SYSERR;
1249 }
1250
1251 PQclear (res);
1252 1060
1253 return GNUNET_OK; 1061 return GNUNET_OK;
1254} 1062}
1255 1063
1256 1064
1257static int 1065static int
1258update_message_id (struct Plugin *plugin, const char *stmt, 1066update_message_id (struct Plugin *plugin,
1067 const char *stmt,
1259 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, 1068 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1260 uint64_t message_id) 1069 uint64_t message_id)
1261{ 1070{
1262 PGresult *res;
1263
1264 struct GNUNET_PQ_QueryParam params[] = { 1071 struct GNUNET_PQ_QueryParam params[] = {
1265 GNUNET_PQ_query_param_uint64 (&message_id), 1072 GNUNET_PQ_query_param_uint64 (&message_id),
1266 GNUNET_PQ_query_param_auto_from_type (channel_key), 1073 GNUNET_PQ_query_param_auto_from_type (channel_key),
1267 GNUNET_PQ_query_param_end 1074 GNUNET_PQ_query_param_end
1268 }; 1075 };
1269 1076
1270 res = GNUNET_PQ_exec_prepared (plugin->dbh, stmt, params); 1077 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
1271 if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh, 1078 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, stmt, params))
1272 res,
1273 PGRES_COMMAND_OK,
1274 "PQexecPrepared", stmt))
1275 {
1276 return GNUNET_SYSERR; 1079 return GNUNET_SYSERR;
1277 }
1278
1279 PQclear (res);
1280 1080
1281 return GNUNET_OK; 1081 return GNUNET_OK;
1282} 1082}
@@ -1487,10 +1287,7 @@ static int
1487state_get (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, 1287state_get (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1488 const char *name, GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls) 1288 const char *name, GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls)
1489{ 1289{
1490 PGresult *res;
1491
1492 struct Plugin *plugin = cls; 1290 struct Plugin *plugin = cls;
1493 int ret = GNUNET_SYSERR;
1494 1291
1495 const char *stmt = "select_state_one"; 1292 const char *stmt = "select_state_one";
1496 1293
@@ -1503,44 +1300,80 @@ state_get (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1503 void *value_current = NULL; 1300 void *value_current = NULL;
1504 size_t value_size = 0; 1301 size_t value_size = 0;
1505 1302
1506 struct GNUNET_PQ_ResultSpec results[] = { 1303 struct GNUNET_PQ_ResultSpec results_select[] = {
1507 GNUNET_PQ_result_spec_variable_size ("value_current", &value_current, &value_size), 1304 GNUNET_PQ_result_spec_variable_size ("value_current", &value_current, &value_size),
1508 GNUNET_PQ_result_spec_end 1305 GNUNET_PQ_result_spec_end
1509 }; 1306 };
1510 1307
1511 res = GNUNET_PQ_exec_prepared (plugin->dbh, stmt, params_select); 1308 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
1512 if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh, 1309 GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, stmt,
1513 res, 1310 params_select, results_select))
1514 PGRES_TUPLES_OK, 1311 return GNUNET_SYSERR;
1515 "PQexecPrepared", stmt))
1516 {
1517 return GNUNET_SYSERR;
1518 }
1519 1312
1520 if (PQntuples (res) == 0) 1313 return cb (cb_cls, name, value_current,
1521 { 1314 value_size);
1522 PQclear (res); 1315}
1523 ret = GNUNET_NO;
1524 }
1525 1316
1526 ret = GNUNET_PQ_extract_result (res, results, 0);
1527 1317
1528 if (GNUNET_OK != ret) 1318
1319/**
1320 * Closure for #get_state_cb.
1321 */
1322struct GetStateContext {
1323 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key;
1324 // const char *name,
1325 GNUNET_PSYCSTORE_StateCallback cb;
1326 void *cb_cls;
1327
1328 const char *value_id;
1329
1330 /* I preserved this but I do not see the point since
1331 * it cannot stop the loop early and gets overwritten ?? */
1332 int ret;
1333};
1334
1335
1336/**
1337 * Callback that retrieves the results of a SELECT statement
1338 * reading form the state table.
1339 *
1340 * Only passed to GNUNET_PQ_eval_prepared_multi_select and
1341 * has type GNUNET_PQ_PostgresResultHandler.
1342 *
1343 * @param cls closure
1344 * @param result the postgres result
1345 * @param num_result the number of results in @a result
1346 */
1347static void
1348get_state_cb (void *cls,
1349 PGresult *res,
1350 unsigned int num_results)
1351{
1352 struct GetStateContext *c = cls;
1353
1354 for (unsigned int i=0;i<num_results;i++)
1529 { 1355 {
1530 PQclear (res); 1356 char *name = "";
1531 return GNUNET_SYSERR; 1357 void *value = NULL;
1532 } 1358 size_t value_size = 0;
1533 1359
1534 ret = cb (cb_cls, name, value_current, 1360 struct GNUNET_PQ_ResultSpec results[] = {
1535 value_size); 1361 GNUNET_PQ_result_spec_string ("name", &name),
1362 GNUNET_PQ_result_spec_variable_size (c->value_id, &value, &value_size),
1363 GNUNET_PQ_result_spec_end
1364 };
1536 1365
1537 GNUNET_PQ_cleanup_result(results); 1366 if (GNUNET_YES != GNUNET_PQ_extract_result (res, results, i))
1538 PQclear (res); 1367 {
1368 GNUNET_PQ_cleanup_result(results); /* previously invoked via PQclear?? */
1369 break; /* nothing more?? */
1370 }
1539 1371
1540 return ret; 1372 c->ret = c->cb (c->cb_cls, (const char *) name, value, value_size);
1373 GNUNET_PQ_cleanup_result(results);
1374 }
1541} 1375}
1542 1376
1543
1544/** 1377/**
1545 * Retrieve all state variables for a channel with the given prefix. 1378 * Retrieve all state variables for a channel with the given prefix.
1546 * 1379 *
@@ -1553,9 +1386,7 @@ state_get_prefix (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_
1553 const char *name, GNUNET_PSYCSTORE_StateCallback cb, 1386 const char *name, GNUNET_PSYCSTORE_StateCallback cb,
1554 void *cb_cls) 1387 void *cb_cls)
1555{ 1388{
1556 PGresult *res;
1557 struct Plugin *plugin = cls; 1389 struct Plugin *plugin = cls;
1558 int ret = GNUNET_NO;
1559 1390
1560 const char *stmt = "select_state_prefix"; 1391 const char *stmt = "select_state_prefix";
1561 1392
@@ -1569,42 +1400,18 @@ state_get_prefix (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_
1569 GNUNET_PQ_query_param_end 1400 GNUNET_PQ_query_param_end
1570 }; 1401 };
1571 1402
1572 char *name2 = ""; 1403 struct GetStateContext gsc = {
1573 void *value_current = NULL; 1404 .cb = cb,
1574 size_t value_size = 0; 1405 .cb_cls = cb_cls,
1575 1406 .value_id = "value_current",
1576 struct GNUNET_PQ_ResultSpec results[] = { 1407 .ret = GNUNET_NO
1577 GNUNET_PQ_result_spec_string ("name", &name2),
1578 GNUNET_PQ_result_spec_variable_size ("value_current", &value_current, &value_size),
1579 GNUNET_PQ_result_spec_end
1580 }; 1408 };
1581 1409
1582 res = GNUNET_PQ_exec_prepared (plugin->dbh, stmt, params_select); 1410 if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
1583 if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh, 1411 stmt, params_select,
1584 res, 1412 &get_state_cb, &gsc))
1585 PGRES_TUPLES_OK,
1586 "PQexecPrepared", stmt))
1587 {
1588 return GNUNET_SYSERR; 1413 return GNUNET_SYSERR;
1589 } 1414 return gsc.ret; /* GNUNET_OK ?? */
1590
1591 int nrows = PQntuples (res);
1592 for (int row = 0; row < nrows; row++)
1593 {
1594 if (GNUNET_OK != GNUNET_PQ_extract_result (res, results, row))
1595 {
1596 break;
1597 }
1598
1599 ret = cb (cb_cls, (const char *) name2,
1600 value_current,
1601 value_size);
1602 GNUNET_PQ_cleanup_result(results);
1603 }
1604
1605 PQclear (res);
1606
1607 return ret;
1608} 1415}
1609 1416
1610 1417
@@ -1620,9 +1427,7 @@ state_get_signed (void *cls,
1620 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, 1427 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1621 GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls) 1428 GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls)
1622{ 1429{
1623 PGresult *res;
1624 struct Plugin *plugin = cls; 1430 struct Plugin *plugin = cls;
1625 int ret = GNUNET_NO;
1626 1431
1627 const char *stmt = "select_state_signed"; 1432 const char *stmt = "select_state_signed";
1628 1433
@@ -1631,43 +1436,18 @@ state_get_signed (void *cls,
1631 GNUNET_PQ_query_param_end 1436 GNUNET_PQ_query_param_end
1632 }; 1437 };
1633 1438
1634 char *name = ""; 1439 struct GetStateContext gsc = {
1635 void *value_signed = NULL; 1440 .cb = cb,
1636 size_t value_size = 0; 1441 .cb_cls = cb_cls,
1637 1442 .value_id = "value_signed",
1638 struct GNUNET_PQ_ResultSpec results[] = { 1443 .ret = GNUNET_NO
1639 GNUNET_PQ_result_spec_string ("name", &name),
1640 GNUNET_PQ_result_spec_variable_size ("value_signed", &value_signed, &value_size),
1641 GNUNET_PQ_result_spec_end
1642 }; 1444 };
1643 1445
1644 res = GNUNET_PQ_exec_prepared (plugin->dbh, stmt, params_select); 1446 if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
1645 if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh, 1447 stmt, params_select,
1646 res, 1448 &get_state_cb, &gsc))
1647 PGRES_TUPLES_OK,
1648 "PQexecPrepared", stmt))
1649 {
1650 return GNUNET_SYSERR; 1449 return GNUNET_SYSERR;
1651 } 1450 return gsc.ret; /* GNUNET_OK ?? */
1652
1653 int nrows = PQntuples (res);
1654 for (int row = 0; row < nrows; row++)
1655 {
1656 if (GNUNET_OK != GNUNET_PQ_extract_result (res, results, row))
1657 {
1658 break;
1659 }
1660
1661 ret = cb (cb_cls, (const char *) name,
1662 value_signed,
1663 value_size);
1664
1665 GNUNET_PQ_cleanup_result (results);
1666 }
1667
1668 PQclear (res);
1669
1670 return ret;
1671} 1451}
1672 1452
1673 1453
diff --git a/src/set/gnunet-service-set.c b/src/set/gnunet-service-set.c
index 12af653c1..f98d43a7d 100644
--- a/src/set/gnunet-service-set.c
+++ b/src/set/gnunet-service-set.c
@@ -1250,6 +1250,10 @@ handle_client_listen (void *cls,
1250 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE, 1250 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE,
1251 struct GNUNET_MessageHeader, 1251 struct GNUNET_MessageHeader,
1252 NULL), 1252 NULL),
1253 GNUNET_MQ_hd_fixed_size (union_p2p_over,
1254 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OVER,
1255 struct GNUNET_MessageHeader,
1256 NULL),
1253 GNUNET_MQ_hd_fixed_size (union_p2p_full_done, 1257 GNUNET_MQ_hd_fixed_size (union_p2p_full_done,
1254 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE, 1258 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE,
1255 struct GNUNET_MessageHeader, 1259 struct GNUNET_MessageHeader,
@@ -1501,6 +1505,10 @@ handle_client_evaluate (void *cls,
1501 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE, 1505 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE,
1502 struct GNUNET_MessageHeader, 1506 struct GNUNET_MessageHeader,
1503 op), 1507 op),
1508 GNUNET_MQ_hd_fixed_size (union_p2p_over,
1509 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OVER,
1510 struct GNUNET_MessageHeader,
1511 op),
1504 GNUNET_MQ_hd_fixed_size (union_p2p_full_done, 1512 GNUNET_MQ_hd_fixed_size (union_p2p_full_done,
1505 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE, 1513 GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE,
1506 struct GNUNET_MessageHeader, 1514 struct GNUNET_MessageHeader,
diff --git a/src/set/gnunet-service-set_union.c b/src/set/gnunet-service-set_union.c
index fc7e578e6..4ca10f0b4 100644
--- a/src/set/gnunet-service-set_union.c
+++ b/src/set/gnunet-service-set_union.c
@@ -769,7 +769,7 @@ send_full_element_iterator (void *cls,
769 struct GNUNET_SET_Element *el = &ee->element; 769 struct GNUNET_SET_Element *el = &ee->element;
770 struct GNUNET_MQ_Envelope *ev; 770 struct GNUNET_MQ_Envelope *ev;
771 771
772 LOG (GNUNET_ERROR_TYPE_INFO, 772 LOG (GNUNET_ERROR_TYPE_DEBUG,
773 "Sending element %s\n", 773 "Sending element %s\n",
774 GNUNET_h2s (key)); 774 GNUNET_h2s (key));
775 ev = GNUNET_MQ_msg_extra (emsg, 775 ev = GNUNET_MQ_msg_extra (emsg,
@@ -796,7 +796,7 @@ send_full_set (struct Operation *op)
796 struct GNUNET_MQ_Envelope *ev; 796 struct GNUNET_MQ_Envelope *ev;
797 797
798 op->state->phase = PHASE_FULL_SENDING; 798 op->state->phase = PHASE_FULL_SENDING;
799 LOG (GNUNET_ERROR_TYPE_INFO, 799 LOG (GNUNET_ERROR_TYPE_DEBUG,
800 "Dedicing to transmit the full set\n"); 800 "Dedicing to transmit the full set\n");
801 /* FIXME: use a more memory-friendly way of doing this with an 801 /* FIXME: use a more memory-friendly way of doing this with an
802 iterator, just as we do in the non-full case! */ 802 iterator, just as we do in the non-full case! */
@@ -924,7 +924,7 @@ handle_union_p2p_strata_estimator (void *cls,
924 (diff > op->state->initial_size / 4) || 924 (diff > op->state->initial_size / 4) ||
925 (0 == other_size) ) 925 (0 == other_size) )
926 { 926 {
927 LOG (GNUNET_ERROR_TYPE_INFO, 927 LOG (GNUNET_ERROR_TYPE_DEBUG,
928 "Deciding to go for full set transmission (diff=%d, own set=%u)\n", 928 "Deciding to go for full set transmission (diff=%d, own set=%u)\n",
929 diff, 929 diff,
930 op->state->initial_size); 930 op->state->initial_size);
@@ -941,7 +941,7 @@ handle_union_p2p_strata_estimator (void *cls,
941 { 941 {
942 struct GNUNET_MQ_Envelope *ev; 942 struct GNUNET_MQ_Envelope *ev;
943 943
944 LOG (GNUNET_ERROR_TYPE_INFO, 944 LOG (GNUNET_ERROR_TYPE_DEBUG,
945 "Telling other peer that we expect its full set\n"); 945 "Telling other peer that we expect its full set\n");
946 op->state->phase = PHASE_EXPECT_IBF; 946 op->state->phase = PHASE_EXPECT_IBF;
947 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL); 947 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL);
@@ -1299,7 +1299,7 @@ handle_union_p2p_ibf (void *cls,
1299 else 1299 else
1300 { 1300 {
1301 GNUNET_assert (op->state->phase == PHASE_EXPECT_IBF_CONT); 1301 GNUNET_assert (op->state->phase == PHASE_EXPECT_IBF_CONT);
1302 LOG (GNUNET_ERROR_TYPE_INFO, 1302 LOG (GNUNET_ERROR_TYPE_DEBUG,
1303 "Received more of IBF\n"); 1303 "Received more of IBF\n");
1304 } 1304 }
1305 GNUNET_assert (NULL != op->state->remote_ibf); 1305 GNUNET_assert (NULL != op->state->remote_ibf);
@@ -1369,18 +1369,55 @@ send_client_element (struct Operation *op,
1369 1369
1370 1370
1371/** 1371/**
1372 * Destroy remote channel.
1373 *
1374 * @param op operation
1375 */
1376void destroy_channel (struct Operation *op)
1377{
1378 struct GNUNET_CADET_Channel *channel;
1379
1380 if (NULL != (channel = op->channel))
1381 {
1382 /* This will free op; called conditionally as this helper function
1383 is also called from within the channel disconnect handler. */
1384 op->channel = NULL;
1385 GNUNET_CADET_channel_destroy (channel);
1386 }
1387}
1388
1389
1390/**
1372 * Signal to the client that the operation has finished and 1391 * Signal to the client that the operation has finished and
1373 * destroy the operation. 1392 * destroy the operation.
1374 * 1393 *
1375 * @param cls operation to destroy 1394 * @param cls operation to destroy
1376 */ 1395 */
1377static void 1396static void
1378send_done_and_destroy (void *cls) 1397send_client_done (void *cls)
1379{ 1398{
1380 struct Operation *op = cls; 1399 struct Operation *op = cls;
1381 struct GNUNET_MQ_Envelope *ev; 1400 struct GNUNET_MQ_Envelope *ev;
1382 struct GNUNET_SET_ResultMessage *rm; 1401 struct GNUNET_SET_ResultMessage *rm;
1383 1402
1403 if (GNUNET_YES == op->state->client_done_sent) {
1404 return;
1405 }
1406
1407 if (PHASE_DONE != op->state->phase) {
1408 LOG (GNUNET_ERROR_TYPE_ERROR,
1409 "union operation failed\n");
1410 ev = GNUNET_MQ_msg (rm, GNUNET_MESSAGE_TYPE_SET_RESULT);
1411 rm->result_status = htons (GNUNET_SET_STATUS_FAILURE);
1412 rm->request_id = htonl (op->client_request_id);
1413 rm->element_type = htons (0);
1414 GNUNET_MQ_send (op->set->cs->mq,
1415 ev);
1416 return;
1417 }
1418
1419 op->state->client_done_sent = GNUNET_YES;
1420
1384 LOG (GNUNET_ERROR_TYPE_INFO, 1421 LOG (GNUNET_ERROR_TYPE_INFO,
1385 "Signalling client that union operation is done\n"); 1422 "Signalling client that union operation is done\n");
1386 ev = GNUNET_MQ_msg (rm, 1423 ev = GNUNET_MQ_msg (rm,
@@ -1391,9 +1428,6 @@ send_done_and_destroy (void *cls)
1391 rm->current_size = GNUNET_htonll (GNUNET_CONTAINER_multihashmap32_size (op->state->key_to_element)); 1428 rm->current_size = GNUNET_htonll (GNUNET_CONTAINER_multihashmap32_size (op->state->key_to_element));
1392 GNUNET_MQ_send (op->set->cs->mq, 1429 GNUNET_MQ_send (op->set->cs->mq,
1393 ev); 1430 ev);
1394 /* Will also call the union-specific cancel function. */
1395 _GSS_operation_destroy (op,
1396 GNUNET_YES);
1397} 1431}
1398 1432
1399 1433
@@ -1422,7 +1456,7 @@ maybe_finish (struct Operation *op)
1422 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE); 1456 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE);
1423 GNUNET_MQ_send (op->mq, 1457 GNUNET_MQ_send (op->mq,
1424 ev); 1458 ev);
1425 /* We now wait until the other peer closes the channel 1459 /* We now wait until the other peer sends P2P_OVER
1426 * after it got all elements from us. */ 1460 * after it got all elements from us. */
1427 } 1461 }
1428 } 1462 }
@@ -1433,8 +1467,11 @@ maybe_finish (struct Operation *op)
1433 num_demanded); 1467 num_demanded);
1434 if (0 == num_demanded) 1468 if (0 == num_demanded)
1435 { 1469 {
1470 struct GNUNET_MQ_Envelope *ev;
1471
1436 op->state->phase = PHASE_DONE; 1472 op->state->phase = PHASE_DONE;
1437 send_done_and_destroy (op); 1473 send_client_done (op);
1474 destroy_channel (op);
1438 } 1475 }
1439 } 1476 }
1440} 1477}
@@ -1732,7 +1769,7 @@ handle_union_p2p_inquiry (void *cls,
1732 const struct IBF_Key *ibf_key; 1769 const struct IBF_Key *ibf_key;
1733 unsigned int num_keys; 1770 unsigned int num_keys;
1734 1771
1735 LOG (GNUNET_ERROR_TYPE_INFO, 1772 LOG (GNUNET_ERROR_TYPE_DEBUG,
1736 "Received union inquiry\n"); 1773 "Received union inquiry\n");
1737 num_keys = (ntohs (msg->header.size) - sizeof (struct InquiryMessage)) 1774 num_keys = (ntohs (msg->header.size) - sizeof (struct InquiryMessage))
1738 / sizeof (struct IBF_Key); 1775 / sizeof (struct IBF_Key);
@@ -1800,7 +1837,7 @@ handle_union_p2p_request_full (void *cls,
1800{ 1837{
1801 struct Operation *op = cls; 1838 struct Operation *op = cls;
1802 1839
1803 LOG (GNUNET_ERROR_TYPE_INFO, 1840 LOG (GNUNET_ERROR_TYPE_DEBUG,
1804 "Received request for full set transmission\n"); 1841 "Received request for full set transmission\n");
1805 if (GNUNET_SET_OPERATION_UNION != op->set->operation) 1842 if (GNUNET_SET_OPERATION_UNION != op->set->operation)
1806 { 1843 {
@@ -1849,28 +1886,28 @@ handle_union_p2p_full_done (void *cls,
1849 op); 1886 op);
1850 1887
1851 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE); 1888 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE);
1852 GNUNET_MQ_notify_sent (ev,
1853 &send_done_and_destroy,
1854 op);
1855 GNUNET_MQ_send (op->mq, 1889 GNUNET_MQ_send (op->mq,
1856 ev); 1890 ev);
1857 op->state->phase = PHASE_DONE; 1891 op->state->phase = PHASE_DONE;
1858 /* we now wait until the other peer shuts the tunnel down*/ 1892 /* we now wait until the other peer sends us the OVER message*/
1859 } 1893 }
1860 break; 1894 break;
1861 case PHASE_FULL_SENDING: 1895 case PHASE_FULL_SENDING:
1862 { 1896 {
1897 struct GNUNET_MQ_Envelope *ev;
1898
1863 LOG (GNUNET_ERROR_TYPE_DEBUG, 1899 LOG (GNUNET_ERROR_TYPE_DEBUG,
1864 "got FULL DONE, finishing\n"); 1900 "got FULL DONE, finishing\n");
1865 /* We sent the full set, and got the response for that. We're done. */ 1901 /* We sent the full set, and got the response for that. We're done. */
1866 op->state->phase = PHASE_DONE; 1902 op->state->phase = PHASE_DONE;
1867 GNUNET_CADET_receive_done (op->channel); 1903 GNUNET_CADET_receive_done (op->channel);
1868 send_done_and_destroy (op); 1904 send_client_done (op);
1905 destroy_channel (op);
1869 return; 1906 return;
1870 } 1907 }
1871 break; 1908 break;
1872 default: 1909 default:
1873 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1910 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1874 "Handle full done phase is %u\n", 1911 "Handle full done phase is %u\n",
1875 (unsigned) op->state->phase); 1912 (unsigned) op->state->phase);
1876 GNUNET_break_op (0); 1913 GNUNET_break_op (0);
@@ -2144,6 +2181,19 @@ handle_union_p2p_done (void *cls,
2144 } 2181 }
2145} 2182}
2146 2183
2184/**
2185 * Handle a over message from a remote peer
2186 *
2187 * @param cls the union operation
2188 * @param mh the message
2189 */
2190void
2191handle_union_p2p_over (void *cls,
2192 const struct GNUNET_MessageHeader *mh)
2193{
2194 send_client_done (cls);
2195}
2196
2147 2197
2148/** 2198/**
2149 * Initiate operation to evaluate a set union with a remote peer. 2199 * Initiate operation to evaluate a set union with a remote peer.
@@ -2372,6 +2422,7 @@ union_copy_state (struct SetState *state)
2372static void 2422static void
2373union_channel_death (struct Operation *op) 2423union_channel_death (struct Operation *op)
2374{ 2424{
2425 send_client_done (op);
2375 _GSS_operation_destroy (op, 2426 _GSS_operation_destroy (op,
2376 GNUNET_YES); 2427 GNUNET_YES);
2377} 2428}
diff --git a/src/set/gnunet-service-set_union.h b/src/set/gnunet-service-set_union.h
index cbf60bcbc..086666770 100644
--- a/src/set/gnunet-service-set_union.h
+++ b/src/set/gnunet-service-set_union.h
@@ -235,5 +235,15 @@ void
235handle_union_p2p_done (void *cls, 235handle_union_p2p_done (void *cls,
236 const struct GNUNET_MessageHeader *mh); 236 const struct GNUNET_MessageHeader *mh);
237 237
238/**
239 * Handle an over message from a remote peer
240 *
241 * @param cls the union operation
242 * @param mh the message
243 */
244void
245handle_union_p2p_over (void *cls,
246 const struct GNUNET_MessageHeader *mh);
247
238 248
239#endif 249#endif
diff --git a/src/set/set_api.c b/src/set/set_api.c
index f5c43a9a7..27e2ccf04 100644
--- a/src/set/set_api.c
+++ b/src/set/set_api.c
@@ -689,7 +689,7 @@ GNUNET_SET_add_element (struct GNUNET_SET_Handle *set,
689 struct GNUNET_MQ_Envelope *mqm; 689 struct GNUNET_MQ_Envelope *mqm;
690 struct GNUNET_SET_ElementMessage *msg; 690 struct GNUNET_SET_ElementMessage *msg;
691 691
692 LOG (GNUNET_ERROR_TYPE_INFO, 692 LOG (GNUNET_ERROR_TYPE_DEBUG,
693 "adding element of type %u to set %p\n", 693 "adding element of type %u to set %p\n",
694 (unsigned int) element->element_type, 694 (unsigned int) element->element_type,
695 set); 695 set);
diff --git a/src/social/gnunet-social.c b/src/social/gnunet-social.c
index 228d69d58..0e52dccfa 100644
--- a/src/social/gnunet-social.c
+++ b/src/social/gnunet-social.c
@@ -718,7 +718,7 @@ guest_recv_local_enter (void *cls, int result,
718 718
719 719
720/** 720/**
721 * Create entry requset message. 721 * Create entry request message.
722 */ 722 */
723static struct GNUNET_PSYC_Message * 723static struct GNUNET_PSYC_Message *
724guest_enter_msg_create () 724guest_enter_msg_create ()
@@ -1227,11 +1227,6 @@ main (int argc, char *const *argv)
1227 gettext_noop ("create a place"), 1227 gettext_noop ("create a place"),
1228 &op_host_enter), 1228 &op_host_enter),
1229 1229
1230 GNUNET_GETOPT_option_flag ('C',
1231 "host-enter",
1232 gettext_noop ("create a place"),
1233 &op_host_enter),
1234
1235 GNUNET_GETOPT_option_flag ('D', 1230 GNUNET_GETOPT_option_flag ('D',
1236 "host-leave", 1231 "host-leave",
1237 gettext_noop ("destroy a place we were hosting"), 1232 gettext_noop ("destroy a place we were hosting"),
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am
index 7687f2348..d65da6bb6 100644
--- a/src/transport/Makefile.am
+++ b/src/transport/Makefile.am
@@ -10,7 +10,6 @@ libexecdir= $(pkglibdir)/libexec/
10pkgcfg_DATA = \ 10pkgcfg_DATA = \
11 transport.conf 11 transport.conf
12 12
13
14if HAVE_MHD 13if HAVE_MHD
15 GN_LIBMHD = -lmicrohttpd 14 GN_LIBMHD = -lmicrohttpd
16 HTTP_SERVER_PLUGIN_LA = libgnunet_plugin_transport_http_server.la 15 HTTP_SERVER_PLUGIN_LA = libgnunet_plugin_transport_http_server.la
@@ -79,6 +78,7 @@ if USE_COVERAGE
79 AM_CFLAGS = --coverage -O0 78 AM_CFLAGS = --coverage -O0
80endif 79endif
81 80
81if HAVE_EXPERIMENTAL
82if LINUX 82if LINUX
83 WLAN_BIN = gnunet-helper-transport-wlan 83 WLAN_BIN = gnunet-helper-transport-wlan
84 WLAN_BIN_DUMMY = gnunet-helper-transport-wlan-dummy 84 WLAN_BIN_DUMMY = gnunet-helper-transport-wlan-dummy
@@ -121,6 +121,8 @@ if MINGW
121endif 121endif
122endif 122endif
123 123
124# end of HAVE_EXPERIMENTAL
125endif
124 126
125 127
126if !MINGW 128if !MINGW
diff --git a/src/transport/plugin_transport_http_server.c b/src/transport/plugin_transport_http_server.c
index ff2d68602..892d97050 100644
--- a/src/transport/plugin_transport_http_server.c
+++ b/src/transport/plugin_transport_http_server.c
@@ -92,6 +92,11 @@ struct ServerRequest
92 */ 92 */
93 int connected; 93 int connected;
94 94
95 /**
96 * Currently suspended
97 */
98 bool suspended;
99
95}; 100};
96 101
97 102
@@ -501,7 +506,9 @@ server_wake_up (void *cls)
501 LOG (GNUNET_ERROR_TYPE_DEBUG, 506 LOG (GNUNET_ERROR_TYPE_DEBUG,
502 "Session %p: Waking up PUT handle\n", 507 "Session %p: Waking up PUT handle\n",
503 s); 508 s);
509 GNUNET_assert (s->server_recv->suspended);
504 MHD_resume_connection (s->server_recv->mhd_conn); 510 MHD_resume_connection (s->server_recv->mhd_conn);
511 s->server_recv->suspended = false;
505} 512}
506 513
507 514
@@ -541,7 +548,11 @@ server_delete_session (struct GNUNET_ATS_Session *s)
541 GNUNET_SCHEDULER_cancel (s->recv_wakeup_task); 548 GNUNET_SCHEDULER_cancel (s->recv_wakeup_task);
542 s->recv_wakeup_task = NULL; 549 s->recv_wakeup_task = NULL;
543 if (NULL != s->server_recv) 550 if (NULL != s->server_recv)
551 {
552 GNUNET_assert (s->server_recv->suspended);
553 s->server_recv->suspended = false;
544 MHD_resume_connection (s->server_recv->mhd_conn); 554 MHD_resume_connection (s->server_recv->mhd_conn);
555 }
545 } 556 }
546 GNUNET_assert (GNUNET_OK == 557 GNUNET_assert (GNUNET_OK ==
547 GNUNET_CONTAINER_multipeermap_remove (plugin->sessions, 558 GNUNET_CONTAINER_multipeermap_remove (plugin->sessions,
@@ -578,6 +589,11 @@ server_delete_session (struct GNUNET_ATS_Session *s)
578 MHD_set_connection_option (s->server_send->mhd_conn, 589 MHD_set_connection_option (s->server_send->mhd_conn,
579 MHD_CONNECTION_OPTION_TIMEOUT, 590 MHD_CONNECTION_OPTION_TIMEOUT,
580 1 /* 0 = no timeout, so this is MIN */); 591 1 /* 0 = no timeout, so this is MIN */);
592 if (s->server_send->suspended)
593 {
594 s->server_send->suspended = false;
595 MHD_resume_connection (s->server_send->mhd_conn);
596 }
581 server_reschedule (plugin, 597 server_reschedule (plugin,
582 s->server_send->mhd_daemon, 598 s->server_send->mhd_daemon,
583 GNUNET_YES); 599 GNUNET_YES);
@@ -760,9 +776,16 @@ http_server_plugin_send (void *cls,
760 GNUNET_free (stat_txt); 776 GNUNET_free (stat_txt);
761 777
762 if (NULL != session->server_send) 778 if (NULL != session->server_send)
779 {
780 if (session->server_send->suspended)
781 {
782 MHD_resume_connection (session->server_send->mhd_conn);
783 session->server_send->suspended = false;
784 }
763 server_reschedule (session->plugin, 785 server_reschedule (session->plugin,
764 session->server_send->mhd_daemon, 786 session->server_send->mhd_daemon,
765 GNUNET_YES); 787 GNUNET_YES);
788 }
766 return bytes_sent; 789 return bytes_sent;
767} 790}
768 791
@@ -1613,6 +1636,12 @@ server_send_callback (void *cls,
1613 s); 1636 s);
1614 return MHD_CONTENT_READER_END_OF_STREAM; 1637 return MHD_CONTENT_READER_END_OF_STREAM;
1615 } 1638 }
1639 else
1640 {
1641 MHD_suspend_connection (s->server_send->mhd_conn);
1642 s->server_send->suspended = true;
1643 return 0;
1644 }
1616 return bytes_read; 1645 return bytes_read;
1617} 1646}
1618 1647
@@ -1868,6 +1897,7 @@ server_access_cb (void *cls,
1868 GNUNET_YES)); 1897 GNUNET_YES));
1869 GNUNET_assert(s->server_recv->mhd_conn == mhd_connection); 1898 GNUNET_assert(s->server_recv->mhd_conn == mhd_connection);
1870 MHD_suspend_connection (s->server_recv->mhd_conn); 1899 MHD_suspend_connection (s->server_recv->mhd_conn);
1900 s->server_recv->suspended = true;
1871 if (NULL == s->recv_wakeup_task) 1901 if (NULL == s->recv_wakeup_task)
1872 s->recv_wakeup_task 1902 s->recv_wakeup_task
1873 = GNUNET_SCHEDULER_add_delayed (delay, 1903 = GNUNET_SCHEDULER_add_delayed (delay,
diff --git a/src/util/crypto_hash.c b/src/util/crypto_hash.c
index 49dbacd0b..20c7ca7ff 100644
--- a/src/util/crypto_hash.c
+++ b/src/util/crypto_hash.c
@@ -440,8 +440,8 @@ GNUNET_CRYPTO_hash_context_start ()
440 */ 440 */
441void 441void
442GNUNET_CRYPTO_hash_context_read (struct GNUNET_HashContext *hc, 442GNUNET_CRYPTO_hash_context_read (struct GNUNET_HashContext *hc,
443 const void *buf, 443 const void *buf,
444 size_t size) 444 size_t size)
445{ 445{
446 gcry_md_write (hc->hd, buf, size); 446 gcry_md_write (hc->hd, buf, size);
447} 447}
diff --git a/src/util/gnunet-ecc.c b/src/util/gnunet-ecc.c
index 2a712f4eb..42ecc2101 100644
--- a/src/util/gnunet-ecc.c
+++ b/src/util/gnunet-ecc.c
@@ -49,6 +49,11 @@ static unsigned int list_keys_count;
49static int print_public_key; 49static int print_public_key;
50 50
51/** 51/**
52 * Flag for printing public key in hex.
53 */
54static int print_public_key_hex;
55
56/**
52 * Flag for printing the output of random example operations. 57 * Flag for printing the output of random example operations.
53 */ 58 */
54static int print_examples_flag; 59static int print_examples_flag;
@@ -195,12 +200,10 @@ print_hex (const char *msg,
195 const void *buf, 200 const void *buf,
196 size_t size) 201 size_t size)
197{ 202{
198 size_t i;
199
200 printf ("%s: ", msg); 203 printf ("%s: ", msg);
201 for (i = 0; i < size; i++) 204 for (size_t i = 0; i < size; i++)
202 { 205 {
203 printf ("%02hhx", ((const char *)buf)[i]); 206 printf ("%02hhx", ((const uint8_t *)buf)[i]);
204 } 207 }
205 printf ("\n"); 208 printf ("\n");
206} 209}
@@ -374,7 +377,7 @@ run (void *cls, char *const *args, const char *cfgfile,
374 create_keys (args[0], args[1]); 377 create_keys (args[0], args[1]);
375 return; 378 return;
376 } 379 }
377 if (print_public_key) 380 if (print_public_key || print_public_key_hex)
378 { 381 {
379 char *str; 382 char *str;
380 struct GNUNET_DISK_FileHandle *keyfile; 383 struct GNUNET_DISK_FileHandle *keyfile;
@@ -388,9 +391,16 @@ run (void *cls, char *const *args, const char *cfgfile,
388 while (sizeof (pk) == GNUNET_DISK_file_read (keyfile, &pk, sizeof (pk))) 391 while (sizeof (pk) == GNUNET_DISK_file_read (keyfile, &pk, sizeof (pk)))
389 { 392 {
390 GNUNET_CRYPTO_eddsa_key_get_public (&pk, &pub); 393 GNUNET_CRYPTO_eddsa_key_get_public (&pk, &pub);
391 str = GNUNET_CRYPTO_eddsa_public_key_to_string (&pub); 394 if (print_public_key_hex)
392 FPRINTF (stdout, "%s\n", str); 395 {
393 GNUNET_free (str); 396 print_hex ("HEX:", &pub, sizeof (pub));
397 }
398 else
399 {
400 str = GNUNET_CRYPTO_eddsa_public_key_to_string (&pub);
401 FPRINTF (stdout, "%s\n", str);
402 GNUNET_free (str);
403 }
394 } 404 }
395 GNUNET_DISK_file_close (keyfile); 405 GNUNET_DISK_file_close (keyfile);
396 } 406 }
@@ -409,34 +419,38 @@ int
409main (int argc, 419main (int argc,
410 char *const *argv) 420 char *const *argv)
411{ 421{
412 list_keys_count = UINT32_MAX;
413 struct GNUNET_GETOPT_CommandLineOption options[] = { 422 struct GNUNET_GETOPT_CommandLineOption options[] = {
414 GNUNET_GETOPT_option_flag ('i', 423 GNUNET_GETOPT_option_flag ('i',
415 "iterate", 424 "iterate",
416 gettext_noop ("list keys included in a file (for testing)"), 425 gettext_noop ("list keys included in a file (for testing)"),
417 &list_keys), 426 &list_keys),
418 GNUNET_GETOPT_option_uint ('e', 427 GNUNET_GETOPT_option_uint ('e',
419 "end=", 428 "end=",
420 "COUNT", 429 "COUNT",
421 gettext_noop ("number of keys to list included in a file (for testing)"), 430 gettext_noop ("number of keys to list included in a file (for testing)"),
422 &list_keys_count), 431 &list_keys_count),
423 GNUNET_GETOPT_option_uint ('g', 432 GNUNET_GETOPT_option_uint ('g',
424 "generate-keys", 433 "generate-keys",
425 "COUNT", 434 "COUNT",
426 gettext_noop ("create COUNT public-private key pairs (for testing)"), 435 gettext_noop ("create COUNT public-private key pairs (for testing)"),
427 &make_keys), 436 &make_keys),
428 GNUNET_GETOPT_option_flag ('p', 437 GNUNET_GETOPT_option_flag ('p',
429 "print-public-key", 438 "print-public-key",
430 gettext_noop ("print the public key in ASCII format"), 439 gettext_noop ("print the public key in ASCII format"),
431 &print_public_key), 440 &print_public_key),
441 GNUNET_GETOPT_option_flag ('x',
442 "print-hex",
443 gettext_noop ("print the public key in HEX format"),
444 &print_public_key_hex),
432 GNUNET_GETOPT_option_flag ('E', 445 GNUNET_GETOPT_option_flag ('E',
433 "examples", 446 "examples",
434 gettext_noop ("print examples of ECC operations (used for compatibility testing)"), 447 gettext_noop ("print examples of ECC operations (used for compatibility testing)"),
435 &print_examples_flag), 448 &print_examples_flag),
436 GNUNET_GETOPT_OPTION_END 449 GNUNET_GETOPT_OPTION_END
437 }; 450 };
438 int ret; 451 int ret;
439 452
453 list_keys_count = UINT32_MAX;
440 if (GNUNET_OK != 454 if (GNUNET_OK !=
441 GNUNET_STRINGS_get_utf8_args (argc, argv, 455 GNUNET_STRINGS_get_utf8_args (argc, argv,
442 &argc, &argv)) 456 &argc, &argv))
diff --git a/src/util/service.c b/src/util/service.c
index f63737e56..fcdf45a51 100644
--- a/src/util/service.c
+++ b/src/util/service.c
@@ -1283,15 +1283,14 @@ setup_service (struct GNUNET_SERVICE_Handle *sh)
1283 slc->sh = sh; 1283 slc->sh = sh;
1284 slc->listen_socket = open_listen_socket (addrs[i], 1284 slc->listen_socket = open_listen_socket (addrs[i],
1285 addrlens[i]); 1285 addrlens[i]);
1286 GNUNET_free (addrs[i]);
1286 if (NULL == slc->listen_socket) 1287 if (NULL == slc->listen_socket)
1287 { 1288 {
1288 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, 1289 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1289 "bind"); 1290 "bind");
1290 GNUNET_free (addrs[i++]);
1291 GNUNET_free (slc); 1291 GNUNET_free (slc);
1292 continue; 1292 continue;
1293 } 1293 }
1294 GNUNET_free (addrs[i++]);
1295 GNUNET_CONTAINER_DLL_insert (sh->slc_head, 1294 GNUNET_CONTAINER_DLL_insert (sh->slc_head,
1296 sh->slc_tail, 1295 sh->slc_tail,
1297 slc); 1296 slc);
diff --git a/src/zonemaster/gnunet-service-zonemaster.c b/src/zonemaster/gnunet-service-zonemaster.c
index 08a09de34..b3a2cb8b3 100644
--- a/src/zonemaster/gnunet-service-zonemaster.c
+++ b/src/zonemaster/gnunet-service-zonemaster.c
@@ -648,7 +648,8 @@ handle_monitor_event (void *cls,
648static void 648static void
649monitor_sync_event (void *cls) 649monitor_sync_event (void *cls)
650{ 650{
651 GNUNET_assert (NULL == zone_publish_task); 651 if ( (NULL == zone_publish_task) &&
652 (NULL == namestore_iter) )
652 zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start, 653 zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start,
653 NULL); 654 NULL);
654} 655}