summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-11-16 15:03:17 +0100
committerChristian Grothoff <christian@grothoff.org>2015-11-16 15:03:17 +0100
commit43d916cdabc15640a84cc8755f7343354eac2751 (patch)
tree07d38281d7e3a45d4a26e1df6bb6883cc1fa4e3b /src
parent89610bad6a8ddff83b0d09f5cbc8b596ece7ad5a (diff)
downloadmerchant-43d916cdabc15640a84cc8755f7343354eac2751.tar.gz
merchant-43d916cdabc15640a84cc8755f7343354eac2751.tar.bz2
merchant-43d916cdabc15640a84cc8755f7343354eac2751.zip
misc fixes, in particular suspend/resume handling and keeping context for requests
Diffstat (limited to 'src')
-rw-r--r--src/backend/Makefile.am2
-rw-r--r--src/backend/taler-merchant-httpd.c12
-rw-r--r--src/backend/taler-merchant-httpd_pay.c193
-rw-r--r--src/include/merchant.h32
4 files changed, 153 insertions, 86 deletions
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am
index d5b283b8..08601781 100644
--- a/src/backend/Makefile.am
+++ b/src/backend/Makefile.am
@@ -5,7 +5,7 @@ bin_PROGRAMS = \
taler-merchant-httpd
taler_merchant_httpd_SOURCES = \
- taler-merchant-httpd.c \
+ 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 \
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c
index 9fdf7a0a..9c1c2257 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -33,6 +33,7 @@
#include "merchant_db.h"
#include "merchant.h"
#include "taler_merchant_lib.h"
+#include "taler-merchant-httpd.h"
#include "taler-mint-httpd_mhd.h"
#include "taler-merchant-httpd_contract.h"
#include "taler-merchant-httpd_pay.h"
@@ -57,7 +58,6 @@ struct GNUNET_CRYPTO_EddsaPrivateKey *privkey;
*/
char *keyfile;
-
/**
* This value tells the mint by which date this merchant would like
* to receive the funds for a deposited payment
@@ -417,9 +417,11 @@ handle_mhd_completion_callback (void *cls,
void **con_cls,
enum MHD_RequestTerminationCode toe)
{
- if (NULL == *con_cls)
+ struct TM_HandlerContext *hc = *con_cls;
+
+ if (NULL == hc)
return;
- TMH_PARSE_post_cleanup_callback (*con_cls);
+ hc->cc (hc);
*con_cls = NULL;
}
@@ -453,7 +455,7 @@ run_daemon (void *cls,
* Kick MHD to run now, to be called after MHD_resume_connection().
*/
void
-trigger_daemon ()
+TM_trigger_daemon ()
{
GNUNET_SCHEDULER_cancel (mhd_task);
run_daemon (NULL, NULL);
@@ -592,7 +594,7 @@ run (void *cls, char *const *args, const char *cfgfile,
mints[cnt].hostname,
&keys_mgmt_cb,
&mints[cnt],
- TALER_MINT_OPTION_END);
+ TALER_MINT_OPTION_END);
EXITIF (NULL == mints[cnt].conn);
poller_task =
GNUNET_SCHEDULER_add_now (&context_task, mints[cnt].ctx);
diff --git a/src/backend/taler-merchant-httpd_pay.c b/src/backend/taler-merchant-httpd_pay.c
index 0d87b680..4644354f 100644
--- a/src/backend/taler-merchant-httpd_pay.c
+++ b/src/backend/taler-merchant-httpd_pay.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,7 +13,6 @@
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 mainly intended to communicate with the frontend
@@ -29,6 +28,7 @@
#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"
@@ -37,16 +37,6 @@
#include "merchant.h"
#include "taler_merchant_lib.h"
-extern struct MERCHANT_Mint *mints;
-extern const struct MERCHANT_WIREFORMAT_Sepa *wire;
-extern PGconn *db_conn;
-extern long long salt;
-extern unsigned int nmints;
-extern struct GNUNET_TIME_Relative edate_delay;
-extern struct GNUNET_CRYPTO_EddsaPrivateKey privkey;
-extern struct GNUNET_SCHEDULER_Task *poller_task;
-extern void context_task (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc);
/**
* Fetch the deposit fee related to the given coin aggregate.
@@ -61,7 +51,7 @@ extern void context_task (void *cls,
* is invalid (including the case when the key is not found),
* GNUNET_SYSERR upon internal errors
*/
-int
+static int
deposit_fee_from_coin_aggregate (struct MHD_Connection *connection,
json_t *coin_aggregate,
struct TALER_Amount *deposit_fee,
@@ -76,7 +66,7 @@ deposit_fee_from_coin_aggregate (struct MHD_Connection *connection,
TMH_PARSE_member_denomination_public_key ("denom_pub", &denom),
TMH_PARSE_MEMBER_END
};
-
+
res = TMH_PARSE_json_data (connection,
coin_aggregate,
spec);
@@ -88,7 +78,7 @@ deposit_fee_from_coin_aggregate (struct MHD_Connection *connection,
mint_index,
mints[mint_index].pending);*/
- if (1 == mints[mint_index].pending)
+ 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);
@@ -107,7 +97,64 @@ deposit_fee_from_coin_aggregate (struct MHD_Connection *connection,
/**
+ * Information we keep for an individual call to the /pay handler.
+ */
+struct PayContext
+{
+
+ /**
+ * This field MUST be first.
+ */
+ struct TM_HandlerContext hc;
+
+ /**
+ * Pointer to the global (malloc'd) array of all coins outcomes
+ */
+ struct MERCHANT_DepositConfirmation *dc;
+
+ /**
+ * MHD connection to return to
+ */
+ struct MHD_Connection *connection;
+
+ /**
+ * 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.
+ */
+ struct MHD_Response *response;
+
+ /**
+ * Transaction id
+ */
+ uint64_t transaction_id;
+
+ /**
+ * Offset of this coin into the array of all coins outcomes
+ */
+ unsigned int index;
+
+ /**
+ * How many coins this paymen is made of.
+ */
+ unsigned int coins_cnt;
+
+ /**
+ * 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).
+ */
+ unsigned int response_code;
+
+};
+
+
+/**
* 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
@@ -117,56 +164,78 @@ deposit_fee_from_coin_aggregate (struct MHD_Connection *connection,
* @param proof the received JSON reply, should be kept as proof (and, in case of errors,
* be forwarded to the customer)
*/
-void
-deposit_cb (void *cls, unsigned int http_status, json_t *proof)
+static void
+deposit_cb (void *cls,
+ unsigned int http_status,
+ json_t *proof)
{
+ struct PayContext *pc = cls;
/* NOTE: what if the mint doesn't respond? Does this callback get
called? */
int i;
- struct MERCHANT_DepositConfirmationCls *dccls;
- dccls = (struct MERCHANT_DepositConfirmationCls *) cls;
printf ("deposit cb\n");
if (GNUNET_SYSERR ==
MERCHANT_DB_update_deposit_permission (db_conn,
- dccls->transaction_id,
+ pc->transaction_id,
0))
/* TODO */
printf ("db error\n");
printf ("/deposit ack'd\n");
- dccls->dc[dccls->index].ackd = 1;
- dccls->dc[dccls->index].exit_status = http_status;
- dccls->dc[dccls->index].proof = proof;
-
+ pc->dc[pc->index].ackd = 1;
+ pc->dc[pc->index].exit_status = http_status;
+ pc->dc[pc->index].proof = proof;
+
/* loop through the confirmation array and return accordingly */
- for (i = 0; i < dccls->coins_cnt; i++)
+ for (i = 0; i < pc->coins_cnt; i++)
{
/* just return if there is at least one coin to be still
confirmed */
- if (!dccls->dc[i].ackd)
+ if (! pc->dc[i].ackd)
{
printf ("still vacant coins\n");
return;
}
}
+ /* Clean up what we can already */
+ GNUNET_free (pc->dc);
+ pc->dc = NULL;
printf ("All /deposit(s) ack'd\n");
- MHD_resume_connection (dccls->connection);
- i = TMH_RESPONSE_reply_json_pack (dccls->connection,
+ pc->response = NULL; /* FIXME; */
+ /*
+ i = TMH_RESPONSE_reply_json_pack (pc->connection,
MHD_HTTP_OK,
"{s:s}",
"result", "all conins ack'd (and connection resumed)");
printf ("mhd res %d\n", i);
- /* TODO at this point, any coin has been confirmed by the mint. So
- check for errors .. */
+ */
- /* Finally */
- GNUNET_free (dccls->dc);
- GNUNET_free (dccls);
+ pc->response_code = MHD_HTTP_OK;
+ MHD_resume_connection (pc->connection);
+ TM_trigger_daemon (); /* we resumed, kick MHD */
}
+
+static void
+pay_context_cleanup (struct TM_HandlerContext *hc)
+{
+ struct PayContext *pc = (struct PayContext *) hc;
+
+ TMH_PARSE_post_cleanup_callback (pc->json_parse_context);
+ if (NULL != pc->response)
+ {
+ MHD_destroy_response (pc->response);
+ pc->response = NULL;
+ }
+ GNUNET_free_non_null (pc->dc);
+ GNUNET_free (pc);
+}
+
+
/**
* 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
@@ -183,6 +252,7 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
const char *upload_data,
size_t *upload_data_size)
{
+ struct PayContext *pc;
json_t *root;
json_t *coins;
char *chosen_mint;
@@ -208,7 +278,6 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
struct TALER_CoinSpendSignatureP coin_sig;
struct GNUNET_HashCode h_contract;
struct MERCHANT_DepositConfirmation *dc;
- struct MERCHANT_DepositConfirmationCls *dccls;
struct TMH_PARSE_FieldSpecification spec[] = {
TMH_PARSE_member_array ("coins", &coins),
@@ -230,6 +299,32 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
TMH_PARSE_MEMBER_END
};
+ if (NULL == connection_cls)
+ {
+ pc = GNUNET_new (struct PayContext);
+ pc->hc.cc = &pay_context_cleanup;
+ pc->connection = connection;
+ *connection_cls = pc;
+ }
+ else
+ {
+ /* not the first call, recover state */
+ pc = *connection_cls;
+ }
+
+ if (0 != pc->response_code)
+ {
+ 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);
+ MHD_destroy_response (pc->response);
+ pc->response = NULL;
+ return res;
+ }
+
res = TMH_PARSE_post_json (connection,
connection_cls,
upload_data,
@@ -280,7 +375,7 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
}
if (-1 == mint_index)
- return TMH_RESPONSE_reply_external_error (connection, "unknown mint");
+ 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 */
@@ -292,9 +387,9 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
}
coins_cnt = json_array_size (coins);
-
+
if (0 == coins_cnt)
- return TMH_RESPONSE_reply_external_error (connection, "no coins given");
+ return TMH_RESPONSE_reply_external_error (connection, "no coins given");
json_array_foreach (coins, coins_index, coin_aggregate)
{
@@ -303,9 +398,9 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
&coin_fee,
mint_index);
if (GNUNET_NO == res)
- return MHD_YES;
+ return MHD_YES;
if (GNUNET_SYSERR == res)
- return MHD_NO;
+ return MHD_NO;
if (0 == coins_index)
acc_fee = coin_fee;
@@ -329,7 +424,7 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
"malformed/non-existent 'coins' field");
/* adding our public key to deposit permission */
- GNUNET_CRYPTO_eddsa_key_get_public (&privkey, &pubkey.eddsa_pub);
+ GNUNET_CRYPTO_eddsa_key_get_public (privkey, &pubkey.eddsa_pub);
json_object_set_new (root,
"merchant_pub",
TALER_json_from_data (&pubkey, sizeof (pubkey)));
@@ -343,7 +438,7 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
/* 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,
@@ -388,13 +483,11 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
if (GNUNET_OK != res)
return res; /* may return GNUNET_NO */
- dccls = GNUNET_malloc (sizeof (struct MERCHANT_DepositConfirmationCls));
- dccls->index = coins_index;
- dccls->dc = dc;
- dccls->coins_cnt = coins_cnt;
- dccls->transaction_id = transaction_id;
- dccls->connection = connection;
-
+ pc->index = coins_index;
+ pc->dc = dc;
+ pc->coins_cnt = coins_cnt;
+ pc->transaction_id = transaction_id;
+
dh = TALER_MINT_deposit (mints[mint_index].conn,
&amount,
edate,
@@ -408,8 +501,8 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
&pubkey,
refund_deadline,
&coin_sig,
- deposit_cb,
- dccls); /*may be destroyed by the time the cb gets called..*/
+ &deposit_cb,
+ pc); /*may be destroyed by the time the cb gets called..*/
if (NULL == dh)
{
MHD_resume_connection (connection);
diff --git a/src/include/merchant.h b/src/include/merchant.h
index 339b1355..582c4cf1 100644
--- a/src/include/merchant.h
+++ b/src/include/merchant.h
@@ -15,7 +15,7 @@
*/
/**
- * @file merchant/merchant.c
+ * @file include/merchant.h
* @brief Common utility functions for merchant
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
*/
@@ -23,8 +23,7 @@
#ifndef MERCHANT_H
#define MERCHANT_H
-#include <gnunet/gnunet_common.h>
-#include <gnunet/gnunet_crypto_lib.h>
+#include <gnunet/gnunet_util_lib.h>
#include <taler/taler_mint_service.h>
#include "merchant.h"
@@ -66,33 +65,6 @@ struct MERCHANT_DepositConfirmation
};
-struct MERCHANT_DepositConfirmationCls
-{
- /**
- * Offset of this coin into the array of all coins outcomes
- */
- unsigned int index;
-
- /**
- * Pointer to the global (malloc'd) array of all coins outcomes
- */
- struct MERCHANT_DepositConfirmation *dc;
-
- /**
- * How many coins this paymen is made of.
- */
- unsigned int coins_cnt;
-
- /**
- * Transaction id
- */
- uint64_t transaction_id;
-
- /**
- * MHD connection to return to
- */
- struct MHD_Connection *connection;
-};
/**
* Mint