-preparations for long polling support

This commit is contained in:
Christian Grothoff 2021-11-15 12:39:35 +01:00
parent ee687c87ed
commit c67df63699
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
3 changed files with 174 additions and 63 deletions

View File

@ -1642,6 +1642,7 @@ do_shutdown (void *cls)
mhd = TALER_MHD_daemon_stop (); mhd = TALER_MHD_daemon_stop ();
TEH_resume_keys_requests (true); TEH_resume_keys_requests (true);
TEH_reserves_get_cleanup (); TEH_reserves_get_cleanup ();
TEH_kyc_check_cleanup ();
TEH_kyc_proof_cleanup (); TEH_kyc_proof_cleanup ();
if (NULL != mhd) if (NULL != mhd)
MHD_stop_daemon (mhd); MHD_stop_daemon (mhd);

View File

@ -33,10 +33,31 @@
/** /**
* Context for the request. * Reserve GET request that is long-polling.
*/ */
struct KycCheckContext struct KycPoller
{ {
/**
* Kept in a DLL.
*/
struct KycPoller *next;
/**
* Kept in a DLL.
*/
struct KycPoller *prev;
/**
* Connection we are handling.
*/
struct MHD_Connection *connection;
/**
* Subscription for the database event we are
* waiting for.
*/
struct GNUNET_DB_EventHandler *eh;
/** /**
* UUID being checked. * UUID being checked.
*/ */
@ -52,9 +73,79 @@ struct KycCheckContext
* have finished the KYC for. * have finished the KYC for.
*/ */
struct TALER_PaytoHash h_payto; struct TALER_PaytoHash h_payto;
/**
* Hash of the payto:// URI that was given to us for auth.
*/
struct TALER_PaytoHash auth_h_payto;
/**
* When will this request time out?
*/
struct GNUNET_TIME_Absolute timeout;
/**
* True if we are still suspended.
*/
bool suspended;
}; };
/**
* Head of list of requests in long polling.
*/
static struct KycPoller *kyp_head;
/**
* Tail of list of requests in long polling.
*/
static struct KycPoller *kyp_tail;
void
TEH_kyc_check_cleanup ()
{
struct KycPoller *kyp;
while (NULL != (kyp = kyp_head))
{
GNUNET_CONTAINER_DLL_remove (kyp_head,
kyp_tail,
kyp);
if (kyp->suspended)
{
kyp->suspended = false;
MHD_resume_connection (kyp->connection);
}
}
}
/**
* Function called once a connection is done to
* clean up the `struct ReservePoller` state.
*
* @param rc context to clean up for
*/
static void
kyp_cleanup (struct TEH_RequestContext *rc)
{
struct KycPoller *kyp = rc->rh_ctx;
GNUNET_assert (! kyp->suspended);
if (NULL != kyp->eh)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Cancelling DB event listening\n");
TEH_plugin->event_listen_cancel (TEH_plugin->cls,
kyp->eh);
kyp->eh = NULL;
}
GNUNET_free (kyp);
}
/** /**
* Function implementing database transaction to check wallet's KYC status. * Function implementing database transaction to check wallet's KYC status.
* Runs the transaction logic; IF it returns a non-error code, the transaction * Runs the transaction logic; IF it returns a non-error code, the transaction
@ -63,7 +154,7 @@ struct KycCheckContext
* returns the soft error code, the function MAY be called again to retry and * returns the soft error code, the function MAY be called again to retry and
* MUST not queue a MHD response. * MUST not queue a MHD response.
* *
* @param cls closure with a `struct KycCheckContext *` * @param cls closure with a `struct KycPoller *`
* @param connection MHD request which triggered the transaction * @param connection MHD request which triggered the transaction
* @param[out] mhd_ret set to MHD response status for @a connection, * @param[out] mhd_ret set to MHD response status for @a connection,
* if transaction failed (!) * if transaction failed (!)
@ -74,13 +165,13 @@ kyc_check (void *cls,
struct MHD_Connection *connection, struct MHD_Connection *connection,
MHD_RESULT *mhd_ret) MHD_RESULT *mhd_ret)
{ {
struct KycCheckContext *kcc = cls; struct KycPoller *kyp = cls;
enum GNUNET_DB_QueryStatus qs; enum GNUNET_DB_QueryStatus qs;
qs = TEH_plugin->select_kyc_status (TEH_plugin->cls, qs = TEH_plugin->select_kyc_status (TEH_plugin->cls,
kcc->payment_target_uuid, kyp->payment_target_uuid,
&kcc->h_payto, &kyp->h_payto,
&kcc->kyc); &kyp->kyc);
if (qs < 0) if (qs < 0)
{ {
if (GNUNET_DB_STATUS_SOFT_ERROR == qs) if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
@ -101,74 +192,89 @@ TEH_handler_kyc_check (
struct TEH_RequestContext *rc, struct TEH_RequestContext *rc,
const char *const args[]) const char *const args[])
{ {
unsigned long long payment_target_uuid; struct KycPoller *kyp = rc->rh_ctx;
MHD_RESULT res; MHD_RESULT res;
enum GNUNET_GenericReturnValue ret; enum GNUNET_GenericReturnValue ret;
char dummy;
struct TALER_PaytoHash h_payto;
if (1 != if (NULL == kyp)
sscanf (args[0],
"%llu%c",
&payment_target_uuid,
&dummy))
{ {
GNUNET_break_op (0); kyp = GNUNET_new (struct KycPoller);
return TALER_MHD_reply_with_error (rc->connection, kyp->connection = rc->connection;
MHD_HTTP_BAD_REQUEST, rc->rh_ctx = kyp;
TALER_EC_GENERIC_PARAMETER_MALFORMED, rc->rh_cleaner = &kyp_cleanup;
"payment_target_uuid");
}
{
const char *ts;
ts = MHD_lookup_connection_value (rc->connection,
MHD_GET_ARGUMENT_KIND,
"timeout_ms");
if (NULL != ts)
{ {
unsigned long long tms; unsigned long long payment_target_uuid;
char dummy;
if (1 != if (1 !=
sscanf (ts, sscanf (args[0],
"%llu%c", "%llu%c",
&tms, &payment_target_uuid,
&dummy)) &dummy))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection, return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST, MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED, TALER_EC_GENERIC_PARAMETER_MALFORMED,
"timeout_ms"); "payment_target_uuid");
} }
/* FIXME: write long polling logic ... */ kyp->payment_target_uuid = (uint64_t) payment_target_uuid;
} }
} {
{ const char *ts;
const char *hps;
hps = MHD_lookup_connection_value (rc->connection, ts = MHD_lookup_connection_value (rc->connection,
MHD_GET_ARGUMENT_KIND, MHD_GET_ARGUMENT_KIND,
"h_payto"); "timeout_ms");
if (NULL == hps) if (NULL != ts)
{ {
GNUNET_break_op (0); char dummy;
return TALER_MHD_reply_with_error (rc->connection, unsigned long long tms;
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MISSING, if (1 !=
"h_payto"); sscanf (ts,
"%llu%c",
&tms,
&dummy))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
"timeout_ms");
}
kyp->timeout = GNUNET_TIME_relative_to_absolute (
GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
tms));
}
} }
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (hps,
strlen (hps),
&h_payto,
sizeof (h_payto)))
{ {
GNUNET_break_op (0); const char *hps;
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST, hps = MHD_lookup_connection_value (rc->connection,
TALER_EC_GENERIC_PARAMETER_MALFORMED, MHD_GET_ARGUMENT_KIND,
"h_payto"); "h_payto");
if (NULL == hps)
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MISSING,
"h_payto");
}
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (hps,
strlen (hps),
&kyp->auth_h_payto,
sizeof (kyp->auth_h_payto)))
{
GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
"h_payto");
}
} }
} }
@ -181,9 +287,6 @@ TEH_handler_kyc_check (
0); 0);
{ {
struct GNUNET_TIME_Absolute now; struct GNUNET_TIME_Absolute now;
struct KycCheckContext kcc = {
.payment_target_uuid = payment_target_uuid
};
now = GNUNET_TIME_absolute_get (); now = GNUNET_TIME_absolute_get ();
(void) GNUNET_TIME_round_abs (&now); (void) GNUNET_TIME_round_abs (&now);
@ -191,12 +294,12 @@ TEH_handler_kyc_check (
"kyc check", "kyc check",
&res, &res,
&kyc_check, &kyc_check,
&kcc); kyp);
if (GNUNET_SYSERR == ret) if (GNUNET_SYSERR == ret)
return res; return res;
if (0 != if (0 !=
GNUNET_memcmp (&kcc.h_payto, GNUNET_memcmp (&kyp->h_payto,
&h_payto)) &kyp->auth_h_payto))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
return TALER_MHD_reply_with_error (rc->connection, return TALER_MHD_reply_with_error (rc->connection,
@ -204,7 +307,7 @@ TEH_handler_kyc_check (
TALER_EC_EXCHANGE_KYC_CHECK_AUTHORIZATION_FAILED, TALER_EC_EXCHANGE_KYC_CHECK_AUTHORIZATION_FAILED,
"h_payto"); "h_payto");
} }
if (! kcc.kyc.ok) if (! kyp->kyc.ok)
{ {
char *url; char *url;
char *redirect_uri; char *redirect_uri;
@ -214,7 +317,7 @@ TEH_handler_kyc_check (
GNUNET_asprintf (&redirect_uri, GNUNET_asprintf (&redirect_uri,
"%s/kyc-proof/%llu", "%s/kyc-proof/%llu",
TEH_base_url, TEH_base_url,
payment_target_uuid); (unsigned long long) kyp->payment_target_uuid);
redirect_uri_encoded = TALER_urlencode (redirect_uri); redirect_uri_encoded = TALER_urlencode (redirect_uri);
GNUNET_free (redirect_uri); GNUNET_free (redirect_uri);
GNUNET_asprintf (&url, GNUNET_asprintf (&url,
@ -239,7 +342,7 @@ TEH_handler_kyc_check (
.purpose.purpose = htonl ( .purpose.purpose = htonl (
TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS), TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS),
.purpose.size = htonl (sizeof (as)), .purpose.size = htonl (sizeof (as)),
.h_payto = kcc.h_payto, .h_payto = kyp->h_payto,
.timestamp = GNUNET_TIME_absolute_hton (now) .timestamp = GNUNET_TIME_absolute_hton (now)
}; };
enum TALER_ErrorCode ec; enum TALER_ErrorCode ec;

View File

@ -39,4 +39,11 @@ TEH_handler_kyc_check (
const char *const args[]); const char *const args[]);
/**
* Clean up long-polling KYC requests during shutdown.
*/
void
TEH_kyc_check_cleanup (void);
#endif #endif