aboutsummaryrefslogtreecommitdiff
path: root/src/backend/taler-merchant-reconciliation.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/taler-merchant-reconciliation.c')
-rw-r--r--src/backend/taler-merchant-reconciliation.c224
1 files changed, 97 insertions, 127 deletions
diff --git a/src/backend/taler-merchant-reconciliation.c b/src/backend/taler-merchant-reconciliation.c
index 23c9a926..8bb88849 100644
--- a/src/backend/taler-merchant-reconciliation.c
+++ b/src/backend/taler-merchant-reconciliation.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2023 Taler Systems SA
+ Copyright (C) 2023-2024 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
@@ -83,48 +83,21 @@ struct Exchange
char *exchange_url;
/**
- * A connection to this exchange
- */
- struct TALER_EXCHANGE_GetKeysHandle *conn;
-
- /**
* The keys of this exchange
*/
struct TALER_EXCHANGE_Keys *keys;
/**
- * Task where we retry fetching /keys from the exchange.
- */
- struct GNUNET_SCHEDULER_Task *retry_task;
-
- /**
* How many active inquiries do we have right now with this exchange.
*/
unsigned int exchange_inquiries;
/**
- * How soon can may we, at the earliest, re-download /keys?
- */
- struct GNUNET_TIME_Absolute first_retry;
-
- /**
- * How long should we wait between the next retry?
- */
- struct GNUNET_TIME_Relative retry_delay;
-
- /**
* How long should we wait between requests
* for transfer details?
*/
struct GNUNET_TIME_Relative transfer_delay;
- /**
- * False to indicate that there is an ongoing
- * /keys transfer we are waiting for;
- * true to indicate that /keys data is up-to-date.
- */
- bool ready;
-
};
@@ -233,6 +206,12 @@ static struct GNUNET_SCHEDULER_Task *task;
static struct GNUNET_DB_EventHandler *eh;
/**
+ * Event handler to learn that there may be new exchange
+ * keys to check.
+ */
+static struct GNUNET_DB_EventHandler *eh_keys;
+
+/**
* How many active inquiries do we have right now.
*/
static unsigned int active_inquiries;
@@ -297,91 +276,6 @@ launch_inquiries_at_exchange (struct Exchange *e)
/**
- * Function that initiates a /keys download.
- *
- * @param cls a `struct Exchange *`
- */
-static void
-download_keys (void *cls);
-
-
-/**
- * Function called with information about who is auditing
- * a particular exchange and what keys the exchange is using.
- *
- * @param cls closure with a `struct Exchange *`
- * @param kr response data
- * @param[in] keys the keys of the exchange
- */
-static void
-cert_cb (
- void *cls,
- const struct TALER_EXCHANGE_KeysResponse *kr,
- struct TALER_EXCHANGE_Keys *keys)
-{
- struct Exchange *e = cls;
- struct GNUNET_TIME_Absolute n;
-
- e->conn = NULL;
- switch (kr->hr.http_status)
- {
- case MHD_HTTP_OK:
- e->ready = true;
- TALER_EXCHANGE_keys_decref (e->keys);
- e->keys = keys;
- launch_inquiries_at_exchange (e);
- /* Reset back-off */
- e->retry_delay = GNUNET_TIME_UNIT_ZERO;
- /* Success: rate limit at once per minute */
- e->first_retry = GNUNET_TIME_relative_to_absolute (
- GNUNET_TIME_UNIT_MINUTES);
- n = GNUNET_TIME_absolute_max (e->first_retry,
- keys->key_data_expiration.abs_time);
- if (NULL != e->retry_task)
- GNUNET_SCHEDULER_cancel (e->retry_task);
- e->retry_task = GNUNET_SCHEDULER_add_at (n,
- &download_keys,
- e);
- break;
- default:
- e->retry_delay
- = GNUNET_TIME_STD_BACKOFF (e->retry_delay);
- e->first_retry
- = GNUNET_TIME_relative_to_absolute (e->retry_delay);
- if (NULL != e->retry_task)
- GNUNET_SCHEDULER_cancel (e->retry_task);
- e->retry_task = GNUNET_SCHEDULER_add_delayed (e->retry_delay,
- &download_keys,
- e);
- break;
- }
-}
-
-
-static void
-download_keys (void *cls)
-{
- struct Exchange *e = cls;
- struct GNUNET_TIME_Relative n;
-
- /* If we do not hear back again soon, try again automatically */
- n = GNUNET_TIME_STD_BACKOFF (e->retry_delay);
- n = GNUNET_TIME_relative_max (n,
- GNUNET_TIME_UNIT_MINUTES);
- e->retry_task = GNUNET_SCHEDULER_add_delayed (n,
- &download_keys,
- e);
- if ( (NULL == e->keys) ||
- (GNUNET_TIME_absolute_is_past (e->keys->key_data_expiration.abs_time)) )
- e->conn = TALER_EXCHANGE_get_keys (ctx,
- e->exchange_url,
- e->keys,
- &cert_cb,
- e);
-}
-
-
-/**
* Updates the transaction status for inquiry @a w to the given values.
*
* @param w inquiry to update status for
@@ -419,6 +313,37 @@ update_transaction_status (const struct Inquiry *w,
/**
+ * Interact with the database to get the current set
+ * of exchange keys known to us.
+ *
+ * @param e the exchange to check
+ */
+static void
+sync_keys (struct Exchange *e)
+{
+ enum GNUNET_DB_QueryStatus qs;
+ struct TALER_EXCHANGE_Keys *keys;
+
+ qs = db_plugin->select_exchange_keys (db_plugin->cls,
+ e->exchange_url,
+ &keys);
+ if (qs < 0)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ TALER_EXCHANGE_keys_decref (e->keys);
+ e->keys = keys;
+ launch_inquiries_at_exchange (e);
+}
+
+
+/**
* Lookup our internal data structure for the given
* @a exchange_url or create one if we do not yet have
* one.
@@ -440,8 +365,7 @@ find_exchange (const char *exchange_url)
GNUNET_CONTAINER_DLL_insert (e_head,
e_tail,
e);
- e->retry_task = GNUNET_SCHEDULER_add_now (&download_keys,
- e);
+ sync_keys (e);
return e;
}
@@ -522,21 +446,11 @@ shutdown_task (void *cls)
end_inquiry (w);
}
GNUNET_free (e->exchange_url);
- if (NULL != e->conn)
- {
- TALER_EXCHANGE_get_keys_cancel (e->conn);
- e->conn = NULL;
- }
if (NULL != e->keys)
{
TALER_EXCHANGE_keys_decref (e->keys);
e->keys = NULL;
}
- if (NULL != e->retry_task)
- {
- GNUNET_SCHEDULER_cancel (e->retry_task);
- e->retry_task = NULL;
- }
GNUNET_CONTAINER_DLL_remove (e_head,
e_tail,
e);
@@ -547,6 +461,11 @@ shutdown_task (void *cls)
db_plugin->event_listen_cancel (eh);
eh = NULL;
}
+ if (NULL != eh_keys)
+ {
+ db_plugin->event_listen_cancel (eh_keys);
+ eh_keys = NULL;
+ }
if (NULL != task)
{
GNUNET_SCHEDULER_cancel (task);
@@ -1007,7 +926,8 @@ exchange_request (void *cls)
struct Exchange *e = w->exchange;
w->task = NULL;
- GNUNET_assert (e->ready);
+ if (NULL == e->keys)
+ return;
w->wdh = TALER_EXCHANGE_transfers_get (
ctx,
e->exchange_url,
@@ -1099,7 +1019,7 @@ start_inquiry (
e->w_tail,
w);
w->exchange = e;
- if (w->exchange->ready)
+ if (NULL != w->exchange->keys)
w->task = GNUNET_SCHEDULER_add_now (&exchange_request,
w);
/* Wait at least 1 minute for /keys */
@@ -1194,6 +1114,42 @@ transfer_added (void *cls,
/**
+ * Function called when keys were channged in the
+ * merchant database. Updates ours.
+ *
+ * @param cls closure (NULL)
+ * @param extra additional event data provided
+ * @param extra_size number of bytes in @a extra
+ */
+static void
+keys_changed (void *cls,
+ const void *extra,
+ size_t extra_size)
+{
+ const char *url = extra;
+ struct Exchange *e;
+
+ (void) cls;
+ if ( (NULL == extra) ||
+ (0 == extra_size) )
+ {
+ GNUNET_break (0);
+ return;
+ }
+ if ('\0' != url[extra_size - 1])
+ {
+ GNUNET_break (0);
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Received keys change notification: reload `%s'\n",
+ url);
+ e = find_exchange (url);
+ sync_keys (e);
+}
+
+
+/**
* First task.
*
* @param cls closure, NULL
@@ -1253,6 +1209,20 @@ run (void *cls,
&transfer_added,
NULL);
}
+ {
+ struct GNUNET_DB_EventHeaderP es = {
+ .size = htons (sizeof (es)),
+ .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KEYS)
+ };
+
+ eh_keys
+ = db_plugin->event_listen (db_plugin->cls,
+ &es,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &keys_changed,
+ NULL);
+ }
+
GNUNET_assert (NULL == task);
task = GNUNET_SCHEDULER_add_now (&find_work,
NULL);