refactoring mint API, mostly done (compiles again, /keys might even work)
This commit is contained in:
parent
6f02d4e355
commit
5740506b24
@ -170,6 +170,18 @@ struct TALER_MasterPublicKeyP
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Type of the public key used by the auditor.
|
||||||
|
*/
|
||||||
|
struct TALER_AuditorPublicKeyP
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Taler uses EdDSA for the auditor's signing key.
|
||||||
|
*/
|
||||||
|
struct GNUNET_CRYPTO_EddsaPublicKey eddsa_pub;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Type of the offline master public keys used by the mint.
|
* @brief Type of the offline master public keys used by the mint.
|
||||||
*/
|
*/
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
* @file include/taler_mint_service.h
|
* @file include/taler_mint_service.h
|
||||||
* @brief C interface of libtalermint, a C library to use mint's HTTP API
|
* @brief C interface of libtalermint, a C library to use mint's HTTP API
|
||||||
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||||
|
* @author Christian Grothoff
|
||||||
*/
|
*/
|
||||||
#ifndef _TALER_MINT_SERVICE_H
|
#ifndef _TALER_MINT_SERVICE_H
|
||||||
#define _TALER_MINT_SERVICE_H
|
#define _TALER_MINT_SERVICE_H
|
||||||
@ -24,14 +25,114 @@
|
|||||||
#include "taler_util.h"
|
#include "taler_util.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Handle to this library context
|
* @brief Handle to this library context. This is where the
|
||||||
|
* main event loop logic lives.
|
||||||
*/
|
*/
|
||||||
struct TALER_MINT_Context;
|
struct TALER_MINT_Context;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Handle to the mint
|
* Initialise a context. A context should be used for each thread and should
|
||||||
|
* not be shared among multiple threads.
|
||||||
|
*
|
||||||
|
* @return the context, NULL on error (failure to initialize)
|
||||||
*/
|
*/
|
||||||
struct TALER_MINT_Handle;
|
struct TALER_MINT_Context *
|
||||||
|
TALER_MINT_init (void);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the information for a select() call to wait until
|
||||||
|
* #TALER_MINT_perform() is ready again. Note that calling
|
||||||
|
* any other TALER_MINT-API may also imply that the library
|
||||||
|
* is again ready for #TALER_MINT_perform().
|
||||||
|
*
|
||||||
|
* Basically, a client should use this API to prepare for select(),
|
||||||
|
* then block on select(), then call #TALER_MINT_perform() and then
|
||||||
|
* start again until the work with the context is done.
|
||||||
|
*
|
||||||
|
* This function will NOT zero out the sets and assumes that @a max_fd
|
||||||
|
* and @a timeout are already set to minimal applicable values. It is
|
||||||
|
* safe to give this API FD-sets and @a max_fd and @a timeout that are
|
||||||
|
* already initialized to some other descriptors that need to go into
|
||||||
|
* the select() call.
|
||||||
|
*
|
||||||
|
* @param ctx context to get the event loop information for
|
||||||
|
* @param read_fd_set will be set for any pending read operations
|
||||||
|
* @param write_fd_set will be set for any pending write operations
|
||||||
|
* @param except_fd_set is here because curl_multi_fdset() has this argument
|
||||||
|
* @param max_fd set to the highest FD included in any set;
|
||||||
|
* if the existing sets have no FDs in it, the initial
|
||||||
|
* value should be "-1". (Note that `max_fd + 1` will need
|
||||||
|
* to be passed to select().)
|
||||||
|
* @param timeout set to the timeout in milliseconds (!); -1 means
|
||||||
|
* no timeout (NULL, blocking forever is OK), 0 means to
|
||||||
|
* proceed immediately with #TALER_MINT_perform().
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
TALER_MINT_get_select_info (struct TALER_MINT_Context *ctx,
|
||||||
|
fd_set *read_fd_set,
|
||||||
|
fd_set *write_fd_set,
|
||||||
|
fd_set *except_fd_set,
|
||||||
|
int *max_fd,
|
||||||
|
long *timeout);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the main event loop for the Taler interaction.
|
||||||
|
*
|
||||||
|
* @param ctx the library context
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
TALER_MINT_perform (struct TALER_MINT_Context *ctx);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanup library initialisation resources. This function should be called
|
||||||
|
* after using this library to cleanup the resources occupied during library's
|
||||||
|
* initialisation.
|
||||||
|
*
|
||||||
|
* @param ctx the library context
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
TALER_MINT_fini (struct TALER_MINT_Context *ctx);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of possible options to be passed to
|
||||||
|
* #TALER_MINT_connect().
|
||||||
|
*/
|
||||||
|
enum TALER_MINT_Option
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Terminator (end of option list).
|
||||||
|
*/
|
||||||
|
TALER_MINT_OPTION_END = 0
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information we get from the mint about auditors.
|
||||||
|
*/
|
||||||
|
struct TALER_MINT_AuditorInformation
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Public key of the auditing institution.
|
||||||
|
*/
|
||||||
|
struct TALER_AuditorPublicKeyP auditor_pub;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL of the auditing institution. The application must check that
|
||||||
|
* this is an acceptable auditor for its purpose and also verify
|
||||||
|
* that the @a auditor_pub matches the auditor's public key given at
|
||||||
|
* that website. We expect that in practice software is going to
|
||||||
|
* often ship with an initial list of accepted auditors, just like
|
||||||
|
* browsers ship with a CA root store.
|
||||||
|
*/
|
||||||
|
const char *auditor_url;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Mint's signature key
|
* @brief Mint's signature key
|
||||||
@ -56,7 +157,7 @@ struct TALER_MINT_SigningPublicKey
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Mint's denomination key
|
* @brief Public information about a mint's denomination key
|
||||||
*/
|
*/
|
||||||
struct TALER_MINT_DenomPublicKey
|
struct TALER_MINT_DenomPublicKey
|
||||||
{
|
{
|
||||||
@ -104,45 +205,94 @@ struct TALER_MINT_DenomPublicKey
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialise a context. A context should be used for each thread and should
|
* Information about keys from the mint.
|
||||||
* not be shared among multiple threads.
|
|
||||||
*
|
|
||||||
* @return the context
|
|
||||||
*/
|
*/
|
||||||
struct TALER_MINT_Context *
|
struct TALER_MINT_Keys
|
||||||
TALER_MINT_init (void);
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Long-term offline signing key of the mint.
|
||||||
|
*/
|
||||||
|
struct TALER_MasterPublicKeyP master_pub;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of the mint's online signing keys.
|
||||||
|
*/
|
||||||
|
struct TALER_MINT_SigningPublicKey *sign_keys;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of the mint's denomination keys.
|
||||||
|
*/
|
||||||
|
struct TALER_MINT_DenomPublicKey *denom_keys;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of the keys of the auditors of the mint.
|
||||||
|
*/
|
||||||
|
struct TALER_AuditorPublicKeyP *auditors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Length of the @e sign_keys array.
|
||||||
|
*/
|
||||||
|
unsigned int num_sign_keys;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Length of the @e denom_keys array.
|
||||||
|
*/
|
||||||
|
unsigned int num_denom_keys;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Length of the @e auditors array.
|
||||||
|
*/
|
||||||
|
unsigned int num_auditors;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleanup library initialisation resources. This function should be called
|
* Function called with information about who is auditing
|
||||||
* after using this library to cleanup the resources occupied during library's
|
* a particular mint and what key the mint is using.
|
||||||
* initialisation.
|
|
||||||
*
|
*
|
||||||
* @param ctx the library context
|
* @param cls closure
|
||||||
|
* @param keys information about the various keys used
|
||||||
|
* by the mint
|
||||||
*/
|
*/
|
||||||
void
|
typedef void
|
||||||
TALER_MINT_cleanup (struct TALER_MINT_Context *ctx);
|
(*TALER_MINT_CertificationCallback) (void *cls,
|
||||||
|
const struct TALER_MINT_Keys *keys);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialise a connection to the mint.
|
* @brief Handle to the mint. This is where we interact with
|
||||||
|
* a particular mint and keep the per-mint information.
|
||||||
|
*/
|
||||||
|
struct TALER_MINT_Handle;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise a connection to the mint. Will connect to the
|
||||||
|
* mint and obtain information about the mint's master public
|
||||||
|
* key and the mint's auditor. The respective information will
|
||||||
|
* be passed to the @a cert_cb once available, and all future
|
||||||
|
* interactions with the mint will be checked to be signed
|
||||||
|
* (where appropriate) by the respective master key.
|
||||||
*
|
*
|
||||||
* @param ctx the context
|
* @param ctx the context
|
||||||
* @param hostname the hostname of the mint
|
* @param url HTTP base URL for the mint
|
||||||
* @param port the point where the mint's HTTP service is running. If port is
|
* @param cert_cb function to call with the mint's certification information
|
||||||
* given as 0, ports 80 or 443 are chosen depending on @a url.
|
* @param cert_cb_cls closure for @a cert_cb
|
||||||
* @param master_key the public master key of the mint. This is used to verify the
|
* @param ... list of additional arguments, terminated by #TALER_MINT_OPTION_END.
|
||||||
* responses of the mint.
|
|
||||||
* @return the mint handle; NULL upon error
|
* @return the mint handle; NULL upon error
|
||||||
*/
|
*/
|
||||||
struct TALER_MINT_Handle *
|
struct TALER_MINT_Handle *
|
||||||
TALER_MINT_connect (struct TALER_MINT_Context *ctx,
|
TALER_MINT_connect (struct TALER_MINT_Context *ctx,
|
||||||
const char *hostname,
|
const char *url,
|
||||||
uint16_t port,
|
TALER_MINT_CertificationCallback cert_cb,
|
||||||
const struct TALER_MasterPublicKeyP *master_key);
|
void *cert_cb_cls,
|
||||||
|
...);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disconnect from the mint
|
* Disconnect from the mint.
|
||||||
*
|
*
|
||||||
* @param mint the mint handle
|
* @param mint the mint handle
|
||||||
*/
|
*/
|
||||||
@ -150,69 +300,9 @@ void
|
|||||||
TALER_MINT_disconnect (struct TALER_MINT_Handle *mint);
|
TALER_MINT_disconnect (struct TALER_MINT_Handle *mint);
|
||||||
|
|
||||||
|
|
||||||
/**
|
#if 0
|
||||||
* @brief A handle to get the keys of a mint
|
|
||||||
*/
|
|
||||||
struct TALER_MINT_KeysGetHandle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Functions of this type are called to signal completion of an asynchronous call.
|
|
||||||
*
|
|
||||||
* @param cls closure
|
|
||||||
* @param emsg if the asynchronous call could not be completed due to an error,
|
|
||||||
* this parameter contains a human readable error message
|
|
||||||
*/
|
|
||||||
typedef void
|
|
||||||
(*TALER_MINT_ContinuationCallback) (void *cls,
|
|
||||||
const char *emsg);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Functions of this type are called to provide the retrieved signing and
|
|
||||||
* denomination keys of the mint. No TALER_MINT_*() functions should be called
|
|
||||||
* in this callback.
|
|
||||||
*
|
|
||||||
* @param cls closure passed to TALER_MINT_keys_get()
|
|
||||||
* @param sign_keys NULL-terminated array of pointers to the mint's signing
|
|
||||||
* keys. NULL if no signing keys are retrieved.
|
|
||||||
* @param denom_keys NULL-terminated array of pointers to the mint's
|
|
||||||
* denomination keys; will be NULL if no signing keys are retrieved.
|
|
||||||
*/
|
|
||||||
typedef void
|
|
||||||
(*TALER_MINT_KeysGetCallback) (void *cls,
|
|
||||||
struct TALER_MINT_SigningPublicKey **sign_keys,
|
|
||||||
struct TALER_MINT_DenomPublicKey **denom_keys);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the signing and denomination key of the mint.
|
|
||||||
*
|
|
||||||
* @param mint handle to the mint
|
|
||||||
* @param cb the callback to call with the keys
|
|
||||||
* @param cb_cls closure for the @a cb callback
|
|
||||||
* @param cont_cb the callback to call after completing this asynchronous call
|
|
||||||
* @param cont_cls the closure for the @a cont_cb callback
|
|
||||||
* @return a handle to this asynchronous call; NULL upon eror
|
|
||||||
*/
|
|
||||||
struct TALER_MINT_KeysGetHandle *
|
|
||||||
TALER_MINT_keys_get (struct TALER_MINT_Handle *mint,
|
|
||||||
TALER_MINT_KeysGetCallback cb,
|
|
||||||
void *cb_cls,
|
|
||||||
TALER_MINT_ContinuationCallback cont_cb,
|
|
||||||
void *cont_cls);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancel the asynchronous call initiated by TALER_MINT_keys_get(). This should
|
|
||||||
* not be called if either of the @a TALER_MINT_KeysGetCallback or @a
|
|
||||||
* TALER_MINT_ContinuationCallback passed to TALER_MINT_keys_get() have been
|
|
||||||
* called.
|
|
||||||
*
|
|
||||||
* @param get the handle for retrieving the keys
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
TALER_MINT_keys_get_cancel (struct TALER_MINT_KeysGetHandle *get);
|
|
||||||
|
|
||||||
|
|
||||||
|
// FIXME: API below with json-crap is too low-level...
|
||||||
/**
|
/**
|
||||||
* @brief A Deposit Handle
|
* @brief A Deposit Handle
|
||||||
*/
|
*/
|
||||||
@ -221,7 +311,7 @@ struct TALER_MINT_DepositHandle;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Callbacks of this type are used to serve the result of submitting a deposit
|
* Callbacks of this type are used to serve the result of submitting a deposit
|
||||||
* permission object to a mint
|
* permission object to a mint.
|
||||||
*
|
*
|
||||||
* @param cls closure
|
* @param cls closure
|
||||||
* @param status 1 for successful deposit, 2 for retry, 0 for failure
|
* @param status 1 for successful deposit, 2 for retry, 0 for failure
|
||||||
@ -256,7 +346,6 @@ TALER_MINT_deposit_submit_json (struct TALER_MINT_Handle *mint,
|
|||||||
json_t *deposit_obj);
|
json_t *deposit_obj);
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/**
|
/**
|
||||||
* Submit a deposit permission to the mint and get the mint's response.
|
* Submit a deposit permission to the mint and get the mint's response.
|
||||||
*
|
*
|
||||||
@ -291,7 +380,6 @@ TALER_MINT_deposit_submit_json_ (struct TALER_MINT_Handle *mint,
|
|||||||
const struct GNUNET_HashCode *h_wire,
|
const struct GNUNET_HashCode *h_wire,
|
||||||
const struct TALER_CoinSignature *csig,
|
const struct TALER_CoinSignature *csig,
|
||||||
json_t *wire_obj);
|
json_t *wire_obj);
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -303,4 +391,7 @@ TALER_MINT_deposit_submit_json_ (struct TALER_MINT_Handle *mint,
|
|||||||
void
|
void
|
||||||
TALER_MINT_deposit_submit_cancel (struct TALER_MINT_DepositHandle *deposit);
|
TALER_MINT_deposit_submit_cancel (struct TALER_MINT_DepositHandle *deposit);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif /* _TALER_MINT_SERVICE_H */
|
#endif /* _TALER_MINT_SERVICE_H */
|
||||||
|
@ -14,7 +14,8 @@ libtalermint_la_LDFLAGS = \
|
|||||||
-no-undefined
|
-no-undefined
|
||||||
|
|
||||||
libtalermint_la_SOURCES = \
|
libtalermint_la_SOURCES = \
|
||||||
mint_api.c
|
mint_api_context.c mint_api_context.h \
|
||||||
|
mint_api_handle.c mint_api_handle.h
|
||||||
|
|
||||||
libtalermint_la_LIBADD = \
|
libtalermint_la_LIBADD = \
|
||||||
-lgnunetutil \
|
-lgnunetutil \
|
||||||
@ -32,4 +33,3 @@ test_mint_api_LDADD = \
|
|||||||
$(top_builddir)/src/util/libtalerutil.la \
|
$(top_builddir)/src/util/libtalerutil.la \
|
||||||
-lgnunetutil \
|
-lgnunetutil \
|
||||||
-ljansson
|
-ljansson
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
370
src/mint-lib/mint_api_context.c
Normal file
370
src/mint-lib/mint_api_context.c
Normal file
@ -0,0 +1,370 @@
|
|||||||
|
/*
|
||||||
|
This file is part of TALER
|
||||||
|
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||||
|
|
||||||
|
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, If not, see
|
||||||
|
<http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @file mint-lib/mint_api_context.c
|
||||||
|
* @brief Implementation of the context part of the mint's HTTP API
|
||||||
|
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||||
|
* @author Christian Grothoff
|
||||||
|
*/
|
||||||
|
#include "platform.h"
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include "taler_mint_service.h"
|
||||||
|
#include "mint_api_context.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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));
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Failsafe flag. Raised if our constructor fails to initialize
|
||||||
|
* the Curl library.
|
||||||
|
*/
|
||||||
|
static int TALER_MINT_curl_fail;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Jobs are CURL requests running within a `struct TALER_MINT_Context`.
|
||||||
|
*/
|
||||||
|
struct MAC_Job
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We keep jobs in a DLL.
|
||||||
|
*/
|
||||||
|
struct MAC_Job *next;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We keep jobs in a DLL.
|
||||||
|
*/
|
||||||
|
struct MAC_Job *prev;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Easy handle of the job.
|
||||||
|
*/
|
||||||
|
CURL *easy_handle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context this job runs in.
|
||||||
|
*/
|
||||||
|
struct TALER_MINT_Context *ctx;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to call upon completion.
|
||||||
|
*/
|
||||||
|
MAC_JobCompletionCallback jcc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closure for @e jcc.
|
||||||
|
*/
|
||||||
|
void *jcc_cls;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context
|
||||||
|
*/
|
||||||
|
struct TALER_MINT_Context
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Curl multi handle
|
||||||
|
*/
|
||||||
|
CURLM *multi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Curl share handle
|
||||||
|
*/
|
||||||
|
CURLSH *share;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We keep jobs in a DLL.
|
||||||
|
*/
|
||||||
|
struct MAC_Job *jobs_head;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We keep jobs in a DLL.
|
||||||
|
*/
|
||||||
|
struct MAC_Job *jobs_tail;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise this library. This function should be called before using any of
|
||||||
|
* the following functions.
|
||||||
|
*
|
||||||
|
* @return library context
|
||||||
|
*/
|
||||||
|
struct TALER_MINT_Context *
|
||||||
|
TALER_MINT_init ()
|
||||||
|
{
|
||||||
|
struct TALER_MINT_Context *ctx;
|
||||||
|
CURLM *multi;
|
||||||
|
CURLSH *share;
|
||||||
|
|
||||||
|
if (TALER_MINT_curl_fail)
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"Curl was not initialised properly\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (NULL == (multi = curl_multi_init ()))
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"Failed to create a Curl multi handle\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (NULL == (share = curl_share_init ()))
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"Failed to create a Curl share handle\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ctx = GNUNET_new (struct TALER_MINT_Context);
|
||||||
|
ctx->multi = multi;
|
||||||
|
ctx->share = share;
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule a CURL request to be executed and call the given @a jcc
|
||||||
|
* upon its completion. Note that the context will make use of the
|
||||||
|
* CURLOPT_PRIVATE facility of the CURL @a eh. Applications can
|
||||||
|
* instead use #MAC_easy_to_closure to extract the @a jcc_cls argument
|
||||||
|
* from a valid @a eh afterwards.
|
||||||
|
*
|
||||||
|
* @param ctx context to execute the job in
|
||||||
|
* @param eh curl easy handle for the request, will
|
||||||
|
* be executed AND cleaned up
|
||||||
|
* @param jcc callback to invoke upon completion
|
||||||
|
* @param jcc_cls closure for @a jcc
|
||||||
|
*/
|
||||||
|
struct MAC_Job *
|
||||||
|
MAC_job_add (struct TALER_MINT_Context *ctx,
|
||||||
|
CURL *eh,
|
||||||
|
MAC_JobCompletionCallback jcc,
|
||||||
|
void *jcc_cls)
|
||||||
|
{
|
||||||
|
struct MAC_Job *job;
|
||||||
|
|
||||||
|
job = GNUNET_new (struct MAC_Job);
|
||||||
|
job->easy_handle = eh;
|
||||||
|
job->ctx = ctx;
|
||||||
|
job->jcc = jcc;
|
||||||
|
job->jcc_cls = jcc_cls;
|
||||||
|
GNUNET_CONTAINER_DLL_insert (ctx->jobs_head,
|
||||||
|
ctx->jobs_tail,
|
||||||
|
job);
|
||||||
|
GNUNET_assert (CURLE_OK ==
|
||||||
|
curl_easy_setopt (eh,
|
||||||
|
CURLOPT_PRIVATE,
|
||||||
|
job));
|
||||||
|
GNUNET_assert (CURLE_OK ==
|
||||||
|
curl_easy_setopt (eh,
|
||||||
|
CURLOPT_SHARE,
|
||||||
|
ctx->share));
|
||||||
|
GNUNET_assert (CURLM_OK ==
|
||||||
|
curl_multi_add_handle (ctx->multi,
|
||||||
|
eh));
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the `jcc_cls` argument from an `eh` that was
|
||||||
|
* given to #MAC_job_add().
|
||||||
|
*
|
||||||
|
* @param eh easy handle that was used
|
||||||
|
* @return the `jcc_cls` that was given to #MAC_job_add().
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
MAC_easy_to_closure (CURL *eh)
|
||||||
|
{
|
||||||
|
struct MAC_Job *job;
|
||||||
|
|
||||||
|
GNUNET_assert (CURLE_OK ==
|
||||||
|
curl_easy_getinfo (eh,
|
||||||
|
CURLINFO_PRIVATE,
|
||||||
|
(char *) &job));
|
||||||
|
return job->jcc_cls;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel a job. Must only be called before the job completion
|
||||||
|
* callback is called for the respective job.
|
||||||
|
*
|
||||||
|
* @param job job to cancel
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
MAC_job_cancel (struct MAC_Job *job)
|
||||||
|
{
|
||||||
|
struct TALER_MINT_Context *ctx = job->ctx;
|
||||||
|
|
||||||
|
GNUNET_CONTAINER_DLL_remove (ctx->jobs_head,
|
||||||
|
ctx->jobs_tail,
|
||||||
|
job);
|
||||||
|
GNUNET_assert (CURLM_OK ==
|
||||||
|
curl_multi_remove_handle (ctx->multi,
|
||||||
|
job->easy_handle));
|
||||||
|
curl_easy_cleanup (job->easy_handle);
|
||||||
|
GNUNET_free (job);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the main event loop for the Taler interaction.
|
||||||
|
*
|
||||||
|
* @param ctx the library context
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
TALER_MINT_perform (struct TALER_MINT_Context *ctx)
|
||||||
|
{
|
||||||
|
CURLMsg *cmsg;
|
||||||
|
struct MAC_Job *job;
|
||||||
|
int n_running;
|
||||||
|
int n_completed;
|
||||||
|
|
||||||
|
(void) curl_multi_perform (ctx->multi,
|
||||||
|
&n_running);
|
||||||
|
while (NULL != (cmsg = curl_multi_info_read (ctx->multi,
|
||||||
|
&n_completed)))
|
||||||
|
{
|
||||||
|
/* Only documented return value is CURLMSG_DONE */
|
||||||
|
GNUNET_break (CURLMSG_DONE == cmsg->msg);
|
||||||
|
GNUNET_assert (CURLE_OK ==
|
||||||
|
curl_easy_getinfo (cmsg->easy_handle,
|
||||||
|
CURLINFO_PRIVATE,
|
||||||
|
(char *) &job));
|
||||||
|
GNUNET_assert (job->ctx == ctx);
|
||||||
|
job->jcc (job->jcc_cls);
|
||||||
|
MAC_job_cancel (job);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the information for a select() call to wait until
|
||||||
|
* #TALER_MINT_perform() is ready again. Note that calling
|
||||||
|
* any other TALER_MINT-API may also imply that the library
|
||||||
|
* is again ready for #TALER_MINT_perform().
|
||||||
|
*
|
||||||
|
* Basically, a client should use this API to prepare for select(),
|
||||||
|
* then block on select(), then call #TALER_MINT_perform() and then
|
||||||
|
* start again until the work with the context is done.
|
||||||
|
*
|
||||||
|
* This function will NOT zero out the sets and assumes that @a max_fd
|
||||||
|
* and @a timeout are already set to minimal applicable values. It is
|
||||||
|
* safe to give this API FD-sets and @a max_fd and @a timeout that are
|
||||||
|
* already initialized to some other descriptors that need to go into
|
||||||
|
* the select() call.
|
||||||
|
*
|
||||||
|
* @param ctx context to get the event loop information for
|
||||||
|
* @param read_fd_set will be set for any pending read operations
|
||||||
|
* @param write_fd_set will be set for any pending write operations
|
||||||
|
* @param except_fd_set is here because curl_multi_fdset() has this argument
|
||||||
|
* @param max_fd set to the highest FD included in any set;
|
||||||
|
* if the existing sets have no FDs in it, the initial
|
||||||
|
* value should be "-1". (Note that `max_fd + 1` will need
|
||||||
|
* to be passed to select().)
|
||||||
|
* @param timeout set to the timeout in milliseconds (!); -1 means
|
||||||
|
* no timeout (NULL, blocking forever is OK), 0 means to
|
||||||
|
* proceed immediately with #TALER_MINT_perform().
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
TALER_MINT_get_select_info (struct TALER_MINT_Context *ctx,
|
||||||
|
fd_set *read_fd_set,
|
||||||
|
fd_set *write_fd_set,
|
||||||
|
fd_set *except_fd_set,
|
||||||
|
int *max_fd,
|
||||||
|
long *timeout)
|
||||||
|
{
|
||||||
|
GNUNET_assert (CURLM_OK ==
|
||||||
|
curl_multi_fdset (ctx->multi,
|
||||||
|
read_fd_set,
|
||||||
|
write_fd_set,
|
||||||
|
except_fd_set,
|
||||||
|
max_fd));
|
||||||
|
GNUNET_assert (CURLM_OK ==
|
||||||
|
curl_multi_timeout (ctx->multi,
|
||||||
|
timeout));
|
||||||
|
if ( (-1 == (*timeout)) &&
|
||||||
|
(NULL != ctx->jobs_head) )
|
||||||
|
*timeout = 1000 * 60 * 5; /* curl is not always good about giving timeouts */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanup library initialisation resources. This function should be called
|
||||||
|
* after using this library to cleanup the resources occupied during library's
|
||||||
|
* initialisation.
|
||||||
|
*
|
||||||
|
* @param ctx the library context
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
TALER_MINT_fini (struct TALER_MINT_Context *ctx)
|
||||||
|
{
|
||||||
|
/* all jobs must have been cancelled at this time, assert this */
|
||||||
|
GNUNET_assert (NULL == ctx->jobs_head);
|
||||||
|
curl_share_cleanup (ctx->share);
|
||||||
|
curl_multi_cleanup (ctx->multi);
|
||||||
|
GNUNET_free (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initial global setup logic, specifically runs the Curl setup.
|
||||||
|
*/
|
||||||
|
__attribute__ ((constructor))
|
||||||
|
void
|
||||||
|
TALER_MINT_constructor__ (void)
|
||||||
|
{
|
||||||
|
CURLcode ret;
|
||||||
|
|
||||||
|
if (CURLE_OK != (ret = curl_global_init (CURL_GLOBAL_DEFAULT)))
|
||||||
|
{
|
||||||
|
CURL_STRERROR (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"curl_global_init",
|
||||||
|
ret);
|
||||||
|
TALER_MINT_curl_fail = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans up after us, specifically runs the Curl cleanup.
|
||||||
|
*/
|
||||||
|
__attribute__ ((destructor))
|
||||||
|
void
|
||||||
|
TALER_MINT_destructor__ (void)
|
||||||
|
{
|
||||||
|
if (TALER_MINT_curl_fail)
|
||||||
|
return;
|
||||||
|
curl_global_cleanup ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end of mint_api_context.c */
|
83
src/mint-lib/mint_api_context.h
Normal file
83
src/mint-lib/mint_api_context.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
This file is part of TALER
|
||||||
|
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||||
|
|
||||||
|
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, If not, see
|
||||||
|
<http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @file mint-lib/mint_api_context.h
|
||||||
|
* @brief Internal interface to the context part of the mint's HTTP API
|
||||||
|
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||||
|
* @author Christian Grothoff
|
||||||
|
*/
|
||||||
|
#include "platform.h"
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include <gnunet/gnunet_util_lib.h>
|
||||||
|
#include "taler_mint_service.h"
|
||||||
|
#include "taler_signatures.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entry in the context's job queue.
|
||||||
|
*/
|
||||||
|
struct MAC_Job;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to call upon completion of a job.
|
||||||
|
*/
|
||||||
|
typedef void
|
||||||
|
(*MAC_JobCompletionCallback)(void *cls);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule a CURL request to be executed and call the given @a jcc
|
||||||
|
* upon its completion. Note that the context will make use of the
|
||||||
|
* CURLOPT_PRIVATE facility of the CURL @a eh. Applications can
|
||||||
|
* instead use #MAC_easy_to_closure to extract the @a jcc_cls argument
|
||||||
|
* from a valid @a eh afterwards.
|
||||||
|
*
|
||||||
|
* @param ctx context to execute the job in
|
||||||
|
* @param eh curl easy handle for the request, will
|
||||||
|
* be executed AND cleaned up
|
||||||
|
* @param jcc callback to invoke upon completion
|
||||||
|
* @param jcc_cls closure for @a jcc
|
||||||
|
*/
|
||||||
|
struct MAC_Job *
|
||||||
|
MAC_job_add (struct TALER_MINT_Context *ctx,
|
||||||
|
CURL *eh,
|
||||||
|
MAC_JobCompletionCallback jcc,
|
||||||
|
void *jcc_cls);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the `jcc_cls` argument from an `eh` that was
|
||||||
|
* given to #MAC_job_add().
|
||||||
|
*
|
||||||
|
* @param eh easy handle that was used
|
||||||
|
* @return the `jcc_cls` that was given to #MAC_job_add().
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
MAC_easy_to_closure (CURL *eh);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel a job. Must only be called before the job completion
|
||||||
|
* callback is called for the respective job.
|
||||||
|
*
|
||||||
|
* @param job job to cancel
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
MAC_job_cancel (struct MAC_Job *job);
|
||||||
|
|
||||||
|
|
||||||
|
/* end of mint_api_context.h */
|
821
src/mint-lib/mint_api_handle.c
Normal file
821
src/mint-lib/mint_api_handle.c
Normal file
@ -0,0 +1,821 @@
|
|||||||
|
/*
|
||||||
|
This file is part of TALER
|
||||||
|
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||||
|
|
||||||
|
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, If not, see
|
||||||
|
<http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @file mint-lib/mint_api_handle.c
|
||||||
|
* @brief Implementation of the "handle" component of the mint's HTTP API
|
||||||
|
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||||
|
* @author Christian Grothoff
|
||||||
|
*/
|
||||||
|
#include "platform.h"
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include <jansson.h>
|
||||||
|
#include <gnunet/gnunet_util_lib.h>
|
||||||
|
#include "taler_mint_service.h"
|
||||||
|
#include "taler_signatures.h"
|
||||||
|
#include "mint_api_context.h"
|
||||||
|
#include "mint_api_handle.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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));
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print JSON parsing related error information
|
||||||
|
*/
|
||||||
|
#define JSON_WARN(error) \
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \
|
||||||
|
"JSON parsing failed at %s:%u: %s (%s)", \
|
||||||
|
__FILE__, __LINE__, error.text, error.source)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stages of initialization for the `struct TALER_MINT_Handle`
|
||||||
|
*/
|
||||||
|
enum MintHandleState
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Just allocated.
|
||||||
|
*/
|
||||||
|
MHS_INIT = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtained the mint's certification data and keys.
|
||||||
|
*/
|
||||||
|
MHS_CERT = 1,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Failed to initialize (fatal).
|
||||||
|
*/
|
||||||
|
MHS_FAILED = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data for the request to get the /keys of a mint.
|
||||||
|
*/
|
||||||
|
struct KeysRequest;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle to the mint
|
||||||
|
*/
|
||||||
|
struct TALER_MINT_Handle
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The context of this handle
|
||||||
|
*/
|
||||||
|
struct TALER_MINT_Context *ctx;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL of the mint (i.e. "http://mint.taler.net/")
|
||||||
|
*/
|
||||||
|
char *url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to call with the mint's certification data,
|
||||||
|
* NULL if this has already been done.
|
||||||
|
*/
|
||||||
|
TALER_MINT_CertificationCallback cert_cb;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closure to pass to @e cert_cb.
|
||||||
|
*/
|
||||||
|
void *cert_cb_cls;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data for the request to get the /keys of a mint,
|
||||||
|
* NULL once we are past stage #MHS_INIT.
|
||||||
|
*/
|
||||||
|
struct KeysRequest *kr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key data of the mint, only valid if
|
||||||
|
* @e handshake_complete is past stage #MHS_CERT.
|
||||||
|
*/
|
||||||
|
struct TALER_MINT_Keys key_data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stage of the mint's initialization routines.
|
||||||
|
*/
|
||||||
|
enum MintHandleState state;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* ***************** Internal /keys fetching ************* */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data for the request to get the /keys of a mint.
|
||||||
|
*/
|
||||||
|
struct KeysRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The connection to mint this request handle will use
|
||||||
|
*/
|
||||||
|
struct TALER_MINT_Handle *mint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The url for this handle
|
||||||
|
*/
|
||||||
|
char *url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entry for this request with the `struct TALER_MINT_Context`.
|
||||||
|
*/
|
||||||
|
struct MAC_Job *job;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error buffer for Curl. Do we need this?
|
||||||
|
*/
|
||||||
|
char emsg[CURL_ERROR_SIZE];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download buffer
|
||||||
|
*/
|
||||||
|
void *buf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the download buffer
|
||||||
|
*/
|
||||||
|
size_t buf_size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error code (based on libc errno) if we failed to download
|
||||||
|
* (i.e. response too large).
|
||||||
|
*/
|
||||||
|
int eno;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback used when downloading the reply to a /keys request.
|
||||||
|
* Just appends all of the data to the `buf` in the
|
||||||
|
* `struct KeysRequest` for further processing. The size of
|
||||||
|
* the download is limited to #GNUNET_MAX_MALLOC_CHECKED, if
|
||||||
|
* the download exceeds this size, we abort with an error.
|
||||||
|
*
|
||||||
|
* @param bufptr data downloaded via HTTP
|
||||||
|
* @param size size of an item in @a bufptr
|
||||||
|
* @param nitems number of items in @a bufptr
|
||||||
|
* @param cls the `struct KeysRequest`
|
||||||
|
* @return number of bytes processed from @a bufptr
|
||||||
|
*/
|
||||||
|
static size_t
|
||||||
|
keys_download_cb (char *bufptr,
|
||||||
|
size_t size,
|
||||||
|
size_t nitems,
|
||||||
|
void *cls)
|
||||||
|
{
|
||||||
|
struct KeysRequest *kr = cls;
|
||||||
|
size_t msize;
|
||||||
|
void *buf;
|
||||||
|
|
||||||
|
if (0 == size * nitems)
|
||||||
|
{
|
||||||
|
/* Nothing (left) to do */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
msize = size * nitems;
|
||||||
|
if ( (msize + kr->buf_size) >= GNUNET_MAX_MALLOC_CHECKED)
|
||||||
|
{
|
||||||
|
kr->eno = ENOMEM;
|
||||||
|
return 0; /* signals an error to curl */
|
||||||
|
}
|
||||||
|
kr->buf = GNUNET_realloc (kr->buf,
|
||||||
|
kr->buf_size + msize);
|
||||||
|
buf = kr->buf + kr->buf_size;
|
||||||
|
memcpy (buf, bufptr, msize);
|
||||||
|
kr->buf_size += msize;
|
||||||
|
return msize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release memory occupied by a keys request.
|
||||||
|
* Note that this does not cancel the request
|
||||||
|
* itself.
|
||||||
|
*
|
||||||
|
* @param kr request to free
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
free_keys_request (struct KeysRequest *kr)
|
||||||
|
{
|
||||||
|
GNUNET_free_non_null (kr->buf);
|
||||||
|
GNUNET_free (kr->url);
|
||||||
|
GNUNET_free (kr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the timestamp encoded as ASCII string as UNIX timstamp.
|
||||||
|
* FIXME: we might want to move this function into libtalerutil.
|
||||||
|
*
|
||||||
|
* @param[out] abs successfully parsed timestamp will be returned thru this parameter
|
||||||
|
* @param tstamp_enc the ASCII encoding of the timestamp
|
||||||
|
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
parse_timestamp (struct GNUNET_TIME_Absolute *abs,
|
||||||
|
const char *tstamp_enc)
|
||||||
|
{
|
||||||
|
unsigned long tstamp;
|
||||||
|
|
||||||
|
if (1 != sscanf (tstamp_enc, "%lu", &tstamp))
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
*abs = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get_zero_ (),
|
||||||
|
GNUNET_TIME_relative_multiply
|
||||||
|
(GNUNET_TIME_UNIT_SECONDS, tstamp));
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define EXITIF(cond) \
|
||||||
|
do { \
|
||||||
|
if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a mint's signing key encoded in JSON.
|
||||||
|
*
|
||||||
|
* @param[out] sign_key where to return the result
|
||||||
|
* @param[in] sign_key_obj json to parse
|
||||||
|
* @param master_key master key to use to verify signature
|
||||||
|
* @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
|
||||||
|
* invalid or the json malformed.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
parse_json_signkey (struct TALER_MINT_SigningPublicKey *sign_key,
|
||||||
|
json_t *sign_key_obj,
|
||||||
|
const struct TALER_MasterPublicKeyP *master_key)
|
||||||
|
{
|
||||||
|
// TODO: try to simplify...
|
||||||
|
json_t *valid_from_obj;
|
||||||
|
json_t *valid_until_obj;
|
||||||
|
json_t *valid_legal_obj;
|
||||||
|
json_t *key_obj;
|
||||||
|
json_t *sig_obj;
|
||||||
|
const char *valid_from_enc;
|
||||||
|
const char *valid_until_enc;
|
||||||
|
const char *valid_legal_enc;
|
||||||
|
const char *key_enc;
|
||||||
|
const char *sig_enc;
|
||||||
|
struct TALER_MintSigningKeyValidityPS sign_key_issue;
|
||||||
|
struct GNUNET_CRYPTO_EddsaSignature sig;
|
||||||
|
struct GNUNET_TIME_Absolute valid_from;
|
||||||
|
struct GNUNET_TIME_Absolute valid_until;
|
||||||
|
struct GNUNET_TIME_Absolute valid_legal;
|
||||||
|
|
||||||
|
EXITIF (JSON_OBJECT != json_typeof (sign_key_obj));
|
||||||
|
EXITIF (NULL == (valid_from_obj = json_object_get (sign_key_obj,
|
||||||
|
"stamp_start")));
|
||||||
|
EXITIF (NULL == (valid_until_obj = json_object_get (sign_key_obj,
|
||||||
|
"stamp_expire")));
|
||||||
|
EXITIF (NULL == (valid_legal_obj = json_object_get (sign_key_obj,
|
||||||
|
"stamp_end")));
|
||||||
|
EXITIF (NULL == (key_obj = json_object_get (sign_key_obj, "key")));
|
||||||
|
EXITIF (NULL == (sig_obj = json_object_get (sign_key_obj, "master_sig")));
|
||||||
|
EXITIF (NULL == (valid_from_enc = json_string_value (valid_from_obj)));
|
||||||
|
EXITIF (NULL == (valid_until_enc = json_string_value (valid_until_obj)));
|
||||||
|
EXITIF (NULL == (valid_legal_enc = json_string_value (valid_legal_obj)));
|
||||||
|
EXITIF (NULL == (key_enc = json_string_value (key_obj)));
|
||||||
|
EXITIF (NULL == (sig_enc = json_string_value (sig_obj)));
|
||||||
|
EXITIF (GNUNET_SYSERR == parse_timestamp (&valid_from,
|
||||||
|
valid_from_enc));
|
||||||
|
EXITIF (GNUNET_SYSERR == parse_timestamp (&valid_until,
|
||||||
|
valid_until_enc));
|
||||||
|
EXITIF (GNUNET_SYSERR == parse_timestamp (&valid_legal,
|
||||||
|
valid_legal_enc));
|
||||||
|
EXITIF (52 != strlen (key_enc)); /* strlen(base32(char[32])) = 52 */
|
||||||
|
EXITIF (103 != strlen (sig_enc)); /* strlen(base32(char[64])) = 103 */
|
||||||
|
EXITIF (GNUNET_OK != GNUNET_STRINGS_string_to_data (sig_enc, 103,
|
||||||
|
&sig, sizeof (sig)));
|
||||||
|
memset (&sign_key_issue,
|
||||||
|
0,
|
||||||
|
sizeof (sign_key_issue));
|
||||||
|
EXITIF (GNUNET_SYSERR ==
|
||||||
|
GNUNET_CRYPTO_eddsa_public_key_from_string (key_enc,
|
||||||
|
52,
|
||||||
|
&sign_key_issue.signkey_pub.eddsa_pub));
|
||||||
|
sign_key_issue.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY);
|
||||||
|
sign_key_issue.purpose.size =
|
||||||
|
htonl (sizeof (sign_key_issue)
|
||||||
|
- offsetof (struct TALER_MintSigningKeyValidityPS, purpose));
|
||||||
|
sign_key_issue.master_public_key = *master_key;
|
||||||
|
sign_key_issue.start = GNUNET_TIME_absolute_hton (valid_from);
|
||||||
|
sign_key_issue.expire = GNUNET_TIME_absolute_hton (valid_until);
|
||||||
|
sign_key_issue.end = GNUNET_TIME_absolute_hton (valid_legal);
|
||||||
|
EXITIF (GNUNET_OK !=
|
||||||
|
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY,
|
||||||
|
&sign_key_issue.purpose,
|
||||||
|
&sig,
|
||||||
|
&master_key->eddsa_pub));
|
||||||
|
sign_key->valid_from = valid_from;
|
||||||
|
sign_key->valid_until = valid_until;
|
||||||
|
sign_key->key = sign_key_issue.signkey_pub;
|
||||||
|
return GNUNET_OK;
|
||||||
|
|
||||||
|
EXITIF_exit:
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse an amount given in JSON encoding.
|
||||||
|
*
|
||||||
|
* @param[in] amount_obj the amount in json
|
||||||
|
* @param[out] where to return the parsed amount
|
||||||
|
* @return #GNUNET_OK if all is well, #GNUNET_SYSERR on parse errors
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
parse_json_amount (json_t *amount_obj,
|
||||||
|
struct TALER_Amount *amt)
|
||||||
|
{
|
||||||
|
// FIXME: check for correctness...
|
||||||
|
json_t *obj;
|
||||||
|
const char *currency_str;
|
||||||
|
int value; // FIXME: bad data type! (64 bit!)
|
||||||
|
int fraction;
|
||||||
|
|
||||||
|
EXITIF (NULL == (obj = json_object_get (amount_obj, "currency")));
|
||||||
|
EXITIF (NULL == (currency_str = json_string_value (obj)));
|
||||||
|
EXITIF (NULL == (obj = json_object_get (amount_obj, "value")));
|
||||||
|
EXITIF (JSON_INTEGER != json_typeof (obj));
|
||||||
|
EXITIF (0 > (value = json_integer_value (obj)));
|
||||||
|
EXITIF (NULL == (obj = json_object_get (amount_obj, "fraction")));
|
||||||
|
EXITIF (JSON_INTEGER != json_typeof (obj));
|
||||||
|
EXITIF (0 > (fraction = json_integer_value (obj)));
|
||||||
|
(void) memset (amt->currency, 0, sizeof (amt->currency));
|
||||||
|
(void) strncpy (amt->currency, currency_str, sizeof (amt->currency) - 1);
|
||||||
|
amt->value = (uint32_t) value;
|
||||||
|
amt->fraction = (uint32_t) fraction;
|
||||||
|
return GNUNET_OK;
|
||||||
|
|
||||||
|
EXITIF_exit:
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a mint's denomination key encoded in JSON.
|
||||||
|
*
|
||||||
|
* @param[out] denom_key where to return the result
|
||||||
|
* @param[in] denom_key_obj json to parse
|
||||||
|
* @param master_key master key to use to verify signature
|
||||||
|
* @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
|
||||||
|
* invalid or the json malformed.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
parse_json_denomkey (struct TALER_MINT_DenomPublicKey *denom_key,
|
||||||
|
json_t *denom_key_obj,
|
||||||
|
struct TALER_MasterPublicKeyP *master_key)
|
||||||
|
{
|
||||||
|
// FIXME: check logic, try to simplify
|
||||||
|
json_t *obj;
|
||||||
|
const char *sig_enc;
|
||||||
|
const char *deposit_valid_until_enc;
|
||||||
|
const char *withdraw_valid_until_enc;
|
||||||
|
const char *valid_from_enc;
|
||||||
|
const char *key_enc;
|
||||||
|
char *buf;
|
||||||
|
size_t buf_size;
|
||||||
|
struct GNUNET_TIME_Absolute valid_from;
|
||||||
|
struct GNUNET_TIME_Absolute withdraw_valid_until;
|
||||||
|
struct GNUNET_TIME_Absolute deposit_valid_until;
|
||||||
|
struct TALER_Amount value;
|
||||||
|
struct TALER_Amount fee_withdraw;
|
||||||
|
struct TALER_Amount fee_deposit;
|
||||||
|
struct TALER_Amount fee_refresh;
|
||||||
|
struct TALER_DenominationKeyValidityPS denom_key_issue;
|
||||||
|
struct GNUNET_CRYPTO_rsa_PublicKey *pk;
|
||||||
|
struct GNUNET_CRYPTO_EddsaSignature sig;
|
||||||
|
|
||||||
|
EXITIF (JSON_OBJECT != json_typeof (denom_key_obj));
|
||||||
|
EXITIF (NULL == (obj = json_object_get (denom_key_obj, "master_sig")));
|
||||||
|
EXITIF (NULL == (sig_enc = json_string_value (obj)));
|
||||||
|
EXITIF (103 != strlen (sig_enc));
|
||||||
|
EXITIF (GNUNET_OK != GNUNET_STRINGS_string_to_data (sig_enc, 103,
|
||||||
|
&sig, sizeof (sig)));
|
||||||
|
EXITIF (NULL == (obj = json_object_get (denom_key_obj, "stamp_expire_deposit")));
|
||||||
|
EXITIF (NULL == (deposit_valid_until_enc = json_string_value (obj)));
|
||||||
|
EXITIF (NULL == (obj = json_object_get (denom_key_obj, "stamp_expire_withdraw")));
|
||||||
|
EXITIF (NULL == (withdraw_valid_until_enc = json_string_value (obj)));
|
||||||
|
EXITIF (NULL == (obj = json_object_get (denom_key_obj, "stamp_start")));
|
||||||
|
EXITIF (NULL == (valid_from_enc = json_string_value (obj)));
|
||||||
|
|
||||||
|
EXITIF (NULL == (obj = json_object_get (denom_key_obj, "denom_pub")));
|
||||||
|
EXITIF (NULL == (key_enc = json_string_value (obj)));
|
||||||
|
|
||||||
|
EXITIF (GNUNET_SYSERR == parse_timestamp (&valid_from, valid_from_enc));
|
||||||
|
EXITIF (GNUNET_SYSERR == parse_timestamp (&withdraw_valid_until,
|
||||||
|
withdraw_valid_until_enc));
|
||||||
|
EXITIF (GNUNET_SYSERR == parse_timestamp (&deposit_valid_until,
|
||||||
|
deposit_valid_until_enc));
|
||||||
|
|
||||||
|
memset (&denom_key_issue, 0, sizeof (denom_key_issue));
|
||||||
|
|
||||||
|
buf_size = (strlen (key_enc) * 5) / 8;
|
||||||
|
buf = GNUNET_malloc (buf_size);
|
||||||
|
|
||||||
|
EXITIF (GNUNET_OK !=
|
||||||
|
GNUNET_STRINGS_string_to_data (key_enc, strlen (key_enc),
|
||||||
|
buf,
|
||||||
|
buf_size));
|
||||||
|
pk = GNUNET_CRYPTO_rsa_public_key_decode (buf, buf_size);
|
||||||
|
GNUNET_free (buf);
|
||||||
|
|
||||||
|
EXITIF (NULL == pk);
|
||||||
|
GNUNET_CRYPTO_rsa_public_key_hash (pk,
|
||||||
|
&denom_key_issue.denom_hash);
|
||||||
|
EXITIF (NULL == (obj = json_object_get (denom_key_obj, "value")));
|
||||||
|
EXITIF (GNUNET_SYSERR == parse_json_amount (obj, &value));
|
||||||
|
EXITIF (NULL == (obj = json_object_get (denom_key_obj, "fee_withdraw")));
|
||||||
|
EXITIF (GNUNET_SYSERR == parse_json_amount (obj, &fee_withdraw));
|
||||||
|
EXITIF (NULL == (obj = json_object_get (denom_key_obj, "fee_deposit")));
|
||||||
|
EXITIF (GNUNET_SYSERR == parse_json_amount (obj, &fee_deposit));
|
||||||
|
EXITIF (NULL == (obj = json_object_get (denom_key_obj, "fee_refresh")));
|
||||||
|
EXITIF (GNUNET_SYSERR == parse_json_amount (obj, &fee_refresh));
|
||||||
|
denom_key_issue.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY);
|
||||||
|
denom_key_issue.purpose.size = htonl
|
||||||
|
(sizeof (struct TALER_DenominationKeyValidityPS) -
|
||||||
|
offsetof (struct TALER_DenominationKeyValidityPS, purpose));
|
||||||
|
denom_key_issue.master = *master_key;
|
||||||
|
denom_key_issue.start = GNUNET_TIME_absolute_hton (valid_from);
|
||||||
|
denom_key_issue.expire_withdraw = GNUNET_TIME_absolute_hton (withdraw_valid_until);
|
||||||
|
denom_key_issue.expire_spend = GNUNET_TIME_absolute_hton (deposit_valid_until);
|
||||||
|
TALER_amount_hton (&denom_key_issue.value,
|
||||||
|
&value);
|
||||||
|
TALER_amount_hton (&denom_key_issue.fee_withdraw,
|
||||||
|
&fee_withdraw);
|
||||||
|
TALER_amount_hton (&denom_key_issue.fee_deposit,
|
||||||
|
&fee_deposit);
|
||||||
|
TALER_amount_hton (&denom_key_issue.fee_refresh,
|
||||||
|
&fee_refresh);
|
||||||
|
EXITIF (GNUNET_SYSERR ==
|
||||||
|
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY,
|
||||||
|
&denom_key_issue.purpose,
|
||||||
|
&sig,
|
||||||
|
&master_key->eddsa_pub));
|
||||||
|
denom_key->key.rsa_public_key = pk;
|
||||||
|
denom_key->valid_from = valid_from;
|
||||||
|
denom_key->withdraw_valid_until = withdraw_valid_until;
|
||||||
|
denom_key->deposit_valid_until = deposit_valid_until;
|
||||||
|
denom_key->value = value;
|
||||||
|
denom_key->fee_withdraw = fee_withdraw;
|
||||||
|
denom_key->fee_deposit = fee_deposit;
|
||||||
|
denom_key->fee_refresh = fee_refresh;
|
||||||
|
return GNUNET_OK;
|
||||||
|
|
||||||
|
EXITIF_exit:
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode the JSON in @a resp_obj from the /keys response and store the data
|
||||||
|
* in the @a key_data.
|
||||||
|
*
|
||||||
|
* @param[in] resp_obj JSON object to parse
|
||||||
|
* @param[out] key_data where to store the results we decoded
|
||||||
|
* @return #GNUNET_OK on success, #GNUNET_SYSERR on error (malformed JSON)
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
decode_keys_json (json_t *resp_obj,
|
||||||
|
struct TALER_MINT_Keys *key_data)
|
||||||
|
{
|
||||||
|
struct GNUNET_TIME_Absolute list_issue_date;
|
||||||
|
|
||||||
|
if (JSON_OBJECT != json_typeof (resp_obj))
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
|
||||||
|
/* parse the master public key */
|
||||||
|
{
|
||||||
|
json_t *master_key_obj;
|
||||||
|
const char *master_key_enc;
|
||||||
|
|
||||||
|
EXITIF (NULL == (master_key_obj =
|
||||||
|
json_object_get (resp_obj,
|
||||||
|
"master_public_key")));
|
||||||
|
EXITIF (NULL == (master_key_enc =
|
||||||
|
json_string_value (master_key_obj)));
|
||||||
|
EXITIF (GNUNET_OK !=
|
||||||
|
GNUNET_CRYPTO_eddsa_public_key_from_string (master_key_enc,
|
||||||
|
strlen (master_key_enc),
|
||||||
|
&key_data->master_pub.eddsa_pub));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse the issue date of the response */
|
||||||
|
{
|
||||||
|
json_t *list_issue_date_obj;
|
||||||
|
const char *tstamp_enc;
|
||||||
|
|
||||||
|
EXITIF (NULL == (list_issue_date_obj =
|
||||||
|
json_object_get (resp_obj,
|
||||||
|
"list_issue_date")));
|
||||||
|
EXITIF (NULL == (tstamp_enc = json_string_value (list_issue_date_obj)));
|
||||||
|
EXITIF (GNUNET_SYSERR == parse_timestamp (&list_issue_date,
|
||||||
|
tstamp_enc));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse the signing keys */
|
||||||
|
{
|
||||||
|
json_t *sign_keys_array;
|
||||||
|
json_t *sign_key_obj;
|
||||||
|
unsigned int index;
|
||||||
|
|
||||||
|
EXITIF (NULL == (sign_keys_array =
|
||||||
|
json_object_get (resp_obj,
|
||||||
|
"signkeys")));
|
||||||
|
EXITIF (JSON_ARRAY != json_typeof (sign_keys_array));
|
||||||
|
EXITIF (0 == (key_data->num_sign_keys =
|
||||||
|
json_array_size (sign_keys_array)));
|
||||||
|
key_data->sign_keys
|
||||||
|
= GNUNET_malloc (sizeof (struct TALER_MINT_SigningPublicKey)
|
||||||
|
* key_data->num_sign_keys);
|
||||||
|
index = 0;
|
||||||
|
json_array_foreach (sign_keys_array, index, sign_key_obj) {
|
||||||
|
EXITIF (GNUNET_SYSERR ==
|
||||||
|
parse_json_signkey (&key_data->sign_keys[index],
|
||||||
|
sign_key_obj,
|
||||||
|
&key_data->master_pub));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse the denomination keys */
|
||||||
|
{
|
||||||
|
json_t *denom_keys_array;
|
||||||
|
json_t *denom_key_obj;
|
||||||
|
unsigned int index;
|
||||||
|
|
||||||
|
EXITIF (NULL == (denom_keys_array =
|
||||||
|
json_object_get (resp_obj, "denoms")));
|
||||||
|
EXITIF (JSON_ARRAY != json_typeof (denom_keys_array));
|
||||||
|
EXITIF (0 == (key_data->num_denom_keys = json_array_size (denom_keys_array)));
|
||||||
|
key_data->denom_keys = GNUNET_malloc (sizeof (struct TALER_MINT_DenomPublicKey)
|
||||||
|
* key_data->num_denom_keys);
|
||||||
|
index = 0;
|
||||||
|
json_array_foreach (denom_keys_array, index, denom_key_obj) {
|
||||||
|
EXITIF (GNUNET_SYSERR ==
|
||||||
|
parse_json_denomkey (&key_data->denom_keys[index],
|
||||||
|
denom_key_obj,
|
||||||
|
&key_data->master_pub));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return GNUNET_OK;
|
||||||
|
|
||||||
|
/* FIXME: parse the auditor keys */
|
||||||
|
|
||||||
|
/* FIXME: parse 'eddsa_sig' */
|
||||||
|
|
||||||
|
/* FIXME: validate signature... */
|
||||||
|
|
||||||
|
EXITIF_exit:
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We have successfully received the reply to the /keys
|
||||||
|
* request from the mint. We now need to parse the reply
|
||||||
|
* and, if successful, store the resulting information
|
||||||
|
* in the `key_data` structure.
|
||||||
|
*
|
||||||
|
* @param kr key request with all of the data to parse
|
||||||
|
* and references to the `struct TALER_MINT_Handle`
|
||||||
|
* where we need to store the result
|
||||||
|
* @return #GNUNET_OK on success,
|
||||||
|
* #GNUNET_SYSERR on failure
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
parse_response_keys_get (struct KeysRequest *kr)
|
||||||
|
{
|
||||||
|
json_t *resp_obj;
|
||||||
|
json_error_t error;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
resp_obj = json_loadb (kr->buf,
|
||||||
|
kr->buf_size,
|
||||||
|
JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK,
|
||||||
|
&error);
|
||||||
|
if (NULL == resp_obj)
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"Unable to parse received /keys data as JSON object\n");
|
||||||
|
GNUNET_free_non_null (kr->buf);
|
||||||
|
kr->buf = NULL;
|
||||||
|
kr->buf_size = 0;
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
GNUNET_free_non_null (kr->buf);
|
||||||
|
kr->buf = NULL;
|
||||||
|
kr->buf_size = 0;
|
||||||
|
ret = decode_keys_json (resp_obj,
|
||||||
|
&kr->mint->key_data);
|
||||||
|
json_decref (resp_obj);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback used when downloading the reply to a /keys request
|
||||||
|
* is complete.
|
||||||
|
*
|
||||||
|
* @param cls the `struct KeysRequest`
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
keys_completed_cb (void *cls)
|
||||||
|
{
|
||||||
|
struct KeysRequest *kr = cls;
|
||||||
|
struct TALER_MINT_Handle *mint = kr->mint;
|
||||||
|
|
||||||
|
if ( (0 != kr->eno) ||
|
||||||
|
(GNUNET_OK !=
|
||||||
|
parse_response_keys_get (kr)) )
|
||||||
|
{
|
||||||
|
mint->kr = NULL;
|
||||||
|
free_keys_request (kr);
|
||||||
|
mint->state = MHS_FAILED;
|
||||||
|
/* notify application that we failed */
|
||||||
|
if (NULL != mint->cert_cb)
|
||||||
|
{
|
||||||
|
mint->cert_cb (mint->cert_cb_cls,
|
||||||
|
NULL);
|
||||||
|
mint->cert_cb = NULL;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mint->kr = NULL;
|
||||||
|
free_keys_request (kr);
|
||||||
|
mint->state = MHS_CERT;
|
||||||
|
/* notify application about the key information */
|
||||||
|
if (NULL != mint->cert_cb)
|
||||||
|
{
|
||||||
|
mint->cert_cb (mint->cert_cb_cls,
|
||||||
|
&mint->key_data);
|
||||||
|
mint->cert_cb = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ********************* library internal API ********* */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the context of a mint.
|
||||||
|
*
|
||||||
|
* @param h the mint handle to query
|
||||||
|
* @return ctx context to execute jobs in
|
||||||
|
*/
|
||||||
|
struct TALER_MINT_Context *
|
||||||
|
MAH_handle_to_context (struct TALER_MINT_Handle *h)
|
||||||
|
{
|
||||||
|
return h->ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the handle is ready to process requests.
|
||||||
|
*
|
||||||
|
* @param h the mint handle to query
|
||||||
|
* @return #GNUNET_YES if we are ready, #GNUNET_NO if not
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
MAH_handle_is_ready (struct TALER_MINT_Handle *h)
|
||||||
|
{
|
||||||
|
return (MHS_CERT == h->state) ? GNUNET_YES : GNUNET_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the URL to use for an API request.
|
||||||
|
*
|
||||||
|
* @param h the mint handle to query
|
||||||
|
* @param path Taler API path (i.e. "/withdraw/sign")
|
||||||
|
* @return the full URI to use with cURL
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
MAH_path_to_url (struct TALER_MINT_Handle *h,
|
||||||
|
const char *path)
|
||||||
|
{
|
||||||
|
char *url;
|
||||||
|
|
||||||
|
GNUNET_asprintf (&url,
|
||||||
|
"%s%s",
|
||||||
|
h->url,
|
||||||
|
path);
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ********************* public API ******************* */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise a connection to the mint. Will connect to the
|
||||||
|
* mint and obtain information about the mint's master public
|
||||||
|
* key and the mint's auditor. The respective information will
|
||||||
|
* be passed to the @a cert_cb once available, and all future
|
||||||
|
* interactions with the mint will be checked to be signed
|
||||||
|
* (where appropriate) by the respective master key.
|
||||||
|
*
|
||||||
|
* @param ctx the context
|
||||||
|
* @param url HTTP base URL for the mint
|
||||||
|
* @param cert_cb function to call with the mint's certification information
|
||||||
|
* @param cert_cb_cls closure for @a cert_cb
|
||||||
|
* @param ... list of additional arguments, terminated by #TALER_MINT_OPTION_END.
|
||||||
|
* @return the mint handle; NULL upon error
|
||||||
|
*/
|
||||||
|
struct TALER_MINT_Handle *
|
||||||
|
TALER_MINT_connect (struct TALER_MINT_Context *ctx,
|
||||||
|
const char *url,
|
||||||
|
TALER_MINT_CertificationCallback cert_cb,
|
||||||
|
void *cert_cb_cls,
|
||||||
|
...)
|
||||||
|
{
|
||||||
|
struct TALER_MINT_Handle *mint;
|
||||||
|
struct KeysRequest *kr;
|
||||||
|
CURL *c;
|
||||||
|
|
||||||
|
mint = GNUNET_new (struct TALER_MINT_Handle);
|
||||||
|
mint->ctx = ctx;
|
||||||
|
mint->url = GNUNET_strdup (url);
|
||||||
|
kr = GNUNET_new (struct KeysRequest);
|
||||||
|
kr->mint = mint;
|
||||||
|
kr->url = MAH_path_to_url (mint, "/keys");
|
||||||
|
c = curl_easy_init ();
|
||||||
|
GNUNET_assert (CURLE_OK ==
|
||||||
|
curl_easy_setopt (c,
|
||||||
|
CURLOPT_URL,
|
||||||
|
kr->url));
|
||||||
|
GNUNET_assert (CURLE_OK ==
|
||||||
|
curl_easy_setopt (c,
|
||||||
|
CURLOPT_ERRORBUFFER,
|
||||||
|
kr->emsg));
|
||||||
|
GNUNET_assert (CURLE_OK ==
|
||||||
|
curl_easy_setopt (c,
|
||||||
|
CURLOPT_WRITEFUNCTION,
|
||||||
|
&keys_download_cb));
|
||||||
|
GNUNET_assert (CURLE_OK ==
|
||||||
|
curl_easy_setopt (c,
|
||||||
|
CURLOPT_WRITEDATA,
|
||||||
|
kr));
|
||||||
|
kr->job = MAC_job_add (mint->ctx,
|
||||||
|
c,
|
||||||
|
&keys_completed_cb,
|
||||||
|
kr);
|
||||||
|
mint->kr = kr;
|
||||||
|
return mint;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnect from the mint
|
||||||
|
*
|
||||||
|
* @param mint the mint handle
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
TALER_MINT_disconnect (struct TALER_MINT_Handle *mint)
|
||||||
|
{
|
||||||
|
if (NULL != mint->kr)
|
||||||
|
{
|
||||||
|
MAC_job_cancel (mint->kr->job);
|
||||||
|
free_keys_request (mint->kr);
|
||||||
|
mint->kr = NULL;
|
||||||
|
}
|
||||||
|
GNUNET_array_grow (mint->key_data.sign_keys,
|
||||||
|
mint->key_data.num_sign_keys,
|
||||||
|
0);
|
||||||
|
GNUNET_array_grow (mint->key_data.denom_keys,
|
||||||
|
mint->key_data.num_denom_keys,
|
||||||
|
0);
|
||||||
|
GNUNET_array_grow (mint->key_data.auditors,
|
||||||
|
mint->key_data.num_auditors,
|
||||||
|
0);
|
||||||
|
GNUNET_free (mint->url);
|
||||||
|
GNUNET_free (mint);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* end of mint_api_handle.c */
|
59
src/mint-lib/mint_api_handle.h
Normal file
59
src/mint-lib/mint_api_handle.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
This file is part of TALER
|
||||||
|
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||||
|
|
||||||
|
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, If not, see
|
||||||
|
<http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @file mint-lib/mint_api_handle.h
|
||||||
|
* @brief Internal interface to the handle part of the mint's HTTP API
|
||||||
|
* @author Christian Grothoff
|
||||||
|
*/
|
||||||
|
#include "platform.h"
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include "taler_mint_service.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the context of a mint.
|
||||||
|
*
|
||||||
|
* @param h the mint handle to query
|
||||||
|
* @return ctx context to execute jobs in
|
||||||
|
*/
|
||||||
|
struct TALER_MINT_Context *
|
||||||
|
MAH_handle_to_context (struct TALER_MINT_Handle *h);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the handle is ready to process requests.
|
||||||
|
*
|
||||||
|
* @param h the mint handle to query
|
||||||
|
* @return #GNUNET_YES if we are ready, #GNUNET_NO if not
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
MAH_handle_is_ready (struct TALER_MINT_Handle *h);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the URL to use for an API request.
|
||||||
|
*
|
||||||
|
* @param h the mint handle to query
|
||||||
|
* @param path Taler API path (i.e. "/withdraw/sign")
|
||||||
|
* @return the full URI to use with cURL
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
MAH_path_to_url (struct TALER_MINT_Handle *h,
|
||||||
|
const char *path);
|
||||||
|
|
||||||
|
|
||||||
|
/* end of mint_api_handle.h */
|
@ -49,7 +49,7 @@ do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
|
|||||||
dh = NULL;
|
dh = NULL;
|
||||||
TALER_MINT_disconnect (mint);
|
TALER_MINT_disconnect (mint);
|
||||||
mint = NULL;
|
mint = NULL;
|
||||||
TALER_MINT_cleanup (ctx);
|
TALER_MINT_fini (ctx);
|
||||||
ctx = NULL;
|
ctx = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user