From f5ce22ddf6da6aae6a9077dba122013c1dbc55d9 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 21 Jun 2023 09:00:58 +0200 Subject: [PATCH] -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 diff --git a/src/include/taler_auditor_service.h b/src/include/taler_auditor_service.h index 2c6685c1c..3d8ca9efb 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 175d25e66..2c9f58596 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 529a2d019..2c9031428 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 21479c106..0b0f4dd4d 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 8acf59467..897dfe60f 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 000000000..ede702a0d --- /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 318b63f94..000000000 --- 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 7ff5bfcdb..000000000 --- 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 0d9bf0416..4d245b077 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 1b4f2b17d..dcd542ad8 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 2e9961c36..e1ae8ba54 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 () };