aboutsummaryrefslogtreecommitdiff
path: root/src/bank-lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/bank-lib')
-rw-r--r--src/bank-lib/Makefile.am3
-rw-r--r--src/bank-lib/bank_api_admin.c21
-rw-r--r--src/bank-lib/bank_api_common.c30
-rw-r--r--src/bank-lib/bank_api_common.h10
-rw-r--r--src/bank-lib/bank_api_history.c91
-rw-r--r--src/bank-lib/bank_api_reject.c245
-rw-r--r--src/bank-lib/fakebank.c256
-rw-r--r--src/bank-lib/test_bank_api.c23
-rw-r--r--src/bank-lib/test_bank_api_with_fakebank.c37
-rw-r--r--src/bank-lib/test_bank_interpreter.c214
-rw-r--r--src/bank-lib/test_bank_interpreter.h29
11 files changed, 868 insertions, 91 deletions
diff --git a/src/bank-lib/Makefile.am b/src/bank-lib/Makefile.am
index 7489fe795..da8dd9d39 100644
--- a/src/bank-lib/Makefile.am
+++ b/src/bank-lib/Makefile.am
@@ -17,7 +17,8 @@ libtalerbank_la_LDFLAGS = \
libtalerbank_la_SOURCES = \
bank_api_admin.c \
bank_api_common.c bank_api_common.h \
- bank_api_history.c
+ bank_api_history.c \
+ bank_api_reject.c
libtalerbank_la_LIBADD = \
$(top_builddir)/src/json/libtalerjson.la \
diff --git a/src/bank-lib/bank_api_admin.c b/src/bank-lib/bank_api_admin.c
index cebd93436..4a1732ed1 100644
--- a/src/bank-lib/bank_api_admin.c
+++ b/src/bank-lib/bank_api_admin.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2015, 2016, 2017 GNUnet e.V.
+ Copyright (C) 2015, 2016, 2017 Taler Systems SA
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
@@ -79,11 +79,13 @@ handle_admin_add_incoming_finished (void *cls,
{
struct TALER_BANK_AdminAddIncomingHandle *aai = cls;
uint64_t serial_id = UINT64_MAX;
+ enum TALER_ErrorCode ec;
aai->job = NULL;
switch (response_code)
{
case 0:
+ ec = TALER_EC_INVALID_RESPONSE;
break;
case MHD_HTTP_OK:
{
@@ -100,29 +102,36 @@ handle_admin_add_incoming_finished (void *cls,
{
GNUNET_break_op (0);
response_code = 0;
+ ec = TALER_EC_INVALID_RESPONSE;
break;
}
+ ec = TALER_EC_NONE;
}
break;
case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the bank is buggy
(or API version conflict); just pass JSON reply to the application */
+ ec = TALER_BANK_parse_ec_ (json);
break;
case MHD_HTTP_FORBIDDEN:
/* Access denied */
+ ec = TALER_BANK_parse_ec_ (json);
break;
case MHD_HTTP_UNAUTHORIZED:
/* Nothing really to verify, bank says one of the signatures is
invalid; as we checked them, this should never happen, we
should pass the JSON reply to the application */
+ ec = TALER_BANK_parse_ec_ (json);
break;
case MHD_HTTP_NOT_FOUND:
/* Nothing really to verify, this should never
happen, we should pass the JSON reply to the application */
+ ec = TALER_BANK_parse_ec_ (json);
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API
leaves this to the application */
+ ec = TALER_BANK_parse_ec_ (json);
break;
default:
/* unexpected response code */
@@ -130,11 +139,13 @@ handle_admin_add_incoming_finished (void *cls,
"Unexpected response code %u\n",
(unsigned int) response_code);
GNUNET_break (0);
+ ec = TALER_BANK_parse_ec_ (json);
response_code = 0;
break;
}
aai->cb (aai->cb_cls,
response_code,
+ ec,
serial_id,
json);
TALER_BANK_admin_add_incoming_cancel (aai);
@@ -151,7 +162,7 @@ handle_admin_add_incoming_finished (void *cls,
* @param bank_base_url URL of the bank (used to execute this request)
* @param auth authentication data to send to the bank
* @param exchange_base_url base URL of the exchange (for tracking)
- * @param wtid wire transfer identifier for the transfer
+ * @param subject wire transfer subject for the transfer
* @param amount amount that was deposited
* @param debit_account_no account number to withdraw from (53 bits at most)
* @param credit_account_no account number to deposit into (53 bits at most)
@@ -166,7 +177,7 @@ TALER_BANK_admin_add_incoming (struct GNUNET_CURL_Context *ctx,
const char *bank_base_url,
const struct TALER_BANK_AuthenticationData *auth,
const char *exchange_base_url,
- const struct TALER_WireTransferIdentifierRawP *wtid,
+ const char *subject,
const struct TALER_Amount *amount,
uint64_t debit_account_no,
uint64_t credit_account_no,
@@ -182,10 +193,10 @@ TALER_BANK_admin_add_incoming (struct GNUNET_CURL_Context *ctx,
GNUNET_break (0);
return NULL;
}
- admin_obj = json_pack ("{s:{s:s}, s:s, s:o, s:o, s:I, s:I}",
+ admin_obj = json_pack ("{s:{s:s}, s:s, s:s, s:o, s:I, s:I}",
"auth", "type", "basic",
"exchange_url", exchange_base_url,
- "wtid", GNUNET_JSON_from_data_auto (wtid),
+ "subject", subject,
"amount", TALER_JSON_from_amount (amount),
"debit_account", (json_int_t) debit_account_no,
"credit_account", (json_int_t) credit_account_no);
diff --git a/src/bank-lib/bank_api_common.c b/src/bank-lib/bank_api_common.c
index 738d2a5b8..b4b197492 100644
--- a/src/bank-lib/bank_api_common.c
+++ b/src/bank-lib/bank_api_common.c
@@ -80,7 +80,7 @@ TALER_BANK_make_auth_header_ (const struct TALER_BANK_AuthenticationData *auth)
authh = append (authh,
"X-Taler-Bank-Password",
auth->details.basic.password);
- return authh;
+ return authh;
}
return NULL;
}
@@ -111,5 +111,33 @@ TALER_BANK_path_to_url_ (const char *u,
}
+/**
+ * Parse error code given in @a json.
+ *
+ * @param json the json to parse
+ * @return error code, or #TALER_EC_INVALID if not found
+ */
+enum TALER_ErrorCode
+TALER_BANK_parse_ec_ (const json_t *json)
+{
+ uint32_t ec;
+
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_uint32 ("ec",
+ &ec),
+ GNUNET_JSON_spec_end()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return TALER_EC_INVALID;
+ }
+ return (enum TALER_ErrorCode) ec;
+}
+
/* end of bank_api_common.c */
diff --git a/src/bank-lib/bank_api_common.h b/src/bank-lib/bank_api_common.h
index 9d7a7800c..5d6578ce0 100644
--- a/src/bank-lib/bank_api_common.h
+++ b/src/bank-lib/bank_api_common.h
@@ -51,4 +51,14 @@ TALER_BANK_path_to_url_ (const char *u,
const char *path);
+/**
+ * Parse error code given in @a json.
+ *
+ * @param json the json to parse
+ * @return error code, or #TALER_EC_INVALID if not found
+ */
+enum TALER_ErrorCode
+TALER_BANK_parse_ec_ (const json_t *json);
+
+
#endif
diff --git a/src/bank-lib/bank_api_history.c b/src/bank-lib/bank_api_history.c
index e134f20f4..a6c7dceac 100644
--- a/src/bank-lib/bank_api_history.c
+++ b/src/bank-lib/bank_api_history.c
@@ -118,22 +118,37 @@ parse_account_history (struct TALER_BANK_HistoryHandle *hh,
return GNUNET_SYSERR;
}
+ if (0 == strcasecmp (sign,
+ "+"))
+ direction = TALER_BANK_DIRECTION_CREDIT;
+ else if (0 == strcasecmp (sign,
+ "-"))
+ direction = TALER_BANK_DIRECTION_DEBIT;
+ else if (0 == strcasecmp (sign,
+ "cancel+"))
+ direction = TALER_BANK_DIRECTION_CREDIT | TALER_BANK_DIRECTION_CANCEL;
+ else if (0 == strcasecmp (sign,
+ "cancel-"))
+ direction = TALER_BANK_DIRECTION_DEBIT | TALER_BANK_DIRECTION_CANCEL;
+ else
+ {
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (hist_spec);
+ return GNUNET_SYSERR;
+ }
td.account_details = json_pack ("{s:s, s:s, s:I}",
"type", "test",
"bank_uri", hh->bank_base_url,
"account_number", (json_int_t) other_account);
- direction = (0 == strcasecmp (sign,
- "+"))
- ? TALER_BANK_DIRECTION_CREDIT
- : TALER_BANK_DIRECTION_DEBIT;
hh->hcb (hh->hcb_cls,
MHD_HTTP_OK,
+ TALER_EC_NONE,
direction,
serial_id,
&td,
transaction);
- GNUNET_JSON_parse_free (hist_spec);
json_decref (td.account_details);
+ GNUNET_JSON_parse_free (hist_spec);
}
return GNUNET_OK;
}
@@ -153,6 +168,7 @@ handle_history_finished (void *cls,
const json_t *json)
{
struct TALER_BANK_HistoryHandle *hh = cls;
+ enum TALER_ErrorCode ec;
hh->job = NULL;
switch (response_code)
@@ -166,31 +182,38 @@ handle_history_finished (void *cls,
{
GNUNET_break_op (0);
response_code = 0;
+ ec = TALER_EC_INVALID_RESPONSE;
break;
}
response_code = MHD_HTTP_NO_CONTENT; /* signal end of list */
break;
case MHD_HTTP_NO_CONTENT:
+ ec = TALER_EC_NONE;
break;
case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the bank is buggy
(or API version conflict); just pass JSON reply to the application */
+ ec = TALER_BANK_parse_ec_ (json);
break;
case MHD_HTTP_FORBIDDEN:
/* Access denied */
+ ec = TALER_BANK_parse_ec_ (json);
break;
case MHD_HTTP_UNAUTHORIZED:
/* Nothing really to verify, bank says one of the signatures is
invalid; as we checked them, this should never happen, we
should pass the JSON reply to the application */
+ ec = TALER_BANK_parse_ec_ (json);
break;
case MHD_HTTP_NOT_FOUND:
/* Nothing really to verify, this should never
happen, we should pass the JSON reply to the application */
+ ec = TALER_BANK_parse_ec_ (json);
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API
leaves this to the application */
+ ec = TALER_BANK_parse_ec_ (json);
break;
default:
/* unexpected response code */
@@ -198,11 +221,13 @@ handle_history_finished (void *cls,
"Unexpected response code %u\n",
(unsigned int) response_code);
GNUNET_break (0);
+ ec = TALER_BANK_parse_ec_ (json);
response_code = 0;
break;
}
hh->hcb (hh->hcb_cls,
response_code,
+ ec,
TALER_BANK_DIRECTION_NONE,
0LLU,
NULL,
@@ -243,6 +268,8 @@ TALER_BANK_history (struct GNUNET_CURL_Context *ctx,
struct TALER_BANK_HistoryHandle *hh;
CURL *eh;
char *url;
+ const char *dir;
+ const char *can;
if (0 == num_results)
{
@@ -254,36 +281,42 @@ TALER_BANK_history (struct GNUNET_CURL_Context *ctx,
GNUNET_break (0);
return NULL;
}
+
+ dir = NULL;
+ if (TALER_BANK_DIRECTION_BOTH == (TALER_BANK_DIRECTION_BOTH & direction))
+ dir = "both";
+ else if (TALER_BANK_DIRECTION_CREDIT == (TALER_BANK_DIRECTION_CREDIT & direction))
+ dir = "credit";
+ else if (TALER_BANK_DIRECTION_DEBIT == (TALER_BANK_DIRECTION_BOTH & direction))
+ dir = "debit";
+ if (NULL == dir)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ if (TALER_BANK_DIRECTION_CANCEL == (TALER_BANK_DIRECTION_CANCEL & direction))
+ can = "show";
+ else
+ can = "omit";
if (UINT64_MAX == start_row)
{
- if (TALER_BANK_DIRECTION_BOTH == direction)
- GNUNET_asprintf (&url,
- "/history?auth=basic&account_number=%llu&delta=%lld",
- (unsigned long long) account_number,
- (long long) num_results);
- else
- GNUNET_asprintf (&url,
- "/history?auth=basic&account_number=%llu&delta=%lld&direction=%s",
- (unsigned long long) account_number,
- (long long) num_results,
- (TALER_BANK_DIRECTION_CREDIT == direction) ? "credit" : "debit");
+ GNUNET_asprintf (&url,
+ "/history?auth=basic&account_number=%llu&delta=%lld&direction=%s&cancelled=%s",
+ (unsigned long long) account_number,
+ (long long) num_results,
+ dir,
+ can);
}
else
{
- if (TALER_BANK_DIRECTION_BOTH == direction)
- GNUNET_asprintf (&url,
- "/history?auth=basic&account_number=%llu&delta=%lld&start=%llu",
- (unsigned long long) account_number,
- (long long) num_results,
- (unsigned long long) start_row);
- else
- GNUNET_asprintf (&url,
- "/history?auth=basic&account_number=%llu&delta=%lld&start=%llu&direction=%s",
- (unsigned long long) account_number,
- (long long) num_results,
- (unsigned long long) start_row,
- (TALER_BANK_DIRECTION_CREDIT == direction) ? "credit" : "debit");
+ GNUNET_asprintf (&url,
+ "/history?auth=basic&account_number=%llu&delta=%lld&start=%llu&direction=%s&cancelled=%s",
+ (unsigned long long) account_number,
+ (long long) num_results,
+ (unsigned long long) start_row,
+ dir,
+ can);
}
hh = GNUNET_new (struct TALER_BANK_HistoryHandle);
diff --git a/src/bank-lib/bank_api_reject.c b/src/bank-lib/bank_api_reject.c
new file mode 100644
index 000000000..c630ccd52
--- /dev/null
+++ b/src/bank-lib/bank_api_reject.c
@@ -0,0 +1,245 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2015, 2016, 2017 Taler Systems SA
+
+ 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, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file bank-lib/bank_api_reject.c
+ * @brief Implementation of the /reject request of the bank's HTTP API
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "bank_api_common.h"
+#include <microhttpd.h> /* just for HTTP status codes */
+#include "taler_signatures.h"
+
+
+/**
+ * @brief A /reject Handle
+ */
+struct TALER_BANK_RejectHandle
+{
+
+ /**
+ * The url for this request.
+ */
+ char *request_url;
+
+ /**
+ * JSON encoding of the request to POST.
+ */
+ char *json_enc;
+
+ /**
+ * Handle for the request.
+ */
+ struct GNUNET_CURL_Job *job;
+
+ /**
+ * HTTP authentication-related headers for the request.
+ */
+ struct curl_slist *authh;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_BANK_RejectResultCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+};
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP /reject request.
+ *
+ * @param cls the `struct TALER_BANK_RejectHandle`
+ * @param response_code HTTP response code, 0 on error
+ * @param json parsed JSON result, NULL on error
+ */
+static void
+handle_reject_finished (void *cls,
+ long response_code,
+ const json_t *json)
+{
+ struct TALER_BANK_RejectHandle *rh = cls;
+ enum TALER_ErrorCode ec;
+
+ rh->job = NULL;
+ switch (response_code)
+ {
+ case 0:
+ ec = TALER_EC_INVALID_RESPONSE;
+ break;
+ case MHD_HTTP_OK:
+ GNUNET_break_op (0);
+ response_code = 0;
+ ec = TALER_EC_INVALID_RESPONSE;
+ break;
+ case MHD_HTTP_NO_CONTENT:
+ ec = TALER_EC_NONE;
+ break;
+ case MHD_HTTP_BAD_REQUEST:
+ /* This should never happen, either us or the bank is buggy
+ (or API version conflict); just pass JSON reply to the application */
+ ec = TALER_BANK_parse_ec_ (json);
+ break;
+ case MHD_HTTP_FORBIDDEN:
+ /* Access denied */
+ ec = TALER_BANK_parse_ec_ (json);
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ /* Nothing really to verify, bank says one of the signatures is
+ invalid; as we checked them, this should never happen, we
+ should pass the JSON reply to the application */
+ ec = TALER_BANK_parse_ec_ (json);
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ /* Nothing really to verify, this should never
+ happen, we should pass the JSON reply to the application */
+ ec = TALER_BANK_parse_ec_ (json);
+ break;
+ case MHD_HTTP_INTERNAL_SERVER_ERROR:
+ /* Server had an internal issue; we should retry, but this API
+ leaves this to the application */
+ ec = TALER_BANK_parse_ec_ (json);
+ break;
+ default:
+ /* unexpected response code */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u\n",
+ (unsigned int) response_code);
+ GNUNET_break (0);
+ ec = TALER_BANK_parse_ec_ (json);
+ response_code = 0;
+ break;
+ }
+ rh->cb (rh->cb_cls,
+ response_code,
+ ec);
+ TALER_BANK_reject_cancel (rh);
+}
+
+
+/**
+ * Request rejection of a wire transfer, marking it as cancelled and voiding
+ * its effects.
+ *
+ * @param ctx curl context for the event loop
+ * @param bank_base_url URL of the bank (used to execute this request)
+ * @param auth authentication data to use
+ * @param account_number which account number should we query
+ * @param rowid transfer to reject
+ * @param rcb the callback to call with the operation result
+ * @param rcb_cls closure for @a rcb
+ * @return NULL
+ * if the inputs are invalid.
+ * In this case, the callback is not called.
+ */
+struct TALER_BANK_RejectHandle *
+TALER_BANK_reject (struct GNUNET_CURL_Context *ctx,
+ const char *bank_base_url,
+ const struct TALER_BANK_AuthenticationData *auth,
+ uint64_t account_number,
+ uint64_t rowid,
+ TALER_BANK_RejectResultCallback rcb,
+ void *rcb_cls)
+{
+ struct TALER_BANK_RejectHandle *rh;
+ json_t *reject_obj;
+ CURL *eh;
+
+ reject_obj = json_pack ("{s:{s:s}, s:I, s:I}",
+ "auth", "type", "basic",
+ "row_id", (json_int_t) rowid,
+ "credit_account", (json_int_t) account_number);
+ if (NULL == reject_obj)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ rh = GNUNET_new (struct TALER_BANK_RejectHandle);
+ rh->cb = rcb;
+ rh->cb_cls = rcb_cls;
+ rh->request_url = TALER_BANK_path_to_url_ (bank_base_url,
+ "/reject");
+ rh->authh = TALER_BANK_make_auth_header_ (auth);
+ /* Append content type header here, can't do it in GNUNET_CURL_job_add
+ as that would override the CURLOPT_HTTPHEADER instead of appending. */
+ {
+ struct curl_slist *ext;
+
+ ext = curl_slist_append (rh->authh,
+ "Content-Type: application/json");
+ if (NULL == ext)
+ GNUNET_break (0);
+ else
+ rh->authh = ext;
+ }
+ eh = curl_easy_init ();
+ GNUNET_assert (NULL != (rh->json_enc =
+ json_dumps (reject_obj,
+ JSON_COMPACT)));
+ json_decref (reject_obj);
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_HTTPHEADER,
+ rh->authh));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_URL,
+ rh->request_url));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_POSTFIELDS,
+ rh->json_enc));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_POSTFIELDSIZE,
+ strlen (rh->json_enc)));
+ rh->job = GNUNET_CURL_job_add (ctx,
+ eh,
+ GNUNET_NO,
+ &handle_reject_finished,
+ rh);
+ return rh;
+}
+
+
+/**
+ * Cancel an reject request. This function cannot be used on a request
+ * handle if the response was is already served for it.
+ *
+ * @param rh the reject request handle
+ */
+void
+TALER_BANK_reject_cancel (struct TALER_BANK_RejectHandle *rh)
+{
+ if (NULL != rh->job)
+ {
+ GNUNET_CURL_job_cancel (rh->job);
+ rh->job = NULL;
+ }
+ curl_slist_free_all (rh->authh);
+ GNUNET_free (rh->request_url);
+ GNUNET_free (rh->json_enc);
+ GNUNET_free (rh);
+}
+
+
+/* end of bank_api_reject.c */
diff --git a/src/bank-lib/fakebank.c b/src/bank-lib/fakebank.c
index 268924151..67175721a 100644
--- a/src/bank-lib/fakebank.c
+++ b/src/bank-lib/fakebank.c
@@ -81,6 +81,11 @@ struct Transaction
* Number of this transaction.
*/
uint64_t serial_id;
+
+ /**
+ * Flag set if the transfer was rejected.
+ */
+ int rejected;
};
@@ -220,6 +225,31 @@ TALER_FAKEBANK_make_transfer (struct TALER_FAKEBANK_Handle *h,
/**
+ * Reject incoming wire transfer to account @a credit_account
+ * as identified by @a rowid.
+ *
+ * @param h fake bank handle
+ * @param rowid identifies transfer to reject
+ * @param credit_account account number of owner of credited account
+ * @return #GNUNET_YES on success, #GNUNET_NO if the wire transfer was not found
+ */
+int
+TALER_FAKEBANK_reject_transfer (struct TALER_FAKEBANK_Handle *h,
+ uint64_t rowid,
+ uint64_t credit_account)
+{
+ for (struct Transaction *t = h->transactions_head; NULL != t; t = t->next)
+ if ( (t->serial_id == rowid) &&
+ (t->credit_account == credit_account) )
+ {
+ t->rejected = GNUNET_YES;
+ return GNUNET_YES;
+ }
+ return GNUNET_NO;
+}
+
+
+/**
* Check that no wire transfers were ordered (or at least none
* that have not been taken care of via #TALER_FAKEBANK_check()).
* If any transactions are onrecord, return #GNUNET_SYSERR.
@@ -288,6 +318,62 @@ TALER_FAKEBANK_stop (struct TALER_FAKEBANK_Handle *h)
/**
+ * Create and queue a bank error message with the HTTP response
+ * code @a response_code on connection @a connection.
+ *
+ * @param connection where to queue the reply
+ * @param response_code http status code to use
+ * @param ec taler error code to use
+ * @param message human readable error message
+ * @return MHD status code
+ */
+static int
+create_bank_error (struct MHD_Connection *connection,
+ unsigned int response_code,
+ enum TALER_ErrorCode ec,
+ const char *message)
+{
+ json_t *json;
+ struct MHD_Response *resp;
+ void *json_str;
+ size_t json_len;
+ int ret;
+
+ json = json_pack ("{s:s, s:I}",
+ "error",
+ message,
+ "ec",
+ (json_int_t) ec);
+ json_str = json_dumps (json,
+ JSON_INDENT(2));
+ json_decref (json);
+ if (NULL == json_str)
+ {
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+ json_len = strlen (json_str);
+ resp = MHD_create_response_from_buffer (json_len,
+ json_str,
+ MHD_RESPMEM_MUST_FREE);
+ if (NULL == resp)
+ {
+ GNUNET_break (0);
+ free (json_str);
+ return MHD_NO;
+ }
+ (void) MHD_add_response_header (resp,
+ MHD_HTTP_HEADER_CONTENT_TYPE,
+ "application/json");
+ ret = MHD_queue_response (connection,
+ response_code,
+ resp);
+ MHD_destroy_response (resp);
+ return ret;
+}
+
+
+/**
* Function called whenever MHD is done with a request. If the
* request was a POST, we may have stored a `struct Buffer *` in the
* @a con_cls that might still need to be cleaned up. Call the
@@ -359,13 +445,13 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h,
break;
}
{
- const char *wtid;
+ const char *subject;
uint64_t debit_account;
uint64_t credit_account;
const char *base_url;
struct TALER_Amount amount;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("wtid", &wtid),
+ GNUNET_JSON_spec_string ("subject", &subject),
GNUNET_JSON_spec_uint64 ("debit_account", &debit_account),
GNUNET_JSON_spec_uint64 ("credit_account", &credit_account),
TALER_JSON_spec_amount ("amount", &amount),
@@ -385,7 +471,7 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h,
debit_account,
credit_account,
&amount,
- wtid,
+ subject,
base_url);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Receiving incoming wire transfer: %llu->%llu from %s\n",
@@ -434,6 +520,94 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h,
/**
+ * Handle incoming HTTP request for /reject.
+ *
+ * @param h the fakebank handle
+ * @param connection the connection
+ * @param upload_data request data
+ * @param upload_data_size size of @a upload_data in bytes
+ * @param con_cls closure for request (a `struct Buffer *`)
+ * @return MHD result code
+ */
+static int
+handle_reject (struct TALER_FAKEBANK_Handle *h,
+ struct MHD_Connection *connection,
+ const char *upload_data,
+ size_t *upload_data_size,
+ void **con_cls)
+{
+ enum GNUNET_JSON_PostResult pr;
+ json_t *json;
+ struct MHD_Response *resp;
+ int ret;
+ int found;
+
+ pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
+ con_cls,
+ upload_data,
+ upload_data_size,
+ &json);
+ switch (pr)
+ {
+ case GNUNET_JSON_PR_OUT_OF_MEMORY:
+ GNUNET_break (0);
+ return MHD_NO;
+ case GNUNET_JSON_PR_CONTINUE:
+ return MHD_YES;
+ case GNUNET_JSON_PR_REQUEST_TOO_LARGE:
+ GNUNET_break (0);
+ return MHD_NO;
+ case GNUNET_JSON_PR_JSON_INVALID:
+ GNUNET_break (0);
+ return MHD_NO;
+ case GNUNET_JSON_PR_SUCCESS:
+ break;
+ }
+ {
+ uint64_t serial_id;
+ uint64_t credit_account;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_uint64 ("row_id", &serial_id),
+ GNUNET_JSON_spec_uint64 ("credit_account", &credit_account),
+ GNUNET_JSON_spec_end ()
+ };
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break (0);
+ json_decref (json);
+ return MHD_NO;
+ }
+ found = TALER_FAKEBANK_reject_transfer (h,
+ serial_id,
+ credit_account);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Rejected wire transfer #%llu (to %llu)\n",
+ (unsigned long long) serial_id,
+ (unsigned long long) credit_account);
+ }
+ json_decref (json);
+
+ if (GNUNET_OK != found)
+ return create_bank_error (connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_BANK_REJECT_NOT_FOUND,
+ "transaction unknown");
+ /* finally build regular response */
+ resp = MHD_create_response_from_buffer (0,
+ NULL,
+ MHD_RESPMEM_PERSISTENT);
+ ret = MHD_queue_response (connection,
+ MHD_HTTP_NO_CONTENT,
+ resp);
+ MHD_destroy_response (resp);
+ return ret;
+}
+
+
+/**
* Handle incoming HTTP request for /history
*
* @param h the fakebank handle
@@ -451,6 +625,7 @@ handle_history (struct TALER_FAKEBANK_Handle *h,
const char *start;
const char *dir;
const char *acc;
+ const char *cancelled;
unsigned long long account_number;
unsigned long long start_number;
long long count;
@@ -469,6 +644,9 @@ handle_history (struct TALER_FAKEBANK_Handle *h,
dir = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND,
"direction");
+ cancelled = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ "cancelled");
start = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND,
"start");
@@ -496,7 +674,14 @@ handle_history (struct TALER_FAKEBANK_Handle *h,
(1 != sscanf (start,
"%llu",
&start_number)) ) ||
- ( (NULL != dir) &&
+ (NULL == dir) ||
+ (NULL == cancelled) ||
+ ( (0 != strcasecmp (cancelled,
+ "OMIT")) &&
+ (0 != strcasecmp (cancelled,
+ "SHOW")) ) ||
+ ( (0 != strcasecmp (dir,
+ "BOTH")) &&
(0 != strcasecmp (dir,
"CREDIT")) &&
(0 != strcasecmp (dir,
@@ -513,13 +698,40 @@ handle_history (struct TALER_FAKEBANK_Handle *h,
dir,
(unsigned long long) account_number,
start);
- if (NULL == dir)
- direction = TALER_BANK_DIRECTION_BOTH;
- else if (0 == strcasecmp (dir,
- "CREDIT"))
+ if (0 == strcasecmp (dir,
+ "CREDIT"))
+ {
direction = TALER_BANK_DIRECTION_CREDIT;
- else
+ }
+ else if (0 == strcasecmp (dir,
+ "DEBIT"))
+ {
direction = TALER_BANK_DIRECTION_DEBIT;
+ }
+ else if (0 == strcasecmp (dir,
+ "BOTH"))
+ {
+ direction = TALER_BANK_DIRECTION_BOTH;
+ }
+ else
+ {
+ GNUNET_assert (0);
+ return MHD_NO;
+ }
+ if (0 == strcasecmp (cancelled,
+ "OMIT"))
+ {
+ /* nothing */
+ } else if (0 == strcasecmp (cancelled,
+ "SHOW"))
+ {
+ direction |= TALER_BANK_DIRECTION_CANCEL;
+ }
+ else
+ {
+ GNUNET_assert (0);
+ return MHD_NO;
+ }
if (NULL == start)
{
if (count > 0)
@@ -557,6 +769,7 @@ handle_history (struct TALER_FAKEBANK_Handle *h,
{
json_t *trans;
char *subject;
+ const char *sign;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Found transaction over %s from %llu to %llu\n",
@@ -564,10 +777,12 @@ handle_history (struct TALER_FAKEBANK_Handle *h,
(unsigned long long) pos->debit_account,
(unsigned long long) pos->credit_account);
- if (! ( ( (account_number == pos->debit_account) &&
- (0 != (direction & TALER_BANK_DIRECTION_DEBIT)) ) ||
- ( (account_number == pos->credit_account) &&
- (0 != (direction & TALER_BANK_DIRECTION_CREDIT) ) ) ) )
+ if ( (! ( ( (account_number == pos->debit_account) &&
+ (0 != (direction & TALER_BANK_DIRECTION_DEBIT)) ) ||
+ ( (account_number == pos->credit_account) &&
+ (0 != (direction & TALER_BANK_DIRECTION_CREDIT) ) ) ) ) ||
+ ( (0 == (direction & TALER_BANK_DIRECTION_CANCEL)) &&
+ (GNUNET_YES == pos->rejected) ) )
{
if (count > 0)
pos = pos->next;
@@ -580,11 +795,15 @@ handle_history (struct TALER_FAKEBANK_Handle *h,
"%s %s",
pos->subject,
pos->exchange_base_url);
+ sign =
+ (account_number == pos->debit_account)
+ ? (pos->rejected ? "cancel-" : "-")
+ : (pos->rejected ? "cancel+" : "+");
trans = json_pack ("{s:I, s:o, s:o, s:s, s:I, s:s}",
"row_id", (json_int_t) pos->serial_id,
"date", GNUNET_JSON_from_time_abs (pos->date),
"amount", TALER_JSON_from_amount (&pos->amount),
- "sign", (account_number == pos->debit_account) ? "-" : "+",
+ "sign", sign,
"counterpart", (json_int_t) ( (account_number == pos->debit_account)
? pos->credit_account
: pos->debit_account),
@@ -699,6 +918,15 @@ handle_mhd_request (void *cls,
upload_data_size,
con_cls);
if ( (0 == strcasecmp (url,
+ "/reject")) &&
+ (0 == strcasecmp (method,
+ MHD_HTTP_METHOD_POST)) )
+ return handle_reject (h,
+ connection,
+ upload_data,
+ upload_data_size,
+ con_cls);
+ if ( (0 == strcasecmp (url,
"/history")) &&
(0 == strcasecmp (method,
MHD_HTTP_METHOD_GET)) )
diff --git a/src/bank-lib/test_bank_api.c b/src/bank-lib/test_bank_api.c
index 19d15ca61..80c462d81 100644
--- a/src/bank-lib/test_bank_api.c
+++ b/src/bank-lib/test_bank_api.c
@@ -50,6 +50,7 @@ run (void *cls)
{ .oc = TBI_OC_ADMIN_ADD_INCOMING,
.label = "deposit-1",
.details.admin_add_incoming.exchange_base_url = "https://exchange.net/", /* bogus */
+ .details.admin_add_incoming.subject = "subject 1",
.details.admin_add_incoming.expected_response_code = MHD_HTTP_OK,
.details.admin_add_incoming.credit_account_no = 1,
.details.admin_add_incoming.debit_account_no = 2, /* Ignored */
@@ -58,6 +59,7 @@ run (void *cls)
{ .oc = TBI_OC_ADMIN_ADD_INCOMING,
.label = "deposit-2",
.details.admin_add_incoming.exchange_base_url = "https://exchange.net/", /* bogus */
+ .details.admin_add_incoming.subject = "subject 2",
.details.admin_add_incoming.expected_response_code = MHD_HTTP_OK,
.details.admin_add_incoming.credit_account_no = 1,
.details.admin_add_incoming.debit_account_no = 2, /* Ignored */
@@ -89,6 +91,27 @@ run (void *cls)
.details.history.direction = TALER_BANK_DIRECTION_DEBIT,
.details.history.start_row_ref = "deposit-1",
.details.history.num_results = 5 },
+ { .oc = TBI_OC_REJECT,
+ .label = "reject-1",
+ .details.reject.cmd_ref = "deposit-1" },
+ { .oc = TBI_OC_HISTORY,
+ .label = "history-r1",
+ .details.history.account_number = 2,
+ .details.history.direction = TALER_BANK_DIRECTION_CREDIT,
+ .details.history.start_row_ref = NULL,
+ .details.history.num_results = 5 },
+ { .oc = TBI_OC_HISTORY,
+ .label = "history-r2",
+ .details.history.account_number = 2,
+ .details.history.direction = TALER_BANK_DIRECTION_DEBIT,
+ .details.history.start_row_ref = NULL,
+ .details.history.num_results = 5 },
+ { .oc = TBI_OC_HISTORY,
+ .label = "history-r3",
+ .details.history.account_number = 2,
+ .details.history.direction = TALER_BANK_DIRECTION_BOTH | TALER_BANK_DIRECTION_CANCEL,
+ .details.history.start_row_ref = NULL,
+ .details.history.num_results = 5 },
{ .oc = TBI_OC_END }
};
diff --git a/src/bank-lib/test_bank_api_with_fakebank.c b/src/bank-lib/test_bank_api_with_fakebank.c
index e16c3a915..440851b15 100644
--- a/src/bank-lib/test_bank_api_with_fakebank.c
+++ b/src/bank-lib/test_bank_api_with_fakebank.c
@@ -48,6 +48,7 @@ run (void *cls)
/* Add EUR:5.01 to account 1 */
{ .oc = TBI_OC_ADMIN_ADD_INCOMING,
.label = "debit-1",
+ .details.admin_add_incoming.subject = "subject 1",
.details.admin_add_incoming.expected_response_code = MHD_HTTP_OK,
.details.admin_add_incoming.credit_account_no = 1,
.details.admin_add_incoming.debit_account_no = 2,
@@ -68,6 +69,7 @@ run (void *cls)
.details.history.num_results = 5 },
{ .oc = TBI_OC_ADMIN_ADD_INCOMING,
.label = "debit-2",
+ .details.admin_add_incoming.subject = "subject 2",
.details.admin_add_incoming.expected_response_code = MHD_HTTP_OK,
.details.admin_add_incoming.credit_account_no = 3,
.details.admin_add_incoming.debit_account_no = 2,
@@ -75,6 +77,7 @@ run (void *cls)
.details.admin_add_incoming.amount = "KUDOS:3.21" },
{ .oc = TBI_OC_ADMIN_ADD_INCOMING,
.label = "credit-2",
+ .details.admin_add_incoming.subject = "credit 2",
.details.admin_add_incoming.expected_response_code = MHD_HTTP_OK,
.details.admin_add_incoming.credit_account_no = 2,
.details.admin_add_incoming.debit_account_no = 3,
@@ -105,6 +108,40 @@ run (void *cls)
/* check transfer list is now empty */
{ .oc = TBI_OC_EXPECT_TRANSFERS_EMPTY,
.label = "expect-empty" },
+ /* Add EUR:5.01 to account 1 */
+ { .oc = TBI_OC_ADMIN_ADD_INCOMING,
+ .label = "credit-for-reject-1",
+ .details.admin_add_incoming.subject = "subject 3",
+ .details.admin_add_incoming.expected_response_code = MHD_HTTP_OK,
+ .details.admin_add_incoming.credit_account_no = 1,
+ .details.admin_add_incoming.debit_account_no = 2,
+ .details.admin_add_incoming.exchange_base_url = "https://exchange.net/",
+ .details.admin_add_incoming.amount = "KUDOS:5.01" },
+ { .oc = TBI_OC_REJECT,
+ .label = "reject-1",
+ .details.reject.cmd_ref = "credit-for-reject-1" },
+ { .oc = TBI_OC_HISTORY,
+ .label = "history-r1",
+ .details.history.account_number = 1,
+ .details.history.direction = TALER_BANK_DIRECTION_BOTH,
+ /* range is exclusive, and everything up to and including "credit-2"
+ was already killed via TBI_OC_EXPECT_TRANSFER and thus won't show
+ in the history. So to see the rejected transfer, we need to start
+ looking after "credit-2" */
+ .details.history.start_row_ref = NULL,
+ .details.history.num_results = 5 },
+ { .oc = TBI_OC_HISTORY,
+ .label = "history-r1c",
+ .details.history.account_number = 1,
+ .details.history.direction = TALER_BANK_DIRECTION_BOTH | TALER_BANK_DIRECTION_CANCEL,
+ .details.history.start_row_ref = NULL,
+ .details.history.num_results = 5 },
+ { .oc = TBI_OC_EXPECT_TRANSFER,
+ .label = "expect-credit-reject-1",
+ .details.expect_transfer.cmd_ref = "credit-for-reject-1" },
+ /* check transfer list is now empty */
+ { .oc = TBI_OC_EXPECT_TRANSFERS_EMPTY,
+ .label = "expect-empty-2" },
{ .oc = TBI_OC_END }
};
diff --git a/src/bank-lib/test_bank_interpreter.c b/src/bank-lib/test_bank_interpreter.c
index f5aee8ee6..fac0ab692 100644
--- a/src/bank-lib/test_bank_interpreter.c
+++ b/src/bank-lib/test_bank_interpreter.c
@@ -110,7 +110,6 @@ static const struct TBI_Command *
find_command (const struct InterpreterState *is,
const char *label)
{
- unsigned int i;
const struct TBI_Command *cmd;
if (NULL == label)
@@ -119,7 +118,7 @@ find_command (const struct InterpreterState *is,
"Attempt to lookup command for empty label\n");
return NULL;
}
- for (i=0;TBI_OC_END != (cmd = &is->commands[i])->oc;i++)
+ for (unsigned int i=0;TBI_OC_END != (cmd = &is->commands[i])->oc;i++)
if ( (NULL != cmd->label) &&
(0 == strcmp (cmd->label,
label)) )
@@ -132,6 +131,63 @@ find_command (const struct InterpreterState *is,
/**
+ * Test if the /admin/add/incoming transaction at offset @a off
+ * has been /rejected.
+ *
+ * @param is interpreter state (where we are right now)
+ * @param off offset of the command to test for rejection
+ * @return #GNUNET_YES if the command at @a off was cancelled
+ */
+static int
+test_cancelled (struct InterpreterState *is,
+ unsigned int off)
+{
+ const struct TBI_Command *cmd = &is->commands[off];
+
+ for (unsigned int i=0;i<is->ip;i++)
+ {
+ const struct TBI_Command *c = &is->commands[i];
+
+ if (TBI_OC_REJECT != c->oc)
+ continue;
+ if (0 == strcmp (c->details.reject.cmd_ref,
+ cmd->label))
+ return GNUNET_YES;
+ }
+ return GNUNET_NO;
+}
+
+
+/**
+ * Test if the /admin/add/incoming transaction at offset @a off
+ * has been #TBI_OC_EXPECT_TRANSFER treated, and thus been
+ * forgotten by the fakebank.
+ *
+ * @param is interpreter state (where we are right now)
+ * @param off offset of the command to test for rejection
+ * @return #GNUNET_YES if the command at @a off was cancelled
+ */
+static int
+test_deleted_by_expected (struct InterpreterState *is,
+ unsigned int off)
+{
+ const struct TBI_Command *cmd = &is->commands[off];
+
+ for (unsigned int i=0;i<is->ip;i++)
+ {
+ const struct TBI_Command *c = &is->commands[i];
+
+ if (TBI_OC_EXPECT_TRANSFER != c->oc)
+ continue;
+ if (0 == strcmp (c->details.expect_transfer.cmd_ref,
+ cmd->label))
+ return GNUNET_YES;
+ }
+ return GNUNET_NO;
+}
+
+
+/**
* Item in the transaction history, as reconstructed from the
* command history.
*/
@@ -214,6 +270,7 @@ build_history (struct InterpreterState *is,
for (unsigned int off = start;off != end + inc; off += inc)
{
const struct TBI_Command *pos = &is->commands[off];
+ int cancelled;
if (TBI_OC_ADMIN_ADD_INCOMING != pos->oc)
continue;
@@ -229,6 +286,15 @@ build_history (struct InterpreterState *is,
continue; /* skip until we find the marker */
if (total >= cmd->details.history.num_results * inc)
break; /* hit limit specified by command */
+ if (GNUNET_YES ==
+ test_deleted_by_expected (is,
+ off))
+ continue;
+ cancelled = test_cancelled (is,
+ off);
+ if ( (GNUNET_YES == cancelled) &&
+ (0 == (cmd->details.history.direction & TALER_BANK_DIRECTION_CANCEL)) )
+ continue;
if ( ( (0 != (cmd->details.history.direction & TALER_BANK_DIRECTION_CREDIT)) &&
(cmd->details.history.account_number ==
pos->details.admin_add_incoming.credit_account_no)) ||
@@ -253,6 +319,7 @@ build_history (struct InterpreterState *is,
for (unsigned int off = start;off != end + inc; off += inc)
{
const struct TBI_Command *pos = &is->commands[off];
+ int cancelled;
if (TBI_OC_ADMIN_ADD_INCOMING != pos->oc)
continue;
@@ -268,6 +335,10 @@ build_history (struct InterpreterState *is,
continue; /* skip until we find the marker */
if (total >= cmd->details.history.num_results * inc)
break; /* hit limit specified by command */
+ if (GNUNET_YES ==
+ test_deleted_by_expected (is,
+ off))
+ continue;
if ( ( (0 != (cmd->details.history.direction & TALER_BANK_DIRECTION_CREDIT)) &&
(cmd->details.history.account_number ==
@@ -280,11 +351,19 @@ build_history (struct InterpreterState *is,
continue;
}
+ cancelled = test_cancelled (is,
+ off);
+ if ( (GNUNET_YES == cancelled) &&
+ (0 == (cmd->details.history.direction & TALER_BANK_DIRECTION_CANCEL)) )
+ continue;
+
if ( (0 != (cmd->details.history.direction & TALER_BANK_DIRECTION_CREDIT)) &&
(cmd->details.history.account_number ==
pos->details.admin_add_incoming.credit_account_no))
{
h[total].direction = TALER_BANK_DIRECTION_CREDIT;
+ if (GNUNET_YES == cancelled)
+ h[total].direction |= TALER_BANK_DIRECTION_CANCEL;
h[total].details.account_details
= json_pack ("{s:s, s:s, s:I}",
"type",
@@ -300,6 +379,8 @@ build_history (struct InterpreterState *is,
pos->details.admin_add_incoming.debit_account_no))
{
h[total].direction = TALER_BANK_DIRECTION_DEBIT;
+ if (GNUNET_YES == cancelled)
+ h[total].direction |= TALER_BANK_DIRECTION_CANCEL;
h[total].details.account_details
= json_pack ("{s:s, s:s, s:I}",
"type",
@@ -323,17 +404,10 @@ build_history (struct InterpreterState *is,
/* h[total].execution_date; // unknown here */
h[total].serial_id
= pos->details.admin_add_incoming.serial_id;
- {
- char *ws;
-
- ws = GNUNET_STRINGS_data_to_string_alloc (&pos->details.admin_add_incoming.wtid,
- sizeof (struct TALER_WireTransferIdentifierRawP));
- GNUNET_asprintf (&h[total].details.wire_transfer_subject,
- "%s %s",
- ws,
- pos->details.admin_add_incoming.exchange_base_url);
- GNUNET_free (ws);
- }
+ GNUNET_asprintf (&h[total].details.wire_transfer_subject,
+ "%s %s",
+ pos->details.admin_add_incoming.subject,
+ pos->details.admin_add_incoming.exchange_base_url);
total++;
}
}
@@ -489,17 +563,33 @@ interpreter_run (void *cls);
/**
+ * Run the next command.
+ *
+ * @param is interpreter to progress
+ */
+static void
+next (struct InterpreterState *is)
+{
+ is->ip++;
+ is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
+ is);
+}
+
+
+/**
* Function called upon completion of our /admin/add/incoming request.
*
* @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
* 0 if the bank's reply is bogus (fails to follow the protocol)
+ * @param ec taler status code
* @param serial_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error
* @param json detailed response from the HTTPD, or NULL if reply was not in JSON
*/
static void
add_incoming_cb (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
uint64_t serial_id,
const json_t *json)
{
@@ -522,9 +612,7 @@ add_incoming_cb (void *cls,
fail (is);
return;
}
- is->ip++;
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
- is);
+ next (is);
}
@@ -538,6 +626,7 @@ add_incoming_cb (void *cls,
* #MHD_HTTP_NO_CONTENT if there are no more results; on success the
* last callback is always of this status (even if `abs(num_results)` were
* already returned).
+ * @param ec taler status code
* @param dir direction of the transfer
* @param serial_id monotonically increasing counter corresponding to the transaction
* @param details details about the wire transfer
@@ -546,6 +635,7 @@ add_incoming_cb (void *cls,
static void
history_cb (void *cls,
unsigned int http_status,
+ enum TALER_ErrorCode ec,
enum TALER_BANK_Direction dir,
uint64_t serial_id,
const struct TALER_BANK_TransferDetails *details,
@@ -580,9 +670,7 @@ history_cb (void *cls,
fail (is);
return;
}
- is->ip++;
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
- is);
+ next (is);
return;
}
if (GNUNET_OK !=
@@ -613,6 +701,38 @@ history_cb (void *cls,
/**
+ * Callbacks of this type are used to serve the result of asking
+ * the bank to reject an incoming wire transfer.
+ *
+ * @param cls closure
+ * @param http_status HTTP response code, #MHD_HTTP_NO_CONTENT (204) for successful status request;
+ * #MHD_HTTP_NOT_FOUND if the rowid is unknown;
+ * 0 if the bank's reply is bogus (fails to follow the protocol),
+ * @param ec detailed error code
+ */
+static void
+reject_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec)
+{
+ struct InterpreterState *is = cls;
+ struct TBI_Command *cmd = &is->commands[is->ip];
+
+ cmd->details.reject.rh = NULL;
+ if (MHD_HTTP_NO_CONTENT != http_status)
+ {
+ GNUNET_break (0);
+ fprintf (stderr,
+ "Unexpected response code %u:\n",
+ http_status);
+ fail (is);
+ return;
+ }
+ next (is);
+}
+
+
+/**
* Run the main interpreter loop that performs bank operations.
*
* @param cls contains the `struct InterpreterState`
@@ -658,15 +778,13 @@ interpreter_run (void *cls)
fail (is);
return;
}
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
- &cmd->details.admin_add_incoming.wtid,
- sizeof (cmd->details.admin_add_incoming.wtid));
+ GNUNET_break (NULL != cmd->details.admin_add_incoming.subject);
cmd->details.admin_add_incoming.aih
= TALER_BANK_admin_add_incoming (is->ctx,
"http://localhost:8080",
&auth,
cmd->details.admin_add_incoming.exchange_base_url,
- &cmd->details.admin_add_incoming.wtid,
+ cmd->details.admin_add_incoming.subject,
&amount,
cmd->details.admin_add_incoming.debit_account_no,
cmd->details.admin_add_incoming.credit_account_no,
@@ -722,7 +840,6 @@ interpreter_run (void *cls)
&amount));
{
char *subject;
- char *expect;
if (GNUNET_OK !=
TALER_FAKEBANK_check (is->fakebank,
@@ -736,22 +853,17 @@ interpreter_run (void *cls)
fail (is);
return;
}
- expect = GNUNET_STRINGS_data_to_string_alloc (&ref->details.admin_add_incoming.wtid,
- sizeof (ref->details.admin_add_incoming.wtid));
- if (0 != strcmp (subject, expect))
+ if (0 != strcmp (ref->details.admin_add_incoming.subject,
+ subject))
{
- GNUNET_free (expect);
GNUNET_free (subject);
GNUNET_break (0);
fail (is);
return;
}
GNUNET_free (subject);
- GNUNET_free (expect);
}
- is->ip++;
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
- is);
+ next (is);
return;
case TBI_OC_EXPECT_TRANSFERS_EMPTY:
if (GNUNET_OK != TALER_FAKEBANK_check_empty (is->fakebank))
@@ -760,9 +872,27 @@ interpreter_run (void *cls)
fail (is);
return;
}
- is->ip++;
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
- is);
+ next (is);
+ return;
+ case TBI_OC_REJECT:
+ ref = find_command (is,
+ cmd->details.reject.cmd_ref);
+ GNUNET_assert (NULL != ref);
+ GNUNET_assert (TBI_OC_ADMIN_ADD_INCOMING == ref->oc);
+ cmd->details.reject.rh
+ = TALER_BANK_reject (is->ctx,
+ "http://localhost:8080",
+ &auth,
+ ref->details.admin_add_incoming.credit_account_no,
+ ref->details.admin_add_incoming.serial_id,
+ &reject_cb,
+ is);
+ if (NULL == cmd->details.reject.rh)
+ {
+ GNUNET_break (0);
+ fail (is);
+ return;
+ }
return;
default:
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -802,7 +932,6 @@ do_shutdown (void *cls)
{
struct InterpreterState *is = cls;
struct TBI_Command *cmd;
- unsigned int i;
if (NULL != is->timeout_task)
{
@@ -810,7 +939,7 @@ do_shutdown (void *cls)
is->timeout_task = NULL;
}
- for (i=0;TBI_OC_END != (cmd = &is->commands[i])->oc;i++)
+ for (unsigned int i=0;TBI_OC_END != (cmd = &is->commands[i])->oc;i++)
{
switch (cmd->oc)
{
@@ -843,6 +972,17 @@ do_shutdown (void *cls)
break;
case TBI_OC_EXPECT_TRANSFERS_EMPTY:
break;
+ case TBI_OC_REJECT:
+ if (NULL != cmd->details.reject.rh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ i,
+ cmd->label);
+ TALER_BANK_reject_cancel (cmd->details.reject.rh);
+ cmd->details.reject.rh = NULL;
+ }
+ break;
default:
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unknown instruction %d at %u (%s)\n",
diff --git a/src/bank-lib/test_bank_interpreter.h b/src/bank-lib/test_bank_interpreter.h
index d4e9c1a6c..ed2a00df7 100644
--- a/src/bank-lib/test_bank_interpreter.h
+++ b/src/bank-lib/test_bank_interpreter.h
@@ -57,7 +57,12 @@ enum TBI_OpCode
/**
* Expect that we have exhaustively gone over all transfers at fakebank.
*/
- TBI_OC_EXPECT_TRANSFERS_EMPTY
+ TBI_OC_EXPECT_TRANSFERS_EMPTY,
+
+ /**
+ * Reject incoming transfer.
+ */
+ TBI_OC_REJECT
};
@@ -110,10 +115,9 @@ struct TBI_Command
const char *exchange_base_url;
/**
- * Wire transfer identifier to use. Initialized to
- * a random value.
+ * Wire transfer subject to use.
*/
- struct TALER_WireTransferIdentifierRawP wtid;
+ const char *subject;
/**
* Which response code do we expect for this command?
@@ -186,6 +190,23 @@ struct TBI_Command
} expect_transfer;
+ /**
+ * Execute /reject operation.
+ */
+ struct {
+
+ /**
+ * Reference to the matching transfer that is now to be rejected.
+ */
+ const char *cmd_ref;
+
+ /**
+ * Set to the API's handle during the operation.
+ */
+ struct TALER_BANK_RejectHandle *rh;
+
+ } reject;
+
} details;
};