aboutsummaryrefslogtreecommitdiff
path: root/src/mint-lib
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-06-21 00:00:33 +0200
committerChristian Grothoff <christian@grothoff.org>2015-06-21 00:00:33 +0200
commited888ca1d8ed305f6a7a5bf7fdb5a6b19fc730fe (patch)
treeac9c6ea9cf729bef8f3f950ca432ac5ed96fc75c /src/mint-lib
parent6e070416c3c04a6277fc890125150b027a5fdf7a (diff)
starting with skeleton for /deposit implementation
Diffstat (limited to 'src/mint-lib')
-rw-r--r--src/mint-lib/mint_api.c175
-rw-r--r--src/mint-lib/mint_api_context.c3
-rw-r--r--src/mint-lib/mint_api_context.h6
-rw-r--r--src/mint-lib/mint_api_deposit.c310
-rw-r--r--src/mint-lib/mint_api_handle.c5
5 files changed, 321 insertions, 178 deletions
diff --git a/src/mint-lib/mint_api.c b/src/mint-lib/mint_api.c
deleted file mode 100644
index 23d591ff1..000000000
--- a/src/mint-lib/mint_api.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mint-lib/mint_api.c
- * @brief Implementation of the client interface to mint's HTTP API
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- */
-#include "platform.h"
-#include <curl/curl.h>
-#include <jansson.h>
-#include <gnunet/gnunet_util_lib.h>
-#include "taler_mint_service.h"
-#include "taler_signatures.h"
-
-
-// leftovers follow...
-
-/**
- * Log error related to CURL operations.
- *
- * @param type log level
- * @param function which function failed to run
- * @param code what was the curl error code
- */
-#define CURL_STRERROR(type, function, code) \
- GNUNET_log (type, "Curl function `%s' has failed at `%s:%d' with error: %s", \
- function, __FILE__, __LINE__, curl_easy_strerror (code));
-
-
-/**
- * Print JSON parsing related error information
- */
-#define JSON_WARN(error) \
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \
- "JSON parsing failed at %s:%u: %s (%s)", \
- __FILE__, __LINE__, error.text, error.source)
-
-/**
- * Failsafe flag. Raised if our constructor fails to initialize
- * the Curl library.
- */
-static int TALER_MINT_curl_fail;
-
-/**
- * A handle to submit a deposit permission and get its status
- */
-struct TALER_MINT_DepositHandle
-{
- /**
- *The connection to mint this request handle will use
- */
- struct TALER_MINT_Handle *mint;
-
- /**
- * The url for this handle
- */
- char *url;
-
- TALER_MINT_DepositResultCallback cb;
-
- void *cb_cls;
-
- char *json_enc;
-
- struct curl_slist *headers;
-
-};
-
-
-
-#define EXITIF(cond) \
- do { \
- if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
- } while (0)
-
-
-
-static int
-parse_deposit_response (void *buf, size_t size, int *r_status, json_t **r_obj)
-{
- json_t *obj;
- const char *status_str;
- json_error_t error;
-
- status_str = NULL;
- obj = NULL;
- obj = json_loadb (buf, size,
- JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK, &error);
- if (NULL == obj)
- {
- JSON_WARN (error);
- return GNUNET_SYSERR;
- }
- EXITIF (-1 == json_unpack (obj, "{s:s}", "status", &status_str));
- TALER_LOG_DEBUG ("Received deposit response: %s from mint\n", status_str);
- if (0 == strcmp ("DEPOSIT_OK", status_str))
- *r_status = 1;
- else if (0 == strcmp ("DEPOSIT_QUEUED", status_str))
- *r_status = 2;
- else
- *r_status = 0;
- *r_obj = obj;
-
- return GNUNET_OK;
- EXITIF_exit:
- json_decref (obj);
- return GNUNET_SYSERR;
-}
-
-#undef EXITIF
-
-
-/**
- * Submit a deposit permission to the mint and get the mint's response
- *
- * @param mint the mint handle
- * @param cb the callback to call when a reply for this request is available
- * @param cb_cls closure for the above callback
- * @param deposit_obj the deposit permission received from the customer along
- * with the wireformat JSON object
- * @return a handle for this request; NULL if the JSON object could not be
- * parsed or is of incorrect format or any other error. In this case,
- * the callback is not called.
- */
-struct TALER_MINT_DepositHandle *
-TALER_MINT_deposit_submit_json (struct TALER_MINT_Handle *mint,
- TALER_MINT_DepositResultCallback cb,
- void *cb_cls,
- json_t *deposit_obj)
-{
- struct TALER_MINT_DepositHandle *dh;
-
- GNUNET_assert (REQUEST_TYPE_NONE == mint->req_type);
- dh = GNUNET_new (struct TALER_MINT_DepositHandle);
- dh->mint = mint;
- mint->req_type = REQUEST_TYPE_DEPOSIT;
- mint->req.deposit = dh;
- dh->cb = cb;
- dh->cb_cls = cb_cls;
- GNUNET_asprintf (&dh->url, "http://%s:%hu/deposit", mint->hostname, mint->port);
- GNUNET_assert (NULL != (dh->json_enc = json_dumps (deposit_obj, JSON_COMPACT)));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (mint->curl, CURLOPT_URL, dh->url));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (mint->curl, CURLOPT_POSTFIELDS,
- dh->json_enc));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (mint->curl, CURLOPT_POSTFIELDSIZE,
- strlen (dh->json_enc)));
- GNUNET_assert (NULL != (dh->headers =
- curl_slist_append (dh->headers, "Content-Type: application/json")));
- GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (mint->curl, CURLOPT_HTTPHEADER, dh->headers));
- if (GNUNET_NO == mint->connected)
- mint_connect (mint);
- perform_now (mint->ctx);
- return dh;
-}
-
-
-/* end of mint_api.c */
diff --git a/src/mint-lib/mint_api_context.c b/src/mint-lib/mint_api_context.c
index 7f70d092a..2daba89e7 100644
--- a/src/mint-lib/mint_api_context.c
+++ b/src/mint-lib/mint_api_context.c
@@ -261,7 +261,8 @@ TALER_MINT_perform (struct TALER_MINT_Context *ctx)
CURLINFO_PRIVATE,
(char *) &job));
GNUNET_assert (job->ctx == ctx);
- job->jcc (job->jcc_cls);
+ job->jcc (job->jcc_cls,
+ cmsg->easy_handle);
MAC_job_cancel (job);
}
}
diff --git a/src/mint-lib/mint_api_context.h b/src/mint-lib/mint_api_context.h
index b64f007bc..235c32bd1 100644
--- a/src/mint-lib/mint_api_context.h
+++ b/src/mint-lib/mint_api_context.h
@@ -34,9 +34,13 @@ struct MAC_Job;
/**
* Function to call upon completion of a job.
+ *
+ * @param cls closure
+ * @param eh original easy handle (for inspection)
*/
typedef void
-(*MAC_JobCompletionCallback)(void *cls);
+(*MAC_JobCompletionCallback)(void *cls,
+ CURL *eh);
/**
diff --git a/src/mint-lib/mint_api_deposit.c b/src/mint-lib/mint_api_deposit.c
new file mode 100644
index 000000000..87a12448f
--- /dev/null
+++ b/src/mint-lib/mint_api_deposit.c
@@ -0,0 +1,310 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors)
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file mint-lib/mint_api_deposit.c
+ * @brief Implementation of the /deposit request of the mint's HTTP API
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_mint_service.h"
+#include "taler_signatures.h"
+
+
+/**
+ * @brief A Deposit Handle
+ */
+struct TALER_MINT_DepositHandle
+{
+
+ /**
+ * 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;
+
+ /**
+ * HTTP headers for the request.
+ */
+ struct curl_slist *headers;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_MINT_DepositResultCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * 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;
+
+};
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP /deposit request.
+ *
+ * @param cls the `struct TALER_MINT_DepositHandle`
+ */
+static void
+handle_deposit_finished (void *cls,
+ CURL *eh)
+{
+ struct TALER_MINT_DepositHandle *dh = cls;
+ unsigned int response_code;
+ json_error_t error;
+ json_t *json;
+
+ json = NULL;
+ if (0 == dh->eno)
+ {
+ json = json_loadb (dh->buf,
+ dh->buf_size,
+ JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK,
+ &error);
+ if (NULL == json)
+ {
+ JSON_WARN (error);
+ response_code = 0;
+ }
+ }
+ if (NULL != json)
+ {
+ response_code = 42;
+ }
+ switch (response_code)
+ {
+ /* FIXME: verify json response signatures
+ (and that format matches response_code) */
+ default:
+ /* unexpected response code */
+ GNUNET_break (0);
+ response_code = 0;
+ break;
+ }
+ dh->cb (dh->cb_cls,
+ response_code,
+ json);
+ json_decref (json);
+ TALER_MINT_deposit_cancel (dh);
+}
+
+
+/**
+ * Callback used when downloading the reply to a /deposit request.
+ * Just appends all of the data to the `buf` in the
+ * `struct TALER_MINT_DepositHandle` 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 TALER_MINT_DepositHandle`
+ * @return number of bytes processed from @a bufptr
+ */
+static int
+deposit_download_cb (char *bufptr,
+ size_t size,
+ size_t nitems,
+ void *cls)
+{
+ struct TALER_MINT_DepositHandle *dh = cls;
+ size_t msize;
+ void *buf;
+
+ if (0 == size * nitems)
+ {
+ /* Nothing (left) to do */
+ return 0;
+ }
+ msize = size * nitems;
+ if ( (msize + dh->buf_size) >= GNUNET_MAX_MALLOC_CHECKED)
+ {
+ dh->eno = ENOMEM;
+ return 0; /* signals an error to curl */
+ }
+ dh->buf = GNUNET_realloc (dh->buf,
+ dh->buf_size + msize);
+ buf = dh->buf + dh->buf_size;
+ memcpy (buf, bufptr, msize);
+ dh->buf_size += msize;
+ return msize;
+}
+
+
+/**
+ * Submit a deposit permission to the mint and get the mint's response.
+ * Note that while we return the response verbatim to the caller for
+ * further processing, we do already verify that the response is
+ * well-formed (i.e. that signatures included in the response are all
+ * valid). If the mint's reply is not well-formed, we return an
+ * HTTP status code of zero to @a cb.
+ *
+ * We also verify that the @a coin_sig is valid for this deposit
+ * request, and that the @a ub_sig is a valid signature for @a
+ * coin_pub. Also, the @a mint must be ready to operate (i.e. have
+ * finished processing the /keys reply). If either check fails, we do
+ * NOT initiate the transaction with the mint and instead return NULL.
+ *
+ * @param mint the mint handle; the mint must be ready to operate
+ * @param amount the amount to be deposited
+ * @param wire the merchant’s account details, in a format supported by the mint
+ * @param h_contract hash of the contact of the merchant with the customer (further details are never disclosed to the mint)
+ * @param coin_pub coin’s public key
+ * @param denom_pub denomination key with which the coin is signed
+ * @param ub_sig mint’s unblinded signature of the coin
+ * @param timestamp timestamp when the contract was finalized, must match approximately the current time of the mint
+ * @param transaction_id transaction id for the transaction between merchant and customer
+ * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests)
+ * @param refund_deadline date until which the merchant can issue a refund to the customer via the mint (can be zero if refunds are not allowed)
+ * @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s private key.
+ * @param cb the callback to call when a reply for this request is available
+ * @param cb_cls closure for the above callback
+ * @return a handle for this request; NULL if the inputs are invalid (i.e.
+ * signatures fail to verify). In this case, the callback is not called.
+ */
+struct TALER_MINT_DepositHandle *
+TALER_MINT_deposit (struct TALER_MINT_Handle *mint,
+ const struct TALER_Amount *amount,
+ json_t *wire_details,
+ const struct GNUNET_HashCode *h_contract,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_DenominationSignature *denom_sig,
+ const struct TALER_DenominationPublicKey *denom_pub,
+ struct GNUNET_TIME_Absolute timestamp,
+ uint64_t transaction_id,
+ const struct TALER_MerchantPublicKeyP *merchant_pub,
+ struct GNUNET_TIME_Absolute refund_deadline,
+ const struct TALER_CoinSpendSignatureP *coin_sig,
+ TALER_MINT_DepositResultCallback cb,
+ void *cb_cls)
+{
+ struct TALER_MINT_DepositHandle *dh;
+ struct TALER_MINT_Context *ctx;
+ json_t *deposit_obj;
+ CURL *eh;
+
+ if (GNUNET_YES !=
+ MAH_handle_is_ready (mint))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ GNUNET_break (0); /* FIXME: verify all sigs! */
+
+ deposit_obj = json_new (); /* FIXME: actually build JSON request */
+
+ dh = GNUNET_new (struct TALER_MINT_DepositHandle);
+ dh->mint = mint;
+ dh->cb = cb;
+ dh->cb_cls = cb_cls;
+ dh->url = MAH_path_to_url (mint, "/deposit");
+ eh = curl_easy_init ();
+ /* FIXME: strdup() json_enc? Free deposit_obj! */
+ GNUNET_assert (NULL != (dh->json_enc =
+ json_dumps (deposit_obj,
+ JSON_COMPACT)));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_URL,
+ dh->url));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_POSTFIELDS,
+ dh->json_enc));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_POSTFIELDSIZE,
+ strlen (dh->json_enc)));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (c,
+ CURLOPT_WRITEFUNCTION,
+ &keys_download_cb));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (c,
+ CURLOPT_WRITEDATA,
+ kr));
+ GNUNET_assert (NULL != (dh->headers =
+ curl_slist_append (dh->headers,
+ "Content-Type: application/json")));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_HTTPHEADER,
+ dh->headers));
+ ctx = MAH_handle_to_context (mint);
+ dh->job = MAC_job_add (ctx,
+ eh,
+ &handle_deposit_reply,
+ dh);
+ return dh;
+}
+
+
+/**
+ * Cancel a deposit permission request. This function cannot be used
+ * on a request handle if a response is already served for it.
+ *
+ * @param deposit the deposit permission request handle
+ */
+void
+TALER_MINT_deposit_cancel (struct TALER_MINT_DepositHandle *deposit)
+{
+ MAC_job_cancel (deposit->job);
+ curl_slist_free_all (deposit->headers);
+ GNUNET_free (deposit->url);
+ GNUNET_free (deposit->json_enc);
+ GNUNET_free (deposit);
+}
+
+
+
+/* end of mint_api_deposit.c */
diff --git a/src/mint-lib/mint_api_handle.c b/src/mint-lib/mint_api_handle.c
index 2f348d475..abd4d0db7 100644
--- a/src/mint-lib/mint_api_handle.c
+++ b/src/mint-lib/mint_api_handle.c
@@ -566,13 +566,16 @@ parse_response_keys_get (struct KeysRequest *kr)
* is complete.
*
* @param cls the `struct KeysRequest`
+ * @param eh easy handle of the original request
*/
static void
-keys_completed_cb (void *cls)
+keys_completed_cb (void *cls,
+ CURL *eh)
{
struct KeysRequest *kr = cls;
struct TALER_MINT_Handle *mint = kr->mint;
+ /* FIXME: might want to check response code? */
if ( (0 != kr->eno) ||
(GNUNET_OK !=
parse_response_keys_get (kr)) )