diff options
Diffstat (limited to 'src/backend/taler-merchant-reconciliation.c')
-rw-r--r-- | src/backend/taler-merchant-reconciliation.c | 224 |
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); |