gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-donau] branch master updated: [donau] uncomment most of donau-htt


From: gnunet
Subject: [taler-donau] branch master updated: [donau] uncomment most of donau-httpd.c
Date: Thu, 07 Dec 2023 17:01:15 +0100

This is an automated email from the git hooks/post-receive script.

lukas-matyja pushed a commit to branch master
in repository donau.

The following commit(s) were added to refs/heads/master by this push:
     new e028dbc  [donau] uncomment most of donau-httpd.c
     new d6a9b5e  Merge remote-tracking branch 'refs/remotes/origin/master'
e028dbc is described below

commit e028dbc25cabe76425fff32243e774b57ddf7d59
Author: Matyja Lukas Adam <lukas.matyja@students.bfh.ch>
AuthorDate: Thu Dec 7 17:00:18 2023 +0100

    [donau] uncomment most of donau-httpd.c
---
 src/donau/Makefile.am   |    3 +
 src/donau/donau-httpd.c | 2690 +++++++++++++++++++++++------------------------
 2 files changed, 1345 insertions(+), 1348 deletions(-)

diff --git a/src/donau/Makefile.am b/src/donau/Makefile.am
index 4e9011f..37aaf43 100644
--- a/src/donau/Makefile.am
+++ b/src/donau/Makefile.am
@@ -30,6 +30,9 @@ donau_httpd_LDADD = \
   $(top_builddir)/src/donaudb/libtalerdonaudb.la \  
   $(top_builddir)/src/util/libtalerdonauutil.la \
   -lmicrohttpd \
+  -ltalermhd   \
+  -ltalerutil  \
+  -ltalertemplating \
   -lgnunetcurl \
   -lgnunetutil \
   -lgnunetjson \
diff --git a/src/donau/donau-httpd.c b/src/donau/donau-httpd.c
index 8360e99..3e5e7cc 100644
--- a/src/donau/donau-httpd.c
+++ b/src/donau/donau-httpd.c
@@ -36,126 +36,126 @@
 #include <gnunet/gnunet_mhd_compat.h>
 #include "donau_util.h"
 
-// /**
-//  * Backlog for listen operation on unix domain sockets.
-//  */
-// #define UNIX_BACKLOG 50
-
-// /**
-//  * How often will we try to connect to the database before giving up?
-//  */
-// #define MAX_DB_RETRIES 5
-
-// /**
-//  * Above what request latency do we start to log?
-//  */
-/* #define WARN_LATENCY GNUNET_TIME_relative_multiply ( \
+/**
+ * Backlog for listen operation on unix domain sockets.
+ */
+#define UNIX_BACKLOG 50
+
+/**
+ * How often will we try to connect to the database before giving up?
+ */
+#define MAX_DB_RETRIES 5
+
+/**
+ * Above what request latency do we start to log?
+ */
+ #define WARN_LATENCY GNUNET_TIME_relative_multiply ( \
      GNUNET_TIME_UNIT_MILLISECONDS, 500)
-*/
-// /**
-//  * Are clients allowed to request /keys for times other than the
-//  * current time? Allowing this could be abused in a DoS-attack
-//  * as building new /keys responses is expensive. Should only be
-//  * enabled for testcases, development and test systems.
-//  */
-// int TEH_allow_keys_timetravel;
+
+/**
+ * Are clients allowed to request /keys for times other than the
+ * current time? Allowing this could be abused in a DoS-attack
+ * as building new /keys responses is expensive. Should only be
+ * enabled for testcases, development and test systems.
+ */
+int TEH_allow_keys_timetravel;
 
 /**
  * Should we allow two HTTPDs to bind to the same port?
  */
 static int allow_address_reuse;
 
-// /**
-//  * The donau's configuration (global)
-//  */
-// const struct GNUNET_CONFIGURATION_Handle *TEH_cfg;
-
-// /**
-//  * Configuration of age restriction
-//  *
-//  * Set after loading the library, enabled in database event handler.
-//  */
-// bool TEH_age_restriction_enabled = false;
-// struct TALER_AgeRestrictionConfig TEH_age_restriction_config = {0};
-
-// /**
-//  * Handle to the HTTP server.
-//  */
-// static struct MHD_Daemon *mhd;
-
-// /**
-//  * How long is caching /keys allowed at most? (global)
-//  */
-// struct GNUNET_TIME_Relative TEH_max_keys_caching;
-
-// /**
-//  * How long is the delay before we close reserves?
-//  */
-// struct GNUNET_TIME_Relative TEH_reserve_closing_delay;
-
-// /**
-//  * Master public key (according to the
-//  * configuration in the donau directory).  (global)
-//  */
-// struct TALER_MasterPublicKeyP TEH_master_public_key;
-
-// /**
-//  * Key used to encrypt KYC attribute data in our database.
-//  */
-// struct TALER_AttributeEncryptionKeyP TEH_attribute_key;
-
-// /**
-//  * Our DB plugin.  (global)
-//  */
-// struct DONAUDB_Plugin *TEH_plugin;
-
-// /**
-//  * Absolute STEFAN parameter.
-//  */
-// struct TALER_Amount TEH_stefan_abs;
-
-// /**
-//  * Logarithmic STEFAN parameter.
-//  */
-// struct TALER_Amount TEH_stefan_log;
-
-// /**
-//  * Linear STEFAN parameter.
-//  */
-// struct TALER_Amount TEH_stefan_lin;
-
-// /**
-//  * Default number of fractional digits to render
-//  * amounts with.
-//  */
-// unsigned int TEH_currency_fraction_digits;
-
-// /**
-//  * Our currency.
-//  */
-// char *TEH_currency;
-
-// /**
-//  * Name of the KYC-AML-trigger evaluation binary.
-//  */
-// char *TEH_kyc_aml_trigger;
-
-// /**
-//  * Option set to #GNUNET_YES if rewards are enabled.
-//  */
-// int TEH_enable_rewards;
-
-// /**
-//  * What is the largest amount we allow a peer to
-//  * merge into a reserve before always triggering
-//  * an AML check?
-//  */
-// struct TALER_Amount TEH_aml_threshold;
-
-// /**
-//  * Our base URL.
-//  */
-// char *TEH_base_url;
+/**
+ * The donau's configuration (global)
+ */
+const struct GNUNET_CONFIGURATION_Handle *TEH_cfg;
+
+/**
+ * Configuration of age restriction
+ *
+ * Set after loading the library, enabled in database event handler.
+ */
+bool TEH_age_restriction_enabled = false;
+struct TALER_AgeRestrictionConfig TEH_age_restriction_config = {0};
+
+/**
+ * Handle to the HTTP server.
+ */
+static struct MHD_Daemon *mhd;
+
+/**
+ * How long is caching /keys allowed at most? (global)
+ */
+struct GNUNET_TIME_Relative TEH_max_keys_caching;
+
+/**
+ * How long is the delay before we close reserves?
+ */
+struct GNUNET_TIME_Relative TEH_reserve_closing_delay;
+
+/**
+ * Master public key (according to the
+ * configuration in the donau directory).  (global)
+ */
+struct TALER_MasterPublicKeyP TEH_master_public_key;
+
+/**
+ * Key used to encrypt KYC attribute data in our database.
+ */
+struct TALER_AttributeEncryptionKeyP TEH_attribute_key;
+
+/**
+ * Our DB plugin.  (global)
+ */
+struct DONAUDB_Plugin *TEH_plugin;
+
+/**
+ * Absolute STEFAN parameter.
+ */
+struct TALER_Amount TEH_stefan_abs;
+
+/**
+ * Logarithmic STEFAN parameter.
+ */
+struct TALER_Amount TEH_stefan_log;
+
+/**
+ * Linear STEFAN parameter.
+ */
+struct TALER_Amount TEH_stefan_lin;
+
+/**
+ * Default number of fractional digits to render
+ * amounts with.
+ */
+unsigned int TEH_currency_fraction_digits;
+
+/**
+ * Our currency.
+ */
+char *TEH_currency;
+
+/**
+ * Name of the KYC-AML-trigger evaluation binary.
+ */
+char *TEH_kyc_aml_trigger;
+
+/**
+ * Option set to #GNUNET_YES if rewards are enabled.
+ */
+int TEH_enable_rewards;
+
+/**
+ * What is the largest amount we allow a peer to
+ * merge into a reserve before always triggering
+ * an AML check?
+ */
+struct TALER_Amount TEH_aml_threshold;
+
+/**
+ * Our base URL.
+ */
+char *TEH_base_url;
 
 /**
  * Default timeout in seconds for HTTP requests.
@@ -167,84 +167,84 @@ static unsigned int connection_timeout = 30;
  */
 static int connection_close;
 
