diff options
author | Christian Grothoff <christian@grothoff.org> | 2023-06-25 16:09:11 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2023-06-25 16:09:11 +0200 |
commit | 0d8aeec575f6e12bb06a5eedeabf70436058595a (patch) | |
tree | cf119dc4cc4463763fce2566a504d549145b1367 | |
parent | bb0967ea0f5d501079981ea33f21f4c133815234 (diff) |
-adapt to latest exchange API change
-rw-r--r-- | src/backend/taler-merchant-httpd_exchanges.c | 402 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_exchanges.h | 80 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_post-orders-ID-pay.c | 213 |
3 files changed, 580 insertions, 115 deletions
diff --git a/src/backend/taler-merchant-httpd_exchanges.c b/src/backend/taler-merchant-httpd_exchanges.c index 090cef95..5bce19a4 100644 --- a/src/backend/taler-merchant-httpd_exchanges.c +++ b/src/backend/taler-merchant-httpd_exchanges.c @@ -104,6 +104,86 @@ struct TMH_EXCHANGES_FindOperation /** + * Information we keep for a pending #MMH_EXCHANGES_keys4exchange() operation. + */ +struct TMH_EXCHANGES_Find2Operation +{ + + /** + * Kept in a DLL. + */ + struct TMH_EXCHANGES_Find2Operation *next; + + /** + * Kept in a DLL. + */ + struct TMH_EXCHANGES_Find2Operation *prev; + + /** + * Function to call with the result. + */ + TMH_EXCHANGES_Find2Continuation fc; + + /** + * Closure for @e fc. + */ + void *fc_cls; + + /** + * Exchange we wait for the /keys for. + */ + struct TMH_Exchange *my_exchange; + + /** + * Task scheduled to asynchronously return the result to + * the find continuation. + */ + struct GNUNET_SCHEDULER_Task *at; + +}; + + +/** + * Information we keep for a pending #MMH_EXCHANGES_wire4exchange() operation. + */ +struct TMH_EXCHANGES_WireOperation +{ + + /** + * Kept in a DLL. + */ + struct TMH_EXCHANGES_WireOperation *next; + + /** + * Kept in a DLL. + */ + struct TMH_EXCHANGES_WireOperation *prev; + + /** + * Function to call with the result. + */ + TMH_EXCHANGES_WireContinuation fc; + + /** + * Closure for @e fc. + */ + void *fc_cls; + + /** + * Exchange we wait for the /wire for. + */ + struct TMH_Exchange *my_exchange; + + /** + * Task scheduled to asynchronously return the result to + * the find continuation. + */ + struct GNUNET_SCHEDULER_Task *at; + +}; + + +/** * Information about wire transfer fees of an exchange, by wire method. */ struct FeesByWireMethod @@ -240,6 +320,26 @@ struct TMH_Exchange struct TMH_EXCHANGES_FindOperation *fo_tail; /** + * Head of FOs pending for this exchange. + */ + struct TMH_EXCHANGES_Find2Operation *fo2_head; + + /** + * Tail of FOs pending for this exchange. + */ + struct TMH_EXCHANGES_Find2Operation *fo2_tail; + + /** + * Head of /wire pending for this exchange. + */ + struct TMH_EXCHANGES_WireOperation *w_head; + + /** + * Tail of /wire pending for this exchange. + */ + struct TMH_EXCHANGES_WireOperation *w_tail; + + /** * Head of accounts of this exchange. */ struct ExchangeAccount *acc_head; @@ -891,8 +991,20 @@ static bool process_find_operations (struct TMH_Exchange *exchange) { struct TMH_EXCHANGES_FindOperation *fn; + struct TMH_EXCHANGES_Find2Operation *fn2; + struct TMH_EXCHANGES_WireOperation *wn; struct GNUNET_TIME_Timestamp now; + fn2 = NULL; + for (struct TMH_EXCHANGES_Find2Operation *fo = exchange->fo2_head; + NULL != fo; + fo = fn2) + { + fo->fc (fo->fc_cls, + TALER_EXCHANGE_get_keys (exchange->conn)); + fn2 = fo->next; + TMH_EXCHANGES_keys4exchange_cancel (fo); + } if (! exchange->have_wire) return true; now = GNUNET_TIME_timestamp_get (); @@ -957,6 +1069,16 @@ process_find_operations (struct TMH_Exchange *exchange) fn = fo->next; TMH_EXCHANGES_find_exchange_cancel (fo); } + wn = NULL; + for (struct TMH_EXCHANGES_WireOperation *w = exchange->w_head; + NULL != w; + w = wn) + { + w->fc (w->fc_cls, + exchange); + wn = w->next; + TMH_EXCHANGES_wire4exchange_cancel (w); + } return false; } @@ -992,6 +1114,7 @@ handle_wire_data (void *cls, if (MHD_HTTP_OK != wr->hr.http_status) { struct TMH_EXCHANGES_FindOperation *fo; + struct TMH_EXCHANGES_WireOperation *w; exchange->have_wire = false; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, @@ -1007,6 +1130,12 @@ handle_wire_data (void *cls, false); TMH_EXCHANGES_find_exchange_cancel (fo); } + while (NULL != (w = exchange->w_head)) + { + w->fc (w->fc_cls, + NULL); + TMH_EXCHANGES_wire4exchange_cancel (w); + } return; } keys = TALER_EXCHANGE_get_keys (exchange->conn); @@ -1024,6 +1153,7 @@ handle_wire_data (void *cls, { /* Report hard failure to all callbacks! */ struct TMH_EXCHANGES_FindOperation *fo; + struct TMH_EXCHANGES_Find2Operation *fo2; struct TALER_EXCHANGE_HttpResponse hrx = { .ec = ecx, .http_status = 0, @@ -1040,6 +1170,12 @@ handle_wire_data (void *cls, false); TMH_EXCHANGES_find_exchange_cancel (fo); } + while (NULL != (fo2 = exchange->fo2_head)) + { + fo2->fc (fo2->fc_cls, + NULL); + TMH_EXCHANGES_keys4exchange_cancel (fo2); + } return; } exchange->have_wire = true; @@ -1148,6 +1284,10 @@ free_exchange_entry (struct TMH_Exchange *exchange) } GNUNET_assert (NULL == exchange->fo_head); GNUNET_assert (NULL == exchange->fo_tail); + GNUNET_assert (NULL == exchange->fo2_head); + GNUNET_assert (NULL == exchange->fo2_tail); + GNUNET_assert (NULL == exchange->w_head); + GNUNET_assert (NULL == exchange->w_tail); GNUNET_free (exchange->url); GNUNET_free (exchange); } @@ -1165,6 +1305,8 @@ fail_and_retry (struct TMH_Exchange *exchange, const struct TALER_EXCHANGE_HttpResponse *hr) { struct TMH_EXCHANGES_FindOperation *fo; + struct TMH_EXCHANGES_Find2Operation *fo2; + struct TMH_EXCHANGES_WireOperation *w; exchange->have_keys = false; if (NULL != exchange->wire_request) @@ -1185,6 +1327,18 @@ fail_and_retry (struct TMH_Exchange *exchange, false); TMH_EXCHANGES_find_exchange_cancel (fo); } + while (NULL != (fo2 = exchange->fo2_head)) + { + fo2->fc (fo2->fc_cls, + NULL); + TMH_EXCHANGES_keys4exchange_cancel (fo2); + } + while (NULL != (w = exchange->w_head)) + { + w->fc (w->fc_cls, + NULL); + TMH_EXCHANGES_wire4exchange_cancel (w); + } if ( (NULL == exchange->fo_head) && (TALER_EC_GENERIC_CONFIGURATION_INVALID == hr->ec) ) { @@ -1345,6 +1499,38 @@ return_result (void *cls) /** + * Task to return find operation result asynchronously to caller. + * + * @param cls a `struct TMH_EXCHANGES_Find2Operation` + */ +static void +return_result2 (void *cls) +{ + struct TMH_EXCHANGES_Find2Operation *fo = cls; + struct TMH_Exchange *exchange = fo->my_exchange; + + fo->at = NULL; + process_find_operations (exchange); +} + + +/** + * Task to return find operation result asynchronously to caller. + * + * @param cls a `struct TMH_EXCHANGES_WireOperation` + */ +static void +return_wire_result (void *cls) +{ + struct TMH_EXCHANGES_WireOperation *w = cls; + struct TMH_Exchange *exchange = w->my_exchange; + + w->at = NULL; + process_find_operations (exchange); +} + + +/** * Lookup exchange by @a exchange_url. * * @param exchange_url base URL to match against @@ -1481,6 +1667,188 @@ TMH_EXCHANGES_find_exchange (const char *chosen_exchange, } +struct TMH_EXCHANGES_Find2Operation * +TMH_EXCHANGES_keys4exchange ( + const char *chosen_exchange, + TMH_EXCHANGES_Find2Continuation fc, + void *fc_cls) +{ + struct TMH_Exchange *exchange; + struct TMH_EXCHANGES_Find2Operation *fo; + + if (NULL == merchant_curl_ctx) + { + GNUNET_break (0); + return NULL; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Trying to find chosen exchange `%s'\n", + chosen_exchange); + /* Check if the exchange is known */ + exchange = lookup_exchange (chosen_exchange); + if (NULL == exchange) + { + /* This is a new exchange */ + exchange = GNUNET_new (struct TMH_Exchange); + exchange->url = GNUNET_strdup (chosen_exchange); + GNUNET_CONTAINER_DLL_insert (exchange_head, + exchange_tail, + exchange); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "The exchange `%s' is new\n", + chosen_exchange); + } + + fo = GNUNET_new (struct TMH_EXCHANGES_Find2Operation); + fo->fc = fc; + fo->fc_cls = fc_cls; + fo->my_exchange = exchange; + GNUNET_CONTAINER_DLL_insert (exchange->fo2_head, + exchange->fo2_tail, + fo); + + if (GNUNET_TIME_absolute_is_past (exchange->first_retry)) + { + /* increment exponential-backoff */ + exchange->retry_delay = RETRY_BACKOFF (exchange->retry_delay); + /* do not allow forced check until both backoff and #FORCED_RELOAD_DELAY + are satisfied again */ + exchange->first_retry + = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_max ( + exchange->retry_delay, + FORCED_RELOAD_DELAY)); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "/keys retry forced, waiting until %s\n", + GNUNET_TIME_absolute2s (exchange->first_retry)); + if (NULL == exchange->conn) + { + /* Not connected at all yet */ + exchange->retry_task + = GNUNET_SCHEDULER_add_now (&retry_exchange, + exchange); + } + else + { + /* Use existing connection, but update /keys */ + exchange->keys_expiration + = TALER_EXCHANGE_check_keys_current (exchange->conn, + TALER_EXCHANGE_CKF_FORCE_DOWNLOAD, + NULL, + NULL); + } + return fo; + } + + if (exchange->have_keys) + { + /* We are not currently waiting for a reply, immediately + return result */ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "The exchange `%s' is ready\n", + exchange->url); + GNUNET_assert (NULL == fo->at); + fo->at = GNUNET_SCHEDULER_add_now (&return_result2, + fo); + return fo; + } + + /* If new or resumed, (re)try fetching /keys */ + if ( (NULL == exchange->conn) && + (NULL == exchange->retry_task) && + (! exchange->have_keys) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Do not have current /keys data for `%s'. Will request /keys now\n", + exchange->url); + exchange->retry_task = GNUNET_SCHEDULER_add_now (&retry_exchange, + exchange); + return fo; + } + /* No activity to launch, we are already doing so */ + return fo; +} + + +struct TMH_EXCHANGES_WireOperation * +TMH_EXCHANGES_wire4exchange ( + const char *chosen_exchange, + TMH_EXCHANGES_WireContinuation fc, + void *fc_cls) +{ + struct TMH_Exchange *exchange; + struct TMH_EXCHANGES_WireOperation *w; + + if (NULL == merchant_curl_ctx) + { + GNUNET_break (0); + return NULL; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Trying to find chosen exchange `%s'\n", + chosen_exchange); + /* Check if the exchange is known */ + exchange = lookup_exchange (chosen_exchange); + if (NULL == exchange) + { + /* This is a new exchange */ + exchange = GNUNET_new (struct TMH_Exchange); + exchange->url = GNUNET_strdup (chosen_exchange); + GNUNET_CONTAINER_DLL_insert (exchange_head, + exchange_tail, + exchange); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "The exchange `%s' is new\n", + chosen_exchange); + } + + w = GNUNET_new (struct TMH_EXCHANGES_WireOperation); + w->fc = fc; + w->fc_cls = fc_cls; + w->my_exchange = exchange; + GNUNET_CONTAINER_DLL_insert (exchange->w_head, + exchange->w_tail, + w); + if (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", + exchange->url); + GNUNET_assert (NULL == w->at); + w->at = GNUNET_SCHEDULER_add_now (&return_wire_result, + w); + return w; + } + + if (NULL == exchange->wire_request) + { + if (NULL == exchange->conn) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Requesting /keys from `%s' to connect\n", + exchange->url); + exchange->conn = TALER_EXCHANGE_connect (merchant_curl_ctx, + exchange->url, + &keys_mgmt_cb, + exchange, + TALER_EXCHANGE_OPTION_END); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Requesting /wire from `%s'\n", + exchange->url); + exchange->wire_request + = TALER_EXCHANGE_wire (exchange->conn, + &handle_wire_data, + exchange); + } + } + return w; +} + + void TMH_EXCHANGES_find_exchange_cancel (struct TMH_EXCHANGES_FindOperation *fo) { @@ -1498,6 +1866,40 @@ TMH_EXCHANGES_find_exchange_cancel (struct TMH_EXCHANGES_FindOperation *fo) } +void +TMH_EXCHANGES_keys4exchange_cancel (struct TMH_EXCHANGES_Find2Operation *fo) +{ + struct TMH_Exchange *exchange = fo->my_exchange; + + if (NULL != fo->at) + { + GNUNET_SCHEDULER_cancel (fo->at); + fo->at = NULL; + } + GNUNET_CONTAINER_DLL_remove (exchange->fo2_head, + exchange->fo2_tail, + fo); + GNUNET_free (fo); +} + + +void +TMH_EXCHANGES_wire4exchange_cancel (struct TMH_EXCHANGES_WireOperation *w) +{ + struct TMH_Exchange *exchange = w->my_exchange; + + if (NULL != w->at) + { + GNUNET_SCHEDULER_cancel (w->at); + w->at = NULL; + } + GNUNET_CONTAINER_DLL_remove (exchange->w_head, + exchange->w_tail, + w); + GNUNET_free (w); +} + + /** * Function called on each configuration section. Finds sections * about exchanges, parses the entries and tries to connect to diff --git a/src/backend/taler-merchant-httpd_exchanges.h b/src/backend/taler-merchant-httpd_exchanges.h index 23424f40..89ba4030 100644 --- a/src/backend/taler-merchant-httpd_exchanges.h +++ b/src/backend/taler-merchant-httpd_exchanges.h @@ -100,10 +100,46 @@ typedef void /** + * Function called with the result of a #TMH_EXCHANGES_keys4exchange() + * operation. + * + * @param cls closure + * @param keys the keys of the exchange + */ +typedef void +(*TMH_EXCHANGES_Find2Continuation)( + void *cls, + struct TALER_EXCHANGE_Keys *keys); + + +/** + * Function called with the result of a #TMH_EXCHANGES_wire4exchange() + * operation. + * + * @param cls closure + * @param wire the wire data of the exchange + */ +typedef void +(*TMH_EXCHANGES_WireContinuation)( + void *cls, + struct TMH_Exchange *wire); + + +/** * Information we keep for a pending #MMH_EXCHANGES_find_exchange() operation. */ struct TMH_EXCHANGES_FindOperation; +/** + * Information we keep for a pending #MMH_EXCHANGES_keys4exchange() operation. + */ +struct TMH_EXCHANGES_Find2Operation; + +/** + * Information we keep for a pending #MMH_EXCHANGES_wire4exchange() operation. + */ +struct TMH_EXCHANGES_WireOperation; + /** * Find a exchange that matches @a chosen_exchange. If we cannot connect @@ -124,6 +160,32 @@ TMH_EXCHANGES_find_exchange (const char *chosen_exchange, /** + * Get /keys of the given @a exchange. + * + * @param exchange URL of the exchange we would like to talk to + * @param fc function to call with the handles for the exchange + * @param fc_cls closure for @a fc + */ +struct TMH_EXCHANGES_Find2Operation * +TMH_EXCHANGES_keys4exchange (const char *exchange, + TMH_EXCHANGES_Find2Continuation fc, + void *fc_cls); + + +/** + * Get /wire of the given @a exchange. + * + * @param exchange URL of the exchange we would like to talk to + * @param fc function to call with the handles for the exchange + * @param fc_cls closure for @a fc + */ +struct TMH_EXCHANGES_WireOperation * +TMH_EXCHANGES_wire4exchange (const char *exchange, + TMH_EXCHANGES_WireContinuation fc, + void *fc_cls); + + +/** * Lookup current wire fee by @a exchange_url and * @a wire_method. * @@ -149,4 +211,22 @@ void TMH_EXCHANGES_find_exchange_cancel (struct TMH_EXCHANGES_FindOperation *fo); +/** + * Abort pending keys details lookup operation. + * + * @param fo handle to operation to abort + */ +void +TMH_EXCHANGES_keys4exchange_cancel (struct TMH_EXCHANGES_Find2Operation *fo); + + +/** + * Abort pending wire details lookup operation. + * + * @param fo handle to operation to abort + */ +void +TMH_EXCHANGES_wire4exchange_cancel (struct TMH_EXCHANGES_WireOperation *fo); + + #endif 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 04224ac5..28ba72df 100644 --- a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c +++ b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c @@ -70,12 +70,6 @@ struct DepositConfirmation struct PayContext *pc; /** - * Handle to the deposit operation we are performing for - * this coin, NULL after the operation is done. - */ - struct TALER_EXCHANGE_DepositHandle *dh; - - /** * URL of the exchange that issued this coin. */ char *exchange_url; @@ -179,7 +173,14 @@ struct ExchangeGroup * the exchange used for this transaction; NULL if no operation is * pending. */ - struct TMH_EXCHANGES_FindOperation *fo; + struct TMH_EXCHANGES_Find2Operation *fo; + + /** + * Handle for operation to lookup /wire from + * the exchange used for this transaction; NULL if no operation is + * pending. + */ + struct TMH_EXCHANGES_WireOperation *gwo; /** * URL of the exchange that issued this coin. Aliases @@ -570,29 +571,6 @@ get_pay_timeout (unsigned int num_coins) } -/** - * Abort all pending /deposit operations. - * - * @param pc pay context to abort - */ -static void -abort_active_deposits (struct PayContext *pc) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Aborting pending /deposit operations\n"); - for (unsigned int i = 0; i<pc->coins_cnt; i++) - { - struct DepositConfirmation *dci = &pc->dc[i]; - - if (NULL != dci->dh) - { - TALER_EXCHANGE_deposit_cancel (dci->dh); - dci->dh = NULL; - } - } -} - - void TMH_force_pc_resume () { @@ -609,7 +587,6 @@ TMH_force_pc_resume () NULL != pc; pc = pc->next) { - abort_active_deposits (pc); if (NULL != pc->timeout_task) { GNUNET_SCHEDULER_cancel (pc->timeout_task); @@ -638,7 +615,6 @@ resume_pay_with_response (struct PayContext *pc, unsigned int response_code, struct MHD_Response *response) { - abort_active_deposits (pc); pc->response_code = response_code; pc->response = response; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -697,7 +673,6 @@ pay_context_cleanup (void *cls) json_decref (pc->contract_terms); pc->contract_terms = NULL; } - abort_active_deposits (pc); for (unsigned int i = 0; i<pc->coins_cnt; i++) { struct DepositConfirmation *dc = &pc->dc[i]; @@ -711,7 +686,9 @@ pay_context_cleanup (void *cls) struct ExchangeGroup *eg = pc->egs[i]; if (NULL != eg->fo) - TMH_EXCHANGES_find_exchange_cancel (eg->fo); + TMH_EXCHANGES_keys4exchange_cancel (eg->fo); + if (NULL != eg->gwo) + TMH_EXCHANGES_wire4exchange_cancel (eg->gwo); GNUNET_free (eg); } GNUNET_free (pc->egs); @@ -1170,35 +1147,29 @@ batch_deposit_cb ( /** - * Function called with the result of our exchange lookup. + * Function called with the result of our exchange keys lookup. * * @param cls the `struct ExchangeGroup` - * @param hr HTTP response details - * @param exchange_handle NULL if exchange was not found to be acceptable - * @param ih internal handle to the exchange + * @param keys the keys of the exchange */ static void -process_pay_with_exchange ( +process_pay_with_keys ( void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - struct TALER_EXCHANGE_Handle *exchange_handle, - struct TMH_Exchange *ih) + struct TALER_EXCHANGE_Keys *keys) { struct ExchangeGroup *eg = cls; struct PayContext *pc = eg->pc; struct TMH_HandlerContext *hc = pc->hc; - const struct TALER_EXCHANGE_Keys *keys; unsigned int group_size; eg->fo = NULL; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Processing payment with exchange %s\n", - (NULL == exchange_handle) - ? "<null>" - : TALER_EXCHANGE_get_base_url (exchange_handle)); + eg->exchange_url); GNUNET_assert (GNUNET_YES == pc->suspended); - if (NULL == hr) + if (NULL == keys) { + GNUNET_break_op (0); pc->pending_at_eg--; resume_pay_with_response ( pc, @@ -1207,45 +1178,6 @@ process_pay_with_exchange ( TALER_JSON_pack_ec (TALER_EC_MERCHANT_GENERIC_EXCHANGE_TIMEOUT))); return; } - if ( (MHD_HTTP_OK != hr->http_status) || - (NULL == exchange_handle) ) - { - pc->pending_at_eg--; - resume_pay_with_response ( - pc, - MHD_HTTP_BAD_GATEWAY, - TALER_MHD_MAKE_JSON_PACK ( - TALER_JSON_pack_ec ( - TALER_EC_MERCHANT_GENERIC_EXCHANGE_CONNECT_FAILURE), - TMH_pack_exchange_reply (hr))); - return; - } - if (GNUNET_OK != - TMH_exchange_check_debit (ih, - pc->wm)) - { - GNUNET_break_op (0); - pc->pending_at_eg--; - resume_pay_with_response ( - pc, - MHD_HTTP_CONFLICT, - TALER_MHD_MAKE_JSON_PACK ( - TALER_JSON_pack_ec ( - TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED))); - return; - } - - keys = TALER_EXCHANGE_get_keys (exchange_handle); - if (NULL == keys) - { - pc->pending_at_eg--; - GNUNET_break (0); /* should not be possible if HTTP status is #MHD_HTTP_OK */ - resume_pay_with_error (pc, - MHD_HTTP_BAD_GATEWAY, - TALER_EC_MERCHANT_GENERIC_EXCHANGE_KEYS_FAILURE, - NULL); - return; - } /* Initiate /batch-deposit operation for all coins of the current exchange (!) */ @@ -1267,21 +1199,6 @@ process_pay_with_exchange ( &dc->cdd.h_denom_pub); if (NULL == denom_details) { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Denomination not found, re-fetching /keys\n"); - if (! eg->tried_force_keys) - { - /* let's try *forcing* a re-download of /keys from the exchange. - Maybe the wallet has seen /keys that we missed. */ - eg->tried_force_keys = true; - eg->fo = TMH_EXCHANGES_find_exchange (eg->exchange_url, - true, - &process_pay_with_exchange, - eg); - if (NULL != eg->fo) - return; - } - /* Forcing failed or we already did it, give up */ pc->pending_at_eg--; resume_pay_with_response ( pc, @@ -1292,9 +1209,9 @@ process_pay_with_exchange ( GNUNET_JSON_pack_data_auto ("h_denom_pub", &dc->cdd.h_denom_pub), GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_object_incref ( + GNUNET_JSON_pack_object_steal ( "exchange_keys", - (json_t *) TALER_EXCHANGE_get_keys_raw (exchange_handle))))); + TALER_EXCHANGE_keys_to_json (keys))))); return; } dc->deposit_fee = denom_details->fees.deposit; @@ -1458,13 +1375,16 @@ AGE_FAIL: GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Initiating batch deposit with %u coins\n", group_size); - eg->bdh = TALER_EXCHANGE_batch_deposit (exchange_handle, - &dcd, - group_size, - cdds, - &batch_deposit_cb, - eg, - &ec); + eg->bdh = TALER_EXCHANGE_batch_deposit ( + merchant_curl_ctx, + eg->exchange_url, + keys, + &dcd, + group_size, + cdds, + &batch_deposit_cb, + eg, + &ec); if (NULL == eg->bdh) { /* Signature was invalid or some other constraint was not satisfied. If @@ -1488,6 +1408,67 @@ AGE_FAIL: /** + * Function called with the result of our exchange lookup. + * + * @param cls the `struct ExchangeGroup` + * @param keys the keys of the exchange + */ +static void +process_pay_with_wire ( + void *cls, + struct TMH_Exchange *wire) +{ + struct ExchangeGroup *eg = cls; + struct PayContext *pc = eg->pc; + + eg->gwo = NULL; + if (NULL == wire) + { + GNUNET_break_op (0); + pc->pending_at_eg--; + /* FIXME: define more specific error code... */ + resume_pay_with_response ( + pc, + MHD_HTTP_BAD_GATEWAY, + TALER_MHD_MAKE_JSON_PACK ( + TALER_JSON_pack_ec ( + TALER_EC_MERCHANT_GENERIC_EXCHANGE_CONNECT_FAILURE))); + return; + } + if (GNUNET_OK != + TMH_exchange_check_debit (wire, + pc->wm)) + { + GNUNET_break_op (0); + pc->pending_at_eg--; + resume_pay_with_response ( + pc, + MHD_HTTP_CONFLICT, + TALER_MHD_MAKE_JSON_PACK ( + TALER_JSON_pack_ec ( + TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED))); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Fetching /keys for %s\n", + eg->exchange_url); + eg->fo = TMH_EXCHANGES_keys4exchange (eg->exchange_url, + &process_pay_with_keys, + eg); + if (NULL == eg->fo) + { + GNUNET_break (0); + pc->pending_at_eg--; + resume_pay_with_error (pc, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_LOOKUP_FAILED, + "Failed to lookup exchange by URL"); + return; + } +} + + +/** * Start batch deposits for all exchanges involved * in this payment. * @@ -1515,11 +1496,13 @@ start_batch_deposits (struct PayContext *pc) } if (! have_coins) continue; /* no coins left to deposit at this exchange */ - eg->fo = TMH_EXCHANGES_find_exchange (eg->exchange_url, - false, - &process_pay_with_exchange, - eg); - if (NULL == eg->fo) + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Getting /wire details for %s\n", + eg->exchange_url); + eg->gwo = TMH_EXCHANGES_wire4exchange (eg->exchange_url, + &process_pay_with_wire, + eg); + if (NULL == eg->gwo) { GNUNET_break (0); resume_pay_with_error (pc, |