summaryrefslogtreecommitdiff
path: root/src/bank-lib/fakebank.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bank-lib/fakebank.c')
-rw-r--r--src/bank-lib/fakebank.c1588
1 files changed, 292 insertions, 1296 deletions
diff --git a/src/bank-lib/fakebank.c b/src/bank-lib/fakebank.c
index 9c4aeb6e9..3a004dc80 100644
--- a/src/bank-lib/fakebank.c
+++ b/src/bank-lib/fakebank.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2016-2020 Taler Systems SA
+ (C) 2016-2024 Taler Systems SA
TALER is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@@ -22,527 +22,19 @@
* @author Christian Grothoff <christian@grothoff.org>
*/
#include "platform.h"
+#include <pthread.h>
+#include <poll.h>
+#ifdef __linux__
+#include <sys/eventfd.h>
+#endif
#include "taler_fakebank_lib.h"
#include "taler_bank_service.h"
#include "taler_mhd_lib.h"
-
-/**
- * Maximum POST request size (for /admin/add-incoming)
- */
-#define REQUEST_BUFFER_MAX (4 * 1024)
-
-
-/**
- * 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 (string, not payto!)
- */
- char *debit_account;
-
- /**
- * Account to credit (string, not payto!)
- */
- char *credit_account;
-
- /**
- * Random unique identifier for the request.
- */
- struct GNUNET_HashCode request_uid;
-
- /**
- * What does the @e subject contain?
- */
- enum
- {
- /**
- * Transfer TO the exchange.
- */
- T_CREDIT,
-
- /**
- * Transfer FROM the exchange.
- */
- T_DEBIT
- } 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;
-
- } debit;
-
- /**
- * Used if @e type is T_CREDIT.
- */
- struct
- {
-
- /**
- * Reserve public key of the credit operation.
- */
- struct TALER_ReservePublicKeyP reserve_pub;
-
- } credit;
-
- } subject;
-
- /**
- * When did the transaction happen?
- */
- struct GNUNET_TIME_Absolute date;
-
- /**
- * Number of this transaction.
- */
- uint64_t row_id;
-
- /**
- * Has this transaction been subjected to #TALER_FAKEBANK_check_credit()
- * or #TALER_FAKEBANK_check_debit()
- * and should thus no longer be counted in
- * #TALER_FAKEBANK_check_empty()?
- */
- int checked;
-};
-
-
-/**
- * Handle for the fake bank.
- */
-struct TALER_FAKEBANK_Handle
-{
- /**
- * We store transactions in a DLL.
- */
- struct Transaction *transactions_head;
-
- /**
- * We store transactions in a DLL.
- */
- struct Transaction *transactions_tail;
-
- /**
- * HTTP server we run to pretend to be the "test" bank.
- */
- struct MHD_Daemon *mhd_bank;
-
- /**
- * Task running HTTP server for the "test" bank.
- */
- struct GNUNET_SCHEDULER_Task *mhd_task;
-
- /**
- * Number of transactions.
- */
- uint64_t serial_counter;
-
- /**
- * Currency used by the fakebank.
- */
- char *currency;
-
- /**
- * BaseURL of the fakebank.
- */
- char *my_baseurl;
-
- /**
- * Our port number.
- */
- uint16_t port;
-
-#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
-};
-
-
-/**
- * Generate log messages for failed check operation.
- *
- * @param h handle to output transaction log for
- */
-static void
-check_log (struct TALER_FAKEBANK_Handle *h)
-{
- for (struct Transaction *t = h->transactions_head; NULL != t; t = t->next)
- {
- if (GNUNET_YES == t->checked)
- continue;
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "%s -> %s (%s) %s (%s)\n",
- t->debit_account,
- t->credit_account,
- TALER_amount2s (&t->amount),
- (T_DEBIT == t->type)
- ? t->subject.debit.exchange_base_url
- : TALER_B2S (&t->subject.credit.reserve_pub),
- (T_DEBIT == t->type) ? "DEBIT" : "CREDIT");
- }
-}
-
-
-/**
- * Check that the @a want_amount was transferred from the @a
- * want_debit to the @a want_credit account. If so, set the @a subject
- * to the transfer identifier and remove the transaction from the
- * list. If the transaction was not recorded, return #GNUNET_SYSERR.
- *
- * @param h bank instance
- * @param want_amount transfer amount desired
- * @param want_debit account that should have been debited
- * @param want_credit account that should have been credited
- * @param exchange_base_url expected base URL of the exchange,
- * i.e. "https://example.com/"; may include a port
- * @param[out] wtid set to the wire transfer identifier
- * @return #GNUNET_OK on success
- */
-int
-TALER_FAKEBANK_check_debit (struct TALER_FAKEBANK_Handle *h,
- const struct TALER_Amount *want_amount,
- const char *want_debit,
- const char *want_credit,
- const char *exchange_base_url,
- struct TALER_WireTransferIdentifierRawP *wtid)
-{
- GNUNET_assert (0 == strcasecmp (want_amount->currency,
- h->currency));
- for (struct Transaction *t = h->transactions_head; NULL != t; t = t->next)
- {
- if ( (0 == strcasecmp (want_debit,
- t->debit_account)) &&
- (0 == strcasecmp (want_credit,
- t->credit_account)) &&
- (0 == TALER_amount_cmp (want_amount,
- &t->amount)) &&
- (GNUNET_NO == t->checked) &&
- (T_DEBIT == t->type) &&
- (0 == strcasecmp (exchange_base_url,
- t->subject.debit.exchange_base_url)) )
- {
- *wtid = t->subject.debit.wtid;
- t->checked = GNUNET_YES;
- return GNUNET_OK;
- }
- }
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Did not find matching transaction! I have:\n");
- check_log (h);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "I wanted: %s->%s (%s) from exchange %s (DEBIT)\n",
- want_debit,
- want_credit,
- TALER_amount2s (want_amount),
- exchange_base_url);
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Check that the @a want_amount was transferred from the @a want_debit to the
- * @a want_credit account with the @a subject. If so, remove the transaction
- * from the list. If the transaction was not recorded, return #GNUNET_SYSERR.
- *
- * @param h bank instance
- * @param want_amount transfer amount desired
- * @param want_debit account that should have been debited
- * @param want_credit account that should have been credited
- * @param reserve_pub reserve public key expected in wire subject
- * @return #GNUNET_OK on success
- */
-int
-TALER_FAKEBANK_check_credit (struct TALER_FAKEBANK_Handle *h,
- const struct TALER_Amount *want_amount,
- const char *want_debit,
- const char *want_credit,
- const struct TALER_ReservePublicKeyP *reserve_pub)
-{
- GNUNET_assert (0 == strcasecmp (want_amount->currency,
- h->currency));
- for (struct Transaction *t = h->transactions_head; NULL != t; t = t->next)
- {
- if ( (0 == strcasecmp (want_debit,
- t->debit_account)) &&
- (0 == strcasecmp (want_credit,
- t->credit_account)) &&
- (0 == TALER_amount_cmp (want_amount,
- &t->amount)) &&
- (GNUNET_NO == t->checked) &&
- (T_CREDIT == t->type) &&
- (0 == GNUNET_memcmp (reserve_pub,
- &t->subject.credit.reserve_pub)) )
- {
- t->checked = GNUNET_YES;
- return GNUNET_OK;
- }
- }
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Did not find matching transaction!\nI have:\n");
- check_log (h);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "I wanted:\n%s -> %s (%s) with subject %s (CREDIT)\n",
- want_debit,
- want_credit,
- TALER_amount2s (want_amount),
- TALER_B2S (reserve_pub));
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Tell the fakebank to create another wire transfer *from* an exchange.
- *
- * @param h fake bank handle
- * @param debit_account account to debit
- * @param credit_account account to credit
- * @param amount amount to transfer
- * @param subject wire transfer subject to use
- * @param exchange_base_url exchange URL
- * @param request_uid unique number to make the request unique, or NULL to create one
- * @param[out] ret_row_id pointer to store the row ID of this transaction
- * @return #GNUNET_YES if the transfer was successful,
- * #GNUNET_SYSERR if the request_uid was reused for a different transfer
- */
-int
-TALER_FAKEBANK_make_transfer (
- struct TALER_FAKEBANK_Handle *h,
- const char *debit_account,
- const char *credit_account,
- const struct TALER_Amount *amount,
- const struct TALER_WireTransferIdentifierRawP *subject,
- const char *exchange_base_url,
- const struct GNUNET_HashCode *request_uid,
- uint64_t *ret_row_id)
-{
- struct Transaction *t;
-
- GNUNET_assert (0 == strcasecmp (amount->currency,
- h->currency));
- GNUNET_break (0 != strncasecmp ("payto://",
- debit_account,
- strlen ("payto://")));
- GNUNET_break (0 != strncasecmp ("payto://",
- credit_account,
- strlen ("payto://")));
- if (NULL != request_uid)
- {
- for (struct Transaction *t = h->transactions_head; NULL != t; t = t->next)
- {
- if (0 != GNUNET_memcmp (request_uid, &t->request_uid))
- continue;
- if ( (0 != strcasecmp (debit_account,
- t->debit_account)) ||
- (0 != strcasecmp (credit_account,
- t->credit_account)) ||
- (0 != TALER_amount_cmp (amount,
- &t->amount)) ||
- (T_DEBIT != t->type) ||
- (0 != GNUNET_memcmp (subject,
- &t->subject.debit.wtid)) )
- {
- /* Transaction exists, but with different details. */
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- *ret_row_id = t->row_id;
- return GNUNET_OK;
- }
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Making transfer from %s to %s over %s and subject %s; for exchange: %s\n",
- debit_account,
- credit_account,
- TALER_amount2s (amount),
- TALER_B2S (subject),
- exchange_base_url);
- t = GNUNET_new (struct Transaction);
- t->debit_account = GNUNET_strdup (debit_account);
- t->credit_account = GNUNET_strdup (credit_account);
- t->amount = *amount;
- t->row_id = ++h->serial_counter;
- t->date = GNUNET_TIME_absolute_get ();
- t->type = T_DEBIT;
- t->subject.debit.exchange_base_url = GNUNET_strdup (exchange_base_url);
- t->subject.debit.wtid = *subject;
- if (NULL == request_uid)
- GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
- &t->request_uid);
- else
- t->request_uid = *request_uid;
- GNUNET_TIME_round_abs (&t->date);
- GNUNET_CONTAINER_DLL_insert_tail (h->transactions_head,
- h->transactions_tail,
- t);
- *ret_row_id = t->row_id;
- return GNUNET_OK;
-}
-
-
-/**
- * Tell the fakebank to create another wire transfer *to* an exchange.
- *
- * @param h fake bank handle
- * @param debit_account account to debit
- * @param credit_account account to credit
- * @param amount amount to transfer
- * @param reserve_pub reserve public key to use in subject
- * @return serial_id of the transfer
- */
-uint64_t
-TALER_FAKEBANK_make_admin_transfer (
- struct TALER_FAKEBANK_Handle *h,
- const char *debit_account,
- const char *credit_account,
- const struct TALER_Amount *amount,
- const struct TALER_ReservePublicKeyP *reserve_pub)
-{
- struct Transaction *t;
-
- GNUNET_assert (0 == strcasecmp (amount->currency,
- h->currency));
- GNUNET_assert (NULL != debit_account);
- GNUNET_assert (NULL != credit_account);
- GNUNET_break (0 != strncasecmp ("payto://",
- debit_account,
- strlen ("payto://")));
- GNUNET_break (0 != strncasecmp ("payto://",
- credit_account,
- strlen ("payto://")));
- t = GNUNET_new (struct Transaction);
- t->debit_account = GNUNET_strdup (debit_account);
- t->credit_account = GNUNET_strdup (credit_account);
- t->amount = *amount;
- t->row_id = ++h->serial_counter;
- t->date = GNUNET_TIME_absolute_get ();
- t->type = T_CREDIT;
- t->subject.credit.reserve_pub = *reserve_pub;
- GNUNET_TIME_round_abs (&t->date);
- GNUNET_CONTAINER_DLL_insert_tail (h->transactions_head,
- h->transactions_tail,
- t);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Making transfer from %s to %s over %s and subject %s at row %llu\n",
- debit_account,
- credit_account,
- TALER_amount2s (amount),
- TALER_B2S (reserve_pub),
- (unsigned long long) t->row_id);
- return t->row_id;
-}
-
-
-/**
- * Check that no wire transfers were ordered (or at least none
- * that have not been taken care of via #TALER_FAKEBANK_check_credit()
- * or #TALER_FAKEBANK_check_debit()).
- * If any transactions are onrecord, return #GNUNET_SYSERR.
- *
- * @param h bank instance
- * @return #GNUNET_OK on success
- */
-int
-TALER_FAKEBANK_check_empty (struct TALER_FAKEBANK_Handle *h)
-{
- struct Transaction *t;
-
- t = h->transactions_head;
- while (NULL != t)
- {
- if (GNUNET_YES != t->checked)
- break;
- t = t->next;
- }
- if (NULL == t)
- return GNUNET_OK;
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Expected empty transaction set, but I have:\n");
- check_log (h);
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Stop running the fake bank.
- *
- * @param h bank to stop
- */
-void
-TALER_FAKEBANK_stop (struct TALER_FAKEBANK_Handle *h)
-{
- struct Transaction *t;
-
- while (NULL != (t = h->transactions_head))
- {
- GNUNET_CONTAINER_DLL_remove (h->transactions_head,
- h->transactions_tail,
- t);
- GNUNET_free (t->debit_account);
- GNUNET_free (t->credit_account);
- if (T_DEBIT == t->type)
- GNUNET_free (t->subject.debit.exchange_base_url);
- GNUNET_free (t);
- }
- if (NULL != h->mhd_task)
- {
- GNUNET_SCHEDULER_cancel (h->mhd_task);
- h->mhd_task = NULL;
- }
-#if EPOLL_SUPPORT
- GNUNET_NETWORK_socket_free_memory_only_ (h->mhd_rfd);
-#endif
- if (NULL != h->mhd_bank)
- {
- MHD_stop_daemon (h->mhd_bank);
- h->mhd_bank = NULL;
- }
- GNUNET_free (h->my_baseurl);
- GNUNET_free (h->currency);
- GNUNET_free (h);
-}
+#include <gnunet/gnunet_mhd_compat.h>
+#include "fakebank.h"
+#include "fakebank_bank.h"
+#include "fakebank_common_lp.h"
+#include "fakebank_tbi.h"
/**
@@ -551,9 +43,9 @@ TALER_FAKEBANK_stop (struct TALER_FAKEBANK_Handle *h)
* @a con_cls that might still need to be cleaned up. Call the
* respective function to free the memory.
*
- * @param cls client-defined closure
+ * @param cls a `struct TALER_FAKEBANK_Handle *`
* @param connection connection handle
- * @param con_cls value as set by the last call to
+ * @param con_cls a `struct ConnectionContext *`
* the #MHD_AccessHandlerCallback
* @param toe reason for request termination
* @see #MHD_OPTION_NOTIFY_COMPLETED
@@ -565,704 +57,16 @@ handle_mhd_completion_callback (void *cls,
void **con_cls,
enum MHD_RequestTerminationCode toe)
{
- /* struct TALER_FAKEBANK_Handle *h = cls; */
- (void) cls;
- (void) connection;
- (void) toe;
- GNUNET_JSON_post_parser_cleanup (*con_cls);
- *con_cls = NULL;
-}
-
-
-/**
- * Handle incoming HTTP request for /admin/add/incoming.
- *
- * @param h the fakebank handle
- * @param connection the connection
- * @param account account into which to deposit the funds (credit)
- * @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_admin_add_incoming (struct TALER_FAKEBANK_Handle *h,
- struct MHD_Connection *connection,
- const char *account,
- const char *upload_data,
- size_t *upload_data_size,
- void **con_cls)
-{
- enum GNUNET_JSON_PostResult pr;
- json_t *json;
- uint64_t row_id;
-
- pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
- connection,
- 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;
- }
- {
- const char *debit_account;
- struct TALER_Amount amount;
- struct TALER_ReservePublicKeyP reserve_pub;
- char *debit;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("reserve_pub", &reserve_pub),
- GNUNET_JSON_spec_string ("debit_account", &debit_account),
- TALER_JSON_spec_amount ("amount", &amount),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json,
- spec,
- NULL, NULL))
- {
- GNUNET_break (0);
- json_decref (json);
- /* We're fakebank, no need for nice error handling */
- return MHD_NO;
- }
- debit = TALER_xtalerbank_account_from_payto (debit_account);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Receiving incoming wire transfer: %s->%s, subject: %s, amount: %s\n",
- debit,
- account,
- TALER_B2S (&reserve_pub),
- TALER_amount2s (&amount));
- row_id = TALER_FAKEBANK_make_admin_transfer (h,
- debit,
- account,
- &amount,
- &reserve_pub);
- GNUNET_free (debit);
- }
- json_decref (json);
-
- /* Finally build response object */
- return TALER_MHD_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:I, s:o}",
- "row_id",
- (json_int_t) row_id,
- "timestamp",
- GNUNET_JSON_from_time_abs (
- h->transactions_tail->date));
-}
-
-
-/**
- * Handle incoming HTTP request for /transfer.
- *
- * @param h the fakebank handle
- * @param connection the connection
- * @param account account making the transfer
- * @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_transfer (struct TALER_FAKEBANK_Handle *h,
- struct MHD_Connection *connection,
- const char *account,
- const char *upload_data,
- size_t *upload_data_size,
- void **con_cls)
-{
- enum GNUNET_JSON_PostResult pr;
- json_t *json;
- uint64_t row_id;
-
- pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
- connection,
- 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;
- }
- {
- struct GNUNET_HashCode uuid;
- struct TALER_WireTransferIdentifierRawP wtid;
- const char *credit_account;
- char *credit;
- const char *base_url;
- struct TALER_Amount amount;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("request_uid",
- &uuid),
- TALER_JSON_spec_amount ("amount",
- &amount),
- GNUNET_JSON_spec_string ("exchange_base_url",
- &base_url),
- GNUNET_JSON_spec_fixed_auto ("wtid",
- &wtid),
- GNUNET_JSON_spec_string ("credit_account",
- &credit_account),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json,
- spec,
- NULL, NULL))
- {
- GNUNET_break (0);
- json_decref (json);
- /* We are fakebank, no need for nice error handling */
- return MHD_NO;
- }
- {
- int ret;
-
- credit = TALER_xtalerbank_account_from_payto (credit_account);
- ret = TALER_FAKEBANK_make_transfer (h,
- account,
- credit,
- &amount,
- &wtid,
- base_url,
- &uuid,
- &row_id);
- if (GNUNET_OK != ret)
- {
- GNUNET_break (0);
- json_decref (json);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_BANK_TRANSFER_REQUEST_UID_REUSED,
- "transfer request UID was reused");
-
-
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Receiving incoming wire transfer: %s->%s, subject: %s, amount: %s, from %s\n",
- account,
- credit,
- TALER_B2S (&wtid),
- TALER_amount2s (&amount),
- base_url);
- GNUNET_free (credit);
- }
- }
- json_decref (json);
-
- /* Finally build response object */
- return TALER_MHD_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:I, s:o}",
- "row_id",
- (json_int_t) row_id,
- /* dummy timestamp */
- "timestamp", GNUNET_JSON_from_time_abs (
- GNUNET_TIME_UNIT_ZERO_ABS));
-}
-
-
-/**
- * Handle incoming HTTP request for / (home page).
- *
- * @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_home_page (struct TALER_FAKEBANK_Handle *h,
- struct MHD_Connection *connection,
- void **con_cls)
-{
- int ret;
- struct MHD_Response *resp;
-#define HELLOMSG "Hello, Fakebank!"
+ struct TALER_FAKEBANK_Handle *h = cls;
+ struct ConnectionContext *cc = *con_cls;
(void) h;
- (void) con_cls;
- resp = MHD_create_response_from_buffer
- (strlen (HELLOMSG),
- HELLOMSG,
- MHD_RESPMEM_MUST_COPY);
-
- ret = MHD_queue_response (connection,
- MHD_HTTP_OK,
- resp);
-
- MHD_destroy_response (resp);
- return ret;
-}
-
-
-/**
- * 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.
- */
- 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;
-
- /**
- * #GNUNET_YES if starting point was given.
- */
- int have_start;
-
-};
-
-
-/**
- * Parse URL history arguments, of _both_ APIs:
- * /history/incoming and /history/outgoing.
- *
- * @param connection MHD connection.
- * @param[out] ha will contain the parsed values.
- * @return #GNUNET_OK only if the parsing succeeds.
- */
-static int
-parse_history_common_args (struct MHD_Connection *connection,
- struct HistoryArgs *ha)
-{
- const char *start;
- const char *delta;
- const char *long_poll_ms;
- unsigned long long lp_timeout;
- unsigned long long sval;
- long long d;
-
- start = MHD_lookup_connection_value (connection,
- MHD_GET_ARGUMENT_KIND,
- "start");
- ha->have_start = (NULL != start);
- delta = MHD_lookup_connection_value (connection,
- MHD_GET_ARGUMENT_KIND,
- "delta");
- long_poll_ms = MHD_lookup_connection_value (connection,
- MHD_GET_ARGUMENT_KIND,
- "long_poll_ms");
- lp_timeout = 0;
- if ( (NULL == delta) ||
- (1 != sscanf (delta,
- "%lld",
- &d)) ||
- ( (NULL != long_poll_ms) &&
- (1 != sscanf (long_poll_ms,
- "%llu",
- &lp_timeout)) ) ||
- ( (NULL != start) &&
- (1 != sscanf (start,
- "%llu",
- &sval)) ) )
- {
- /* Fail if one of the above failed. */
- /* 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 (NULL == start)
- ha->start_idx = (d > 0) ? 0 : UINT64_MAX;
- else
- ha->start_idx = (uint64_t) sval;
- ha->delta = (int64_t) d;
- if (0 == ha->delta)
- {
- GNUNET_break (0);
- return GNUNET_NO;
- }
- ha->lp_timeout
- = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
- lp_timeout);
- return GNUNET_OK;
-}
-
-
-/**
- * Handle incoming HTTP request for /history/outgoing
- *
- * @param h the fakebank handle
- * @param connection the connection
- * @param account which account the request is about
- * @return MHD result code
- */
-static int
-handle_debit_history (struct TALER_FAKEBANK_Handle *h,
- struct MHD_Connection *connection,
- const char *account)
-{
- struct HistoryArgs ha;
- const struct Transaction *pos;
- json_t *history;
-
- if (GNUNET_OK !=
- parse_history_common_args (connection,
- &ha))
- {
- GNUNET_break (0);
- return MHD_NO;
- }
-
- if (! ha.have_start)
- {
- pos = (0 > ha.delta)
- ? 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 == ha.start_idx)
- break;
- if (NULL == pos)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Invalid start specified, transaction %llu not known!\n",
- (unsigned long long) ha.start_idx);
- return MHD_NO;
- }
- /* range is exclusive, skip the matching entry */
- if (0 > ha.delta)
- pos = pos->prev;
- else
- pos = pos->next;
- }
- else
- {
- /* list is empty */
- pos = NULL;
- }
- history = json_array ();
- while ( (0 != ha.delta) &&
- (NULL != pos) )
- {
- if ( (0 == strcasecmp (pos->debit_account,
- account)) &&
- (T_DEBIT == pos->type) )
- {
- json_t *trans;
- char *credit_payto;
- char *debit_payto;
-
- GNUNET_asprintf (&credit_payto,
- "payto://x-taler-bank/localhost/%s",
- pos->credit_account);
-
- GNUNET_asprintf (&debit_payto,
- "payto://x-taler-bank/localhost/%s",
- pos->debit_account);
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "made credit_payto (%s) from credit_account (%s) within fakebank\n",
- credit_payto,
- pos->credit_account);
-
- trans = json_pack
- ("{s:I, s:o, s:o, s:s, s:s, s:s, s:o}",
- "row_id", (json_int_t) pos->row_id,
- "date", GNUNET_JSON_from_time_abs (pos->date),
- "amount", TALER_JSON_from_amount (&pos->amount),
- "credit_account", credit_payto,
- "debit_account", debit_payto,
- "exchange_base_url",
- pos->subject.debit.exchange_base_url,
- "wtid", GNUNET_JSON_from_data_auto (
- &pos->subject.debit.wtid));
- GNUNET_free (credit_payto);
- GNUNET_free (debit_payto);
- GNUNET_assert (0 ==
- json_array_append_new (history,
- trans));
- if (ha.delta > 0)
- ha.delta--;
- else
- ha.delta++;
- }
- if (0 > ha.delta)
- pos = pos->prev;
- if (0 < ha.delta)
- pos = pos->next;
- }
- return TALER_MHD_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:o}",
- "outgoing_transactions",
- history);
-}
-
-
-/**
- * Handle incoming HTTP request for /history/incoming
- *
- * @param h the fakebank handle
- * @param connection the connection
- * @param account which account the request is about
- * @return MHD result code
- */
-static int
-handle_credit_history (struct TALER_FAKEBANK_Handle *h,
- struct MHD_Connection *connection,
- const char *account)
-{
- struct HistoryArgs ha;
- const struct Transaction *pos;
- json_t *history;
-
- if (GNUNET_OK !=
- parse_history_common_args (connection,
- &ha))
- {
- GNUNET_break (0);
- return MHD_NO;
- }
- if (! ha.have_start)
- {
- pos = (0 > ha.delta)
- ? 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 == ha.start_idx)
- break;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Skipping transaction %s->%s (%s) at %llu (looking for start index %llu)\n",
- pos->debit_account,
- pos->credit_account,
- TALER_B2S (&pos->subject.credit.reserve_pub),
- (unsigned long long) pos->row_id,
- (unsigned long long) ha.start_idx);
- }
- if (NULL == pos)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Invalid start specified, transaction %llu not known!\n",
- (unsigned long long) ha.start_idx);
- return MHD_NO;
- }
- /* range is exclusive, skip the matching entry */
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Skipping transaction %s->%s (%s) (start index %llu is exclusive)\n",
- pos->debit_account,
- pos->credit_account,
- TALER_B2S (&pos->subject.credit.reserve_pub),
- (unsigned long long) ha.start_idx);
- if (0 > ha.delta)
- pos = pos->prev;
- else
- pos = pos->next;
- }
- else
- {
- /* list is empty */
- pos = NULL;
- }
- history = json_array ();
- while ( (0 != ha.delta) &&
- (NULL != pos) )
- {
- if ( (0 == strcasecmp (pos->credit_account,
- account)) &&
- (T_CREDIT == pos->type) )
- {
- json_t *trans;
- char *credit_payto;
- char *debit_payto;
-
- GNUNET_asprintf (&credit_payto,
- "payto://x-taler-bank/localhost/%s",
- pos->credit_account);
-
- GNUNET_asprintf (&debit_payto,
- "payto://x-taler-bank/localhost/%s",
- pos->debit_account);
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "made credit_payto (%s) from credit_account (%s) within fakebank\n",
- credit_payto,
- pos->credit_account);
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Returning transaction %s->%s (%s) at %llu\n",
- pos->debit_account,
- pos->credit_account,
- TALER_B2S (&pos->subject.credit.reserve_pub),
- (unsigned long long) pos->row_id);
- trans = json_pack
- ("{s:I, s:o, s:o, s:s, s:s, s:o}",
- "row_id", (json_int_t) pos->row_id,
- "date", GNUNET_JSON_from_time_abs (pos->date),
- "amount", TALER_JSON_from_amount (&pos->amount),
- "credit_account", credit_payto,
- "debit_account", debit_payto,
- "reserve_pub", GNUNET_JSON_from_data_auto (
- &pos->subject.credit.reserve_pub));
- GNUNET_free (credit_payto);
- GNUNET_free (debit_payto);
- GNUNET_assert (0 ==
- json_array_append_new (history,
- trans));
- if (ha.delta > 0)
- ha.delta--;
- else
- ha.delta++;
- }
- else if (T_CREDIT == pos->type)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Skipping transaction %s->%s (%s) at row %llu\n",
- pos->debit_account,
- pos->credit_account,
- TALER_B2S (&pos->subject.credit.reserve_pub),
- (unsigned long long) pos->row_id);
- }
- if (0 > ha.delta)
- pos = pos->prev;
- if (0 < ha.delta)
- pos = pos->next;
- }
- return TALER_MHD_reply_json_pack (connection,
- MHD_HTTP_OK,
- "{s:o}",
- "incoming_transactions",
- history);
-}
-
-
-/**
- * Handle incoming HTTP request.
- *
- * @param h our handle
- * @param connection the connection
- * @param url the requested url
- * @param method the method (POST, GET, ...)
- * @param account which account should process the request
- * @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
-serve (struct TALER_FAKEBANK_Handle *h,
- struct MHD_Connection *connection,
- const char *account,
- const char *url,
- const char *method,
- const char *upload_data,
- size_t *upload_data_size,
- void **con_cls)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Fakebank, serving URL `%s' for account `%s'\n",
- url,
- account);
- if ( (0 == strcmp (url,
- "/")) &&
- (0 == strcasecmp (method,
- MHD_HTTP_METHOD_GET)) )
- return handle_home_page (h,
- connection,
- con_cls);
- if ( (0 == strcmp (url,
- "/admin/add-incoming")) &&
- (0 == strcasecmp (method,
- MHD_HTTP_METHOD_POST)) )
- return handle_admin_add_incoming (h,
- connection,
- account,
- upload_data,
- upload_data_size,
- con_cls);
- if ( (0 == strcmp (url,
- "/transfer")) &&
- (NULL != account) &&
- (0 == strcasecmp (method,
- MHD_HTTP_METHOD_POST)) )
- return handle_transfer (h,
- connection,
- account,
- upload_data,
- upload_data_size,
- con_cls);
- if ( (0 == strcmp (url,
- "/history/incoming")) &&
- (NULL != account) &&
- (0 == strcasecmp (method,
- MHD_HTTP_METHOD_GET)) )
- return handle_credit_history (h,
- connection,
- account);
- if ( (0 == strcmp (url,
- "/history/outgoing")) &&
- (NULL != account) &&
- (0 == strcasecmp (method,
- MHD_HTTP_METHOD_GET)) )
- return handle_debit_history (h,
- connection,
- account);
-
- /* Unexpected URL path, just close the connection. */
- /* we're rather impolite here, but it's a testcase. */
- TALER_LOG_ERROR ("Breaking URL: %s\n",
- url);
- GNUNET_break_op (0);
- return MHD_NO;
+ (void) connection;
+ (void) toe;
+ if (NULL == cc)
+ return;
+ cc->ctx_cleaner (cc->ctx);
+ GNUNET_free (cc);
}
@@ -1276,10 +80,10 @@ serve (struct TALER_FAKEBANK_Handle *h,
* @param version HTTP version (ignored)
* @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 *`)
+ * @param con_cls closure for request
* @return MHD result code
*/
-static int
+static MHD_RESULT
handle_mhd_request (void *cls,
struct MHD_Connection *connection,
const char *url,
@@ -1290,43 +94,31 @@ handle_mhd_request (void *cls,
void **con_cls)
{
struct TALER_FAKEBANK_Handle *h = cls;
- char *account = NULL;
- char *end;
- int ret;
(void) version;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Handling request for `%s'\n",
- url);
- if ( (strlen (url) > 1) &&
- (NULL != (end = strchr (url + 1, '/'))) )
+ if (0 == strncmp (url,
+ "/taler-integration/",
+ strlen ("/taler-integration/")))
{
- account = GNUNET_strndup (url + 1,
- end - url - 1);
- url = end;
+ url += strlen ("/taler-integration");
+ return TALER_FAKEBANK_tbi_main_ (h,
+ connection,
+ url,
+ method,
+ upload_data,
+ upload_data_size,
+ con_cls);
}
- ret = serve (h,
- connection,
- account,
- url,
- method,
- upload_data,
- upload_data_size,
- con_cls);
- GNUNET_free_non_null (account);
- return ret;
+ return TALER_FAKEBANK_bank_main_ (h,
+ connection,
+ url,
+ method,
+ upload_data,
+ upload_data_size,
+ con_cls);
}
-/**
- * Task run whenever HTTP server operations are pending.
- *
- * @param cls the `struct TALER_FAKEBANK_Handle`
- */
-static void
-run_mhd (void *cls);
-
-
#if EPOLL_SUPPORT
/**
* Schedule MHD. This function should be called initially when an
@@ -1342,6 +134,7 @@ schedule_httpd (struct TALER_FAKEBANK_Handle *h)
MHD_UNSIGNED_LONG_LONG timeout;
struct GNUNET_TIME_Relative tv;
+ GNUNET_assert (-1 != h->mhd_fd);
haveto = MHD_get_timeout (h->mhd_bank,
&timeout);
if (MHD_YES == haveto)
@@ -1353,7 +146,7 @@ schedule_httpd (struct TALER_FAKEBANK_Handle *h)
h->mhd_task =
GNUNET_SCHEDULER_add_read_net (tv,
h->mhd_rfd,
- &run_mhd,
+ &TALER_FAKEBANK_run_mhd_,
h);
}
@@ -1379,16 +172,27 @@ schedule_httpd (struct TALER_FAKEBANK_Handle *h)
MHD_UNSIGNED_LONG_LONG timeout;
struct GNUNET_TIME_Relative tv;
+#ifdef __linux__
+ GNUNET_assert (-1 == h->lp_event);
+#else
+ GNUNET_assert (-1 == h->lp_event_in);
+ GNUNET_assert (-1 == h->lp_event_out);
+#endif
FD_ZERO (&rs);
FD_ZERO (&ws);
FD_ZERO (&es);
max = -1;
- if (MHD_YES != MHD_get_fdset (h->mhd_bank, &rs, &ws, &es, &max))
+ if (MHD_YES != MHD_get_fdset (h->mhd_bank,
+ &rs,
+ &ws,
+ &es,
+ &max))
{
GNUNET_assert (0);
return;
}
- haveto = MHD_get_timeout (h->mhd_bank, &timeout);
+ haveto = MHD_get_timeout (h->mhd_bank,
+ &timeout);
if (MHD_YES == haveto)
tv.rel_value_us = (uint64_t) timeout * 1000LL;
else
@@ -1397,8 +201,12 @@ schedule_httpd (struct TALER_FAKEBANK_Handle *h)
{
wrs = GNUNET_NETWORK_fdset_create ();
wws = GNUNET_NETWORK_fdset_create ();
- GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
- GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
+ GNUNET_NETWORK_fdset_copy_native (wrs,
+ &rs,
+ max + 1);
+ GNUNET_NETWORK_fdset_copy_native (wws,
+ &ws,
+ max + 1);
}
else
{
@@ -1412,7 +220,8 @@ schedule_httpd (struct TALER_FAKEBANK_Handle *h)
tv,
wrs,
wws,
- &run_mhd, h);
+ &TALER_FAKEBANK_run_mhd_,
+ h);
if (NULL != wrs)
GNUNET_NETWORK_fdset_destroy (wrs);
if (NULL != wws)
@@ -1428,71 +237,258 @@ schedule_httpd (struct TALER_FAKEBANK_Handle *h)
*
* @param cls the `struct TALER_FAKEBANK_Handle`
*/
-static void
-run_mhd (void *cls)
+void
+TALER_FAKEBANK_run_mhd_ (void *cls)
{
struct TALER_FAKEBANK_Handle *h = cls;
h->mhd_task = NULL;
- MHD_run (h->mhd_bank);
+ h->mhd_again = true;
+ while (h->mhd_again)
+ {
+ h->mhd_again = false;
+ MHD_run (h->mhd_bank);
+ }
+#ifdef __linux__
+ GNUNET_assert (-1 == h->lp_event);
+#else
+ GNUNET_assert (-1 == h->lp_event_in);
+ GNUNET_assert (-1 == h->lp_event_out);
+#endif
schedule_httpd (h);
}
-/**
- * Start the fake bank. The fake bank will, like the normal bank, listen for
- * requests for /admin/add/incoming and /transfer. However, instead of
- * executing or storing those requests, it will simply allow querying whether
- * such a request has been made via #TALER_FAKEBANK_check_debit() and
- * #TALER_FAKEBANK_check_credit() as well as the history API.
- *
- * This is useful for writing testcases to check whether the exchange
- * would have issued the correct wire transfer orders.
- *
- * @param port port to listen to
- * @param currency currency the bank uses
- * @return NULL on error
- */
struct TALER_FAKEBANK_Handle *
TALER_FAKEBANK_start (uint16_t port,
const char *currency)
{
+ return TALER_FAKEBANK_start2 (port,
+ currency,
+ 65536, /* RAM limit */
+ 1);
+}
+
+
+struct TALER_FAKEBANK_Handle *
+TALER_FAKEBANK_start2 (uint16_t port,
+ const char *currency,
+ uint64_t ram_limit,
+ unsigned int num_threads)
+{
+ struct TALER_Amount zero;
+
+ if (GNUNET_OK !=
+ TALER_amount_set_zero (currency,
+ &zero))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ return TALER_FAKEBANK_start3 ("localhost",
+ port,
+ NULL,
+ currency,
+ ram_limit,
+ num_threads,
+ &zero);
+}
+
+
+struct TALER_FAKEBANK_Handle *
+TALER_FAKEBANK_start3 (const char *hostname,
+ uint16_t port,
+ const char *exchange_url,
+ const char *currency,
+ uint64_t ram_limit,
+ unsigned int num_threads,
+ const struct TALER_Amount *signup_bonus)
+{
struct TALER_FAKEBANK_Handle *h;
+ if (SIZE_MAX / sizeof (struct Transaction *) < ram_limit)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "This CPU architecture does not support keeping %llu transactions in RAM\n",
+ (unsigned long long) ram_limit);
+ return NULL;
+ }
GNUNET_assert (strlen (currency) < TALER_CURRENCY_LEN);
+ if (0 != strcmp (signup_bonus->currency,
+ currency))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
h = GNUNET_new (struct TALER_FAKEBANK_Handle);
+ h->signup_bonus = *signup_bonus;
+ if (NULL != exchange_url)
+ h->exchange_url = GNUNET_strdup (exchange_url);
+#ifdef __linux__
+ h->lp_event = -1;
+#else
+ h->lp_event_in = -1;
+ h->lp_event_out = -1;
+#endif
+#if EPOLL_SUPPORT
+ h->mhd_fd = -1;
+#endif
h->port = port;
+ h->ram_limit = ram_limit;
+ h->serial_counter = 0;
+ GNUNET_assert (0 ==
+ pthread_mutex_init (&h->accounts_lock,
+ NULL));
+ GNUNET_assert (0 ==
+ pthread_mutex_init (&h->rpubs_lock,
+ NULL));
+ GNUNET_assert (0 ==
+ pthread_mutex_init (&h->uuid_map_lock,
+ NULL));
+ GNUNET_assert (0 ==
+ pthread_mutex_init (&h->big_lock,
+ NULL));
+ h->transactions
+ = GNUNET_malloc_large (sizeof (struct Transaction *)
+ * ram_limit);
+ if (NULL == h->transactions)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+ "malloc");
+ TALER_FAKEBANK_stop (h);
+ return NULL;
+ }
+ h->accounts = GNUNET_CONTAINER_multihashmap_create (128,
+ GNUNET_NO);
+ h->uuid_map = GNUNET_CONTAINER_multihashmap_create (ram_limit * 4 / 3,
+ GNUNET_YES);
+ if (NULL == h->uuid_map)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+ "malloc");
+ TALER_FAKEBANK_stop (h);
+ return NULL;
+ }
+ h->rpubs = GNUNET_CONTAINER_multipeermap_create (ram_limit * 4 / 3,
+ GNUNET_NO);
+ if (NULL == h->rpubs)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+ "malloc");
+ TALER_FAKEBANK_stop (h);
+ return NULL;
+ }
+ h->lp_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
h->currency = GNUNET_strdup (currency);
+ h->hostname = GNUNET_strdup (hostname);
GNUNET_asprintf (&h->my_baseurl,
- "http://localhost:%u/",
+ "http://%s:%u/",
+ h->hostname,
(unsigned int) port);
- h->mhd_bank = MHD_start_daemon (MHD_USE_DEBUG
+ if (0 == num_threads)
+ {
+ h->mhd_bank = MHD_start_daemon (
+ MHD_USE_DEBUG
#if EPOLL_SUPPORT
- | MHD_USE_EPOLL_INTERNAL_THREAD
-#else
- | MHD_USE_INTERNAL_POLLING_THREAD
+ | MHD_USE_EPOLL
#endif
- | MHD_USE_DUAL_STACK,
- port,
- NULL, NULL,
- &handle_mhd_request, h,
- MHD_OPTION_NOTIFY_COMPLETED,
- &handle_mhd_completion_callback, h,
- MHD_OPTION_LISTEN_BACKLOG_SIZE,
- (unsigned int) 1024,
- MHD_OPTION_END);
- if (NULL == h->mhd_bank)
- {
- GNUNET_free (h->currency);
- GNUNET_free (h);
- return NULL;
- }
+ | MHD_USE_DUAL_STACK
+ | MHD_ALLOW_SUSPEND_RESUME,
+ port,
+ NULL, NULL,
+ &handle_mhd_request, h,
+ MHD_OPTION_NOTIFY_COMPLETED,
+ &handle_mhd_completion_callback, h,
+ MHD_OPTION_LISTEN_BACKLOG_SIZE,
+ (unsigned int) 1024,
+ MHD_OPTION_CONNECTION_LIMIT,
+ (unsigned int) 65536,
+ MHD_OPTION_END);
+ if (NULL == h->mhd_bank)
+ {
+ TALER_FAKEBANK_stop (h);
+ return NULL;
+ }
#if EPOLL_SUPPORT
- h->mhd_fd = MHD_get_daemon_info (h->mhd_bank,
- MHD_DAEMON_INFO_EPOLL_FD)->epoll_fd;
- h->mhd_rfd = GNUNET_NETWORK_socket_box_native (h->mhd_fd);
+ h->mhd_fd = MHD_get_daemon_info (h->mhd_bank,
+ MHD_DAEMON_INFO_EPOLL_FD)->epoll_fd;
+ h->mhd_rfd = GNUNET_NETWORK_socket_box_native (h->mhd_fd);
#endif
- schedule_httpd (h);
+ schedule_httpd (h);
+ }
+ else
+ {
+#ifdef __linux__
+ h->lp_event = eventfd (0,
+ EFD_CLOEXEC);
+ if (-1 == h->lp_event)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+ "eventfd");
+ TALER_FAKEBANK_stop (h);
+ return NULL;
+ }
+#else
+ {
+ int pipefd[2];
+
+ if (0 != pipe (pipefd))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+ "pipe");
+ TALER_FAKEBANK_stop (h);
+ return NULL;
+ }
+ h->lp_event_out = pipefd[0];
+ h->lp_event_in = pipefd[1];
+ }
+#endif
+ if (0 !=
+ pthread_create (&h->lp_thread,
+ NULL,
+ &TALER_FAKEBANK_lp_expiration_thread_,
+ h))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+ "pthread_create");
+#ifdef __linux__
+ GNUNET_break (0 == close (h->lp_event));
+ h->lp_event = -1;
+#else
+ GNUNET_break (0 == close (h->lp_event_in));
+ GNUNET_break (0 == close (h->lp_event_out));
+ h->lp_event_in = -1;
+ h->lp_event_out = -1;
+#endif
+ TALER_FAKEBANK_stop (h);
+ return NULL;
+ }
+ h->mhd_bank = MHD_start_daemon (
+ MHD_USE_DEBUG
+ | MHD_USE_AUTO_INTERNAL_THREAD
+ | MHD_ALLOW_SUSPEND_RESUME
+ | MHD_USE_TURBO
+ | MHD_USE_TCP_FASTOPEN
+ | MHD_USE_DUAL_STACK,
+ port,
+ NULL, NULL,
+ &handle_mhd_request, h,
+ MHD_OPTION_NOTIFY_COMPLETED,
+ &handle_mhd_completion_callback, h,
+ MHD_OPTION_LISTEN_BACKLOG_SIZE,
+ (unsigned int) 1024,
+ MHD_OPTION_CONNECTION_LIMIT,
+ (unsigned int) 65536,
+ MHD_OPTION_THREAD_POOL_SIZE,
+ num_threads,
+ MHD_OPTION_END);
+ if (NULL == h->mhd_bank)
+ {
+ GNUNET_break (0);
+ TALER_FAKEBANK_stop (h);
+ return NULL;
+ }
+ }
return h;
}