diff options
Diffstat (limited to 'src/backend/taler-merchant-httpd_exchanges.c')
-rw-r--r-- | src/backend/taler-merchant-httpd_exchanges.c | 973 |
1 files changed, 480 insertions, 493 deletions
diff --git a/src/backend/taler-merchant-httpd_exchanges.c b/src/backend/taler-merchant-httpd_exchanges.c index 665607c1..ff4360b0 100644 --- a/src/backend/taler-merchant-httpd_exchanges.c +++ b/src/backend/taler-merchant-httpd_exchanges.c @@ -66,18 +66,18 @@ /** * Information we keep for a pending #MMH_EXCHANGES_keys4exchange() operation. */ -struct TMH_EXCHANGES_Find2Operation +struct TMH_EXCHANGES_KeysOperation { /** * Kept in a DLL. */ - struct TMH_EXCHANGES_Find2Operation *next; + struct TMH_EXCHANGES_KeysOperation *next; /** * Kept in a DLL. */ - struct TMH_EXCHANGES_Find2Operation *prev; + struct TMH_EXCHANGES_KeysOperation *prev; /** * Function to call with the result. @@ -254,7 +254,7 @@ struct ExchangeAccount /** - * Exchange + * Internal representation for an exchange */ struct TMH_Exchange { @@ -272,12 +272,12 @@ struct TMH_Exchange /** * Head of FOs pending for this exchange. */ - struct TMH_EXCHANGES_Find2Operation *fo2_head; + struct TMH_EXCHANGES_KeysOperation *keys_head; /** * Tail of FOs pending for this exchange. */ - struct TMH_EXCHANGES_Find2Operation *fo2_tail; + struct TMH_EXCHANGES_KeysOperation *keys_tail; /** * Head of /wire pending for this exchange. @@ -290,6 +290,11 @@ struct TMH_Exchange struct TMH_EXCHANGES_WireOperation *w_tail; /** + * Request to /keys needed for our /wire operation. + */ + struct TMH_EXCHANGES_KeysOperation *ko; + + /** * Head of accounts of this exchange. */ struct ExchangeAccount *acc_head; @@ -335,8 +340,7 @@ struct TMH_Exchange struct FeesByWireMethod *wire_fees_tail; /** - * Master public key, guaranteed to be set ONLY for - * trusted exchanges. + * Master public key of the exchange. */ struct TALER_MasterPublicKeyP master_pub; @@ -377,16 +381,17 @@ struct TMH_Exchange /** - * Context for all exchange operations (useful to the event loop). - * FIXME: rename, move to taler-merchant-httpd.c + * Opaque wire details abstraction returned to a client after successfully + * obtaining /wire. */ -struct GNUNET_CURL_Context *merchant_curl_ctx; +struct TMH_ExchangeWireDetails +{ + /** + * Internal representation of the exchange + */ + struct TMH_Exchange *exchange; +}; -/** - * Context for integrating #merchant_curl_ctx with the - * GNUnet event loop. - */ -static struct GNUNET_CURL_RescheduleContext *merchant_curl_rc; /** * Head of exchanges we know about. @@ -405,19 +410,6 @@ static struct TMH_Exchange *exchange_tail; */ static int trusted_exchange_count; -/** - * Function called with information about who is auditing - * a particular exchange and what key the exchange is using. - * - * @param cls closure, will be `struct TMH_Exchange` - * @param kr response details - * @param[in] keys keys object returned - */ -static void -keys_mgmt_cb (void *cls, - const struct TALER_EXCHANGE_KeysResponse *kr, - struct TALER_EXCHANGE_Keys *keys); - /** * Free data structures within @a ea, but not @a ea @@ -475,6 +467,36 @@ purge_exchange_accounts (struct TMH_Exchange *exchange) /** + * Lookup exchange by @a exchange_url. Create one + * if it does not exist. + * + * @param exchange_url base URL to match against + * @return fresh entry if exchange was not yet known + */ +static struct TMH_Exchange * +lookup_exchange (const char *exchange_url) +{ + struct TMH_Exchange *exchange; + + for (exchange = exchange_head; + NULL != exchange; + exchange = exchange->next) + if (0 == strcmp (exchange->url, + exchange_url)) + return exchange; + exchange = GNUNET_new (struct TMH_Exchange); + exchange->url = GNUNET_strdup (exchange_url); + GNUNET_CONTAINER_DLL_insert (exchange_head, + exchange_tail, + exchange); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "The exchange `%s' is new\n", + exchange_url); + return exchange; +} + + +/** * Set the list of accounts of @a exchange. * * @param[in,out] exchange exchange to initialize or update @@ -536,10 +558,24 @@ set_exchange_accounts ( /** - * Retry getting information from the given exchange in - * the closure. + * Function called with information about who is auditing + * a particular exchange and what key the exchange is using. * - * @param cls the exchange + * @param cls closure, will be `struct TMH_Exchange` + * @param kr response details + * @param[in] keys keys object returned + */ +static void +keys_mgmt_cb ( + void *cls, + const struct TALER_EXCHANGE_KeysResponse *kr, + struct TALER_EXCHANGE_Keys *keys); + + +/** + * Retry getting keys from the given exchange in the closure. + * + * @param cls the `struct TMH_Exchange *` */ static void retry_exchange (void *cls) @@ -549,18 +585,31 @@ retry_exchange (void *cls) /* might be a scheduled reload and not our first attempt */ exchange->retry_task = NULL; if (NULL != exchange->conn) - return; + return; /* already trying */ + if ( (NULL != exchange->keys) && + (GNUNET_TIME_absolute_is_future ( + exchange->keys->key_data_expiration.abs_time)) ) + return; /* still have a valid reply */ + /* increment exponential-backoff */ + exchange->retry_delay + = RETRY_BACKOFF (exchange->retry_delay); + /* No download 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_DEBUG, - "Connecting to exchange %s in retry_exchange()\n", + "Fetching /keys from exchange %s in retry_exchange()\n", exchange->url); - if ( (NULL == exchange->keys) || - (GNUNET_TIME_absolute_is_past ( - exchange->keys->key_data_expiration.abs_time)) ) - exchange->conn = TALER_EXCHANGE_get_keys (merchant_curl_ctx, - exchange->url, - exchange->keys, - &keys_mgmt_cb, - exchange); + exchange->conn + = TALER_EXCHANGE_get_keys ( + TMH_curl_ctx, + exchange->url, + exchange->keys, + &keys_mgmt_cb, + exchange); /* Note: while the API spec says 'returns NULL on error', the implementation actually never returns NULL. */ GNUNET_break (NULL != exchange->conn); @@ -568,9 +617,200 @@ retry_exchange (void *cls) /** - * Function called with information about the wire fees - * for each wire method. Stores the wire fees with the - * exchange for later use. + * Check if we have any remaining pending requests for the + * given @a exchange, and if we have the required data, call + * the callback. + * + * @param exchange the exchange to check for pending find operations + * @return true if we need /wire data from @a exchange + */ +static bool +process_find_operations (struct TMH_Exchange *exchange) +{ + struct TMH_EXCHANGES_KeysOperation *fn2; + struct TMH_EXCHANGES_WireOperation *wn; + struct GNUNET_TIME_Timestamp now; + + fn2 = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Processing find operations for `%s'\n", + exchange->url); + for (struct TMH_EXCHANGES_KeysOperation *fo = exchange->keys_head; + NULL != fo; + fo = fn2) + { + fn2 = fo->next; + fo->fc (fo->fc_cls, + exchange->keys); + TMH_EXCHANGES_keys4exchange_cancel (fo); + } + if (! exchange->have_wire) + return true; + now = GNUNET_TIME_timestamp_get (); + for (struct FeesByWireMethod *fbw = exchange->wire_fees_head; + NULL != fbw; + fbw = fbw->next) + { + bool removed = false; + + while ( (NULL != fbw->af) && + (GNUNET_TIME_timestamp_cmp (fbw->af->end_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) + { + exchange->have_wire = false; + return true; /* We just removed previous fees, try fetching update */ + } + } + if (GNUNET_TIME_timestamp_cmp (fbw->af->start_date, + >, + now)) + { + /* 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)); + } + } + + if (! exchange->have_wire) + return true; /* need /wire response to continue */ + { + struct TMH_ExchangeWireDetails wd = { + .exchange = exchange + }; + + wn = NULL; + for (struct TMH_EXCHANGES_WireOperation *w = exchange->w_head; + NULL != w; + w = wn) + { + wn = w->next; + w->fc (w->fc_cls, + &wd); + TMH_EXCHANGES_wire4exchange_cancel (w); + } + } + return false; +} + + +/** + * Task to asynchronously return keys operation result to caller. + * + * @param cls a `struct TMH_EXCHANGES_KeysOperation` + */ +static void +return_keys (void *cls) +{ + struct TMH_EXCHANGES_KeysOperation *fo = cls; + struct TMH_Exchange *exchange = fo->my_exchange; + + fo->at = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Returning key data for %s instantly\n", + exchange->url); + process_find_operations (exchange); +} + + +struct TMH_EXCHANGES_KeysOperation * +TMH_EXCHANGES_keys4exchange ( + const char *chosen_exchange, + TMH_EXCHANGES_Find2Continuation fc, + void *fc_cls) +{ + struct TMH_Exchange *exchange; + struct TMH_EXCHANGES_KeysOperation *fo; + + if (NULL == TMH_curl_ctx) + { + GNUNET_break (0); + return NULL; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Trying to find chosen exchange `%s'\n", + chosen_exchange); + exchange = lookup_exchange (chosen_exchange); + fo = GNUNET_new (struct TMH_EXCHANGES_KeysOperation); + fo->fc = fc; + fo->fc_cls = fc_cls; + fo->my_exchange = exchange; + GNUNET_CONTAINER_DLL_insert (exchange->keys_head, + exchange->keys_tail, + fo); + if ( (NULL != exchange->keys) && + (GNUNET_TIME_absolute_is_future ( + exchange->keys->key_data_expiration.abs_time)) ) + { + /* We have a valid 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_keys, + fo); + return fo; + } + if ( (NULL == exchange->retry_task) && + (NULL == exchange->conn) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "No valid keys, fetching /keys at %s\n", + GNUNET_TIME_absolute2s (exchange->first_retry)); + exchange->retry_task + = GNUNET_SCHEDULER_add_at (exchange->first_retry, + &retry_exchange, + exchange); + return fo; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Next /keys request scheduled for %s\n", + GNUNET_TIME_absolute2s ( + exchange->first_retry)); + /* No activity to launch, we are already doing so. */ + return fo; +} + + +void +TMH_EXCHANGES_keys4exchange_cancel ( + struct TMH_EXCHANGES_KeysOperation *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->keys_head, + exchange->keys_tail, + fo); + GNUNET_free (fo); +} + + +/** + * Function called with information about the wire fees for each wire method. + * Stores the wire fees with the exchange for later use. * * @param exchange connection to the exchange * @param master_pub public key of the exchange @@ -910,90 +1150,13 @@ get_wire_fees (struct TMH_Exchange *exchange, /** * Check if we have any remaining pending requests for the * given @a exchange, and if we have the required data, call - * the callback. + * the callback. If requests without /wire data remain, + * retry the /wire request after some delay. * - * @param exchange the exchange to check for pending find operations - * @return true if we need /wire data from @a exchange + * Must only be called if 'exchange->keys' is non-NULL. + * + * @param cls a `struct TMH_Exchange` to check */ -static bool -process_find_operations (struct TMH_Exchange *exchange) -{ - 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, - exchange->keys); - fn2 = fo->next; - TMH_EXCHANGES_keys4exchange_cancel (fo); - } - if (! exchange->have_wire) - return true; - now = GNUNET_TIME_timestamp_get (); - for (struct FeesByWireMethod *fbw = exchange->wire_fees_head; - NULL != fbw; - fbw = fbw->next) - { - bool removed = false; - - while ( (NULL != fbw->af) && - (GNUNET_TIME_timestamp_cmp (fbw->af->end_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) - { - exchange->have_wire = false; - return true; /* We just removed previous fees, try fetching update */ - } - } - if (GNUNET_TIME_timestamp_cmp (fbw->af->start_date, - >, - now)) - { - /* 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)); - } - } - - if (! exchange->have_wire) - return true; /* need /wire response to continue */ - 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; -} - - static void wire_task_cb (void *cls); @@ -1053,15 +1216,15 @@ handle_wire_data (void *cls, if (TALER_EC_NONE != ecx) { /* Report hard failure to all callbacks! */ - struct TMH_EXCHANGES_Find2Operation *fo2; + struct TMH_EXCHANGES_KeysOperation *keys; GNUNET_break_op (0); exchange->have_wire = false; - while (NULL != (fo2 = exchange->fo2_head)) + while (NULL != (keys = exchange->keys_head)) { - fo2->fc (fo2->fc_cls, - NULL); - TMH_EXCHANGES_keys4exchange_cancel (fo2); + keys->fc (keys->fc_cls, + NULL); + TMH_EXCHANGES_keys4exchange_cancel (keys); } return; } @@ -1091,16 +1254,6 @@ handle_wire_data (void *cls, } -/** - * Check if we have any remaining pending requests for the - * given @a exchange, and if we have the required data, call - * the callback. If requests without /wire data remain, - * retry the /wire request after some delay. - * - * Must only be called if 'exchange->keys' is non-NULL. - * - * @param cls a `struct TMH_Exchange` to check - */ static void wire_task_cb (void *cls) { @@ -1113,7 +1266,7 @@ wire_task_cb (void *cls) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Initiating /wire download\n"); exchange->wire_request - = TALER_EXCHANGE_wire (merchant_curl_ctx, + = TALER_EXCHANGE_wire (TMH_curl_ctx, exchange->url, exchange->keys, &handle_wire_data, @@ -1172,8 +1325,8 @@ free_exchange_entry (struct TMH_Exchange *exchange) GNUNET_SCHEDULER_cancel (exchange->retry_task); exchange->retry_task = NULL; } - GNUNET_assert (NULL == exchange->fo2_head); - GNUNET_assert (NULL == exchange->fo2_tail); + GNUNET_assert (NULL == exchange->keys_head); + GNUNET_assert (NULL == exchange->keys_tail); GNUNET_assert (NULL == exchange->w_head); GNUNET_assert (NULL == exchange->w_tail); GNUNET_free (exchange->url); @@ -1192,7 +1345,7 @@ static void fail_and_retry (struct TMH_Exchange *exchange, const struct TALER_EXCHANGE_HttpResponse *hr) { - struct TMH_EXCHANGES_Find2Operation *fo2; + struct TMH_EXCHANGES_KeysOperation *keys; struct TMH_EXCHANGES_WireOperation *w; if (NULL != exchange->wire_request) @@ -1205,11 +1358,11 @@ fail_and_retry (struct TMH_Exchange *exchange, GNUNET_SCHEDULER_cancel (exchange->wire_task); exchange->wire_task = NULL; } - while (NULL != (fo2 = exchange->fo2_head)) + while (NULL != (keys = exchange->keys_head)) { - fo2->fc (fo2->fc_cls, - NULL); - TMH_EXCHANGES_keys4exchange_cancel (fo2); + keys->fc (keys->fc_cls, + NULL); + TMH_EXCHANGES_keys4exchange_cancel (keys); } while (NULL != (w = exchange->w_head)) { @@ -1233,14 +1386,24 @@ fail_and_retry (struct TMH_Exchange *exchange, true)); if (NULL != exchange->retry_task) GNUNET_SCHEDULER_cancel (exchange->retry_task); - exchange->first_retry = GNUNET_TIME_relative_to_absolute ( - exchange->retry_delay); - exchange->retry_task = GNUNET_SCHEDULER_add_delayed (exchange->retry_delay, - &retry_exchange, - exchange); + exchange->first_retry + = GNUNET_TIME_relative_to_absolute ( + exchange->retry_delay); + exchange->retry_task + = GNUNET_SCHEDULER_add_delayed (exchange->retry_delay, + &retry_exchange, + exchange); } +/** + * Function called with the result of a + * /keys request to the exchange. + * + * @param cls a `struct TMH_Exchange *` + * @param kr response details + * @param[in] keys key data now owned by this function + */ static void keys_mgmt_cb (void *cls, const struct TALER_EXCHANGE_KeysResponse *kr, @@ -1293,13 +1456,14 @@ keys_mgmt_cb (void *cls, enum GNUNET_DB_QueryStatus qs; TMH_db->preflight (TMH_db->cls); - qs = TMH_db->insert_exchange_signkey (TMH_db->cls, - &keys->master_pub, - &sign_key->key, - sign_key->valid_from, - sign_key->valid_until, - sign_key->valid_legal, - &sign_key->master_sig); + qs = TMH_db->insert_exchange_signkey ( + TMH_db->cls, + &keys->master_pub, + &sign_key->key, + sign_key->valid_from, + sign_key->valid_until, + sign_key->valid_legal, + &sign_key->master_sig); /* 0 is OK, we may already have the key in the DB! */ if (0 > qs) { @@ -1315,7 +1479,7 @@ keys_mgmt_cb (void *cls, delay = GNUNET_TIME_absolute_get_remaining ( keys->key_data_expiration.abs_time); GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "/keys response from expires at %s! Retrying at that time!\n", + "/keys response expires at %s! Retrying at that time!\n", GNUNET_TIME_absolute2s ( keys->key_data_expiration.abs_time)); delay = GNUNET_TIME_relative_max (delay, @@ -1327,6 +1491,7 @@ keys_mgmt_cb (void *cls, = GNUNET_SCHEDULER_add_delayed (delay, &retry_exchange, exchange); + if ( (process_find_operations (exchange)) && (NULL == exchange->wire_request) && (NULL == exchange->wire_task) ) @@ -1335,7 +1500,7 @@ keys_mgmt_cb (void *cls, "Got key data, but also need wire data. Will request /wire now\n"); exchange->wire_request = TALER_EXCHANGE_wire ( - merchant_curl_ctx, + TMH_curl_ctx, exchange->url, exchange->keys, &handle_wire_data, @@ -1347,22 +1512,6 @@ keys_mgmt_cb (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 @@ -1376,115 +1525,6 @@ return_wire_result (void *cls) } -/** - * Lookup exchange by @a exchange_url. - * - * @param exchange_url base URL to match against - * @return NULL if exchange is not yet known - */ -static struct TMH_Exchange * -lookup_exchange (const char *exchange_url) -{ - for (struct TMH_Exchange *exchange = exchange_head; - NULL != exchange; - exchange = exchange->next) - if (0 == strcmp (exchange->url, - exchange_url)) - return exchange; - return NULL; -} - - -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->retry_task) - exchange->retry_task - = GNUNET_SCHEDULER_add_now (&retry_exchange, - exchange); - return fo; - } - - if (NULL != exchange->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->keys) && - (NULL == exchange->retry_task) ) - { - 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, @@ -1494,7 +1534,7 @@ TMH_EXCHANGES_wire4exchange ( struct TMH_Exchange *exchange; struct TMH_EXCHANGES_WireOperation *w; - if (NULL == merchant_curl_ctx) + if (NULL == TMH_curl_ctx) { GNUNET_break (0); return NULL; @@ -1502,21 +1542,7 @@ TMH_EXCHANGES_wire4exchange ( 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; @@ -1536,56 +1562,42 @@ TMH_EXCHANGES_wire4exchange ( w); return w; } - - if (NULL == exchange->wire_request) + if (NULL != exchange->wire_request) + return w; /* /wire request is active, do nothing */ + if ( (NULL != exchange->keys) && + (GNUNET_TIME_absolute_is_future ( + exchange->keys->key_data_expiration.abs_time)) ) { - if (NULL == exchange->conn) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Requesting /keys from `%s' to connect\n", - exchange->url); - exchange->conn = TALER_EXCHANGE_get_keys (merchant_curl_ctx, - exchange->url, - exchange->keys, - &keys_mgmt_cb, - exchange); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Requesting /wire from `%s'\n", - exchange->url); - exchange->wire_request - = TALER_EXCHANGE_wire (merchant_curl_ctx, - exchange->url, - exchange->keys, - &handle_wire_data, - exchange); - } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Requesting /wire from `%s'\n", + exchange->url); + exchange->wire_request + = TALER_EXCHANGE_wire (TMH_curl_ctx, + exchange->url, + exchange->keys, + &handle_wire_data, + exchange); + return w; } - return w; -} - - -void -TMH_EXCHANGES_keys4exchange_cancel (struct TMH_EXCHANGES_Find2Operation *fo) -{ - struct TMH_Exchange *exchange = fo->my_exchange; + if ( (NULL == exchange->keys) && + ( (NULL != exchange->conn) || + (NULL != exchange->retry_task) ) ) + return w; /* /keys request active, do nothing */ - 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); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "No valid keys, fetching /keys at %s\n", + GNUNET_TIME_absolute2s (exchange->first_retry)); + exchange->retry_task + = GNUNET_SCHEDULER_add_at (exchange->first_retry, + &retry_exchange, + exchange); + return w; } void -TMH_EXCHANGES_wire4exchange_cancel (struct TMH_EXCHANGES_WireOperation *w) +TMH_EXCHANGES_wire4exchange_cancel ( + struct TMH_EXCHANGES_WireOperation *w) { struct TMH_Exchange *exchange = w->my_exchange; @@ -1601,10 +1613,128 @@ TMH_EXCHANGES_wire4exchange_cancel (struct TMH_EXCHANGES_WireOperation *w) } +enum GNUNET_GenericReturnValue +TMH_EXCHANGES_lookup_wire_fee ( + const struct TMH_ExchangeWireDetails *wd, + const char *wire_method, + struct TALER_Amount *wire_fee) +{ + struct TMH_Exchange *exchange = wd->exchange; + const struct FeesByWireMethod *fbm; + const struct TALER_EXCHANGE_WireAggregateFees *af; + + if (! exchange->have_wire) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + fbm = get_wire_fees (exchange, + GNUNET_TIME_timestamp_get (), + wire_method); + if (NULL == fbm) + return GNUNET_NO; + af = fbm->af; + *wire_fee = af->fees.wire; + return GNUNET_OK; +} + + +enum GNUNET_GenericReturnValue +TMH_exchange_check_debit ( + const struct TMH_ExchangeWireDetails *wd, + const struct TMH_WireMethod *wm) +{ + struct TMH_Exchange *ex = wd->exchange; + for (struct ExchangeAccount *acc = ex->acc_head; + NULL != acc; + acc = acc->next) + { + bool ok = true; + + if (0 != strcmp (acc->wire_method, + wm->wire_method)) + continue; + if (NULL != acc->conversion_url) + continue; /* never use accounts with conversion */ + for (struct Restriction *r = acc->d_head; + NULL != r; + r = r->next) + { + switch (r->type) + { + case TALER_EXCHANGE_AR_INVALID: + GNUNET_break (0); + ok = false; + break; + case TALER_EXCHANGE_AR_DENY: + ok = false; + break; + case TALER_EXCHANGE_AR_REGEX: + if (0 != regexec (&r->details.regex.ex, + wm->payto_uri, + 0, NULL, 0)) + ok = false; + break; + } + if (! ok) + break; + } + + if (ok) + return GNUNET_OK; + } + return GNUNET_NO; +} + + +json_t * +TMH_exchange_get_acceptable (const struct TMH_WireMethod *wm) +{ + json_t *te = json_array (); + + GNUNET_assert (NULL != te); + for (struct TMH_Exchange *exchange = exchange_head; + NULL != exchange; + exchange = exchange->next) + { + json_t *j_exchange; + unsigned int priority; + + if (! exchange->trusted) + continue; + priority = 512; /* medium */ + if (exchange->have_wire) + { + struct TMH_ExchangeWireDetails wd = { + .exchange = exchange + }; + + if (GNUNET_OK == + TMH_exchange_check_debit (&wd, + wm)) + priority = 1024; /* high */ + else + priority = 0; /* negative response */ + } + j_exchange = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("url", + exchange->url), + GNUNET_JSON_pack_uint64 ("priority", + priority), + GNUNET_JSON_pack_data_auto ("master_pub", + &exchange->master_pub)); + GNUNET_assert (NULL != j_exchange); + GNUNET_assert (0 == + json_array_append_new (te, + j_exchange)); + } + return te; +} + + /** * Function called on each configuration section. Finds sections - * about exchanges, parses the entries and tries to connect to - * it in order to fetch /keys. + * about exchanges, parses the entries. * * @param cls closure, with a `const struct GNUNET_CONFIGURATION_Handle *` * @param section name of the section @@ -1677,7 +1807,7 @@ accept_exchanges (void *cls, GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, section, "MASTER_KEY", - _ ("ill-formed EdDSA key")); + "malformed EdDSA key"); } GNUNET_free (mks); } @@ -1686,7 +1816,6 @@ accept_exchanges (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "MASTER_KEY missing in section '%s', not trusting exchange\n", section); - } GNUNET_CONTAINER_DLL_insert (exchange_head, exchange_tail, @@ -1698,53 +1827,8 @@ accept_exchanges (void *cls, enum GNUNET_GenericReturnValue -TMH_EXCHANGES_lookup_wire_fee (const char *exchange_url, - const char *wire_method, - struct TALER_Amount *wire_fee) -{ - struct TMH_Exchange *exchange; - const struct FeesByWireMethod *fbm; - const struct TALER_EXCHANGE_WireAggregateFees *af; - - exchange = lookup_exchange (exchange_url); - if (NULL == exchange) - { - return GNUNET_SYSERR; - } - if (! exchange->have_wire) - { - return GNUNET_SYSERR; - } - fbm = get_wire_fees (exchange, - GNUNET_TIME_timestamp_get (), - wire_method); - if (NULL == fbm) - return GNUNET_NO; - af = fbm->af; - *wire_fee = af->fees.wire; - return GNUNET_OK; -} - - -enum GNUNET_GenericReturnValue TMH_EXCHANGES_init (const struct GNUNET_CONFIGURATION_Handle *cfg) { - merchant_curl_ctx - = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, - &merchant_curl_rc); - if (NULL == merchant_curl_ctx) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - merchant_curl_rc = GNUNET_CURL_gnunet_rc_create (merchant_curl_ctx); - /* Disable 100 continue processing */ - GNUNET_break (GNUNET_OK == - GNUNET_CURL_append_header (merchant_curl_ctx, - MHD_HTTP_HEADER_EXPECT ":")); - - GNUNET_CURL_enable_async_scope_header (merchant_curl_ctx, - "Taler-Correlation-Id"); /* get exchanges from the merchant configuration and try to connect to them */ GNUNET_CONFIGURATION_iterate_sections (cfg, &accept_exchanges, @@ -1759,103 +1843,6 @@ TMH_EXCHANGES_done () { while (NULL != exchange_head) free_exchange_entry (exchange_head); - if (NULL != merchant_curl_ctx) - { - GNUNET_CURL_fini (merchant_curl_ctx); - merchant_curl_ctx = NULL; - } - if (NULL != merchant_curl_rc) - { - GNUNET_CURL_gnunet_rc_destroy (merchant_curl_rc); - merchant_curl_rc = NULL; - } -} - - -enum GNUNET_GenericReturnValue -TMH_exchange_check_debit (struct TMH_Exchange *ex, - const struct TMH_WireMethod *wm) -{ - for (struct ExchangeAccount *acc = ex->acc_head; - NULL != acc; - acc = acc->next) - { - bool ok = true; - - if (0 != strcmp (acc->wire_method, - wm->wire_method)) - continue; - if (NULL != acc->conversion_url) - continue; /* never use accounts with conversion */ - for (struct Restriction *r = acc->d_head; - NULL != r; - r = r->next) - { - switch (r->type) - { - case TALER_EXCHANGE_AR_INVALID: - GNUNET_break (0); - ok = false; - break; - case TALER_EXCHANGE_AR_DENY: - ok = false; - break; - case TALER_EXCHANGE_AR_REGEX: - if (0 != regexec (&r->details.regex.ex, - wm->payto_uri, - 0, NULL, 0)) - ok = false; - break; - } - if (! ok) - break; - } - - if (ok) - return GNUNET_OK; - } - return GNUNET_NO; -} - - -json_t * -TMH_exchange_get_acceptable (const struct TMH_WireMethod *wm) -{ - json_t *te = json_array (); - - GNUNET_assert (NULL != te); - for (struct TMH_Exchange *exchange = exchange_head; - NULL != exchange; - exchange = exchange->next) - { - json_t *j_exchange; - unsigned int priority; - - if (! exchange->trusted) - continue; - priority = 512; /* medium */ - if (exchange->have_wire) - { - if (GNUNET_OK == - TMH_exchange_check_debit (exchange, - wm)) - priority = 1024; /* high */ - else - priority = 0; /* negative response */ - } - j_exchange = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("url", - exchange->url), - GNUNET_JSON_pack_uint64 ("priority", - priority), - GNUNET_JSON_pack_data_auto ("master_pub", - &exchange->master_pub)); - GNUNET_assert (NULL != j_exchange); - GNUNET_assert (0 == - json_array_append_new (te, - j_exchange)); - } - return te; } |