summaryrefslogtreecommitdiff
path: root/src/backend/taler-merchant-httpd_exchanges.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/taler-merchant-httpd_exchanges.c')
-rw-r--r--src/backend/taler-merchant-httpd_exchanges.c973
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;
}