From 08b084003d06ea0db8fb645c4d30f5153a2af56e Mon Sep 17 00:00:00 2001 From: "Schanzenbach, Martin" Date: Tue, 8 Oct 2019 21:53:23 +0200 Subject: use correct plugin name; thanks Corvus Corax --- src/transport/plugin_transport_http_server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transport/plugin_transport_http_server.c b/src/transport/plugin_transport_http_server.c index 51555a56f..6e106fe78 100644 --- a/src/transport/plugin_transport_http_server.c +++ b/src/transport/plugin_transport_http_server.c @@ -2856,7 +2856,7 @@ server_start_report_addresses (struct HTTP_Server_Plugin *plugin) plugin->nat = GNUNET_NAT_register (plugin->env->cfg, - "transport-http_server", + plugin->name, IPPROTO_TCP, (unsigned int) res, (const struct sockaddr **) addrs, -- cgit v1.2.3 From 5682fc71092a9d64654d83b5c8b45520bd32459b Mon Sep 17 00:00:00 2001 From: "Schanzenbach, Martin" Date: Tue, 8 Oct 2019 22:15:57 +0200 Subject: allow to disable IP scan w/ HOLE_EXTERNAL; thanks Corvus Corax --- src/nat/gnunet-service-nat.c | 15 +++++++++++++-- src/nat/nat.conf.in | 3 +++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/nat/gnunet-service-nat.c b/src/nat/gnunet-service-nat.c index 694949dde..59a340324 100644 --- a/src/nat/gnunet-service-nat.c +++ b/src/nat/gnunet-service-nat.c @@ -335,6 +335,11 @@ static struct StunExternalIP *se_tail; */ int enable_upnp; +/** + * Is IP Scanning enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled, + * without, only explicitly specified IPs will be handled (HOLE_EXTERNAL) + */ +int enable_ipscan; /** * Remove and free an entry from the #lal_head DLL. @@ -1939,12 +1944,18 @@ run (void *cls, &dyndns_frequency)) dyndns_frequency = DYNDNS_FREQUENCY; + enable_ipscan + = GNUNET_CONFIGURATION_get_value_yesno (cfg, + "NAT", + "ENABLE_IPSCAN"); + GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); stats = GNUNET_STATISTICS_create ("nat", cfg); - scan_task = GNUNET_SCHEDULER_add_now (&run_scan, - NULL); + if (GNUNET_YES == enable_ipscan) + scan_task = GNUNET_SCHEDULER_add_now (&run_scan, + NULL); } diff --git a/src/nat/nat.conf.in b/src/nat/nat.conf.in index a8dbee953..4c068c394 100644 --- a/src/nat/nat.conf.in +++ b/src/nat/nat.conf.in @@ -12,6 +12,9 @@ UNIX_MATCH_GID = YES # Enable UPNP by default? ENABLE_UPNP = YES +# Enable scanning for all system IP addresses? +ENABLE_IPSCAN = YES + # Disable IPv6 support # FIXME: move entirely to transport plugins! DISABLEV6 = NO -- cgit v1.2.3 From f412ffb84409079f236e7046344ef99fdcd02a9a Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 9 Oct 2019 22:38:41 +0200 Subject: fix primary issue from #5907 --- src/gns/gnunet-gns.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/gns/gnunet-gns.c b/src/gns/gnunet-gns.c index 5f4061f7d..510e46d14 100644 --- a/src/gns/gnunet-gns.c +++ b/src/gns/gnunet-gns.c @@ -201,6 +201,12 @@ run (void *cls, cfg = c; to_task = NULL; + { + char *colon; + + if (NULL != (colon = strchr (lookup_name, ':'))) + *colon = '\0'; + } if (GNUNET_OK != GNUNET_DNSPARSER_check_name (lookup_name)) { fprintf (stderr, -- cgit v1.2.3 From 3b80c8d9daddaeaf033d0b0d3f6cda842a939c8d Mon Sep 17 00:00:00 2001 From: "Schanzenbach, Martin" Date: Fri, 11 Oct 2019 11:06:24 +0200 Subject: fix changes in identities --- src/identity/plugin_rest_identity.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/identity/plugin_rest_identity.c b/src/identity/plugin_rest_identity.c index 247d09282..e052ac6b3 100644 --- a/src/identity/plugin_rest_identity.c +++ b/src/identity/plugin_rest_identity.c @@ -1234,11 +1234,46 @@ init_egos (void *cls, GNUNET_IDENTITY_ego_get_public_key (ego, &pk); ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk); ego_entry->ego = ego; - GNUNET_asprintf (&ego_entry->identifier, "%s", identifier); + ego_entry->identifier = GNUNET_strdup (identifier); GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head, handle->ego_tail, ego_entry); + return; + } + // Check if ego exists + for (ego_entry = handle->ego_head; NULL != ego_entry;) + { + struct EgoEntry *tmp = ego_entry; + ego_entry = ego_entry->next; + if (ego != tmp->ego) + continue; + // Deleted + if (NULL == identifier) + { + GNUNET_CONTAINER_DLL_remove (handle->ego_head, + handle->ego_tail, + tmp); + GNUNET_free (tmp->keystring); + GNUNET_free (tmp->identifier); + GNUNET_free (tmp); + } + else { + // Renamed + GNUNET_free (tmp->identifier); + tmp->identifier = GNUNET_strdup (identifier); + } + return; } + // New ego + ego_entry = GNUNET_new (struct EgoEntry); + GNUNET_IDENTITY_ego_get_public_key (ego, &pk); + ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk); + ego_entry->ego = ego; + GNUNET_asprintf (&ego_entry->identifier, "%s", identifier); + GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head, + handle->ego_tail, + ego_entry); + } /** -- cgit v1.2.3 From 559daabee673134f03d76f16d25c1e0ef23b4fdc Mon Sep 17 00:00:00 2001 From: "Schanzenbach, Martin" Date: Fri, 11 Oct 2019 14:48:02 +0200 Subject: fix rest; uncrustify --- src/gns/Makefile.am | 4 ++ src/gns/test_gns_cname_lookup.sh | 4 +- src/gns/test_gns_gns2dns_cname_lookup.sh | 2 +- src/gns/test_gns_lookup.conf | 2 +- src/gns/test_plugin_rest_gns.sh | 67 +++++++++++++++++++++----------- src/util/gnunet-service-resolver.c | 10 +++-- 6 files changed, 59 insertions(+), 30 deletions(-) diff --git a/src/gns/Makefile.am b/src/gns/Makefile.am index 4a152a6df..6cc09c098 100644 --- a/src/gns/Makefile.am +++ b/src/gns/Makefile.am @@ -268,6 +268,10 @@ check_SCRIPTS += \ test_proxy.sh endif endif +if HAVE_JSON +check_SCRIPTS += \ + test_plugin_rest_gns.sh +endif endif diff --git a/src/gns/test_gns_cname_lookup.sh b/src/gns/test_gns_cname_lookup.sh index d168e4acb..f71346127 100755 --- a/src/gns/test_gns_cname_lookup.sh +++ b/src/gns/test_gns_cname_lookup.sh @@ -45,7 +45,7 @@ gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_NAME_PLUS -t CNAME -V $TEST_RE gnunet-namestore -p -z $MY_EGO -a -n $TEST_RECORD_CNAME_SERVER -t A -V $TEST_IP_PLUS -e never -c test_gns_lookup.conf RES_CNAME=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_PLUS -t A -c test_gns_lookup.conf` RES_CNAME_RAW=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_PLUS -t CNAME -c test_gns_lookup.conf` -RES_CNAME_DNS=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_DNS -t A -c test_gns_lookup.conf` +RES_CNAME_DNS=`$DO_TIMEOUT gnunet-gns --raw -u $TEST_DOMAIN_DNS -t A -c test_gns_lookup.conf | grep $TEST_IP_DNS` echo NOW gnunet-gns --raw -u $TEST_DOMAIN_DNS -t A -c test_gns_lookup.conf echo WON @@ -76,7 +76,7 @@ else exit 1 fi -if [ "$RES_CNAME_DNS" = "$TEST_IP_DNS" ] +if echo "$RES_CNAME_DNS" | grep "$TEST_IP_DNS" > /dev/null then echo "PASS: IP resolution from DNS" exit 0 diff --git a/src/gns/test_gns_gns2dns_cname_lookup.sh b/src/gns/test_gns_gns2dns_cname_lookup.sh index 87d684515..71e48a2bd 100755 --- a/src/gns/test_gns_gns2dns_cname_lookup.sh +++ b/src/gns/test_gns_gns2dns_cname_lookup.sh @@ -85,7 +85,7 @@ else ret=1 fi -if [ "$RES_IP6" = "$TEST_IP6" ] +if echo "$RES_IP6" | grep "$TEST_IP6" > /dev/null then echo "PASS: Resolved $TEST_DOMAIN to $RES_IP6." else diff --git a/src/gns/test_gns_lookup.conf b/src/gns/test_gns_lookup.conf index 2b874f80d..130d190e7 100644 --- a/src/gns/test_gns_lookup.conf +++ b/src/gns/test_gns_lookup.conf @@ -1,7 +1,7 @@ @INLINE@ test_gns_defaults.conf [namecache] -DISABLE = YES +DISABLE = NO [PATHS] GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-gns-peer-1/ diff --git a/src/gns/test_plugin_rest_gns.sh b/src/gns/test_plugin_rest_gns.sh index ec495a04b..09f155e01 100755 --- a/src/gns/test_plugin_rest_gns.sh +++ b/src/gns/test_plugin_rest_gns.sh @@ -1,7 +1,20 @@ -#!/usr/bin/bash - -#First, start gnunet-arm and the rest-service. -#Exit 0 means success, exit 1 means failed test +#!/bin/sh +# This file is in the public domain. +trap "gnunet-arm -e -c test_gns_lookup.conf" SIGINT + +LOCATION=$(which gnunet-config) +if [ -z $LOCATION ] +then + LOCATION="gnunet-config" +fi +$LOCATION --version 1> /dev/null +if test $? != 0 +then + echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" + exit 77 +fi + +rm -rf `gnunet-config -c test_gns_lookup.conf -f -s paths -o GNUNET_TEST_HOME` gns_link="http://localhost:7776/gns" wrong_link="http://localhost:7776/gnsandmore" @@ -9,42 +22,50 @@ wrong_link="http://localhost:7776/gnsandmore" curl_get () { #$1 is link #$2 is grep - cache="$(curl -v "$1" 2>&1 | grep "$2")" - #echo $cache + cache="$(gnurl -v "$1" 2>&1 | grep "$2")" + echo "$cache" if [ "" == "$cache" ] then + gnunet-identity -D "$TEST_TLD" -c test_gns_lookup.conf > /dev/null 2>&1 + gnunet-arm -e -c test_gns_lookup.conf exit 1 fi } +TEST_TLD="testtld" -gnunet-identity -D "test_plugin_rest_gns" > /dev/null 2>&1 +gnunet-arm -s -c test_gns_lookup.conf +gnunet-arm -I +gnunet-identity -D "$TEST_TLD" -c test_gns_lookup.conf > /dev/null 2>&1 -curl_get "$gns_link/www.test_plugin_rest_gns" "error" +curl_get "$gns_link/www.$TEST_TLD" "error" -gnunet-identity -C "test_plugin_rest_gns" +gnunet-identity -C "$TEST_TLD" -c test_gns_lookup.conf +sleep 0.5 +curl_get "$gns_link/www.$TEST_TLD" "\[\]" -curl_get "$gns_link/www.test_plugin_rest_gns" "\[\]" +gnunet-namestore -z "$TEST_TLD" -p -a -n www -e 1d -V 1.1.1.1 -t A -c test_gns_lookup.conf -gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www -e 1d -V 1.1.1.1 -t A +curl_get "$gns_link/www.$TEST_TLD" "1.1.1.1" -curl_get "$gns_link/www.test_plugin_rest_gns" "1.1.1.1" +gnunet-namestore -z "$TEST_TLD" -p -a -n www -e 1d -V 1::1 -t AAAA -c test_gns_lookup.conf -gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www -e 1d -V 1::1 -t AAAA +curl_get "$gns_link/www.$TEST_TLD" "1::1.*1.1.1.1" -curl_get "$gns_link/www.test_plugin_rest_gns" "1::1.*1.1.1.1" +gnunet-namestore -z "$TEST_TLD" -p -a -n www -e 1d -V 1.1.1.2 -t A -c test_gns_lookup.conf -gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www -e 1d -V 1.1.1.2 -t A +curl_get "$gns_link/www.$TEST_TLD" "1.1.1.2.*1::1.*1.1.1.1" +curl_get "$gns_link/www.$TEST_TLD?record_type=A" "1.1.1.2.*1.1.1.1" +curl_get "$gns_link/www.$TEST_TLD?record_type=AAAA" "1::1" +curl_get "$gns_link/www.$TEST_TLD?record_type=WRONG_TYPE" "1.1.1.2.*1::1.*1.1.1.1" -curl_get "$gns_link/www.test_plugin_rest_gns" "1.1.1.2.*1::1.*1.1.1.1" -curl_get "$gns_link/www.test_plugin_rest_gns?record_type=A" "1.1.1.2.*1.1.1.1" -curl_get "$gns_link/www.test_plugin_rest_gns?record_type=AAAA" "1::1" -curl_get "$gns_link/www.test_plugin_rest_gns?record_type=WRONG_TYPE" "1.1.1.2.*1::1.*1.1.1.1" +gnunet-namestore -z "$TEST_TLD" -p -a -n www1 -e 1d -V 1.1.1.1 -t A -c test_gns_lookup.conf +curl_get "$gns_link/www1.$TEST_TLD" "1.1.1.1" -gnunet-namestore -z "test_plugin_rest_gns" -p -a -n www1 -e 1d -V 1.1.1.1 -t A -curl_get "$gns_link/www1.test_plugin_rest_gns" "1.1.1.1" +gnunet-namestore -z "$TEST_TLD" -d -n www1 -c test_gns_lookup.conf +gnunet-namestore -z "$TEST_TLD" -d -n www -c test_gns_lookup.conf -gnunet-identity -D "test_plugin_rest_gns" > /dev/null 2>&1 +gnunet-identity -D "$TEST_TLD" -c test_gns_lookup.conf > /dev/null 2>&1 -curl_get "$gns_link/www1.test_plugin_rest_gns" "error" +curl_get "$gns_link/www1.$TEST_TLD" "error" exit 0 diff --git a/src/util/gnunet-service-resolver.c b/src/util/gnunet-service-resolver.c index 23ba39fee..d7d456fba 100644 --- a/src/util/gnunet-service-resolver.c +++ b/src/util/gnunet-service-resolver.c @@ -642,9 +642,9 @@ try_cache (const char *hostname, const struct GNUNET_DNSPARSER_Record *record = rle->record; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Found cache entry for '%s', record type '%u'\n", + "Checking cache entry for '%s', record is for '%s'\n", hostname, - record_type); + record->name); if ((GNUNET_DNSPARSER_TYPE_CNAME == record->type) && (GNUNET_DNSPARSER_TYPE_CNAME != record_type) && (GNUNET_NO == found)) { @@ -653,7 +653,8 @@ try_cache (const char *hostname, process_get (hostname, record_type, client_request_id, client); return GNUNET_YES; /* counts as a cache "hit" */ } - found |= send_reply (rle->record, record_type, client_request_id, client); + if (0 == strcmp (record->name, hostname)) + found |= send_reply (rle->record, record_type, client_request_id, client); } if (GNUNET_NO == found) return GNUNET_NO; /* had records, but none matched! */ @@ -723,6 +724,9 @@ cache_answers (const char *name, { rc = GNUNET_new (struct ResolveCache); rc->hostname = GNUNET_strdup (name); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Caching record for name %s under %s\n", + record->name, name); GNUNET_CONTAINER_DLL_insert (cache_head, cache_tail, rc); cache_size++; } -- cgit v1.2.3 From 47ab1ded5ef79da36c4e769fae7fba2af84405d7 Mon Sep 17 00:00:00 2001 From: "Schanzenbach, Martin" Date: Fri, 11 Oct 2019 16:17:23 +0200 Subject: add namestore rest tests --- src/gns/test_plugin_rest_gns.sh | 7 +- src/namestore/Makefile.am | 7 + src/namestore/test_plugin_rest_namestore.sh | 195 +++++++++++++--------------- 3 files changed, 101 insertions(+), 108 deletions(-) diff --git a/src/gns/test_plugin_rest_gns.sh b/src/gns/test_plugin_rest_gns.sh index 09f155e01..da46330d6 100755 --- a/src/gns/test_plugin_rest_gns.sh +++ b/src/gns/test_plugin_rest_gns.sh @@ -23,7 +23,7 @@ curl_get () { #$1 is link #$2 is grep cache="$(gnurl -v "$1" 2>&1 | grep "$2")" - echo "$cache" + #echo "$cache" if [ "" == "$cache" ] then gnunet-identity -D "$TEST_TLD" -c test_gns_lookup.conf > /dev/null 2>&1 @@ -34,9 +34,6 @@ curl_get () { TEST_TLD="testtld" gnunet-arm -s -c test_gns_lookup.conf -gnunet-arm -I -gnunet-identity -D "$TEST_TLD" -c test_gns_lookup.conf > /dev/null 2>&1 - curl_get "$gns_link/www.$TEST_TLD" "error" gnunet-identity -C "$TEST_TLD" -c test_gns_lookup.conf @@ -67,5 +64,5 @@ gnunet-namestore -z "$TEST_TLD" -d -n www -c test_gns_lookup.conf gnunet-identity -D "$TEST_TLD" -c test_gns_lookup.conf > /dev/null 2>&1 curl_get "$gns_link/www1.$TEST_TLD" "error" - +gnunet-arm -e -c -c test_gns_lookup.conf exit 0 diff --git a/src/namestore/Makefile.am b/src/namestore/Makefile.am index b9fa83103..646effd9b 100644 --- a/src/namestore/Makefile.am +++ b/src/namestore/Makefile.am @@ -681,6 +681,13 @@ check_SCRIPTS = \ test_namestore_lookup.sh \ test_namestore_delete.sh +if HAVE_MHD +if HAVE_JSON +check_SCRIPTS += \ + test_plugin_rest_namestore.sh +endif +endif + EXTRA_DIST = \ test_common.c \ test_namestore_api.conf \ diff --git a/src/namestore/test_plugin_rest_namestore.sh b/src/namestore/test_plugin_rest_namestore.sh index 532c7caae..f3a4b7c49 100755 --- a/src/namestore/test_plugin_rest_namestore.sh +++ b/src/namestore/test_plugin_rest_namestore.sh @@ -1,44 +1,65 @@ -#!/usr/bin/bash +#!/bin/sh +trap "gnunet-arm -e -c test_gns_lookup.conf" SIGINT -#First, start gnunet-arm and the rest-service. -#Exit 0 means success, exit 1 means failed test +LOCATION=$(which gnunet-config) +if [ -z $LOCATION ] +then + LOCATION="gnunet-config" +fi +$LOCATION --version 1> /dev/null +if test $? != 0 +then + echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" + exit 77 +fi + +rm -rf `gnunet-config -c test_namestore_api.conf -f -s paths -o GNUNET_TEST_HOME` namestore_link="http://localhost:7776/namestore" wrong_link="http://localhost:7776/namestoreandmore" curl_get () { - #$1 is link - #$2 is grep - cache="$(curl -v "$1" 2>&1 | grep "$2")" - echo $cache - if [ "" == "$cache" ] - then - exit 1 - fi + #$1 is link + #$2 is grep + resp=$(curl -v "$1" 2>&1) + cache="$(echo $resp | grep "$2")" + #echo $cache + if [ "" == "$cache" ] + then + echo "Error in get response: $resp, expected $2" + gnunet-arm -e -c test_namestore_api.conf + exit 1 + fi } curl_post () { - #$1 is link - #$2 is data - #$3 is grep - cache="$(curl -v -X "POST" "$1" --data "$2" 2>&1 | grep "$3")" - echo $cache - if [ "" == "$cache" ] - then - exit 1 - fi + #$1 is link + #$2 is data + #$3 is grep + resp=$(curl -v -X "POST" "$1" --data "$2" 2>&1) + cache="$(echo $resp | grep "$3")" + #echo $cache + if [ "" == "$cache" ] + then + echo "Error in post response: $resp ($2), expected $3" + gnunet-arm -e -c test_namestore_api.conf + exit 1 + fi } curl_delete () { - #$1 is link - #$2 is grep - cache="$(curl -v -X "DELETE" "$1" 2>&1 | grep "$2")" - echo $cache - if [ "" == "$cache" ] - then - exit 1 - fi + #$1 is link + #$2 is grep + resp=$(curl -v -X "DELETE" "$1" 2>&1) + cache="$(echo $resp | grep "$2")" + #echo $cache + if [ "" == "$cache" ] + then + echo "Error in delete response: $resp, expected $2" + gnunet-arm -e -c test_namestore_api.conf + exit 1 + fi } # curl_put () { @@ -55,93 +76,61 @@ curl_delete () { #Test subsystem default identity +TEST_ID="test" +gnunet-arm -s -c test_namestore_api.conf +gnunet-arm -i rest -c test_namestore_api.conf #Test GET -gnunet-identity -D "test_plugin_rest_namestore" -gnunet-identity -C "test_plugin_rest_namestore" -test="$(gnunet-namestore -D -z "test_plugin_rest_namestore")" -name="test_plugin_rest_namestore" -public="$(gnunet-identity -d | grep "test_plugin_rest_namestore" | awk 'NR==1{print $3}')" -if [ "" == "$test" ] -then - #if no entries for test_plugin_rest_namestore - curl_get "${namestore_link}/$name" "error" - curl_get "${namestore_link}/" "error" - curl_get "${namestore_link}/$public" "error" -else - #if entries exists (that should not be possible) - curl_get "${namestore_link}" "HTTP/1.1 200 OK" - curl_get "${namestore_link}/$name" "HTTP/1.1 200 OK" - curl_get "${namestore_link}/" "error" - curl_get "${namestore_link}/$public" "error" -fi -gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY" +gnunet-identity -C $TEST_ID -c test_namestore_api.conf +test="$(gnunet-namestore -D -z $TEST_ID -c test_namestore_api.conf)" +name=$TEST_ID +public="$(gnunet-identity -d -c test_namestore_api.conf | grep $TEST_ID | awk 'NR==1{print $3}')" +gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY" -c test_namestore_api.conf curl_get "${namestore_link}" "HTTP/1.1 200 OK" curl_get "${namestore_link}/$name" "HTTP/1.1 200 OK" -curl_get "${namestore_link}/" "error" curl_get "${namestore_link}/$public" "error" -gnunet-namestore -z $name -d -n "test_entry" +gnunet-namestore -z $name -d -n "test_entry" -c test_namestore_api.conf #Test POST with NAME -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -#value -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value_missing":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -#time -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"0d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"10000d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"now","flag":0,"record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"","flag":0,"record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time_missing":"1d","flag":0,"record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -#flag -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":2,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":8,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":16,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":-1,"record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":"Test","record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":,"record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag_missing":0,"record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 +curl_post "${namestore_link}/$name" '{"data": [{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0}],"record_name":"test_entry"}' "HTTP/1.1 204 No Content" +gnunet-namestore -z $name -d -n "test_entry" -c test_namestore_api.conf > /dev/null 2>&1 + +# invalid values +curl_post "${namestore_link}/$name" '{"data": [{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRGxxx", "record_type":"PKEY", "expiration_time":"1d","flag":0}],"record_name":"test_entry"}' "error" +gnunet-namestore -z $name -d -n "test_entry" -c test_namestore_api.conf > /dev/null 2>&1 + + +curl_post "${namestore_link}/$name" '{"data": [{"value":"", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name"}]:"test_entry"}' "error" +gnunet-namestore -z $name -d -n "test_entry" -c test_namestore_api.conf > /dev/null 2>&1 + +curl_post "${namestore_link}/$name" '{"data": [{"record_type":"PKEY", "expiration_time":"1d","flag":0}],"record_name":"test_entry"}' "error" +gnunet-namestore -z $name -d -n "test_entry" -c test_namestore_api.conf > /dev/null 2>&1 + +#expirations +curl_post "${namestore_link}/$name" '{"data": [{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"0d","flag":0}],"record_name":"test_entry"}' "HTTP/1.1 204" +gnunet-namestore -z $name -d -n "test_entry" -c test_namestore_api.conf > /dev/null 2>&1 + +curl_post "${namestore_link}/$name" '{"data": [{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"10000d","flag":0}],"record_name":"test_entry"}' "HTTP/1.1 204" +gnunet-namestore -z $name -d -n "test_entry" -c test_namestore_api.conf > /dev/null 2>&1 + +curl_post "${namestore_link}/$name" '{"data": [{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"now","flag":0}],"record_name":"test_entry"}' "error" +gnunet-namestore -z $name -d -n "test_entry" -c test_namestore_api.conf > /dev/null 2>&1 + +curl_post "${namestore_link}/$name" '{"data": [{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time_missing":"1d","flag":0}],"record_name":"test_entry"}' "error" +gnunet-namestore -z $name -d -n "test_entry" -c test_namestore_api.conf > /dev/null 2>&1 + #record_name -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "HTTP/1.1 204 No Content" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":""}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 -curl_post "${namestore_link}/$name" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name_missing":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 - -#wrong zone -curl_post "${namestore_link}/$public" '{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0,"record_name":"test_entry"}' "error" -gnunet-namestore -z $name -d -n "test_entry" > /dev/null 2>&1 +curl_post "${namestore_link}/$name" '{"data": [{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0}],"record_name":""}' "error" +gnunet-namestore -z $name -d -n "test_entry" -c test_namestore_api.conf > /dev/null 2>&1 +curl_post "${namestore_link}/$name" '{"data": [{"value":"HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG", "record_type":"PKEY", "expiration_time":"1d","flag":0}],"record_name_missing":"test_entry"}' "error" +gnunet-namestore -z $name -d -n "test_entry" -c test_namestore_api.conf > /dev/null 2>&1 #Test DELETE -gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY" +gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY" -c test_namestore_api.conf curl_delete "${namestore_link}/$name?record_name=test_entry" "HTTP/1.1 204" curl_delete "${namestore_link}/$name?record_name=test_entry" "error" -gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY" +gnunet-namestore -z $name -p -a -n "test_entry" -e "1d" -V "HVX38H2CB7WJM0WCPWT9CFX6GASMYJVR65RN75SJSSKAYVYXHMRG" -t "PKEY" -c test_namestore_api.conf curl_delete "${namestore_link}/$public?record_name=test_entry" "error" - -#Test default identity -#not possible without defining - +gnunet-arm -e -c test_namestore_api.conf exit 0; -- cgit v1.2.3 From f4636ad9ec863234f11c3118c9341d82d6debf66 Mon Sep 17 00:00:00 2001 From: "Schanzenbach, Martin" Date: Fri, 11 Oct 2019 18:35:28 +0200 Subject: make test compatible with macos --- src/namestore/test_plugin_namestore.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/namestore/test_plugin_namestore.c b/src/namestore/test_plugin_namestore.c index a3d9f44c4..a0490fd9c 100644 --- a/src/namestore/test_plugin_namestore.c +++ b/src/namestore/test_plugin_namestore.c @@ -167,8 +167,9 @@ run (void *cls, } put_record (nsp, 1); get_record (nsp, 1); - +#ifndef DARWIN unload_plugin (nsp); +#endif } -- cgit v1.2.3 From 0c6bb9dd10c6ef0a15573a7863dba99c491a1ee6 Mon Sep 17 00:00:00 2001 From: "Schanzenbach, Martin" Date: Fri, 11 Oct 2019 18:35:56 +0200 Subject: add bug ref --- src/namestore/test_plugin_namestore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/namestore/test_plugin_namestore.c b/src/namestore/test_plugin_namestore.c index a0490fd9c..03b1a21e4 100644 --- a/src/namestore/test_plugin_namestore.c +++ b/src/namestore/test_plugin_namestore.c @@ -167,7 +167,7 @@ run (void *cls, } put_record (nsp, 1); get_record (nsp, 1); -#ifndef DARWIN +#ifndef DARWIN // #5582 unload_plugin (nsp); #endif } -- cgit v1.2.3 From 1e023a539b4f0b9f68ae6948d3328eafb7ba49e2 Mon Sep 17 00:00:00 2001 From: "Schanzenbach, Martin" Date: Fri, 11 Oct 2019 19:11:06 +0200 Subject: fix non deterministic test --- src/peerstore/test_peerstore_api_data.conf | 3 ++- src/peerstore/test_peerstore_api_sync.c | 29 +++++++++++++++-------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/peerstore/test_peerstore_api_data.conf b/src/peerstore/test_peerstore_api_data.conf index 3ebda50eb..614d0cf5b 100644 --- a/src/peerstore/test_peerstore_api_data.conf +++ b/src/peerstore/test_peerstore_api_data.conf @@ -5,8 +5,9 @@ GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-peerstore START_ON_DEMAND = YES BINARY = gnunet-service-peerstore UNIXPATH = $GNUNET_TMP/gnunet-service-peerstore.sock -HOME = $SERVICEHOME DATABASE = sqlite +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES #PREFIX = xterm -e gdb --args [peerstore-sqlite] diff --git a/src/peerstore/test_peerstore_api_sync.c b/src/peerstore/test_peerstore_api_sync.c index b2ac860b7..503cb2f1e 100644 --- a/src/peerstore/test_peerstore_api_sync.c +++ b/src/peerstore/test_peerstore_api_sync.c @@ -109,7 +109,6 @@ iterate_cb (void *cls, static void test_cont (void *cls) { - h = GNUNET_PEERSTORE_connect (cfg); GNUNET_PEERSTORE_iterate (h, subsystem, &pid, key, @@ -117,6 +116,19 @@ test_cont (void *cls) NULL); } +static void +store_cont (void *cls, int success) +{ + ok = success; + /* We need to wait a little bit to give the disconnect + a chance to actually finish the operation; otherwise, + the test may fail non-deterministically if the new + connection is faster than the cleanup routine of the + old one. */ + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &test_cont, + NULL); +} /** * Actually run the test. @@ -132,18 +144,7 @@ test1 () val, strlen (val) + 1, GNUNET_TIME_UNIT_FOREVER_ABS, GNUNET_PEERSTORE_STOREOPTION_REPLACE, - NULL, NULL); - GNUNET_PEERSTORE_disconnect (h, - GNUNET_YES); - h = NULL; - /* We need to wait a little bit to give the disconnect - a chance to actually finish the operation; otherwise, - the test may fail non-deterministically if the new - connection is faster than the cleanup routine of the - old one. */ - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, - &test_cont, - NULL); + &store_cont, NULL); } @@ -171,7 +172,7 @@ main (int argc, char *argv[]) if (0 != GNUNET_TESTING_service_run ("test-gnunet-peerstore-sync", "peerstore", - "test_peerstore_api_data.conf", + "peerstore.conf", &run, NULL)) return 1; if (0 != ok) -- cgit v1.2.3 From 8ed3ad85fa8c0faa213157610379d69875b10ccb Mon Sep 17 00:00:00 2001 From: "Schanzenbach, Martin" Date: Fri, 11 Oct 2019 21:37:41 +0200 Subject: we probably want to actually test the sync --- src/peerstore/test_peerstore_api_sync.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/peerstore/test_peerstore_api_sync.c b/src/peerstore/test_peerstore_api_sync.c index 503cb2f1e..bfeae6ed8 100644 --- a/src/peerstore/test_peerstore_api_sync.c +++ b/src/peerstore/test_peerstore_api_sync.c @@ -109,6 +109,7 @@ iterate_cb (void *cls, static void test_cont (void *cls) { + h = GNUNET_PEERSTORE_connect (cfg); GNUNET_PEERSTORE_iterate (h, subsystem, &pid, key, @@ -116,6 +117,16 @@ test_cont (void *cls) NULL); } +static void +disc_cont (void *cls) +{ + GNUNET_PEERSTORE_disconnect (h, GNUNET_YES); + h = NULL; + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &test_cont, + NULL); +} + static void store_cont (void *cls, int success) { @@ -125,9 +136,8 @@ store_cont (void *cls, int success) the test may fail non-deterministically if the new connection is faster than the cleanup routine of the old one. */ - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, - &test_cont, - NULL); + GNUNET_SCHEDULER_add_now (&disc_cont, + NULL); } /** -- cgit v1.2.3 From e3e21acb23283915c97e6ef1c167325f4592665c Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 11 Oct 2019 20:55:59 +0200 Subject: libgnunetpq API change to fix #5733 --- src/datacache/plugin_datacache_postgres.c | 25 +--- src/datastore/plugin_datastore_postgres.c | 20 +--- src/include/gnunet_pq_lib.h | 133 ++++++++++++++------- src/namecache/plugin_namecache_postgres.c | 38 ++---- src/namestore/plugin_namestore_postgres.c | 64 +++------- src/pq/Makefile.am | 2 +- src/pq/pq.c | 43 ++++--- src/pq/pq.h | 57 +++++++++ src/pq/pq_connect.c | 169 ++++++++++++++++++++++----- src/pq/pq_eval.c | 59 ++++++---- src/pq/pq_exec.c | 15 ++- src/pq/pq_prepare.c | 39 +++++-- src/pq/pq_result_helper.c | 2 +- src/pq/test_pq.c | 186 +++++++++++++++--------------- 14 files changed, 517 insertions(+), 335 deletions(-) create mode 100644 src/pq/pq.h diff --git a/src/datacache/plugin_datacache_postgres.c b/src/datacache/plugin_datacache_postgres.c index 59dff9067..c532550ae 100644 --- a/src/datacache/plugin_datacache_postgres.c +++ b/src/datacache/plugin_datacache_postgres.c @@ -48,7 +48,7 @@ struct Plugin /** * Native Postgres database handle. */ - PGconn *dbh; + struct GNUNET_PQ_Context *dbh; /** * Number of key-value pairs in the database. @@ -122,26 +122,11 @@ init_connection (struct Plugin *plugin) }; plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->env->cfg, - "datacache-postgres"); + "datacache-postgres", + es, + ps); if (NULL == plugin->dbh) return GNUNET_SYSERR; - if (GNUNET_OK != - GNUNET_PQ_exec_statements (plugin->dbh, - es)) - { - PQfinish (plugin->dbh); - plugin->dbh = NULL; - return GNUNET_SYSERR; - } - - if (GNUNET_OK != - GNUNET_PQ_prepare_statements (plugin->dbh, - ps)) - { - PQfinish (plugin->dbh); - plugin->dbh = NULL; - return GNUNET_SYSERR; - } return GNUNET_OK; } @@ -710,7 +695,7 @@ libgnunet_plugin_datacache_postgres_done (void *cls) struct GNUNET_DATACACHE_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; - PQfinish (plugin->dbh); + GNUNET_PQ_disconnect (plugin->dbh); GNUNET_free (plugin); GNUNET_free (api); return NULL; diff --git a/src/datastore/plugin_datastore_postgres.c b/src/datastore/plugin_datastore_postgres.c index 181cf8cf8..0811edfd7 100644 --- a/src/datastore/plugin_datastore_postgres.c +++ b/src/datastore/plugin_datastore_postgres.c @@ -54,7 +54,7 @@ struct Plugin /** * Native Postgres database handle. */ - PGconn *dbh; + struct GNUNET_PQ_Context *dbh; }; @@ -172,21 +172,11 @@ init_connection (struct Plugin *plugin) #undef RESULT_COLUMNS plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->env->cfg, - "datastore-postgres"); + "datastore-postgres", + es, + ps); if (NULL == plugin->dbh) return GNUNET_SYSERR; - - if ((GNUNET_OK != - GNUNET_PQ_exec_statements (plugin->dbh, - es)) || - (GNUNET_OK != - GNUNET_PQ_prepare_statements (plugin->dbh, - ps))) - { - PQfinish (plugin->dbh); - plugin->dbh = NULL; - return GNUNET_SYSERR; - } return GNUNET_OK; } @@ -974,7 +964,7 @@ libgnunet_plugin_datastore_postgres_done (void *cls) struct GNUNET_DATASTORE_PluginFunctions *api = cls; struct Plugin *plugin = api->cls; - PQfinish (plugin->dbh); + GNUNET_PQ_disconnect (plugin->dbh); GNUNET_free (plugin); GNUNET_free (api); return NULL; diff --git a/src/include/gnunet_pq_lib.h b/src/include/gnunet_pq_lib.h index 6c576c8ab..a56df21fd 100644 --- a/src/include/gnunet_pq_lib.h +++ b/src/include/gnunet_pq_lib.h @@ -46,15 +46,16 @@ * @param scratch_length number of entries left in @a scratch * @return -1 on error, number of offsets used in @a scratch otherwise */ -typedef int (*GNUNET_PQ_QueryConverter) (void *cls, - const void *data, - size_t data_len, - void *param_values[], - int param_lengths[], - int param_formats[], - unsigned int param_length, - void *scratch[], - unsigned int scratch_length); +typedef int +(*GNUNET_PQ_QueryConverter) (void *cls, + const void *data, + size_t data_len, + void *param_values[], + int param_lengths[], + int param_formats[], + unsigned int param_length, + void *scratch[], + unsigned int scratch_length); /** @@ -214,12 +215,13 @@ GNUNET_PQ_query_param_uint64 (const uint64_t *x); * #GNUNET_YES if all results could be extracted * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL) */ -typedef int (*GNUNET_PQ_ResultConverter) (void *cls, - PGresult *result, - int row, - const char *fname, - size_t *dst_size, - void *dst); +typedef int +(*GNUNET_PQ_ResultConverter) (void *cls, + PGresult *result, + int row, + const char *fname, + size_t *dst_size, + void *dst); /** @@ -229,7 +231,9 @@ typedef int (*GNUNET_PQ_ResultConverter) (void *cls, * @param cls closure * @param rd result data to clean up */ -typedef void (*GNUNET_PQ_ResultCleanup) (void *cls, void *rd); +typedef void +(*GNUNET_PQ_ResultCleanup) (void *cls, + void *rd); /** @@ -419,17 +423,23 @@ GNUNET_PQ_result_spec_uint64 (const char *name, uint64_t *u64); /* ************************* pq.c functions ************************ */ +/** + * Postgres context. + */ +struct GNUNET_PQ_Context; + + /** * Execute a prepared statement. * - * @param db_conn database connection + * @param db database context * @param name name of the prepared statement * @param params parameters to the statement * @return postgres result * @deprecated (should become an internal API) */ PGresult * -GNUNET_PQ_exec_prepared (PGconn *db_conn, +GNUNET_PQ_exec_prepared (struct GNUNET_PQ_Context *db, const char *name, const struct GNUNET_PQ_QueryParam *params); @@ -468,7 +478,7 @@ GNUNET_PQ_cleanup_result (struct GNUNET_PQ_ResultSpec *rs); * Check the @a result's error code to see what happened. * Also logs errors. * - * @param connection connection to execute the statement in + * @param db database to execute the statement in * @param statement_name name of the statement that created @a result * @param result result to check * @return status code from the result, mapping PQ status @@ -478,7 +488,7 @@ GNUNET_PQ_cleanup_result (struct GNUNET_PQ_ResultSpec *rs); * @deprecated (low level, let's see if we can do with just the high-level functions) */ enum GNUNET_DB_QueryStatus -GNUNET_PQ_eval_result (PGconn *connection, +GNUNET_PQ_eval_result (struct GNUNET_PQ_Context *db, const char *statement_name, PGresult *result); @@ -488,7 +498,7 @@ GNUNET_PQ_eval_result (PGconn *connection, * statement in @a connnection using the given @a params. Returns the * resulting session state. * - * @param connection connection to execute the statement in + * @param db database to execute the statement with * @param statement_name name of the statement * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) * @return status code from the result, mapping PQ status @@ -500,7 +510,7 @@ GNUNET_PQ_eval_result (PGconn *connection, * zero; if INSERT was successful, we return one. */ enum GNUNET_DB_QueryStatus -GNUNET_PQ_eval_prepared_non_select (PGconn *connection, +GNUNET_PQ_eval_prepared_non_select (struct GNUNET_PQ_Context *db, const char *statement_name, const struct GNUNET_PQ_QueryParam *params); @@ -513,9 +523,10 @@ GNUNET_PQ_eval_prepared_non_select (PGconn *connection, * @param result the postgres result * @param num_result the number of results in @a result */ -typedef void (*GNUNET_PQ_PostgresResultHandler) (void *cls, - PGresult *result, - unsigned int num_results); +typedef void +(*GNUNET_PQ_PostgresResultHandler) (void *cls, + PGresult *result, + unsigned int num_results); /** @@ -525,7 +536,7 @@ typedef void (*GNUNET_PQ_PostgresResultHandler) (void *cls, * status including the number of results given to @a rh (possibly zero). * @a rh will not have been called if the return value is negative. * - * @param connection connection to execute the statement in + * @param db database to execute the statement with * @param statement_name name of the statement * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) * @param rh function to call with the result set, NULL to ignore @@ -534,7 +545,7 @@ typedef void (*GNUNET_PQ_PostgresResultHandler) (void *cls, * codes to `enum GNUNET_DB_QueryStatus`. */ enum GNUNET_DB_QueryStatus -GNUNET_PQ_eval_prepared_multi_select (PGconn *connection, +GNUNET_PQ_eval_prepared_multi_select (struct GNUNET_PQ_Context *db, const char *statement_name, const struct GNUNET_PQ_QueryParam *params, GNUNET_PQ_PostgresResultHandler rh, @@ -549,7 +560,7 @@ GNUNET_PQ_eval_prepared_multi_select (PGconn *connection, * value was #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT. Returns the * resulting session status. * - * @param connection connection to execute the statement in + * @param db database to execute the statement with * @param statement_name name of the statement * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) * @param[in,out] rs result specification to use for storing the result of the query @@ -557,11 +568,11 @@ GNUNET_PQ_eval_prepared_multi_select (PGconn *connection, * codes to `enum GNUNET_DB_QueryStatus`. */ enum GNUNET_DB_QueryStatus -GNUNET_PQ_eval_prepared_singleton_select ( - PGconn *connection, - const char *statement_name, - const struct GNUNET_PQ_QueryParam *params, - struct GNUNET_PQ_ResultSpec *rs); +GNUNET_PQ_eval_prepared_singleton_select (struct GNUNET_PQ_Context *db, + const char *statement_name, + const struct + GNUNET_PQ_QueryParam *params, + struct GNUNET_PQ_ResultSpec *rs); /* ******************** pq_prepare.c functions ************** */ @@ -587,6 +598,7 @@ struct GNUNET_PQ_PreparedStatement * Number of arguments included in @e sql. */ unsigned int num_arguments; + }; @@ -616,14 +628,14 @@ GNUNET_PQ_make_prepare (const char *name, /** * Request creation of prepared statements @a ps from Postgres. * - * @param connection connection to prepare the statements for + * @param db database to prepare the statements for * @param ps #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared * statements. * @return #GNUNET_OK on success, * #GNUNET_SYSERR on error */ int -GNUNET_PQ_prepare_statements (PGconn *connection, +GNUNET_PQ_prepare_statements (struct GNUNET_PQ_Context *db, const struct GNUNET_PQ_PreparedStatement *ps); @@ -681,14 +693,14 @@ GNUNET_PQ_make_try_execute (const char *sql); /** * Request execution of an array of statements @a es from Postgres. * - * @param connection connection to execute the statements over + * @param pq database to execute the statements in * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared * statements. * @return #GNUNET_OK on success (modulo statements where errors can be ignored) * #GNUNET_SYSERR on error */ int -GNUNET_PQ_exec_statements (PGconn *connection, +GNUNET_PQ_exec_statements (struct GNUNET_PQ_Context *db, const struct GNUNET_PQ_ExecuteStatement *es); @@ -698,26 +710,61 @@ GNUNET_PQ_exec_statements (PGconn *connection, /** * Create a connection to the Postgres database using @a config_str * for the configuration. Initialize logging via GNUnet's log - * routines and disable Postgres's logger. + * routines and disable Postgres's logger. Also ensures that the + * statements in @a es are executed whenever we (re)connect to the + * database, and that the prepared statements in @a ps are "ready". + * If statements in @es fail that were created with + * #GNUNET_PQ_make_execute(), then the entire operation fails. * * @param config_str configuration to use + * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated + * array of statements to execute upon EACH connection, can be NULL + * @param ps array of prepared statements to prepare, can be NULL * @return NULL on error */ -PGconn * -GNUNET_PQ_connect (const char *config_str); +struct GNUNET_PQ_Context * +GNUNET_PQ_connect (const char *config_str, + const struct GNUNET_PQ_ExecuteStatement *es, + const struct GNUNET_PQ_PreparedStatement *ps); /** * Connect to a postgres database using the configuration - * option "CONFIG" in @a section. + * option "CONFIG" in @a section. Also ensures that the + * statements in @a es are executed whenever we (re)connect to the + * database, and that the prepared statements in @a ps are "ready". * * @param cfg configuration * @param section configuration section to use to get Postgres configuration options + * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated + * array of statements to execute upon EACH connection, can be NULL + * @param ps array of prepared statements to prepare, can be NULL * @return the postgres handle, NULL on error */ -PGconn * +struct GNUNET_PQ_Context * GNUNET_PQ_connect_with_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, - const char *section); + const char *section, + const struct GNUNET_PQ_ExecuteStatement *es, + const struct GNUNET_PQ_PreparedStatement *ps); + + +/** + * Reinitialize the database @a db. + * + * @param db database connection to reinitialize + */ +void +GNUNET_PQ_reconnect (struct GNUNET_PQ_Context *db); + + +/** + * Disconnect from the database, destroying the prepared statements + * and releasing other associated resources. + * + * @param db database handle to disconnect (will be free'd) + */ +void +GNUNET_PQ_disconnect (struct GNUNET_PQ_Context *db); #endif /* GNUNET_PQ_LIB_H_ */ diff --git a/src/namecache/plugin_namecache_postgres.c b/src/namecache/plugin_namecache_postgres.c index e4b360ef2..35bf5c2ff 100644 --- a/src/namecache/plugin_namecache_postgres.c +++ b/src/namecache/plugin_namecache_postgres.c @@ -42,9 +42,9 @@ struct Plugin const struct GNUNET_CONFIGURATION_Handle *cfg; /** - * Native Postgres database handle. + * Postgres database handle. */ - PGconn *dbh; + struct GNUNET_PQ_Context *dbh; }; @@ -75,10 +75,6 @@ database_setup (struct Plugin *plugin) "WITH OIDS"); const struct GNUNET_PQ_ExecuteStatement *cr; - plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg, - "namecache-postgres"); - if (NULL == plugin->dbh) - return GNUNET_SYSERR; if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg, "namecache-postgres", @@ -90,7 +86,6 @@ database_setup (struct Plugin *plugin) { cr = &es_default; } - { struct GNUNET_PQ_ExecuteStatement es[] = { *cr, @@ -100,18 +95,6 @@ database_setup (struct Plugin *plugin) "CREATE INDEX ir_block_expiration ON ns096blocks (expiration_time)"), GNUNET_PQ_EXECUTE_STATEMENT_END }; - - if (GNUNET_OK != - GNUNET_PQ_exec_statements (plugin->dbh, - es)) - { - PQfinish (plugin->dbh); - plugin->dbh = NULL; - return GNUNET_SYSERR; - } - } - - { struct GNUNET_PQ_PreparedStatement ps[] = { GNUNET_PQ_make_prepare ("cache_block", "INSERT INTO ns096blocks (query, block, expiration_time) VALUES " @@ -128,16 +111,13 @@ database_setup (struct Plugin *plugin) GNUNET_PQ_PREPARED_STATEMENT_END }; - if (GNUNET_OK != - GNUNET_PQ_prepare_statements (plugin->dbh, - ps)) - { - PQfinish (plugin->dbh); - plugin->dbh = NULL; - return GNUNET_SYSERR; - } + plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg, + "namecache-postgres", + es, + ps); } - + if (NULL == plugin->dbh) + return GNUNET_SYSERR; return GNUNET_OK; } @@ -311,7 +291,7 @@ namecache_postgres_lookup_block (void *cls, static void database_shutdown (struct Plugin *plugin) { - PQfinish (plugin->dbh); + GNUNET_PQ_disconnect (plugin->dbh); plugin->dbh = NULL; } diff --git a/src/namestore/plugin_namestore_postgres.c b/src/namestore/plugin_namestore_postgres.c index 5148ca0f5..23893538b 100644 --- a/src/namestore/plugin_namestore_postgres.c +++ b/src/namestore/plugin_namestore_postgres.c @@ -45,9 +45,9 @@ struct Plugin const struct GNUNET_CONFIGURATION_Handle *cfg; /** - * Native Postgres database handle. + * Postgres database handle. */ - PGconn *dbh; + struct GNUNET_PQ_Context *dbh; }; @@ -88,30 +88,8 @@ database_setup (struct Plugin *plugin) ")" "WITH OIDS"); const struct GNUNET_PQ_ExecuteStatement *cr; + struct GNUNET_PQ_ExecuteStatement sc = GNUNET_PQ_EXECUTE_STATEMENT_END; - plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg, - "namestore-postgres"); - if (NULL == plugin->dbh) - return GNUNET_SYSERR; - if (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg, - "namestore-postgres", - "ASYNC_COMMIT")) - { - struct GNUNET_PQ_ExecuteStatement es[] = { - GNUNET_PQ_make_try_execute ("SET synchronous_commit TO off"), - GNUNET_PQ_EXECUTE_STATEMENT_END - }; - - if (GNUNET_OK != - GNUNET_PQ_exec_statements (plugin->dbh, - es)) - { - PQfinish (plugin->dbh); - plugin->dbh = NULL; - return GNUNET_SYSERR; - } - } if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg, "namestore-postgres", @@ -124,6 +102,12 @@ database_setup (struct Plugin *plugin) cr = &es_default; } + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg, + "namestore-postgres", + "ASYNC_COMMIT")) + sc = GNUNET_PQ_make_try_execute ("SET synchronous_commit TO off"); + { struct GNUNET_PQ_ExecuteStatement es[] = { *cr, @@ -135,20 +119,9 @@ database_setup (struct Plugin *plugin) "ON ns098records (label)"), GNUNET_PQ_make_try_execute ("CREATE INDEX IF NOT EXISTS zone_label " "ON ns098records (zone_private_key,label)"), + sc, GNUNET_PQ_EXECUTE_STATEMENT_END }; - - if (GNUNET_OK != - GNUNET_PQ_exec_statements (plugin->dbh, - es)) - { - PQfinish (plugin->dbh); - plugin->dbh = NULL; - return GNUNET_SYSERR; - } - } - - { struct GNUNET_PQ_PreparedStatement ps[] = { GNUNET_PQ_make_prepare ("store_records", "INSERT INTO ns098records" @@ -183,16 +156,13 @@ database_setup (struct Plugin *plugin) GNUNET_PQ_PREPARED_STATEMENT_END }; - if (GNUNET_OK != - GNUNET_PQ_prepare_statements (plugin->dbh, - ps)) - { - PQfinish (plugin->dbh); - plugin->dbh = NULL; - return GNUNET_SYSERR; - } + plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg, + "namestore-postgres", + es, + ps); } - + if (NULL == plugin->dbh) + return GNUNET_SYSERR; return GNUNET_OK; } @@ -593,7 +563,7 @@ namestore_postgres_zone_to_name (void *cls, static void database_shutdown (struct Plugin *plugin) { - PQfinish (plugin->dbh); + GNUNET_PQ_disconnect (plugin->dbh); plugin->dbh = NULL; } diff --git a/src/pq/Makefile.am b/src/pq/Makefile.am index 9270e6fe0..750a1d48d 100644 --- a/src/pq/Makefile.am +++ b/src/pq/Makefile.am @@ -22,7 +22,7 @@ libgnunetpq_la_LIBADD = -lpq \ libgnunetpq_la_LDFLAGS = \ $(POSTGRESQL_LDFLAGS) \ $(GN_LIB_LDFLAGS) \ - -version-info 0:0:0 + -version-info 1:0:0 if ENABLE_TEST_RUN TESTS = \ diff --git a/src/pq/pq.c b/src/pq/pq.c index 7e97c8f72..d2b9a6174 100644 --- a/src/pq/pq.c +++ b/src/pq/pq.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet - Copyright (C) 2014, 2015, 2016 GNUnet e.V. + Copyright (C) 2014, 2015, 2016, 2017, 2019 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -25,33 +25,30 @@ * @author Christian Grothoff */ #include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_pq_lib.h" - +#include "pq.h" /** * Execute a prepared statement. * - * @param db_conn database connection + * @param db database handle * @param name name of the prepared statement * @param params parameters to the statement * @return postgres result */ PGresult * -GNUNET_PQ_exec_prepared (PGconn *db_conn, +GNUNET_PQ_exec_prepared (struct GNUNET_PQ_Context *db, const char *name, const struct GNUNET_PQ_QueryParam *params) { unsigned int len; - unsigned int i; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running prepared statement `%s' on %p\n", name, - db_conn); + db); /* count the number of parameters */ len = 0; - for (i = 0; 0 != params[i].num_params; i++) + for (unsigned int i = 0; 0 != params[i].num_params; i++) len += params[i].num_params; /* new scope to allow stack allocation without alloca */ @@ -67,10 +64,11 @@ GNUNET_PQ_exec_prepared (PGconn *db_conn, unsigned int soff; PGresult *res; int ret; + ConnStatusType status; off = 0; soff = 0; - for (i = 0; 0 != params[i].num_params; i++) + for (unsigned int i = 0; 0 != params[i].num_params; i++) { const struct GNUNET_PQ_QueryParam *x = ¶ms[i]; @@ -97,13 +95,24 @@ GNUNET_PQ_exec_prepared (PGconn *db_conn, "pq", "Executing prepared SQL statement `%s'\n", name); - res = PQexecPrepared (db_conn, + res = PQexecPrepared (db->conn, name, len, (const char **) param_values, param_lengths, param_formats, 1); + if ( (PGRES_COMMAND_OK != PQresultStatus (res)) && + (CONNECTION_OK != (status = PQstatus (db->conn))) ) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "pq", + "Database disconnected on SQL statement `%s' (reconnecting)\n", + name); + GNUNET_PQ_reconnect (db); + res = NULL; + } + for (off = 0; off < soff; off++) GNUNET_free (scratch[off]); return res; @@ -120,9 +129,7 @@ GNUNET_PQ_exec_prepared (PGconn *db_conn, void GNUNET_PQ_cleanup_result (struct GNUNET_PQ_ResultSpec *rs) { - unsigned int i; - - for (i = 0; NULL != rs[i].conv; i++) + for (unsigned int i = 0; NULL != rs[i].conv; i++) if (NULL != rs[i].cleaner) rs[i].cleaner (rs[i].cls, rs[i].dst); @@ -145,12 +152,12 @@ GNUNET_PQ_extract_result (PGresult *result, struct GNUNET_PQ_ResultSpec *rs, int row) { - unsigned int i; - int ret; - - for (i = 0; NULL != rs[i].conv; i++) + if (NULL == result) + return GNUNET_SYSERR; + for (unsigned int i = 0; NULL != rs[i].conv; i++) { struct GNUNET_PQ_ResultSpec *spec; + int ret; spec = &rs[i]; ret = spec->conv (spec->cls, diff --git a/src/pq/pq.h b/src/pq/pq.h new file mode 100644 index 000000000..b30f4f0d4 --- /dev/null +++ b/src/pq/pq.h @@ -0,0 +1,57 @@ +/* + This file is part of GNUnet + Copyright (C) 2017, 2019 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/** + * @file pq/pq.h + * @brief shared internal data structures of libgnunetpq + * @author Christian Grothoff + */ +#ifndef PQ_H +#define PQ_H + +#include "gnunet_util_lib.h" +#include "gnunet_pq_lib.h" + +/** + * Handle to Postgres database. + */ +struct GNUNET_PQ_Context +{ + /** + * Actual connection. + */ + PGconn *conn; + + /** + * Statements to execute upon connection. + */ + struct GNUNET_PQ_ExecuteStatement *es; + + /** + * Prepared statements. + */ + struct GNUNET_PQ_PreparedStatement *ps; + + /** + * Configuration to use to connect to the DB. + */ + char *config_str; +}; + +#endif diff --git a/src/pq/pq_connect.c b/src/pq/pq_connect.c index 79b9d6107..7599f4b15 100644 --- a/src/pq/pq_connect.c +++ b/src/pq/pq_connect.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet - Copyright (C) 2017 GNUnet e.V. + Copyright (C) 2017, 2019 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -23,8 +23,7 @@ * @author Christian Grothoff */ #include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_pq_lib.h" +#include "pq.h" /** @@ -40,12 +39,14 @@ pq_notice_receiver_cb (void *arg, const PGresult *res) { /* do nothing, intentionally */ + (void) arg; + (void) res; } /** * Function called by libpq whenever it wants to log something. - * We log those using the Taler logger. + * We log those using the GNUnet logger. * * @param arg the SQL connection that was used * @param message information about some libpq event @@ -54,6 +55,7 @@ static void pq_notice_processor_cb (void *arg, const char *message) { + (void) arg; GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "pq", "%s", @@ -64,68 +66,175 @@ pq_notice_processor_cb (void *arg, /** * Create a connection to the Postgres database using @a config_str * for the configuration. Initialize logging via GNUnet's log - * routines and disable Postgres's logger. + * routines and disable Postgres's logger. Also ensures that the + * statements in @a es are executed whenever we (re)connect to the + * database, and that the prepared statements in @a ps are "ready". + * If statements in @es fail that were created with + * #GNUNET_PQ_make_execute(), then the entire operation fails. + * + * The caller MUST ensure that @a es and @a ps remain allocated and + * initialized in memory until #GNUNET_PQ_disconnect() is called, + * as they may be needed repeatedly and no copy will be made. * * @param config_str configuration to use + * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated + * array of statements to execute upon EACH connection, can be NULL + * @param ps array of prepared statements to prepare, can be NULL * @return NULL on error */ -PGconn * -GNUNET_PQ_connect (const char *config_str) +struct GNUNET_PQ_Context * +GNUNET_PQ_connect (const char *config_str, + const struct GNUNET_PQ_ExecuteStatement *es, + const struct GNUNET_PQ_PreparedStatement *ps) { - PGconn *conn; + struct GNUNET_PQ_Context *db; + unsigned int elen = 0; + unsigned int plen = 0; + + if (NULL != es) + while (NULL != es[elen].sql) + elen++; + if (NULL != ps) + while (NULL != ps[plen].name) + plen++; + + db = GNUNET_new (struct GNUNET_PQ_Context); + db->config_str = GNUNET_strdup (config_str); + if (0 != elen) + { + db->es = GNUNET_new_array (elen + 1, + struct GNUNET_PQ_ExecuteStatement); + memcpy (db->es, + es, + elen * sizeof (struct GNUNET_PQ_ExecuteStatement)); + } + if (0 != plen) + { + db->ps = GNUNET_new_array (plen + 1, + struct GNUNET_PQ_PreparedStatement); + memcpy (db->ps, + ps, + plen * sizeof (struct GNUNET_PQ_PreparedStatement)); + } + GNUNET_PQ_reconnect (db); + if (NULL == db->conn) + { + GNUNET_free (db->config_str); + GNUNET_free (db); + return NULL; + } + return db; +} + - conn = PQconnectdb (config_str); - if ((NULL == conn) || - (CONNECTION_OK != - PQstatus (conn))) +/** + * Reinitialize the database @a db. + * + * @param db database connection to reinitialize + */ +void +GNUNET_PQ_reconnect (struct GNUNET_PQ_Context *db) +{ + if (NULL != db->conn) + PQfinish (db->conn); + db->conn = PQconnectdb (db->config_str); + if ((NULL == db->conn) || + (CONNECTION_OK != PQstatus (db->conn))) { GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "pq", "Database connection to '%s' failed: %s\n", - config_str, - (NULL != conn) ? - PQerrorMessage (conn) + db->config_str, + (NULL != db->conn) ? + PQerrorMessage (db->conn) : "PQconnectdb returned NULL"); - if (NULL != conn) - PQfinish (conn); - return NULL; + if (NULL != db->conn) + { + PQfinish (db->conn); + db->conn = NULL; + } + return; } - PQsetNoticeReceiver (conn, + PQsetNoticeReceiver (db->conn, &pq_notice_receiver_cb, - conn); - PQsetNoticeProcessor (conn, + db); + PQsetNoticeProcessor (db->conn, &pq_notice_processor_cb, - conn); - return conn; + db); + if ( (NULL != db->es) && + (GNUNET_OK != + GNUNET_PQ_exec_statements (db, + db->es)) ) + { + PQfinish (db->conn); + db->conn = NULL; + return; + } + if ( (NULL != db->ps) && + (GNUNET_OK != + GNUNET_PQ_prepare_statements (db, + db->ps)) ) + { + PQfinish (db->conn); + db->conn = NULL; + return; + } } /** * Connect to a postgres database using the configuration - * option "CONFIG" in @a section. + * option "CONFIG" in @a section. Also ensures that the + * statements in @a es are executed whenever we (re)connect to the + * database, and that the prepared statements in @a ps are "ready". + * + * The caller MUST ensure that @a es and @a ps remain allocated and + * initialized in memory until #GNUNET_PQ_disconnect() is called, + * as they may be needed repeatedly and no copy will be made. * * @param cfg configuration * @param section configuration section to use to get Postgres configuration options + * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated + * array of statements to execute upon EACH connection, can be NULL + * @param ps array of prepared statements to prepare, can be NULL * @return the postgres handle, NULL on error */ -PGconn * +struct GNUNET_PQ_Context * GNUNET_PQ_connect_with_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, - const char *section) + const char *section, + const struct GNUNET_PQ_ExecuteStatement *es, + const struct GNUNET_PQ_PreparedStatement *ps) { - PGconn *dbh; + struct GNUNET_PQ_Context *db; char *conninfo; - /* Open database and precompile statements */ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, section, "CONFIG", &conninfo)) conninfo = NULL; - dbh = GNUNET_PQ_connect (conninfo == NULL ? "" : conninfo); + db = GNUNET_PQ_connect (conninfo == NULL ? "" : conninfo, + es, + ps); GNUNET_free_non_null (conninfo); - return dbh; + return db; } +/** + * Disconnect from the database, destroying the prepared statements + * and releasing other associated resources. + * + * @param db database handle to disconnect (will be free'd) + */ +void +GNUNET_PQ_disconnect (struct GNUNET_PQ_Context *db) +{ + GNUNET_free_non_null (db->es); + GNUNET_free_non_null (db->ps); + PQfinish (db->conn); + GNUNET_free (db); +} + /* end of pq/pq_connect.c */ diff --git a/src/pq/pq_eval.c b/src/pq/pq_eval.c index 1d041f226..5bcf8ca0e 100644 --- a/src/pq/pq_eval.c +++ b/src/pq/pq_eval.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet - Copyright (C) 2017 GNUnet e.V. + Copyright (C) 2017, 2019 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -23,8 +23,7 @@ * @author Christian Grothoff */ #include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_pq_lib.h" +#include "pq.h" /** @@ -47,7 +46,7 @@ * Check the @a result's error code to see what happened. * Also logs errors. * - * @param connection connection to execute the statement in + * @param db database to execute the statement with * @param statement_name name of the statement that created @a result * @param result result to check * @return status code from the result, mapping PQ status @@ -57,17 +56,31 @@ * @deprecated (low level, let's see if we can do with just the high-level functions) */ enum GNUNET_DB_QueryStatus -GNUNET_PQ_eval_result (PGconn *connection, +GNUNET_PQ_eval_result (struct GNUNET_PQ_Context *db, const char *statement_name, PGresult *result) { ExecStatusType est; + if (NULL == result) + return GNUNET_DB_STATUS_SOFT_ERROR; est = PQresultStatus (result); if ((PGRES_COMMAND_OK != est) && (PGRES_TUPLES_OK != est)) { const char *sqlstate; + ConnStatusType status; + + if (CONNECTION_OK != (status = PQstatus (db->conn))) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, + "pq", + "Database connection failed during query `%s': %d (reconnecting)\n", + statement_name, + status); + GNUNET_PQ_reconnect (db); + return GNUNET_DB_STATUS_SOFT_ERROR; + } sqlstate = PQresultErrorField (result, PG_DIAG_SQLSTATE); @@ -94,7 +107,7 @@ GNUNET_PQ_eval_result (PGconn *connection, PG_DIAG_MESSAGE_DETAIL), PQresultErrorMessage (result), PQresStatus (PQresultStatus (result)), - PQerrorMessage (connection)); + PQerrorMessage (db->conn)); return GNUNET_DB_STATUS_SOFT_ERROR; } if (0 == strcmp (sqlstate, @@ -111,7 +124,7 @@ GNUNET_PQ_eval_result (PGconn *connection, PG_DIAG_MESSAGE_DETAIL), PQresultErrorMessage (result), PQresStatus (PQresultStatus (result)), - PQerrorMessage (connection)); + PQerrorMessage (db->conn)); return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; } GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, @@ -124,7 +137,7 @@ GNUNET_PQ_eval_result (PGconn *connection, PG_DIAG_MESSAGE_DETAIL), PQresultErrorMessage (result), PQresStatus (PQresultStatus (result)), - PQerrorMessage (connection)); + PQerrorMessage (db->conn)); return GNUNET_DB_STATUS_HARD_ERROR; } return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; @@ -136,7 +149,7 @@ GNUNET_PQ_eval_result (PGconn *connection, * statement in @a connnection using the given @a params. Returns the * resulting session state. * - * @param connection connection to execute the statement in + * @param db database to execute the statement with * @param statement_name name of the statement * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) * @return status code from the result, mapping PQ status @@ -148,17 +161,19 @@ GNUNET_PQ_eval_result (PGconn *connection, * zero; if INSERT was successful, we return one. */ enum GNUNET_DB_QueryStatus -GNUNET_PQ_eval_prepared_non_select (PGconn *connection, +GNUNET_PQ_eval_prepared_non_select (struct GNUNET_PQ_Context *db, const char *statement_name, const struct GNUNET_PQ_QueryParam *params) { PGresult *result; enum GNUNET_DB_QueryStatus qs; - result = GNUNET_PQ_exec_prepared (connection, + result = GNUNET_PQ_exec_prepared (db, statement_name, params); - qs = GNUNET_PQ_eval_result (connection, + if (NULL == result) + return GNUNET_DB_STATUS_SOFT_ERROR; + qs = GNUNET_PQ_eval_result (db, statement_name, result); if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) @@ -182,7 +197,7 @@ GNUNET_PQ_eval_prepared_non_select (PGconn *connection, * status including the number of results given to @a rh (possibly zero). * @a rh will not have been called if the return value is negative. * - * @param connection connection to execute the statement in + * @param db database to execute the statement with * @param statement_name name of the statement * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) * @param rh function to call with the result set, NULL to ignore @@ -191,7 +206,7 @@ GNUNET_PQ_eval_prepared_non_select (PGconn *connection, * codes to `enum GNUNET_DB_QueryStatus`. */ enum GNUNET_DB_QueryStatus -GNUNET_PQ_eval_prepared_multi_select (PGconn *connection, +GNUNET_PQ_eval_prepared_multi_select (struct GNUNET_PQ_Context *db, const char *statement_name, const struct GNUNET_PQ_QueryParam *params, GNUNET_PQ_PostgresResultHandler rh, @@ -201,10 +216,12 @@ GNUNET_PQ_eval_prepared_multi_select (PGconn *connection, enum GNUNET_DB_QueryStatus qs; unsigned int ret; - result = GNUNET_PQ_exec_prepared (connection, + result = GNUNET_PQ_exec_prepared (db, statement_name, params); - qs = GNUNET_PQ_eval_result (connection, + if (NULL == result) + return GNUNET_DB_STATUS_SOFT_ERROR; + qs = GNUNET_PQ_eval_result (db, statement_name, result); if (qs < 0) @@ -230,7 +247,7 @@ GNUNET_PQ_eval_prepared_multi_select (PGconn *connection, * value was #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT. Returns the * resulting session status. * - * @param connection connection to execute the statement in + * @param db database to execute the statement with * @param statement_name name of the statement * @param params parameters to give to the statement (#GNUNET_PQ_query_param_end-terminated) * @param[in,out] rs result specification to use for storing the result of the query @@ -238,7 +255,7 @@ GNUNET_PQ_eval_prepared_multi_select (PGconn *connection, * codes to `enum GNUNET_DB_QueryStatus`. */ enum GNUNET_DB_QueryStatus -GNUNET_PQ_eval_prepared_singleton_select (PGconn *connection, +GNUNET_PQ_eval_prepared_singleton_select (struct GNUNET_PQ_Context *db, const char *statement_name, const struct GNUNET_PQ_QueryParam *params, @@ -247,10 +264,12 @@ GNUNET_PQ_eval_prepared_singleton_select (PGconn *connection, PGresult *result; enum GNUNET_DB_QueryStatus qs; - result = GNUNET_PQ_exec_prepared (connection, + result = GNUNET_PQ_exec_prepared (db, statement_name, params); - qs = GNUNET_PQ_eval_result (connection, + if (NULL == result) + return GNUNET_DB_STATUS_SOFT_ERROR; + qs = GNUNET_PQ_eval_result (db, statement_name, result); if (qs < 0) diff --git a/src/pq/pq_exec.c b/src/pq/pq_exec.c index 00527151a..fd4feae53 100644 --- a/src/pq/pq_exec.c +++ b/src/pq/pq_exec.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet - Copyright (C) 2017 GNUnet e.V. + Copyright (C) 2017, 2019 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -23,8 +23,7 @@ * @author Christian Grothoff */ #include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_pq_lib.h" +#include "pq.h" /** @@ -67,14 +66,14 @@ GNUNET_PQ_make_try_execute (const char *sql) /** * Request execution of an array of statements @a es from Postgres. * - * @param connection connection to execute the statements over + * @param db database to execute the statements with * @param es #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared * statements. * @return #GNUNET_OK on success (modulo statements where errors can be ignored) * #GNUNET_SYSERR on error */ int -GNUNET_PQ_exec_statements (PGconn *connection, +GNUNET_PQ_exec_statements (struct GNUNET_PQ_Context *db, const struct GNUNET_PQ_ExecuteStatement *es) { for (unsigned int i = 0; NULL != es[i].sql; i++) @@ -84,8 +83,8 @@ GNUNET_PQ_exec_statements (PGconn *connection, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running statement `%s' on %p\n", es[i].sql, - connection); - result = PQexec (connection, + db); + result = PQexec (db->conn, es[i].sql); if ((GNUNET_NO == es[i].ignore_errors) && (PGRES_COMMAND_OK != PQresultStatus (result))) @@ -100,7 +99,7 @@ GNUNET_PQ_exec_statements (PGconn *connection, PG_DIAG_MESSAGE_DETAIL), PQresultErrorMessage (result), PQresStatus (PQresultStatus (result)), - PQerrorMessage (connection)); + PQerrorMessage (db->conn)); PQclear (result); return GNUNET_SYSERR; } diff --git a/src/pq/pq_prepare.c b/src/pq/pq_prepare.c index 0facf100f..b7003fb69 100644 --- a/src/pq/pq_prepare.c +++ b/src/pq/pq_prepare.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet - Copyright (C) 2017 GNUnet e.V. + Copyright (C) 2017, 2019 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -23,8 +23,7 @@ * @author Christian Grothoff */ #include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_pq_lib.h" +#include "pq.h" /** @@ -53,16 +52,42 @@ GNUNET_PQ_make_prepare (const char *name, /** * Request creation of prepared statements @a ps from Postgres. * - * @param connection connection to prepare the statements for + * @param db database to prepare the statements for * @param ps #GNUNET_PQ_PREPARED_STATEMENT_END-terminated array of prepared * statements. * @return #GNUNET_OK on success, * #GNUNET_SYSERR on error */ int -GNUNET_PQ_prepare_statements (PGconn *connection, +GNUNET_PQ_prepare_statements (struct GNUNET_PQ_Context *db, const struct GNUNET_PQ_PreparedStatement *ps) { + if (db->ps != ps) + { + /* add 'ps' to list db->ps of prepared statements to run on reconnect! */ + unsigned int olen = 0; /* length of existing 'db->ps' array */ + unsigned int nlen = 0; /* length of 'ps' array */ + struct GNUNET_PQ_PreparedStatement *rps; /* combined array */ + + if (NULL != db->ps) + while (NULL != db->ps[olen].name) + olen++; + while (NULL != ps[nlen].name) + nlen++; + rps = GNUNET_new_array (olen + nlen + 1, + struct GNUNET_PQ_PreparedStatement); + if (NULL != db->ps) + memcpy (rps, + db->ps, + olen * sizeof (struct GNUNET_PQ_PreparedStatement)); + memcpy (&rps[olen], + ps, + nlen * sizeof (struct GNUNET_PQ_PreparedStatement)); + GNUNET_free_non_null (db->ps); + db->ps = rps; + } + + /* actually prepare statements */ for (unsigned int i = 0; NULL != ps[i].name; i++) { PGresult *ret; @@ -72,7 +97,7 @@ GNUNET_PQ_prepare_statements (PGconn *connection, "Preparing SQL statement `%s' as `%s'\n", ps[i].sql, ps[i].name); - ret = PQprepare (connection, + ret = PQprepare (db->conn, ps[i].name, ps[i].sql, ps[i].num_arguments, @@ -84,7 +109,7 @@ GNUNET_PQ_prepare_statements (PGconn *connection, _ ("PQprepare (`%s' as `%s') failed with error: %s\n"), ps[i].sql, ps[i].name, - PQerrorMessage (connection)); + PQerrorMessage (db->conn)); PQclear (ret); return GNUNET_SYSERR; } diff --git a/src/pq/pq_result_helper.c b/src/pq/pq_result_helper.c index cfb16ac12..1fb1e71c0 100644 --- a/src/pq/pq_result_helper.c +++ b/src/pq/pq_result_helper.c @@ -587,7 +587,7 @@ extract_abs_time (void *cls, res = (int64_t *) PQgetvalue (result, row, fnum); - if (INT64_MAX == *res) + if (INT64_MAX == GNUNET_ntohll ((uint64_t) *res)) *udst = GNUNET_TIME_UNIT_FOREVER_ABS; else udst->abs_value_us = GNUNET_ntohll ((uint64_t) *res); diff --git a/src/pq/test_pq.c b/src/pq/test_pq.c index 697d8e580..a103aca5d 100644 --- a/src/pq/test_pq.c +++ b/src/pq/test_pq.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet - (C) 2015, 2016 GNUnet e.V. + (C) 2015, 2016, 2019 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -23,75 +23,65 @@ * @author Christian Grothoff */ #include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_pq_lib.h" +#include "pq.h" /** * Setup prepared statements. * - * @param db_conn connection handle to initialize + * @param db database handle to initialize * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure */ static int -postgres_prepare (PGconn *db_conn) +postgres_prepare (struct GNUNET_PQ_Context *db) { - PGresult *result; - -#define PREPARE(name, sql, ...) \ - do { \ - result = PQprepare (db_conn, name, sql, __VA_ARGS__); \ - if (PGRES_COMMAND_OK != PQresultStatus (result)) \ - { \ - GNUNET_break (0); \ - PQclear (result); result = NULL; \ - return GNUNET_SYSERR; \ - } \ - PQclear (result); result = NULL; \ - } while (0); + struct GNUNET_PQ_PreparedStatement ps[] = { + GNUNET_PQ_make_prepare ("test_insert", + "INSERT INTO test_pq (" + " pub" + ",sig" + ",abs_time" + ",forever" + ",hash" + ",vsize" + ",u16" + ",u32" + ",u64" + ") VALUES " + "($1, $2, $3, $4, $5, $6," + "$7, $8, $9);", + 9), + GNUNET_PQ_make_prepare ("test_select", + "SELECT" + " pub" + ",sig" + ",abs_time" + ",forever" + ",hash" + ",vsize" + ",u16" + ",u32" + ",u64" + " FROM test_pq" + " ORDER BY abs_time DESC " + " LIMIT 1;", + 0), + GNUNET_PQ_PREPARED_STATEMENT_END + }; - PREPARE ("test_insert", - "INSERT INTO test_pq (" - " pub" - ",sig" - ",abs_time" - ",forever" - ",hash" - ",vsize" - ",u16" - ",u32" - ",u64" - ") VALUES " - "($1, $2, $3, $4, $5, $6," - "$7, $8, $9);", - 9, NULL); - PREPARE ("test_select", - "SELECT" - " pub" - ",sig" - ",abs_time" - ",forever" - ",hash" - ",vsize" - ",u16" - ",u32" - ",u64" - " FROM test_pq" - " ORDER BY abs_time DESC " - " LIMIT 1;", - 0, NULL); - return GNUNET_OK; -#undef PREPARE + return GNUNET_PQ_prepare_statements (db, + ps); } /** * Run actual test queries. * + * @param db database handle * @return 0 on success */ static int -run_queries (PGconn *conn) +run_queries (struct GNUNET_PQ_Context *db) { struct GNUNET_CRYPTO_RsaPublicKey *pub; struct GNUNET_CRYPTO_RsaPublicKey *pub2 = NULL; @@ -155,7 +145,7 @@ run_queries (PGconn *conn) GNUNET_PQ_result_spec_end }; - result = GNUNET_PQ_exec_prepared (conn, + result = GNUNET_PQ_exec_prepared (db, "test_insert", params_insert); if (PGRES_COMMAND_OK != PQresultStatus (result)) @@ -171,7 +161,7 @@ run_queries (PGconn *conn) } PQclear (result); - result = GNUNET_PQ_exec_prepared (conn, + result = GNUNET_PQ_exec_prepared (db, "test_select", params_select); if (1 != @@ -224,67 +214,71 @@ int main (int argc, const char *const argv[]) { - PGconn *conn; - PGresult *result; + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS test_pq (" + " pub BYTEA NOT NULL" + ",sig BYTEA NOT NULL" + ",abs_time INT8 NOT NULL" + ",forever INT8 NOT NULL" + ",hash BYTEA NOT NULL CHECK(LENGTH(hash)=64)" + ",vsize VARCHAR NOT NULL" + ",u16 INT2 NOT NULL" + ",u32 INT4 NOT NULL" + ",u64 INT8 NOT NULL" + ")"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; + struct GNUNET_PQ_Context *db; int ret; GNUNET_log_setup ("test-pq", "WARNING", NULL); - conn = PQconnectdb ("postgres:///gnunetcheck"); - if (CONNECTION_OK != PQstatus (conn)) + db = GNUNET_PQ_connect ("postgres:///gnunetcheck", + es, + NULL); + if (CONNECTION_OK != PQstatus (db->conn)) { fprintf (stderr, "Cannot run test, database connection failed: %s\n", - PQerrorMessage (conn)); + PQerrorMessage (db->conn)); GNUNET_break (0); - PQfinish (conn); + GNUNET_PQ_disconnect (db); return 77; /* signal test was skipped */ } - - result = PQexec (conn, - "CREATE TEMPORARY TABLE IF NOT EXISTS test_pq (" - " pub BYTEA NOT NULL" - ",sig BYTEA NOT NULL" - ",abs_time INT8 NOT NULL" - ",forever INT8 NOT NULL" - ",hash BYTEA NOT NULL CHECK(LENGTH(hash)=64)" - ",vsize VARCHAR NOT NULL" - ",u16 INT2 NOT NULL" - ",u32 INT4 NOT NULL" - ",u64 INT8 NOT NULL" - ")"); - if (PGRES_COMMAND_OK != PQresultStatus (result)) - { - fprintf (stderr, - "Failed to create table: %s\n", - PQerrorMessage (conn)); - PQclear (result); - PQfinish (conn); - return 1; - } - PQclear (result); if (GNUNET_OK != - postgres_prepare (conn)) + postgres_prepare (db)) { GNUNET_break (0); - PQfinish (conn); + GNUNET_PQ_disconnect (db); return 1; } - ret = run_queries (conn); - result = PQexec (conn, - "DROP TABLE test_pq"); - if (PGRES_COMMAND_OK != PQresultStatus (result)) + ret = run_queries (db); +#if TEST_RESTART + fprintf (stderr, "Please restart Postgres database now!\n"); + sleep (60); + ret = run_queries (db); + fprintf (stderr, "Result: %d (expect: 1 -- if you restarted the DB)\n", ret); + ret = run_queries (db); + fprintf (stderr, "Result: %d (expect: 0)\n", ret); +#endif { - fprintf (stderr, - "Failed to create table: %s\n", - PQerrorMessage (conn)); - PQclear (result); - PQfinish (conn); - return 1; + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_execute ("DROP TABLE test_pq"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; + + if (GNUNET_OK != + GNUNET_PQ_exec_statements (db, + es)) + { + fprintf (stderr, + "Failed to drop table\n"); + GNUNET_PQ_disconnect (db); + return 1; + } } - PQclear (result); - PQfinish (conn); + GNUNET_PQ_disconnect (db); return ret; } -- cgit v1.2.3 From 195fd08b9f0f46efd63dd87fb8f5fdbaca8ca610 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 11 Oct 2019 23:20:13 +0200 Subject: add GNUNET_PQ_reconnect_if_down --- src/include/gnunet_pq_lib.h | 9 +++++++++ src/pq/pq_connect.c | 14 ++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/include/gnunet_pq_lib.h b/src/include/gnunet_pq_lib.h index a56df21fd..2aea77b7f 100644 --- a/src/include/gnunet_pq_lib.h +++ b/src/include/gnunet_pq_lib.h @@ -748,6 +748,15 @@ GNUNET_PQ_connect_with_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_PQ_PreparedStatement *ps); +/** + * Reinitialize the database @a db if the connection is down. + * + * @param db database connection to reinitialize + */ +void +GNUNET_PQ_reconnect_if_down (struct GNUNET_PQ_Context *db); + + /** * Reinitialize the database @a db. * diff --git a/src/pq/pq_connect.c b/src/pq/pq_connect.c index 7599f4b15..882df4f89 100644 --- a/src/pq/pq_connect.c +++ b/src/pq/pq_connect.c @@ -127,6 +127,20 @@ GNUNET_PQ_connect (const char *config_str, } +/** + * Reinitialize the database @a db if the connection is down. + * + * @param db database connection to reinitialize + */ +void +GNUNET_PQ_reconnect_if_down (struct GNUNET_PQ_Context *db) +{ + if (CONNECTION_BAD != PQstatus (db->conn)) + return; + GNUNET_PQ_reconnect (db); +} + + /** * Reinitialize the database @a db. * -- cgit v1.2.3