commit 6d0eb81a357adccd185b631b2793a840d779c162
parent daa8104795567076745f8062a0aaffa0d1eceb0f
Author: Marcello Stanisci <marcello.stanisci@inria.fr>
Date: Mon, 26 Sep 2016 16:50:57 +0200
Merge branch 'receiver'
Conflicts:
src/backend/taler-merchant-httpd.c
Diffstat:
9 files changed, 161 insertions(+), 85 deletions(-)
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c
@@ -46,10 +46,18 @@
#define UNIX_BACKLOG 500
/**
- * NULL-terminated array of all merchants instances known
- * by this backend
+ * Hashmap pointing at merchant instances by 'id'. An 'id' is
+ * just a string that identifies a merchant instance. When a frontend
+ * needs to specify an instance to the backend, it does so by 'id'
*/
-struct MerchantInstance **instances;
+struct GNUNET_CONTAINER_MultiHashMap *by_id_map;
+
+/**
+ * Hashmap pointing at merchant instances by public key. This map
+ * is mainly used to check whether there is more than one instance
+ * using the same key
+ */
+struct GNUNET_CONTAINER_MultiHashMap *by_kpub_map;
/**
* The port we are running on
@@ -225,6 +233,22 @@ url_handler (void *cls,
/**
+ * Callback that frees all the elements in the hashmap
+ *
+ * @param cls closure
+ * @param key current key
+ * @param value current value
+ */
+int
+hashmap_free (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
+{
+ GNUNET_free (value);
+ return GNUNET_YES;
+}
+
+/**
* Shutdown task (magically invoked when the application is being
* quit)
*
@@ -250,17 +274,14 @@ do_shutdown (void *cls)
}
TMH_EXCHANGES_done ();
TMH_AUDITORS_done ();
- if (NULL != instances)
- {
- unsigned int i;
- for (i=0; NULL != instances[i]; i++)
- {
- json_decref (instances[i]->j_wire);
- GNUNET_free (instances[i]->id);
- GNUNET_free (instances[i]);
- }
- }
+ GNUNET_CONTAINER_multihashmap_iterate (by_id_map,
+ &hashmap_free,
+ NULL);
+ if (NULL != by_id_map)
+ GNUNET_CONTAINER_multihashmap_destroy (by_id_map);
+ if (NULL != by_kpub_map)
+ GNUNET_CONTAINER_multihashmap_destroy (by_kpub_map);
}
@@ -403,6 +424,9 @@ instances_iterator_cb (void *cls,
struct MerchantInstance *mi;
struct IterateInstancesCls *iic;
struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
+ /* used as hashmap keys */
+ struct GNUNET_HashCode h_pk;
+ struct GNUNET_HashCode h_id;
iic = cls;
substr = strstr (section, "merchant-instance-");
@@ -454,7 +478,11 @@ instances_iterator_cb (void *cls,
&mi->pubkey.eddsa_pub);
GNUNET_free (pk);
- /** To free or not to free **/
+ /**
+ * FIXME: 'token' must NOT be freed, as it is handled by the
+ * gnunet_configuration facility. OTOH mi->id does need to be freed,
+ * because it is a duplicate.
+ */
mi->id = GNUNET_strdup (token + 1);
if (0 == strcmp ("default", mi->id))
iic->default_instance = GNUNET_YES;
@@ -485,14 +513,52 @@ instances_iterator_cb (void *cls,
"Failed to hash wireformat\n");
iic->ret |= GNUNET_SYSERR;
}
- #if EXTRADEBUG
+ #define EXTRADEBUG
+ #ifdef EXTRADEBUGG
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Found wireformat instance:\n");
json_dumpf (mi->j_wire, stdout, 0);
printf ("\n");
#endif
- GNUNET_array_append (instances, iic->current_index, mi);
+ GNUNET_CRYPTO_hash (mi->id,
+ strlen(mi->id),
+ &h_id);
+ GNUNET_CRYPTO_hash (&mi->pubkey.eddsa_pub,
+ sizeof (struct GNUNET_CRYPTO_EddsaPublicKey),
+ &h_pk);
+ if (GNUNET_OK !=
+ GNUNET_CONTAINER_multihashmap_put (by_id_map,
+ &h_id,
+ mi,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to put an entry into the 'by_id' hashmap\n");
+ iic->ret |= GNUNET_SYSERR;
+ }
+ #ifdef EXTRADEBUG
+ else {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Added element at %p, by by-id key %s of '%s' in hashmap\n",
+ mi,
+ GNUNET_h2s (&h_id),
+ mi->id);
+ GNUNET_assert (NULL != GNUNET_CONTAINER_multihashmap_get (by_id_map,
+ &h_id));
+ }
+ #endif
+
+ if (GNUNET_OK !=
+ GNUNET_CONTAINER_multihashmap_put (by_kpub_map,
+ &h_pk,
+ mi,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to put an entry into the 'by_kpub_map' hashmap\n");
+ iic->ret |= GNUNET_SYSERR;
+ }
}
/**
@@ -511,16 +577,29 @@ instances_iterator_cb (void *cls,
struct MerchantInstance *
get_instance (struct json_t *json)
{
- unsigned int i;
struct json_t *receiver;
+ const char *receiver_str;
+ struct GNUNET_HashCode h_receiver;
+ struct MerchantInstance *ret;
+
/*FIXME who decrefs receiver?*/
if (NULL == (receiver = json_object_get (json, "receiver")))
receiver = json_string ("default");
- for (i=0; NULL != instances[i]; i++)
- if (0 == strcmp (json_string_value (receiver), instances[i]->id))
- return instances[i];
- return NULL;
+ receiver_str = json_string_value (receiver);
+ GNUNET_CRYPTO_hash (receiver_str,
+ strlen (receiver_str),
+ &h_receiver);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Looking for by-id key %s of '%s' in hashmap\n",
+ GNUNET_h2s (&h_receiver),
+ receiver_str);
+ /* We're fine if that returns NULL, the calling routine knows how
+ to handle that */
+ ret = GNUNET_CONTAINER_multihashmap_get (by_id_map,
+ &h_receiver);
+ GNUNET_break (NULL != ret);
+ return ret;
}
/**
@@ -581,38 +660,6 @@ iterate_instances (const struct GNUNET_CONFIGURATION_Handle *config,
GNUNET_PLUGIN_unload (lib_name,
iic->plugin);
GNUNET_free (lib_name);
- GNUNET_array_append (instances, iic->current_index, NULL);
- #if EXTRADEBUG
- unsigned int i;
- for (i=0; NULL != instances[i]; i++)
- {
- char *hash;
- char *priv;
- char *pub;
-
- hash =
- GNUNET_STRINGS_data_to_string_alloc (&instances[i]->h_wire,
- sizeof (struct GNUNET_HashCode));
- priv =
- GNUNET_STRINGS_data_to_string_alloc (&instances[i]->privkey.eddsa_priv,
- sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
- pub =
- GNUNET_STRINGS_data_to_string_alloc (&instances[i]->pubkey.eddsa_pub,
- sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "instances[%d]: id=%s,\nj_wire=%s,\nj_hash=%s,\npriv=%s,\npub=%s\n",
- i,
- instances[i]->id,
- json_dumps (instances[i]->j_wire, JSON_INDENT (2)),
- hash,
- priv,
- pub);
-
- GNUNET_free (hash);
- GNUNET_free (priv);
- GNUNET_free (pub);
- }
- #endif
GNUNET_free (iic);
return GNUNET_OK;
@@ -666,6 +713,20 @@ run (void *cls,
return;
}
+ if (NULL ==
+ (by_id_map = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO)))
+ {
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ if (NULL ==
+ (by_kpub_map = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO)))
+ {
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
if (GNUNET_SYSERR ==
GNUNET_CONFIGURATION_get_value_time (config,
"merchant",
diff --git a/src/backend/taler-merchant-httpd.h b/src/backend/taler-merchant-httpd.h
@@ -46,8 +46,8 @@ struct IterateInstancesCls {
/**
* Current index in the global array of #MerchantInstance
- * types. Used by the callback in order to properly place
- * the instance it is parsing
+ * types. Used by the callback in order to know which index
+ * is associated to the element being processed.
*/
unsigned int current_index;
diff --git a/src/backend/taler-merchant-httpd_contract.c b/src/backend/taler-merchant-httpd_contract.c
@@ -259,6 +259,7 @@ MH_handler_contract (struct TMH_RequestHandler *rh,
GNUNET_assert (GNUNET_OK ==
TALER_JSON_hash (jcontract,
&contract.h_contract));
+ contract.merchant_pub = mi->pubkey;
GNUNET_CRYPTO_eddsa_sign (&mi->privkey.eddsa_priv,
&contract.purpose,
&contract_sig);
diff --git a/src/backend/taler-merchant-httpd_pay.c b/src/backend/taler-merchant-httpd_pay.c
@@ -922,6 +922,9 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
}
pc->mi = get_instance (root);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "/pay: picked instance %s\n",
+ pc->mi->id);
if (NULL == pc->mi)
{
@@ -946,6 +949,7 @@ MH_handler_pay (struct TMH_RequestHandler *rh,
TALER_amount_hton (&cp.max_fee,
&pc->max_fee);
cp.h_contract = pc->h_contract;
+ cp.merchant_pub = pc->mi->pubkey;
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_CONTRACT,
&cp.purpose,
diff --git a/src/backend/taler-merchant-httpd_track-transaction.c b/src/backend/taler-merchant-httpd_track-transaction.c
@@ -33,6 +33,11 @@
/**
+ * Map containing all the known merchant instances
+ */
+extern struct GNUNET_CONTAINER_MultiHashMap *by_id_map;
+
+/**
* How long to wait before giving up processing with the exchange?
*/
#define TRACK_TIMEOUT (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30))
@@ -767,8 +772,6 @@ coin_cb (void *cls,
tcc));
}
-extern struct MerchantInstance **instances;
-
/**
* Handle a "/track/transaction" request.
*
@@ -790,8 +793,8 @@ MH_handler_track_transaction (struct TMH_RequestHandler *rh,
unsigned long long transaction_id;
const char *str;
const char *receiver;
- unsigned int i;
int ret;
+ struct GNUNET_HashCode h_receiver;
if (NULL == *connection_cls)
{
@@ -847,12 +850,12 @@ MH_handler_track_transaction (struct TMH_RequestHandler *rh,
"receiver");
if (NULL == receiver)
receiver = "default";
-
+ GNUNET_CRYPTO_hash (receiver,
+ strlen (receiver),
+ &h_receiver);
tctx->mi = NULL;
- for (i=0; NULL != instances[i]; i++)
- if (0 == strcmp (receiver, instances[i]->id))
- tctx->mi = instances[i];
-
+ GNUNET_assert (NULL != (tctx->mi = GNUNET_CONTAINER_multihashmap_get (by_id_map,
+ &h_receiver)));
if (NULL == tctx->mi)
return TMH_RESPONSE_reply_bad_request (connection,
"unknown receiver");
diff --git a/src/lib/merchant_api_track_transaction.c b/src/lib/merchant_api_track_transaction.c
@@ -252,9 +252,10 @@ TALER_MERCHANT_track_transaction (struct GNUNET_CURL_Context *ctx,
tdo->cb = track_transaction_cb;
tdo->cb_cls = track_transaction_cb_cls;
GNUNET_asprintf (&tdo->url,
- "%s/track/transaction?id=%llu",
+ "%s/track/transaction?id=%llu&receiver=%s",
backend_uri,
- (unsigned long long) transaction_id);
+ (unsigned long long) transaction_id,
+ receiver);
eh = curl_easy_init ();
GNUNET_assert (CURLE_OK ==
curl_easy_setopt (eh,
diff --git a/src/lib/test_merchant_api.c b/src/lib/test_merchant_api.c
@@ -1670,12 +1670,12 @@ interpreter_run (void *cls)
GNUNET_assert (NULL != ref);
cmd->details.track_transfer.tdo =
TALER_MERCHANT_track_transfer (ctx,
- MERCHANT_URI,
- receiver,
- &ref->details.check_bank_transfer.wtid,
- EXCHANGE_URI,
- &track_transfer_cb,
- is);
+ MERCHANT_URI,
+ receiver,
+ &ref->details.check_bank_transfer.wtid,
+ EXCHANGE_URI,
+ &track_transfer_cb,
+ is);
return;
case OC_TRACK_TRANSACTION:
ref = find_command (is,
@@ -2177,9 +2177,6 @@ int
main (int argc,
char * const *argv)
{
- /* Value from "gnunet-ecc -p test_merchant.priv" */
- const char *merchant_pub_str
- = "5TRNSWAWHKBJ7G4T3PKRCQA6MCB3MX82F4M2XXS1653KE1V8RFPG";
struct GNUNET_OS_Process *proc;
struct GNUNET_OS_Process *exchanged;
struct GNUNET_OS_Process *merchantd;
@@ -2187,6 +2184,9 @@ main (int argc,
struct GNUNET_CONFIGURATION_Handle *cfg;
unsigned int cnt;
struct GNUNET_SIGNAL_Context *shc_chld;
+ char *instance_section;
+ char *keyfile;
+ struct GNUNET_CRYPTO_EddsaPrivateKey *kpriv;
unsetenv ("XDG_DATA_HOME");
unsetenv ("XDG_CONFIG_HOME");
@@ -2204,7 +2204,20 @@ main (int argc,
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Using non default receiver '%s'\n",
receiver);
+ GNUNET_asprintf (&instance_section,
+ "merchant-instance-%s",
+ receiver);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ instance_section,
+ "KEYFILE",
+ &keyfile));
+ kpriv = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile);
+ GNUNET_CRYPTO_eddsa_key_get_public (kpriv, &merchant_pub.eddsa_pub);
+
+ GNUNET_free (keyfile);
+ GNUNET_free (instance_section);
db = TALER_MERCHANTDB_plugin_load (cfg);
if (NULL == db)
{
@@ -2221,12 +2234,6 @@ main (int argc,
TALER_MERCHANTDB_plugin_unload (db);
GNUNET_CONFIGURATION_destroy (cfg);
-
- GNUNET_assert (GNUNET_OK ==
- GNUNET_STRINGS_string_to_data (merchant_pub_str,
- strlen (merchant_pub_str),
- &merchant_pub,
- sizeof (merchant_pub)));
proc = GNUNET_OS_start_process (GNUNET_NO,
GNUNET_OS_INHERIT_STD_ALL,
NULL, NULL, NULL,
diff --git a/src/lib/test_merchant_api.conf b/src/lib/test_merchant_api.conf
@@ -22,9 +22,6 @@ PORT = 8082
# FIXME: is this one used?
HOSTNAME = localhost
-# Where is our private key?
-KEYFILE = test_merchant.priv
-
# How quickly do we want the exchange to send us our money?
# Used only if the frontend does not specify a value.
# FIXME: EDATE is a bit short, 'execution_delay'?
@@ -39,7 +36,7 @@ WIREFORMAT = test
# If set, this option will drive the testcase so that
# `INSTANCE' will be the used merchant instance. Otherwise
# we use the 'default' instance
-INSTANCE = tor
+INSTANCE = tor
[merchant-exchange-test]
URI = http://localhost:8081/
@@ -52,7 +49,7 @@ KEYFILE = test_merchant.priv
TEST_RESPONSE_FILE = ${TALER_CONFIG_HOME}/merchant/wire/test.json
[merchant-instance-tor]
-KEYFILE = test_merchant.priv
+KEYFILE = tor_merchant.priv
[tor-wireformat]
TEST_RESPONSE_FILE = ${TALER_CONFIG_HOME}/merchant/wire/test.json
diff --git a/src/lib/tor_merchant.priv b/src/lib/tor_merchant.priv
@@ -0,0 +1 @@
+=¨³‚WÁË#K®-…ËzNÌ;qr®“o<{ënNºý
+\ No newline at end of file