summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/Makefile.am3
-rw-r--r--src/backend/merchant.conf3
-rw-r--r--src/backend/taler-merchant-httpd.c26
-rw-r--r--src/backend/taler-merchant-httpd.h6
-rw-r--r--src/backend/taler-merchant-httpd_contract.c25
-rw-r--r--src/backend/taler-merchant-httpd_exchanges.c125
-rw-r--r--src/backend/taler-merchant-httpd_mhd.c8
-rw-r--r--src/backend/taler-merchant-httpd_parsing.c55
-rw-r--r--src/backend/taler-merchant-httpd_pay.c115
-rw-r--r--src/backend/taler-merchant-httpd_responses.c36
-rw-r--r--src/backend/taler-merchant-httpd_responses.h21
-rw-r--r--src/backend/taler-merchant-httpd_track.c70
-rw-r--r--src/backend/taler-merchant-httpd_track.h (renamed from src/backend/taler-merchant-httpd_util.h)14
-rw-r--r--src/backend/taler-merchant-httpd_util.c105
14 files changed, 363 insertions, 249 deletions
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am
index 7436eaa2..1e2f1d1b 100644
--- a/src/backend/Makefile.am
+++ b/src/backend/Makefile.am
@@ -21,7 +21,8 @@ taler_merchant_httpd_SOURCES = \
taler-merchant-httpd_exchanges.c taler-merchant-httpd_exchanges.h \
taler-merchant-httpd_contract.c taler-merchant-httpd_contract.h \
taler-merchant-httpd_pay.c taler-merchant-httpd_pay.h \
- taler-merchant-httpd_util.c taler-merchant-httpd_util.h
+ taler-merchant-httpd_track.c taler-merchant-httpd_track.h
+
taler_merchant_httpd_LDADD = \
$(top_srcdir)/src/backenddb/libtalermerchantdb.la \
diff --git a/src/backend/merchant.conf b/src/backend/merchant.conf
index eee0dfef..e925c6de 100644
--- a/src/backend/merchant.conf
+++ b/src/backend/merchant.conf
@@ -20,10 +20,11 @@ KEYFILE = ${TALER_DATA_HOME}/merchant/merchant.priv
DB = postgres
# Which wireformat does this merchant use? (test/sepa/etc.)
-# WIREFORMAT = "test"
+WIREFORMAT = test
# Determines which wire plugin will be used. We currently only
# support one wire plugin at a time!
+WIRE_TRANSFER_DELAY = 3 week
# Configuration for postgres database.
[merchantdb-postgres]
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c
index c02d5610..73541dd6 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -37,7 +37,7 @@
#include "taler-merchant-httpd_exchanges.h"
#include "taler-merchant-httpd_contract.h"
#include "taler-merchant-httpd_pay.h"
-#include "taler-merchant-httpd_util.h"
+#include "taler-merchant-httpd_track.h"
/**
@@ -80,7 +80,7 @@ static char *keyfile;
* This value tells the exchange by which date this merchant would like
* to receive the funds for a deposited payment
*/
-struct GNUNET_TIME_Relative edate_delay;
+struct GNUNET_TIME_Relative wire_transfer_delay;
/**
* Which currency is supported by this merchant?
@@ -174,12 +174,6 @@ url_handler (void *cls,
{ "/", MHD_HTTP_METHOD_GET, "text/plain",
"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 },
- { "/hash-contract", MHD_HTTP_METHOD_POST, "application/json",
- NULL, 0,
- &MH_handler_hash_contract, MHD_HTTP_OK },
- { "/hash-contract", NULL, "text/plain",
- "Only POST is allowed", 0,
- &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
{ "/contract", MHD_HTTP_METHOD_POST, "application/json",
NULL, 0,
&MH_handler_contract, MHD_HTTP_OK },
@@ -193,6 +187,12 @@ url_handler (void *cls,
{ "/pay", NULL, "text/plain",
"Only POST is allowed", 0,
&TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
+ { "/track/deposit", MHD_HTTP_METHOD_GET, "application/json",
+ NULL, 0,
+ &MH_handler_track_deposit, MHD_HTTP_OK},
+ { "/track/deposit", NULL, "text/plain",
+ "Only GET is allowed", 0,
+ &TMH_MHD_handler_static_response, MHD_HTTP_OK},
{NULL, NULL, NULL, NULL, 0, 0 }
};
@@ -483,6 +483,10 @@ run (void *cls,
result = GNUNET_SYSERR;
GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
NULL);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_log_setup ("taler-merchant-httpd",
+ "INFO",
+ NULL));
if (GNUNET_SYSERR ==
TMH_EXCHANGES_init (config))
{
@@ -511,12 +515,12 @@ run (void *cls,
if (GNUNET_SYSERR ==
GNUNET_CONFIGURATION_get_value_time (config,
"merchant",
- "EDATE",
- &edate_delay))
+ "WIRE_TRANSFER_DELAY",
+ &wire_transfer_delay))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"merchant",
- "EDATE");
+ "WIRE_TRANSFER_DELAY");
GNUNET_SCHEDULER_shutdown ();
return;
}
diff --git a/src/backend/taler-merchant-httpd.h b/src/backend/taler-merchant-httpd.h
index 3594c01f..2ca3c20b 100644
--- a/src/backend/taler-merchant-httpd.h
+++ b/src/backend/taler-merchant-httpd.h
@@ -179,10 +179,10 @@ extern struct TALER_MERCHANTDB_Plugin *db;
/**
* If the frontend does NOT specify an execution date, how long should
* we tell the exchange to wait to aggregate transactions before
- * executing? This delay is added to the current time when we
- * generate the advisory execution time for the exchange.
+ * executing the wire transfer? This delay is added to the current
+ * time when we generate the advisory execution time for the exchange.
*/
-extern struct GNUNET_TIME_Relative edate_delay;
+extern struct GNUNET_TIME_Relative wire_transfer_delay;
/**
* Kick MHD to run now, to be called after MHD_resume_connection().
diff --git a/src/backend/taler-merchant-httpd_contract.c b/src/backend/taler-merchant-httpd_contract.c
index af18ce11..0278a7f7 100644
--- a/src/backend/taler-merchant-httpd_contract.c
+++ b/src/backend/taler-merchant-httpd_contract.c
@@ -57,7 +57,7 @@ check_products (json_t *products)
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_string ("description", &description),
/* FIXME: there are other fields in the product specification
- that rre currently not labeled as optional. Maybe check
+ that are currently not labeled as optional. Maybe check
those as well, or make them truly optional. */
GNUNET_JSON_spec_end()
};
@@ -187,29 +187,6 @@ MH_handler_contract (struct TMH_RequestHandler *rh,
"products in contract request malformed");
}
- /* Check if this transaction ID erroneously corresponds to a
- contract that already paid, in which case we should refuse
- to sign it again (frontend buggy, it should use a fresh
- transaction ID each time)! */
- if (GNUNET_OK ==
- db->check_payment (db->cls,
- transaction_id))
- {
- struct MHD_Response *resp;
- int ret;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Transaction %llu already paid in the past, refusing to sign!\n",
- (unsigned long long) transaction_id);
- resp = MHD_create_response_from_buffer (strlen ("Duplicate transaction ID!"),
- "Duplicate transaction ID!",
- MHD_RESPMEM_PERSISTENT);
- ret = MHD_queue_response (connection,
- MHD_HTTP_FORBIDDEN,
- resp);
- MHD_destroy_response (resp);
- return ret;
- }
/* add fields to the contract that the backend should provide */
json_object_set (jcontract,
diff --git a/src/backend/taler-merchant-httpd_exchanges.c b/src/backend/taler-merchant-httpd_exchanges.c
index 0501784a..4593c3d2 100644
--- a/src/backend/taler-merchant-httpd_exchanges.c
+++ b/src/backend/taler-merchant-httpd_exchanges.c
@@ -24,10 +24,26 @@
#include "taler-merchant-httpd_exchanges.h"
+
+/**
+ * Delay after which we'll re-fetch key information from the exchange.
+ */
+#define RELOAD_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
+
/**
- * How often do we retry fetching /keys?
+ * Threshold after which exponential backoff should not increase.
*/
-#define KEYS_RETRY_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
+#define RETRY_BACKOFF_THRESHOLD GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
+
+
+/**
+ * Perform our exponential back-off calculation, starting at 1 ms
+ * and then going by a factor of 2 up unto a maximum of RETRY_BACKOFF_THRESHOLD.
+ *
+ * @param r current backoff time, initially zero
+ */
+#define RETRY_BACKOFF(r) GNUNET_TIME_relative_min (RETRY_BACKOFF_THRESHOLD, \
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_MILLISECONDS, (r)), 2));
/**
@@ -68,7 +84,8 @@ struct TMH_EXCHANGES_FindOperation
struct Exchange *my_exchange;
/**
- * Task scheduled to asynchrnously return the result.
+ * Task scheduled to asynchronously return the result to
+ * the find continuation.
*/
struct GNUNET_SCHEDULER_Task *at;
@@ -118,9 +135,9 @@ struct Exchange
struct TALER_MasterPublicKeyP master_pub;
/**
- * At what time should we try to fetch /keys again?
+ * How long should we wait between the next retry?
*/
- struct GNUNET_TIME_Absolute retry_time;
+ struct GNUNET_TIME_Relative retry_delay;
/**
* Task where we retry fetching /keys from the exchange.
@@ -128,8 +145,9 @@ struct Exchange
struct GNUNET_SCHEDULER_Task *retry_task;
/**
- * Flag which indicates whether some HTTP transfer between
- * this merchant and the exchange is still ongoing
+ * #GNUNET_YES to indicate that there is an ongoing
+ * transfer we are waiting for,
+ * #GNUNET_NO to indicate that key data is up-to-date.
*/
int pending;
@@ -201,12 +219,16 @@ retry_exchange (void *cls)
{
struct Exchange *exchange = cls;
+ /* might be a scheduled reload and not our first attempt */
exchange->retry_task = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Connecting to exchange exchange %s in retry_exchange\n",
exchange->uri);
-
- exchange->pending = GNUNET_SYSERR; /* failed hard */
+ if (NULL != exchange->conn)
+ {
+ TALER_EXCHANGE_disconnect (exchange->conn);
+ exchange->conn = NULL;
+ }
exchange->conn = TALER_EXCHANGE_connect (merchant_curl_ctx,
exchange->uri,
&keys_mgmt_cb,
@@ -236,39 +258,41 @@ keys_mgmt_cb (void *cls,
{
struct Exchange *exchange = cls;
struct TMH_EXCHANGES_FindOperation *fo;
+ struct GNUNET_TIME_Absolute expire;
+ struct GNUNET_TIME_Relative delay;
- if (NULL != keys)
- {
- exchange->pending = GNUNET_NO;
- }
- else
+ if (NULL == keys)
{
+ exchange->pending = GNUNET_YES;
+ exchange->retry_delay = RETRY_BACKOFF (exchange->retry_delay);
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to fetch /keys from `%s'\n",
- exchange->uri);
- TALER_EXCHANGE_disconnect (exchange->conn);
- exchange->conn = NULL;
- exchange->retry_time = GNUNET_TIME_relative_to_absolute (KEYS_RETRY_FREQ);
- /* Always retry trusted exchanges in the background, so that we don't have
- * to wait for a customer to trigger it and thus delay his response */
- if (GNUNET_YES == exchange->trusted)
- {
- exchange->retry_task = GNUNET_SCHEDULER_add_delayed (KEYS_RETRY_FREQ,
- &retry_exchange,
- exchange);
- }
- else
- {
- exchange->pending = GNUNET_SYSERR; /* failed hard */
- }
+ "Failed to fetch /keys from `%s', retrying in %s\n",
+ exchange->uri,
+ GNUNET_STRINGS_relative_time_to_string (exchange->retry_delay,
+ GNUNET_YES));
+ exchange->retry_task = GNUNET_SCHEDULER_add_delayed (exchange->retry_delay,
+ &retry_exchange,
+ exchange);
+ return;
}
+ expire = TALER_EXCHANGE_check_keys_current (exchange->conn);
+ if (0 == expire.abs_value_us)
+ delay = RELOAD_DELAY;
+ else
+ delay = GNUNET_TIME_absolute_get_remaining (expire);
+ exchange->retry_delay = GNUNET_TIME_UNIT_ZERO;
+ exchange->retry_task
+ = GNUNET_SCHEDULER_add_delayed (delay,
+ &retry_exchange,
+ exchange);
+ exchange->pending = GNUNET_NO;
while (NULL != (fo = exchange->fo_head))
{
GNUNET_CONTAINER_DLL_remove (exchange->fo_head,
exchange->fo_tail,
fo);
fo->fc (fo->fc_cls,
- (NULL != keys) ? exchange->conn : NULL,
+ exchange->conn,
exchange->trusted);
GNUNET_free (fo);
}
@@ -312,7 +336,7 @@ return_result (void *cls)
*/
struct TMH_EXCHANGES_FindOperation *
TMH_EXCHANGES_find_exchange (const char *chosen_exchange,
- TMH_EXCHANGES_FindContinuation fc, // process payment
+ TMH_EXCHANGES_FindContinuation fc,
void *fc_cls)
{
struct Exchange *exchange;
@@ -359,29 +383,6 @@ TMH_EXCHANGES_find_exchange (const char *chosen_exchange,
chosen_exchange);
}
- if (GNUNET_SYSERR == exchange->pending)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Maybe retrying previously contacted exchange `%s'\n",
- chosen_exchange);
- /* check if we should resume this exchange */
- if (0 == GNUNET_TIME_absolute_get_remaining (exchange->retry_time).rel_value_us)
- {
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Retrying exchange `%s'\n",
- chosen_exchange);
- exchange->pending = GNUNET_YES;
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Not retrying exchange `%s', too early\n",
- chosen_exchange);
- }
- }
-
-
fo = GNUNET_new (struct TMH_EXCHANGES_FindOperation);
fo->fc = fc;
fo->fc_cls = fc_cls;
@@ -390,7 +391,7 @@ TMH_EXCHANGES_find_exchange (const char *chosen_exchange,
exchange->fo_tail,
fo);
- if (GNUNET_YES != exchange->pending) // can post coins
+ if (GNUNET_YES != exchange->pending)
{
/* We are not currently waiting for a reply, immediately
return result */
@@ -434,13 +435,14 @@ TMH_EXCHANGES_find_exchange_cancel (struct TMH_EXCHANGES_FindOperation *fo)
/**
* Function called on each configuration section. Finds sections
- * about exchanges and parses the entries.
+ * about exchanges, parses the entries and tries to connect to
+ * it in order to fetch /keys.
*
* @param cls closure, with a `const struct GNUNET_CONFIGURATION_Handle *`
* @param section name of the section
*/
static void
-parse_exchanges (void *cls,
+accept_exchanges (void *cls,
const char *section)
{
const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
@@ -524,10 +526,11 @@ TMH_EXCHANGES_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
return GNUNET_SYSERR;
}
merchant_curl_rc = GNUNET_CURL_gnunet_rc_create (merchant_curl_ctx);
+ /* get exchanges from the merchant configuration and try to connect to them */
GNUNET_CONFIGURATION_iterate_sections (cfg,
- &parse_exchanges,
+ &accept_exchanges,
(void *) cfg);
- /* build JSON with list of trusted exchanges */
+ /* build JSON with list of trusted exchanges (will be included in contracts) */
trusted_exchanges = json_array ();
for (exchange = exchange_head; NULL != exchange; exchange = exchange->next)
{
diff --git a/src/backend/taler-merchant-httpd_mhd.c b/src/backend/taler-merchant-httpd_mhd.c
index 23a47707..34fdb113 100644
--- a/src/backend/taler-merchant-httpd_mhd.c
+++ b/src/backend/taler-merchant-httpd_mhd.c
@@ -41,10 +41,10 @@
*/
int
TMH_MHD_handler_static_response (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
{
struct MHD_Response *response;
int ret;
diff --git a/src/backend/taler-merchant-httpd_parsing.c b/src/backend/taler-merchant-httpd_parsing.c
index 9b0a3863..c7cdfd15 100644
--- a/src/backend/taler-merchant-httpd_parsing.c
+++ b/src/backend/taler-merchant-httpd_parsing.c
@@ -27,12 +27,6 @@
#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;
/**
* Initial size for POST request buffer.
@@ -129,9 +123,9 @@ buffer_append (struct Buffer *buf,
if (data_size + buf->fill > buf->alloc)
{
char *new_buf;
- size_t new_size = buf->alloc;
+ size_t new_size = buf->alloc ? buf->alloc : 1;
while (new_size < buf->fill + data_size)
- new_size += 2;
+ new_size *= 2;
if (new_size > max_size)
return GNUNET_NO;
new_buf = GNUNET_malloc (new_size);
@@ -313,4 +307,49 @@ TMH_PARSE_json_data (struct MHD_Connection *connection,
}
+
+/**
+ * Extract base32crockford encoded data from request.
+ *
+ * Queues an error response to the connection if the parameter is
+ * missing or invalid.
+ *
+ * @param connection the MHD connection
+ * @param param_name the name of the parameter with the key
+ * @param[out] out_data pointer to store the result
+ * @param out_size expected size of data
+ * @return
+ * #GNUNET_YES if the the argument is present
+ * #GNUNET_NO if the argument is absent or malformed
+ * #GNUNET_SYSERR on internal error (error response could not be sent)
+ */
+int
+TMH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection,
+ const char *param_name,
+ void *out_data,
+ size_t out_size)
+{
+ const char *str;
+
+ str = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ param_name);
+ if (NULL == str)
+ {
+ return (MHD_NO ==
+ TMH_RESPONSE_reply_arg_missing (connection, param_name))
+ ? GNUNET_SYSERR : GNUNET_NO;
+ }
+ if (GNUNET_OK !=
+ GNUNET_STRINGS_string_to_data (str,
+ strlen (str),
+ out_data,
+ out_size))
+ return (MHD_NO ==
+ TMH_RESPONSE_reply_arg_invalid (connection, param_name))
+ ? GNUNET_SYSERR : GNUNET_NO;
+ return GNUNET_OK;
+}
+
+
/* end of taler-merchant-httpd_parsing.c */
diff --git a/src/backend/taler-merchant-httpd_pay.c b/src/backend/taler-merchant-httpd_pay.c
index bd8dc742..8a32732d 100644
--- a/src/backend/taler-merchant-httpd_pay.c
+++ b/src/backend/taler-merchant-httpd_pay.c
@@ -18,6 +18,7 @@
* @brief handling of /pay requests
* @author Marcello Stanisci
* @author Christian Grothoff
+ * @author Florian Dold
*/
#include "platform.h"
#include <jansson.h>
@@ -33,6 +34,12 @@
/**
+ * How long to wait before giving up processing with the exchange?
+ */
+#define PAY_TIMEOUT (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30))
+
+
+/**
* Information we keep for an individual call to the /pay handler.
*/
struct PayContext;
@@ -175,11 +182,11 @@ struct PayContext
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.)
+ * Wire transfer deadline. How soon would the merchant like the
+ * wire transfer to be executed? (Can be given by the frontend
+ * or be determined by our configuration via #wire_transfer_delay.)
*/
- struct GNUNET_TIME_Absolute edate;
+ struct GNUNET_TIME_Absolute wire_transfer_deadline;
/**
* Response to return, NULL if we don't have one yet.
@@ -206,6 +213,13 @@ struct PayContext
*/
unsigned int response_code;
+ /**
+ * Task called when the (suspended) processing for
+ * the /pay request times out.
+ * Happens when we don't get a response from the exchange.
+ */
+ struct GNUNET_SCHEDULER_Task *timeout_task;
+
};
@@ -228,10 +242,16 @@ resume_pay_with_response (struct PayContext *pc,
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Resuming /pay handling as exchange interaction is done (%u)\n",
response_code);
+ if (NULL != pc->timeout_task)
+ {
+ GNUNET_SCHEDULER_cancel (pc->timeout_task);
+ pc->timeout_task = NULL;
+ }
MHD_resume_connection (pc->connection);
TMH_trigger_daemon (); /* we resumed, kick MHD */
}
+
/**
* Convert denomination key to its base32 representation
*
@@ -311,10 +331,13 @@ deposit_cb (void *cls,
if (NULL == proof)
{
- /* FIXME: is this the right code for when the exchange fails? */
+ /* We can't do anything meaningful here, the exchange did something wrong */
+ /* FIXME: any useful information we can include? */
resume_pay_with_response (pc,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TMH_RESPONSE_make_internal_error ("Exchange failed, no proof available"));
+ MHD_HTTP_SERVICE_UNAVAILABLE,
+ TMH_RESPONSE_make_json_pack ("{s:s, s:s}",
+ "error", "exchange failed",
+ "hint", "The exchange provided an unexpected response"));
}
else
{
@@ -375,6 +398,12 @@ pay_context_cleanup (struct TM_HandlerContext *hc)
struct PayContext *pc = (struct PayContext *) hc;
unsigned int i;
+ if (NULL != pc->timeout_task)
+ {
+ GNUNET_SCHEDULER_cancel (pc->timeout_task);
+ pc->timeout_task = NULL;
+ }
+
TMH_PARSE_post_cleanup_callback (pc->json_parse_context);
for (i=0;i<pc->coins_cnt;i++)
{
@@ -466,9 +495,10 @@ process_pay_with_exchange (void *cls,
GNUNET_break_op (0);
resume_pay_with_response (pc,
MHD_HTTP_BAD_REQUEST,
- TMH_RESPONSE_make_json_pack ("{s:s, s:o}",
- "hint", "unknown denom to exchange",
- "denom_pub", GNUNET_JSON_from_rsa_public_key (dc->denom.rsa_public_key)));
+ TMH_RESPONSE_make_json_pack ("{s:s, s:o, s:o}",
+ "error", "denomination not found",
+ "denom_pub", GNUNET_JSON_from_rsa_public_key (dc->denom.rsa_public_key),
+ "exchange_keys", TALER_EXCHANGE_get_keys_raw (mh)));
denom_enc = denomination_to_string_alloc (&dc->denom);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "unknown denom to exchange: %s\n", denom_enc);
GNUNET_free (denom_enc);
@@ -484,10 +514,10 @@ process_pay_with_exchange (void *cls,
resume_pay_with_response (pc,
MHD_HTTP_BAD_REQUEST,
TMH_RESPONSE_make_json_pack ("{s:s, s:o}",
- "hint", "no acceptable auditor for denomination",
+ "error", "invalid denomination",
"denom_pub", GNUNET_JSON_from_rsa_public_key (dc->denom.rsa_public_key)));
denom_enc = denomination_to_string_alloc (&dc->denom);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "no acceptable auditor for denomination: %s\n", denom_enc);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "client offered invalid denomination: %s\n", denom_enc);
GNUNET_free (denom_enc);
return;
}
@@ -593,7 +623,7 @@ process_pay_with_exchange (void *cls,
dc->dh = TALER_EXCHANGE_deposit (mh,
&dc->percoin_amount,
- pc->edate,
+ pc->wire_transfer_deadline,
j_wire,
&pc->h_contract,
&dc->coin_pub,
@@ -623,6 +653,33 @@ process_pay_with_exchange (void *cls,
/**
+ * Handle a timeout for the processing of the pay request.
+ *
+ * @param cls closure
+ */
+static void
+handle_pay_timeout (void *cls)
+{
+ struct PayContext *pc = cls;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Resuming /pay with error after timeout\n");
+
+ pc->timeout_task = NULL;
+
+ if (NULL != pc->fo)
+ {
+ TMH_EXCHANGES_find_exchange_cancel (pc->fo);
+ pc->fo = NULL;
+ }
+
+ resume_pay_with_response (pc,
+ MHD_HTTP_SERVICE_UNAVAILABLE,
+ TMH_RESPONSE_make_internal_error ("exchange not reachable"));
+}
+
+
+/**
* Accomplish this payment.
*
* @param rh context of the handler
@@ -748,18 +805,24 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
"invalid merchant signature supplied");
}
- /* '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"))
+ /* 'wire_transfer_deadline' is optional, if it is not present,
+ generate it here; it will be timestamp plus the
+ wire_transfer_delay supplied in config file */
+ if (NULL == json_object_get (root, "wire_transfer_deadline"))
{
- pc->edate = GNUNET_TIME_absolute_add (pc->timestamp,
- edate_delay);
+ pc->wire_transfer_deadline = GNUNET_TIME_absolute_add (pc->timestamp,
+ wire_transfer_delay);
+ if (pc->wire_transfer_deadline.abs_value_us < pc->refund_deadline.abs_value_us)
+ {
+ /* Refund value very large, delay wire transfer accordingly */
+ pc->wire_transfer_deadline = pc->refund_deadline;
+ }
}
else
{
struct GNUNET_JSON_Specification espec[] = {
- GNUNET_JSON_spec_absolute_time ("edate", &pc->edate),
+ GNUNET_JSON_spec_absolute_time ("wire_transfer_deadline",
+ &pc->wire_transfer_deadline),
GNUNET_JSON_spec_end()
};
@@ -772,6 +835,14 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
GNUNET_break (0);
return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
}
+ if (pc->wire_transfer_deadline.abs_value_us < pc->refund_deadline.abs_value_us)
+ {
+ GNUNET_break (0);
+ json_decref (root);
+ return TMH_RESPONSE_reply_external_error (connection,
+ "refund deadline after wire transfer deadline");
+ }
+
}
@@ -833,9 +904,6 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
/* Payment succeeded in the past; take short cut
and accept immediately */
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Transaction %llu already paid in the past, taking short cut.\n",
- (unsigned long long) pc->transaction_id);
resp = MHD_create_response_from_buffer (0,
NULL,
MHD_RESPMEM_PERSISTENT);
@@ -859,6 +927,7 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Suspending /pay handling while working with the exchange\n");
MHD_suspend_connection (connection);
+ pc->timeout_task = GNUNET_SCHEDULER_add_delayed (PAY_TIMEOUT, handle_pay_timeout, pc);
json_decref (root);
return MHD_YES;
}
diff --git a/src/backend/taler-merchant-httpd_responses.c b/src/backend/taler-merchant-httpd_responses.c
index 0f066ba9..d63eacb5 100644
--- a/src/backend/taler-merchant-httpd_responses.c
+++ b/src/backend/taler-merchant-httpd_responses.c
@@ -289,5 +289,41 @@ TMH_RESPONSE_make_external_error (const char *hint)
"hint", hint);
}
+/**
+ * Send a response indicating a missing argument.
+ *
+ * @param connection the MHD connection to use
+ * @param param_name the parameter that is missing
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection,
+ const char *param_name)
+{
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{ s:s, s:s}",
+ "error", "missing parameter",
+ "parameter", param_name);
+}
+
+
+/**
+ * Send a response indicating an invalid argument.
+ *
+ * @param connection the MHD connection to use
+ * @param param_name the parameter that is invalid
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection,
+ const char *param_name)
+{
+ return TMH_RESPONSE_reply_json_pack (connection,
+ MHD_HTTP_BAD_REQUEST,
+ "{s:s, s:s}",
+ "error", "invalid parameter",
+ "parameter", param_name);
+}
/* end of taler-exchange-httpd_responses.c */
diff --git a/src/backend/taler-merchant-httpd_responses.h b/src/backend/taler-merchant-httpd_responses.h
index abf90949..7314e0bb 100644
--- a/src/backend/taler-merchant-httpd_responses.h
+++ b/src/backend/taler-merchant-httpd_responses.h
@@ -157,4 +157,25 @@ TMH_RESPONSE_reply_request_too_large (struct MHD_Connection *connection);
void
TMH_RESPONSE_add_global_headers (struct MHD_Response *response);
+/**
+ * Send a response indicating a missing argument.
+ *
+ * @param connection the MHD connection to use
+ * @param param_name the parameter that is missing
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection,
+ const char *param_name);
+
+/**
+ * Send a response indicating an invalid argument.
+ *
+ * @param connection the MHD connection to use
+ * @param param_name the parameter that is invalid
+ * @return a MHD result code
+ */
+int
+TMH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection,
+ const char *param_name);
#endif
diff --git a/src/backend/taler-merchant-httpd_track.c b/src/backend/taler-merchant-httpd_track.c
new file mode 100644
index 00000000..47e5461a
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_track.c
@@ -0,0 +1,70 @@
+/*
+ This file is part of TALER
+ (C) 2014, 2015, 2016 INRIA
+
+ 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 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_track.c
+ * @brief implement API for tracking deposits and wire transfers
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include <jansson.h>
+#include <taler/taler_signatures.h>
+#include <taler/taler_json_lib.h>
+#include "taler-merchant-httpd.h"
+#include "taler-merchant-httpd_mhd.h"
+#include "taler-merchant-httpd_parsing.h"
+#include "taler-merchant-httpd_auditors.h"
+#include "taler-merchant-httpd_exchanges.h"
+#include "taler-merchant-httpd_responses.h"
+
+
+extern char *TMH_merchant_currency_string;
+
+
+/**
+ * Manages a /track/deposit call, thus it calls the /wire/deposit
+ * offered by the exchange in order to return the set of deposits
+ * (of coins) associated with a given wire transfer
+ *
+ * @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)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+MH_handler_track_deposit (struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ static struct TMH_RequestHandler pong =
+ {
+ "", NULL, "text/html",
+ "/track/deposit served\n", 0,
+ &TMH_MHD_handler_static_response, MHD_HTTP_OK
+ };
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "serving /track/deposit\n");
+ return TMH_MHD_handler_static_response (&pong,
+ connection,
+ connection_cls,
+ upload_data,
+ upload_data_size);
+}
+
+/* end of taler-merchant-httpd_contract.c */
diff --git a/src/backend/taler-merchant-httpd_util.h b/src/backend/taler-merchant-httpd_track.h
index cbf4693a..51dde1b9 100644
--- a/src/backend/taler-merchant-httpd_util.h
+++ b/src/backend/taler-merchant-httpd_track.h
@@ -14,17 +14,17 @@
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file backend/taler-merchant-httpd_contract.h
- * @brief headers for /contract handler
+ * @file backend/taler-merchant-httpd_track.h
+ * @brief headers for /track/{deposit,wtid} handler
* @author Marcello Stanisci
*/
-#ifndef TALER_EXCHANGE_HTTPD_UTIL_H
-#define TALER_EXCHANGE_HTTPD_UTIL_H
#include <microhttpd.h>
#include "taler-merchant-httpd.h"
/**
- * Manage a contract request
+ * Manages a /track/deposit call, thus it calls the /wire/deposit
+ * offered by the exchange in order to return the set of deposits
+ * (of coins) associated with a given wire transfer
*
* @param rh context of the handler
* @param connection the MHD connection to handle
@@ -34,10 +34,8 @@
* @return MHD result code
*/
int
-MH_handler_hash_contract (struct TMH_RequestHandler *rh,
+MH_handler_track_deposit (struct TMH_RequestHandler *rh,
struct MHD_Connection *connection,
void **connection_cls,
const char *upload_data,
size_t *upload_data_size);
-
-#endif
diff --git a/src/backend/taler-merchant-httpd_util.c b/src/backend/taler-merchant-httpd_util.c
deleted file mode 100644
index 9d62722c..00000000
--- a/src/backend/taler-merchant-httpd_util.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- This file is part of TALER
- (C) 2014, 2015, 2016 GNUnet e.V. and INRIA
-
- 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 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_contract.c
- * @brief HTTP serving layer mainly intended to communicate with the frontend
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include <jansson.h>
-#include <taler/taler_signatures.h>
-#include <taler/taler_json_lib.h>
-#include "taler-merchant-httpd.h"
-#include "taler-merchant-httpd_parsing.h"
-#include "taler-merchant-httpd_auditors.h"
-#include "taler-merchant-httpd_exchanges.h"
-#include "taler-merchant-httpd_responses.h"
-
-
-/**
- * Hashes a plain JSON contract sending the result to the other end of
- * HTTP communication
- *
- * @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)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-MH_handler_hash_contract (struct TMH_RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- json_t *root;
- json_t *jcontract;
- int res;
- struct GNUNET_HashCode hc;
- struct TMH_JsonParseContext *ctx;
-
- if (NULL == *connection_cls)
- {
- ctx = GNUNET_new (struct TMH_JsonParseContext);
- ctx->hc.cc = &TMH_json_parse_cleanup;
- *connection_cls = ctx;
- }
- else
- {
- ctx = *connection_cls;
- }
-
- res = TMH_PARSE_post_json (connection,
- &ctx->json_parse_context,
- upload_data,
- upload_data_size,
- &root);
-
- if (GNUNET_SYSERR == res)
- return MHD_NO;
- /* the POST's body has to be further fetched */
- if ((GNUNET_NO == res) || (NULL == root))
- return MHD_YES;
-
- jcontract = json_object_get (root, "contract");
-
- if (NULL == jcontract)
- {
- return TMH_RESPONSE_reply_external_error (connection,
- "missing 'contract' field");
- }
-
- if (GNUNET_OK != TALER_JSON_hash (jcontract,
- &hc))
- {
- return TMH_RESPONSE_reply_external_error (connection,
- "expected object as contract");
- }
-
- GNUNET_assert (GNUNET_OK ==
- TALER_JSON_hash (jcontract,
- &hc));
-
- /* return final response */
- res = TMH_RESPONSE_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:O}",
- "hash", GNUNET_JSON_from_data_auto (&hc));
- json_decref (root);
- return res;
-}