-// /**
-//  * -I command-line flag given?
-//  */
-// int TEH_check_invariants_flag;
-
-// /**
-//  * True if we should commit suicide once all active
-//  * connections are finished.
-//  */
-// bool TEH_suicide;
-
-// /**
-//  * Signature of the configuration of all enabled extensions,
-//  * signed by the donau's offline master key with purpose
-//  * TALER_SIGNATURE_MASTER_EXTENSION.
-//  */
-// struct TALER_MasterSignatureP TEH_extensions_sig;
-// bool TEH_extensions_signed = false;
-
-// /**
-//  * Value to return from main()
-//  */
-// static int global_ret;
-
-// /**
-//  * Port to run the daemon on.
-//  */
-// static uint16_t serve_port;
-
-// /**
-//  * Counter for the number of requests this HTTP has processed so far.
-//  */
-// static unsigned long long req_count;
-
-// /**
-//  * Counter for the number of open connections.
-//  */
-// static unsigned long long active_connections;
-
-// /**
-//  * Limit for the number of requests this HTTP may process before restarting.
-//  * (This was added as one way of dealing with unavoidable memory 
fragmentation
-//  * happening slowly over time.)
-//  */
-// static unsigned long long req_max;
-
-// /**
-//  * Context for all CURL operations (useful to the event loop)
-//  */
-// struct GNUNET_CURL_Context *TEH_curl_ctx;
-
-// /**
-//  * Context for integrating #TEH_curl_ctx with the
-//  * GNUnet event loop.
-//  */
-// static struct GNUNET_CURL_RescheduleContext *donau_curl_rc;
-
-// /**
-//  * Signature of functions that handle operations on coins.
-//  *
-//  * @param connection the MHD connection to handle
-//  * @param coin_pub the public key of the coin
-//  * @param root uploaded JSON data
-//  * @return MHD result code
-//  */
-// typedef MHD_RESULT
-// (*CoinOpHandler)(struct MHD_Connection *connection,
-//                  const struct TALER_CoinSpendPublicKeyP *coin_pub,
-//                  const json_t *root);
-
-
-// /**
-//  * Generate a 404 "not found" reply on @a connection with
-//  * the hint @a details.
-//  *
-//  * @param connection where to send the reply on
-//  * @param details details for the error message, can be NULL
-//  */
+/**
+ * -I command-line flag given?
+ */
+int TEH_check_invariants_flag;
+
+/**
+ * True if we should commit suicide once all active
+ * connections are finished.
+ */
+bool TEH_suicide;
+
+/**
+ * Signature of the configuration of all enabled extensions,
+ * signed by the donau's offline master key with purpose
+ * TALER_SIGNATURE_MASTER_EXTENSION.
+ */
+struct TALER_MasterSignatureP TEH_extensions_sig;
+bool TEH_extensions_signed = false;
+
+/**
+ * Value to return from main()
+ */
+static int global_ret;
+
+/**
+ * Port to run the daemon on.
+ */
+static uint16_t serve_port;
+
+/**
+ * Counter for the number of requests this HTTP has processed so far.
+ */
+//static unsigned long long req_count;
+
+/**
+ * Counter for the number of open connections.
+ */
+static unsigned long long active_connections;
+
+/**
+ * Limit for the number of requests this HTTP may process before restarting.
+ * (This was added as one way of dealing with unavoidable memory fragmentation
+ * happening slowly over time.)
+ */
+static unsigned long long req_max;
+
+/**
+ * Context for all CURL operations (useful to the event loop)
+ */
+struct GNUNET_CURL_Context *TEH_curl_ctx;
+
+/**
+ * Context for integrating #TEH_curl_ctx with the
+ * GNUnet event loop.
+ */
+static struct GNUNET_CURL_RescheduleContext *donau_curl_rc;
+
+/**
+ * Signature of functions that handle operations on coins.
+ *
+ * @param connection the MHD connection to handle
+ * @param coin_pub the public key of the coin
+ * @param root uploaded JSON data
+ * @return MHD result code
+ */
+typedef MHD_RESULT
+(*CoinOpHandler)(struct MHD_Connection *connection,
+                 const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                 const json_t *root);
+
+
+/**
+ * Generate a 404 "not found" reply on @a connection with
+ * the hint @a details.
+ *
+ * @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)
@@ -256,1195 +256,1190 @@ static int connection_close;
 // }
 
 
-// /**
-//  * Function called whenever MHD is done with a request.  If the
-//  * request was a POST, we may have stored a `struct Buffer *` in the
-//  * @a con_cls that might still need to be cleaned up.  Call the
-//  * respective function to free the memory.
-//  *
-//  * @param cls client-defined closure
-//  * @param connection connection handle
-//  * @param con_cls value as set by the last call to
-//  *        the #MHD_AccessHandlerCallback
-//  * @param toe reason for request termination
-//  * @see #MHD_OPTION_NOTIFY_COMPLETED
-//  * @ingroup request
-//  */
-// static void
-// handle_mhd_completion_callback (void *cls,
-//                                 struct MHD_Connection *connection,
-//                                 void **con_cls,
-//                                 enum MHD_RequestTerminationCode toe)
-// {
-//   struct TEH_RequestContext *rc = *con_cls;
-//   struct GNUNET_AsyncScopeSave old_scope;
-
-//   (void) cls;
-//   if (NULL == rc)
-//     return;
-//   GNUNET_async_scope_enter (&rc->async_scope_id,
-//                             &old_scope);
-//   check_suicide ();
-//   TEH_check_invariants ();
-//   if (NULL != rc->rh_cleaner)
-//     rc->rh_cleaner (rc);
-//   TEH_check_invariants ();
-//   {
-// #if MHD_VERSION >= 0x00097304
-//     const union MHD_ConnectionInfo *ci;
-//     unsigned int http_status = 0;
-
-//     ci = MHD_get_connection_info (connection,
-//                                   MHD_CONNECTION_INFO_HTTP_STATUS);
-//     if (NULL != ci)
-//       http_status = ci->http_status;
-//     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-//                 "Request for `%s' completed with HTTP status %u (%d)\n",
-//                 rc->url,
-//                 http_status,
-//                 toe);
-// #else
-//     (void) connection;
-//     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-//                 "Request for `%s' completed (%d)\n",
-//                 rc->url,
-//                 toe);
-// #endif
-//   }
-
-//   TALER_MHD_parse_post_cleanup_callback (rc->opaque_post_parsing_context);
-//   /* Sanity-check that we didn't leave any transactions hanging */
-//   // GNUNET_break (GNUNET_OK ==
-//   // TEH_plugin->preflight (TEH_plugin->cls));
-//   {
-//     struct GNUNET_TIME_Relative latency;
-
-//     latency = GNUNET_TIME_absolute_get_duration (rc->start_time);
-//     if (latency.rel_value_us >
-//         WARN_LATENCY.rel_value_us)
-//       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-//                   "Request for `%s' took %s\n",
-//                   rc->url,
-//                   GNUNET_STRINGS_relative_time_to_string (latency,
-//                                                           GNUNET_YES));
-//   }
-//   GNUNET_free (rc);
-//   *con_cls = NULL;
-//   GNUNET_async_scope_restore (&old_scope);
-// }
+/**
+ * Function called whenever MHD is done with a request.  If the
+ * request was a POST, we may have stored a `struct Buffer *` in the
+ * @a con_cls that might still need to be cleaned up.  Call the
+ * respective function to free the memory.
+ *
+ * @param cls client-defined closure
+ * @param connection connection handle
+ * @param con_cls value as set by the last call to
+ *        the #MHD_AccessHandlerCallback
+ * @param toe reason for request termination
+ * @see #MHD_OPTION_NOTIFY_COMPLETED
+ * @ingroup request
+ */
+static void
+handle_mhd_completion_callback (void *cls,
+                                struct MHD_Connection *connection,
+                                void **con_cls,
+                                enum MHD_RequestTerminationCode toe)
+{
+  struct TEH_RequestContext *rc = *con_cls;
+  struct GNUNET_AsyncScopeSave old_scope;
+
+  (void) cls;
+  if (NULL == rc)
+    return;
+  GNUNET_async_scope_enter (&rc->async_scope_id,
+                            &old_scope);
+  //check_suicide ();
+  //TEH_check_invariants ();
+  if (NULL != rc->rh_cleaner)
+    rc->rh_cleaner (rc);
+  //TEH_check_invariants ();
+  {
+#if MHD_VERSION >= 0x00097304
+    const union MHD_ConnectionInfo *ci;
+    unsigned int http_status = 0;
+
+    ci = MHD_get_connection_info (connection,
+                                  MHD_CONNECTION_INFO_HTTP_STATUS);
+    if (NULL != ci)
+      http_status = ci->http_status;
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Request for `%s' completed with HTTP status %u (%d)\n",
+                rc->url,
+                http_status,
+                toe);
+#else
+    (void) connection;
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Request for `%s' completed (%d)\n",
+                rc->url,
+                toe);
+#endif
+  }
+
+  TALER_MHD_parse_post_cleanup_callback (rc->opaque_post_parsing_context);
+  /* Sanity-check that we didn't leave any transactions hanging */
+  GNUNET_break (GNUNET_OK ==
+  TEH_plugin->preflight (TEH_plugin->cls));
+  {
+    struct GNUNET_TIME_Relative latency;
+
+    latency = GNUNET_TIME_absolute_get_duration (rc->start_time);
+    if (latency.rel_value_us >
+        WARN_LATENCY.rel_value_us)
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                  "Request for `%s' took %s\n",
+                  rc->url,
+                  GNUNET_STRINGS_relative_time_to_string (latency,
+                                                          GNUNET_YES));
+  }
+  GNUNET_free (rc);
+  *con_cls = NULL;
+  GNUNET_async_scope_restore (&old_scope);
+}
 
 
-// /**
-//  * We found a request handler responsible for handling a request. Parse the
-//  * @a upload_data (if applicable) and the @a url and call the
-//  * handler.
-//  *
-//  * @param rc request context
-//  * @param url rest of the URL to parse
-//  * @param upload_data upload data to parse (if available)
-//  * @param[in,out] upload_data_size number of bytes in @a upload_data
-//  * @return MHD result code
-//  */
-// static MHD_RESULT
-// proceed_with_handler (struct TEH_RequestContext *rc,
-//                       const char *url,
-//                       const char *upload_data,
-//                       size_t *upload_data_size)
-// {
-//   const struct TEH_RequestHandler *rh = rc->rh;
-//   const char *args[rh->nargs + 2];
-//   size_t ulen = strlen (url) + 1;
-//   json_t *root = NULL;
-//   MHD_RESULT ret;
-
-//   /* We do check for "ulen" here, because we'll later stack-allocate a 
buffer
-//      of that size and don't want to enable malicious clients to cause us
-//      huge stack allocations. */
-//   if (ulen > 512)
-//   {
-//     /* 512 is simply "big enough", as it is bigger than "6 * 54",
-//        which is the longest URL format we ever get (for
-//        /deposits/).  The value should be adjusted if we ever define protocol
-//        endpoints with plausibly longer inputs.  */
-//     GNUNET_break_op (0);
-//     return TALER_MHD_reply_with_error (rc->connection,
-//                                        MHD_HTTP_URI_TOO_LONG,
-//                                        TALER_EC_GENERIC_URI_TOO_LONG,
-//                                        url);
-//   }
-
-//   /* All POST endpoints come with a body in JSON format. So we parse
-//      the JSON here. */
-//   if (0 == strcasecmp (rh->method,
-//                        MHD_HTTP_METHOD_POST))
-//   {
-//     enum GNUNET_GenericReturnValue res;
-
-//     res = TALER_MHD_parse_post_json (rc->connection,
-//                                      &rc->opaque_post_parsing_context,
-//                                      upload_data,
-//                                      upload_data_size,
-//                                      &root);
-//     if (GNUNET_SYSERR == res)
-//     {
-//       GNUNET_assert (NULL == root);
-//       return MHD_NO; /* bad upload, could not even generate error */
-//     }
-//     if ( (GNUNET_NO == res) ||
-//          (NULL == root) )
-//     {
-//       GNUNET_assert (NULL == root);
-//       return MHD_YES; /* so far incomplete upload or parser error */
-//     }
-//   }
-
-//   {
-//     char d[ulen];
-//     unsigned int i;
-//     char *sp;
-
-//     /* Parse command-line arguments */
-//     /* make a copy of 'url' because 'strtok_r()' will modify */
-//     GNUNET_memcpy (d,
-//                    url,
-//                    ulen);
-//     i = 0;
-//     args[i++] = strtok_r (d, "/", &sp);
-//     while ( (NULL != args[i - 1]) &&
-//             (i <= rh->nargs + 1) )
-//       args[i++] = strtok_r (NULL, "/", &sp);
-//     /* make sure above loop ran nicely until completion, and also
-//        that there is no excess data in 'd' afterwards */
-//     if ( ( (rh->nargs_is_upper_bound) &&
-//            (i - 1 > rh->nargs) ) ||
-//          ( (! rh->nargs_is_upper_bound) &&
-//            (i - 1 != rh->nargs) ) )
-//     {
-//       char emsg[128 + 512];
-
-//       GNUNET_snprintf (emsg,
-//                        sizeof (emsg),
-//                        "Got %u+/%u segments for `%s' request (`%s')",
-//                        i - 1,
-//                        rh->nargs,
-//                        rh->url,
-//                        url);
-//       GNUNET_break_op (0);
-//       json_decref (root);
-//       return TALER_MHD_reply_with_error (rc->connection,
-//                                          MHD_HTTP_NOT_FOUND,
-//                                          
TALER_EC_DONAU_GENERIC_WRONG_NUMBER_OF_SEGMENTS,
-//                                          emsg);
-//     }
-//     GNUNET_assert (NULL == args[i - 1]);
-
-//     /* Above logic ensures that 'root' is exactly non-NULL for POST 
operations,
-//        so we test for 'root' to decide which handler to invoke. */
-//     if (0 == strcasecmp (rh->method,
-//                          MHD_HTTP_METHOD_POST))
-//       ret = rh->handler.post (rc,
-//                               root,
-//                               args);
-//     else if (0 == strcasecmp (rh->method,
-//                               MHD_HTTP_METHOD_DELETE))
-//       ret = rh->handler.delete (rc,
-//                                 args);
-//     else /* Only GET left */
-//       ret = rh->handler.get (rc,
-//                              args);
-//   }
-//   json_decref (root);
-//   return ret;
-// }
+/**
+ * We found a request handler responsible for handling a request. Parse the
+ * @a upload_data (if applicable) and the @a url and call the
+ * handler.
+ *
+ * @param rc request context
+ * @param url rest of the URL to parse
+ * @param upload_data upload data to parse (if available)
+ * @param[in,out] upload_data_size number of bytes in @a upload_data
+ * @return MHD result code
+ */
+static MHD_RESULT
+proceed_with_handler (struct TEH_RequestContext *rc,
+                      const char *url,
+                      const char *upload_data,
+                      size_t *upload_data_size)
+{
+  const struct TEH_RequestHandler *rh = rc->rh;
+  const char *args[rh->nargs + 2];
+  size_t ulen = strlen (url) + 1;
+  json_t *root = NULL;
+  MHD_RESULT ret;
+
+  /* We do check for "ulen" here, because we'll later stack-allocate a buffer
+     of that size and don't want to enable malicious clients to cause us
+     huge stack allocations. */
+  if (ulen > 512)
+  {
+    /* 512 is simply "big enough", as it is bigger than "6 * 54",
+       which is the longest URL format we ever get (for
+       /deposits/).  The value should be adjusted if we ever define protocol
+       endpoints with plausibly longer inputs.  */
+    GNUNET_break_op (0);
+    return TALER_MHD_reply_with_error (rc->connection,
+                                       MHD_HTTP_URI_TOO_LONG,
+                                       TALER_EC_GENERIC_URI_TOO_LONG,
+                                       url);
+  }
+
+  /* All POST endpoints come with a body in JSON format. So we parse
+     the JSON here. */
+  if (0 == strcasecmp (rh->method,
+                       MHD_HTTP_METHOD_POST))
+  {
+    enum GNUNET_GenericReturnValue res;
+
+    res = TALER_MHD_parse_post_json (rc->connection,
+                                     &rc->opaque_post_parsing_context,
+                                     upload_data,
+                                     upload_data_size,
+                                     &root);
+    if (GNUNET_SYSERR == res)
+    {
+      GNUNET_assert (NULL == root);
+      return MHD_NO; /* bad upload, could not even generate error */
+    }
+    if ( (GNUNET_NO == res) ||
+         (NULL == root) )
+    {
+      GNUNET_assert (NULL == root);
+      return MHD_YES; /* so far incomplete upload or parser error */
+    }
+  }
+
+  {
+    char d[ulen];
+    unsigned int i;
+    char *sp;
+
+    /* Parse command-line arguments */
+    /* make a copy of 'url' because 'strtok_r()' will modify */
+    GNUNET_memcpy (d,
+                   url,
+                   ulen);
+    i = 0;
+    args[i++] = strtok_r (d, "/", &sp);
+    while ( (NULL != args[i - 1]) &&
+            (i <= rh->nargs + 1) )
+      args[i++] = strtok_r (NULL, "/", &sp);
+    /* make sure above loop ran nicely until completion, and also
+       that there is no excess data in 'd' afterwards */
+    if ( ( (rh->nargs_is_upper_bound) &&
+           (i - 1 > rh->nargs) ) ||
+         ( (! rh->nargs_is_upper_bound) &&
+           (i - 1 != rh->nargs) ) )
+    {
+      char emsg[128 + 512];
+
+      GNUNET_snprintf (emsg,
+                       sizeof (emsg),
+                       "Got %u+/%u segments for `%s' request (`%s')",
+                       i - 1,
+                       rh->nargs,
+                       rh->url,
+                       url);
+      GNUNET_break_op (0);
+      json_decref (root);
+      return TALER_MHD_reply_with_error (rc->connection,
+                                         MHD_HTTP_NOT_FOUND,
+                                         
TALER_EC_EXCHANGE_GENERIC_WRONG_NUMBER_OF_SEGMENTS,
+                                         emsg);
+    }
+    GNUNET_assert (NULL == args[i - 1]);
+
+    /* Above logic ensures that 'root' is exactly non-NULL for POST operations,
+       so we test for 'root' to decide which handler to invoke. */
+    if (0 == strcasecmp (rh->method,
+                         MHD_HTTP_METHOD_POST))
+      ret = rh->handler.post (rc,
+                              root,
+                              args);
+    else if (0 == strcasecmp (rh->method,
+                              MHD_HTTP_METHOD_DELETE))
+      ret = rh->handler.delete (rc,
+                                args);
+    else /* Only GET left */
+      ret = rh->handler.get (rc,
+                             args);
+  }
+  json_decref (root);
+  return ret;
+}
 
 
-// /**
-//  * Handle a "/seed" request.
-//  *
-//  * @param rc request context
-//  * @param args array of additional options (must be empty for this function)
-//  * @return MHD result code
-//  */
-// static MHD_RESULT
-// handler_seed (struct TEH_RequestContext *rc,
-//               const char *const args[])
-// {
-// #define SEED_SIZE 32
-//   char *body;
-//   MHD_RESULT ret;
-//   struct MHD_Response *resp;
-
-//   (void) args;
-//   body = malloc (SEED_SIZE); /* must use malloc(), because MHD will use 
free() */
-//   if (NULL == body)
-//     return MHD_NO;
-//   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
-//                               body,
-//                               SEED_SIZE);
-//   resp = MHD_create_response_from_buffer (SEED_SIZE,
-//                                           body,
-//                                           MHD_RESPMEM_MUST_FREE);
-//   TALER_MHD_add_global_headers (resp);
-//   ret = MHD_queue_response (rc->connection,
-//                             MHD_HTTP_OK,
-//                             resp);
-//   GNUNET_break (MHD_YES == ret);
-//   MHD_destroy_response (resp);
-//   return ret;
-// #undef SEED_SIZE
-// }
+/**
+ * Handle a "/seed" request.
+ *
+ * @param rc request context
+ * @param args array of additional options (must be empty for this function)
+ * @return MHD result code
+ */
+static MHD_RESULT
+handler_seed (struct TEH_RequestContext *rc,
+              const char *const args[])
+{
+#define SEED_SIZE 32
+  char *body;
+  MHD_RESULT ret;
+  struct MHD_Response *resp;
+
+  (void) args;
+  body = malloc (SEED_SIZE); /* must use malloc(), because MHD will use free() 
*/
+  if (NULL == body)
+    return MHD_NO;
+  GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+                              body,
+                              SEED_SIZE);
+  resp = MHD_create_response_from_buffer (SEED_SIZE,
+                                          body,
+                                          MHD_RESPMEM_MUST_FREE);
+  TALER_MHD_add_global_headers (resp);
+  ret = MHD_queue_response (rc->connection,
+                            MHD_HTTP_OK,
+                            resp);
+  GNUNET_break (MHD_YES == ret);
+  MHD_destroy_response (resp);
+  return ret;
+#undef SEED_SIZE
+}
 
 
-// /**
-//  * Handle incoming HTTP request.
-//  *
-//  * @param cls closure for MHD daemon (unused)
-//  * @param connection the connection
-//  * @param url the requested url
-//  * @param method the method (POST, GET, ...)
-//  * @param version HTTP version (ignored)
-//  * @param upload_data request data
-//  * @param upload_data_size size of @a upload_data in bytes
-//  * @param con_cls closure for request (a `struct TEH_RequestContext *`)
-//  * @return MHD result code
-//  */
-// static MHD_RESULT
-// handle_mhd_request (void *cls,
-//                     struct MHD_Connection *connection,
-//                     const char *url,
-//                     const char *method,
-//                     const char *version,
-//                     const char *upload_data,
-//                     size_t *upload_data_size,
-//                     void **con_cls)
-// {
-//   static struct TEH_RequestHandler handlers[] = {
+/**
+ * Handle incoming HTTP request.
+ *
+ * @param cls closure for MHD daemon (unused)
+ * @param connection the connection
+ * @param url the requested url
+ * @param method the method (POST, GET, ...)
+ * @param version HTTP version (ignored)
+ * @param upload_data request data
+ * @param upload_data_size size of @a upload_data in bytes
+ * @param con_cls closure for request (a `struct TEH_RequestContext *`)
+ * @return MHD result code
+ */
+static MHD_RESULT
+handle_mhd_request (void *cls,
+                    struct MHD_Connection *connection,
+                    const char *url,
+                    const char *method,
+                    const char *version,
+                    const char *upload_data,
+                    size_t *upload_data_size,
+                    void **con_cls)
+{
+  static struct TEH_RequestHandler handlers[] = {
 /* /robots.txt: disallow everything */
-// {
-//   .url = "robots.txt",
-//   .method = MHD_HTTP_METHOD_GET,
-//   .handler.get = &TEH_handler_static_response,
-//   .mime_type = "text/plain",
-//   .data = "User-agent: *\nDisallow: /\n",
-//   .response_code = MHD_HTTP_OK
-// },
+{
+  .url = "robots.txt",
+  .method = MHD_HTTP_METHOD_GET,
+  //.handler.get = &TEH_handler_static_response,
+  .mime_type = "text/plain",
+  .data = "User-agent: *\nDisallow: /\n",
+  .response_code = MHD_HTTP_OK
+},
 /* Landing page, tell humans to go away. */
-// {
-//   .url = "",
-//   .method = MHD_HTTP_METHOD_GET,
-//   .handler.get = TEH_handler_static_response,
-//   .mime_type = "text/plain",
-//   .data =
-//     "Hello, I'm the Taler donau. This HTTP server is not for humans.\n",
-//   .response_code = MHD_HTTP_OK
-// },
+{
+  .url = "",
+  .method = MHD_HTTP_METHOD_GET,
+  //.handler.get = TEH_handler_static_response,
+  .mime_type = "text/plain",
+  .data =
+    "Hello, I'm the Taler donau. This HTTP server is not for humans.\n",
+  .response_code = MHD_HTTP_OK
+},
 /* AGPL licensing page, redirect to source. As per the AGPL-license, every
        deployment is required to offer the user a download of the source of
        the actual deployment. We make this easy by including a redirect to the
        source here. */
-// {
-//   .url = "agpl",
-//   .method = MHD_HTTP_METHOD_GET,
-//   .handler.get = &TEH_handler_agpl_redirect
-// },
-// {
-//   .url = "seed",
-//   .method = MHD_HTTP_METHOD_GET,
-//   .handler.get = &handler_seed
-// },
+{
+  .url = "agpl",
+  .method = MHD_HTTP_METHOD_GET,
+  //.handler.get = &TEH_handler_agpl_redirect
+},
+{
+  .url = "seed",
+  .method = MHD_HTTP_METHOD_GET,
+  .handler.get = &handler_seed
+},
 /* Configuration */
-// {
-//   .url = "config",
-//   .method = MHD_HTTP_METHOD_GET,
-//   .handler.get = &TEH_handler_config
-// },
+{
+  .url = "config",
+  .method = MHD_HTTP_METHOD_GET,
+  //.handler.get = &TEH_handler_config
+},
 /* Performance metrics */
-// {
-//   .url = "metrics",
-//   .method = MHD_HTTP_METHOD_GET,
-//   .handler.get = &TEH_handler_metrics
-// },
+{
+  .url = "metrics",
+  .method = MHD_HTTP_METHOD_GET,
+  //.handler.get = &TEH_handler_metrics
+},
 /* Terms of service */
-// {
-//   .url = "terms",
-//   .method = MHD_HTTP_METHOD_GET,
-//   .handler.get = &TEH_handler_terms
-// },
+{
+  .url = "terms",
+  .method = MHD_HTTP_METHOD_GET,
+  //.handler.get = &TEH_handler_terms
+},
 /* Privacy policy */
-// {
-//   .url = "privacy",
-//   .method = MHD_HTTP_METHOD_GET,
-//   .handler.get = &TEH_handler_privacy
-// },
+{
+  .url = "privacy",
+  .method = MHD_HTTP_METHOD_GET,
+  //.handler.get = &TEH_handler_privacy
+},
 /* Return key material and fundamental properties for this donau */
-// {
-//   .url = "keys",
-//   .method = MHD_HTTP_METHOD_GET,
-//   .handler.get = &TEH_keys_get_handler,
-// },
+{
+  .url = "keys",
+  .method = MHD_HTTP_METHOD_GET,
+  //.handler.get = &TEH_keys_get_handler,
+},
 /* request R, used in clause schnorr withdraw and refresh */
-// {
-//   .url = "csr-melt",
-//   .method = MHD_HTTP_METHOD_POST,
-//   .handler.post = &TEH_handler_csr_melt,
-//   .nargs = 0
-// },
-
-
-//     /* mark end of list */
-//     {
-//       .url = NULL
-//     }
-//   };
-//   struct TEH_RequestContext *rc = *con_cls;
-//   struct GNUNET_AsyncScopeSave old_scope;
-//   const char *correlation_id = NULL;
-
-//   (void) cls;
-//   (void) version;
-//   if (NULL == rc)
-//   {
-//     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-//                 "Handling new request\n");
-
-//     /* We're in a new async scope! */
-//     rc = *con_cls = GNUNET_new (struct TEH_RequestContext);
-//     rc->start_time = GNUNET_TIME_absolute_get ();
-//     GNUNET_async_scope_fresh (&rc->async_scope_id);
-//     TEH_check_invariants ();
-//     rc->url = url;
-//     rc->connection = connection;
-//     /* We only read the correlation ID on the first callback for every 
client */
-//     correlation_id = MHD_lookup_connection_value (connection,
-//                                                   MHD_HEADER_KIND,
-//                                                   "Taler-Correlation-Id");
-//     if ( (NULL != correlation_id) &&
-//          (GNUNET_YES !=
-//           GNUNET_CURL_is_valid_scope_id (correlation_id)) )
-//     {
-//       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-//                   "illegal incoming correlation ID\n");
-//       correlation_id = NULL;
-//     }
-
-//     /* Check if upload is in bounds */
-//     if (0 == strcasecmp (method,
-//                          MHD_HTTP_METHOD_POST))
-//     {
-//       TALER_MHD_check_content_length (connection,
-//                                       TALER_MHD_REQUEST_BUFFER_MAX);
-//     }
-//   }
-
-//   GNUNET_async_scope_enter (&rc->async_scope_id,
-//                             &old_scope);
-//   TEH_check_invariants ();
-//   if (NULL != correlation_id)
-//     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-//                 "Handling request (%s) for URL '%s', correlation_id=%s\n",
-//                 method,
-//                 url,
-//                 correlation_id);
-//   else
-//     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-//                 "Handling request (%s) for URL '%s'\n",
-//                 method,
-//                 url);
-//   /* on repeated requests, check our cache first */
-//   if (NULL != rc->rh)
-//   {
-//     MHD_RESULT ret;
-//     const char *start;
-
-//     if ('\0' == url[0])
-//       /* strange, should start with '/', treat as just "/" */
-//       url = "/";
-//     start = strchr (url + 1, '/');
-//     if (NULL == start)
-//       start = "";
-//     ret = proceed_with_handler (rc,
-//                                 start,
-//                                 upload_data,
-//                                 upload_data_size);
-//     GNUNET_async_scope_restore (&old_scope);
-//     return ret;
-//   }
-
-//   if ( (0 == strcasecmp (method,
-//                          MHD_HTTP_METHOD_OPTIONS)) &&
-//        (0 == strcmp ("*",
-//                      url)) )
-//     return TALER_MHD_reply_cors_preflight (connection);
-
-//   if (0 == strcasecmp (method,
-//                        MHD_HTTP_METHOD_HEAD))
-//     method = MHD_HTTP_METHOD_GET; /* treat HEAD as GET here, MHD will do 
the rest */
-
-//   /* parse first part of URL */
-//   {
-//     bool found = false;
-//     size_t tok_size;
-//     const char *tok;
-//     const char *rest;
-
-//     if ('\0' == url[0])
-//       /* strange, should start with '/', treat as just "/" */
-//       url = "/";
-//     tok = url + 1;
-//     rest = strchr (tok, '/');
-//     if (NULL == rest)
-//     {
-//       tok_size = strlen (tok);
-//     }
-//     else
-//     {
-//       tok_size = rest - tok;
-//       rest++; /* skip over '/' */
-//     }
-//     for (unsigned int i = 0; NULL != handlers[i].url; i++)
-//     {
-//       struct TEH_RequestHandler *rh = &handlers[i];
-
-//       if ( (0 != strncmp (tok,
-//                           rh->url,
-//                           tok_size)) ||
-//            (tok_size != strlen (rh->url) ) )
-//         continue;
-//       found = true;
-//       /* The URL is a match!  What we now do depends on the method. */
-//       if (0 == strcasecmp (method,
-//                            MHD_HTTP_METHOD_OPTIONS))
-//       {
-//         GNUNET_async_scope_restore (&old_scope);
-//         return TALER_MHD_reply_cors_preflight (connection);
-//       }
-//       GNUNET_assert (NULL != rh->method);
-//       if (0 == strcasecmp (method,
-//                            rh->method))
-//       {
-//         MHD_RESULT ret;
-
-//         /* cache to avoid the loop next time */
-//         rc->rh = rh;
-//         /* run handler */
-//         ret = proceed_with_handler (rc,
-//                                     url + tok_size + 1,
-//                                     upload_data,
-//                                     upload_data_size);
-//         GNUNET_async_scope_restore (&old_scope);
-//         return ret;
-//       }
-//     }
-
-//     if (found)
-//     {
-//       /* we found a matching address, but the method is wrong */
-//       struct MHD_Response *reply;
-//       MHD_RESULT ret;
-//       char *allowed = NULL;
-
-//       GNUNET_break_op (0);
-//       for (unsigned int i = 0; NULL != handlers[i].url; i++)
-//       {
-//         struct TEH_RequestHandler *rh = &handlers[i];
-
-//         if ( (0 != strncmp (tok,
-//                             rh->url,
-//                             tok_size)) ||
-//              (tok_size != strlen (rh->url) ) )
-//           continue;
-//         if (NULL == allowed)
-//         {
-//           allowed = GNUNET_strdup (rh->method);
-//         }
-//         else
-//         {
-//           char *tmp;
-
-//           GNUNET_asprintf (&tmp,
-//                            "%s, %s",
-//                            allowed,
-//                            rh->method);
-//           GNUNET_free (allowed);
-//           allowed = tmp;
-//         }
-//         if (0 == strcasecmp (rh->method,
-//                              MHD_HTTP_METHOD_GET))
-//         {
-//           char *tmp;
-
-//           GNUNET_asprintf (&tmp,
-//                            "%s, %s",
-//                            allowed,
-//                            MHD_HTTP_METHOD_HEAD);
-//           GNUNET_free (allowed);
-//           allowed = tmp;
-//         }
-//       }
-//       reply = TALER_MHD_make_error (TALER_EC_GENERIC_METHOD_INVALID,
-//                                     method);
-//       GNUNET_break (MHD_YES ==
-//                     MHD_add_response_header (reply,
-//                                              MHD_HTTP_HEADER_ALLOW,
-//                                              allowed));
-//       GNUNET_free (allowed);
-//       ret = MHD_queue_response (connection,
-//                                 MHD_HTTP_METHOD_NOT_ALLOWED,
-//                                 reply);
-//       MHD_destroy_response (reply);
-//       return ret;
-//     }
-//   }
-
-//   /* No handler matches, generate not found */
-//   {
-//     MHD_RESULT ret;
-
-//     ret = TALER_MHD_reply_with_error (connection,
-//                                       MHD_HTTP_NOT_FOUND,
-//                                       TALER_EC_GENERIC_ENDPOINT_UNKNOWN,
-//                                       url);
-//     GNUNET_async_scope_restore (&old_scope);
-//     return ret;
-//   }
-// }
+{
+  .url = "csr-melt",
+  .method = MHD_HTTP_METHOD_POST,
+  //.handler.post = &TEH_handler_csr_melt,
+  .nargs = 0
+},
 
 
-// /**
-//  * Load configuration parameters for the donau
-//  * server into the corresponding global variables.
-//  *
-//  * @return #GNUNET_OK on success
-//  */
-// static enum GNUNET_GenericReturnValue
-// donau_serve_process_config (void)
-// {
-//   if (GNUNET_OK !=
-//       TALER_KYCLOGIC_kyc_init (TEH_cfg))
-//   {
-//     return GNUNET_SYSERR;
-//   }
-//   if (GNUNET_OK !=
-//       GNUNET_CONFIGURATION_get_value_number (TEH_cfg,
-//                                              "donau",
-//                                              "MAX_REQUESTS",
-//                                              &req_max))
-//   {
-//     req_max = ULLONG_MAX;
-//   }
-//   if (GNUNET_OK !=
-//       GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
-//                                            "donaudb",
-//                                            "IDLE_RESERVE_EXPIRATION_TIME",
-//                                            &TEH_reserve_closing_delay))
-//   {
-//     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
-//                                "donaudb",
-//                                "IDLE_RESERVE_EXPIRATION_TIME");
-//     /* use default */
-//     TEH_reserve_closing_delay
-//       = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_WEEKS,
-//                                        4);
-//   }
-
-//   if (GNUNET_OK !=
-//       GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
-//                                            "donau",
-//                                            "MAX_KEYS_CACHING",
-//                                            &TEH_max_keys_caching))
-//   {
-//     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
-//                                "donau",
-//                                "MAX_KEYS_CACHING",
-//                                "valid relative time expected");
-//     return GNUNET_SYSERR;
-//   }
-//   if (GNUNET_OK !=
-//       GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
-//                                              "donau",
-//                                              "KYC_AML_TRIGGER",
-//                                              &TEH_kyc_aml_trigger))
-//   {
-//     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
-//                                "donau",
-//                                "KYC_AML_TRIGGER");
-//     return GNUNET_SYSERR;
-//   }
-//   if (GNUNET_OK !=
-//       TALER_config_get_currency (TEH_cfg,
-//                                  &TEH_currency))
-//   {
-//     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
-//                                "taler",
-//                                "CURRENCY");
-//     return GNUNET_SYSERR;
-//   }
-//   {
-//     unsigned long long cfd;
-
-//     if (GNUNET_OK !=
-//         GNUNET_CONFIGURATION_get_value_number (TEH_cfg,
-//                                                "donau",
-//                                                "CURRENCY_FRACTION_DIGITS",
-//                                                &cfd))
-//       cfd = 0;
-//     if (cfd > 8)
-//     {
-//       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
-//                                  "taler",
-//                                  "CURRENCY_FRACTION_DIGITS",
-//                                  "Value must be below 8");
-//       return GNUNET_SYSERR;
-//     }
-//     TEH_currency_fraction_digits = (unsigned int) cfd;
-//   }
-//   if (GNUNET_OK !=
-//       TALER_config_get_amount (TEH_cfg,
-//                                "donau",
-//                                "AML_THRESHOLD",
-//                                &TEH_aml_threshold))
-//   {
-//     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-//                 "Need amount in section `donau' under `AML_THRESHOLD'\n");
-//     return GNUNET_SYSERR;
-//   }
-//   if (GNUNET_OK !=
-//       TALER_config_get_amount (TEH_cfg,
-//                                "donau",
-//                                "STEFAN_ABS",
-//                                &TEH_stefan_abs))
-//   {
-//     GNUNET_assert (GNUNET_OK ==
-//                    TALER_amount_set_zero (TEH_currency,
-//                                           &TEH_stefan_abs));
-//   }
-//   if (GNUNET_OK !=
-//       TALER_config_get_amount (TEH_cfg,
-//                                "donau",
-//                                "STEFAN_LOG",
-//                                &TEH_stefan_log))
-//   {
-//     GNUNET_assert (GNUNET_OK ==
-//                    TALER_amount_set_zero (TEH_currency,
-//                                           &TEH_stefan_log));
-//   }
-//   if (GNUNET_OK !=
-//       TALER_config_get_amount (TEH_cfg,
-//                                "donau",
-//                                "STEFAN_LIN",
-//                                &TEH_stefan_lin))
-//   {
-//     GNUNET_assert (GNUNET_OK ==
-//                    TALER_amount_set_zero (TEH_currency,
-//                                           &TEH_stefan_lin));
-//   }
-
-//   if (0 != strcmp (TEH_currency,
-//                    TEH_aml_threshold.currency))
-//   {
-//     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-//                 "Amount in section `donau' under `AML_THRESHOLD' uses the 
wrong currency!\n");
-//     return GNUNET_SYSERR;
-//   }
-//   TEH_enable_rewards
-//     = GNUNET_CONFIGURATION_get_value_yesno (
-//         TEH_cfg,
-//         "donau",
-//         "ENABLE_REWARDS");
-//   if (GNUNET_SYSERR == TEH_enable_rewards)
-//   {
-//     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-//                 "Need YES or NO in section `donau' under 
`ENABLE_REWARDS'\n");
-//     return GNUNET_SYSERR;
-//   }
-//   if (GNUNET_OK !=
-//       GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
-//                                              "donau",
-//                                              "BASE_URL",
-//                                              &TEH_base_url))
-//   {
-//     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
-//                                "donau",
-//                                "BASE_URL");
-//     return GNUNET_SYSERR;
-//   }
-//   if (! TALER_url_valid_charset (TEH_base_url))
-//   {
-//     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
-//                                "donau",
-//                                "BASE_URL",
-//                                "invalid URL");
-//     return GNUNET_SYSERR;
-//   }
-
-//   {
-//     char *master_public_key_str;
-
-//     if (GNUNET_OK !=
-//         GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
-//                                                "donau",
-//                                                "MASTER_PUBLIC_KEY",
-//                                                &master_public_key_str))
-//     {
-//       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
-//                                  "donau",
-//                                  "MASTER_PUBLIC_KEY");
-//       return GNUNET_SYSERR;
-//     }
-//     if (GNUNET_OK !=
-//         GNUNET_CRYPTO_eddsa_public_key_from_string (master_public_key_str,
-//                                                     strlen (
-//                                                       
master_public_key_str),
-//                                                     &TEH_master_public_key.
-//                                                     eddsa_pub))
-//     {
-//       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
-//                                  "donau",
-//                                  "MASTER_PUBLIC_KEY",
-//                                  "invalid base32 encoding for a master 
public key");
-//       GNUNET_free (master_public_key_str);
-//       return GNUNET_SYSERR;
-//     }
-//     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-//                 "Launching donau with public key `%s'...\n",
-//                 master_public_key_str);
-//     GNUNET_free (master_public_key_str);
-//   }
-
-//   {
-//     char *attr_enc_key_str;
-
-//     if (GNUNET_OK !=
-//         GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
-//                                                "donau",
-//                                                "ATTRIBUTE_ENCRYPTION_KEY",
-//                                                &attr_enc_key_str))
-//     {
-//       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
-//                                  "donau",
-//                                  "ATTRIBUTE_ENCRYPTION_KEY");
-//       return GNUNET_SYSERR;
-//     }
-//     GNUNET_CRYPTO_hash (attr_enc_key_str,
-//                         strlen (attr_enc_key_str),
-//                         &TEH_attribute_key.hash);
-//     GNUNET_free (attr_enc_key_str);
-//   }
-
-//   for (unsigned int i = 0; i<MAX_DB_RETRIES; i++)
-//   {
-//     TEH_plugin = DONAUDB_plugin_load (TEH_cfg);
-//     if (NULL != TEH_plugin)
-//       break;
-//     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-//                 "Failed to connect to DB, will try again %u times\n",
-//                 MAX_DB_RETRIES - i);
-//     sleep (1);
-//   }
-//   if (NULL == TEH_plugin)
-//   {
-//     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-//                 "Failed to initialize DB subsystem. Giving up.\n");
-//     return GNUNET_SYSERR;
-//   }
-//   return GNUNET_OK;
-// }
+    /* mark end of list */
+    {
+      .url = NULL
+    }
+  };
+  struct TEH_RequestContext *rc = *con_cls;
+  struct GNUNET_AsyncScopeSave old_scope;
+  const char *correlation_id = NULL;
+
+  (void) cls;
+  (void) version;
+  if (NULL == rc)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Handling new request\n");
+
+    /* We're in a new async scope! */
+    rc = *con_cls = GNUNET_new (struct TEH_RequestContext);
+    rc->start_time = GNUNET_TIME_absolute_get ();
+    GNUNET_async_scope_fresh (&rc->async_scope_id);
+    //TEH_check_invariants ();
+    rc->url = url;
+    rc->connection = connection;
+    /* We only read the correlation ID on the first callback for every client 
*/
+    correlation_id = MHD_lookup_connection_value (connection,
+                                                  MHD_HEADER_KIND,
+                                                  "Taler-Correlation-Id");
+    if ( (NULL != correlation_id) &&
+         (GNUNET_YES !=
+          GNUNET_CURL_is_valid_scope_id (correlation_id)) )
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "illegal incoming correlation ID\n");
+      correlation_id = NULL;
+    }
+
+    /* Check if upload is in bounds */
+    if (0 == strcasecmp (method,
+                         MHD_HTTP_METHOD_POST))
+    {
+      TALER_MHD_check_content_length (connection,
+                                      TALER_MHD_REQUEST_BUFFER_MAX);
+    }
+  }
+
+  GNUNET_async_scope_enter (&rc->async_scope_id,
+                            &old_scope);
+  //TEH_check_invariants ();
+  if (NULL != correlation_id)
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Handling request (%s) for URL '%s', correlation_id=%s\n",
+                method,
+                url,
+                correlation_id);
+  else
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Handling request (%s) for URL '%s'\n",
+                method,
+                url);
+  /* on repeated requests, check our cache first */
+  if (NULL != rc->rh)
+  {
+    MHD_RESULT ret;
+    const char *start;
+
+    if ('\0' == url[0])
+      /* strange, should start with '/', treat as just "/" */
+      url = "/";
+    start = strchr (url + 1, '/');
+    if (NULL == start)
+      start = "";
+    ret = proceed_with_handler (rc,
+                                start,
+                                upload_data,
+                                upload_data_size);
+    GNUNET_async_scope_restore (&old_scope);
+    return ret;
+  }
+
+  if ( (0 == strcasecmp (method,
+                         MHD_HTTP_METHOD_OPTIONS)) &&
+       (0 == strcmp ("*",
+                     url)) )
+    return TALER_MHD_reply_cors_preflight (connection);
+
+  if (0 == strcasecmp (method,
+                       MHD_HTTP_METHOD_HEAD))
+    method = MHD_HTTP_METHOD_GET; /* treat HEAD as GET here, MHD will do the 
rest */
+
+  /* parse first part of URL */
+  {
+    bool found = false;
+    size_t tok_size;
+    const char *tok;
+    const char *rest;
+
+    if ('\0' == url[0])
+      /* strange, should start with '/', treat as just "/" */
+      url = "/";
+    tok = url + 1;
+    rest = strchr (tok, '/');
+    if (NULL == rest)
+    {
+      tok_size = strlen (tok);
+    }
+    else
+    {
+      tok_size = rest - tok;
+      rest++; /* skip over '/' */
+    }
+    for (unsigned int i = 0; NULL != handlers[i].url; i++)
+    {
+      struct TEH_RequestHandler *rh = &handlers[i];
+
+      if ( (0 != strncmp (tok,
+                          rh->url,
+                          tok_size)) ||
+           (tok_size != strlen (rh->url) ) )
+        continue;
+      found = true;
+      /* The URL is a match!  What we now do depends on the method. */
+      if (0 == strcasecmp (method,
+                           MHD_HTTP_METHOD_OPTIONS))
+      {
+        GNUNET_async_scope_restore (&old_scope);
+        return TALER_MHD_reply_cors_preflight (connection);
+      }
+      GNUNET_assert (NULL != rh->method);
+      if (0 == strcasecmp (method,
+                           rh->method))
+      {
+        MHD_RESULT ret;
+
+        /* cache to avoid the loop next time */
+        rc->rh = rh;
+        /* run handler */
+        ret = proceed_with_handler (rc,
+                                    url + tok_size + 1,
+                                    upload_data,
+                                    upload_data_size);
+        GNUNET_async_scope_restore (&old_scope);
+        return ret;
+      }
+    }
+
+    if (found)
+    {
+      /* we found a matching address, but the method is wrong */
+      struct MHD_Response *reply;
+      MHD_RESULT ret;
+      char *allowed = NULL;
+
+      GNUNET_break_op (0);
+      for (unsigned int i = 0; NULL != handlers[i].url; i++)
+      {
+        struct TEH_RequestHandler *rh = &handlers[i];
+
+        if ( (0 != strncmp (tok,
+                            rh->url,
+                            tok_size)) ||
+             (tok_size != strlen (rh->url) ) )
+          continue;
+        if (NULL == allowed)
+        {
+          allowed = GNUNET_strdup (rh->method);
+        }
+        else
+        {
+          char *tmp;
+
+          GNUNET_asprintf (&tmp,
+                           "%s, %s",
+                           allowed,
+                           rh->method);
+          GNUNET_free (allowed);
+          allowed = tmp;
+        }
+        if (0 == strcasecmp (rh->method,
+                             MHD_HTTP_METHOD_GET))
+        {
+          char *tmp;
+
+          GNUNET_asprintf (&tmp,
+                           "%s, %s",
+                           allowed,
+                           MHD_HTTP_METHOD_HEAD);
+          GNUNET_free (allowed);
+          allowed = tmp;
+        }
+      }
+      reply = TALER_MHD_make_error (TALER_EC_GENERIC_METHOD_INVALID,
+                                    method);
+      GNUNET_break (MHD_YES ==
+                    MHD_add_response_header (reply,
+                                             MHD_HTTP_HEADER_ALLOW,
+                                             allowed));
+      GNUNET_free (allowed);
+      ret = MHD_queue_response (connection,
+                                MHD_HTTP_METHOD_NOT_ALLOWED,
+                                reply);
+      MHD_destroy_response (reply);
+      return ret;
+    }
+  }
+
+  /* No handler matches, generate not found */
+  {
+    MHD_RESULT ret;
+
+    ret = TALER_MHD_reply_with_error (connection,
+                                      MHD_HTTP_NOT_FOUND,
+                                      TALER_EC_GENERIC_ENDPOINT_UNKNOWN,
+                                      url);
+    GNUNET_async_scope_restore (&old_scope);
+    return ret;
+  }
+}
 
 
-// /**
-//  * Called when the main thread exits, writes out performance
-//  * stats if requested.
-//  */
-// static void
-// write_stats (void)
-// {
-//   struct GNUNET_DISK_FileHandle *fh;
-//   pid_t pid = getpid ();
-//   char *benchmark_dir;
-//   char *s;
-//   struct rusage usage;
-
-//   benchmark_dir = getenv ("GNUNET_BENCHMARK_DIR");
-//   if (NULL == benchmark_dir)
-//     return;
-//   GNUNET_asprintf (&s,
-//                    "%s/taler-donau-%llu.txt",
-//                    benchmark_dir,
-//                    (unsigned long long) pid);
-//   fh = GNUNET_DISK_file_open (s,
-//                               (GNUNET_DISK_OPEN_WRITE
-//                                | GNUNET_DISK_OPEN_TRUNCATE
-//                                | GNUNET_DISK_OPEN_CREATE),
-//                               (GNUNET_DISK_PERM_USER_READ
-//                                | GNUNET_DISK_PERM_USER_WRITE));
-//   GNUNET_free (s);
-//   if (NULL == fh)
-//     return; /* permission denied? */
-
-//   /* Collect stats, summed up for all threads */
-//   GNUNET_assert (0 ==
-//                  getrusage (RUSAGE_SELF,
-//                             &usage));
-//   GNUNET_asprintf (&s,
-//                    "time_donau sys %llu user %llu\n",
-//                    (unsigned long long) (usage.ru_stime.tv_sec * 1000 * 1000
-//                                          + usage.ru_stime.tv_usec),
-//                    (unsigned long long) (usage.ru_utime.tv_sec * 1000 * 1000
-//                                          + usage.ru_utime.tv_usec));
-//   GNUNET_assert (GNUNET_SYSERR !=
-//                  GNUNET_DISK_file_write_blocking (fh,
-//                                                   s,
-//                                                   strlen (s)));
-//   GNUNET_free (s);
-//   GNUNET_assert (GNUNET_OK ==
-//                  GNUNET_DISK_file_close (fh));
-// }
+/**
+ * Load configuration parameters for the donau
+ * server into the corresponding global variables.
+ *
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+donau_serve_process_config (void)
+{
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_number (TEH_cfg,
+                                             "donau",
+                                             "MAX_REQUESTS",
+                                             &req_max))
+  {
+    req_max = ULLONG_MAX;
+  }
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
+                                           "donaudb",
+                                           "IDLE_RESERVE_EXPIRATION_TIME",
+                                           &TEH_reserve_closing_delay))
+  {
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                               "donaudb",
+                               "IDLE_RESERVE_EXPIRATION_TIME");
+    /* use default */
+    TEH_reserve_closing_delay
+      = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_WEEKS,
+                                       4);
+  }
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
+                                           "donau",
+                                           "MAX_KEYS_CACHING",
+                                           &TEH_max_keys_caching))
+  {
+    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+                               "donau",
+                               "MAX_KEYS_CACHING",
+                               "valid relative time expected");
+    return GNUNET_SYSERR;
+  }
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
+                                             "donau",
+                                             "KYC_AML_TRIGGER",
+                                             &TEH_kyc_aml_trigger))
+  {
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                               "donau",
+                               "KYC_AML_TRIGGER");
+    return GNUNET_SYSERR;
+  }
+  if (GNUNET_OK !=
+      TALER_config_get_currency (TEH_cfg,
+                                 &TEH_currency))
+  {
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                               "taler",
+                               "CURRENCY");
+    return GNUNET_SYSERR;
+  }
+  {
+    unsigned long long cfd;
+
+    if (GNUNET_OK !=
+        GNUNET_CONFIGURATION_get_value_number (TEH_cfg,
+                                               "donau",
+                                               "CURRENCY_FRACTION_DIGITS",
+                                               &cfd))
+      cfd = 0;
+    if (cfd > 8)
+    {
+      GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+                                 "taler",
+                                 "CURRENCY_FRACTION_DIGITS",
+                                 "Value must be below 8");
+      return GNUNET_SYSERR;
+    }
+    TEH_currency_fraction_digits = (unsigned int) cfd;
+  }
+  if (GNUNET_OK !=
+      TALER_config_get_amount (TEH_cfg,
+                               "donau",
+                               "AML_THRESHOLD",
+                               &TEH_aml_threshold))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Need amount in section `donau' under `AML_THRESHOLD'\n");
+    return GNUNET_SYSERR;
+  }
+  if (GNUNET_OK !=
+      TALER_config_get_amount (TEH_cfg,
+                               "donau",
+                               "STEFAN_ABS",
+                               &TEH_stefan_abs))
+  {
+    GNUNET_assert (GNUNET_OK ==
+                   TALER_amount_set_zero (TEH_currency,
+                                          &TEH_stefan_abs));
+  }
+  if (GNUNET_OK !=
+      TALER_config_get_amount (TEH_cfg,
+                               "donau",
+                               "STEFAN_LOG",
+                               &TEH_stefan_log))
+  {
+    GNUNET_assert (GNUNET_OK ==
+                   TALER_amount_set_zero (TEH_currency,
+                                          &TEH_stefan_log));
+  }
+  if (GNUNET_OK !=
+      TALER_config_get_amount (TEH_cfg,
+                               "donau",
+                               "STEFAN_LIN",
+                               &TEH_stefan_lin))
+  {
+    GNUNET_assert (GNUNET_OK ==
+                   TALER_amount_set_zero (TEH_currency,
+                                          &TEH_stefan_lin));
+  }
+
+  if (0 != strcmp (TEH_currency,
+                   TEH_aml_threshold.currency))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Amount in section `donau' under `AML_THRESHOLD' uses the 
wrong currency!\n");
+    return GNUNET_SYSERR;
+  }
+  TEH_enable_rewards
+    = GNUNET_CONFIGURATION_get_value_yesno (
+        TEH_cfg,
+        "donau",
+        "ENABLE_REWARDS");
+  if (GNUNET_SYSERR == TEH_enable_rewards)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Need YES or NO in section `donau' under `ENABLE_REWARDS'\n");
+    return GNUNET_SYSERR;
+  }
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
+                                             "donau",
+                                             "BASE_URL",
+                                             &TEH_base_url))
+  {
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                               "donau",
+                               "BASE_URL");
+    return GNUNET_SYSERR;
+  }
+  if (! TALER_url_valid_charset (TEH_base_url))
+  {
+    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+                               "donau",
+                               "BASE_URL",
+                               "invalid URL");
+    return GNUNET_SYSERR;
+  }
+
+  {
+    char *master_public_key_str;
+
+    if (GNUNET_OK !=
+        GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
+                                               "donau",
+                                               "MASTER_PUBLIC_KEY",
+                                               &master_public_key_str))
+    {
+      GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                                 "donau",
+                                 "MASTER_PUBLIC_KEY");
+      return GNUNET_SYSERR;
+    }
+    if (GNUNET_OK !=
+        GNUNET_CRYPTO_eddsa_public_key_from_string (master_public_key_str,
+                                                    strlen (
+                                                      master_public_key_str),
+                                                    &TEH_master_public_key.
+                                                    eddsa_pub))
+    {
+      GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+                                 "donau",
+                                 "MASTER_PUBLIC_KEY",
+                                 "invalid base32 encoding for a master public 
key");
+      GNUNET_free (master_public_key_str);
+      return GNUNET_SYSERR;
+    }
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Launching donau with public key `%s'...\n",
+                master_public_key_str);
+    GNUNET_free (master_public_key_str);
+  }
+
+  {
+    char *attr_enc_key_str;
+
+    if (GNUNET_OK !=
+        GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
+                                               "donau",
+                                               "ATTRIBUTE_ENCRYPTION_KEY",
+                                               &attr_enc_key_str))
+    {
+      GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                                 "donau",
+                                 "ATTRIBUTE_ENCRYPTION_KEY");
+      return GNUNET_SYSERR;
+    }
+    GNUNET_CRYPTO_hash (attr_enc_key_str,
+                        strlen (attr_enc_key_str),
+                        &TEH_attribute_key.hash);
+    GNUNET_free (attr_enc_key_str);
+  }
+
+  for (unsigned int i = 0; i<MAX_DB_RETRIES; i++)
+  {
+    TEH_plugin = DONAUDB_plugin_load (TEH_cfg);
+    if (NULL != TEH_plugin)
+      break;
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Failed to connect to DB, will try again %u times\n",
+                MAX_DB_RETRIES - i);
+    sleep (1);
+  }
+  if (NULL == TEH_plugin)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Failed to initialize DB subsystem. Giving up.\n");
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Called when the main thread exits, writes out performance
+ * stats if requested.
+ */
+static void
+write_stats (void)
+{
+  struct GNUNET_DISK_FileHandle *fh;
+  pid_t pid = getpid ();
+  char *benchmark_dir;
+  char *s;
+  struct rusage usage;
+
+  benchmark_dir = getenv ("GNUNET_BENCHMARK_DIR");
+  if (NULL == benchmark_dir)
+    return;
+  GNUNET_asprintf (&s,
+                   "%s/taler-donau-%llu.txt",
+                   benchmark_dir,
+                   (unsigned long long) pid);
+  fh = GNUNET_DISK_file_open (s,
+                              (GNUNET_DISK_OPEN_WRITE
+                               | GNUNET_DISK_OPEN_TRUNCATE
+                               | GNUNET_DISK_OPEN_CREATE),
+                              (GNUNET_DISK_PERM_USER_READ
+                               | GNUNET_DISK_PERM_USER_WRITE));
+  GNUNET_free (s);
+  if (NULL == fh)
+    return; /* permission denied? */
+
+  /* Collect stats, summed up for all threads */
+  GNUNET_assert (0 ==
+                 getrusage (RUSAGE_SELF,
+                            &usage));
+  GNUNET_asprintf (&s,
+                   "time_donau sys %llu user %llu\n",
+                   (unsigned long long) (usage.ru_stime.tv_sec * 1000 * 1000
+                                         + usage.ru_stime.tv_usec),
+                   (unsigned long long) (usage.ru_utime.tv_sec * 1000 * 1000
+                                         + usage.ru_utime.tv_usec));
+  GNUNET_assert (GNUNET_SYSERR !=
+                 GNUNET_DISK_file_write_blocking (fh,
+                                                  s,
+                                                  strlen (s)));
+  GNUNET_free (s);
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_DISK_file_close (fh));
+}
 
 
-// /* Developer logic for supporting the `-f' option. */
-// #if HAVE_DEVELOPER
+/* Developer logic for supporting the `-f' option. */
 
