summaryrefslogtreecommitdiff
path: root/src/backend/melted
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/melted')
-rw-r--r--src/backend/melted/Makefile.am61
-rw-r--r--src/backend/melted/README9
-rw-r--r--src/backend/melted/copy.sh15
-rw-r--r--src/backend/melted/merchant.c173
-rw-r--r--src/backend/melted/merchant.h110
-rw-r--r--src/backend/melted/merchant_db.c348
-rw-r--r--src/backend/melted/merchant_db.h98
-rw-r--r--src/backend/melted/taler-merchant-httpd.c506
8 files changed, 1320 insertions, 0 deletions
diff --git a/src/backend/melted/Makefile.am b/src/backend/melted/Makefile.am
new file mode 100644
index 00000000..14b36e8a
--- /dev/null
+++ b/src/backend/melted/Makefile.am
@@ -0,0 +1,61 @@
+# This Makefile.am is in the public domain
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+if USE_COVERAGE
+ AM_CFLAGS = --coverage -O0
+ XLIB = -lgcov
+endif
+
+bin_PROGRAMS = \
+ taler-mint-httpd \
+ taler-merchant-httpd
+
+taler_mint_httpd_SOURCES = \
+ taler-mint-httpd.c taler-mint-httpd.h \
+ taler-mint-httpd_keystate.c taler-mint-httpd_keystate.h \
+ taler-mint-httpd_db.c taler-mint-httpd_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_mhd.c taler-mint-httpd_mhd.h \
+ taler-mint-httpd_admin.c taler-mint-httpd_admin.h \
+ taler-mint-httpd_deposit.c taler-mint-httpd_deposit.h \
+ taler-mint-httpd_withdraw.c taler-mint-httpd_withdraw.h \
+ taler-mint-httpd_refresh.c taler-mint-httpd_refresh.h
+taler_mint_httpd_LDADD = \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/mintdb/libtalermintdb.la \
+ -lmicrohttpd \
+ -ljansson \
+ -lgnunetutil \
+ -lpthread
+taler_merchant_httpd_SOURCES = \
+ taler-merchant-httpd.c \
+ merchant.c merchant.h \
+ merchant_db.c merchant_db.h \
+ taler-mint-httpd_keystate.c taler-mint-httpd_keystate.h \
+ taler-mint-httpd_db.c taler-mint-httpd_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_mhd.c taler-mint-httpd_mhd.h \
+ taler-mint-httpd_admin.c taler-mint-httpd_admin.h \
+ taler-mint-httpd_deposit.c taler-mint-httpd_deposit.h \
+ taler-mint-httpd_withdraw.c taler-mint-httpd_withdraw.h \
+ taler-mint-httpd_refresh.c taler-mint-httpd_refresh.h
+
+taler_merchant_httpd_LDADD = \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/mintdb/libtalermintdb.la \
+ -lmicrohttpd \
+ -ljansson \
+ -lgnunetutil \
+ -ltalerpq \
+ -lgnunetpostgres \
+ -lpq \
+ -lpthread
+
+if HAVE_DEVELOPER
+taler_mint_httpd_SOURCES += \
+ taler-mint-httpd_test.c taler-mint-httpd_test.h
+endif
diff --git a/src/backend/melted/README b/src/backend/melted/README
new file mode 100644
index 00000000..45c4fb80
--- /dev/null
+++ b/src/backend/melted/README
@@ -0,0 +1,9 @@
+Since the merchant's backend makes use of several routines that are native
+to the mint (in particular, those aimed to parse JSON object in HTTP POSTs),
+and since there is no possibility to export some of them in a shared library,
+then the files in this directory need to be moved *inside* the mint/src/mint
+directory in order to be compiled. Use 'copy.sh SRC DST' (STILL NOT TESTED)
+to copy the files in the desired location.
+
+Lastly, passing CFLAGS='-I/usr/include/postgresql' to ./configure seems to be
+mandatory, in order to compile the merchant http daemon.
diff --git a/src/backend/melted/copy.sh b/src/backend/melted/copy.sh
new file mode 100644
index 00000000..6b2fd098
--- /dev/null
+++ b/src/backend/melted/copy.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+# copy all the backend relevant files into the directory given
+# as argument. The intended use is to move back and forth those files
+# (since they are git'ed on the merchant's repository) as long as not
+# configure flag like --enable-merchant will be available from the mint
+
+# STILL NOT TESTED
+
+cp -t $2 \
+$1/Makefile.am \
+$1/merchant.c \
+$1/merchant_db.c \
+$1/merchant_db.h \
+$1/merchant.h \
+$1/taler-merchant-httpd.c
diff --git a/src/backend/melted/merchant.c b/src/backend/melted/merchant.c
new file mode 100644
index 00000000..f124a030
--- /dev/null
+++ b/src/backend/melted/merchant.c
@@ -0,0 +1,173 @@
+/*
+ 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_MintInfo **mints)
+{
+ char *mints_str;
+ char *token_nf; /* do no free (nf) */
+ char *mint_section;
+ char *mint_hostname;
+ char *mint_pubkey_enc;
+ struct MERCHANT_MintInfo *r_mints;
+ struct MERCHANT_MintInfo mint;
+ unsigned long long mint_port;
+ unsigned int cnt;
+ int OK;
+
+ OK = 0;
+ mints_str = NULL;
+ token_nf = NULL;
+ mint_section = NULL;
+ mint_hostname = NULL;
+ mint_pubkey_enc = 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));
+ EXITIF (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg,
+ mint_section,
+ "PORT",
+ &mint_port));
+ EXITIF (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ mint_section,
+ "PUBKEY",
+ &mint_pubkey_enc));
+ EXITIF (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_public_key_from_string (mint_pubkey_enc,
+ strlen (mint_pubkey_enc),
+ &mint.pubkey));
+ mint.hostname = mint_hostname;
+ mint.port = (uint16_t) mint_port;
+ GNUNET_array_append (r_mints, cnt, mint);
+ mint_hostname = NULL;
+ GNUNET_free (mint_pubkey_enc);
+ mint_pubkey_enc = 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);
+ GNUNET_free_non_null (mint_pubkey_enc);
+ if (!OK)
+ {
+ GNUNET_free_non_null (r_mints);
+ return GNUNET_SYSERR;
+ }
+
+ *mints = r_mints;
+ 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/melted/merchant.h b/src/backend/melted/merchant.h
new file mode 100644
index 00000000..c66131ed
--- /dev/null
+++ b/src/backend/melted/merchant.h
@@ -0,0 +1,110 @@
+/*
+ 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>
+ */
+
+#ifndef MERCHANT_H
+#define MERCHANT_H
+
+#include <gnunet/gnunet_common.h>
+#include <gnunet/gnunet_crypto_lib.h>
+
+/**
+ * A mint
+ */
+struct MERCHANT_MintInfo {
+ /**
+ * Hostname
+ */
+ char *hostname;
+
+ /**
+ * The public key of the mint
+ */
+ struct GNUNET_CRYPTO_EddsaPublicKey pubkey;
+
+ /**
+ * The port where the mint's service is running
+ */
+ uint16_t port;
+
+};
+
+
+/**
+ * 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_MintInfo **mints);
+
+
+GNUNET_NETWORK_STRUCT_BEGIN
+struct MERCHANT_WIREFORMAT_Sepa
+{
+ /**
+ * The international bank account number
+ */
+ char *iban;
+
+ /**
+ * Name of the bank account holder
+ */
+ char *name;
+
+ /**
+ *The bank identification code
+ */
+ char *bic;
+
+ /**
+ * The latest payout date when the payment corresponding to this account has
+ * to take place. A value of 0 indicates a transfer as soon as possible.
+ */
+ struct GNUNET_TIME_AbsoluteNBO payout;
+};
+GNUNET_NETWORK_STRUCT_END
+
+/**
+ * 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);
+
+
+/**
+ * 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);
+
+#endif /* MERCHANT_H */
diff --git a/src/backend/melted/merchant_db.c b/src/backend/melted/merchant_db.c
new file mode 100644
index 00000000..66ab5bcf
--- /dev/null
+++ b/src/backend/melted/merchant_db.c
@@ -0,0 +1,348 @@
+/*
+ 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_db.c
+ * @brief database helper functions used by the merchant
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <taler/taler_util.h>
+#include <taler/taler_pq_lib.h>
+#include "merchant_db.h"
+
+
+#define PQSQL_strerror(kind, cmd, res) \
+ GNUNET_log_from (kind, "merchant-db", \
+ "SQL %s failed at %s:%u with error: %s", \
+ cmd, __FILE__, __LINE__, PQresultErrorMessage (res));
+
+/**
+ * Shorthand for exit jumps.
+ */
+#define EXITIF(cond) \
+ do { \
+ if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
+ } while (0)
+
+
+/**
+ * Connect to postgresql database
+ *
+ * @param cfg the configuration handle
+ * @return connection to the postgresql database; NULL upon error
+ */
+PGconn *
+MERCHANT_DB_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ return GNUNET_POSTGRES_connect (cfg, "merchant-db");
+}
+
+
+/**
+ * Disconnect from the database
+ *
+ * @param conn database handle to close
+ */
+void
+MERCHANT_DB_disconnect (PGconn *conn)
+{
+ PQfinish (conn);
+}
+
+
+/**
+ * Initialize merchant tables
+ *
+ * @param conn the connection handle to postgres db.
+ * @param tmp GNUNET_YES if the tables are to be made temporary i.e. their
+ * contents are dropped when the @a conn is closed
+ * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
+ */
+int
+MERCHANT_DB_initialize (PGconn *conn, int tmp)
+{
+ const char *tmp_str = (1 == tmp) ? "TEMPORARY" : "";
+ char *sql;
+ PGresult *res;
+ ExecStatusType status;
+ int ret;
+
+ res = NULL;
+ (void) GNUNET_asprintf (&sql,
+ "BEGIN TRANSACTION;"
+ "CREATE %1$s TABLE IF NOT EXISTS contracts ("
+ "transaction_id SERIAL8 PRIMARY KEY,"
+ "amount INT4 NOT NULL,"
+ "amount_fraction INT4 NOT NULL,"
+ "description TEXT NOT NULL,"
+ "nounce BYTEA NOT NULL,"
+ "expiry INT8 NOT NULL,"
+ "product INT8 NOT NULL);"
+ "CREATE %1$s TABLE IF NOT EXISTS checkouts ("
+ "coin_pub BYTEA PRIMARY KEY,"
+ "transaction_id INT8 REFERENCES contracts(transaction_id),"
+ "amount INT4 NOT NULL,"
+ "amount_fraction INT4 NOT NULL,"
+ "coin_sig BYTEA NOT NULL);",
+ tmp_str);
+ ret = GNUNET_POSTGRES_exec (conn, sql);
+ (void) GNUNET_POSTGRES_exec (conn,
+ (GNUNET_OK == ret) ? "COMMIT;" : "ROLLBACK");
+ GNUNET_free (sql);
+ if (GNUNET_OK != ret)
+ return ret;
+
+ while (NULL != (res = PQgetResult (conn)))
+ {
+ status = PQresultStatus (res);
+ PQclear (res);
+ }
+
+ EXITIF (NULL == (res = PQprepare
+ (conn,
+ "contract_create",
+ "INSERT INTO contracts"
+ "(amount, amount_fraction, description,"
+ "nounce, expiry, product) VALUES"
+ "($1, $2, $3, $4, $5, $6)"
+ "RETURNING transaction_id",
+ 6, NULL)));
+ EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus(res)));
+ PQclear (res);
+
+ EXITIF (NULL == (res = PQprepare
+ (conn,
+ "get_contract_product",
+ "SELECT ("
+ "product"
+ ") FROM contracts "
+ "WHERE ("
+ "transaction_id=$1"
+ ")",
+ 1, NULL)));
+ EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus(res)));
+ PQclear (res);
+
+ EXITIF (NULL == (res = PQprepare
+ (conn,
+ "checkout_create",
+ "INSERT INTO checkouts ("
+ "coin_pub,"
+ "transaction_id,"
+ "amount,"
+ "amount_fraction,"
+ "coin_sig"
+ ") VALUES ("
+ "$1, $2, $3, $4, $5"
+ ")",
+ 5, NULL)));
+ EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus (res)));
+ PQclear (res);
+
+ EXITIF (NULL == (res = PQprepare
+ (conn,
+ "get_checkout_product",
+ "SELECT ("
+ "product"
+ ") FROM contracts "
+ "WHERE "
+ "transaction_id IN ("
+ "SELECT (transaction_id) FROM checkouts "
+ "WHERE coin_pub=$1"
+ ")",
+ 1, NULL)));
+ EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus (res)));
+ PQclear (res);
+
+ return GNUNET_OK;
+
+ EXITIF_exit:
+ if (NULL != res)
+ {
+ PQSQL_strerror (GNUNET_ERROR_TYPE_ERROR, "PQprepare", res);
+ PQclear (res);
+ }
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Inserts a contract record into the database and if successfull returns the
+ * serial number of the inserted row.
+ *
+ * @param conn the database connection
+ * @param expiry the time when the contract will expire
+ * @param amount the taler amount corresponding to the contract
+ * @param desc descripition of the contract
+ * @param nounce a random 64-bit nounce
+ * @param product description to identify a product
+ * @return -1 upon error; the serial id of the inserted contract upon success
+ */
+long long
+MERCHANT_DB_contract_create (PGconn *conn,
+ struct GNUNET_TIME_Absolute expiry,
+ struct TALER_Amount *amount,
+ const char *desc,
+ uint64_t nounce,
+ uint64_t product)
+{
+ PGresult *res;
+ uint64_t expiry_ms_nbo;
+ uint32_t value_nbo;
+ uint32_t fraction_nbo;
+ uint64_t nounce_nbo;
+ ExecStatusType status;
+ uint64_t id;
+ /* ported. To be tested/compiled */
+ struct TALER_PQ_QueryParam params[] = {
+ TALER_PQ_query_param_uint32 (&value_nbo),
+ TALER_PQ_query_param_uint32 (&fraction_nbo),
+ /* a *string* is being put in the following statement,
+ though the API talks about a *blob*. Will this be liked by
+ the DB ? */
+ TALER_PQ_query_param_fixed_size (desc, strlen(desc)),
+ TALER_PQ_query_param_uint64 (&nounce_nbo),
+ TALER_PQ_query_param_uint64 (&expiry_ms_nbo),
+ TALER_PQ_query_param_uint64 (&product),
+ TALER_PQ_query_param_end
+ };
+ struct TALER_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_uint64 ("transaction_id", &id),
+ TALER_PQ_result_spec_end
+ };
+
+ expiry_ms_nbo = GNUNET_htonll (expiry.abs_value_us);
+ value_nbo = htonl (amount->value);
+ fraction_nbo = htonl (amount->fraction);
+ nounce_nbo = GNUNET_htonll (nounce);
+ product = GNUNET_htonll (product);
+ /* NOTE: the statement is prepared by MERCHANT_DB_initialize function */
+ res = TALER_PQ_exec_prepared (conn, "contract_create", params);
+ status = PQresultStatus (res);
+ EXITIF (PGRES_TUPLES_OK != status);
+ EXITIF (1 != PQntuples (res));
+ EXITIF (GNUNET_YES != TALER_PQ_extract_result (res, rs, 0));
+ PQclear (res);
+ return GNUNET_ntohll ((uint64_t) id);
+
+ EXITIF_exit:
+ PQclear (res);
+ return -1;
+}
+
+long long
+MERCHANT_DB_get_contract_product (PGconn *conn,
+ uint64_t contract_id)
+{
+ PGresult *res;
+ uint64_t product;
+ ExecStatusType status;
+ struct TALER_PQ_QueryParam params[] = {
+ TALER_PQ_query_param_uint64 (&contract_id),
+ TALER_PQ_query_param_end
+ };
+ struct TALER_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_uint64 ("product", &product),
+ TALER_PQ_result_spec_end
+ };
+
+ contract_id = GNUNET_htonll (contract_id);
+ res = TALER_PQ_exec_prepared (conn, "get_contract_product", params);
+ status = PQresultStatus (res);
+ EXITIF (PGRES_TUPLES_OK != status);
+ EXITIF (1 != PQntuples (res));
+ EXITIF (GNUNET_YES != TALER_PQ_extract_result (res, rs, 0));
+ PQclear (res);
+ return GNUNET_ntohll ((uint64_t) product);
+
+ EXITIF_exit:
+ PQclear (res);
+ return -1;
+}
+
+unsigned int
+MERCHANT_DB_checkout_create (PGconn *conn,
+ struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub,
+ uint64_t transaction_id,
+ struct TALER_Amount *amount,
+ struct GNUNET_CRYPTO_rsa_Signature *coin_sig)
+{
+ PGresult *res;
+ ExecStatusType status;
+ uint32_t value_nbo;
+ uint32_t fraction_nbo;
+ struct TALER_PQ_QueryParam params[] = {
+ TALER_PQ_query_param_rsa_public_key (coin_pub),
+ TALER_PQ_query_param_uint64 (&transaction_id),
+ TALER_PQ_query_param_uint32 (&value_nbo),
+ TALER_PQ_query_param_uint32 (&fraction_nbo),
+ TALER_PQ_query_param_rsa_signature (coin_sig),
+ TALER_PQ_query_param_end
+ };
+
+ transaction_id = GNUNET_htonll (transaction_id);
+ value_nbo = htonl (amount->value);
+ fraction_nbo = htonl (amount->fraction);
+ res = TALER_PQ_exec_prepared (conn, "checkout_create", params);
+ status = PQresultStatus (res);
+ EXITIF (PGRES_COMMAND_OK != status);
+ PQclear (res);
+ return GNUNET_OK;
+
+ EXITIF_exit:
+ PQclear (res);
+ return GNUNET_SYSERR;
+}
+
+
+long long
+MERCHANT_DB_get_checkout_product (PGconn *conn,
+ struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub)
+{
+ PGresult *res;
+ ExecStatusType status;
+ uint64_t product;
+ struct TALER_PQ_QueryParam params[] = {
+ TALER_PQ_query_param_rsa_public_key (coin_pub),
+ TALER_PQ_query_param_end
+ };
+ struct TALER_PQ_ResultSpec rs[] = {
+ TALER_PQ_result_spec_uint64 ("product", &product),
+ TALER_PQ_result_spec_end
+ };
+
+ product = -1;
+ res = TALER_PQ_exec_prepared (conn, "get_checkout_product", params);
+ status = PQresultStatus (res);
+ EXITIF (PGRES_TUPLES_OK != status);
+ if (0 == PQntuples (res))
+ {
+ TALER_LOG_DEBUG ("Checkout not found for given coin");
+ goto EXITIF_exit;
+ }
+ EXITIF (1 != PQntuples (res));
+ EXITIF (GNUNET_YES != TALER_PQ_extract_result (res, rs, 0));
+ PQclear (res);
+ return GNUNET_ntohll ((uint64_t) product);
+
+ EXITIF_exit:
+ PQclear (res);
+ return -1;
+}
+/* end of merchant-db.c */
diff --git a/src/backend/melted/merchant_db.h b/src/backend/melted/merchant_db.h
new file mode 100644
index 00000000..bf334989
--- /dev/null
+++ b/src/backend/melted/merchant_db.h
@@ -0,0 +1,98 @@
+/*
+ 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_db.h
+ * @brief database helper functions used by the merchant
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+
+#ifndef MERCHANT_DB_H
+#define MERCHANT_DB_H
+
+#include <gnunet/gnunet_postgres_lib.h>
+#include <taler/taler_util.h>
+
+/**
+ * Connect to postgresql database
+ *
+ * @param cfg the configuration handle
+ * @return connection to the postgresql database; NULL upon error
+ */
+PGconn *
+MERCHANT_DB_connect (const struct GNUNET_CONFIGURATION_Handle *cfg);
+
+
+/**
+ * Disconnect from the database
+ *
+ * @param conn database handle to close
+ */
+void
+MERCHANT_DB_disconnect (PGconn *conn);
+
+
+/**
+ * Initialize merchant tables
+ *
+ * @param conn the connection handle to postgres db.
+ * @param tmp GNUNET_YES if the tables are to be made temporary i.e. their
+ * contents are dropped when the @a conn is closed
+ * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
+ */
+int
+MERCHANT_DB_initialize (PGconn *conn, int tmp);
+
+
+/**
+ * Inserts a contract record into the database and if successfull returns the
+ * serial number of the inserted row.
+ *
+ * @param conn the database connection
+ * @param expiry the time when the contract will expire
+ * @param amount the taler amount corresponding to the contract
+ * @param desc descripition of the contract
+ * @param nounce a random 64-bit nounce
+ * @param product description to identify a product
+ * @return -1 upon error; the serial id of the inserted contract upon success
+ */
+long long
+MERCHANT_DB_contract_create (PGconn *conn,
+ struct GNUNET_TIME_Absolute expiry,
+ struct TALER_Amount *amount,
+ const char *desc,
+ uint64_t nounce,
+ uint64_t product);
+
+long long
+MERCHANT_DB_get_contract_product (PGconn *conn,
+ uint64_t contract_id);
+
+unsigned int
+MERCHANT_DB_checkout_create (PGconn *conn,
+ struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub,
+ uint64_t transaction_id,
+ struct TALER_Amount *amount,
+ struct GNUNET_CRYPTO_rsa_Signature *coin_sig);
+
+
+long long
+MERCHANT_DB_get_checkout_product (PGconn *conn,
+ struct GNUNET_CRYPTO_rsa_PublicKey *coin_pub);
+
+#endif /* MERCHANT_DB_H */
+
+/* end of merchant-db.h */
diff --git a/src/backend/melted/taler-merchant-httpd.c b/src/backend/melted/taler-merchant-httpd.c
new file mode 100644
index 00000000..336f8915
--- /dev/null
+++ b/src/backend/melted/taler-merchant-httpd.c
@@ -0,0 +1,506 @@
+/*
+ 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/backend/taler-merchant-httpd.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 <taler/taler_json_lib.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 "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.
+ */
+#define EXITIF(cond) \
+ do { \
+ 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
+ */
+unsigned short port;
+
+/**
+ * The MHD Daemon
+ */
+static struct MHD_Daemon *mhd;
+
+/**
+ * Connection handle to the our database
+ */
+PGconn *db_conn;
+
+/**
+ * Which currency is used by this mint?
+ * (verbatim copy from mint's code, just to make this
+ * merchant's source compile)
+ */
+char *TMH_mint_currency_string;
+
+/* As above */
+struct TALER_MINTDB_Plugin *TMH_plugin;
+
+
+/**
+ * As above, though the merchant does need some form of
+ * configuration
+ */
+struct GNUNET_CONFIGURATION_Handle *cfg;
+
+
+/**
+ * As above
+ */
+int TMH_test_mode;
+
+
+/**
+ * As above
+ */
+char *TMH_mint_directory;
+
+
+/**
+ * As above
+ */
+struct GNUNET_CRYPTO_EddsaPublicKey TMH_master_public_key;
+
+/**
+ * As above
+ */
+char *TMH_expected_wire_format;
+
+/**
+ * Shutdown task identifier
+ */
+static struct GNUNET_SCHEDULER_Task *shutdown_task;
+
+/**
+ * Our wireformat
+ */
+static struct MERCHANT_WIREFORMAT_Sepa *wire;
+
+/**
+ * Should we do a dry run where temporary tables are used for storing the data.
+ */
+static int dry;
+
+/**
+ * Global return code
+ */
+static int result;
+
+/**
+* Return the given message to the other end of connection
+* @msg (0-terminated) message to show
+* @param connection a MHD connection
+* @param resp where to store the response for the calling function
+* @return HTTP status code reflecting the operation outcome
+*
+*/
+
+static unsigned int
+generate_message (struct MHD_Response **resp, const char *msg) // this parameter was preceded by a '_' in its original file. Why?
+{
+
+ unsigned int ret;
+
+ *resp = MHD_create_response_from_buffer (strlen (msg), (void *) msg,
+ MHD_RESPMEM_PERSISTENT);
+ ret = 200;
+ return ret;
+
+
+}
+
+/**
+* Generate the 'hello world' response
+* @param connection a MHD connection
+* @param resp where to store the response for the calling function
+* @return HTTP status code reflecting the operation outcome
+*
+*/
+
+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";
+ unsigned int ret;
+
+ *resp = MHD_create_response_from_buffer (strlen (hello), (void *) hello,
+ MHD_RESPMEM_PERSISTENT);
+ ret = 200;
+ return ret;
+
+
+}
+
+
+/**
+* Manage a non 200 HTTP status. I.e. it shows a 'failure' page to
+* the client
+* @param connection the channel thorugh which send the message
+* @status the HTTP status to examine
+* @return GNUNET_OK on successful message sending, GNUNET_SYSERR upon error
+*
+*/
+
+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> \
+<h3>The resource you are looking for is not found.</h3> \
+</center></body></html>";
+ static char page_500[]="\
+<!DOCTYPE html> <html><title>Internal Server Error</title><body><center> \
+<h3>The server experienced an internal error and hence cannot serve your \
+request</h3></center></body></html>";
+ struct MHD_Response *resp;
+ char *page;
+ size_t size;
+#define PAGE(number) \
+ do {page=page_ ## number; size=sizeof(page_ ## number)-1;} while(0)
+
+ GNUNET_assert (400 <= status);
+ resp = NULL;
+ switch (status)
+ {
+ case 404:
+ PAGE(404);
+ break;
+ default:
+ status = 500;
+ case 500:
+ PAGE(500);
+ }
+#undef PAGE
+
+ EXITIF (NULL == (resp = MHD_create_response_from_buffer (size,
+ page,
+ MHD_RESPMEM_PERSISTENT)));
+ EXITIF (MHD_YES != MHD_queue_response (connection, status, resp));
+ MHD_destroy_response (resp);
+ return GNUNET_OK;
+
+ EXITIF_exit:
+ if (NULL != resp)
+ MHD_destroy_response (resp);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+* 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;
+}
+
+
+/**
+ * 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
+ * must call MHD callbacks to provide content to give back to the
+ * client and return an HTTP status code (i.e. #MHD_HTTP_OK,
+ * #MHD_HTTP_NOT_FOUND, etc.).
+ *
+ * @param cls argument given together with the function
+ * pointer when the handler was registered with MHD
+ * @param url the requested url
+ * @param method the HTTP method used (#MHD_HTTP_METHOD_GET,
+ * #MHD_HTTP_METHOD_PUT, etc.)
+ * @param version the HTTP version string (i.e.
+ * #MHD_HTTP_VERSION_1_1)
+ * @param upload_data the data being uploaded (excluding HEADERS,
+ * for a POST that fits into memory and that is encoded
+ * with a supported encoding, the POST data will NOT be
+ * given in upload_data and is instead available as
+ * part of #MHD_get_connection_values; very large POST
+ * data *will* be made available incrementally in
+ * @a upload_data)
+ * @param upload_data_size set initially to the size of the
+ * @a upload_data provided; the method must update this
+ * value to the number of bytes NOT processed;
+ * @param con_cls pointer that the callback can set to some
+ * address and that will be preserved by MHD for future
+ * calls for this request; since the access handler may
+ * be called many times (i.e., for a PUT/POST operation
+ * with plenty of upload data) this allows the application
+ * to easily associate some request-specific state.
+ * If necessary, this state can be cleaned up in the
+ * global #MHD_RequestCompletedCallback (which
+ * can be set with the #MHD_OPTION_NOTIFY_COMPLETED).
+ * Initially, `*con_cls` will be NULL.
+ * @return #MHD_YES if the connection was handled successfully,
+ * #MHD_NO if the socket must be closed due to a serios
+ * error while handling the request
+ */
+
+static int
+url_handler (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data,
+ size_t *upload_data_size,
+ void **connection_cls)
+{
+
+ unsigned int status;
+ unsigned int no_destroy;
+ struct MHD_Response *resp;
+ struct TALER_Amount price;
+ json_t json_price;
+ json_t *root;
+ int res;
+ char *desc;
+
+ #define URL_HELLO "/hello"
+ #define URL_CONTRACT "/contract"
+ no_destroy = 0;
+ resp = NULL;
+ status = 500;
+ if (0 == strncasecmp (url, URL_HELLO, sizeof (URL_HELLO)))
+ {
+ if (0 == strcmp (MHD_HTTP_METHOD_GET, method))
+ status = generate_hello (&resp); //TBD
+ else
+ GNUNET_break (0);
+ }
+
+ // 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
+
+ /*
+ 1. parse the json
+ 2. generate the contract
+ 3. pack the contract's json
+ 4. return it
+ */
+
+ res = TMH_PARSE_post_json (connection,
+ connection_cls,
+ upload_data,
+ upload_data_size,
+ &root);
+
+ if (GNUNET_SYSERR == res)
+ return MHD_NO;
+ if ( (GNUNET_NO == res) || (NULL == root) )
+ return MHD_YES;
+
+ /* not really needed for getting just a string. Though it'd be very handy
+ to enhace the mint's JSON-parsing capabilities with the merchant's needs.
+
+ struct TMH_PARSE_FieldSpecification spec[] = {
+ TMH_PARSE_member_variable ("desc", (void **) &desc, &desc_len),
+ TMH_PARSE_member_amount ("price", &price),
+ TMH_PARSE_MEMBER_END
+ };
+ res = TMH_PARSE_json_data (connection,
+ root,
+ spec); */
+ /*
+
+ The expected JSON :
+
+ {
+ "desc" : "some description",
+ "price" : a JSON compliant TALER_Amount objet
+ }
+
+ */
+
+ if (!json_unpack (root, "{s:s, s:o}", "desc", &desc, "price", &json_price))
+ status = generate_message (&resp, "unable to parse /contract JSON");
+ else
+ {
+ if (GNUNET_OK != TALER_json_to_amount (&json_price, &price))
+ status = generate_message (&resp, "unable to parse `price' field in /contract JSON");
+ else
+ {
+ /* Let's generate this contract! */
+ /* First, initialize the DB, since it'll be stored there */
+
+
+
+
+
+ }
+
+ }
+
+
+
+
+
+
+ }
+
+ if (NULL != resp)
+ {
+ EXITIF (MHD_YES != MHD_queue_response (connection, status, resp));
+ 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;
+
+}
+
+/**
+ * Shutdown task (magically invoked when the application is being
+ * quit)
+ *
+ * @param cls NULL
+ * @param tc scheduler task context
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+
+ if (NULL != mhd)
+ {
+ MHD_stop_daemon (mhd);
+ mhd = NULL;
+ }
+
+}
+
+
+/**
+ * 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!)
+ * @param config configuration
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *config)
+{
+
+ port = 9966;
+
+
+ EXITIF (NULL == (wire = TALER_MERCHANT_parse_wireformat_sepa (config)));
+ EXITIF (GNUNET_OK != MERCHANT_DB_initialize (db_conn, dry));
+
+ shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+ &do_shutdown, NULL);
+
+ mhd = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY,
+ port,
+ NULL, NULL,
+ &url_handler, NULL,
+ MHD_OPTION_END);
+
+
+ EXITIF (NULL == mhd);
+ result = GNUNET_OK;
+
+ EXITIF_exit:
+ if (GNUNET_OK != result)
+ GNUNET_SCHEDULER_shutdown ();
+
+
+}
+
+/**
+ * The main function of the serve tool
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+
+ 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
+ };
+
+
+ if (GNUNET_OK !=
+ GNUNET_PROGRAM_run (argc, argv,
+ "taler-merchant-serve",
+ "Serve merchant's HTTP interface",
+ options, &run, NULL))
+ return 3;
+ return (GNUNET_OK == result) ? 0 : 1;
+
+
+
+}