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.c120
1 files changed, 60 insertions, 60 deletions
diff --git a/src/backend/taler-merchant-httpd_exchanges.c b/src/backend/taler-merchant-httpd_exchanges.c
index 9a292365..d980ef09 100644
--- a/src/backend/taler-merchant-httpd_exchanges.c
+++ b/src/backend/taler-merchant-httpd_exchanges.c
@@ -24,10 +24,26 @@
#include "taler-merchant-httpd_exchanges.h"
+
+/**
+ * Delay after which we'll re-fetch key information from the exchange.
+ */
+#define RELOAD_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
+
+/**
+ * Threshold after which exponential backoff should not increase.
+ */
+#define RETRY_BACKOFF_THRESHOLD GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
+
+
/**
- * How often do we retry fetching /keys?
+ * Perform our exponential back-off calculation, starting at 1 ms
+ * and then going by a factor of 2 up unto a maximum of RETRY_BACKOFF_THRESHOLD.
+ *
+ * @param r current backoff time, initially zero
*/
-#define KEYS_RETRY_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
+#define RETRY_BACKOFF(r) GNUNET_TIME_relative_min (RETRY_BACKOFF_THRESHOLD, \
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_MILLISECONDS, (r)), 2));
/**
@@ -68,7 +84,8 @@ struct TMH_EXCHANGES_FindOperation
struct Exchange *my_exchange;
/**
- * Task scheduled to asynchrnously return the result.
+ * Task scheduled to asynchronously return the result to
+ * the find continuation.
*/
struct GNUNET_SCHEDULER_Task *at;
@@ -118,18 +135,23 @@ struct Exchange
struct TALER_MasterPublicKeyP master_pub;
/**
- * At what time should we try to fetch /keys again?
+ * How long should we wait between the next retry?
*/
- struct GNUNET_TIME_Absolute retry_time;
+ struct GNUNET_TIME_Relative retry_delay;
/**
* Task where we retry fetching /keys from the exchange.
+ *
+ * Can also be active when pending=GNUNET_NO,
+ * since we periodically (every hour) reload the
+ * exchange keys.
*/
struct GNUNET_SCHEDULER_Task *retry_task;
/**
- * Flag which indicates whether some HTTP transfer between
- * this merchant and the exchange is still ongoing
+ * GNUNET_YES to indicate that there is an ongoing
+ * transfer we're waiting for,
+ * GNUNET_NO to indicate that key data is up-to-date.
*/
int pending;
@@ -201,12 +223,14 @@ retry_exchange (void *cls)
{
struct Exchange *exchange = cls;
+ /* might be a scheduled reload and not our first attempt */
+ exchange->pending = GNUNET_YES;
exchange->retry_task = NULL;
+
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Connecting to exchange exchange %s in retry_exchange\n",
exchange->uri);
- exchange->pending = GNUNET_SYSERR; /* failed hard */
exchange->conn = TALER_EXCHANGE_connect (merchant_curl_ctx,
exchange->uri,
&keys_mgmt_cb,
@@ -237,38 +261,36 @@ keys_mgmt_cb (void *cls,
struct Exchange *exchange = cls;
struct TMH_EXCHANGES_FindOperation *fo;
- if (NULL != keys)
- {
- exchange->pending = GNUNET_NO;
- }
- else
+ GNUNET_assert (GNUNET_YES == exchange->pending);
+
+ if (NULL == keys)
{
+ exchange->retry_delay = RETRY_BACKOFF (exchange->retry_delay);
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to fetch /keys from `%s'\n",
- exchange->uri);
+ "Failed to fetch /keys from `%s', retrying in %s\n",
+ exchange->uri,
+ GNUNET_STRINGS_relative_time_to_string (exchange->retry_delay, GNUNET_YES));
TALER_EXCHANGE_disconnect (exchange->conn);
exchange->conn = NULL;
- exchange->retry_time = GNUNET_TIME_relative_to_absolute (KEYS_RETRY_FREQ);
- /* Always retry trusted exchanges in the background, so that we don't have
- * to wait for a customer to trigger it and thus delay his response */
- if (GNUNET_YES == exchange->trusted)
- {
- exchange->retry_task = GNUNET_SCHEDULER_add_delayed (KEYS_RETRY_FREQ,
- &retry_exchange,
- exchange);
- }
- else
- {
- exchange->pending = GNUNET_SYSERR; /* failed hard */
- }
+ exchange->retry_task = GNUNET_SCHEDULER_add_delayed (exchange->retry_delay,
+ &retry_exchange,
+ exchange);
+ return;
}
+
+ exchange->pending = GNUNET_NO;
+ /* Schedule for our regular reload. */
+ /* FIXME: we might want to take HTTP cache control into account */
+ exchange->retry_task = GNUNET_SCHEDULER_add_delayed (RELOAD_DELAY,
+ &retry_exchange,
+ exchange);
while (NULL != (fo = exchange->fo_head))
{
GNUNET_CONTAINER_DLL_remove (exchange->fo_head,
exchange->fo_tail,
fo);
fo->fc (fo->fc_cls,
- (NULL != keys) ? exchange->conn : NULL,
+ exchange->conn,
exchange->trusted);
GNUNET_free (fo);
}
@@ -312,7 +334,7 @@ return_result (void *cls)
*/
struct TMH_EXCHANGES_FindOperation *
TMH_EXCHANGES_find_exchange (const char *chosen_exchange,
- TMH_EXCHANGES_FindContinuation fc, // process payment
+ TMH_EXCHANGES_FindContinuation fc,
void *fc_cls)
{
struct Exchange *exchange;
@@ -359,29 +381,6 @@ TMH_EXCHANGES_find_exchange (const char *chosen_exchange,
chosen_exchange);
}
- if (GNUNET_SYSERR == exchange->pending)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Maybe retrying previously contacted exchange `%s'\n",
- chosen_exchange);
- /* check if we should resume this exchange */
- if (0 == GNUNET_TIME_absolute_get_remaining (exchange->retry_time).rel_value_us)
- {
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Retrying exchange `%s'\n",
- chosen_exchange);
- exchange->pending = GNUNET_YES;
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Not retrying exchange `%s', too early\n",
- chosen_exchange);
- }
- }
-
-
fo = GNUNET_new (struct TMH_EXCHANGES_FindOperation);
fo->fc = fc;
fo->fc_cls = fc_cls;
@@ -434,13 +433,14 @@ TMH_EXCHANGES_find_exchange_cancel (struct TMH_EXCHANGES_FindOperation *fo)
/**
* Function called on each configuration section. Finds sections
- * about exchanges and parses the entries.
+ * about exchanges, parses the entries and tries to connect to
+ * it in order to fetch /keys.
*
* @param cls closure, with a `const struct GNUNET_CONFIGURATION_Handle *`
* @param section name of the section
*/
static void
-parse_exchanges (void *cls,
+accept_exchanges (void *cls,
const char *section)
{
const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
@@ -524,19 +524,19 @@ TMH_EXCHANGES_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
return GNUNET_SYSERR;
}
merchant_curl_rc = GNUNET_CURL_gnunet_rc_create (merchant_curl_ctx);
+ /* get exchanges from the merchant configuration and try to connect to them */
GNUNET_CONFIGURATION_iterate_sections (cfg,
- &parse_exchanges,
+ &accept_exchanges,
(void *) cfg);
- /* build JSON with list of trusted exchanges */
+ /* build JSON with list of trusted exchanges (will be included in contracts) */
trusted_exchanges = json_array ();
for (exchange = exchange_head; NULL != exchange; exchange = exchange->next)
{
if (GNUNET_YES != exchange->trusted)
continue;
j_exchange = json_pack ("{s:s, s:o}",
- "url", exchange->uri,
- "master_pub", GNUNET_JSON_from_data (&exchange->master_pub,
- sizeof (struct TALER_MasterPublicKeyP)));
+ "url", exchange->uri,
+ "master_pub", GNUNET_JSON_from_data_auto (&exchange->master_pub));
json_array_append_new (trusted_exchanges,
j_exchange);
}