gnunet-svn
[Top][All Lists]
Advanced

[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.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]