Merge branch 'master' of git+ssh://taler.net/var/git/exchange

This commit is contained in:
Christian Grothoff 2016-05-31 18:59:19 +02:00
commit 07449ce578
8 changed files with 408 additions and 67 deletions

View File

@ -13,9 +13,9 @@ taler_exchange_benchmark_SOURCES = \
taler-exchange-benchmark.c taler-exchange-benchmark.c
taler_exchange_benchmark_LDADD = \ taler_exchange_benchmark_LDADD = \
$(LIBGCRYPT_LIBS) \ $(LIBGCRYPT_LIBS) \
-ltalerexchange \ $(top_builddir)/src/json/libtalerjson.la \
-ltalerjson \ $(top_builddir)/src/util/libtalerutil.la \
-ltalerutil \ $(top_builddir)/src/exchange-lib/libtalerexchange.la \
-lgnunetjson \ -lgnunetjson \
-lgnunetcurl \ -lgnunetcurl \
-lgnunetutil \ -lgnunetutil \

View File

@ -108,6 +108,11 @@ struct TALER_EXCHANGE_Handle
*/ */
struct TALER_EXCHANGE_Keys key_data; struct TALER_EXCHANGE_Keys key_data;
/**
* When does @e key_data expire?
*/
struct GNUNET_TIME_Absolute key_data_expiration;
/** /**
* Raw key data of the exchange, only valid if * Raw key data of the exchange, only valid if
* @e handshake_complete is past stage #MHS_CERT. * @e handshake_complete is past stage #MHS_CERT.
@ -144,6 +149,12 @@ struct KeysRequest
*/ */
struct GNUNET_CURL_Job *job; struct GNUNET_CURL_Job *job;
/**
* Expiration time according to "Expire:" header.
* 0 if not provided by the server.
*/
struct GNUNET_TIME_Absolute expire;
}; };
@ -485,6 +496,7 @@ decode_keys_json (const json_t *resp_obj,
struct GNUNET_HashContext *hash_context; struct GNUNET_HashContext *hash_context;
struct TALER_ExchangePublicKeyP pub; struct TALER_ExchangePublicKeyP pub;
memset (key_data, 0, sizeof (struct TALER_EXCHANGE_Keys));
if (JSON_OBJECT != json_typeof (resp_obj)) if (JSON_OBJECT != json_typeof (resp_obj))
return GNUNET_SYSERR; return GNUNET_SYSERR;
@ -604,6 +616,58 @@ decode_keys_json (const json_t *resp_obj,
} }
/**
* Free key data object.
*
* @param key_data data to free (pointer itself excluded)
*/
static void
free_key_data (struct TALER_EXCHANGE_Keys *key_data)
{
unsigned int i;
GNUNET_array_grow (key_data->sign_keys,
key_data->num_sign_keys,
0);
for (i=0;i<key_data->num_denom_keys;i++)
GNUNET_CRYPTO_rsa_public_key_free (key_data->denom_keys[i].key.rsa_public_key);
GNUNET_array_grow (key_data->denom_keys,
key_data->num_denom_keys,
0);
GNUNET_array_grow (key_data->auditors,
key_data->num_auditors,
0);
}
/**
* Initiate download of /keys from the exchange.
*
* @param exchange where to download /keys from
*/
static void
request_keys (struct TALER_EXCHANGE_Handle *exchange);
/**
* Check if our current response for /keys is valid, and if
* not trigger download.
*
* @param exchange exchange to check keys for
* @return until when the response is current, 0 if we are re-downloading
*/
struct GNUNET_TIME_Absolute
TALER_EXCHANGE_check_keys_current (struct TALER_EXCHANGE_Handle *exchange)
{
if (NULL != exchange->kr)
return GNUNET_TIME_UNIT_ZERO_ABS;
if (0 < GNUNET_TIME_absolute_get_remaining (exchange->key_data_expiration).rel_value_us)
return exchange->key_data_expiration;
request_keys (exchange);
return GNUNET_TIME_UNIT_ZERO_ABS;
}
/** /**
* Callback used when downloading the reply to a /keys request * Callback used when downloading the reply to a /keys request
* is complete. * is complete.
@ -619,13 +683,16 @@ keys_completed_cb (void *cls,
{ {
struct KeysRequest *kr = cls; struct KeysRequest *kr = cls;
struct TALER_EXCHANGE_Handle *exchange = kr->exchange; struct TALER_EXCHANGE_Handle *exchange = kr->exchange;
TALER_EXCHANGE_CertificationCallback cb; struct TALER_EXCHANGE_Keys kd;
struct TALER_EXCHANGE_Keys kd_old;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received keys from URL `%s' with status %ld.\n", "Received keys from URL `%s' with status %ld.\n",
kr->url, kr->url,
response_code); response_code);
switch (response_code) { kd_old = exchange->key_data;
switch (response_code)
{
case 0: case 0:
break; break;
case MHD_HTTP_OK: case MHD_HTTP_OK:
@ -635,11 +702,14 @@ keys_completed_cb (void *cls,
break; break;
} }
if (GNUNET_OK != if (GNUNET_OK !=
decode_keys_json (resp_obj, &kr->exchange->key_data)) decode_keys_json (resp_obj,
&kd))
{ {
response_code = 0; response_code = 0;
break; break;
} }
exchange->key_data = kd;
json_decref (exchange->key_data_raw);
exchange->key_data_raw = json_deep_copy (resp_obj); exchange->key_data_raw = json_deep_copy (resp_obj);
break; break;
default: default:
@ -655,24 +725,25 @@ keys_completed_cb (void *cls,
free_keys_request (kr); free_keys_request (kr);
exchange->state = MHS_FAILED; exchange->state = MHS_FAILED;
/* notify application that we failed */ /* notify application that we failed */
if (NULL != (cb = exchange->cert_cb)) exchange->cert_cb (exchange->cert_cb_cls,
{ NULL);
exchange->cert_cb = NULL; if (NULL != exchange->key_data_raw)
cb (exchange->cert_cb_cls, {
NULL); json_decref (exchange->key_data_raw);
} exchange->key_data_raw = NULL;
}
free_key_data (&kd_old);
return; return;
} }
exchange->kr = NULL; exchange->kr = NULL;
exchange->key_data_expiration = kr->expire;
free_keys_request (kr); free_keys_request (kr);
exchange->state = MHS_CERT; exchange->state = MHS_CERT;
/* notify application about the key information */ /* notify application about the key information */
if (NULL != (cb = exchange->cert_cb)) exchange->cert_cb (exchange->cert_cb_cls,
{ &exchange->key_data);
exchange->cert_cb = NULL; free_key_data (&kd_old);
cb (exchange->cert_cb_cls,
&exchange->key_data);
}
} }
@ -730,6 +801,108 @@ MAH_path_to_url (struct TALER_EXCHANGE_Handle *h,
} }
/**
* Parse HTTP timestamp.
*
* @param date header to parse header
* @param at where to write the result
* @return #GNUNET_OK on success
*/
static int
parse_date_string (const char *date,
struct GNUNET_TIME_Absolute *at)
{
static const char *const days[] =
{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
static const char *const mons[] =
{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
struct tm now;
time_t t;
char day[3];
char mon[3];
unsigned int i;
unsigned int mday;
unsigned int year;
unsigned int h;
unsigned int m;
unsigned int s;
if (7 != sscanf (date,
"%3s, %02u %3s %04u %02u:%02u:%02u GMT",
day,
&mday,
mon,
&year,
&h,
&m,
&s))
return GNUNET_SYSERR;
memset (&now, 0, sizeof (now));
now.tm_year = year - 1900;
now.tm_mday = mday;
now.tm_hour = h;
now.tm_min = m;
now.tm_sec = s;
now.tm_wday = 7;
for (i=0;i<7;i++)
if (0 == strcasecmp (days[i], day))
now.tm_wday = i;
now.tm_mon = 12;
for (i=0;i<12;i++)
if (0 == strcasecmp (mons[i], mon))
now.tm_mon = i;
if ( (7 == now.tm_mday) ||
(12 == now.tm_mon) )
return GNUNET_SYSERR;
t = mktime (&now);
at->abs_value_us = 1000LL * 1000LL * t;
return GNUNET_OK;
}
/**
* Function called for each header in the HTTP /keys response.
* Finds the "Expire:" header and parses it, storing the result
* in the "expire" field fo the keys request.
*
* @param buffer header data received
* @param size size of an item in @a buffer
* @param nitems number of items in @a buffer
* @param userdata the `struct KeysRequest`
* @return `size * nitems` on success (everything else aborts)
*/
static size_t
header_cb (char *buffer,
size_t size,
size_t nitems,
void *userdata)
{
struct KeysRequest *kr = userdata;
size_t total = size * nitems;
char *val;
if (total < strlen (MHD_HTTP_HEADER_EXPIRES ": "))
return total;
if (0 != strncasecmp (MHD_HTTP_HEADER_EXPIRES ": ",
buffer,
strlen (MHD_HTTP_HEADER_EXPIRES ": ")))
return total;
val = GNUNET_strndup (&buffer[strlen (MHD_HTTP_HEADER_EXPIRES ": ")],
total - strlen (MHD_HTTP_HEADER_EXPIRES ": "));
if (GNUNET_OK !=
parse_date_string (val,
&kr->expire))
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to parse %s-header `%s'\n",
MHD_HTTP_HEADER_EXPIRES,
val);
}
GNUNET_free (val);
return total;
}
/* ********************* public API ******************* */ /* ********************* public API ******************* */
/** /**
@ -755,40 +928,62 @@ TALER_EXCHANGE_connect (struct GNUNET_CURL_Context *ctx,
...) ...)
{ {
struct TALER_EXCHANGE_Handle *exchange; struct TALER_EXCHANGE_Handle *exchange;
struct KeysRequest *kr;
CURL *c;
exchange = GNUNET_new (struct TALER_EXCHANGE_Handle); exchange = GNUNET_new (struct TALER_EXCHANGE_Handle);
exchange->ctx = ctx; exchange->ctx = ctx;
exchange->url = GNUNET_strdup (url); exchange->url = GNUNET_strdup (url);
exchange->cert_cb = cert_cb; exchange->cert_cb = cert_cb;
exchange->cert_cb_cls = cert_cb_cls; exchange->cert_cb_cls = cert_cb_cls;
request_keys (exchange);
return exchange;
}
/**
* Initiate download of /keys from the exchange.
*
* @param exchange where to download /keys from
*/
static void
request_keys (struct TALER_EXCHANGE_Handle *exchange)
{
struct KeysRequest *kr;
CURL *eh;
GNUNET_assert (NULL == exchange->kr);
kr = GNUNET_new (struct KeysRequest); kr = GNUNET_new (struct KeysRequest);
kr->exchange = exchange; kr->exchange = exchange;
kr->url = MAH_path_to_url (exchange, "/keys"); kr->url = MAH_path_to_url (exchange, "/keys");
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Requesting keys with URL `%s'.\n", "Requesting keys with URL `%s'.\n",
kr->url); kr->url);
c = curl_easy_init (); eh = curl_easy_init ();
GNUNET_assert (CURLE_OK == GNUNET_assert (CURLE_OK ==
curl_easy_setopt (c, curl_easy_setopt (eh,
CURLOPT_VERBOSE, CURLOPT_VERBOSE,
0)); 0));
GNUNET_assert (CURLE_OK == GNUNET_assert (CURLE_OK ==
curl_easy_setopt (c, curl_easy_setopt (eh,
CURLOPT_STDERR, CURLOPT_TIMEOUT,
stdout)); (long) 300));
GNUNET_assert (CURLE_OK == GNUNET_assert (CURLE_OK ==
curl_easy_setopt (c, curl_easy_setopt (eh,
CURLOPT_HEADERFUNCTION,
&header_cb));
GNUNET_assert (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_HEADERDATA,
kr));
GNUNET_assert (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_URL, CURLOPT_URL,
kr->url)); kr->url));
kr->job = GNUNET_CURL_job_add (exchange->ctx, kr->job = GNUNET_CURL_job_add (exchange->ctx,
c, eh,
GNUNET_NO, GNUNET_NO,
&keys_completed_cb, &keys_completed_cb,
kr); kr);
exchange->kr = kr; exchange->kr = kr;
return exchange;
} }
@ -800,26 +995,18 @@ TALER_EXCHANGE_connect (struct GNUNET_CURL_Context *ctx,
void void
TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange) TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange)
{ {
unsigned int i;
if (NULL != exchange->kr) if (NULL != exchange->kr)
{ {
GNUNET_CURL_job_cancel (exchange->kr->job); GNUNET_CURL_job_cancel (exchange->kr->job);
free_keys_request (exchange->kr); free_keys_request (exchange->kr);
exchange->kr = NULL; exchange->kr = NULL;
} }
GNUNET_array_grow (exchange->key_data.sign_keys, free_key_data (&exchange->key_data);
exchange->key_data.num_sign_keys, if (NULL != exchange->key_data_raw)
0); {
for (i=0;i<exchange->key_data.num_denom_keys;i++) json_decref (exchange->key_data_raw);
GNUNET_CRYPTO_rsa_public_key_free (exchange->key_data.denom_keys[i].key.rsa_public_key); exchange->key_data_raw = NULL;
GNUNET_array_grow (exchange->key_data.denom_keys, }
exchange->key_data.num_denom_keys,
0);
GNUNET_array_grow (exchange->key_data.auditors,
exchange->key_data.num_auditors,
0);
json_decref (exchange->key_data_raw);
GNUNET_free (exchange->url); GNUNET_free (exchange->url);
GNUNET_free (exchange); GNUNET_free (exchange);
} }
@ -863,7 +1050,7 @@ TALER_EXCHANGE_test_signing_key (const struct TALER_EXCHANGE_Keys *keys,
*/ */
const struct TALER_EXCHANGE_DenomPublicKey * const struct TALER_EXCHANGE_DenomPublicKey *
TALER_EXCHANGE_get_denomination_key (const struct TALER_EXCHANGE_Keys *keys, TALER_EXCHANGE_get_denomination_key (const struct TALER_EXCHANGE_Keys *keys,
const struct TALER_DenominationPublicKey *pk) const struct TALER_DenominationPublicKey *pk)
{ {
unsigned int i; unsigned int i;
@ -884,7 +1071,7 @@ TALER_EXCHANGE_get_denomination_key (const struct TALER_EXCHANGE_Keys *keys,
*/ */
const struct TALER_EXCHANGE_DenomPublicKey * const struct TALER_EXCHANGE_DenomPublicKey *
TALER_EXCHANGE_get_denomination_key_by_hash (const struct TALER_EXCHANGE_Keys *keys, TALER_EXCHANGE_get_denomination_key_by_hash (const struct TALER_EXCHANGE_Keys *keys,
const struct GNUNET_HashCode *hc) const struct GNUNET_HashCode *hc)
{ {
unsigned int i; unsigned int i;
@ -904,8 +1091,9 @@ TALER_EXCHANGE_get_denomination_key_by_hash (const struct TALER_EXCHANGE_Keys *k
* @return the exchange's key set * @return the exchange's key set
*/ */
const struct TALER_EXCHANGE_Keys * const struct TALER_EXCHANGE_Keys *
TALER_EXCHANGE_get_keys (const struct TALER_EXCHANGE_Handle *exchange) TALER_EXCHANGE_get_keys (struct TALER_EXCHANGE_Handle *exchange)
{ {
(void) TALER_EXCHANGE_check_keys_current (exchange);
return &exchange->key_data; return &exchange->key_data;
} }
@ -918,8 +1106,9 @@ TALER_EXCHANGE_get_keys (const struct TALER_EXCHANGE_Handle *exchange)
* @return the exchange's keys in raw JSON * @return the exchange's keys in raw JSON
*/ */
json_t * json_t *
TALER_EXCHANGE_get_keys_raw (const struct TALER_EXCHANGE_Handle *exchange) TALER_EXCHANGE_get_keys_raw (struct TALER_EXCHANGE_Handle *exchange)
{ {
(void) TALER_EXCHANGE_check_keys_current (exchange);
return json_deep_copy (exchange->key_data_raw); return json_deep_copy (exchange->key_data_raw);
} }

View File

@ -88,6 +88,11 @@ struct TMH_KS_StateHandle
*/ */
struct GNUNET_TIME_Absolute next_reload; struct GNUNET_TIME_Absolute next_reload;
/**
* When does the first active denomination key expire (for deposit)?
*/
struct GNUNET_TIME_Absolute min_dk_expire;
/** /**
* Exchange signing key that should be used currently. * Exchange signing key that should be used currently.
*/ */
@ -217,6 +222,7 @@ reload_keys_denom_iter (void *cls,
struct TMH_KS_StateHandle *ctx = cls; struct TMH_KS_StateHandle *ctx = cls;
struct GNUNET_TIME_Absolute now; struct GNUNET_TIME_Absolute now;
struct GNUNET_TIME_Absolute horizon; struct GNUNET_TIME_Absolute horizon;
struct GNUNET_TIME_Absolute expire_deposit;
struct GNUNET_HashCode denom_key_hash; struct GNUNET_HashCode denom_key_hash;
struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *d2; struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *d2;
struct TALER_EXCHANGEDB_Session *session; struct TALER_EXCHANGEDB_Session *session;
@ -235,8 +241,8 @@ reload_keys_denom_iter (void *cls,
return GNUNET_OK; return GNUNET_OK;
} }
now = GNUNET_TIME_absolute_get (); now = GNUNET_TIME_absolute_get ();
if (GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_deposit).abs_value_us < expire_deposit = GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_deposit);
now.abs_value_us) if (expire_deposit.abs_value_us < now.abs_value_us)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Skipping expired denomination key `%s'\n", "Skipping expired denomination key `%s'\n",
@ -339,6 +345,8 @@ reload_keys_denom_iter (void *cls,
GNUNET_free (d2); GNUNET_free (d2);
return GNUNET_OK; return GNUNET_OK;
} }
ctx->min_dk_expire = GNUNET_TIME_absolute_min (ctx->min_dk_expire,
expire_deposit);
json_array_append_new (ctx->denom_keys_array, json_array_append_new (ctx->denom_keys_array,
denom_key_issue_to_json (&dki->denom_pub, denom_key_issue_to_json (&dki->denom_pub,
&dki->issue)); &dki->issue));
@ -643,7 +651,7 @@ TMH_KS_acquire_ (const char *location)
{ {
key_state = GNUNET_new (struct TMH_KS_StateHandle); key_state = GNUNET_new (struct TMH_KS_StateHandle);
key_state->hash_context = GNUNET_CRYPTO_hash_context_start (); key_state->hash_context = GNUNET_CRYPTO_hash_context_start ();
key_state->min_dk_expire = GNUNET_TIME_UNIT_FOREVER_ABS;
key_state->denom_keys_array = json_array (); key_state->denom_keys_array = json_array ();
GNUNET_assert (NULL != key_state->denom_keys_array); GNUNET_assert (NULL != key_state->denom_keys_array);
@ -680,7 +688,6 @@ TMH_KS_acquire_ (const char *location)
return NULL; return NULL;
} }
ks.purpose.size = htonl (sizeof (ks)); ks.purpose.size = htonl (sizeof (ks));
ks.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_KEY_SET); ks.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_KEY_SET);
ks.list_issue_date = GNUNET_TIME_absolute_hton (key_state->reload_time); ks.list_issue_date = GNUNET_TIME_absolute_hton (key_state->reload_time);
@ -691,7 +698,9 @@ TMH_KS_acquire_ (const char *location)
GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv.eddsa_priv, GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv.eddsa_priv,
&ks.purpose, &ks.purpose,
&sig.eddsa_signature)); &sig.eddsa_signature));
key_state->next_reload = GNUNET_TIME_absolute_ntoh (key_state->current_sign_key_issue.issue.expire); key_state->next_reload =
GNUNET_TIME_absolute_min (GNUNET_TIME_absolute_ntoh (key_state->current_sign_key_issue.issue.expire),
key_state->min_dk_expire);
if (0 == key_state->next_reload.abs_value_us) if (0 == key_state->next_reload.abs_value_us)
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"No valid signing key found!\n"); "No valid signing key found!\n");
@ -1001,6 +1010,58 @@ TMH_KS_sign (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
} }
/**
* Produce HTTP "Date:" header.
*
* @param at time to write to @a date
* @param[out] date where to write the header, with
* at least 128 bytes available space.
*/
static void
get_date_string (struct GNUNET_TIME_Absolute at,
char *date)
{
static const char *const days[] =
{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
static const char *const mons[] =
{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
"Nov", "Dec"
};
struct tm now;
time_t t;
#if !defined(HAVE_C11_GMTIME_S) && !defined(HAVE_W32_GMTIME_S) && !defined(HAVE_GMTIME_R)
struct tm* pNow;
#endif
date[0] = 0;
t = (time_t) (at.abs_value_us / 1000LL / 1000LL);
#if defined(HAVE_C11_GMTIME_S)
if (NULL == gmtime_s (&t, &now))
return;
#elif defined(HAVE_W32_GMTIME_S)
if (0 != gmtime_s (&now, &t))
return;
#elif defined(HAVE_GMTIME_R)
if (NULL == gmtime_r(&t, &now))
return;
#else
pNow = gmtime(&t);
if (NULL == pNow)
return;
now = *pNow;
#endif
sprintf (date,
"%3s, %02u %3s %04u %02u:%02u:%02u GMT",
days[now.tm_wday % 7],
(unsigned int) now.tm_mday,
mons[now.tm_mon % 12],
(unsigned int) (1900 + now.tm_year),
(unsigned int) now.tm_hour,
(unsigned int) now.tm_min,
(unsigned int) now.tm_sec);
}
/** /**
* Function to call to handle the request by sending * Function to call to handle the request by sending
* back static data from the @a rh. * back static data from the @a rh.
@ -1022,6 +1083,7 @@ TMH_KS_handler_keys (struct TMH_RequestHandler *rh,
struct TMH_KS_StateHandle *key_state; struct TMH_KS_StateHandle *key_state;
struct MHD_Response *response; struct MHD_Response *response;
int ret; int ret;
char dat[128];
key_state = TMH_KS_acquire (); key_state = TMH_KS_acquire ();
response = MHD_create_response_from_buffer (strlen (key_state->keys_json), response = MHD_create_response_from_buffer (strlen (key_state->keys_json),
@ -1034,9 +1096,22 @@ TMH_KS_handler_keys (struct TMH_RequestHandler *rh,
return MHD_NO; return MHD_NO;
} }
TMH_RESPONSE_add_global_headers (response); TMH_RESPONSE_add_global_headers (response);
(void) MHD_add_response_header (response, GNUNET_break (MHD_YES ==
"Content-Type", MHD_add_response_header (response,
rh->mime_type); MHD_HTTP_HEADER_CONTENT_TYPE,
rh->mime_type));
get_date_string (key_state->reload_time,
dat);
GNUNET_break (MHD_YES ==
MHD_add_response_header (response,
MHD_HTTP_HEADER_LAST_MODIFIED,
dat));
get_date_string (key_state->next_reload,
dat);
GNUNET_break (MHD_YES ==
MHD_add_response_header (response,
MHD_HTTP_HEADER_EXPIRES,
dat));
ret = MHD_queue_response (connection, ret = MHD_queue_response (connection,
rh->response_code, rh->response_code,
response); response);

View File

@ -40,9 +40,10 @@ void
TMH_RESPONSE_add_global_headers (struct MHD_Response *response) TMH_RESPONSE_add_global_headers (struct MHD_Response *response)
{ {
if (TMH_exchange_connection_close) if (TMH_exchange_connection_close)
(void) MHD_add_response_header (response, GNUNET_break (MHD_YES ==
MHD_HTTP_HEADER_CONNECTION, MHD_add_response_header (response,
"close"); MHD_HTTP_HEADER_CONNECTION,
"close"));
} }

View File

@ -4298,6 +4298,12 @@ postgres_gc (void *cls)
conn = connect_to_postgres (pc); conn = connect_to_postgres (pc);
if (NULL == conn) if (NULL == conn)
return GNUNET_SYSERR; return GNUNET_SYSERR;
if (GNUNET_OK !=
postgres_prepare (conn))
{
PQfinish (conn);
return GNUNET_SYSERR;
}
result = GNUNET_PQ_exec_prepared (conn, result = GNUNET_PQ_exec_prepared (conn,
"gc_prewire", "gc_prewire",
params_none); params_none);

View File

@ -202,11 +202,17 @@ destroy_denom_key_pair (struct DenomKeyPair *dkp)
* *
* @param size the size of the denomination key * @param size the size of the denomination key
* @param session the DB session * @param session the DB session
* @param now time to use for key generation, legal expiration will be 3h later.
* @param fee_withdraw withdraw fee to use
* @param fee_deposit deposit fee to use
* @param fee_refresh refresh fee to use
* @param fee_refund refund fee to use
* @return the denominaiton key pair; NULL upon error * @return the denominaiton key pair; NULL upon error
*/ */
static struct DenomKeyPair * static struct DenomKeyPair *
create_denom_key_pair (unsigned int size, create_denom_key_pair (unsigned int size,
struct TALER_EXCHANGEDB_Session *session, struct TALER_EXCHANGEDB_Session *session,
struct GNUNET_TIME_Absolute now,
const struct TALER_Amount *value, const struct TALER_Amount *value,
const struct TALER_Amount *fee_withdraw, const struct TALER_Amount *fee_withdraw,
const struct TALER_Amount *fee_deposit, const struct TALER_Amount *fee_deposit,
@ -216,7 +222,6 @@ create_denom_key_pair (unsigned int size,
struct DenomKeyPair *dkp; struct DenomKeyPair *dkp;
struct TALER_EXCHANGEDB_DenominationKeyIssueInformation dki; struct TALER_EXCHANGEDB_DenominationKeyIssueInformation dki;
struct TALER_EXCHANGEDB_DenominationKeyInformationP issue2; struct TALER_EXCHANGEDB_DenominationKeyInformationP issue2;
struct GNUNET_TIME_Absolute now;
dkp = GNUNET_new (struct DenomKeyPair); dkp = GNUNET_new (struct DenomKeyPair);
dkp->priv.rsa_private_key = GNUNET_CRYPTO_rsa_private_key_create (size); dkp->priv.rsa_private_key = GNUNET_CRYPTO_rsa_private_key_create (size);
@ -230,7 +235,6 @@ create_denom_key_pair (unsigned int size,
0, 0,
sizeof (struct TALER_EXCHANGEDB_DenominationKeyIssueInformation)); sizeof (struct TALER_EXCHANGEDB_DenominationKeyIssueInformation));
dki.denom_pub = dkp->pub; dki.denom_pub = dkp->pub;
now = GNUNET_TIME_absolute_get ();
GNUNET_TIME_round_abs (&now); GNUNET_TIME_round_abs (&now);
dki.issue.properties.start = GNUNET_TIME_absolute_hton (now); dki.issue.properties.start = GNUNET_TIME_absolute_hton (now);
dki.issue.properties.expire_withdraw = GNUNET_TIME_absolute_hton dki.issue.properties.expire_withdraw = GNUNET_TIME_absolute_hton
@ -558,7 +562,7 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
struct TALER_EXCHANGEDB_LinkDataList *ldl; struct TALER_EXCHANGEDB_LinkDataList *ldl;
struct TALER_EXCHANGEDB_LinkDataList *ldlp; struct TALER_EXCHANGEDB_LinkDataList *ldlp;
struct TALER_DenominationSignature ev_sigs[MELT_NEW_COINS]; struct TALER_DenominationSignature ev_sigs[MELT_NEW_COINS];
unsigned int cnt; unsigned int cnt;
unsigned int i; unsigned int i;
int ret; int ret;
@ -575,6 +579,7 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
/* create a denomination (value: 1; fraction: 100) */ /* create a denomination (value: 1; fraction: 100) */
dkp = create_denom_key_pair (512, dkp = create_denom_key_pair (512,
session, session,
GNUNET_TIME_absolute_get (),
&value, &value,
&fee_withdraw, &fee_withdraw,
&fee_deposit, &fee_deposit,
@ -645,6 +650,7 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
{ {
new_dkp[cnt] = create_denom_key_pair (1024, new_dkp[cnt] = create_denom_key_pair (1024,
session, session,
GNUNET_TIME_absolute_get (),
&value, &value,
&fee_withdraw, &fee_withdraw,
&fee_deposit, &fee_deposit,
@ -974,6 +980,54 @@ deposit_cb (void *cls,
} }
/**
* Test garbage collection.
*
* @param session DB session to use
* @return #GNUNET_OK on success
*/
static int
test_gc (struct TALER_EXCHANGEDB_Session *session)
{
struct DenomKeyPair *dkp;
struct GNUNET_TIME_Absolute now;
struct GNUNET_TIME_Absolute past;
struct TALER_EXCHANGEDB_DenominationKeyInformationP issue2;
now = GNUNET_TIME_absolute_get ();
past = GNUNET_TIME_absolute_subtract (now,
GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS,
4));
dkp = create_denom_key_pair (1024,
session,
past,
&value,
&fee_withdraw,
&fee_deposit,
&fee_refresh,
&fee_refund);
if (GNUNET_OK !=
plugin->gc (plugin->cls))
{
GNUNET_break(0);
destroy_denom_key_pair (dkp);
return GNUNET_SYSERR;
}
if (GNUNET_OK ==
plugin->get_denomination_info (plugin->cls,
session,
&dkp->pub,
&issue2))
{
GNUNET_break(0);
destroy_denom_key_pair (dkp);
return GNUNET_SYSERR;
}
destroy_denom_key_pair (dkp);
return GNUNET_OK;
}
/** /**
* Main function that will be run by the scheduler. * Main function that will be run by the scheduler.
* *
@ -1093,7 +1147,9 @@ run (void *cls)
value.fraction * 2, value.fraction * 2,
value.currency)); value.currency));
result = 5; result = 5;
dkp = create_denom_key_pair (1024, session, dkp = create_denom_key_pair (1024,
session,
GNUNET_TIME_absolute_get (),
&value, &value,
&fee_withdraw, &fee_withdraw,
&fee_deposit, &fee_deposit,
@ -1427,6 +1483,9 @@ run (void *cls)
transaction_id_wt, transaction_id_wt,
&cb_wtid_check, &cb_wtid_check,
&cb_wtid_never)); &cb_wtid_never));
FAILIF (GNUNET_OK !=
test_gc (session));
result = 0; result = 0;
drop: drop:

View File

@ -220,7 +220,7 @@ struct TALER_EXCHANGE_Keys
* *
* @param cls closure * @param cls closure
* @param keys information about the various keys used * @param keys information about the various keys used
* by the exchange * by the exchange, NULL if /keys failed
*/ */
typedef void typedef void
(*TALER_EXCHANGE_CertificationCallback) (void *cls, (*TALER_EXCHANGE_CertificationCallback) (void *cls,
@ -244,7 +244,8 @@ struct TALER_EXCHANGE_Handle;
* *
* @param ctx the context * @param ctx the context
* @param url HTTP base URL for the exchange * @param url HTTP base URL for the exchange
* @param cert_cb function to call with the exchange's certification information * @param cert_cb function to call with the exchange's certification information,
* possibly called repeatedly if the information changes
* @param cert_cb_cls closure for @a cert_cb * @param cert_cb_cls closure for @a cert_cb
* @param ... list of additional arguments, terminated by #TALER_EXCHANGE_OPTION_END. * @param ... list of additional arguments, terminated by #TALER_EXCHANGE_OPTION_END.
* @return the exchange handle; NULL upon error * @return the exchange handle; NULL upon error
@ -273,18 +274,28 @@ TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange);
* @return the exchange's key set * @return the exchange's key set
*/ */
const struct TALER_EXCHANGE_Keys * const struct TALER_EXCHANGE_Keys *
TALER_EXCHANGE_get_keys (const struct TALER_EXCHANGE_Handle *exchange); TALER_EXCHANGE_get_keys (struct TALER_EXCHANGE_Handle *exchange);
/** /**
* Obtain the keys from the exchange in the * Check if our current response for /keys is valid, and if
* raw JSON format * not, trigger /keys download.
*
* @param exchange exchange to check keys for
* @return until when the response is current, 0 if we are re-downloading
*/
struct GNUNET_TIME_Absolute
TALER_EXCHANGE_check_keys_current (struct TALER_EXCHANGE_Handle *exchange);
/**
* Obtain the keys from the exchange in the raw JSON format.
* *
* @param exchange the exchange handle * @param exchange the exchange handle
* @return the exchange's keys in raw JSON * @return the exchange's keys in raw JSON
*/ */
json_t * json_t *
TALER_EXCHANGE_get_keys_raw (const struct TALER_EXCHANGE_Handle *exchange); TALER_EXCHANGE_get_keys_raw (struct TALER_EXCHANGE_Handle *exchange);
/** /**