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
Copyright (C) 2014-2018 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3, or (at your
option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
TALER is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see
You should have received a copy of the GNU General Public
License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file exchange-lib/exchange_api_handle.c
* @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
* exchange and obtain information about the exchange's master public
* key and the exchange's auditor. The respective information will
* be passed to the @a cert_cb once available, and all future
* interactions with the exchange will be checked to be signed
* (where appropriate) by the respective master key.
* exchange and obtain information about the exchange's master
* public key and the exchange's auditor.
* The respective information will be passed to the @a cert_cb
* once available, and all future interactions with the exchange
* will be checked to be signed (where appropriate) by the
* respective master key.
*
* @param ctx the context
* @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 ... 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
*/
struct TALER_EXCHANGE_Handle *
TALER_EXCHANGE_connect (struct GNUNET_CURL_Context *ctx,
const char *url,
TALER_EXCHANGE_CertificationCallback cert_cb,
void *cert_cb_cls,
...)
TALER_EXCHANGE_connect
(struct GNUNET_CURL_Context *ctx,
const char *url,
TALER_EXCHANGE_CertificationCallback cert_cb,
void *cert_cb_cls,
...)
{
struct TALER_EXCHANGE_Handle *exchange;
va_list ap;

View File

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

View File

@ -60,8 +60,9 @@ batch_run (void *cls,
struct BatchState *bs = cls;
bs->batch_ip++;
TALER_LOG_DEBUG ("Running batched command: %s\n",
bs->batch[bs->batch_ip].label);
if (NULL != 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. */
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.
*
@ -91,6 +119,7 @@ serialize_keys_cleanup (void *cls,
json_decref (sks->keys);
}
GNUNET_free ((char *) sks->exchange_url);
GNUNET_free (sks);
}
@ -140,15 +169,23 @@ cb (void *cls,
const struct TALER_EXCHANGE_Keys *keys,
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)
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.
*
@ -161,13 +198,14 @@ connect_with_state_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
{
struct ConnectWithStateState *cwss = cls;
const struct TALER_TESTING_Command *state_cmd;
const json_t *serialized_keys;
const char *state_reference = cls;
const char *exchange_url;
cwss->is = is;
state_cmd = TALER_TESTING_interpreter_lookup_command
(is, state_reference);
(is, cwss->state_reference);
/* Command providing serialized keys not found. */
if (NULL == state_cmd)
@ -197,7 +235,7 @@ connect_with_state_run (void *cls,
(is->ctx,
exchange_url,
cb,
is,
cwss,
TALER_EXCHANGE_OPTION_DATA,
serialized_keys,
TALER_EXCHANGE_OPTION_END);
@ -216,7 +254,9 @@ connect_with_state_cleanup
(void *cls,
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;
}
/**
* Make a connect-with-state CMD. This command
* 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,
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 = {
.cls = (char *) state_reference,
.cls = cwss,
.label = label,
.run = connect_with_state_run,
.cleanup = connect_with_state_cleanup

View File

@ -94,6 +94,7 @@ wire_cb (void *cls,
&ws->is->commands[ws->is->ip];
struct TALER_Amount expected_fee;
TALER_LOG_DEBUG ("Checking parsed /wire response\n");
ws->wh = NULL;
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);
}
if (GNUNET_OK != ws->method_found)
@ -148,6 +151,7 @@ wire_cb (void *cls,
return;
}
}
TALER_TESTING_interpreter_next (ws->is);
}

View File

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