commit e2b004b38d75e69a6b12f842107e5778a51c4f42
parent 550a9adee3a7307b7a0d8bffa5f5b15fec9452b6
Author: Christian Grothoff <christian@grothoff.org>
Date: Thu, 12 Dec 2024 00:01:22 +0100
add missing timeout logic (#9303)
Diffstat:
6 files changed, 101 insertions(+), 25 deletions(-)
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
@@ -142,6 +142,11 @@ struct GNUNET_TIME_Relative TEH_max_keys_caching;
struct GNUNET_TIME_Relative TEH_reserve_closing_delay;
/**
+ * How long do we allow AML programs to run?
+ */
+struct GNUNET_TIME_Relative TEH_aml_program_timeout;
+
+/**
* Master public key (according to the
* configuration in the exchange directory). (global)
*/
@@ -2220,6 +2225,20 @@ exchange_serve_process_config (const char *cfg_fn)
= GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_WEEKS,
4);
}
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
+ "exchangedb",
+ "MAX_AML_PROGRAM_RUNTIME",
+ &TEH_aml_program_timeout))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchangedb",
+ "MAX_AML_PROGRAM_RUNTIME");
+ /* use default */
+ TEH_aml_program_timeout
+ = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES,
+ 1);
+ }
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
diff --git a/src/exchange/taler-exchange-httpd.h b/src/exchange/taler-exchange-httpd.h
@@ -42,6 +42,11 @@ extern struct GNUNET_TIME_Relative TEH_max_keys_caching;
extern struct GNUNET_TIME_Relative TEH_reserve_closing_delay;
/**
+ * How long do we allow AML programs to run?
+ */
+extern struct GNUNET_TIME_Relative TEH_aml_program_timeout;
+
+/**
* The exchange's configuration.
*/
extern const struct GNUNET_CONFIGURATION_Handle *TEH_cfg;
diff --git a/src/exchange/taler-exchange-httpd_common_kyc.c b/src/exchange/taler-exchange-httpd_common_kyc.c
@@ -160,23 +160,16 @@ kyc_aml_finished (
struct TEH_KycMeasureRunContext *kat = cls;
enum GNUNET_DB_QueryStatus qs;
struct GNUNET_AsyncScopeSave old_scope;
- enum GNUNET_GenericReturnValue res;
kat->kyc_aml = NULL;
- GNUNET_async_scope_enter (&kat->scope,
- &old_scope);
- res = TEH_plugin->start (TEH_plugin->cls,
- "kyc-persist-aml-program-result");
- if (GNUNET_OK != res)
+ if (NULL != kat->async_task)
{
- GNUNET_break (0);
- kat->cb (kat->cb_cls,
- TALER_EC_GENERIC_DB_START_FAILED,
- "kyc-persist-aml-program-result");
- TEH_kyc_run_measure_cancel (kat);
- GNUNET_async_scope_restore (&old_scope);
- return;
+ GNUNET_SCHEDULER_cancel (kat->async_task);
+ kat->async_task = NULL;
}
+ GNUNET_async_scope_enter (&kat->scope,
+ &old_scope);
+ TEH_plugin->preflight (TEH_plugin->cls);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"AML program finished with status %d\n",
(int) apr->status);
@@ -191,7 +184,6 @@ kyc_aml_finished (
case GNUNET_DB_STATUS_SOFT_ERROR:
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
GNUNET_break (0);
- TEH_plugin->rollback (TEH_plugin->cls);
kat->cb (kat->cb_cls,
TALER_EC_GENERIC_DB_STORE_FAILED,
"persist_aml_program_result");
@@ -201,17 +193,6 @@ kyc_aml_finished (
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
break;
}
- qs = TEH_plugin->commit (TEH_plugin->cls);
- if (qs < 0)
- {
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- kat->cb (kat->cb_cls,
- GNUNET_DB_STATUS_SOFT_ERROR == qs
- ? TALER_EC_GENERIC_DB_SOFT_FAILURE
- : TALER_EC_GENERIC_DB_COMMIT_FAILED,
- "kyc-persist-aml-program-result");
- return;
- }
switch (apr->status)
{
case TALER_KYCLOGIC_AMLR_FAILURE:
@@ -366,6 +347,37 @@ TEH_kyc_store_attributes (
}
+/**
+ * Task run when an AML program takes too long and runs into a
+ * timeout. Kills the AML program and reports an error.
+ *
+ * @param cls a `struct TEH_KycMeasureRunContext *`
+ */
+static void
+kyc_aml_timeout (void *cls)
+{
+ struct TEH_KycMeasureRunContext *kat = cls;
+ const char *prog_name
+ = TALER_KYCLOGIC_run_aml_program_get_name (kat->kyc_aml);
+ struct TALER_KYCLOGIC_AmlProgramResult apr = {
+ .status = TALER_KYCLOGIC_AMLR_FAILURE,
+ .details.failure.fallback_measure
+ = TALER_KYCLOGIC_get_aml_program_fallback (prog_name),
+ .details.failure.error_message = prog_name,
+ .details.failure.ec = TALER_EC_EXCHANGE_KYC_GENERIC_AML_PROGRAM_TIMEOUT
+ };
+
+ kat->async_task = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "AML program `%s' exceeded maximum runtime. Aborting it.\n",
+ prog_name);
+ TALER_KYCLOGIC_run_aml_program_cancel (kat->kyc_aml);
+ kat->kyc_aml = NULL;
+ kyc_aml_finished (kat,
+ &apr);
+}
+
+
struct TEH_KycMeasureRunContext *
TEH_kyc_run_measure_for_attributes (
const struct GNUNET_AsyncScopeId *scope,
@@ -409,6 +421,11 @@ TEH_kyc_run_measure_for_attributes (
.attribute_key = &TEH_attribute_key
};
+ GNUNET_assert (NULL == kat->async_task);
+ kat->async_task
+ = GNUNET_SCHEDULER_add_delayed (TEH_aml_program_timeout,
+ &kyc_aml_timeout,
+ kat);
kat->kyc_aml
= TALER_KYCLOGIC_run_aml_program (
kat->jmeasures,
@@ -539,6 +556,11 @@ TEH_kyc_run_measure_directly (
.attribute_key = &TEH_attribute_key
};
+ GNUNET_assert (NULL == kat->async_task);
+ kat->async_task
+ = GNUNET_SCHEDULER_add_delayed (TEH_aml_program_timeout,
+ &kyc_aml_timeout,
+ kat);
kat->kyc_aml
= TALER_KYCLOGIC_run_aml_program3 (
instant_ms,
diff --git a/src/exchangedb/exchangedb_aml.c b/src/exchangedb/exchangedb_aml.c
@@ -313,6 +313,12 @@ aml_result_callback (
}
+/**
+ * Task run when an AML program takes too long and runs into a
+ * timeout. Kills the AML program and reports an error.
+ *
+ * @param cls a `struct TEH_KycMeasureRunContext *`
+ */
static void
aml_program_timeout (void *cls)
{
@@ -328,6 +334,8 @@ aml_program_timeout (void *cls)
enum GNUNET_DB_QueryStatus qs;
ru->t = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "AML program hit timeout!\n");
TALER_KYCLOGIC_run_aml_program_cancel (ru->amlh);
ru->amlh = NULL;
GNUNET_assert (NULL != apr.details.failure.fallback_measure);
diff --git a/src/include/taler_kyclogic_lib.h b/src/include/taler_kyclogic_lib.h
@@ -1091,6 +1091,18 @@ TALER_KYCLOGIC_run_aml_program3 (
/**
+ * Get the name of the AML program run by @a aprh.
+ * Can of course only be called while @a aprh is running.
+ *
+ * @param aprh handle to the AML program
+ * @return name of the AML program
+ */
+const char *
+TALER_KYCLOGIC_run_aml_program_get_name (
+ const struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh);
+
+
+/**
* Cancel running AML program.
*
* @param[in] aprh handle of program to cancel
diff --git a/src/kyclogic/kyclogic_api.c b/src/kyclogic/kyclogic_api.c
@@ -4244,12 +4244,22 @@ TALER_KYCLOGIC_run_aml_program3 (
}
+const char *
+TALER_KYCLOGIC_run_aml_program_get_name (
+ const struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh)
+{
+ return aprh->program->program_name;
+}
+
+
void
TALER_KYCLOGIC_run_aml_program_cancel (
struct TALER_KYCLOGIC_AmlProgramRunnerHandle *aprh)
{
if (NULL != aprh->proc)
{
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Killing AML program\n");
TALER_JSON_external_conversion_stop (aprh->proc);
aprh->proc = NULL;
}