merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

commit 2fbdccc8dc18157e2df7486e4ecedee343c81d8d
parent b3c7ea82a6a1ade4a310a6958c232207560d4c1a
Author: Marcello Stanisci <marcello.stanisci@inria.fr>
Date:   Tue, 27 Oct 2015 21:58:14 +0100

Adding context event loop, plus some code cleaning

Diffstat:
Dsrc/backend/melted/Makefile.am | 62--------------------------------------------------------------
Dsrc/backend/melted/README | 9---------
Dsrc/backend/melted/copy.sh | 17-----------------
Dsrc/backend/melted/merchant.c | 173-------------------------------------------------------------------------------
Dsrc/backend/melted/merchant.conf | 18------------------
Dsrc/backend/melted/merchant.h | 110-------------------------------------------------------------------------------
Dsrc/backend/melted/merchant_db.c | 354-------------------------------------------------------------------------------
Dsrc/backend/melted/merchant_db.h | 101-------------------------------------------------------------------------------
Dsrc/backend/melted/myconf.sh | 3---
Dsrc/backend/melted/taler-merchant-httpd.c | 821-------------------------------------------------------------------------------
Msrc/backend/merchant.c | 6+++---
Msrc/backend/taler-merchant-httpd.c | 178+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Msrc/include/merchant.h | 49++++++-------------------------------------------
Msrc/tests/Makefile.am | 2+-
Dsrc/tests/merchant.c | 173-------------------------------------------------------------------------------
15 files changed, 116 insertions(+), 1960 deletions(-)

