Merge branch 'master' of ssh://git.taler.net/exchange

This commit is contained in:
Özgür Kesim 2023-04-22 15:39:14 +02:00
commit 89a9224c3b
Signed by: oec
GPG Key ID: 3D76A56D79EDD9D7
13 changed files with 1713 additions and 1853 deletions

@ -1 +1 @@
Subproject commit 7adfb722ac988170a31cdfd8132073eb7f2a6c43 Subproject commit bf43b20a0362ac19bcf1bab9c33215e55d8d9f36

View File

@ -46,6 +46,12 @@
<anchorfile>microhttpd.h</anchorfile> <anchorfile>microhttpd.h</anchorfile>
<arglist></arglist> <arglist></arglist>
</member> </member>
<member kind="define">
<type>#define</type>
<name>MHD_HTTP_CONTENT_TOO_LARGE</name>
<anchorfile>microhttpd.h</anchorfile>
<arglist></arglist>
</member>
<member kind="define"> <member kind="define">
<type>#define</type> <type>#define</type>
<name>MHD_HTTP_REQUEST_TIMEOUT</name> <name>MHD_HTTP_REQUEST_TIMEOUT</name>

View File

@ -400,6 +400,148 @@ struct Transaction
}; };
/**
* 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;
/**
* Payto URI of the account.
*/
char *payto_uri;
/**
* JSON object we are building to return.
*/
json_t *history;
};
/**
* Function called to clean up a history context.
*
* @param cls a `struct HistoryContext *`
*/
static void
history_cleanup (void *cls)
{
struct HistoryContext *hc = cls;
GNUNET_free (hc->payto_uri);
json_decref (hc->history);
GNUNET_free (hc);
}
/**
* 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;
};
/**
* Function called to clean up a withdraw context.
*
* @param cls a `struct WithdrawContext *`
*/
static void
withdraw_cleanup (void *cls)
{
struct WithdrawContext *wc = cls;
GNUNET_free (wc);
}
/** /**
* Handle for the fake bank. * Handle for the fake bank.
*/ */
@ -569,13 +711,6 @@ struct TALER_FAKEBANK_Handle
}; };
/**
* Special address "con_cls" can point to to indicate that the handler has
* been called more than once already (was previously suspended).
*/
static int special_ptr;
/** /**
* Task run whenever HTTP server operations are pending. * Task run whenever HTTP server operations are pending.
* *
@ -1583,15 +1718,14 @@ handle_mhd_completion_callback (void *cls,
enum MHD_RequestTerminationCode toe) enum MHD_RequestTerminationCode toe)
{ {
/* struct TALER_FAKEBANK_Handle *h = cls; */ /* struct TALER_FAKEBANK_Handle *h = cls; */
struct ConnectionContext *cc = *con_cls;
(void) cls; (void) cls;
(void) connection; (void) connection;
(void) toe; (void) toe;
if (NULL == *con_cls) if (NULL == cc)
return; return;
if (&special_ptr == *con_cls) cc->ctx_cleaner (cc->ctx);
return; GNUNET_free (cc);
GNUNET_JSON_post_parser_cleanup (*con_cls);
*con_cls = NULL;
} }
@ -1603,7 +1737,7 @@ handle_mhd_completion_callback (void *cls,
* @param account account into which to deposit the funds (credit) * @param account account into which to deposit the funds (credit)
* @param upload_data request data * @param upload_data request data
* @param upload_data_size size of @a upload_data in bytes * @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 (a `struct ConnectionContext *`)
* @return MHD result code * @return MHD result code
*/ */
static MHD_RESULT static MHD_RESULT
@ -1614,14 +1748,21 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h,
size_t *upload_data_size, size_t *upload_data_size,
void **con_cls) void **con_cls)
{ {
struct ConnectionContext *cc = *con_cls;
enum GNUNET_JSON_PostResult pr; enum GNUNET_JSON_PostResult pr;
json_t *json; json_t *json;
uint64_t row_id; uint64_t row_id;
struct GNUNET_TIME_Timestamp timestamp; struct GNUNET_TIME_Timestamp timestamp;
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup;
*con_cls = cc;
}
pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
connection, connection,
con_cls, &cc->ctx,
upload_data, upload_data,
upload_data_size, upload_data_size,
&json); &json);
@ -1736,7 +1877,7 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h,
* @param account account making the transfer * @param account account making the transfer
* @param upload_data request data * @param upload_data request data
* @param upload_data_size size of @a upload_data in bytes * @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 (a `struct ConnectionContext *`)
* @return MHD result code * @return MHD result code
*/ */
static MHD_RESULT static MHD_RESULT
@ -1747,14 +1888,21 @@ handle_transfer (struct TALER_FAKEBANK_Handle *h,
size_t *upload_data_size, size_t *upload_data_size,
void **con_cls) void **con_cls)
{ {
struct ConnectionContext *cc = *con_cls;
enum GNUNET_JSON_PostResult pr; enum GNUNET_JSON_PostResult pr;
json_t *json; json_t *json;
uint64_t row_id; uint64_t row_id;
struct GNUNET_TIME_Timestamp ts; struct GNUNET_TIME_Timestamp ts;
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup;
*con_cls = cc;
}
pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
connection, connection,
con_cls, &cc->ctx,
upload_data, upload_data,
upload_data_size, upload_data_size,
&json); &json);
@ -1895,42 +2043,6 @@ handle_home_page (struct TALER_FAKEBANK_Handle *h,
} }
/**
* 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;
};
/** /**
* Parse URL history arguments, of _both_ APIs: * Parse URL history arguments, of _both_ APIs:
* /history/incoming and /history/outgoing. * /history/incoming and /history/outgoing.
@ -2176,7 +2288,7 @@ start_lp (struct TALER_FAKEBANK_Handle *h,
* @param h the fakebank handle * @param h the fakebank handle
* @param connection the connection * @param connection the connection
* @param account which account the request is about * @param account which account the request is about
* @param con_cls closure for request (NULL or &special_ptr) * @param con_cls closure for request
*/ */
static MHD_RESULT static MHD_RESULT
handle_debit_history (struct TALER_FAKEBANK_Handle *h, handle_debit_history (struct TALER_FAKEBANK_Handle *h,
@ -2184,87 +2296,106 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h,
const char *account, const char *account,
void **con_cls) void **con_cls)
{ {
struct HistoryArgs ha; struct ConnectionContext *cc = *con_cls;
struct Account *acc; struct HistoryContext *hc;
struct Transaction *pos; struct Transaction *pos;
json_t *history;
char *debit_payto;
enum GNUNET_GenericReturnValue ret; enum GNUNET_GenericReturnValue ret;
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
cc->ctx_cleaner = &history_cleanup;
*con_cls = cc;
hc = GNUNET_new (struct HistoryContext);
cc->ctx = hc;
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Handling /history/outgoing connection %p\n", "Handling /history/outgoing connection %p\n",
connection); connection);
if (GNUNET_OK != if (GNUNET_OK !=
(ret = parse_history_common_args (h, (ret = parse_history_common_args (h,
connection, connection,
&ha))) &hc->ha)))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES; return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES;
} }
if (&special_ptr == *con_cls) GNUNET_assert (0 ==
ha.lp_timeout = GNUNET_TIME_UNIT_ZERO; pthread_mutex_lock (&h->big_lock));
acc = lookup_account (h, hc->acc = lookup_account (h,
account, account,
NULL); NULL);
if (NULL == acc) if (NULL == hc->acc)
{ {
GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock));
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND, MHD_HTTP_NOT_FOUND,
TALER_EC_BANK_UNKNOWN_ACCOUNT, TALER_EC_BANK_UNKNOWN_ACCOUNT,
account); account);
} }
GNUNET_asprintf (&debit_payto, GNUNET_asprintf (&hc->payto_uri,
"payto://x-taler-bank/localhost/%s?receiver-name=%s", "payto://x-taler-bank/localhost/%s?receiver-name=%s",
account, account,
acc->receiver_name); hc->acc->receiver_name);
history = json_array (); /* New invariant: */
if (NULL == history) GNUNET_assert (0 == strcmp (hc->payto_uri,
hc->acc->payto_uri));
hc->history = json_array ();
if (NULL == hc->history)
{ {
GNUNET_break (0); GNUNET_break (0);
GNUNET_free (debit_payto); GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock));
return MHD_NO; return MHD_NO;
} }
GNUNET_assert (0 == hc->timeout = GNUNET_TIME_relative_to_absolute (hc->ha.lp_timeout);
pthread_mutex_lock (&h->big_lock));
if (! ha.have_start)
{
pos = (0 > ha.delta)
? acc->out_tail
: acc->out_head;
} }
else else
{ {
struct Transaction *t = h->transactions[ha.start_idx % h->ram_limit]; hc = cc->ctx;
GNUNET_assert (0 ==
pthread_mutex_lock (&h->big_lock));
}
if (! hc->ha.have_start)
{
pos = (0 > hc->ha.delta)
? hc->acc->out_tail
: hc->acc->out_head;
}
else
{
struct Transaction *t = h->transactions[hc->ha.start_idx % h->ram_limit];
bool overflow; bool overflow;
uint64_t dir; uint64_t dir;
bool skip = true; bool skip = true;
dir = (0 > ha.delta) ? (h->ram_limit - 1) : 1; dir = (0 > hc->ha.delta) ? (h->ram_limit - 1) : 1;
overflow = (t->row_id != ha.start_idx); overflow = (t->row_id != hc->ha.start_idx);
/* If account does not match, linear scan for /* If account does not match, linear scan for
first matching account. */ first matching account. */
while ( (! overflow) && while ( (! overflow) &&
(NULL != t) && (NULL != t) &&
(t->debit_account != acc) ) (t->debit_account != hc->acc) )
{ {
skip = false; skip = false;
t = h->transactions[(t->row_id + dir) % h->ram_limit]; t = h->transactions[(t->row_id + dir) % h->ram_limit];
if ( (NULL != t) && if ( (NULL != t) &&
(t->row_id == ha.start_idx) ) (t->row_id == hc->ha.start_idx) )
overflow = true; /* full circle, give up! */ overflow = true; /* full circle, give up! */
} }
if ( (NULL == t) || if ( (NULL == t) ||
overflow) overflow)
{ {
if (GNUNET_TIME_relative_is_zero (ha.lp_timeout) && /* FIXME: these conditions are unclear to me. */
(0 < ha.delta)) if ( (GNUNET_TIME_relative_is_zero (hc->ha.lp_timeout)) &&
(0 < hc->ha.delta))
{ {
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
if (overflow) if (overflow)
{ {
GNUNET_free (debit_payto);
return TALER_MHD_reply_with_ec ( return TALER_MHD_reply_with_ec (
connection, connection,
TALER_EC_BANK_ANCIENT_TRANSACTION_GONE, TALER_EC_BANK_ANCIENT_TRANSACTION_GONE,
@ -2272,35 +2403,36 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h,
} }
goto finish; goto finish;
} }
*con_cls = &special_ptr; if (h->in_shutdown)
{
GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock));
goto finish;
}
start_lp (h, start_lp (h,
connection, connection,
acc, hc->acc,
ha.lp_timeout, GNUNET_TIME_absolute_get_remaining (hc->timeout),
LP_DEBIT, LP_DEBIT,
NULL); NULL);
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
json_decref (history);
GNUNET_free (debit_payto);
return MHD_YES; return MHD_YES;
} }
if (t->debit_account != acc) if (t->debit_account != hc->acc)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Invalid start specified, transaction %llu not with account %s!\n", "Invalid start specified, transaction %llu not with account %s!\n",
(unsigned long long) ha.start_idx, (unsigned long long) hc->ha.start_idx,
account); account);
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
GNUNET_free (debit_payto);
json_decref (history);
return MHD_NO; return MHD_NO;
} }
if (skip) if (skip)
{ {
/* range is exclusive, skip the matching entry */ /* range is exclusive, skip the matching entry */
if (0 > ha.delta) if (0 > hc->ha.delta)
pos = t->prev_out; pos = t->prev_out;
else else
pos = t->next_out; pos = t->next_out;
@ -2313,9 +2445,9 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h,
if (NULL != pos) if (NULL != pos)
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Returning %lld debit transactions starting (inclusive) from %llu\n", "Returning %lld debit transactions starting (inclusive) from %llu\n",
(long long) ha.delta, (long long) hc->ha.delta,
(unsigned long long) pos->row_id); (unsigned long long) pos->row_id);
while ( (0 != ha.delta) && while ( (0 != hc->ha.delta) &&
(NULL != pos) ) (NULL != pos) )
{ {
json_t *trans; json_t *trans;
@ -2327,9 +2459,9 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h,
"Unexpected CREDIT transaction #%llu for account `%s'\n", "Unexpected CREDIT transaction #%llu for account `%s'\n",
(unsigned long long) pos->row_id, (unsigned long long) pos->row_id,
account); account);
if (0 > ha.delta) if (0 > hc->ha.delta)
pos = pos->prev_in; pos = pos->prev_in;
if (0 < ha.delta) if (0 < hc->ha.delta)
pos = pos->next_in; pos = pos->next_in;
continue; continue;
} }
@ -2348,7 +2480,7 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h,
GNUNET_JSON_pack_string ("credit_account", GNUNET_JSON_pack_string ("credit_account",
credit_payto), credit_payto),
GNUNET_JSON_pack_string ("debit_account", GNUNET_JSON_pack_string ("debit_account",
debit_payto), // FIXME #7275: inefficient to return this here always! hc->payto_uri), // FIXME #7275: inefficient to return this here always!
GNUNET_JSON_pack_string ("exchange_base_url", GNUNET_JSON_pack_string ("exchange_base_url",
pos->subject.debit.exchange_base_url), pos->subject.debit.exchange_base_url),
GNUNET_JSON_pack_data_auto ("wtid", GNUNET_JSON_pack_data_auto ("wtid",
@ -2356,51 +2488,55 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h,
GNUNET_assert (NULL != trans); GNUNET_assert (NULL != trans);
GNUNET_free (credit_payto); GNUNET_free (credit_payto);
GNUNET_assert (0 == GNUNET_assert (0 ==
json_array_append_new (history, json_array_append_new (hc->history,
trans)); trans));
if (ha.delta > 0) if (hc->ha.delta > 0)
ha.delta--; hc->ha.delta--;
else else
ha.delta++; hc->ha.delta++;
if (0 > ha.delta) if (0 > hc->ha.delta)
pos = pos->prev_out; pos = pos->prev_out;
if (0 < ha.delta) if (0 < hc->ha.delta)
pos = pos->next_out; pos = pos->next_out;
} }
if ( (0 == json_array_size (history)) && if ( (0 == json_array_size (hc->history)) &&
(! GNUNET_TIME_relative_is_zero (ha.lp_timeout)) && (! h->in_shutdown) &&
(0 < ha.delta)) (GNUNET_TIME_absolute_is_future (hc->timeout)) &&
(0 < hc->ha.delta))
{ {
*con_cls = &special_ptr;
start_lp (h, start_lp (h,
connection, connection,
acc, hc->acc,
ha.lp_timeout, GNUNET_TIME_absolute_get_remaining (hc->timeout),
LP_DEBIT, LP_DEBIT,
NULL); NULL);
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
json_decref (history);
return MHD_YES; return MHD_YES;
} }
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
finish: finish:
if (0 == json_array_size (history)) if (0 == json_array_size (hc->history))
{ {
json_decref (history); GNUNET_break (h->in_shutdown ||
(! GNUNET_TIME_absolute_is_future (hc->timeout)));
return TALER_MHD_reply_static (connection, return TALER_MHD_reply_static (connection,
MHD_HTTP_NO_CONTENT, MHD_HTTP_NO_CONTENT,
NULL, NULL,
NULL, NULL,
0); 0);
} }
GNUNET_free (debit_payto); {
json_t *h = hc->history;
hc->history = NULL;
return TALER_MHD_REPLY_JSON_PACK (connection, return TALER_MHD_REPLY_JSON_PACK (connection,
MHD_HTTP_OK, MHD_HTTP_OK,
GNUNET_JSON_pack_array_steal ( GNUNET_JSON_pack_array_steal (
"outgoing_transactions", "outgoing_transactions",
history)); h));
}
} }
@ -2419,77 +2555,101 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h,
const char *account, const char *account,
void **con_cls) void **con_cls)
{ {
struct HistoryArgs ha; struct ConnectionContext *cc = *con_cls;
struct Account *acc; struct HistoryContext *hc;
const struct Transaction *pos; const struct Transaction *pos;
json_t *history;
const char *credit_payto;
enum GNUNET_GenericReturnValue ret; enum GNUNET_GenericReturnValue ret;
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
cc->ctx_cleaner = &history_cleanup;
*con_cls = cc;
hc = GNUNET_new (struct HistoryContext);
cc->ctx = hc;
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Handling /history/incoming connection %p (%d)\n", "Handling /history/incoming connection %p\n",
connection, connection);
(*con_cls == &special_ptr));
if (GNUNET_OK != if (GNUNET_OK !=
(ret = parse_history_common_args (h, (ret = parse_history_common_args (h,
connection, connection,
&ha))) &hc->ha)))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES; return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES;
} }
if (&special_ptr == *con_cls) GNUNET_assert (0 ==
ha.lp_timeout = GNUNET_TIME_UNIT_ZERO; pthread_mutex_lock (&h->big_lock));
*con_cls = &special_ptr; hc->acc = lookup_account (h,
acc = lookup_account (h,
account, account,
NULL); NULL);
if (NULL == acc) if (NULL == hc->acc)
{ {
GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock));
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_error (connection,
MHD_HTTP_NOT_FOUND, MHD_HTTP_NOT_FOUND,
TALER_EC_BANK_UNKNOWN_ACCOUNT, TALER_EC_BANK_UNKNOWN_ACCOUNT,
account); account);
} }
history = json_array (); /* FIXME: was simply: acc->payto_uri -- same!? */
GNUNET_assert (NULL != history); GNUNET_asprintf (&hc->payto_uri,
credit_payto = acc->payto_uri; "payto://x-taler-bank/localhost/%s?receiver-name=%s",
GNUNET_assert (0 == account,
pthread_mutex_lock (&h->big_lock)); hc->acc->receiver_name);
if (! ha.have_start) GNUNET_assert (0 == strcmp (hc->payto_uri,
hc->acc->payto_uri));
hc->history = json_array ();
if (NULL == hc->history)
{ {
pos = (0 > ha.delta) GNUNET_break (0);
? acc->in_tail GNUNET_assert (0 ==
: acc->in_head; pthread_mutex_unlock (&h->big_lock));
return MHD_NO;
}
hc->timeout = GNUNET_TIME_relative_to_absolute (hc->ha.lp_timeout);
} }
else else
{ {
struct Transaction *t = h->transactions[ha.start_idx % h->ram_limit]; hc = cc->ctx;
GNUNET_assert (0 ==
pthread_mutex_lock (&h->big_lock));
}
if (! hc->ha.have_start)
{
pos = (0 > hc->ha.delta)
? hc->acc->in_tail
: hc->acc->in_head;
}
else
{
struct Transaction *t = h->transactions[hc->ha.start_idx % h->ram_limit];
bool overflow; bool overflow;
uint64_t dir; uint64_t dir;
bool skip = true; bool skip = true;
overflow = ( (NULL != t) && (t->row_id != ha.start_idx) ); overflow = ( (NULL != t) && (t->row_id != hc->ha.start_idx) );
dir = (0 > ha.delta) ? (h->ram_limit - 1) : 1; dir = (0 > hc->ha.delta) ? (h->ram_limit - 1) : 1;
/* If account does not match, linear scan for /* If account does not match, linear scan for
first matching account. */ first matching account. */
while ( (! overflow) && while ( (! overflow) &&
(NULL != t) && (NULL != t) &&
(t->credit_account != acc) ) (t->credit_account != hc->acc) )
{ {
skip = false; skip = false;
t = h->transactions[(t->row_id + dir) % h->ram_limit]; t = h->transactions[(t->row_id + dir) % h->ram_limit];
if ( (NULL != t) && if ( (NULL != t) &&
(t->row_id == ha.start_idx) ) (t->row_id == hc->ha.start_idx) )
overflow = true; /* full circle, give up! */ overflow = true; /* full circle, give up! */
} }
if ( (NULL == t) || if ( (NULL == t) ||
overflow) overflow)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_INFO, /* FIXME: these conditions are unclear to me. */
"No transactions available, suspending request\n"); if (GNUNET_TIME_relative_is_zero (hc->ha.lp_timeout) &&
if (GNUNET_TIME_relative_is_zero (ha.lp_timeout) && (0 < hc->ha.delta))
(0 < ha.delta))
{ {
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
@ -2500,23 +2660,27 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h,
NULL); NULL);
goto finish; goto finish;
} }
*con_cls = &special_ptr; if (h->in_shutdown)
{
GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock));
goto finish;
}
start_lp (h, start_lp (h,
connection, connection,
acc, hc->acc,
ha.lp_timeout, GNUNET_TIME_absolute_get_remaining (hc->timeout),
LP_CREDIT, LP_CREDIT,
NULL); NULL);
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
json_decref (history);
return MHD_YES; return MHD_YES;
} }
if (skip) if (skip)
{ {
/* range from application is exclusive, skip the /* range from application is exclusive, skip the
matching entry */ matching entry */
if (0 > ha.delta) if (0 > hc->ha.delta)
pos = t->prev_in; pos = t->prev_in;
else else
pos = t->next_in; pos = t->next_in;
@ -2529,9 +2693,9 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h,
if (NULL != pos) if (NULL != pos)
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Returning %lld credit transactions starting (inclusive) from %llu\n", "Returning %lld credit transactions starting (inclusive) from %llu\n",
(long long) ha.delta, (long long) hc->ha.delta,
(unsigned long long) pos->row_id); (unsigned long long) pos->row_id);
while ( (0 != ha.delta) && while ( (0 != hc->ha.delta) &&
(NULL != pos) ) (NULL != pos) )
{ {
json_t *trans; json_t *trans;
@ -2542,9 +2706,9 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h,
"Unexpected DEBIT transaction #%llu for account `%s'\n", "Unexpected DEBIT transaction #%llu for account `%s'\n",
(unsigned long long) pos->row_id, (unsigned long long) pos->row_id,
account); account);
if (0 > ha.delta) if (0 > hc->ha.delta)
pos = pos->prev_in; pos = pos->prev_in;
if (0 < ha.delta) if (0 < hc->ha.delta)
pos = pos->next_in; pos = pos->next_in;
continue; continue;
} }
@ -2556,57 +2720,62 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h,
TALER_JSON_pack_amount ("amount", TALER_JSON_pack_amount ("amount",
&pos->amount), &pos->amount),
GNUNET_JSON_pack_string ("credit_account", GNUNET_JSON_pack_string ("credit_account",
credit_payto), // FIXME #7275: inefficient to repeat this always here! hc->payto_uri), // FIXME #7275: inefficient to repeat this always here!
GNUNET_JSON_pack_string ("debit_account", GNUNET_JSON_pack_string ("debit_account",
pos->debit_account->payto_uri), pos->debit_account->payto_uri),
GNUNET_JSON_pack_data_auto ("reserve_pub", GNUNET_JSON_pack_data_auto ("reserve_pub",
&pos->subject.credit.reserve_pub)); &pos->subject.credit.reserve_pub));
GNUNET_assert (NULL != trans); GNUNET_assert (NULL != trans);
GNUNET_assert (0 == GNUNET_assert (0 ==
json_array_append_new (history, json_array_append_new (hc->history,
trans)); trans));
if (ha.delta > 0) if (hc->ha.delta > 0)
ha.delta--; hc->ha.delta--;
else else
ha.delta++; hc->ha.delta++;
if (0 > ha.delta) if (0 > hc->ha.delta)
pos = pos->prev_in; pos = pos->prev_in;
if (0 < ha.delta) if (0 < hc->ha.delta)
pos = pos->next_in; pos = pos->next_in;
} }
if ( (0 == json_array_size (history)) && if ( (0 == json_array_size (hc->history)) &&
(! GNUNET_TIME_relative_is_zero (ha.lp_timeout)) && (! h->in_shutdown) &&
(0 < ha.delta)) (GNUNET_TIME_absolute_is_future (hc->timeout)) &&
(0 < hc->ha.delta))
{ {
*con_cls = &special_ptr;
start_lp (h, start_lp (h,
connection, connection,
acc, hc->acc,
ha.lp_timeout, GNUNET_TIME_absolute_get_remaining (hc->timeout),
LP_CREDIT, LP_CREDIT,
NULL); NULL);
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
json_decref (history);
return MHD_YES; return MHD_YES;
} }
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
finish: finish:
if (0 == json_array_size (history)) if (0 == json_array_size (hc->history))
{ {
json_decref (history); GNUNET_break (h->in_shutdown ||
(! GNUNET_TIME_absolute_is_future (hc->timeout)));
return TALER_MHD_reply_static (connection, return TALER_MHD_reply_static (connection,
MHD_HTTP_NO_CONTENT, MHD_HTTP_NO_CONTENT,
NULL, NULL,
NULL, NULL,
0); 0);
} }
{
json_t *h = hc->history;
hc->history = NULL;
return TALER_MHD_REPLY_JSON_PACK (connection, return TALER_MHD_REPLY_JSON_PACK (connection,
MHD_HTTP_OK, MHD_HTTP_OK,
GNUNET_JSON_pack_array_steal ( GNUNET_JSON_pack_array_steal (
"incoming_transactions", "incoming_transactions",
history)); h));
}
} }
@ -2711,13 +2880,21 @@ get_withdrawal_operation (struct TALER_FAKEBANK_Handle *h,
struct GNUNET_TIME_Relative lp, struct GNUNET_TIME_Relative lp,
void **con_cls) void **con_cls)
{ {
struct WithdrawalOperation *wo; struct ConnectionContext *cc = *con_cls;
struct WithdrawContext *wc;
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_lock (&h->big_lock)); pthread_mutex_lock (&h->big_lock));
wo = lookup_withdrawal_operation (h, if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
cc->ctx_cleaner = &withdraw_cleanup;
*con_cls = cc;
wc = GNUNET_new (struct WithdrawContext);
cc->ctx = wc;
wc->wo = lookup_withdrawal_operation (h,
wopid); wopid);
if (NULL == wo) if (NULL == wc->wo)
{ {
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
@ -2726,10 +2903,16 @@ get_withdrawal_operation (struct TALER_FAKEBANK_Handle *h,
TALER_EC_BANK_TRANSACTION_NOT_FOUND, TALER_EC_BANK_TRANSACTION_NOT_FOUND,
wopid); wopid);
} }
if ( (NULL != *con_cls) || wc->timeout = GNUNET_TIME_relative_to_absolute (lp);
(GNUNET_TIME_relative_is_zero (lp)) || }
wo->confirmation_done || else
wo->aborted) {
wc = cc->ctx;
}
if (GNUNET_TIME_absolute_is_past (wc->timeout) ||
h->in_shutdown ||
wc->wo->confirmation_done ||
wc->wo->aborted)
{ {
json_t *wt; json_t *wt;
@ -2744,27 +2927,26 @@ get_withdrawal_operation (struct TALER_FAKEBANK_Handle *h,
connection, connection,
MHD_HTTP_OK, MHD_HTTP_OK,
GNUNET_JSON_pack_bool ("aborted", GNUNET_JSON_pack_bool ("aborted",
wo->aborted), wc->wo->aborted),
GNUNET_JSON_pack_bool ("selection_done", GNUNET_JSON_pack_bool ("selection_done",
wo->selection_done), wc->wo->selection_done),
GNUNET_JSON_pack_bool ("transfer_done", GNUNET_JSON_pack_bool ("transfer_done",
wo->confirmation_done), wc->wo->confirmation_done),
GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("suggested_exchange", GNUNET_JSON_pack_string ("suggested_exchange",
h->exchange_url)), h->exchange_url)),
TALER_JSON_pack_amount ("amount", TALER_JSON_pack_amount ("amount",
&wo->amount), &wc->wo->amount),
GNUNET_JSON_pack_array_steal ("wire_types", GNUNET_JSON_pack_array_steal ("wire_types",
wt)); wt));
} }
*con_cls = &special_ptr;
start_lp (h, start_lp (h,
connection, connection,
wo->debit_account, wc->wo->debit_account,
lp, GNUNET_TIME_absolute_get_remaining (wc->timeout),
LP_WITHDRAW, LP_WITHDRAW,
wo); wc->wo);
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock)); pthread_mutex_unlock (&h->big_lock));
return MHD_YES; return MHD_YES;
@ -2903,13 +3085,20 @@ post_withdrawal_operation (struct TALER_FAKEBANK_Handle *h,
size_t *upload_data_size, size_t *upload_data_size,
void **con_cls) void **con_cls)
{ {
struct ConnectionContext *cc = *con_cls;
enum GNUNET_JSON_PostResult pr; enum GNUNET_JSON_PostResult pr;
json_t *json; json_t *json;
MHD_RESULT res; MHD_RESULT res;
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup;
*con_cls = cc;
}
pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
connection, connection,
con_cls, &cc->ctx,
upload_data, upload_data,
upload_data_size, upload_data_size,
&json); &json);
@ -3294,13 +3483,20 @@ post_account_withdrawals_access (struct TALER_FAKEBANK_Handle *h,
size_t *upload_data_size, size_t *upload_data_size,
void **con_cls) void **con_cls)
{ {
struct ConnectionContext *cc = *con_cls;
enum GNUNET_JSON_PostResult pr; enum GNUNET_JSON_PostResult pr;
json_t *json; json_t *json;
MHD_RESULT res; MHD_RESULT res;
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup;
*con_cls = cc;
}
pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
connection, connection,
con_cls, &cc->ctx,
upload_data, upload_data,
upload_data_size, upload_data_size,
&json); &json);
@ -3367,13 +3563,20 @@ post_testing_register (struct TALER_FAKEBANK_Handle *h,
size_t *upload_data_size, size_t *upload_data_size,
void **con_cls) void **con_cls)
{ {
struct ConnectionContext *cc = *con_cls;
enum GNUNET_JSON_PostResult pr; enum GNUNET_JSON_PostResult pr;
json_t *json; json_t *json;
MHD_RESULT res; MHD_RESULT res;
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup;
*con_cls = cc;
}
pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
connection, connection,
con_cls, &cc->ctx,
upload_data, upload_data,
upload_data_size, upload_data_size,
&json); &json);

