From d6838ed841185c7850c3f52d91d1baa9a1f90a7e Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 20 Jun 2023 21:57:13 +0200 Subject: -doxygen fixes --- src/include/taler_testing_lib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/include/taler_testing_lib.h') diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h index 28213d1d..175d25e6 100644 --- a/src/include/taler_testing_lib.h +++ b/src/include/taler_testing_lib.h @@ -514,7 +514,7 @@ typedef void * Iterates over all of the top-level commands of an * interpreter. * - * @param[in] interpreter to iterate over + * @param[in] is interpreter to iterate over * @param asc true in execution order, false for reverse execution order * @param cb function to call on each command * @param cb_cls closure for cb -- cgit v1.2.3 From f5ce22ddf6da6aae6a9077dba122013c1dbc55d9 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 21 Jun 2023 09:00:58 +0200 Subject: -more clean up of auditor api: atomization complete --- src/include/taler_auditor_service.h | 55 ++-- src/include/taler_testing_lib.h | 1 - src/lib/Makefile.am | 2 +- src/lib/auditor_api_deposit_confirmation.c | 3 +- src/lib/auditor_api_exchanges.c | 3 +- src/lib/auditor_api_get_config.c | 288 +++++++++++++++++++ src/lib/auditor_api_handle.c | 438 ----------------------------- src/lib/auditor_api_handle.h | 59 ---- src/lib/exchange_api_handle.c | 23 +- src/testing/test_auditor_api_version.c | 19 +- src/testing/testing_api_cmd_get_auditor.c | 27 +- 11 files changed, 363 insertions(+), 555 deletions(-) create mode 100644 src/lib/auditor_api_get_config.c delete mode 100644 src/lib/auditor_api_handle.c delete mode 100644 src/lib/auditor_api_handle.h (limited to 'src/include/taler_testing_lib.h') diff --git a/src/include/taler_auditor_service.h b/src/include/taler_auditor_service.h index 2c6685c1..3d8ca9ef 100644 --- a/src/include/taler_auditor_service.h +++ b/src/include/taler_auditor_service.h @@ -28,12 +28,12 @@ #include -/* ********************* /version *********************** */ +/* ********************* /config *********************** */ /** - * @brief Information we get from the auditor about auditors. + * @brief Information we get from the auditor about itself. */ -struct TALER_AUDITOR_VersionInformation +struct TALER_AUDITOR_ConfigInformation { /** * Public key of the auditing institution. Wallets and merchants @@ -147,9 +147,9 @@ struct TALER_AUDITOR_HttpResponse /** - * Response to /version request. + * Response to /config request. */ -struct TALER_AUDITOR_VersionResponse +struct TALER_AUDITOR_ConfigResponse { /** * HTTP response. @@ -174,11 +174,12 @@ struct TALER_AUDITOR_VersionResponse enum TALER_AUDITOR_VersionCompatibility compat; /** - * Version data returned by /config. + * Config data returned by /config. */ - struct TALER_AUDITOR_VersionInformation vi; + struct TALER_AUDITOR_ConfigInformation vi; } ok; + } details; }; @@ -191,46 +192,45 @@ struct TALER_AUDITOR_VersionResponse * @param vr response data */ typedef void -(*TALER_AUDITOR_VersionCallback) ( +(*TALER_AUDITOR_ConfigCallback) ( void *cls, - const struct TALER_AUDITOR_VersionResponse *vr); + const struct TALER_AUDITOR_ConfigResponse *vr); /** * @brief Handle to the auditor. This is where we interact with * a particular auditor and keep the per-auditor information. */ -struct TALER_AUDITOR_Handle; +struct TALER_AUDITOR_GetConfigHandle; /** - * Initialise a connection to the auditor. Will connect to the + * Obtain meta data about an auditor. Will connect to the * auditor and obtain information about the auditor's master public * key and the auditor's auditor. The respective information will - * be passed to the @a version_cb once available, and all future - * interactions with the auditor will be checked to be signed - * (where appropriate) by the respective master key. + * be passed to the @a config_cb once available. * * @param ctx the context for CURL requests * @param url HTTP base URL for the auditor - * @param version_cb function to call with the auditor's version information - * @param version_cb_cls closure for @a version_cb + * @param config_cb function to call with the auditor's config information + * @param config_cb_cls closure for @a config_cb * @return the auditor handle; NULL upon error */ -struct TALER_AUDITOR_Handle * -TALER_AUDITOR_connect (struct GNUNET_CURL_Context *ctx, - const char *url, - TALER_AUDITOR_VersionCallback version_cb, - void *version_cb_cls); +struct TALER_AUDITOR_GetConfigHandle * +TALER_AUDITOR_get_config (struct GNUNET_CURL_Context *ctx, + const char *url, + TALER_AUDITOR_ConfigCallback config_cb, + void *config_cb_cls); /** - * Disconnect from the auditor. + * Cancel auditor config request. * * @param auditor the auditor handle */ void -TALER_AUDITOR_disconnect (struct TALER_AUDITOR_Handle *auditor); +TALER_AUDITOR_get_config_cancel (struct + TALER_AUDITOR_GetConfigHandle *auditor); /** @@ -271,11 +271,10 @@ typedef void * that the response is well-formed. If the auditor's reply is not * well-formed, we return an HTTP status code of zero to @a cb. * - * We also verify that the @a exchange_sig is valid for this deposit-confirmation - * request, and that the @a master_sig is a valid signature for @a - * exchange_pub. Also, the @a auditor must be ready to operate (i.e. have - * finished processing the /version reply). If either check fails, we do - * NOT initiate the transaction with the auditor and instead return NULL. + * We also verify that the @a exchange_sig is valid for this + * deposit-confirmation request, and that the @a master_sig is a valid + * signature for @a exchange_pub. If the check fails, we do NOT initiate the + * transaction with the auditor and instead return NULL. * * @param ctx the context for CURL requests * @param url HTTP base URL for the auditor diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h index 175d25e6..2c9f5859 100644 --- a/src/include/taler_testing_lib.h +++ b/src/include/taler_testing_lib.h @@ -2692,7 +2692,6 @@ TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits, op (fresh_coins, const struct TALER_TESTING_FreshCoinData *) \ op (claim_token, const struct TALER_ClaimTokenP) \ op (relative_time, const struct GNUNET_TIME_Relative) \ - op (auditor, struct TALER_AUDITOR_Handle) \ op (exchange, struct TALER_EXCHANGE_Handle) \ op (fakebank, struct TALER_FAKEBANK_Handle) \ op (process, struct GNUNET_OS_Process *) diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 529a2d01..2c903142 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -96,7 +96,7 @@ libtalerauditor_la_LDFLAGS = \ -no-undefined libtalerauditor_la_SOURCES = \ auditor_api_curl_defaults.c auditor_api_curl_defaults.h \ - auditor_api_handle.c auditor_api_handle.h \ + auditor_api_get_config.c \ auditor_api_deposit_confirmation.c \ auditor_api_exchanges.c libtalerauditor_la_LIBADD = \ diff --git a/src/lib/auditor_api_deposit_confirmation.c b/src/lib/auditor_api_deposit_confirmation.c index 21479c10..0b0f4dd4 100644 --- a/src/lib/auditor_api_deposit_confirmation.c +++ b/src/lib/auditor_api_deposit_confirmation.c @@ -25,9 +25,10 @@ #include #include #include +#include "taler_util.h" +#include "taler_curl_lib.h" #include "taler_json_lib.h" #include "taler_auditor_service.h" -#include "auditor_api_handle.h" #include "taler_signatures.h" #include "auditor_api_curl_defaults.h" diff --git a/src/lib/auditor_api_exchanges.c b/src/lib/auditor_api_exchanges.c index 8acf5946..897dfe60 100644 --- a/src/lib/auditor_api_exchanges.c +++ b/src/lib/auditor_api_exchanges.c @@ -27,7 +27,8 @@ #include #include "taler_json_lib.h" #include "taler_auditor_service.h" -#include "auditor_api_handle.h" +#include "taler_util.h" +#include "taler_curl_lib.h" #include "taler_signatures.h" #include "auditor_api_curl_defaults.h" diff --git a/src/lib/auditor_api_get_config.c b/src/lib/auditor_api_get_config.c new file mode 100644 index 00000000..ede702a0 --- /dev/null +++ b/src/lib/auditor_api_get_config.c @@ -0,0 +1,288 @@ +/* + This file is part of TALER + Copyright (C) 2014-2023 Taler Systems SA + + 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. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see + +*/ +/** + * @file lib/auditor_api_get_config.c + * @brief Implementation of /config for the auditor's HTTP API + * @author Sree Harsha Totakura + * @author Christian Grothoff + */ +#include "platform.h" +#include +#include +#include "taler_json_lib.h" +#include "taler_auditor_service.h" +#include "taler_signatures.h" +#include "auditor_api_curl_defaults.h" + + +/** + * Which revision of the Taler auditor protocol is implemented + * by this library? Used to determine compatibility. + */ +#define TALER_PROTOCOL_CURRENT 0 + +/** + * How many revisions back are we compatible to? + */ +#define TALER_PROTOCOL_AGE 0 + + +/** + * Log error related to CURL operations. + * + * @param type log level + * @param function which function failed to run + * @param code what was the curl error code + */ +#define CURL_STRERROR(type, function, code) \ + GNUNET_log (type, "Curl function `%s' has failed at `%s:%d' with error: %s", \ + function, __FILE__, __LINE__, curl_easy_strerror (code)); + + +/** + * Handle for the get config request. + */ +struct TALER_AUDITOR_GetConfigHandle +{ + /** + * The context of this handle + */ + struct GNUNET_CURL_Context *ctx; + + /** + * Function to call with the auditor's certification data, + * NULL if this has already been done. + */ + TALER_AUDITOR_ConfigCallback config_cb; + + /** + * Closure to pass to @e config_cb. + */ + void *config_cb_cls; + + /** + * Data for the request to get the /config of a auditor, + * NULL once we are past stage #MHS_INIT. + */ + struct GNUNET_CURL_Job *vr; + + /** + * The url for the @e vr job. + */ + char *vr_url; + +}; + + +/* ***************** Internal /config fetching ************* */ + +/** + * Decode the JSON in @a resp_obj from the /config response and store the data + * in the @a key_data. + * + * @param[in] resp_obj JSON object to parse + * @param[in,out] auditor where to store the results we decoded + * @param[out] vc where to store config compatibility data + * @return #TALER_EC_NONE on success + */ +static enum TALER_ErrorCode +decode_config_json (const json_t *resp_obj, + struct TALER_AUDITOR_ConfigInformation *vi, + enum TALER_AUDITOR_VersionCompatibility *vc) +{ + unsigned int age; + unsigned int revision; + unsigned int current; + char dummy; + const char *ver; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ("version", + &ver), + GNUNET_JSON_spec_fixed_auto ("auditor_public_key", + &vi->auditor_pub), + GNUNET_JSON_spec_end () + }; + + if (JSON_OBJECT != json_typeof (resp_obj)) + { + GNUNET_break_op (0); + return TALER_EC_GENERIC_JSON_INVALID; + } + /* check the config */ + if (GNUNET_OK != + GNUNET_JSON_parse (resp_obj, + spec, + NULL, NULL)) + { + GNUNET_break_op (0); + return TALER_EC_GENERIC_JSON_INVALID; + } + if (3 != sscanf (ver, + "%u:%u:%u%c", + ¤t, + &revision, + &age, + &dummy)) + { + GNUNET_break_op (0); + return TALER_EC_GENERIC_VERSION_MALFORMED; + } + vi->version = ver; + *vc = TALER_AUDITOR_VC_MATCH; + if (TALER_PROTOCOL_CURRENT < current) + { + *vc |= TALER_AUDITOR_VC_NEWER; + if (TALER_PROTOCOL_CURRENT < current - age) + *vc |= TALER_AUDITOR_VC_INCOMPATIBLE; + } + if (TALER_PROTOCOL_CURRENT > current) + { + *vc |= TALER_AUDITOR_VC_OLDER; + if (TALER_PROTOCOL_CURRENT - TALER_PROTOCOL_AGE > current) + *vc |= TALER_AUDITOR_VC_INCOMPATIBLE; + } + return TALER_EC_NONE; +} + + +/** + * Callback used when downloading the reply to a /config request + * is complete. + * + * @param cls the `struct TALER_AUDITOR_GetConfigHandle` + * @param response_code HTTP response code, 0 on error + * @param gresp_obj parsed JSON result, NULL on error, must be a `const json_t *` + */ +static void +config_completed_cb (void *cls, + long response_code, + const void *gresp_obj) +{ + struct TALER_AUDITOR_GetConfigHandle *auditor = cls; + const json_t *resp_obj = gresp_obj; + struct TALER_AUDITOR_ConfigResponse vr = { + .hr.reply = resp_obj, + .hr.http_status = (unsigned int) response_code + }; + + auditor->vr = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received config from URL `%s' with status %ld.\n", + auditor->vr_url, + response_code); + switch (response_code) + { + case 0: + GNUNET_break_op (0); + vr.hr.ec = TALER_EC_INVALID; + break; + case MHD_HTTP_OK: + if (NULL == resp_obj) + { + GNUNET_break_op (0); + vr.hr.http_status = 0; + vr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + break; + } + vr.hr.ec = decode_config_json (resp_obj, + &vr.details.ok.vi, + &vr.details.ok.compat); + if (TALER_EC_NONE != vr.hr.ec) + { + GNUNET_break_op (0); + vr.hr.http_status = 0; + break; + } + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + vr.hr.ec = TALER_JSON_get_error_code (resp_obj); + vr.hr.hint = TALER_JSON_get_error_hint (resp_obj); + break; + default: + vr.hr.ec = TALER_JSON_get_error_code (resp_obj); + vr.hr.hint = TALER_JSON_get_error_hint (resp_obj); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u/%d\n", + (unsigned int) response_code, + (int) vr.hr.ec); + break; + } + auditor->config_cb (auditor->config_cb_cls, + &vr); + TALER_AUDITOR_get_config_cancel (auditor); +} + + +struct TALER_AUDITOR_GetConfigHandle * +TALER_AUDITOR_get_config (struct GNUNET_CURL_Context *ctx, + const char *url, + TALER_AUDITOR_ConfigCallback config_cb, + void *config_cb_cls) +{ + struct TALER_AUDITOR_GetConfigHandle *auditor; + CURL *eh; + + auditor = GNUNET_new (struct TALER_AUDITOR_GetConfigHandle); + auditor->config_cb = config_cb; + auditor->config_cb_cls = config_cb_cls; + auditor->ctx = ctx; + auditor->vr_url = TALER_url_join (url, + "config", + NULL); + if (NULL == auditor->vr_url) + { + GNUNET_break (0); + GNUNET_free (auditor->vr_url); + GNUNET_free (auditor); + return NULL; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Requesting auditor config with URL `%s'.\n", + auditor->vr_url); + eh = TALER_AUDITOR_curl_easy_get_ (auditor->vr_url); + if (NULL == eh) + { + GNUNET_break (0); + TALER_AUDITOR_get_config_cancel (auditor); + return NULL; + } + GNUNET_break (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_TIMEOUT, + (long) 300)); + auditor->vr = GNUNET_CURL_job_add (auditor->ctx, + eh, + &config_completed_cb, + auditor); + return auditor; +} + + +void +TALER_AUDITOR_get_config_cancel (struct TALER_AUDITOR_GetConfigHandle *auditor) +{ + if (NULL != auditor->vr) + { + GNUNET_CURL_job_cancel (auditor->vr); + auditor->vr = NULL; + } + GNUNET_free (auditor->vr_url); + GNUNET_free (auditor); +} + + +/* end of auditor_api_get_config.c */ diff --git a/src/lib/auditor_api_handle.c b/src/lib/auditor_api_handle.c deleted file mode 100644 index 318b63f9..00000000 --- a/src/lib/auditor_api_handle.c +++ /dev/null @@ -1,438 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2022 Taler Systems SA - - 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. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/auditor_api_handle.c - * @brief Implementation of the "handle" component of the auditor's HTTP API - * @author Sree Harsha Totakura - * @author Christian Grothoff - */ -#include "platform.h" -#include -#include -#include "taler_json_lib.h" -#include "taler_auditor_service.h" -#include "taler_signatures.h" -#include "auditor_api_handle.h" -#include "auditor_api_curl_defaults.h" -#include "backoff.h" - -/** - * Which revision of the Taler auditor protocol is implemented - * by this library? Used to determine compatibility. - */ -#define TALER_PROTOCOL_CURRENT 0 - -/** - * How many revisions back are we compatible to? - */ -#define TALER_PROTOCOL_AGE 0 - - -/** - * Log error related to CURL operations. - * - * @param type log level - * @param function which function failed to run - * @param code what was the curl error code - */ -#define CURL_STRERROR(type, function, code) \ - GNUNET_log (type, "Curl function `%s' has failed at `%s:%d' with error: %s", \ - function, __FILE__, __LINE__, curl_easy_strerror (code)); - -/** - * Stages of initialization for the `struct TALER_AUDITOR_Handle` - */ -enum AuditorHandleState -{ - /** - * Just allocated. - */ - MHS_INIT = 0, - - /** - * Obtained the auditor's versioning data and version. - */ - MHS_VERSION = 1, - - /** - * Failed to initialize (fatal). - */ - MHS_FAILED = 2 -}; - - -/** - * Handle to the auditor - */ -struct TALER_AUDITOR_Handle -{ - /** - * The context of this handle - */ - struct GNUNET_CURL_Context *ctx; - - /** - * The URL of the auditor (i.e. "http://auditor.taler.net/") - */ - char *url; - - /** - * Function to call with the auditor's certification data, - * NULL if this has already been done. - */ - TALER_AUDITOR_VersionCallback version_cb; - - /** - * Closure to pass to @e version_cb. - */ - void *version_cb_cls; - - /** - * Data for the request to get the /config of a auditor, - * NULL once we are past stage #MHS_INIT. - */ - struct GNUNET_CURL_Job *vr; - - /** - * The url for the @e vr job. - */ - char *vr_url; - - /** - * Task for retrying /config request. - */ - struct GNUNET_SCHEDULER_Task *retry_task; - - /** - * /config data of the auditor, only valid if - * @e handshake_complete is past stage #MHS_VERSION. - */ - char *version; - - /** - * Version information for the callback. - */ - struct TALER_AUDITOR_VersionInformation vi; - - /** - * Retry /config frequency. - */ - struct GNUNET_TIME_Relative retry_delay; - - /** - * Stage of the auditor's initialization routines. - */ - enum AuditorHandleState state; - -}; - - -/* ***************** Internal /config fetching ************* */ - -/** - * Decode the JSON in @a resp_obj from the /config response and store the data - * in the @a key_data. - * - * @param[in] resp_obj JSON object to parse - * @param[in,out] auditor where to store the results we decoded - * @param[out] vc where to store version compatibility data - * @return #TALER_EC_NONE on success - */ -static enum TALER_ErrorCode -decode_version_json (const json_t *resp_obj, - struct TALER_AUDITOR_Handle *auditor, - enum TALER_AUDITOR_VersionCompatibility *vc) -{ - struct TALER_AUDITOR_VersionInformation *vi = &auditor->vi; - unsigned int age; - unsigned int revision; - unsigned int current; - char dummy; - const char *ver; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_string ("version", - &ver), - GNUNET_JSON_spec_fixed_auto ("auditor_public_key", - &vi->auditor_pub), - GNUNET_JSON_spec_end () - }; - - if (JSON_OBJECT != json_typeof (resp_obj)) - { - GNUNET_break_op (0); - return TALER_EC_GENERIC_JSON_INVALID; - } - /* check the version */ - if (GNUNET_OK != - GNUNET_JSON_parse (resp_obj, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return TALER_EC_GENERIC_JSON_INVALID; - } - if (3 != sscanf (ver, - "%u:%u:%u%c", - ¤t, - &revision, - &age, - &dummy)) - { - GNUNET_break_op (0); - return TALER_EC_GENERIC_VERSION_MALFORMED; - } - GNUNET_free (auditor->version); - auditor->version = GNUNET_strdup (ver); - vi->version = auditor->version; - *vc = TALER_AUDITOR_VC_MATCH; - if (TALER_PROTOCOL_CURRENT < current) - { - *vc |= TALER_AUDITOR_VC_NEWER; - if (TALER_PROTOCOL_CURRENT < current - age) - *vc |= TALER_AUDITOR_VC_INCOMPATIBLE; - } - if (TALER_PROTOCOL_CURRENT > current) - { - *vc |= TALER_AUDITOR_VC_OLDER; - if (TALER_PROTOCOL_CURRENT - TALER_PROTOCOL_AGE > current) - *vc |= TALER_AUDITOR_VC_INCOMPATIBLE; - } - return TALER_EC_NONE; -} - - -/** - * Initiate download of /config from the auditor. - * - * @param cls auditor where to download /config from - */ -static void -request_version (void *cls); - - -/** - * Callback used when downloading the reply to a /config request - * is complete. - * - * @param cls the `struct TALER_AUDITOR_Handle` - * @param response_code HTTP response code, 0 on error - * @param gresp_obj parsed JSON result, NULL on error, must be a `const json_t *` - */ -static void -version_completed_cb (void *cls, - long response_code, - const void *gresp_obj) -{ - struct TALER_AUDITOR_Handle *auditor = cls; - const json_t *resp_obj = gresp_obj; - struct TALER_AUDITOR_VersionResponse vr = { - .hr.reply = resp_obj, - .hr.http_status = (unsigned int) response_code - }; - - auditor->vr = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Received version from URL `%s' with status %ld.\n", - auditor->url, - response_code); - switch (response_code) - { - case 0: - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* NOTE: this design is debatable. We MAY want to throw this error at the - client. We may then still additionally internally re-try. */ - GNUNET_assert (NULL == auditor->retry_task); - auditor->retry_delay = EXCHANGE_LIB_BACKOFF (auditor->retry_delay); - auditor->retry_task = GNUNET_SCHEDULER_add_delayed (auditor->retry_delay, - &request_version, - auditor); - return; - case MHD_HTTP_OK: - if (NULL == resp_obj) - { - GNUNET_break_op (0); - TALER_LOG_WARNING ("NULL body for a 200-OK /config\n"); - vr.hr.http_status = 0; - vr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - break; - } - vr.hr.ec = decode_version_json (resp_obj, - auditor, - &vr.details.ok.compat); - if (TALER_EC_NONE != vr.hr.ec) - { - GNUNET_break_op (0); - vr.hr.http_status = 0; - break; - } - auditor->state = MHS_VERSION; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Auditor %s is ready!\n", - auditor->url); - vr.details.ok.vi = auditor->vi; - auditor->retry_delay = GNUNET_TIME_UNIT_ZERO; /* restart quickly */ - break; - default: - vr.hr.ec = TALER_JSON_get_error_code (resp_obj); - vr.hr.hint = TALER_JSON_get_error_hint (resp_obj); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d\n", - (unsigned int) response_code, - (int) vr.hr.ec); - break; - } - if (MHD_HTTP_OK != response_code) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "/config failed for auditor %s: %u!\n", - auditor->url, - (unsigned int) response_code); - auditor->state = MHS_FAILED; - } - auditor->version_cb (auditor->version_cb_cls, - &vr); -} - - -/** - * Initiate download of /config from the auditor. - * - * @param cls auditor where to download /config from - */ -static void -request_version (void *cls) -{ - struct TALER_AUDITOR_Handle *auditor = cls; - CURL *eh; - - auditor->retry_task = NULL; - GNUNET_assert (NULL == auditor->vr); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Requesting auditor version with URL `%s'.\n", - auditor->vr_url); - eh = TALER_AUDITOR_curl_easy_get_ (auditor->vr_url); - if (NULL == eh) - { - GNUNET_break (0); - auditor->retry_delay = EXCHANGE_LIB_BACKOFF (auditor->retry_delay); - auditor->retry_task = GNUNET_SCHEDULER_add_delayed (auditor->retry_delay, - &request_version, - auditor); - return; - } - GNUNET_break (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_TIMEOUT, - (long) 300)); - auditor->vr = GNUNET_CURL_job_add (auditor->ctx, - eh, - &version_completed_cb, - auditor); -} - - -/* ********************* library internal API ********* */ - - -struct GNUNET_CURL_Context * -TALER_AUDITOR_handle_to_context_ (struct TALER_AUDITOR_Handle *h) -{ - return h->ctx; -} - - -enum GNUNET_GenericReturnValue -TALER_AUDITOR_handle_is_ready_ (struct TALER_AUDITOR_Handle *h) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Checking if auditor at `%s` is now ready: %s\n", - h->url, - (MHD_VERSION == h->state) ? "yes" : "no"); - return (MHS_VERSION == h->state) ? GNUNET_YES : GNUNET_NO; -} - - -char * -TALER_AUDITOR_path_to_url_ (struct TALER_AUDITOR_Handle *h, - const char *path) -{ - GNUNET_assert ('/' == path[0]); - return TALER_url_join (h->url, - path + 1, - NULL); -} - - -/* ********************* public API ******************* */ - - -struct TALER_AUDITOR_Handle * -TALER_AUDITOR_connect (struct GNUNET_CURL_Context *ctx, - const char *url, - TALER_AUDITOR_VersionCallback version_cb, - void *version_cb_cls) -{ - struct TALER_AUDITOR_Handle *auditor; - - auditor = GNUNET_new (struct TALER_AUDITOR_Handle); - auditor->version_cb = version_cb; - auditor->version_cb_cls = version_cb_cls; - auditor->retry_delay = GNUNET_TIME_UNIT_SECONDS; /* start slowly */ - auditor->ctx = ctx; - auditor->url = GNUNET_strdup (url); - auditor->vr_url = TALER_AUDITOR_path_to_url_ (auditor, - "/config"); - if (NULL == auditor->vr_url) - { - GNUNET_break (0); - GNUNET_free (auditor->url); - GNUNET_free (auditor); - return NULL; - } - auditor->retry_task = GNUNET_SCHEDULER_add_now (&request_version, - auditor); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Connecting to auditor at URL `%s'.\n", - url); - return auditor; -} - - -void -TALER_AUDITOR_disconnect (struct TALER_AUDITOR_Handle *auditor) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Disconnecting from auditor at URL `%s'.\n", - auditor->url); - if (NULL != auditor->vr) - { - GNUNET_CURL_job_cancel (auditor->vr); - auditor->vr = NULL; - } - if (NULL != auditor->retry_task) - { - GNUNET_SCHEDULER_cancel (auditor->retry_task); - auditor->retry_task = NULL; - } - GNUNET_free (auditor->version); - GNUNET_free (auditor->vr_url); - GNUNET_free (auditor->url); - GNUNET_free (auditor); -} - - -/* end of auditor_api_handle.c */ diff --git a/src/lib/auditor_api_handle.h b/src/lib/auditor_api_handle.h deleted file mode 100644 index 7ff5bfcd..00000000 --- a/src/lib/auditor_api_handle.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 Taler Systems SA - - 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. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/auditor_api_handle.h - * @brief Internal interface to the handle part of the auditor's HTTP API - * @author Christian Grothoff - */ -#include "platform.h" -#include -#include "taler_auditor_service.h" -#include "taler_curl_lib.h" - -/** - * Get the context of a auditor. - * - * @param h the auditor handle to query - * @return ctx context to execute jobs in - */ -struct GNUNET_CURL_Context * -TALER_AUDITOR_handle_to_context_ (struct TALER_AUDITOR_Handle *h); - - -/** - * Check if the handle is ready to process requests. - * - * @param h the auditor handle to query - * @return #GNUNET_YES if we are ready, #GNUNET_NO if not - */ -int -TALER_AUDITOR_handle_is_ready_ (struct TALER_AUDITOR_Handle *h); - - -/** - * Obtain the URL to use for an API request. - * - * @param h the auditor handle to query - * @param path Taler API path (i.e. "/deposit-confirmation") - * @return the full URL to use with cURL - */ -char * -TALER_AUDITOR_path_to_url_ (struct TALER_AUDITOR_Handle *h, - const char *path); - - -/* end of auditor_api_handle.h */ diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c index 0d9bf041..4d245b07 100644 --- a/src/lib/exchange_api_handle.c +++ b/src/lib/exchange_api_handle.c @@ -110,7 +110,7 @@ struct TEAH_AuditorListEntry /** * Handle to the auditor. */ - struct TALER_AUDITOR_Handle *ah; + struct TALER_AUDITOR_GetConfigHandle *ah; /** * Head of DLL of interactions with this auditor. @@ -583,13 +583,14 @@ parse_global_fee (struct TALER_EXCHANGE_GlobalFee *gf, * @param vr response from the auditor */ static void -auditor_version_cb ( +auditor_config_cb ( void *cls, - const struct TALER_AUDITOR_VersionResponse *vr) + const struct TALER_AUDITOR_ConfigResponse *vr) { struct TEAH_AuditorListEntry *ale = cls; enum TALER_AUDITOR_VersionCompatibility compat; + ale->ah = NULL; if (MHD_HTTP_OK != vr->hr.http_status) { /* In this case, we don't mark the auditor as 'up' */ @@ -664,10 +665,10 @@ update_auditors (struct TALER_EXCHANGE_Handle *exchange) GNUNET_CONTAINER_DLL_insert (exchange->auditors_head, exchange->auditors_tail, ale); - ale->ah = TALER_AUDITOR_connect (exchange->ctx, - ale->auditor_url, - &auditor_version_cb, - ale); + ale->ah = TALER_AUDITOR_get_config (exchange->ctx, + ale->auditor_url, + &auditor_config_cb, + ale); } } @@ -2137,9 +2138,11 @@ TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange) GNUNET_CONTAINER_DLL_remove (exchange->auditors_head, exchange->auditors_tail, ale); - TALER_LOG_DEBUG ("Disconnecting the auditor `%s'\n", - ale->auditor_url); - TALER_AUDITOR_disconnect (ale->ah); + if (NULL != ale->ah) + { + TALER_AUDITOR_get_config_cancel (ale->ah); + ale->ah = NULL; + } GNUNET_free (ale->auditor_url); GNUNET_free (ale); } diff --git a/src/testing/test_auditor_api_version.c b/src/testing/test_auditor_api_version.c index 1b4f2b17..dcd542ad 100644 --- a/src/testing/test_auditor_api_version.c +++ b/src/testing/test_auditor_api_version.c @@ -41,7 +41,7 @@ */ #define CONFIG_FILE "test_auditor_api-rsa.conf" -static struct TALER_AUDITOR_Handle *ah; +static struct TALER_AUDITOR_GetConfigHandle *ah; static struct GNUNET_CURL_Context *ctx; @@ -62,7 +62,11 @@ do_shutdown (void *cls) GNUNET_SCHEDULER_cancel (tt); tt = NULL; } - TALER_AUDITOR_disconnect (ah); + if (NULL != ah) + { + TALER_AUDITOR_get_config_cancel (ah); + ah = NULL; + } GNUNET_CURL_fini (ctx); GNUNET_CURL_gnunet_rc_destroy (rc); } @@ -86,9 +90,10 @@ do_timeout (void *cls) */ static void version_cb (void *cls, - const struct TALER_AUDITOR_VersionResponse *vr) + const struct TALER_AUDITOR_ConfigResponse *vr) { (void) cls; + ah = NULL; if ( (MHD_HTTP_OK == vr->hr.http_status) && (TALER_AUDITOR_VC_MATCH == vr->details.ok.compat) ) global_ret = 0; @@ -113,10 +118,10 @@ run (void *cls) ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, &rc); rc = GNUNET_CURL_gnunet_rc_create (ctx); - ah = TALER_AUDITOR_connect (ctx, - auditor_url, - &version_cb, - NULL); + ah = TALER_AUDITOR_get_config (ctx, + auditor_url, + &version_cb, + NULL); GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, diff --git a/src/testing/testing_api_cmd_get_auditor.c b/src/testing/testing_api_cmd_get_auditor.c index 2e9961c3..e1ae8ba5 100644 --- a/src/testing/testing_api_cmd_get_auditor.c +++ b/src/testing/testing_api_cmd_get_auditor.c @@ -49,9 +49,9 @@ struct GetAuditorState struct TALER_TESTING_Interpreter *is; /** - * Auditor handle we produced. + * Auditor handle used to get the configuration. */ - struct TALER_AUDITOR_Handle *auditor; + struct TALER_AUDITOR_GetConfigHandle *auditor; /** * URL of the auditor. @@ -75,16 +75,25 @@ struct GetAuditorState static void version_cb ( void *cls, - const struct TALER_AUDITOR_VersionResponse *vr) + const struct TALER_AUDITOR_ConfigResponse *vr) { struct GetAuditorState *gas = cls; + gas->auditor = NULL; if (MHD_HTTP_OK != vr->hr.http_status) { TALER_TESTING_unexpected_status (gas->is, vr->hr.http_status); return; } + if ( (NULL != gas->priv_file) && + (0 != GNUNET_memcmp (&gas->auditor_pub, + &vr->details.ok.vi.auditor_pub)) ) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (gas->is); + return; + } TALER_TESTING_interpreter_next (gas->is); } @@ -126,10 +135,10 @@ get_auditor_run (void *cls, } gas->is = is; gas->auditor - = TALER_AUDITOR_connect (TALER_TESTING_interpreter_get_context (is), - gas->auditor_url, - &version_cb, - gas); + = TALER_AUDITOR_get_config (TALER_TESTING_interpreter_get_context (is), + gas->auditor_url, + &version_cb, + gas); if (NULL == gas->auditor) { GNUNET_break (0); @@ -153,7 +162,8 @@ get_auditor_cleanup (void *cls, if (NULL != gas->auditor) { - TALER_AUDITOR_disconnect (gas->auditor); + GNUNET_break (0); + TALER_AUDITOR_get_config_cancel (gas->auditor); gas->auditor = NULL; } GNUNET_free (gas->priv_file); @@ -182,7 +192,6 @@ get_auditor_traits (void *cls, struct TALER_TESTING_Trait traits[] = { TALER_TESTING_make_trait_auditor_priv (&gas->auditor_priv), TALER_TESTING_make_trait_auditor_pub (&gas->auditor_pub), - TALER_TESTING_make_trait_auditor (gas->auditor), TALER_TESTING_make_trait_auditor_url (gas->auditor_url), TALER_TESTING_trait_end () }; -- cgit v1.2.3 From 7bb95475994504fa56902159be4f4789a3793a38 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 22 Jun 2023 20:26:34 +0200 Subject: more API cleanup --- src/benchmark/taler-exchange-benchmark.c | 2 +- src/include/taler_exchange_service.h | 6 +- src/include/taler_testing_lib.h | 11 + src/lib/exchange_api_reserves_get.c | 25 +- src/testing/testing_api_cmd_reserve_get.c | 23 +- src/testing/testing_api_helpers_exchange.c | 796 ----------------------------- src/testing/testing_api_traits.c | 27 + 7 files changed, 63 insertions(+), 827 deletions(-) delete mode 100644 src/testing/testing_api_helpers_exchange.c (limited to 'src/include/taler_testing_lib.h') diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index daae5ba6..947e2948 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -514,7 +514,7 @@ parallel_benchmark (TALER_TESTING_Main main_cb, /* We always wait for the exchange, no matter if it's running locally or remotely */ - if (0 != TALER_TESTING_wait_exchange_ready (ec.exchange_url)) + if (0 != TALER_TESTING_wait_httpd_ready (ec.exchange_url)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to detect running exchange at `%s'\n", diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index 3e0206eb..80299cdf 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -2127,7 +2127,8 @@ typedef void * reply is not well-formed, we return an HTTP status code of zero to * @a cb. * - * @param exchange the exchange handle; the exchange must be ready to operate + * @param ctx curl context + * @param url exchange base URL * @param reserve_pub public key of the reserve to inspect * @param timeout how long to wait for an affirmative reply * (enables long polling if the reserve does not yet exist) @@ -2138,7 +2139,8 @@ typedef void */ struct TALER_EXCHANGE_ReservesGetHandle * TALER_EXCHANGE_reserves_get ( - struct TALER_EXCHANGE_Handle *exchange, + struct GNUNET_CURL_Context *ctx, + const char *url, const struct TALER_ReservePublicKeyP *reserve_pub, struct GNUNET_TIME_Relative timeout, TALER_EXCHANGE_ReservesGetCallback cb, diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h index 2c9f5859..6554bc95 100644 --- a/src/include/taler_testing_lib.h +++ b/src/include/taler_testing_lib.h @@ -2740,4 +2740,15 @@ struct TALER_EXCHANGE_Handle * TALER_TESTING_get_exchange (struct TALER_TESTING_Interpreter *is); +/** + * Get exchange URL from interpreter. Convenience function. + * + * @param is interpreter state. + * @return the exchange URL, or NULL on error + */ +const char * +TALER_TESTING_get_exchange_url ( + struct TALER_TESTING_Interpreter *is); + + #endif diff --git a/src/lib/exchange_api_reserves_get.c b/src/lib/exchange_api_reserves_get.c index 1c2c2b02..73354023 100644 --- a/src/lib/exchange_api_reserves_get.c +++ b/src/lib/exchange_api_reserves_get.c @@ -38,11 +38,6 @@ struct TALER_EXCHANGE_ReservesGetHandle { - /** - * The connection to exchange this request handle will use - */ - struct TALER_EXCHANGE_Handle *exchange; - /** * The url for this request. */ @@ -186,23 +181,17 @@ handle_reserves_get_finished (void *cls, struct TALER_EXCHANGE_ReservesGetHandle * TALER_EXCHANGE_reserves_get ( - struct TALER_EXCHANGE_Handle *exchange, + struct GNUNET_CURL_Context *ctx, + const char *url, const struct TALER_ReservePublicKeyP *reserve_pub, struct GNUNET_TIME_Relative timeout, TALER_EXCHANGE_ReservesGetCallback cb, void *cb_cls) { struct TALER_EXCHANGE_ReservesGetHandle *rgh; - struct GNUNET_CURL_Context *ctx; CURL *eh; char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 16 + 32]; - if (GNUNET_YES != - TEAH_handle_is_ready (exchange)) - { - GNUNET_break (0); - return NULL; - } { char pub_str[sizeof (struct TALER_ReservePublicKeyP) * 2]; char *end; @@ -223,22 +212,21 @@ TALER_EXCHANGE_reserves_get ( if (GNUNET_TIME_relative_is_zero (timeout)) GNUNET_snprintf (arg_str, sizeof (arg_str), - "/reserves/%s", + "reserves/%s", pub_str); else GNUNET_snprintf (arg_str, sizeof (arg_str), - "/reserves/%s?timeout_ms=%s", + "reserves/%s?timeout_ms=%s", pub_str, timeout_str); } rgh = GNUNET_new (struct TALER_EXCHANGE_ReservesGetHandle); - rgh->exchange = exchange; rgh->cb = cb; rgh->cb_cls = cb_cls; rgh->reserve_pub = *reserve_pub; - rgh->url = TEAH_path_to_url (exchange, - arg_str); + rgh->url = TALER_url_join (url, + arg_str); if (NULL == rgh->url) { GNUNET_free (rgh); @@ -252,7 +240,6 @@ TALER_EXCHANGE_reserves_get ( GNUNET_free (rgh); return NULL; } - ctx = TEAH_handle_to_context (exchange); rgh->job = GNUNET_CURL_job_add (ctx, eh, &handle_reserves_get_finished, diff --git a/src/testing/testing_api_cmd_reserve_get.c b/src/testing/testing_api_cmd_reserve_get.c index a4345940..9a938cf8 100644 --- a/src/testing/testing_api_cmd_reserve_get.c +++ b/src/testing/testing_api_cmd_reserve_get.c @@ -178,12 +178,15 @@ status_run (void *cls, { struct StatusState *ss = cls; const struct TALER_TESTING_Command *create_reserve; - struct TALER_EXCHANGE_Handle *exchange - = TALER_TESTING_get_exchange (is); + const char *exchange_url; - if (NULL == exchange) - return; ss->is = is; + exchange_url = TALER_TESTING_get_exchange_url (is); + if (NULL == exchange_url) + { + GNUNET_break (0); + return; + } create_reserve = TALER_TESTING_interpreter_lookup_command (is, ss->reserve_reference); @@ -197,11 +200,13 @@ status_run (void *cls, TALER_TESTING_interpreter_fail (is); return; } - ss->rsh = TALER_EXCHANGE_reserves_get (exchange, - ss->reserve_pubp, - ss->timeout, - &reserve_status_cb, - ss); + ss->rsh = TALER_EXCHANGE_reserves_get ( + TALER_TESTING_interpreter_get_context (is), + exchange_url, + ss->reserve_pubp, + ss->timeout, + &reserve_status_cb, + ss); if (! GNUNET_TIME_relative_is_zero (ss->timeout)) { TALER_TESTING_interpreter_next (is); diff --git a/src/testing/testing_api_helpers_exchange.c b/src/testing/testing_api_helpers_exchange.c deleted file mode 100644 index 1444f154..00000000 --- a/src/testing/testing_api_helpers_exchange.c +++ /dev/null @@ -1,796 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018-2020 Taler Systems SA - - 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. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ - -/** - * @file testing/testing_api_helpers_exchange.c - * @brief helper functions - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "taler_signatures.h" -#include "taler_extensions.h" -#include "taler_testing_lib.h" - -/** - * Run multiple taler-exchange-httpd processes in - * parallel using GNU parallel? - */ -#define GNU_PARALLEL 0 - - -void -TALER_TESTING_cleanup_files (const char *config_name) -{ - if (GNUNET_OK != - GNUNET_CONFIGURATION_parse_and_run (config_name, - &TALER_TESTING_cleanup_files_cfg, - NULL)) - exit (77); -} - - -enum GNUNET_GenericReturnValue -TALER_TESTING_run_auditor_exchange (const char *config_filename, - const char *exchange_master_pub, - const char *exchange_base_url, - int do_remove) -{ - struct GNUNET_OS_Process *proc; - enum GNUNET_OS_ProcessStatusType type; - unsigned long code; - - TALER_LOG_DEBUG ("Add exchange (%s,%s) to the auditor\n", - exchange_base_url, - exchange_master_pub); - - proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-auditor-exchange", - "taler-auditor-exchange", - "-c", config_filename, - "-u", exchange_base_url, - "-m", exchange_master_pub, - (GNUNET_YES == do_remove) - ? "-r" - : NULL, - NULL); - if (NULL == proc) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to run `taler-auditor-exchange`, is your PATH correct?\n"); - return GNUNET_SYSERR; - } - GNUNET_assert (GNUNET_OK == - GNUNET_OS_process_wait_status (proc, - &type, - &code)); - GNUNET_OS_process_destroy (proc); - if ( (0 != code) || - (GNUNET_OS_PROCESS_EXITED != type) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "taler-auditor-exchange terminated with error (%d/%d)\n", - (int) type, - (int) code); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -enum GNUNET_GenericReturnValue -TALER_TESTING_exchange_db_reset (const char *config_filename) -{ - struct GNUNET_OS_Process *proc; - enum GNUNET_OS_ProcessStatusType type; - unsigned long code; - - proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-exchange-dbinit", - "taler-exchange-dbinit", - "-c", config_filename, - "-L", "WARNING", - "-r", - NULL); - if (NULL == proc) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to run `taler-exchange-dbinit`, is your PATH correct?\n"); - return GNUNET_NO; - } - if (GNUNET_SYSERR == - GNUNET_OS_process_wait_status (proc, - &type, - &code)) - { - GNUNET_break (0); - GNUNET_OS_process_destroy (proc); - return GNUNET_SYSERR; - } - GNUNET_OS_process_destroy (proc); - if ( (type == GNUNET_OS_PROCESS_EXITED) && - (0 != code) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to setup (exchange) database, exit code %d\n", - (int) code); - return GNUNET_NO; - } - if ( (type != GNUNET_OS_PROCESS_EXITED) || - (0 != code) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected error (%d/%d) running `taler-exchange-dbinit'!\n", - (int) type, - (int) code); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -enum GNUNET_GenericReturnValue -TALER_TESTING_auditor_db_reset (const char *config_filename) -{ - struct GNUNET_OS_Process *proc; - enum GNUNET_OS_ProcessStatusType type; - unsigned long code; - - proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-auditor-dbinit", - "taler-auditor-dbinit", - "-c", config_filename, - "-R", - NULL); - if (NULL == proc) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to run `taler-auditor-dbinit`, is your PATH correct?\n"); - return GNUNET_NO; - } - if (GNUNET_SYSERR == - GNUNET_OS_process_wait_status (proc, - &type, - &code)) - { - GNUNET_break (0); - GNUNET_OS_process_destroy (proc); - return GNUNET_SYSERR; - } - GNUNET_OS_process_destroy (proc); - if ( (type == GNUNET_OS_PROCESS_EXITED) && - (0 != code) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to setup (auditor) database, exit code %d\n", - (int) code); - return GNUNET_NO; - } - if ( (type != GNUNET_OS_PROCESS_EXITED) || - (0 != code) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected error (%d/%d) running `taler-auditor-dbinit'!\n", - (int) type, - (int) code); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Type of closure for - * #sign_keys_for_exchange. - */ -struct SignInfo -{ - /** - * Members will be set to the exchange configuration. - */ - struct TALER_TESTING_ExchangeConfiguration *ec; - - /** - * Name of the configuration file to use. - */ - const char *config_filename; - - /** - * Did we reset the database? - */ - int db_reset; -}; - - -/** - * Sign the keys for an exchange given configuration @a cfg. - * The information to be signed must be in a file "auditor.in". - * - * @param[in,out] cls a `struct SignInfo` with further parameters - * @param cfg configuration to use - * @return #GNUNET_OK on success - */ -static enum GNUNET_GenericReturnValue -sign_keys_for_exchange (void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct SignInfo *si = cls; - char *exchange_master_pub; - int ret; - - /* Load the extensions */ - if (GNUNET_OK != TALER_extensions_init (cfg)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "couldn't load extensions"); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "exchange", - "BASE_URL", - &si->ec->exchange_url)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - "exchange", - "BASE_URL"); - si->ec->exchange_url = NULL; - return GNUNET_NO; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "auditor", - "BASE_URL", - &si->ec->auditor_url)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - "auditor", - "BASE_URL"); - GNUNET_free (si->ec->exchange_url); - si->ec->exchange_url = NULL; - si->ec->auditor_url = NULL; - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "exchange", - "MASTER_PUBLIC_KEY", - &exchange_master_pub)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", - "MASTER_PUBLIC_KEY"); - ret = GNUNET_SYSERR; - goto fail; - } - if ( (GNUNET_OK != - TALER_TESTING_run_auditor_exchange (si->config_filename, - exchange_master_pub, - si->ec->exchange_url, - GNUNET_NO)) && - (GNUNET_YES == si->db_reset) ) - { - ret = GNUNET_NO; - goto fail; - } - GNUNET_free (exchange_master_pub); - return GNUNET_OK; -fail: - GNUNET_free (si->ec->exchange_url); - GNUNET_free (si->ec->auditor_url); - si->ec->exchange_url = NULL; - si->ec->auditor_url = NULL; - return ret; -} - - -enum GNUNET_GenericReturnValue -TALER_TESTING_prepare_exchange (const char *config_filename, - int reset_db, - struct TALER_TESTING_ExchangeConfiguration *ec) -{ - struct SignInfo si = { - .config_filename = config_filename, - .ec = ec, - .db_reset = reset_db - }; - - if (GNUNET_YES == reset_db) - { - if (GNUNET_OK != - TALER_TESTING_exchange_db_reset (config_filename)) - return GNUNET_NO; - if (GNUNET_OK != - TALER_TESTING_auditor_db_reset (config_filename)) - return GNUNET_NO; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_parse_and_run (config_filename, - &sign_keys_for_exchange, - &si)) - return GNUNET_NO; - return GNUNET_OK; -} - - -int -TALER_TESTING_wait_exchange_ready (const char *base_url) -{ - char *wget_cmd; - unsigned int iter; - - GNUNET_asprintf (&wget_cmd, - "wget -q -t 1 -T 1 %sseed -o /dev/null -O /dev/null", - base_url); // make sure ends with '/' - /* give child time to start and bind against the socket */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Waiting for `taler-exchange-httpd` service to be ready (check with: %s)\n", - wget_cmd); - iter = 0; - do - { - if (10 == iter) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to launch `taler-exchange-httpd` service (or `wget')\n"); - GNUNET_free (wget_cmd); - return 77; - } - sleep (1); - iter++; - } - while (0 != system (wget_cmd)); - GNUNET_free (wget_cmd); - return 0; -} - - -/** - * Wait for the auditor to have started. Waits for at - * most 10s, after that returns 77 to indicate an error. - * - * @param base_url what URL should we expect the auditor - * to be running at - * @return 0 on success - */ -int -TALER_TESTING_wait_auditor_ready (const char *base_url) -{ - char *wget_cmd; - unsigned int iter; - - GNUNET_asprintf (&wget_cmd, - "wget -q -t 1 -T 1 %sversion -o /dev/null -O /dev/null", - base_url); // make sure ends with '/' - /* give child time to start and bind against the socket */ - fprintf (stderr, - "Waiting for `taler-auditor-httpd' to be ready at %s\n", - base_url); - iter = 0; - do - { - if (10 == iter) - { - fprintf (stderr, - "Failed to launch `taler-auditor-httpd' (or `wget')\n"); - GNUNET_free (wget_cmd); - return 77; - } - fprintf (stderr, ".\n"); - sleep (1); - iter++; - } - while (0 != system (wget_cmd)); - GNUNET_free (wget_cmd); - return 0; -} - - -enum GNUNET_GenericReturnValue -TALER_TESTING_setup_with_exchange (TALER_TESTING_Main main_cb, - void *main_cb_cls, - const char *config_file) -{ - struct TALER_TESTING_SetupContext setup_ctx = { - .config_filename = config_file, - .main_cb = main_cb, - .main_cb_cls = main_cb_cls - }; - enum GNUNET_GenericReturnValue result; - - result = - GNUNET_CONFIGURATION_parse_and_run (config_file, - &TALER_TESTING_setup_with_exchange_cfg, - &setup_ctx); - if (GNUNET_OK != result) - return result; - return GNUNET_OK; -} - - -/** - * Stop taler-exchange-crypto helpers. - * - * @param[in] helpers the process handles. - */ -static void -stop_helpers (struct GNUNET_OS_Process *helpers[3]) -{ - for (unsigned int i = 0; i<3; i++) - { - if (NULL == helpers[i]) - continue; - GNUNET_break (0 == - GNUNET_OS_process_kill (helpers[i], - SIGTERM)); - GNUNET_break (GNUNET_OK == - GNUNET_OS_process_wait (helpers[i])); - GNUNET_OS_process_destroy (helpers[i]); - } -} - - -/** - * Start taler-exchange-crypto helpers. - * - * @param config_filename configuration file to use - * @param[out] helpers where to store the process handles. - */ -static enum GNUNET_GenericReturnValue -start_helpers (const char *config_filename, - struct GNUNET_OS_Process *helpers[3]) -{ - char *dir; - const struct GNUNET_OS_ProjectData *pd; - - pd = GNUNET_OS_project_data_get (); - GNUNET_OS_init (TALER_project_data_default ()); - dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR); - GNUNET_OS_init (pd); - if (NULL == dir) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - { - char *fn; - - GNUNET_asprintf (&fn, - "%s/%s", - dir, - "taler-exchange-secmod-eddsa"); - helpers[0] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - fn, - "taler-exchange-secmod-eddsa", - "-c", config_filename, - "-L", "INFO", - NULL); - GNUNET_free (fn); - } - { - char *fn; - - GNUNET_asprintf (&fn, - "%s/%s", - dir, - "taler-exchange-secmod-rsa"); - helpers[1] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - fn, - "taler-exchange-secmod-rsa", - "-c", config_filename, - "-L", "INFO", - NULL); - GNUNET_free (fn); - } - { - char *fn; - - GNUNET_asprintf (&fn, - "%s/%s", - dir, - "taler-exchange-secmod-cs"); - helpers[2] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - fn, - "taler-exchange-secmod-cs", - "-c", config_filename, - "-L", "INFO", - NULL); - GNUNET_free (fn); - } - GNUNET_free (dir); - if ( (NULL == helpers[0]) || - (NULL == helpers[1]) || - (NULL == helpers[2]) ) - { - stop_helpers (helpers); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -enum GNUNET_GenericReturnValue -TALER_TESTING_setup_with_exchange_cfg ( - void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - const struct TALER_TESTING_SetupContext *setup_ctx = cls; - struct GNUNET_OS_Process *exchanged; - struct GNUNET_OS_Process *helpers[3]; - unsigned long long port; - char *serve; - char *base_url; - int result; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "exchange", - "SERVE", - &serve)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", - "SERVE"); - return GNUNET_NO; - } - - if (0 == strcmp ("tcp", - serve)) - { - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, - "exchange", - "PORT", - &port)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", - "PORT"); - GNUNET_free (serve); - return GNUNET_NO; - } - - if (GNUNET_OK != - GNUNET_NETWORK_test_port_free (IPPROTO_TCP, - (uint16_t) port)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Required port %llu not available, skipping.\n", - port); - GNUNET_free (serve); - return GNUNET_NO; - } - } - GNUNET_free (serve); - if (GNUNET_OK != - start_helpers (setup_ctx->config_filename, - helpers)) - { - GNUNET_break (0); - return 77; - } - exchanged = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, -#if GNU_PARALLEL - "parallel", -#endif - "taler-exchange-httpd", - "taler-exchange-httpd", - "-L", "INFO", - "-a", /* some tests may need timetravel */ - "-c", setup_ctx->config_filename, -#if GNU_PARALLEL - "-r", - ":::", - "-", - "-", - "-", - "-", -#endif - NULL); - if (NULL == exchanged) - { - GNUNET_break (0); - stop_helpers (helpers); - return 77; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "exchange", - "BASE_URL", - &base_url)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", - "BASE_URL"); - stop_helpers (helpers); - return GNUNET_NO; - } - - if (0 != TALER_TESTING_wait_exchange_ready (base_url)) - { - GNUNET_free (base_url); - stop_helpers (helpers); - GNUNET_break (0 == - GNUNET_OS_process_kill (exchanged, - SIGTERM)); -#if GNU_PARALLEL - /* GNU Parallel kills on 2nd SIGTERM, need to give it a - chance to process the 1st signal first... */ - sleep (1); - GNUNET_break (0 == - GNUNET_OS_process_kill (exchanged, - SIGTERM)); -#endif - GNUNET_break (GNUNET_OK == - GNUNET_OS_process_wait (exchanged)); - GNUNET_OS_process_destroy (exchanged); - return 77; - } - GNUNET_free (base_url); - - /* NOTE: this call blocks. */ - result = TALER_TESTING_setup (setup_ctx->main_cb, - setup_ctx->main_cb_cls, - cfg, - exchanged, - GNUNET_YES); - GNUNET_break (0 == - GNUNET_OS_process_kill (exchanged, - SIGTERM)); -#if GNU_PARALLEL - /* GNU Parallel kills on 2nd SIGTERM, need to give it a - chance to process the 1st signal first... */ - sleep (1); - GNUNET_break (0 == - GNUNET_OS_process_kill (exchanged, - SIGTERM)); -#endif - GNUNET_break (GNUNET_OK == - GNUNET_OS_process_wait (exchanged)); - GNUNET_OS_process_destroy (exchanged); - stop_helpers (helpers); - return result; -} - - -enum GNUNET_GenericReturnValue -TALER_TESTING_setup_with_auditor_and_exchange_cfg ( - void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - const struct TALER_TESTING_SetupContext *setup_ctx = cls; - struct GNUNET_OS_Process *auditord; - unsigned long long port; - char *serve; - char *base_url; - int result; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "auditor", - "SERVE", - &serve)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "auditor", - "SERVE"); - return GNUNET_NO; - } - - if (0 == strcmp ("tcp", serve)) - { - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, - "auditor", - "PORT", - &port)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "auditor", - "PORT"); - GNUNET_free (serve); - return GNUNET_NO; - } - - if (GNUNET_OK != - GNUNET_NETWORK_test_port_free (IPPROTO_TCP, - (uint16_t) port)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Required port %llu not available, skipping.\n", - port); - GNUNET_free (serve); - return GNUNET_NO; - } - } - GNUNET_free (serve); - auditord = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-auditor-httpd", - "taler-auditor-httpd", - "-c", setup_ctx->config_filename, - NULL); - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "auditor", - "BASE_URL", - &base_url)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "auditor", - "BASE_URL"); - return GNUNET_NO; - } - - if (0 != TALER_TESTING_wait_auditor_ready (base_url)) - { - GNUNET_free (base_url); - GNUNET_break (0 == - GNUNET_OS_process_kill (auditord, - SIGTERM)); - GNUNET_break (GNUNET_OK == - GNUNET_OS_process_wait (auditord)); - GNUNET_OS_process_destroy (auditord); - return 77; - } - GNUNET_free (base_url); - - /* NOTE: this call blocks. */ - result = TALER_TESTING_setup_with_exchange_cfg ((void *) setup_ctx, - cfg); - GNUNET_break (0 == - GNUNET_OS_process_kill (auditord, - SIGTERM)); - GNUNET_break (GNUNET_OK == - GNUNET_OS_process_wait (auditord)); - GNUNET_OS_process_destroy (auditord); - return result; -} - - -enum GNUNET_GenericReturnValue -TALER_TESTING_setup_with_auditor_and_exchange (TALER_TESTING_Main main_cb, - void *main_cb_cls, - const char *config_file) -{ - struct TALER_TESTING_SetupContext setup_ctx = { - .config_filename = config_file, - .main_cb = main_cb, - .main_cb_cls = main_cb_cls - }; - - return GNUNET_CONFIGURATION_parse_and_run ( - config_file, - &TALER_TESTING_setup_with_auditor_and_exchange_cfg, - &setup_ctx); -} - - -/* end of testing_api_helpers_exchange.c */ diff --git a/src/testing/testing_api_traits.c b/src/testing/testing_api_traits.c index d84e2c37..27eef5a5 100644 --- a/src/testing/testing_api_traits.c +++ b/src/testing/testing_api_traits.c @@ -102,4 +102,31 @@ TALER_TESTING_get_exchange (struct TALER_TESTING_Interpreter *is) } +const char * +TALER_TESTING_get_exchange_url (struct TALER_TESTING_Interpreter *is) +{ + const char *exchange_url; + const struct TALER_TESTING_Command *exchange_cmd; + + exchange_cmd + = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return NULL; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_exchange_url (exchange_cmd, + &exchange_url)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return NULL; + } + return exchange_url; +} + + /* end of testing_api_traits.c */ -- cgit v1.2.3 From 75733ee00efc6d5342ed8b4fccd637efaebdce06 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 25 Jun 2023 13:59:47 +0200 Subject: more work on atomizing exchange API: deposit --- contrib/gana | 2 +- src/auditor/taler-auditor-httpd.c | 2 + src/include/taler_exchange_service.h | 159 +++--------- src/include/taler_testing_lib.h | 12 + src/lib/Makefile.am | 1 - src/lib/exchange_api_batch_deposit.c | 267 +++++++++++++++------ src/lib/exchange_api_handle.c | 93 ++----- src/lib/exchange_api_handle.h | 46 +--- src/testing/test_exchange_api.conf | 2 +- .../taler/auditor/offline-keys/auditor.priv | 1 + src/testing/testing_api_cmd_batch_deposit.c | 26 +- src/testing/testing_api_cmd_deposit.c | 34 ++- src/testing/testing_api_cmd_get_exchange.c | 3 +- src/testing/testing_api_traits.c | 28 +++ 14 files changed, 327 insertions(+), 349 deletions(-) create mode 100644 src/testing/test_exchange_api_home/taler/auditor/offline-keys/auditor.priv (limited to 'src/include/taler_testing_lib.h') diff --git a/contrib/gana b/contrib/gana index 3e5591a7..5f377301 160000 --- a/contrib/gana +++ b/contrib/gana @@ -1 +1 @@ -Subproject commit 3e5591a7e3fd93ba46fc2b538c63f0c16336283d +Subproject commit 5f377301db4d94c485422ecda277fe850e29504a diff --git a/src/auditor/taler-auditor-httpd.c b/src/auditor/taler-auditor-httpd.c index 68316082..a59ce3de 100644 --- a/src/auditor/taler-auditor-httpd.c +++ b/src/auditor/taler-auditor-httpd.c @@ -157,6 +157,8 @@ handle_config (struct TAH_RequestHandler *rh, if (NULL == ver) { ver = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("name", + "taler-auditor"), GNUNET_JSON_pack_string ("version", AUDITOR_PROTOCOL_VERSION), GNUNET_JSON_pack_string ("currency", diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index 065c2dcd..9cb5f083 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -573,10 +573,30 @@ TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange); * @param exchange the exchange handle * @return the exchange's key set */ -const struct TALER_EXCHANGE_Keys * +struct TALER_EXCHANGE_Keys * TALER_EXCHANGE_get_keys (struct TALER_EXCHANGE_Handle *exchange); +/** + * Increment reference counter for @a keys + * + * @param[in,out] keys object to increment reference counter for + * @return keys, with incremented reference counter + */ +struct TALER_EXCHANGE_Keys * +TALER_EXCHANGE_keys_incref (struct TALER_EXCHANGE_Keys *keys); + + +/** + * Deccrement reference counter for @a keys. + * Frees @a keys if reference counter becomes zero. + * + * @param[in,out] keys object to decrement reference counter for + */ +void +TALER_EXCHANGE_keys_decref (struct TALER_EXCHANGE_Keys *keys); + + /** * Let the user set the last valid denomination time manually. * @@ -1151,135 +1171,6 @@ struct TALER_EXCHANGE_DepositContractDetail }; -/** - * @brief A Deposit Handle - */ -struct TALER_EXCHANGE_DepositHandle; - - -/** - * Structure with information about a deposit - * operation's result. - */ -struct TALER_EXCHANGE_DepositResult -{ - /** - * HTTP response data - */ - struct TALER_EXCHANGE_HttpResponse hr; - - union - { - - /** - * Information returned if the HTTP status is - * #MHD_HTTP_OK. - */ - struct - { - /** - * Time when the exchange generated the deposit confirmation - */ - struct GNUNET_TIME_Timestamp deposit_timestamp; - - /** - * signature provided by the exchange - */ - const struct TALER_ExchangeSignatureP *exchange_sig; - - /** - * exchange key used to sign @a exchange_sig. - */ - const struct TALER_ExchangePublicKeyP *exchange_pub; - - /** - * Base URL for looking up wire transfers, or - * NULL to use the default base URL. - */ - const char *transaction_base_url; - - } ok; - - /** - * Information returned if the HTTP status is - * #MHD_HTTP_CONFLICT. - */ - struct - { - /* TODO: returning full details is not implemented */ - } conflict; - - } details; -}; - - -/** - * Callbacks of this type are used to serve the result of submitting a - * deposit permission request to a exchange. - * - * @param cls closure - * @param dr deposit response details - */ -typedef void -(*TALER_EXCHANGE_DepositResultCallback) ( - void *cls, - const struct TALER_EXCHANGE_DepositResult *dr); - - -/** - * Submit a deposit permission to the exchange and get the exchange's - * response. This API is typically used by a merchant. Note that - * while we return the response verbatim to the caller for further - * processing, we do already verify that the response is well-formed - * (i.e. that signatures included in the response are all valid). If - * the exchange's reply is not well-formed, we return an HTTP status code - * of zero to @a cb. - * - * We also verify that the @a cdd.coin_sig is valid for this deposit - * request, and that the @a cdd.ub_sig is a valid signature for @a - * coin_pub. Also, the @a exchange must be ready to operate (i.e. have - * finished processing the /keys reply). If either check fails, we do - * NOT initiate the transaction with the exchange and instead return NULL. - * - * @param exchange the exchange handle; the exchange must be ready to operate - * @param dcd details about the contract the deposit is for - * @param cdd details about the coin to be deposited - * @param cb the callback to call when a reply for this request is available - * @param cb_cls closure for the above callback - * @param[out] ec if NULL is returned, set to the error code explaining why the operation failed - * @return a handle for this request; NULL if the inputs are invalid (i.e. - * signatures fail to verify). In this case, the callback is not called. - */ -struct TALER_EXCHANGE_DepositHandle * -TALER_EXCHANGE_deposit ( - struct TALER_EXCHANGE_Handle *exchange, - const struct TALER_EXCHANGE_DepositContractDetail *dcd, - const struct TALER_EXCHANGE_CoinDepositDetail *cdd, - TALER_EXCHANGE_DepositResultCallback cb, - void *cb_cls, - enum TALER_ErrorCode *ec); - - -/** - * Change the chance that our deposit confirmation will be given to the - * auditor to 100%. - * - * @param deposit the deposit permission request handle - */ -void -TALER_EXCHANGE_deposit_force_dc (struct TALER_EXCHANGE_DepositHandle *deposit); - - -/** - * Cancel a deposit permission request. This function cannot be used - * on a request handle if a response is already served for it. - * - * @param deposit the deposit permission request handle - */ -void -TALER_EXCHANGE_deposit_cancel (struct TALER_EXCHANGE_DepositHandle *deposit); - - /** * @brief A Batch Deposit Handle */ @@ -1374,7 +1265,9 @@ typedef void * finished processing the /keys reply). If either check fails, we do * NOT initiate the transaction with the exchange and instead return NULL. * - * @param exchange the exchange handle; the exchange must be ready to operate + * @param ctx curl context + * @param url exchange base URL + * @param keys exchange keys * @param dcd details about the contract the deposit is for * @param num_cdds length of the @a cdds array * @param cdds array with details about the coins to be deposited @@ -1386,7 +1279,9 @@ typedef void */ struct TALER_EXCHANGE_BatchDepositHandle * TALER_EXCHANGE_batch_deposit ( - struct TALER_EXCHANGE_Handle *exchange, + struct GNUNET_CURL_Context *ctx, + const char *url, + struct TALER_EXCHANGE_Keys *keys, const struct TALER_EXCHANGE_DepositContractDetail *dcd, unsigned int num_cdds, const struct TALER_EXCHANGE_CoinDepositDetail *cdds, diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h index 6554bc95..2ef7ef60 100644 --- a/src/include/taler_testing_lib.h +++ b/src/include/taler_testing_lib.h @@ -2694,6 +2694,7 @@ TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits, op (relative_time, const struct GNUNET_TIME_Relative) \ op (exchange, struct TALER_EXCHANGE_Handle) \ op (fakebank, struct TALER_FAKEBANK_Handle) \ + op (keys, struct TALER_EXCHANGE_Keys) \ op (process, struct GNUNET_OS_Process *) @@ -2751,4 +2752,15 @@ TALER_TESTING_get_exchange_url ( struct TALER_TESTING_Interpreter *is); +/** + * Get exchange keys from interpreter. Convenience function. + * + * @param is interpreter state. + * @return the exchange keys, or NULL on error + */ +struct TALER_EXCHANGE_Keys * +TALER_TESTING_get_keys ( + struct TALER_TESTING_Interpreter *is); + + #endif diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 2c903142..53190bc5 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -32,7 +32,6 @@ libtalerexchange_la_SOURCES = \ exchange_api_csr_melt.c \ exchange_api_csr_withdraw.c \ exchange_api_handle.c exchange_api_handle.h \ - exchange_api_deposit.c \ exchange_api_deposits_get.c \ exchange_api_kyc_check.c \ exchange_api_kyc_proof.c \ diff --git a/src/lib/exchange_api_batch_deposit.c b/src/lib/exchange_api_batch_deposit.c index bb17737f..22ae2d58 100644 --- a/src/lib/exchange_api_batch_deposit.c +++ b/src/lib/exchange_api_batch_deposit.c @@ -44,6 +44,39 @@ */ #define AUDITOR_CHANCE 20 + +/** + * Entry in list of ongoing interactions with an auditor. + */ +struct TEAH_AuditorInteractionEntry +{ + /** + * DLL entry. + */ + struct TEAH_AuditorInteractionEntry *next; + + /** + * DLL entry. + */ + struct TEAH_AuditorInteractionEntry *prev; + + /** + * URL of our auditor. For logging. + */ + const char *auditor_url; + + /** + * Interaction state. + */ + struct TALER_AUDITOR_DepositConfirmationHandle *dch; + + /** + * Batch deposit this is for. + */ + struct TALER_EXCHANGE_BatchDepositHandle *dh; +}; + + /** * @brief A Deposit Handle */ @@ -51,9 +84,9 @@ struct TALER_EXCHANGE_BatchDepositHandle { /** - * The connection to exchange this request handle will use + * The keys of the exchange. */ - struct TALER_EXCHANGE_Handle *exchange; + struct TALER_EXCHANGE_Keys *keys; /** * Context for our curl request(s). @@ -117,11 +150,31 @@ struct TALER_EXCHANGE_BatchDepositHandle */ struct TALER_ExchangeSignatureP *exchange_sigs; + /** + * Head of DLL of interactions with this auditor. + */ + struct TEAH_AuditorInteractionEntry *ai_head; + + /** + * Tail of DLL of interactions with this auditor. + */ + struct TEAH_AuditorInteractionEntry *ai_tail; + + /** + * Result to return to the application once @e ai_head is empty. + */ + struct TALER_EXCHANGE_BatchDepositResult dr; + /** * Exchange signing public key, set for #auditor_cb. */ struct TALER_ExchangePublicKeyP exchange_pub; + /** + * Response object to free at the end. + */ + json_t *response; + /** * Chance that we will inform the auditor about the deposit * is 1:n, where the value of this field is "n". @@ -136,6 +189,52 @@ struct TALER_EXCHANGE_BatchDepositHandle }; +/** + * Finish batch deposit operation by calling the callback. + * + * @param[in] dh handle to finished batch deposit operation + */ +static void +finish_dh (struct TALER_EXCHANGE_BatchDepositHandle *dh) +{ + dh->cb (dh->cb_cls, + &dh->dr); + TALER_EXCHANGE_batch_deposit_cancel (dh); +} + + +/** + * Function called with the result from our call to the + * auditor's /deposit-confirmation handler. + * + * @param cls closure of type `struct TEAH_AuditorInteractionEntry *` + * @param dcr response + */ +static void +acc_confirmation_cb ( + void *cls, + const struct TALER_AUDITOR_DepositConfirmationResponse *dcr) +{ + struct TEAH_AuditorInteractionEntry *aie = cls; + struct TALER_EXCHANGE_BatchDepositHandle *dh = aie->dh; + + if (MHD_HTTP_OK != dcr->hr.http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to submit deposit confirmation to auditor `%s' with HTTP status %d (EC: %d). This is acceptable if it does not happen often.\n", + aie->auditor_url, + dcr->hr.http_status, + dcr->hr.ec); + } + GNUNET_CONTAINER_DLL_remove (dh->ai_head, + dh->ai_tail, + aie); + GNUNET_free (aie); + if (NULL == dh->ai_head) + finish_dh (dh); +} + + /** * Function called for each auditor to give us a chance to possibly * launch a deposit confirmation interaction. @@ -143,15 +242,13 @@ struct TALER_EXCHANGE_BatchDepositHandle * @param cls closure * @param auditor_url base URL of the auditor * @param auditor_pub public key of the auditor - * @return NULL if no deposit confirmation interaction was launched */ -static struct TEAH_AuditorInteractionEntry * +static void auditor_cb (void *cls, const char *auditor_url, const struct TALER_AuditorPublicKeyP *auditor_pub) { struct TALER_EXCHANGE_BatchDepositHandle *dh = cls; - const struct TALER_EXCHANGE_Keys *key_state; const struct TALER_EXCHANGE_SigningPublicKey *spk; struct TEAH_AuditorInteractionEntry *aie; struct TALER_Amount amount_without_fee; @@ -164,29 +261,30 @@ auditor_cb (void *cls, { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Not providing deposit confirmation to auditor\n"); - return NULL; + return; } coin = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, dh->num_cdds); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Will provide deposit confirmation to auditor `%s'\n", TALER_B2S (auditor_pub)); - key_state = TALER_EXCHANGE_get_keys (dh->exchange); - dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state, + dki = TALER_EXCHANGE_get_denomination_key_by_hash (dh->keys, &dh->cdds[coin].h_denom_pub); GNUNET_assert (NULL != dki); - spk = TALER_EXCHANGE_get_signing_key_info (key_state, + spk = TALER_EXCHANGE_get_signing_key_info (dh->keys, &dh->exchange_pub); if (NULL == spk) { GNUNET_break_op (0); - return NULL; + return; } GNUNET_assert (0 <= TALER_amount_subtract (&amount_without_fee, &dh->cdds[coin].amount, &dki->fees.deposit)); aie = GNUNET_new (struct TEAH_AuditorInteractionEntry); + aie->dh = dh; + aie->auditor_url = auditor_url; aie->dch = TALER_AUDITOR_deposit_confirmation ( dh->ctx, auditor_url, @@ -201,14 +299,16 @@ auditor_cb (void *cls, &dh->dcd.merchant_pub, &dh->exchange_pub, &dh->exchange_sigs[coin], - &key_state->master_pub, + &dh->keys->master_pub, spk->valid_from, spk->valid_until, spk->valid_legal, &spk->master_sig, - &TEAH_acc_confirmation_cb, + &acc_confirmation_cb, aie); - return aie; + GNUNET_CONTAINER_DLL_insert (dh->ai_head, + dh->ai_tail, + aie); } @@ -227,22 +327,19 @@ handle_deposit_finished (void *cls, { struct TALER_EXCHANGE_BatchDepositHandle *dh = cls; const json_t *j = response; - struct TALER_EXCHANGE_BatchDepositResult dr = { - .hr.reply = j, - .hr.http_status = (unsigned int) response_code - }; - const struct TALER_EXCHANGE_Keys *keys; + struct TALER_EXCHANGE_BatchDepositResult *dr = &dh->dr; dh->job = NULL; - keys = TALER_EXCHANGE_get_keys (dh->exchange); + dh->response = json_incref ((json_t*) j); + dr->hr.reply = dh->response; + dr->hr.http_status = (unsigned int) response_code; switch (response_code) { case 0: - dr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + dr->hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; break; case MHD_HTTP_OK: { - const struct TALER_EXCHANGE_Keys *key_state; const json_t *sigs; json_t *sig; unsigned int idx; @@ -253,7 +350,7 @@ handle_deposit_finished (void *cls, &dh->exchange_pub), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_string ("transaction_base_url", - &dr.details.ok.transaction_base_url), + &dr->details.ok.transaction_base_url), NULL), GNUNET_JSON_spec_timestamp ("exchange_timestamp", &dh->exchange_timestamp), @@ -266,27 +363,26 @@ handle_deposit_finished (void *cls, NULL, NULL)) { GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + dr->hr.http_status = 0; + dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } if (json_array_size (sigs) != dh->num_cdds) { GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + dr->hr.http_status = 0; + dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } dh->exchange_sigs = GNUNET_new_array (dh->num_cdds, struct TALER_ExchangeSignatureP); - key_state = TALER_EXCHANGE_get_keys (dh->exchange); if (GNUNET_OK != - TALER_EXCHANGE_test_signing_key (key_state, + TALER_EXCHANGE_test_signing_key (dh->keys, &dh->exchange_pub)) { GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE; + dr->hr.http_status = 0; + dr->hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE; break; } json_array_foreach (sigs, idx, sig) @@ -305,11 +401,11 @@ handle_deposit_finished (void *cls, NULL, NULL)) { GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + dr->hr.http_status = 0; + dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } - dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state, + dki = TALER_EXCHANGE_get_denomination_key_by_hash (dh->keys, &dh->cdds[idx]. h_denom_pub); GNUNET_assert (NULL != dki); @@ -333,42 +429,41 @@ handle_deposit_finished (void *cls, &dh->exchange_sigs[idx])) { GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE; + dr->hr.http_status = 0; + dr->hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE; break; } } - TEAH_get_auditors_for_dc (dh->exchange, + TEAH_get_auditors_for_dc (dh->keys, &auditor_cb, dh); } - dr.details.ok.exchange_sigs = dh->exchange_sigs; - dr.details.ok.exchange_pub = &dh->exchange_pub; - dr.details.ok.deposit_timestamp = dh->exchange_timestamp; - dr.details.ok.num_signatures = dh->num_cdds; + dr->details.ok.exchange_sigs = dh->exchange_sigs; + dr->details.ok.exchange_pub = &dh->exchange_pub; + dr->details.ok.deposit_timestamp = dh->exchange_timestamp; + dr->details.ok.num_signatures = dh->num_cdds; break; case MHD_HTTP_BAD_REQUEST: /* This should never happen, either us or the exchange is buggy (or API version conflict); just pass JSON reply to the application */ - dr.hr.ec = TALER_JSON_get_error_code (j); - dr.hr.hint = TALER_JSON_get_error_hint (j); + dr->hr.ec = TALER_JSON_get_error_code (j); + dr->hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_FORBIDDEN: - dr.hr.ec = TALER_JSON_get_error_code (j); - dr.hr.hint = TALER_JSON_get_error_hint (j); + dr->hr.ec = TALER_JSON_get_error_code (j); + dr->hr.hint = TALER_JSON_get_error_hint (j); /* Nothing really to verify, exchange says one of the signatures is invalid; as we checked them, this should never happen, we should pass the JSON reply to the application */ break; case MHD_HTTP_NOT_FOUND: - dr.hr.ec = TALER_JSON_get_error_code (j); - dr.hr.hint = TALER_JSON_get_error_hint (j); + dr->hr.ec = TALER_JSON_get_error_code (j); + dr->hr.hint = TALER_JSON_get_error_hint (j); /* Nothing really to verify, this should never happen, we should pass the JSON reply to the application */ break; case MHD_HTTP_CONFLICT: { - const struct TALER_EXCHANGE_Keys *key_state; struct TALER_CoinSpendPublicKeyP coin_pub; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("coin_pub", @@ -384,8 +479,8 @@ handle_deposit_finished (void *cls, NULL, NULL)) { GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + dr->hr.http_status = 0; + dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } for (unsigned int i = 0; inum_cdds; i++) @@ -394,14 +489,13 @@ handle_deposit_finished (void *cls, GNUNET_memcmp (&coin_pub, &dh->cdds[i].coin_pub)) continue; - key_state = TALER_EXCHANGE_get_keys (dh->exchange); - dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state, + dki = TALER_EXCHANGE_get_denomination_key_by_hash (dh->keys, &dh->cdds[i]. h_denom_pub); GNUNET_assert (NULL != dki); if (GNUNET_OK != TALER_EXCHANGE_check_coin_conflict_ ( - keys, + dh->keys, j, dki, &dh->cdds[i].coin_pub, @@ -409,8 +503,8 @@ handle_deposit_finished (void *cls, &dh->cdds[i].amount)) { GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + dr->hr.http_status = 0; + dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } found = true; @@ -419,12 +513,12 @@ handle_deposit_finished (void *cls, if (! found) { GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + dr->hr.http_status = 0; + dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } - dr.hr.ec = TALER_JSON_get_error_code (j); - dr.hr.hint = TALER_JSON_get_error_hint (j); + dr->hr.ec = TALER_JSON_get_error_code (j); + dr->hr.hint = TALER_JSON_get_error_hint (j); } break; case MHD_HTTP_GONE: @@ -432,35 +526,37 @@ handle_deposit_finished (void *cls, /* Note: one might want to check /keys for revocation signature here, alas tricky in case our /keys is outdated => left to clients */ - dr.hr.ec = TALER_JSON_get_error_code (j); - dr.hr.hint = TALER_JSON_get_error_hint (j); + dr->hr.ec = TALER_JSON_get_error_code (j); + dr->hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_INTERNAL_SERVER_ERROR: - dr.hr.ec = TALER_JSON_get_error_code (j); - dr.hr.hint = TALER_JSON_get_error_hint (j); + dr->hr.ec = TALER_JSON_get_error_code (j); + dr->hr.hint = TALER_JSON_get_error_hint (j); /* Server had an internal issue; we should retry, but this API leaves this to the application */ break; default: /* unexpected response code */ - dr.hr.ec = TALER_JSON_get_error_code (j); - dr.hr.hint = TALER_JSON_get_error_hint (j); + dr->hr.ec = TALER_JSON_get_error_code (j); + dr->hr.hint = TALER_JSON_get_error_hint (j); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for exchange deposit\n", (unsigned int) response_code, - dr.hr.ec); + dr->hr.ec); GNUNET_break_op (0); break; } - dh->cb (dh->cb_cls, - &dr); - TALER_EXCHANGE_batch_deposit_cancel (dh); + if (NULL != dh->ai_head) + return; + finish_dh (dh); } struct TALER_EXCHANGE_BatchDepositHandle * TALER_EXCHANGE_batch_deposit ( - struct TALER_EXCHANGE_Handle *exchange, + struct GNUNET_CURL_Context *ctx, + const char *url, + struct TALER_EXCHANGE_Keys *keys, const struct TALER_EXCHANGE_DepositContractDetail *dcd, unsigned int num_cdds, const struct TALER_EXCHANGE_CoinDepositDetail *cdds, @@ -468,15 +564,12 @@ TALER_EXCHANGE_batch_deposit ( void *cb_cls, enum TALER_ErrorCode *ec) { - const struct TALER_EXCHANGE_Keys *key_state; struct TALER_EXCHANGE_BatchDepositHandle *dh; json_t *deposit_obj; json_t *deposits; CURL *eh; struct TALER_Amount amount_without_fee; - GNUNET_assert (GNUNET_YES == - TEAH_handle_is_ready (exchange)); if (GNUNET_TIME_timestamp_cmp (dcd->refund_deadline, >, dcd->wire_deadline)) @@ -485,10 +578,8 @@ TALER_EXCHANGE_batch_deposit ( *ec = TALER_EC_EXCHANGE_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE; return NULL; } - key_state = TALER_EXCHANGE_get_keys (exchange); dh = GNUNET_new (struct TALER_EXCHANGE_BatchDepositHandle); dh->auditor_chance = AUDITOR_CHANCE; - dh->exchange = exchange; dh->cb = cb; dh->cb_cls = cb_cls; dh->cdds = GNUNET_memdup (cdds, @@ -509,7 +600,7 @@ TALER_EXCHANGE_batch_deposit ( const struct TALER_EXCHANGE_CoinDepositDetail *cdd = &cdds[i]; const struct TALER_EXCHANGE_DenomPublicKey *dki; - dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state, + dki = TALER_EXCHANGE_get_denomination_key_by_hash (keys, &cdd->h_denom_pub); if (NULL == dki) { @@ -568,8 +659,9 @@ TALER_EXCHANGE_batch_deposit ( &cdd->coin_sig) ))); } - dh->url = TEAH_path_to_url (exchange, - "/batch-deposit"); + dh->url = TALER_url_join (url, + "batch-deposit", + NULL); if (NULL == dh->url) { GNUNET_break (0); @@ -623,8 +715,9 @@ TALER_EXCHANGE_batch_deposit ( GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "URL for deposit: `%s'\n", dh->url); - dh->ctx = TEAH_handle_to_context (exchange); - dh->job = GNUNET_CURL_job_add2 (dh->ctx, + dh->ctx = ctx; + dh->keys = TALER_EXCHANGE_keys_incref (keys); + dh->job = GNUNET_CURL_job_add2 (ctx, eh, dh->post_ctx.headers, &handle_deposit_finished, @@ -645,15 +738,31 @@ void TALER_EXCHANGE_batch_deposit_cancel ( struct TALER_EXCHANGE_BatchDepositHandle *deposit) { + struct TEAH_AuditorInteractionEntry *aie; + + while (NULL != (aie = deposit->ai_head)) + { + GNUNET_assert (aie->dh == deposit); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Not sending deposit confirmation to auditor `%s' due to cancellation\n", + aie->auditor_url); + TALER_AUDITOR_deposit_confirmation_cancel (aie->dch); + GNUNET_CONTAINER_DLL_remove (deposit->ai_head, + deposit->ai_tail, + aie); + GNUNET_free (aie); + } if (NULL != deposit->job) { GNUNET_CURL_job_cancel (deposit->job); deposit->job = NULL; } + TALER_EXCHANGE_keys_decref (deposit->keys); GNUNET_free (deposit->url); GNUNET_free (deposit->cdds); GNUNET_free (deposit->exchange_sigs); TALER_curl_easy_post_finished (&deposit->post_ctx); + json_decref (deposit->response); GNUNET_free (deposit); } diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c index 4d245b07..7e302112 100644 --- a/src/lib/exchange_api_handle.c +++ b/src/lib/exchange_api_handle.c @@ -112,16 +112,6 @@ struct TEAH_AuditorListEntry */ struct TALER_AUDITOR_GetConfigHandle *ah; - /** - * Head of DLL of interactions with this auditor. - */ - struct TEAH_AuditorInteractionEntry *ai_head; - - /** - * Tail of DLL of interactions with this auditor. - */ - struct TEAH_AuditorInteractionEntry *ai_tail; - /** * Public key of the auditor. */ @@ -168,58 +158,24 @@ struct KeysRequest void -TEAH_acc_confirmation_cb ( - void *cls, - const struct TALER_AUDITOR_DepositConfirmationResponse *dcr) -{ - struct TEAH_AuditorInteractionEntry *aie = cls; - struct TEAH_AuditorListEntry *ale = aie->ale; - - if (MHD_HTTP_OK != dcr->hr.http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to submit deposit confirmation to auditor `%s' with HTTP status %d (EC: %d). This is acceptable if it does not happen often.\n", - ale->auditor_url, - dcr->hr.http_status, - dcr->hr.ec); - } - GNUNET_CONTAINER_DLL_remove (ale->ai_head, - ale->ai_tail, - aie); - GNUNET_free (aie); -} - - -void -TEAH_get_auditors_for_dc (struct TALER_EXCHANGE_Handle *h, +TEAH_get_auditors_for_dc (struct TALER_EXCHANGE_Keys *keys, TEAH_AuditorCallback ac, void *ac_cls) { - if (NULL == h->auditors_head) + if (0 == keys->num_auditors) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "No auditor available for exchange `%s'. Not submitting deposit confirmations.\n", - h->url); + "No auditor available. Not submitting deposit confirmations.\n"); return; } - for (struct TEAH_AuditorListEntry *ale = h->auditors_head; - NULL != ale; - ale = ale->next) + for (unsigned int i = 0; inum_auditors; i++) { - struct TEAH_AuditorInteractionEntry *aie; + const struct TALER_EXCHANGE_AuditorInformation *auditor + = &keys->auditors[i]; - if (! ale->is_up) - continue; - aie = ac (ac_cls, - ale->auditor_url, - &ale->auditor_pub); - if (NULL != aie) - { - aie->ale = ale; - GNUNET_CONTAINER_DLL_insert (ale->ai_head, - ale->ai_tail, - aie); - } + ac (ac_cls, + auditor->auditor_url, + &auditor->auditor_pub); } } @@ -2121,20 +2077,6 @@ TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange) while (NULL != (ale = exchange->auditors_head)) { - struct TEAH_AuditorInteractionEntry *aie; - - while (NULL != (aie = ale->ai_head)) - { - GNUNET_assert (aie->ale == ale); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Not sending deposit confirmation to auditor `%s' due to exchange disconnect\n", - ale->auditor_url); - TALER_AUDITOR_deposit_confirmation_cancel (aie->dch); - GNUNET_CONTAINER_DLL_remove (ale->ai_head, - ale->ai_tail, - aie); - GNUNET_free (aie); - } GNUNET_CONTAINER_DLL_remove (exchange->auditors_head, exchange->auditors_tail, ale); @@ -2275,7 +2217,7 @@ TALER_EXCHANGE_get_denomination_key_by_hash ( } -const struct TALER_EXCHANGE_Keys * +struct TALER_EXCHANGE_Keys * TALER_EXCHANGE_get_keys (struct TALER_EXCHANGE_Handle *exchange) { (void) TALER_EXCHANGE_check_keys_current (exchange, @@ -2297,4 +2239,19 @@ TALER_EXCHANGE_get_keys_raw (struct TALER_EXCHANGE_Handle *exchange) } +struct TALER_EXCHANGE_Keys * +TALER_EXCHANGE_keys_incref (struct TALER_EXCHANGE_Keys *keys) +{ + // FIXME + return keys; +} + + +void +TALER_EXCHANGE_keys_decref (struct TALER_EXCHANGE_Keys *keys) +{ + // FIXME +} + + /* end of exchange_api_handle.c */ diff --git a/src/lib/exchange_api_handle.h b/src/lib/exchange_api_handle.h index 8e3b1065..6b96e21e 100644 --- a/src/lib/exchange_api_handle.h +++ b/src/lib/exchange_api_handle.h @@ -34,32 +34,6 @@ struct TEAH_AuditorListEntry; -/** - * Entry in list of ongoing interactions with an auditor. - */ -struct TEAH_AuditorInteractionEntry -{ - /** - * DLL entry. - */ - struct TEAH_AuditorInteractionEntry *next; - - /** - * DLL entry. - */ - struct TEAH_AuditorInteractionEntry *prev; - - /** - * Which auditor is this action associated with? - */ - struct TEAH_AuditorListEntry *ale; - - /** - * Interaction state. - */ - struct TALER_AUDITOR_DepositConfirmationHandle *dch; -}; - /** * Stages of initialization for the `struct TALER_EXCHANGE_Handle` */ @@ -180,38 +154,24 @@ struct TALER_EXCHANGE_Handle * @param cls closure * @param auditor_url base URL of the auditor * @param auditor_pub public key of the auditor - * @return NULL if no deposit confirmation interaction was launched */ -typedef struct TEAH_AuditorInteractionEntry * +typedef void (*TEAH_AuditorCallback)(void *cls, const char *auditor_url, const struct TALER_AuditorPublicKeyP *auditor_pub); -/** - * Signature of functions called with the result from our call to the - * auditor's /deposit-confirmation handler. - * - * @param cls closure of type `struct TEAH_AuditorInteractionEntry *` - * @param dcr response - */ -void -TEAH_acc_confirmation_cb ( - void *cls, - const struct TALER_AUDITOR_DepositConfirmationResponse *dcr); - - /** * Iterate over all available auditors for @a h, calling * @a ac and giving it a chance to start a deposit * confirmation interaction. * - * @param h exchange to go over auditors for + * @param keys the keys to go over auditors for * @param ac function to call per auditor * @param ac_cls closure for @a ac */ void -TEAH_get_auditors_for_dc (struct TALER_EXCHANGE_Handle *h, +TEAH_get_auditors_for_dc (struct TALER_EXCHANGE_Keys *keys, TEAH_AuditorCallback ac, void *ac_cls); diff --git a/src/testing/test_exchange_api.conf b/src/testing/test_exchange_api.conf index 9ed12412..b7f8c5c6 100644 --- a/src/testing/test_exchange_api.conf +++ b/src/testing/test_exchange_api.conf @@ -11,7 +11,7 @@ CURRENCY_ROUND_UNIT = EUR:0.01 [auditor] BASE_URL = "http://localhost:8083/" PORT = 8083 -PUBLIC_KEY = SA7JVMCW3MMN7SYAWJ9AB0BGJDX6MP3PNN2JWQ3T8233MDSQC7Z0 +PUBLIC_KEY = T0XJ9QZ59YDN7QG3RE40SB2HY7W0ASR1EKF4WZDGZ1G159RSQC80 TINY_AMOUNT = EUR:0.01 [auditordb-postgres] diff --git a/src/testing/test_exchange_api_home/taler/auditor/offline-keys/auditor.priv b/src/testing/test_exchange_api_home/taler/auditor/offline-keys/auditor.priv new file mode 100644 index 00000000..7e712e48 --- /dev/null +++ b/src/testing/test_exchange_api_home/taler/auditor/offline-keys/auditor.priv @@ -0,0 +1 @@ +G,U{~#r-H  \ No newline at end of file diff --git a/src/testing/testing_api_cmd_batch_deposit.c b/src/testing/testing_api_cmd_batch_deposit.c index 6a05071a..0a4fbd25 100644 --- a/src/testing/testing_api_cmd_batch_deposit.c +++ b/src/testing/testing_api_cmd_batch_deposit.c @@ -251,12 +251,15 @@ batch_deposit_run (void *cls, &wire_salt), GNUNET_JSON_spec_end () }; - struct TALER_EXCHANGE_Handle *exchange - = TALER_TESTING_get_exchange (is); + const char *exchange_url + = TALER_TESTING_get_exchange_url (is); (void) cmd; - if (NULL == exchange) + if (NULL == exchange_url) + { + GNUNET_break (0); return; + } memset (cdds, 0, sizeof (cdds)); @@ -383,13 +386,16 @@ batch_deposit_run (void *cls, .refund_deadline = ds->refund_deadline }; - ds->dh = TALER_EXCHANGE_batch_deposit (exchange, - &dcd, - ds->num_coins, - cdds, - &batch_deposit_cb, - ds, - &ec); + ds->dh = TALER_EXCHANGE_batch_deposit ( + TALER_TESTING_interpreter_get_context (is), + exchange_url, + TALER_TESTING_get_keys (is), + &dcd, + ds->num_coins, + cdds, + &batch_deposit_cb, + ds, + &ec); } if (NULL == ds->dh) { diff --git a/src/testing/testing_api_cmd_deposit.c b/src/testing/testing_api_cmd_deposit.c index 3d5c00ab..f2a3a269 100644 --- a/src/testing/testing_api_cmd_deposit.c +++ b/src/testing/testing_api_cmd_deposit.c @@ -98,7 +98,7 @@ struct DepositState /** * Deposit handle while operation is running. */ - struct TALER_EXCHANGE_DepositHandle *dh; + struct TALER_EXCHANGE_BatchDepositHandle *dh; /** * Timestamp of the /deposit operation in the wallet (contract signing time). @@ -215,7 +215,7 @@ do_retry (void *cls) */ static void deposit_cb (void *cls, - const struct TALER_EXCHANGE_DepositResult *dr) + const struct TALER_EXCHANGE_BatchDepositResult *dr) { struct DepositState *ds = cls; @@ -254,10 +254,11 @@ deposit_cb (void *cls, } if (MHD_HTTP_OK == dr->hr.http_status) { + GNUNET_assert (1 == dr->details.ok.num_signatures); ds->deposit_succeeded = GNUNET_YES; ds->exchange_timestamp = dr->details.ok.deposit_timestamp; ds->exchange_pub = *dr->details.ok.exchange_pub; - ds->exchange_sig = *dr->details.ok.exchange_sig; + ds->exchange_sig = dr->details.ok.exchange_sigs[0]; } TALER_TESTING_interpreter_next (ds->is); } @@ -296,12 +297,15 @@ deposit_run (void *cls, &wire_salt), GNUNET_JSON_spec_end () }; - struct TALER_EXCHANGE_Handle *exchange - = TALER_TESTING_get_exchange (is); + const char *exchange_url + = TALER_TESTING_get_exchange_url (is); (void) cmd; - if (NULL == exchange) + if (NULL == exchange_url) + { + GNUNET_break (0); return; + } ds->is = is; if (NULL != ds->deposit_reference) { @@ -469,12 +473,16 @@ deposit_run (void *cls, .refund_deadline = ds->refund_deadline }; - ds->dh = TALER_EXCHANGE_deposit (exchange, - &dcd, - &cdd, - &deposit_cb, - ds, - &ec); + ds->dh = TALER_EXCHANGE_batch_deposit ( + TALER_TESTING_interpreter_get_context (is), + exchange_url, + TALER_TESTING_get_keys (is), + &dcd, + 1, + &cdd, + &deposit_cb, + ds, + &ec); } if (NULL == ds->dh) { @@ -505,7 +513,7 @@ deposit_cleanup (void *cls, { TALER_TESTING_command_incomplete (ds->is, cmd->label); - TALER_EXCHANGE_deposit_cancel (ds->dh); + TALER_EXCHANGE_batch_deposit_cancel (ds->dh); ds->dh = NULL; } if (NULL != ds->retry_task) diff --git a/src/testing/testing_api_cmd_get_exchange.c b/src/testing/testing_api_cmd_get_exchange.c index 2fc8ba77..2822616c 100644 --- a/src/testing/testing_api_cmd_get_exchange.c +++ b/src/testing/testing_api_cmd_get_exchange.c @@ -189,7 +189,7 @@ get_exchange_traits (void *cls, { struct GetExchangeState *ges = cls; unsigned int off = (NULL == ges->master_priv_file) ? 1 : 0; - const struct TALER_EXCHANGE_Keys *keys + struct TALER_EXCHANGE_Keys *keys = TALER_EXCHANGE_get_keys (ges->exchange); if (NULL != keys) @@ -198,6 +198,7 @@ get_exchange_traits (void *cls, TALER_TESTING_make_trait_master_priv (&ges->master_priv), TALER_TESTING_make_trait_master_pub (&keys->master_pub), TALER_TESTING_make_trait_exchange (ges->exchange), + TALER_TESTING_make_trait_keys (keys), TALER_TESTING_make_trait_exchange_url (ges->exchange_url), TALER_TESTING_trait_end () }; diff --git a/src/testing/testing_api_traits.c b/src/testing/testing_api_traits.c index 27eef5a5..d00a8d8c 100644 --- a/src/testing/testing_api_traits.c +++ b/src/testing/testing_api_traits.c @@ -129,4 +129,32 @@ TALER_TESTING_get_exchange_url (struct TALER_TESTING_Interpreter *is) } +struct TALER_EXCHANGE_Keys * +TALER_TESTING_get_keys ( + struct TALER_TESTING_Interpreter *is) +{ + struct TALER_EXCHANGE_Keys *keys; + const struct TALER_TESTING_Command *exchange_cmd; + + exchange_cmd + = TALER_TESTING_interpreter_get_command (is, + "exchange"); + if (NULL == exchange_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return NULL; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_keys (exchange_cmd, + &keys)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return NULL; + } + return keys; +} + + /* end of testing_api_traits.c */ -- cgit v1.2.3