summaryrefslogtreecommitdiff
path: root/src/backend/taler-merchant-httpd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/taler-merchant-httpd.c')
-rw-r--r--src/backend/taler-merchant-httpd.c667
1 files changed, 466 insertions, 201 deletions
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c
index 6ca70937..46379809 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -22,9 +22,23 @@
#include "platform.h"
#include <microhttpd.h>
+#include <jansson.h>
#include <gnunet/gnunet_util_lib.h>
#include <taler/taler_json_lib.h>
-
+#include <taler/taler_mint_service.h>
+#include "taler-mint-httpd_parsing.h"
+#include "taler-mint-httpd_mhd.h"
+#include "taler-mint-httpd_admin.h"
+#include "taler-mint-httpd_deposit.h"
+#include "taler-mint-httpd_withdraw.h"
+#include "taler-mint-httpd_refresh.h"
+#include "taler-mint-httpd_keystate.h"
+#include "taler-mint-httpd_responses.h"
+#include "merchant.h"
+#include "merchant_db.h"
+
+extern struct MERCHANT_WIREFORMAT_Sepa *
+TALER_MERCHANT_parse_wireformat_sepa (const struct GNUNET_CONFIGURATION_Handle *cfg);
/**
* Shorthand for exit jumps.
@@ -34,232 +48,168 @@
if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
} while (0)
-// task 1. Just implement a hello world server launched a` la GNUNET
-
/**
- * The port we are running on
+ * Macro to round microseconds to seconds in GNUNET_TIME_* structs.
*/
-unsigned short port;
+#define ROUND_TO_SECS(name,us_field) name.us_field -= name.us_field % (1000 * 1000)
/**
- * The MHD Daemon
+ * Our hostname
*/
-static struct MHD_Daemon *mhd;
+static char *hostname;
/**
- * Shutdown task identifier
+ * The port we are running on
*/
-static struct GNUNET_SCHEDULER_Task *shutdown_task;
+static long long unsigned port;
/**
- * Should we do a dry run where temporary tables are used for storing the data.
+ * Merchant's private key
*/
-static int dry;
+struct GNUNET_CRYPTO_EddsaPrivateKey *privkey;
/**
- * Global return code
+ * The MHD Daemon
*/
-static int result;
-
-/** Beginning of JSON parse logic
-* Located here only for testing purposes since the service they provide is already
-* implemented in the mint's code; it just needs to be exported as a library. To be announced as a issue.
-*/
+static struct MHD_Daemon *mhd;
/**
- * Initial size for POST
- * request buffer.
+ * Connection handle to the our database
*/
-#define REQUEST_BUFFER_INITIAL 1024
+PGconn *db_conn;
/**
- * Maximum POST request size
+ * Which currency is used by this mint?
+ * (verbatim copy from mint's code, just to make this
+ * merchant's source compile)
*/
-#define REQUEST_BUFFER_MAX (1024*1024)
+char *TMH_mint_currency_string;
+
+/* As above */
+struct TALER_MINTDB_Plugin *TMH_plugin;
/**
- * Buffer for POST requests.
+ * As above, though the merchant does need some form of
+ * configuration
*/
-struct Buffer
-{
- /**
- * Allocated memory
- */
- char *data;
+struct GNUNET_CONFIGURATION_Handle *cfg;
- /**
- * Number of valid bytes in buffer.
- */
- size_t fill;
- /**
- * Number of allocated bytes in buffer.
- */
- size_t alloc;
-};
+/**
+ * As above
+ */
+int TMH_test_mode;
/**
- * Initialize a buffer.
- *
- * @param buf the buffer to initialize
- * @param data the initial data
- * @param data_size size of the initial data
- * @param alloc_size size of the buffer
- * @param max_size maximum size that the buffer can grow to
- * @return a GNUnet result code
+ * As above
*/
-static int
-buffer_init (struct Buffer *buf, const void *data, size_t data_size, size_t alloc_size, size_t max_size)
-{
- if (data_size > max_size || alloc_size > max_size)
- return GNUNET_SYSERR;
- if (data_size > alloc_size)
- alloc_size = data_size;
- buf->data = GNUNET_malloc (alloc_size);
- memcpy (buf->data, data, data_size);
- return GNUNET_OK;
-}
+char *TMH_mint_directory;
/**
- * Free the data in a buffer. Does *not* free
- * the buffer object itself.
- *
- * @param buf buffer to de-initialize
+ * As above
*/
-static void
-buffer_deinit (struct Buffer *buf)
-{
- GNUNET_free (buf->data);
- buf->data = NULL;
-}
+struct GNUNET_CRYPTO_EddsaPublicKey TMH_master_public_key;
+/**
+ * As above
+ */
+char *TMH_expected_wire_format;
/**
- * Append data to a buffer, growing the buffer if necessary.
- *
- * @param buf the buffer to append to
- * @param data the data to append
- * @param size the size of @a data
- * @param max_size maximum size that the buffer can grow to
- * @return GNUNET_OK on success,
- * GNUNET_NO if the buffer can't accomodate for the new data
- * GNUNET_SYSERR on fatal error (out of memory?)
+ * Shutdown task identifier
*/
-static int
-buffer_append (struct Buffer *buf, const void *data, size_t data_size, size_t max_size)
-{
- if (buf->fill + data_size > max_size)
- return GNUNET_NO;
- if (data_size + buf->fill > buf->alloc)
- {
- char *new_buf;
- size_t new_size = buf->alloc;
- while (new_size < buf->fill + data_size)
- new_size += 2;
- if (new_size > max_size)
- return GNUNET_NO;
- new_buf = GNUNET_malloc (new_size);
- memcpy (new_buf, buf->data, buf->fill);
- buf->data = new_buf;
- buf->alloc = new_size;
- }
- memcpy (buf->data + buf->fill, data, data_size);
- buf->fill += data_size;
- return GNUNET_OK;
-}
+static struct GNUNET_SCHEDULER_Task *shutdown_task;
+/**
+ * Our wireformat
+ */
+static struct MERCHANT_WIREFORMAT_Sepa *wire;
+/**
+ * Hash of the wireformat
+ */
+static struct GNUNET_HashCode h_wire;
/**
- * Process a POST request containing a JSON object.
- *
- * @param connection the MHD connection
- * @param con_cs the closure (contains a 'struct Buffer *')
- * @param upload_data the POST data
- * @param upload_data_size the POST data size
- * @param json the JSON object for a completed request
- *
- * @returns
- * GNUNET_YES if json object was parsed
- * GNUNET_NO is request incomplete or invalid
- * GNUNET_SYSERR on internal error
+ * Should we do a dry run where temporary tables are used for storing the data.
*/
-static int
-process_post_json (struct MHD_Connection *connection,
- void **con_cls,
- const char *upload_data,
- size_t *upload_data_size,
- json_t **json)
+static int dry;
+
+/**
+ * Global return code
+ */
+static int result;
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+struct Contract
{
- struct Buffer *r = *con_cls;
+ /**
+ * The signature of the merchant for this contract
+ */
+ struct GNUNET_CRYPTO_EddsaSignature sig;
- if (NULL == *con_cls)
- {
- /* We are seeing a fresh POST request. */
+ /**
+ * Purpose header for the signature over contract
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- r = GNUNET_new (struct Buffer);
- if (GNUNET_OK != buffer_init (r, upload_data, *upload_data_size,
- REQUEST_BUFFER_INITIAL, REQUEST_BUFFER_MAX))
- {
- *con_cls = NULL;
- buffer_deinit (r);
- GNUNET_free (r);
- return GNUNET_SYSERR;
- }
- *upload_data_size = 0;
- *con_cls = r;
- return GNUNET_NO;
- }
- if (0 != *upload_data_size)
- {
- /* We are seeing an old request with more data available. */
+ /**
+ * The transaction identifier
+ */
+ char m[13];
- if (GNUNET_OK != buffer_append (r, upload_data, *upload_data_size,
- REQUEST_BUFFER_MAX))
- {
- /* Request too long or we're out of memory. */
+ /**
+ * Expiry time
+ */
+ struct GNUNET_TIME_AbsoluteNBO t;
- *con_cls = NULL;
- buffer_deinit (r);
- GNUNET_free (r);
- return GNUNET_SYSERR;
- }
- *upload_data_size = 0;
- return GNUNET_NO;
- }
+ /**
+ * The invoice amount
+ */
+ struct TALER_AmountNBO amount;
- /* We have seen the whole request. */
+ /**
+ * The hash of the preferred wire format + nounce
+ */
+ struct GNUNET_HashCode h_wire;
- *json = json_loadb (r->data, r->fill, 0, NULL);
- buffer_deinit (r);
- GNUNET_free (r);
- if (NULL == *json)
- {
- struct MHD_Response *resp;
- int ret;
-
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Can't parse JSON request body\n");
- resp = MHD_create_response_from_buffer (strlen ("parse error"),
- "parse error",
- MHD_RESPMEM_PERSISTENT);
- ret = MHD_queue_response (connection,
- MHD_HTTP_BAD_REQUEST,
- resp);
- MHD_destroy_response (resp);
- return ret;
- }
- *con_cls = NULL;
+ /**
+ * The contract data
+ */
+ char a[];
+};
- return GNUNET_YES;
-}
+GNUNET_NETWORK_STRUCT_END
+/**
+ * Mint context
+ */
+static struct TALER_MINT_Context *mctx;
-/* ************** END of JSON POST processing logic ************ */
+/**
+ * Context information of the mints we trust
+ */
+struct Mint
+{
+ /**
+ * Public key of this mint
+ */
+ struct GNUNET_CRYPTO_EddsaPublicKey pubkey;
+ /**
+ * Connection handle to this mint
+ */
+ struct TALER_MINT_Handle *conn;
+};
+/**
+ * Hashmap to store the mint context information
+ */
+static struct GNUNET_CONTAINER_MultiPeerMap *mints_map;
/**
* Return the given message to the other end of connection
@@ -296,7 +246,7 @@ static unsigned int
generate_hello (struct MHD_Response **resp) // this parameter was preceded by a '_' in its original file. Why?
{
- const char *hello = "Hello customer";
+ const char *hello = "Hello customer\n";
unsigned int ret;
*resp = MHD_create_response_from_buffer (strlen (hello), (void *) hello,
@@ -307,6 +257,26 @@ generate_hello (struct MHD_Response **resp) // this parameter was preceded by a
}
+/**
+ * Callback for catching serious error conditions from MHD.
+ *
+ * @param cls user specified value
+ * @param file where the error occured
+ * @param line where the error occured
+ * @param reason error detail, may be NULL
+ */
+static void
+mhd_panic_cb (void *cls,
+ const char *file,
+ unsigned int line,
+ const char *reason)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "MHD panicked at %s:%u: %s",
+ file, line, reason);
+ result = GNUNET_SYSERR;
+ GNUNET_SCHEDULER_shutdown ();
+}
/**
* Manage a non 200 HTTP status. I.e. it shows a 'failure' page to
@@ -320,7 +290,6 @@ generate_hello (struct MHD_Response **resp) // this parameter was preceded by a
static int
failure_resp (struct MHD_Connection *connection, unsigned int status)
{
- printf ("called failure mgmt\n");
static char page_404[]="\
<!DOCTYPE html> \
<html><title>Resource not found</title><body><center> \
@@ -365,6 +334,91 @@ request</h3></center></body></html>";
/**
+* Generate the hash containing the information (= a nounce + merchant's IBAN) to
+* redeem money from mint in a subsequent /deposit operation
+* @param nounce the nounce
+* @return the hash to be included in the contract's blob
+*
+*/
+
+static struct GNUNET_HashCode
+hash_wireformat (uint64_t nounce)
+{
+ struct GNUNET_HashContext *hc;
+ struct GNUNET_HashCode hash;
+
+ hc = GNUNET_CRYPTO_hash_context_start ();
+ GNUNET_CRYPTO_hash_context_read (hc, wire->iban, strlen (wire->iban));
+ GNUNET_CRYPTO_hash_context_read (hc, wire->name, strlen (wire->name));
+ GNUNET_CRYPTO_hash_context_read (hc, wire->bic, strlen (wire->bic));
+ nounce = GNUNET_htonll (nounce);
+ GNUNET_CRYPTO_hash_context_read (hc, &nounce, sizeof (nounce));
+ GNUNET_CRYPTO_hash_context_finish (hc, &hash);
+ return hash;
+}
+
+
+
+/*
+* Make a binary blob representing a contract, store it into the DB, sign it
+* and return a pointer to it.
+* @param a 0-terminated string representing the description of this
+* @param c_id contract id provided by the frontend
+* purchase (it should contain a human readable description of the good
+* in question)
+* @param product some product numerical id. Its indended use is to link the
+* good, or service being sold to some entry in the DB managed by the frontend
+* @price the cost of this good or service
+* @return pointer to the allocated contract (which has a field, 'sig', holding
+* its own signature), NULL upon errors
+*/
+
+struct Contract *
+generate_and_store_contract (const char *a, uint64_t c_id, uint64_t product, struct TALER_Amount *price)
+{
+
+ struct Contract *contract;
+ struct GNUNET_TIME_Absolute expiry;
+ uint64_t nounce;
+ uint64_t contract_id_nbo;
+
+ expiry = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_UNIT_DAYS);
+ ROUND_TO_SECS (expiry, abs_value_us);
+ nounce = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX);
+ EXITIF (GNUNET_SYSERR == MERCHANT_DB_contract_create (db_conn,
+ &expiry,
+ price,
+ c_id,
+ a,
+ nounce,
+ product));
+ contract_id_nbo = GNUNET_htonll ((uint64_t) c_id);
+ contract = GNUNET_malloc (sizeof (struct Contract) + strlen (a) + 1);
+ contract->purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT);
+ contract->purpose.size = htonl (sizeof (struct Contract)
+ - offsetof (struct Contract, purpose)
+ + strlen (a) + 1);
+ GNUNET_STRINGS_data_to_string (&contract_id_nbo, sizeof (contract_id_nbo),
+ contract->m, sizeof (contract->m));
+ contract->t = GNUNET_TIME_absolute_hton (expiry);
+ (void) strcpy (contract->a, a);
+ contract->h_wire = hash_wireformat (nounce);
+ TALER_amount_hton (&contract->amount, price);
+ GNUNET_CRYPTO_eddsa_sign (privkey, &contract->purpose, &contract->sig);
+ return contract;
+
+ /* legacy from old merchant */
+ EXITIF_exit:
+ if (NULL != contract)
+ {
+ GNUNET_free (contract);
+ }
+ return NULL;
+}
+
+
+/**
* A client has requested the given url using the given method
* (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT,
* #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc). The callback
@@ -412,19 +466,32 @@ url_handler (void *cls,
const char *version,
const char *upload_data,
size_t *upload_data_size,
- void **con_cls)
+ void **connection_cls)
{
unsigned int status;
unsigned int no_destroy;
+ json_int_t prod_id;
+ json_int_t contract_id;
+ struct Contract *contract;
struct MHD_Response *resp;
-
+ struct TALER_Amount price;
+ struct GNUNET_CRYPTO_EddsaPublicKey pub;
+ json_t *json_price;
+ json_t *root;
+ json_t *contract_enc;
+ json_t *sig_enc;
+ json_t *eddsa_pub_enc;
+ json_t *response;
+
+ int res;
+ const char *desc;
#define URL_HELLO "/hello"
#define URL_CONTRACT "/contract"
no_destroy = 0;
resp = NULL;
- status = 500;
+ status = MHD_HTTP_INTERNAL_SERVER_ERROR;
if (0 == strncasecmp (url, URL_HELLO, sizeof (URL_HELLO)))
{
if (0 == strcmp (MHD_HTTP_METHOD_GET, method))
@@ -436,24 +503,134 @@ url_handler (void *cls,
// to be called by the frontend passing all the product's information
// which are relevant for the contract's generation
if (0 == strncasecmp (url, URL_CONTRACT, sizeof (URL_CONTRACT)))
+ {
+ if (0 == strcmp (MHD_HTTP_METHOD_GET, method))
+ status = generate_message (&resp, "Sorry, only POST is allowed");
+ else
+ res = TMH_PARSE_post_json (connection,
+ connection_cls,
+ upload_data,
+ upload_data_size,
+ &root);
+
+ if (GNUNET_SYSERR == res)
{
- if (0 == strcmp (MHD_HTTP_METHOD_GET, method))
- status = generate_message (&resp, "Sorry, only POST is allowed");
- else
-
- /*
- 1. parse the json
- 2. generate the contract
- 3. pack the contract's json
- 4. return it
- */
-
- GNUNET_break (0);
-
+ status = generate_message (&resp, "unable to parse JSON root");
+ return MHD_NO;
}
+ if ((GNUNET_NO == res) || (NULL == root))
+ return MHD_YES;
+
+ /* The frontend should supply a JSON in the follwoing format:
+ {
+
+ "desc" : string human-readable describing this deal,
+ "product" : uint64-like integer referring to the product in some
+ DB adminstered by the frontend,
+ "cid" : uint64-like integer, this contract's id
+ "price" : a 'struct TALER_Amount' in the Taler compliant JSON format }
+
+ */
+
+ #if 0
+ /*res = json_typeof (root); <- seg fault*/
+ json_int_t id;
+ const char *desc_test;
+ const char *cur_test;
+ json_t *id_json;
+ json_t *desc_json;
+ json_t *cur_json;
+ id_json = json_object_get (root, "product");
+ desc_json = json_object_get (root, "desc");
+ id = json_integer_value (id_json);
+ desc_test = json_string_value (desc_json);
+ json_price = json_object_get (root, "price");
+ json_typeof (json_price);
+ cur_json = json_object_get (json_price, "currency");
+ cur_test = json_string_value (cur_json);
+ printf ("id is %" JSON_INTEGER_FORMAT "\n", id);
+ printf ("desc is %s\n", desc_test);
+ TALER_json_to_amount (json_price, &price);
+ printf ("cur_test is %s\n", price.currency);
+ json_error_t err;
+ if (res = json_unpack_ex (root, &err, JSON_VALIDATE_ONLY, "{s:s, s:I, s:o}",
+ "desc",
+ //&desc,
+ "product",
+ //&prod_id,
+ "price"//,
+ //json_price
+ ))
+ #else
+ if ((res = json_unpack (root, "{s:s, s:I, s:I, s:o}",
+ "desc",
+ &desc,
+ "product",
+ &prod_id,
+ "cid",
+ &contract_id,
+ "price",
+ &json_price
+ )))
+ #endif
+
+
+ /* still not possible to return a taler-compliant error message
+ since this JSON format is not among the taler officials ones */
+ {
+ status = generate_message (&resp, "unable to parse /contract JSON\n");
+ }
+ else
+ {
+ if (GNUNET_OK != TALER_json_to_amount (json_price, &price))
+ {/* still not possible to return a taler-compliant error message
+ since this JSON format is not among the taler officials ones */
+ status = generate_message (&resp, "unable to parse `price' field in /contract JSON");}
+ else
+ {
+ /* Let's generate this contract! */
+ if (NULL == (contract = generate_and_store_contract (desc, contract_id, prod_id, &price)))
+ {
+ /* status equals 500, so the user will get a "Internal server error" */
+ //failure_resp (connection, status);
+ status = generate_message (&resp, "unable to generate and store this contract");
+ //return MHD_YES;
+
+ }
+ else
+ {
+ json_decref (root);
+ json_decref (json_price);
+
+ printf ("Good contract\n");
+ /* the contract is good and stored in DB, produce now JSON to return.
+ As of now, the format is {"contract" : base32contract,
+ "sig" : contractSignature,
+ "eddsa_pub" : keyToCheckSignatureAgainst
+ }
+
+ */
+
+ sig_enc = TALER_json_from_eddsa_sig (&contract->purpose, &contract->sig);
+ GNUNET_CRYPTO_eddsa_key_get_public (privkey, &pub);
+ eddsa_pub_enc = TALER_json_from_data ((void *) &pub, sizeof (pub));
+ /* cutting of the signature at the beginning */
+ contract_enc = TALER_json_from_data (&contract->purpose, sizeof (*contract)
+ - offsetof (struct Contract, purpose)
+ + strlen (desc) +1);
+ response = json_pack ("{s:o, s:o, s:o}", "contract", contract_enc, "sig", sig_enc,
+ "eddsa_pub", eddsa_pub_enc);
+ TMH_RESPONSE_reply_json (connection, response, MHD_HTTP_OK);
+ printf ("Got something?\n");
+ return MHD_YES;
+ /* FRONTIER - CODE ABOVE STILL NOT TESTED */
+ }
+ }
+ }
+ }
if (NULL != resp)
{
@@ -461,15 +638,14 @@ url_handler (void *cls,
if (!no_destroy)
MHD_destroy_response (resp);
}
- else
- EXITIF (GNUNET_OK != failure_resp (connection, status));
- return MHD_YES;
-
- EXITIF_exit:
- result = GNUNET_SYSERR;
- //GNUNET_SCHEDULER_shutdown (); to a later stage, maybe
- return MHD_NO;
+ else
+ EXITIF (GNUNET_OK != failure_resp (connection, status));
+ return MHD_YES;
+ EXITIF_exit:
+ result = GNUNET_SYSERR;
+ GNUNET_SCHEDULER_shutdown ();
+ return MHD_NO;
}
/**
@@ -488,10 +664,38 @@ do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
MHD_stop_daemon (mhd);
mhd = NULL;
}
+
+ if (NULL != db_conn)
+ {
+ MERCHANT_DB_disconnect (db_conn);
+ db_conn = NULL;
+ }
+
}
+
+/**
+ * Function called with information about who is auditing
+ * a particular mint and what key the mint is using.
+ *
+ * @param cls closure
+ * @param keys information about the various keys used
+ * by the mint
+ */
+void
+keys_mgmt_cb (void *cls, const struct TALER_MINT_Keys *keys)
+{
+ /* which kind of mint's keys a merchant should need? Sign
+ keys? It has already the mint's (master?) public key from
+ the conf file */
+ return;
+
+}
+
+
+
/**
* Main function that will be run by the scheduler.
*
@@ -505,10 +709,63 @@ run (void *cls, char *const *args, const char *cfgfile,
const struct GNUNET_CONFIGURATION_Handle *config)
{
- port = 9966;
+ char *keyfile;
+ unsigned int nmints;
+ unsigned int cnt;
+ struct MERCHANT_MintInfo *mint_infos;
+ void *keys_mgmt_cls;
+ mint_infos = NULL;
+ keyfile = NULL;
+ result = GNUNET_SYSERR;
shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
&do_shutdown, NULL);
+ EXITIF (GNUNET_SYSERR == (nmints = TALER_MERCHANT_parse_mints (config,
+ &mint_infos)));
+ EXITIF (NULL == (wire = TALER_MERCHANT_parse_wireformat_sepa (config)));
+ EXITIF (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (config,
+ "merchant",
+ "KEYFILE",
+ &keyfile));
+ EXITIF (NULL == (privkey = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile)));
+ EXITIF (NULL == (db_conn = MERCHANT_DB_connect (config)));
+ EXITIF (GNUNET_OK != MERCHANT_DB_initialize (db_conn, GNUNET_NO));
+ EXITIF (GNUNET_SYSERR ==
+ GNUNET_CONFIGURATION_get_value_number (config,
+ "merchant",
+ "port",
+ &port));
+ EXITIF (GNUNET_SYSERR ==
+ GNUNET_CONFIGURATION_get_value_string (config,
+ "merchant",
+ "hostname",
+ &hostname));
+
+ EXITIF (NULL == (mctx = TALER_MINT_init ()));
+ EXITIF (NULL == (mints_map = GNUNET_CONTAINER_multipeermap_create (nmints, GNUNET_YES)));
+
+ for (cnt = 0; cnt < nmints; cnt++)
+ {
+ struct Mint *mint;
+
+ mint = GNUNET_new (struct Mint);
+ mint->pubkey = mint_infos[cnt].pubkey;
+ /* port this to the new API */
+ mint->conn = TALER_MINT_connect (mctx,
+ mint_infos[cnt].hostname,
+ &keys_mgmt_cb,
+ keys_mgmt_cls); /*<- safe?segfault friendly?*/
+
+ /* NOTE: the keys mgmt callback should roughly do what the following lines do */
+ EXITIF (NULL == mint->conn);
+
+ EXITIF (GNUNET_SYSERR == GNUNET_CONTAINER_multipeermap_put
+ (mints_map,
+ (struct GNUNET_PeerIdentity *) /* to retrieve now from cb's args -> */&mint->pubkey,
+ mint,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
+ }
+
mhd = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY,
port,
@@ -518,12 +775,17 @@ run (void *cls, char *const *args, const char *cfgfile,
EXITIF (NULL == mhd);
+ /* WARNING: a 'poll_mhd ()' call is here in the original merchant. Is that
+ mandatory ? */
+ GNUNET_CRYPTO_hash (wire, sizeof (*wire), &h_wire);
result = GNUNET_OK;
EXITIF_exit:
if (GNUNET_OK != result)
GNUNET_SCHEDULER_shutdown ();
-
+ GNUNET_free_non_null (keyfile);
+ if (GNUNET_OK != result)
+ GNUNET_SCHEDULER_shutdown ();
}
@@ -539,7 +801,10 @@ main (int argc, char *const *argv)
{
static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- GNUNET_GETOPT_OPTION_END
+ {'t', "temp", NULL,
+ gettext_noop ("Use temporary database tables"), GNUNET_NO,
+ &GNUNET_GETOPT_set_one, &dry},
+ GNUNET_GETOPT_OPTION_END
};