View File

@ -28,7 +28,7 @@ DB = postgres
# exchange (or the twister) is actually listening. # exchange (or the twister) is actually listening.
base_url = "http://localhost:8081/" base_url = "http://localhost:8081/"
WIREWATCH_IDLE_SLEEP_INTERVAL = 1500 ms WIREWATCH_IDLE_SLEEP_INTERVAL = 500 ms
[exchange-offline] [exchange-offline]
MASTER_PRIV_FILE = ${TALER_DATA_HOME}/exchange/offline-keys/master.priv MASTER_PRIV_FILE = ${TALER_DATA_HOME}/exchange/offline-keys/master.priv
@ -51,11 +51,11 @@ MAX_DEBT = EUR:100000000000.0
MAX_DEBT_BANK = EUR:1000000000000000.0 MAX_DEBT_BANK = EUR:1000000000000000.0
[benchmark] [benchmark]
USER_PAYTO_URI = payto://x-taler-bank/localhost:8082/42 USER_PAYTO_URI = payto://x-taler-bank/localhost:8082/42?receiver-name=user42
[exchange-account-2] [exchange-account-2]
# What is the payto://-URL of the exchange (to generate wire response) # What is the payto://-URL of the exchange (to generate wire response)
PAYTO_URI = "payto://x-taler-bank/localhost:8082/Exchange" PAYTO_URI = "payto://x-taler-bank/localhost:8082/Exchange?receiver-name=Exchange"
enable_debit = YES enable_debit = YES
enable_credit = YES enable_credit = YES

