Merge branch 'master' of ssh://taler.net:/var/git/mint
This commit is contained in:
commit
a396f4e7fa
10
configure.ac
10
configure.ac
@ -199,6 +199,10 @@ TALER_PLUGIN_LDFLAGS="-export-dynamic -avoid-version -module -no-undefined"
|
||||
AC_SUBST(TALER_LIB_LDFLAGS)
|
||||
AC_SUBST(TALER_PLUGIN_LDFLAGS)
|
||||
|
||||
CFLAGS_SAVE=$CFLAGS
|
||||
LDFLAGS_SAVE=$LDFLAGS
|
||||
LIBS_SAVE="$LIBS"
|
||||
|
||||
|
||||
AM_CONDITIONAL(HAVE_POSTGRESQL, test x$postgres = xtrue)
|
||||
|
||||
@ -249,6 +253,10 @@ then
|
||||
fi
|
||||
fi
|
||||
|
||||
CFLAGS=$CFLAGS_SAVE
|
||||
LDFLAGS=$LDFLAGS_SAVE
|
||||
LIBS=$LIBS_SAVE
|
||||
|
||||
|
||||
# should developer logic be compiled (not-for-production code)?
|
||||
AC_MSG_CHECKING(whether to compile developer logic)
|
||||
@ -349,6 +357,8 @@ AC_CONFIG_FILES([Makefile
|
||||
src/include/Makefile
|
||||
src/util/Makefile
|
||||
src/pq/Makefile
|
||||
src/bank-lib/Makefile
|
||||
src/wire/Makefile
|
||||
src/mintdb/Makefile
|
||||
src/mint/Makefile
|
||||
src/mint-tools/Makefile
|
||||
|
@ -7,10 +7,10 @@ if WALLET_ONLY
|
||||
SUBDIRS = include util
|
||||
else
|
||||
|
||||
SUBDIRS = include util $(PQ_DIR) mintdb mint mint-tools
|
||||
SUBDIRS = include util $(PQ_DIR) bank-lib wire mintdb mint mint-tools
|
||||
if HAVE_LIBCURL
|
||||
SUBDIRS += mint-lib
|
||||
else
|
||||
else
|
||||
if HAVE_LIBGNURL
|
||||
SUBDIRS += mint-lib
|
||||
endif
|
||||
|
45
src/bank-lib/Makefile.am
Normal file
45
src/bank-lib/Makefile.am
Normal file
@ -0,0 +1,45 @@
|
||||
# This Makefile.am is in the public domain
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src/include
|
||||
|
||||
if USE_COVERAGE
|
||||
AM_CFLAGS = --coverage -O0
|
||||
XLIB = -lgcov
|
||||
endif
|
||||
|
||||
lib_LTLIBRARIES = \
|
||||
libtalerbank.la
|
||||
|
||||
libtalerbank_la_LDFLAGS = \
|
||||
-version-info 0:0:0 \
|
||||
-no-undefined
|
||||
|
||||
libtalerbank_la_SOURCES = \
|
||||
bank_api_context.c bank_api_context.h \
|
||||
bank_api_json.c bank_api_json.h \
|
||||
bank_api_admin.c
|
||||
|
||||
libtalerbank_la_LIBADD = \
|
||||
-lgnunetutil \
|
||||
-ljansson \
|
||||
$(XLIB)
|
||||
|
||||
if HAVE_LIBCURL
|
||||
libtalerbank_la_LIBADD += -lcurl
|
||||
else
|
||||
if HAVE_LIBGNURL
|
||||
libtalerbank_la_LIBADD += -lgnurl
|
||||
endif
|
||||
endif
|
||||
|
||||
check_PROGRAMS = \
|
||||
test_bank_api
|
||||
|
||||
TESTS = \
|
||||
$(check_PROGRAMS)
|
||||
|
||||
test_bank_api_SOURCES = \
|
||||
test_bank_api.c
|
||||
test_bank_api_LDADD = \
|
||||
libtalerbank.la \
|
||||
$(top_builddir)/src/util/libtalerutil.la \
|
||||
-lgnunetutil
|
240
src/bank-lib/bank_api_admin.c
Normal file
240
src/bank-lib/bank_api_admin.c
Normal file
@ -0,0 +1,240 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2015, 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is 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 bank-lib/bank_api_admin.c
|
||||
* @brief Implementation of the /admin/ requests of the bank's HTTP API
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include <curl/curl.h>
|
||||
#include <jansson.h>
|
||||
#include <microhttpd.h> /* just for HTTP status codes */
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include "taler_bank_service.h"
|
||||
#include "bank_api_json.h"
|
||||
#include "bank_api_context.h"
|
||||
#include "taler_signatures.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief An admin/add/incoming Handle
|
||||
*/
|
||||
struct TALER_BANK_AdminAddIncomingHandle
|
||||
{
|
||||
|
||||
/**
|
||||
* The connection to bank this request handle will use
|
||||
*/
|
||||
struct TALER_BANK_Context *bank;
|
||||
|
||||
/**
|
||||
* The url for this request.
|
||||
*/
|
||||
char *url;
|
||||
|
||||
/**
|
||||
* JSON encoding of the request to POST.
|
||||
*/
|
||||
char *json_enc;
|
||||
|
||||
/**
|
||||
* Handle for the request.
|
||||
*/
|
||||
struct BAC_Job *job;
|
||||
|
||||
/**
|
||||
* HTTP headers for the request.
|
||||
*/
|
||||
struct curl_slist *headers;
|
||||
|
||||
/**
|
||||
* Function to call with the result.
|
||||
*/
|
||||
TALER_BANK_AdminAddIncomingResultCallback cb;
|
||||
|
||||
/**
|
||||
* Closure for @a cb.
|
||||
*/
|
||||
void *cb_cls;
|
||||
|
||||
/**
|
||||
* Download buffer
|
||||
*/
|
||||
struct BAC_DownloadBuffer db;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Function called when we're done processing the
|
||||
* HTTP /admin/add/incoming request.
|
||||
*
|
||||
* @param cls the `struct TALER_BANK_AdminAddIncomingHandle`
|
||||
* @param eh the curl request handle
|
||||
*/
|
||||
static void
|
||||
handle_admin_add_incoming_finished (void *cls,
|
||||
CURL *eh)
|
||||
{
|
||||
struct TALER_BANK_AdminAddIncomingHandle *aai = cls;
|
||||
long response_code;
|
||||
json_t *json;
|
||||
|
||||
aai->job = NULL;
|
||||
json = BAC_download_get_result (&aai->db,
|
||||
eh,
|
||||
&response_code);
|
||||
switch (response_code)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case MHD_HTTP_OK:
|
||||
break;
|
||||
case MHD_HTTP_BAD_REQUEST:
|
||||
/* This should never happen, either us or the bank is buggy
|
||||
(or API version conflict); just pass JSON reply to the application */
|
||||
break;
|
||||
case MHD_HTTP_FORBIDDEN:
|
||||
/* Access denied */
|
||||
break;
|
||||
case MHD_HTTP_UNAUTHORIZED:
|
||||
/* Nothing really to verify, bank says one of the signatures is
|
||||
invalid; as we checked them, this should never happen, we
|
||||
should pass the JSON reply to the application */
|
||||
break;
|
||||
case MHD_HTTP_NOT_FOUND:
|
||||
/* Nothing really to verify, this should never
|
||||
happen, we should pass the JSON reply to the application */
|
||||
break;
|
||||
case MHD_HTTP_INTERNAL_SERVER_ERROR:
|
||||
/* Server had an internal issue; we should retry, but this API
|
||||
leaves this to the application */
|
||||
break;
|
||||
default:
|
||||
/* unexpected response code */
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Unexpected response code %u\n",
|
||||
response_code);
|
||||
GNUNET_break (0);
|
||||
response_code = 0;
|
||||
break;
|
||||
}
|
||||
aai->cb (aai->cb_cls,
|
||||
response_code);
|
||||
json_decref (json);
|
||||
TALER_BANK_admin_add_incoming_cancel (aai);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notify the bank that we have received an incoming transaction
|
||||
* which fills a reserve. Note that this API is an administrative
|
||||
* API and thus not accessible to typical bank clients, but only
|
||||
* to the operators of the bank.
|
||||
*
|
||||
* @param bank the bank handle; the bank must be ready to operate
|
||||
* @param reserve_pub public key of the reserve
|
||||
* @param amount amount that was deposited
|
||||
* @param execution_date when did we receive the amount
|
||||
* @param account_no account number (53 bits at most)
|
||||
* @param res_cb the callback to call when the final result for this request is available
|
||||
* @param res_cb_cls closure for the above callback
|
||||
* @return NULL
|
||||
* if the inputs are invalid (i.e. invalid amount).
|
||||
* In this case, the callback is not called.
|
||||
*/
|
||||
struct TALER_BANK_AdminAddIncomingHandle *
|
||||
TALER_BANK_admin_add_incoming (struct TALER_BANK_Context *bank,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
const struct TALER_Amount *amount,
|
||||
uint64_t account_no,
|
||||
TALER_BANK_AdminAddIncomingResultCallback res_cb,
|
||||
void *res_cb_cls)
|
||||
{
|
||||
struct TALER_BANK_AdminAddIncomingHandle *aai;
|
||||
json_t *admin_obj;
|
||||
CURL *eh;
|
||||
|
||||
admin_obj = json_pack ("{s:o, s:o," /* reserve_pub/amount */
|
||||
" s:I}", /* execution_Date/wire */
|
||||
"wtid", TALER_json_from_data (wtid,
|
||||
sizeof (*wtid)),
|
||||
"amount", TALER_json_from_amount (amount),
|
||||
"account", (json_int_t) account_no);
|
||||
aai = GNUNET_new (struct TALER_BANK_AdminAddIncomingHandle);
|
||||
aai->bank = bank;
|
||||
aai->cb = res_cb;
|
||||
aai->cb_cls = res_cb_cls;
|
||||
aai->url = BAC_path_to_url (bank, "/admin/add/incoming");
|
||||
|
||||
eh = curl_easy_init ();
|
||||
GNUNET_assert (NULL != (aai->json_enc =
|
||||
json_dumps (admin_obj,
|
||||
JSON_COMPACT)));
|
||||
json_decref (admin_obj);
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_URL,
|
||||
aai->url));
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_POSTFIELDS,
|
||||
aai->json_enc));
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_POSTFIELDSIZE,
|
||||
strlen (aai->json_enc)));
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_WRITEFUNCTION,
|
||||
&BAC_download_cb));
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_WRITEDATA,
|
||||
&aai->db));
|
||||
aai->job = BAC_job_add (bank,
|
||||
eh,
|
||||
GNUNET_YES,
|
||||
&handle_admin_add_incoming_finished,
|
||||
aai);
|
||||
return aai;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cancel an add incoming. This function cannot be used on a request
|
||||
* handle if a response is already served for it.
|
||||
*
|
||||
* @param aai the admin add incoming request handle
|
||||
*/
|
||||
void
|
||||
TALER_BANK_admin_add_incoming_cancel (struct TALER_BANK_AdminAddIncomingHandle *aai)
|
||||
{
|
||||
if (NULL != aai->job)
|
||||
{
|
||||
BAC_job_cancel (aai->job);
|
||||
aai->job = NULL;
|
||||
}
|
||||
curl_slist_free_all (aai->headers);
|
||||
GNUNET_free_non_null (aai->db.buf);
|
||||
GNUNET_free (aai->url);
|
||||
GNUNET_free (aai->json_enc);
|
||||
GNUNET_free (aai);
|
||||
}
|
||||
|
||||
|
||||
/* end of bank_api_admin.c */
|
570
src/bank-lib/bank_api_context.c
Normal file
570
src/bank-lib/bank_api_context.c
Normal file
@ -0,0 +1,570 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is 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 bank-lib/bank_api_context.c
|
||||
* @brief Implementation of the context part of the bank's HTTP API
|
||||
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include <curl/curl.h>
|
||||
#include "taler_bank_service.h"
|
||||
#include "bank_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\n", \
|
||||
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)\n", \
|
||||
__FILE__, __LINE__, error.text, error.source)
|
||||
|
||||
|
||||
/**
|
||||
* Failsafe flag. Raised if our constructor fails to initialize
|
||||
* the Curl library.
|
||||
*/
|
||||
static int TALER_BANK_curl_fail;
|
||||
|
||||
|
||||
/**
|
||||
* Jobs are CURL requests running within a `struct TALER_BANK_Context`.
|
||||
*/
|
||||
struct BAC_Job
|
||||
{
|
||||
|
||||
/**
|
||||
* We keep jobs in a DLL.
|
||||
*/
|
||||
struct BAC_Job *next;
|
||||
|
||||
/**
|
||||
* We keep jobs in a DLL.
|
||||
*/
|
||||
struct BAC_Job *prev;
|
||||
|
||||
/**
|
||||
* Easy handle of the job.
|
||||
*/
|
||||
CURL *easy_handle;
|
||||
|
||||
/**
|
||||
* Context this job runs in.
|
||||
*/
|
||||
struct TALER_BANK_Context *ctx;
|
||||
|
||||
/**
|
||||
* Function to call upon completion.
|
||||
*/
|
||||
BAC_JobCompletionCallback jcc;
|
||||
|
||||
/**
|
||||
* Closure for @e jcc.
|
||||
*/
|
||||
void *jcc_cls;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Context
|
||||
*/
|
||||
struct TALER_BANK_Context
|
||||
{
|
||||
/**
|
||||
* Curl multi handle
|
||||
*/
|
||||
CURLM *multi;
|
||||
|
||||
/**
|
||||
* Curl share handle
|
||||
*/
|
||||
CURLSH *share;
|
||||
|
||||
/**
|
||||
* We keep jobs in a DLL.
|
||||
*/
|
||||
struct BAC_Job *jobs_head;
|
||||
|
||||
/**
|
||||
* We keep jobs in a DLL.
|
||||
*/
|
||||
struct BAC_Job *jobs_tail;
|
||||
|
||||
/**
|
||||
* HTTP header "application/json", created once and used
|
||||
* for all requests that need it.
|
||||
*/
|
||||
struct curl_slist *json_header;
|
||||
|
||||
/**
|
||||
* Base URL of the bank.
|
||||
*/
|
||||
char *url;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Initialise this library. This function should be called before using any of
|
||||
* the following functions.
|
||||
*
|
||||
* @param url HTTP base URL for the bank
|
||||
* @return library context
|
||||
*/
|
||||
struct TALER_BANK_Context *
|
||||
TALER_BANK_init (const char *url)
|
||||
{
|
||||
struct TALER_BANK_Context *ctx;
|
||||
CURLM *multi;
|
||||
CURLSH *share;
|
||||
|
||||
if (TALER_BANK_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_BANK_Context);
|
||||
ctx->multi = multi;
|
||||
ctx->share = share;
|
||||
ctx->url = GNUNET_strdup (url);
|
||||
GNUNET_assert (NULL != (ctx->json_header =
|
||||
curl_slist_append (NULL,
|
||||
"Content-Type: application/json")));
|
||||
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 #BAC_easy_to_closure to extract the @a jcc_cls argument
|
||||
* from a valid @a eh afterwards.
|
||||
*
|
||||
* This function modifies the CURL handle to add the
|
||||
* "Content-Type: application/json" header if @a add_json is set.
|
||||
*
|
||||
* @param ctx context to execute the job in
|
||||
* @param eh curl easy handle for the request, will
|
||||
* be executed AND cleaned up
|
||||
* @param add_json add "application/json" content type header
|
||||
* @param jcc callback to invoke upon completion
|
||||
* @param jcc_cls closure for @a jcc
|
||||
*/
|
||||
struct BAC_Job *
|
||||
BAC_job_add (struct TALER_BANK_Context *ctx,
|
||||
CURL *eh,
|
||||
int add_json,
|
||||
BAC_JobCompletionCallback jcc,
|
||||
void *jcc_cls)
|
||||
{
|
||||
struct BAC_Job *job;
|
||||
|
||||
if (GNUNET_YES == add_json)
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_HTTPHEADER,
|
||||
ctx->json_header));
|
||||
|
||||
job = GNUNET_new (struct BAC_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 #BAC_job_add().
|
||||
*
|
||||
* @param eh easy handle that was used
|
||||
* @return the `jcc_cls` that was given to #BAC_job_add().
|
||||
*/
|
||||
void *
|
||||
BAC_easy_to_closure (CURL *eh)
|
||||
{
|
||||
struct BAC_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
|
||||
BAC_job_cancel (struct BAC_Job *job)
|
||||
{
|
||||
struct TALER_BANK_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_BANK_perform (struct TALER_BANK_Context *ctx)
|
||||
{
|
||||
CURLMsg *cmsg;
|
||||
struct BAC_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,
|
||||
cmsg->easy_handle);
|
||||
BAC_job_cancel (job);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain the information for a select() call to wait until
|
||||
* #TALER_BANK_perform() is ready again. Note that calling
|
||||
* any other TALER_BANK-API may also imply that the library
|
||||
* is again ready for #TALER_BANK_perform().
|
||||
*
|
||||
* Basically, a client should use this API to prepare for select(),
|
||||
* then block on select(), then call #TALER_BANK_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_BANK_perform().
|
||||
*/
|
||||
void
|
||||
TALER_BANK_get_select_info (struct TALER_BANK_Context *ctx,
|
||||
fd_set *read_fd_set,
|
||||
fd_set *write_fd_set,
|
||||
fd_set *except_fd_set,
|
||||
int *max_fd,
|
||||
long *timeout)
|
||||
{
|
||||
long to;
|
||||
int m;
|
||||
|
||||
m = -1;
|
||||
GNUNET_assert (CURLM_OK ==
|
||||
curl_multi_fdset (ctx->multi,
|
||||
read_fd_set,
|
||||
write_fd_set,
|
||||
except_fd_set,
|
||||
&m));
|
||||
to = *timeout;
|
||||
*max_fd = GNUNET_MAX (m, *max_fd);
|
||||
GNUNET_assert (CURLM_OK ==
|
||||
curl_multi_timeout (ctx->multi,
|
||||
&to));
|
||||
|
||||
/* Only if what we got back from curl is smaller than what we
|
||||
already had (-1 == infinity!), then update timeout */
|
||||
if ( (to < *timeout) &&
|
||||
(-1 != to) )
|
||||
*timeout = to;
|
||||
if ( (-1 == (*timeout)) &&
|
||||
(NULL != ctx->jobs_head) )
|
||||
*timeout = to;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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_BANK_fini (struct TALER_BANK_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);
|
||||
curl_slist_free_all (ctx->json_header);
|
||||
GNUNET_free (ctx->url);
|
||||
GNUNET_free (ctx);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain the URL to use for an API request.
|
||||
*
|
||||
* @param h the mint handle to query
|
||||
* @param path Taler API path (i.e. "/reserve/withdraw")
|
||||
* @return the full URI to use with cURL
|
||||
*/
|
||||
char *
|
||||
BAC_path_to_url (struct TALER_BANK_Context *h,
|
||||
const char *path)
|
||||
{
|
||||
char *url;
|
||||
|
||||
if ( ('/' == path[0]) &&
|
||||
(0 < strlen (h->url)) &&
|
||||
('/' == h->url[strlen (h->url) - 1]) )
|
||||
path++; /* avoid generating URL with "//" from concat */
|
||||
GNUNET_asprintf (&url,
|
||||
"%s%s",
|
||||
h->url,
|
||||
path);
|
||||
return url;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback used when downloading the reply to an HTTP request.
|
||||
* Just appends all of the data to the `buf` in the
|
||||
* `struct BAC_DownloadBuffer` 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
|
||||
*/
|
||||
size_t
|
||||
BAC_download_cb (char *bufptr,
|
||||
size_t size,
|
||||
size_t nitems,
|
||||
void *cls)
|
||||
{
|
||||
struct BAC_DownloadBuffer *db = cls;
|
||||
size_t msize;
|
||||
void *buf;
|
||||
|
||||
if (0 == size * nitems)
|
||||
{
|
||||
/* Nothing (left) to do */
|
||||
return 0;
|
||||
}
|
||||
msize = size * nitems;
|
||||
if ( (msize + db->buf_size) >= GNUNET_MAX_MALLOC_CHECKED)
|
||||
{
|
||||
db->eno = ENOMEM;
|
||||
return 0; /* signals an error to curl */
|
||||
}
|
||||
db->buf = GNUNET_realloc (db->buf,
|
||||
db->buf_size + msize);
|
||||
buf = db->buf + db->buf_size;
|
||||
memcpy (buf, bufptr, msize);
|
||||
db->buf_size += msize;
|
||||
return msize;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain information about the final result about the
|
||||
* HTTP download. If the download was successful, parses
|
||||
* the JSON in the @a db and returns it. Also returns
|
||||
* the HTTP @a response_code. If the download failed,
|
||||
* the return value is NULL. The response code is set
|
||||
* in any case, on download errors to zero.
|
||||
*
|
||||
* Calling this function also cleans up @a db.
|
||||
*
|
||||
* @param db download buffer
|
||||
* @param eh CURL handle (to get the response code)
|
||||
* @param[out] response_code set to the HTTP response code
|
||||
* (or zero if we aborted the download, i.e.
|
||||
* because the response was too big, or if
|
||||
* the JSON we received was malformed).
|
||||
* @return NULL if downloading a JSON reply failed
|
||||
*/
|
||||
json_t *
|
||||
BAC_download_get_result (struct BAC_DownloadBuffer *db,
|
||||
CURL *eh,
|
||||
long *response_code)
|
||||
{
|
||||
json_t *json;
|
||||
json_error_t error;
|
||||
char *ct;
|
||||
|
||||
if ( (CURLE_OK !=
|
||||
curl_easy_getinfo (eh,
|
||||
CURLINFO_CONTENT_TYPE,
|
||||
&ct)) ||
|
||||
(NULL == ct) ||
|
||||
(0 != strcasecmp (ct,
|
||||
"application/json")) )
|
||||
{
|
||||
/* No content type or explicitly not JSON, refuse to parse
|
||||
(but keep response code) */
|
||||
if (CURLE_OK !=
|
||||
curl_easy_getinfo (eh,
|
||||
CURLINFO_RESPONSE_CODE,
|
||||
response_code))
|
||||
{
|
||||
/* unexpected error... */
|
||||
GNUNET_break (0);
|
||||
*response_code = 0;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
json = NULL;
|
||||
if (0 == db->eno)
|
||||
{
|
||||
json = json_loadb (db->buf,
|
||||
db->buf_size,
|
||||
JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK,
|
||||
&error);
|
||||
if (NULL == json)
|
||||
{
|
||||
JSON_WARN (error);
|
||||
*response_code = 0;
|
||||
}
|
||||
}
|
||||
GNUNET_free_non_null (db->buf);
|
||||
db->buf = NULL;
|
||||
db->buf_size = 0;
|
||||
if (NULL != json)
|
||||
{
|
||||
if (CURLE_OK !=
|
||||
curl_easy_getinfo (eh,
|
||||
CURLINFO_RESPONSE_CODE,
|
||||
response_code))
|
||||
{
|
||||
/* unexpected error... */
|
||||
GNUNET_break (0);
|
||||
*response_code = 0;
|
||||
}
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initial global setup logic, specifically runs the Curl setup.
|
||||
*/
|
||||
__attribute__ ((constructor))
|
||||
void
|
||||
TALER_BANK_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_BANK_curl_fail = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cleans up after us, specifically runs the Curl cleanup.
|
||||
*/
|
||||
__attribute__ ((destructor))
|
||||
void
|
||||
TALER_BANK_destructor__ (void)
|
||||
{
|
||||
if (TALER_BANK_curl_fail)
|
||||
return;
|
||||
curl_global_cleanup ();
|
||||
}
|
||||
|
||||
/* end of bank_api_context.c */
|
181
src/bank-lib/bank_api_context.h
Normal file
181
src/bank-lib/bank_api_context.h
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is 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 bank-lib/bank_api_context.h
|
||||
* @brief Internal interface to the context part of the bank'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_bank_service.h"
|
||||
#include "taler_signatures.h"
|
||||
|
||||
|
||||
/**
|
||||
* Entry in the context's job queue.
|
||||
*/
|
||||
struct BAC_Job;
|
||||
|
||||
/**
|
||||
* Function to call upon completion of a job.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param eh original easy handle (for inspection)
|
||||
*/
|
||||
typedef void
|
||||
(*BAC_JobCompletionCallback)(void *cls,
|
||||
CURL *eh);
|
||||
|
||||
|
||||
/**
|
||||
* 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 #BAC_easy_to_closure to extract the @a jcc_cls argument
|
||||
* from a valid @a eh afterwards.
|
||||
*
|
||||
* This function modifies the CURL handle to add the
|
||||
* "Content-Type: application/json" header if @a add_json is set.
|
||||
*
|
||||
* @param ctx context to execute the job in
|
||||
* @param eh curl easy handle for the request, will
|
||||
* be executed AND cleaned up
|
||||
* @param add_json add "application/json" content type header
|
||||
* @param jcc callback to invoke upon completion
|
||||
* @param jcc_cls closure for @a jcc
|
||||
*/
|
||||
struct BAC_Job *
|
||||
BAC_job_add (struct TALER_BANK_Context *ctx,
|
||||
CURL *eh,
|
||||
int add_json,
|
||||
BAC_JobCompletionCallback jcc,
|
||||
void *jcc_cls);
|
||||
|
||||
|
||||
/**
|
||||
* Obtain the `jcc_cls` argument from an `eh` that was
|
||||
* given to #BAC_job_add().
|
||||
*
|
||||
* @param eh easy handle that was used
|
||||
* @return the `jcc_cls` that was given to #BAC_job_add().
|
||||
*/
|
||||
void *
|
||||
BAC_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
|
||||
BAC_job_cancel (struct BAC_Job *job);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Buffer data structure we use to buffer the HTTP download
|
||||
* before giving it to the JSON parser.
|
||||
*/
|
||||
struct BAC_DownloadBuffer
|
||||
{
|
||||
|
||||
/**
|
||||
* 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 an HTTP request.
|
||||
* Just appends all of the data to the `buf` in the
|
||||
* `struct BAC_DownloadBuffer` 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.
|
||||
*
|
||||
* Should be used by the various routines as the
|
||||
* CURLOPT_WRITEFUNCTION. A `struct BAC_DownloadBuffer` needs to be
|
||||
* passed to the CURLOPT_WRITEDATA.
|
||||
*
|
||||
* Afterwards, `eno` needs to be checked to ensure that the download
|
||||
* completed correctly.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
size_t
|
||||
BAC_download_cb (char *bufptr,
|
||||
size_t size,
|
||||
size_t nitems,
|
||||
void *cls);
|
||||
|
||||
|
||||
/**
|
||||
* Obtain information about the final result about the
|
||||
* HTTP download. If the download was successful, parses
|
||||
* the JSON in the @a db and returns it. Also returns
|
||||
* the HTTP @a response_code. If the download failed,
|
||||
* the return value is NULL. The response code is set
|
||||
* in any case, on download errors to zero.
|
||||
*
|
||||
* Calling this function also cleans up @a db.
|
||||
*
|
||||
* @param db download buffer
|
||||
* @param eh CURL handle (to get the response code)
|
||||
* @param[out] response_code set to the HTTP response code
|
||||
* (or zero if we aborted the download, i.e.
|
||||
* because the response was too big, or if
|
||||
* the JSON we received was malformed).
|
||||
* @return NULL if downloading a JSON reply failed
|
||||
*/
|
||||
json_t *
|
||||
BAC_download_get_result (struct BAC_DownloadBuffer *db,
|
||||
CURL *eh,
|
||||
long *response_code);
|
||||
|
||||
|
||||
/**
|
||||
* Obtain the URL to use for an API request.
|
||||
*
|
||||
* @param h the bank handle to query
|
||||
* @param path Taler API path (i.e. "/reserve/withdraw")
|
||||
* @return the full URI to use with cURL
|
||||
*/
|
||||
char *
|
||||
BAC_path_to_url (struct TALER_BANK_Context *h,
|
||||
const char *path);
|
||||
|
||||
|
||||
/* end of bank_api_context.h */
|
525
src/bank-lib/bank_api_json.c
Normal file
525
src/bank-lib/bank_api_json.c
Normal file
@ -0,0 +1,525 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License along with
|
||||
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file bank-lib/bank_api_json.c
|
||||
* @brief functions to parse incoming requests (JSON snippets)
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "bank_api_json.h"
|
||||
|
||||
/**
|
||||
* Navigate and parse data in a JSON tree.
|
||||
*
|
||||
* @param root the JSON node to start the navigation at.
|
||||
* @param spec parse specification array
|
||||
* @return offset in @a spec where parsing failed, -1 on success (!)
|
||||
*/
|
||||
static int
|
||||
parse_json (json_t *root,
|
||||
struct BAJ_Specification *spec)
|
||||
{
|
||||
int i;
|
||||
json_t *pos; /* what's our current position? */
|
||||
|
||||
pos = root;
|
||||
for (i=0;BAJ_CMD_END != spec[i].cmd;i++)
|
||||
{
|
||||
pos = json_object_get (root,
|
||||
spec[i].field);
|
||||
if (NULL == pos)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return i;
|
||||
}
|
||||
switch (spec[i].cmd)
|
||||
{
|
||||
case BAJ_CMD_END:
|
||||
GNUNET_assert (0);
|
||||
return i;
|
||||
case BAJ_CMD_AMOUNT:
|
||||
if (GNUNET_OK !=
|
||||
TALER_json_to_amount (pos,
|
||||
spec[i].details.amount))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return i;
|
||||
}
|
||||
break;
|
||||
case BAJ_CMD_TIME_ABSOLUTE:
|
||||
if (GNUNET_OK !=
|
||||
TALER_json_to_abs (pos,
|
||||
spec[i].details.abs_time))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return i;
|
||||
}
|
||||
break;
|
||||
|
||||
case BAJ_CMD_STRING:
|
||||
{
|
||||
const char *str;
|
||||
|
||||
str = json_string_value (pos);
|
||||
if (NULL == str)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return i;
|
||||
}
|
||||
*spec[i].details.strptr = str;
|
||||
}
|
||||
break;
|
||||
|
||||
case BAJ_CMD_BINARY_FIXED:
|
||||
{
|
||||
const char *str;
|
||||
int res;
|
||||
|
||||
str = json_string_value (pos);
|
||||
if (NULL == str)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return i;
|
||||
}
|
||||
res = GNUNET_STRINGS_string_to_data (str, strlen (str),
|
||||
spec[i].details.fixed_data.dest,
|
||||
spec[i].details.fixed_data.dest_size);
|
||||
if (GNUNET_OK != res)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BAJ_CMD_BINARY_VARIABLE:
|
||||
{
|
||||
const char *str;
|
||||
size_t size;
|
||||
void *data;
|
||||
int res;
|
||||
|
||||
str = json_string_value (pos);
|
||||
if (NULL == str)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return i;
|
||||
}
|
||||
size = (strlen (str) * 5) / 8;
|
||||
if (size >= 1024)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return i;
|
||||
}
|
||||
data = GNUNET_malloc (size);
|
||||
res = GNUNET_STRINGS_string_to_data (str,
|
||||
strlen (str),
|
||||
data,
|
||||
size);
|
||||
if (GNUNET_OK != res)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_free (data);
|
||||
return i;
|
||||
}
|
||||
*spec[i].details.variable_data.dest_p = data;
|
||||
*spec[i].details.variable_data.dest_size_p = size;
|
||||
}
|
||||
break;
|
||||
|
||||
case BAJ_CMD_RSA_PUBLIC_KEY:
|
||||
{
|
||||
size_t size;
|
||||
const char *str;
|
||||
int res;
|
||||
void *buf;
|
||||
|
||||
str = json_string_value (pos);
|
||||
if (NULL == str)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return i;
|
||||
}
|
||||
size = (strlen (str) * 5) / 8;
|
||||
buf = GNUNET_malloc (size);
|
||||
res = GNUNET_STRINGS_string_to_data (str,
|
||||
strlen (str),
|
||||
buf,
|
||||
size);
|
||||
if (GNUNET_OK != res)
|
||||
{
|
||||
GNUNET_free (buf);
|
||||
GNUNET_break_op (0);
|
||||
return i;
|
||||
}
|
||||
*spec[i].details.rsa_public_key
|
||||
= GNUNET_CRYPTO_rsa_public_key_decode (buf,
|
||||
size);
|
||||
GNUNET_free (buf);
|
||||
if (NULL == spec[i].details.rsa_public_key)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BAJ_CMD_RSA_SIGNATURE:
|
||||
{
|
||||
size_t size;
|
||||
const char *str;
|
||||
int res;
|
||||
void *buf;
|
||||
|
||||
str = json_string_value (pos);
|
||||
if (NULL == str)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return i;
|
||||
}
|
||||
size = (strlen (str) * 5) / 8;
|
||||
buf = GNUNET_malloc (size);
|
||||
res = GNUNET_STRINGS_string_to_data (str,
|
||||
strlen (str),
|
||||
buf,
|
||||
size);
|
||||
if (GNUNET_OK != res)
|
||||
{
|
||||
GNUNET_free (buf);
|
||||
GNUNET_break_op (0);
|
||||
return i;
|
||||
}
|
||||
*spec[i].details.rsa_signature
|
||||
= GNUNET_CRYPTO_rsa_signature_decode (buf,
|
||||
size);
|
||||
GNUNET_free (buf);
|
||||
if (NULL == spec[i].details.rsa_signature)
|
||||
return i;
|
||||
}
|
||||
break;
|
||||
|
||||
case BAJ_CMD_UINT16:
|
||||
{
|
||||
json_int_t val;
|
||||
|
||||
if (! json_is_integer (pos))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return i;
|
||||
}
|
||||
val = json_integer_value (pos);
|
||||
if ( (0 > val) || (val > UINT16_MAX) )
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return i;
|
||||
}
|
||||
*spec[i].details.u16 = (uint16_t) val;
|
||||
}
|
||||
break;
|
||||
|
||||
case BAJ_CMD_UINT64:
|
||||
{
|
||||
json_int_t val;
|
||||
|
||||
if (! json_is_integer (pos))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return i;
|
||||
}
|
||||
val = json_integer_value (pos);
|
||||
*spec[i].details.u64 = (uint64_t) val;
|
||||
}
|
||||
break;
|
||||
|
||||
case BAJ_CMD_JSON_OBJECT:
|
||||
{
|
||||
if (! (json_is_object (pos) || json_is_array (pos)) )
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return i;
|
||||
}
|
||||
json_incref (pos);
|
||||
*spec[i].details.obj = pos;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
GNUNET_break (0);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1; /* all OK! */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Free all elements allocated during a
|
||||
* #BAJ_parse_json() operation.
|
||||
*
|
||||
* @param spec specification of the parse operation
|
||||
* @param end number of elements in @a spec to process
|
||||
*/
|
||||
static void
|
||||
parse_free (struct BAJ_Specification *spec,
|
||||
int end)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0;i<end;i++)
|
||||
{
|
||||
switch (spec[i].cmd)
|
||||
{
|
||||
case BAJ_CMD_END:
|
||||
GNUNET_assert (0);
|
||||
return;
|
||||
case BAJ_CMD_AMOUNT:
|
||||
break;
|
||||
case BAJ_CMD_TIME_ABSOLUTE:
|
||||
break;
|
||||
case BAJ_CMD_BINARY_FIXED:
|
||||
break;
|
||||
case BAJ_CMD_STRING:
|
||||
break;
|
||||
case BAJ_CMD_BINARY_VARIABLE:
|
||||
GNUNET_free (*spec[i].details.variable_data.dest_p);
|
||||
*spec[i].details.variable_data.dest_p = NULL;
|
||||
*spec[i].details.variable_data.dest_size_p = 0;
|
||||
break;
|
||||
case BAJ_CMD_RSA_PUBLIC_KEY:
|
||||
GNUNET_CRYPTO_rsa_public_key_free (*spec[i].details.rsa_public_key);
|
||||
*spec[i].details.rsa_public_key = NULL;
|
||||
break;
|
||||
case BAJ_CMD_RSA_SIGNATURE:
|
||||
GNUNET_CRYPTO_rsa_signature_free (*spec[i].details.rsa_signature);
|
||||
*spec[i].details.rsa_signature = NULL;
|
||||
break;
|
||||
case BAJ_CMD_JSON_OBJECT:
|
||||
json_decref (*spec[i].details.obj);
|
||||
*spec[i].details.obj = NULL;
|
||||
break;
|
||||
default:
|
||||
GNUNET_break (0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Navigate and parse data in a JSON tree.
|
||||
*
|
||||
* @param root the JSON node to start the navigation at.
|
||||
* @param spec parse specification array
|
||||
* @return #GNUNET_OK on success, #GNUNET_SYSERR on error
|
||||
*/
|
||||
int
|
||||
BAJ_parse_json (const json_t *root,
|
||||
struct BAJ_Specification *spec)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = parse_json ((json_t *) root,
|
||||
spec);
|
||||
if (-1 == ret)
|
||||
return GNUNET_OK;
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"JSON field `%s` (%d) had unexpected value\n",
|
||||
spec[ret].field,
|
||||
ret);
|
||||
parse_free (spec, ret);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Free all elements allocated during a
|
||||
* #BAJ_parse_json() operation.
|
||||
*
|
||||
* @param spec specification of the parse operation
|
||||
*/
|
||||
void
|
||||
BAJ_parse_free (struct BAJ_Specification *spec)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0;BAJ_CMD_END != spec[i].cmd;i++) ;
|
||||
parse_free (spec, i);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The expected field stores a string.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param strptr where to store a pointer to the field
|
||||
*/
|
||||
struct BAJ_Specification
|
||||
BAJ_spec_string (const char *name,
|
||||
const char **strptr)
|
||||
{
|
||||
struct BAJ_Specification ret =
|
||||
{
|
||||
.cmd = BAJ_CMD_STRING,
|
||||
.field = name,
|
||||
.details.strptr = strptr
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specification for parsing an absolute time value.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param at where to store the absolute time found under @a name
|
||||
*/
|
||||
struct BAJ_Specification
|
||||
BAJ_spec_absolute_time (const char *name,
|
||||
struct GNUNET_TIME_Absolute *at)
|
||||
{
|
||||
struct BAJ_Specification ret =
|
||||
{
|
||||
.cmd = BAJ_CMD_TIME_ABSOLUTE,
|
||||
.field = name,
|
||||
.details.abs_time = at
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specification for parsing an amount value.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param amount where to store the amount found under @a name
|
||||
*/
|
||||
struct BAJ_Specification
|
||||
BAJ_spec_amount (const char *name,
|
||||
struct TALER_Amount *amount)
|
||||
{
|
||||
struct BAJ_Specification ret =
|
||||
{
|
||||
.cmd = BAJ_CMD_AMOUNT,
|
||||
.field = name,
|
||||
.details.amount = amount
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 16-bit integer.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param[out] u16 where to store the integer found under @a name
|
||||
*/
|
||||
struct BAJ_Specification
|
||||
BAJ_spec_uint16 (const char *name,
|
||||
uint16_t *u16)
|
||||
{
|
||||
struct BAJ_Specification ret =
|
||||
{
|
||||
.cmd = BAJ_CMD_UINT16,
|
||||
.field = name,
|
||||
.details.u16 = u16
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 64-bit integer.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param[out] u64 where to store the integer found under @a name
|
||||
*/
|
||||
struct BAJ_Specification
|
||||
BAJ_spec_uint64 (const char *name,
|
||||
uint64_t *u64)
|
||||
{
|
||||
struct BAJ_Specification ret =
|
||||
{
|
||||
.cmd = BAJ_CMD_UINT64,
|
||||
.field = name,
|
||||
.details.u64 = u64
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* JSON object.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param[out] jsonp where to store the JSON found under @a name
|
||||
*/
|
||||
struct BAJ_Specification
|
||||
BAJ_spec_json (const char *name,
|
||||
json_t **jsonp)
|
||||
{
|
||||
struct BAJ_Specification ret =
|
||||
{
|
||||
.cmd = BAJ_CMD_JSON_OBJECT,
|
||||
.field = name,
|
||||
.details.obj = jsonp
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specification for parsing an RSA public key.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param pk where to store the RSA key found under @a name
|
||||
*/
|
||||
struct BAJ_Specification
|
||||
BAJ_spec_rsa_public_key (const char *name,
|
||||
struct GNUNET_CRYPTO_rsa_PublicKey **pk)
|
||||
{
|
||||
struct BAJ_Specification ret =
|
||||
{
|
||||
.cmd = BAJ_CMD_RSA_PUBLIC_KEY,
|
||||
.field = name,
|
||||
.details.rsa_public_key = pk
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specification for parsing an RSA signature.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param sig where to store the RSA signature found under @a name
|
||||
*/
|
||||
struct BAJ_Specification
|
||||
BAJ_spec_rsa_signature (const char *name,
|
||||
struct GNUNET_CRYPTO_rsa_Signature **sig)
|
||||
{
|
||||
struct BAJ_Specification ret =
|
||||
{
|
||||
.cmd = BAJ_CMD_RSA_SIGNATURE,
|
||||
.field = name,
|
||||
.details.rsa_signature = sig
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* end of bank_api_json.c */
|
352
src/bank-lib/bank_api_json.h
Normal file
352
src/bank-lib/bank_api_json.h
Normal file
@ -0,0 +1,352 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero 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_json.h
|
||||
* @brief functions to parse incoming requests (JSON snippets)
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include "taler_util.h"
|
||||
#include <jansson.h>
|
||||
|
||||
|
||||
/**
|
||||
* Enumeration with the various commands for the
|
||||
* #BAJ_parse_json interpreter.
|
||||
*/
|
||||
enum BAJ_Command
|
||||
{
|
||||
|
||||
/**
|
||||
* End of command list.
|
||||
*/
|
||||
BAJ_CMD_END,
|
||||
|
||||
/**
|
||||
* Parse amount at current position.
|
||||
*/
|
||||
BAJ_CMD_AMOUNT,
|
||||
|
||||
/**
|
||||
* Parse absolute time at current position.
|
||||
*/
|
||||
BAJ_CMD_TIME_ABSOLUTE,
|
||||
|
||||
/**
|
||||
* Parse fixed binary value at current position.
|
||||
*/
|
||||
BAJ_CMD_BINARY_FIXED,
|
||||
|
||||
/**
|
||||
* Parse variable-size binary value at current position.
|
||||
*/
|
||||
BAJ_CMD_BINARY_VARIABLE,
|
||||
|
||||
/**
|
||||
* Parse RSA public key at current position.
|
||||
*/
|
||||
BAJ_CMD_RSA_PUBLIC_KEY,
|
||||
|
||||
/**
|
||||
* Parse RSA signature at current position.
|
||||
*/
|
||||
BAJ_CMD_RSA_SIGNATURE,
|
||||
|
||||
/**
|
||||
* Parse `const char *` JSON string at current position.
|
||||
*/
|
||||
BAJ_CMD_STRING,
|
||||
|
||||
/**
|
||||
* Parse `uint16_t` integer at the current position.
|
||||
*/
|
||||
BAJ_CMD_UINT16,
|
||||
|
||||
/**
|
||||
* Parse `uint64_t` integer at the current position.
|
||||
*/
|
||||
BAJ_CMD_UINT64,
|
||||
|
||||
/**
|
||||
* Parse JSON object at the current position.
|
||||
*/
|
||||
BAJ_CMD_JSON_OBJECT,
|
||||
|
||||
/**
|
||||
* Parse ??? at current position.
|
||||
*/
|
||||
BAJ_CMD_C
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Entry in parser specification for #BAJ_parse_json.
|
||||
*/
|
||||
struct BAJ_Specification
|
||||
{
|
||||
|
||||
/**
|
||||
* Command to execute.
|
||||
*/
|
||||
enum BAJ_Command cmd;
|
||||
|
||||
/**
|
||||
* Name of the field to access.
|
||||
*/
|
||||
const char *field;
|
||||
|
||||
/**
|
||||
* Further details for the command.
|
||||
*/
|
||||
union {
|
||||
|
||||
/**
|
||||
* Where to store amount for #BAJ_CMD_AMOUNT.
|
||||
*/
|
||||
struct TALER_Amount *amount;
|
||||
|
||||
/**
|
||||
* Where to store time, for #BAJ_CMD_TIME_ABSOLUTE.
|
||||
*/
|
||||
struct GNUNET_TIME_Absolute *abs_time;
|
||||
|
||||
/**
|
||||
* Where to write binary data, for #BAJ_CMD_BINARY_FIXED.
|
||||
*/
|
||||
struct {
|
||||
/**
|
||||
* Where to write the data.
|
||||
*/
|
||||
void *dest;
|
||||
|
||||
/**
|
||||
* How many bytes to write to @e dest.
|
||||
*/
|
||||
size_t dest_size;
|
||||
|
||||
} fixed_data;
|
||||
|
||||
/**
|
||||
* Where to write binary data, for #BAJ_CMD_BINARY_VARIABLE.
|
||||
*/
|
||||
struct {
|
||||
/**
|
||||
* Where to store the pointer with the data (is allocated).
|
||||
*/
|
||||
void **dest_p;
|
||||
|
||||
/**
|
||||
* Where to store the number of bytes allocated at `*dest`.
|
||||
*/
|
||||
size_t *dest_size_p;
|
||||
|
||||
} variable_data;
|
||||
|
||||
/**
|
||||
* Where to store the RSA public key for #BAJ_CMD_RSA_PUBLIC_KEY
|
||||
*/
|
||||
struct GNUNET_CRYPTO_rsa_PublicKey **rsa_public_key;
|
||||
|
||||
/**
|
||||
* Where to store the RSA signature for #BAJ_CMD_RSA_SIGNATURE
|
||||
*/
|
||||
struct GNUNET_CRYPTO_rsa_Signature **rsa_signature;
|
||||
|
||||
/**
|
||||
* Details for #BAJ_CMD_EDDSA_SIGNATURE
|
||||
*/
|
||||
struct {
|
||||
|
||||
/**
|
||||
* Where to store the purpose.
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose **purpose_p;
|
||||
|
||||
/**
|
||||
* Key to verify the signature against.
|
||||
*/
|
||||
const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key;
|
||||
|
||||
} eddsa_signature;
|
||||
|
||||
/**
|
||||
* Where to store a pointer to the string.
|
||||
*/
|
||||
const char **strptr;
|
||||
|
||||
/**
|
||||
* Where to store 16-bit integer.
|
||||
*/
|
||||
uint16_t *u16;
|
||||
|
||||
/**
|
||||
* Where to store 64-bit integer.
|
||||
*/
|
||||
uint64_t *u64;
|
||||
|
||||
/**
|
||||
* Where to store a JSON object.
|
||||
*/
|
||||
json_t **obj;
|
||||
|
||||
} details;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Navigate and parse data in a JSON tree.
|
||||
*
|
||||
* @param root the JSON node to start the navigation at.
|
||||
* @param spec parse specification array
|
||||
* @return #GNUNET_OK on success, #GNUNET_SYSERR on error
|
||||
*/
|
||||
int
|
||||
BAJ_parse_json (const json_t *root,
|
||||
struct BAJ_Specification *spec);
|
||||
|
||||
|
||||
/**
|
||||
* Free all elements allocated during a
|
||||
* #BAJ_parse_json() operation.
|
||||
*
|
||||
* @param spec specification of the parse operation
|
||||
*/
|
||||
void
|
||||
BAJ_parse_free (struct BAJ_Specification *spec);
|
||||
|
||||
|
||||
/**
|
||||
* End of a parser specification.
|
||||
*/
|
||||
#define BAJ_spec_end { .cmd = BAJ_CMD_END }
|
||||
|
||||
/**
|
||||
* Fixed size object (in network byte order, encoded using Crockford
|
||||
* Base32hex encoding).
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param obj pointer where to write the data (type of `*obj` will determine size)
|
||||
*/
|
||||
#define BAJ_spec_fixed_auto(name,obj) { .cmd = BAJ_CMD_BINARY_FIXED, .field = name, .details.fixed_data.dest = obj, .details.fixed_data.dest_size = sizeof (*obj) }
|
||||
|
||||
|
||||
/**
|
||||
* Variable size object (in network byte order, encoded using Crockford
|
||||
* Base32hex encoding).
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param obj pointer where to write the data (a `void **`)
|
||||
* @param size where to store the number of bytes allocated for @a obj (of type `size_t *`
|
||||
*/
|
||||
#define BAJ_spec_varsize(name,obj,size) { .cmd = BAJ_CMD_BINARY_VARIABLE, .field = name, .details.variable_data.dest_p = obj, .details.variable_data.dest_size_p = size }
|
||||
|
||||
|
||||
/**
|
||||
* The expected field stores a string.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param strptr where to store a pointer to the field
|
||||
*/
|
||||
struct BAJ_Specification
|
||||
BAJ_spec_string (const char *name,
|
||||
const char **strptr);
|
||||
|
||||
|
||||
/**
|
||||
* Absolute time.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param[out] at where to store the absolute time found under @a name
|
||||
*/
|
||||
struct BAJ_Specification
|
||||
BAJ_spec_absolute_time (const char *name,
|
||||
struct GNUNET_TIME_Absolute *at);
|
||||
|
||||
|
||||
/**
|
||||
* 16-bit integer.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param[out] u16 where to store the integer found under @a name
|
||||
*/
|
||||
struct BAJ_Specification
|
||||
BAJ_spec_uint16 (const char *name,
|
||||
uint16_t *u16);
|
||||
|
||||
|
||||
/**
|
||||
* 64-bit integer.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param[out] u64 where to store the integer found under @a name
|
||||
*/
|
||||
struct BAJ_Specification
|
||||
BAJ_spec_uint64 (const char *name,
|
||||
uint64_t *u64);
|
||||
|
||||
|
||||
/**
|
||||
* JSON object.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param[out] jsonp where to store the JSON found under @a name
|
||||
*/
|
||||
struct BAJ_Specification
|
||||
BAJ_spec_json (const char *name,
|
||||
json_t **jsonp);
|
||||
|
||||
|
||||
/**
|
||||
* Specification for parsing an amount value.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param amount where to store the amount under @a name
|
||||
*/
|
||||
struct BAJ_Specification
|
||||
BAJ_spec_amount (const char *name,
|
||||
struct TALER_Amount *amount);
|
||||
|
||||
|
||||
/**
|
||||
* Specification for parsing an RSA public key.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param pk where to store the RSA key found under @a name
|
||||
*/
|
||||
struct BAJ_Specification
|
||||
BAJ_spec_rsa_public_key (const char *name,
|
||||
struct GNUNET_CRYPTO_rsa_PublicKey **pk);
|
||||
|
||||
|
||||
/**
|
||||
* Specification for parsing an RSA signature.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param sig where to store the RSA signature found under @a name
|
||||
*/
|
||||
struct BAJ_Specification
|
||||
BAJ_spec_rsa_signature (const char *name,
|
||||
struct GNUNET_CRYPTO_rsa_Signature **sig);
|
||||
|
||||
|
||||
|
||||
|
||||
/* end of mint_api_json.h */
|
542
src/bank-lib/test_bank_api.c
Normal file
542
src/bank-lib/test_bank_api.c
Normal file
@ -0,0 +1,542 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is 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 bank/test_bank_api.c
|
||||
* @brief testcase to test bank's HTTP API interface
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_util.h"
|
||||
#include "taler_signatures.h"
|
||||
#include "taler_bank_service.h"
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <microhttpd.h>
|
||||
|
||||
|
||||
/**
|
||||
* Main execution context for the main loop.
|
||||
*/
|
||||
static struct TALER_BANK_Context *ctx;
|
||||
|
||||
/**
|
||||
* Task run on shutdown.
|
||||
*/
|
||||
static struct GNUNET_SCHEDULER_Task *shutdown_task;
|
||||
|
||||
/**
|
||||
* Task that runs the main event loop.
|
||||
*/
|
||||
static struct GNUNET_SCHEDULER_Task *ctx_task;
|
||||
|
||||
/**
|
||||
* Result of the testcases, #GNUNET_OK on success
|
||||
*/
|
||||
static int result;
|
||||
|
||||
|
||||
/**
|
||||
* Opcodes for the interpreter.
|
||||
*/
|
||||
enum OpCode
|
||||
{
|
||||
/**
|
||||
* Termination code, stops the interpreter loop (with success).
|
||||
*/
|
||||
OC_END = 0,
|
||||
|
||||
/**
|
||||
* Add funds to a reserve by (faking) incoming wire transfer.
|
||||
*/
|
||||
OC_ADMIN_ADD_INCOMING
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Details for a bank operation to execute.
|
||||
*/
|
||||
struct Command
|
||||
{
|
||||
/**
|
||||
* Opcode of the command.
|
||||
*/
|
||||
enum OpCode oc;
|
||||
|
||||
/**
|
||||
* Label for the command, can be NULL.
|
||||
*/
|
||||
const char *label;
|
||||
|
||||
/**
|
||||
* Which response code do we expect for this command?
|
||||
*/
|
||||
unsigned int expected_response_code;
|
||||
|
||||
/**
|
||||
* Details about the command.
|
||||
*/
|
||||
union
|
||||
{
|
||||
|
||||
/**
|
||||
* Information for a #OC_ADMIN_ADD_INCOMING command.
|
||||
*/
|
||||
struct
|
||||
{
|
||||
|
||||
/**
|
||||
* String describing the amount to add to the reserve.
|
||||
*/
|
||||
const char *amount;
|
||||
|
||||
/**
|
||||
* Account number.
|
||||
*/
|
||||
uint64_t account_no;
|
||||
|
||||
/**
|
||||
* Wire transfer identifier to use. Initialized to
|
||||
* a random value.
|
||||
*/
|
||||
struct TALER_WireTransferIdentifierRawP wtid;
|
||||
|
||||
/**
|
||||
* Set to the API's handle during the operation.
|
||||
*/
|
||||
struct TALER_BANK_AdminAddIncomingHandle *aih;
|
||||
|
||||
} admin_add_incoming;
|
||||
|
||||
} details;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* State of the interpreter loop.
|
||||
*/
|
||||
struct InterpreterState
|
||||
{
|
||||
/**
|
||||
* Keys from the bank.
|
||||
*/
|
||||
const struct TALER_BANK_Keys *keys;
|
||||
|
||||
/**
|
||||
* Commands the interpreter will run.
|
||||
*/
|
||||
struct Command *commands;
|
||||
|
||||
/**
|
||||
* Interpreter task (if one is scheduled).
|
||||
*/
|
||||
struct GNUNET_SCHEDULER_Task *task;
|
||||
|
||||
/**
|
||||
* Instruction pointer. Tells #interpreter_run() which
|
||||
* instruction to run next.
|
||||
*/
|
||||
unsigned int ip;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Task that runs the context's event loop with the GNUnet scheduler.
|
||||
*
|
||||
* @param cls unused
|
||||
* @param tc scheduler context (unused)
|
||||
*/
|
||||
static void
|
||||
context_task (void *cls,
|
||||
const struct GNUNET_SCHEDULER_TaskContext *tc);
|
||||
|
||||
|
||||
/**
|
||||
* Run the context task, the working set has changed.
|
||||
*/
|
||||
static void
|
||||
trigger_context_task ()
|
||||
{
|
||||
GNUNET_SCHEDULER_cancel (ctx_task);
|
||||
ctx_task = GNUNET_SCHEDULER_add_now (&context_task,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The testcase failed, return with an error code.
|
||||
*
|
||||
* @param is interpreter state to clean up
|
||||
*/
|
||||
static void
|
||||
fail (struct InterpreterState *is)
|
||||
{
|
||||
result = GNUNET_SYSERR;
|
||||
GNUNET_SCHEDULER_shutdown ();
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Find a command by label.
|
||||
*
|
||||
* @param is interpreter state to search
|
||||
* @param label label to look for
|
||||
* @return NULL if command was not found
|
||||
*/
|
||||
static const struct Command *
|
||||
find_command (const struct InterpreterState *is,
|
||||
const char *label)
|
||||
{
|
||||
unsigned int i;
|
||||
const struct Command *cmd;
|
||||
|
||||
if (NULL == label)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"Attempt to lookup command for empty label\n");
|
||||
return NULL;
|
||||
}
|
||||
for (i=0;OC_END != (cmd = &is->commands[i])->oc;i++)
|
||||
if ( (NULL != cmd->label) &&
|
||||
(0 == strcmp (cmd->label,
|
||||
label)) )
|
||||
return cmd;
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"Command not found: %s\n",
|
||||
label);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Run the main interpreter loop that performs bank operations.
|
||||
*
|
||||
* @param cls contains the `struct InterpreterState`
|
||||
* @param tc scheduler context
|
||||
*/
|
||||
static void
|
||||
interpreter_run (void *cls,
|
||||
const struct GNUNET_SCHEDULER_TaskContext *tc);
|
||||
|
||||
|
||||
/**
|
||||
* Function called upon completion of our /admin/add/incoming request.
|
||||
*
|
||||
* @param cls closure with the interpreter state
|
||||
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
|
||||
* 0 if the bank's reply is bogus (fails to follow the protocol)
|
||||
*/
|
||||
static void
|
||||
add_incoming_cb (void *cls,
|
||||
unsigned int http_status)
|
||||
{
|
||||
struct InterpreterState *is = cls;
|
||||
struct Command *cmd = &is->commands[is->ip];
|
||||
|
||||
cmd->details.admin_add_incoming.aih = NULL;
|
||||
if (cmd->expected_response_code != http_status)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
is->ip++;
|
||||
is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
|
||||
is);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run the main interpreter loop that performs bank operations.
|
||||
*
|
||||
* @param cls contains the `struct InterpreterState`
|
||||
* @param tc scheduler context
|
||||
*/
|
||||
static void
|
||||
interpreter_run (void *cls,
|
||||
const struct GNUNET_SCHEDULER_TaskContext *tc)
|
||||
{
|
||||
struct InterpreterState *is = cls;
|
||||
struct Command *cmd = &is->commands[is->ip];
|
||||
struct TALER_Amount amount;
|
||||
|
||||
is->task = NULL;
|
||||
if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Test aborted by shutdown request\n");
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
switch (cmd->oc)
|
||||
{
|
||||
case OC_END:
|
||||
result = GNUNET_OK;
|
||||
GNUNET_SCHEDULER_shutdown ();
|
||||
return;
|
||||
case OC_ADMIN_ADD_INCOMING:
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_string_to_amount (cmd->details.admin_add_incoming.amount,
|
||||
&amount))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to parse amount `%s' at %u\n",
|
||||
cmd->details.admin_add_incoming.amount,
|
||||
is->ip);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
|
||||
&cmd->details.admin_add_incoming.wtid,
|
||||
sizeof (cmd->details.admin_add_incoming.wtid));
|
||||
cmd->details.admin_add_incoming.aih
|
||||
= TALER_BANK_admin_add_incoming (ctx,
|
||||
&cmd->details.admin_add_incoming.wtid,
|
||||
&amount,
|
||||
cmd->details.admin_add_incoming.account_no,
|
||||
&add_incoming_cb,
|
||||
is);
|
||||
if (NULL == cmd->details.admin_add_incoming.aih)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
trigger_context_task ();
|
||||
return;
|
||||
default:
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Unknown instruction %d at %u (%s)\n",
|
||||
cmd->oc,
|
||||
is->ip,
|
||||
cmd->label);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function run when the test terminates (good or bad).
|
||||
* Cleans up our state.
|
||||
*
|
||||
* @param cls the interpreter state.
|
||||
* @param tc unused
|
||||
*/
|
||||
static void
|
||||
do_shutdown (void *cls,
|
||||
const struct GNUNET_SCHEDULER_TaskContext *tc)
|
||||
{
|
||||
struct InterpreterState *is = cls;
|
||||
struct Command *cmd;
|
||||
unsigned int i;
|
||||
|
||||
shutdown_task = NULL;
|
||||
for (i=0;OC_END != (cmd = &is->commands[i])->oc;i++)
|
||||
{
|
||||
switch (cmd->oc)
|
||||
{
|
||||
case OC_END:
|
||||
GNUNET_assert (0);
|
||||
break;
|
||||
case OC_ADMIN_ADD_INCOMING:
|
||||
if (NULL != cmd->details.admin_add_incoming.aih)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"Command %u (%s) did not complete\n",
|
||||
i,
|
||||
cmd->label);
|
||||
TALER_BANK_admin_add_incoming_cancel (cmd->details.admin_add_incoming.aih);
|
||||
cmd->details.admin_add_incoming.aih = NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Unknown instruction %d at %u (%s)\n",
|
||||
cmd->oc,
|
||||
i,
|
||||
cmd->label);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (NULL != is->task)
|
||||
{
|
||||
GNUNET_SCHEDULER_cancel (is->task);
|
||||
is->task = NULL;
|
||||
}
|
||||
GNUNET_free (is);
|
||||
if (NULL != ctx_task)
|
||||
{
|
||||
GNUNET_SCHEDULER_cancel (ctx_task);
|
||||
ctx_task = NULL;
|
||||
}
|
||||
if (NULL != ctx)
|
||||
{
|
||||
TALER_BANK_fini (ctx);
|
||||
ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Task that runs the context's event loop with the GNUnet scheduler.
|
||||
*
|
||||
* @param cls unused
|
||||
* @param tc scheduler context (unused)
|
||||
*/
|
||||
static void
|
||||
context_task (void *cls,
|
||||
const struct GNUNET_SCHEDULER_TaskContext *tc)
|
||||
{
|
||||
long timeout;
|
||||
int max_fd;
|
||||
fd_set read_fd_set;
|
||||
fd_set write_fd_set;
|
||||
fd_set except_fd_set;
|
||||
struct GNUNET_NETWORK_FDSet *rs;
|
||||
struct GNUNET_NETWORK_FDSet *ws;
|
||||
struct GNUNET_TIME_Relative delay;
|
||||
|
||||
ctx_task = NULL;
|
||||
TALER_BANK_perform (ctx);
|
||||
max_fd = -1;
|
||||
timeout = -1;
|
||||
FD_ZERO (&read_fd_set);
|
||||
FD_ZERO (&write_fd_set);
|
||||
FD_ZERO (&except_fd_set);
|
||||
TALER_BANK_get_select_info (ctx,
|
||||
&read_fd_set,
|
||||
&write_fd_set,
|
||||
&except_fd_set,
|
||||
&max_fd,
|
||||
&timeout);
|
||||
if (timeout >= 0)
|
||||
delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
|
||||
timeout);
|
||||
else
|
||||
delay = GNUNET_TIME_UNIT_FOREVER_REL;
|
||||
rs = GNUNET_NETWORK_fdset_create ();
|
||||
GNUNET_NETWORK_fdset_copy_native (rs,
|
||||
&read_fd_set,
|
||||
max_fd + 1);
|
||||
ws = GNUNET_NETWORK_fdset_create ();
|
||||
GNUNET_NETWORK_fdset_copy_native (ws,
|
||||
&write_fd_set,
|
||||
max_fd + 1);
|
||||
ctx_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
|
||||
delay,
|
||||
rs,
|
||||
ws,
|
||||
&context_task,
|
||||
cls);
|
||||
GNUNET_NETWORK_fdset_destroy (rs);
|
||||
GNUNET_NETWORK_fdset_destroy (ws);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Main function that will be run by the scheduler.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param args remaining command-line arguments
|
||||
* @param cfgfile name of the configuration file used (for saving, can be NULL!)
|
||||
* @param config configuration
|
||||
*/
|
||||
static void
|
||||
run (void *cls,
|
||||
const struct GNUNET_SCHEDULER_TaskContext *tc)
|
||||
{
|
||||
struct InterpreterState *is;
|
||||
static struct Command commands[] =
|
||||
{
|
||||
/* Add EUR:5.01 to account 42 */
|
||||
{ .oc = OC_ADMIN_ADD_INCOMING,
|
||||
.label = "deposit-1",
|
||||
.expected_response_code = MHD_HTTP_OK,
|
||||
.details.admin_add_incoming.account_no = 42,
|
||||
.details.admin_add_incoming.amount = "EUR:5.01" },
|
||||
|
||||
{ .oc = OC_END }
|
||||
};
|
||||
|
||||
is = GNUNET_new (struct InterpreterState);
|
||||
is->commands = commands;
|
||||
|
||||
ctx = TALER_BANK_init ("http://localhost:8081");
|
||||
GNUNET_assert (NULL != ctx);
|
||||
ctx_task = GNUNET_SCHEDULER_add_now (&context_task,
|
||||
ctx);
|
||||
is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
|
||||
is);
|
||||
shutdown_task
|
||||
= GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
|
||||
(GNUNET_TIME_UNIT_SECONDS, 150),
|
||||
&do_shutdown, is);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Main function for the testcase for the bank API.
|
||||
*
|
||||
* @param argc expected to be 1
|
||||
* @param argv expected to only contain the program name
|
||||
*/
|
||||
int
|
||||
main (int argc,
|
||||
char * const *argv)
|
||||
{
|
||||
struct GNUNET_OS_Process *bankd;
|
||||
|
||||
GNUNET_log_setup ("test-bank-api",
|
||||
"WARNING",
|
||||
NULL);
|
||||
bankd = GNUNET_OS_start_process (GNUNET_NO,
|
||||
GNUNET_OS_INHERIT_STD_ALL,
|
||||
NULL, NULL, NULL,
|
||||
"taler-bank-httpd",
|
||||
"taler-bank-httpd",
|
||||
"-d", "test-bank-home",
|
||||
NULL);
|
||||
if (NULL == bankd)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"taler-bank-httpd not found, skipping test\n");
|
||||
return 77; /* report 'skip' */
|
||||
}
|
||||
/* give child time to start and bind against the socket */
|
||||
fprintf (stderr,
|
||||
"Waiting for taler-bank-httpd to be ready");
|
||||
do
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
sleep (1);
|
||||
}
|
||||
while (0 != system ("wget -q -t 1 -T 1 http://127.0.0.1:8081/keys -o /dev/null -O /dev/null"));
|
||||
fprintf (stderr, "\n");
|
||||
result = GNUNET_SYSERR;
|
||||
GNUNET_SCHEDULER_run (&run, NULL);
|
||||
GNUNET_OS_process_kill (bankd,
|
||||
SIGTERM);
|
||||
GNUNET_OS_process_wait (bankd);
|
||||
GNUNET_OS_process_destroy (bankd);
|
||||
return (GNUNET_OK == result) ? 0 : 1;
|
||||
}
|
||||
|
||||
/* end of test_bank_api.c */
|
@ -20,7 +20,9 @@ talerinclude_HEADERS = \
|
||||
taler_mintdb_lib.h \
|
||||
taler_mintdb_plugin.h \
|
||||
taler_pq_lib.h \
|
||||
taler_signatures.h
|
||||
taler_signatures.h \
|
||||
taler_wire_lib.h \
|
||||
taler_wire_plugin.h
|
||||
|
||||
endif
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
161
src/include/taler_bank_service.h
Normal file
161
src/include/taler_bank_service.h
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2015, 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License along with
|
||||
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file include/taler_bank_service.h
|
||||
* @brief C interface of libtalerbank, a C library to use the Taler bank's HTTP API
|
||||
* This is currently ONLY used to provide the "test" wire transfer protocol.
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef _TALER_BANK_SERVICE_H
|
||||
#define _TALER_BANK_SERVICE_H
|
||||
|
||||
#include "taler_util.h"
|
||||
|
||||
/* ********************* event loop *********************** */
|
||||
|
||||
/**
|
||||
* @brief Handle to this library context. This is where the
|
||||
* main event loop logic lives.
|
||||
*/
|
||||
struct TALER_BANK_Context;
|
||||
|
||||
|
||||
/**
|
||||
* Initialise a context. A context should be used for each thread and should
|
||||
* not be shared among multiple threads.
|
||||
*
|
||||
* @param url HTTP base URL for the bank
|
||||
* @return the context, NULL on error (failure to initialize)
|
||||
*/
|
||||
struct TALER_BANK_Context *
|
||||
TALER_BANK_init (const char *url);
|
||||
|
||||
|
||||
/**
|
||||
* Obtain the information for a select() call to wait until
|
||||
* #TALER_BANK_perform() is ready again. Note that calling
|
||||
* any other TALER_BANK-API may also imply that the library
|
||||
* is again ready for #TALER_BANK_perform().
|
||||
*
|
||||
* Basically, a client should use this API to prepare for select(),
|
||||
* then block on select(), then call #TALER_BANK_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_BANK_perform().
|
||||
*/
|
||||
void
|
||||
TALER_BANK_get_select_info (struct TALER_BANK_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_BANK_perform (struct TALER_BANK_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_BANK_fini (struct TALER_BANK_Context *ctx);
|
||||
|
||||
|
||||
/* ********************* /admin/add/incoming *********************** */
|
||||
|
||||
|
||||
/**
|
||||
* @brief A /admin/add/incoming Handle
|
||||
*/
|
||||
struct TALER_BANK_AdminAddIncomingHandle;
|
||||
|
||||
|
||||
/**
|
||||
* Callbacks of this type are used to serve the result of submitting
|
||||
* information about an incoming transaction to a bank.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
|
||||
* 0 if the bank's reply is bogus (fails to follow the protocol)
|
||||
*/
|
||||
typedef void
|
||||
(*TALER_BANK_AdminAddIncomingResultCallback) (void *cls,
|
||||
unsigned int http_status);
|
||||
|
||||
|
||||
/**
|
||||
* Notify the bank that we have received an incoming transaction
|
||||
* which fills a reserve. Note that this API is an administrative
|
||||
* API and thus not accessible to typical bank clients, but only
|
||||
* to the operators of the bank.
|
||||
*
|
||||
* @param bank the bank handle; the bank must be ready to operate
|
||||
* @param reserve_pub public key of the reserve
|
||||
* @param amount amount that was deposited
|
||||
* @param execution_date when did we receive the amount
|
||||
* @param account_no account number (53 bits at most)
|
||||
* @param res_cb the callback to call when the final result for this request is available
|
||||
* @param res_cb_cls closure for the above callback
|
||||
* @return NULL
|
||||
* if the inputs are invalid (i.e. invalid amount).
|
||||
* In this case, the callback is not called.
|
||||
*/
|
||||
struct TALER_BANK_AdminAddIncomingHandle *
|
||||
TALER_BANK_admin_add_incoming (struct TALER_BANK_Context *bank,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
const struct TALER_Amount *amount,
|
||||
uint64_t account_no,
|
||||
TALER_BANK_AdminAddIncomingResultCallback res_cb,
|
||||
void *res_cb_cls);
|
||||
|
||||
|
||||
/**
|
||||
* Cancel an add incoming. This function cannot be used on a request
|
||||
* handle if a response is already served for it.
|
||||
*
|
||||
* @param aai the admin add incoming request handle
|
||||
*/
|
||||
void
|
||||
TALER_BANK_admin_add_incoming_cancel (struct TALER_BANK_AdminAddIncomingHandle *aai);
|
||||
|
||||
#endif /* _TALER_BANK_SERVICE_H */
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
@ -428,6 +428,61 @@ struct TALER_RefreshLinkDecrypted
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Length of the raw value in the Taler wire transfer identifier
|
||||
* (in binary representation).
|
||||
*/
|
||||
#define TALER_WIRE_TRANSFER_IDENTIFIER_LEN 32
|
||||
|
||||
/**
|
||||
* #TALER_WIRE_TRANSFER_IDENTIFIER_LEN as a string.
|
||||
*/
|
||||
#define TALER_WIRE_TRANSFER_IDENTIFIER_LEN_STR "32"
|
||||
|
||||
/**
|
||||
* Raw value of a wire transfer subjects, without the checksum.
|
||||
*/
|
||||
struct TALER_WireTransferIdentifierRawP
|
||||
{
|
||||
|
||||
/**
|
||||
* Raw value. Note that typical payment systems (SEPA, ACH) support
|
||||
* at least two lines of 27 ASCII characters to encode a transaction
|
||||
* subject or "details", for a total of 54 characters. (The payment
|
||||
* system protocols often support more lines, but the forms presented
|
||||
* to customers are usually limited to 54 characters.)
|
||||
*
|
||||
* With a Base32-encoding of 5 bit per character, this gives us 270
|
||||
* bits or (rounded down) 33 bytes. So we use the first 32 bytes to
|
||||
* encode the actual value (i.e. a 256-bit / 32-byte public key or
|
||||
* a hash code), and the last byte for a minimalistic checksum.
|
||||
*/
|
||||
uint8_t raw[TALER_WIRE_TRANSFER_IDENTIFIER_LEN];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Binary information encoded in Crockford's Base32 in wire transfer
|
||||
* subjects of transfers from Taler to a merchant. The actual value
|
||||
* is chosen by the mint and has no particular semantics, other than
|
||||
* being unique so that the mint can lookup details about the wire
|
||||
* transfer when needed.
|
||||
*/
|
||||
struct TALER_WireTransferIdentifierP
|
||||
{
|
||||
|
||||
/**
|
||||
* Raw value.
|
||||
*/
|
||||
struct TALER_WireTransferIdentifierRawP raw;
|
||||
|
||||
/**
|
||||
* Checksum using CRC8 over the @e raw data.
|
||||
*/
|
||||
uint8_t crc8;
|
||||
};
|
||||
|
||||
|
||||
GNUNET_NETWORK_STRUCT_END
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU Affero General Public License as published by the Free Software
|
||||
@ -1059,5 +1059,162 @@ void
|
||||
TALER_MINT_admin_add_incoming_cancel (struct TALER_MINT_AdminAddIncomingHandle *aai);
|
||||
|
||||
|
||||
/* ********************* /wire/deposits *********************** */
|
||||
|
||||
/**
|
||||
* @brief A /wire/deposits Handle
|
||||
*/
|
||||
struct TALER_MINT_WireDepositsHandle;
|
||||
|
||||
|
||||
/**
|
||||
* Details for one of the /deposit operations that the
|
||||
* mint combined into a single wire transfer.
|
||||
*/
|
||||
struct TALER_WireDepositDetails
|
||||
{
|
||||
/**
|
||||
* Hash of the contract.
|
||||
*/
|
||||
struct GNUNET_HashCode h_contract;
|
||||
|
||||
/**
|
||||
* Which coin was deposited?
|
||||
*/
|
||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||
|
||||
/**
|
||||
* Value of the deposit (including fee).
|
||||
*/
|
||||
struct TALER_Amount coin_value;
|
||||
|
||||
/**
|
||||
* Fee charged by the mint for the deposit.
|
||||
*/
|
||||
struct TALER_Amount coin_fee;
|
||||
|
||||
/**
|
||||
* Merchant's transaction identifier.
|
||||
*/
|
||||
uint64_t transaction_id;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Function called with detailed wire transfer data, including all
|
||||
* of the coin transactions that were combined into the wire transfer.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param http_status HTTP status code we got, 0 on mint protocol violation
|
||||
* @param json original json reply (may include signatures, those have then been
|
||||
* validated already)
|
||||
* @param wtid extracted wire transfer identifier, or NULL if the mint could
|
||||
* not provide any (set only if @a http_status is #MHD_HTTP_OK)
|
||||
* @param total_amount total amount of the wire transfer, or NULL if the mint could
|
||||
* not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK)
|
||||
* @param details_length length of the @a details array
|
||||
* @param details array with details about the combined transactions
|
||||
*/
|
||||
typedef void
|
||||
(*TALER_MINT_WireDepositsCallback)(void *cls,
|
||||
unsigned int http_status,
|
||||
json_t *json,
|
||||
const struct GNUNET_HashCode *h_wire,
|
||||
const struct TALER_Amount *total_amount,
|
||||
unsigned int details_length,
|
||||
const struct TALER_WireDepositDetails *details);
|
||||
|
||||
|
||||
/**
|
||||
* Query the mint about which transactions were combined
|
||||
* to create a wire transfer.
|
||||
*
|
||||
* @param mint mint to query
|
||||
* @param wtid raw wire transfer identifier to get information about
|
||||
* @param cb callback to call
|
||||
* @param cb_cls closure for @a cb
|
||||
* @return handle to cancel operation
|
||||
*/
|
||||
struct TALER_MINT_WireDepositsHandle *
|
||||
TALER_MINT_wire_deposits (struct TALER_MINT_Handle *mint,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
TALER_MINT_WireDepositsCallback cb,
|
||||
void *cb_cls);
|
||||
|
||||
|
||||
/**
|
||||
* Cancel wire deposits request. This function cannot be used on a request
|
||||
* handle if a response is already served for it.
|
||||
*
|
||||
* @param wdh the wire deposits request handle
|
||||
*/
|
||||
void
|
||||
TALER_MINT_wire_deposits_cancel (struct TALER_MINT_WireDepositsHandle *wdh);
|
||||
|
||||
|
||||
/* ********************* /deposit/wtid *********************** */
|
||||
|
||||
|
||||
/**
|
||||
* @brief A /deposit/wtid Handle
|
||||
*/
|
||||
struct TALER_MINT_DepositWtidHandle;
|
||||
|
||||
|
||||
/**
|
||||
* Function called with detailed wire transfer data.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param http_status HTTP status code we got, 0 on mint protocol violation
|
||||
* @param json original json reply (may include signatures, those have then been
|
||||
* validated already)
|
||||
* @param wtid wire transfer identifier used by the mint, NULL if mint did not
|
||||
* yet execute the transaction
|
||||
* @param execution_time actual or planned execution time for the wire transfer
|
||||
* @param coin_contribution contribution to the @a total_amount of the deposited coin (may be NULL)
|
||||
*/
|
||||
typedef void
|
||||
(*TALER_MINT_DepositWtidCallback)(void *cls,
|
||||
unsigned int http_status,
|
||||
json_t *json,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
struct GNUNET_TIME_Absolute execution_time,
|
||||
const struct TALER_Amount *coin_contribution);
|
||||
|
||||
|
||||
/**
|
||||
* Obtain the wire transfer details for a given deposit.
|
||||
*
|
||||
* @param mint the mint to query
|
||||
* @param merchant_priv the merchant's private key
|
||||
* @param h_wire hash of merchant's wire transfer details
|
||||
* @param h_contract hash of the contract
|
||||
* @param coin_pub public key of the coin
|
||||
* @param transaction_id transaction identifier
|
||||
* @param cb function to call with the result
|
||||
* @param cb_cls closure for @a cb
|
||||
* @return handle to abort request
|
||||
*/
|
||||
struct TALER_MINT_DepositWtidHandle *
|
||||
TALER_MINT_deposit_wtid (struct TALER_MINT_Handle *mint,
|
||||
const struct TALER_MerchantPrivateKeyP *merchant_priv,
|
||||
const struct GNUNET_HashCode *h_wire,
|
||||
const struct GNUNET_HashCode *h_contract,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
uint64_t transaction_id,
|
||||
TALER_MINT_DepositWtidCallback cb,
|
||||
void *cb_cls);
|
||||
|
||||
|
||||
/**
|
||||
* Cancel deposit wtid request. This function cannot be used on a request
|
||||
* handle if a response is already served for it.
|
||||
*
|
||||
* @param dwh the wire deposits request handle
|
||||
*/
|
||||
void
|
||||
TALER_MINT_deposit_wtid_cancel (struct TALER_MINT_DepositWtidHandle *dwh);
|
||||
|
||||
|
||||
#endif /* _TALER_MINT_SERVICE_H */
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015, 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
@ -530,20 +530,24 @@ struct TALER_MINTDB_Session;
|
||||
* corresponding wire transaction.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param id transaction ID (used as future `min_id` to avoid
|
||||
* iterating over transactions more than once)
|
||||
* @param rowid unique ID for the deposit in our DB, used for marking
|
||||
* it as 'tiny' or 'done'
|
||||
* @param merchant_pub public key of the merchant
|
||||
* @param coin_pub public key of the coin
|
||||
* @param amount_with_fee amount that was deposited including fee
|
||||
* @param deposit_fee amount the mint gets to keep as transaction fees
|
||||
* @param transaction_id unique transaction ID chosen by the merchant
|
||||
* @param h_contract hash of the contract between merchant and customer
|
||||
* @param wire_deadline by which the merchant adviced that he would like the
|
||||
* wire transfer to be executed
|
||||
* @param wire wire details for the merchant
|
||||
* @param wire wire details for the merchant, NULL from iterate_matching_deposits()
|
||||
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
|
||||
*/
|
||||
typedef int
|
||||
(*TALER_MINTDB_DepositIterator)(void *cls,
|
||||
uint64_t id,
|
||||
unsigned long long rowid,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_Amount *amount_with_fee,
|
||||
const struct TALER_Amount *deposit_fee,
|
||||
uint64_t transaction_id,
|
||||
@ -570,21 +574,67 @@ typedef void
|
||||
|
||||
/**
|
||||
* Function called with the results of the lookup of the
|
||||
* wire transfer identifier information.
|
||||
*
|
||||
* wire transfer identifier information. Only called if
|
||||
* we are at least aware of the transaction existing.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param wtid base32-encoded wire transfer identifier, NULL
|
||||
* @param wtid wire transfer identifier, NULL
|
||||
* if the transaction was not yet done
|
||||
* @param coin_contribution how much did the coin we asked about
|
||||
* contribute to the total transfer value? (deposit value including fee)
|
||||
* @param coin_fee how much did the mint charge for the deposit fee
|
||||
* @param execution_time when was the transaction done, or
|
||||
* when we expect it to be done (if @a wtid was NULL);
|
||||
* #GNUNET_TIME_UNIT_FOREVER_ABS if the /deposit is unknown
|
||||
* to the mint
|
||||
* when we expect it to be done (if @a wtid was NULL)
|
||||
*/
|
||||
typedef void
|
||||
(*TALER_MINTDB_DepositWtidCallback)(void *cls,
|
||||
const char *wtid,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
const struct TALER_Amount *coin_contribution,
|
||||
const struct TALER_Amount *coin_fee,
|
||||
struct GNUNET_TIME_Absolute execution_time);
|
||||
|
||||
|
||||
/**
|
||||
* Function called with the results of the lookup of the
|
||||
* transaction data associated with a wire transfer identifier.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
|
||||
* @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls)
|
||||
* @param h_contract which contract was this payment about
|
||||
* @param transaction_id merchant's transaction ID for the payment
|
||||
* @param coin_pub which public key was this payment about
|
||||
* @param coin_value amount contributed by this coin in total (with fee)
|
||||
* @param coin_fee applicable fee for this coin
|
||||
* @param transfer_value total amount of the wire transfer
|
||||
*/
|
||||
typedef void
|
||||
(*TALER_MINTDB_WireTransferDataCallback)(void *cls,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
const struct GNUNET_HashCode *h_wire,
|
||||
const struct GNUNET_HashCode *h_contract,
|
||||
uint64_t transaction_id,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_Amount *coin_value,
|
||||
const struct TALER_Amount *coin_fee,
|
||||
const struct TALER_Amount *transfer_value);
|
||||
|
||||
|
||||
/**
|
||||
* Callback with data about a prepared transaction.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param rowid row identifier used to mark prepared transaction as done
|
||||
* @param buf transaction data that was persisted, NULL on error
|
||||
* @param buf_size number of bytes in @a buf, 0 on error
|
||||
*/
|
||||
typedef void
|
||||
(*TALER_MINTDB_WirePreparationCallback) (void *cls,
|
||||
unsigned long long rowid,
|
||||
const char *buf,
|
||||
size_t buf_size);
|
||||
|
||||
|
||||
/**
|
||||
* @brief The plugin API, returned from the plugin's "init" function.
|
||||
* The argument given to "init" is simply a configuration handle.
|
||||
@ -848,27 +898,78 @@ struct TALER_MINTDB_Plugin
|
||||
|
||||
|
||||
/**
|
||||
* Obtain information about deposits. Iterates over all deposits
|
||||
* above a certain ID. Use a @a min_id of 0 to start at the beginning.
|
||||
* This operation is executed in its own transaction in transaction
|
||||
* mode "REPEATABLE READ", i.e. we should only see valid deposits.
|
||||
* Mark a deposit as tiny, thereby declaring that it cannot be
|
||||
* executed by itself and should no longer be returned by
|
||||
* @e iterate_ready_deposits()
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param session connection to the database
|
||||
* @param min_id deposit to start at
|
||||
* @param limit maximum number of transactions to fetch
|
||||
* @param deposit_cb function to call for each deposit
|
||||
* @param deposit_rowid identifies the deposit row to modify
|
||||
* @return #GNUNET_OK on success, #GNUNET_SYSERR on error
|
||||
*/
|
||||
int
|
||||
(*mark_deposit_tiny) (void *cls,
|
||||
struct TALER_MINTDB_Session *session,
|
||||
unsigned long long rowid);
|
||||
|
||||
|
||||
/**
|
||||
* Mark a deposit as done, thereby declaring that it cannot be
|
||||
* executed at all anymore, and should no longer be returned by
|
||||
* @e iterate_ready_deposits() or @e iterate_matching_deposits().
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param session connection to the database
|
||||
* @param deposit_rowid identifies the deposit row to modify
|
||||
* @return #GNUNET_OK on success, #GNUNET_SYSERR on error
|
||||
*/
|
||||
int
|
||||
(*mark_deposit_done) (void *cls,
|
||||
struct TALER_MINTDB_Session *session,
|
||||
unsigned long long rowid);
|
||||
|
||||
|
||||
/**
|
||||
* Obtain information about deposits that are ready to be executed.
|
||||
* Such deposits must not be marked as "tiny" or "done", and the
|
||||
* execution time must be in the past.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param session connection to the database
|
||||
* @param deposit_cb function to call for ONE such deposit
|
||||
* @param deposit_cb_cls closure for @a deposit_cb
|
||||
* @return number of rows processed, 0 if none exist,
|
||||
* #GNUNET_SYSERR on error
|
||||
*/
|
||||
int
|
||||
(*iterate_deposits) (void *cls,
|
||||
struct TALER_MINTDB_Session *session,
|
||||
uint64_t min_id,
|
||||
uint32_t limit,
|
||||
TALER_MINTDB_DepositIterator deposit_cb,
|
||||
void *deposit_cb_cls);
|
||||
(*get_ready_deposit) (void *cls,
|
||||
struct TALER_MINTDB_Session *session,
|
||||
TALER_MINTDB_DepositIterator deposit_cb,
|
||||
void *deposit_cb_cls);
|
||||
|
||||
|
||||
/**
|
||||
* Obtain information about other pending deposits for the same
|
||||
* destination. Those deposits must not already be "done".
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param session connection to the database
|
||||
* @param h_wire destination of the wire transfer
|
||||
* @param merchant_pub public key of the merchant
|
||||
* @param deposit_cb function to call for each deposit
|
||||
* @param deposit_cb_cls closure for @a deposit_cb
|
||||
* @param limit maximum number of matching deposits to return
|
||||
* @return number of rows processed, 0 if none exist,
|
||||
* #GNUNET_SYSERR on error
|
||||
*/
|
||||
int
|
||||
(*iterate_matching_deposits) (void *cls,
|
||||
struct TALER_MINTDB_Session *session,
|
||||
const struct GNUNET_HashCode *h_wire,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
TALER_MINTDB_DepositIterator deposit_cb,
|
||||
void *deposit_cb_cls,
|
||||
uint32_t limit);
|
||||
|
||||
|
||||
/**
|
||||
@ -1112,10 +1213,10 @@ struct TALER_MINTDB_Plugin
|
||||
*/
|
||||
int
|
||||
(*insert_refresh_out) (void *cls,
|
||||
struct TALER_MINTDB_Session *session,
|
||||
const struct GNUNET_HashCode *session_hash,
|
||||
uint16_t newcoin_index,
|
||||
const struct TALER_DenominationSignature *ev_sig);
|
||||
struct TALER_MINTDB_Session *session,
|
||||
const struct GNUNET_HashCode *session_hash,
|
||||
uint16_t newcoin_index,
|
||||
const struct TALER_DenominationSignature *ev_sig);
|
||||
|
||||
|
||||
/**
|
||||
@ -1194,12 +1295,33 @@ struct TALER_MINTDB_Plugin
|
||||
struct TALER_MINTDB_TransactionList *list);
|
||||
|
||||
|
||||
/**
|
||||
* Lookup the list of Taler transactions that was aggregated
|
||||
* into a wire transfer by the respective @a raw_wtid.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param session database connection
|
||||
* @param wtid the raw wire transfer identifier we used
|
||||
* @param cb function to call on each transaction found
|
||||
* @param cb_cls closure for @a cb
|
||||
* @return #GNUNET_OK on success, #GNUNET_SYSERR on database errors,
|
||||
* #GNUNET_NO if we found no results
|
||||
*/
|
||||
int
|
||||
(*lookup_wire_transfer) (void *cls,
|
||||
struct TALER_MINTDB_Session *session,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
TALER_MINTDB_WireTransferDataCallback cb,
|
||||
void *cb_cls);
|
||||
|
||||
|
||||
/**
|
||||
* Try to find the wire transfer details for a deposit operation.
|
||||
* If we did not execute the deposit yet, return when it is supposed
|
||||
* to be executed.
|
||||
*
|
||||
*
|
||||
* @param cls closure
|
||||
* @param session database connection
|
||||
* @param h_contract hash of the contract
|
||||
* @param h_wire hash of merchant wire details
|
||||
* @param coin_pub public key of deposited coin
|
||||
@ -1207,10 +1329,12 @@ struct TALER_MINTDB_Plugin
|
||||
* @param transaction_id transaction identifier
|
||||
* @param cb function to call with the result
|
||||
* @param cb_cls closure to pass to @a cb
|
||||
* @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors
|
||||
* @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors,
|
||||
* #GNUNET_NO if nothing was found
|
||||
*/
|
||||
int
|
||||
(*wire_lookup_deposit_wtid)(void *cls,
|
||||
struct TALER_MINTDB_Session *session,
|
||||
const struct GNUNET_HashCode *h_contract,
|
||||
const struct GNUNET_HashCode *h_wire,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
@ -1219,7 +1343,91 @@ struct TALER_MINTDB_Plugin
|
||||
TALER_MINTDB_DepositWtidCallback cb,
|
||||
void *cb_cls);
|
||||
|
||||
|
||||
/**
|
||||
* Function called to insert aggregation information into the DB.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param session database connection
|
||||
* @param wtid the raw wire transfer identifier we used
|
||||
* @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
|
||||
* @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls)
|
||||
* @param h_contract which contract was this payment about
|
||||
* @param transaction_id merchant's transaction ID for the payment
|
||||
* @param execution_time when did we execute the transaction
|
||||
* @param coin_pub which public key was this payment about
|
||||
* @param coin_value amount contributed by this coin in total
|
||||
* @param coin_fee deposit fee charged by mint for this coin
|
||||
* @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors
|
||||
*/
|
||||
int
|
||||
(*insert_aggregation_tracking)(void *cls,
|
||||
struct TALER_MINTDB_Session *session,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
const struct GNUNET_HashCode *h_wire,
|
||||
const struct GNUNET_HashCode *h_contract,
|
||||
uint64_t transaction_id,
|
||||
struct GNUNET_TIME_Absolute execution_time,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_Amount *coin_value,
|
||||
const struct TALER_Amount *coin_fee);
|
||||
|
||||
|
||||
/**
|
||||
* Function called to insert wire transfer commit data into the DB.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param session database connection
|
||||
* @param type type of the wire transfer (i.e. "sepa")
|
||||
* @param buf buffer with wire transfer preparation data
|
||||
* @param buf_size number of bytes in @a buf
|
||||
* @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors
|
||||
*/
|
||||
int
|
||||
(*wire_prepare_data_insert)(void *cls,
|
||||
struct TALER_MINTDB_Session *session,
|
||||
const char *type,
|
||||
const char *buf,
|
||||
size_t buf_size);
|
||||
|
||||
|
||||
/**
|
||||
* Function called to mark wire transfer commit data as finished.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param session database connection
|
||||
* @param rowid which entry to mark as finished
|
||||
* @return #GNUNET_OK on success, #GNUNET_SYSERR on DB errors
|
||||
*/
|
||||
int
|
||||
(*wire_prepare_data_mark_finished)(void *cls,
|
||||
struct TALER_MINTDB_Session *session,
|
||||
unsigned long long rowid);
|
||||
|
||||
|
||||
/**
|
||||
* Function called to get an unfinished wire transfer
|
||||
* preparation data. Fetches at most one item.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param session database connection
|
||||
* @param type type fo the wire transfer (i.e. "sepa")
|
||||
* @param cb function to call for ONE unfinished item
|
||||
* @param cb_cls closure for @a cb
|
||||
* @return #GNUNET_OK on success,
|
||||
* #GNUNET_NO if there are no entries,
|
||||
* #GNUNET_SYSERR on DB errors
|
||||
*/
|
||||
int
|
||||
(*wire_prepare_data_get)(void *cls,
|
||||
struct TALER_MINTDB_Session *session,
|
||||
const char *type,
|
||||
TALER_MINTDB_WirePreparationCallback cb,
|
||||
void *cb_cls);
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* _NEURO_MINT_DB_H */
|
||||
#endif /* _TALER_MINT_DB_H */
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
@ -156,7 +156,7 @@ struct TALER_PQ_QueryParam
|
||||
* @param x pointer to the query parameter to pass
|
||||
*/
|
||||
struct TALER_PQ_QueryParam
|
||||
TALER_PQ_query_param_amount_nbo(const struct TALER_AmountNBO *x);
|
||||
TALER_PQ_query_param_amount_nbo (const struct TALER_AmountNBO *x);
|
||||
|
||||
|
||||
/**
|
||||
@ -168,7 +168,7 @@ TALER_PQ_query_param_amount_nbo(const struct TALER_AmountNBO *x);
|
||||
* @param x pointer to the query parameter to pass
|
||||
*/
|
||||
struct TALER_PQ_QueryParam
|
||||
TALER_PQ_query_param_amount(const struct TALER_Amount *x);
|
||||
TALER_PQ_query_param_amount (const struct TALER_Amount *x);
|
||||
|
||||
|
||||
/**
|
||||
@ -178,7 +178,7 @@ TALER_PQ_query_param_amount(const struct TALER_Amount *x);
|
||||
* @param x the query parameter to pass.
|
||||
*/
|
||||
struct TALER_PQ_QueryParam
|
||||
TALER_PQ_query_param_rsa_public_key(const struct GNUNET_CRYPTO_rsa_PublicKey *x);
|
||||
TALER_PQ_query_param_rsa_public_key (const struct GNUNET_CRYPTO_rsa_PublicKey *x);
|
||||
|
||||
|
||||
/**
|
||||
@ -188,7 +188,7 @@ TALER_PQ_query_param_rsa_public_key(const struct GNUNET_CRYPTO_rsa_PublicKey *x)
|
||||
* @param x the query parameter to pass
|
||||
*/
|
||||
struct TALER_PQ_QueryParam
|
||||
TALER_PQ_query_param_rsa_signature(const struct GNUNET_CRYPTO_rsa_Signature *x);
|
||||
TALER_PQ_query_param_rsa_signature (const struct GNUNET_CRYPTO_rsa_Signature *x);
|
||||
|
||||
|
||||
/**
|
||||
@ -198,7 +198,7 @@ TALER_PQ_query_param_rsa_signature(const struct GNUNET_CRYPTO_rsa_Signature *x);
|
||||
* @param x pointer to the query parameter to pass
|
||||
*/
|
||||
struct TALER_PQ_QueryParam
|
||||
TALER_PQ_query_param_absolute_time(const struct GNUNET_TIME_Absolute *x);
|
||||
TALER_PQ_query_param_absolute_time (const struct GNUNET_TIME_Absolute *x);
|
||||
|
||||
|
||||
/**
|
||||
@ -208,7 +208,7 @@ TALER_PQ_query_param_absolute_time(const struct GNUNET_TIME_Absolute *x);
|
||||
* @param x pointer to the query parameter to pass
|
||||
*/
|
||||
struct TALER_PQ_QueryParam
|
||||
TALER_PQ_query_param_absolute_time_nbo(const struct GNUNET_TIME_AbsoluteNBO *x);
|
||||
TALER_PQ_query_param_absolute_time_nbo (const struct GNUNET_TIME_AbsoluteNBO *x);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015, 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
@ -106,6 +106,11 @@
|
||||
*/
|
||||
#define TALER_SIGNATURE_MINT_WIRE_TYPES 1036
|
||||
|
||||
/**
|
||||
* Signature where the Mint confirms the /deposit/wtid response.
|
||||
*/
|
||||
#define TALER_SIGNATURE_MINT_CONFIRM_WIRE 1036
|
||||
|
||||
|
||||
/*********************/
|
||||
/* Wallet signatures */
|
||||
@ -854,6 +859,33 @@ struct TALER_ContractPS
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||
|
||||
/**
|
||||
* Merchant-generated transaction ID to detect duplicate
|
||||
* transactions, in big endian. The merchant must communicate a
|
||||
* merchant-unique ID to the customer for each transaction. Note
|
||||
* that different coins that are part of the same transaction can
|
||||
* use the same transaction ID. The transaction ID is useful for
|
||||
* later disputes, and the merchant's contract offer (@e h_contract)
|
||||
* with the customer should include the offer's term and transaction
|
||||
* ID signed with a key from the merchant. This field must match
|
||||
* the corresponding field in the JSON contract.
|
||||
*/
|
||||
uint64_t transaction_id GNUNET_PACKED;
|
||||
|
||||
/**
|
||||
* The total amount to be paid to the merchant. Note that if deposit
|
||||
* fees are higher than @e max_fee, the actual total must be higher
|
||||
* to cover the additional fees. This field must match the
|
||||
* corresponding field in the JSON contract.
|
||||
*/
|
||||
struct TALER_AmountNBO total_amount;
|
||||
|
||||
/**
|
||||
* The maximum fee the merchant is willing to cover. This field
|
||||
* must match the corresponding field in the JSON contract.
|
||||
*/
|
||||
struct TALER_AmountNBO max_fee;
|
||||
|
||||
/**
|
||||
* Hash of the JSON contract in UTF-8 including 0-termination,
|
||||
* using JSON_COMPACT | JSON_SORT_KEYS
|
||||
@ -863,6 +895,65 @@ struct TALER_ContractPS
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Details affirmed by the mint about a wire transfer the mint
|
||||
* claims to have done with respect to a deposit operation.
|
||||
*/
|
||||
struct TALER_ConfirmWirePS
|
||||
{
|
||||
/**
|
||||
* Purpose header for the signature over the contract with
|
||||
* purpose #TALER_SIGNATURE_MINT_CONFIRM_WIRE.
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||
|
||||
/**
|
||||
* Hash over the wiring information of the merchant.
|
||||
*/
|
||||
struct GNUNET_HashCode h_wire GNUNET_PACKED;
|
||||
|
||||
/**
|
||||
* Hash over the contract for which this deposit is made.
|
||||
*/
|
||||
struct GNUNET_HashCode h_contract GNUNET_PACKED;
|
||||
|
||||
/**
|
||||
* Raw value (binary encoding) of the wire transfer subject.
|
||||
*/
|
||||
struct TALER_WireTransferIdentifierRawP wtid;
|
||||
|
||||
/**
|
||||
* The coin's public key. This is the value that must have been
|
||||
* signed (blindly) by the Mint.
|
||||
*/
|
||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||
|
||||
/**
|
||||
* Merchant-generated transaction ID to detect duplicate
|
||||
* transactions, in big endian. The merchant must communicate a
|
||||
* merchant-unique ID to the customer for each transaction. Note
|
||||
* that different coins that are part of the same transaction can
|
||||
* use the same transaction ID. The transaction ID is useful for
|
||||
* later disputes, and the merchant's contract offer (@e h_contract)
|
||||
* with the customer should include the offer's term and transaction
|
||||
* ID signed with a key from the merchant.
|
||||
*/
|
||||
uint64_t transaction_id GNUNET_PACKED;
|
||||
|
||||
/**
|
||||
* When did the mint execute this transfer? Note that the
|
||||
* timestamp may not be exactly the same on the wire, i.e.
|
||||
* because the wire has a different timezone or resolution.
|
||||
*/
|
||||
struct GNUNET_TIME_AbsoluteNBO execution_time;
|
||||
|
||||
/**
|
||||
* The contribution of @e coin_pub to the total transfer volume.
|
||||
* This is the value of the deposit minus the fee.
|
||||
*/
|
||||
struct TALER_AmountNBO coin_contribution;
|
||||
|
||||
};
|
||||
|
||||
GNUNET_NETWORK_STRUCT_END
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
48
src/include/taler_wire_lib.h
Normal file
48
src/include/taler_wire_lib.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is 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 include/taler_wire_lib.h
|
||||
* @brief Interface for loading and unloading wire plugins
|
||||
* @author Christian Grothoff <christian@grothoff.org>
|
||||
*/
|
||||
#ifndef TALER_WIRE_H
|
||||
#define TALER_WIRE_H
|
||||
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include "taler_wire_plugin.h"
|
||||
|
||||
|
||||
/**
|
||||
* Load a WIRE plugin.
|
||||
*
|
||||
* @param cfg configuration to use
|
||||
* @param plugin_name name of the plugin to load
|
||||
* @return #GNUNET_OK on success
|
||||
*/
|
||||
struct TALER_WIRE_Plugin *
|
||||
TALER_WIRE_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg,
|
||||
const char *plugin_name);
|
||||
|
||||
/**
|
||||
* Unload a WIRE plugin.
|
||||
*
|
||||
* @param plugin the plugin to unload
|
||||
*/
|
||||
void
|
||||
TALER_WIRE_plugin_unload (struct TALER_WIRE_Plugin *plugin);
|
||||
|
||||
|
||||
#endif
|
180
src/include/taler_wire_plugin.h
Normal file
180
src/include/taler_wire_plugin.h
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is 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 include/taler_wire_plugin.h
|
||||
* @brief Plugin API for the handling of wire transactions
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef TALER_WIRE_PLUGIN_H
|
||||
#define TALER_WIRE_PLUGIN_H
|
||||
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <jansson.h>
|
||||
#include "taler_util.h"
|
||||
|
||||
|
||||
/**
|
||||
* Callback with prepared transaction.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param buf transaction data to persist, NULL on error
|
||||
* @param buf_size number of bytes in @a buf, 0 on error
|
||||
*/
|
||||
typedef void
|
||||
(*TALER_WIRE_PrepareTransactionCallback) (void *cls,
|
||||
const char *buf,
|
||||
size_t buf_size);
|
||||
|
||||
|
||||
/**
|
||||
* Handle returned for cancelling a preparation step.
|
||||
*/
|
||||
struct TALER_WIRE_PrepareHandle;
|
||||
|
||||
|
||||
/**
|
||||
* Handle returned for cancelling an execution step.
|
||||
*/
|
||||
struct TALER_WIRE_ExecuteHandle;
|
||||
|
||||
|
||||
/**
|
||||
* Function called with the result from the execute step.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param success #GNUNET_OK on success, #GNUNET_SYSERR on failure
|
||||
* @param emsg NULL on success, otherwise an error message
|
||||
*/
|
||||
typedef void
|
||||
(*TALER_WIRE_ConfirmationCallback)(void *cls,
|
||||
int success,
|
||||
const char *emsg);
|
||||
|
||||
|
||||
/**
|
||||
* @brief The plugin API, returned from the plugin's "init" function.
|
||||
* The argument given to "init" is simply a configuration handle.
|
||||
*/
|
||||
struct TALER_WIRE_Plugin
|
||||
{
|
||||
|
||||
/**
|
||||
* Closure for all callbacks.
|
||||
*/
|
||||
void *cls;
|
||||
|
||||
/**
|
||||
* Name of the library which generated this plugin. Set by the
|
||||
* plugin loader.
|
||||
*/
|
||||
char *library_name;
|
||||
|
||||
/**
|
||||
* Round amount DOWN to the amount that can be transferred via the wire
|
||||
* method. For example, Taler may support 0.000001 EUR as a unit of
|
||||
* payment, but SEPA only supports 0.01 EUR. This function would
|
||||
* round 0.125 EUR to 0.12 EUR in this case.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param[in,out] amount amount to round down
|
||||
* @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary,
|
||||
* #GNUNET_SYSERR if the amount or currency was invalid
|
||||
*/
|
||||
int
|
||||
(*amount_round) (void *cls,
|
||||
struct TALER_Amount *amount);
|
||||
|
||||
|
||||
/**
|
||||
* Check if the given wire format JSON object is correctly formatted
|
||||
*
|
||||
* @param wire the JSON wire format object
|
||||
* @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
|
||||
*/
|
||||
int
|
||||
(*wire_validate) (const json_t *wire);
|
||||
|
||||
|
||||
/**
|
||||
* Prepare for exeuction of a wire transfer.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param wire valid wire account information
|
||||
* @param amount amount to transfer, already rounded
|
||||
* @param wtid wire transfer identifier to use
|
||||
* @param ptc function to call with the prepared data to persist
|
||||
* @param ptc_cls closure for @a ptc
|
||||
* @return NULL on failure
|
||||
*/
|
||||
struct TALER_WIRE_PrepareHandle *
|
||||
(*prepare_wire_transfer) (void *cls,
|
||||
const json_t *wire,
|
||||
const struct TALER_Amount *amount,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
TALER_WIRE_PrepareTransactionCallback ptc,
|
||||
void *ptc_cls);
|
||||
|
||||
/**
|
||||
* Abort preparation of a wire transfer. For example,
|
||||
* because we are shutting down.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param pth preparation to cancel
|
||||
*/
|
||||
void
|
||||
(*prepare_wire_transfer_cancel) (void *cls,
|
||||
struct TALER_WIRE_PrepareHandle *pth);
|
||||
|
||||
|
||||
/**
|
||||
* Execute a wire transfer.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param buf buffer with the prepared execution details
|
||||
* @param buf_size number of bytes in @a buf
|
||||
* @param cc function to call upon success
|
||||
* @param cc_cls closure for @a cc
|
||||
* @return NULL on error
|
||||
*/
|
||||
struct TALER_WIRE_ExecuteHandle *
|
||||
(*execute_wire_transfer) (void *cls,
|
||||
const char *buf,
|
||||
size_t buf_size,
|
||||
TALER_WIRE_ConfirmationCallback cc,
|
||||
void *cc_cls);
|
||||
|
||||
|
||||
/**
|
||||
* Abort execution of a wire transfer. For example, because we are
|
||||
* shutting down. Note that if an execution is aborted, it may or
|
||||
* may not still succeed. The caller MUST run @e
|
||||
* execute_wire_transfer again for the same request as soon as
|
||||
* possilbe, to ensure that the request either ultimately succeeds
|
||||
* or ultimately fails. Until this has been done, the transaction is
|
||||
* in limbo (i.e. may or may not have been committed).
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param eh execution to cancel
|
||||
*/
|
||||
void
|
||||
(*execute_wire_transfer_cancel) (void *cls,
|
||||
struct TALER_WIRE_ExecuteHandle *eh);
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* TALER_WIRE_PLUGIN_H */
|
@ -20,10 +20,12 @@ libtalermint_la_SOURCES = \
|
||||
mint_api_handle.c mint_api_handle.h \
|
||||
mint_api_admin.c \
|
||||
mint_api_deposit.c \
|
||||
mint_api_deposit_wtid.c \
|
||||
mint_api_refresh.c \
|
||||
mint_api_refresh_link.c \
|
||||
mint_api_reserve.c \
|
||||
mint_api_wire.c
|
||||
mint_api_wire.c \
|
||||
mint_api_wire_deposits.c
|
||||
|
||||
libtalermint_la_LIBADD = \
|
||||
-lgnunetutil \
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
@ -288,7 +288,7 @@ TALER_MINT_perform (struct TALER_MINT_Context *ctx)
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_getinfo (cmsg->easy_handle,
|
||||
CURLINFO_PRIVATE,
|
||||
(char *) &job));
|
||||
(char **) &job));
|
||||
GNUNET_assert (job->ctx == ctx);
|
||||
job->jcc (job->jcc_cls,
|
||||
cmsg->easy_handle);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
@ -434,6 +434,14 @@ TALER_MINT_deposit (struct TALER_MINT_Handle *mint,
|
||||
TALER_LOG_WARNING ("Denomination key unknown to mint\n");
|
||||
return NULL;
|
||||
}
|
||||
if (GNUNET_SYSERR ==
|
||||
TALER_amount_subtract (&amount_without_fee,
|
||||
amount,
|
||||
&dki->fee_deposit))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (GNUNET_OK !=
|
||||
verify_signatures (dki,
|
||||
@ -492,9 +500,6 @@ TALER_MINT_deposit (struct TALER_MINT_Handle *mint,
|
||||
dh->depconf.transaction_id = GNUNET_htonll (transaction_id);
|
||||
dh->depconf.timestamp = GNUNET_TIME_absolute_hton (timestamp);
|
||||
dh->depconf.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
|
||||
TALER_amount_subtract (&amount_without_fee,
|
||||
amount,
|
||||
&dki->fee_deposit);
|
||||
TALER_amount_hton (&dh->depconf.amount_without_fee,
|
||||
&amount_without_fee);
|
||||
dh->depconf.coin_pub = *coin_pub;
|
||||
|
379
src/mint-lib/mint_api_deposit_wtid.c
Normal file
379
src/mint-lib/mint_api_deposit_wtid.c
Normal file
@ -0,0 +1,379 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015, 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is 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_deposit_wtid.c
|
||||
* @brief Implementation of the /deposit/wtid request of the mint's HTTP API
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include <curl/curl.h>
|
||||
#include <jansson.h>
|
||||
#include <microhttpd.h> /* just for HTTP status codes */
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include "taler_mint_service.h"
|
||||
#include "mint_api_common.h"
|
||||
#include "mint_api_json.h"
|
||||
#include "mint_api_context.h"
|
||||
#include "mint_api_handle.h"
|
||||
#include "taler_signatures.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief A Deposit Wtid Handle
|
||||
*/
|
||||
struct TALER_MINT_DepositWtidHandle
|
||||
{
|
||||
|
||||
/**
|
||||
* The connection to mint this request handle will use
|
||||
*/
|
||||
struct TALER_MINT_Handle *mint;
|
||||
|
||||
/**
|
||||
* The url for this request.
|
||||
*/
|
||||
char *url;
|
||||
|
||||
/**
|
||||
* JSON encoding of the request to POST.
|
||||
*/
|
||||
char *json_enc;
|
||||
|
||||
/**
|
||||
* Handle for the request.
|
||||
*/
|
||||
struct MAC_Job *job;
|
||||
|
||||
/**
|
||||
* Function to call with the result.
|
||||
*/
|
||||
TALER_MINT_DepositWtidCallback cb;
|
||||
|
||||
/**
|
||||
* Closure for @a cb.
|
||||
*/
|
||||
void *cb_cls;
|
||||
|
||||
/**
|
||||
* Download buffer
|
||||
*/
|
||||
struct MAC_DownloadBuffer db;
|
||||
|
||||
/**
|
||||
* Information the mint should sign in response.
|
||||
* (with pre-filled fields from the request).
|
||||
*/
|
||||
struct TALER_ConfirmWirePS depconf;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Verify that the signature on the "200 OK" response
|
||||
* from the mint is valid.
|
||||
*
|
||||
* @param dwh deposit wtid handle
|
||||
* @param json json reply with the signature
|
||||
* @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
|
||||
*/
|
||||
static int
|
||||
verify_deposit_wtid_signature_ok (const struct TALER_MINT_DepositWtidHandle *dwh,
|
||||
json_t *json)
|
||||
{
|
||||
struct TALER_MintSignatureP mint_sig;
|
||||
struct TALER_MintPublicKeyP mint_pub;
|
||||
const struct TALER_MINT_Keys *key_state;
|
||||
struct MAJ_Specification spec[] = {
|
||||
MAJ_spec_fixed_auto ("mint_sig", &mint_sig),
|
||||
MAJ_spec_fixed_auto ("mint_pub", &mint_pub),
|
||||
MAJ_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
MAJ_parse_json (json,
|
||||
spec))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
key_state = TALER_MINT_get_keys (dwh->mint);
|
||||
if (GNUNET_OK !=
|
||||
TALER_MINT_test_signing_key (key_state,
|
||||
&mint_pub))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MINT_CONFIRM_WIRE,
|
||||
&dwh->depconf.purpose,
|
||||
&mint_sig.eddsa_signature,
|
||||
&mint_pub.eddsa_pub))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called when we're done processing the
|
||||
* HTTP /deposit/wtid request.
|
||||
*
|
||||
* @param cls the `struct TALER_MINT_DepositWtidHandle`
|
||||
* @param eh the curl request handle
|
||||
*/
|
||||
static void
|
||||
handle_deposit_wtid_finished (void *cls,
|
||||
CURL *eh)
|
||||
{
|
||||
struct TALER_MINT_DepositWtidHandle *dwh = cls;
|
||||
long response_code;
|
||||
json_t *json;
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid = NULL;
|
||||
struct GNUNET_TIME_Absolute execution_time = GNUNET_TIME_UNIT_FOREVER_ABS;
|
||||
const struct TALER_Amount *coin_contribution = NULL;
|
||||
struct TALER_Amount coin_contribution_s;
|
||||
|
||||
dwh->job = NULL;
|
||||
json = MAC_download_get_result (&dwh->db,
|
||||
eh,
|
||||
&response_code);
|
||||
switch (response_code)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case MHD_HTTP_OK:
|
||||
{
|
||||
struct MAJ_Specification spec[] = {
|
||||
MAJ_spec_fixed_auto ("wtid", &dwh->depconf.wtid),
|
||||
MAJ_spec_absolute_time ("execution_time", &execution_time),
|
||||
MAJ_spec_amount ("coin_contribution", &coin_contribution_s),
|
||||
MAJ_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
MAJ_parse_json (json,
|
||||
spec))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
response_code = 0;
|
||||
break;
|
||||
}
|
||||
wtid = &dwh->depconf.wtid;
|
||||
dwh->depconf.execution_time = GNUNET_TIME_absolute_hton (execution_time);
|
||||
TALER_amount_hton (&dwh->depconf.coin_contribution,
|
||||
&coin_contribution_s);
|
||||
coin_contribution = &coin_contribution_s;
|
||||
if (GNUNET_OK !=
|
||||
verify_deposit_wtid_signature_ok (dwh,
|
||||
json))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
response_code = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MHD_HTTP_ACCEPTED:
|
||||
{
|
||||
/* Transaction known, but not executed yet */
|
||||
struct MAJ_Specification spec[] = {
|
||||
MAJ_spec_absolute_time ("execution_time", &execution_time),
|
||||
MAJ_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
MAJ_parse_json (json,
|
||||
spec))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
response_code = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MHD_HTTP_BAD_REQUEST:
|
||||
/* This should never happen, either us or the mint is buggy
|
||||
(or API version conflict); just pass JSON reply to the application */
|
||||
break;
|
||||
case MHD_HTTP_UNAUTHORIZED:
|
||||
/* Nothing really to verify, mint says one of the signatures is
|
||||
invalid; as we checked them, this should never happen, we
|
||||
should pass the JSON reply to the application */
|
||||
break;
|
||||
case MHD_HTTP_NOT_FOUND:
|
||||
/* Mint does not know about transaction;
|
||||
we should pass the reply to the application */
|
||||
break;
|
||||
case MHD_HTTP_INTERNAL_SERVER_ERROR:
|
||||
/* Server had an internal issue; we should retry, but this API
|
||||
leaves this to the application */
|
||||
break;
|
||||
default:
|
||||
/* unexpected response code */
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Unexpected response code %u\n",
|
||||
response_code);
|
||||
GNUNET_break (0);
|
||||
response_code = 0;
|
||||
break;
|
||||
}
|
||||
dwh->cb (dwh->cb_cls,
|
||||
response_code,
|
||||
json,
|
||||
wtid,
|
||||
execution_time,
|
||||
coin_contribution);
|
||||
json_decref (json);
|
||||
TALER_MINT_deposit_wtid_cancel (dwh);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain wire transfer details about an existing deposit operation.
|
||||
*
|
||||
* @param mint the mint to query
|
||||
* @param merchant_priv the merchant's private key
|
||||
* @param h_wire hash of merchant's wire transfer details
|
||||
* @param h_contract hash of the contract
|
||||
* @param coin_pub public key of the coin
|
||||
* @param transaction_id transaction identifier
|
||||
* @param cb function to call with the result
|
||||
* @param cb_cls closure for @a cb
|
||||
* @return handle to abort request
|
||||
*/
|
||||
struct TALER_MINT_DepositWtidHandle *
|
||||
TALER_MINT_deposit_wtid (struct TALER_MINT_Handle *mint,
|
||||
const struct TALER_MerchantPrivateKeyP *merchant_priv,
|
||||
const struct GNUNET_HashCode *h_wire,
|
||||
const struct GNUNET_HashCode *h_contract,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
uint64_t transaction_id,
|
||||
TALER_MINT_DepositWtidCallback cb,
|
||||
void *cb_cls)
|
||||
{
|
||||
struct TALER_DepositTrackPS dtp;
|
||||
struct TALER_MerchantSignatureP merchant_sig;
|
||||
struct TALER_MINT_DepositWtidHandle *dwh;
|
||||
struct TALER_MINT_Context *ctx;
|
||||
json_t *deposit_wtid_obj;
|
||||
CURL *eh;
|
||||
|
||||
if (GNUNET_YES !=
|
||||
MAH_handle_is_ready (mint))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return NULL;
|
||||
}
|
||||
dtp.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_DEPOSIT_WTID);
|
||||
dtp.purpose.size = htonl (sizeof (dtp));
|
||||
dtp.h_contract = *h_contract;
|
||||
dtp.h_wire = *h_wire;
|
||||
dtp.transaction_id = GNUNET_htonll (transaction_id);
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv->eddsa_priv,
|
||||
&dtp.merchant.eddsa_pub);
|
||||
|
||||
dtp.coin_pub = *coin_pub;
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
GNUNET_CRYPTO_eddsa_sign (&merchant_priv->eddsa_priv,
|
||||
&dtp.purpose,
|
||||
&merchant_sig.eddsa_sig));
|
||||
deposit_wtid_obj = json_pack ("{s:o, s:o," /* H_wire, H_contract */
|
||||
" s:o, s:I," /* coin_pub, transaction_id */
|
||||
" s:o, s:o}", /* merchant_pub, merchant_sig */
|
||||
"H_wire", TALER_json_from_data (h_wire,
|
||||
sizeof (struct GNUNET_HashCode)),
|
||||
"H_contract", TALER_json_from_data (h_contract,
|
||||
sizeof (struct GNUNET_HashCode)),
|
||||
"coin_pub", TALER_json_from_data (coin_pub,
|
||||
sizeof (*coin_pub)),
|
||||
"transaction_id", (json_int_t) transaction_id,
|
||||
"merchant_pub", TALER_json_from_data (&dtp.merchant,
|
||||
sizeof (struct TALER_MerchantPublicKeyP)),
|
||||
"merchant_sig", TALER_json_from_data (&merchant_sig,
|
||||
sizeof (merchant_sig)));
|
||||
|
||||
dwh = GNUNET_new (struct TALER_MINT_DepositWtidHandle);
|
||||
dwh->mint = mint;
|
||||
dwh->cb = cb;
|
||||
dwh->cb_cls = cb_cls;
|
||||
dwh->url = MAH_path_to_url (mint, "/deposit/wtid");
|
||||
dwh->depconf.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS));
|
||||
dwh->depconf.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_WIRE);
|
||||
dwh->depconf.h_wire = *h_wire;
|
||||
dwh->depconf.h_contract = *h_contract;
|
||||
dwh->depconf.coin_pub = *coin_pub;
|
||||
dwh->depconf.transaction_id = GNUNET_htonll (transaction_id);
|
||||
|
||||
eh = curl_easy_init ();
|
||||
GNUNET_assert (NULL != (dwh->json_enc =
|
||||
json_dumps (deposit_wtid_obj,
|
||||
JSON_COMPACT)));
|
||||
json_decref (deposit_wtid_obj);
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_URL,
|
||||
dwh->url));
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_POSTFIELDS,
|
||||
dwh->json_enc));
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_POSTFIELDSIZE,
|
||||
strlen (dwh->json_enc)));
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_WRITEFUNCTION,
|
||||
&MAC_download_cb));
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_WRITEDATA,
|
||||
&dwh->db));
|
||||
ctx = MAH_handle_to_context (mint);
|
||||
dwh->job = MAC_job_add (ctx,
|
||||
eh,
|
||||
GNUNET_YES,
|
||||
&handle_deposit_wtid_finished,
|
||||
dwh);
|
||||
return dwh;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cancel deposit wtid request. This function cannot be used on a request
|
||||
* handle if a response is already served for it.
|
||||
*
|
||||
* @param dwh the wire deposits request handle
|
||||
*/
|
||||
void
|
||||
TALER_MINT_deposit_wtid_cancel (struct TALER_MINT_DepositWtidHandle *dwh)
|
||||
{
|
||||
if (NULL != dwh->job)
|
||||
{
|
||||
MAC_job_cancel (dwh->job);
|
||||
dwh->job = NULL;
|
||||
}
|
||||
GNUNET_free_non_null (dwh->db.buf);
|
||||
GNUNET_free (dwh->url);
|
||||
GNUNET_free (dwh->json_enc);
|
||||
GNUNET_free (dwh);
|
||||
}
|
||||
|
||||
|
||||
/* end of mint_api_deposit_wtid.c */
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
@ -755,7 +755,7 @@ TALER_MINT_connect (struct TALER_MINT_Context *ctx,
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (c,
|
||||
CURLOPT_VERBOSE,
|
||||
1));
|
||||
0));
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (c,
|
||||
CURLOPT_STDERR,
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -232,6 +232,20 @@ parse_json (json_t *root,
|
||||
}
|
||||
break;
|
||||
|
||||
case MAJ_CMD_UINT64:
|
||||
{
|
||||
json_int_t val;
|
||||
|
||||
if (! json_is_integer (pos))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return i;
|
||||
}
|
||||
val = json_integer_value (pos);
|
||||
*spec[i].details.u64 = (uint64_t) val;
|
||||
}
|
||||
break;
|
||||
|
||||
case MAJ_CMD_JSON_OBJECT:
|
||||
{
|
||||
if (! (json_is_object (pos) || json_is_array (pos)) )
|
||||
@ -428,6 +442,26 @@ MAJ_spec_uint16 (const char *name,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 64-bit integer.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param[out] u64 where to store the integer found under @a name
|
||||
*/
|
||||
struct MAJ_Specification
|
||||
MAJ_spec_uint64 (const char *name,
|
||||
uint64_t *u64)
|
||||
{
|
||||
struct MAJ_Specification ret =
|
||||
{
|
||||
.cmd = MAJ_CMD_UINT64,
|
||||
.field = name,
|
||||
.details.u64 = u64
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* JSON object.
|
||||
*
|
||||
|
@ -78,6 +78,11 @@ enum MAJ_Command
|
||||
*/
|
||||
MAJ_CMD_UINT16,
|
||||
|
||||
/**
|
||||
* Parse `uint64_t` integer at the current position.
|
||||
*/
|
||||
MAJ_CMD_UINT64,
|
||||
|
||||
/**
|
||||
* Parse JSON object at the current position.
|
||||
*/
|
||||
@ -191,6 +196,11 @@ struct MAJ_Specification
|
||||
*/
|
||||
uint16_t *u16;
|
||||
|
||||
/**
|
||||
* Where to store 64-bit integer.
|
||||
*/
|
||||
uint64_t *u64;
|
||||
|
||||
/**
|
||||
* Where to store a JSON object.
|
||||
*/
|
||||
@ -282,6 +292,17 @@ MAJ_spec_uint16 (const char *name,
|
||||
uint16_t *u16);
|
||||
|
||||
|
||||
/**
|
||||
* 64-bit integer.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param[out] u64 where to store the integer found under @a name
|
||||
*/
|
||||
struct MAJ_Specification
|
||||
MAJ_spec_uint64 (const char *name,
|
||||
uint64_t *u64);
|
||||
|
||||
|
||||
/**
|
||||
* JSON object.
|
||||
*
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
@ -334,12 +334,9 @@ free_melt_data (struct MeltData *md)
|
||||
|
||||
for (i=0;i<TALER_CNC_KAPPA;i++)
|
||||
{
|
||||
if (NULL != md->fresh_coins)
|
||||
{
|
||||
for (j=0;j<md->num_fresh_coins;j++)
|
||||
free_fresh_coin (&md->fresh_coins[i][j]);
|
||||
GNUNET_free (md->fresh_coins[i]);
|
||||
}
|
||||
for (j=0;j<md->num_fresh_coins;j++)
|
||||
free_fresh_coin (&md->fresh_coins[i][j]);
|
||||
GNUNET_free (md->fresh_coins[i]);
|
||||
}
|
||||
/* Finally, clean up a bit...
|
||||
(NOTE: compilers might optimize this away, so this is
|
||||
@ -774,7 +771,7 @@ deserialize_melt_data (const char *buf,
|
||||
&buf[off],
|
||||
buf_size - off,
|
||||
&ok);
|
||||
if (off != buf_size)
|
||||
if (off != buf_size)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
ok = GNUNET_NO;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2015, 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
@ -185,6 +185,17 @@ parse_refresh_link_ok (struct TALER_MINT_RefreshLinkHandle *rlh,
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
num_coins = 0;
|
||||
/* Theoretically, a coin may have been melted repeatedly
|
||||
into different sessions; so the response is an array
|
||||
which contains information by melting session. That
|
||||
array contains another array. However, our API returns
|
||||
a single 1d array, so we flatten the 2d array that is
|
||||
returned into a single array. Note that usually a coin
|
||||
is melted at most once, and so we'll only run this
|
||||
loop once for 'session=0' in most cases.
|
||||
|
||||
num_coins tracks the size of the 1d array we return,
|
||||
whilst 'i' and 'session' track the 2d array. */
|
||||
for (session=0;session<json_array_size (json); session++)
|
||||
{
|
||||
json_t *jsona;
|
||||
@ -194,7 +205,7 @@ parse_refresh_link_ok (struct TALER_MINT_RefreshLinkHandle *rlh,
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
MAJ_parse_json (json_array_get (json,
|
||||
MAJ_parse_json (json_array_get (json,
|
||||
session),
|
||||
spec))
|
||||
{
|
||||
@ -212,13 +223,17 @@ parse_refresh_link_ok (struct TALER_MINT_RefreshLinkHandle *rlh,
|
||||
num_coins += json_array_size (jsona);
|
||||
MAJ_parse_free (spec);
|
||||
}
|
||||
/* Now that we know how big the 1d array is, allocate
|
||||
and fill it. */
|
||||
{
|
||||
unsigned int off_coin;
|
||||
unsigned int off_coin; /* index into 1d array */
|
||||
unsigned int i;
|
||||
struct TALER_CoinSpendPrivateKeyP coin_privs[num_coins];
|
||||
struct TALER_DenominationSignature sigs[num_coins];
|
||||
struct TALER_DenominationPublicKey pubs[num_coins];
|
||||
|
||||
|
||||
memset (sigs, 0, sizeof (sigs));
|
||||
memset (pubs, 0, sizeof (pubs));
|
||||
off_coin = 0;
|
||||
for (session=0;session<json_array_size (json); session++)
|
||||
{
|
||||
@ -233,7 +248,7 @@ parse_refresh_link_ok (struct TALER_MINT_RefreshLinkHandle *rlh,
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
MAJ_parse_json (json_array_get (json,
|
||||
MAJ_parse_json (json_array_get (json,
|
||||
session),
|
||||
spec))
|
||||
{
|
||||
@ -246,13 +261,13 @@ parse_refresh_link_ok (struct TALER_MINT_RefreshLinkHandle *rlh,
|
||||
MAJ_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
|
||||
/* decode all coins */
|
||||
for (i=0;i<json_array_size (jsona);i++)
|
||||
{
|
||||
if (GNUNET_OK !=
|
||||
parse_refresh_link_coin (rlh,
|
||||
json_array_get (jsona,
|
||||
json_array_get (jsona,
|
||||
i),
|
||||
&trans_pub,
|
||||
&secret_enc,
|
||||
@ -265,6 +280,7 @@ parse_refresh_link_ok (struct TALER_MINT_RefreshLinkHandle *rlh,
|
||||
}
|
||||
}
|
||||
/* check if we really got all, then invoke callback */
|
||||
off_coin += i;
|
||||
if (i != json_array_size (jsona))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
@ -272,9 +288,9 @@ parse_refresh_link_ok (struct TALER_MINT_RefreshLinkHandle *rlh,
|
||||
MAJ_parse_free (spec);
|
||||
break;
|
||||
}
|
||||
off_coin += json_array_size (jsona);
|
||||
MAJ_parse_free (spec);
|
||||
}
|
||||
} /* end of for (session) */
|
||||
|
||||
if (off_coin == num_coins)
|
||||
{
|
||||
rlh->link_cb (rlh->link_cb_cls,
|
||||
@ -294,9 +310,13 @@ parse_refresh_link_ok (struct TALER_MINT_RefreshLinkHandle *rlh,
|
||||
}
|
||||
|
||||
/* clean up */
|
||||
for (i=0;i<num_coins;i++)
|
||||
for (i=0;i<off_coin;i++)
|
||||
{
|
||||
if (NULL != sigs[i].rsa_signature)
|
||||
GNUNET_CRYPTO_rsa_signature_free (sigs[i].rsa_signature);
|
||||
if (NULL != pubs[i].rsa_public_key)
|
||||
GNUNET_CRYPTO_rsa_public_key_free (pubs[i].rsa_public_key);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
284
src/mint-lib/mint_api_wire_deposits.c
Normal file
284
src/mint-lib/mint_api_wire_deposits.c
Normal file
@ -0,0 +1,284 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015, 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is 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_wire_deposits.c
|
||||
* @brief Implementation of the /wire/deposits request of the mint's HTTP API
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include <curl/curl.h>
|
||||
#include <jansson.h>
|
||||
#include <microhttpd.h> /* just for HTTP status codes */
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include "taler_mint_service.h"
|
||||
#include "mint_api_common.h"
|
||||
#include "mint_api_json.h"
|
||||
#include "mint_api_context.h"
|
||||
#include "mint_api_handle.h"
|
||||
#include "taler_signatures.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief A /wire/deposits Handle
|
||||
*/
|
||||
struct TALER_MINT_WireDepositsHandle
|
||||
{
|
||||
|
||||
/**
|
||||
* The connection to mint this request handle will use
|
||||
*/
|
||||
struct TALER_MINT_Handle *mint;
|
||||
|
||||
/**
|
||||
* The url for this request.
|
||||
*/
|
||||
char *url;
|
||||
|
||||
/**
|
||||
* Handle for the request.
|
||||
*/
|
||||
struct MAC_Job *job;
|
||||
|
||||
/**
|
||||
* Function to call with the result.
|
||||
*/
|
||||
TALER_MINT_WireDepositsCallback cb;
|
||||
|
||||
/**
|
||||
* Closure for @a cb.
|
||||
*/
|
||||
void *cb_cls;
|
||||
|
||||
/**
|
||||
* Download buffer
|
||||
*/
|
||||
struct MAC_DownloadBuffer db;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Function called when we're done processing the
|
||||
* HTTP /wire/deposits request.
|
||||
*
|
||||
* @param cls the `struct TALER_MINT_WireDepositsHandle`
|
||||
* @param eh the curl request handle
|
||||
*/
|
||||
static void
|
||||
handle_wire_deposits_finished (void *cls,
|
||||
CURL *eh)
|
||||
{
|
||||
struct TALER_MINT_WireDepositsHandle *wdh = cls;
|
||||
long response_code;
|
||||
json_t *json;
|
||||
|
||||
wdh->job = NULL;
|
||||
json = MAC_download_get_result (&wdh->db,
|
||||
eh,
|
||||
&response_code);
|
||||
switch (response_code)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case MHD_HTTP_OK:
|
||||
{
|
||||
json_t *details_j;
|
||||
struct GNUNET_HashCode h_wire;
|
||||
struct TALER_Amount total_amount;
|
||||
struct TALER_MerchantPublicKeyP merchant_pub;
|
||||
unsigned int num_details;
|
||||
struct MAJ_Specification spec[] = {
|
||||
MAJ_spec_fixed_auto ("H_wire", &h_wire),
|
||||
MAJ_spec_fixed_auto ("merchant_pub", &merchant_pub),
|
||||
MAJ_spec_amount ("total_amount", &total_amount),
|
||||
MAJ_spec_json ("details", &details_j),
|
||||
MAJ_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
MAJ_parse_json (json,
|
||||
spec))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
response_code = 0;
|
||||
break;
|
||||
}
|
||||
num_details = json_array_size (details_j);
|
||||
{
|
||||
struct TALER_WireDepositDetails details[num_details];
|
||||
unsigned int i;
|
||||
|
||||
for (i=0;i<num_details;i++)
|
||||
{
|
||||
struct TALER_WireDepositDetails *detail = &details[i];
|
||||
struct json_t *detail_j = json_array_get (details_j, i);
|
||||
struct MAJ_Specification spec_detail[] = {
|
||||
MAJ_spec_fixed_auto ("H_contract", &detail->h_contract),
|
||||
MAJ_spec_amount ("deposit_value", &detail->coin_value),
|
||||
MAJ_spec_amount ("deposit_fee", &detail->coin_fee),
|
||||
MAJ_spec_uint64 ("transaction_id", &detail->transaction_id),
|
||||
MAJ_spec_fixed_auto ("coin_pub", &detail->coin_pub),
|
||||
MAJ_spec_end
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
MAJ_parse_json (detail_j,
|
||||
spec_detail))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
response_code = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (0 == response_code)
|
||||
break;
|
||||
wdh->cb (wdh->cb_cls,
|
||||
response_code,
|
||||
json,
|
||||
&h_wire,
|
||||
&total_amount,
|
||||
num_details,
|
||||
details);
|
||||
json_decref (json);
|
||||
TALER_MINT_wire_deposits_cancel (wdh);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MHD_HTTP_BAD_REQUEST:
|
||||
/* This should never happen, either us or the mint is buggy
|
||||
(or API version conflict); just pass JSON reply to the application */
|
||||
break;
|
||||
case MHD_HTTP_UNAUTHORIZED:
|
||||
/* Nothing really to verify, mint says one of the signatures is
|
||||
invalid; as we checked them, this should never happen, we
|
||||
should pass the JSON reply to the application */
|
||||
break;
|
||||
case MHD_HTTP_NOT_FOUND:
|
||||
/* Mint does not know about transaction;
|
||||
we should pass the reply to the application */
|
||||
break;
|
||||
case MHD_HTTP_INTERNAL_SERVER_ERROR:
|
||||
/* Server had an internal issue; we should retry, but this API
|
||||
leaves this to the application */
|
||||
break;
|
||||
default:
|
||||
/* unexpected response code */
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Unexpected response code %u\n",
|
||||
response_code);
|
||||
GNUNET_break (0);
|
||||
response_code = 0;
|
||||
break;
|
||||
}
|
||||
wdh->cb (wdh->cb_cls,
|
||||
response_code,
|
||||
json,
|
||||
NULL, NULL, 0, NULL);
|
||||
json_decref (json);
|
||||
TALER_MINT_wire_deposits_cancel (wdh);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Query the mint about which transactions were combined
|
||||
* to create a wire transfer.
|
||||
*
|
||||
* @param mint mint to query
|
||||
* @param wtid raw wire transfer identifier to get information about
|
||||
* @param cb callback to call
|
||||
* @param cb_cls closure for @a cb
|
||||
* @return handle to cancel operation
|
||||
*/
|
||||
struct TALER_MINT_WireDepositsHandle *
|
||||
TALER_MINT_wire_deposits (struct TALER_MINT_Handle *mint,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
TALER_MINT_WireDepositsCallback cb,
|
||||
void *cb_cls)
|
||||
{
|
||||
struct TALER_MINT_WireDepositsHandle *wdh;
|
||||
struct TALER_MINT_Context *ctx;
|
||||
char *buf;
|
||||
char *path;
|
||||
CURL *eh;
|
||||
|
||||
if (GNUNET_YES !=
|
||||
MAH_handle_is_ready (mint))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wdh = GNUNET_new (struct TALER_MINT_WireDepositsHandle);
|
||||
wdh->mint = mint;
|
||||
wdh->cb = cb;
|
||||
wdh->cb_cls = cb_cls;
|
||||
|
||||
buf = GNUNET_STRINGS_data_to_string_alloc (wtid,
|
||||
sizeof (struct TALER_WireTransferIdentifierRawP));
|
||||
GNUNET_asprintf (&path,
|
||||
"/wire/deposits?wtid=%s",
|
||||
buf);
|
||||
wdh->url = MAH_path_to_url (wdh->mint,
|
||||
path);
|
||||
GNUNET_free (buf);
|
||||
GNUNET_free (path);
|
||||
|
||||
eh = curl_easy_init ();
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_URL,
|
||||
wdh->url));
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_WRITEFUNCTION,
|
||||
&MAC_download_cb));
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_WRITEDATA,
|
||||
&wdh->db));
|
||||
ctx = MAH_handle_to_context (mint);
|
||||
wdh->job = MAC_job_add (ctx,
|
||||
eh,
|
||||
GNUNET_YES,
|
||||
&handle_wire_deposits_finished,
|
||||
wdh);
|
||||
return wdh;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cancel wire deposits request. This function cannot be used on a request
|
||||
* handle if a response is already served for it.
|
||||
*
|
||||
* @param wdh the wire deposits request handle
|
||||
*/
|
||||
void
|
||||
TALER_MINT_wire_deposits_cancel (struct TALER_MINT_WireDepositsHandle *wdh)
|
||||
{
|
||||
if (NULL != wdh->job)
|
||||
{
|
||||
MAC_job_cancel (wdh->job);
|
||||
wdh->job = NULL;
|
||||
}
|
||||
GNUNET_free_non_null (wdh->db.buf);
|
||||
GNUNET_free (wdh->url);
|
||||
GNUNET_free (wdh);
|
||||
}
|
||||
|
||||
|
||||
/* end of mint_api_wire_deposits.c */
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015, 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
@ -111,7 +111,17 @@ enum OpCode
|
||||
/**
|
||||
* Verify the mint's /wire-method.
|
||||
*/
|
||||
OC_WIRE
|
||||
OC_WIRE,
|
||||
|
||||
/**
|
||||
* Verify mint's /wire/deposits method.
|
||||
*/
|
||||
OC_WIRE_DEPOSITS,
|
||||
|
||||
/**
|
||||
* Verify mint's /deposit/wtid method.
|
||||
*/
|
||||
OC_DEPOSIT_WTID
|
||||
|
||||
};
|
||||
|
||||
@ -470,6 +480,60 @@ struct Command
|
||||
|
||||
} wire;
|
||||
|
||||
/**
|
||||
* Information for the /wire/deposits's command.
|
||||
*/
|
||||
struct {
|
||||
|
||||
/**
|
||||
* Handle to the wire deposits request.
|
||||
*/
|
||||
struct TALER_MINT_WireDepositsHandle *wdh;
|
||||
|
||||
/**
|
||||
* Reference to a /deposit/wtid command. If set, we use the
|
||||
* WTID from that command.
|
||||
*/
|
||||
const char *wtid_ref;
|
||||
|
||||
/**
|
||||
* WTID to use (used if @e wtid_ref is NULL).
|
||||
*/
|
||||
struct TALER_WireTransferIdentifierRawP wtid;
|
||||
|
||||
/* TODO: may want to add list of deposits we expected
|
||||
to see aggregated here in the future. */
|
||||
|
||||
} wire_deposits;
|
||||
|
||||
/**
|
||||
* Information for the /deposit/wtid command.
|
||||
*/
|
||||
struct {
|
||||
|
||||
/**
|
||||
* Handle to the deposit wtid request.
|
||||
*/
|
||||
struct TALER_MINT_DepositWtidHandle *dwh;
|
||||
|
||||
/**
|
||||
* Which /deposit operation should we obtain WTID data for?
|
||||
*/
|
||||
const char *deposit_ref;
|
||||
|
||||
/**
|
||||
* What is the expected total amount? Only used if
|
||||
* @e expected_response_code was #MHD_HTTP_OK.
|
||||
*/
|
||||
struct TALER_Amount total_amount_expected;
|
||||
|
||||
/**
|
||||
* Wire transfer identifier, set if #MHD_HTTP_OK was the response code.
|
||||
*/
|
||||
struct TALER_WireTransferIdentifierRawP wtid;
|
||||
|
||||
} deposit_wtid;
|
||||
|
||||
} details;
|
||||
|
||||
};
|
||||
@ -1219,6 +1283,158 @@ wire_cb (void *cls,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called with detailed wire transfer data, including all
|
||||
* of the coin transactions that were combined into the wire transfer.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param http_status HTTP status code we got, 0 on mint protocol violation
|
||||
* @param json original json reply (may include signatures, those have then been
|
||||
* validated already)
|
||||
* @param wtid extracted wire transfer identifier, or NULL if the mint could
|
||||
* not provide any (set only if @a http_status is #MHD_HTTP_OK)
|
||||
* @param total_amount total amount of the wire transfer, or NULL if the mint could
|
||||
* not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK)
|
||||
* @param details_length length of the @a details array
|
||||
* @param details array with details about the combined transactions
|
||||
*/
|
||||
static void
|
||||
wire_deposits_cb (void *cls,
|
||||
unsigned int http_status,
|
||||
json_t *json,
|
||||
const struct GNUNET_HashCode *h_wire,
|
||||
const struct TALER_Amount *total_amount,
|
||||
unsigned int details_length,
|
||||
const struct TALER_WireDepositDetails *details)
|
||||
{
|
||||
struct InterpreterState *is = cls;
|
||||
struct Command *cmd = &is->commands[is->ip];
|
||||
const struct Command *ref;
|
||||
|
||||
cmd->details.wire_deposits.wdh = NULL;
|
||||
ref = find_command (is,
|
||||
cmd->details.wire_deposits.wtid_ref);
|
||||
if (cmd->expected_response_code != http_status)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Unexpected response code %u to command %s\n",
|
||||
http_status,
|
||||
cmd->label);
|
||||
json_dumpf (json, stderr, 0);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
switch (http_status)
|
||||
{
|
||||
case MHD_HTTP_OK:
|
||||
if (0 != TALER_amount_cmp (total_amount,
|
||||
&ref->details.deposit_wtid.total_amount_expected))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Total amount missmatch to command %s\n",
|
||||
http_status,
|
||||
cmd->label);
|
||||
json_dumpf (json, stderr, 0);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
if (NULL != ref->details.deposit_wtid.deposit_ref)
|
||||
{
|
||||
const struct Command *dep;
|
||||
struct GNUNET_HashCode hw;
|
||||
|
||||
dep = find_command (is,
|
||||
ref->details.deposit_wtid.deposit_ref);
|
||||
GNUNET_CRYPTO_hash (dep->details.deposit.wire_details,
|
||||
strlen (dep->details.deposit.wire_details),
|
||||
&hw);
|
||||
if (0 != memcmp (&hw,
|
||||
h_wire,
|
||||
sizeof (struct GNUNET_HashCode)))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Wire hash missmatch to command %s\n",
|
||||
cmd->label);
|
||||
json_dumpf (json, stderr, 0);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* move to next command */
|
||||
is->ip++;
|
||||
is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
|
||||
is);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called with detailed wire transfer data.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param http_status HTTP status code we got, 0 on mint protocol violation
|
||||
* @param json original json reply (may include signatures, those have then been
|
||||
* validated already)
|
||||
* @param wtid wire transfer identifier used by the mint, NULL if mint did not
|
||||
* yet execute the transaction
|
||||
* @param execution_time actual or planned execution time for the wire transfer
|
||||
* @param coin_contribution contribution to the @a total_amount of the deposited coin (may be NULL)
|
||||
* @param total_amount total amount of the wire transfer, or NULL if the mint could
|
||||
* not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK)
|
||||
*/
|
||||
static void
|
||||
deposit_wtid_cb (void *cls,
|
||||
unsigned int http_status,
|
||||
json_t *json,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
struct GNUNET_TIME_Absolute execution_time,
|
||||
const struct TALER_Amount *coin_contribution,
|
||||
const struct TALER_Amount *total_amount)
|
||||
{
|
||||
struct InterpreterState *is = cls;
|
||||
struct Command *cmd = &is->commands[is->ip];
|
||||
|
||||
cmd->details.deposit_wtid.dwh = NULL;
|
||||
if (cmd->expected_response_code != http_status)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Unexpected response code %u to command %s\n",
|
||||
http_status,
|
||||
cmd->label);
|
||||
json_dumpf (json, stderr, 0);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
switch (http_status)
|
||||
{
|
||||
case MHD_HTTP_OK:
|
||||
cmd->details.deposit_wtid.wtid = *wtid;
|
||||
if (0 != TALER_amount_cmp (total_amount,
|
||||
&cmd->details.deposit_wtid.total_amount_expected))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Total amount missmatch to command %s\n",
|
||||
cmd->label);
|
||||
json_dumpf (json, stderr, 0);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* move to next command */
|
||||
is->ip++;
|
||||
is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
|
||||
is);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run the main interpreter loop that performs mint operations.
|
||||
*
|
||||
@ -1401,7 +1617,9 @@ interpreter_run (void *cls,
|
||||
struct GNUNET_TIME_Absolute refund_deadline;
|
||||
struct GNUNET_TIME_Absolute wire_deadline;
|
||||
struct GNUNET_TIME_Absolute timestamp;
|
||||
struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
|
||||
struct TALER_MerchantPublicKeyP merchant_pub;
|
||||
json_t *contract;
|
||||
json_t *wire;
|
||||
|
||||
GNUNET_assert (NULL !=
|
||||
@ -1444,37 +1662,51 @@ interpreter_run (void *cls,
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
GNUNET_CRYPTO_hash (cmd->details.deposit.contract,
|
||||
strlen (cmd->details.deposit.contract),
|
||||
&h_contract);
|
||||
contract = json_loads (cmd->details.deposit.contract,
|
||||
JSON_REJECT_DUPLICATES,
|
||||
NULL);
|
||||
if (NULL == contract)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to parse contract details `%s' at %u/%s\n",
|
||||
cmd->details.deposit.contract,
|
||||
is->ip,
|
||||
cmd->label);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
TALER_hash_json (contract,
|
||||
&h_contract);
|
||||
wire = json_loads (cmd->details.deposit.wire_details,
|
||||
JSON_REJECT_DUPLICATES,
|
||||
NULL);
|
||||
if (NULL == wire)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to parse wire details `%s' at %u\n",
|
||||
"Failed to parse wire details `%s' at %u/%s\n",
|
||||
cmd->details.deposit.wire_details,
|
||||
is->ip);
|
||||
is->ip,
|
||||
cmd->label);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
|
||||
&coin_pub.eddsa_pub);
|
||||
|
||||
priv = GNUNET_CRYPTO_eddsa_key_create ();
|
||||
cmd->details.deposit.merchant_priv.eddsa_priv = *priv;
|
||||
GNUNET_free (priv);
|
||||
if (0 != cmd->details.deposit.refund_deadline.rel_value_us)
|
||||
{
|
||||
struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
|
||||
|
||||
priv = GNUNET_CRYPTO_eddsa_key_create ();
|
||||
cmd->details.deposit.merchant_priv.eddsa_priv = *priv;
|
||||
GNUNET_free (priv);
|
||||
refund_deadline = GNUNET_TIME_relative_to_absolute (cmd->details.deposit.refund_deadline);
|
||||
}
|
||||
else
|
||||
{
|
||||
refund_deadline = GNUNET_TIME_UNIT_ZERO_ABS;
|
||||
}
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.deposit.merchant_priv.eddsa_priv,
|
||||
&merchant_pub.eddsa_pub);
|
||||
|
||||
wire_deadline = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_DAYS);
|
||||
timestamp = GNUNET_TIME_absolute_get ();
|
||||
TALER_round_abs_time (×tamp);
|
||||
@ -1686,6 +1918,85 @@ interpreter_run (void *cls,
|
||||
is);
|
||||
trigger_context_task ();
|
||||
return;
|
||||
case OC_WIRE_DEPOSITS:
|
||||
if (NULL != cmd->details.wire_deposits.wtid_ref)
|
||||
{
|
||||
ref = find_command (is,
|
||||
cmd->details.wire_deposits.wtid_ref);
|
||||
GNUNET_assert (NULL != ref);
|
||||
cmd->details.wire_deposits.wtid = ref->details.deposit_wtid.wtid;
|
||||
}
|
||||
cmd->details.wire_deposits.wdh
|
||||
= TALER_MINT_wire_deposits (mint,
|
||||
&cmd->details.wire_deposits.wtid,
|
||||
&wire_deposits_cb,
|
||||
is);
|
||||
trigger_context_task ();
|
||||
return;
|
||||
case OC_DEPOSIT_WTID:
|
||||
{
|
||||
struct GNUNET_HashCode h_wire;
|
||||
struct GNUNET_HashCode h_contract;
|
||||
json_t *wire;
|
||||
json_t *contract;
|
||||
const struct Command *coin;
|
||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||
|
||||
ref = find_command (is,
|
||||
cmd->details.deposit_wtid.deposit_ref);
|
||||
GNUNET_assert (NULL != ref);
|
||||
coin = find_command (is,
|
||||
ref->details.deposit.coin_ref);
|
||||
GNUNET_assert (NULL != coin);
|
||||
switch (coin->oc)
|
||||
{
|
||||
case OC_WITHDRAW_SIGN:
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&coin->details.reserve_withdraw.coin_priv.eddsa_priv,
|
||||
&coin_pub.eddsa_pub);
|
||||
break;
|
||||
case OC_REFRESH_REVEAL:
|
||||
{
|
||||
const struct FreshCoin *fc;
|
||||
unsigned int idx;
|
||||
|
||||
idx = ref->details.deposit.coin_idx;
|
||||
GNUNET_assert (idx < coin->details.refresh_reveal.num_fresh_coins);
|
||||
fc = &coin->details.refresh_reveal.fresh_coins[idx];
|
||||
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
|
||||
&coin_pub.eddsa_pub);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
GNUNET_assert (0);
|
||||
}
|
||||
|
||||
wire = json_loads (ref->details.deposit.wire_details,
|
||||
JSON_REJECT_DUPLICATES,
|
||||
NULL);
|
||||
GNUNET_assert (NULL != wire);
|
||||
TALER_hash_json (wire,
|
||||
&h_wire);
|
||||
json_decref (wire);
|
||||
contract = json_loads (ref->details.deposit.contract,
|
||||
JSON_REJECT_DUPLICATES,
|
||||
NULL);
|
||||
GNUNET_assert (NULL != contract);
|
||||
TALER_hash_json (contract,
|
||||
&h_contract);
|
||||
json_decref (contract);
|
||||
cmd->details.deposit_wtid.dwh
|
||||
= TALER_MINT_deposit_wtid (mint,
|
||||
&ref->details.deposit.merchant_priv,
|
||||
&h_wire,
|
||||
&h_contract,
|
||||
&coin_pub,
|
||||
ref->details.deposit.transaction_id,
|
||||
&deposit_wtid_cb,
|
||||
is);
|
||||
trigger_context_task ();
|
||||
}
|
||||
return;
|
||||
default:
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Unknown instruction %d at %u (%s)\n",
|
||||
@ -1695,8 +2006,6 @@ interpreter_run (void *cls,
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
|
||||
is);
|
||||
}
|
||||
|
||||
|
||||
@ -1829,10 +2138,36 @@ do_shutdown (void *cls,
|
||||
case OC_WIRE:
|
||||
if (NULL != cmd->details.wire.wh)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"Command %u (%s) did not complete\n",
|
||||
i,
|
||||
cmd->label);
|
||||
TALER_MINT_wire_cancel (cmd->details.wire.wh);
|
||||
cmd->details.wire.wh = NULL;
|
||||
}
|
||||
break;
|
||||
case OC_WIRE_DEPOSITS:
|
||||
if (NULL != cmd->details.wire_deposits.wdh)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"Command %u (%s) did not complete\n",
|
||||
i,
|
||||
cmd->label);
|
||||
TALER_MINT_wire_deposits_cancel (cmd->details.wire_deposits.wdh);
|
||||
cmd->details.wire_deposits.wdh = NULL;
|
||||
}
|
||||
break;
|
||||
case OC_DEPOSIT_WTID:
|
||||
if (NULL != cmd->details.deposit_wtid.dwh)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"Command %u (%s) did not complete\n",
|
||||
i,
|
||||
cmd->label);
|
||||
TALER_MINT_deposit_wtid_cancel (cmd->details.deposit_wtid.dwh);
|
||||
cmd->details.deposit_wtid.dwh = NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Unknown instruction %d at %u (%s)\n",
|
||||
@ -2047,7 +2382,7 @@ run (void *cls,
|
||||
.details.deposit.amount = "EUR:5",
|
||||
.details.deposit.coin_ref = "withdraw-coin-1",
|
||||
.details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }",
|
||||
.details.deposit.contract = "{ \"items\"={ \"name\":\"ice cream\", \"value\":1 } }",
|
||||
.details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }",
|
||||
.details.deposit.transaction_id = 1 },
|
||||
|
||||
/* Try to overdraw funds ... */
|
||||
@ -2064,7 +2399,7 @@ run (void *cls,
|
||||
.details.deposit.amount = "EUR:5",
|
||||
.details.deposit.coin_ref = "withdraw-coin-1",
|
||||
.details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":43 }",
|
||||
.details.deposit.contract = "{ \"items\"={ \"name\":\"ice cream\", \"value\":1 } }",
|
||||
.details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }",
|
||||
.details.deposit.transaction_id = 1 },
|
||||
/* Try to double-spend the 5 EUR coin at the same merchant (but different
|
||||
transaction ID) */
|
||||
@ -2074,7 +2409,7 @@ run (void *cls,
|
||||
.details.deposit.amount = "EUR:5",
|
||||
.details.deposit.coin_ref = "withdraw-coin-1",
|
||||
.details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }",
|
||||
.details.deposit.contract = "{ \"items\"={ \"name\":\"ice cream\", \"value\":1 } }",
|
||||
.details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }",
|
||||
.details.deposit.transaction_id = 2 },
|
||||
/* Try to double-spend the 5 EUR coin at the same merchant (but different
|
||||
contract) */
|
||||
@ -2084,7 +2419,7 @@ run (void *cls,
|
||||
.details.deposit.amount = "EUR:5",
|
||||
.details.deposit.coin_ref = "withdraw-coin-1",
|
||||
.details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }",
|
||||
.details.deposit.contract = "{ \"items\"={ \"name\":\"ice cream\", \"value\":2 } }",
|
||||
.details.deposit.contract = "{ \"items\":[{ \"name\":\"ice cream\", \"value\":2 } ] }",
|
||||
.details.deposit.transaction_id = 1 },
|
||||
|
||||
/* ***************** /refresh testing ******************** */
|
||||
@ -2109,7 +2444,7 @@ run (void *cls,
|
||||
.details.deposit.amount = "EUR:1",
|
||||
.details.deposit.coin_ref = "refresh-withdraw-coin-1",
|
||||
.details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }",
|
||||
.details.deposit.contract = "{ \"items\"={ \"name\":\"ice cream\", \"value\"EUR:1 } }",
|
||||
.details.deposit.contract = "{ \"items\" : [ { \"name\":\"ice cream\", \"value\":\"EUR:1\" } ] }",
|
||||
.details.deposit.transaction_id = 42421 },
|
||||
|
||||
/* Melt the rest of the coin's value (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */
|
||||
@ -2143,7 +2478,7 @@ run (void *cls,
|
||||
.details.deposit.coin_ref = "refresh-reveal-1",
|
||||
.details.deposit.coin_idx = 0,
|
||||
.details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }",
|
||||
.details.deposit.contract = "{ \"items\"={ \"name\":\"ice cream\", \"value\":3 } }",
|
||||
.details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":3 } ] }",
|
||||
.details.deposit.transaction_id = 2 },
|
||||
|
||||
/* Test successfully spending coins from the refresh operation:
|
||||
@ -2155,7 +2490,7 @@ run (void *cls,
|
||||
.details.deposit.coin_ref = "refresh-reveal-1",
|
||||
.details.deposit.coin_idx = 4,
|
||||
.details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }",
|
||||
.details.deposit.contract = "{ \"items\"={ \"name\":\"ice cream\", \"value\":3 } }",
|
||||
.details.deposit.contract = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":3 } ] }",
|
||||
.details.deposit.transaction_id = 2 },
|
||||
|
||||
/* Test running a failing melt operation (same operation again must fail) */
|
||||
@ -2168,6 +2503,35 @@ run (void *cls,
|
||||
// FIXME: also test with coin that was already melted
|
||||
// (signature differs from coin that was deposited...)
|
||||
/* *************** end of /refresh testing ************** */
|
||||
|
||||
/* ************** Test tracking API ******************** */
|
||||
/* Try resolving a deposit's WTID, as we never triggered
|
||||
execution of transactions, the answer should be that
|
||||
the mint knows about the deposit, but has no WTID yet. */
|
||||
{ .oc = OC_DEPOSIT_WTID,
|
||||
.label = "deposit-wtid-found",
|
||||
.expected_response_code = MHD_HTTP_ACCEPTED,
|
||||
.details.deposit_wtid.deposit_ref = "deposit-simple" },
|
||||
/* Try resolving a deposit's WTID for a failed deposit.
|
||||
As the deposit failed, the answer should be that
|
||||
the mint does NOT know about the deposit. */
|
||||
{ .oc = OC_DEPOSIT_WTID,
|
||||
.label = "deposit-wtid-failing",
|
||||
.expected_response_code = MHD_HTTP_NOT_FOUND,
|
||||
.details.deposit_wtid.deposit_ref = "deposit-double-2" },
|
||||
/* Try resolving an undefined (all zeros) WTID; this
|
||||
should fail as obviously the mint didn't use that
|
||||
WTID value for any transaction. */
|
||||
{ .oc = OC_WIRE_DEPOSITS,
|
||||
.label = "wire-deposit-failing",
|
||||
.expected_response_code = MHD_HTTP_NOT_FOUND },
|
||||
|
||||
/* TODO: trigger aggregation logic and then check the
|
||||
cases where tracking succeeds! */
|
||||
|
||||
/* ************** End of tracking API testing************* */
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
{ .oc = OC_END }
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -7,21 +7,33 @@ if USE_COVERAGE
|
||||
endif
|
||||
|
||||
bin_PROGRAMS = \
|
||||
taler-mint-aggregator \
|
||||
taler-mint-httpd
|
||||
|
||||
taler_mint_aggregator_SOURCES = \
|
||||
taler-mint-aggregator.c
|
||||
taler_mint_aggregator_LDADD = \
|
||||
$(LIBGCRYPT_LIBS) \
|
||||
$(top_builddir)/src/util/libtalerutil.la \
|
||||
$(top_builddir)/src/wire/libtalerwire.la \
|
||||
$(top_builddir)/src/mintdb/libtalermintdb.la \
|
||||
-ljansson \
|
||||
-lgnunetutil
|
||||
|
||||
taler_mint_httpd_SOURCES = \
|
||||
taler-mint-httpd.c taler-mint-httpd.h \
|
||||
taler-mint-httpd_keystate.c taler-mint-httpd_keystate.h \
|
||||
taler-mint-httpd_db.c taler-mint-httpd_db.h \
|
||||
taler-mint-httpd_parsing.c taler-mint-httpd_parsing.h \
|
||||
taler-mint-httpd_responses.c taler-mint-httpd_responses.h \
|
||||
taler-mint-httpd_mhd.c taler-mint-httpd_mhd.h \
|
||||
taler-mint-httpd_admin.c taler-mint-httpd_admin.h \
|
||||
taler-mint-httpd_db.c taler-mint-httpd_db.h \
|
||||
taler-mint-httpd_deposit.c taler-mint-httpd_deposit.h \
|
||||
taler-mint-httpd_keystate.c taler-mint-httpd_keystate.h \
|
||||
taler-mint-httpd_mhd.c taler-mint-httpd_mhd.h \
|
||||
taler-mint-httpd_parsing.c taler-mint-httpd_parsing.h \
|
||||
taler-mint-httpd_refresh.c taler-mint-httpd_refresh.h \
|
||||
taler-mint-httpd_reserve.c taler-mint-httpd_reserve.h \
|
||||
taler-mint-httpd_responses.c taler-mint-httpd_responses.h \
|
||||
taler-mint-httpd_tracking.c taler-mint-httpd_tracking.h \
|
||||
taler-mint-httpd_wire.c taler-mint-httpd_wire.h \
|
||||
taler-mint-httpd_refresh.c taler-mint-httpd_refresh.h
|
||||
taler-mint-httpd_validation.c taler-mint-httpd_validation.h
|
||||
taler_mint_httpd_LDADD = \
|
||||
$(LIBGCRYPT_LIBS) \
|
||||
$(top_builddir)/src/util/libtalerutil.la \
|
||||
|
914
src/mint/taler-mint-aggregator.c
Normal file
914
src/mint/taler-mint-aggregator.c
Normal file
@ -0,0 +1,914 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License along with
|
||||
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file taler-mint-aggregator.c
|
||||
* @brief Process that aggregates outgoing transactions and executes them
|
||||
* @author Christian Grothoff
|
||||
*
|
||||
* TODO:
|
||||
* - simplify global_ret: make it a global!
|
||||
* - handle shutdown more nicely (call 'cancel' method on wire transfers)
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <jansson.h>
|
||||
#include <pthread.h>
|
||||
#include "taler_mintdb_lib.h"
|
||||
#include "taler_mintdb_plugin.h"
|
||||
#include "taler_wire_lib.h"
|
||||
|
||||
/**
|
||||
* Which currency is used by this mint?
|
||||
*/
|
||||
static char *mint_currency_string;
|
||||
|
||||
/**
|
||||
* Which wireformat should be supported by this aggregator?
|
||||
*/
|
||||
static char *mint_wireformat;
|
||||
|
||||
/**
|
||||
* Base directory of the mint (global)
|
||||
*/
|
||||
static char *mint_directory;
|
||||
|
||||
/**
|
||||
* The mint's configuration (global)
|
||||
*/
|
||||
static struct GNUNET_CONFIGURATION_Handle *cfg;
|
||||
|
||||
/**
|
||||
* Our DB plugin.
|
||||
*/
|
||||
static struct TALER_MINTDB_Plugin *db_plugin;
|
||||
|
||||
/**
|
||||
* Our wire plugin.
|
||||
*/
|
||||
static struct TALER_WIRE_Plugin *wire_plugin;
|
||||
|
||||
/**
|
||||
* Task for the main #run() function.
|
||||
*/
|
||||
static struct GNUNET_SCHEDULER_Task *task;
|
||||
|
||||
/**
|
||||
* Limit on the number of transactions we aggregate at once. Note
|
||||
* that the limit must be big enough to ensure that when transactions
|
||||
* of the smallest possible unit are aggregated, they do surpass the
|
||||
* "tiny" threshold beyond which we never trigger a wire transaction!
|
||||
*
|
||||
* TODO: make configurable (via config file or command line option)
|
||||
*/
|
||||
static unsigned int aggregation_limit = 10000;
|
||||
|
||||
|
||||
/**
|
||||
* Load configuration parameters for the mint
|
||||
* server into the corresponding global variables.
|
||||
*
|
||||
* @param mint_directory the mint's directory
|
||||
* @return #GNUNET_OK on success
|
||||
*/
|
||||
static int
|
||||
mint_serve_process_config (const char *mint_directory)
|
||||
{
|
||||
char *type;
|
||||
|
||||
cfg = TALER_config_load (mint_directory);
|
||||
if (NULL == cfg)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failed to load mint configuration\n");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CONFIGURATION_get_value_string (cfg,
|
||||
"mint",
|
||||
"currency",
|
||||
&mint_currency_string))
|
||||
{
|
||||
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
|
||||
"mint",
|
||||
"currency");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (strlen (mint_currency_string) >= TALER_CURRENCY_LEN)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Currency `%s' longer than the allowed limit of %u characters.",
|
||||
mint_currency_string,
|
||||
(unsigned int) TALER_CURRENCY_LEN);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (NULL != mint_wireformat)
|
||||
GNUNET_CONFIGURATION_set_value_string (cfg,
|
||||
"mint",
|
||||
"wireformat",
|
||||
mint_wireformat);
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CONFIGURATION_get_value_string (cfg,
|
||||
"mint",
|
||||
"wireformat",
|
||||
&type))
|
||||
{
|
||||
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
|
||||
"mint",
|
||||
"wireformat");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
if (NULL ==
|
||||
(db_plugin = TALER_MINTDB_plugin_load (cfg)))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failed to initialize DB subsystem\n");
|
||||
GNUNET_free (type);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
if (NULL ==
|
||||
(wire_plugin = TALER_WIRE_plugin_load (cfg,
|
||||
type)))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failed to load wire plugin for `%s'\n",
|
||||
type);
|
||||
GNUNET_free (type);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
GNUNET_free (type);
|
||||
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Information about one aggregation process to
|
||||
* be executed.
|
||||
*/
|
||||
struct AggregationUnit
|
||||
{
|
||||
/**
|
||||
* Public key of the merchant.
|
||||
*/
|
||||
struct TALER_MerchantPublicKeyP merchant_pub;
|
||||
|
||||
/**
|
||||
* Total amount to be transferred.
|
||||
*/
|
||||
struct TALER_Amount total_amount;
|
||||
|
||||
/**
|
||||
* Hash of @e wire.
|
||||
*/
|
||||
struct GNUNET_HashCode h_wire;
|
||||
|
||||
/**
|
||||
* Wire transfer identifier we use.
|
||||
*/
|
||||
struct TALER_WireTransferIdentifierRawP wtid;
|
||||
|
||||
/**
|
||||
* Row ID of the transaction that started it all.
|
||||
*/
|
||||
unsigned long long row_id;
|
||||
|
||||
/**
|
||||
* The current time.
|
||||
*/
|
||||
struct GNUNET_TIME_Absolute execution_time;
|
||||
|
||||
/**
|
||||
* Wire details of the merchant.
|
||||
*/
|
||||
json_t *wire;
|
||||
|
||||
/**
|
||||
* Database session for all of our transactions.
|
||||
*/
|
||||
struct TALER_MINTDB_Session *session;
|
||||
|
||||
/**
|
||||
* Wire preparation handle.
|
||||
*/
|
||||
struct TALER_WIRE_PrepareHandle *ph;
|
||||
|
||||
/**
|
||||
* Array of #aggregation_limit row_ids from the
|
||||
* aggregation.
|
||||
*/
|
||||
unsigned long long *additional_rows;
|
||||
|
||||
/**
|
||||
* Pointer to global return value. Closure for #run().
|
||||
*/
|
||||
int *global_ret;
|
||||
|
||||
/**
|
||||
* Offset specifying how many #additional_rows are in use.
|
||||
*/
|
||||
unsigned int rows_offset;
|
||||
|
||||
/**
|
||||
* Set to #GNUNET_YES if we have to abort due to failure.
|
||||
*/
|
||||
int failed;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Function called with details about deposits that have been made,
|
||||
* with the goal of executing the corresponding wire transaction.
|
||||
*
|
||||
* @param cls closure with the `struct AggregationUnit`
|
||||
* @param row_id identifies database entry
|
||||
* @param merchant_pub public key of the merchant
|
||||
* @param coin_pub public key of the coin
|
||||
* @param amount_with_fee amount that was deposited including fee
|
||||
* @param deposit_fee amount the mint gets to keep as transaction fees
|
||||
* @param transaction_id unique transaction ID chosen by the merchant
|
||||
* @param h_contract hash of the contract between merchant and customer
|
||||
* @param wire_deadline by which the merchant adviced that he would like the
|
||||
* wire transfer to be executed
|
||||
* @param wire wire details for the merchant
|
||||
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
|
||||
*/
|
||||
static int
|
||||
deposit_cb (void *cls,
|
||||
unsigned long long row_id,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_Amount *amount_with_fee,
|
||||
const struct TALER_Amount *deposit_fee,
|
||||
uint64_t transaction_id,
|
||||
const struct GNUNET_HashCode *h_contract,
|
||||
struct GNUNET_TIME_Absolute wire_deadline,
|
||||
const json_t *wire)
|
||||
{
|
||||
struct AggregationUnit *au = cls;
|
||||
|
||||
au->merchant_pub = *merchant_pub;
|
||||
if (GNUNET_OK !=
|
||||
TALER_amount_subtract (&au->total_amount,
|
||||
amount_with_fee,
|
||||
deposit_fee))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Fatally malformed record at %llu\n",
|
||||
row_id);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
au->row_id = row_id;
|
||||
au->wire = (json_t *) wire;
|
||||
au->execution_time = GNUNET_TIME_absolute_get ();
|
||||
TALER_hash_json (au->wire,
|
||||
&au->h_wire);
|
||||
json_incref (au->wire);
|
||||
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
|
||||
&au->wtid,
|
||||
sizeof (au->wtid));
|
||||
if (GNUNET_OK !=
|
||||
db_plugin->insert_aggregation_tracking (db_plugin->cls,
|
||||
au->session,
|
||||
&au->wtid,
|
||||
merchant_pub,
|
||||
&au->h_wire,
|
||||
h_contract,
|
||||
transaction_id,
|
||||
au->execution_time,
|
||||
coin_pub,
|
||||
amount_with_fee,
|
||||
deposit_fee))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
db_plugin->mark_deposit_done (db_plugin->cls,
|
||||
au->session,
|
||||
row_id))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
au->failed = GNUNET_YES;
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Function called with details about another deposit we
|
||||
* can aggregate into an existing aggregation unit.
|
||||
*
|
||||
* @param cls closure with the `struct AggregationUnit`
|
||||
* @param row_id identifies database entry
|
||||
* @param merchant_pub public key of the merchant
|
||||
* @param coin_pub public key of the coin
|
||||
* @param amount_with_fee amount that was deposited including fee
|
||||
* @param deposit_fee amount the mint gets to keep as transaction fees
|
||||
* @param transaction_id unique transaction ID chosen by the merchant
|
||||
* @param h_contract hash of the contract between merchant and customer
|
||||
* @param wire_deadline by which the merchant adviced that he would like the
|
||||
* wire transfer to be executed
|
||||
* @param wire wire details for the merchant
|
||||
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
|
||||
*/
|
||||
static int
|
||||
aggregate_cb (void *cls,
|
||||
unsigned long long row_id,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_Amount *amount_with_fee,
|
||||
const struct TALER_Amount *deposit_fee,
|
||||
uint64_t transaction_id,
|
||||
const struct GNUNET_HashCode *h_contract,
|
||||
struct GNUNET_TIME_Absolute wire_deadline,
|
||||
const json_t *wire)
|
||||
{
|
||||
struct AggregationUnit *au = cls;
|
||||
struct TALER_Amount delta;
|
||||
|
||||
GNUNET_break (0 ==
|
||||
memcmp (&au->merchant_pub,
|
||||
merchant_pub,
|
||||
sizeof (struct TALER_MerchantPublicKeyP)));
|
||||
/* compute contribution of this coin after fees */
|
||||
if (GNUNET_OK !=
|
||||
TALER_amount_subtract (&delta,
|
||||
amount_with_fee,
|
||||
deposit_fee))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Fatally malformed record at %llu\n",
|
||||
row_id);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
/* add to total */
|
||||
if (GNUNET_OK !=
|
||||
TALER_amount_add (&au->total_amount,
|
||||
&au->total_amount,
|
||||
&delta))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Overflow or currency incompatibility during aggregation at %llu\n",
|
||||
row_id);
|
||||
/* Skip this one, but keep going! */
|
||||
return GNUNET_OK;
|
||||
}
|
||||
if (au->rows_offset >= aggregation_limit)
|
||||
{
|
||||
/* Bug: we asked for at most #aggregation_limit results! */
|
||||
GNUNET_break (0);
|
||||
/* Skip this one, but keep going. */
|
||||
return GNUNET_OK;
|
||||
}
|
||||
if (NULL == au->additional_rows)
|
||||
au->additional_rows = GNUNET_new_array (aggregation_limit,
|
||||
unsigned long long);
|
||||
/* "append" to our list of rows */
|
||||
au->additional_rows[au->rows_offset++] = row_id;
|
||||
/* insert into aggregation tracking table */
|
||||
if (GNUNET_OK !=
|
||||
db_plugin->insert_aggregation_tracking (db_plugin->cls,
|
||||
au->session,
|
||||
&au->wtid,
|
||||
merchant_pub,
|
||||
&au->h_wire,
|
||||
h_contract,
|
||||
transaction_id,
|
||||
au->execution_time,
|
||||
coin_pub,
|
||||
amount_with_fee,
|
||||
deposit_fee))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
db_plugin->mark_deposit_done (db_plugin->cls,
|
||||
au->session,
|
||||
row_id))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
au->failed = GNUNET_YES;
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to be called with the prepared transfer data.
|
||||
*
|
||||
* @param cls closure with the `struct AggregationUnit`
|
||||
* @param buf transaction data to persist, NULL on error
|
||||
* @param buf_size number of bytes in @a buf, 0 on error
|
||||
*/
|
||||
static void
|
||||
prepare_cb (void *cls,
|
||||
const char *buf,
|
||||
size_t buf_size);
|
||||
|
||||
|
||||
/**
|
||||
* Main work function that queries the DB and aggregates transactions
|
||||
* into larger wire transfers.
|
||||
*
|
||||
* @param cls pointer to an `int` which we will return from main()
|
||||
* @param tc scheduler context
|
||||
*/
|
||||
static void
|
||||
run_aggregation (void *cls,
|
||||
const struct GNUNET_SCHEDULER_TaskContext *tc)
|
||||
{
|
||||
int *global_ret = cls;
|
||||
struct TALER_MINTDB_Session *session;
|
||||
struct AggregationUnit *au;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
|
||||
return;
|
||||
if (NULL == (session = db_plugin->get_session (db_plugin->cls,
|
||||
GNUNET_NO)))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to obtain database session!\n");
|
||||
*global_ret = GNUNET_SYSERR;
|
||||
return;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
db_plugin->start (db_plugin->cls,
|
||||
session))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to start database transaction!\n");
|
||||
*global_ret = GNUNET_SYSERR;
|
||||
return;
|
||||
}
|
||||
au = GNUNET_new (struct AggregationUnit);
|
||||
au->session = session;
|
||||
ret = db_plugin->get_ready_deposit (db_plugin->cls,
|
||||
session,
|
||||
&deposit_cb,
|
||||
au);
|
||||
if (GNUNET_OK != ret)
|
||||
{
|
||||
GNUNET_free (au);
|
||||
db_plugin->rollback (db_plugin->cls,
|
||||
session);
|
||||
if (0 != ret)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to execute deposit iteration!\n");
|
||||
*global_ret = GNUNET_SYSERR;
|
||||
return;
|
||||
}
|
||||
/* nothing to do, sleep for a minute and try again */
|
||||
task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
|
||||
&run_aggregation,
|
||||
global_ret);
|
||||
return;
|
||||
}
|
||||
/* Now try to find other deposits to aggregate */
|
||||
ret = db_plugin->iterate_matching_deposits (db_plugin->cls,
|
||||
session,
|
||||
&au->h_wire,
|
||||
&au->merchant_pub,
|
||||
&aggregate_cb,
|
||||
au,
|
||||
aggregation_limit);
|
||||
if ( (GNUNET_SYSERR == ret) ||
|
||||
(GNUNET_YES == au->failed) )
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to execute deposit iteration!\n");
|
||||
GNUNET_free_non_null (au->additional_rows);
|
||||
GNUNET_free (au);
|
||||
db_plugin->rollback (db_plugin->cls,
|
||||
session);
|
||||
*global_ret = GNUNET_SYSERR;
|
||||
return;
|
||||
}
|
||||
/* Round to the unit supported by the wire transfer method */
|
||||
GNUNET_assert (GNUNET_SYSERR !=
|
||||
wire_plugin->amount_round (wire_plugin->cls,
|
||||
&au->total_amount));
|
||||
/* Check if after rounding down, we still have an amount to transfer */
|
||||
if ( (0 == au->total_amount.value) &&
|
||||
(0 == au->total_amount.fraction) )
|
||||
{
|
||||
/* Rollback ongoing transaction, as we will not use the respective
|
||||
WTID and thus need to remove the tracking data */
|
||||
db_plugin->rollback (db_plugin->cls,
|
||||
session);
|
||||
/* Start another transaction to mark all* of the selected deposits
|
||||
*as minor! */
|
||||
if (GNUNET_OK !=
|
||||
db_plugin->start (db_plugin->cls,
|
||||
session))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to start database transaction!\n");
|
||||
*global_ret = GNUNET_SYSERR;
|
||||
GNUNET_free_non_null (au->additional_rows);
|
||||
GNUNET_free (au);
|
||||
return;
|
||||
}
|
||||
/* Mark transactions by row_id as minor */
|
||||
ret = GNUNET_OK;
|
||||
if (GNUNET_OK !=
|
||||
db_plugin->mark_deposit_tiny (db_plugin->cls,
|
||||
session,
|
||||
au->row_id))
|
||||
ret = GNUNET_SYSERR;
|
||||
else
|
||||
for (i=0;i<au->rows_offset;i++)
|
||||
if (GNUNET_OK !=
|
||||
db_plugin->mark_deposit_tiny (db_plugin->cls,
|
||||
session,
|
||||
au->additional_rows[i]))
|
||||
ret = GNUNET_SYSERR;
|
||||
/* commit */
|
||||
if (GNUNET_OK !=
|
||||
db_plugin->commit (db_plugin->cls,
|
||||
session))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"Failed to commit database transaction!\n");
|
||||
}
|
||||
GNUNET_free_non_null (au->additional_rows);
|
||||
GNUNET_free (au);
|
||||
/* start again */
|
||||
task = GNUNET_SCHEDULER_add_now (&run_aggregation,
|
||||
global_ret);
|
||||
return;
|
||||
}
|
||||
au->global_ret = global_ret;
|
||||
au->ph = wire_plugin->prepare_wire_transfer (wire_plugin->cls,
|
||||
au->wire,
|
||||
&au->total_amount,
|
||||
&au->wtid,
|
||||
&prepare_cb,
|
||||
au);
|
||||
/* FIXME: currently we have no clean-up plan on
|
||||
shutdown to call prepare_wire_transfer_cancel!
|
||||
Maybe make 'au' global? */
|
||||
if (NULL == au->ph)
|
||||
{
|
||||
GNUNET_break (0); /* why? how to best recover? */
|
||||
db_plugin->rollback (db_plugin->cls,
|
||||
session);
|
||||
GNUNET_free_non_null (au->additional_rows);
|
||||
GNUNET_free (au);
|
||||
/* start again */
|
||||
task = GNUNET_SCHEDULER_add_now (&run_aggregation,
|
||||
global_ret);
|
||||
return;
|
||||
}
|
||||
/* otherwise we continue with #prepare_cb(), see below */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Execute the wire transfers that we have committed to
|
||||
* do.
|
||||
*
|
||||
* @param cls pointer to an `int` which we will return from main()
|
||||
* @param tc scheduler context
|
||||
*/
|
||||
static void
|
||||
run_transfers (void *cls,
|
||||
const struct GNUNET_SCHEDULER_TaskContext *tc);
|
||||
|
||||
|
||||
/**
|
||||
* Function to be called with the prepared transfer data.
|
||||
*
|
||||
* @param cls closure with the `struct AggregationUnit`
|
||||
* @param buf transaction data to persist, NULL on error
|
||||
* @param buf_size number of bytes in @a buf, 0 on error
|
||||
*/
|
||||
static void
|
||||
prepare_cb (void *cls,
|
||||
const char *buf,
|
||||
size_t buf_size)
|
||||
{
|
||||
struct AggregationUnit *au = cls;
|
||||
int *global_ret = au->global_ret;
|
||||
struct TALER_MINTDB_Session *session = au->session;
|
||||
|
||||
GNUNET_free_non_null (au->additional_rows);
|
||||
GNUNET_free (au);
|
||||
if (NULL == buf)
|
||||
{
|
||||
GNUNET_break (0); /* why? how to best recover? */
|
||||
db_plugin->rollback (db_plugin->cls,
|
||||
session);
|
||||
/* start again */
|
||||
task = GNUNET_SCHEDULER_add_now (&run_aggregation,
|
||||
global_ret);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Commit our intention to execute the wire transfer! */
|
||||
if (GNUNET_OK !=
|
||||
db_plugin->wire_prepare_data_insert (db_plugin->cls,
|
||||
session,
|
||||
mint_wireformat,
|
||||
buf,
|
||||
buf_size))
|
||||
{
|
||||
GNUNET_break (0); /* why? how to best recover? */
|
||||
db_plugin->rollback (db_plugin->cls,
|
||||
session);
|
||||
/* start again */
|
||||
task = GNUNET_SCHEDULER_add_now (&run_aggregation,
|
||||
global_ret);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now we can finally commit the overall transaction, as we are
|
||||
again consistent if all of this passes. */
|
||||
if (GNUNET_OK !=
|
||||
db_plugin->commit (db_plugin->cls,
|
||||
session))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Failed to commit database transaction!\n");
|
||||
/* try again */
|
||||
task = GNUNET_SCHEDULER_add_now (&run_aggregation,
|
||||
global_ret);
|
||||
return;
|
||||
}
|
||||
|
||||
/* run alternative task: actually do wire transfer! */
|
||||
task = GNUNET_SCHEDULER_add_now (&run_transfers,
|
||||
&global_ret);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Data we keep to #run_transfers().
|
||||
*/
|
||||
struct WirePrepareData
|
||||
{
|
||||
|
||||
/**
|
||||
* Database session for all of our transactions.
|
||||
*/
|
||||
struct TALER_MINTDB_Session *session;
|
||||
|
||||
/**
|
||||
* Wire execution handle.
|
||||
*/
|
||||
struct TALER_WIRE_ExecuteHandle *eh;
|
||||
|
||||
/**
|
||||
* Pointer to global return value. Closure for #run().
|
||||
*/
|
||||
int *global_ret;
|
||||
|
||||
|
||||
/**
|
||||
* Row ID of the transfer.
|
||||
*/
|
||||
unsigned long long row_id;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Function called with the result from the execute step.
|
||||
*
|
||||
* @param cls closure with the `struct WirePrepareData`
|
||||
* @param success #GNUNET_OK on success, #GNUNET_SYSERR on failure
|
||||
* @param emsg NULL on success, otherwise an error message
|
||||
*/
|
||||
static void
|
||||
wire_confirm_cb (void *cls,
|
||||
int success,
|
||||
const char *emsg)
|
||||
{
|
||||
struct WirePrepareData *wpd = cls;
|
||||
int *global_ret = wpd->global_ret;
|
||||
struct TALER_MINTDB_Session *session = wpd->session;
|
||||
|
||||
wpd->eh = NULL;
|
||||
if (GNUNET_SYSERR == success)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Wire transaction failed: %s\n",
|
||||
emsg);
|
||||
db_plugin->rollback (db_plugin->cls,
|
||||
session);
|
||||
*global_ret = GNUNET_SYSERR;
|
||||
GNUNET_free (wpd);
|
||||
return;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
db_plugin->wire_prepare_data_mark_finished (db_plugin->cls,
|
||||
session,
|
||||
wpd->row_id))
|
||||
{
|
||||
GNUNET_break (0); /* why!? */
|
||||
db_plugin->rollback (db_plugin->cls,
|
||||
session);
|
||||
*global_ret = GNUNET_SYSERR;
|
||||
GNUNET_free (wpd);
|
||||
return;
|
||||
}
|
||||
GNUNET_free (wpd);
|
||||
if (GNUNET_OK !=
|
||||
db_plugin->commit (db_plugin->cls,
|
||||
session))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Failed to commit database transaction!\n");
|
||||
/* try again */
|
||||
task = GNUNET_SCHEDULER_add_now (&run_aggregation,
|
||||
global_ret);
|
||||
return;
|
||||
}
|
||||
/* continue with #run_transfers(), just to guard
|
||||
against the unlikely case that there are more. */
|
||||
task = GNUNET_SCHEDULER_add_now (&run_transfers,
|
||||
&global_ret);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback with data about a prepared transaction.
|
||||
*
|
||||
* @param cls closure with the `struct WirePrepareData`
|
||||
* @param rowid row identifier used to mark prepared transaction as done
|
||||
* @param buf transaction data that was persisted, NULL on error
|
||||
* @param buf_size number of bytes in @a buf, 0 on error
|
||||
*/
|
||||
static void
|
||||
wire_prepare_cb (void *cls,
|
||||
unsigned long long rowid,
|
||||
const char *buf,
|
||||
size_t buf_size)
|
||||
{
|
||||
struct WirePrepareData *wpd = cls;
|
||||
int *global_ret = wpd->global_ret;
|
||||
|
||||
wpd->row_id = rowid;
|
||||
wpd->eh = wire_plugin->execute_wire_transfer (wire_plugin->cls,
|
||||
buf,
|
||||
buf_size,
|
||||
&wire_confirm_cb,
|
||||
wpd);
|
||||
/* FIXME: currently we have no clean-up plan on
|
||||
shutdown to call execute_wire_transfer_cancel!
|
||||
Maybe make 'wpd' global? */
|
||||
if (NULL == wpd->eh)
|
||||
{
|
||||
GNUNET_break (0); /* why? how to best recover? */
|
||||
db_plugin->rollback (db_plugin->cls,
|
||||
wpd->session);
|
||||
*global_ret = GNUNET_SYSERR;
|
||||
GNUNET_free (wpd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Execute the wire transfers that we have committed to
|
||||
* do.
|
||||
*
|
||||
* @param cls pointer to an `int` which we will return from main()
|
||||
* @param tc scheduler context
|
||||
*/
|
||||
static void
|
||||
run_transfers (void *cls,
|
||||
const struct GNUNET_SCHEDULER_TaskContext *tc)
|
||||
{
|
||||
int *global_ret = cls;
|
||||
int ret;
|
||||
struct WirePrepareData *wpd;
|
||||
struct TALER_MINTDB_Session *session;
|
||||
|
||||
if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
|
||||
return;
|
||||
if (NULL == (session = db_plugin->get_session (db_plugin->cls,
|
||||
GNUNET_NO)))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to obtain database session!\n");
|
||||
*global_ret = GNUNET_SYSERR;
|
||||
return;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
db_plugin->start (db_plugin->cls,
|
||||
session))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to start database transaction!\n");
|
||||
*global_ret = GNUNET_SYSERR;
|
||||
return;
|
||||
}
|
||||
wpd = GNUNET_new (struct WirePrepareData);
|
||||
wpd->session = session;
|
||||
wpd->global_ret = global_ret;
|
||||
ret = db_plugin->wire_prepare_data_get (db_plugin->cls,
|
||||
session,
|
||||
mint_wireformat,
|
||||
&wire_prepare_cb,
|
||||
wpd);
|
||||
if (GNUNET_SYSERR == ret)
|
||||
{
|
||||
GNUNET_break (0); /* why? how to best recover? */
|
||||
db_plugin->rollback (db_plugin->cls,
|
||||
session);
|
||||
*global_ret = GNUNET_SYSERR;
|
||||
GNUNET_free (wpd);
|
||||
return;
|
||||
}
|
||||
if (GNUNET_NO == ret)
|
||||
{
|
||||
/* no more prepared wire transfers, go back to aggregation! */
|
||||
db_plugin->rollback (db_plugin->cls,
|
||||
session);
|
||||
task = GNUNET_SCHEDULER_add_now (&run_aggregation,
|
||||
global_ret);
|
||||
GNUNET_free (wpd);
|
||||
return;
|
||||
}
|
||||
/* otherwise, continues in #wire_prepare_cb() */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The main function of the taler-mint-httpd server ("the mint").
|
||||
*
|
||||
* @param argc number of arguments from the command line
|
||||
* @param argv command line arguments
|
||||
* @return 0 ok, 1 on error
|
||||
*/
|
||||
int
|
||||
main (int argc,
|
||||
char *const *argv)
|
||||
{
|
||||
static const struct GNUNET_GETOPT_CommandLineOption options[] = {
|
||||
{'d', "mint-dir", "DIR",
|
||||
"mint directory with configuration and keys for operating the mint", 1,
|
||||
&GNUNET_GETOPT_set_filename, &mint_directory},
|
||||
{'f', "format", "WIREFORMAT",
|
||||
"wireformat to use, overrides WIREFORMAT option in [mint] section", 1,
|
||||
&GNUNET_GETOPT_set_filename, &mint_wireformat},
|
||||
TALER_GETOPT_OPTION_HELP ("background process that aggregates and executes wire transfers to merchants"),
|
||||
GNUNET_GETOPT_OPTION_VERSION (VERSION "-" VCS_VERSION),
|
||||
GNUNET_GETOPT_OPTION_END
|
||||
};
|
||||
int ret = GNUNET_OK;
|
||||
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
GNUNET_log_setup ("taler-mint-aggregator",
|
||||
"INFO",
|
||||
NULL));
|
||||
if (0 >=
|
||||
GNUNET_GETOPT_run ("taler-mint-aggregator",
|
||||
options,
|
||||
argc, argv))
|
||||
return 1;
|
||||
if (NULL == mint_directory)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Mint directory not specified\n");
|
||||
return 1;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
mint_serve_process_config (mint_directory))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
GNUNET_SCHEDULER_run (&run_transfers, &ret);
|
||||
|
||||
TALER_MINTDB_plugin_unload (db_plugin);
|
||||
TALER_WIRE_plugin_unload (wire_plugin);
|
||||
return (GNUNET_SYSERR == ret) ? 1 : 0;
|
||||
}
|
||||
|
||||
/* end of taler-mint-aggregator.c */
|
@ -39,6 +39,7 @@
|
||||
#include "taler-mint-httpd_test.h"
|
||||
#endif
|
||||
#include "taler_mintdb_plugin.h"
|
||||
#include "taler-mint-httpd_validation.h"
|
||||
|
||||
/**
|
||||
* Which currency is used by this mint?
|
||||
@ -66,13 +67,6 @@ struct GNUNET_CONFIGURATION_Handle *cfg;
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey TMH_master_public_key;
|
||||
|
||||
/**
|
||||
* In which format does this MINT expect wiring instructions?
|
||||
* NULL-terminated array of 0-terminated wire format types,
|
||||
* suitable for passing to #TALER_json_validate_wireformat().
|
||||
*/
|
||||
const char **TMH_expected_wire_formats;
|
||||
|
||||
/**
|
||||
* Our DB plugin.
|
||||
*/
|
||||
@ -384,9 +378,6 @@ mint_serve_process_config (const char *mint_directory)
|
||||
{
|
||||
unsigned long long port;
|
||||
char *TMH_master_public_key_str;
|
||||
char *wireformats;
|
||||
const char *token;
|
||||
unsigned int len;
|
||||
|
||||
cfg = TALER_config_load (mint_directory);
|
||||
if (NULL == cfg)
|
||||
@ -414,35 +405,9 @@ mint_serve_process_config (const char *mint_directory)
|
||||
(unsigned int) TALER_CURRENCY_LEN);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
/* Find out list of supported wire formats */
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CONFIGURATION_get_value_string (cfg,
|
||||
"mint",
|
||||
"wireformat",
|
||||
&wireformats))
|
||||
{
|
||||
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
|
||||
"mint",
|
||||
"wireformat");
|
||||
TMH_VALIDATION_init (cfg))
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
/* build NULL-terminated array of TMH_expected_wire_formats */
|
||||
TMH_expected_wire_formats = GNUNET_new_array (1,
|
||||
const char *);
|
||||
len = 1;
|
||||
for (token = strtok (wireformats,
|
||||
" ");
|
||||
NULL != token;
|
||||
token = strtok (NULL,
|
||||
" "))
|
||||
{
|
||||
/* Grow by 1, appending NULL-terminator */
|
||||
GNUNET_array_append (TMH_expected_wire_formats,
|
||||
len,
|
||||
NULL);
|
||||
TMH_expected_wire_formats[len - 2] = GNUNET_strdup (token);
|
||||
}
|
||||
GNUNET_free (wireformats);
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CONFIGURATION_get_value_string (cfg,
|
||||
@ -453,6 +418,7 @@ mint_serve_process_config (const char *mint_directory)
|
||||
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
|
||||
"mint",
|
||||
"master_public_key");
|
||||
TMH_VALIDATION_done ();
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
@ -463,6 +429,7 @@ mint_serve_process_config (const char *mint_directory)
|
||||
fprintf (stderr,
|
||||
"Invalid master public key given in mint configuration.");
|
||||
GNUNET_free (TMH_master_public_key_str);
|
||||
TMH_VALIDATION_done ();
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
GNUNET_free (TMH_master_public_key_str);
|
||||
@ -472,6 +439,7 @@ mint_serve_process_config (const char *mint_directory)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failed to initialize DB subsystem\n");
|
||||
TMH_VALIDATION_done ();
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (GNUNET_YES ==
|
||||
@ -496,6 +464,7 @@ mint_serve_process_config (const char *mint_directory)
|
||||
"mint",
|
||||
"port",
|
||||
"port number required");
|
||||
TMH_VALIDATION_done ();
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
@ -505,6 +474,7 @@ mint_serve_process_config (const char *mint_directory)
|
||||
fprintf (stderr,
|
||||
"Invalid configuration (value out of range): %llu is not a valid port\n",
|
||||
port);
|
||||
TMH_VALIDATION_done ();
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
serve_port = (uint16_t) port;
|
||||
@ -772,6 +742,7 @@ main (int argc,
|
||||
session);
|
||||
}
|
||||
TALER_MINTDB_plugin_unload (TMH_plugin);
|
||||
TMH_VALIDATION_done ();
|
||||
return (GNUNET_SYSERR == ret) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#include <microhttpd.h>
|
||||
|
||||
|
||||
/**
|
||||
* Which currency is used by this mint?
|
||||
*/
|
||||
@ -52,13 +53,6 @@ extern int TMH_test_mode;
|
||||
*/
|
||||
extern char *TMH_mint_directory;
|
||||
|
||||
/**
|
||||
* In which formats does this MINT expect wiring instructions?
|
||||
* NULL-terminated array of 0-terminated wire format types,
|
||||
* suitable for passing to #TALER_json_validate_wireformat().
|
||||
*/
|
||||
extern const char **TMH_expected_wire_formats;
|
||||
|
||||
/**
|
||||
* Master public key (according to the
|
||||
* configuration in the mint directory).
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "taler-mint-httpd_admin.h"
|
||||
#include "taler-mint-httpd_parsing.h"
|
||||
#include "taler-mint-httpd_responses.h"
|
||||
#include "taler-mint-httpd_validation.h"
|
||||
|
||||
|
||||
/**
|
||||
@ -144,8 +145,7 @@ TMH_ADMIN_handler_admin_add_incoming (struct TMH_RequestHandler *rh,
|
||||
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
|
||||
}
|
||||
if (GNUNET_YES !=
|
||||
TALER_json_validate_wireformat (TMH_expected_wire_formats,
|
||||
wire))
|
||||
TMH_json_validate_wireformat (wire))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
TMH_PARSE_release_data (spec);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015, 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
@ -1551,10 +1551,215 @@ TMH_DB_execute_admin_add_incoming (struct MHD_Connection *connection,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Closure for #handle_transaction_data.
|
||||
*/
|
||||
struct WtidTransactionContext
|
||||
{
|
||||
|
||||
/**
|
||||
* Total amount of the wire transfer, as calculated by
|
||||
* summing up the individual amounts. To be rounded down
|
||||
* to calculate the real transfer amount at the end.
|
||||
* Only valid if @e is_valid is #GNUNET_YES.
|
||||
*/
|
||||
struct TALER_Amount total;
|
||||
|
||||
/**
|
||||
* Value we find in the DB for the @e total; only valid if @e is_valid
|
||||
* is #GNUNET_YES.
|
||||
*/
|
||||
struct TALER_Amount db_transaction_value;
|
||||
|
||||
/**
|
||||
* Public key of the merchant, only valid if @e is_valid
|
||||
* is #GNUNET_YES.
|
||||
*/
|
||||
struct TALER_MerchantPublicKeyP merchant_pub;
|
||||
|
||||
/**
|
||||
* Hash of the wire details of the merchant (identical for all
|
||||
* deposits), only valid if @e is_valid is #GNUNET_YES.
|
||||
*/
|
||||
struct GNUNET_HashCode h_wire;
|
||||
|
||||
/**
|
||||
* JSON array with details about the individual deposits.
|
||||
*/
|
||||
json_t *deposits;
|
||||
|
||||
/**
|
||||
* Initially #GNUNET_NO, if we found no deposits so far. Set to
|
||||
* #GNUNET_YES if we got transaction data, and the database replies
|
||||
* remained consistent with respect to @e merchant_pub and @e h_wire
|
||||
* (as they should). Set to #GNUNET_SYSERR if we encountered an
|
||||
* internal error.
|
||||
*/
|
||||
int is_valid;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Function called with the results of the lookup of the
|
||||
* transaction data for the given wire transfer identifier.
|
||||
*
|
||||
* @param cls our context for transmission
|
||||
* @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
|
||||
* @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls)
|
||||
* @param h_contract which contract was this payment about
|
||||
* @param transaction_id merchant's transaction ID for the payment
|
||||
* @param coin_pub which public key was this payment about
|
||||
* @param deposit_value amount contributed by this coin in total
|
||||
* @param deposit_fee deposit fee charged by mint for this coin
|
||||
* @param transaction_value total value of the wire transaction
|
||||
*/
|
||||
static void
|
||||
handle_transaction_data (void *cls,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
const struct GNUNET_HashCode *h_wire,
|
||||
const struct GNUNET_HashCode *h_contract,
|
||||
uint64_t transaction_id,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_Amount *deposit_value,
|
||||
const struct TALER_Amount *deposit_fee,
|
||||
const struct TALER_Amount *transaction_value)
|
||||
{
|
||||
struct WtidTransactionContext *ctx = cls;
|
||||
struct TALER_Amount delta;
|
||||
|
||||
if (GNUNET_SYSERR == ctx->is_valid)
|
||||
return;
|
||||
if (GNUNET_NO == ctx->is_valid)
|
||||
{
|
||||
ctx->merchant_pub = *merchant_pub;
|
||||
ctx->h_wire = *h_wire;
|
||||
ctx->db_transaction_value = *transaction_value;
|
||||
ctx->is_valid = GNUNET_YES;
|
||||
if (GNUNET_OK !=
|
||||
TALER_amount_subtract (&ctx->total,
|
||||
deposit_value,
|
||||
deposit_fee))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
ctx->is_valid = GNUNET_SYSERR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (0 != memcmp (&ctx->merchant_pub,
|
||||
merchant_pub,
|
||||
sizeof (struct TALER_MerchantPublicKeyP))) ||
|
||||
(0 != memcmp (&ctx->h_wire,
|
||||
h_wire,
|
||||
sizeof (struct GNUNET_HashCode))) ||
|
||||
(0 != TALER_amount_cmp (transaction_value,
|
||||
&ctx->db_transaction_value)) )
|
||||
{
|
||||
GNUNET_break (0);
|
||||
ctx->is_valid = GNUNET_SYSERR;
|
||||
return;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
TALER_amount_subtract (&delta,
|
||||
deposit_value,
|
||||
deposit_fee))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
ctx->is_valid = GNUNET_SYSERR;
|
||||
return;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
TALER_amount_add (&ctx->total,
|
||||
&ctx->total,
|
||||
&delta))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
ctx->is_valid = GNUNET_SYSERR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* NOTE: We usually keep JSON stuff out of the _DB file, and this
|
||||
is also ugly if we ever add signatures over this data. (#4135) */
|
||||
json_array_append (ctx->deposits,
|
||||
json_pack ("{s:o, s:o, s:o, s:I, s:o}",
|
||||
"deposit_value", TALER_json_from_amount (deposit_value),
|
||||
"deposit_fee", TALER_json_from_amount (deposit_fee),
|
||||
"H_contract", TALER_json_from_data (h_contract,
|
||||
sizeof (struct GNUNET_HashCode)),
|
||||
"transaction_id", (json_int_t) transaction_id,
|
||||
"coin_pub", TALER_json_from_data (coin_pub,
|
||||
sizeof (struct TALER_CoinSpendPublicKeyP))));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Execute a "/wire/deposits". Returns the transaction information
|
||||
* associated with the given wire transfer identifier.
|
||||
*
|
||||
* @param connection the MHD connection to handle
|
||||
* @param wtid wire transfer identifier to resolve
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TMH_DB_execute_wire_deposits (struct MHD_Connection *connection,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid)
|
||||
{
|
||||
int ret;
|
||||
struct WtidTransactionContext ctx;
|
||||
struct TALER_MINTDB_Session *session;
|
||||
|
||||
if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls,
|
||||
TMH_test_mode)))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return TMH_RESPONSE_reply_internal_db_error (connection);
|
||||
}
|
||||
ctx.is_valid = GNUNET_NO;
|
||||
ctx.deposits = json_array ();
|
||||
ret = TMH_plugin->lookup_wire_transfer (TMH_plugin->cls,
|
||||
session,
|
||||
wtid,
|
||||
&handle_transaction_data,
|
||||
&ctx);
|
||||
if (GNUNET_SYSERR == ret)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
json_decref (ctx.deposits);
|
||||
return TMH_RESPONSE_reply_internal_db_error (connection);
|
||||
}
|
||||
if (GNUNET_SYSERR == ctx.is_valid)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
json_decref (ctx.deposits);
|
||||
return TMH_RESPONSE_reply_internal_db_error (connection);
|
||||
}
|
||||
if (GNUNET_NO == ctx.is_valid)
|
||||
{
|
||||
json_decref (ctx.deposits);
|
||||
return TMH_RESPONSE_reply_arg_unknown (connection,
|
||||
"wtid");
|
||||
}
|
||||
if (0 != TALER_amount_cmp (&ctx.total,
|
||||
&ctx.db_transaction_value))
|
||||
{
|
||||
/* FIXME: this CAN actually differ, due to rounding
|
||||
down. But we should still check that the values
|
||||
do match after rounding 'total' down! */
|
||||
}
|
||||
return TMH_RESPONSE_reply_wire_deposit_details (connection,
|
||||
&ctx.db_transaction_value,
|
||||
&ctx.merchant_pub,
|
||||
&ctx.h_wire,
|
||||
ctx.deposits);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Closure for #handle_wtid_data.
|
||||
*/
|
||||
struct DepositWtidContext
|
||||
struct DepositWtidContext
|
||||
{
|
||||
|
||||
/**
|
||||
@ -1562,6 +1767,26 @@ struct DepositWtidContext
|
||||
*/
|
||||
struct MHD_Connection *connection;
|
||||
|
||||
/**
|
||||
* Hash of the contract we are looking up.
|
||||
*/
|
||||
struct GNUNET_HashCode h_contract;
|
||||
|
||||
/**
|
||||
* Hash of the wire transfer details we are looking up.
|
||||
*/
|
||||
struct GNUNET_HashCode h_wire;
|
||||
|
||||
/**
|
||||
* Public key we are looking up.
|
||||
*/
|
||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||
|
||||
/**
|
||||
* Transaction ID we are looking up.
|
||||
*/
|
||||
uint64_t transaction_id;
|
||||
|
||||
/**
|
||||
* MHD result code to return.
|
||||
*/
|
||||
@ -1572,10 +1797,13 @@ struct DepositWtidContext
|
||||
/**
|
||||
* Function called with the results of the lookup of the
|
||||
* wire transfer identifier information.
|
||||
*
|
||||
*
|
||||
* @param cls our context for transmission
|
||||
* @param wtid base32-encoded wire transfer identifier, NULL
|
||||
* @param wtid raw wire transfer identifier, NULL
|
||||
* if the transaction was not yet done
|
||||
* @param coin_contribution how much did the coin we asked about
|
||||
* contribute to the total transfer value? (deposit value including fee)
|
||||
* @param coin_fee how much did the mint charge for the deposit fee
|
||||
* @param execution_time when was the transaction done, or
|
||||
* when we expect it to be done (if @a wtid was NULL);
|
||||
* #GNUNET_TIME_UNIT_FOREVER_ABS if the /deposit is unknown
|
||||
@ -1583,23 +1811,41 @@ struct DepositWtidContext
|
||||
*/
|
||||
static void
|
||||
handle_wtid_data (void *cls,
|
||||
const char *wtid,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
const struct TALER_Amount *coin_contribution,
|
||||
const struct TALER_Amount *coin_fee,
|
||||
struct GNUNET_TIME_Absolute execution_time)
|
||||
{
|
||||
struct DepositWtidContext *ctx = cls;
|
||||
struct TALER_Amount coin_delta;
|
||||
|
||||
if (NULL == wtid)
|
||||
{
|
||||
if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us ==
|
||||
execution_time.abs_value_us)
|
||||
ctx->res = TMH_RESPONSE_reply_deposit_unknown (ctx->connection);
|
||||
else
|
||||
ctx->res = TMH_RESPONSE_reply_deposit_pending (ctx->connection);
|
||||
ctx->res = TMH_RESPONSE_reply_deposit_pending (ctx->connection,
|
||||
execution_time);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->res = TMH_RESPONSE_reply_deposit_wtid (ctx->connection);
|
||||
}
|
||||
if (GNUNET_SYSERR ==
|
||||
TALER_amount_subtract (&coin_delta,
|
||||
coin_contribution,
|
||||
coin_fee))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
ctx->res = TMH_RESPONSE_reply_internal_db_error (ctx->connection);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->res = TMH_RESPONSE_reply_deposit_wtid (ctx->connection,
|
||||
&ctx->h_contract,
|
||||
&ctx->h_wire,
|
||||
&ctx->coin_pub,
|
||||
&coin_delta,
|
||||
ctx->transaction_id,
|
||||
wtid,
|
||||
execution_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1625,21 +1871,46 @@ TMH_DB_execute_deposit_wtid (struct MHD_Connection *connection,
|
||||
{
|
||||
int ret;
|
||||
struct DepositWtidContext ctx;
|
||||
struct TALER_MINTDB_Session *session;
|
||||
|
||||
if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls,
|
||||
TMH_test_mode)))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return TMH_RESPONSE_reply_internal_db_error (connection);
|
||||
}
|
||||
ctx.connection = connection;
|
||||
ctx.h_contract = *h_contract;
|
||||
ctx.h_wire = *h_wire;
|
||||
ctx.coin_pub = *coin_pub;
|
||||
ctx.transaction_id = transaction_id;
|
||||
ctx.res = GNUNET_SYSERR;
|
||||
ret = TMH_plugin->wire_lookup_deposit_wtid (TMH_plugin->cls,
|
||||
session,
|
||||
h_contract,
|
||||
h_wire,
|
||||
coin_pub,
|
||||
merchant_pub,
|
||||
transaction_id,
|
||||
&handle_wtid_data,
|
||||
connection);
|
||||
&ctx);
|
||||
if (GNUNET_SYSERR == ret)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_break (GNUNET_SYSERR == ctx.res);
|
||||
return TMH_RESPONSE_reply_internal_db_error (connection);
|
||||
}
|
||||
if (GNUNET_NO == ret)
|
||||
{
|
||||
GNUNET_break (GNUNET_SYSERR == ctx.res);
|
||||
return TMH_RESPONSE_reply_deposit_unknown (connection);
|
||||
}
|
||||
if (GNUNET_SYSERR == ctx.res)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return TMH_RESPONSE_reply_internal_error (connection,
|
||||
"bug resolving deposit wtid");
|
||||
}
|
||||
return ctx.res;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
@ -192,6 +192,19 @@ TMH_DB_execute_admin_add_incoming (struct MHD_Connection *connection,
|
||||
json_t *wire);
|
||||
|
||||
|
||||
/**
|
||||
* Execute a "/wire/deposits". Returns the transaction information
|
||||
* associated with the given wire transfer identifier.
|
||||
*
|
||||
* @param connection the MHD connection to handle
|
||||
* @param wtid wire transfer identifier to resolve
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TMH_DB_execute_wire_deposits (struct MHD_Connection *connection,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid);
|
||||
|
||||
|
||||
/**
|
||||
* Execute a "/deposit/wtid". Returns the transfer information
|
||||
* associated with the given deposit.
|
||||
@ -212,5 +225,6 @@ TMH_DB_execute_deposit_wtid (struct MHD_Connection *connection,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
uint64_t transaction_id);
|
||||
|
||||
|
||||
#endif
|
||||
/* TALER_MINT_HTTPD_DB_H */
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "taler-mint-httpd_deposit.h"
|
||||
#include "taler-mint-httpd_responses.h"
|
||||
#include "taler-mint-httpd_keystate.h"
|
||||
#include "taler-mint-httpd_validation.h"
|
||||
|
||||
|
||||
/**
|
||||
@ -162,8 +163,7 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection,
|
||||
return MHD_YES; /* failure */
|
||||
|
||||
if (GNUNET_YES !=
|
||||
TALER_json_validate_wireformat (TMH_expected_wire_formats,
|
||||
wire))
|
||||
TMH_json_validate_wireformat (wire))
|
||||
{
|
||||
TMH_PARSE_release_data (spec);
|
||||
return TMH_RESPONSE_reply_arg_unknown (connection,
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
Copyright (C) 2014, 2015, 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU Affero General Public License as published by the Free Software
|
||||
@ -1056,15 +1056,15 @@ TMH_RESPONSE_reply_refresh_link_success (struct MHD_Connection *connection,
|
||||
* 404 reply.
|
||||
*
|
||||
* @param connection connection to the client
|
||||
* @param
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection,
|
||||
...)
|
||||
TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection)
|
||||
{
|
||||
GNUNET_break (0); // FIXME: not implemented
|
||||
return MHD_NO;
|
||||
return TMH_RESPONSE_reply_json_pack (connection,
|
||||
MHD_HTTP_NOT_FOUND,
|
||||
"{s:s}",
|
||||
"error", "Deposit unknown");
|
||||
}
|
||||
|
||||
|
||||
@ -1073,15 +1073,17 @@ TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection,
|
||||
* we did not execute the deposit yet. Generate a 202 reply.
|
||||
*
|
||||
* @param connection connection to the client
|
||||
* @param
|
||||
* @param planned_exec_time planned execution time
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection,
|
||||
...)
|
||||
struct GNUNET_TIME_Absolute planned_exec_time)
|
||||
{
|
||||
GNUNET_break (0); // FIXME: not implemented
|
||||
return MHD_NO;
|
||||
return TMH_RESPONSE_reply_json_pack (connection,
|
||||
MHD_HTTP_ACCEPTED,
|
||||
"{s:o}",
|
||||
"execution_time", TALER_json_from_abs (planned_exec_time));
|
||||
}
|
||||
|
||||
|
||||
@ -1090,15 +1092,86 @@ TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection,
|
||||
* them. Generates the 200 reply.
|
||||
*
|
||||
* @param connection connection to the client
|
||||
* @param
|
||||
* @param h_contract hash of the contract
|
||||
* @param h_wire hash of wire account details
|
||||
* @param coin_pub public key of the coin
|
||||
* @param coin_contribution how much did the coin we asked about
|
||||
* contribute to the total transfer value? (deposit value minus fee)
|
||||
* @param transaction_id merchant transaction identifier
|
||||
* @param wtid raw wire transfer identifier
|
||||
* @param exec_time execution time of the wire transfer
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TMH_RESPONSE_reply_deposit_wtid (struct MHD_Connection *connection,
|
||||
...)
|
||||
const struct GNUNET_HashCode *h_contract,
|
||||
const struct GNUNET_HashCode *h_wire,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_Amount *coin_contribution,
|
||||
uint64_t transaction_id,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
struct GNUNET_TIME_Absolute exec_time)
|
||||
{
|
||||
GNUNET_break (0); // FIXME: not implemented
|
||||
return MHD_NO;
|
||||
struct TALER_ConfirmWirePS cw;
|
||||
struct TALER_MintPublicKeyP pub;
|
||||
struct TALER_MintSignatureP sig;
|
||||
|
||||
cw.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_WIRE);
|
||||
cw.purpose.size = htonl (sizeof (struct TALER_ConfirmWirePS));
|
||||
cw.h_wire = *h_wire;
|
||||
cw.h_contract = *h_contract;
|
||||
cw.wtid = *wtid;
|
||||
cw.coin_pub = *coin_pub;
|
||||
cw.transaction_id = GNUNET_htonll (transaction_id);
|
||||
cw.execution_time = GNUNET_TIME_absolute_hton (exec_time);
|
||||
TALER_amount_hton (&cw.coin_contribution,
|
||||
coin_contribution);
|
||||
TMH_KS_sign (&cw.purpose,
|
||||
&pub,
|
||||
&sig);
|
||||
return TMH_RESPONSE_reply_json_pack (connection,
|
||||
MHD_HTTP_OK,
|
||||
"{s:o, s:o, s:o, s:o, s:o, s:o}",
|
||||
"wtid", TALER_json_from_data (wtid,
|
||||
sizeof (*wtid)),
|
||||
"execution_time", TALER_json_from_abs (exec_time),
|
||||
"coin_contribution", TALER_json_from_amount (coin_contribution),
|
||||
"mint_sig", TALER_json_from_data (&sig,
|
||||
sizeof (sig)),
|
||||
"mint_pub", TALER_json_from_data (&pub,
|
||||
sizeof (pub)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A merchant asked for transaction details about a wire transfer.
|
||||
* Provide them. Generates the 200 reply.
|
||||
*
|
||||
* @param connection connection to the client
|
||||
* @param total total amount that was transferred
|
||||
* @param merchant_pub public key of the merchant
|
||||
* @param h_wire destination account
|
||||
* @param deposits details about the combined deposits
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TMH_RESPONSE_reply_wire_deposit_details (struct MHD_Connection *connection,
|
||||
const struct TALER_Amount *total,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
const struct GNUNET_HashCode *h_wire,
|
||||
json_t *deposits)
|
||||
{
|
||||
/* FIXME: #4135: signing not implemented here */
|
||||
return TMH_RESPONSE_reply_json_pack (connection,
|
||||
MHD_HTTP_OK,
|
||||
"{s:o, s:o, s:o, s:o}",
|
||||
"total", TALER_json_from_amount (total),
|
||||
"merchant_pub", TALER_json_from_data (merchant_pub,
|
||||
sizeof (struct TALER_MerchantPublicKeyP)),
|
||||
"h_wire", TALER_json_from_data (h_wire,
|
||||
sizeof (struct GNUNET_HashCode)),
|
||||
"deposits", deposits);
|
||||
}
|
||||
|
||||
|
||||
/* end of taler-mint-httpd_responses.c */
|
||||
|
@ -253,12 +253,10 @@ TMH_RESPONSE_reply_deposit_insufficient_funds (struct MHD_Connection *connection
|
||||
* 404 reply.
|
||||
*
|
||||
* @param connection connection to the client
|
||||
* @param
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection,
|
||||
...);
|
||||
TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection);
|
||||
|
||||
|
||||
/**
|
||||
@ -266,12 +264,12 @@ TMH_RESPONSE_reply_deposit_unknown (struct MHD_Connection *connection,
|
||||
* we did not execute the deposit yet. Generate a 202 reply.
|
||||
*
|
||||
* @param connection connection to the client
|
||||
* @param
|
||||
* @param planned_exec_time planned execution time
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection,
|
||||
...);
|
||||
struct GNUNET_TIME_Absolute planned_exec_time);
|
||||
|
||||
|
||||
/**
|
||||
@ -279,12 +277,43 @@ TMH_RESPONSE_reply_deposit_pending (struct MHD_Connection *connection,
|
||||
* them. Generates the 200 reply.
|
||||
*
|
||||
* @param connection connection to the client
|
||||
* @param
|
||||
* @param h_contract hash of the contract
|
||||
* @param h_wire hash of wire account details
|
||||
* @param coin_pub public key of the coin
|
||||
* @param coin_contribution contribution of this coin to the total amount transferred
|
||||
* @param transaction_id merchant transaction identifier
|
||||
* @param wtid raw wire transfer identifier
|
||||
* @param exec_time execution time of the wire transfer
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TMH_RESPONSE_reply_deposit_wtid (struct MHD_Connection *connection,
|
||||
...);
|
||||
const struct GNUNET_HashCode *h_contract,
|
||||
const struct GNUNET_HashCode *h_wire,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_Amount *coin_contribution,
|
||||
uint64_t transaction_id,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
struct GNUNET_TIME_Absolute exec_time);
|
||||
|
||||
|
||||
/**
|
||||
* A merchant asked for transaction details about a wire transfer.
|
||||
* Provide them. Generates the 200 reply.
|
||||
*
|
||||
* @param connection connection to the client
|
||||
* @param total total amount that was transferred
|
||||
* @param merchant_pub public key of the merchant
|
||||
* @param h_wire destination account
|
||||
* @param deposits details about the combined deposits
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TMH_RESPONSE_reply_wire_deposit_details (struct MHD_Connection *connection,
|
||||
const struct TALER_Amount *total,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
const struct GNUNET_HashCode *h_wire,
|
||||
json_t *deposits);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
Copyright (C) 2014, 2015, 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU Affero General Public License as published by the Free Software
|
||||
@ -46,8 +46,19 @@ TMH_TRACKING_handler_wire_deposits (struct TMH_RequestHandler *rh,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size)
|
||||
{
|
||||
GNUNET_break (0); // not implemented
|
||||
return MHD_NO;
|
||||
struct TALER_WireTransferIdentifierRawP wtid;
|
||||
int res;
|
||||
|
||||
res = TMH_PARSE_mhd_request_arg_data (connection,
|
||||
"wtid",
|
||||
&wtid,
|
||||
sizeof (struct TALER_WireTransferIdentifierRawP));
|
||||
if (GNUNET_SYSERR == res)
|
||||
return MHD_NO; /* internal error */
|
||||
if (GNUNET_NO == res)
|
||||
return MHD_YES; /* parse error */
|
||||
return TMH_DB_execute_wire_deposits (connection,
|
||||
&wtid);
|
||||
}
|
||||
|
||||
|
||||
@ -57,7 +68,7 @@ TMH_TRACKING_handler_wire_deposits (struct TMH_RequestHandler *rh,
|
||||
*
|
||||
* @param connection the MHD connection to handle
|
||||
* @param tps signed request to execute
|
||||
* @param merchant_pub public key from the merchant
|
||||
* @param merchant_pub public key from the merchant
|
||||
* @param merchant_sig signature from the merchant (to be checked)
|
||||
* @param transaction_id transaction ID (in host byte order)
|
||||
* @return MHD result code
|
||||
@ -110,13 +121,12 @@ TMH_TRACKING_handler_deposit_wtid (struct TMH_RequestHandler *rh,
|
||||
struct TALER_DepositTrackPS tps;
|
||||
uint64_t transaction_id;
|
||||
struct TALER_MerchantSignatureP merchant_sig;
|
||||
struct TALER_MerchantPublicKeyP merchant_pub;
|
||||
struct TMH_PARSE_FieldSpecification spec[] = {
|
||||
TMH_PARSE_member_fixed ("H_wire", &tps.h_wire),
|
||||
TMH_PARSE_member_fixed ("H_contract", &tps.h_contract),
|
||||
TMH_PARSE_member_fixed ("coin_pub", &tps.coin_pub),
|
||||
TMH_PARSE_member_uint64 ("transaction_id", &transaction_id),
|
||||
TMH_PARSE_member_fixed ("merchant_pub", &merchant_pub),
|
||||
TMH_PARSE_member_fixed ("merchant_pub", &tps.merchant),
|
||||
TMH_PARSE_member_fixed ("merchant_sig", &merchant_sig),
|
||||
TMH_PARSE_MEMBER_END
|
||||
};
|
||||
@ -143,7 +153,7 @@ TMH_TRACKING_handler_deposit_wtid (struct TMH_RequestHandler *rh,
|
||||
tps.transaction_id = GNUNET_htonll (transaction_id);
|
||||
res = check_and_handle_deposit_wtid_request (connection,
|
||||
&tps,
|
||||
&merchant_pub,
|
||||
&tps.merchant,
|
||||
&merchant_sig,
|
||||
transaction_id);
|
||||
TMH_PARSE_release_data (spec);
|
||||
|
231
src/mint/taler-mint-httpd_validation.c
Normal file
231
src/mint/taler-mint-httpd_validation.c
Normal file
@ -0,0 +1,231 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License along with
|
||||
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file taler-mint-httpd_validation.c
|
||||
* @brief helpers for calling the wire plugins to validate addresses
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include "taler-mint-httpd_validation.h"
|
||||
#include "taler_wire_plugin.h"
|
||||
|
||||
|
||||
/**
|
||||
* Information we keep for each plugin.
|
||||
*/
|
||||
struct Plugin
|
||||
{
|
||||
|
||||
/**
|
||||
* We keep plugins in a DLL.
|
||||
*/
|
||||
struct Plugin *next;
|
||||
|
||||
/**
|
||||
* We keep plugins in a DLL.
|
||||
*/
|
||||
struct Plugin *prev;
|
||||
|
||||
/**
|
||||
* Type of the wireformat.
|
||||
*/
|
||||
char *type;
|
||||
|
||||
/**
|
||||
* Pointer to the plugin.
|
||||
*/
|
||||
struct TALER_WIRE_Plugin *plugin;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Head of DLL of wire plugins.
|
||||
*/
|
||||
static struct Plugin *wire_head;
|
||||
|
||||
/**
|
||||
* Tail of DLL of wire plugins.
|
||||
*/
|
||||
static struct Plugin *wire_tail;
|
||||
|
||||
|
||||
/**
|
||||
* Initialize validation subsystem.
|
||||
*
|
||||
* @param cfg configuration to use
|
||||
* @return #GNUNET_OK on success
|
||||
*/
|
||||
int
|
||||
TMH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
|
||||
{
|
||||
struct Plugin *p;
|
||||
char *wireformats;
|
||||
char *lib_name;
|
||||
const char *token;
|
||||
|
||||
/* Find out list of supported wire formats */
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CONFIGURATION_get_value_string (cfg,
|
||||
"mint",
|
||||
"wireformat",
|
||||
&wireformats))
|
||||
{
|
||||
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
|
||||
"mint",
|
||||
"wireformat");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
for (token = strtok (wireformats,
|
||||
" ");
|
||||
NULL != token;
|
||||
token = strtok (NULL,
|
||||
" "))
|
||||
{
|
||||
(void) GNUNET_asprintf (&lib_name,
|
||||
"libtaler_plugin_wire_%s",
|
||||
lib_name);
|
||||
p = GNUNET_new (struct Plugin);
|
||||
p->type = GNUNET_strdup (token);
|
||||
p->plugin = GNUNET_PLUGIN_load (lib_name,
|
||||
(void *) cfg);
|
||||
if (NULL == p->plugin)
|
||||
{
|
||||
GNUNET_free (p);
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to load plugin %s\n",
|
||||
lib_name);
|
||||
GNUNET_free (lib_name);
|
||||
TMH_VALIDATION_done ();
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
p->plugin->library_name = lib_name;
|
||||
GNUNET_CONTAINER_DLL_insert (wire_head,
|
||||
wire_tail,
|
||||
p);
|
||||
}
|
||||
GNUNET_free (wireformats);
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shutdown validation subsystem.
|
||||
*/
|
||||
void
|
||||
TMH_VALIDATION_done ()
|
||||
{
|
||||
struct Plugin *p;
|
||||
char *lib_name;
|
||||
|
||||
while (NULL != (p = wire_head))
|
||||
{
|
||||
GNUNET_CONTAINER_DLL_remove (wire_head,
|
||||
wire_tail,
|
||||
p);
|
||||
lib_name = p->plugin->library_name;
|
||||
GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name,
|
||||
p->plugin));
|
||||
GNUNET_free (lib_name);
|
||||
GNUNET_free (p->type);
|
||||
GNUNET_free (p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if the given wire format JSON object is correctly formatted as
|
||||
* a wire address.
|
||||
*
|
||||
* @param wire the JSON wire format object
|
||||
* @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
|
||||
*/
|
||||
int
|
||||
TMH_json_validate_wireformat (const json_t *wire)
|
||||
{
|
||||
const char *stype;
|
||||
json_error_t error;
|
||||
struct Plugin *p;
|
||||
|
||||
if (0 != json_unpack_ex ((json_t *) wire,
|
||||
&error, 0,
|
||||
"{s:s}",
|
||||
"type", &stype))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
for (p=wire_head; NULL != p; p = p->next)
|
||||
if (0 == strcasecmp (p->type,
|
||||
stype))
|
||||
return p->plugin->wire_validate (wire);
|
||||
return GNUNET_NO;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if we support the given wire method.
|
||||
*
|
||||
* @param type type of wire method to check
|
||||
* @return #GNUNET_YES if the method is supported
|
||||
*/
|
||||
int
|
||||
TMH_VALIDATION_test_method (const char *type)
|
||||
{
|
||||
struct Plugin *p;
|
||||
|
||||
for (p=wire_head;NULL != p;p = p->next)
|
||||
if (0 == strcasecmp (type,
|
||||
p->type))
|
||||
return GNUNET_YES;
|
||||
return GNUNET_NO;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain supported validation methods as a JSON array,
|
||||
* and as a hash.
|
||||
*
|
||||
* @param[out] h set to the hash of the JSON methods
|
||||
* @return JSON array with the supported validation methods
|
||||
*/
|
||||
json_t *
|
||||
TMH_VALIDATION_get_methods (struct GNUNET_HashCode *h)
|
||||
{
|
||||
json_t *methods;
|
||||
struct GNUNET_HashContext *hc;
|
||||
const char *wf;
|
||||
struct Plugin *p;
|
||||
|
||||
methods = json_array ();
|
||||
hc = GNUNET_CRYPTO_hash_context_start ();
|
||||
for (p=wire_head;NULL != p;p = p->next)
|
||||
{
|
||||
wf = p->type;
|
||||
json_array_append_new (methods,
|
||||
json_string (wf));
|
||||
GNUNET_CRYPTO_hash_context_read (hc,
|
||||
wf,
|
||||
strlen (wf) + 1);
|
||||
}
|
||||
GNUNET_CRYPTO_hash_context_finish (hc,
|
||||
h);
|
||||
return methods;
|
||||
}
|
||||
|
||||
|
||||
/* end of taler-mint-httpd_validation.c */
|
76
src/mint/taler-mint-httpd_validation.h
Normal file
76
src/mint/taler-mint-httpd_validation.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License along with
|
||||
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file taler-mint-httpd_validation.h
|
||||
* @brief helpers for calling the wire plugins to validate addresses
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef TALER_MINT_HTTPD_VALIDATION_H
|
||||
#define TALER_MINT_HTTPD_VALIDATION_H
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <jansson.h>
|
||||
|
||||
|
||||
/**
|
||||
* Initialize validation subsystem.
|
||||
*
|
||||
* @param cfg configuration to use
|
||||
* @return #GNUNET_OK on success
|
||||
*/
|
||||
int
|
||||
TMH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg);
|
||||
|
||||
|
||||
/**
|
||||
* Shutdown validation subsystem.
|
||||
*/
|
||||
void
|
||||
TMH_VALIDATION_done (void);
|
||||
|
||||
|
||||
/**
|
||||
* Check if the given wire format JSON object is correctly formatted as
|
||||
* a wire address.
|
||||
*
|
||||
* @param wire the JSON wire format object
|
||||
* @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
|
||||
*/
|
||||
int
|
||||
TMH_json_validate_wireformat (const json_t *wire);
|
||||
|
||||
/**
|
||||
* Check if we support the given wire method.
|
||||
*
|
||||
* @param type type of wire method to check
|
||||
* @return #GNUNET_YES if the method is supported
|
||||
*/
|
||||
int
|
||||
TMH_VALIDATION_test_method (const char *type);
|
||||
|
||||
|
||||
/**
|
||||
* Obtain supported validation methods as a JSON array,
|
||||
* and as a hash.
|
||||
*
|
||||
* @param[out] h set to the hash of the JSON methods
|
||||
* @return JSON array with the supported validation methods
|
||||
*/
|
||||
json_t *
|
||||
TMH_VALIDATION_get_methods (struct GNUNET_HashCode *h);
|
||||
|
||||
|
||||
#endif
|
@ -21,6 +21,7 @@
|
||||
#include "platform.h"
|
||||
#include "taler-mint-httpd_keystate.h"
|
||||
#include "taler-mint-httpd_responses.h"
|
||||
#include "taler-mint-httpd_validation.h"
|
||||
#include "taler-mint-httpd_wire.h"
|
||||
#include <jansson.h>
|
||||
|
||||
@ -45,24 +46,10 @@ TMH_WIRE_handler_wire (struct TMH_RequestHandler *rh,
|
||||
struct TALER_MintPublicKeyP pub;
|
||||
struct TALER_MintSignatureP sig;
|
||||
json_t *methods;
|
||||
struct GNUNET_HashContext *hc;
|
||||
unsigned int i;
|
||||
const char *wf;
|
||||
|
||||
methods = json_array ();
|
||||
hc = GNUNET_CRYPTO_hash_context_start ();
|
||||
for (i=0;NULL != (wf = TMH_expected_wire_formats[i]); i++)
|
||||
{
|
||||
json_array_append_new (methods,
|
||||
json_string (wf));
|
||||
GNUNET_CRYPTO_hash_context_read (hc,
|
||||
wf,
|
||||
strlen (wf) + 1);
|
||||
}
|
||||
wsm.purpose.size = htonl (sizeof (wsm));
|
||||
wsm.purpose.purpose = htonl (TALER_SIGNATURE_MINT_WIRE_TYPES);
|
||||
GNUNET_CRYPTO_hash_context_finish (hc,
|
||||
&wsm.h_wire_types);
|
||||
methods = TMH_VALIDATION_get_methods (&wsm.h_wire_types);
|
||||
TMH_KS_sign (&wsm.purpose,
|
||||
&pub,
|
||||
&sig);
|
||||
@ -97,7 +84,6 @@ TMH_WIRE_handler_wire_test (struct TMH_RequestHandler *rh,
|
||||
struct MHD_Response *response;
|
||||
int ret;
|
||||
char *wire_test_redirect;
|
||||
unsigned int i;
|
||||
|
||||
response = MHD_create_response_from_buffer (0, NULL,
|
||||
MHD_RESPMEM_PERSISTENT);
|
||||
@ -107,11 +93,7 @@ TMH_WIRE_handler_wire_test (struct TMH_RequestHandler *rh,
|
||||
return MHD_NO;
|
||||
}
|
||||
TMH_RESPONSE_add_global_headers (response);
|
||||
for (i=0;NULL != TMH_expected_wire_formats[i];i++)
|
||||
if (0 == strcasecmp ("test",
|
||||
TMH_expected_wire_formats[i]))
|
||||
break;
|
||||
if (NULL == TMH_expected_wire_formats[i])
|
||||
if (GNUNET_NO == TMH_VALIDATION_test_method ("test"))
|
||||
{
|
||||
/* Return 501: not implemented */
|
||||
ret = MHD_queue_response (connection,
|
||||
@ -165,13 +147,8 @@ TMH_WIRE_handler_wire_sepa (struct TMH_RequestHandler *rh,
|
||||
char *sepa_wire_file;
|
||||
int fd;
|
||||
struct stat sbuf;
|
||||
unsigned int i;
|
||||
|
||||
for (i=0;NULL != TMH_expected_wire_formats[i];i++)
|
||||
if (0 == strcasecmp ("sepa",
|
||||
TMH_expected_wire_formats[i]))
|
||||
break;
|
||||
if (NULL == TMH_expected_wire_formats[i])
|
||||
if (GNUNET_NO == TMH_VALIDATION_test_method ("sepa"))
|
||||
{
|
||||
/* Return 501: not implemented */
|
||||
response = MHD_create_response_from_buffer (0, NULL,
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
@ -83,67 +83,5 @@ TALER_MINTDB_plugin_unload (struct TALER_MINTDB_Plugin *plugin)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Libtool search path before we started.
|
||||
*/
|
||||
static char *old_dlsearchpath;
|
||||
|
||||
|
||||
/**
|
||||
* Setup libtool paths.
|
||||
*/
|
||||
void __attribute__ ((constructor))
|
||||
plugin_init ()
|
||||
{
|
||||
int err;
|
||||
const char *opath;
|
||||
char *path;
|
||||
char *cpath;
|
||||
|
||||
err = lt_dlinit ();
|
||||
if (err > 0)
|
||||
{
|
||||
FPRINTF (stderr,
|
||||
_("Initialization of plugin mechanism failed: %s!\n"),
|
||||
lt_dlerror ());
|
||||
return;
|
||||
}
|
||||
opath = lt_dlgetsearchpath ();
|
||||
if (NULL != opath)
|
||||
old_dlsearchpath = GNUNET_strdup (opath);
|
||||
path = TALER_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
|
||||
if (NULL != path)
|
||||
{
|
||||
if (NULL != opath)
|
||||
{
|
||||
GNUNET_asprintf (&cpath, "%s:%s", opath, path);
|
||||
lt_dlsetsearchpath (cpath);
|
||||
GNUNET_free (path);
|
||||
GNUNET_free (cpath);
|
||||
}
|
||||
else
|
||||
{
|
||||
lt_dlsetsearchpath (path);
|
||||
GNUNET_free (path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shutdown libtool.
|
||||
*/
|
||||
void __attribute__ ((destructor))
|
||||
plugin_fini ()
|
||||
{
|
||||
lt_dlsetsearchpath (old_dlsearchpath);
|
||||
if (NULL != old_dlsearchpath)
|
||||
{
|
||||
GNUNET_free (old_dlsearchpath);
|
||||
old_dlsearchpath = NULL;
|
||||
}
|
||||
lt_dlexit ();
|
||||
}
|
||||
|
||||
|
||||
/* end of mintdb_plugin.c */
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
@ -67,9 +67,11 @@ PERF_TALER_MINTDB_denomination_init ()
|
||||
properties.expire_withdraw = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_forever_());
|
||||
properties.expire_spend = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_forever_());
|
||||
properties.expire_legal = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_forever_());
|
||||
TALER_string_to_amount (CURRENCY ":1.1", &amount);
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_string_to_amount (CURRENCY ":1.1", &amount));
|
||||
TALER_amount_hton (&properties.value, &amount);
|
||||
TALER_string_to_amount (CURRENCY ":0.1", &amount);
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_string_to_amount (CURRENCY ":0.1", &amount));
|
||||
TALER_amount_hton (&properties.fee_withdraw, &amount);
|
||||
TALER_amount_hton (&properties.fee_deposit, &amount);
|
||||
TALER_amount_hton (&properties.fee_refresh, &amount);
|
||||
@ -467,8 +469,8 @@ PERF_TALER_MINTDB_refresh_session_free (struct TALER_MINTDB_RefreshSession *refr
|
||||
{
|
||||
if (NULL == refresh_session)
|
||||
return GNUNET_OK;
|
||||
return GNUNET_OK;
|
||||
GNUNET_free (refresh_session);
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -502,10 +504,12 @@ PERF_TALER_MINTDB_refresh_melt_init (struct GNUNET_HashCode *session,
|
||||
&to_sign.purpose,
|
||||
&coin_sig.eddsa_signature);
|
||||
}
|
||||
GNUNET_assert (GNUNET_OK == TALER_string_to_amount (CURRENCY ":1.1",
|
||||
&amount));
|
||||
GNUNET_assert (GNUNET_OK == TALER_string_to_amount (CURRENCY ":0.1",
|
||||
&amount_with_fee));
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_string_to_amount (CURRENCY ":1.1",
|
||||
&amount));
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_string_to_amount (CURRENCY ":0.1",
|
||||
&amount_with_fee));
|
||||
melt = GNUNET_new (struct TALER_MINTDB_RefreshMelt);
|
||||
melt->coin.coin_pub = coin->public_info.coin_pub;
|
||||
melt->coin.denom_sig.rsa_signature =
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015, 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
@ -14,7 +14,7 @@
|
||||
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file mint/test_mintdb.c
|
||||
* @file mintdb/test_mintdb.c
|
||||
* @brief test cases for DB interaction functions
|
||||
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||
*/
|
||||
@ -305,8 +305,10 @@ test_melting (struct TALER_MINTDB_Session *session)
|
||||
RND_BLK (&refresh_session);
|
||||
RND_BLK (&session_hash);
|
||||
melts = NULL;
|
||||
dkp = NULL;
|
||||
new_dkp = NULL;
|
||||
new_denom_pubs = NULL;
|
||||
ret_denom_pubs = NULL;
|
||||
/* create and test a refresh session */
|
||||
refresh_session.num_oldcoins = MELT_OLD_COINS;
|
||||
refresh_session.num_newcoins = 1;
|
||||
@ -324,11 +326,11 @@ test_melting (struct TALER_MINTDB_Session *session)
|
||||
sizeof (refresh_session)));
|
||||
|
||||
/* create a denomination (value: 1; fraction: 100) */
|
||||
dkp = create_denom_key_pair(512, session,
|
||||
&value,
|
||||
&fee_withdraw,
|
||||
&fee_deposit,
|
||||
&fee_refresh);
|
||||
dkp = create_denom_key_pair (512, session,
|
||||
&value,
|
||||
&fee_withdraw,
|
||||
&fee_deposit,
|
||||
&fee_refresh);
|
||||
/* create MELT_OLD_COINS number of refresh melts */
|
||||
melts = GNUNET_new_array (MELT_OLD_COINS, struct TALER_MINTDB_RefreshMelt);
|
||||
for (cnt=0; cnt < MELT_OLD_COINS; cnt++)
|
||||
@ -416,7 +418,8 @@ test_melting (struct TALER_MINTDB_Session *session)
|
||||
ret = GNUNET_OK;
|
||||
|
||||
drop:
|
||||
destroy_denom_key_pair (dkp);
|
||||
if (NULL != dkp)
|
||||
destroy_denom_key_pair (dkp);
|
||||
if (NULL != melts)
|
||||
{
|
||||
for (cnt = 0; cnt < MELT_OLD_COINS; cnt++)
|
||||
@ -439,6 +442,114 @@ test_melting (struct TALER_MINTDB_Session *session)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback that should never be called.
|
||||
*/
|
||||
static void
|
||||
cb_wt_never (void *cls,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
const struct GNUNET_HashCode *h_wire,
|
||||
const struct GNUNET_HashCode *h_contract,
|
||||
uint64_t transaction_id,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_Amount *coin_value,
|
||||
const struct TALER_Amount *coin_fee,
|
||||
const struct TALER_Amount *transfer_value)
|
||||
{
|
||||
GNUNET_assert (0); /* this statement should be unreachable */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback that should never be called.
|
||||
*/
|
||||
static void
|
||||
cb_wtid_never (void *cls,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
const struct TALER_Amount *coin_contribution,
|
||||
const struct TALER_Amount *coin_fee,
|
||||
const struct TALER_Amount *total_amount,
|
||||
struct GNUNET_TIME_Absolute execution_time)
|
||||
{
|
||||
GNUNET_assert (0);
|
||||
}
|
||||
|
||||
|
||||
static struct TALER_MerchantPublicKeyP merchant_pub_wt;
|
||||
static struct GNUNET_HashCode h_wire_wt;
|
||||
static struct GNUNET_HashCode h_contract_wt;
|
||||
static uint64_t transaction_id_wt;
|
||||
static struct TALER_CoinSpendPublicKeyP coin_pub_wt;
|
||||
static struct TALER_Amount coin_value_wt;
|
||||
static struct TALER_Amount coin_fee_wt;
|
||||
static struct TALER_Amount transfer_value_wt;
|
||||
static struct GNUNET_TIME_Absolute execution_time_wt;
|
||||
static struct TALER_WireTransferIdentifierRawP wtid_wt;
|
||||
|
||||
|
||||
/**
|
||||
* Callback that should be called with the WT data.
|
||||
*/
|
||||
static void
|
||||
cb_wt_check (void *cls,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
const struct GNUNET_HashCode *h_wire,
|
||||
const struct GNUNET_HashCode *h_contract,
|
||||
uint64_t transaction_id,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_Amount *coin_value,
|
||||
const struct TALER_Amount *coin_fee,
|
||||
const struct TALER_Amount *transfer_value)
|
||||
{
|
||||
GNUNET_assert (cls == &cb_wt_never);
|
||||
GNUNET_assert (0 == memcmp (merchant_pub,
|
||||
&merchant_pub_wt,
|
||||
sizeof (struct TALER_MerchantPublicKeyP)));
|
||||
GNUNET_assert (0 == memcmp (h_wire,
|
||||
&h_wire_wt,
|
||||
sizeof (struct GNUNET_HashCode)));
|
||||
GNUNET_assert (0 == memcmp (h_contract,
|
||||
&h_contract_wt,
|
||||
sizeof (struct GNUNET_HashCode)));
|
||||
GNUNET_assert (transaction_id == transaction_id_wt);
|
||||
GNUNET_assert (0 == memcmp (coin_pub,
|
||||
&coin_pub_wt,
|
||||
sizeof (struct TALER_CoinSpendPublicKeyP)));
|
||||
GNUNET_assert (0 == TALER_amount_cmp (coin_value,
|
||||
&coin_value_wt));
|
||||
GNUNET_assert (0 == TALER_amount_cmp (coin_fee,
|
||||
&coin_fee_wt));
|
||||
GNUNET_assert (0 == TALER_amount_cmp (transfer_value,
|
||||
&transfer_value_wt));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback that should be called with the WT data.
|
||||
*/
|
||||
static void
|
||||
cb_wtid_check (void *cls,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
const struct TALER_Amount *coin_contribution,
|
||||
const struct TALER_Amount *coin_fee,
|
||||
const struct TALER_Amount *total_amount,
|
||||
struct GNUNET_TIME_Absolute execution_time)
|
||||
{
|
||||
GNUNET_assert (cls == &cb_wtid_never);
|
||||
GNUNET_assert (0 == memcmp (wtid,
|
||||
&wtid_wt,
|
||||
sizeof (struct TALER_WireTransferIdentifierRawP)));
|
||||
GNUNET_assert (execution_time.abs_value_us ==
|
||||
execution_time_wt.abs_value_us);
|
||||
GNUNET_assert (0 == TALER_amount_cmp (coin_contribution,
|
||||
&coin_value_wt));
|
||||
GNUNET_assert (0 == TALER_amount_cmp (coin_fee,
|
||||
&coin_fee_wt));
|
||||
GNUNET_assert (0 == TALER_amount_cmp (total_amount,
|
||||
&transfer_value_wt));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Main function that will be run by the scheduler.
|
||||
*
|
||||
@ -455,7 +566,6 @@ run (void *cls,
|
||||
{
|
||||
struct TALER_MINTDB_Session *session;
|
||||
struct TALER_ReservePublicKeyP reserve_pub;
|
||||
struct TALER_Amount amount;
|
||||
struct DenomKeyPair *dkp;
|
||||
struct TALER_MINTDB_CollectableBlindcoin cbc;
|
||||
struct TALER_MINTDB_CollectableBlindcoin cbc2;
|
||||
@ -465,6 +575,7 @@ run (void *cls,
|
||||
struct TALER_MINTDB_CollectableBlindcoin *withdraw;
|
||||
struct TALER_MINTDB_Deposit deposit;
|
||||
struct TALER_MINTDB_Deposit deposit2;
|
||||
struct TALER_WireTransferIdentifierRawP wtid;
|
||||
json_t *wire;
|
||||
json_t *just;
|
||||
const char * const json_wire_str =
|
||||
@ -563,11 +674,7 @@ run (void *cls,
|
||||
= GNUNET_CRYPTO_rsa_sign (dkp->priv.rsa_private_key,
|
||||
&cbc.h_coin_envelope,
|
||||
sizeof (cbc.h_coin_envelope));
|
||||
(void) memcpy (&cbc.reserve_pub,
|
||||
&reserve_pub,
|
||||
sizeof (reserve_pub));
|
||||
amount.value--;
|
||||
amount.fraction--;
|
||||
cbc.reserve_pub = reserve_pub;
|
||||
cbc.amount_with_fee = value;
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_amount_get_zero (CURRENCY, &cbc.withdraw_fee));
|
||||
@ -652,9 +759,7 @@ run (void *cls,
|
||||
plugin->have_deposit (plugin->cls,
|
||||
session,
|
||||
&deposit));
|
||||
(void) memcpy (&deposit2,
|
||||
&deposit,
|
||||
sizeof (deposit));
|
||||
deposit2 = deposit;
|
||||
deposit2.transaction_id++; /* should fail if transaction id is different */
|
||||
FAILIF (GNUNET_NO !=
|
||||
plugin->have_deposit (plugin->cls,
|
||||
@ -666,15 +771,79 @@ run (void *cls,
|
||||
plugin->have_deposit (plugin->cls,
|
||||
session,
|
||||
&deposit2));
|
||||
(void) memcpy (&deposit2.merchant_pub,
|
||||
&deposit.merchant_pub,
|
||||
sizeof (deposit.merchant_pub));
|
||||
deposit2.merchant_pub = deposit.merchant_pub;
|
||||
RND_BLK (&deposit2.coin.coin_pub); /* should fail if coin is different */
|
||||
FAILIF (GNUNET_NO !=
|
||||
plugin->have_deposit (plugin->cls,
|
||||
session,
|
||||
&deposit2));
|
||||
FAILIF (GNUNET_OK != test_melting (session));
|
||||
|
||||
/* setup values for wire transfer aggregation data */
|
||||
memset (&wtid, 42, sizeof (wtid));
|
||||
memset (&merchant_pub_wt, 43, sizeof (merchant_pub_wt));
|
||||
memset (&h_wire_wt, 44, sizeof (h_wire_wt));
|
||||
memset (&h_contract_wt, 45, sizeof (h_contract_wt));
|
||||
memset (&coin_pub_wt, 46, sizeof (coin_pub_wt));
|
||||
transaction_id_wt = 47;
|
||||
execution_time_wt = GNUNET_TIME_absolute_get ();
|
||||
memset (&merchant_pub_wt, 48, sizeof (merchant_pub_wt));
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_string_to_amount (CURRENCY "KUDOS:1.000010",
|
||||
&coin_value_wt));
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_string_to_amount (CURRENCY "KUDOS:0.000010",
|
||||
&coin_fee_wt));
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_string_to_amount (CURRENCY "KUDOS:1.000000",
|
||||
&transfer_value_wt));
|
||||
|
||||
FAILIF (GNUNET_NO !=
|
||||
plugin->lookup_wire_transfer (plugin->cls,
|
||||
session,
|
||||
&wtid_wt,
|
||||
&cb_wt_never,
|
||||
NULL));
|
||||
FAILIF (GNUNET_NO !=
|
||||
plugin->wire_lookup_deposit_wtid (plugin->cls,
|
||||
session,
|
||||
&h_contract_wt,
|
||||
&h_wire_wt,
|
||||
&coin_pub_wt,
|
||||
&merchant_pub_wt,
|
||||
transaction_id_wt,
|
||||
&cb_wtid_never,
|
||||
NULL));
|
||||
/* insert WT data */
|
||||
FAILIF (GNUNET_OK !=
|
||||
plugin->insert_aggregation_tracking (plugin->cls,
|
||||
session,
|
||||
&wtid_wt,
|
||||
&merchant_pub_wt,
|
||||
&h_wire_wt,
|
||||
&h_contract_wt,
|
||||
transaction_id_wt,
|
||||
execution_time_wt,
|
||||
&coin_pub_wt,
|
||||
&coin_value_wt,
|
||||
&coin_fee_wt,
|
||||
&transfer_value_wt));
|
||||
FAILIF (GNUNET_OK !=
|
||||
plugin->lookup_wire_transfer (plugin->cls,
|
||||
session,
|
||||
&wtid_wt,
|
||||
&cb_wt_check,
|
||||
&cb_wt_never));
|
||||
FAILIF (GNUNET_OK !=
|
||||
plugin->wire_lookup_deposit_wtid (plugin->cls,
|
||||
session,
|
||||
&h_contract_wt,
|
||||
&h_wire_wt,
|
||||
&coin_pub_wt,
|
||||
&merchant_pub_wt,
|
||||
transaction_id_wt,
|
||||
&cb_wtid_check,
|
||||
&cb_wtid_never));
|
||||
result = 0;
|
||||
|
||||
drop:
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2015 Christian Grothoff (and other contributing authors)
|
||||
(C) 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -33,6 +33,7 @@ libtalerutil_la_SOURCES = \
|
||||
util.c \
|
||||
json.c \
|
||||
os_installation.c \
|
||||
plugin.c \
|
||||
wireformats.c
|
||||
|
||||
libtalerutil_la_LIBADD = \
|
||||
@ -48,14 +49,12 @@ libtalerutil_la_LDFLAGS = \
|
||||
TESTS = \
|
||||
test_amount \
|
||||
test_crypto \
|
||||
test_json \
|
||||
test_wireformats
|
||||
test_json
|
||||
|
||||
check_PROGRAMS= \
|
||||
test_amount \
|
||||
test_crypto \
|
||||
test_json \
|
||||
test_wireformats
|
||||
test_json
|
||||
|
||||
|
||||
test_amount_SOURCES = \
|
||||
@ -76,10 +75,3 @@ test_json_LDADD = \
|
||||
-lgnunetutil \
|
||||
-ljansson \
|
||||
libtalerutil.la
|
||||
|
||||
test_wireformats_SOURCES = \
|
||||
test_wireformats.c
|
||||
test_wireformats_LDADD = \
|
||||
-lgnunetutil \
|
||||
-ljansson \
|
||||
libtalerutil.la
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of GNUnet.
|
||||
Copyright (C) 2006-2014 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2006-2014 GNUnet e.V.
|
||||
|
||||
GNUnet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published
|
||||
|
88
src/util/plugin.c
Normal file
88
src/util/plugin.c
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is 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 util/plugin.c
|
||||
* @brief Setup paths so that we can load Taler plugins
|
||||
* @author Christian Grothoff
|
||||
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_util.h"
|
||||
#include <ltdl.h>
|
||||
|
||||
/**
|
||||
* Libtool search path before we started.
|
||||
*/
|
||||
static char *old_dlsearchpath;
|
||||
|
||||
|
||||
/**
|
||||
* Setup libtool paths.
|
||||
*/
|
||||
void __attribute__ ((constructor))
|
||||
plugin_init ()
|
||||
{
|
||||
int err;
|
||||
const char *opath;
|
||||
char *path;
|
||||
char *cpath;
|
||||
|
||||
err = lt_dlinit ();
|
||||
if (err > 0)
|
||||
{
|
||||
FPRINTF (stderr,
|
||||
_("Initialization of plugin mechanism failed: %s!\n"),
|
||||
lt_dlerror ());
|
||||
return;
|
||||
}
|
||||
opath = lt_dlgetsearchpath ();
|
||||
if (NULL != opath)
|
||||
old_dlsearchpath = GNUNET_strdup (opath);
|
||||
path = TALER_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
|
||||
if (NULL != path)
|
||||
{
|
||||
if (NULL != opath)
|
||||
{
|
||||
GNUNET_asprintf (&cpath, "%s:%s", opath, path);
|
||||
lt_dlsetsearchpath (cpath);
|
||||
GNUNET_free (path);
|
||||
GNUNET_free (cpath);
|
||||
}
|
||||
else
|
||||
{
|
||||
lt_dlsetsearchpath (path);
|
||||
GNUNET_free (path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shutdown libtool.
|
||||
*/
|
||||
void __attribute__ ((destructor))
|
||||
plugin_fini ()
|
||||
{
|
||||
lt_dlsetsearchpath (old_dlsearchpath);
|
||||
if (NULL != old_dlsearchpath)
|
||||
{
|
||||
GNUNET_free (old_dlsearchpath);
|
||||
old_dlsearchpath = NULL;
|
||||
}
|
||||
lt_dlexit ();
|
||||
}
|
||||
|
||||
/* end of plugin.c */
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2015 Christian Grothoff (and other contributing authors)
|
||||
(C) 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2015 Christian Grothoff (and other contributing authors)
|
||||
(C) 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2015 Christian Grothoff (and other contributing authors)
|
||||
(C) 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
|
||||
Copyright (C) 2014, 2015 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
78
src/wire/Makefile.am
Normal file
78
src/wire/Makefile.am
Normal file
@ -0,0 +1,78 @@
|
||||
# This Makefile.am is in the public domain
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src/include
|
||||
|
||||
if USE_COVERAGE
|
||||
AM_CFLAGS = --coverage -O0
|
||||
XLIB = -lgcov
|
||||
endif
|
||||
|
||||
plugindir = $(libdir)/taler
|
||||
|
||||
plugin_LTLIBRARIES = \
|
||||
libtaler_plugin_wire_sepa.la \
|
||||
libtaler_plugin_wire_test.la
|
||||
|
||||
noinst_LTLIBRARIES = \
|
||||
libtaler_plugin_wire_template.la
|
||||
|
||||
lib_LTLIBRARIES = \
|
||||
libtalerwire.la
|
||||
|
||||
|
||||
libtaler_plugin_wire_test_la_SOURCES = \
|
||||
plugin_wire_test.c
|
||||
libtaler_plugin_wire_test_la_LIBADD = \
|
||||
$(LTLIBINTL)
|
||||
libtaler_plugin_wire_test_la_LDFLAGS = \
|
||||
$(TALER_PLUGIN_LDFLAGS) \
|
||||
$(top_builddir)/src/bank-lib/libtalerbank.la \
|
||||
$(top_builddir)/src/util/libtalerutil.la \
|
||||
-lgnunetutil $(XLIB)
|
||||
|
||||
|
||||
libtaler_plugin_wire_sepa_la_SOURCES = \
|
||||
plugin_wire_sepa.c
|
||||
libtaler_plugin_wire_sepa_la_LIBADD = \
|
||||
$(LTLIBINTL)
|
||||
libtaler_plugin_wire_sepa_la_LDFLAGS = \
|
||||
$(TALER_PLUGIN_LDFLAGS) \
|
||||
$(top_builddir)/src/util/libtalerutil.la \
|
||||
-lgnunetutil $(XLIB)
|
||||
|
||||
|
||||
libtaler_plugin_wire_template_la_SOURCES = \
|
||||
plugin_wire_template.c
|
||||
libtaler_plugin_wire_template_la_LIBADD = \
|
||||
$(LTLIBINTL)
|
||||
libtaler_plugin_wire_template_la_LDFLAGS = \
|
||||
$(TALER_PLUGIN_LDFLAGS) \
|
||||
$(top_builddir)/src/util/libtalerutil.la \
|
||||
-lgnunetutil $(XLIB)
|
||||
|
||||
|
||||
libtalerwire_la_SOURCES = \
|
||||
wire.c
|
||||
libtalerwire_la_LIBADD = \
|
||||
-lgnunetutil \
|
||||
$(XLIB)
|
||||
libtalerwire_la_LDFLAGS = \
|
||||
-version-info 0:0:0 \
|
||||
-export-dynamic -no-undefined
|
||||
|
||||
|
||||
TESTS = \
|
||||
test_sepa_wireformat
|
||||
|
||||
check_PROGRAMS= \
|
||||
test_sepa_wireformat
|
||||
|
||||
|
||||
|
||||
test_sepa_wireformat_SOURCES = \
|
||||
test_sepa_wireformat.c
|
||||
test_sepa_wireformat_LDADD = \
|
||||
-lgnunetutil \
|
||||
-ljansson \
|
||||
libtalerwire.la \
|
||||
$(top_builddir)/src/util/libtalerutil.la
|
||||
|
545
src/wire/plugin_wire_sepa.c
Normal file
545
src/wire/plugin_wire_sepa.c
Normal file
@ -0,0 +1,545 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is 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 plugin_wire_sepa.c
|
||||
* @brief wire plugin for transfers using SEPA/EBICS
|
||||
* @author Florian Dold
|
||||
* @author Christian Grothoff
|
||||
* @author Sree Harsha Totakura
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_wire_plugin.h"
|
||||
|
||||
|
||||
/**
|
||||
* Type of the "cls" argument given to each of the functions in
|
||||
* our API.
|
||||
*/
|
||||
struct SepaClosure
|
||||
{
|
||||
|
||||
/**
|
||||
* Which currency do we support?
|
||||
*/
|
||||
char *currency;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Round amount DOWN to the amount that can be transferred via the wire
|
||||
* method. For example, Taler may support 0.000001 EUR as a unit of
|
||||
* payment, but SEPA only supports 0.01 EUR. This function would
|
||||
* round 0.125 EUR to 0.12 EUR in this case.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param[in,out] amount amount to round down
|
||||
* @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary,
|
||||
* #GNUNET_SYSERR if the amount or currency was invalid
|
||||
*/
|
||||
static int
|
||||
sepa_amount_round (void *cls,
|
||||
struct TALER_Amount *amount)
|
||||
{
|
||||
struct SepaClosure *sc = cls;
|
||||
uint32_t delta;
|
||||
|
||||
if (0 != strcasecmp (amount->currency,
|
||||
sc->currency))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
delta = amount->fraction % (TALER_AMOUNT_FRAC_BASE / 100);
|
||||
if (0 == delta)
|
||||
return GNUNET_NO;
|
||||
amount->fraction -= delta;
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
|
||||
/* Taken from GNU gettext */
|
||||
|
||||
/**
|
||||
* Entry in the country table.
|
||||
*/
|
||||
struct table_entry
|
||||
{
|
||||
/**
|
||||
* 2-Character international country code.
|
||||
*/
|
||||
const char *code;
|
||||
|
||||
/**
|
||||
* Long English name of the country.
|
||||
*/
|
||||
const char *english;
|
||||
};
|
||||
|
||||
|
||||
/* Keep the following table in sync with gettext.
|
||||
WARNING: the entries should stay sorted according to the code */
|
||||
/**
|
||||
* List of country codes.
|
||||
*/
|
||||
static const struct table_entry country_table[] =
|
||||
{
|
||||
{ "AE", "U.A.E." },
|
||||
{ "AF", "Afghanistan" },
|
||||
{ "AL", "Albania" },
|
||||
{ "AM", "Armenia" },
|
||||
{ "AN", "Netherlands Antilles" },
|
||||
{ "AR", "Argentina" },
|
||||
{ "AT", "Austria" },
|
||||
{ "AU", "Australia" },
|
||||
{ "AZ", "Azerbaijan" },
|
||||
{ "BA", "Bosnia and Herzegovina" },
|
||||
{ "BD", "Bangladesh" },
|
||||
{ "BE", "Belgium" },
|
||||
{ "BG", "Bulgaria" },
|
||||
{ "BH", "Bahrain" },
|
||||
{ "BN", "Brunei Darussalam" },
|
||||
{ "BO", "Bolivia" },
|
||||
{ "BR", "Brazil" },
|
||||
{ "BT", "Bhutan" },
|
||||
{ "BY", "Belarus" },
|
||||
{ "BZ", "Belize" },
|
||||
{ "CA", "Canada" },
|
||||
{ "CG", "Congo" },
|
||||
{ "CH", "Switzerland" },
|
||||
{ "CI", "Cote d'Ivoire" },
|
||||
{ "CL", "Chile" },
|
||||
{ "CM", "Cameroon" },
|
||||
{ "CN", "People's Republic of China" },
|
||||
{ "CO", "Colombia" },
|
||||
{ "CR", "Costa Rica" },
|
||||
{ "CS", "Serbia and Montenegro" },
|
||||
{ "CZ", "Czech Republic" },
|
||||
{ "DE", "Germany" },
|
||||
{ "DK", "Denmark" },
|
||||
{ "DO", "Dominican Republic" },
|
||||
{ "DZ", "Algeria" },
|
||||
{ "EC", "Ecuador" },
|
||||
{ "EE", "Estonia" },
|
||||
{ "EG", "Egypt" },
|
||||
{ "ER", "Eritrea" },
|
||||
{ "ES", "Spain" },
|
||||
{ "ET", "Ethiopia" },
|
||||
{ "FI", "Finland" },
|
||||
{ "FO", "Faroe Islands" },
|
||||
{ "FR", "France" },
|
||||
{ "GB", "United Kingdom" },
|
||||
{ "GD", "Caribbean" },
|
||||
{ "GE", "Georgia" },
|
||||
{ "GL", "Greenland" },
|
||||
{ "GR", "Greece" },
|
||||
{ "GT", "Guatemala" },
|
||||
{ "HK", "Hong Kong" },
|
||||
{ "HK", "Hong Kong S.A.R." },
|
||||
{ "HN", "Honduras" },
|
||||
{ "HR", "Croatia" },
|
||||
{ "HT", "Haiti" },
|
||||
{ "HU", "Hungary" },
|
||||
{ "ID", "Indonesia" },
|
||||
{ "IE", "Ireland" },
|
||||
{ "IL", "Israel" },
|
||||
{ "IN", "India" },
|
||||
{ "IQ", "Iraq" },
|
||||
{ "IR", "Iran" },
|
||||
{ "IS", "Iceland" },
|
||||
{ "IT", "Italy" },
|
||||
{ "JM", "Jamaica" },
|
||||
{ "JO", "Jordan" },
|
||||
{ "JP", "Japan" },
|
||||
{ "KE", "Kenya" },
|
||||
{ "KG", "Kyrgyzstan" },
|
||||
{ "KH", "Cambodia" },
|
||||
{ "KR", "South Korea" },
|
||||
{ "KW", "Kuwait" },
|
||||
{ "KZ", "Kazakhstan" },
|
||||
{ "LA", "Laos" },
|
||||
{ "LB", "Lebanon" },
|
||||
{ "LI", "Liechtenstein" },
|
||||
{ "LK", "Sri Lanka" },
|
||||
{ "LT", "Lithuania" },
|
||||
{ "LU", "Luxembourg" },
|
||||
{ "LV", "Latvia" },
|
||||
{ "LY", "Libya" },
|
||||
{ "MA", "Morocco" },
|
||||
{ "MC", "Principality of Monaco" },
|
||||
{ "MD", "Moldava" },
|
||||
{ "MD", "Moldova" },
|
||||
{ "ME", "Montenegro" },
|
||||
{ "MK", "Former Yugoslav Republic of Macedonia" },
|
||||
{ "ML", "Mali" },
|
||||
{ "MM", "Myanmar" },
|
||||
{ "MN", "Mongolia" },
|
||||
{ "MO", "Macau S.A.R." },
|
||||
{ "MT", "Malta" },
|
||||
{ "MV", "Maldives" },
|
||||
{ "MX", "Mexico" },
|
||||
{ "MY", "Malaysia" },
|
||||
{ "NG", "Nigeria" },
|
||||
{ "NI", "Nicaragua" },
|
||||
{ "NL", "Netherlands" },
|
||||
{ "NO", "Norway" },
|
||||
{ "NP", "Nepal" },
|
||||
{ "NZ", "New Zealand" },
|
||||
{ "OM", "Oman" },
|
||||
{ "PA", "Panama" },
|
||||
{ "PE", "Peru" },
|
||||
{ "PH", "Philippines" },
|
||||
{ "PK", "Islamic Republic of Pakistan" },
|
||||
{ "PL", "Poland" },
|
||||
{ "PR", "Puerto Rico" },
|
||||
{ "PT", "Portugal" },
|
||||
{ "PY", "Paraguay" },
|
||||
{ "QA", "Qatar" },
|
||||
{ "RE", "Reunion" },
|
||||
{ "RO", "Romania" },
|
||||
{ "RS", "Serbia" },
|
||||
{ "RU", "Russia" },
|
||||
{ "RW", "Rwanda" },
|
||||
{ "SA", "Saudi Arabia" },
|
||||
{ "SE", "Sweden" },
|
||||
{ "SG", "Singapore" },
|
||||
{ "SI", "Slovenia" },
|
||||
{ "SK", "Slovak" },
|
||||
{ "SN", "Senegal" },
|
||||
{ "SO", "Somalia" },
|
||||
{ "SR", "Suriname" },
|
||||
{ "SV", "El Salvador" },
|
||||
{ "SY", "Syria" },
|
||||
{ "TH", "Thailand" },
|
||||
{ "TJ", "Tajikistan" },
|
||||
{ "TM", "Turkmenistan" },
|
||||
{ "TN", "Tunisia" },
|
||||
{ "TR", "Turkey" },
|
||||
{ "TT", "Trinidad and Tobago" },
|
||||
{ "TW", "Taiwan" },
|
||||
{ "TZ", "Tanzania" },
|
||||
{ "UA", "Ukraine" },
|
||||
{ "US", "United States" },
|
||||
{ "UY", "Uruguay" },
|
||||
{ "VA", "Vatican" },
|
||||
{ "VE", "Venezuela" },
|
||||
{ "VN", "Viet Nam" },
|
||||
{ "YE", "Yemen" },
|
||||
{ "ZA", "South Africa" },
|
||||
{ "ZW", "Zimbabwe" }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Country code comparator function, for binary search with bsearch().
|
||||
*
|
||||
* @param ptr1 pointer to a `struct table_entry`
|
||||
* @param ptr2 pointer to a `struct table_entry`
|
||||
* @return result of strncmp()'ing the 2-digit country codes of the entries
|
||||
*/
|
||||
static int
|
||||
cmp_country_code (const void *ptr1,
|
||||
const void *ptr2)
|
||||
{
|
||||
const struct table_entry *cc1 = ptr1;
|
||||
const struct table_entry *cc2 = ptr2;
|
||||
|
||||
return strncmp (cc1->code,
|
||||
cc2->code,
|
||||
2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validates given IBAN according to the European Banking Standards. See:
|
||||
* http://www.europeanpaymentscouncil.eu/documents/ECBS%20IBAN%20standard%20EBS204_V3.2.pdf
|
||||
*
|
||||
* @param iban the IBAN number to validate
|
||||
* @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
|
||||
*/
|
||||
static int
|
||||
validate_iban (const char *iban)
|
||||
{
|
||||
char cc[2];
|
||||
char ibancpy[35];
|
||||
struct table_entry cc_entry;
|
||||
unsigned int len;
|
||||
char *nbuf;
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
unsigned long long dividend;
|
||||
unsigned long long remainder;
|
||||
int nread;
|
||||
int ret;
|
||||
|
||||
len = strlen (iban);
|
||||
if (len > 34)
|
||||
return GNUNET_NO;
|
||||
strncpy (cc, iban, 2);
|
||||
strncpy (ibancpy, iban + 4, len - 4);
|
||||
strncpy (ibancpy + len - 4, iban, 4);
|
||||
ibancpy[len] = '\0';
|
||||
cc_entry.code = cc;
|
||||
cc_entry.english = NULL;
|
||||
if (NULL ==
|
||||
bsearch (&cc_entry,
|
||||
country_table,
|
||||
sizeof (country_table) / sizeof (struct table_entry),
|
||||
sizeof (struct table_entry),
|
||||
&cmp_country_code))
|
||||
return GNUNET_NO;
|
||||
nbuf = GNUNET_malloc ((len * 2) + 1);
|
||||
for (i=0, j=0; i < len; i++)
|
||||
{
|
||||
if (isalpha ((int) ibancpy[i]))
|
||||
{
|
||||
if (2 != snprintf(&nbuf[j],
|
||||
3,
|
||||
"%2u",
|
||||
(ibancpy[i] - 'A' + 10)))
|
||||
{
|
||||
GNUNET_free (nbuf);
|
||||
return GNUNET_NO;
|
||||
}
|
||||
j += 2;
|
||||
continue;
|
||||
}
|
||||
nbuf[j] = ibancpy[i];
|
||||
j++;
|
||||
}
|
||||
for (j=0;'\0' != nbuf[j];j++)
|
||||
GNUNET_assert (isdigit(nbuf[j]));
|
||||
GNUNET_assert (sizeof(dividend) >= 8);
|
||||
remainder = 0;
|
||||
for (i=0; i<j; i+=16)
|
||||
{
|
||||
if (1 !=
|
||||
(ret = sscanf (&nbuf[i],
|
||||
"%16llu %n",
|
||||
÷nd,
|
||||
&nread)))
|
||||
{
|
||||
GNUNET_free (nbuf);
|
||||
return GNUNET_NO;
|
||||
}
|
||||
if (0 != remainder)
|
||||
dividend += remainder * (pow (10, nread));
|
||||
remainder = dividend % 97;
|
||||
}
|
||||
GNUNET_free (nbuf);
|
||||
if (1 == remainder)
|
||||
return GNUNET_YES;
|
||||
return GNUNET_NO;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if the given wire format JSON object is correctly formatted
|
||||
*
|
||||
* @param wire the JSON wire format object
|
||||
* @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
|
||||
*/
|
||||
static int
|
||||
sepa_wire_validate (const json_t *wire)
|
||||
{
|
||||
json_error_t error;
|
||||
const char *type;
|
||||
const char *iban;
|
||||
const char *name;
|
||||
const char *bic;
|
||||
uint64_t r;
|
||||
const char *address;
|
||||
|
||||
if (0 != json_unpack_ex
|
||||
((json_t *) wire,
|
||||
&error, JSON_STRICT,
|
||||
"{"
|
||||
"s:s," /* TYPE: sepa */
|
||||
"s:s," /* IBAN: iban */
|
||||
"s:s," /* name: beneficiary name */
|
||||
"s:s," /* BIC: beneficiary bank's BIC */
|
||||
"s:i," /* r: random 64-bit integer nounce */
|
||||
"s:s" /* address: address of the beneficiary */
|
||||
"}",
|
||||
"type", &type,
|
||||
"IBAN", &iban,
|
||||
"name", &name,
|
||||
"bic", &bic,
|
||||
"r", &r,
|
||||
"address", &address))
|
||||
{
|
||||
TALER_json_warn (error);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (0 != strcasecmp (type,
|
||||
"sepa"))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Transfer type `%s' invalid\n",
|
||||
type);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (1 != validate_iban (iban))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"IBAN `%s' invalid\n",
|
||||
iban);
|
||||
return GNUNET_NO;
|
||||
}
|
||||
return GNUNET_YES;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepare for exeuction of a wire transfer.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param wire valid wire account information
|
||||
* @param amount amount to transfer, already rounded
|
||||
* @param wtid wire transfer identifier to use
|
||||
* @param psc function to call with the prepared data to persist
|
||||
* @param psc_cls closure for @a psc
|
||||
* @return NULL on failure
|
||||
*/
|
||||
static struct TALER_WIRE_PrepareHandle *
|
||||
sepa_prepare_wire_transfer (void *cls,
|
||||
const json_t *wire,
|
||||
const struct TALER_Amount *amount,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
TALER_WIRE_PrepareTransactionCallback psc,
|
||||
void *psc_cls)
|
||||
{
|
||||
GNUNET_break (0); // FIXME: not implemented
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Abort preparation of a wire transfer. For example,
|
||||
* because we are shutting down.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param pth preparation to cancel
|
||||
*/
|
||||
static void
|
||||
sepa_prepare_wire_transfer_cancel (void *cls,
|
||||
struct TALER_WIRE_PrepareHandle *pth)
|
||||
{
|
||||
GNUNET_break (0); // FIXME: not implemented
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Execute a wire transfer.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param buf buffer with the prepared execution details
|
||||
* @param buf_size number of bytes in @a buf
|
||||
* @param cc function to call upon success
|
||||
* @param cc_cls closure for @a cc
|
||||
* @return NULL on error
|
||||
*/
|
||||
static struct TALER_WIRE_ExecuteHandle *
|
||||
sepa_execute_wire_transfer (void *cls,
|
||||
const char *buf,
|
||||
size_t buf_size,
|
||||
TALER_WIRE_ConfirmationCallback cc,
|
||||
void *cc_cls)
|
||||
{
|
||||
GNUNET_break (0); // FIXME: not implemented
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Abort execution of a wire transfer. For example, because we are
|
||||
* shutting down. Note that if an execution is aborted, it may or
|
||||
* may not still succeed. The caller MUST run @e
|
||||
* execute_wire_transfer again for the same request as soon as
|
||||
* possilbe, to ensure that the request either ultimately succeeds
|
||||
* or ultimately fails. Until this has been done, the transaction is
|
||||
* in limbo (i.e. may or may not have been committed).
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param eh execution to cancel
|
||||
*/
|
||||
static void
|
||||
sepa_execute_wire_transfer_cancel (void *cls,
|
||||
struct TALER_WIRE_ExecuteHandle *eh)
|
||||
{
|
||||
GNUNET_break (0); // FIXME: not implemented
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize sepa-wire subsystem.
|
||||
*
|
||||
* @param cls a configuration instance
|
||||
* @return NULL on error, otherwise a `struct TALER_WIRE_Plugin`
|
||||
*/
|
||||
void *
|
||||
libtaler_plugin_wire_sepa_init (void *cls)
|
||||
{
|
||||
struct GNUNET_CONFIGURATION_Handle *cfg = cls;
|
||||
struct SepaClosure *sc;
|
||||
struct TALER_WIRE_Plugin *plugin;
|
||||
|
||||
sc = GNUNET_new (struct SepaClosure);
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CONFIGURATION_get_value_string (cfg,
|
||||
"mint",
|
||||
"CURRENCY",
|
||||
&sc->currency))
|
||||
{
|
||||
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
|
||||
"mint",
|
||||
"CURRENCY");
|
||||
GNUNET_free (sc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
plugin = GNUNET_new (struct TALER_WIRE_Plugin);
|
||||
plugin->cls = sc;
|
||||
plugin->amount_round = &sepa_amount_round;
|
||||
plugin->wire_validate = &sepa_wire_validate;
|
||||
plugin->prepare_wire_transfer = &sepa_prepare_wire_transfer;
|
||||
plugin->prepare_wire_transfer_cancel = &sepa_prepare_wire_transfer_cancel;
|
||||
plugin->execute_wire_transfer = &sepa_execute_wire_transfer;
|
||||
plugin->execute_wire_transfer_cancel = &sepa_execute_wire_transfer_cancel;
|
||||
return plugin;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shutdown Sepa wire subsystem.
|
||||
*
|
||||
* @param cls a `struct TALER_WIRE_Plugin`
|
||||
* @return NULL (always)
|
||||
*/
|
||||
void *
|
||||
libtaler_plugin_wire_sepa_done (void *cls)
|
||||
{
|
||||
struct TALER_WIRE_Plugin *plugin = cls;
|
||||
struct SepaClosure *sc = plugin->cls;
|
||||
|
||||
GNUNET_free (sc->currency);
|
||||
GNUNET_free (sc);
|
||||
GNUNET_free (plugin);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* end of plugin_wire_sepa.c */
|
243
src/wire/plugin_wire_template.c
Normal file
243
src/wire/plugin_wire_template.c
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is 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 plugin_wire_template.c
|
||||
* @brief template for wire plugins; replace "template" with real plugin name!
|
||||
* @author Florian Dold
|
||||
* @author Christian Grothoff
|
||||
* @author Sree Harsha Totakura
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_wire_plugin.h"
|
||||
|
||||
|
||||
/**
|
||||
* Type of the "cls" argument given to each of the functions in
|
||||
* our API.
|
||||
*/
|
||||
struct TemplateClosure
|
||||
{
|
||||
|
||||
/**
|
||||
* URI of the bank for sending funds to the bank.
|
||||
*/
|
||||
char *bank_uri;
|
||||
|
||||
/**
|
||||
* Which currency do we support?
|
||||
*/
|
||||
char *currency;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Round amount DOWN to the amount that can be transferred via the wire
|
||||
* method. For example, Taler may support 0.000001 EUR as a unit of
|
||||
* payment, but SEPA only supports 0.01 EUR. This function would
|
||||
* round 0.125 EUR to 0.12 EUR in this case.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param[in,out] amount amount to round down
|
||||
* @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary,
|
||||
* #GNUNET_SYSERR if the amount or currency was invalid
|
||||
*/
|
||||
static int
|
||||
template_amount_round (void *cls,
|
||||
struct TALER_Amount *amount)
|
||||
{
|
||||
struct TemplateClosure *tc = cls;
|
||||
|
||||
if (0 != strcasecmp (amount->currency,
|
||||
tc->currency))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
GNUNET_break (0); // not implemented
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if the given wire format JSON object is correctly formatted
|
||||
*
|
||||
* @param wire the JSON wire format object
|
||||
* @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
|
||||
*/
|
||||
static int
|
||||
template_wire_validate (const json_t *wire)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepare for exeuction of a wire transfer.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param wire valid wire account information
|
||||
* @param amount amount to transfer, already rounded
|
||||
* @param wtid wire transfer identifier to use
|
||||
* @param ptc function to call with the prepared data to persist
|
||||
* @param ptc_cls closure for @a ptc
|
||||
* @return NULL on failure
|
||||
*/
|
||||
static struct TALER_WIRE_PrepareHandle *
|
||||
template_prepare_wire_transfer (void *cls,
|
||||
const json_t *wire,
|
||||
const struct TALER_Amount *amount,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
TALER_WIRE_PrepareTransactionCallback ptc,
|
||||
void *ptc_cls)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Abort preparation of a wire transfer. For example,
|
||||
* because we are shutting down.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param pth preparation to cancel
|
||||
*/
|
||||
static void
|
||||
template_prepare_wire_transfer_cancel (void *cls,
|
||||
struct TALER_WIRE_PrepareHandle *pth)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Execute a wire transfer.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param buf buffer with the prepared execution details
|
||||
* @param buf_size number of bytes in @a buf
|
||||
* @param cc function to call upon success
|
||||
* @param cc_cls closure for @a cc
|
||||
* @return NULL on error
|
||||
*/
|
||||
static struct TALER_WIRE_ExecuteHandle *
|
||||
template_execute_wire_transfer (void *cls,
|
||||
const char *buf,
|
||||
size_t buf_size,
|
||||
TALER_WIRE_ConfirmationCallback cc,
|
||||
void *cc_cls)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Abort execution of a wire transfer. For example, because we are
|
||||
* shutting down. Note that if an execution is aborted, it may or
|
||||
* may not still succeed. The caller MUST run @e
|
||||
* execute_wire_transfer again for the same request as soon as
|
||||
* possilbe, to ensure that the request either ultimately succeeds
|
||||
* or ultimately fails. Until this has been done, the transaction is
|
||||
* in limbo (i.e. may or may not have been committed).
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param eh execution to cancel
|
||||
*/
|
||||
static void
|
||||
template_execute_wire_transfer_cancel (void *cls,
|
||||
struct TALER_WIRE_ExecuteHandle *eh)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize template-wire subsystem.
|
||||
*
|
||||
* @param cls a configuration instance
|
||||
* @return NULL on error, otherwise a `struct TALER_WIRE_Plugin`
|
||||
*/
|
||||
void *
|
||||
libtaler_plugin_wire_template_init (void *cls)
|
||||
{
|
||||
struct GNUNET_CONFIGURATION_Handle *cfg = cls;
|
||||
struct TemplateClosure *tc;
|
||||
struct TALER_WIRE_Plugin *plugin;
|
||||
|
||||
tc = GNUNET_new (struct TemplateClosure);
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CONFIGURATION_get_value_string (cfg,
|
||||
"wire-template",
|
||||
"bank_uri",
|
||||
&tc->bank_uri))
|
||||
{
|
||||
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
|
||||
"wire-template",
|
||||
"bank_uri");
|
||||
GNUNET_free (tc);
|
||||
return NULL;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CONFIGURATION_get_value_string (cfg,
|
||||
"mint",
|
||||
"CURRENCY",
|
||||
&tc->currency))
|
||||
{
|
||||
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
|
||||
"mint",
|
||||
"CURRENCY");
|
||||
GNUNET_free (tc->bank_uri);
|
||||
GNUNET_free (tc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
plugin = GNUNET_new (struct TALER_WIRE_Plugin);
|
||||
plugin->cls = tc;
|
||||
plugin->amount_round = &template_amount_round;
|
||||
plugin->wire_validate = &template_wire_validate;
|
||||
plugin->prepare_wire_transfer = &template_prepare_wire_transfer;
|
||||
plugin->prepare_wire_transfer_cancel = &template_prepare_wire_transfer_cancel;
|
||||
plugin->execute_wire_transfer = &template_execute_wire_transfer;
|
||||
plugin->execute_wire_transfer_cancel = &template_execute_wire_transfer_cancel;
|
||||
return plugin;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shutdown Template wire subsystem.
|
||||
*
|
||||
* @param cls a `struct TALER_WIRE_Plugin`
|
||||
* @return NULL (always)
|
||||
*/
|
||||
void *
|
||||
libtaler_plugin_wire_template_done (void *cls)
|
||||
{
|
||||
struct TALER_WIRE_Plugin *plugin = cls;
|
||||
struct TemplateClosure *tc = plugin->cls;
|
||||
|
||||
GNUNET_free (tc->bank_uri);
|
||||
GNUNET_free (tc->currency);
|
||||
GNUNET_free (tc);
|
||||
GNUNET_free (plugin);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* end of plugin_wire_template.c */
|
581
src/wire/plugin_wire_test.c
Normal file
581
src/wire/plugin_wire_test.c
Normal file
@ -0,0 +1,581 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is 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 plugin_wire_test.c
|
||||
* @brief plugin for the "test" wire method
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_wire_plugin.h"
|
||||
#include "taler_bank_service.h"
|
||||
|
||||
/* only for HTTP status codes */
|
||||
#include <microhttpd.h>
|
||||
|
||||
/**
|
||||
* Type of the "cls" argument given to each of the functions in
|
||||
* our API.
|
||||
*/
|
||||
struct TestClosure
|
||||
{
|
||||
|
||||
/**
|
||||
* Handle to the bank for sending funds to the bank.
|
||||
*/
|
||||
struct TALER_BANK_Context *bank;
|
||||
|
||||
/**
|
||||
* Which currency do we support?
|
||||
*/
|
||||
char *currency;
|
||||
|
||||
/**
|
||||
* Handle to the bank task, or NULL.
|
||||
*/
|
||||
struct GNUNET_SCHEDULER_Task *bt;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handle returned by #test_prepare_wire_transfer.
|
||||
*/
|
||||
struct TALER_WIRE_PrepareHandle
|
||||
{
|
||||
|
||||
/**
|
||||
* Task we use for async execution.
|
||||
*/
|
||||
struct GNUNET_SCHEDULER_Task *task;
|
||||
|
||||
/**
|
||||
* Test closure we run in.
|
||||
*/
|
||||
struct TestClosure *tc;
|
||||
|
||||
/**
|
||||
* Wire data for the transfer.
|
||||
*/
|
||||
json_t *wire;
|
||||
|
||||
/**
|
||||
* Function to call with the serialized data.
|
||||
*/
|
||||
TALER_WIRE_PrepareTransactionCallback ptc;
|
||||
|
||||
/**
|
||||
* Closure for @e ptc.
|
||||
*/
|
||||
void *ptc_cls;
|
||||
|
||||
/**
|
||||
* Amount to transfer.
|
||||
*/
|
||||
struct TALER_Amount amount;
|
||||
|
||||
/**
|
||||
* Subject of the wire transfer.
|
||||
*/
|
||||
struct TALER_WireTransferIdentifierRawP wtid;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handle returned by #test_execute_wire_transfer.
|
||||
*/
|
||||
struct TALER_WIRE_ExecuteHandle
|
||||
{
|
||||
|
||||
/**
|
||||
* Handle to the HTTP request to the bank.
|
||||
*/
|
||||
struct TALER_BANK_AdminAddIncomingHandle *aaih;
|
||||
|
||||
/**
|
||||
* Function to call with the result.
|
||||
*/
|
||||
TALER_WIRE_ConfirmationCallback cc;
|
||||
|
||||
/**
|
||||
* Closure for @e cc.
|
||||
*/
|
||||
void *cc_cls;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Task that runs the bank's context's event loop with the GNUnet
|
||||
* scheduler.
|
||||
*
|
||||
* @param cls our `struct TestClosure`
|
||||
* @param tc scheduler context (unused)
|
||||
*/
|
||||
static void
|
||||
context_task (void *cls,
|
||||
const struct GNUNET_SCHEDULER_TaskContext *sct)
|
||||
{
|
||||
struct TestClosure *tc = cls;
|
||||
long timeout;
|
||||
int max_fd;
|
||||
fd_set read_fd_set;
|
||||
fd_set write_fd_set;
|
||||
fd_set except_fd_set;
|
||||
struct GNUNET_NETWORK_FDSet *rs;
|
||||
struct GNUNET_NETWORK_FDSet *ws;
|
||||
struct GNUNET_TIME_Relative delay;
|
||||
|
||||
tc->bt = NULL;
|
||||
TALER_BANK_perform (tc->bank);
|
||||
max_fd = -1;
|
||||
timeout = -1;
|
||||
FD_ZERO (&read_fd_set);
|
||||
FD_ZERO (&write_fd_set);
|
||||
FD_ZERO (&except_fd_set);
|
||||
TALER_BANK_get_select_info (tc->bank,
|
||||
&read_fd_set,
|
||||
&write_fd_set,
|
||||
&except_fd_set,
|
||||
&max_fd,
|
||||
&timeout);
|
||||
if (timeout >= 0)
|
||||
delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
|
||||
timeout);
|
||||
else
|
||||
delay = GNUNET_TIME_UNIT_FOREVER_REL;
|
||||
rs = GNUNET_NETWORK_fdset_create ();
|
||||
GNUNET_NETWORK_fdset_copy_native (rs,
|
||||
&read_fd_set,
|
||||
max_fd + 1);
|
||||
ws = GNUNET_NETWORK_fdset_create ();
|
||||
GNUNET_NETWORK_fdset_copy_native (ws,
|
||||
&write_fd_set,
|
||||
max_fd + 1);
|
||||
tc->bt = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
|
||||
delay,
|
||||
rs,
|
||||
ws,
|
||||
&context_task,
|
||||
cls);
|
||||
GNUNET_NETWORK_fdset_destroy (rs);
|
||||
GNUNET_NETWORK_fdset_destroy (ws);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run the bank task now.
|
||||
*
|
||||
* @param tc context for which we should initiate running the task
|
||||
*/
|
||||
static void
|
||||
run_bt (struct TestClosure *tc)
|
||||
{
|
||||
if (NULL != tc->bt)
|
||||
GNUNET_SCHEDULER_cancel (tc->bt);
|
||||
tc->bt = GNUNET_SCHEDULER_add_now (&context_task,
|
||||
tc);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Round amount DOWN to the amount that can be transferred via the wire
|
||||
* method. For example, Taler may support 0.000001 EUR as a unit of
|
||||
* payment, but SEPA only supports 0.01 EUR. This function would
|
||||
* round 0.125 EUR to 0.12 EUR in this case.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param[in,out] amount amount to round down
|
||||
* @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary,
|
||||
* #GNUNET_SYSERR if the amount or currency was invalid
|
||||
*/
|
||||
static int
|
||||
test_amount_round (void *cls,
|
||||
struct TALER_Amount *amount)
|
||||
{
|
||||
struct TestClosure *tc = cls;
|
||||
uint32_t delta;
|
||||
|
||||
if (0 != strcasecmp (amount->currency,
|
||||
tc->currency))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
/* 'test' method supports 1/100 of the unit currency, i.e. 0.01 CUR */
|
||||
delta = amount->fraction % (TALER_AMOUNT_FRAC_BASE / 100);
|
||||
if (0 == delta)
|
||||
return GNUNET_NO;
|
||||
amount->fraction -= delta;
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if the given wire format JSON object is correctly formatted
|
||||
*
|
||||
* @param wire the JSON wire format object
|
||||
* @return #GNUNET_YES if correctly formatted; #GNUNET_NO if not
|
||||
*/
|
||||
static int
|
||||
test_wire_validate (const json_t *wire)
|
||||
{
|
||||
GNUNET_break (0); /* FIXME: we still need to define the
|
||||
proper wire format for 'test' */
|
||||
return GNUNET_YES;
|
||||
}
|
||||
|
||||
|
||||
GNUNET_NETWORK_STRUCT_BEGIN
|
||||
/**
|
||||
* Format we used for serialized transaction data.
|
||||
*/
|
||||
struct BufFormatP
|
||||
{
|
||||
|
||||
/**
|
||||
* The wire transfer identifier.
|
||||
*/
|
||||
struct TALER_WireTransferIdentifierRawP wtid;
|
||||
|
||||
/**
|
||||
* The amount.
|
||||
*/
|
||||
struct TALER_AmountNBO amount;
|
||||
|
||||
/* followed by serialized 'wire' JSON data */
|
||||
|
||||
};
|
||||
GNUNET_NETWORK_STRUCT_END
|
||||
|
||||
|
||||
/**
|
||||
* Prepare for exeuction of a wire transfer. Calls the
|
||||
* callback with the serialized state.
|
||||
*
|
||||
* @param cls the `struct TALER_WIRE_PrepareHandle`
|
||||
* @param sct unused
|
||||
*/
|
||||
static void
|
||||
do_prepare (void *cls,
|
||||
const struct GNUNET_SCHEDULER_TaskContext *sct)
|
||||
{
|
||||
struct TALER_WIRE_PrepareHandle *pth = cls;
|
||||
char *wire_enc;
|
||||
size_t len;
|
||||
struct BufFormatP bf;
|
||||
|
||||
pth->task = NULL;
|
||||
/* serialize the state into a 'buf' */
|
||||
wire_enc = json_dumps (pth->wire,
|
||||
JSON_COMPACT | JSON_SORT_KEYS);
|
||||
if (NULL == wire_enc)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
pth->ptc (pth->ptc_cls,
|
||||
NULL,
|
||||
0);
|
||||
GNUNET_free (pth);
|
||||
return;
|
||||
}
|
||||
len = strlen (wire_enc) + 1;
|
||||
bf.wtid = pth->wtid;
|
||||
TALER_amount_hton (&bf.amount,
|
||||
&pth->amount);
|
||||
{
|
||||
char buf[sizeof (struct BufFormatP) + len];
|
||||
|
||||
memcpy (buf,
|
||||
&bf,
|
||||
sizeof (struct BufFormatP));
|
||||
memcpy (&buf[sizeof (struct BufFormatP)],
|
||||
wire_enc,
|
||||
len);
|
||||
|
||||
/* finally give the state back */
|
||||
pth->ptc (pth->ptc_cls,
|
||||
buf,
|
||||
sizeof (buf));
|
||||
}
|
||||
free (wire_enc); /* not using GNUNET_free(),
|
||||
as this one is allocated by libjansson */
|
||||
GNUNET_free (pth);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepare for exeuction of a wire transfer. Note that we should call
|
||||
* @a ptc asynchronously (as that is what the API requires, because
|
||||
* some transfer methods need it). So while we could immediately call
|
||||
* @a ptc, we first bundle up all the data and schedule a task to do
|
||||
* the work.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param wire valid wire account information
|
||||
* @param amount amount to transfer, already rounded
|
||||
* @param wtid wire transfer identifier to use
|
||||
* @param ptc function to call with the prepared data to persist
|
||||
* @param ptc_cls closure for @a ptc
|
||||
* @return NULL on failure
|
||||
*/
|
||||
static struct TALER_WIRE_PrepareHandle *
|
||||
test_prepare_wire_transfer (void *cls,
|
||||
const json_t *wire,
|
||||
const struct TALER_Amount *amount,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
TALER_WIRE_PrepareTransactionCallback ptc,
|
||||
void *ptc_cls)
|
||||
{
|
||||
struct TestClosure *tc = cls;
|
||||
struct TALER_WIRE_PrepareHandle *pth;
|
||||
|
||||
if (GNUNET_YES !=
|
||||
test_wire_validate (wire))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return NULL;
|
||||
}
|
||||
pth = GNUNET_new (struct TALER_WIRE_PrepareHandle);
|
||||
pth->tc = tc;
|
||||
pth->wire = (json_t *) wire;
|
||||
json_incref (pth->wire);
|
||||
pth->wtid = *wtid;
|
||||
pth->ptc = ptc;
|
||||
pth->ptc_cls = ptc_cls;
|
||||
pth->amount = *amount;
|
||||
pth->task = GNUNET_SCHEDULER_add_now (&do_prepare,
|
||||
pth);
|
||||
return pth;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Abort preparation of a wire transfer. For example,
|
||||
* because we are shutting down.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param pth preparation to cancel
|
||||
*/
|
||||
static void
|
||||
test_prepare_wire_transfer_cancel (void *cls,
|
||||
struct TALER_WIRE_PrepareHandle *pth)
|
||||
{
|
||||
GNUNET_SCHEDULER_cancel (pth->task);
|
||||
json_decref (pth->wire);
|
||||
GNUNET_free (pth);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called with the result of submitting information about an incoming
|
||||
* transaction to a bank.
|
||||
*
|
||||
* @param cls closure with the `struct TALER_WIRE_ExecuteHandle`
|
||||
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
|
||||
* 0 if the bank's reply is bogus (fails to follow the protocol)
|
||||
*/
|
||||
static void
|
||||
execute_cb (void *cls,
|
||||
unsigned int http_status)
|
||||
{
|
||||
struct TALER_WIRE_ExecuteHandle *eh = cls;
|
||||
char s[14];
|
||||
|
||||
eh->aaih = NULL;
|
||||
GNUNET_snprintf (s,
|
||||
sizeof (s),
|
||||
"%u",
|
||||
http_status);
|
||||
eh->cc (eh->cc_cls,
|
||||
(MHD_HTTP_OK == http_status) ? GNUNET_OK : GNUNET_SYSERR,
|
||||
(MHD_HTTP_OK == http_status) ? NULL : s);
|
||||
GNUNET_free (eh);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Execute a wire transfer.
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param buf buffer with the prepared execution details
|
||||
* @param buf_size number of bytes in @a buf
|
||||
* @param cc function to call upon success
|
||||
* @param cc_cls closure for @a cc
|
||||
* @return NULL on error
|
||||
*/
|
||||
static struct TALER_WIRE_ExecuteHandle *
|
||||
test_execute_wire_transfer (void *cls,
|
||||
const char *buf,
|
||||
size_t buf_size,
|
||||
TALER_WIRE_ConfirmationCallback cc,
|
||||
void *cc_cls)
|
||||
{
|
||||
struct TestClosure *tc = cls;
|
||||
struct TALER_WIRE_ExecuteHandle *eh;
|
||||
json_t *wire;
|
||||
struct TALER_Amount amount;
|
||||
struct BufFormatP bf;
|
||||
|
||||
if ( (buf_size <= sizeof (struct BufFormatP)) ||
|
||||
('\0' != buf[buf_size -1]) )
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return NULL;
|
||||
}
|
||||
memcpy (&bf,
|
||||
buf,
|
||||
sizeof (bf));
|
||||
TALER_amount_ntoh (&amount,
|
||||
&bf.amount);
|
||||
wire = json_loads (&buf[sizeof (struct BufFormatP)],
|
||||
JSON_REJECT_DUPLICATES,
|
||||
NULL);
|
||||
if (NULL == wire)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GNUNET_assert (GNUNET_YES ==
|
||||
test_wire_validate (wire));
|
||||
eh = GNUNET_new (struct TALER_WIRE_ExecuteHandle);
|
||||
eh->cc = cc;
|
||||
eh->cc_cls = cc_cls;
|
||||
eh->aaih = TALER_BANK_admin_add_incoming (tc->bank,
|
||||
&bf.wtid,
|
||||
&amount,
|
||||
wire,
|
||||
&execute_cb,
|
||||
eh);
|
||||
json_decref (wire);
|
||||
if (NULL == eh->aaih)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_free (eh);
|
||||
return NULL;
|
||||
}
|
||||
run_bt (tc);
|
||||
return eh;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Abort execution of a wire transfer. For example, because we are
|
||||
* shutting down. Note that if an execution is aborted, it may or
|
||||
* may not still succeed. The caller MUST run @e
|
||||
* execute_wire_transfer again for the same request as soon as
|
||||
* possilbe, to ensure that the request either ultimately succeeds
|
||||
* or ultimately fails. Until this has been done, the transaction is
|
||||
* in limbo (i.e. may or may not have been committed).
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param eh execution to cancel
|
||||
*/
|
||||
static void
|
||||
test_execute_wire_transfer_cancel (void *cls,
|
||||
struct TALER_WIRE_ExecuteHandle *eh)
|
||||
{
|
||||
TALER_BANK_admin_add_incoming_cancel (eh->aaih);
|
||||
GNUNET_free (eh);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize test-wire subsystem.
|
||||
*
|
||||
* @param cls a configuration instance
|
||||
* @return NULL on error, otherwise a `struct TALER_WIRE_Plugin`
|
||||
*/
|
||||
void *
|
||||
libtaler_plugin_wire_test_init (void *cls)
|
||||
{
|
||||
struct GNUNET_CONFIGURATION_Handle *cfg = cls;
|
||||
struct TestClosure *tc;
|
||||
struct TALER_WIRE_Plugin *plugin;
|
||||
char *uri;
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CONFIGURATION_get_value_string (cfg,
|
||||
"wire-test",
|
||||
"bank_uri",
|
||||
&uri))
|
||||
{
|
||||
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
|
||||
"wire-test",
|
||||
"bank_uri");
|
||||
return NULL;
|
||||
}
|
||||
tc = GNUNET_new (struct TestClosure);
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CONFIGURATION_get_value_string (cfg,
|
||||
"mint",
|
||||
"CURRENCY",
|
||||
&tc->currency))
|
||||
{
|
||||
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
|
||||
"mint",
|
||||
"CURRENCY");
|
||||
GNUNET_free (uri);
|
||||
GNUNET_free (tc);
|
||||
return NULL;
|
||||
}
|
||||
tc->bank = TALER_BANK_init (uri);
|
||||
if (NULL == tc->bank)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
GNUNET_free (tc->currency);
|
||||
GNUNET_free (tc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
plugin = GNUNET_new (struct TALER_WIRE_Plugin);
|
||||
plugin->cls = tc;
|
||||
plugin->amount_round = &test_amount_round;
|
||||
plugin->wire_validate = &test_wire_validate;
|
||||
plugin->prepare_wire_transfer = &test_prepare_wire_transfer;
|
||||
plugin->prepare_wire_transfer_cancel = &test_prepare_wire_transfer_cancel;
|
||||
plugin->execute_wire_transfer = &test_execute_wire_transfer;
|
||||
plugin->execute_wire_transfer_cancel = &test_execute_wire_transfer_cancel;
|
||||
return plugin;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shutdown Test wire subsystem.
|
||||
*
|
||||
* @param cls a `struct TALER_WIRE_Plugin`
|
||||
* @return NULL (always)
|
||||
*/
|
||||
void *
|
||||
libtaler_plugin_wire_test_done (void *cls)
|
||||
{
|
||||
struct TALER_WIRE_Plugin *plugin = cls;
|
||||
struct TestClosure *tc = plugin->cls;
|
||||
|
||||
if (NULL != tc->bt)
|
||||
{
|
||||
GNUNET_SCHEDULER_cancel (tc->bt);
|
||||
tc->bt = NULL;
|
||||
}
|
||||
TALER_BANK_fini (tc->bank);
|
||||
GNUNET_free (tc->currency);
|
||||
GNUNET_free (tc);
|
||||
GNUNET_free (plugin);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* end of plugin_wire_test.c */
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
(C) 2015, 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
@ -15,14 +15,15 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file util/test_wireformats.c
|
||||
* @brief Tests for JSON validations
|
||||
* @file wire/test_sepa_wireformat.c
|
||||
* @brief Tests for JSON SEPA format validation
|
||||
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#include "taler_util.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_wire_lib.h"
|
||||
|
||||
|
||||
/* Valid SEPA data */
|
||||
static const char * const valid_wire_str =
|
||||
@ -65,33 +66,39 @@ int
|
||||
main(int argc,
|
||||
const char *const argv[])
|
||||
{
|
||||
const char *unsupported[] = {
|
||||
"unsupported",
|
||||
NULL
|
||||
};
|
||||
const char *sepa[] = {
|
||||
"SEPA",
|
||||
NULL
|
||||
};
|
||||
json_t *wire;
|
||||
json_error_t error;
|
||||
int ret;
|
||||
struct GNUNET_CONFIGURATION_Handle *cfg;
|
||||
struct TALER_WIRE_Plugin *plugin;
|
||||
|
||||
GNUNET_log_setup ("test-json-validations", "WARNING", NULL);
|
||||
GNUNET_log_setup ("test-sepa-wireformats",
|
||||
"WARNING",
|
||||
NULL);
|
||||
cfg = GNUNET_CONFIGURATION_create ();
|
||||
GNUNET_CONFIGURATION_set_value_string (cfg,
|
||||
"mint",
|
||||
"currency",
|
||||
"EUR");
|
||||
plugin = TALER_WIRE_plugin_load (cfg,
|
||||
"sepa");
|
||||
GNUNET_assert (NULL != plugin);
|
||||
(void) memset(&error, 0, sizeof(error));
|
||||
GNUNET_assert (NULL != (wire = json_loads (unsupported_wire_str, 0, NULL)));
|
||||
GNUNET_assert (1 != TALER_json_validate_wireformat (unsupported, wire));
|
||||
GNUNET_assert (GNUNET_YES != plugin->wire_validate (wire));
|
||||
json_decref (wire);
|
||||
GNUNET_assert (NULL != (wire = json_loads (invalid_wire_str, 0, NULL)));
|
||||
GNUNET_assert (1 != TALER_json_validate_wireformat (sepa, wire));
|
||||
GNUNET_assert (GNUNET_NO == plugin->wire_validate (wire));
|
||||
json_decref (wire);
|
||||
GNUNET_assert (NULL != (wire = json_loads (invalid_wire_str2, 0, NULL)));
|
||||
GNUNET_assert (1 != TALER_json_validate_wireformat (sepa, wire));
|
||||
GNUNET_assert (GNUNET_NO == plugin->wire_validate (wire));
|
||||
json_decref (wire);
|
||||
GNUNET_assert (NULL != (wire = json_loads (valid_wire_str, 0, &error)));
|
||||
ret = TALER_json_validate_wireformat (sepa, wire);
|
||||
ret = plugin->wire_validate (wire);
|
||||
json_decref (wire);
|
||||
if (1 == ret)
|
||||
return 0;
|
||||
return 1;
|
||||
TALER_WIRE_plugin_unload (plugin);
|
||||
GNUNET_CONFIGURATION_destroy (cfg);
|
||||
if (GNUNET_NO == ret)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
72
src/wire/wire.c
Normal file
72
src/wire/wire.c
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2015, 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is 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 wire/wire.c
|
||||
* @brief Functions for loading wire plugins
|
||||
* @author Christian Grothoff <christian@grothoff.org>
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_util.h"
|
||||
#include "taler_wire_lib.h"
|
||||
|
||||
/**
|
||||
* Load a WIRE plugin.
|
||||
*
|
||||
* @param cfg configuration to use
|
||||
* @param plugin_name name of the plugin to load
|
||||
* @return #GNUNET_OK on success
|
||||
*/
|
||||
struct TALER_WIRE_Plugin *
|
||||
TALER_WIRE_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg,
|
||||
const char *plugin_name)
|
||||
{
|
||||
char *lib_name;
|
||||
struct TALER_WIRE_Plugin *plugin;
|
||||
|
||||
(void) GNUNET_asprintf (&lib_name,
|
||||
"libtaler_plugin_wire_%s",
|
||||
plugin_name);
|
||||
plugin = GNUNET_PLUGIN_load (lib_name,
|
||||
(void *) cfg);
|
||||
if (NULL != plugin)
|
||||
plugin->library_name = lib_name;
|
||||
else
|
||||
GNUNET_free (lib_name);
|
||||
return plugin;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unload a WIRE plugin.
|
||||
*
|
||||
* @param plugin the plugin to unload
|
||||
*/
|
||||
void
|
||||
TALER_WIRE_plugin_unload (struct TALER_WIRE_Plugin *plugin)
|
||||
{
|
||||
char *lib_name;
|
||||
|
||||
if (NULL == plugin)
|
||||
return;
|
||||
lib_name = plugin->library_name;
|
||||
GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name,
|
||||
plugin));
|
||||
GNUNET_free (lib_name);
|
||||
}
|
||||
|
||||
|
||||
/* end of wire.c */
|
Loading…
Reference in New Issue
Block a user