diff options
| author | Christian Grothoff <christian@grothoff.org> | 2015-06-21 00:00:33 +0200 | 
|---|---|---|
| committer | Christian Grothoff <christian@grothoff.org> | 2015-06-21 00:00:33 +0200 | 
| commit | ed888ca1d8ed305f6a7a5bf7fdb5a6b19fc730fe (patch) | |
| tree | ac9c6ea9cf729bef8f3f950ca432ac5ed96fc75c /src/mint-lib | |
| parent | 6e070416c3c04a6277fc890125150b027a5fdf7a (diff) | |
starting with skeleton for /deposit implementation
Diffstat (limited to 'src/mint-lib')
| -rw-r--r-- | src/mint-lib/mint_api.c | 175 | ||||
| -rw-r--r-- | src/mint-lib/mint_api_context.c | 3 | ||||
| -rw-r--r-- | src/mint-lib/mint_api_context.h | 6 | ||||
| -rw-r--r-- | src/mint-lib/mint_api_deposit.c | 310 | ||||
| -rw-r--r-- | src/mint-lib/mint_api_handle.c | 5 | 
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 23d591ff..00000000 --- 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 7f70d092..2daba89e 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 b64f007b..235c32bd 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 00000000..87a12448 --- /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 2f348d47..abd4d0db 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)) )  | 