View File

@ -689,6 +689,8 @@ parallel_benchmark (void)
} }
/* But be extra sure we did finish all shards by doing one more */ /* But be extra sure we did finish all shards by doing one more */
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
"Shard check phase\n");
wirewatch[0] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, wirewatch[0] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
NULL, NULL, NULL, NULL, NULL, NULL,
"taler-exchange-wirewatch", "taler-exchange-wirewatch",

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
(C) 2014-2020 Taler Systems SA (C) 2014-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it TALER is free software; you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as under the terms of the GNU Affero General Public License as

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2014-2022 Taler Systems SA Copyright (C) 2014-2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software terms of the GNU Affero General Public License as published by the Free Software
@ -62,6 +62,16 @@ struct ReservePoller
*/ */
struct GNUNET_TIME_Absolute timeout; struct GNUNET_TIME_Absolute timeout;
/**
* Public key of the reserve the inquiry is about.
*/
struct TALER_ReservePublicKeyP reserve_pub;
/**
* Balance of the reserve, set in the callback.
*/
struct TALER_Amount balance;
/** /**
* True if we are still suspended. * True if we are still suspended.
*/ */
@ -84,13 +94,10 @@ static struct ReservePoller *rp_tail;
void void
TEH_reserves_get_cleanup () TEH_reserves_get_cleanup ()
{ {
struct ReservePoller *rp; for (struct ReservePoller *rp = rp_head;
NULL != rp;
while (NULL != (rp = rp_head)) rp = rp->next)
{ {
GNUNET_CONTAINER_DLL_remove (rp_head,
rp_tail,
rp);
if (rp->suspended) if (rp->suspended)
{ {
rp->suspended = false; rp->suspended = false;
@ -115,11 +122,14 @@ rp_cleanup (struct TEH_RequestContext *rc)
if (NULL != rp->eh) if (NULL != rp->eh)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Cancelling DB event listening\n"); "Cancelling DB event listening on cleanup (odd unless during shutdown)\n");
TEH_plugin->event_listen_cancel (TEH_plugin->cls, TEH_plugin->event_listen_cancel (TEH_plugin->cls,
rp->eh); rp->eh);
rp->eh = NULL; rp->eh = NULL;
} }
GNUNET_CONTAINER_DLL_remove (rp_head,
rp_tail,
rp);
GNUNET_free (rp); GNUNET_free (rp);
} }
@ -137,26 +147,15 @@ db_event_cb (void *cls,
const void *extra, const void *extra,
size_t extra_size) size_t extra_size)
{ {
struct TEH_RequestContext *rc = cls; struct ReservePoller *rp = cls;
struct ReservePoller *rp = rc->rh_ctx;
struct GNUNET_AsyncScopeSave old_scope; struct GNUNET_AsyncScopeSave old_scope;
(void) extra; (void) extra;
(void) extra_size; (void) extra_size;
if (NULL == rp)
return; /* event triggered while main transaction
was still running */
if (! rp->suspended) if (! rp->suspended)
return; /* might get multiple wake-up events */ return; /* might get multiple wake-up events */
rp->suspended = false;
GNUNET_async_scope_enter (&rc->async_scope_id,
&old_scope);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Resuming from long-polling on reserve\n");
TEH_check_invariants (); TEH_check_invariants ();
GNUNET_CONTAINER_DLL_remove (rp_head, rp->suspended = false;
rp_tail,
rp);
MHD_resume_connection (rp->connection); MHD_resume_connection (rp->connection);
TALER_MHD_daemon_trigger (); TALER_MHD_daemon_trigger ();
TEH_check_invariants (); TEH_check_invariants ();
@ -164,85 +163,29 @@ db_event_cb (void *cls,
} }
/**
* Closure for #reserve_history_transaction.
*/
struct ReserveHistoryContext
{
/**
* Public key of the reserve the inquiry is about.
*/
struct TALER_ReservePublicKeyP reserve_pub;
/**
* Balance of the reserve, set in the callback.
*/
struct TALER_Amount balance;
/**
* Set to true if we did not find the reserve.
*/
bool not_found;
};
/**
* Function implementing /reserves/ GET transaction.
* Execute a /reserves/ GET. Given the public key of a reserve,
* return the associated transaction history. Runs the
* transaction logic; IF it returns a non-error code, the transaction
* logic MUST NOT queue a MHD response. IF it returns an hard error,
* the transaction logic MUST queue a MHD response and set @a mhd_ret.
* IF it returns the soft error code, the function MAY be called again
* to retry and MUST not queue a MHD response.
*
* @param cls a `struct ReserveHistoryContext *`
* @param connection MHD request which triggered the transaction
* @param[out] mhd_ret set to MHD response status for @a connection,
* if transaction failed (!)
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
reserve_balance_transaction (void *cls,
struct MHD_Connection *connection,
MHD_RESULT *mhd_ret)
{
struct ReserveHistoryContext *rsc = cls;
enum GNUNET_DB_QueryStatus qs;
qs = TEH_plugin->get_reserve_balance (TEH_plugin->cls,
&rsc->reserve_pub,
&rsc->balance);
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
{
GNUNET_break (0);
*mhd_ret
= TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_FETCH_FAILED,
"get_reserve_balance");
}
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
rsc->not_found = true;
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
rsc->not_found = false;
return qs;
}
MHD_RESULT MHD_RESULT
TEH_handler_reserves_get (struct TEH_RequestContext *rc, TEH_handler_reserves_get (struct TEH_RequestContext *rc,
const char *const args[1]) const char *const args[1])
{ {
struct ReserveHistoryContext rsc; struct ReservePoller *rp = rc->rh_ctx;
struct GNUNET_TIME_Relative timeout = GNUNET_TIME_UNIT_ZERO;
struct GNUNET_DB_EventHandler *eh = NULL;
if (NULL == rp)
{
struct GNUNET_TIME_Relative timeout
= GNUNET_TIME_UNIT_ZERO;
rp = GNUNET_new (struct ReservePoller);
rp->connection = rc->connection;
rc->rh_ctx = rp;
rc->rh_cleaner = &rp_cleanup;
GNUNET_CONTAINER_DLL_insert (rp_head,
rp_tail,
rp);
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (args[0], GNUNET_STRINGS_string_to_data (args[0],
strlen (args[0]), strlen (args[0]),
&rsc.reserve_pub, &rp->reserve_pub,
sizeof (rsc.reserve_pub))) sizeof (rp->reserve_pub)))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection, return TALER_MHD_reply_with_error (rc->connection,
@ -277,47 +220,58 @@ TEH_handler_reserves_get (struct TEH_RequestContext *rc,
timeout_ms); timeout_ms);
} }
} }
if ( (! GNUNET_TIME_relative_is_zero (timeout)) && rp->timeout = GNUNET_TIME_relative_to_absolute (timeout);
(NULL == rc->rh_ctx) ) }
if ( (GNUNET_TIME_absolute_is_future (rp->timeout)) &&
(NULL == rp->eh) )
{ {
struct TALER_ReserveEventP rep = { struct TALER_ReserveEventP rep = {
.header.size = htons (sizeof (rep)), .header.size = htons (sizeof (rep)),
.header.type = htons (TALER_DBEVENT_EXCHANGE_RESERVE_INCOMING), .header.type = htons (TALER_DBEVENT_EXCHANGE_RESERVE_INCOMING),
.reserve_pub = rsc.reserve_pub .reserve_pub = rp->reserve_pub
}; };
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Starting DB event listening\n"); "Starting DB event listening until %s\n",
eh = TEH_plugin->event_listen (TEH_plugin->cls, GNUNET_TIME_absolute2s (rp->timeout));
timeout, rp->eh = TEH_plugin->event_listen (
TEH_plugin->cls,
GNUNET_TIME_absolute_get_remaining (rp->timeout),
&rep.header, &rep.header,
&db_event_cb, &db_event_cb,
rc); rp);
} }
{ {
MHD_RESULT mhd_ret; enum GNUNET_DB_QueryStatus qs;
if (GNUNET_OK != qs = TEH_plugin->get_reserve_balance (TEH_plugin->cls,
TEH_DB_run_transaction (rc->connection, &rp->reserve_pub,
"get reserve balance", &rp->balance);
TEH_MT_REQUEST_OTHER, switch (qs)
&mhd_ret,
&reserve_balance_transaction,
&rsc))
{ {
if (NULL != eh) case GNUNET_DB_STATUS_SOFT_ERROR:
TEH_plugin->event_listen_cancel (TEH_plugin->cls, GNUNET_break (0); /* single-shot query should never have soft-errors */
eh); return TALER_MHD_reply_with_error (rc->connection,
return mhd_ret; MHD_HTTP_INTERNAL_SERVER_ERROR,
} TALER_EC_GENERIC_DB_SOFT_FAILURE,
} "get_reserve_balance");
/* generate proper response */ case GNUNET_DB_STATUS_HARD_ERROR:
if (rsc.not_found) GNUNET_break (0);
{ return TALER_MHD_reply_with_error (rc->connection,
struct ReservePoller *rp = rc->rh_ctx; MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_FETCH_FAILED,
if ( (NULL != rp) || "get_reserve_balance");
(GNUNET_TIME_relative_is_zero (timeout)) ) case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Got reserve balance of %s\n",
TALER_amount2s (&rp->balance));
return TALER_MHD_REPLY_JSON_PACK (rc->connection,
MHD_HTTP_OK,
TALER_JSON_pack_amount ("balance",
&rp->balance));
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
if (! GNUNET_TIME_absolute_is_future (rp->timeout))
{ {
return TALER_MHD_reply_with_error (rc->connection, return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_NOT_FOUND, MHD_HTTP_NOT_FOUND,
@ -326,29 +280,16 @@ TEH_handler_reserves_get (struct TEH_RequestContext *rc,
} }
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Long-polling on reserve for %s\n", "Long-polling on reserve for %s\n",
GNUNET_STRINGS_relative_time_to_string (timeout, GNUNET_STRINGS_relative_time_to_string (
GNUNET_YES)); GNUNET_TIME_absolute_get_remaining (rp->timeout),
rp = GNUNET_new (struct ReservePoller); true));
rp->connection = rc->connection;
rp->timeout = GNUNET_TIME_relative_to_absolute (timeout);
rp->eh = eh;
rc->rh_ctx = rp;
rc->rh_cleaner = &rp_cleanup;
rp->suspended = true; rp->suspended = true;
GNUNET_CONTAINER_DLL_insert (rp_head,
rp_tail,
rp);
MHD_suspend_connection (rc->connection); MHD_suspend_connection (rc->connection);
return MHD_YES; return MHD_YES;
} }
if (NULL != eh) }
TEH_plugin->event_listen_cancel (TEH_plugin->cls, GNUNET_break (0);
eh); return MHD_NO;
return TALER_MHD_REPLY_JSON_PACK (
rc->connection,
MHD_HTTP_OK,
TALER_JSON_pack_amount ("balance",
&rsc.balance));
} }

