aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2024-10-01 14:05:42 +0200
committerChristian Grothoff <christian@grothoff.org>2024-10-01 14:05:42 +0200
commit12c8aeb66e1a1f8dc8b4cefa78c11459e6a657d3 (patch)
treeb56a74c94bdafe79626398a80a997b34f631d257
parent1e2a6651223c41f9c3ed09c2e98678d175b0e2cc (diff)
fix #9197: wait at most 250ms for /keys from exchanges before giving up
-rw-r--r--src/backend/taler-merchant-httpd_private-post-orders.c71
-rw-r--r--src/include/taler_merchant_service.h15
2 files changed, 86 insertions, 0 deletions
diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c b/src/backend/taler-merchant-httpd_private-post-orders.c
index 7053ac70..c1583791 100644
--- a/src/backend/taler-merchant-httpd_private-post-orders.c
+++ b/src/backend/taler-merchant-httpd_private-post-orders.c
@@ -68,6 +68,14 @@
*/
#define STANDARD_LABEL_MERCHANT_ADDRESS "_ma"
+/**
+ * How long do we wait at most for /keys from the exchange(s)?
+ * Ensures that we do not block forever just because some exchange
+ * fails to respond *or* because our taler-merchant-keyscheck
+ * refuses a forced download.
+ */
+#define MAX_KEYS_WAIT \
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250)
/**
* Generate the base URL for the given merchant instance.
@@ -449,6 +457,17 @@ struct OrderContext
* order creation requests exceeds legal limits.
*/
struct TALER_Amount total_exchange_limit;
+
+ /**
+ * How long do we wait at most until giving up on getting keys?
+ */
+ struct GNUNET_TIME_Absolute keys_timeout;
+
+ /**
+ * Task to wake us up on @e keys_timeout.
+ */
+ struct GNUNET_SCHEDULER_Task *wakeup_task;
+
} set_exchanges;
/**
@@ -664,6 +683,11 @@ clean_order (void *cls)
GNUNET_free (rx->url);
GNUNET_free (rx);
}
+ if (NULL != oc->set_exchanges.wakeup_task)
+ {
+ GNUNET_SCHEDULER_cancel (oc->set_exchanges.wakeup_task);
+ oc->set_exchanges.wakeup_task = NULL;
+ }
if (NULL != oc->set_exchanges.exchanges)
{
json_decref (oc->set_exchanges.exchanges);
@@ -2105,6 +2129,28 @@ notify_kyc_required (const struct OrderContext *oc)
/**
+ * Task run when we are timing out on /keys and will just
+ * proceed with what we got.
+ *
+ * @param cls our `struct OrderContext *` to resume
+ */
+static void
+wakeup_timeout (void *cls)
+{
+ struct OrderContext *oc = cls;
+
+ oc->set_exchanges.wakeup_task = NULL;
+ GNUNET_assert (GNUNET_YES == oc->suspended);
+ GNUNET_CONTAINER_DLL_remove (oc_head,
+ oc_tail,
+ oc);
+ MHD_resume_connection (oc->connection);
+ oc->suspended = GNUNET_NO;
+ TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
+}
+
+
+/**
* Set list of acceptable exchanges in @a oc. Upon success, continue
* processing with set_max_fee().
*
@@ -2114,6 +2160,11 @@ notify_kyc_required (const struct OrderContext *oc)
static bool
set_exchanges (struct OrderContext *oc)
{
+ if (NULL != oc->set_exchanges.wakeup_task)
+ {
+ GNUNET_SCHEDULER_cancel (oc->set_exchanges.wakeup_task);
+ oc->set_exchanges.wakeup_task = NULL;
+ }
if (TALER_amount_is_zero (&oc->parse_order.brutto))
{
/* Total amount is zero, so we don't actually need exchanges! */
@@ -2127,6 +2178,8 @@ set_exchanges (struct OrderContext *oc)
matter. */
if (NULL == oc->set_exchanges.exchanges)
{
+ oc->set_exchanges.keys_timeout
+ = GNUNET_TIME_relative_to_absolute (MAX_KEYS_WAIT);
oc->set_exchanges.exchanges = json_array ();
GNUNET_assert (NULL != oc->set_exchanges.exchanges);
GNUNET_assert (
@@ -2147,11 +2200,29 @@ set_exchanges (struct OrderContext *oc)
oc);
}
}
+ if (GNUNET_TIME_absolute_is_past (oc->set_exchanges.keys_timeout))
+ {
+ struct RekeyExchange *rx;
+
+ while (NULL != (rx = oc->set_exchanges.pending_reload_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (oc->set_exchanges.pending_reload_head,
+ oc->set_exchanges.pending_reload_tail,
+ rx);
+ TMH_EXCHANGES_keys4exchange_cancel (rx->fo);
+ GNUNET_free (rx->url);
+ GNUNET_free (rx);
+ }
+ }
if (NULL != oc->set_exchanges.pending_reload_head)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Still trying to (re)load %skeys\n",
oc->set_exchanges.pending_reload_head->url);
+ oc->set_exchanges.wakeup_task
+ = GNUNET_SCHEDULER_add_at (oc->set_exchanges.keys_timeout,
+ &wakeup_timeout,
+ oc);
MHD_suspend_connection (oc->connection);
oc->suspended = GNUNET_YES;
GNUNET_CONTAINER_DLL_insert (oc_head,
diff --git a/src/include/taler_merchant_service.h b/src/include/taler_merchant_service.h
index 05ea273b..0ad7dc75 100644
--- a/src/include/taler_merchant_service.h
+++ b/src/include/taler_merchant_service.h
@@ -3239,6 +3239,21 @@ struct TALER_MERCHANT_PayResponse
// TODO: might want to return further details on errors,
// especially refund signatures on double-pay conflict.
+ struct
+ {
+
+ /**
+ * Array of exchange URLs which had legal problems.
+ */
+ const char **exchanges;
+
+ /**
+ * Length of the @e exchanges array.
+ */
+ unsigned int num_exchanges;
+
+ } unavailable_for_legal_reasons;
+
} details;
};