/*
This file is part of TALER
(C) 2016-2023 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
*/
/**
* @file bank-lib/fakebank.h
* @brief general state of the fakebank
* @author Christian Grothoff
*/
#ifndef FAKEBANK_H
#define FAKEBANK_H
#include "taler_fakebank_lib.h"
#include "taler_bank_service.h"
#include "taler_mhd_lib.h"
#include
/**
* How long are exchange base URLs allowed to be at most?
* Set to a relatively low number as this does contribute
* significantly to our RAM consumption.
*/
#define MAX_URL_LEN 64
/**
* Maximum POST request size.
*/
#define REQUEST_BUFFER_MAX (4 * 1024)
/**
* Per account information.
*/
struct Account;
/**
* Types of long polling activities.
*/
enum LongPollType
{
/**
* Transfer TO the exchange.
*/
LP_CREDIT,
/**
* Transfer FROM the exchange.
*/
LP_DEBIT,
/**
* Withdraw operation completion/abort.
*/
LP_WITHDRAW
};
/**
* Client waiting for activity on this account.
*/
struct LongPoller
{
/**
* Kept in a DLL.
*/
struct LongPoller *next;
/**
* Kept in a DLL.
*/
struct LongPoller *prev;
/**
* Fakebank this long poller belongs with.
*/
struct TALER_FAKEBANK_Handle *h;
/**
* Account this long poller is waiting on.
*/
struct Account *account;
/**
* Withdraw operation we are waiting on,
* only if @e type is #LP_WITHDRAW, otherwise NULL.
*/
const struct WithdrawalOperation *wo;
/**
* Entry in the heap for this long poller.
*/
struct GNUNET_CONTAINER_HeapNode *hn;
/**
* Client that is waiting for transactions.
*/
struct MHD_Connection *conn;
/**
* When will this long poller time out?
*/
struct GNUNET_TIME_Absolute timeout;
/**
* What does the @e connection wait for?
*/
enum LongPollType type;
};
/**
* Details about a transcation we (as the simulated bank) received.
*/
struct Transaction;
/**
* Information we keep per withdraw operation.
*/
struct WithdrawalOperation
{
/**
* Unique (random) operation ID.
*/
struct GNUNET_ShortHashCode wopid;
/**
* Debited account.
*/
struct Account *debit_account;
/**
* Target exchange account, or NULL if unknown.
*/
const struct Account *exchange_account;
/**
* RowID of the resulting transaction, if any. Otherwise 0.
*/
uint64_t row_id;
/**
* Amount transferred.
*/
struct TALER_Amount amount;
/**
* Public key of the reserve, wire transfer subject.
*/
struct TALER_ReservePublicKeyP reserve_pub;
/**
* When was the transaction made? 0 if not yet.
*/
struct GNUNET_TIME_Timestamp timestamp;
/**
* Was the withdrawal aborted?
*/
bool aborted;
/**
* Did the bank confirm the withdrawal?
*/
bool confirmation_done;
/**
* Is @e reserve_pub initialized?
*/
bool selection_done;
};
/**
* Per account information.
*/
struct Account
{
/**
* Inbound transactions for this account in a MDLL.
*/
struct Transaction *in_head;
/**
* Inbound transactions for this account in a MDLL.
*/
struct Transaction *in_tail;
/**
* Outbound transactions for this account in a MDLL.
*/
struct Transaction *out_head;
/**
* Outbound transactions for this account in a MDLL.
*/
struct Transaction *out_tail;
/**
* Kept in a DLL.
*/
struct LongPoller *lp_head;
/**
* Kept in a DLL.
*/
struct LongPoller *lp_tail;
/**
* Account name (string, not payto!)
*/
char *account_name;
/**
* Receiver name for payto:// URIs.
*/
char *receiver_name;
/**
* Payto URI for this account.
*/
char *payto_uri;
/**
* Password set for the account (if any).
*/
char *password;
/**
* Current account balance.
*/
struct TALER_Amount balance;
/**
* true if the balance is negative.
*/
bool is_negative;
};
/**
* Details about a transcation we (as the simulated bank) received.
*/
struct Transaction
{
/**
* We store inbound transactions in a MDLL.
*/
struct Transaction *next_in;
/**
* We store inbound transactions in a MDLL.
*/
struct Transaction *prev_in;
/**
* We store outbound transactions in a MDLL.
*/
struct Transaction *next_out;
/**
* We store outbound transactions in a MDLL.
*/
struct Transaction *prev_out;
/**
* Amount to be transferred.
*/
struct TALER_Amount amount;
/**
* Account to debit.
*/
struct Account *debit_account;
/**
* Account to credit.
*/
struct Account *credit_account;
/**
* Random unique identifier for the request.
* Used to detect idempotent requests.
*/
struct GNUNET_HashCode request_uid;
/**
* When did the transaction happen?
*/
struct GNUNET_TIME_Timestamp date;
/**
* Number of this transaction.
*/
uint64_t row_id;
/**
* What does the @e subject contain?
*/
enum
{
/**
* Transfer TO the exchange.
*/
T_CREDIT,
/**
* Transfer FROM the exchange.
*/
T_DEBIT,
/**
* Exchange-to-exchange WAD transfer.
*/
T_WAD,
} type;
/**
* Wire transfer subject.
*/
union
{
/**
* Used if @e type is T_DEBIT.
*/
struct
{
/**
* Subject of the transfer.
*/
struct TALER_WireTransferIdentifierRawP wtid;
/**
* Base URL of the exchange.
*/
char exchange_base_url[MAX_URL_LEN];
} debit;
/**
* Used if @e type is T_CREDIT.
*/
struct
{
/**
* Reserve public key of the credit operation.
*/
struct TALER_ReservePublicKeyP reserve_pub;
} credit;
/**
* Used if @e type is T_WAD.
*/
struct
{
/**
* Subject of the transfer.
*/
struct TALER_WadIdentifierP wad;
/**
* Base URL of the originating exchange.
*/
char origin_base_url[MAX_URL_LEN];
} wad;
} subject;
/**
* Has this transaction not yet been subjected to
* #TALER_FAKEBANK_check_credit() or #TALER_FAKEBANK_check_debit() and
* should thus be counted in #TALER_FAKEBANK_check_empty()?
*/
bool unchecked;
};
/**
* Function called to clean up context of a connection.
*
* @param ctx context to clean up
*/
typedef void
(*ConnectionCleaner)(void *ctx);
/**
* Universal context we keep per connection.
*/
struct ConnectionContext
{
/**
* Function we call upon completion to clean up.
*/
ConnectionCleaner ctx_cleaner;
/**
* Request-handler specific context.
*/
void *ctx;
};
/**
* This is the "base" structure for both the /history and the
* /history-range API calls.
*/
struct HistoryArgs
{
/**
* Bank account number of the requesting client.
*/
uint64_t account_number;
/**
* Index of the starting transaction, exclusive (!).
*/
uint64_t start_idx;
/**
* Requested number of results and order
* (positive: ascending, negative: descending)
*/
int64_t delta;
/**
* Timeout for long polling.
*/
struct GNUNET_TIME_Relative lp_timeout;
/**
* true if starting point was given.
*/
bool have_start;
};
/**
* Context we keep per history request.
*/
struct HistoryContext
{
/**
* When does this request time out.
*/
struct GNUNET_TIME_Absolute timeout;
/**
* Client arguments for this request.
*/
struct HistoryArgs ha;
/**
* Account the request is about.
*/
struct Account *acc;
/**
* JSON object we are building to return.
*/
json_t *history;
};
/**
* Context we keep per get withdrawal operation request.
*/
struct WithdrawContext
{
/**
* When does this request time out.
*/
struct GNUNET_TIME_Absolute timeout;
/**
* The withdrawal operation this is about.
*/
struct WithdrawalOperation *wo;
};
/**
* Handle for the fake bank.
*/
struct TALER_FAKEBANK_Handle
{
/**
* We store transactions in a revolving array.
*/
struct Transaction **transactions;
/**
* HTTP server we run to pretend to be the "test" bank.
*/
struct MHD_Daemon *mhd_bank;
/**
* Task running HTTP server for the "test" bank,
* unless we are using a thread pool (then NULL).
*/
struct GNUNET_SCHEDULER_Task *mhd_task;
/**
* Task for expiring long-polling connections,
* unless we are using a thread pool (then NULL).
*/
struct GNUNET_SCHEDULER_Task *lp_task;
/**
* Task for expiring long-polling connections, unless we are using the
* GNUnet scheduler (then NULL).
*/
pthread_t lp_thread;
/**
* MIN-heap of long pollers, sorted by timeout.
*/
struct GNUNET_CONTAINER_Heap *lp_heap;
/**
* Hashmap of reserve public keys to
* `struct Transaction` with that reserve public
* key. Used to prevent public-key reuse.
*/
struct GNUNET_CONTAINER_MultiPeerMap *rpubs;
/**
* Hashmap of short hashes (wopids) to
* `struct WithdrawalOperation`.
* Used to lookup withdrawal operations.
*/
struct GNUNET_CONTAINER_MultiShortmap *wops;
/**
* (Base) URL to suggest for the exchange. Can
* be NULL if there is no suggestion to be made.
*/
char *exchange_url;
/**
* Lock for accessing @a rpubs map.
*/
pthread_mutex_t rpubs_lock;
/**
* Hashmap of hashes of account names to `struct Account`.
*/
struct GNUNET_CONTAINER_MultiHashMap *accounts;
/**
* Lock for accessing @a accounts hash map.
*/
pthread_mutex_t accounts_lock;
/**
* Hashmap of hashes of transaction request_uids to `struct Transaction`.
*/
struct GNUNET_CONTAINER_MultiHashMap *uuid_map;
/**
* Lock for accessing @a uuid_map.
*/
pthread_mutex_t uuid_map_lock;
/**
* Lock for accessing the internals of
* accounts and transaction array entries.
*/
pthread_mutex_t big_lock;
/**
* How much money should be put into new accounts
* on /register.
*/
struct TALER_Amount signup_bonus;
/**
* Current transaction counter.
*/
uint64_t serial_counter;
/**
* Number of transactions we keep in memory (at most).
*/
uint64_t ram_limit;
/**
* Currency used by the fakebank.
*/
char *currency;
/**
* Hostname of the fakebank.
*/
char *hostname;
/**
* BaseURL of the fakebank.
*/
char *my_baseurl;
/**
* Our port number.
*/
uint16_t port;
#ifdef __linux__
/**
* Event FD to signal @a lp_thread a change in
* @a lp_heap.
*/
int lp_event;
#else
/**
* Pipe input to signal @a lp_thread a change in
* @a lp_heap.
*/
int lp_event_in;
/**
* Pipe output to signal @a lp_thread a change in
* @a lp_heap.
*/
int lp_event_out;
#endif
/**
* Set to true once we are shutting down.
*/
bool in_shutdown;
/**
* Should we run MHD immediately again?
*/
bool mhd_again;
#if EPOLL_SUPPORT
/**
* Boxed @e mhd_fd.
*/
struct GNUNET_NETWORK_Handle *mhd_rfd;
/**
* File descriptor to use to wait for MHD.
*/
int mhd_fd;
#endif
};
/**
* Task run whenever HTTP server operations are pending.
*
* @param cls the `struct TALER_FAKEBANK_Handle`
*/
void
TALER_FAKEBANK_run_mhd_ (void *cls);
#endif