From 3db683d6e794c72448824d1e4ed75d6636bf3b22 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 1 May 2023 19:38:05 +0200 Subject: -fix FTBFS and /wire fetching logic --- src/backend/taler-merchant-httpd_exchanges.c | 278 ++++++++++----------- .../taler-merchant-httpd_post-orders-ID-pay.c | 3 + 2 files changed, 138 insertions(+), 143 deletions(-) (limited to 'src/backend') diff --git a/src/backend/taler-merchant-httpd_exchanges.c b/src/backend/taler-merchant-httpd_exchanges.c index 90875836..df38bca2 100644 --- a/src/backend/taler-merchant-httpd_exchanges.c +++ b/src/backend/taler-merchant-httpd_exchanges.c @@ -30,9 +30,10 @@ #define MAX_RETRIES 3 /** - * Delay after which we'll re-fetch key information from the exchange. + * Minimum delay after which we'll re-fetch key information from the exchange. */ -#define RELOAD_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2) +#define MIN_RELOAD_DELAY GNUNET_TIME_relative_multiply ( \ + GNUNET_TIME_UNIT_MINUTES, 2) /** * Delay after which we'll allow clients to force us to re-fetch key @@ -98,11 +99,6 @@ struct TMH_EXCHANGES_FindOperation */ struct Exchange *my_exchange; - /** - * Wire method we care about for fees, NULL if we do not care about wire fees. - */ - char *wire_method; - /** * Task scheduled to asynchronously return the result to * the find continuation. @@ -208,6 +204,11 @@ struct Exchange */ struct GNUNET_TIME_Absolute first_retry; + /** + * How soon should we re-download /keys? + */ + struct GNUNET_TIME_Timestamp keys_expiration; + /** * How long should we wait between the next retry? */ @@ -224,11 +225,11 @@ struct Exchange struct GNUNET_SCHEDULER_Task *retry_task; /** - * true to indicate that there is an ongoing - * transfer we are waiting for, - * false to indicate that key data is up-to-date. + * Falsoe to indicate that there is a /keys request + * we are waiting for. + * True to indicate that /keys data is up-to-date. */ - bool pending; + bool have_keys; /** * true if this exchange is from our configuration and @@ -278,10 +279,10 @@ json_t *TMH_trusted_exchanges; * a particular exchange and what key the exchange is using. * * @param cls closure, will be `struct Exchange` so that - * when this function gets called, it will change the flag 'pending' - * to 'false'. Note: 'keys' is automatically saved inside the exchange's + * when this function gets called, it will change the flag 'have_keys' + * to 'true'. Note: 'keys' is automatically saved inside the exchange's * handle, which is contained inside 'struct Exchange', when - * this callback is called. Thus, once 'pending' turns 'false', + * this callback is called. Thus, once 'have_keys' turns 'true', * it is safe to call 'TALER_EXCHANGE_get_keys()' on the exchange's handle, * in order to get the "good" keys. * @param kr response details @@ -577,6 +578,8 @@ process_wire_accounts (struct Exchange *exchange, { TMH_db->rollback (TMH_db->cls); GNUNET_break (0); + json_decref (debit_restrictions); + json_decref (credit_restrictions); return TALER_EC_MERCHANT_GENERIC_EXCHANGE_WIRE_REQUEST_FAILED; } } @@ -588,6 +591,8 @@ process_wire_accounts (struct Exchange *exchange, { TMH_db->rollback (TMH_db->cls); GNUNET_break (0); + json_decref (debit_restrictions); + json_decref (credit_restrictions); return TALER_EC_MERCHANT_GENERIC_EXCHANGE_WIRE_REQUEST_FAILED; } } @@ -598,6 +603,8 @@ process_wire_accounts (struct Exchange *exchange, debit_restrictions, credit_restrictions, &account->master_sig); + json_decref (debit_restrictions); + json_decref (credit_restrictions); if (qs < 0) { TMH_db->rollback (TMH_db->cls); @@ -677,87 +684,72 @@ process_find_operations (struct Exchange *exchange) { struct TMH_EXCHANGES_FindOperation *fn; struct GNUNET_TIME_Timestamp now; - bool need_wire; + if (! exchange->have_wire) + return true; now = GNUNET_TIME_timestamp_get (); - need_wire = false; - for (struct TMH_EXCHANGES_FindOperation *fo = exchange->fo_head; - NULL != fo; - fo = fn) + for (struct FeesByWireMethod *fbw = exchange->wire_fees_head; + NULL != fbw; + fbw = fbw->next) { - const struct FeesByWireMethod *fbw; + bool removed = false; - fn = fo->next; - if (NULL != fo->wire_method) + while ( (NULL != fbw->af) && + (GNUNET_TIME_timestamp_cmp (fbw->af->end_date, + <, + now)) ) { - /* Find fee structure for our wire method */ - fbw = get_wire_fees (exchange, - now, - fo->wire_method); - if (NULL == fbw) - { - need_wire = true; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Missing wire fees for exchange %s and method %s\n", - exchange->url, - fo->wire_method); - /* Do not warn if this is before our first attempt */ - if (! GNUNET_TIME_relative_is_zero (exchange->wire_retry_delay)) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Exchange does not support `%s' wire method (will retry later)\n", - fo->wire_method); - fbw = NULL; - continue; - } - if (NULL == fbw->af) - { - /* Disagreement on the current time */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Exchange has no wire fees configured for `%s' wire method (will retry later)\n", - fo->wire_method); - fbw = NULL; - continue; - } - if (GNUNET_TIME_timestamp_cmp (fbw->af->start_date, - >, - now)) + struct TALER_EXCHANGE_WireAggregateFees *af = fbw->af; + + fbw->af = af->next; + GNUNET_free (af); + removed = true; + } + if (NULL == fbw->af) + { + /* Disagreement on the current time */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Exchange has no wire fees configured for `%s' wire method\n", + fbw->wire_method); + if (removed) { - /* Disagreement on the current time */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Exchange's earliest fee is %s ahead of our time. Clock skew issue?\n", - GNUNET_TIME_relative2s ( - GNUNET_TIME_absolute_get_remaining ( - fbw->af->start_date.abs_time), - true)); - fbw = NULL; - continue; + exchange->have_wire = false; + return true; /* We just removed previous fees, try fetching update */ } } - else + if (GNUNET_TIME_timestamp_cmp (fbw->af->start_date, + >, + now)) { - /* no wire transfer method given, so we yield no fee */ - fbw = NULL; + /* Disagreement on the current time */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Exchange's earliest fee is %s ahead of our time. Clock skew issue?\n", + GNUNET_TIME_relative2s ( + GNUNET_TIME_absolute_get_remaining ( + fbw->af->start_date.abs_time), + true)); } - { - struct TALER_EXCHANGE_HttpResponse hr = { - .http_status = MHD_HTTP_OK, - }; + } - if ( (NULL != fo->wire_method) && - (! exchange->have_wire) ) - { - /* We needed /wire, but didn't get it. That's not "200 OK". */ - hr.http_status = MHD_HTTP_BAD_GATEWAY; - hr.ec = TALER_EC_MERCHANT_GENERIC_EXCHANGE_WIRE_REQUEST_FAILED; - } - fo->fc (fo->fc_cls, - &hr, - exchange->conn, - exchange->trusted); - } + if (! exchange->have_wire) + return true; /* need /wire response to continue */ + fn = NULL; + for (struct TMH_EXCHANGES_FindOperation *fo = exchange->fo_head; + NULL != fo; + fo = fn) + { + struct TALER_EXCHANGE_HttpResponse hr = { + .http_status = MHD_HTTP_OK, + }; + + fo->fc (fo->fc_cls, + &hr, + exchange->conn, + exchange->trusted); + fn = fo->next; TMH_EXCHANGES_find_exchange_cancel (fo); } - return need_wire; + return false; } @@ -772,7 +764,7 @@ wire_task_cb (void *cls); * If the request fails to generate a valid response from the * exchange, @a http_status will also be zero. * - * Must only be called if 'exchange->pending' is #GNUNET_NO, + * Must only be called if 'exchange->have_keys' is true. * that is #TALER_EXCHANGE_get_keys() will succeed. * * @param cls closure, a `struct Exchange` @@ -855,8 +847,8 @@ handle_wire_data (void *cls, exchange->wire_retry_delay); exchange->wire_retry_delay = RETRY_BACKOFF (exchange->wire_retry_delay); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Exchange does not support our wire method. Retrying in %s\n", - + "Need %s/wire, next download attempt in %s\n", + exchange->url, GNUNET_STRINGS_relative_time_to_string ( exchange->wire_retry_delay, true)); @@ -874,7 +866,7 @@ handle_wire_data (void *cls, * the callback. If requests without /wire data remain, * retry the /wire request after some delay. * - * Must only be called if 'exchange->pending' is #GNUNET_NO, + * Must only be called if 'exchange->have_keys' is true, * that is #TALER_EXCHANGE_get_keys() will succeed. * * @param cls a `struct Exchange` to check @@ -885,7 +877,7 @@ wire_task_cb (void *cls) struct Exchange *exchange = cls; exchange->wire_task = NULL; - GNUNET_assert (! exchange->pending); + GNUNET_assert (exchange->have_keys); if (! process_find_operations (exchange)) return; /* no more need */ GNUNET_assert (NULL == exchange->wire_request); @@ -965,7 +957,7 @@ fail_and_retry (struct Exchange *exchange, { struct TMH_EXCHANGES_FindOperation *fo; - exchange->pending = true; + exchange->have_keys = false; if (NULL != exchange->wire_request) { TALER_EXCHANGE_wire_cancel (exchange->wire_request); @@ -998,7 +990,7 @@ fail_and_retry (struct Exchange *exchange, (int) hr->ec, hr->http_status, GNUNET_STRINGS_relative_time_to_string (exchange->retry_delay, - GNUNET_YES)); + true)); if (NULL != exchange->retry_task) GNUNET_SCHEDULER_cancel (exchange->retry_task); exchange->first_retry = GNUNET_TIME_relative_to_absolute ( @@ -1014,7 +1006,6 @@ keys_mgmt_cb (void *cls, const struct TALER_EXCHANGE_KeysResponse *kr) { struct Exchange *exchange = cls; - struct GNUNET_TIME_Timestamp expire; struct GNUNET_TIME_Relative delay; const struct TALER_EXCHANGE_Keys *keys; @@ -1077,26 +1068,19 @@ keys_mgmt_cb (void *cls, } } - exchange->first_retry = GNUNET_TIME_relative_to_absolute (RELOAD_DELAY); - expire = TALER_EXCHANGE_check_keys_current (exchange->conn, - TALER_EXCHANGE_CKF_NONE); - if (0 == GNUNET_TIME_absolute_is_zero (expire.abs_time)) - { - delay = RELOAD_DELAY; - } - else - { - delay = GNUNET_TIME_absolute_get_remaining (expire.abs_time); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "/keys response from expires at %s! Retrying at that time!\n", - GNUNET_TIME_absolute2s (expire.abs_time)); - } - if (GNUNET_TIME_relative_is_zero (delay)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "/keys response from exchange expired immediately! Retrying in 1 minute.\n"); - delay = GNUNET_TIME_UNIT_MINUTES; - } + exchange->first_retry + = GNUNET_TIME_relative_to_absolute (MIN_RELOAD_DELAY); + exchange->keys_expiration + = TALER_EXCHANGE_check_keys_current (exchange->conn, + TALER_EXCHANGE_CKF_NONE); + delay = GNUNET_TIME_absolute_get_remaining ( + exchange->keys_expiration.abs_time); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "/keys response from expires at %s! Retrying at that time!\n", + GNUNET_TIME_absolute2s ( + exchange->keys_expiration.abs_time)); + delay = GNUNET_TIME_relative_max (delay, + MIN_RELOAD_DELAY); exchange->retry_delay = GNUNET_TIME_UNIT_ZERO; if (NULL != exchange->retry_task) GNUNET_SCHEDULER_cancel (exchange->retry_task); @@ -1104,16 +1088,17 @@ keys_mgmt_cb (void *cls, = GNUNET_SCHEDULER_add_delayed (delay, &retry_exchange, exchange); - exchange->pending = false; + exchange->have_keys = true; if ( (process_find_operations (exchange)) && (NULL == exchange->wire_request) && (NULL == exchange->wire_task) ) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got key data, but also need wire data. Will request /wire now\n"); - exchange->wire_request = TALER_EXCHANGE_wire (exchange->conn, - &handle_wire_data, - exchange); + exchange->wire_request + = TALER_EXCHANGE_wire (exchange->conn, + &handle_wire_data, + exchange); } } @@ -1132,13 +1117,16 @@ return_result (void *cls) fo->at = NULL; if ( (process_find_operations (exchange)) && (NULL == exchange->wire_request) && - (! exchange->pending) && + (exchange->have_keys) && (NULL != exchange->wire_task) ) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Do not have current wire data. Will re-request /wire in 1 minute\n"); + "Do not have current wire data. Will re-request /wire in %s\n", + GNUNET_STRINGS_relative_time_to_string ( + exchange->wire_retry_delay, + true)); exchange->wire_task - = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, + = GNUNET_SCHEDULER_add_delayed (exchange->wire_retry_delay, &wire_task_cb, exchange); } @@ -1172,8 +1160,6 @@ TMH_EXCHANGES_find_exchange (const char *chosen_exchange, { struct Exchange *exchange; struct TMH_EXCHANGES_FindOperation *fo; - struct GNUNET_TIME_Timestamp now; - const char *wire_method = NULL; if (NULL == merchant_curl_ctx) { @@ -1190,7 +1176,6 @@ TMH_EXCHANGES_find_exchange (const char *chosen_exchange, /* This is a new exchange */ exchange = GNUNET_new (struct Exchange); exchange->url = GNUNET_strdup (chosen_exchange); - exchange->pending = true; GNUNET_CONTAINER_DLL_insert (exchange_head, exchange_tail, exchange); @@ -1203,13 +1188,13 @@ TMH_EXCHANGES_find_exchange (const char *chosen_exchange, fo->fc = fc; fo->fc_cls = fc_cls; fo->my_exchange = exchange; - if (NULL != wire_method) - fo->wire_method = GNUNET_strdup (wire_method); GNUNET_CONTAINER_DLL_insert (exchange->fo_head, exchange->fo_tail, fo); - if ( (force_reload) && - (GNUNET_TIME_absolute_is_past (exchange->first_retry)) ) + if ( (GNUNET_TIME_absolute_is_past (exchange->first_retry)) && + (force_reload || + (GNUNET_TIME_absolute_is_past ( + exchange->keys_expiration.abs_time))) ) { /* increment exponential-backoff */ exchange->retry_delay = RETRY_BACKOFF (exchange->retry_delay); @@ -1222,25 +1207,20 @@ TMH_EXCHANGES_find_exchange (const char *chosen_exchange, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "/keys retry forced, waiting until %s\n", GNUNET_TIME_absolute2s (exchange->first_retry)); - /* NOTE: return value tells us how long /keys should still - be valid. */ - (void) TALER_EXCHANGE_check_keys_current (exchange->conn, - TALER_EXCHANGE_CKF_FORCE_DOWNLOAD); + exchange->keys_expiration + = TALER_EXCHANGE_check_keys_current (exchange->conn, + TALER_EXCHANGE_CKF_FORCE_DOWNLOAD); return fo; } - now = GNUNET_TIME_timestamp_get (); - if ( (! exchange->pending) && - ( (NULL == fo->wire_method) || - (NULL != get_wire_fees (exchange, - now, - fo->wire_method)) ) ) + if ( (exchange->have_keys) && + (exchange->have_wire) ) { /* We are not currently waiting for a reply, immediately return result */ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "The exchange `%s' is ready\n", - chosen_exchange); + exchange->url); GNUNET_assert (NULL == fo->at); fo->at = GNUNET_SCHEDULER_add_now (&return_result, fo); @@ -1250,23 +1230,28 @@ TMH_EXCHANGES_find_exchange (const char *chosen_exchange, /* If new or resumed, (re)try fetching /keys */ if ( (NULL == exchange->conn) && (NULL == exchange->retry_task) && - (exchange->pending) ) + (! exchange->have_keys) ) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Do not have current /keys data for `%s'. Will request /keys now\n", - chosen_exchange); + exchange->url); exchange->retry_task = GNUNET_SCHEDULER_add_now (&retry_exchange, exchange); + return fo; } - else if ( (! exchange->pending) && - (NULL == exchange->wire_task) && - (NULL == exchange->wire_request) ) + if ( (exchange->have_keys) && + (! exchange->have_wire) && + (NULL == exchange->wire_task) && + (NULL == exchange->wire_request) ) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Do not have required wire data. Will re-request /wire now\n"); + "Do not have required /wire data. Will re-request %s/wire now\n", + exchange->url); exchange->wire_task = GNUNET_SCHEDULER_add_now (&wire_task_cb, exchange); + return fo; } + /* No activity to launch, we are already doing so */ return fo; } @@ -1284,7 +1269,6 @@ TMH_EXCHANGES_find_exchange_cancel (struct TMH_EXCHANGES_FindOperation *fo) GNUNET_CONTAINER_DLL_remove (exchange->fo_head, exchange->fo_tail, fo); - GNUNET_free (fo->wire_method); GNUNET_free (fo); } @@ -1378,7 +1362,6 @@ accept_exchanges (void *cls, GNUNET_CONTAINER_DLL_insert (exchange_head, exchange_tail, exchange); - exchange->pending = true; GNUNET_assert (NULL == exchange->retry_task); exchange->retry_task = GNUNET_SCHEDULER_add_now (&retry_exchange, exchange); @@ -1396,9 +1379,18 @@ TMH_EXCHANGES_lookup_wire_fee (const char *exchange_url, exchange = lookup_exchange (exchange_url); if (NULL == exchange) + { + fprintf (stderr, + "No %s yet\n", + exchange_url); return GNUNET_SYSERR; + } if (! exchange->have_wire) + { + fprintf (stderr, + "No wire yet\n"); return GNUNET_SYSERR; + } fbm = get_wire_fees (exchange, GNUNET_TIME_timestamp_get (), wire_method); diff --git a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c index 55e345e6..afec3b25 100644 --- a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c +++ b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c @@ -1440,6 +1440,9 @@ AGE_FAIL: { enum TALER_ErrorCode ec; + fprintf (stderr, + "%d\n", + ret); ec = (GNUNET_NO == ret) ? TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED : TALER_EC_MERCHANT_GENERIC_EXCHANGE_WIRE_REQUEST_FAILED; -- cgit v1.2.3