View File

@ -57,6 +57,12 @@ static struct TALER_BANK_CreditHistoryHandle *hh;
*/ */
static bool hh_returned_data; static bool hh_returned_data;
/**
* Set to true if the request for history did not
* succeed because the account was unknown.
*/
static bool hh_account_404;
/** /**
* When did we start the last @e hh request? * When did we start the last @e hh request?
*/ */
@ -472,9 +478,9 @@ transaction_completed (void)
GNUNET_SCHEDULER_shutdown (); GNUNET_SCHEDULER_shutdown ();
return; return;
} }
if (! hh_returned_data) if (! (hh_returned_data || hh_account_404) )
{ {
/* Enforce long polling delay even if the server ignored it /* Enforce long-polling delay even if the server ignored it
and returned earlier */ and returned earlier */
struct GNUNET_TIME_Relative latency; struct GNUNET_TIME_Relative latency;
struct GNUNET_TIME_Relative left; struct GNUNET_TIME_Relative left;
@ -482,8 +488,17 @@ transaction_completed (void)
latency = GNUNET_TIME_absolute_get_duration (hh_start_time); latency = GNUNET_TIME_absolute_get_duration (hh_start_time);
left = GNUNET_TIME_relative_subtract (longpoll_timeout, left = GNUNET_TIME_relative_subtract (longpoll_timeout,
latency); latency);
if (! (test_mode ||
GNUNET_TIME_relative_is_zero (left)) )
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, // WARNING,
"Server did not respect long-polling, enforcing client-side by sleeping for %s\n",
GNUNET_TIME_relative2s (left,
true));
delayed_until = GNUNET_TIME_relative_to_absolute (left); delayed_until = GNUNET_TIME_relative_to_absolute (left);
} }
if (hh_account_404)
delayed_until = GNUNET_TIME_relative_to_absolute (
GNUNET_TIME_UNIT_MILLISECONDS);
if (test_mode) if (test_mode)
delayed_until = GNUNET_TIME_UNIT_ZERO_ABS; delayed_until = GNUNET_TIME_UNIT_ZERO_ABS;
GNUNET_assert (NULL == task); GNUNET_assert (NULL == task);
@ -709,7 +724,7 @@ history_cb (void *cls,
} }
GNUNET_assert (NULL == task); GNUNET_assert (NULL == task);
hh = NULL; hh = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"History request returned with HTTP status %u\n", "History request returned with HTTP status %u\n",
reply->http_status); reply->http_status);
switch (reply->http_status) switch (reply->http_status)
@ -723,6 +738,7 @@ history_cb (void *cls,
transaction_completed (); transaction_completed ();
return; return;
case MHD_HTTP_NOT_FOUND: case MHD_HTTP_NOT_FOUND:
hh_account_404 = true;
if (ignore_account_404) if (ignore_account_404)
{ {
transaction_completed (); transaction_completed ();
@ -761,6 +777,7 @@ continue_with_shard (void *cls)
(unsigned long long) latest_row_off); (unsigned long long) latest_row_off);
hh_start_time = GNUNET_TIME_absolute_get (); hh_start_time = GNUNET_TIME_absolute_get ();
hh_returned_data = false; hh_returned_data = false;
hh_account_404 = false;
hh = TALER_BANK_credit_history (ctx, hh = TALER_BANK_credit_history (ctx,
ai->auth, ai->auth,
latest_row_off, latest_row_off,
@ -857,6 +874,17 @@ lock_shard (void *cls)
job_name, job_name,
GNUNET_STRINGS_relative_time_to_string (rdelay, GNUNET_STRINGS_relative_time_to_string (rdelay,
true)); true));
#if 1
if (GNUNET_TIME_relative_cmp (rdelay,
>,
GNUNET_TIME_UNIT_SECONDS))
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Delay would have been for %s\n",
GNUNET_TIME_relative2s (rdelay,
true));
rdelay = GNUNET_TIME_relative_min (rdelay,
GNUNET_TIME_UNIT_SECONDS);
#endif
delayed_until = GNUNET_TIME_relative_to_absolute (rdelay); delayed_until = GNUNET_TIME_relative_to_absolute (rdelay);
} }
GNUNET_assert (NULL == task); GNUNET_assert (NULL == task);
@ -869,7 +897,7 @@ lock_shard (void *cls)
job_name, job_name,
GNUNET_STRINGS_relative_time_to_string ( GNUNET_STRINGS_relative_time_to_string (
wirewatch_idle_sleep_interval, wirewatch_idle_sleep_interval,
GNUNET_YES)); true));
delayed_until = GNUNET_TIME_relative_to_absolute ( delayed_until = GNUNET_TIME_relative_to_absolute (
wirewatch_idle_sleep_interval); wirewatch_idle_sleep_interval);
shard_open = false; shard_open = false;

