diff options
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/exchange_api_deposit.c | 103 | ||||
| -rw-r--r-- | src/lib/exchange_api_handle.c | 216 | ||||
| -rw-r--r-- | src/lib/exchange_api_handle.h | 55 | 
3 files changed, 293 insertions, 81 deletions
| diff --git a/src/lib/exchange_api_deposit.c b/src/lib/exchange_api_deposit.c index 55b3ca6b..9ff9d97d 100644 --- a/src/lib/exchange_api_deposit.c +++ b/src/lib/exchange_api_deposit.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2014, 2015, 2018 GNUnet e.V. +  Copyright (C) 2014, 2015, 2018, 2019 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 @@ -76,6 +76,16 @@ struct TALER_EXCHANGE_DepositHandle    struct TALER_DepositConfirmationPS depconf;    /** +   * Exchange signature, set for #auditor_cb. +   */ +  struct TALER_ExchangeSignatureP exchange_sig; + +  /** +   * Exchange signing public key, set for #auditor_cb. +   */ +  struct TALER_ExchangePublicKeyP exchange_pub; + +  /**     * Value of the /deposit transaction, including fee.     */    struct TALER_Amount amount_with_fee; @@ -89,21 +99,52 @@ struct TALER_EXCHANGE_DepositHandle  /** - * Signature of functions called with the result from our call to the - * auditor's /deposit-confirmation handler. + * Function called for each auditor to give us a chance to possibly + * launch a deposit confirmation interaction.   *   * @param cls closure - * @param http_status HTTP status code, 200 on success - * @param ec taler protocol error status code, 0 on success - * @param json raw json response + * @param ah handle to the auditor + * @param auditor_pub public key of the auditor + * @return NULL if no deposit confirmation interaction was launched   */ -static void -acc_confirmation_cb (void *cls, -		     unsigned int http_status, -		     enum TALER_ErrorCode ec, -		     const json_t *json) +static struct TEAH_AuditorInteractionEntry * +auditor_cb (void *cls, +            struct TALER_AUDITOR_Handle *ah, +            const struct TALER_AuditorPublicKeyP *auditor_pub)  { -  /* FIXME: clean up state, some logging on errors! */ +  struct TALER_EXCHANGE_DepositHandle *dh = cls; +  const struct TALER_EXCHANGE_Keys *key_state; +  const struct TALER_EXCHANGE_SigningPublicKey *spk; +  struct TALER_Amount amount_without_fee; +  struct TEAH_AuditorInteractionEntry *aie; + +  if (1 /* #5447: replace with "for all auditors, if auditor selected for DC notification... */) +    return NULL; +  key_state = TALER_EXCHANGE_get_keys (dh->exchange); +  spk = TALER_EXCHANGE_get_signing_key_details (key_state, +                                                &dh->exchange_pub); +  GNUNET_assert (NULL != spk); +  TALER_amount_ntoh (&amount_without_fee, +                     &dh->depconf.amount_without_fee); +  aie = GNUNET_new (struct TEAH_AuditorInteractionEntry); +  aie->dch = TALER_AUDITOR_deposit_confirmation (ah, +                                                 &dh->depconf.h_wire, +                                                 &dh->depconf.h_contract_terms, +                                                 GNUNET_TIME_absolute_ntoh (dh->depconf.timestamp), +                                                 GNUNET_TIME_absolute_ntoh (dh->depconf.refund_deadline), +                                                 &amount_without_fee, +                                                 &dh->depconf.coin_pub, +                                                 &dh->depconf.merchant, +                                                 &dh->exchange_pub, +                                                 &dh->exchange_sig, +                                                 &key_state->master_pub, +                                                 spk->valid_from, +                                                 spk->valid_until, +                                                 spk->valid_legal, +                                                 &spk->master_sig, +                                                 &TEAH_acc_confirmation_cb, +                                                 aie); +  return aie;  } @@ -118,7 +159,7 @@ acc_confirmation_cb (void *cls,   * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not   */  static int -verify_deposit_signature_ok (const struct TALER_EXCHANGE_DepositHandle *dh, +verify_deposit_signature_ok (struct TALER_EXCHANGE_DepositHandle *dh,                               const json_t *json,  			     struct TALER_ExchangeSignatureP *exchange_sig,                               struct TALER_ExchangePublicKeyP *exchange_pub) @@ -155,37 +196,11 @@ verify_deposit_signature_ok (const struct TALER_EXCHANGE_DepositHandle *dh,      GNUNET_break_op (0);      return GNUNET_SYSERR;    } -  if (0 /* #5447: replace with "for all auditors, if auditor selected for DC notification... */) -  { -    struct TALER_AUDITOR_DepositConfirmationHandle *dch; -    const struct TALER_EXCHANGE_SigningPublicKey *spk; -    struct TALER_Amount amount_without_fee; - -    spk = TALER_EXCHANGE_get_signing_key_details (key_state, -						  exchange_pub); -    GNUNET_assert (NULL != spk); -    TALER_amount_ntoh (&amount_without_fee, -		       &dh->depconf.amount_without_fee); -    dch = TALER_AUDITOR_deposit_confirmation (NULL /* FIXME: auditor */, -					      &dh->depconf.h_wire, -					      &dh->depconf.h_contract_terms, -					      GNUNET_TIME_absolute_ntoh (dh->depconf.timestamp), -					      GNUNET_TIME_absolute_ntoh (dh->depconf.refund_deadline), -					      &amount_without_fee, -					      &dh->depconf.coin_pub, -					      &dh->depconf.merchant, -					      exchange_pub, -					      exchange_sig, -					      &key_state->master_pub, -					      spk->valid_from, -					      spk->valid_until, -					      spk->valid_legal, -					      &spk->master_sig, -					      &acc_confirmation_cb, -					      NULL /* FIXME: context! */); -  } - - +  dh->exchange_sig = *exchange_sig; +  dh->exchange_pub = *exchange_pub; +  TEAH_get_auditors_for_dc (dh->exchange, +                            &auditor_cb, +                            dh);    return GNUNET_OK;  } diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c index 9743b1f0..8eedfd60 100644 --- a/src/lib/exchange_api_handle.c +++ b/src/lib/exchange_api_handle.c @@ -92,46 +92,24 @@ struct KeysRequest;  /** - * Entry in list of ongoing interactions with an auditor. - */ -struct AuditorInteractionEntry -{ -  /** -   * DLL entry. -   */ -  struct AuditorInteractionEntry *next; - -  /** -   * DLL entry. -   */ -  struct AuditorInteractionEntry *prev; - -  /** -   * Interaction state. -   */ -  struct TALER_AUDITOR_DepositConfirmationHandle *dch; -}; - - -/**   * Entry in DLL of auditors used by an exchange.   */ -struct AuditorListEntry +struct TEAH_AuditorListEntry  {    /**     * Next pointer of DLL.     */ -  struct AuditorListEntry *next; +  struct TEAH_AuditorListEntry *next;    /**     * Prev pointer of DLL.     */ -  struct AuditorListEntry *prev; +  struct TEAH_AuditorListEntry *prev;    /**     * Base URL of the auditor.     */ -  const char *auditor_url; +  char *auditor_url;    /**     * Handle to the auditor. @@ -141,12 +119,12 @@ struct AuditorListEntry    /**     * Head of DLL of interactions with this auditor.     */ -  struct AuditorInteractionEntry *ai_head; +  struct TEAH_AuditorInteractionEntry *ai_head;    /**     * Tail of DLL of interactions with this auditor.     */ -  struct AuditorInteractionEntry *ai_tail; +  struct TEAH_AuditorInteractionEntry *ai_tail;    /**     * Public key of the auditor. @@ -208,12 +186,12 @@ struct TALER_EXCHANGE_Handle    /**     * Head of DLL of auditors of this exchange.     */ -  struct AuditorListEntry *auditors_head; +  struct TEAH_AuditorListEntry *auditors_head;    /**     * Tail of DLL of auditors of this exchange.     */ -  struct AuditorListEntry *auditors_tail; +  struct TEAH_AuditorListEntry *auditors_tail;    /**     * Key data of the exchange, only valid if @@ -271,6 +249,39 @@ struct KeysRequest  /** + * Signature of functions called with the result from our call to the + * auditor's /deposit-confirmation handler. + * + * @param cls closure of type `struct TEAH_AuditorInteractionEntry *` + * @param http_status HTTP status code, 200 on success + * @param ec taler protocol error status code, 0 on success + * @param json raw json response + */ +void +TEAH_acc_confirmation_cb (void *cls, +                          unsigned int http_status, +                          enum TALER_ErrorCode ec, +                          const json_t *json) +{ +  struct TEAH_AuditorInteractionEntry *aie = cls; +  struct TEAH_AuditorListEntry *ale = aie->ale; + +  if (MHD_HTTP_OK != http_status) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                _("Failed to submit deposit confirmation to auditor `%s' with HTTP status %d (EC: %d). This is acceptable if it does not happen often.\n"), +                ale->auditor_url, +                http_status, +                (int) ec); +  } +  GNUNET_CONTAINER_DLL_remove (ale->ai_head, +                               ale->ai_tail, +                               aie); +  GNUNET_free (aie); +} + + +/**   * Iterate over all available auditors for @a h, calling   * @param ah and giving it a chance to start a deposit   * confirmation interaction. @@ -284,14 +295,38 @@ TEAH_get_auditors_for_dc (struct TALER_EXCHANGE_Handle *h,  			  TEAH_AuditorCallback ac,  			  void *ac_cls)  { -  // FIXME! +  if (NULL == h->auditors_head) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_INFO, +                _("No auditor available for exchange `%s'. Not submitting deposit confirmations.\n"), +                h->url); +    return; +  } +  for (struct TEAH_AuditorListEntry *ale = h->auditors_head; +       NULL != ale; +       ale = ale->next) +  { +    struct TEAH_AuditorInteractionEntry *aie; + +    if (GNUNET_NO == ale->is_up) +      continue; +    aie = ac (ac_cls, +              ale->ah, +              &ale->auditor_pub); +    if (NULL != aie) +    { +      aie->ale = ale; +      GNUNET_CONTAINER_DLL_insert (ale->ai_head, +                                   ale->ai_tail, +                                   aie); +    } +  }  }  /** - * Release memory occupied by a keys request. - * Note that this does not cancel the request - * itself. + * Release memory occupied by a keys request.  Note that this does not + * cancel the request itself.   *   * @param kr request to free   */ @@ -602,6 +637,90 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,  /** + * Function called with information about the auditor.  Marks an + * auditor as 'up'. + * + * @param cls closure, a `struct TEAH_AuditorListEntry *` + * @param vi basic information about the auditor + * @param compat protocol compatibility information + */ +static void +auditor_version_cb (void *cls, +                    const struct TALER_AUDITOR_VersionInformation *vi, +                    enum TALER_AUDITOR_VersionCompatibility compat) +{ +  struct TEAH_AuditorListEntry *ale = cls; + +  if (0 != (TALER_AUDITOR_VC_INCOMPATIBLE & compat)) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                _("Auditor `%s' runs incompatible protocol version!\n"), +                ale->auditor_url); +    if (0 != (TALER_AUDITOR_VC_OLDER & compat)) +    { +      GNUNET_log (GNUNET_ERROR_TYPE_INFO, +                  _("Auditor `%s' runs outdated protocol version!\n"), +                  ale->auditor_url); +    } +    if (0 != (TALER_AUDITOR_VC_NEWER & compat)) +    { +      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                  _("Auditor `%s' runs more recent incompatible version. We should upgrade!\n"), +                  ale->auditor_url); +    } +    return; +  } +  ale->is_up = GNUNET_YES; +} + + +/** + * Recalculate our auditor list, we got /keys and it may have + * changed. + * + * @param exchange exchange for which to update the list. + */ +static void +update_auditors (struct TALER_EXCHANGE_Handle *exchange) +{ +  struct TALER_EXCHANGE_Keys *kd = &exchange->key_data; + +  for (unsigned int i=0;i<kd->num_auditors;i++) +  { +    struct TALER_EXCHANGE_AuditorInformation *auditor = &kd->auditors[i]; +    struct TEAH_AuditorListEntry *ale = NULL; + +    for (struct TEAH_AuditorListEntry *a = exchange->auditors_head; +         NULL != a; +         a = a->next) +    { +      if (0 == memcmp (&auditor->auditor_pub, +                       &a->auditor_pub, +                       sizeof (struct TALER_AuditorPublicKeyP))) +      { +        ale = a; +        break; +      } +    } +    if (NULL != ale) +      continue; /* found, no need to add */ +    /* new auditor, add */ +    ale = GNUNET_new (struct TEAH_AuditorListEntry); +    ale->auditor_pub = auditor->auditor_pub; +    ale->auditor_url = GNUNET_strdup (auditor->auditor_url); +    GNUNET_CONTAINER_DLL_insert (exchange->auditors_head, +                                 exchange->auditors_tail, +                                 ale); +    ale->ah = TALER_AUDITOR_connect (exchange->ctx, +                                     ale->auditor_url, +                                     &auditor_version_cb, +                                     ale); +  } +} + + + +/**   * Decode the JSON in @a resp_obj from the /keys response   * and store the data in the @a key_data.   * @@ -827,6 +946,7 @@ decode_keys_json (const json_t *resp_obj,  	GNUNET_array_grow (key_data->auditors,  			   key_data->auditors_size,  			   key_data->auditors_size * 2 + 2); +      GNUNET_assert (NULL != ai.auditor_url);        key_data->auditors[key_data->num_auditors++] = ai;      };    } @@ -997,6 +1117,7 @@ keys_completed_cb (void *cls,        struct TALER_EXCHANGE_AuditorInformation *anew = &kd.auditors[i];        anew->auditor_pub = aold->auditor_pub; +      GNUNET_assert (NULL != aold->auditor_url);        anew->auditor_url = GNUNET_strdup (aold->auditor_url);        GNUNET_array_grow (anew->denom_keys,                           anew->num_denom_keys, @@ -1072,6 +1193,7 @@ keys_completed_cb (void *cls,    exchange->key_data_expiration = kr->expire;    free_keys_request (kr);    exchange->state = MHS_CERT; +  update_auditors (exchange);    /* notify application about the key information */    exchange->cert_cb (exchange->cert_cb_cls,                       &exchange->key_data, @@ -1305,6 +1427,7 @@ deserialize_data (struct TALER_EXCHANGE_Handle *exchange,    exchange->key_data = key_data;    exchange->key_data_expiration = expire;    exchange->state = MHS_CERT; +  update_auditors (exchange);    /* notify application about the key information */    exchange->cert_cb (exchange->cert_cb_cls,                       &exchange->key_data, @@ -1619,6 +1742,31 @@ request_keys (void *cls)  void  TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange)  { +  struct TEAH_AuditorListEntry *ale; + +  while (NULL != (ale = exchange->auditors_head)) +  { +    struct TEAH_AuditorInteractionEntry *aie; + +    while (NULL != (aie = ale->ai_head)) +    { +      GNUNET_assert (aie->ale == ale); +      GNUNET_log (GNUNET_ERROR_TYPE_INFO, +                  _("Not sending deposit confirmation to auditor `%s' due to exchange disconnect\n"), +                  ale->auditor_url); +      TALER_AUDITOR_deposit_confirmation_cancel (aie->dch); +      GNUNET_CONTAINER_DLL_remove (ale->ai_head, +                                   ale->ai_tail, +                                   aie); +      GNUNET_free (aie); +    } +    GNUNET_CONTAINER_DLL_remove (exchange->auditors_head, +                                 exchange->auditors_tail, +                                 ale); +    TALER_AUDITOR_disconnect (ale->ah); +    GNUNET_free (ale->auditor_url); +    GNUNET_free (ale); +  }    if (NULL != exchange->kr)    {      GNUNET_CURL_job_cancel (exchange->kr->job); diff --git a/src/lib/exchange_api_handle.h b/src/lib/exchange_api_handle.h index f06fa4ee..2c01e319 100644 --- a/src/lib/exchange_api_handle.h +++ b/src/lib/exchange_api_handle.h @@ -27,21 +27,70 @@  /** + * Entry in DLL of auditors used by an exchange. + */ +struct TEAH_AuditorListEntry; + + +/** + * Entry in list of ongoing interactions with an auditor. + */ +struct TEAH_AuditorInteractionEntry +{ +  /** +   * DLL entry. +   */ +  struct TEAH_AuditorInteractionEntry *next; + +  /** +   * DLL entry. +   */ +  struct TEAH_AuditorInteractionEntry *prev; + +  /** +   * Which auditor is this action associated with? +   */ +  struct TEAH_AuditorListEntry *ale; + +  /** +   * Interaction state. +   */ +  struct TALER_AUDITOR_DepositConfirmationHandle *dch; +}; + + +/**   * Function called for each auditor to give us a chance to possibly - * launch a deposit confirmation interaction.   - *  + * launch a deposit confirmation interaction. + *   * @param cls closure   * @param ah handle to the auditor   * @param auditor_pub public key of the auditor   * @return NULL if no deposit confirmation interaction was launched   */ -typedef struct TALER_AUDITOR_DepositConfirmationHandle * +typedef struct TEAH_AuditorInteractionEntry *  (*TEAH_AuditorCallback)(void *cls,  			struct TALER_AUDITOR_Handle *ah,  			const struct TALER_AuditorPublicKeyP *auditor_pub);  /** + * Signature of functions called with the result from our call to the + * auditor's /deposit-confirmation handler. + * + * @param cls closure of type `struct TEAH_AuditorInteractionEntry *` + * @param http_status HTTP status code, 200 on success + * @param ec taler protocol error status code, 0 on success + * @param json raw json response + */ +void +TEAH_acc_confirmation_cb (void *cls, +                          unsigned int http_status, +                          enum TALER_ErrorCode ec, +                          const json_t *json); + + +/**   * Iterate over all available auditors for @a h, calling   * @param ah and giving it a chance to start a deposit   * confirmation interaction. | 