+#if HAVE_DEVELOPER
 /**
  * Option `-f' (specifies an input file to give to the HTTP server).
  */
 static char *input_filename;
 
 
-// /**
-//  * Run 'nc' or 'ncat' as a fake HTTP client using #input_filename
-//  * as the input for the request.  If launching the client worked,
-//  * run the #TEH_KS_loop() event loop as usual.
-//  *
-//  * @return child pid
-//  */
-// static pid_t
-// run_fake_client (void)
-// {
-//   pid_t cld;
-//   char ports[6];
-//   int fd;
-
-//   if (0 == strcmp (input_filename,
-//                    "-"))
-//     fd = STDIN_FILENO;
-//   else
-//     fd = open (input_filename,
-//                O_RDONLY);
-//   if (-1 == fd)
-//   {
-//     fprintf (stderr,
-//              "Failed to open `%s': %s\n",
-//              input_filename,
-//              strerror (errno));
-//     return -1;
-//   }
-//   /* Fake HTTP client request with #input_filename as input.
-//      We do this using the nc tool. */
-//   GNUNET_snprintf (ports,
-//                    sizeof (ports),
-//                    "%u",
-//                    serve_port);
-//   if (0 == (cld = fork ()))
-//   {
-//     GNUNET_break (0 == close (0));
-//     GNUNET_break (0 == dup2 (fd, 0));
-//     GNUNET_break (0 == close (fd));
-//     if ( (0 != execlp ("nc",
-//                        "nc",
-//                        "localhost",
-//                        ports,
-//                        "-w", "30",
-//                        NULL)) &&
-//          (0 != execlp ("ncat",
-//                        "ncat",
-//                        "localhost",
-//                        ports,
-//                        "-i", "30",
-//                        NULL)) )
-//     {
-//       fprintf (stderr,
-//                "Failed to run both `nc' and `ncat': %s\n",
-//                strerror (errno));
-//     }
-//     _exit (1);
-//   }
-//   /* parent process */
-//   if (0 != strcmp (input_filename,
-//                    "-"))
-//     GNUNET_break (0 == close (fd));
-//   return cld;
-// }
+/**
+ * Run 'nc' or 'ncat' as a fake HTTP client using #input_filename
+ * as the input for the request.  If launching the client worked,
+ * run the #TEH_KS_loop() event loop as usual.
+ *
+ * @return child pid
+ */
+static pid_t
+run_fake_client (void)
+{
+  pid_t cld;
+  char ports[6];
+  int fd;
+
+  if (0 == strcmp (input_filename,
+                   "-"))
+    fd = STDIN_FILENO;
+  else
+    fd = open (input_filename,
+               O_RDONLY);
+  if (-1 == fd)
+  {
+    fprintf (stderr,
+             "Failed to open `%s': %s\n",
+             input_filename,
+             strerror (errno));
+    return -1;
+  }
+  /* Fake HTTP client request with #input_filename as input.
+     We do this using the nc tool. */
+  GNUNET_snprintf (ports,
+                   sizeof (ports),
+                   "%u",
+                   serve_port);
+  if (0 == (cld = fork ()))
+  {
+    GNUNET_break (0 == close (0));
+    GNUNET_break (0 == dup2 (fd, 0));
+    GNUNET_break (0 == close (fd));
+    if ( (0 != execlp ("nc",
+                       "nc",
+                       "localhost",
+                       ports,
+                       "-w", "30",
+                       NULL)) &&
+         (0 != execlp ("ncat",
+                       "ncat",
+                       "localhost",
+                       ports,
+                       "-i", "30",
+                       NULL)) )
+    {
+      fprintf (stderr,
+               "Failed to run both `nc' and `ncat': %s\n",
+               strerror (errno));
+    }
+    _exit (1);
+  }
+  /* parent process */
+  if (0 != strcmp (input_filename,
+                   "-"))
+    GNUNET_break (0 == close (fd));
+  return cld;
+}
 
 
-// /**
-//  * Run the donau to serve a single request only, without threads.
-//  *
-//  * @return #GNUNET_OK on success
-//  */
-// static void
-// run_single_request (void)
-// {
-//   pid_t xfork;
-
-//   xfork = fork ();
-//   if (-1 == xfork)
-//   {
-//     global_ret = EXIT_FAILURE;
-//     GNUNET_SCHEDULER_shutdown ();
-//     return;
-//   }
-//   if (0 == xfork)
-//   {
-//     pid_t cld;
-
-//     cld = run_fake_client ();
-//     if (-1 == cld)
-//       _exit (EXIT_FAILURE);
-//     _exit (EXIT_SUCCESS);
-//   }
-
-//   {
-//     int status;
-
-//     if (xfork != waitpid (xfork,
-//                           &status,
-//                           0))
-//       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-//                   "Waiting for `nc' child failed: %s\n",
-//                   strerror (errno));
-//   }
-// }
+/**
+ * Run the donau to serve a single request only, without threads.
+ *
+ * @return #GNUNET_OK on success
+ */
+static void
+run_single_request (void)
+{
+  pid_t xfork;
+
+  xfork = fork ();
+  if (-1 == xfork)
+  {
+    global_ret = EXIT_FAILURE;
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+  if (0 == xfork)
+  {
+    pid_t cld;
+
+    cld = run_fake_client ();
+    if (-1 == cld)
+      _exit (EXIT_FAILURE);
+    _exit (EXIT_SUCCESS);
+  }
+
+  {
+    int status;
+
+    if (xfork != waitpid (xfork,
+                          &status,
+                          0))
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Waiting for `nc' child failed: %s\n",
+                  strerror (errno));
+  }
+}
 
+#endif
+/* end of HAVE_DEVELOPER */
 
-// /* end of HAVE_DEVELOPER */
-// #endif
-
-
-// /**
-//  * Signature of the callback used by MHD to notify the application
-//  * about completed connections.  If we are running in test-mode with
-//  * an input_filename, this function is used to terminate the HTTPD
-//  * after the first request has been processed.
-//  *
-//  * @param cls client-defined closure, NULL
-//  * @param connection connection handle (ignored)
-//  * @param socket_context socket-specific pointer (ignored)
-//  * @param toe reason for connection notification
-//  */
-// static void
-// connection_done (void *cls,
-//                  struct MHD_Connection *connection,
-//                  void **socket_context,
-//                  enum MHD_ConnectionNotificationCode toe)
-// {
-//   (void) cls;
-//   (void) connection;
-//   (void) socket_context;
-
-//   switch (toe)
-//   {
-//   case MHD_CONNECTION_NOTIFY_STARTED:
-//     active_connections++;
-//     break;
-//   case MHD_CONNECTION_NOTIFY_CLOSED:
-//     active_connections--;
-//     if (TEH_suicide &&
-//         (0 == active_connections) )
-//       GNUNET_SCHEDULER_shutdown ();
-//     break;
-//   }
-// #if HAVE_DEVELOPER
-//   /* We only act if the connection is closed. */
-//   if (MHD_CONNECTION_NOTIFY_CLOSED != toe)
-//     return;
-//   if (NULL != input_filename)
-//     GNUNET_SCHEDULER_shutdown ();
-// #endif
-// }
 
 
-// /**
-//  * Function run on shutdown.
-//  *
-//  * @param cls NULL
-//  */
-// static void
-// do_shutdown (void *cls)
-// {
-//   struct MHD_Daemon *mhd;
-//   (void) cls;
-
-//   mhd = TALER_MHD_daemon_stop ();
-//   TEH_resume_keys_requests (true);
-//   TEH_deposits_get_cleanup ();
-//   TEH_reserves_get_cleanup ();
-//   TEH_purses_get_cleanup ();
-//   TEH_kyc_check_cleanup ();
-//   TEH_kyc_proof_cleanup ();
-//   TALER_KYCLOGIC_kyc_done ();
-//   if (NULL != mhd)
-//   {
-//     MHD_stop_daemon (mhd);
-//     mhd = NULL;
-//   }
-//   TEH_wire_done ();
-//   TEH_extensions_done ();
-//   TEH_keys_finished ();
-//   if (NULL != TEH_plugin)
-//   {
-//     DONAUDB_plugin_unload (TEH_plugin);
-//     TEH_plugin = NULL;
-//   }
-//   if (NULL != TEH_curl_ctx)
-//   {
-//     GNUNET_CURL_fini (TEH_curl_ctx);
-//     TEH_curl_ctx = NULL;
-//   }
-//   if (NULL != donau_curl_rc)
-//   {
-//     GNUNET_CURL_gnunet_rc_destroy (donau_curl_rc);
-//     donau_curl_rc = NULL;
-//   }
-//   TALER_TEMPLATING_done ();
-// }
+/**
+ * Signature of the callback used by MHD to notify the application
+ * about completed connections.  If we are running in test-mode with
+ * an input_filename, this function is used to terminate the HTTPD
+ * after the first request has been processed.
+ *
+ * @param cls client-defined closure, NULL
+ * @param connection connection handle (ignored)
+ * @param socket_context socket-specific pointer (ignored)
+ * @param toe reason for connection notification
+ */
+static void
+connection_done (void *cls,
+                 struct MHD_Connection *connection,
+                 void **socket_context,
+                 enum MHD_ConnectionNotificationCode toe)
+{
+  (void) cls;
+  (void) connection;
+  (void) socket_context;
+
+  switch (toe)
+  {
+  case MHD_CONNECTION_NOTIFY_STARTED:
+    active_connections++;
+    break;
+  case MHD_CONNECTION_NOTIFY_CLOSED:
+    active_connections--;
+    if (TEH_suicide &&
+        (0 == active_connections) )
+      GNUNET_SCHEDULER_shutdown ();
+    break;
+  }
+#if HAVE_DEVELOPER
+  /* We only act if the connection is closed. */
+  if (MHD_CONNECTION_NOTIFY_CLOSED != toe)
+    return;
+  if (NULL != input_filename)
+    GNUNET_SCHEDULER_shutdown ();
+#endif
+}
 
 
-// /**
-//  * Main function that will be run by the scheduler.
-//  *
-//  * @param cls closure
-//  * @param args remaining command-line arguments
-//  * @param cfgfile name of the configuration file used (for saving, can be
-//  *        NULL!)
-//  * @param config configuration
-//  */
-// static void
-// run (void *cls,
-//      char *const *args,
-//      const char *cfgfile,
-//      const struct GNUNET_CONFIGURATION_Handle *config)
-// {
-//   enum TALER_MHD_GlobalOptions go;
-//   int fh;
-
-//   (void) cls;
-//   (void) args;
-//   (void ) cfgfile;
-//   go = TALER_MHD_GO_NONE;
-//   if (connection_close)
-//     go |= TALER_MHD_GO_FORCE_CONNECTION_CLOSE;
-//   TALER_MHD_setup (go);
-//   TEH_cfg = config;
-
-//   if (GNUNET_OK !=
-//       donau_serve_process_config ())
-//   {
-//     global_ret = EXIT_NOTCONFIGURED;
-//     GNUNET_SCHEDULER_shutdown ();
-//     return;
-//   }
-//   if (GNUNET_OK !=
-//       TALER_TEMPLATING_init ("donau"))
-//   {
-//     global_ret = EXIT_FAILURE;
-//     GNUNET_SCHEDULER_shutdown ();
-//     return;
-//   }
-//   // if (GNUNET_SYSERR ==
-//   //     TEH_plugin->preflight (TEH_plugin->cls))
-//   // {
-//   //   global_ret = EXIT_FAILURE;
-//   //   GNUNET_SCHEDULER_shutdown ();
-//   //   return;
-//   // }
-//   if (GNUNET_OK !=
-//       TEH_extensions_init ())
-//   {
-//     global_ret = EXIT_FAILURE;
-//     GNUNET_SCHEDULER_shutdown ();
-//     return;
-//   }
-//   if (GNUNET_OK !=
-//       TEH_keys_init ())
-//   {
-//     global_ret = EXIT_FAILURE;
-//     GNUNET_SCHEDULER_shutdown ();
-//     return;
-//   }
-//   if (GNUNET_OK !=
-//       TEH_wire_init ())
-//   {
-//     global_ret = EXIT_FAILURE;
-//     GNUNET_SCHEDULER_shutdown ();
-//     return;
-//   }
-
-//   TEH_load_terms (TEH_cfg);
-//   TEH_curl_ctx
-//     = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
-//                         &donau_curl_rc);
-//   if (NULL == TEH_curl_ctx)
-//   {
-//     GNUNET_break (0);
-//     global_ret = EXIT_FAILURE;
-//     GNUNET_SCHEDULER_shutdown ();
-//     return;
-//   }
-//   donau_curl_rc = GNUNET_CURL_gnunet_rc_create (TEH_curl_ctx);
-//   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
-//                                  NULL);
-//   fh = TALER_MHD_bind (TEH_cfg,
-//                        "donau",
-//                        &serve_port);
-//   if ( (0 == serve_port) &&
-//        (-1 == fh) )
-//   {
-//     GNUNET_SCHEDULER_shutdown ();
-//     return;
-//   }
-//   mhd = MHD_start_daemon (MHD_USE_SUSPEND_RESUME
-//                           | MHD_USE_PIPE_FOR_SHUTDOWN
-//                           | MHD_USE_DEBUG | MHD_USE_DUAL_STACK
-//                           | MHD_USE_TCP_FASTOPEN,
-//                           (-1 == fh) ? serve_port : 0,
-//                           NULL, NULL,
-//                           &handle_mhd_request, NULL,
-//                           MHD_OPTION_LISTEN_BACKLOG_SIZE,
-//                           (unsigned int) 1024,
-//                           MHD_OPTION_LISTEN_SOCKET,
-//                           fh,
-//                           MHD_OPTION_EXTERNAL_LOGGER,
-//                           &TALER_MHD_handle_logs,
-//                           NULL,
-//                           MHD_OPTION_NOTIFY_COMPLETED,
-//                           &handle_mhd_completion_callback,
-//                           NULL,
-//                           MHD_OPTION_NOTIFY_CONNECTION,
-//                           &connection_done,
-//                           NULL,
-//                           MHD_OPTION_CONNECTION_TIMEOUT,
-//                           connection_timeout,
-//                           (0 == allow_address_reuse)
-//                           ? MHD_OPTION_END
-//                           : MHD_OPTION_LISTENING_ADDRESS_REUSE,
-//                           (unsigned int) allow_address_reuse,
-//                           MHD_OPTION_END);
-//   if (NULL == mhd)
-//   {
-//     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-//                 "Failed to launch HTTP service. Is the port in use?\n");
-//     GNUNET_SCHEDULER_shutdown ();
-//     return;
-//   }
-//   global_ret = EXIT_SUCCESS;
-//   TALER_MHD_daemon_start (mhd);
-//   atexit (&write_stats);
-
-// #if HAVE_DEVELOPER
-//   if (NULL != input_filename)
-//     run_single_request ();
-// #endif
-// }
+/**
+ * Function run on shutdown.
+ *
+ * @param cls NULL
+ */
+static void
+do_shutdown (void *cls)
+{
+  struct MHD_Daemon *mhd;
+  (void) cls;
+
+  mhd = TALER_MHD_daemon_stop ();
+  // TEH_resume_keys_requests (true);
+  // TEH_deposits_get_cleanup ();
+  // TEH_reserves_get_cleanup ();
+  // TEH_purses_get_cleanup ();
+  // TEH_kyc_check_cleanup ();
+  // TEH_kyc_proof_cleanup ();
+  // TALER_KYCLOGIC_kyc_done ();
+  if (NULL != mhd)
+  {
+    MHD_stop_daemon (mhd);
+    mhd = NULL;
+  }
+  // TEH_wire_done ();
+  // TEH_extensions_done ();
+  // TEH_keys_finished ();
+  if (NULL != TEH_plugin)
+  {
+    DONAUDB_plugin_unload (TEH_plugin);
+    TEH_plugin = NULL;
+  }
+  if (NULL != TEH_curl_ctx)
+  {
+    GNUNET_CURL_fini (TEH_curl_ctx);
+    TEH_curl_ctx = NULL;
+  }
+  if (NULL != donau_curl_rc)
+  {
+    GNUNET_CURL_gnunet_rc_destroy (donau_curl_rc);
+    donau_curl_rc = NULL;
+  }
+  TALER_TEMPLATING_done ();
+}
+
+
+/**
+ * Main function that will be run by the scheduler.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be
+ *        NULL!)
+ * @param config configuration
+ */
+static void
+run (void *cls,
+     char *const *args,
+     const char *cfgfile,
+     const struct GNUNET_CONFIGURATION_Handle *config)
+{
+  enum TALER_MHD_GlobalOptions go;
+  int fh;
+
+  (void) cls;
+  (void) args;
+  (void ) cfgfile;
+  go = TALER_MHD_GO_NONE;
+  if (connection_close)
+    go |= TALER_MHD_GO_FORCE_CONNECTION_CLOSE;
+  TALER_MHD_setup (go);
+  TEH_cfg = config;
+
+  if (GNUNET_OK !=
+      donau_serve_process_config ())
+  {
+    global_ret = EXIT_NOTCONFIGURED;
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+  if (GNUNET_OK !=
+      TALER_TEMPLATING_init ("donau"))
+  {
+    global_ret = EXIT_FAILURE;
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+  if (GNUNET_SYSERR ==
+      TEH_plugin->preflight (TEH_plugin->cls))
+  {
+    global_ret = EXIT_FAILURE;
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+  // if (GNUNET_OK !=
+  //     TEH_extensions_init ())
+  // {
+  //   global_ret = EXIT_FAILURE;
+  //   GNUNET_SCHEDULER_shutdown ();
+  //   return;
+  // }
+  // if (GNUNET_OK !=
+  //     TEH_keys_init ())
+  // {
+  //   global_ret = EXIT_FAILURE;
+  //   GNUNET_SCHEDULER_shutdown ();
+  //   return;
+  // }
+  // if (GNUNET_OK !=
+  //     TEH_wire_init ())
+  // {
+  //   global_ret = EXIT_FAILURE;
+  //   GNUNET_SCHEDULER_shutdown ();
+  //   return;
+  // }
+
+  //TEH_load_terms (TEH_cfg);
+  TEH_curl_ctx
+    = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
+                        &donau_curl_rc);
+  if (NULL == TEH_curl_ctx)
+  {
+    GNUNET_break (0);
+    global_ret = EXIT_FAILURE;
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+  donau_curl_rc = GNUNET_CURL_gnunet_rc_create (TEH_curl_ctx);
+  GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
+                                 NULL);
+  fh = TALER_MHD_bind (TEH_cfg,
+                       "donau",
+                       &serve_port);
+  if ( (0 == serve_port) &&
+       (-1 == fh) )
+  {
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+  mhd = MHD_start_daemon (MHD_USE_SUSPEND_RESUME
+                          | MHD_USE_PIPE_FOR_SHUTDOWN
+                          | MHD_USE_DEBUG | MHD_USE_DUAL_STACK
+                          | MHD_USE_TCP_FASTOPEN,
+                          (-1 == fh) ? serve_port : 0,
+                          NULL, NULL,
+                          &handle_mhd_request, NULL,
+                          MHD_OPTION_LISTEN_BACKLOG_SIZE,
+                          (unsigned int) 1024,
+                          MHD_OPTION_LISTEN_SOCKET,
+                          fh,
+                          MHD_OPTION_EXTERNAL_LOGGER,
+                          &TALER_MHD_handle_logs,
+                          NULL,
+                          MHD_OPTION_NOTIFY_COMPLETED,
+                          &handle_mhd_completion_callback,
+                          NULL,
+                          MHD_OPTION_NOTIFY_CONNECTION,
+                          &connection_done,
+                          NULL,
+                          MHD_OPTION_CONNECTION_TIMEOUT,
+                          connection_timeout,
+                          (0 == allow_address_reuse)
+                          ? MHD_OPTION_END
+                          : MHD_OPTION_LISTENING_ADDRESS_REUSE,
+                          (unsigned int) allow_address_reuse,
+                          MHD_OPTION_END);
+  if (NULL == mhd)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Failed to launch HTTP service. Is the port in use?\n");
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+  global_ret = EXIT_SUCCESS;
+  TALER_MHD_daemon_start (mhd);
+  atexit (&write_stats);
+
+#if HAVE_DEVELOPER
+  if (NULL != input_filename)
+    run_single_request ();
+#endif
+}
 
 /**
  * The main function of the taler-donau-httpd server ("the donau").
@@ -1488,17 +1483,16 @@ main (int argc,
   (void)options[0]; // delete me
   ret = 1; // delete me
   DONAU_OS_init ();
-  // ret = GNUNET_PROGRAM_run (argc, argv,
-  //                           "taler-donau-httpd",
-  //                           "Taler donau HTTP service",
-  //                           options,
-  //                           &run, NULL);
+  ret = GNUNET_PROGRAM_run (argc, argv,
+                            "taler-donau-httpd",
+                            "Taler donau HTTP service",
+                            options,
+                            &run, NULL);
   if (GNUNET_SYSERR == ret)
     return EXIT_INVALIDARGUMENT;
   if (GNUNET_NO == ret)
     return EXIT_SUCCESS;
-  // return global_ret;
-  return -1;
+  return global_ret;
 }
 
 /* end of taler-donau-httpd.c */
\ No newline at end of file

-- 
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]