diff options
Diffstat (limited to 'src/bank-lib/fakebank.c')
-rw-r--r-- | src/bank-lib/fakebank.c | 954 |
1 files changed, 17 insertions, 937 deletions
diff --git a/src/bank-lib/fakebank.c b/src/bank-lib/fakebank.c index f3b58fd26..37aae0423 100644 --- a/src/bank-lib/fakebank.c +++ b/src/bank-lib/fakebank.c @@ -25,6 +25,7 @@ #include "platform.h" #include "taler_fakebank_lib.h" #include "taler_bank_service.h" +#include "fakebank.h" /** * Maximum POST request size (for /admin/add/incoming) @@ -33,169 +34,6 @@ /** - * Parse URL arguments of a /history[-range] HTTP request. - * - * @param connection MHD connection object. - * @param ha @a HistoryArgs structure. - */ -#define PARSE_HISTORY_ARGS(connection, ha) \ - parse_history_args_ (connection, ha, __FUNCTION__) - -/** - * Details about a transcation we (as the simulated bank) received. - */ -struct Transaction -{ - /** - * We store transactions in a DLL. - */ - struct Transaction *next; - - /** - * We store transactions in a DLL. - */ - struct Transaction *prev; - - /** - * Amount to be transferred. - */ - struct TALER_Amount amount; - - /** - * Account to debit. - */ - uint64_t debit_account; - - /** - * Account to credit. - */ - uint64_t credit_account; - - /** - * Subject of the transfer. - */ - char *subject; - - /** - * Base URL of the exchange. - */ - char *exchange_base_url; - - /** - * When did the transaction happen? - */ - struct GNUNET_TIME_Absolute date; - - /** - * Number of this transaction. - */ - uint64_t row_id; - - /** - * Flag set if the transfer was rejected. - */ - int rejected; - - /** - * Has this transaction been subjected to #TALER_FAKEBANK_check() - * and should thus no longer be counted in - * #TALER_FAKEBANK_check_empty()? - */ - int checked; -}; - - -/** - * Needed to implement ascending/descending ordering - * of /history results. - */ -struct HistoryElement -{ - - /** - * History JSON element. - */ - json_t *element; - - /** - * Previous element. - */ - struct HistoryElement *prev; - - /** - * Next element. - */ - struct HistoryElement *next; -}; - - -/** - * Values to implement the "/history-range" range. - */ -struct HistoryRangeDates -{ - /** - * Oldest row in the results. - */ - struct GNUNET_TIME_Absolute start; - - /** - * Youngest row in the results. - */ - struct GNUNET_TIME_Absolute end; -}; - -/** - * Values to implement the "/history" range. - */ -struct HistoryRangeIds -{ - - /** - * (Exclusive) row ID for the result set. - */ - unsigned long long start; - - /** - * How many transactions we want in the result set. If - * negative/positive, @a start will be strictly younger/older - * of any element in the result set. - */ - long long count; -}; - - -/** - * This is the "base" structure for both the /history and the - * /history-range API calls. - */ -struct HistoryArgs -{ - - /** - * Direction asked by the client: CREDIT / DEBIT / BOTH / CANCEL. - */ - enum TALER_BANK_Direction direction; - - /** - * Bank account number of the requesting client. - */ - unsigned long long account_number; - - /** - * Ordering of the results. - */ - unsigned int ascending; - - /** - * Overloaded type that indicates the "range" to be returned - * in the results; this can be either a date range, or a - * starting row id + the count. - */ - void *range; -}; - -/** * Handle for the fake bank. */ struct TALER_FAKEBANK_Handle @@ -746,442 +584,6 @@ handle_reject (struct TALER_FAKEBANK_Handle *h, return ret; } -/*********************************** - * Serving "/history" starts here. * - ***********************************/ - -/** - * Type for a function that decides whether or not - * the history-building loop should iterate once again. - * Typically called from inside the 'while' condition. - * - * @param ha history argument. - * @param pos current position. - * @return GNUNET_YES if the iteration shuold go on. - */ -typedef int (*CheckAdvance) - (const struct HistoryArgs *ha, - const struct Transaction *pos); - -/** - * Type for a function that steps over the next element - * in the list of all transactions, after the current @a pos - * _got_ included in the result. - */ -typedef struct Transaction * (*Step) - (const struct HistoryArgs *ha, - const struct Transaction *pos); - -/* - * Type for a function that steps over the next element - * in the list of all transactions, after the current @a pos - * did _not_ get included in the result. - */ -typedef struct Transaction * (*Skip) - (const struct HistoryArgs *ha, - const struct Transaction *pos); - - - - -/** - * Decides whether the history builder will advance or not - * to the next element. - * - * @param ha history args - * @return GNUNET_YES/NO to advance/not-advance. - */ -static int -handle_history_advance (const struct HistoryArgs *ha, - const struct Transaction *pos) -{ - const struct HistoryRangeIds *hri = ha->range; - - return (NULL != pos) && (0 != hri->count); -} - - -/** - * Iterates on the "next" element to be processed. To - * be used when the current element does not get inserted in - * the result. - * - * @param ha history arguments. - * @param pos current element being processed. - * @return the next element to be processed. - */ -static struct Transaction * -handle_history_skip (const struct HistoryArgs *ha, - const struct Transaction *pos) -{ - const struct HistoryRangeIds *hri = ha->range; - - if (hri->count > 0) - return pos->next; - if (hri->count < 0) - return pos->prev; - return NULL; -} - - -/** - * Iterates on the "next" element to be processed. To - * be used when the current element _gets_ inserted in the result. - * - * @param ha history arguments. - * @param pos current element being processed. - * @return the next element to be processed. - */ -static struct Transaction * -handle_history_step (const struct HistoryArgs *ha, - const struct Transaction *pos) -{ - struct HistoryRangeIds *hri = ha->range; - - if (hri->count > 0) - { - hri->count--; - return pos->next; - } - if (hri->count < 0) - { - hri->count++; - return pos->prev; - } - return NULL; -} - - -/** - * Decides whether the history builder will advance or not - * to the next element. - * - * @param ha history args - * @return GNUNET_YES/NO to advance/not-advance. - */ -static int -handle_history_range_advance (const struct HistoryArgs *ha, - const struct Transaction *pos) -{ - const struct HistoryRangeDates *hrd = ha->range; - - if ( (NULL != pos) && - (pos->date.abs_value_us <= hrd->end.abs_value_us) ) - return GNUNET_YES; - - return GNUNET_NO; -} - - -/** - * Iterates towards the "next" element to be processed. To - * be used when the current element does not get inserted in - * the result. - * - * @param ha history arguments. - * @param pos current element being processed. - * @return the next element to be processed. - */ -static struct Transaction * -handle_history_range_skip (const struct HistoryArgs *ha, - const struct Transaction *pos) -{ - /* Transactions - * are stored from "head"/older to "tail"/younger. */ - return pos->next; -} - -/** - * Iterates on the "next" element to be processed. To - * be used when the current element _gets_ inserted in the result. - * Same implementation of the "skip" counterpart, as /history-range - * does not have the notion of count/delta. - */ -Step handle_history_range_step = handle_history_range_skip; - -/** - * Actual history response builder. - * - * @param pos first (included) element in the result set. - * @param ha history arguments. - * @param caller_name which function is building the history. - * @return MHD_YES / MHD_NO, after having enqueued the response - * object into MHD. - */ -static int -build_history_response (struct MHD_Connection *connection, - struct Transaction *pos, - struct HistoryArgs *ha, - Skip skip, - Step step, - CheckAdvance advance) -{ - - struct HistoryElement *history_results_head = NULL; - struct HistoryElement *history_results_tail = NULL; - struct HistoryElement *history_element = NULL; - json_t *history; - json_t *jresponse; - int ret; - - while (advance (ha, - pos)) - { - json_t *trans; - char *subject; - const char *sign; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Found transaction over %s from %llu to %llu\n", - TALER_amount2s (&pos->amount), - (unsigned long long) pos->debit_account, - (unsigned long long) pos->credit_account); - - if ( (! ( ( (ha->account_number == pos->debit_account) && - (0 != (ha->direction & TALER_BANK_DIRECTION_DEBIT)) ) || - ( (ha->account_number == pos->credit_account) && - (0 != (ha->direction & TALER_BANK_DIRECTION_CREDIT) ) ) ) ) || - ( (0 == (ha->direction & TALER_BANK_DIRECTION_CANCEL)) && - (GNUNET_YES == pos->rejected) ) ) - { - pos = skip (ha, - pos); - continue; - } - - GNUNET_asprintf (&subject, - "%s %s", - pos->subject, - pos->exchange_base_url); - sign = - (ha->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->row_id, - "date", GNUNET_JSON_from_time_abs (pos->date), - "amount", TALER_JSON_from_amount (&pos->amount), - "sign", sign, - "counterpart", (json_int_t) - ( (ha->account_number == pos->debit_account) - ? pos->credit_account - : pos->debit_account), - "wt_subject", subject); - GNUNET_assert (NULL != trans); - GNUNET_free (subject); - - history_element = GNUNET_new (struct HistoryElement); - history_element->element = trans; - - - /* XXX: the ordering feature is missing. */ - - GNUNET_CONTAINER_DLL_insert_tail (history_results_head, - history_results_tail, - history_element); - pos = step (ha, pos); - } - - history = json_array (); - if (NULL != history_results_head) - history_element = history_results_head; - - while (NULL != history_element) - { - json_array_append_new (history, - history_element->element); - history_element = history_element->next; - if (NULL != history_element) - GNUNET_free_non_null (history_element->prev); - } - GNUNET_free_non_null (history_results_tail); - - if (0 == json_array_size (history)) - { - struct MHD_Response *resp; - - json_decref (history); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Returning empty transaction history\n"); - resp = MHD_create_response_from_buffer - (0, - "", - MHD_RESPMEM_PERSISTENT); - ret = MHD_queue_response (connection, - MHD_HTTP_NO_CONTENT, - resp); - MHD_destroy_response (resp); - return ret; - } - - jresponse = json_pack ("{s:o}", - "data", - history); - if (NULL == jresponse) - { - GNUNET_break (0); - return MHD_NO; - } - - /* Finally build response object */ - { - struct MHD_Response *resp; - void *json_str; - size_t json_len; - - json_str = json_dumps (jresponse, - JSON_INDENT(2)); - json_decref (jresponse); - 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, - MHD_HTTP_OK, - resp); - MHD_destroy_response (resp); - } - return ret; -} - - - -/** - * Parse URL history arguments, of _both_ APIs: - * /history and /history-range. - * - * @param connection MHD connection. - * @param function_name name of the caller. - * @param ha[out] will contain the parsed values. - * @return GNUNET_OK only if the parsing succeedes. - */ -static int -parse_history_common_args (struct MHD_Connection *connection, - struct HistoryArgs *ha) -{ - /** - * @variable - * Just check if given and == "basic", no need to keep around. - */ - const char *auth; - - /** - * All those will go into the structure, after parsing. - */ - const char *direction; - const char *cancelled; - const char *ordering; - const char *account_number; - - - auth = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "auth"); - direction = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "direction"); - cancelled = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "cancelled"); - ordering = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "ordering"); - account_number = MHD_lookup_connection_value - (connection, - MHD_GET_ARGUMENT_KIND, - "account_number"); - - /* Fail if one of the above failed. */ - if ( (NULL == direction) || - (NULL == cancelled) || - ( (0 != strcasecmp (cancelled, - "OMIT")) && - (0 != strcasecmp (cancelled, - "SHOW")) ) || - ( (0 != strcasecmp (direction, - "BOTH")) && - (0 != strcasecmp (direction, - "CREDIT")) && - (0 != strcasecmp (direction, - "DEBIT")) ) || - (1 != sscanf (account_number, - "%llu", - &ha->account_number)) || - ( (NULL == auth) || (0 != strcasecmp (auth, - "basic")) ) ) - { - /* Invalid request, given that this is fakebank we impolitely - * just kill the connection instead of returning a nice error. - */ - GNUNET_break (0); - return GNUNET_NO; - } - - if (0 == strcasecmp (direction, - "CREDIT")) - { - ha->direction = TALER_BANK_DIRECTION_CREDIT; - } - else if (0 == strcasecmp (direction, - "DEBIT")) - { - ha->direction = TALER_BANK_DIRECTION_DEBIT; - } - else if (0 == strcasecmp (direction, - "BOTH")) - { - ha->direction = TALER_BANK_DIRECTION_BOTH; - } - - /* Direction is invalid. */ - else - { - GNUNET_break (0); - return GNUNET_NO; - } - - if (0 == strcasecmp (cancelled, - "OMIT")) - { - /* nothing */ - } else if (0 == strcasecmp (cancelled, - "SHOW")) - { - ha->direction |= TALER_BANK_DIRECTION_CANCEL; - } - - /* Cancel-showing policy is invalid. */ - else - { - GNUNET_break (0); - return GNUNET_NO; - } - - if ((NULL != ordering) - && 0 == strcmp ("ascending", - ordering)) - ha->ascending = GNUNET_YES; - else - ha->ascending = GNUNET_NO; - - return GNUNET_OK; -} - /** * Handle incoming HTTP request for /history * @@ -1201,8 +603,8 @@ handle_history_new (struct TALER_FAKEBANK_Handle *h, const char *delta; struct Transaction *pos; - if (GNUNET_OK != parse_history_common_args (connection, - &ha)) + if (GNUNET_OK != TFH_parse_history_common_args (connection, + &ha)) { GNUNET_break (0); return MHD_NO; @@ -1259,12 +661,12 @@ handle_history_new (struct TALER_FAKEBANK_Handle *h, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "/history, start row (0 == no transactions exist): %llu\n", NULL != pos ? pos->row_id : 0); - return build_history_response (connection, - pos, - &ha, - &handle_history_skip, - &handle_history_step, - &handle_history_advance); + return TFH_build_history_response (connection, + pos, + &ha, + &TFH_handle_history_skip, + &TFH_handle_history_step, + &TFH_handle_history_advance); } /** @@ -1288,7 +690,7 @@ handle_history_range (struct TALER_FAKEBANK_Handle *h, long long unsigned int end_stamp; struct Transaction *pos; - if (GNUNET_OK != parse_history_common_args (connection, + if (GNUNET_OK != TFH_parse_history_common_args (connection, &ha)) { GNUNET_break (0); @@ -1309,7 +711,7 @@ handle_history_range (struct TALER_FAKEBANK_Handle *h, &end_stamp)) ) { GNUNET_break (0); - return GNUNET_NO; + return MHD_NO; } hrd.start.abs_value_us = start_stamp * 1000LL * 1000LL; @@ -1325,336 +727,14 @@ handle_history_range (struct TALER_FAKEBANK_Handle *h, if (hrd.start.abs_value_us <= pos->date.abs_value_us) break; } - return build_history_response (connection, - pos, - &ha, - &handle_history_range_skip, - handle_history_range_step, - &handle_history_range_advance); -} - -/** - * Handle incoming HTTP request for /history - * - * @param h the fakebank handle - * @param connection the connection - * @param con_cls place to store state, not used - * @return MHD result code - */ -static int -handle_history (struct TALER_FAKEBANK_Handle *h, - struct MHD_Connection *connection, - void **con_cls) -{ - const char *auth; - const char *delta; - const char *start; - const char *dir; - const char *acc; - const char *cancelled; - const char *ordering; - unsigned long long account_number; - unsigned long long start_number; - long long count; - enum TALER_BANK_Direction direction; - struct Transaction *pos; - json_t *history; - json_t *jresponse; - int ret; - int ascending; - struct HistoryElement *history_results_head = NULL; - struct HistoryElement *history_results_tail = NULL; - struct HistoryElement *history_element = NULL; - - auth = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "auth"); - delta = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "delta"); - 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"); - ordering = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "ordering"); - acc = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - "account_number"); - if ( (NULL == auth) || - (0 != strcasecmp (auth, - "basic")) || - (NULL == acc) || - (NULL == delta) ) - { - /* Invalid request, - given that this is fakebank we impolitely just - kill the connection instead of returning a nice error. */ - GNUNET_break (0); - return MHD_NO; - } - start_number = 0; - if ( (1 != sscanf (delta, - "%lld", - &count)) || - (1 != sscanf (acc, - "%llu", - &account_number)) || - ( (NULL != start) && - (1 != sscanf (start, - "%llu", - &start_number)) ) || - (NULL == dir) || - (NULL == cancelled) || - ( (0 != strcasecmp (cancelled, - "OMIT")) && - (0 != strcasecmp (cancelled, - "SHOW")) ) || - ( (0 != strcasecmp (dir, - "BOTH")) && - (0 != strcasecmp (dir, - "CREDIT")) && - (0 != strcasecmp (dir, - "DEBIT")) ) ) - { - /* Invalid request, given that this is fakebank we impolitely - * just kill the connection instead of returning a nice error. - */ - GNUNET_break (0); - return MHD_NO; - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Client asked for up to %lld results of type %s for account %llu starting at %llu\n", - count, - dir, - (unsigned long long) account_number, - start_number); - if (0 == strcasecmp (dir, - "CREDIT")) - { - direction = TALER_BANK_DIRECTION_CREDIT; - } - 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) - pos = 0 > count ? h->transactions_tail : h->transactions_head; - - else if (NULL != h->transactions_head) - { - for (pos = h->transactions_head; - NULL != pos; - pos = pos->next) - if (pos->row_id == start_number) - break; - if (NULL == pos) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Invalid range specified, transaction %llu not known!\n", - (unsigned long long) start_number); - return MHD_NO; - } - /* range is exclusive, skip the matching entry */ - if (count > 0) - pos = pos->next; - if (count < 0) - pos = pos->prev; - } - else - { - /* list is empty */ - pos = NULL; - } - - history = json_array (); - if ((NULL != ordering) - && 0 == strcmp ("ascending", - ordering)) - ascending = GNUNET_YES; - else - ascending = GNUNET_NO; - - while ( (NULL != pos) && - (0 != count) ) - { - json_t *trans; - char *subject; - const char *sign; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Found transaction over %s from %llu to %llu\n", - TALER_amount2s (&pos->amount), - (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) ) ) ) ) || - ( (0 == (direction & TALER_BANK_DIRECTION_CANCEL)) && - (GNUNET_YES == pos->rejected) ) ) - { - if (count > 0) - pos = pos->next; - if (count < 0) - pos = pos->prev; - continue; - } - - GNUNET_asprintf (&subject, - "%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->row_id, - "date", GNUNET_JSON_from_time_abs (pos->date), - "amount", TALER_JSON_from_amount (&pos->amount), - "sign", sign, - "counterpart", (json_int_t) ( (account_number == pos->debit_account) - ? pos->credit_account - : pos->debit_account), - "wt_subject", subject); - GNUNET_assert (NULL != trans); - GNUNET_free (subject); - - history_element = GNUNET_new (struct HistoryElement); - history_element->element = trans; - - if (((0 < count) && (GNUNET_YES == ascending)) - || ((0 > count) && (GNUNET_NO == ascending))) - GNUNET_CONTAINER_DLL_insert_tail (history_results_head, - history_results_tail, - history_element); - else - GNUNET_CONTAINER_DLL_insert (history_results_head, - history_results_tail, - history_element); - if (count > 0) - { - pos = pos->next; - count--; - } - if (count < 0) - { - pos = pos->prev; - count++; - } - } - - if (NULL != history_results_head) - history_element = history_results_head; - while (NULL != history_element) - { - json_array_append_new (history, - history_element->element); - history_element = history_element->next; - if (NULL != history_element) - GNUNET_free_non_null (history_element->prev); - } - GNUNET_free_non_null (history_results_tail); - - if (0 == json_array_size (history)) - { - struct MHD_Response *resp; - - json_decref (history); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Returning empty transaction history\n"); - resp = MHD_create_response_from_buffer (0, - "", - MHD_RESPMEM_PERSISTENT); - ret = MHD_queue_response (connection, - MHD_HTTP_NO_CONTENT, - resp); - MHD_destroy_response (resp); - return ret; - } - - jresponse = json_pack ("{s:o}", - "data", - history); - if (NULL == jresponse) - { - GNUNET_break (0); - return MHD_NO; - } - - /* Finally build response object */ - { - struct MHD_Response *resp; - void *json_str; - size_t json_len; - - json_str = json_dumps (jresponse, - JSON_INDENT(2)); - json_decref (jresponse); - 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, - MHD_HTTP_OK, - resp); - MHD_destroy_response (resp); - } - return ret; + return TFH_build_history_response (connection, + pos, + &ha, + &TFH_handle_history_range_skip, + TFH_handle_history_range_step, + &TFH_handle_history_range_advance); } -/*********************************** - * End of /history implementation. * - ***********************************/ - /** * Handle incoming HTTP request. * |