5136: fix multiple invocations of /keys callback.

Basically, we allow such a callback to be invoked only once.
Subsequent invocations (due to keys updates / whatever) cause
the callback to simply return in a do-nothing fashion.

Also: adding a /wire CMD - that uses /keys - after serilized
keys have been loaded.
This commit is contained in:
Marcello Stanisci 2019-01-08 15:59:14 +01:00
parent 00596e245e
commit 93a6bbfc58
No known key found for this signature in database
GPG Key ID: 8D526861953F4C0F
6 changed files with 108 additions and 37 deletions

View File

@ -2,18 +2,21 @@
This file is part of TALER This file is part of TALER
Copyright (C) 2014-2018 GNUnet e.V. Copyright (C) 2014-2018 GNUnet e.V.
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
terms of the GNU General Public License as published by the Free Software under the terms of the GNU General Public License as published
Foundation; either version 3, or (at your option) any later version. by the Free Software Foundation; either version 3, or (at your
option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY TALER is distributed in the hope that it will be useful, but
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR WITHOUT ANY WARRANTY; without even the implied warranty of
A PARTICULAR PURPOSE. See the GNU General Public License for more details. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public
TALER; see the file COPYING. If not, see License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/> <http://www.gnu.org/licenses/>
*/ */
/** /**
* @file exchange-lib/exchange_api_handle.c * @file exchange-lib/exchange_api_handle.c
* @brief Implementation of the "handle" component of the exchange's HTTP API * @brief Implementation of the "handle" component of the exchange's HTTP API
@ -1372,25 +1375,29 @@ TALER_EXCHANGE_serialize_data (struct TALER_EXCHANGE_Handle *exchange)
/** /**
* Initialise a connection to the exchange. Will connect to the * Initialise a connection to the exchange. Will connect to the
* exchange and obtain information about the exchange's master public * exchange and obtain information about the exchange's master
* key and the exchange's auditor. The respective information will * public key and the exchange's auditor.
* be passed to the @a cert_cb once available, and all future * The respective information will be passed to the @a cert_cb
* interactions with the exchange will be checked to be signed * once available, and all future interactions with the exchange
* (where appropriate) by the respective master key. * will be checked to be signed (where appropriate) by the
* respective master key.
* *
* @param ctx the context * @param ctx the context
* @param url HTTP base URL for the exchange * @param url HTTP base URL for the exchange
* @param cert_cb function to call with the exchange's certification information * @param cert_cb function to call with the exchange's
* certification information
* @param cert_cb_cls closure for @a cert_cb * @param cert_cb_cls closure for @a cert_cb
* @param ... list of additional arguments, terminated by #TALER_EXCHANGE_OPTION_END. * @param ... list of additional arguments,
* terminated by #TALER_EXCHANGE_OPTION_END.
* @return the exchange handle; NULL upon error * @return the exchange handle; NULL upon error
*/ */
struct TALER_EXCHANGE_Handle * struct TALER_EXCHANGE_Handle *
TALER_EXCHANGE_connect (struct GNUNET_CURL_Context *ctx, TALER_EXCHANGE_connect
const char *url, (struct GNUNET_CURL_Context *ctx,
TALER_EXCHANGE_CertificationCallback cert_cb, const char *url,
void *cert_cb_cls, TALER_EXCHANGE_CertificationCallback cert_cb,
...) void *cert_cb_cls,
...)
{ {
struct TALER_EXCHANGE_Handle *exchange; struct TALER_EXCHANGE_Handle *exchange;
va_list ap; va_list ap;

View File

@ -213,6 +213,7 @@ handle_wire_finished (void *cls,
enum TALER_ErrorCode ec; enum TALER_ErrorCode ec;
const json_t *j = response; const json_t *j = response;
TALER_LOG_DEBUG ("Checking raw /wire response\n");
wh->job = NULL; wh->job = NULL;
ec = TALER_EC_NONE; ec = TALER_EC_NONE;
switch (response_code) switch (response_code)
@ -411,10 +412,10 @@ TALER_EXCHANGE_wire (struct TALER_EXCHANGE_Handle *exchange,
eh = TEL_curl_easy_get (wh->url); eh = TEL_curl_easy_get (wh->url);
ctx = TEAH_handle_to_context (exchange); ctx = TEAH_handle_to_context (exchange);
wh->job = GNUNET_CURL_job_add (ctx, wh->job = GNUNET_CURL_job_add (ctx,
eh, eh,
GNUNET_YES, GNUNET_YES,
&handle_wire_finished, &handle_wire_finished,
wh); wh);
return wh; return wh;
} }

View File

@ -60,8 +60,9 @@ batch_run (void *cls,
struct BatchState *bs = cls; struct BatchState *bs = cls;
bs->batch_ip++; bs->batch_ip++;
TALER_LOG_DEBUG ("Running batched command: %s\n", if (NULL != bs->batch[bs->batch_ip].label)
bs->batch[bs->batch_ip].label); TALER_LOG_DEBUG ("Running batched command: %s\n",
bs->batch[bs->batch_ip].label);
/* hit end command, leap to next top-level command. */ /* hit end command, leap to next top-level command. */
if (NULL == bs->batch[bs->batch_ip].label) if (NULL == bs->batch[bs->batch_ip].label)

View File

@ -48,6 +48,34 @@ struct SerializeKeysState
}; };
/**
* Internal state for a connect-with-state CMD.
*/
struct ConnectWithStateState
{
/**
* Reference to a CMD that offers a serialized key-state
* that will be used in the reconnection.
*/
const char *state_reference;
/**
* If set to GNUNET_YES, then the /keys callback has already
* been passed the control to the next CMD. This is necessary
* because it is not uncommon that the /keys callback gets
* invoked multiple times, and without this flag, we would keep
* going "next" CMD upon every invocation (causing impredictable
* behaviour as for the instruction pointer.)
*/
unsigned int consumed;
/**
* Interpreter state.
*/
struct TALER_TESTING_Interpreter *is;
};
/** /**
* Run the command. * Run the command.
* *
@ -91,6 +119,7 @@ serialize_keys_cleanup (void *cls,
json_decref (sks->keys); json_decref (sks->keys);
} }
GNUNET_free ((char *) sks->exchange_url);
GNUNET_free (sks); GNUNET_free (sks);
} }
@ -140,15 +169,23 @@ cb (void *cls,
const struct TALER_EXCHANGE_Keys *keys, const struct TALER_EXCHANGE_Keys *keys,
enum TALER_EXCHANGE_VersionCompatibility compat) enum TALER_EXCHANGE_VersionCompatibility compat)
{ {
struct TALER_TESTING_Interpreter *is = cls; struct ConnectWithStateState *cwss = cls;
if (GNUNET_YES == cwss->consumed)
{
TALER_LOG_DEBUG ("Reconnection /keys 'cb' invoked already,"
" nothing to do\n");
return;
}
cwss->consumed = GNUNET_YES;
if (NULL == keys) if (NULL == keys)
TALER_TESTING_interpreter_fail (is); TALER_TESTING_interpreter_fail (cwss->is);
TALER_TESTING_interpreter_next (is); TALER_LOG_DEBUG ("reconnect next CMD\n");
TALER_TESTING_interpreter_next (cwss->is);
} }
/** /**
* Run the command. * Run the command.
* *
@ -161,13 +198,14 @@ connect_with_state_run (void *cls,
const struct TALER_TESTING_Command *cmd, const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is) struct TALER_TESTING_Interpreter *is)
{ {
struct ConnectWithStateState *cwss = cls;
const struct TALER_TESTING_Command *state_cmd; const struct TALER_TESTING_Command *state_cmd;
const json_t *serialized_keys; const json_t *serialized_keys;
const char *state_reference = cls;
const char *exchange_url; const char *exchange_url;
cwss->is = is;
state_cmd = TALER_TESTING_interpreter_lookup_command state_cmd = TALER_TESTING_interpreter_lookup_command
(is, state_reference); (is, cwss->state_reference);
/* Command providing serialized keys not found. */ /* Command providing serialized keys not found. */
if (NULL == state_cmd) if (NULL == state_cmd)
@ -197,7 +235,7 @@ connect_with_state_run (void *cls,
(is->ctx, (is->ctx,
exchange_url, exchange_url,
cb, cb,
is, cwss,
TALER_EXCHANGE_OPTION_DATA, TALER_EXCHANGE_OPTION_DATA,
serialized_keys, serialized_keys,
TALER_EXCHANGE_OPTION_END); TALER_EXCHANGE_OPTION_END);
@ -216,7 +254,9 @@ connect_with_state_cleanup
(void *cls, (void *cls,
const struct TALER_TESTING_Command *cmd) const struct TALER_TESTING_Command *cmd)
{ {
return; struct ConnectWithStateState *cwss = cls;
GNUNET_free (cwss);
} }
/** /**
@ -244,7 +284,6 @@ TALER_TESTING_cmd_serialize_keys (const char *label)
return cmd; return cmd;
} }
/** /**
* Make a connect-with-state CMD. This command * Make a connect-with-state CMD. This command
* will use a serialized key state to reconnect * will use a serialized key state to reconnect
@ -259,8 +298,14 @@ struct TALER_TESTING_Command
TALER_TESTING_cmd_connect_with_state (const char *label, TALER_TESTING_cmd_connect_with_state (const char *label,
const char *state_reference) const char *state_reference)
{ {
struct ConnectWithStateState *cwss;
cwss = GNUNET_new (struct ConnectWithStateState);
cwss->state_reference = state_reference;
cwss->consumed = GNUNET_NO;
struct TALER_TESTING_Command cmd = { struct TALER_TESTING_Command cmd = {
.cls = (char *) state_reference, .cls = cwss,
.label = label, .label = label,
.run = connect_with_state_run, .run = connect_with_state_run,
.cleanup = connect_with_state_cleanup .cleanup = connect_with_state_cleanup

View File

@ -94,6 +94,7 @@ wire_cb (void *cls,
&ws->is->commands[ws->is->ip]; &ws->is->commands[ws->is->ip];
struct TALER_Amount expected_fee; struct TALER_Amount expected_fee;
TALER_LOG_DEBUG ("Checking parsed /wire response\n");
ws->wh = NULL; ws->wh = NULL;
if (ws->expected_response_code != http_status) if (ws->expected_response_code != http_status)
{ {
@ -137,6 +138,8 @@ wire_cb (void *cls,
} }
} }
} }
TALER_LOG_DEBUG ("Freeing method '%s'\n",
method);
GNUNET_free (method); GNUNET_free (method);
} }
if (GNUNET_OK != ws->method_found) if (GNUNET_OK != ws->method_found)
@ -148,6 +151,7 @@ wire_cb (void *cls,
return; return;
} }
} }
TALER_TESTING_interpreter_next (ws->is); TALER_TESTING_interpreter_next (ws->is);
} }

View File

@ -237,6 +237,8 @@ struct TALER_TESTING_Command
TALER_TESTING_cmd_end (void) TALER_TESTING_cmd_end (void)
{ {
static struct TALER_TESTING_Command cmd; static struct TALER_TESTING_Command cmd;
cmd.label = NULL;
return cmd; return cmd;
} }
@ -269,13 +271,18 @@ interpreter_run (void *cls)
if (NULL == cmd->label) if (NULL == cmd->label)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Running command END\n");
is->result = GNUNET_OK; is->result = GNUNET_OK;
GNUNET_SCHEDULER_shutdown (); GNUNET_SCHEDULER_shutdown ();
return; return;
} }
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Running command `%s'\n", "Running command `%s'\n",
cmd->label); cmd->label);
cmd->run (cmd->cls, cmd->run (cmd->cls,
cmd, cmd,
is); is);
@ -293,10 +300,16 @@ do_shutdown (void *cls)
{ {
struct TALER_TESTING_Interpreter *is = cls; struct TALER_TESTING_Interpreter *is = cls;
struct TALER_TESTING_Command *cmd; struct TALER_TESTING_Command *cmd;
const char *label;
label = is->commands[is->ip].label;
if (NULL == label)
label = "END";
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Executing shutdown at `%s'\n", "Executing shutdown at `%s'\n",
is->commands[is->ip].label); label);
for (unsigned int j=0;NULL != (cmd = &is->commands[j])->label;j++) for (unsigned int j=0;NULL != (cmd = &is->commands[j])->label;j++)
cmd->cleanup (cmd->cls, cmd->cleanup (cmd->cls,
cmd); cmd);