diff --git a/src/backend/melted/Makefile.am b/src/backend/melted/Makefile.am @@ -1,62 +0,0 @@ -# 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 \ - -ltalermint \ - -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 @@ -1,9 +0,0 @@ -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 @@ -1,17 +0,0 @@ -#!/bin/bash -# copy all the backend relevant files from the first to the second -# directory given in the arguments. -# 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 \ -$1/merchant.conf diff --git a/src/backend/melted/merchant.c b/src/backend/melted/merchant.c @@ -1,173 +0,0 @@ -/* - 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.conf b/src/backend/melted/merchant.conf @@ -1,18 +0,0 @@ -[merchant] -PORT = 9966 -HOSTNAME = localhost -TRUSTED_MINTS = taler -KEYFILE = merchant.priv - -[mint-taler] -HOSTNAME = demo.taler.net -PORT = 80 -PUBKEY = Q1WVGRGC1F4W7RYC6M23AEGFEXQEHQ730K3GG0B67VPHQSRR75H0 - -[merchant-db] -CONFIG = postgres:///taler - -[wire-sepa] -IBAN = DE67830654080004822650 -NAME = GNUNET E.V -BIC = GENODEF1SRL diff --git a/src/backend/melted/merchant.h b/src/backend/melted/merchant.h @@ -1,110 +0,0 @@ -/* - 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 @@ -1,354 +0,0 @@ -/* - 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 (" - "contract_id INT8 PRIMARY KEY," - "amount INT8 NOT NULL," - "amount_fraction INT4 NOT NULL," - "amount_currency VARCHAR(" TALER_CURRENCY_LEN_STR ") NOT NULL," - "description TEXT NOT NULL," - "nounce INT8 NOT NULL," - "expiry INT8 NOT NULL," - "product INT8 NOT NULL);" - "CREATE %1$s TABLE IF NOT EXISTS checkouts (" - "coin_pub BYTEA PRIMARY KEY," - "contract_id INT8 REFERENCES contracts(contract_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" - "(contract_id, amount, amount_fraction, amount_currency," - "description, nounce, expiry, product) VALUES" - "($1, $2, $3, $4, $5, $6, $7, $8)", - 8, NULL))); - EXITIF (PGRES_COMMAND_OK != (status = PQresultStatus(res))); - PQclear (res); - - EXITIF (NULL == (res = PQprepare - (conn, - "get_contract_product", - "SELECT (" - "product" - ") FROM contracts " - "WHERE (" - "contract_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," - "contract_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 " - "contract_id IN (" - "SELECT (contract_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 c_id contract's id - * @param desc descripition of the contract - * @param nounce a random 64-bit nounce - * @param product description to identify a product - * @return GNUNET_OK on success, GNUNET_SYSERR upon error - */ - -uint32_t -MERCHANT_DB_contract_create (PGconn *conn, - const struct GNUNET_TIME_Absolute *expiry, - const struct TALER_Amount *amount, - uint64_t c_id, - const char *desc, - uint64_t nounce, - uint64_t product) -{ - PGresult *res; - #if 0 - uint64_t expiry_ms_nbo; - uint64_t value_nbo; - uint32_t fraction_nbo; - uint64_t nounce_nbo; - #endif - ExecStatusType status; - - #if 0 - /* - NOTE: the conversion to nl(l) happens *inside* the query param helpers; since - the policy imposes this format for storing values. */ - value_nbo = GNUNET_htonll (amount->value); - fraction_nbo = GNUNET_htonll (amount->fraction); - nounce_nbo = GNUNET_htonll (nounce); - expiry_ms_nbo = GNUNET_htonll (expiry.abs_value_us); - product = GNUNET_htonll (product); - #endif - - /* ported. To be tested/compiled */ - struct TALER_PQ_QueryParam params[] = { - TALER_PQ_query_param_uint64 (&c_id), - TALER_PQ_query_param_amount (amount), - /* a *string* is being put in the following statement, - though the API talks about a *blob*. Will this be liked by - the DB ? */ - // the following inserts a string as a blob. Will Taler provide a param-from-string helper? - TALER_PQ_query_param_fixed_size (desc, strlen(desc)), - TALER_PQ_query_param_uint64 (&nounce), - TALER_PQ_query_param_absolute_time (expiry), - TALER_PQ_query_param_uint64 (&product), - TALER_PQ_query_param_end - }; - - /* NOTE: the statement is prepared by MERCHANT_DB_initialize function */ - res = TALER_PQ_exec_prepared (conn, "contract_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_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 @@ -1,101 +0,0 @@ -/* - 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 c_id this contract's identification number - * @param desc descripition of the contract - * @param nounce a random 64-bit nounce - * @param product description to identify a product - * @return GNUNET_OK on success, GNUNET_SYSERR upon error - */ - -uint32_t -MERCHANT_DB_contract_create (PGconn *conn, - const struct GNUNET_TIME_Absolute *expiry, - const struct TALER_Amount *amount, - uint64_t c_id, - 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/myconf.sh b/src/backend/melted/myconf.sh @@ -1,3 +0,0 @@ -#!/bin/sh - -./configure CFLAGS='-I/usr/include/postgresql' diff --git a/src/backend/melted/taler-merchant-httpd.c b/src/backend/melted/taler-merchant-httpd.c @@ -1,821 +0,0 @@ -/* - 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/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. - */ -#define EXITIF(cond) \ - do { \ - if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ - } while (0) - -/** - * Macro to round microseconds to seconds in GNUNET_TIME_* structs. - */ -#define ROUND_TO_SECS(name,us_field) name.us_field -= name.us_field % (1000 * 1000) - -/** - * Our hostname - */ -static char *hostname; - -/** - * The port we are running on - */ -static long long unsigned port; - -/** - * Merchant's private key - */ -struct GNUNET_CRYPTO_EddsaPrivateKey *privkey; - -/** - * 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; - -/** - * Hash of the wireformat - */ -static struct GNUNET_HashCode h_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; - -GNUNET_NETWORK_STRUCT_BEGIN - -struct Contract -{ - /** - * The signature of the merchant for this contract - */ - struct GNUNET_CRYPTO_EddsaSignature sig; - - /** - * Purpose header for the signature over contract - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - - /** - * The transaction identifier - */ - char m[13]; - - /** - * Expiry time - */ - struct GNUNET_TIME_AbsoluteNBO t; - - /** - * The invoice amount - */ - struct TALER_AmountNBO amount; - - /** - * The hash of the preferred wire format + nounce - */ - struct GNUNET_HashCode h_wire; - - /** - * The contract data - */ - char a[]; -}; - -GNUNET_NETWORK_STRUCT_END - -/** - * Mint context - */ -static struct TALER_MINT_Context *mctx; - -/** - * 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 -* @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\n"; - unsigned int ret; - - *resp = MHD_create_response_from_buffer (strlen (hello), (void *) hello, - MHD_RESPMEM_PERSISTENT); - ret = 200; - return ret; - - -} - -/** - * 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 -* 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) -{ - 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; -} - - - -/* -* 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 - * 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; - 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 = MHD_HTTP_INTERNAL_SERVER_ERROR; - 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 - res = TMH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &root); - - if (GNUNET_SYSERR == res) - { - 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) - { - 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 (); - 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; - } - - 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. - * - * @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) -{ - - 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, - NULL, NULL, - &url_handler, NULL, - MHD_OPTION_END); - - - 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 (); - -} - -/** - * 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; - - - -} diff --git a/src/backend/merchant.c b/src/backend/merchant.c @@ -42,15 +42,15 @@ */ int TALER_MERCHANT_parse_mints (const struct GNUNET_CONFIGURATION_Handle *cfg, - struct MERCHANT_MintInfo **mints) + struct MERCHANT_Mint **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; + struct MERCHANT_Mint *r_mints; + struct MERCHANT_Mint mint; unsigned long long mint_port; unsigned int cnt; int OK; diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c @@ -16,7 +16,8 @@ /** * @file merchant/backend/taler-merchant-httpd.c - * @brief HTTP serving layer mainly intended to communicate with the frontend + * @brief HTTP serving layer intended to perform crypto-work and + * communication with the mint * @author Marcello Stanisci */ @@ -63,7 +64,7 @@ static struct TALER_MINT_Context *mctx; /** * Mints' URL,port,key triples */ -struct MERCHANT_MintInfo *mint_infos; +struct MERCHANT_Mint *mints; /** * Shutdown task identifier @@ -71,9 +72,9 @@ struct MERCHANT_MintInfo *mint_infos; static struct GNUNET_SCHEDULER_Task *shutdown_task; /** - * Hashmap to store the mint context information + * Context "poller" identifier */ -static struct GNUNET_CONTAINER_MultiPeerMap *mints_map; +static struct GNUNET_SCHEDULER_Task *poller_task; /** * Our wireformat @@ -101,12 +102,6 @@ static int result; PGconn *db_conn; /** - * Hashmap (with 'big entries') to make a mint's base URL - * to point to some mint-describing structure - */ -static struct GNUNET_CONTAINER_MultiHashMap *mints_hashmap; - -/** * Context information of the mints we trust */ struct Mint @@ -253,7 +248,7 @@ 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 key from the conf file */ - /* HOT UPDATE: the merchants needs the denomination keys! + /* HOT UPDATE: the merchants need the denomination keys! Because it wants to (firstly) verify the deposit confirmation sent by the mint, and the signed blob depends (among the other things) on the coin's deposit fee. That information @@ -261,10 +256,7 @@ keys_mgmt_cb (void *cls, const struct TALER_MINT_Keys *keys) Again, the merchant needs it because it wants to verify that the wallet didn't exceede the limit imposed by the merchant on the total deposit fee for a purchase */ - - - return; - + printf ("Unregistering connection currently at %p\n", cls); } @@ -279,6 +271,12 @@ static void do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { + if (NULL != poller_task) + { + GNUNET_SCHEDULER_cancel (poller_task); + poller_task = NULL; + } + if (NULL != mhd) { MHD_stop_daemon (mhd); @@ -290,18 +288,77 @@ do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) MERCHANT_DB_disconnect (db_conn); db_conn = NULL; } - if (keyfile != NULL) + if (NULL != keyfile) GNUNET_free (privkey); } /** + * Task that runs the context's event loop with the GNUnet scheduler. + * + * @param cls unused + * @param tc scheduler context (unused) + */ +static void +context_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + long timeout; + int max_fd; + fd_set read_fd_set; + fd_set write_fd_set; + fd_set except_fd_set; + struct GNUNET_NETWORK_FDSet *rs; + struct GNUNET_NETWORK_FDSet *ws; + struct GNUNET_TIME_Relative delay; + + poller_task = NULL; + TALER_MINT_perform (mctx); + max_fd = -1; + timeout = -1; + FD_ZERO (&read_fd_set); + FD_ZERO (&write_fd_set); + FD_ZERO (&except_fd_set); + TALER_MINT_get_select_info (mctx, + &read_fd_set, + &write_fd_set, + &except_fd_set, + &max_fd, + &timeout); + if (timeout >= 0) + delay = + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, + timeout); + else + delay = GNUNET_TIME_UNIT_FOREVER_REL; + rs = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_copy_native (rs, + &read_fd_set, + max_fd + 1); + ws = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_copy_native (ws, + &write_fd_set, + max_fd + 1); + poller_task = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + delay, + rs, + ws, + &context_task, + cls); + GNUNET_NETWORK_fdset_destroy (rs); + GNUNET_NETWORK_fdset_destroy (ws); +} + + +/** * 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 cfgfile name of the configuration file used (for saving, can be + * NULL!) * @param config configuration */ void @@ -313,21 +370,32 @@ run (void *cls, char *const *args, const char *cfgfile, void *keys_mgmt_cls; keys_mgmt_cls = NULL; - mint_infos = NULL; + mints = 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_YES)); + shutdown_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &do_shutdown, + NULL); + EXITIF (GNUNET_SYSERR == + (nmints = + TALER_MERCHANT_parse_mints (config, + &mints))); + 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_YES)); EXITIF (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (config, "merchant", @@ -338,48 +406,17 @@ run (void *cls, char *const *args, const char *cfgfile, "merchant", "hostname", &hostname)); - EXITIF (NULL == (mctx = TALER_MINT_init ())); - /* Still not used */ - EXITIF (NULL == (mints_map = GNUNET_CONTAINER_multipeermap_create (nmints, GNUNET_YES))); - /* Used when the wallet points out which mint it want to deal with. - That indication is made through the mint's base URL, which will be - the hash-key for this table */ - EXITIF (NULL == (mints_hashmap = GNUNET_CONTAINER_multihashmap_create (nmints, GNUNET_NO))); - for (cnt = 0; cnt < nmints; cnt++) { - struct Mint *mint; - struct GNUNET_HashCode mint_key; - - 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)); - - /* 1 create hash key - 2 create big entry - 3 put - */ - GNUNET_CRYPTO_hash (mint_infos[cnt].hostname, - strlen (mint_infos[cnt].hostname), - &mint_key); - GNUNET_CONTAINER_multihashmap_put (mints_hashmap, - &mint_key, - &mint_infos[cnt], - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); + mints[cnt].conn = TALER_MINT_connect (mctx, + mints[cnt].hostname, + &keys_mgmt_cb, + &mints[cnt]); + printf ("trying to, %p\n", &mints[cnt]); + EXITIF (NULL == mints[cnt].conn); + poller_task = + GNUNET_SCHEDULER_add_now (&context_task, mctx); } mhd = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY, @@ -389,9 +426,6 @@ run (void *cls, char *const *args, const char *cfgfile, MHD_OPTION_END); EXITIF (NULL == mhd); - - /* WARNING: a 'poll_mhd ()' call is here in the original merchant. Is that - mandatory ? */ result = GNUNET_OK; EXITIF_exit: diff --git a/src/include/merchant.h b/src/include/merchant.h @@ -25,6 +25,7 @@ #include <gnunet/gnunet_common.h> #include <gnunet/gnunet_crypto_lib.h> +#include <taler/taler_mint_service.h> /** * Macro to round microseconds to seconds in GNUNET_TIME_* structs. @@ -42,7 +43,8 @@ /** * A mint */ -struct MERCHANT_MintInfo { +struct MERCHANT_Mint +{ /** * Hostname */ @@ -58,50 +60,11 @@ struct MERCHANT_MintInfo { */ uint16_t port; - /* According to the mint's location, some of the following - fields may be omitted. In case of numbers, they will be set - to zero, otherwise SET TO nuLL */ - - /** - * The Country where the mint operates from - */ - char *country; - - /** - * The city where the mint operates from - */ - char *city; - - /** - * The State (within a Country) where the mint - * operates from - */ - char *state; - /** - * The region where the mint operates from + * A connection to this mint */ - char *region; + struct TALER_MINT_Handle *conn; - /** - * The province where the mint operates from - */ - char *province; - - /** - * The ZIP code where the mint operates from - */ - uint16_t zip_code; - - /** - * The street's name where the mint operates from - */ - char *street; - - /** - * The street number where the mint operates from - */ - uint16_t street_no; }; @@ -116,7 +79,7 @@ struct MERCHANT_MintInfo { */ int TALER_MERCHANT_parse_mints (const struct GNUNET_CONFIGURATION_Handle *cfg, - struct MERCHANT_MintInfo **mints); + struct MERCHANT_Mint **mints); GNUNET_NETWORK_STRUCT_BEGIN diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am @@ -9,7 +9,7 @@ bin_PROGRAMS = \ test_contract_SOURCES = \ test_contract.c \ - merchant.c \ + ../backend/merchant.c \ ../backend-lib/merchant_db.c ../backend-lib/merchant_db.h test_contract_LDADD = \ diff --git a/src/tests/merchant.c b/src/tests/merchant.c @@ -1,173 +0,0 @@ -/* - 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 */