[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-donau] 03/03: [donau] first iteration on /keys: adapt structs and
From: |
gnunet |
Subject: |
[taler-donau] 03/03: [donau] first iteration on /keys: adapt structs and includes from exchange get /keys as well |
Date: |
Sat, 06 Jan 2024 23:18:12 +0100 |
This is an automated email from the git hooks/post-receive script.
pius-loosli pushed a commit to branch master
in repository donau.
commit f49c763dba881e5b90fb46c01e7036779cd26a4b
Author: Pius Loosli <loosp2@bfh.ch>
AuthorDate: Sat Jan 6 23:14:09 2024 +0100
[donau] first iteration on /keys: adapt structs and includes from exchange
get /keys as well
---
src/donau/donau-httpd.c | 45 +--
src/donau/donau-httpd_keys.c | 667 ++++++++++++++++++++++++++++++++-----------
src/donau/donau-httpd_keys.h | 121 +++++++-
3 files changed, 618 insertions(+), 215 deletions(-)
diff --git a/src/donau/donau-httpd.c b/src/donau/donau-httpd.c
index 125f244..54c750d 100644
--- a/src/donau/donau-httpd.c
+++ b/src/donau/donau-httpd.c
@@ -176,15 +176,15 @@ typedef MHD_RESULT
* @param connection where to send the reply on
* @param details details for the error message, can be NULL
*/
-static MHD_RESULT
-r404 (struct MHD_Connection *connection,
- const char *details)
-{
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_NOT_FOUND,
-
TALER_EC_EXCHANGE_GENERIC_OPERATION_UNKNOWN,
- details);
-}
+// static MHD_RESULT
+// r404 (struct MHD_Connection *connection,
+// const char *details)
+// {
+// return TALER_MHD_reply_with_error (connection,
+// MHD_HTTP_NOT_FOUND,
+//
TALER_EC_EXCHANGE_GENERIC_OPERATION_UNKNOWN,
+// details);
+// }
/**
@@ -386,31 +386,6 @@ proceed_with_handler (struct DH_RequestContext *rc,
}
-/**
- * Handle a GET "/management" request.
- *
- * @param rc request context
- * @param args array of additional options (must be [0] == "keys")
- * @return MHD result code
- */
-static MHD_RESULT
-handle_get_keys (struct DH_RequestContext *rc,
- const char *const args[2])
-{
- if ( (NULL != args[0]) &&
- (0 == strcmp (args[0],
- "keys")) &&
- (NULL == args[1]) )
- {
- return DH_get_keys_handler (rc->rh,
- rc->connection);
- }
- GNUNET_break_op (0);
- return r404 (rc->connection,
- "/management/*");
-}
-
-
/**
* Handle incoming HTTP request.
*
@@ -454,7 +429,7 @@ handle_mhd_request (void *cls,
{
.url = "keys",
.method = MHD_HTTP_METHOD_GET,
- .handler.get = &handle_get_keys,
+ .handler.get = &DH_keys_get_handler,
.nargs = 1
},
/**
diff --git a/src/donau/donau-httpd_keys.c b/src/donau/donau-httpd_keys.c
index dcff3de..6558bfc 100644
--- a/src/donau/donau-httpd_keys.c
+++ b/src/donau/donau-httpd_keys.c
@@ -27,13 +27,159 @@
#include "donau-httpd_config.h"
#include "donaudb_plugin.h"
-
/**
* How many /keys request do we hold in suspension at
* most at any time?
*/
#define SKR_LIMIT 32
+/**
+ * When do we forcefully timeout a /keys request?
+ */
+#define KEYS_TIMEOUT GNUNET_TIME_UNIT_MINUTES
+
+/**
+ * Number of entries in the @e skr_head DLL.
+ */
+static unsigned int skr_size;
+
+/**
+ * Handle to a connection that should be force-resumed
+ * with a hard error due to @a skr_size hitting
+ * #SKR_LIMIT.
+ */
+static struct MHD_Connection *skr_connection;
+
+/**
+ * Entry of /keys requests that are currently suspended because we are
+ * waiting for /keys to become ready.
+ */
+struct SuspendedKeysRequests
+{
+ /**
+ * Kept in a DLL.
+ */
+ struct SuspendedKeysRequests *next;
+
+ /**
+ * Kept in a DLL.
+ */
+ struct SuspendedKeysRequests *prev;
+
+ /**
+ * The suspended connection.
+ */
+ struct MHD_Connection *connection;
+
+ /**
+ * When does this request timeout?
+ */
+ struct GNUNET_TIME_Absolute timeout;
+};
+
+/**
+ * Head of DLL of suspended /keys requests.
+ */
+static struct SuspendedKeysRequests *skr_head;
+
+/**
+ * Tail of DLL of suspended /keys requests.
+ */
+static struct SuspendedKeysRequests *skr_tail;
+
+/**
+ * Task to force timeouts on /keys requests.
+ */
+static struct GNUNET_SCHEDULER_Task *keys_tt;
+
+/**
+ * Are we shutting down?
+ */
+static bool terminating;
+
+/**
+ * Function called to forcefully resume suspended keys requests.
+ *
+ * @param cls unused, NULL
+ */
+static void
+keys_timeout_cb (void *cls)
+{
+ struct SuspendedKeysRequests *skr;
+
+ (void) cls;
+ keys_tt = NULL;
+ while (NULL != (skr = skr_head))
+ {
+ if (GNUNET_TIME_absolute_is_future (skr->timeout))
+ break;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Resuming /keys request due to timeout\n");
+ GNUNET_CONTAINER_DLL_remove (skr_head,
+ skr_tail,
+ skr);
+ MHD_resume_connection (skr->connection);
+ TALER_MHD_daemon_trigger ();
+ GNUNET_free (skr);
+ }
+ if (NULL == skr)
+ return;
+ keys_tt = GNUNET_SCHEDULER_add_at (skr->timeout,
+ &keys_timeout_cb,
+ NULL);
+}
+
+
+/**
+ * Suspend /keys request while we (hopefully) are waiting to be
+ * provisioned with key material.
+ *
+ * @param[in] connection to suspend
+ */
+static MHD_RESULT
+suspend_request (struct MHD_Connection *connection)
+{
+ struct SuspendedKeysRequests *skr;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Suspending /keys request until key material changes\n");
+ if (terminating)
+ {
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
+ "Exchange terminating");
+ }
+ skr = GNUNET_new (struct SuspendedKeysRequests);
+ skr->connection = connection;
+ MHD_suspend_connection (connection);
+ GNUNET_CONTAINER_DLL_insert (skr_head,
+ skr_tail,
+ skr);
+ skr->timeout = GNUNET_TIME_relative_to_absolute (KEYS_TIMEOUT);
+ if (NULL == keys_tt)
+ {
+ keys_tt = GNUNET_SCHEDULER_add_at (skr->timeout,
+ &keys_timeout_cb,
+ NULL);
+ }
+ skr_size++;
+ if (skr_size > SKR_LIMIT)
+ {
+ skr = skr_tail;
+ GNUNET_CONTAINER_DLL_remove (skr_head,
+ skr_tail,
+ skr);
+ skr_size--;
+ skr_connection = skr->connection;
+ MHD_resume_connection (skr->connection);
+ TALER_MHD_daemon_trigger ();
+ GNUNET_free (skr);
+ }
+ return MHD_YES;
+}
+
+
/**
* Information about a donation unit on offer by the donation unit helper.
*/
@@ -115,17 +261,17 @@ static uint64_t key_generation;
/**
* RSA security module public key, all zero if not known.
*/
-static struct TALER_SecurityModulePublicKeyP donation_unit_rsa_sm_pub;
+// static struct TALER_SecurityModulePublicKeyP donation_unit_rsa_sm_pub;
/**
* CS security module public key, all zero if not known.
*/
-static struct TALER_SecurityModulePublicKeyP donation_unit_cs_sm_pub;
+// static struct TALER_SecurityModulePublicKeyP donation_unit_cs_sm_pub;
/**
* EdDSA security module public key, all zero if not known.
*/
-static struct TALER_SecurityModulePublicKeyP esign_sm_pub;
+// static struct TALER_SecurityModulePublicKeyP esign_sm_pub;
/**
@@ -302,9 +448,9 @@ struct HelperState
};
/**
- * Closure for #add_denom_key_cb.
+ * Closure for #add_donation_unit_key_cb.
*/
-struct DenomKeyCtx
+struct DonationUnitKeyCtx
{
/**
* Heap for sorting active donation unit keys by start time.
@@ -447,11 +593,10 @@ finish_keys_response (struct DH_KeyStateHandle *ksh)
GNUNET_assert (NULL != recoup);
heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX);
{
- struct DenomKeyCtx dkc = {
- .recoup = recoup,
- .heap = heap,
- .min_dk_frequency = GNUNET_TIME_UNIT_FOREVER_REL,
- };
+ // struct DonationUnitKeyCtx dkc = {
+ // .heap = heap,
+ // .min_dk_frequency = GNUNET_TIME_UNIT_FOREVER_REL,
+ // };
// GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
// &add_denom_key_cb,
@@ -500,7 +645,7 @@ finish_keys_response (struct DH_KeyStateHandle *ksh)
ret = GNUNET_OK;
-CLEANUP:
+// CLEANUP:
json_decref (grouped_donation_units);
json_decref (sctx.signkeys);
json_decref (recoup);
@@ -735,11 +880,11 @@ setup_key_helpers (struct HelperState *hs)
* @return NULL on error (i.e. failed to access database)
*/
static struct DH_KeyStateHandle *
-build_key_state (struct HelperState *hs,
- bool management_only)
+build_key_state (struct HelperState *hs /*,
+ bool management_only*/)
{
struct DH_KeyStateHandle *ksh;
- enum GNUNET_DB_QueryStatus qs;
+ // enum GNUNET_DB_QueryStatus qs;
ksh = GNUNET_new (struct DH_KeyStateHandle);
ksh->signature_expires = GNUNET_TIME_UNIT_FOREVER_TS;
@@ -801,11 +946,11 @@ build_key_state (struct HelperState *hs,
// return NULL;
// }
- if (management_only)
- {
- ksh->management_only = true;
- return ksh;
- }
+ // if (management_only)
+ // {
+ // ksh->management_only = true;
+ // return ksh;
+ // }
if (GNUNET_OK !=
finish_keys_response (ksh))
@@ -839,14 +984,14 @@ DH_keys_update_states ()
static struct DH_KeyStateHandle *
-keys_get_state (bool management_only)
+DH_keys_get_state (/*bool management_only*/)
{
struct DH_KeyStateHandle *old_ksh;
struct DH_KeyStateHandle *ksh;
old_ksh = key_state;
if (NULL == old_ksh)
{
- ksh = build_key_state (NULL, management_only);
+ ksh = build_key_state (NULL /*, management_only*/);
ksh = NULL;
if (NULL == ksh)
return NULL;
@@ -860,8 +1005,8 @@ keys_get_state (bool management_only)
"Rebuilding /keys, generation upgrade from %llu to %llu\n",
(unsigned long long) old_ksh->key_generation,
(unsigned long long) key_generation);
- ksh = build_key_state (old_ksh->helpers,
- management_only);
+ ksh = build_key_state (old_ksh->helpers /*,
+ management_only*/);
key_state = ksh;
old_ksh->helpers = NULL;
destroy_key_state (old_ksh,
@@ -895,179 +1040,353 @@ struct FutureBuilderContext
};
+// /**
+// * Function called on all of our current and future donation unit keys
+// * known to the helper process. Filters out those that are current
+// * and adds the remaining donation unit keys (with their configuration
+// * data) to the JSON array.
+// *
+// * @param cls the `struct FutureBuilderContext *`
+// * @param h_donation_unit_pub hash of the donation unit public key
+// * @param value a `struct HelperDenomination`
+// * @return #GNUNET_OK (continue to iterate)
+// */
+// static enum GNUNET_GenericReturnValue
+// add_donation_unitkey_cb (void *cls,
+// const struct GNUNET_HashCode *h_donation_unit_pub,
+// void *value)
+// {
+// struct FutureBuilderContext *fbc = cls;
+// struct HelperDonationUnit *helper_donation_unit = value;
+// struct DH_DonationUnitKey *donation_unit_key;
+// struct DONAUDB_DonationUnitKeyMetaData meta = {0};
+
+// donation_unit_key = GNUNET_CONTAINER_multihashmap_get
(fbc->ksh->denomkey_map,
+//
h_donation_unit_pub);
+// if (NULL != donation_unit_key)
+// return GNUNET_OK; /* skip: this key is already active! */
+// // if (GNUNET_TIME_relative_is_zero (hd->validity_duration))
+// // return GNUNET_OK; /* this key already expired! */
+
+// GNUNET_assert (
+// 0 ==
+// json_array_append_new (
+// fbc->donation_units,
+// GNUNET_JSON_PACK (
+// TALER_JSON_pack_amount ("value",
+// &meta.value),
+// GNUNET_JSON_pack_uint64 ("year",
+// meta.validity_year),
+// GNUNET_JSON_pack_data_auto ("donation_unit_pub",
+//
&helper_donation_unit->donation_unit_pub)
+// // GNUNET_JSON_pack_string ("section_name",
+// // helper_donation_unit->section_name)
+// )));
+// return GNUNET_OK;
+// }
+
+
+// /**
+// * Function called on all of our current and future exchange signing keys
+// * known to the helper process. Filters out those that are current
+// * and adds the remaining signing keys (with their configuration
+// * data) to the JSON array.
+// *
+// * @param cls the `struct FutureBuilderContext *`
+// * @param pid actually the exchange public key (type disguised)
+// * @param value a `struct HelperDenomination`
+// * @return #GNUNET_OK (continue to iterate)
+// */
+// static enum GNUNET_GenericReturnValue
+// add_signkey_cb (void *cls,
+// const struct GNUNET_PeerIdentity *pid,
+// void *value)
+// {
+// struct FutureBuilderContext *fbc = cls;
+// struct HelperSignkey *hsk = value;
+// struct SigningKey *sk;
+// // struct GNUNET_TIME_Timestamp stamp_expire;
+// // struct GNUNET_TIME_Timestamp legal_end;
+
+// sk = GNUNET_CONTAINER_multipeermap_get (fbc->ksh->signkey_map,
+// pid);
+// if (NULL != sk)
+// return GNUNET_OK; /* skip: this key is already active */
+// // if (GNUNET_TIME_relative_is_zero (hsk->validity_duration))
+// // return GNUNET_OK; /* this key already expired! */
+// // stamp_expire = GNUNET_TIME_absolute_to_timestamp (
+// // GNUNET_TIME_absolute_add (hsk->start_time.abs_time,
+// // hsk->validity_duration));
+// // legal_end = GNUNET_TIME_absolute_to_timestamp (
+// // GNUNET_TIME_absolute_add (stamp_expire.abs_time,
+// // signkey_legal_duration));
+// GNUNET_assert (0 ==
+// json_array_append_new (
+// fbc->signkeys,
+// GNUNET_JSON_PACK (
+// GNUNET_JSON_pack_data_auto ("key",
+// &hsk->donau_pub),
+// // GNUNET_JSON_pack_timestamp ("stamp_end",
+// // legal_end),
+// GNUNET_JSON_pack_data_auto ("year",
+// &hsk->year)
+// // GNUNET_JSON_pack_data_auto ("signkey_secmod_sig",
+// // &hsk->sm_sig)
+// )));
+// return GNUNET_OK;
+// }
+
+
+// MHD_RESULT
+// DH_get_keys_handler (const struct DH_RequestHandler *rh,
+// struct MHD_Connection *connection)
+// {
+// struct DH_KeyStateHandle *ksh;
+// json_t *reply;
+
+// (void) rh;
+// ksh = keys_get_state (true);
+// if (NULL == ksh)
+// {
+// return TALER_MHD_reply_with_error (connection,
+// MHD_HTTP_SERVICE_UNAVAILABLE,
+//
TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
+// "no key state");
+// }
+// sync_key_helpers (ksh->helpers);
+// if (NULL == ksh->management_keys_reply)
+// {
+// struct FutureBuilderContext fbc = {
+// .ksh = ksh,
+// .donation_units = json_array (),
+// .signkeys = json_array ()
+// };
+// if ( (GNUNET_is_zero (&donation_unit_rsa_sm_pub)) &&
+// (GNUNET_is_zero (&donation_unit_cs_sm_pub)) )
+// {
+// /* Either IPC failed, or neither helper had any donation_unit
configured. */
+// return TALER_MHD_reply_with_error (connection,
+// MHD_HTTP_BAD_GATEWAY,
+//
TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE,
+// NULL);
+// }
+// if (GNUNET_is_zero (&esign_sm_pub))
+// {
+// return TALER_MHD_reply_with_error (connection,
+// MHD_HTTP_BAD_GATEWAY,
+//
TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE,
+// NULL);
+// }
+// GNUNET_assert (NULL != fbc.donation_units);
+// GNUNET_assert (NULL != fbc.signkeys);
+// GNUNET_CONTAINER_multihashmap_iterate (ksh->helpers->donation_unit_keys,
+// &add_donation_unitkey_cb,
+// &fbc);
+// GNUNET_CONTAINER_multipeermap_iterate (ksh->helpers->esign_keys,
+// &add_signkey_cb,
+// &fbc);
+// reply = GNUNET_JSON_PACK (
+// GNUNET_JSON_pack_array_steal ("future_donation_units",
+// fbc.donation_units),
+// GNUNET_JSON_pack_array_steal ("future_signkeys",
+// fbc.signkeys),
+// GNUNET_JSON_pack_data_auto ("donation_unit_secmod_public_key",
+// &donation_unit_rsa_sm_pub),
+// GNUNET_JSON_pack_data_auto ("donation_unit_secmod_cs_public_key",
+// &donation_unit_cs_sm_pub),
+// GNUNET_JSON_pack_data_auto ("signkey_secmod_public_key",
+// &esign_sm_pub));
+// GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+// "Returning GET /keys response:\n");
+// if (NULL == reply)
+// return TALER_MHD_reply_with_error (connection,
+// MHD_HTTP_INTERNAL_SERVER_ERROR,
+//
TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE,
+// NULL);
+// GNUNET_assert (NULL == ksh->management_keys_reply);
+// ksh->management_keys_reply = reply;
+// }
+// else
+// {
+// reply = ksh->management_keys_reply;
+// }
+// return TALER_MHD_reply_json (connection,
+// reply,
+// MHD_HTTP_OK);
+// }
+
/**
- * Function called on all of our current and future donation unit keys
- * known to the helper process. Filters out those that are current
- * and adds the remaining donation unit keys (with their configuration
- * data) to the JSON array.
+ * Comparator used for a binary search by cherry_pick_date for @a key in the
+ * `struct KeysResponseData` array. See libc's qsort() and bsearch() functions.
*
- * @param cls the `struct FutureBuilderContext *`
- * @param h_donation_unit_pub hash of the donation unit public key
- * @param value a `struct HelperDenomination`
- * @return #GNUNET_OK (continue to iterate)
+ * @param key pointer to a `struct GNUNET_TIME_Timestamp`
+ * @param value pointer to a `struct KeysResponseData` array entry
+ * @return 0 if time matches, -1 if key is smaller, 1 if key is larger
*/
-static enum GNUNET_GenericReturnValue
-add_donation_unitkey_cb (void *cls,
- const struct GNUNET_HashCode *h_donation_unit_pub,
- void *value)
+static int
+krd_search_comparator (const void *key,
+ const void *value)
{
- struct FutureBuilderContext *fbc = cls;
- struct HelperDonationUnit *helper_donation_unit = value;
- struct DH_DonationUnitKey *donation_unit_key;
- struct DONAUDB_DonationUnitKeyMetaData meta = {0};
-
- donation_unit_key = GNUNET_CONTAINER_multihashmap_get
(fbc->ksh->denomkey_map,
- h_donation_unit_pub);
- if (NULL != donation_unit_key)
- return GNUNET_OK; /* skip: this key is already active! */
- // if (GNUNET_TIME_relative_is_zero (hd->validity_duration))
- // return GNUNET_OK; /* this key already expired! */
-
- GNUNET_assert (
- 0 ==
- json_array_append_new (
- fbc->donation_units,
- GNUNET_JSON_PACK (
- TALER_JSON_pack_amount ("value",
- &meta.value),
- GNUNET_JSON_pack_uint64 ("year",
- meta.validity_year),
- GNUNET_JSON_pack_data_auto ("donation_unit_pub",
- &helper_donation_unit->donation_unit_pub)
- // GNUNET_JSON_pack_string ("section_name",
- // helper_donation_unit->section_name)
- )));
- return GNUNET_OK;
+ const struct GNUNET_TIME_Timestamp *kd = key;
+ const struct KeysResponseData *krd = value;
+
+ if (GNUNET_TIME_timestamp_cmp (*kd,
+ >,
+ krd->cherry_pick_date))
+ return -1;
+ if (GNUNET_TIME_timestamp_cmp (*kd,
+ <,
+ krd->cherry_pick_date))
+ return 1;
+ return 0;
}
/**
- * Function called on all of our current and future exchange signing keys
- * known to the helper process. Filters out those that are current
- * and adds the remaining signing keys (with their configuration
- * data) to the JSON array.
+ * Callback used to set headers in a response.
*
- * @param cls the `struct FutureBuilderContext *`
- * @param pid actually the exchange public key (type disguised)
- * @param value a `struct HelperDenomination`
- * @return #GNUNET_OK (continue to iterate)
+ * @param cls closure
+ * @param[in,out] resp response to modify
*/
-static enum GNUNET_GenericReturnValue
-add_signkey_cb (void *cls,
- const struct GNUNET_PeerIdentity *pid,
- void *value)
+typedef void
+(*TEH_RESPONSE_SetHeaders)(void *cls,
+ struct MHD_Response *resp);
+
+
+MHD_RESULT
+DH_RESPONSE_reply_not_modified (
+ struct MHD_Connection *connection,
+ const char *etags,
+ TEH_RESPONSE_SetHeaders cb,
+ void *cb_cls)
{
- struct FutureBuilderContext *fbc = cls;
- struct HelperSignkey *hsk = value;
- struct SigningKey *sk;
- // struct GNUNET_TIME_Timestamp stamp_expire;
- // struct GNUNET_TIME_Timestamp legal_end;
-
- sk = GNUNET_CONTAINER_multipeermap_get (fbc->ksh->signkey_map,
- pid);
- if (NULL != sk)
- return GNUNET_OK; /* skip: this key is already active */
- // if (GNUNET_TIME_relative_is_zero (hsk->validity_duration))
- // return GNUNET_OK; /* this key already expired! */
- // stamp_expire = GNUNET_TIME_absolute_to_timestamp (
- // GNUNET_TIME_absolute_add (hsk->start_time.abs_time,
- // hsk->validity_duration));
- // legal_end = GNUNET_TIME_absolute_to_timestamp (
- // GNUNET_TIME_absolute_add (stamp_expire.abs_time,
- // signkey_legal_duration));
- GNUNET_assert (0 ==
- json_array_append_new (
- fbc->signkeys,
- GNUNET_JSON_PACK (
- GNUNET_JSON_pack_data_auto ("key",
- &hsk->donau_pub),
- // GNUNET_JSON_pack_timestamp ("stamp_end",
- // legal_end),
- GNUNET_JSON_pack_data_auto ("year",
- &hsk->year)
- // GNUNET_JSON_pack_data_auto ("signkey_secmod_sig",
- // &hsk->sm_sig)
- )));
- return GNUNET_OK;
+ MHD_RESULT ret;
+ struct MHD_Response *resp;
+
+ resp = MHD_create_response_from_buffer (0,
+ NULL,
+ MHD_RESPMEM_PERSISTENT);
+ cb (cb_cls,
+ resp);
+ GNUNET_break (MHD_YES ==
+ MHD_add_response_header (resp,
+ MHD_HTTP_HEADER_ETAG,
+ etags));
+ ret = MHD_queue_response (connection,
+ MHD_HTTP_NOT_MODIFIED,
+ resp);
+ GNUNET_break (MHD_YES == ret);
+ MHD_destroy_response (resp);
+ return ret;
}
MHD_RESULT
-DH_get_keys_handler (const struct DH_RequestHandler *rh,
- struct MHD_Connection *connection)
+DH_keys_get_handler (struct DH_RequestContext *rc,
+ const char *const args[])
{
- struct DH_KeyStateHandle *ksh;
- json_t *reply;
+ struct GNUNET_TIME_Timestamp last_issue_date;
+ const char *etag;
+
+ etag = MHD_lookup_connection_value (rc->connection,
+ MHD_HEADER_KIND,
+ MHD_HTTP_HEADER_IF_NONE_MATCH);
+ (void) args;
+ // {
+ // const char *have_cherrypick;
+
+ // have_cherrypick = MHD_lookup_connection_value (rc->connection,
+ // MHD_GET_ARGUMENT_KIND,
+ // "last_issue_date");
+ // if (NULL != have_cherrypick)
+ // {
+ // unsigned long long cherrypickn;
+
+ // if (1 !=
+ // sscanf (have_cherrypick,
+ // "%llu",
+ // &cherrypickn))
+ // {
+ // GNUNET_break_op (0);
+ // return TALER_MHD_reply_with_error (rc->connection,
+ // MHD_HTTP_BAD_REQUEST,
+ //
TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ // have_cherrypick);
+ // }
+ // /* The following multiplication may overflow; but this should not
really
+ // be a problem, as giving back 'older' data than what the client
asks for
+ // (given that the client asks for data in the distant future) is not
+ // problematic */
+ // last_issue_date = GNUNET_TIME_timestamp_from_s (cherrypickn);
+ // }
+ // else
+ // {
+ // last_issue_date = GNUNET_TIME_UNIT_ZERO_TS;
+ // }
+ // }
- (void) rh;
- ksh = keys_get_state (true);
- if (NULL == ksh)
- {
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_SERVICE_UNAVAILABLE,
- TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
- "no key state");
- }
- sync_key_helpers (ksh->helpers);
- if (NULL == ksh->management_keys_reply)
{
- struct FutureBuilderContext fbc = {
- .ksh = ksh,
- .donation_units = json_array (),
- .signkeys = json_array ()
- };
- if ( (GNUNET_is_zero (&donation_unit_rsa_sm_pub)) &&
- (GNUNET_is_zero (&donation_unit_cs_sm_pub)) )
+ struct DH_KeyStateHandle *ksh;
+ const struct KeysResponseData *krd;
+
+ ksh = DH_keys_get_state ();
+ if ( (NULL == ksh) ||
+ (0 == ksh->krd_array_length) )
{
- /* Either IPC failed, or neither helper had any donation_unit
configured. */
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_BAD_GATEWAY,
-
TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE,
- NULL);
+ if ( ( (SKR_LIMIT == skr_size) &&
+ (rc->connection == skr_connection) ) ||
+ DH_suicide)
+ {
+ return TALER_MHD_reply_with_error (
+ rc->connection,
+ MHD_HTTP_SERVICE_UNAVAILABLE,
+ TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
+ DH_suicide
+ ? "server terminating"
+ : "too many connections suspended waiting on /keys");
+ }
+ return suspend_request (rc->connection);
}
- if (GNUNET_is_zero (&esign_sm_pub))
+ krd = bsearch (&last_issue_date,
+ ksh->krd_array,
+ ksh->krd_array_length,
+ sizeof (struct KeysResponseData),
+ &krd_search_comparator);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Filtering /keys by cherry pick date %s found entry %u/%u\n",
+ GNUNET_TIME_timestamp2s (last_issue_date),
+ (unsigned int) (krd - ksh->krd_array),
+ ksh->krd_array_length);
+ if ( (NULL == krd) &&
+ (ksh->krd_array_length > 0) )
{
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_BAD_GATEWAY,
-
TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE,
- NULL);
+ if (! GNUNET_TIME_absolute_is_zero (last_issue_date.abs_time))
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Client provided invalid cherry picking timestamp %s,
returning full response\n",
+ GNUNET_TIME_timestamp2s (last_issue_date));
+ krd = &ksh->krd_array[ksh->krd_array_length - 1];
}
- GNUNET_assert (NULL != fbc.donation_units);
- GNUNET_assert (NULL != fbc.signkeys);
- GNUNET_CONTAINER_multihashmap_iterate (ksh->helpers->donation_unit_keys,
- &add_donation_unitkey_cb,
- &fbc);
- GNUNET_CONTAINER_multipeermap_iterate (ksh->helpers->esign_keys,
- &add_signkey_cb,
- &fbc);
- reply = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_array_steal ("future_donation_units",
- fbc.donation_units),
- GNUNET_JSON_pack_array_steal ("future_signkeys",
- fbc.signkeys),
- GNUNET_JSON_pack_data_auto ("donation_unit_secmod_public_key",
- &donation_unit_rsa_sm_pub),
- GNUNET_JSON_pack_data_auto ("donation_unit_secmod_cs_public_key",
- &donation_unit_cs_sm_pub),
- GNUNET_JSON_pack_data_auto ("signkey_secmod_public_key",
- &esign_sm_pub));
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Returning GET /keys response:\n");
- if (NULL == reply)
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
-
TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE,
- NULL);
- GNUNET_assert (NULL == ksh->management_keys_reply);
- ksh->management_keys_reply = reply;
- }
- else
- {
- reply = ksh->management_keys_reply;
+ if (NULL == krd)
+ {
+ /* Likely keys not ready *yet*.
+ Wait until they are. */
+ return suspend_request (rc->connection);
+ }
+ if ( (NULL != etag) &&
+ (0 == strcmp (etag,
+ krd->etag)) )
+ return DH_RESPONSE_reply_not_modified (rc->connection,
+ krd->etag,
+ &setup_general_response_headers,
+ ksh);
+
+ return MHD_queue_response (rc->connection,
+ MHD_HTTP_OK,
+ (MHD_YES ==
+ TALER_MHD_can_compress (rc->connection))
+ ? krd->response_compressed
+ : krd->response_uncompressed);
}
- return TALER_MHD_reply_json (connection,
- reply,
- MHD_HTTP_OK);
}
diff --git a/src/donau/donau-httpd_keys.h b/src/donau/donau-httpd_keys.h
index 92a1b95..9d46f67 100644
--- a/src/donau/donau-httpd_keys.h
+++ b/src/donau/donau-httpd_keys.h
@@ -57,16 +57,125 @@ struct DH_DonationUnitKey
};
/**
- * Function to call to handle requests to "/management/keys" by sending
- * back our future key material.
+ * Information needed to create a blind signature.
+ */
+// struct DH_CoinSignData
+// {
+/**
+ * Hash of key to sign with.
+ */
+// const struct TALER_DenominationHashP *h_denom_pub;
+
+/**
+ * Blinded planchet to sign over.
+ */
+// const struct TALER_BlindedPlanchet *bp;
+// };
+
+
+// /**
+// * Request to sign @a csds.
+// *
+// * @param csds array with data to blindly sign (and keys to sign with)
+// * @param csds_length length of @a csds array
+// * @param for_melt true if this is for a melt operation
+// * @param[out] bss array set to the blind signature on success; must be of
length @a csds_length
+// * @return #TALER_EC_NONE on success
+// */
+// enum TALER_ErrorCode
+// TEH_keys_denomination_batch_sign (
+// unsigned int csds_length,
+// const struct TEH_CoinSignData csds[static csds_length],
+// bool for_melt,
+// struct TALER_BlindedDenominationSignature bss[static csds_length]);
+
+
+// /**
+// * Information needed to derive the CS r_pub.
+// */
+// struct TEH_CsDeriveData
+// {
+// /**
+// * Hash of key to sign with.
+// */
+// const struct TALER_DenominationHashP *h_denom_pub;
+
+// /**
+// * Nonce to use.
+// */
+// const struct GNUNET_CRYPTO_CsSessionNonce *nonce;
+// };
+
+
+// /**
+// * Request to derive CS @a r_pub using the denomination and nonce from @a
cdd.
+// *
+// * @param cdd data to compute @a r_pub from
+// * @param for_melt true if this is for a melt operation
+// * @param[out] r_pub where to write the result
+// * @return #TALER_EC_NONE on success
+// */
+// enum TALER_ErrorCode
+// TEH_keys_denomination_cs_r_pub (
+// const struct TEH_CsDeriveData *cdd,
+// bool for_melt,
+// struct GNUNET_CRYPTO_CSPublicRPairP *r_pub);
+
+// /**
+// * Request to derive a bunch of CS @a r_pubs using the
+// * denominations and nonces from @a cdds.
+// *
+// * @param cdds array to compute @a r_pubs from
+// * @param cdds_length length of the @a cdds array
+// * @param for_melt true if this is for a melt operation
+// * @param[out] r_pubs array where to write the result; must be of length @a
cdds_length
+// * @return #TALER_EC_NONE on success
+// */
+// enum TALER_ErrorCode
+// TEH_keys_denomination_cs_batch_r_pub (
+// unsigned int cdds_length,
+// const struct TEH_CsDeriveData cdds[static cdds_length],
+// bool for_melt,
+// struct GNUNET_CRYPTO_CSPublicRPairP r_pubs[static cdds_length]);
+
+
+/**
+ * Fully clean up keys subsystem.
+ */
+void
+TEH_keys_finished (void);
+
+
+/**
+ * Resumes all suspended /keys requests, we may now have key material
+ * (or are shutting down).
*
- * @param rh context of the handler
- * @param connection the MHD connection to handle
+ * @param do_shutdown are we shutting down?
+ */
+void
+TEH_resume_keys_requests (bool do_shutdown);
+
+
+/**
+ * Function to call to handle requests to "/keys" by sending
+ * back our current key material.
+ *
+ * @param rc request context
+ * @param args array of additional options (must be empty for this function)
* @return MHD result code
*/
MHD_RESULT
-DH_get_keys_handler (const struct DH_RequestHandler *rh,
- struct MHD_Connection *connection);
+DH_keys_get_handler (struct DH_RequestContext *rc,
+ const char *const args[]);
+
+
+/**
+ * Initialize keys subsystem.
+ *
+ * @return #GNUNET_OK on success
+ */
+enum GNUNET_GenericReturnValue
+TEH_keys_init (void);
#endif
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.