summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/Makefile.am30
-rw-r--r--src/backend/QUESTIONS6
-rw-r--r--src/backend/README7
-rw-r--r--src/backend/merchant.c219
-rw-r--r--src/backend/merchant.conf43
-rw-r--r--src/backend/taler-merchant-httpd.c421
-rw-r--r--src/backend/taler-merchant-httpd.h132
-rw-r--r--src/backend/taler-merchant-httpd_auditors.c239
-rw-r--r--src/backend/taler-merchant-httpd_auditors.h74
-rw-r--r--src/backend/taler-merchant-httpd_contract.c147
-rw-r--r--src/backend/taler-merchant-httpd_contract.h9
-rw-r--r--src/backend/taler-merchant-httpd_mhd.c (renamed from src/backend/taler-mint-httpd_mhd.c)14
-rw-r--r--src/backend/taler-merchant-httpd_mhd.h (renamed from src/backend/taler-mint-httpd_mhd.h)4
-rw-r--r--src/backend/taler-merchant-httpd_mints.c530
-rw-r--r--src/backend/taler-merchant-httpd_mints.h105
-rw-r--r--src/backend/taler-merchant-httpd_parsing.c (renamed from src/backend/taler-mint-httpd_parsing.c)15
-rw-r--r--src/backend/taler-merchant-httpd_parsing.h (renamed from src/backend/taler-mint-httpd_parsing.h)0
-rw-r--r--src/backend/taler-merchant-httpd_pay.c902
-rw-r--r--src/backend/taler-merchant-httpd_pay.h10
-rw-r--r--src/backend/taler-merchant-httpd_responses.c (renamed from src/backend/taler-mint-httpd_responses.c)111
-rw-r--r--src/backend/taler-merchant-httpd_responses.h (renamed from src/backend/taler-mint-httpd_responses.h)52
-rw-r--r--src/backend/taler-mint-httpd.h85
22 files changed, 2036 insertions, 1119 deletions
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am
index 08601781..a99fab99 100644
--- a/src/backend/Makefile.am
+++ b/src/backend/Makefile.am
@@ -6,28 +6,18 @@ bin_PROGRAMS = \
taler_merchant_httpd_SOURCES = \
taler-merchant-httpd.c taler-merchant-httpd.h \
- merchant.c merchant.h \
- ../backend-lib/merchant_db.c ../backend-lib/merchant_db.h \
- taler-mint-httpd_parsing.c taler-mint-httpd_parsing.h \
- taler-mint-httpd_responses.c taler-mint-httpd_responses.h \
- taler-mint-httpd.h \
- taler-mint-httpd_mhd.c taler-mint-httpd_mhd.h \
- taler-merchant-httpd_contract.c \
- taler-merchant-httpd_contract.h \
- taler-merchant-httpd_pay.c \
- taler-merchant-httpd_pay.h
-
+ taler-merchant-httpd_parsing.c taler-merchant-httpd_parsing.h \
+ taler-merchant-httpd_responses.c taler-merchant-httpd_responses.h \
+ taler-merchant-httpd_mhd.c taler-merchant-httpd_mhd.h \
+ taler-merchant-httpd_auditors.c taler-merchant-httpd_auditors.h \
+ taler-merchant-httpd_mints.c taler-merchant-httpd_mints.h \
+ taler-merchant-httpd_contract.c taler-merchant-httpd_contract.h \
+ taler-merchant-httpd_pay.c taler-merchant-httpd_pay.h
taler_merchant_httpd_LDADD = \
- $(LIBGCRYPT_LIBS) \
+ $(top_srcdir)/src/backenddb/libtalermerchantdb.la \
+ -ltalermint \
-ltalerutil \
-lmicrohttpd \
-ljansson \
- -lcurl \
- -lgnunetutil \
- $(top_srcdir)/src/backend-lib/libtalermerchant.la \
- -ltalermint \
- -ltalerpq \
- -lgnunetpostgres \
- -lpq \
- -lpthread
+ -lgnunetutil
diff --git a/src/backend/QUESTIONS b/src/backend/QUESTIONS
deleted file mode 100644
index b992e96f..00000000
--- a/src/backend/QUESTIONS
+++ /dev/null
@@ -1,6 +0,0 @@
-1. why does the merchant daemon appears to be some executable under some
-.libs directory even though it gets launched through an executable located
-elsewhere?
-
-2. why does the httpd prints three times the URL corresponding to GET /some/url
-?
diff --git a/src/backend/README b/src/backend/README
deleted file mode 100644
index 999dd9e6..00000000
--- a/src/backend/README
+++ /dev/null
@@ -1,7 +0,0 @@
-Here are the files implementing the backend which is in charge of doing
-cryptographic calls, binary manipulations and some HTTP/JSON communication.
-
-NOTE:
-
-Makefile.am contains some hardcoded paths that need to be tuned to pick
-the right files.
diff --git a/src/backend/merchant.c b/src/backend/merchant.c
deleted file mode 100644
index 02b37fb8..00000000
--- a/src/backend/merchant.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- This file is part of TALER
- (C) 2014 Christian Grothoff (and other contributing authors)
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file merchant/merchant.c
- * @brief Common utility functions for merchant
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- */
-
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include "merchant.h"
-
-
-#define EXITIF(cond) \
- do { \
- if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
- } while (0)
-
-
-/**
- * Parses mints from the configuration.
- *
- * @param cfg the configuration
- * @param mints the array of mints upon successful parsing. Will be NULL upon
- * error.
- * @return the number of mints in the above array; GNUNET_SYSERR upon error in
- * parsing.
- */
-int
-TALER_MERCHANT_parse_mints (const struct GNUNET_CONFIGURATION_Handle *cfg,
- struct MERCHANT_Mint **mints)
-{
- char *mints_str;
- char *token_nf; /* do no free (nf) */
- char *mint_section;
- char *mint_hostname;
- struct MERCHANT_Mint *r_mints;
- struct MERCHANT_Mint mint;
- unsigned int cnt;
- int OK;
-
- OK = 0;
- mints_str = NULL;
- token_nf = NULL;
- mint_section = NULL;
- mint_hostname = NULL;
- r_mints = NULL;
- cnt = 0;
- EXITIF (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
- "merchant",
- "TRUSTED_MINTS",
- &mints_str));
- for (token_nf = strtok (mints_str, " ");
- NULL != token_nf;
- token_nf = strtok (NULL, " "))
- {
- GNUNET_assert (0 < GNUNET_asprintf (&mint_section,
- "mint-%s", token_nf));
- EXITIF (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- mint_section,
- "HOSTNAME",
- &mint_hostname));
- mint.hostname = mint_hostname;
- GNUNET_array_append (r_mints, cnt, mint);
- mint_hostname = NULL;
- GNUNET_free (mint_section);
- mint_section = NULL;
- }
- OK = 1;
-
- EXITIF_exit:
- GNUNET_free_non_null (mints_str);
- GNUNET_free_non_null (mint_section);
- GNUNET_free_non_null (mint_hostname);
- if (!OK)
- {
- GNUNET_free_non_null (r_mints);
- return GNUNET_SYSERR;
- }
-
- *mints = r_mints;
- return cnt;
-}
-
-/**
- * Parses auditors from the configuration.
- *
- * @param cfg the configuration
- * @param mints the array of auditors upon successful parsing. Will be NULL upon
- * error.
- * @return the number of auditors in the above array; GNUNET_SYSERR upon error in
- * parsing.
- */
-int
-TALER_MERCHANT_parse_auditors (const struct GNUNET_CONFIGURATION_Handle *cfg,
- struct MERCHANT_Auditor **auditors)
-{
- char *auditors_str;
- char *token_nf; /* do no free (nf) */
- char *auditor_section;
- char *auditor_name;
- struct MERCHANT_Auditor *r_auditors;
- struct MERCHANT_Auditor auditor;
- unsigned int cnt;
- int OK;
-
- OK = 0;
- auditors_str = NULL;
- token_nf = NULL;
- auditor_section = NULL;
- auditor_name = NULL;
- r_auditors = NULL;
- cnt = 0;
- EXITIF (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "merchant",
- "AUDITORS",
- &auditors_str));
- for (token_nf = strtok (auditors_str, " ");
- NULL != token_nf;
- token_nf = strtok (NULL, " "))
- {
- GNUNET_assert (0 < GNUNET_asprintf (&auditor_section,
- "auditor-%s", token_nf));
- EXITIF (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- auditor_section,
- "NAME",
- &auditor_name));
- auditor.name = auditor_name;
- GNUNET_array_append (r_auditors, cnt, auditor);
- auditor_name = NULL;
- GNUNET_free (auditor_section);
- auditor_section = NULL;
- }
- OK = 1;
-
- EXITIF_exit:
- GNUNET_free_non_null (auditors_str);
- GNUNET_free_non_null (auditor_section);
- GNUNET_free_non_null (auditor_name);
- if (!OK)
- {
- GNUNET_free_non_null (r_auditors);
- return GNUNET_SYSERR;
- }
-
- *auditors = r_auditors;
- return cnt;
-}
-
-
-/**
- * Parse the SEPA information from the configuration. If any of the required
- * fileds is missing return NULL.
- *
- * @param cfg the configuration
- * @return Sepa details as a structure; NULL upon error
- */
-struct MERCHANT_WIREFORMAT_Sepa *
-TALER_MERCHANT_parse_wireformat_sepa (const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- struct MERCHANT_WIREFORMAT_Sepa *wf;
-
- wf = GNUNET_new (struct MERCHANT_WIREFORMAT_Sepa);
- EXITIF (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
- "wire-sepa",
- "IBAN",
- &wf->iban));
- EXITIF (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
- "wire-sepa",
- "NAME",
- &wf->name));
- EXITIF (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
- "wire-sepa",
- "BIC",
- &wf->bic));
- return wf;
-
- EXITIF_exit:
- GNUNET_free_non_null (wf->iban);
- GNUNET_free_non_null (wf->name);
- GNUNET_free_non_null (wf->bic);
- GNUNET_free (wf);
- return NULL;
-
-}
-
-
-/**
- * Destroy and free resouces occupied by the wireformat structure
- *
- * @param wf the wireformat structure
- */
-void
-TALER_MERCHANT_destroy_wireformat_sepa (struct MERCHANT_WIREFORMAT_Sepa *wf)
-{
- GNUNET_free_non_null (wf->iban);
- GNUNET_free_non_null (wf->name);
- GNUNET_free_non_null (wf->bic);
- GNUNET_free (wf);
-}
-
-/* end of merchant.c */
diff --git a/src/backend/merchant.conf b/src/backend/merchant.conf
index 4515fd41..80a7b412 100644
--- a/src/backend/merchant.conf
+++ b/src/backend/merchant.conf
@@ -1,21 +1,52 @@
+# Sample configuration file for a merchant.
[merchant]
+
+# Which port do we run the backend on? (HTTP server)
PORT = 9966
+
+# FIXME: is this one used?
HOSTNAME = localhost
-TRUSTED_MINTS = taler
+
+# Where is our private key?
KEYFILE = merchant.priv
+
+# What currency does this backend accept?
CURRENCY = KUDOS
+
+# FIXME: to be revised
+TRUSTED_MINTS = taler
+
+# How quickly do we want the mint to send us our money?
+# Used only if the frontend does not specify a value.
+# FIXME: EDATE is a bit short, 'execution_delay'?
EDATE = 3 week
-AUDITORS = france
+
+# Which plugin (backend) do we use for the DB.
+DB = postgres
[mint-taler]
-HOSTNAME = mint.demo.taler.net
+URI = mint.demo.taler.net
+MASTER_KEY = Q1WVGRGC1F4W7RYC6M23AEGFEXQEHQ730K3GG0B67VPHQSRR75H0
+
+# Auditors must be in sections "auditor-", the rest of the section
+# name could be anything.
+[auditor-ezb]
+# Informal name of the auditor. Just for the user.
+NAME = European Central Bank
+
+# URI of the auditor (especially for in the future, when the
+# auditor offers an automated issue reporting system).
+# Not really used today.
+URI = http://taler.ezb.eu/
-[auditor-france]
-NAME = Charles De Gaulle
+# This is the important bit: the signing key of the auditor.
+PUBLIC_KEY = 9QXF7XY7E9VPV47B5Z806NDFSX2VJ79SVHHD29QEQ3BG31ANHZ60
-[merchant-db]
+# This specifies which database we use.
+[merchantdb-postgres]
CONFIG = postgres:///talerdemo
+# "wire-" sections include wire details, here for SEPA.
[wire-sepa]
IBAN = DE67830654080004822650
NAME = GNUNET E.V
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c
index ba359bd1..2cc553e9 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2014 Christian Grothoff (and other contributing authors)
+ (C) 2014, 2015 Christian Grothoff (and other contributing authors)
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -13,40 +13,40 @@
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
*/
-
/**
* @file merchant/backend/taler-merchant-httpd.c
* @brief HTTP serving layer intended to perform crypto-work and
* communication with the mint
* @author Marcello Stanisci
+ * @author Christian Grothoff
*/
-
#include "platform.h"
#include <microhttpd.h>
#include <jansson.h>
#include <gnunet/gnunet_util_lib.h>
-#include <curl/curl.h>
#include <taler/taler_util.h>
#include <taler/taler_mint_service.h>
-#include "taler-mint-httpd_parsing.h"
-#include "taler-mint-httpd_responses.h"
-#include "merchant_db.h"
-#include "merchant.h"
-#include "taler_merchant_lib.h"
+#include "taler-merchant-httpd_parsing.h"
+#include "taler-merchant-httpd_responses.h"
+#include "taler_merchantdb_lib.h"
#include "taler-merchant-httpd.h"
-#include "taler-mint-httpd_mhd.h"
+#include "taler-merchant-httpd_mhd.h"
+#include "taler-merchant-httpd_auditors.h"
+#include "taler-merchant-httpd_mints.h"
#include "taler-merchant-httpd_contract.h"
#include "taler-merchant-httpd_pay.h"
+
+
/**
- * Our hostname
+ * Our wire format details in JSON format (with salt).
*/
-static char *hostname;
+struct json_t *j_wire;
/**
- * The port we are running on
+ * Hash of our wire format details as given in #j_wire.
*/
-static long long unsigned port;
+struct GNUNET_HashCode h_wire;
/**
* Merchant's private key
@@ -54,30 +54,35 @@ static long long unsigned port;
struct GNUNET_CRYPTO_EddsaPrivateKey *privkey;
/**
- * File holding the merchant's private key
+ * Merchant's public key
*/
-char *keyfile;
+struct TALER_MerchantPublicKeyP pubkey;
/**
- * This value tells the mint by which date this merchant would like
- * to receive the funds for a deposited payment
+ * Our hostname
*/
-struct GNUNET_TIME_Relative edate_delay;
+static char *hostname;
/**
- * To make 'TMH_PARSE_navigate_json ()' compile
+ * The port we are running on
*/
-char *TMH_mint_currency_string;
+static long long unsigned port;
/**
- * Trusted mints
+ * File holding the merchant's private key
+ */
+static char *keyfile;
+
+/**
+ * This value tells the mint by which date this merchant would like
+ * to receive the funds for a deposited payment
*/
-struct MERCHANT_Mint *mints;
+struct GNUNET_TIME_Relative edate_delay;
/**
- * Active auditors
+ * Which currency is supported by this merchant?
*/
-struct MERCHANT_Auditor *auditors;
+char *TMH_merchant_currency_string;
/**
* Shutdown task identifier
@@ -90,31 +95,6 @@ static struct GNUNET_SCHEDULER_Task *shutdown_task;
static struct GNUNET_SCHEDULER_Task *mhd_task;
/**
- * Context "poller" identifier
- */
-struct GNUNET_SCHEDULER_Task *poller_task;
-
-/**
- * Our wireformat
- */
-struct MERCHANT_WIREFORMAT_Sepa *wire;
-
-/**
- * Salt used to hash the wire object
- */
-long long salt;
-
-/**
- * The number of accepted mints
- */
-unsigned int nmints;
-
-/**
- * The number of active auditors
- */
-unsigned int nauditors;
-
-/**
* Should we do a dry run where temporary tables are used for storing the data.
*/
static int dry;
@@ -127,13 +107,14 @@ static int result;
/**
* Connection handle to the our database
*/
-PGconn *db_conn;
+struct TALER_MERCHANTDB_Plugin *db;
/**
* The MHD Daemon
*/
static struct MHD_Daemon *mhd;
+
/**
* A client has requested the given url using the given method
* (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT,
@@ -190,15 +171,9 @@ url_handler (void *cls,
"Hello, I'm a merchant's Taler backend. This HTTP server is not for humans.\n", 0,
&TMH_MHD_handler_static_response, MHD_HTTP_OK },
- /* Further test page */
- { "/hello", MHD_HTTP_METHOD_GET, "text/plain",
- "Hello, Customer.\n", 0,
- &TMH_MHD_handler_static_response, MHD_HTTP_OK },
-
{ "/contract", MHD_HTTP_METHOD_POST, "application/json",
NULL, 0,
&MH_handler_contract, MHD_HTTP_OK },
-
{ "/contract", NULL, "text/plain",
"Only POST is allowed", 0,
&TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
@@ -206,33 +181,24 @@ url_handler (void *cls,
{ "/pay", MHD_HTTP_METHOD_POST, "application/json",
NULL, 0,
&MH_handler_pay, MHD_HTTP_OK },
-
{ "/pay", NULL, "text/plain",
"Only POST is allowed", 0,
&TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
-
{NULL, NULL, NULL, NULL, 0, 0 }
};
-
static struct TMH_RequestHandler h404 =
{
"", NULL, "text/html",
"<html><title>404: not found</title></html>", 0,
&TMH_MHD_handler_static_response, MHD_HTTP_NOT_FOUND
};
-
- /* Compiler complains about non returning a value in a non-void
- declared function: the FIX is to return what the handler for
- a particular URL returns */
-
struct TMH_RequestHandler *rh;
unsigned int i;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Handling request for URL '%s'\n",
+ "Handling request for URL `%s'\n",
url);
-
for (i=0;NULL != handlers[i].url;i++)
{
rh = &handlers[i];
@@ -252,43 +218,6 @@ url_handler (void *cls,
con_cls,
upload_data,
upload_data_size);
-
-}
-
-/**
- * Function called with information about who is auditing
- * a particular mint and what key the mint is using.
- *
- * @param cls closure, will be 'struct MERCHANT_Mint' so that
- * when this function gets called, it will change the flag 'pending'
- * to 'false'. Note: 'keys' is automatically saved inside the mint's
- * handle, which is contained inside 'struct MERCHANT_Mint', when
- * this callback is called. Thus, once 'pending' turns 'false',
- * it is safe to call 'TALER_MINT_get_keys()' on the mint's handle,
- * in order to get the "good" keys.
- *
- * @param keys information about the various keys used
- * by the mint
- */
-static void
-keys_mgmt_cb (void *cls, const struct TALER_MINT_Keys *keys)
-{
- /* HOT UPDATE: the merchants need the denomination keys!
- Because it wants to (firstly) verify the deposit confirmation
- sent by the mint, and the signed blob depends (among the
- other things) on the coin's deposit fee. That information
- is never communicated by the wallet to the merchant.
- Again, the merchant needs it because it wants to verify that
- the wallet didn't exceede the limit imposed by the merchant
- on the total deposit fee for a purchase */
-
- if (NULL != keys)
- {
- ((struct MERCHANT_Mint *) cls)->pending = 0;
- }
- else
- printf ("no keys gotten\n");
-
}
@@ -302,19 +231,6 @@ keys_mgmt_cb (void *cls, const struct TALER_MINT_Keys *keys)
static void
do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- unsigned int cnt;
-
- for (cnt = 0; cnt < nmints; cnt++)
- {
- if (NULL != mints[cnt].conn)
- TALER_MINT_disconnect (mints[cnt].conn);
-
- }
- if (NULL != poller_task)
- {
- GNUNET_SCHEDULER_cancel (poller_task);
- poller_task = NULL;
- }
if (NULL != mhd_task)
{
GNUNET_SCHEDULER_cancel (mhd_task);
@@ -325,77 +241,19 @@ do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
MHD_stop_daemon (mhd);
mhd = NULL;
}
- if (NULL != db_conn)
+ if (NULL != db)
{
- MERCHANT_DB_disconnect (db_conn);
- db_conn = NULL;
+ TALER_MERCHANTDB_plugin_unload (db);
+ db = NULL;
}
+ TMH_MINTS_done ();
+ TMH_AUDITORS_done ();
if (NULL != keyfile)
GNUNET_free (privkey);
}
/**
- * Task that runs the context's event loop using the GNUnet scheduler.
- *
- * @param cls mint context
- * @param tc scheduler context (unused)
- */
-void
-context_task (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- long timeout;
- int max_fd;
- fd_set read_fd_set;
- fd_set write_fd_set;
- fd_set except_fd_set;
- struct GNUNET_NETWORK_FDSet *rs;
- struct GNUNET_NETWORK_FDSet *ws;
- struct GNUNET_TIME_Relative delay;
- struct TALER_MINT_Context *ctx;
-
- ctx = (struct TALER_MINT_Context *) cls;
- poller_task = NULL;
- TALER_MINT_perform (ctx);
- max_fd = -1;
- timeout = -1;
- FD_ZERO (&read_fd_set);
- FD_ZERO (&write_fd_set);
- FD_ZERO (&except_fd_set);
- TALER_MINT_get_select_info (ctx,
- &read_fd_set,
- &write_fd_set,
- &except_fd_set,
- &max_fd,
- &timeout);
- if (timeout >= 0)
- delay =
- GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
- timeout);
- else
- delay = GNUNET_TIME_UNIT_FOREVER_REL;
- rs = GNUNET_NETWORK_fdset_create ();
- GNUNET_NETWORK_fdset_copy_native (rs,
- &read_fd_set,
- max_fd + 1);
- ws = GNUNET_NETWORK_fdset_create ();
- GNUNET_NETWORK_fdset_copy_native (ws,
- &write_fd_set,
- max_fd + 1);
- poller_task =
- GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
- delay,
- rs,
- ws,
- &context_task,
- cls);
- GNUNET_NETWORK_fdset_destroy (rs);
- GNUNET_NETWORK_fdset_destroy (ws);
-}
-
-
-/**
* 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
@@ -451,9 +309,12 @@ run_daemon (void *cls,
/**
* Kick MHD to run now, to be called after MHD_resume_connection().
+ * Basically, we need to explicitly resume MHD's event loop whenever
+ * we made progress serving a request. This function re-schedules
+ * the task processing MHD's activities to run immediately.
*/
void
-TM_trigger_daemon ()
+TMH_trigger_daemon ()
{
GNUNET_SCHEDULER_cancel (mhd_task);
run_daemon (NULL, NULL);
@@ -461,6 +322,100 @@ TM_trigger_daemon ()
/**
+ * Parse the SEPA information from the configuration. If any of the
+ * required fields is missing return an error.
+ *
+ * @param cfg the configuration
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+parse_wireformat_sepa (const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ unsigned long long salt;
+ char *iban;
+ char *name;
+ char *bic;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg,
+ "wire-sepa",
+ "SALT",
+ &salt))
+ {
+ salt = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE,
+ UINT64_MAX);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "No SALT option given in `wire-sepa`, using %llu\n",
+ (unsigned long long) salt);
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "wire-sepa",
+ "IBAN",
+ &iban))
+ return GNUNET_SYSERR;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "wire-sepa",
+ "NAME",
+ &name))
+ {
+ GNUNET_free (iban);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "wire-sepa",
+ "BIC",
+ &bic))
+ {
+ GNUNET_free (iban);
+ GNUNET_free (name);
+ GNUNET_free (bic);
+ }
+ j_wire = json_pack ("{s:s, s:s, s:s, s:s, s:o}",
+ "type", "SEPA",
+ "IBAN", iban,
+ "name", name,
+ "bic", bic,
+ "r", json_integer (salt));
+ GNUNET_free (iban);
+ GNUNET_free (name);
+ GNUNET_free (bic);
+ if (NULL == j_wire)
+ return GNUNET_SYSERR;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Verify that #j_wire contains a well-formed wire format, and
+ * update #h_wire to match it (if successful).
+ *
+ * @param allowed which wire format is allowed/expected?
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+validate_and_hash_wireformat (const char *allowed)
+{
+ const char *allowed_arr[] = {
+ allowed,
+ NULL
+ };
+
+ if (GNUNET_YES !=
+ TALER_json_validate_wireformat (allowed_arr,
+ j_wire))
+ return GNUNET_SYSERR;
+ if (GNUNET_SYSERR ==
+ TALER_hash_json (j_wire,
+ &h_wire))
+ return MHD_NO;
+ return GNUNET_OK;
+}
+
+
+/**
* Function that queries MHD's select sets and
* starts the task waiting for them.
*
@@ -510,55 +465,49 @@ prepare_daemon ()
}
-
/**
* 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!)
+ * NULL!)
* @param config configuration
*/
void
-run (void *cls, char *const *args, const char *cfgfile,
+run (void *cls,
+ char *const *args,
+ const char *cfgfile,
const struct GNUNET_CONFIGURATION_Handle *config)
{
-
- unsigned int cnt;
- mints = NULL;
- keyfile = NULL;
result = GNUNET_SYSERR;
shutdown_task =
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
- &do_shutdown,
- NULL);
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "merchant launched\n");
-
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+ &do_shutdown,
+ NULL);
EXITIF (GNUNET_SYSERR ==
- (nmints =
- TALER_MERCHANT_parse_mints (config,
- &mints)));
+ TMH_MINTS_init (config));
EXITIF (GNUNET_SYSERR ==
- (nauditors =
- TALER_MERCHANT_parse_auditors (config,
- &auditors)));
- EXITIF (NULL ==
- (wire =
- TALER_MERCHANT_parse_wireformat_sepa (config)));
+ TMH_AUDITORS_init (config));
+ /* FIXME: for now, we just support SEPA here: */
+ EXITIF (GNUNET_OK !=
+ parse_wireformat_sepa (config));
+ EXITIF (GNUNET_OK !=
+ validate_and_hash_wireformat ("SEPA"));
EXITIF (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (config,
- "merchant",
- "KEYFILE",
- &keyfile));
+ GNUNET_CONFIGURATION_get_value_filename (config,
+ "merchant",
+ "KEYFILE",
+ &keyfile));
EXITIF (NULL ==
- (privkey =
- GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile)));
+ (privkey =
+ GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile)));
+ GNUNET_CRYPTO_eddsa_key_get_public (privkey,
+ &pubkey.eddsa_pub);
EXITIF (NULL ==
- (db_conn = MERCHANT_DB_connect (config)));
+ (db = TALER_MERCHANTDB_plugin_load (config)));
EXITIF (GNUNET_OK !=
- MERCHANT_DB_initialize (db_conn, dry));
+ db->initialize (db->cls, dry));
EXITIF (GNUNET_SYSERR ==
GNUNET_CONFIGURATION_get_value_number (config,
"merchant",
@@ -573,30 +522,13 @@ run (void *cls, char *const *args, const char *cfgfile,
GNUNET_CONFIGURATION_get_value_string (config,
"merchant",
"CURRENCY",
- &TMH_mint_currency_string));
+ &TMH_merchant_currency_string));
EXITIF (GNUNET_SYSERR ==
GNUNET_CONFIGURATION_get_value_time (config,
- "merchant",
- "EDATE",
- &edate_delay));
-
- salt = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE,
- UINT64_MAX);
-
- for (cnt = 0; cnt < nmints; cnt++)
- {
- EXITIF (NULL == (mints[cnt].ctx = TALER_MINT_init ()));
- mints[cnt].pending = 1;
- mints[cnt].conn = TALER_MINT_connect (mints[cnt].ctx,
- mints[cnt].hostname,
- &keys_mgmt_cb,
- &mints[cnt],
- TALER_MINT_OPTION_END);
- EXITIF (NULL == mints[cnt].conn);
- poller_task =
- GNUNET_SCHEDULER_add_now (&context_task, mints[cnt].ctx);
- }
+ "merchant",
+ "EDATE",
+ &edate_delay));
mhd = MHD_start_daemon (MHD_USE_SUSPEND_RESUME,
port,
@@ -609,15 +541,15 @@ run (void *cls, char *const *args, const char *cfgfile,
result = GNUNET_OK;
mhd_task = prepare_daemon ();
- EXITIF_exit:
- if (GNUNET_OK != result)
- GNUNET_SCHEDULER_shutdown ();
+ EXITIF_exit:
+ if (GNUNET_OK != result)
+ GNUNET_SCHEDULER_shutdown ();
GNUNET_free_non_null (keyfile);
- if (GNUNET_OK != result)
- GNUNET_SCHEDULER_shutdown ();
-
+ if (GNUNET_OK != result)
+ GNUNET_SCHEDULER_shutdown ();
}
+
/**
* The main function of the serve tool
*
@@ -628,21 +560,18 @@ run (void *cls, char *const *args, const char *cfgfile,
int
main (int argc, char *const *argv)
{
-
- static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
{'t', "temp", NULL,
gettext_noop ("Use temporary database tables"), GNUNET_NO,
&GNUNET_GETOPT_set_one, &dry},
- GNUNET_GETOPT_OPTION_END
- };
-
+ GNUNET_GETOPT_OPTION_END
+ };
if (GNUNET_OK !=
GNUNET_PROGRAM_run (argc, argv,
- "taler-merchant-http",
- "Serve merchant's HTTP interface",
+ "taler-merchant-httpd",
+ "Taler merchant's HTTP backend interface",
options, &run, NULL))
return 3;
return (GNUNET_OK == result) ? 0 : 1;
-
}
diff --git a/src/backend/taler-merchant-httpd.h b/src/backend/taler-merchant-httpd.h
index b60d91bd..25242617 100644
--- a/src/backend/taler-merchant-httpd.h
+++ b/src/backend/taler-merchant-httpd.h
@@ -18,16 +18,83 @@
* @brief HTTP serving layer mainly intended to communicate with the frontend
* @author Marcello Stanisci
*/
+#ifndef TALER_MERCHANT_HTTPD_H
+#define TALER_MERCHANT_HTTPD_H
-#include "merchant_db.h"
+#include "platform.h"
+#include "taler_merchantdb_lib.h"
+#include <microhttpd.h>
/**
- * Kick MHD to run now, to be called after MHD_resume_connection().
+ * Shorthand for exit jumps.
*/
-void
-TM_trigger_daemon (void);
+#define EXITIF(cond) \
+ do { \
+ if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
+ } while (0)
+
+
+/**
+ * @brief Struct describing an URL and the handler for it.
+ */
+struct TMH_RequestHandler
+{
+
+ /**
+ * URL the handler is for.
+ */
+ const char *url;
+
+ /**
+ * Method the handler is for, NULL for "all".
+ */
+ const char *method;
+
+ /**
+ * Mime type to use in reply (hint, can be NULL).
+ */
+ const char *mime_type;
+
+ /**
+ * Raw data for the @e handler
+ */
+ const void *data;
+
+ /**
+ * Number of bytes in @e data, 0 for 0-terminated.
+ */
+ size_t data_size;
+
+ /**
+ * Function to call to handle the request.
+ *
+ * @param rh this struct
+ * @param mime_type the @e mime_type for the reply (hint, can be NULL)
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+ int (*handler)(struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
+
+ /**
+ * Default response code.
+ */
+ int response_code;
+};
+/**
+ * Each MHD response handler that sets the "connection_cls" to a
+ * non-NULL value must use a struct that has this struct as its first
+ * member. This struct contains a single callback, which will be
+ * invoked to clean up the memory when the contection is completed.
+ */
struct TM_HandlerContext;
/**
@@ -41,30 +108,65 @@ typedef void
(*TM_ContextCleanup)(struct TM_HandlerContext *hc);
+/**
+ * Each MHD response handler that sets the "connection_cls" to a
+ * non-NULL value must use a struct that has this struct as its first
+ * member. This struct contains a single callback, which will be
+ * invoked to clean up the memory when the contection is completed.
+ */
struct TM_HandlerContext
{
+ /**
+ * Function to execute the handler-specific cleanup of the
+ * (typically larger) context.
+ */
TM_ContextCleanup cc;
};
-extern struct MERCHANT_Mint *mints;
-extern struct MERCHANT_WIREFORMAT_Sepa *wire;
+/**
+ * Our wire format details in JSON format (with salt).
+ */
+extern json_t *j_wire;
+
+/**
+ * Hash of our wire format details as given in #j_wire.
+ */
+extern struct GNUNET_HashCode h_wire;
-extern PGconn *db_conn;
+/**
+ * Our private key (for the merchant to sign contracts).
+ */
+extern struct GNUNET_CRYPTO_EddsaPrivateKey *privkey;
-extern long long salt;
+/**
+ * Our public key, corresponds to #privkey.
+ */
+extern struct TALER_MerchantPublicKeyP pubkey;
-extern unsigned int nmints;
+/**
+ * Handle to the database backend.
+ */
+extern struct TALER_MERCHANTDB_Plugin *db;
+/**
+ * If the frontend does NOT specify an execution date, how long should
+ * we tell the mint to wait to aggregate transactions before
+ * executing? This delay is added to the current time when we
+ * generate the advisory execution time for the mint.
+ */
extern struct GNUNET_TIME_Relative edate_delay;
-extern struct GNUNET_CRYPTO_EddsaPrivateKey *privkey;
-
-extern struct GNUNET_SCHEDULER_Task *poller_task;
+/**
+ * Kick MHD to run now, to be called after MHD_resume_connection().
+ * Basically, we need to explicitly resume MHD's event loop whenever
+ * we made progress serving a request. This function re-schedules
+ * the task processing MHD's activities to run immediately.
+ */
+void
+TMH_trigger_daemon (void);
-void
-context_task (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc);
+#endif
diff --git a/src/backend/taler-merchant-httpd_auditors.c b/src/backend/taler-merchant-httpd_auditors.c
new file mode 100644
index 00000000..84558ed0
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_auditors.c
@@ -0,0 +1,239 @@
+/*
+ This file is part of TALER
+ (C) 2014, 2015 Christian Grothoff (and other contributing authors)
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file backend/taler-merchant-httpd_auditors.c
+ * @brief logic this HTTPD keeps for each mint we interact with
+ * @author Marcello Stanisci
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler-merchant-httpd_auditors.h"
+
+/**
+ * Our representation of an auditor.
+ */
+struct Auditor
+{
+ /**
+ * Auditor's legal name.
+ */
+ char *name;
+
+ /**
+ * Auditor's URI.
+ */
+ char *uri;
+
+ /**
+ * Public key of the auditor.
+ */
+ struct TALER_AuditorPublicKeyP public_key;
+
+};
+
+
+/**
+ * Array of the auditors this merchant is willing to accept.
+ */
+static struct Auditor *auditors;
+
+/**
+ * The length of the #auditors array.
+ */
+static unsigned int nauditors;
+
+/**
+ * JSON representation of the auditors accepted by this mint.
+ */
+json_t *j_auditors;
+
+
+/**
+ * Check if the given @a dk issued by mint @a mh is audited by
+ * an auditor that is acceptable for this merchant. (And if the
+ * denomination is not yet expired or something silly like that.)
+ *
+ * @param mh mint issuing @a dk
+ * @param dk a denomination issued by @a mh
+ * @param mint_trusted #GNUNET_YES if the mint of @a dk is trusted by config
+ * @return #GNUNET_OK if we accept this denomination
+ */
+int
+TMH_AUDITORS_check_dk (struct TALER_MINT_Handle *mh,
+ const struct TALER_MINT_DenomPublicKey *dk,
+ int mint_trusted)
+{
+ const struct TALER_MINT_Keys *keys;
+ const struct TALER_MINT_AuditorInformation *ai;
+ unsigned int i;
+ unsigned int j;
+
+ if (0 == GNUNET_TIME_absolute_get_remaining (dk->deposit_valid_until).rel_value_us)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Denomination key offered by client has expired for deposits\n");
+ return GNUNET_SYSERR; /* expired */
+ }
+ if (GNUNET_YES == mint_trusted)
+ return GNUNET_OK;
+ keys = TALER_MINT_get_keys (mh);
+ if (NULL == keys)
+ {
+ /* this should never happen, keys should have been successfully
+ obtained before we even got into this function */
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ for (i=0;i<keys->num_auditors;i++)
+ {
+ ai = &keys->auditors[i];
+ for (j=0;j<ai->num_denom_keys;j++)
+ if (ai->denom_keys[j] == dk)
+ return GNUNET_OK;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Denomination key %s offered by client not audited by accepted auditor\n",
+ GNUNET_h2s (&dk->h_key));
+ return GNUNET_NO;
+}
+
+
+/**
+ * Function called on each configuration section. Finds sections
+ * about auditors and parses the entries.
+ *
+ * @param cls closure, with a `const struct GNUNET_CONFIGURATION_Handle *`
+ * @param section name of the section
+ */
+static void
+parse_auditors (void *cls,
+ const char *section)
+{
+ const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
+ char *pks;
+ struct Auditor auditor;
+
+ if (0 != strncasecmp (section,
+ "auditor-",
+ strlen ("auditor-")))
+ return;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ section,
+ "NAME",
+ &auditor.name))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "NAME");
+ return;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ section,
+ "URI",
+ &auditor.uri))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "URI");
+ GNUNET_free (auditor.name);
+ return;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ section,
+ "PUBLIC_KEY",
+ &pks))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "PUBLIC_KEY");
+ GNUNET_free (auditor.name);
+ GNUNET_free (auditor.uri);
+ return;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_public_key_from_string (pks,
+ strlen (pks),
+ &auditor.public_key.eddsa_pub))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "PUBLIC_KEY",
+ "valid public key");
+ GNUNET_free (auditor.name);
+ GNUNET_free (auditor.uri);
+ GNUNET_free (pks);
+ return;
+ }
+ GNUNET_free (pks);
+ GNUNET_array_append (auditors,
+ nauditors,
+ auditor);
+}
+
+
+/**
+ * Parses auditor information from the configuration.
+ *
+ * @param cfg the configuration
+ * @return the number of auditors found; #GNUNET_SYSERR upon error in
+ * parsing.
+ */
+int
+TMH_AUDITORS_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ unsigned int cnt;
+
+ GNUNET_CONFIGURATION_iterate_sections (cfg,
+ &parse_auditors,
+ (void *) cfg);
+
+ /* Generate preferred mint(s) array. */
+ j_auditors = json_array ();
+ for (cnt = 0; cnt < nauditors; cnt++)
+ json_array_append_new (j_auditors,
+ json_pack ("{s:s, s:o, s:s}",
+ "name", auditors[cnt].name,
+ "auditor_pub", TALER_json_from_data (&auditors[cnt].public_key,
+ sizeof (struct TALER_AuditorPublicKeyP)),
+ "uri", auditors[cnt].uri));
+ return nauditors;
+}
+
+
+/**
+ * Release auditor information state.
+ */
+void
+TMH_AUDITORS_done ()
+{
+ unsigned int i;
+
+ json_decref (j_auditors);
+ j_auditors = NULL;
+ for (i=0;i<nauditors;i++)
+ {
+ GNUNET_free (auditors[i].name);
+ GNUNET_free (auditors[i].uri);
+ }
+ GNUNET_free (auditors);
+ auditors = NULL;
+ nauditors = 0;
+}
+
+/* end of taler-merchant-httpd_auditors.c */
diff --git a/src/backend/taler-merchant-httpd_auditors.h b/src/backend/taler-merchant-httpd_auditors.h
new file mode 100644
index 00000000..1a05a78d
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_auditors.h
@@ -0,0 +1,74 @@
+/*
+ This file is part of TALER
+ (C) 2014, 2015 Christian Grothoff (and other contributing authors)
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file backend/taler-merchant-httpd_auditors.h
+ * @brief logic this HTTPD keeps for each mint we interact with
+ * @author Marcello Stanisci
+ * @author Christian Grothoff
+ */
+#ifndef TALER_MERCHANT_HTTPD_AUDITORS_H
+#define TALER_MERCHANT_HTTPD_AUDITORS_H
+
+#include <jansson.h>
+#include <gnunet/gnunet_util_lib.h>
+#include <taler/taler_util.h>
+#include <taler/taler_mint_service.h>
+#include "taler-merchant-httpd.h"
+
+
+/**
+ * JSON representation of the auditors accepted by this mint.
+ */
+extern json_t *j_auditors;
+
+
+/**
+ * Parses auditor information from the configuration.
+ *
+ * @param cfg the configuration
+ * @return the number of auditors found; #GNUNET_SYSERR upon error in
+ * parsing.
+ */
+int
+TMH_AUDITORS_init (const struct GNUNET_CONFIGURATION_Handle *cfg);
+
+
+/**
+ * Check if the given @a dk issued by mint @a mh is audited by
+ * an auditor that is acceptable for this merchant. (And if the
+ * denomination is not yet expired or something silly like that.)
+ *
+ * @param mh mint issuing @a dk
+ * @param dk a denomination issued by @a mh
+ * @param mint_trusted #GNUNET_YES if the mint of @a dk is trusted by config
+ * @return #GNUNET_OK if we accept this denomination
+ */
+int
+TMH_AUDITORS_check_dk (struct TALER_MINT_Handle *mh,
+ const struct TALER_MINT_DenomPublicKey *dk,
+ int mint_trusted);
+
+
+/**
+ * Release auditor information state.
+ */
+void
+TMH_AUDITORS_done (void);
+
+
+
+
+#endif
diff --git a/src/backend/taler-merchant-httpd_contract.c b/src/backend/taler-merchant-httpd_contract.c
index c42a8b37..e44d3b84 100644
--- a/src/backend/taler-merchant-httpd_contract.c
+++ b/src/backend/taler-merchant-httpd_contract.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2014 Christian Grothoff (and other contributing authors)
+ (C) 2014, 2015 Christian Grothoff (and other contributing authors)
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -13,39 +13,30 @@
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
*/
-
/**
- * @file merchant/backend/taler-merchant-httpd.c
+ * @file backend/taler-merchant-httpd_contract.c
* @brief HTTP serving layer mainly intended to communicate with the frontend
* @author Marcello Stanisci
*/
-
#include "platform.h"
-#include <microhttpd.h>
#include <jansson.h>
-#include <gnunet/gnunet_util_lib.h>
-#include <curl/curl.h>
#include <taler/taler_signatures.h>
-#include <taler/taler_amount_lib.h>
-#include <taler/taler_json_lib.h>
-#include <taler/taler_mint_service.h>
-#include "taler-mint-httpd.h"
-#include "taler-mint-httpd_parsing.h"
-#include "taler-mint-httpd_responses.h"
-#include "merchant_db.h"
-#include "merchant.h"
-#include "taler_merchant_lib.h"
#include "taler-merchant-httpd.h"
+#include "taler-merchant-httpd_parsing.h"
+#include "taler-merchant-httpd_auditors.h"
+#include "taler-merchant-httpd_mints.h"
+#include "taler-merchant-httpd_responses.h"
-extern struct MERCHANT_Auditor *auditors;
-extern unsigned int nauditors;
/**
- * Manage a contract request. In practical terms, it adds the fields 'mints',
- * 'merchant_pub', and 'H_wire' to the contract 'proposition' gotten from the
- * frontend. Finally, it adds (outside of the contract) a signature of the
- * (hashed stringification) of this contract and the hashed stringification
- * of this contract to the final bundle sent back to the frontend.
+ * Manage a contract request. In practical terms, it adds the fields
+ * 'mints', 'merchant_pub', and 'H_wire' to the contract 'proposition'
+ * gotten from the frontend. Finally, it adds (outside of the
+ * contract) a signature of the (hashed stringification) of the
+ * contract (and the hashed stringification of this contract as well
+ * to aid diagnostics) to the final bundle, which is then send back to
+ * the frontend.
+ *
* @param rh context of the handler
* @param connection the MHD connection to handle
* @param[in,out] connection_cls the connection's closure (can be updated)
@@ -61,18 +52,8 @@ MH_handler_contract (struct TMH_RequestHandler *rh,
size_t *upload_data_size)
{
json_t *root;
- json_t *trusted_mints;
- json_t *j_auditors;
- json_t *auditor;
- json_t *mint;
- json_t *j_wire;
- const struct TALER_MINT_Keys *keys;
int res;
- int cnt;
- struct GNUNET_HashCode h_wire;
- struct GNUNET_CRYPTO_EddsaPublicKey pubkey;
- struct MERCHANT_Contract contract;
- char *contract_str;
+ struct TALER_ContractPS contract;
struct GNUNET_CRYPTO_EddsaSignature contract_sig;
res = TMH_PARSE_post_json (connection,
@@ -82,87 +63,43 @@ MH_handler_contract (struct TMH_RequestHandler *rh,
&root);
if (GNUNET_SYSERR == res)
return MHD_NO;
- /* the POST's body has to be further fetched */ if ((GNUNET_NO == res) || (NULL == root))
+ /* the POST's body has to be further fetched */
+ if ((GNUNET_NO == res) || (NULL == root))
return MHD_YES;
- /* Generate preferred mint(s) array. */
-
- trusted_mints = json_array ();
- for (cnt = 0; cnt < nmints; cnt++)
- {
- if (!mints[cnt].pending)
- {
- keys = TALER_MINT_get_keys (mints[cnt].conn);
- mint = json_pack ("{s:s, s:o}",
- "url", mints[cnt].hostname,
- "master_pub",
- TALER_json_from_data
- (&keys->master_pub.eddsa_pub,
- sizeof (keys->master_pub.eddsa_pub)));
- json_array_append_new (trusted_mints, mint);
- }
- }
- j_auditors = json_array ();
- for (cnt = 0; cnt < nauditors; cnt++)
- {
- auditor = json_pack ("{s:s}",
- "name", auditors[cnt].name);
- json_array_append_new (j_auditors, auditor);
- }
-
- /**
- * Return badly if no mints are trusted (or no call to /keys has still
- * returned the expected data). WARNING: it
- * may be possible that a mint trusted by the wallet is good, but
- * still pending; that case must be handled with some "polling-style"
- * routine, simply ignored, or ended with an invitation to the wallet
- * to just retry later
- */
- if (!json_array_size (trusted_mints))
- return MHD_NO;
-
- /**
- * Hard error, no action can be taken by a wallet
- */
- if (!json_array_size (j_auditors))
- return MHD_NO;
-
- json_object_set_new (root, "mints", trusted_mints);
- json_object_set_new (root, "auditors", j_auditors);
-
- if (NULL == (j_wire = MERCHANT_get_wire_json (wire,
- salt)))
- return MHD_NO;
-
- /* hash wire objcet */
- if (GNUNET_SYSERR ==
- TALER_hash_json (j_wire, &h_wire))
- return MHD_NO;
-
+ /* add fields to the "root" that the backend should provide */
+ json_object_set (root,
+ "mints",
+ trusted_mints);
+ json_object_set (root,
+ "auditors",
+ j_auditors);
json_object_set_new (root,
"H_wire",
- TALER_json_from_data (&h_wire, sizeof (h_wire)));
-
- GNUNET_CRYPTO_eddsa_key_get_public (privkey, &pubkey);
+ TALER_json_from_data (&h_wire,
+ sizeof (h_wire)));
json_object_set_new (root,
"merchant_pub",
- TALER_json_from_data (&pubkey, sizeof (pubkey)));
-
- /* Sign */
- contract_str = json_dumps (root, JSON_COMPACT | JSON_SORT_KEYS);
- GNUNET_CRYPTO_hash (contract_str, strlen (contract_str), &contract.h_contract);
+ TALER_json_from_data (&pubkey,
+ sizeof (pubkey)));
+ /* create contract signature */
+ GNUNET_assert (GNUNET_OK ==
+ TALER_hash_json (root,
+ &contract.h_contract));
contract.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT);
contract.purpose.size = htonl (sizeof (contract));
- GNUNET_CRYPTO_eddsa_sign (privkey, &contract.purpose, &contract_sig);
-
+ GNUNET_CRYPTO_eddsa_sign (privkey,
+ &contract.purpose,
+ &contract_sig);
+ /* return final response */
return TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_OK,
"{s:o, s:o, s:o}",
"contract", root,
- "sig", TALER_json_from_data
- (&contract_sig, sizeof (contract_sig)),
- "H_contract", TALER_json_from_data
- (&contract.h_contract,
- sizeof (contract.h_contract)));
-
+ "sig", TALER_json_from_data (&contract_sig,
+ sizeof (contract_sig)),
+ "H_contract", TALER_json_from_data (&contract.h_contract,
+ sizeof (contract.h_contract)));
}
+
+/* end of taler-merchant-httpd_contract.c */
diff --git a/src/backend/taler-merchant-httpd_contract.h b/src/backend/taler-merchant-httpd_contract.h
index 5e72c514..44cef909 100644
--- a/src/backend/taler-merchant-httpd_contract.h
+++ b/src/backend/taler-merchant-httpd_contract.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2014 Christian Grothoff (and other contributing authors)
+ (C) 2014, 2015 Christian Grothoff (and other contributing authors)
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -13,17 +13,15 @@
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
*/
-
/**
- * @file merchant/backend/taler-merchant-httpd_contract.h
+ * @file backend/taler-merchant-httpd_contract.h
* @brief headers for /contract handler
* @author Marcello Stanisci
*/
-
#ifndef TALER_MINT_HTTPD_CONTRACT_H
#define TALER_MINT_HTTPD_CONTRACT_H
#include <microhttpd.h>
-#include "taler-mint-httpd.h"
+#include "taler-merchant-httpd.h"
/**
* Manage a contract request
@@ -33,7 +31,6 @@
* @param[in,out] connection_cls the connection's closure (can be updated)
* @param upload_data upload data
* @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- *
* @return MHD result code
*/
int
diff --git a/src/backend/taler-mint-httpd_mhd.c b/src/backend/taler-merchant-httpd_mhd.c
index 419c4fb0..6fd18d9c 100644
--- a/src/backend/taler-mint-httpd_mhd.c
+++ b/src/backend/taler-merchant-httpd_mhd.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014 GNUnet e.V.
+ Copyright (C) 2014, 2015 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
@@ -13,9 +13,8 @@
You should have received a copy of the GNU Affero General Public License along with
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
*/
-
/**
- * @file taler-mint-httpd_mhd.c
+ * @file taler-merchant-httpd_mhd.c
* @brief helpers for MHD interaction; these are TALER_MINT_handler_ functions
* that generate simple MHD replies that do not require any real operations
* to be performed (error handling, static pages, etc.)
@@ -24,14 +23,9 @@
* @author Christian Grothoff
*/
#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
#include <jansson.h>
-#include <microhttpd.h>
-#include <pthread.h>
-#include "taler-mint-httpd_responses.h"
-#include "taler-mint-httpd.h"
-#include "taler-mint-httpd_mhd.h"
-#include "taler-mint-httpd_responses.h"
+#include "taler-merchant-httpd_mhd.h"
+#include "taler-merchant-httpd_responses.h"
/**
diff --git a/src/backend/taler-mint-httpd_mhd.h b/src/backend/taler-merchant-httpd_mhd.h
index a9f575df..3fe137db 100644
--- a/src/backend/taler-mint-httpd_mhd.h
+++ b/src/backend/taler-merchant-httpd_mhd.h
@@ -15,7 +15,7 @@
*/
/**
- * @file taler-mint-httpd_mhd.h
+ * @file taler-merchant-httpd_mhd.h
* @brief helpers for MHD interaction, used to generate simple responses
* @author Florian Dold
* @author Benedikt Mueller
@@ -25,7 +25,7 @@
#define TALER_MINT_HTTPD_MHD_H
#include <gnunet/gnunet_util_lib.h>
#include <microhttpd.h>
-#include "taler-mint-httpd.h"
+#include "taler-merchant-httpd.h"
/**
diff --git a/src/backend/taler-merchant-httpd_mints.c b/src/backend/taler-merchant-httpd_mints.c
new file mode 100644
index 00000000..e93419cd
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_mints.c
@@ -0,0 +1,530 @@
+/*
+ This file is part of TALER
+ (C) 2014, 2015 Christian Grothoff (and other contributing authors)
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file backend/taler-merchant-httpd_mints.c
+ * @brief logic this HTTPD keeps for each mint we interact with
+ * @author Marcello Stanisci
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler-merchant-httpd_mints.h"
+
+
+/**
+ * How often do we retry fetching /keys?
+ */
+#define KEYS_RETRY_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 60)
+
+
+/**
+ * Mint
+ */
+struct Mint;
+
+
+/**
+ * Information we keep for a pending #MMH_MINTS_find_mint() operation.
+ */
+struct TMH_MINTS_FindOperation
+{
+
+ /**
+ * Kept in a DLL.
+ */
+ struct TMH_MINTS_FindOperation *next;
+
+ /**
+ * Kept in a DLL.
+ */
+ struct TMH_MINTS_FindOperation *prev;
+
+ /**
+ * Function to call with the result.
+ */
+ TMH_MINTS_FindContinuation fc;
+
+ /**
+ * Closure for @e fc.
+ */
+ void *fc_cls;
+
+ /**
+ * Mint we wait for the /keys for.
+ */
+ struct Mint *my_mint;
+
+ /**
+ * Task scheduled to asynchrnously return the result.
+ */
+ struct GNUNET_SCHEDULER_Task *at;
+
+};
+
+
+/**
+ * Mint
+ */
+struct Mint
+{
+
+ /**
+ * Kept in a DLL.
+ */
+ struct Mint *next;
+
+ /**
+ * Kept in a DLL.
+ */
+ struct Mint *prev;
+
+ /**
+ * Head of FOs pending for this mint.
+ */
+ struct TMH_MINTS_FindOperation *fo_head;
+
+ /**
+ * Tail of FOs pending for this mint.
+ */
+ struct TMH_MINTS_FindOperation *fo_tail;
+
+ /**
+ * (base) URI of the mint.
+ */
+ char *uri;
+
+ /**
+ * A connection to this mint
+ */
+ struct TALER_MINT_Handle *conn;
+
+ /**
+ * Master public key, guaranteed to be set ONLY for
+ * trusted mints.
+ */
+ struct TALER_MasterPublicKeyP master_pub;
+
+ /**
+ * At what time should we try to fetch /keys again?
+ */
+ struct GNUNET_TIME_Absolute retry_time;
+
+ /**
+ * Flag which indicates whether some HTTP transfer between
+ * this merchant and the mint is still ongoing
+ */
+ int pending;
+
+ /**
+ * #GNUNET_YES if this mint is from our configuration and
+ * explicitly trusted, #GNUNET_NO if we need to check each
+ * key to be sure it is trusted.
+ */
+ int trusted;
+
+};
+
+
+/**
+ * Context for all mint operations (useful to the event loop)
+ */
+static struct TALER_MINT_Context *ctx;
+
+/**
+ * Task we use to drive the interaction with this mint.
+ */
+static struct GNUNET_SCHEDULER_Task *poller_task;
+
+/**
+ * Head of mints we know about.
+ */
+static struct Mint *mint_head;
+
+/**
+ * Tail of mints we know about.
+ */
+static struct Mint *mint_tail;
+
+/**
+ * List of our trusted mints for inclusion in contracts.
+ */
+json_t *trusted_mints;
+
+
+/**
+ * Function called with information about who is auditing
+ * a particular mint and what key the mint is using.
+ *
+ * @param cls closure, will be `struct Mint` so that
+ * when this function gets called, it will change the flag 'pending'
+ * to 'false'. Note: 'keys' is automatically saved inside the mint's
+ * handle, which is contained inside 'struct Mint', when
+ * this callback is called. Thus, once 'pending' turns 'false',
+ * it is safe to call 'TALER_MINT_get_keys()' on the mint's handle,
+ * in order to get the "good" keys.
+ * @param keys information about the various keys used
+ * by the mint
+ */
+static void
+keys_mgmt_cb (void *cls,
+ const struct TALER_MINT_Keys *keys)
+{
+ struct Mint *mint = cls;
+ struct TMH_MINTS_FindOperation *fo;
+
+ if (NULL != keys)
+ {
+ mint->pending = GNUNET_NO;
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to fetch /keys from `%s'\n",
+ mint->uri);
+ TALER_MINT_disconnect (mint->conn);
+ mint->conn = NULL;
+ mint->pending = GNUNET_SYSERR; /* failed hard */
+ mint->retry_time = GNUNET_TIME_relative_to_absolute (KEYS_RETRY_FREQ);
+ }
+ while (NULL != (fo = mint->fo_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (mint->fo_head,
+ mint->fo_tail,
+ fo);
+ fo->fc (fo->fc_cls,
+ (NULL != keys) ? mint->conn : NULL,
+ mint->trusted);
+ GNUNET_free (fo);
+ }
+}
+
+
+/**
+ * Task that runs the mint's event loop using the GNUnet scheduler.
+ *
+ * @param cls a `struct Mint *`
+ * @param tc scheduler context (unused)
+ */
+static void
+context_task (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ long timeout;
+ int max_fd;
+ fd_set read_fd_set;
+ fd_set write_fd_set;
+ fd_set except_fd_set;
+ struct GNUNET_NETWORK_FDSet *rs;
+ struct GNUNET_NETWORK_FDSet *ws;
+ struct GNUNET_TIME_Relative delay;
+
+ poller_task = NULL;
+ TALER_MINT_perform (ctx);
+ max_fd = -1;
+ timeout = -1;
+ FD_ZERO (&read_fd_set);
+ FD_ZERO (&write_fd_set);
+ FD_ZERO (&except_fd_set);
+ TALER_MINT_get_select_info (ctx,
+ &read_fd_set,
+ &write_fd_set,
+ &except_fd_set,
+ &max_fd,
+ &timeout);
+ if (timeout >= 0)
+ delay =
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
+ timeout);
+ else
+ delay = GNUNET_TIME_UNIT_FOREVER_REL;
+ rs = GNUNET_NETWORK_fdset_create ();
+ GNUNET_NETWORK_fdset_copy_native (rs,
+ &read_fd_set,
+ max_fd + 1);
+ ws = GNUNET_NETWORK_fdset_create ();
+ GNUNET_NETWORK_fdset_copy_native (ws,
+ &write_fd_set,
+ max_fd + 1);
+ poller_task =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ delay,
+ rs,
+ ws,
+ &context_task,
+ NULL);
+ GNUNET_NETWORK_fdset_destroy (rs);
+ GNUNET_NETWORK_fdset_destroy (ws);
+}
+
+
+/**
+ * Task to return find operation result asynchronously to caller.
+ *
+ * @param cls a `struct TMH_MINTS_FindOperation`
+ * @param tc unused
+ */
+static void
+return_result (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct TMH_MINTS_FindOperation *fo = cls;
+ struct Mint *mint = fo->my_mint;
+
+ fo->at = NULL;
+ GNUNET_CONTAINER_DLL_remove (mint->fo_head,
+ mint->fo_tail,
+ fo);
+ fo->fc (fo->fc_cls,
+ (GNUNET_SYSERR == mint->pending) ? NULL : mint->conn,
+ mint->trusted);
+ GNUNET_free (fo);
+ GNUNET_SCHEDULER_cancel (poller_task);
+ GNUNET_SCHEDULER_add_now (&context_task,
+ NULL);
+}
+
+
+/**
+ * Find a mint that matches @a chosen_mint. If we cannot connect
+ * to the mint, or if it is not acceptable, @a fc is called with
+ * NULL for the mint.
+ *
+ * @param chosen_mint URI of the mint we would like to talk to
+ * @param fc function to call with the handles for the mint
+ * @param fc_cls closure for @a fc
+ * @return NULL on error
+ */
+struct TMH_MINTS_FindOperation *
+TMH_MINTS_find_mint (const char *chosen_mint,
+ TMH_MINTS_FindContinuation fc,
+ void *fc_cls)
+{
+ struct Mint *mint;
+ struct TMH_MINTS_FindOperation *fo;
+
+ if (NULL == ctx)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ /* Check if the mint is known */
+ for (mint = mint_head; NULL != mint; mint = mint->next)
+ /* test it by checking public key --- FIXME: hostname or public key!?
+ Should probably be URI, not hostname anyway! */
+ if (0 == strcmp (mint->uri,
+ chosen_mint))
+ break;
+ if (NULL == mint)
+ {
+ /* This is a new mint */
+ mint = GNUNET_new (struct Mint);
+ mint->uri = GNUNET_strdup (chosen_mint);
+ mint->pending = GNUNET_YES;
+ GNUNET_CONTAINER_DLL_insert (mint_head,
+ mint_tail,
+ mint);
+ }
+
+ /* check if we should resume this mint */
+ if ( (GNUNET_SYSERR == mint->pending) &&
+ (0 == GNUNET_TIME_absolute_get_remaining (mint->retry_time).rel_value_us) )
+ mint->pending = GNUNET_YES;
+
+
+ fo = GNUNET_new (struct TMH_MINTS_FindOperation);
+ fo->fc = fc;
+ fo->fc_cls = fc_cls;
+ fo->my_mint = mint;
+ GNUNET_CONTAINER_DLL_insert (mint->fo_head,
+ mint->fo_tail,
+ fo);
+
+ if (GNUNET_NO == mint->pending)
+ {
+ /* We are not currently waiting for a reply, immediately
+ return result */
+ fo->at = GNUNET_SCHEDULER_add_now (&return_result,
+ fo);
+ return fo;
+ }
+
+ /* If new or resumed, retry fetching /keys */
+ if ( (NULL == mint->conn) &&
+ (GNUNET_YES == mint->pending) )
+ {
+ mint->conn = TALER_MINT_connect (ctx,
+ mint->uri,
+ &keys_mgmt_cb,
+ mint,
+ TALER_MINT_OPTION_END);
+ GNUNET_break (NULL != mint->conn);
+ }
+ return fo;
+}
+
+
+/**
+ * Abort pending find operation.
+ *
+ * @param fo handle to operation to abort
+ */
+void
+TMH_MINTS_find_mint_cancel (struct TMH_MINTS_FindOperation *fo)
+{
+ struct Mint *mint = fo->my_mint;
+
+ if (NULL != fo->at)
+ {
+ GNUNET_SCHEDULER_cancel (fo->at);
+ fo->at = NULL;
+ }
+ GNUNET_CONTAINER_DLL_remove (mint->fo_head,
+ mint->fo_tail,
+ fo);
+ GNUNET_free (fo);
+}
+
+
+/**
+ * Function called on each configuration section. Finds sections
+ * about mints and parses the entries.
+ *
+ * @param cls closure, with a `const struct GNUNET_CONFIGURATION_Handle *`
+ * @param section name of the section
+ */
+static void
+parse_mints (void *cls,
+ const char *section)
+{
+ const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
+ char *uri;
+ char *mks;
+ struct Mint *mint;
+
+ if (0 != strncasecmp (section,
+ "mint-",
+ strlen ("mint-")))
+ return;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ section,
+ "URI",
+ &uri))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "URI");
+ return;
+ }
+ mint = GNUNET_new (struct Mint);
+ mint->uri = uri;
+ if (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ section,
+ "MASTER_KEY",
+ &mks))
+ {
+ if (GNUNET_OK ==
+ GNUNET_CRYPTO_eddsa_public_key_from_string (mks,
+ strlen (mks),
+ &mint->master_pub.eddsa_pub))
+ {
+ mint->trusted = GNUNET_YES;
+ }
+ else
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "MASTER_KEY",
+ _("ill-formed key"));
+ }
+ GNUNET_free (mks);
+ }
+ GNUNET_CONTAINER_DLL_insert (mint_head,
+ mint_tail,
+ mint);
+ mint->pending = GNUNET_YES;
+ mint->conn = TALER_MINT_connect (ctx,
+ mint->uri,
+ &keys_mgmt_cb,
+ mint,
+ TALER_MINT_OPTION_END);
+ GNUNET_break (NULL != mint->conn);
+}
+
+
+/**
+ * Parses "trusted" mints listed in the configuration.
+ *
+ * @param cfg the configuration
+ * @return #GNUNET_OK on success; #GNUNET_SYSERR upon error in
+ * parsing.
+ */
+int
+TMH_MINTS_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ struct Mint *mint;
+ json_t *j_mint;
+
+ ctx = TALER_MINT_init ();
+ if (NULL == ctx)
+ return GNUNET_SYSERR;
+ GNUNET_CONFIGURATION_iterate_sections (cfg,
+ &parse_mints,
+ (void *) cfg);
+ /* build JSON with list of trusted mints */
+ trusted_mints = json_array ();
+ for (mint = mint_head; NULL != mint; mint = mint->next)
+ {
+ if (GNUNET_YES != mint->trusted)
+ continue;
+ j_mint = json_pack ("{s:s, s:o}",
+ "url", mint->uri,
+ "master_pub", TALER_json_from_data (&mint->master_pub,
+ sizeof (struct TALER_MasterPublicKeyP)));
+ json_array_append_new (trusted_mints,
+ j_mint);
+ }
+ poller_task = GNUNET_SCHEDULER_add_now (&context_task,
+ NULL);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called to shutdown the mints subsystem.
+ */
+void
+TMH_MINTS_done ()
+{
+ struct Mint *mint;
+
+ while (NULL != (mint = mint_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (mint_head,
+ mint_tail,
+ mint);
+ if (NULL != mint->conn)
+ TALER_MINT_disconnect (mint->conn);
+ GNUNET_free (mint->uri);
+ GNUNET_free (mint);
+ }
+ if (NULL != poller_task)
+ {
+ GNUNET_SCHEDULER_cancel (poller_task);
+ poller_task = NULL;
+ }
+ TALER_MINT_fini (ctx);
+}
diff --git a/src/backend/taler-merchant-httpd_mints.h b/src/backend/taler-merchant-httpd_mints.h
new file mode 100644
index 00000000..a4684f59
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_mints.h
@@ -0,0 +1,105 @@
+/*
+ This file is part of TALER
+ (C) 2014, 2015 Christian Grothoff (and other contributing authors)
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file backend/taler-merchant-httpd_mints.h
+ * @brief logic this HTTPD keeps for each mint we interact with
+ * @author Marcello Stanisci
+ * @author Christian Grothoff
+ */
+#ifndef TALER_MERCHANT_HTTPD_MINTS_H
+#define TALER_MERCHANT_HTTPD_MINTS_H
+
+#include <jansson.h>
+#include <gnunet/gnunet_util_lib.h>
+#include <curl/curl.h>
+#include <taler/taler_util.h>
+#include <taler/taler_mint_service.h>
+#include "taler-merchant-httpd.h"
+
+
+/**
+ * List of our trusted mints in JSON format for inclusion in contracts.
+ */
+extern json_t *trusted_mints;
+
+
+/**
+ * Parses "trusted" mints listed in the configuration.
+ *
+ * @param cfg the configuration
+ * @return #GNUNET_OK on success; #GNUNET_SYSERR upon error in
+ * parsing or initialization.
+ */
+int
+TMH_MINTS_init (const struct GNUNET_CONFIGURATION_Handle *cfg);
+
+
+/**
+ * Function called to shutdown the mints subsystem.
+ */
+void
+TMH_MINTS_done (void);
+
+
+/**
+ * Function called with the result of a #TMH_MINTS_find_mint()
+ * operation.
+ *
+ * @param cls closure
+ * @param mh handle to the mint context
+ * @param mint_trusted #GNUNET_YES if this mint is trusted by config
+ */
+typedef void
+(*TMH_MINTS_FindContinuation)(void *cls,
+ struct TALER_MINT_Handle *mh,
+ int mint_trusted);
+
+
+/**
+ * Information we keep for a pending #MMH_MINTS_find_mint() operation.
+ */
+struct TMH_MINTS_FindOperation;
+
+
+/**
+ * Find a mint that matches @a chosen_mint. If we cannot connect
+ * to the mint, or if it is not acceptable, @a fc is called with
+ * NULL for the mint.
+ *
+ * @param chosen_mint URI of the mint we would like to talk to
+ * @param fc function to call with the handles for the mint
+ * @param fc_cls closure for @a fc
+ *
+ * FIXME: should probably return a value to *cancel* the
+ * operation in case MHD connection goes down and needs to
+ * free fc_cls.
+ */
+struct TMH_MINTS_FindOperation *
+TMH_MINTS_find_mint (const char *chosen_mint,
+ TMH_MINTS_FindContinuation fc,
+ void *fc_cls);
+
+
+/**
+ * Abort pending find operation.
+ *
+ * @param fo handle to operation to abort
+ */
+void
+TMH_MINTS_find_mint_cancel (struct TMH_MINTS_FindOperation *fo);
+
+
+#endif
diff --git a/src/backend/taler-mint-httpd_parsing.c b/src/backend/taler-merchant-httpd_parsing.c
index 9efd6c23..14a87ff4 100644
--- a/src/backend/taler-mint-httpd_parsing.c
+++ b/src/backend/taler-merchant-httpd_parsing.c
@@ -21,19 +21,18 @@
* @author Benedikt Mueller
* @author Christian Grothoff
*/
-
#include "platform.h"
#include <gnunet/gnunet_util_lib.h>
-#include "taler-mint-httpd_parsing.h"
-#include "taler-mint-httpd_responses.h"
+#include "taler-merchant-httpd_parsing.h"
+#include "taler-merchant-httpd_responses.h"
/* Although the following declaration isn't in any case useful
to a merchant's activity, it's needed here to make the function
'TMH_PARSE_nagivate_json ()' compile fine; so its value will be
kept on some merchant's accepted currency. For multi currencies
merchants, that of course would require a patch */
+extern char *TMH_merchant_currency_string;
-extern char *TMH_mint_currency_string;
/**
* Initial size for POST request buffer.
*/
@@ -145,6 +144,7 @@ buffer_append (struct Buffer *buf,
return GNUNET_OK;
}
+
/**
* Function called whenever we are done with a request
* to clean up our state.
@@ -164,6 +164,7 @@ TMH_PARSE_post_cleanup_callback (void *con_cls)
}
}
+
/**
* Release all memory allocated for the variable-size fields in
* the parser specification.
@@ -249,6 +250,7 @@ release_data (struct TMH_PARSE_FieldSpecification *spec,
}
}
+
/**
* Process a POST request containing a JSON object. This function
* realizes an MHD POST processor that will (incrementally) process
@@ -350,6 +352,7 @@ TMH_PARSE_post_json (struct MHD_Connection *connection,
return GNUNET_YES;
}
+
/**
* Generate line in parser specification for string. The returned
* string is already nul-terminated internally by JSON, so no length
@@ -634,7 +637,7 @@ TMH_PARSE_navigate_json (struct MHD_Connection *connection,
case TMH_PARSE_JNC_RET_STRING:
{
- void **where = va_arg (argp, void **);
+ void **where = va_arg (argp, void **);
*where = (void*) json_string_value (root);
ret = GNUNET_OK;
}
@@ -876,7 +879,7 @@ TMH_PARSE_navigate_json (struct MHD_Connection *connection,
break;
}
if (0 != strcmp (where->currency,
- TMH_mint_currency_string))
+ TMH_merchant_currency_string))
{
GNUNET_break_op (0);
ret = (MHD_YES !=
diff --git a/src/backend/taler-mint-httpd_parsing.h b/src/backend/taler-merchant-httpd_parsing.h
index dae65092..dae65092 100644
--- a/src/backend/taler-mint-httpd_parsing.h
+++ b/src/backend/taler-merchant-httpd_parsing.h
diff --git a/src/backend/taler-merchant-httpd_pay.c b/src/backend/taler-merchant-httpd_pay.c
index 1951d2d0..319a7001 100644
--- a/src/backend/taler-merchant-httpd_pay.c
+++ b/src/backend/taler-merchant-httpd_pay.c
@@ -14,81 +14,86 @@
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file merchant/backend/taler-merchant-httpd.c
- * @brief HTTP serving layer mainly intended to communicate with the frontend
+ * @file backend/taler-merchant-httpd_pay.c
+ * @brief handling of /pay requests
* @author Marcello Stanisci
+ * @author Christian Grothoff
*/
-
#include "platform.h"
-#include <microhttpd.h>
#include <jansson.h>
#include <gnunet/gnunet_util_lib.h>
-#include <curl/curl.h>
#include <taler/taler_signatures.h>
-#include <taler/taler_amount_lib.h>
#include <taler/taler_json_lib.h>
#include <taler/taler_mint_service.h>
#include "taler-merchant-httpd.h"
-#include "taler-mint-httpd.h"
-#include "taler-mint-httpd_parsing.h"
-#include "taler-mint-httpd_responses.h"
-#include "taler-mint-httpd_mhd.h"
-#include "merchant_db.h"
-#include "merchant.h"
-#include "taler_merchant_lib.h"
+#include "taler-merchant-httpd_parsing.h"
+#include "taler-merchant-httpd_responses.h"
+#include "taler-merchant-httpd_auditors.h"
+#include "taler-merchant-httpd_mints.h"
+#include "taler_merchantdb_lib.h"
+
+
+/**
+ * Information we keep for an individual call to the /pay handler.
+ */
+struct PayContext;
/**
- * Fetch the deposit fee related to the given coin aggregate.
- * @param connection the connection to send an error response to
- * @param coin_aggregate a coin "aggregate" is the JSON set of
- * values contained in a single cell of the 'coins' array sent
- * in a payment
- * @param deposit_fee where to store the resulting deposit fee
- * @param mint_index the index which points the chosen mint within
- * the global 'mints' array
- * @return GNUNET_OK if successful, GNUNET_NO if the data supplied
- * is invalid (including the case when the key is not found),
- * GNUNET_SYSERR upon internal errors
+ * Information kept during a /pay request for each coin.
*/
-static int
-deposit_fee_from_coin_aggregate (struct MHD_Connection *connection,
- json_t *coin_aggregate,
- struct TALER_Amount *deposit_fee,
- unsigned int mint_index)
+struct MERCHANT_DepositConfirmation
{
- int res;
- const struct TALER_MINT_Keys *keys;
- const struct TALER_MINT_DenomPublicKey *denom_details;
+
+ /**
+ * Reference to the main PayContext
+ */
+ struct PayContext *pc;
+
+ /**
+ * Handle to the deposit operation we are performing for
+ * this coin, NULL after the operation is done.
+ */
+ struct TALER_MINT_DepositHandle *dh;
+
+ /**
+ * Denomination of this coin.
+ */
struct TALER_DenominationPublicKey denom;
- struct TMH_PARSE_FieldSpecification spec[] = {
- TMH_PARSE_member_denomination_public_key ("denom_pub", &denom),
- TMH_PARSE_MEMBER_END
- };
-
- res = TMH_PARSE_json_data (connection,
- coin_aggregate,
- spec);
- if (GNUNET_OK != res)
- return res; /* may return GNUNET_NO */
-
- if (1 == mints[mint_index].pending)
- return GNUNET_SYSERR;
- keys = TALER_MINT_get_keys (mints[mint_index].conn);
- denom_details = TALER_MINT_get_denomination_key (keys, &denom);
- if (NULL == denom_details)
- {
- TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s, s:o}",
- "hint", "unknown denom to mint",
- "denom_pub", TALER_json_from_rsa_public_key (denom.rsa_public_key));
- return GNUNET_NO;
- }
- *deposit_fee = denom_details->fee_deposit;
- return GNUNET_OK;
-}
+ /**
+ * Amount "f" that this coin contributes to the overall payment.
+ * This amount includes the deposit fee.
+ */
+ struct TALER_Amount percoin_amount;
+
+ /**
+ * Amount this coin contributes to the total purchase price.
+ */
+ struct TALER_Amount amount_without_fee;
+
+ /**
+ * Public key of the coin.
+ */
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+
+ /**
+ * Signature using the @e denom key over the @e coin_pub.
+ */
+ struct TALER_DenominationSignature ub_sig;
+
+ /**
+ * Signature of the coin's private key over the contract.
+ */
+ struct TALER_CoinSpendSignatureP coin_sig;
+
+ /**
+ * Offset of this coin into the `dc` array of all coins in the
+ * @e pc.
+ */
+ unsigned int index;
+
+};
/**
@@ -103,7 +108,7 @@ struct PayContext
struct TM_HandlerContext hc;
/**
- * Pointer to the global (malloc'd) array of all coins outcomes
+ * Array with @e coins_cnt coins we are despositing.
*/
struct MERCHANT_DepositConfirmation *dc;
@@ -113,146 +118,452 @@ struct PayContext
struct MHD_Connection *connection;
/**
+ * Handle to the mint that we are doing the payment with.
+ * (initially NULL while @e fo is trying to find a mint).
+ */
+ struct TALER_MINT_Handle *mh;
+
+ /**
+ * Handle for operation to lookup /keys (and auditors) from
+ * the mint used for this transaction; NULL if no operation is
+ * pending.
+ */
+ struct TMH_MINTS_FindOperation *fo;
+
+ /**
* Placeholder for #TMH_PARSE_post_json() to keep its internal state.
*/
void *json_parse_context;
/**
- * Response to return, NULL if we don't have one yet.
+ * Mint URI given in @e root.
*/
- struct MHD_Response *response;
+ char *chosen_mint;
/**
- * Transaction id
+ * Transaction ID given in @e root.
*/
uint64_t transaction_id;
/**
- * How many coins this paymen is made of.
+ * Maximum fee the merchant is willing to pay, from @e root.
+ * Note that IF the total fee of the mint is higher, that is
+ * acceptable to the merchant if the customer is willing to
+ * pay the difference (i.e. amount - max_fee <= actual-amount - actual-fee).
+ */
+ struct TALER_Amount max_fee;
+
+ /**
+ * Amount from @e root. This is the amount the merchant expects
+ * to make, minus @e max_fee.
+ */
+ struct TALER_Amount amount;
+
+ /**
+ * Timestamp from @e root.
+ */
+ struct GNUNET_TIME_Absolute timestamp;
+
+ /**
+ * Refund deadline from @e root.
+ */
+ struct GNUNET_TIME_Absolute refund_deadline;
+
+ /**
+ * "H_contract" from @e root.
+ */
+ struct GNUNET_HashCode h_contract;
+
+ /**
+ * Execution date. How soon would the merchant like the
+ * transaction to be executed? (Can be given by the frontend
+ * or be determined by our configuration via #edate_delay.)
+ */
+ struct GNUNET_TIME_Absolute edate;
+
+ /**
+ * Response to return, NULL if we don't have one yet.
+ */
+ struct MHD_Response *response;
+
+ /**
+ * Number of coins this payment is made of. Length
+ * of the @e dc array.
*/
unsigned int coins_cnt;
/**
+ * Number of transactions still pending. Initially set to
+ * @e coins_cnt, decremented on each transaction that
+ * successfully finished.
+ */
+ unsigned int pending;
+
+ /**
* HTTP status code to use for the reply, i.e 200 for "OK".
* Special value UINT_MAX is used to indicate hard errors
- * (no reply, return MHD_NO).
+ * (no reply, return #MHD_NO).
*/
unsigned int response_code;
};
+
/**
- * Information needed by a single /deposit callback to refer to its
- * own coin inside the confirmations array, namely `struct MERCHANT_DepositConfirmation *dc`
- * above. Note: this information can NOT be shared between all the callbacks.
+ * Resume the given pay context and send the given response.
+ * Stores the response in the @a pc and signals MHD to resume
+ * the connection. Also ensures MHD runs immediately.
+ *
+ * @param pc payment context
+ * @param response_code response code to use
+ * @param response response data to send back
*/
-struct DepositCallbackContext
+static void
+resume_pay_with_response (struct PayContext *pc,
+ unsigned int response_code,
+ struct MHD_Response *response)
{
+ pc->response_code = response_code;
+ pc->response = response;
+ MHD_resume_connection (pc->connection);
+ TMH_trigger_daemon (); /* we resumed, kick MHD */
+}
- /**
- * Offset of this coin into the array of all coins outcomes
- */
- unsigned int index;
- /**
- * Reference to the main PayContext
- */
- struct PayContext *pc;
+/**
+ * Abort all pending /deposit operations.
+ *
+ * @param pc pay context to abort
+ */
+static void
+abort_deposit (struct PayContext *pc)
+{
+ unsigned int i;
+
+ for (i=0;i<pc->coins_cnt;i++)
+ {
+ struct MERCHANT_DepositConfirmation *dci = &pc->dc[i];
+
+ if (NULL != dci->dh)
+ {
+ TALER_MINT_deposit_cancel (dci->dh);
+ dci->dh = NULL;
+ }
+ }
+}
-};
/**
* Callback to handle a deposit permission's response.
*
- * @param cls see `struct MERCHANT_DepositConfirmationCls` (i.e. a poinetr to the global
- * array of confirmations and an index for this call in that array). That way, the last
- * executed callback can detect that no other confirmations are on the way, and can pack
- * a response for the wallet
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit;
- * 0 if the mint's reply is bogus (fails to follow the protocol)
- * @param proof the received JSON reply, should be kept as proof (and, in case of errors,
- * be forwarded to the customer)
+ * @param cls a `struct MERCHANT_DepositConfirmation` (i.e. a pointer
+ * into the global array of confirmations and an index for this call
+ * in that array). That way, the last executed callback can detect
+ * that no other confirmations are on the way, and can pack a response
+ * for the wallet
+ * @param http_status HTTP response code, #MHD_HTTP_OK
+ * (200) for successful deposit; 0 if the mint's reply is bogus (fails
+ * to follow the protocol)
+ * @param proof the received JSON reply,
+ * should be kept as proof (and, in case of errors, be forwarded to
+ * the customer)
*/
static void
deposit_cb (void *cls,
unsigned int http_status,
json_t *proof)
{
- struct DepositCallbackContext *dcc = cls;
- int i;
-
- /*FIXME the index is the same for every individual cb */
- if (GNUNET_SYSERR ==
- MERCHANT_DB_update_deposit_permission (db_conn,
- dcc->pc->transaction_id,
- 0))
- /* TODO */
- printf ("db error\n");
- dcc->pc->dc[dcc->index].ackd = 1;
- dcc->pc->dc[dcc->index].exit_status = http_status;
- dcc->pc->dc[dcc->index].proof = proof;
-
- /* loop through the confirmation array and return accordingly */
- for (i = 0; i < dcc->pc->coins_cnt; i++)
+ struct MERCHANT_DepositConfirmation *dc = cls;
+ struct PayContext *pc = dc->pc;
+
+ dc->dh = NULL;
+ pc->pending--;
+ if (MHD_HTTP_OK != http_status)
{
- /* just return if there is at least one coin to be still
- confirmed */
- if (! dcc->pc->dc[i].ackd)
- {
- printf ("still vacant coins\n");
- return;
- }
+ /* Transaction failed; stop all other ongoing deposits */
+ abort_deposit (pc);
+ /* Forward error including 'proof' for the body */
+ resume_pay_with_response (pc,
+ http_status,
+ TMH_RESPONSE_make_json (proof));
+ return;
}
-
- printf ("All /deposit(s) ack'd\n");
-
- dcc->pc->response = MHD_create_response_from_buffer (strlen ("All coins ack'd by the mint\n"),
- "All coins ack'd by the mint\n",
- MHD_RESPMEM_MUST_COPY);
- dcc->pc->response_code = MHD_HTTP_OK;
- /* Clean up what we can already */
- MHD_resume_connection (dcc->pc->connection);
- TM_trigger_daemon (); /* we resumed, kick MHD */
+ /* store result to DB */
+ if (GNUNET_OK !=
+ db->store_payment (db->cls,
+ &pc->h_contract,
+ &h_wire,
+ pc->transaction_id,
+ pc->timestamp,
+ pc->refund_deadline,
+ &dc->amount_without_fee,
+ &dc->coin_pub,
+ proof))
+ {
+ /* internal error */
+ abort_deposit (pc);
+ /* Forward error including 'proof' for the body */
+ resume_pay_with_response (pc,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TMH_RESPONSE_make_internal_error ("Merchant database error"));
+ return;
+ }
+ if (0 != pc->pending)
+ return; /* still more to do */
+ resume_pay_with_response (pc,
+ MHD_HTTP_OK,
+ MHD_create_response_from_buffer (0,
+ NULL,
+ MHD_RESPMEM_PERSISTENT));
}
+/**
+ * Custom cleanup routine for a `struct PayContext`.
+ *
+ * @param hc the `struct PayContext` to clean up.
+ */
static void
pay_context_cleanup (struct TM_HandlerContext *hc)
{
- int i;
struct PayContext *pc = (struct PayContext *) hc;
-
- for (i = 0; i < pc->coins_cnt; i++)
- GNUNET_free_non_null (pc->dc[i].dcc);
+ unsigned int i;
TMH_PARSE_post_cleanup_callback (pc->json_parse_context);
+ for (i=0;i<pc->coins_cnt;i++)
+ {
+ struct MERCHANT_DepositConfirmation *dc = &pc->dc[i];
- #if 0
+ if (NULL != dc->dh)
+ {
+ TALER_MINT_deposit_cancel (dc->dh);
+ dc->dh = NULL;
+ }
+ if (NULL != dc->denom.rsa_public_key)
+ {
+ GNUNET_CRYPTO_rsa_public_key_free (dc->denom.rsa_public_key);
+ dc->denom.rsa_public_key = NULL;
+ }
+ if (NULL != dc->ub_sig.rsa_signature)
+ {
+ GNUNET_CRYPTO_rsa_signature_free (dc->ub_sig.rsa_signature);
+ dc->ub_sig.rsa_signature = NULL;
+ }
+ }
+ GNUNET_free_non_null (pc->dc);
+ if (NULL != pc->fo)
+ {
+ TMH_MINTS_find_mint_cancel (pc->fo);
+ pc->fo = NULL;
+ }
if (NULL != pc->response)
{
- /* undestroyable regardless of the other MHD_destroy_response called
- in this source, FIXME */
-
MHD_destroy_response (pc->response);
pc->response = NULL;
}
- #endif
-
- GNUNET_free_non_null (pc->dc);
GNUNET_free (pc);
}
/**
+ * Function called with the result of our mint lookup.
+ *
+ * @param cls the `struct PayContext`
+ * @param mh NULL if mint was not found to be acceptable
+ * @param mint_trusted #GNUNET_YES if this mint is trusted by config
+ */
+static void
+process_pay_with_mint (void *cls,
+ struct TALER_MINT_Handle *mh,
+ int mint_trusted)
+{
+ struct PayContext *pc = cls;
+ struct TALER_Amount acc_fee;
+ struct TALER_Amount acc_amount;
+ const struct TALER_MINT_Keys *keys;
+ unsigned int i;
+
+ pc->fo = NULL;
+ if (NULL == mh)
+ {
+ /* The mint on offer is not in the set of our (trusted)
+ mints. Reject the payment. */
+ GNUNET_break_op (0);
+ resume_pay_with_response (pc,
+ MHD_HTTP_PRECONDITION_FAILED,
+ TMH_RESPONSE_make_external_error ("mint not supported"));
+ return;
+ }
+ pc->mh = mh;
+
+ keys = TALER_MINT_get_keys (mh);
+ if (NULL == keys)
+ {
+ GNUNET_break (0);
+ resume_pay_with_response (pc,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TMH_RESPONSE_make_internal_error ("no keys"));
+ return;
+ }
+
+ /* Total up the fees and the value of the deposited coins! */
+ for (i=0;i<pc->coins_cnt;i++)
+ {
+ struct MERCHANT_DepositConfirmation *dc = &pc->dc[i];
+ const struct TALER_MINT_DenomPublicKey *denom_details;
+
+ denom_details = TALER_MINT_get_denomination_key (keys,
+ &dc->denom);
+ if (NULL == denom_details)
+ {
+ resume_pay_with_response (pc,
+ MHD_HTTP_BAD_REQUEST,
+ TMH_RESPONSE_make_json_pack ("{s:s, s:o}",
+ "hint", "unknown denom to mint",
+ "denom_pub", TALER_json_from_rsa_public_key (dc->denom.rsa_public_key)));
+ return;
+ }
+ if (GNUNET_OK !=
+ TMH_AUDITORS_check_dk (mh,
+ denom_details,
+ mint_trusted))
+ {
+ resume_pay_with_response (pc,
+ MHD_HTTP_BAD_REQUEST,
+ TMH_RESPONSE_make_json_pack ("{s:s, s:o}",
+ "hint", "no acceptable auditor for denomination",
+ "denom_pub", TALER_json_from_rsa_public_key (dc->denom.rsa_public_key)));
+ return;
+ }
+ if (0 == i)
+ {
+ acc_fee = denom_details->fee_deposit;
+ acc_amount = dc->percoin_amount;
+ }
+ else
+ {
+ if ( (GNUNET_OK !=
+ TALER_amount_add (&acc_fee,
+ &denom_details->fee_deposit,
+ &acc_fee)) ||
+ (GNUNET_OK !=
+ TALER_amount_add (&acc_amount,
+ &dc->percoin_amount,
+ &acc_amount)) )
+ {
+ GNUNET_break_op (0);
+ /* Overflow in these amounts? Very strange. */
+ resume_pay_with_response (pc,
+ MHD_HTTP_BAD_REQUEST,
+ TMH_RESPONSE_make_internal_error ("Overflow adding up amounts"));
+ return;
+ }
+ }
+ if (GNUNET_SYSERR ==
+ TALER_amount_subtract (&dc->amount_without_fee,
+ &dc->percoin_amount,
+ &denom_details->fee_deposit))
+ {
+ GNUNET_break_op (0);
+ /* fee higher than residual coin value, makes no sense. */
+ resume_pay_with_response (pc,
+ MHD_HTTP_BAD_REQUEST,
+ TMH_RESPONSE_make_internal_error ("Fee higher than coin value"));
+ return;
+ }
+ }
+
+ /* Now check that the customer paid enough for the full contract */
+ if (-1 == TALER_amount_cmp (&pc->max_fee,
+ &acc_fee))
+ {
+ /* acc_fee > max_fee, customer needs to cover difference */
+ struct TALER_Amount excess_fee;
+ struct TALER_Amount total_needed;
+
+ /* compute fee amount to be covered by customer */
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_subtract (&excess_fee,
+ &acc_fee,
+ &pc->max_fee));
+ /* add that to the total */
+ if (GNUNET_OK !=
+ TALER_amount_add (&total_needed,
+ &excess_fee,
+ &pc->amount))
+ {
+ GNUNET_break (0);
+ resume_pay_with_response (pc,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TMH_RESPONSE_make_internal_error ("overflow"));
+ return;
+ }
+ /* check if total payment sufficies */
+ if (-1 == TALER_amount_cmp (&acc_amount,
+ &total_needed))
+ {
+ resume_pay_with_response (pc,
+ MHD_HTTP_NOT_ACCEPTABLE,
+ TMH_RESPONSE_make_external_error ("insufficient funds (including excessive mint fees to be covered by customer)"));
+ return;
+ }
+ }
+ else
+ {
+ /* fees are acceptable, we cover them all; let's check the amount */
+ if (-1 == TALER_amount_cmp (&acc_amount,
+ &pc->amount))
+ {
+ resume_pay_with_response (pc,
+ MHD_HTTP_NOT_ACCEPTABLE,
+ TMH_RESPONSE_make_external_error ("insufficient funds"));
+ return;
+ }
+ }
+
+ /* Initiate /deposit operation for all coins */
+ for (i=0;i<pc->coins_cnt;i++)
+ {
+ struct MERCHANT_DepositConfirmation *dc = &pc->dc[i];
+
+ dc->dh = TALER_MINT_deposit (mh,
+ &dc->percoin_amount,
+ pc->edate,
+ j_wire,
+ &pc->h_contract,
+ &dc->coin_pub,
+ &dc->ub_sig,
+ &dc->denom,
+ pc->timestamp,
+ pc->transaction_id,
+ &pubkey,
+ pc->refund_deadline,
+ &dc->coin_sig,
+ &deposit_cb,
+ dc);
+ if (NULL == dc->dh)
+ {
+ resume_pay_with_response (pc,
+ MHD_HTTP_SERVICE_UNAVAILABLE,
+ TMH_RESPONSE_make_json_pack ("{s:s, s:i}",
+ "mint", pc->chosen_mint,
+ "transaction_id", pc->transaction_id));
+ return;
+ }
+ }
+}
+
+
+/**
* Accomplish this payment.
*
* @param rh context of the handler
* @param connection the MHD connection to handle
* @param[in,out] connection_cls the connection's closure
- * (can be updated)
+ * (can be updated)
* @param upload_data upload data
* @param[in,out] upload_data_size number of bytes (left) in @a
- * upload_data
+ * upload_data
* @return MHD result code
*/
int
@@ -263,53 +574,8 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
size_t *upload_data_size)
{
struct PayContext *pc;
- json_t *root;
- json_t *coins;
- char *chosen_mint;
- json_t *coin_aggregate;
- json_t *wire_details;
- unsigned int mint_index; /*a cell in the global array*/
- unsigned int coins_index;
- unsigned int coins_cnt;
- uint64_t transaction_id;
int res;
- struct TALER_MINT_DepositHandle *dh;
- struct TALER_Amount max_fee;
- struct TALER_Amount acc_fee;
- struct TALER_Amount coin_fee;
- struct TALER_Amount amount;
- struct TALER_Amount percoin_amount;
- struct GNUNET_TIME_Absolute edate;
- struct GNUNET_TIME_Absolute timestamp;
- struct GNUNET_TIME_Absolute refund_deadline;
- struct TALER_MerchantPublicKeyP pubkey;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- struct TALER_DenominationPublicKey denom_pub;
- struct TALER_DenominationSignature ub_sig;
- struct TALER_CoinSpendSignatureP coin_sig;
- struct GNUNET_HashCode h_contract;
- struct MERCHANT_DepositConfirmation *dc;
-
- struct TMH_PARSE_FieldSpecification spec[] = {
- TMH_PARSE_member_array ("coins", &coins),
- TMH_PARSE_member_string ("mint", &chosen_mint),
- TMH_PARSE_member_amount ("max_fee", &max_fee),
- TMH_PARSE_member_amount ("amount", &amount),
- TMH_PARSE_member_time_abs ("timestamp", &timestamp),
- TMH_PARSE_member_time_abs ("refund_deadline", &refund_deadline),
- TMH_PARSE_member_uint64 ("transaction_id", &transaction_id),
- TMH_PARSE_member_fixed ("H_contract", &h_contract),
- TMH_PARSE_MEMBER_END
- };
-
- struct TMH_PARSE_FieldSpecification coin_aggregate_spec[] = {
- TMH_PARSE_member_amount ("f", &percoin_amount),
- TMH_PARSE_member_fixed ("coin_pub", &coin_pub.eddsa_pub),
- TMH_PARSE_member_denomination_public_key ("denom_pub", &denom_pub),
- TMH_PARSE_member_denomination_signature ("ub_sig", &ub_sig),
- TMH_PARSE_member_fixed ("coin_sig", &coin_sig.eddsa_signature),
- TMH_PARSE_MEMBER_END
- };
+ json_t *root;
if (NULL == *connection_cls)
{
@@ -325,21 +591,17 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
}
if (0 != pc->response_code)
{
+ /* We are *done* processing the request, just queue the response (!) */
if (UINT_MAX == pc->response_code)
return MHD_NO; /* hard error */
- /* We are *done* processing the request, just queue the response (!) */
res = MHD_queue_response (connection,
pc->response_code,
pc->response);
- #if 0
- if (pc->response != NULL)
+ if (NULL != pc->response)
{
- /* undestroyable regardless of the other MHD_destroy_response called
- in this source, FIXME */
MHD_destroy_response (pc->response);
pc->response = NULL;
}
- #endif
return res;
}
@@ -349,201 +611,109 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
upload_data_size,
&root);
if (GNUNET_SYSERR == res)
- return MHD_NO;
- /* the POST's body has to be further fetched */
+ return MHD_NO; /* error parsing JSON */
if ((GNUNET_NO == res) || (NULL == root))
- return MHD_YES;
-
- res = TMH_PARSE_json_data (connection,
- root,
- spec);
-
- if (GNUNET_YES != res)
- return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
-
- /* 1 Check if the chosen mint is among the merchant's preferred.
-
- An error in this case could be due to:
-
- * the wallet indicated a non existent mint
- * the wallet indicated a non trusted mint
+ return MHD_YES; /* the POST's body has to be further fetched */
- NOTE: by preventively checking this, the merchant
- avoids getting HTTP response codes from random
- websites that may mislead the wallet in the way
- of managing the error. Of course, that protect the
- merchant from POSTing coins to untrusted mints.
-
- */
-
- for (mint_index = 0; mint_index <= nmints; mint_index++)
+ /* Got the JSON upload, parse it */
{
- /* no mint found in array */
- if (mint_index == nmints)
+ json_t *coins;
+ json_t *coin;
+ unsigned int coins_index;
+ struct TMH_PARSE_FieldSpecification spec[] = {
+ TMH_PARSE_member_array ("coins", &coins),
+ TMH_PARSE_member_string ("mint", &pc->chosen_mint),
+ TMH_PARSE_member_uint64 ("transaction_id", &pc->transaction_id),
+ TMH_PARSE_member_amount ("max_fee", &pc->max_fee),
+ TMH_PARSE_member_amount ("amount", &pc->amount),
+ TMH_PARSE_member_time_abs ("timestamp", &pc->timestamp),
+ TMH_PARSE_member_time_abs ("refund_deadline", &pc->refund_deadline),
+ TMH_PARSE_member_fixed ("H_contract", &pc->h_contract),
+ TMH_PARSE_MEMBER_END
+ };
+
+ res = TMH_PARSE_json_data (connection,
+ root,
+ spec);
+ if (GNUNET_YES != res)
{
- mint_index = -1;
- break;
+ json_decref (root);
+ return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
}
- /* test it by checking public key */
- if (0 == strcmp (mints[mint_index].hostname,
- chosen_mint))
- break;
-
- }
-
- if (-1 == mint_index)
- return TMH_RESPONSE_reply_external_error (connection, "unknown mint");
-
- /* no 'edate' from frontend. Generate it here; it will be timestamp
- + a edate delay supplied in config file */
- if (NULL == json_object_get (root, "edate"))
- {
- edate = GNUNET_TIME_absolute_add (timestamp, edate_delay);
- if (-1 == json_object_set (root, "edate", TALER_json_from_abs (edate)))
- return MHD_NO;
- }
-
- coins_cnt = json_array_size (coins);
-
- if (0 == coins_cnt)
- return TMH_RESPONSE_reply_external_error (connection, "no coins given");
-
- json_array_foreach (coins, coins_index, coin_aggregate)
- {
- res = deposit_fee_from_coin_aggregate (connection,
- coin_aggregate,
- &coin_fee,
- mint_index);
- if (GNUNET_NO == res)
- return MHD_YES;
- if (GNUNET_SYSERR == res)
- return MHD_NO;
-
- if (0 == coins_index)
- acc_fee = coin_fee;
+ /* 'edate' is optional, if it is not present, generate it here; it
+ will be timestamp plus the edate_delay supplied in config
+ file */
+ if (NULL == json_object_get (root, "edate"))
+ {
+ pc->edate = GNUNET_TIME_absolute_add (pc->timestamp,
+ edate_delay);
+ }
else
- TALER_amount_add (&acc_fee,
- &acc_fee,
- &coin_fee);
- }
-
-
- if (-1 == TALER_amount_cmp (&max_fee, &acc_fee))
- return MHD_HTTP_NOT_ACCEPTABLE;
-
- /* cutting off unneeded fields from deposit permission as
- gotten from the wallet */
- if (-1 == json_object_del (root, "mint"))
- return TMH_RESPONSE_reply_external_error (connection,
- "malformed/non-existent 'mint' field");
- if (-1 == json_object_del (root, "coins"))
- return TMH_RESPONSE_reply_external_error (connection,
- "malformed/non-existent 'coins' field");
-
- /* adding our public key to deposit permission */
- GNUNET_CRYPTO_eddsa_key_get_public (privkey, &pubkey.eddsa_pub);
- json_object_set_new (root,
- "merchant_pub",
- TALER_json_from_data (&pubkey, sizeof (pubkey)));
-
- wire_details = MERCHANT_get_wire_json (wire, salt);
- /* since memory is zero'd out by GNUNET_malloc, any 'ackd' field will be
- (implicitly) set to false */
- dc = GNUNET_malloc (coins_cnt * sizeof (struct MERCHANT_DepositConfirmation));
- if (NULL == dc)
- return TMH_RESPONSE_reply_internal_error (connection, "memory failure");
-
- /* DEBUG CHECKPOINT: return a provisory fullfilment page to the wallet
- to test the reception of coins array */
-
- #ifdef COINSCHECKPOINT
- rh->data = "Coins received\n";
- return TMH_MHD_handler_static_response (rh,
- connection,
- connection_cls,
- upload_data,
- upload_data_size);
-
- #endif
-
- /* suspend connection until the last coin has been ack'd to the cb.
- That last cb will finally resume the connection and send back a response */
- MHD_suspend_connection (connection);
-
- pc->dc = dc;
- pc->coins_cnt = coins_cnt;
- pc->transaction_id = transaction_id;
+ {
+ struct TMH_PARSE_FieldSpecification espec[] = {
+ TMH_PARSE_member_time_abs ("edate", &pc->edate),
+ TMH_PARSE_MEMBER_END
+ };
+
+ res = TMH_PARSE_json_data (connection,
+ root,
+ espec);
+ if (GNUNET_YES != res)
+ {
+ json_decref (root);
+ return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+ }
+ }
- json_array_foreach (coins, coins_index, coin_aggregate)
- {
+ pc->coins_cnt = json_array_size (coins);
+ if (0 == pc->coins_cnt)
+ {
+ json_decref (root);
+ return TMH_RESPONSE_reply_external_error (connection,
+ "no coins given");
+ }
+ /* note: 1 coin = 1 deposit confirmation expected */
+ pc->dc = GNUNET_new_array (pc->coins_cnt,
+ struct MERCHANT_DepositConfirmation);
- /* 3 For each coin in DB
-
- a. Generate a deposit permission
- b. store it in DB
- c. POST to the mint (see mint-lib for this)
- (retry until getting a persisten state)
- */
-
- /* a */
- if (-1 == json_object_update (root, coin_aggregate))
- return TMH_RESPONSE_reply_internal_error (connection,
- "deposit permission not generated for storing");
-
- /* b */
- char *deposit_permission_str = json_dumps (root, JSON_COMPACT);
- if (GNUNET_OK != MERCHANT_DB_store_deposit_permission (db_conn,
- deposit_permission_str,
- transaction_id,
- 1,
- mints[mint_index].hostname))
- return TMH_RESPONSE_reply_internal_error (connection, "internal DB failure");
- res = TMH_PARSE_json_data (connection,
- coin_aggregate,
- coin_aggregate_spec);
- if (GNUNET_OK != res)
- return res; /* may return GNUNET_NO */
-
- /* c */
- struct DepositCallbackContext *percoin_dcc = GNUNET_new (struct DepositCallbackContext);
- pc->dc[coins_index].dcc = percoin_dcc;
- percoin_dcc->index = coins_index;
- percoin_dcc->pc = pc;
-
- dh = TALER_MINT_deposit (mints[mint_index].conn,
- &percoin_amount,
- edate,
- wire_details,
- &h_contract,
- &coin_pub,
- &ub_sig,
- &denom_pub,
- timestamp,
- transaction_id,
- &pubkey,
- refund_deadline,
- &coin_sig,
- &deposit_cb,
- percoin_dcc); /*FIXME TODO instantiate an individual cls for each
- cb: each of them needs an index which points the
- array of all the confirmations */
- if (NULL == dh)
+ json_array_foreach (coins, coins_index, coin)
{
- MHD_resume_connection (connection);
- return TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_SERVICE_UNAVAILABLE,
- "{s:s, s:i}",
- "mint", mints[mint_index].hostname,
- "transaction_id", transaction_id);
+ struct MERCHANT_DepositConfirmation *dc = &pc->dc[coins_index];
+ struct TMH_PARSE_FieldSpecification spec[] = {
+ TMH_PARSE_member_denomination_public_key ("denom_pub", &dc->denom),
+ TMH_PARSE_member_amount ("f", &dc->percoin_amount),
+ TMH_PARSE_member_fixed ("coin_pub", &dc->coin_pub),
+ TMH_PARSE_member_denomination_signature ("ub_sig", &dc->ub_sig),
+ TMH_PARSE_member_fixed ("coin_sig", &dc->coin_sig),
+ TMH_PARSE_MEMBER_END
+ };
+
+ res = TMH_PARSE_json_data (connection,
+ coin,
+ spec);
+ if (GNUNET_YES != res)
+ {
+ json_decref (root);
+ return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+ }
+ dc->index = coins_index;
+ dc->pc = pc;
}
}
- GNUNET_SCHEDULER_cancel (poller_task);
- GNUNET_SCHEDULER_add_now (context_task, mints[mint_index].ctx);
- return MHD_YES;
+ /* Find the responsible mint, this may take a while... */
+ pc->pending = pc->coins_cnt;
+ pc->fo = TMH_MINTS_find_mint (pc->chosen_mint,
+ &process_pay_with_mint,
+ pc);
- /* 4 Return response code: success, or whatever data the
- mint sent back regarding some bad coin */
+ /* ... so we suspend connection until the last coin has been ack'd
+ or until we have encountered a hard error. Eventually, we will
+ resume the connection and send back a response using
+ #resume_pay_with_response(). */
+ MHD_suspend_connection (connection);
+ json_decref (root);
+ return MHD_YES;
}
diff --git a/src/backend/taler-merchant-httpd_pay.h b/src/backend/taler-merchant-httpd_pay.h
index 6a796e06..0836f9ba 100644
--- a/src/backend/taler-merchant-httpd_pay.h
+++ b/src/backend/taler-merchant-httpd_pay.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2014 Christian Grothoff (and other contributing authors)
+ (C) 2014, 2015 Christian Grothoff (and other contributing authors)
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -13,17 +13,16 @@
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
*/
-
/**
- * @file merchant/backend/taler-merchant-httpd_contract.h
+ * @file backend/taler-merchant-httpd_pay.h
* @brief headers for /pay handler
* @author Marcello Stanisci
*/
-
#ifndef TALER_MINT_HTTPD_PAY_H
#define TALER_MINT_HTTPD_PAY_H
#include <microhttpd.h>
-#include "taler-mint-httpd.h"
+#include "taler-merchant-httpd.h"
+
/**
* Manage a payment
@@ -33,7 +32,6 @@
* @param[in,out] connection_cls the connection's closure (can be updated)
* @param upload_data upload data
* @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- *
* @return MHD result code
*/
int
diff --git a/src/backend/taler-mint-httpd_responses.c b/src/backend/taler-merchant-httpd_responses.c
index 00a4d25f..d8ba1170 100644
--- a/src/backend/taler-mint-httpd_responses.c
+++ b/src/backend/taler-merchant-httpd_responses.c
@@ -14,7 +14,7 @@
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file taler-mint-httpd_responses.c
+ * @file taler-merchant-httpd_responses.c
* @brief API for generating the various replies of the mint; these
* functions are called TMH_RESPONSE_reply_ and they generate
* and queue MHD response objects for a given connection.
@@ -23,27 +23,22 @@
* @author Christian Grothoff
*/
#include "platform.h"
-#include "taler-mint-httpd_responses.h"
+#include "taler-merchant-httpd_responses.h"
#include <taler/taler_util.h>
#include <gnunet/gnunet_util_lib.h>
/**
- * Send JSON object as response.
+ * Make JSON response object.
*
- * @param connection the MHD connection
* @param json the json object
- * @param response_code the http response code
- * @return MHD result code
+ * @return MHD response object
*/
-int
-TMH_RESPONSE_reply_json (struct MHD_Connection *connection,
- const json_t *json,
- unsigned int response_code)
+struct MHD_Response *
+TMH_RESPONSE_make_json (const json_t *json)
{
struct MHD_Response *resp;
char *json_str;
- int ret;
json_str = json_dumps (json, JSON_INDENT(2));
GNUNET_assert (NULL != json_str);
@@ -53,11 +48,34 @@ TMH_RESPONSE_reply_json (struct MHD_Connection *connection,
{
free (json_str);
GNUNET_break (0);
- return MHD_NO;
+ return NULL;
}
(void) MHD_add_response_header (resp,
MHD_HTTP_HEADER_CONTENT_TYPE,
"application/json");
+ return resp;
+}
+
+
+/**
+ * Send JSON object as response.
+ *
+ * @param connection the MHD connection
+ * @param json the json object
+ * @param response_code the http response code
+ * @return MHD result code
+ */
+int
+TMH_RESPONSE_reply_json (struct MHD_Connection *connection,
+ const json_t *json,
+ unsigned int response_code)
+{
+ struct MHD_Response *resp;
+ int ret;
+
+ resp = TMH_RESPONSE_make_json (json);
+ if (NULL == resp)
+ return MHD_NO;
ret = MHD_queue_response (connection,
response_code,
resp);
@@ -67,6 +85,40 @@ TMH_RESPONSE_reply_json (struct MHD_Connection *connection,
/**
+ * Make JSON response object.
+ *
+ * @param fmt format string for pack
+ * @param ... varargs
+ * @return MHD response object
+ */
+struct MHD_Response *
+TMH_RESPONSE_make_json_pack (const char *fmt,
+ ...)
+{
+ json_t *json;
+ va_list argp;
+ struct MHD_Response *ret;
+ json_error_t jerror;
+
+ va_start (argp, fmt);
+ json = json_vpack_ex (&jerror, 0, fmt, argp);
+ va_end (argp);
+ if (NULL == json)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to pack JSON with format `%s': %s\n",
+ fmt,
+ jerror.text);
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+ ret = TMH_RESPONSE_make_json (json);
+ json_decref (json);
+ return ret;
+}
+
+
+/**
* Function to call to handle the request by building a JSON
* reply from a format string and varargs.
*
@@ -106,6 +158,22 @@ TMH_RESPONSE_reply_json_pack (struct MHD_Connection *connection,
return ret;
}
+
+/**
+ * Create a response indicating an internal error.
+ *
+ * @param hint hint about the internal error's nature
+ * @return a MHD response object
+ */
+struct MHD_Response *
+TMH_RESPONSE_make_internal_error (const char *hint)
+{
+ return TMH_RESPONSE_make_json_pack ("{s:s, s:s}",
+ "error", "internal error",
+ "hint", hint);
+}
+
+
/**
* Send a response indicating an internal error.
*
@@ -124,6 +192,7 @@ TMH_RESPONSE_reply_internal_error (struct MHD_Connection *connection,
"hint", hint);
}
+
/**
* Send a response indicating that the request was too big.
*
@@ -186,6 +255,7 @@ TMH_RESPONSE_add_global_headers (struct MHD_Response *response)
"close");
}
+
/**
* Send a response indicating an external error.
*
@@ -203,4 +273,21 @@ TMH_RESPONSE_reply_external_error (struct MHD_Connection *connection,
"error", "client error",
"hint", hint);
}
+
+
+/**
+ * Create a response indicating an external error.
+ *
+ * @param hint hint about the internal error's nature
+ * @return a MHD response object
+ */
+struct MHD_Response *
+TMH_RESPONSE_make_external_error (const char *hint)
+{
+ return TMH_RESPONSE_make_json_pack ("{s:s, s:s}",
+ "error", "client error",
+ "hint", hint);
+}
+
+
/* end of taler-mint-httpd_responses.c */
diff --git a/src/backend/taler-mint-httpd_responses.h b/src/backend/taler-merchant-httpd_responses.h
index f947bd57..7240d601 100644
--- a/src/backend/taler-mint-httpd_responses.h
+++ b/src/backend/taler-merchant-httpd_responses.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014 GNUnet e.V.
+ Copyright (C) 2014, 2015 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
@@ -15,7 +15,7 @@
*/
/**
- * @file taler-mint-httpd_responses.h
+ * @file taler-merchant-httpd_responses.h
* @brief API for generating the various replies of the mint; these
* functions are called TMH_RESPONSE_reply_ and they generate
* and queue MHD response objects for a given connection.
@@ -31,6 +31,16 @@
#include <pthread.h>
/**
+ * Make JSON response object.
+ *
+ * @param json the json object
+ * @return MHD response object
+ */
+struct MHD_Response *
+TMH_RESPONSE_make_json (const json_t *json);
+
+
+/**
* Send JSON object as response.
*
* @param connection the MHD connection
@@ -45,6 +55,18 @@ TMH_RESPONSE_reply_json (struct MHD_Connection *connection,
/**
+ * Make JSON response object.
+ *
+ * @param fmt format string for pack
+ * @param ... varargs
+ * @return MHD response object
+ */
+struct MHD_Response *
+TMH_RESPONSE_make_json_pack (const char *fmt,
+ ...);
+
+
+/**
* Function to call to handle the request by building a JSON
* reply from a format string and varargs.
*
@@ -70,6 +92,7 @@ TMH_RESPONSE_reply_json_pack (struct MHD_Connection *connection,
int
TMH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection);
+
/**
* Send a response indicating an internal error.
*
@@ -80,6 +103,18 @@ TMH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection);
int
TMH_RESPONSE_reply_internal_error (struct MHD_Connection *connection,
const char *hint);
+
+
+/**
+ * Create a response indicating an internal error.
+ *
+ * @param hint hint about the internal error's nature
+ * @return a MHD response object
+ */
+struct MHD_Response *
+TMH_RESPONSE_make_internal_error (const char *hint);
+
+
/**
* Send a response indicating an external error.
*
@@ -90,6 +125,18 @@ TMH_RESPONSE_reply_internal_error (struct MHD_Connection *connection,
int
TMH_RESPONSE_reply_external_error (struct MHD_Connection *connection,
const char *hint);
+
+
+/**
+ * Create a response indicating an external error.
+ *
+ * @param hint hint about the internal error's nature
+ * @return a MHD response object
+ */
+struct MHD_Response *
+TMH_RESPONSE_make_external_error (const char *hint);
+
+
/**
* Send a response indicating that the request was too big.
*
@@ -99,6 +146,7 @@ TMH_RESPONSE_reply_external_error (struct MHD_Connection *connection,
int
TMH_RESPONSE_reply_request_too_large (struct MHD_Connection *connection);
+
/**
* Add headers we want to return in every response.
* Useful for testing, like if we want to always close
diff --git a/src/backend/taler-mint-httpd.h b/src/backend/taler-mint-httpd.h
deleted file mode 100644
index ad8702f0..00000000
--- a/src/backend/taler-mint-httpd.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd.h
- * @brief Global declarations for the mint
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- *
- * FIXME: Consider which of these need to really be globals...
- */
-#ifndef TALER_MINT_HTTPD_H
-#define TALER_MINT_HTTPD_H
-
-#include <microhttpd.h>
-
-/**
- * @brief Struct describing an URL and the handler for it.
- */
-struct TMH_RequestHandler
-{
-
- /**
- * URL the handler is for.
- */
- const char *url;
-
- /**
- * Method the handler is for, NULL for "all".
- */
- const char *method;
-
- /**
- * Mime type to use in reply (hint, can be NULL).
- */
- const char *mime_type;
-
- /**
- * Raw data for the @e handler
- */
- const void *data;
-
- /**
- * Number of bytes in @e data, 0 for 0-terminated.
- */
- size_t data_size;
-
- /**
- * Function to call to handle the request.
- *
- * @param rh this struct
- * @param mime_type the @e mime_type for the reply (hint, can be NULL)
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
- int (*handler)(struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
- /**
- * Default response code.
- */
- int response_code;
-};
-
-
-#endif