diff options
author | Marcello Stanisci <marcello.stanisci@inria.fr> | 2015-09-30 09:00:21 +0200 |
---|---|---|
committer | Marcello Stanisci <marcello.stanisci@inria.fr> | 2015-09-30 09:00:21 +0200 |
commit | ae89e08fd7d59cd81c69221c723c64c05dfacf3f (patch) | |
tree | 8fbe1d2dbf94a9e5c0f19a62be1d57418e4ac902 | |
parent | d28fc4e6fc458573e3dc58f3f68b694337bc2384 (diff) | |
download | merchant-ae89e08fd7d59cd81c69221c723c64c05dfacf3f.tar.gz merchant-ae89e08fd7d59cd81c69221c723c64c05dfacf3f.tar.bz2 merchant-ae89e08fd7d59cd81c69221c723c64c05dfacf3f.zip |
adding error code for primary key violation
-rw-r--r-- | src/backend-lib/merchant_db.c | 44 | ||||
-rw-r--r-- | src/backend-lib/taler-merchant-httpd_contract.c | 73 | ||||
-rw-r--r-- | src/backend-lib/taler_merchant_contract_lib.h | 51 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd.c | 25 | ||||
-rw-r--r-- | src/tests/Makefile.am | 10 | ||||
-rw-r--r-- | src/tests/test_contract.c (renamed from src/tests/merchant-contract-test.c) | 46 |
6 files changed, 108 insertions, 141 deletions
diff --git a/src/backend-lib/merchant_db.c b/src/backend-lib/merchant_db.c index 6c67eb9d..befb2c48 100644 --- a/src/backend-lib/merchant_db.c +++ b/src/backend-lib/merchant_db.c @@ -208,22 +208,25 @@ 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. +* Insert a contract record into the database and if successfull +* return the serial number of the inserted row. * * @param conn the database connection * @param timestamp the timestamp of this contract * @param expiry the time when the contract will expire -* @param edate when the merchant wants to receive the wire transfer corresponding -* to this deal (this value is also a field inside the 'wire' JSON format) -* @param refund deadline until which the merchant can return the paid amount +* @param edate when the merchant wants to receive the wire transfer +* corresponding to this deal (this value is also a field inside the +* 'wire' JSON format) +* @param refund deadline until which the merchant can return the paid +* amount * @param amount the taler amount corresponding to the contract * @param hash of the stringified JSON corresponding to this 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 +* @return GNUNET_OK on success, GNUNET_NO if attempting to insert an +* already inserted @a c_id, GNUNET_SYSERR for other errors. */ uint32_t @@ -268,7 +271,34 @@ MERCHANT_DB_contract_create (PGconn *conn, /* 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); + + if (PGRES_COMMAND_OK != status) + { + const char *sqlstate; + + sqlstate = PQresultErrorField (res, PG_DIAG_SQLSTATE); + if (NULL == sqlstate) + { + /* very unexpected... */ + GNUNET_break (0); + PQclear (res); + return GNUNET_SYSERR; + } + /* 40P01: deadlock, 40001: serialization failure */ + if ( (0 == strcmp (sqlstate, + "23505"))) + { + /* Primary key violation */ + PQclear (res); + return GNUNET_NO; + } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Database commit failure: %s\n", + sqlstate); + PQclear (res); + return GNUNET_SYSERR; + } + PQclear (res); return GNUNET_OK; diff --git a/src/backend-lib/taler-merchant-httpd_contract.c b/src/backend-lib/taler-merchant-httpd_contract.c index 1f9d095a..5a937e66 100644 --- a/src/backend-lib/taler-merchant-httpd_contract.c +++ b/src/backend-lib/taler-merchant-httpd_contract.c @@ -24,31 +24,6 @@ } while (0) /** -* 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 -* @param wire the merchant's wire details -* @return the hash to be included in the contract's blob -* -*/ - -static struct GNUNET_HashCode -hash_wireformat (uint64_t nounce, const struct MERCHANT_WIREFORMAT_Sepa *wire) -{ - 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; -} - -/** * Take the global wire details and return a JSON containing them, * compliantly with the Taler's API. * @param wire the merchant's wire details @@ -99,22 +74,24 @@ MERCHANT_get_wire_json (const struct MERCHANT_WIREFORMAT_Sepa *wire, * to this deal (this value is also a field inside the 'wire' JSON format) * @param refund deadline until which the merchant can return the paid amount * @param nounce the nounce used to hash the wire details -* @param contract_str where to store -* @return pointer to the (stringified) contract; NULL upon errors +* @param a will be pointed to the (allocated) stringified 0-terminated contract +* @return GNUNET_OK on success, GNUNET_NO if attempting to double insert the +* same contract, GNUNET_SYSERR in case of other (mostly DB related) errors. */ /** * TODO: inspect reference counting and, accordingly, free those json_t*(s) * still allocated */ -char * -MERCHANT_handle_contract (const json_t *j_contract, +uint32_t +MERCHANT_handle_contract (json_t *j_contract, PGconn *db_conn, struct Contract *contract, struct GNUNET_TIME_Absolute timestamp, struct GNUNET_TIME_Absolute expiry, struct GNUNET_TIME_Absolute edate, struct GNUNET_TIME_Absolute refund, + char **a, uint64_t nounce) { json_t *j_amount; @@ -135,39 +112,27 @@ MERCHANT_handle_contract (const json_t *j_contract, &j_product_id)) { printf ("no unpacking\n"); - return NULL; + return GNUNET_SYSERR; } - /* DB will store the amount -- WARNING: this call produces a - 'protocol violation' in json.c */ - - #if 0 - char *str = json_dumps (j_amount, JSON_INDENT(2) | JSON_PRESERVE_ORDER); - printf ("extracted amount : %s\n", str); - #endif - - TALER_json_to_amount (j_amount, &amount); contract_str = json_dumps (j_contract, JSON_COMPACT | JSON_PRESERVE_ORDER); + *a = contract_str; GNUNET_CRYPTO_hash (contract_str, strlen (contract_str) + 1, &contract->h_contract_details); contract->purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT); contract->purpose.size = htonl (sizeof (struct Contract)); // DB mgmt - if (GNUNET_SYSERR == MERCHANT_DB_contract_create (db_conn, - timestamp, - expiry, - edate, - refund, - &amount, - &contract->h_contract_details, - (uint64_t) j_trans_id, // safe? - contract_str, - nounce, - (uint64_t) j_product_id)) - return NULL; - return contract_str; + return MERCHANT_DB_contract_create (db_conn, + timestamp, + expiry, + edate, + refund, + &amount, + &contract->h_contract_details, + (uint64_t) j_trans_id, // safe? + contract_str, + nounce, + (uint64_t) j_product_id); } - - diff --git a/src/backend-lib/taler_merchant_contract_lib.h b/src/backend-lib/taler_merchant_contract_lib.h index cc02f70d..692c849d 100644 --- a/src/backend-lib/taler_merchant_contract_lib.h +++ b/src/backend-lib/taler_merchant_contract_lib.h @@ -17,47 +17,6 @@ struct Contract }; -GNUNET_NETWORK_STRUCT_BEGIN - -struct ContractNBO -{ - /** - * Purpose header for the signature over contract - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - - /** - * The transaction identifier. NOTE: it was m[13]. TODO: - * change the API accordingly! - */ - uint64_t m; - - /** - * Expiry time - */ - struct GNUNET_TIME_AbsoluteNBO t; - - /** - * The invoice amount - */ - struct TALER_AmountNBO amount; - - /** - * The hash of the merchant's wire details (bank account information), with a nounce - */ - struct GNUNET_HashCode h_wire; - - /** - * Hash of the JSON contract in UTF-8 including 0-termination, - * using JSON_COMPACT encoding with sorted fields. - */ - struct GNUNET_HashCode h_contract_details; - -}; - -GNUNET_NETWORK_STRUCT_END - - /** * Take the global wire details and return a JSON containing them, * compliantly with the Taler's API. @@ -86,20 +45,22 @@ MERCHANT_get_wire_json (const struct MERCHANT_WIREFORMAT_Sepa *wire, * to this deal (this value is also a field inside the 'wire' JSON format) * @param refund deadline until which the merchant can return the paid amount * @param nounce the nounce used to hash the wire details -* @param contract_str where to store -* @return pointer to the (stringified) contract; NULL upon errors +* @param a will be pointed to the (allocated) stringified 0-terminated contract +* @return GNUNET_OK on success, GNUNET_NO if attempting to double insert the +* same contract, GNUNET_SYSERR in case of other (mostly DB related) errors. */ /** * TODO: inspect reference counting and, accordingly, free those json_t*(s) * still allocated */ -char * -MERCHANT_handle_contract (const json_t *j_contract, +uint32_t +MERCHANT_handle_contract (json_t *j_contract, PGconn *db_conn, struct Contract *contract, struct GNUNET_TIME_Absolute timestamp, struct GNUNET_TIME_Absolute expiry, struct GNUNET_TIME_Absolute edate, struct GNUNET_TIME_Absolute refund, + char **a, uint64_t nounce); diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c index 15f72586..bd74405a 100644 --- a/src/backend/taler-merchant-httpd.c +++ b/src/backend/taler-merchant-httpd.c @@ -366,7 +366,7 @@ url_handler (void *cls, CURL *curl; CURLcode curl_res; - int res = GNUNET_SYSERR; + uint32_t res = GNUNET_SYSERR; #define URL_HELLO "/hello" #define URL_CONTRACT "/contract" @@ -588,18 +588,25 @@ url_handler (void *cls, goto end; } - if (NULL == (contract_str = MERCHANT_handle_contract (root, - db_conn, - &contract, - now, - expiry, - edate, - refund, - nounce))) + res = MERCHANT_handle_contract (root, + db_conn, + &contract, + now, + expiry, + edate, + refund, + &contract_str, + nounce); + if (GNUNET_SYSERR == res) { status = MHD_HTTP_INTERNAL_SERVER_ERROR; goto end; } + if (GNUNET_NO == res) + { + status = MHD_HTTP_METHOD_NOT_ACCEPTABLE; + goto end; + } GNUNET_CRYPTO_eddsa_sign (privkey, &contract.purpose, &c_sig); GNUNET_CRYPTO_hash (contract_str, strlen (contract_str) + 1, &h_contract_str); diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index dc88fc08..8dd350e7 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -2,17 +2,17 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/backend-lib/ bin_PROGRAMS = \ - merchant-contract-test + test-contract #merchant_contract_test_CFLAGS = \ # -Wl,--verbose -merchant_contract_test_SOURCES = \ - merchant-contract-test.c \ +test_contract_SOURCES = \ + test_contract.c \ merchant.c \ ../backend-lib/merchant_db.c ../backend-lib/merchant_db.h -merchant_contract_test_LDADD = \ +test_contract_LDADD = \ $(LIBGCRYPT_LIBS) \ -ltalerutil \ -ltalermerchant \ @@ -22,5 +22,5 @@ merchant_contract_test_LDADD = \ -ltalerpq \ -lgnunetpostgres \ -lpq \ - -ltalermerchant \ + $(top_srcdir)/src/backend-lib/libtalermerchant.la \ -lpthread diff --git a/src/tests/merchant-contract-test.c b/src/tests/test_contract.c index 20f8d2ba..47b3b0e6 100644 --- a/src/tests/merchant-contract-test.c +++ b/src/tests/test_contract.c @@ -24,6 +24,7 @@ #include <jansson.h> #include <gnunet/gnunet_util_lib.h> #include <taler/taler_json_lib.h> +#include "merchant.h" #include "merchant_db.h" #include <taler_merchant_lib.h> @@ -107,11 +108,13 @@ run (void *cls, char *const *args, const char *cfgfile, #else struct Contract contract; #endif - struct GNUNET_TIME_Absolute deldate; struct GNUNET_TIME_Absolute edate; struct GNUNET_TIME_Absolute now; uint64_t nounce; struct GNUNET_HashCode h_contract_str; + char *aa; + char *fancy_time; + uint32_t ret; db_conn = NULL; keyfile = NULL; @@ -150,7 +153,8 @@ run (void *cls, char *const *args, const char *cfgfile, j_amount = TALER_json_from_amount (&amount); /* Transaction ID*/ - t_id = (int32_t) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); + //t_id = (int32_t) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); + t_id = 321; if (t_id < 0) j_id = json_integer ((-1) * t_id); @@ -276,38 +280,38 @@ run (void *cls, char *const *args, const char *cfgfile, j_wire = MERCHANT_get_wire_json (wire, nounce, now); - if (NULL == (contract_tmp_str = MERCHANT_handle_contract (j_fake_contract, - db_conn, - &contract, - now, - now, - now, - now, - nounce))) - - printf ("errors in contract handling\n"); + ret = MERCHANT_handle_contract (j_fake_contract, + db_conn, + &contract, + now, + now, + now, + now, + &aa, + nounce); + if (ret == GNUNET_NO) + { + printf ("Failed, contract already in DB\n"); + return; + } else printf ("handling contract fine\n"); - /* try to get from DB the generated contract - - printf ("contract string : %s\n", contract_tmp_str); - return; - - */ + printf ("contract string : %s\n", aa); - GNUNET_CRYPTO_hash (contract_tmp_str, strlen (contract_tmp_str) + 1, &h_contract_str); + GNUNET_CRYPTO_hash (aa, strlen (aa) + 1, &h_contract_str); if (GNUNET_SYSERR == MERCHANT_DB_get_contract_values (db_conn, &h_contract_str, &nounce, &edate)) printf ("no hash found\n"); else { - char *late = GNUNET_STRINGS_absolute_time_to_string (edate); + fancy_time = GNUNET_STRINGS_absolute_time_to_string (edate); printf ("hash found!, nounce is : %llu\n", nounce); - printf ("hash found!, time is : %s\n", late); + printf ("hash found!, time is : %s\n", fancy_time); } + return; } |