File diff suppressed because it is too large Load Diff

View File

@ -1409,7 +1409,7 @@ irbt_cb_table_purse_decision (struct PostgresClosure *pg,
GNUNET_PQ_query_param_timestamp ( GNUNET_PQ_query_param_timestamp (
&td->details.purse_decision.action_timestamp), &td->details.purse_decision.action_timestamp),
GNUNET_PQ_query_param_bool ( GNUNET_PQ_query_param_bool (
&td->details.purse_decision.refunded), td->details.purse_decision.refunded),
GNUNET_PQ_query_param_end GNUNET_PQ_query_param_end
}; };

File diff suppressed because it is too large Load Diff

View File

@ -34,7 +34,6 @@
*/ */
struct WirewatchState struct WirewatchState
{ {
/** /**
* Process for the wirewatcher. * Process for the wirewatcher.
*/ */

View File

@ -353,7 +353,7 @@ maint_child_death (void *cls)
while (TALER_TESTING_cmd_is_batch (cmd)) while (TALER_TESTING_cmd_is_batch (cmd))
cmd = TALER_TESTING_cmd_batch_get_current (cmd); cmd = TALER_TESTING_cmd_batch_get_current (cmd);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Got SIGCHLD for `%s'.\n", "Got SIGCHLD for `%s'.\n",
cmd->label); cmd->label);
is->child_death_task = NULL; is->child_death_task = NULL;