exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

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:
Msrc/exchange/taler-exchange-httpd.c | 19+++++++++++++++++++
Msrc/exchange/taler-exchange-httpd.h | 5+++++
Msrc/exchange/taler-exchange-httpd_common_kyc.c | 72+++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/exchangedb/exchangedb_aml.c | 8++++++++
Msrc/include/taler_kyclogic_lib.h | 12++++++++++++
Msrc/kyclogic/kyclogic_api.c | 10++++++++++
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; }