merchant

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

commit 7afcc8275c0e8e19ceeb178bca21c7988966cba5
parent cb930318e14b314288d762d690b69ff86e7ee466
Author: Christian Grothoff <christian@grothoff.org>
Date:   Thu,  9 Jun 2016 19:36:24 +0200

skeleton for /track/transfer and /track/transaction, renaming to match latest exchange API

Diffstat:
Msrc/backend/Makefile.am | 4++--
Msrc/backend/taler-merchant-httpd.c | 8++++----
Dsrc/backend/taler-merchant-httpd_track-deposit.c | 520-------------------------------------------------------------------------------
Dsrc/backend/taler-merchant-httpd_track-deposit.h | 47-----------------------------------------------
Msrc/backend/taler-merchant-httpd_track-transaction.c | 28++++++++++++++--------------
Asrc/backend/taler-merchant-httpd_track-transfer.c | 521+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/backend/taler-merchant-httpd_track-transfer.h | 47+++++++++++++++++++++++++++++++++++++++++++++++
Msrc/include/taler_merchant_service.h | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Msrc/lib/Makefile.am | 3++-
Dsrc/lib/merchant_api_track.c | 196-------------------------------------------------------------------------------
Asrc/lib/merchant_api_track_transaction.c | 193+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/merchant_api_track_transfer.c | 197+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/lib/test_merchant_api.c | 16++++++++--------
13 files changed, 1077 insertions(+), 835 deletions(-)

diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am @@ -21,8 +21,8 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_exchanges.c taler-merchant-httpd_exchanges.h \ taler-merchant-httpd_contract.c taler-merchant-httpd_contract.h \ taler-merchant-httpd_pay.c taler-merchant-httpd_pay.h \ - taler-merchant-httpd_track-deposit.c taler-merchant-httpd_track-deposit.h \ - taler-merchant-httpd_track-transaction.c taler-merchant-httpd_track-transaction.h + taler-merchant-httpd_track-transaction.c taler-merchant-httpd_track-transaction.h \ + taler-merchant-httpd_track-transfer.c taler-merchant-httpd_track-transfer.h taler_merchant_httpd_LDADD = \ diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c @@ -37,8 +37,8 @@ #include "taler-merchant-httpd_exchanges.h" #include "taler-merchant-httpd_contract.h" #include "taler-merchant-httpd_pay.h" -#include "taler-merchant-httpd_track-deposit.h" #include "taler-merchant-httpd_track-transaction.h" +#include "taler-merchant-httpd_track-transfer.h" /** @@ -188,10 +188,10 @@ url_handler (void *cls, { "/pay", NULL, "text/plain", "Only POST is allowed", 0, &TMH_MHD_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED }, - { "/track/deposit", MHD_HTTP_METHOD_GET, "application/json", + { "/track/transfer", MHD_HTTP_METHOD_GET, "application/json", NULL, 0, - &MH_handler_track_deposit, MHD_HTTP_OK}, - { "/track/deposit", NULL, "text/plain", + &MH_handler_track_transfer, MHD_HTTP_OK}, + { "/track/transfer", NULL, "text/plain", "Only GET is allowed", 0, &TMH_MHD_handler_static_response, MHD_HTTP_OK}, { "/track/transaction", MHD_HTTP_METHOD_GET, "application/json", diff --git a/src/backend/taler-merchant-httpd_track-deposit.c b/src/backend/taler-merchant-httpd_track-deposit.c @@ -1,520 +0,0 @@ -/* - This file is part of TALER - (C) 2014, 2015, 2016 INRIA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero 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 backend/taler-merchant-httpd_track-deposit.c - * @brief implement API for tracking deposits and wire transfers - * @author Marcello Stanisci - * @author Christian Grothoff - */ -#include "platform.h" -#include <jansson.h> -#include <taler/taler_signatures.h> -#include <taler/taler_json_lib.h> -#include "taler-merchant-httpd.h" -#include "taler-merchant-httpd_mhd.h" -#include "taler-merchant-httpd_parsing.h" -#include "taler-merchant-httpd_auditors.h" -#include "taler-merchant-httpd_exchanges.h" -#include "taler-merchant-httpd_responses.h" -#include "taler-merchant-httpd_track-deposit.h" - - -/** - * How long to wait before giving up processing with the exchange? - */ -#define TRACK_TIMEOUT (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)) - - -/** - * Context used for handing /track/deposit requests. - */ -struct DepositTrackContext -{ - - /** - * This MUST be first! - */ - struct TM_HandlerContext hc; - - /** - * Handle to the exchange. - */ - struct TALER_EXCHANGE_Handle *eh; - - /** - * Handle for the /wire/deposits request. - */ - struct TALER_EXCHANGE_WireDepositsHandle *wdh; - - /** - * HTTP connection we are handling. - */ - struct MHD_Connection *connection; - - /** - * Response to return upon resume. - */ - struct MHD_Response *response; - - /** - * Handle for operation to lookup /keys (and auditors) from - * the exchange used for this transaction; NULL if no operation is - * pending. - */ - struct TMH_EXCHANGES_FindOperation *fo; - - /** - * Task run on timeout. - */ - struct GNUNET_SCHEDULER_Task *timeout_task; - - /** - * URI of the exchange. - */ - char *uri; - - /** - * Pointer to the detail that we are currently - * checking in #check_deposit(). - */ - const struct TALER_WireDepositDetails *current_detail; - - /** - * Argument for the /wire/deposits request. - */ - struct TALER_WireTransferIdentifierRawP wtid; - - /** - * Response code to return. - */ - unsigned int response_code; - - /** - * #GNUNET_NO if we did not find a matching coin. - * #GNUNET_SYSERR if we found a matching coin, but the amounts do not match. - * #GNUNET_OK if we did find a matching coin. - */ - int check_deposit_result; -}; - - -/** - * Free the @a rctx. - * - * @param rctx data to free - */ -static void -free_deposit_track_context (struct DepositTrackContext *rctx) -{ - if (NULL != rctx->fo) - { - TMH_EXCHANGES_find_exchange_cancel (rctx->fo); - rctx->fo = NULL; - } - if (NULL != rctx->timeout_task) - { - GNUNET_SCHEDULER_cancel (rctx->timeout_task); - rctx->timeout_task = NULL; - } - if (NULL != rctx->wdh) - { - TALER_EXCHANGE_wire_deposits_cancel (rctx->wdh); - rctx->wdh = NULL; - } - if (NULL != rctx->uri) - { - GNUNET_free (rctx->uri); - rctx->uri = NULL; - } - GNUNET_free (rctx); -} - - -/** - * Resume the given /track/deposit operation and send the given response. - * Stores the response in the @a rctx and signals MHD to resume - * the connection. Also ensures MHD runs immediately. - * - * @param rctx deposit tracking context - * @param response_code response code to use - * @param response response data to send back - */ -static void -resume_track_deposit_with_response (struct DepositTrackContext *rctx, - unsigned int response_code, - struct MHD_Response *response) -{ - rctx->response_code = response_code; - rctx->response = response; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Resuming /track/transaction handling as exchange interaction is done (%u)\n", - response_code); - if (NULL != rctx->timeout_task) - { - GNUNET_SCHEDULER_cancel (rctx->timeout_task); - rctx->timeout_task = NULL; - } - MHD_resume_connection (rctx->connection); - TMH_trigger_daemon (); /* we resumed, kick MHD */ -} - - -/** - * Custom cleanup routine for a `struct DepositTrackContext`. - * - * @param hc the `struct DepositTrackContext` to clean up. - */ -static void -track_deposit_cleanup (struct TM_HandlerContext *hc) -{ - struct DepositTrackContext *rctx = (struct DepositTrackContext *) hc; - - free_deposit_track_context (rctx); -} - - -/** - * Function called with information about a coin that was deposited. - * Verify that it matches the information claimed by the exchange. - * Update the `check_deposit_result` field accordingly. - * - * @param cls closure with our `struct DepositTrackContext *` - * @param transaction_id of the contract - * @param coin_pub public key of the coin - * @param amount_with_fee amount the exchange will deposit for this coin - * @param deposit_fee fee the exchange will charge for this coin - * @param exchange_proof proof from exchange that coin was accepted - */ -static void -check_deposit (void *cls, - uint64_t transaction_id, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_Amount *amount_with_fee, - const struct TALER_Amount *deposit_fee, - const json_t *exchange_proof) -{ - struct DepositTrackContext *rctx = cls; - const struct TALER_WireDepositDetails *wdd = rctx->current_detail; - - if (0 != memcmp (&wdd->coin_pub, - coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP))) - return; /* not the coin we're looking for */ - if ( (0 != TALER_amount_cmp (amount_with_fee, - &wdd->coin_value)) || - (0 != TALER_amount_cmp (deposit_fee, - &wdd->coin_fee)) ) - { - /* Disagreement between the exchange and us about how much this - coin is worth! */ - GNUNET_break_op (0); - rctx->check_deposit_result = GNUNET_SYSERR; - return; - } - rctx->check_deposit_result = GNUNET_OK; -} - - -/** - * Function called with detailed wire transfer data, including all - * of the coin transactions that were combined into the wire transfer. - * - * @param cls closure - * @param http_status HTTP status code we got, 0 on exchange protocol violation - * @param exchange_pub public key of the exchange used to sign @a json - * @param json original json reply (may include signatures, those have then been - * validated already) - * @param wtid extracted wire transfer identifier, or NULL if the exchange could - * not provide any (set only if @a http_status is #MHD_HTTP_OK) - * @param total_amount total amount of the wire transfer, or NULL if the exchange could - * not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK) - * @param details_length length of the @a details array - * @param details array with details about the combined transactions - */ -static void -wire_deposit_cb (void *cls, - unsigned int http_status, - const struct TALER_ExchangePublicKeyP *exchange_pub, - const json_t *json, - const struct GNUNET_HashCode *h_wire, - const struct TALER_Amount *total_amount, - unsigned int details_length, - const struct TALER_WireDepositDetails *details) -{ - struct DepositTrackContext *rctx = cls; - unsigned int i; - int ret; - - rctx->wdh = NULL; - if (MHD_HTTP_OK != http_status) - { - resume_track_deposit_with_response - (rctx, - MHD_HTTP_FAILED_DEPENDENCY, - TMH_RESPONSE_make_json_pack ("{s:I, s:O}", - "exchange_status", (json_int_t) http_status, - "details", json)); - return; - } - - if (GNUNET_OK != - db->store_transfer_to_proof (db->cls, - rctx->uri, - &rctx->wtid, - exchange_pub, - json)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to persist wire transfer proof in DB\n"); - } - - for (i=0;i<details_length;i++) - { - rctx->current_detail = &details[i]; - rctx->check_deposit_result = GNUNET_NO; - ret = db->find_payments_by_id (rctx, - details[i].transaction_id, - &check_deposit, - rctx); - if (GNUNET_SYSERR == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to verify existing payment data in DB\n"); - } - if ( (GNUNET_NO == ret) || - (GNUNET_NO == rctx->check_deposit_result) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to find payment data in DB\n"); - } - if (GNUNET_SYSERR == rctx->check_deposit_result) - { - /* #check_deposit() failed, do something! */ - GNUNET_break (0); - /* FIXME: generate nicer custom response */ - resume_track_deposit_with_response - (rctx, - MHD_HTTP_FAILED_DEPENDENCY, - TMH_RESPONSE_make_json_pack ("{s:I, s:O}", - "index", (json_int_t) i, - "details", json)); - return; - } - ret = db->store_coin_to_transfer (db->cls, - details[i].transaction_id, - &details[i].coin_pub, - &rctx->wtid); - if (GNUNET_OK != ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to persist coin to wire transfer mapping in DB\n"); - } - } - /* FIXME: might want a more custom response here... */ - resume_track_deposit_with_response - (rctx, - MHD_HTTP_OK, - TMH_RESPONSE_make_json_pack ("{s:I, s:O}", - "exchange_status", (json_int_t) http_status, - "details", json)); -} - - -/** - * Function called with the result of our exchange lookup. - * - * @param cls the `struct DepositTrackContext` - * @param eh NULL if exchange was not found to be acceptable - * @param exchange_trusted #GNUNET_YES if this exchange is trusted by config - */ -static void -process_track_deposit_with_exchange (void *cls, - struct TALER_EXCHANGE_Handle *eh, - int exchange_trusted) -{ - struct DepositTrackContext *rctx = cls; - - rctx->fo = NULL; - rctx->eh = eh; - rctx->wdh = TALER_EXCHANGE_wire_deposits (eh, - &rctx->wtid, - &wire_deposit_cb, - rctx); -} - - -/** - * Handle a timeout for the processing of the track deposit request. - * - * @param cls closure - */ -static void -handle_track_deposit_timeout (void *cls) -{ - struct DepositTrackContext *rctx = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Resuming /track/deposit with error after timeout\n"); - rctx->timeout_task = NULL; - - if (NULL != rctx->fo) - { - TMH_EXCHANGES_find_exchange_cancel (rctx->fo); - rctx->fo = NULL; - } - resume_track_deposit_with_response (rctx, - MHD_HTTP_SERVICE_UNAVAILABLE, - TMH_RESPONSE_make_internal_error ("exchange not reachable")); -} - - -/** - * Function called with information about a wire transfer identifier. - * Generate a response based on the given @a proof. - * - * @param cls closure - * @param proof proof from exchange about what the wire transfer was for - */ -static void -proof_cb (void *cls, - const json_t *proof) -{ - struct DepositTrackContext *rctx = cls; - - rctx->response_code = MHD_HTTP_OK; - /* FIXME: might want a more custom response here... */ - rctx->response = TMH_RESPONSE_make_json_pack ("{s:I, s:O}", - "exchange_status", (json_int_t) MHD_HTTP_OK, - "details", proof); -} - - -/** - * Manages a /track/deposit call, thus it calls the /track/wtid - * offered by the exchange in order to return the set of deposits - * (of coins) associated with a given wire transfer. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -MH_handler_track_deposit (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - struct DepositTrackContext *rctx; - const char *str; - const char *uri; - int ret; - - if (NULL == *connection_cls) - { - rctx = GNUNET_new (struct DepositTrackContext); - rctx->hc.cc = &track_deposit_cleanup; - rctx->connection = connection; - *connection_cls = rctx; - } - else - { - /* not first call, recover state */ - rctx = *connection_cls; - } - - if (0 != rctx->response_code) - { - /* We are *done* processing the request, just queue the response (!) */ - if (UINT_MAX == rctx->response_code) - { - GNUNET_break (0); - return MHD_NO; /* hard error */ - } - ret = MHD_queue_response (connection, - rctx->response_code, - rctx->response); - if (NULL != rctx->response) - { - MHD_destroy_response (rctx->response); - rctx->response = NULL; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Queueing response (%u) for /track/deposit (%s).\n", - (unsigned int) rctx->response_code, - ret ? "OK" : "FAILED"); - return ret; - } - - uri = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "exchange"); - if (NULL == uri) - return TMH_RESPONSE_reply_bad_request (connection, - "exchange argument missing"); - rctx->uri = GNUNET_strdup (uri); - - str = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "wtid"); - if (NULL == str) - return TMH_RESPONSE_reply_bad_request (connection, - "wtid argument missing"); - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (str, - strlen (str), - &rctx->wtid, - sizeof (rctx->wtid))) - { - return TMH_RESPONSE_reply_bad_request (connection, - "wtid argument malformed"); - } - - /* Check if reply is already in database! */ - ret = db->find_proof_by_wtid (db->cls, - rctx->uri, - &rctx->wtid, - &proof_cb, - rctx); - if (0 != rctx->response_code) - { - ret = MHD_queue_response (connection, - rctx->response_code, - rctx->response); - if (NULL != rctx->response) - { - MHD_destroy_response (rctx->response); - rctx->response = NULL; - } - return ret; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Suspending /track/deposit handling while working with the exchange\n"); - MHD_suspend_connection (connection); - rctx->fo = TMH_EXCHANGES_find_exchange (uri, - &process_track_deposit_with_exchange, - rctx); - rctx->timeout_task = GNUNET_SCHEDULER_add_delayed (TRACK_TIMEOUT, - &handle_track_deposit_timeout, - rctx); - return MHD_NO; -} - -/* end of taler-merchant-httpd_track-deposit.c */ diff --git a/src/backend/taler-merchant-httpd_track-deposit.h b/src/backend/taler-merchant-httpd_track-deposit.h @@ -1,47 +0,0 @@ -/* - This file is part of TALER - (C) 2014, 2015 GNUnet e.V. - - 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 backend/taler-merchant-httpd_track-deposit.h - * @brief headers for /track/deposit handler - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#ifndef TALER_MERCHANT_HTTPD_TRACK_DEPOSIT_H -#define TALER_MERCHANT_HTTPD_TRACK_DEPOSIT_H -#include <microhttpd.h> -#include "taler-merchant-httpd.h" - -/** - * Manages a /track/deposit call, thus it calls the /wire/deposit - * offered by the exchange in order to return the set of deposits - * (of coins) associated with a given wire transfer - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -MH_handler_track_deposit (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -#endif diff --git a/src/backend/taler-merchant-httpd_track-transaction.c b/src/backend/taler-merchant-httpd_track-transaction.c @@ -72,7 +72,7 @@ struct TrackCoinContext /** * Handle for the request to resolve the WTID for this coin. */ - struct TALER_EXCHANGE_DepositWtidHandle *dwh; + struct TALER_EXCHANGE_TrackTransactionHandle *dwh; /** * Wire transfer identifier for this coin. @@ -138,7 +138,7 @@ struct TrackTransactionContext /** * Handle we use to resolve transactions for a given WTID. */ - struct TALER_EXCHANGE_WireDepositsHandle *wdh; + struct TALER_EXCHANGE_TrackTransferHandle *wdh; /** * Response to return upon resume. @@ -205,14 +205,14 @@ free_tctx (struct TrackTransactionContext *tctx) tcc); if (NULL != tcc->dwh) { - TALER_EXCHANGE_deposit_wtid_cancel (tcc->dwh); + TALER_EXCHANGE_track_transaction_cancel (tcc->dwh); tcc->dwh = NULL; } GNUNET_free (tcc); } if (NULL != tctx->wdh) { - TALER_EXCHANGE_wire_deposits_cancel (tctx->wdh); + TALER_EXCHANGE_track_transfer_cancel (tctx->wdh); tctx->wdh = NULL; } if (NULL != tctx->fo) @@ -315,7 +315,7 @@ wire_deposits_cb (void *cls, const struct GNUNET_HashCode *h_wire, const struct TALER_Amount *total_amount, unsigned int details_length, - const struct TALER_WireDepositDetails *details) + const struct TALER_TrackTransferDetails *details) { struct TrackTransactionContext *tctx = cls; struct TrackCoinContext *tcc; @@ -403,7 +403,7 @@ wtid_cb (void *cls, tcc->dwh = NULL; tctx->current_wtid = *wtid; - tctx->wdh = TALER_EXCHANGE_wire_deposits (tctx->eh, + tctx->wdh = TALER_EXCHANGE_track_transfer (tctx->eh, wtid, &wire_deposits_cb, tctx); @@ -436,14 +436,14 @@ trace_coins (struct TrackTransactionContext *tctx) #endif return; } - tcc->dwh = TALER_EXCHANGE_deposit_wtid (tctx->eh, - &privkey, - &tctx->h_wire, - &tctx->h_contract, - &tcc->coin_pub, - tctx->transaction_id, - &wtid_cb, - tcc); + tcc->dwh = TALER_EXCHANGE_track_transaction (tctx->eh, + &privkey, + &tctx->h_wire, + &tctx->h_contract, + &tcc->coin_pub, + tctx->transaction_id, + &wtid_cb, + tcc); } diff --git a/src/backend/taler-merchant-httpd_track-transfer.c b/src/backend/taler-merchant-httpd_track-transfer.c @@ -0,0 +1,521 @@ +/* + This file is part of TALER + (C) 2014, 2015, 2016 INRIA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero 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 backend/taler-merchant-httpd_track-transfer.c + * @brief implement API for tracking transfers and wire transfers + * @author Marcello Stanisci + * @author Christian Grothoff + */ +#include "platform.h" +#include <jansson.h> +#include <taler/taler_signatures.h> +#include <taler/taler_json_lib.h> +#include "taler-merchant-httpd.h" +#include "taler-merchant-httpd_mhd.h" +#include "taler-merchant-httpd_parsing.h" +#include "taler-merchant-httpd_auditors.h" +#include "taler-merchant-httpd_exchanges.h" +#include "taler-merchant-httpd_responses.h" +#include "taler-merchant-httpd_track-transfer.h" + + +/** + * How long to wait before giving up processing with the exchange? + */ +#define TRACK_TIMEOUT (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)) + + +/** + * Context used for handing /track/transfer requests. + */ +struct TransferTrackContext +{ + + /** + * This MUST be first! + */ + struct TM_HandlerContext hc; + + /** + * Handle to the exchange. + */ + struct TALER_EXCHANGE_Handle *eh; + + /** + * Handle for the /wire/transfers request. + */ + struct TALER_EXCHANGE_TrackTransferHandle *wdh; + + /** + * HTTP connection we are handling. + */ + struct MHD_Connection *connection; + + /** + * Response to return upon resume. + */ + struct MHD_Response *response; + + /** + * Handle for operation to lookup /keys (and auditors) from + * the exchange used for this transaction; NULL if no operation is + * pending. + */ + struct TMH_EXCHANGES_FindOperation *fo; + + /** + * Task run on timeout. + */ + struct GNUNET_SCHEDULER_Task *timeout_task; + + /** + * URI of the exchange. + */ + char *uri; + + /** + * Pointer to the detail that we are currently + * checking in #check_transfer(). + */ + const struct TALER_TrackTransferDetails *current_detail; + + /** + * Argument for the /wire/transfers request. + */ + struct TALER_WireTransferIdentifierRawP wtid; + + /** + * Response code to return. + */ + unsigned int response_code; + + /** + * #GNUNET_NO if we did not find a matching coin. + * #GNUNET_SYSERR if we found a matching coin, but the amounts do not match. + * #GNUNET_OK if we did find a matching coin. + */ + int check_transfer_result; +}; + + +/** + * Free the @a rctx. + * + * @param rctx data to free + */ +static void +free_transfer_track_context (struct TransferTrackContext *rctx) +{ + if (NULL != rctx->fo) + { + TMH_EXCHANGES_find_exchange_cancel (rctx->fo); + rctx->fo = NULL; + } + if (NULL != rctx->timeout_task) + { + GNUNET_SCHEDULER_cancel (rctx->timeout_task); + rctx->timeout_task = NULL; + } + if (NULL != rctx->wdh) + { + TALER_EXCHANGE_track_transfer_cancel (rctx->wdh); + rctx->wdh = NULL; + } + if (NULL != rctx->uri) + { + GNUNET_free (rctx->uri); + rctx->uri = NULL; + } + GNUNET_free (rctx); +} + + +/** + * Resume the given /track/transfer operation and send the given response. + * Stores the response in the @a rctx and signals MHD to resume + * the connection. Also ensures MHD runs immediately. + * + * @param rctx transfer tracking context + * @param response_code response code to use + * @param response response data to send back + */ +static void +resume_track_transfer_with_response (struct TransferTrackContext *rctx, + unsigned int response_code, + struct MHD_Response *response) +{ + rctx->response_code = response_code; + rctx->response = response; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Resuming /track/transaction handling as exchange interaction is done (%u)\n", + response_code); + if (NULL != rctx->timeout_task) + { + GNUNET_SCHEDULER_cancel (rctx->timeout_task); + rctx->timeout_task = NULL; + } + MHD_resume_connection (rctx->connection); + TMH_trigger_daemon (); /* we resumed, kick MHD */ +} + + +/** + * Custom cleanup routine for a `struct TransferTrackContext`. + * + * @param hc the `struct TransferTrackContext` to clean up. + */ +static void +track_transfer_cleanup (struct TM_HandlerContext *hc) +{ + struct TransferTrackContext *rctx = (struct TransferTrackContext *) hc; + + free_transfer_track_context (rctx); +} + + +/** + * Function called with information about a coin that was transfered. + * Verify that it matches the information claimed by the exchange. + * Update the `check_transfer_result` field accordingly. + * + * @param cls closure with our `struct TransferTrackContext *` + * @param transaction_id of the contract + * @param coin_pub public key of the coin + * @param amount_with_fee amount the exchange will transfer for this coin + * @param transfer_fee fee the exchange will charge for this coin + * @param exchange_proof proof from exchange that coin was accepted + */ +static void +check_transfer (void *cls, + uint64_t transaction_id, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_Amount *amount_with_fee, + const struct TALER_Amount *transfer_fee, + const json_t *exchange_proof) +{ + struct TransferTrackContext *rctx = cls; + const struct TALER_TrackTransferDetails *wdd = rctx->current_detail; + + if (0 != memcmp (&wdd->coin_pub, + coin_pub, + sizeof (struct TALER_CoinSpendPublicKeyP))) + return; /* not the coin we're looking for */ + if ( (0 != TALER_amount_cmp (amount_with_fee, + &wdd->coin_value)) || + (0 != TALER_amount_cmp (transfer_fee, + &wdd->coin_fee)) ) + { + /* Disagreement between the exchange and us about how much this + coin is worth! */ + GNUNET_break_op (0); + rctx->check_transfer_result = GNUNET_SYSERR; + return; + } + rctx->check_transfer_result = GNUNET_OK; +} + + +/** + * Function called with detailed wire transfer data, including all + * of the coin transactions that were combined into the wire transfer. + * + * @param cls closure + * @param http_status HTTP status code we got, 0 on exchange protocol violation + * @param exchange_pub public key of the exchange used to sign @a json + * @param json original json reply (may include signatures, those have then been + * validated already) + * @param wtid extracted wire transfer identifier, or NULL if the exchange could + * not provide any (set only if @a http_status is #MHD_HTTP_OK) + * @param total_amount total amount of the wire transfer, or NULL if the exchange could + * not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK) + * @param details_length length of the @a details array + * @param details array with details about the combined transactions + */ +static void +wire_transfer_cb (void *cls, + unsigned int http_status, + const struct TALER_ExchangePublicKeyP *exchange_pub, + const json_t *json, + const struct GNUNET_HashCode *h_wire, + const struct TALER_Amount *total_amount, + unsigned int details_length, + const struct TALER_TrackTransferDetails *details) +{ + struct TransferTrackContext *rctx = cls; + unsigned int i; + int ret; + + rctx->wdh = NULL; + if (MHD_HTTP_OK != http_status) + { + resume_track_transfer_with_response + (rctx, + MHD_HTTP_FAILED_DEPENDENCY, + TMH_RESPONSE_make_json_pack ("{s:I, s:O}", + "exchange_status", (json_int_t) http_status, + "details", json)); + return; + } + + if (GNUNET_OK != + db->store_transfer_to_proof (db->cls, + rctx->uri, + &rctx->wtid, + exchange_pub, + json)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to persist wire transfer proof in DB\n"); + } + + for (i=0;i<details_length;i++) + { + rctx->current_detail = &details[i]; + rctx->check_transfer_result = GNUNET_NO; + ret = db->find_payments_by_id (rctx, + details[i].transaction_id, + &check_transfer, + rctx); + if (GNUNET_SYSERR == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to verify existing payment data in DB\n"); + } + if ( (GNUNET_NO == ret) || + (GNUNET_NO == rctx->check_transfer_result) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to find payment data in DB\n"); + } + if (GNUNET_SYSERR == rctx->check_transfer_result) + { + /* #check_transfer() failed, do something! */ + GNUNET_break (0); + /* FIXME: generate nicer custom response */ + resume_track_transfer_with_response + (rctx, + MHD_HTTP_FAILED_DEPENDENCY, + TMH_RESPONSE_make_json_pack ("{s:I, s:O}", + "index", (json_int_t) i, + "details", json)); + return; + } + ret = db->store_coin_to_transfer (db->cls, + details[i].transaction_id, + &details[i].coin_pub, + &rctx->wtid); + if (GNUNET_OK != ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to persist coin to wire transfer mapping in DB\n"); + } + } + /* FIXME: might want a more custom response here... */ + resume_track_transfer_with_response + (rctx, + MHD_HTTP_OK, + TMH_RESPONSE_make_json_pack ("{s:I, s:O}", + "exchange_status", (json_int_t) http_status, + "details", json)); +} + + +/** + * Function called with the result of our exchange lookup. + * + * @param cls the `struct TransferTrackContext` + * @param eh NULL if exchange was not found to be acceptable + * @param exchange_trusted #GNUNET_YES if this exchange is trusted by config + */ +static void +process_track_transfer_with_exchange (void *cls, + struct TALER_EXCHANGE_Handle *eh, + int exchange_trusted) +{ + struct TransferTrackContext *rctx = cls; + + rctx->fo = NULL; + rctx->eh = eh; + rctx->wdh = TALER_EXCHANGE_track_transfer (eh, + &rctx->wtid, + &wire_transfer_cb, + rctx); +} + + +/** + * Handle a timeout for the processing of the track transfer request. + * + * @param cls closure + */ +static void +handle_track_transfer_timeout (void *cls) +{ + struct TransferTrackContext *rctx = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Resuming /track/transfer with error after timeout\n"); + rctx->timeout_task = NULL; + + if (NULL != rctx->fo) + { + TMH_EXCHANGES_find_exchange_cancel (rctx->fo); + rctx->fo = NULL; + } + resume_track_transfer_with_response (rctx, + MHD_HTTP_SERVICE_UNAVAILABLE, + TMH_RESPONSE_make_internal_error ("exchange not reachable")); +} + + +/** + * Function called with information about a wire transfer identifier. + * Generate a response based on the given @a proof. + * + * @param cls closure + * @param proof proof from exchange about what the wire transfer was for + */ +static void +proof_cb (void *cls, + const json_t *proof) +{ + struct TransferTrackContext *rctx = cls; + + rctx->response_code = MHD_HTTP_OK; + /* FIXME: might want a more custom response here... */ + rctx->response = TMH_RESPONSE_make_json_pack ("{s:I, s:O}", + "exchange_status", (json_int_t) MHD_HTTP_OK, + "details", proof); +} + + +/** + * Manages a /track/transfer call, thus it calls the /track/wtid + * offered by the exchange in order to return the set of transfers + * (of coins) associated with a given wire transfer. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +MH_handler_track_transfer (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + struct TransferTrackContext *rctx; + const char *str; + const char *uri; + int ret; + + if (NULL == *connection_cls) + { + rctx = GNUNET_new (struct TransferTrackContext); + rctx->hc.cc = &track_transfer_cleanup; + rctx->connection = connection; + *connection_cls = rctx; + } + else + { + /* not first call, recover state */ + rctx = *connection_cls; + } + + if (0 != rctx->response_code) + { + /* We are *done* processing the request, just queue the response (!) */ + if (UINT_MAX == rctx->response_code) + { + GNUNET_break (0); + return MHD_NO; /* hard error */ + } + ret = MHD_queue_response (connection, + rctx->response_code, + rctx->response); + if (NULL != rctx->response) + { + MHD_destroy_response (rctx->response); + rctx->response = NULL; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Queueing response (%u) for /track/transfer (%s).\n", + (unsigned int) rctx->response_code, + ret ? "OK" : "FAILED"); + return ret; + } + + uri = MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, + "exchange"); + if (NULL == uri) + return TMH_RESPONSE_reply_bad_request (connection, + "exchange argument missing"); + rctx->uri = GNUNET_strdup (uri); + + str = MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, + "wtid"); + if (NULL == str) + return TMH_RESPONSE_reply_bad_request (connection, + "wtid argument missing"); + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (str, + strlen (str), + &rctx->wtid, + sizeof (rctx->wtid))) + { + return TMH_RESPONSE_reply_bad_request (connection, + "wtid argument malformed"); + } + + /* Check if reply is already in database! */ + ret = db->find_proof_by_wtid (db->cls, + rctx->uri, + &rctx->wtid, + &proof_cb, + rctx); + if (0 != rctx->response_code) + { + ret = MHD_queue_response (connection, + rctx->response_code, + rctx->response); + if (NULL != rctx->response) + { + MHD_destroy_response (rctx->response); + rctx->response = NULL; + } + return ret; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Suspending /track/transfer handling while working with the exchange\n"); + MHD_suspend_connection (connection); + rctx->fo = TMH_EXCHANGES_find_exchange (uri, + &process_track_transfer_with_exchange, + rctx); + rctx->timeout_task + = GNUNET_SCHEDULER_add_delayed (TRACK_TIMEOUT, + &handle_track_transfer_timeout, + rctx); + return MHD_NO; +} + +/* end of taler-merchant-httpd_track-transfer.c */ diff --git a/src/backend/taler-merchant-httpd_track-transfer.h b/src/backend/taler-merchant-httpd_track-transfer.h @@ -0,0 +1,47 @@ +/* + This file is part of TALER + (C) 2014, 2015 GNUnet e.V. + + 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 backend/taler-merchant-httpd_track-transfer.h + * @brief headers for /track/transfer handler + * @author Christian Grothoff + * @author Marcello Stanisci + */ +#ifndef TALER_MERCHANT_HTTPD_TRACK_TRANSFER_H +#define TALER_MERCHANT_HTTPD_TRACK_TRANSFER_H +#include <microhttpd.h> +#include "taler-merchant-httpd.h" + +/** + * Manages a /track/transfer call, thus it calls the /wire/transfer + * offered by the exchange in order to return the set of transfers + * (of coins) associated with a given wire transfer + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[in,out] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +MH_handler_track_transfer (struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size); + + +#endif diff --git a/src/include/taler_merchant_service.h b/src/include/taler_merchant_service.h @@ -26,49 +26,6 @@ #include <gnunet/gnunet_curl_lib.h> #include <jansson.h> -/* ********************* /track/deposit *********************** */ - -/** - * @brief Handle to a /contract operation at a merchant's backend. - */ -struct TALER_MERCHANT_TrackDepositOperation; - -/** - * Callbacks of this type are used to work the result of submitting a /track/deposit request to a merchant - */ -typedef void -(*TALER_MERCHANT_TrackDepositCallback) (void *cls, - unsigned int http_status, - const json_t *obj); - -/** - * Request backend to return deposits associated with a given wtid. - * - * @param ctx execution context - * @param backend_uri URI of the backend (having /track/deposit appended) - * @param wtid base32 string indicating a wtid - * @param exchange base URL of the exchange in charge of returning the wanted information - * @param trackdeposit_cb the callback to call when a reply for this request is available - * @param trackdeposit_cb_cls closure for @a contract_cb - * @return a handle for this request - */ -struct TALER_MERCHANT_TrackDepositOperation * -TALER_MERCHANT_track_deposit (struct GNUNET_CURL_Context *ctx, - const char *backend_uri, - const struct TALER_WireTransferIdentifierRawP *wtid, - const char *exchange_uri, - TALER_MERCHANT_TrackDepositCallback trackdeposit_cb, - void *trackdeposit_cb_cls); - - -/** - * Cancel a /track/deposit request. This function cannot be used - * on a request handle if a response is already served for it. - * - * @param co the deposit's tracking operation - */ -void -TALER_MERCHANT_track_deposit_cancel (struct TALER_MERCHANT_TrackDepositOperation *tdo); /* ********************* /contract *********************** */ @@ -340,5 +297,94 @@ void TALER_MERCHANT_pay_cancel (struct TALER_MERCHANT_Pay *ph); +/* ********************* /track/transfer *********************** */ + +/** + * @brief Handle to a /contract operation at a merchant's backend. + */ +struct TALER_MERCHANT_TrackTransferHandle; + +/** + * Callbacks of this type are used to work the result of submitting a /track/transfer request to a merchant + */ +typedef void +(*TALER_MERCHANT_TrackTransferCallback) (void *cls, + unsigned int http_status, + const json_t *obj); + +/** + * Request backend to return deposits associated with a given wtid. + * + * @param ctx execution context + * @param backend_uri URI of the backend (having /track/transfer appended) + * @param wtid base32 string indicating a wtid + * @param exchange base URL of the exchange in charge of returning the wanted information + * @param track_transfer_cb the callback to call when a reply for this request is available + * @param track_transfer_cb_cls closure for @a track_transfer_cb + * @return a handle for this request + */ +struct TALER_MERCHANT_TrackTransferHandle * +TALER_MERCHANT_track_transfer (struct GNUNET_CURL_Context *ctx, + const char *backend_uri, + const struct TALER_WireTransferIdentifierRawP *wtid, + const char *exchange_uri, + TALER_MERCHANT_TrackTransferCallback track_transfer_cb, + void *track_transfer_cb_cls); + + +/** + * Cancel a /track/transfer request. This function cannot be used + * on a request handle if a response is already served for it. + * + * @param co the deposit's tracking operation + */ +void +TALER_MERCHANT_track_transfer_cancel (struct TALER_MERCHANT_TrackTransferHandle *tdo); + + +/* ********************* /track/transaction *********************** */ + +/** + * @brief Handle to a /contract operation at a merchant's backend. + */ +struct TALER_MERCHANT_TrackTransactionHandle; + +/** + * Callbacks of this type are used to work the result of submitting a /track/transaction request to a merchant + */ +typedef void +(*TALER_MERCHANT_TrackTransactionCallback) (void *cls, + unsigned int http_status, + const json_t *obj); + +/** + * Request backend to return deposits associated with a given wtid. + * + * @param ctx execution context + * @param backend_uri URI of the backend (having /track/transaction appended) + * @param wtid base32 string indicating a wtid + * @param exchange base URL of the exchange in charge of returning the wanted information + * @param track_transaction_cb the callback to call when a reply for this request is available + * @param track_transaction_cb_cls closure for @a track_transaction_cb + * @return a handle for this request + */ +struct TALER_MERCHANT_TrackTransactionHandle * +TALER_MERCHANT_track_transaction (struct GNUNET_CURL_Context *ctx, + const char *backend_uri, + uint64_t transaction_id, + const char *exchange_uri, + TALER_MERCHANT_TrackTransactionCallback track_transaction_cb, + void *track_transaction_cb_cls); + + +/** + * Cancel a /track/transaction request. This function cannot be used + * on a request handle if a response is already served for it. + * + * @param co the deposit's tracking operation + */ +void +TALER_MERCHANT_track_transaction_cancel (struct TALER_MERCHANT_TrackTransactionHandle *tdo); + #endif /* _TALER_MERCHANT_SERVICE_H */ diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am @@ -16,7 +16,8 @@ libtalermerchant_la_LDFLAGS = \ libtalermerchant_la_SOURCES = \ merchant_api_contract.c \ merchant_api_pay.c \ - merchant_api_track.c + merchant_api_track_transaction.c \ + merchant_api_track_transfer.c libtalermerchant_la_LIBADD = \ -ltalerexchange \ diff --git a/src/lib/merchant_api_track.c b/src/lib/merchant_api_track.c @@ -1,196 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015, 2016 GNUnet e.V. and INRIA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Lesser General Public License as published by the Free Software - Foundation; either version 2.1, 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License along with - TALER; see the file COPYING.LGPL. If not, If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file lib/merchant_api_contract.c - * @brief Implementation of the /track/deposit and /track/wtid request of the - * merchant's HTTP API - * @author Marcello Stanisci - */ -#include "platform.h" -#include <curl/curl.h> -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include <gnunet/gnunet_curl_lib.h> -#include "taler_merchant_service.h" -#include <taler/taler_json_lib.h> -#include <taler/taler_signatures.h> - - -/** - * @brief A Contract Operation Handle - */ -struct TALER_MERCHANT_TrackDepositOperation -{ - - /** - * The url for this request. - */ - char *url; - - /** - * base32 identifier being the 'witd' parameter required by the - * exchange - */ - char *wtid; - - /** - * Handle for the request. - */ - struct GNUNET_CURL_Job *job; - - /** - * Function to call with the result. - */ - TALER_MERCHANT_TrackDepositCallback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * Reference to the execution context. - */ - struct GNUNET_CURL_Context *ctx; -}; - - -/** - * Function called when we're done processing the - * HTTP /track/deposit request. - * - * @param cls the `struct TALER_MERCHANT_TrackDepositOperation` - * @param response_code HTTP response code, 0 on error - * @param json response body, NULL if not in JSON - */ -static void -handle_trackdeposit_finished (void *cls, - long response_code, - const json_t *json) -{ - struct TALER_MERCHANT_TrackDepositOperation *tdo = cls; - - tdo->job = NULL; - switch (response_code) - { - case 0: - break; - case MHD_HTTP_OK: - { - /* Work out argument for external callback from the body .. */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "200 returned from /track/deposit\n"); - /* FIXME: actually verify signature */ - } - break; - case MHD_HTTP_NOT_FOUND: - /* Nothing really to verify, this should never - happen, we should pass the JSON reply to the application */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "track deposit URI not found\n"); - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - break; - default: - /* unexpected response code */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u\n", - (unsigned int) response_code); - GNUNET_break (0); - response_code = 0; - break; - } - /* FIXME: figure out which parameters ought to be passed back */ - tdo->cb (tdo->cb_cls, - response_code, - json); -} - - -/** - * Request backend to return deposits associated with a given wtid. - * - * @param ctx execution context - * @param backend_uri URI of the backend (having "/track/deposit" appended) - * @param wtid base32 string indicating a wtid - * @param exchange base URL of the exchange in charge of returning the wanted information - * @param trackdeposit_cb the callback to call when a reply for this request is available - * @param trackdeposit_cb_cls closure for @a contract_cb - * @return a handle for this request - */ -struct TALER_MERCHANT_TrackDepositOperation * -TALER_MERCHANT_track_deposit (struct GNUNET_CURL_Context *ctx, - const char *backend_uri, - const struct TALER_WireTransferIdentifierRawP *wtid, - const char *exchange_uri, - TALER_MERCHANT_TrackDepositCallback trackdeposit_cb, - void *trackdeposit_cb_cls) -{ - struct TALER_MERCHANT_TrackDepositOperation *tdo; - CURL *eh; - char *wtid_str; - - wtid_str = GNUNET_STRINGS_data_to_string_alloc (wtid, - sizeof (struct TALER_WireTransferIdentifierRawP)); - tdo = GNUNET_new (struct TALER_MERCHANT_TrackDepositOperation); - tdo->ctx = ctx; - tdo->cb = trackdeposit_cb; - tdo->cb_cls = trackdeposit_cb_cls; - /* URI gotten with /track/deposit already appended... */ - GNUNET_asprintf (&tdo->url, - "%s?wtid=%s&exchange=%s", - backend_uri, - wtid_str, - exchange_uri); - GNUNET_free (wtid_str); - eh = curl_easy_init (); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_URL, - tdo->url)); - tdo->job = GNUNET_CURL_job_add (ctx, - eh, - GNUNET_YES, - &handle_trackdeposit_finished, - tdo); - return tdo; -} - - -/** - * Cancel a /track/deposit request. This function cannot be used - * on a request handle if a response is already served for it. - * - * @param co the deposit's tracking operation - */ -void -TALER_MERCHANT_track_deposit_cancel (struct TALER_MERCHANT_TrackDepositOperation *tdo) -{ - if (NULL != tdo->job) - { - GNUNET_CURL_job_cancel (tdo->job); - tdo->job = NULL; - } - GNUNET_free (tdo->url); - GNUNET_free (tdo->wtid); - GNUNET_free (tdo); -} - -/* end of merchant_api_track.c */ diff --git a/src/lib/merchant_api_track_transaction.c b/src/lib/merchant_api_track_transaction.c @@ -0,0 +1,193 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015, 2016 GNUnet e.V. and INRIA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 2.1, 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along with + TALER; see the file COPYING.LGPL. If not, If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file lib/merchant_api_track_transaction.c + * @brief Implementation of the /track/transaction request of the + * merchant's HTTP API + * @author Marcello Stanisci + * @author Christian Grothoff + */ +#include "platform.h" +#include <curl/curl.h> +#include <jansson.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_curl_lib.h> +#include "taler_merchant_service.h" +#include <taler/taler_json_lib.h> +#include <taler/taler_signatures.h> + + +/** + * @brief A handle for tracking transactions. + */ +struct TALER_MERCHANT_TrackTransactionHandle +{ + + /** + * The url for this request. + */ + char *url; + + /** + * base32 identifier being the 'witd' parameter required by the + * exchange + */ + char *wtid; + + /** + * Handle for the request. + */ + struct GNUNET_CURL_Job *job; + + /** + * Function to call with the result. + */ + TALER_MERCHANT_TrackTransactionCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Reference to the execution context. + */ + struct GNUNET_CURL_Context *ctx; +}; + + +/** + * Function called when we're done processing the + * HTTP /track/transaction request. + * + * @param cls the `struct TALER_MERCHANT_TrackTransactionHandle` + * @param response_code HTTP response code, 0 on error + * @param json response body, NULL if not in JSON + */ +static void +handle_tracktransaction_finished (void *cls, + long response_code, + const json_t *json) +{ + struct TALER_MERCHANT_TrackTransactionHandle *tdo = cls; + + tdo->job = NULL; + switch (response_code) + { + case 0: + break; + case MHD_HTTP_OK: + { + /* Work out argument for external callback from the body .. */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "200 returned from /track/transaction\n"); + /* FIXME: actually verify signature */ + } + break; + case MHD_HTTP_NOT_FOUND: + /* Nothing really to verify, this should never + happen, we should pass the JSON reply to the application */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "track transaction URI not found\n"); + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + break; + default: + /* unexpected response code */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u\n", + (unsigned int) response_code); + GNUNET_break (0); + response_code = 0; + break; + } + /* FIXME: figure out which parameters ought to be passed back */ + tdo->cb (tdo->cb_cls, + response_code, + json); +} + + +/** + * Request backend to return transactions associated with a given wtid. + * + * @param ctx execution context + * @param backend_uri URI of the backend (having "/track/transaction" appended) + * @param wtid base32 string indicating a wtid + * @param exchange base URL of the exchange in charge of returning the wanted information + * @param track_transaction_cb the callback to call when a reply for this request is available + * @param track_transaction_cb_cls closure for @a contract_cb + * @return a handle for this request + */ +struct TALER_MERCHANT_TrackTransactionHandle * +TALER_MERCHANT_track_transaction (struct GNUNET_CURL_Context *ctx, + const char *backend_uri, + uint64_t transaction_id, + const char *exchange_uri, + TALER_MERCHANT_TrackTransactionCallback track_transaction_cb, + void *track_transaction_cb_cls) +{ + struct TALER_MERCHANT_TrackTransactionHandle *tdo; + CURL *eh; + + tdo = GNUNET_new (struct TALER_MERCHANT_TrackTransactionHandle); + tdo->ctx = ctx; + tdo->cb = track_transaction_cb; + tdo->cb_cls = track_transaction_cb_cls; + /* URI gotten with /track/transaction already appended... */ + GNUNET_asprintf (&tdo->url, + "%s?transaction=%llu&exchange=%s", + backend_uri, + (unsigned long long) transaction_id, + exchange_uri); + eh = curl_easy_init (); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_URL, + tdo->url)); + tdo->job = GNUNET_CURL_job_add (ctx, + eh, + GNUNET_YES, + &handle_tracktransaction_finished, + tdo); + return tdo; +} + + +/** + * Cancel a /track/transaction request. This function cannot be used + * on a request handle if a response is already served for it. + * + * @param co the transaction's tracking handle + */ +void +TALER_MERCHANT_track_transaction_cancel (struct TALER_MERCHANT_TrackTransactionHandle *tdo) +{ + if (NULL != tdo->job) + { + GNUNET_CURL_job_cancel (tdo->job); + tdo->job = NULL; + } + GNUNET_free (tdo->url); + GNUNET_free (tdo->wtid); + GNUNET_free (tdo); +} + +/* end of merchant_api_track_transaction.c */ diff --git a/src/lib/merchant_api_track_transfer.c b/src/lib/merchant_api_track_transfer.c @@ -0,0 +1,197 @@ +/* + This file is part of TALER + Copyright (C) 2014, 2015, 2016 GNUnet e.V. and INRIA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Lesser General Public License as published by the Free Software + Foundation; either version 2.1, 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along with + TALER; see the file COPYING.LGPL. If not, If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file lib/merchant_api_track_transfer.c + * @brief Implementation of the /track/transfer request of the + * merchant's HTTP API + * @author Marcello Stanisci + * @author Christian Grothoff + */ +#include "platform.h" +#include <curl/curl.h> +#include <jansson.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_curl_lib.h> +#include "taler_merchant_service.h" +#include <taler/taler_json_lib.h> +#include <taler/taler_signatures.h> + + +/** + * @brief A Handle for tracking wire transfers. + */ +struct TALER_MERCHANT_TrackTransferHandle +{ + + /** + * The url for this request. + */ + char *url; + + /** + * base32 identifier being the 'witd' parameter required by the + * exchange + */ + char *wtid; + + /** + * Handle for the request. + */ + struct GNUNET_CURL_Job *job; + + /** + * Function to call with the result. + */ + TALER_MERCHANT_TrackTransferCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * Reference to the execution context. + */ + struct GNUNET_CURL_Context *ctx; +}; + + +/** + * Function called when we're done processing the + * HTTP /track/transfer request. + * + * @param cls the `struct TALER_MERCHANT_TrackTransferHandle` + * @param response_code HTTP response code, 0 on error + * @param json response body, NULL if not in JSON + */ +static void +handle_track_transfer_finished (void *cls, + long response_code, + const json_t *json) +{ + struct TALER_MERCHANT_TrackTransferHandle *tdo = cls; + + tdo->job = NULL; + switch (response_code) + { + case 0: + break; + case MHD_HTTP_OK: + { + /* Work out argument for external callback from the body .. */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "200 returned from /track/transfer\n"); + /* FIXME: actually verify signature */ + } + break; + case MHD_HTTP_NOT_FOUND: + /* Nothing really to verify, this should never + happen, we should pass the JSON reply to the application */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "track transfer URI not found\n"); + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + break; + default: + /* unexpected response code */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u\n", + (unsigned int) response_code); + GNUNET_break (0); + response_code = 0; + break; + } + /* FIXME: figure out which parameters ought to be passed back */ + tdo->cb (tdo->cb_cls, + response_code, + json); +} + + +/** + * Request backend to return transfers associated with a given wtid. + * + * @param ctx execution context + * @param backend_uri URI of the backend (having "/track/transfer" appended) + * @param wtid base32 string indicating a wtid + * @param exchange base URL of the exchange in charge of returning the wanted information + * @param tracktransfer_cb the callback to call when a reply for this request is available + * @param tracktransfer_cb_cls closure for @a contract_cb + * @return a handle for this request + */ +struct TALER_MERCHANT_TrackTransferHandle * +TALER_MERCHANT_track_transfer (struct GNUNET_CURL_Context *ctx, + const char *backend_uri, + const struct TALER_WireTransferIdentifierRawP *wtid, + const char *exchange_uri, + TALER_MERCHANT_TrackTransferCallback tracktransfer_cb, + void *tracktransfer_cb_cls) +{ + struct TALER_MERCHANT_TrackTransferHandle *tdo; + CURL *eh; + char *wtid_str; + + wtid_str = GNUNET_STRINGS_data_to_string_alloc (wtid, + sizeof (struct TALER_WireTransferIdentifierRawP)); + tdo = GNUNET_new (struct TALER_MERCHANT_TrackTransferHandle); + tdo->ctx = ctx; + tdo->cb = tracktransfer_cb; + tdo->cb_cls = tracktransfer_cb_cls; + /* URI gotten with /track/transfer already appended... */ + GNUNET_asprintf (&tdo->url, + "%s?wtid=%s&exchange=%s", + backend_uri, + wtid_str, + exchange_uri); + GNUNET_free (wtid_str); + eh = curl_easy_init (); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_URL, + tdo->url)); + tdo->job = GNUNET_CURL_job_add (ctx, + eh, + GNUNET_YES, + &handle_track_transfer_finished, + tdo); + return tdo; +} + + +/** + * Cancel a /track/transfer request. This function cannot be used + * on a request handle if a response is already served for it. + * + * @param co the transfer's tracking handle + */ +void +TALER_MERCHANT_track_transfer_cancel (struct TALER_MERCHANT_TrackTransferHandle *tdo) +{ + if (NULL != tdo->job) + { + GNUNET_CURL_job_cancel (tdo->job); + tdo->job = NULL; + } + GNUNET_free (tdo->url); + GNUNET_free (tdo->wtid); + GNUNET_free (tdo); +} + +/* end of merchant_api_track_transfer.c */ diff --git a/src/lib/test_merchant_api.c b/src/lib/test_merchant_api.c @@ -459,9 +459,9 @@ struct Command char *check_bank_ref; /** - * Handle to a /track/deposit operation + * Handle to a /track/transfer operation */ - struct TALER_MERCHANT_TrackDepositOperation *tdo; + struct TALER_MERCHANT_TrackTransferHandle *tdo; } track_deposit; @@ -944,7 +944,7 @@ maint_child_death (void *cls) /** - * Callback for a /track/deposit operation + * Callback for a /track/transfer operation * * @param cls closure for this function * @param http_status HTTP response code returned by the server @@ -963,13 +963,13 @@ track_deposit_cb (void *cls, if (MHD_HTTP_OK == http_status) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Ok from /track/deposit handler\n"); + "Ok from /track/transfer handler\n"); result = GNUNET_OK; } else { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Not Ok from /track/deposit handler\n"); + "Not Ok from /track/transfer handler\n"); result = GNUNET_SYSERR; } next_command (is); @@ -1448,7 +1448,7 @@ interpreter_run (void *cls) cmd->details.track_deposit.check_bank_ref); GNUNET_assert (NULL != ref); cmd->details.track_deposit.tdo = - TALER_MERCHANT_track_deposit (ctx, + TALER_MERCHANT_track_transfer (ctx, MERCHANT_URI "track/deposit", &ref->details.check_bank_transfer.wtid, EXCHANGE_URI, @@ -1594,10 +1594,10 @@ do_shutdown (void *cls) break; case OC_TRACK_DEPOSIT: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "shutting down /track/deposit\n"); + "shutting down /track/transfer\n"); if (NULL != cmd->details.track_deposit.tdo) { - TALER_MERCHANT_track_deposit_cancel (cmd->details.track_deposit.tdo); + TALER_MERCHANT_track_transfer_cancel (cmd->details.track_deposit.tdo); cmd->details.track_deposit.tdo = NULL; } break;