summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/taler-merchant-httpd.c196
-rw-r--r--src/backend/taler-merchant-httpd.h37
-rw-r--r--src/backend/taler-merchant-httpd_private-delete-instances-ID.c7
-rw-r--r--src/backend/taler-merchant-httpd_private-patch-instances-ID.c3
-rw-r--r--src/backend/taler-merchant-httpd_private-post-instances-ID-auth.c33
-rw-r--r--src/backend/taler-merchant-httpd_private-post-instances.c1
6 files changed, 197 insertions, 80 deletions
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c
index 104d7435..577672b9 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -22,6 +22,7 @@
* @author Florian Dold
*/
#include "platform.h"
+#include <taler/taler_dbevents.h>
#include <taler/taler_bank_service.h>
#include <taler/taler_exchange_service.h>
#include "taler-merchant-httpd_auditors.h"
@@ -101,6 +102,11 @@ int TMH_force_audit;
struct TALER_MERCHANTDB_Plugin *TMH_db;
/**
+ * Event handler for instance settings changes.
+ */
+static struct GNUNET_DB_EventHandler *instance_eh;
+
+/**
* Hashmap pointing at merchant instances by 'id'. An 'id' is
* just a string that identifies a merchant instance. When a frontend
* needs to specify an instance to the backend, it does so by 'id'
@@ -241,22 +247,14 @@ TMH_compute_auth (const char *token,
*
* @param[in,out] mi merchant instance to update and possibly free
*/
-void
-TMH_instance_decref (struct TMH_MerchantInstance *mi)
+static void
+instance_decref (struct TMH_MerchantInstance *mi)
{
struct TMH_WireMethod *wm;
- struct GNUNET_HashCode h_instance;
mi->rc--;
if (0 != mi->rc)
return;
- GNUNET_CRYPTO_hash (mi->settings.id,
- strlen (mi->settings.id),
- &h_instance);
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CONTAINER_multihashmap_remove (TMH_by_id_map,
- &h_instance,
- mi));
TMH_force_get_orders_resume (mi);
while (NULL != (wm = (mi->wm_head)))
{
@@ -277,22 +275,27 @@ TMH_instance_decref (struct TMH_MerchantInstance *mi)
/**
- * Callback that frees all the instances in the hashmap
+ * Callback that frees an instances removing
+ * it from the global hashmap.
*
* @param cls closure, NULL
* @param key current key
* @param value a `struct TMH_MerchantInstance`
*/
-static int
-instance_free_cb (void *cls,
- const struct GNUNET_HashCode *key,
- void *value)
+int
+TMH_instance_free_cb (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
{
struct TMH_MerchantInstance *mi = value;
(void) cls;
(void) key;
- TMH_instance_decref (mi);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_remove (TMH_by_id_map,
+ &mi->h_instance,
+ mi));
+ instance_decref (mi);
return GNUNET_YES;
}
@@ -732,6 +735,11 @@ do_shutdown (void *cls)
mhd = NULL;
}
TMH_RESERVES_done ();
+ if (NULL != instance_eh)
+ {
+ TMH_db->event_listen_cancel (instance_eh);
+ instance_eh = NULL;
+ }
if (NULL != TMH_db)
{
TALER_MERCHANTDB_plugin_unload (TMH_db);
@@ -755,7 +763,7 @@ do_shutdown (void *cls)
if (NULL != TMH_by_id_map)
{
GNUNET_CONTAINER_multihashmap_iterate (TMH_by_id_map,
- &instance_free_cb,
+ &TMH_instance_free_cb,
NULL);
GNUNET_CONTAINER_multihashmap_destroy (TMH_by_id_map);
TMH_by_id_map = NULL;
@@ -799,7 +807,7 @@ handle_mhd_completion_callback (void *cls,
if (NULL != hc->request_body)
json_decref (hc->request_body);
if (NULL != hc->instance)
- TMH_instance_decref (hc->instance);
+ instance_decref (hc->instance);
memset (&hc->async_scope_id,
0,
sizeof (struct GNUNET_AsyncScopeId));
@@ -914,8 +922,6 @@ struct TMH_MerchantInstance *
TMH_lookup_instance (const char *instance_id)
{
struct GNUNET_HashCode h_instance;
- struct TMH_MerchantInstance *mi;
- struct GNUNET_TIME_Relative age;
if (NULL == instance_id)
instance_id = "default";
@@ -928,16 +934,8 @@ TMH_lookup_instance (const char *instance_id)
instance_id);
/* We're fine if that returns NULL, the calling routine knows how
to handle that */
- mi = GNUNET_CONTAINER_multihashmap_get (TMH_by_id_map,
- &h_instance);
- if (NULL == mi)
- return mi;
- age = GNUNET_TIME_absolute_get_duration (mi->staleness);
- if (age.rel_value_us > INSTANCE_STALENESS.rel_value_us)
- {
- // FIXME: referesh from DB
- }
- return mi;
+ return GNUNET_CONTAINER_multihashmap_get (TMH_by_id_map,
+ &h_instance);
}
@@ -950,7 +948,6 @@ TMH_lookup_instance (const char *instance_id)
int
TMH_add_instance (struct TMH_MerchantInstance *mi)
{
- struct GNUNET_HashCode h_instance;
const char *id;
int ret;
@@ -959,13 +956,13 @@ TMH_add_instance (struct TMH_MerchantInstance *mi)
id = "default";
GNUNET_CRYPTO_hash (id,
strlen (id),
- &h_instance);
+ &mi->h_instance);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Looking for by-id key %s of `%s' in hashmap\n",
- GNUNET_h2s (&h_instance),
+ GNUNET_h2s (&mi->h_instance),
id);
ret = GNUNET_CONTAINER_multihashmap_put (TMH_by_id_map,
- &h_instance,
+ &mi->h_instance,
mi,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
if (GNUNET_OK == ret)
@@ -2043,6 +2040,15 @@ add_instance_cb (void *cls,
struct TMH_MerchantInstance *mi;
(void) cls;
+ mi = TMH_lookup_instance (is->id);
+ if (NULL != mi)
+ {
+ /* (outdated) entry exists, remove old entry */
+ (void) TMH_instance_free_cb (NULL,
+ &mi->h_instance,
+ mi);
+ }
+
mi = GNUNET_new (struct TMH_MerchantInstance);
mi->settings = *is;
mi->auth = *ias;
@@ -2055,7 +2061,6 @@ add_instance_cb (void *cls,
else
mi->deleted = true;
mi->merchant_pub = *merchant_pub;
- mi->staleness = GNUNET_TIME_absolute_get ();
for (unsigned int i = 0; i<accounts_length; i++)
{
const struct TALER_MERCHANTDB_AccountDetails *acc = &accounts[i];
@@ -2078,6 +2083,98 @@ add_instance_cb (void *cls,
/**
+ * Trigger (re)loading of instance settings from DB.
+ *
+ * @param cls NULL
+ * @param extra ID of the instance that changed, NULL
+ * to load all instances (will not handle purges!)
+ * @param extra_len number of bytes in @a extra
+ */
+static void
+load_instances (void *cls,
+ const void *extra,
+ size_t extra_len)
+{
+ enum GNUNET_DB_QueryStatus qs;
+ const char *id = extra;
+
+ (void) cls;
+ (void) extra;
+ (void) extra_len;
+ if ( (NULL != extra) &&
+ ( (0 == extra_len) ||
+ ('\0' != id[extra_len - 1]) ) )
+ {
+ GNUNET_break (0); /* bogus notification */
+ extra = NULL;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Received instance settings notification: reload `%s'\n",
+ id);
+ if (NULL == extra)
+ {
+ qs = TMH_db->lookup_instances (TMH_db->cls,
+ false,
+ &add_instance_cb,
+ NULL);
+ }
+ else
+ {
+ struct TMH_MerchantInstance *mi;
+
+ /* This must be done here to handle instance
+ purging, as for purged instances, the DB
+ lookup below will otherwise do nothing */
+ mi = TMH_lookup_instance (id);
+ if (NULL != mi)
+ {
+ (void) TMH_instance_free_cb (NULL,
+ &mi->h_instance,
+ mi);
+ }
+ qs = TMH_db->lookup_instance (TMH_db->cls,
+ id,
+ false,
+ &add_instance_cb,
+ NULL);
+ }
+ if (0 > qs)
+ {
+ GNUNET_break (0);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+}
+
+
+/**
+ * A transaction modified an instance setting
+ * (or created/deleted/purged one). Notify all
+ * backends about the change.
+ *
+ * @param id ID of the instance that changed
+ */
+void
+TMH_reload_instances (const char *id)
+{
+ struct GNUNET_DB_EventHeaderP es = {
+ es.size = ntohs (sizeof (es)),
+ es.type = ntohs (sizeof (TALER_DBEVENT_MERCHANT_INSTANCE_SETTINGS))
+ };
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Generating instance settings notification: reload `%s'\n",
+ id);
+ TMH_db->event_notify (TMH_db->cls,
+ &es,
+ id,
+ (NULL == id)
+ ? 0
+ : strlen (id) + 1);
+}
+
+
+/**
* Main function that will be run by the scheduler.
*
* @param cls closure
@@ -2175,8 +2272,8 @@ run (void *cls,
return;
}
if (NULL ==
- (TMH_by_id_map = GNUNET_CONTAINER_multihashmap_create (1,
- GNUNET_NO)))
+ (TMH_by_id_map = GNUNET_CONTAINER_multihashmap_create (4,
+ GNUNET_YES)))
{
GNUNET_SCHEDULER_shutdown ();
return;
@@ -2195,21 +2292,20 @@ run (void *cls,
GNUNET_SCHEDULER_shutdown ();
return;
}
- /* load instances */
{
- enum GNUNET_DB_QueryStatus qs;
-
- qs = TMH_db->lookup_instances (TMH_db->cls,
- false,
- &add_instance_cb,
- NULL);
- if (0 > qs)
- {
- GNUNET_break (0);
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
+ struct GNUNET_DB_EventHeaderP es = {
+ es.size = ntohs (sizeof (es)),
+ es.type = ntohs (sizeof (TALER_DBEVENT_MERCHANT_INSTANCE_SETTINGS))
+ };
+
+ instance_eh = TMH_db->event_listen (TMH_db->cls,
+ &es,
+ &load_instances,
+ NULL);
}
+ load_instances (NULL,
+ NULL,
+ 0);
/* start watching reserves */
TMH_RESERVES_init ();
fh = TALER_MHD_bind (cfg,
diff --git a/src/backend/taler-merchant-httpd.h b/src/backend/taler-merchant-httpd.h
index 03e62d2c..64bd8ad1 100644
--- a/src/backend/taler-merchant-httpd.h
+++ b/src/backend/taler-merchant-httpd.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2018 Taler Systems SA
+ Copyright (C) 2014-2021 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -108,6 +108,11 @@ struct TMH_MerchantInstance
struct TMH_WireMethod *wm_tail;
/**
+ * Hash of the instance ID, key for the DHT.
+ */
+ struct GNUNET_HashCode h_instance;
+
+ /**
* Head of DLL of long-polling GET /orders requests of this instance.
*/
struct TMH_PendingOrder *po_head;
@@ -138,12 +143,6 @@ struct TMH_MerchantInstance
struct TALER_MERCHANTDB_InstanceAuthSettings auth;
/**
- * Timestamp when we last updated this instance's data
- * with the information from the database.
- */
- struct GNUNET_TIME_Absolute staleness;
-
- /**
* Reference counter on this structure. Only destroyed if the
* counter hits zero.
*/
@@ -512,12 +511,17 @@ TMH_long_poll_resume2 (const char *session_id,
/**
- * Decrement reference counter of @a mi, and free if it hits zero.
+ * Callback that frees an instances removing
+ * it from the global hashmap.
*
- * @param[in,out] mi merchant instance to update and possibly free
+ * @param cls closure, NULL
+ * @param key current key
+ * @param value a `struct TMH_MerchantInstance`
*/
-void
-TMH_instance_decref (struct TMH_MerchantInstance *mi);
+int
+TMH_instance_free_cb (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value);
/**
@@ -541,6 +545,17 @@ TMH_lookup_instance (const char *instance_id);
/**
+ * A transaction modified an instance setting
+ * (or created/deleted/purged one). Notify all
+ * backends about the change.
+ *
+ * @param id ID of the instance that changed
+ */
+void
+TMH_reload_instances (const char *id);
+
+
+/**
* Check that @a token hashes to @a hash under @a salt for
* merchant instance authentication.
*
diff --git a/src/backend/taler-merchant-httpd_private-delete-instances-ID.c b/src/backend/taler-merchant-httpd_private-delete-instances-ID.c
index 0de88164..bb0c8e56 100644
--- a/src/backend/taler-merchant-httpd_private-delete-instances-ID.c
+++ b/src/backend/taler-merchant-httpd_private-delete-instances-ID.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2020 Taler Systems SA
+ (C) 2020-2021 Taler Systems SA
TALER 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
@@ -73,8 +73,11 @@ delete_instances_ID (struct TMH_MerchantInstance *mi,
? "Instance unknown"
: "Private key unknown");
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ TMH_reload_instances (mi->settings.id);
if (purge)
- TMH_instance_decref (mi);
+ TMH_instance_free_cb (NULL,
+ &mi->h_instance,
+ mi);
else
mi->deleted = true;
return TALER_MHD_reply_static (connection,
diff --git a/src/backend/taler-merchant-httpd_private-patch-instances-ID.c b/src/backend/taler-merchant-httpd_private-patch-instances-ID.c
index 65f1760f..482ef048 100644
--- a/src/backend/taler-merchant-httpd_private-patch-instances-ID.c
+++ b/src/backend/taler-merchant-httpd_private-patch-instances-ID.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2020 Taler Systems SA
+ (C) 2020-2021 Taler Systems SA
TALER is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
@@ -370,6 +370,7 @@ giveup:
}
GNUNET_JSON_parse_free (spec);
+ TMH_reload_instances (mi->settings.id);
return TALER_MHD_reply_static (connection,
MHD_HTTP_NO_CONTENT,
NULL,
diff --git a/src/backend/taler-merchant-httpd_private-post-instances-ID-auth.c b/src/backend/taler-merchant-httpd_private-post-instances-ID-auth.c
index 17316348..eef710b6 100644
--- a/src/backend/taler-merchant-httpd_private-post-instances-ID-auth.c
+++ b/src/backend/taler-merchant-httpd_private-post-instances-ID-auth.c
@@ -108,25 +108,25 @@ post_instances_ID_auth (struct TMH_MerchantInstance *mi,
switch (qs)
{
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- /* Instance got purged. */
- TMH_db->rollback (TMH_db->cls);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_UNAUTHORIZED,
- TALER_EC_GENERIC_DB_COMMIT_FAILED,
- NULL);
- case GNUNET_DB_STATUS_SOFT_ERROR:
- TMH_db->rollback (TMH_db->cls);
- goto retry;
- case GNUNET_DB_STATUS_HARD_ERROR:
- TMH_db->rollback (TMH_db->cls);
- return TALER_MHD_reply_with_error (connection,
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ /* Instance got purged. */
+ TMH_db->rollback (TMH_db->cls);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_UNAUTHORIZED,
+ TALER_EC_GENERIC_DB_COMMIT_FAILED,
+ NULL);
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ TMH_db->rollback (TMH_db->cls);
+ goto retry;
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ TMH_db->rollback (TMH_db->cls);
+ return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_FETCH_FAILED,
NULL);
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- /* Success! */
- break;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ /* Success! */
+ break;
}
if (GNUNET_OK !=
@@ -183,6 +183,7 @@ retry:
for the default instance. */
GNUNET_assert (NULL == TMH_default_auth);
}
+ TMH_reload_instances (mi->settings.id);
return TALER_MHD_reply_static (connection,
MHD_HTTP_NO_CONTENT,
NULL,
diff --git a/src/backend/taler-merchant-httpd_private-post-instances.c b/src/backend/taler-merchant-httpd_private-post-instances.c
index 2d3f660c..7951652a 100644
--- a/src/backend/taler-merchant-httpd_private-post-instances.c
+++ b/src/backend/taler-merchant-httpd_private-post-instances.c
@@ -459,6 +459,7 @@ retry:
/* Finally, also update our running process */
GNUNET_assert (GNUNET_OK ==
TMH_add_instance (mi));
+ TMH_reload_instances (mi->settings.id);
}
GNUNET_JSON_parse_free (spec);
GNUNET_free (TMH_default_auth); /* clear it: user just either created default