LCOV - code coverage report
Current view: top level - wire - plugin_wire_test.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 235 360 65.3 %
Date: 2017-11-25 11:31:41 Functions: 14 19 73.7 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2016 GNUnet e.V. & Inria
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU General Public License as published by the Free Software
       7             :   Foundation; either version 3, or (at your option) any later version.
       8             : 
       9             :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10             :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11             :   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU General Public License along with
      14             :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : 
      17             : /**
      18             :  * @file plugin_wire_test.c
      19             :  * @brief plugin for the "test" wire method
      20             :  * @author Christian Grothoff
      21             :  */
      22             : #include "platform.h"
      23             : #include "taler_wire_plugin.h"
      24             : #include "taler_bank_service.h"
      25             : #include "taler_signatures.h"
      26             : #include <gnunet/gnunet_curl_lib.h>
      27             : 
      28             : /* only for HTTP status codes */
      29             : #include <microhttpd.h>
      30             : 
      31             : /**
      32             :  * Type of the "cls" argument given to each of the functions in
      33             :  * our API.
      34             :  */
      35             : struct TestClosure
      36             : {
      37             : 
      38             :   /**
      39             :    * Which currency do we support?
      40             :    */
      41             :   char *currency;
      42             : 
      43             :   /**
      44             :    * URI of our bank.
      45             :    */
      46             :   char *bank_uri;
      47             : 
      48             :   /**
      49             :    * Authentication information.
      50             :    */
      51             :   struct TALER_BANK_AuthenticationData auth;
      52             : 
      53             :   /**
      54             :    * Handle to the context for sending funds to the bank.
      55             :    */
      56             :   struct GNUNET_CURL_Context *ctx;
      57             : 
      58             :   /**
      59             :    * Scheduler context for running the @e ctx.
      60             :    */
      61             :   struct GNUNET_CURL_RescheduleContext *rc;
      62             : 
      63             :   /**
      64             :    * Number of the account that the exchange has at the bank for
      65             :    * transfers.
      66             :    */
      67             :   unsigned long long exchange_account_no;
      68             : 
      69             : };
      70             : 
      71             : 
      72             : /**
      73             :  * Handle returned by #test_prepare_wire_transfer.
      74             :  */
      75             : struct TALER_WIRE_PrepareHandle
      76             : {
      77             : 
      78             :   /**
      79             :    * Task we use for async execution.
      80             :    */
      81             :   struct GNUNET_SCHEDULER_Task *task;
      82             : 
      83             :   /**
      84             :    * Test closure we run in.
      85             :    */
      86             :   struct TestClosure *tc;
      87             : 
      88             :   /**
      89             :    * Wire data for the transfer.
      90             :    */
      91             :   json_t *wire;
      92             : 
      93             :   /**
      94             :    * Base URL to use for the exchange.
      95             :    */
      96             :   char *exchange_base_url;
      97             : 
      98             :   /**
      99             :    * Function to call with the serialized data.
     100             :    */
     101             :   TALER_WIRE_PrepareTransactionCallback ptc;
     102             : 
     103             :   /**
     104             :    * Closure for @e ptc.
     105             :    */
     106             :   void *ptc_cls;
     107             : 
     108             :   /**
     109             :    * Amount to transfer.
     110             :    */
     111             :   struct TALER_Amount amount;
     112             : 
     113             :   /**
     114             :    * Subject of the wire transfer.
     115             :    */
     116             :   struct TALER_WireTransferIdentifierRawP wtid;
     117             : 
     118             : 
     119             : };
     120             : 
     121             : 
     122             : /**
     123             :  * Handle returned by #test_execute_wire_transfer.
     124             :  */
     125             : struct TALER_WIRE_ExecuteHandle
     126             : {
     127             : 
     128             :   /**
     129             :    * Handle to the HTTP request to the bank.
     130             :    */
     131             :   struct TALER_BANK_AdminAddIncomingHandle *aaih;
     132             : 
     133             :   /**
     134             :    * Function to call with the result.
     135             :    */
     136             :   TALER_WIRE_ConfirmationCallback cc;
     137             : 
     138             :   /**
     139             :    * Closure for @e cc.
     140             :    */
     141             :   void *cc_cls;
     142             : };
     143             : 
     144             : 
     145             : 
     146             : /**
     147             :  * Round amount DOWN to the amount that can be transferred via the wire
     148             :  * method.  For example, Taler may support 0.000001 EUR as a unit of
     149             :  * payment, but SEPA only supports 0.01 EUR.  This function would
     150             :  * round 0.125 EUR to 0.12 EUR in this case.
     151             :  *
     152             :  * @param cls the @e cls of this struct with the plugin-specific state
     153             :  * @param[in,out] amount amount to round down
     154             :  * @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary,
     155             :  *         #GNUNET_SYSERR if the amount or currency was invalid
     156             :  */
     157             : static int
     158          21 : test_amount_round (void *cls,
     159             :                    struct TALER_Amount *amount)
     160             : {
     161          21 :   struct TestClosure *tc = cls;
     162             :   uint32_t delta;
     163             : 
     164          21 :   if (NULL == tc->currency)
     165             :   {
     166           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     167             :                                "taler",
     168             :                                "CURRENCY");
     169           0 :     return GNUNET_SYSERR; /* not configured with currency */
     170             :   }
     171          21 :   if (0 != strcasecmp (amount->currency,
     172          21 :                        tc->currency))
     173             :   {
     174           1 :     GNUNET_break (0);
     175           1 :     return GNUNET_SYSERR;
     176             :   }
     177             :   /* 'test' method supports 1/100 of the unit currency, i.e. 0.01 CUR */
     178          20 :   delta = amount->fraction % (TALER_AMOUNT_FRAC_BASE / 100);
     179          20 :   if (0 == delta)
     180          16 :     return GNUNET_NO;
     181           4 :   amount->fraction -= delta;
     182           4 :   return GNUNET_OK;
     183             : }
     184             : 
     185             : 
     186             : /**
     187             :  * Compute purpose for signing.
     188             :  *
     189             :  * @param account number of the account
     190             :  * @param bank_uri URI of the bank
     191             :  * @param[out] wsd purpose to be signed
     192             :  */
     193             : static void
     194           7 : compute_purpose (uint64_t account,
     195             :                  const char *bank_uri,
     196             :                  struct TALER_MasterWireDetailsPS *wsd)
     197             : {
     198             :   struct GNUNET_HashContext *hc;
     199           7 :   uint64_t n = GNUNET_htonll (account);
     200             : 
     201           7 :   wsd->purpose.size = htonl (sizeof (struct TALER_MasterWireDetailsPS));
     202           7 :   wsd->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_TEST_DETAILS);
     203           7 :   hc = GNUNET_CRYPTO_hash_context_start ();
     204           7 :   GNUNET_CRYPTO_hash_context_read (hc,
     205             :                                    "test",
     206             :                                    strlen ("test") + 1);
     207           7 :   GNUNET_CRYPTO_hash_context_read (hc,
     208             :                                    &n,
     209             :                                    sizeof (n));
     210           7 :   GNUNET_CRYPTO_hash_context_read (hc,
     211             :                                    bank_uri,
     212           7 :                                    strlen (bank_uri) + 1);
     213           7 :   GNUNET_CRYPTO_hash_context_finish (hc,
     214             :                                      &wsd->h_sepa_details);
     215           7 : }
     216             : 
     217             : 
     218             : /**
     219             :  * Check if the given wire format JSON object is correctly formatted.
     220             :  * Right now, the only thing we require is a field
     221             :  * "account_number" which must contain a positive 53-bit integer.
     222             :  *
     223             :  * @param cls the @e cls of this struct with the plugin-specific state
     224             :  * @param wire the JSON wire format object
     225             :  * @param master_pub public key of the exchange to verify against
     226             :  * @param[out] emsg set to an error message, unless we return #TALER_EC_NONE;
     227             :  *             error message must be freed by the caller using GNUNET_free()
     228             :  * @return #TALER_EC_NONE if correctly formatted
     229             :  */
     230             : static enum TALER_ErrorCode
     231          63 : test_wire_validate (void *cls,
     232             :                     const json_t *wire,
     233             :                     const struct TALER_MasterPublicKeyP *master_pub,
     234             :                     char **emsg)
     235             : {
     236          63 :   struct TestClosure *tc = cls;
     237             :   json_error_t error;
     238             :   json_int_t account_no;
     239             :   const char *bank_uri;
     240             :   const char *sig_s;
     241             :   struct TALER_MasterWireDetailsPS wsd;
     242             :   struct TALER_MasterSignatureP sig;
     243             : 
     244          63 :   *emsg = NULL;
     245          63 :   if (0 !=
     246          63 :       json_unpack_ex ((json_t *) wire,
     247             :                       &error,
     248             :                       0,
     249             :                       "{s:I, s:s}",
     250             :                       "account_number", &account_no,
     251             :                       "bank_uri", &bank_uri))
     252             :   {
     253             :     char *dump;
     254             : 
     255           0 :     dump = json_dumps (wire, 0);
     256           0 :     GNUNET_asprintf (emsg,
     257             :                      "JSON parsing failed at %s:%u: %s (%s): %s\n",
     258             :                      __FILE__, __LINE__,
     259             :                      error.text,
     260             :                      error.source,
     261             :                      dump);
     262           0 :     free (dump);
     263           0 :     return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_JSON;
     264             :   }
     265         126 :   if ( (account_no < 0) ||
     266          63 :        (account_no > (1LL << 53)) )
     267             :   {
     268           0 :     GNUNET_asprintf (emsg,
     269             :                      "Account number %llu outside of permitted range\n",
     270             :                      account_no);
     271           0 :     return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_ACCOUNT_NUMBER;
     272             :   }
     273         124 :   if ( (NULL != tc->bank_uri) &&
     274          61 :        (0 != strcmp (bank_uri,
     275          61 :                      tc->bank_uri)) )
     276             :   {
     277           0 :     GNUNET_asprintf (emsg,
     278             :                      "Wire specifies bank URI `%s', but this exchange only supports `%s'\n",
     279             :                      bank_uri,
     280             :                      tc->bank_uri);
     281           0 :     return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_BANK;
     282             :   }
     283          63 :   if (NULL == master_pub)
     284             :   {
     285          57 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     286             :                 "Skipping signature check as master public key not given\n");
     287          57 :     return TALER_EC_NONE;
     288             :   }
     289           6 :   if (0 !=
     290           6 :       json_unpack_ex ((json_t *) wire,
     291             :                       &error,
     292             :                       0,
     293             :                       "{s:s}",
     294             :                       "sig", &sig_s))
     295             :   {
     296           0 :     GNUNET_asprintf (emsg,
     297             :                      "Signature check required, but signature is missing\n");
     298           0 :     return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_SIGNATURE;
     299             :   }
     300           6 :   compute_purpose (account_no,
     301             :                    bank_uri,
     302             :                    &wsd);
     303           6 :   if (GNUNET_OK !=
     304           6 :       GNUNET_STRINGS_string_to_data (sig_s,
     305             :                                      strlen (sig_s),
     306             :                                      &sig,
     307             :                                      sizeof (sig)))
     308             :   {
     309           0 :     GNUNET_break (0);
     310           0 :     return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_SIGNATURE;
     311             :   }
     312           6 :   if (GNUNET_OK !=
     313           6 :       GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_TEST_DETAILS,
     314             :                                   &wsd.purpose,
     315             :                                   &sig.eddsa_signature,
     316             :                                   &master_pub->eddsa_pub))
     317             :   {
     318           0 :     GNUNET_asprintf (emsg,
     319             :                      "Signature using public key `%s' invalid\n",
     320             :                      TALER_B2S (master_pub));
     321           0 :     return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_SIGNATURE;
     322             :   }
     323           6 :   return TALER_EC_NONE;
     324             : }
     325             : 
     326             : 
     327             : /**
     328             :  * Obtain wire transfer details in the plugin-specific format
     329             :  * from the configuration.
     330             :  *
     331             :  * @param cls closure
     332             :  * @param cfg configuration with details about wire accounts
     333             :  * @param account_name which section in the configuration should we parse
     334             :  * @return NULL if @a cfg fails to have valid wire details for @a account_name
     335             :  */
     336             : static json_t *
     337           3 : test_get_wire_details (void *cls,
     338             :                        const struct GNUNET_CONFIGURATION_Handle *cfg,
     339             :                        const char *account_name)
     340             : {
     341           3 :   struct TestClosure *tc = cls;
     342             :   char *test_wire_file;
     343             :   json_error_t err;
     344             :   json_t *ret;
     345             :   char *emsg;
     346             : 
     347             :   /* Fetch reply */
     348           3 :   if (GNUNET_OK !=
     349           3 :       GNUNET_CONFIGURATION_get_value_filename (cfg,
     350             :                                                account_name,
     351             :                                                "TEST_RESPONSE_FILE",
     352             :                                                &test_wire_file))
     353             :   {
     354           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     355             :                                account_name,
     356             :                                "TEST_RESPONSE_FILE");
     357           0 :     return NULL;
     358             :   }
     359           3 :   ret = json_load_file (test_wire_file,
     360             :                         JSON_REJECT_DUPLICATES,
     361             :                         &err);
     362           3 :   if (NULL == ret)
     363             :   {
     364           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     365             :                 "Failed to parse JSON in %s: %s (%s:%u)\n",
     366             :                 test_wire_file,
     367             :                 err.text,
     368             :                 err.source,
     369             :                 err.line);
     370           0 :     GNUNET_free (test_wire_file);
     371           0 :     return NULL;
     372             :   }
     373           3 :   if (TALER_EC_NONE !=
     374           3 :       test_wire_validate (tc,
     375             :                           ret,
     376             :                           NULL,
     377             :                           &emsg))
     378             :   {
     379           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     380             :                 "Failed to validate TEST wire data in %s: %s\n",
     381             :                 test_wire_file,
     382             :                 emsg);
     383           0 :     GNUNET_free (emsg);
     384           0 :     GNUNET_free (test_wire_file);
     385           0 :     json_decref (ret);
     386           0 :     return NULL;
     387             :   }
     388           3 :   GNUNET_free (test_wire_file);
     389           3 :   return ret;
     390             : }
     391             : 
     392             : 
     393             : GNUNET_NETWORK_STRUCT_BEGIN
     394             : /**
     395             :  * Format we used for serialized transaction data.
     396             :  */
     397             : struct BufFormatP
     398             : {
     399             : 
     400             :   /**
     401             :    * The wire transfer identifier.
     402             :    */
     403             :   struct TALER_WireTransferIdentifierRawP wtid;
     404             : 
     405             :   /**
     406             :    * The amount.
     407             :    */
     408             :   struct TALER_AmountNBO amount;
     409             : 
     410             :   /* followed by serialized 'wire' JSON data (0-terminated) */
     411             : 
     412             :   /* followed by 0-terminated base URL */
     413             : 
     414             : };
     415             : GNUNET_NETWORK_STRUCT_END
     416             : 
     417             : 
     418             : /**
     419             :  * Abort preparation of a wire transfer. For example,
     420             :  * because we are shutting down.
     421             :  *
     422             :  * @param cls the @e cls of this struct with the plugin-specific state
     423             :  * @param pth preparation to cancel
     424             :  */
     425             : static void
     426          18 : test_prepare_wire_transfer_cancel (void *cls,
     427             :                                    struct TALER_WIRE_PrepareHandle *pth)
     428             : {
     429          18 :   if (NULL != pth->task)
     430           0 :     GNUNET_SCHEDULER_cancel (pth->task);
     431          18 :   json_decref (pth->wire);
     432          18 :   GNUNET_free (pth->exchange_base_url);
     433          18 :   GNUNET_free (pth);
     434          18 : }
     435             : 
     436             : 
     437             : /**
     438             :  * Prepare for exeuction of a wire transfer.  Calls the
     439             :  * callback with the serialized state.
     440             :  *
     441             :  * @param cls the `struct TALER_WIRE_PrepareHandle`
     442             :  */
     443             : static void
     444          18 : do_prepare (void *cls)
     445             : {
     446          18 :   struct TALER_WIRE_PrepareHandle *pth = cls;
     447             :   char *wire_enc;
     448             :   size_t len_w;
     449             :   size_t len_b;
     450             :   struct BufFormatP bf;
     451             : 
     452          18 :   pth->task = NULL;
     453             :   /* serialize the state into a 'buf' */
     454          18 :   wire_enc = json_dumps (pth->wire,
     455             :                          JSON_COMPACT | JSON_SORT_KEYS);
     456          18 :   if (NULL == wire_enc)
     457             :   {
     458           0 :     GNUNET_break (0);
     459           0 :     pth->ptc (pth->ptc_cls,
     460             :               NULL,
     461             :               0);
     462           0 :     test_prepare_wire_transfer_cancel (NULL,
     463             :                                        pth);
     464           0 :     return;
     465             :   }
     466          18 :   len_w = strlen (wire_enc) + 1;
     467          18 :   len_b = strlen (pth->exchange_base_url) + 1;
     468          18 :   bf.wtid = pth->wtid;
     469          18 :   TALER_amount_hton (&bf.amount,
     470          18 :                      &pth->amount);
     471          18 :   {
     472          18 :     char buf[sizeof (struct BufFormatP) + len_w + len_b];
     473             : 
     474          18 :     memcpy (buf,
     475             :             &bf,
     476             :             sizeof (struct BufFormatP));
     477          18 :     memcpy (&buf[sizeof (struct BufFormatP)],
     478             :             wire_enc,
     479             :             len_w);
     480          18 :     memcpy (&buf[sizeof (struct BufFormatP) + len_w],
     481          18 :             pth->exchange_base_url,
     482             :             len_b);
     483             : 
     484             :     /* finally give the state back */
     485          18 :     pth->ptc (pth->ptc_cls,
     486             :               buf,
     487             :               sizeof (buf));
     488             :   }
     489          18 :   free (wire_enc); /* not using GNUNET_free(),
     490             :                       as this one is allocated by libjansson */
     491          18 :   test_prepare_wire_transfer_cancel (NULL,
     492             :                                      pth);
     493             : }
     494             : 
     495             : 
     496             : /**
     497             :  * Prepare for exeuction of a wire transfer.  Note that we should call
     498             :  * @a ptc asynchronously (as that is what the API requires, because
     499             :  * some transfer methods need it).  So while we could immediately call
     500             :  * @a ptc, we first bundle up all the data and schedule a task to do
     501             :  * the work.
     502             :  *
     503             :  * @param cls the @e cls of this struct with the plugin-specific state
     504             :  * @param wire valid wire account information
     505             :  * @param amount amount to transfer, already rounded
     506             :  * @param exchange_base_url base URL of this exchange
     507             :  * @param wtid wire transfer identifier to use
     508             :  * @param ptc function to call with the prepared data to persist
     509             :  * @param ptc_cls closure for @a ptc
     510             :  * @return NULL on failure
     511             :  */
     512             : static struct TALER_WIRE_PrepareHandle *
     513          18 : test_prepare_wire_transfer (void *cls,
     514             :                             const json_t *wire,
     515             :                             const struct TALER_Amount *amount,
     516             :                             const char *exchange_base_url,
     517             :                             const struct TALER_WireTransferIdentifierRawP *wtid,
     518             :                             TALER_WIRE_PrepareTransactionCallback ptc,
     519             :                             void *ptc_cls)
     520             : {
     521          18 :   struct TestClosure *tc = cls;
     522             :   struct TALER_WIRE_PrepareHandle *pth;
     523             :   char *emsg;
     524             : 
     525          18 :   if (TALER_EC_NONE !=
     526          18 :       test_wire_validate (tc,
     527             :                           wire,
     528             :                           NULL,
     529             :                           &emsg))
     530             :   {
     531           0 :     GNUNET_break_op (0);
     532           0 :     GNUNET_free (emsg);
     533           0 :     return NULL;
     534             :   }
     535          18 :   pth = GNUNET_new (struct TALER_WIRE_PrepareHandle);
     536          18 :   pth->tc = tc;
     537          18 :   pth->wire = json_incref ((json_t *) wire);
     538          18 :   pth->exchange_base_url = GNUNET_strdup (exchange_base_url);
     539          18 :   pth->wtid = *wtid;
     540          18 :   pth->ptc = ptc;
     541          18 :   pth->ptc_cls = ptc_cls;
     542          18 :   pth->amount = *amount;
     543          18 :   pth->task = GNUNET_SCHEDULER_add_now (&do_prepare,
     544             :                                         pth);
     545          18 :   return pth;
     546             : }
     547             : 
     548             : 
     549             : /**
     550             :  * Called with the result of submitting information about an incoming
     551             :  * transaction to a bank.
     552             :  *
     553             :  * @param cls closure with the `struct TALER_WIRE_ExecuteHandle`
     554             :  * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
     555             :  *                    0 if the bank's reply is bogus (fails to follow the protocol)
     556             :  * @param serial_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error
     557             :  * @param json detailed response from the HTTPD, or NULL if reply was not JSON
     558             :  */
     559             : static void
     560          18 : execute_cb (void *cls,
     561             :             unsigned int http_status,
     562             :             uint64_t serial_id,
     563             :             const json_t *json)
     564             : {
     565          18 :   struct TALER_WIRE_ExecuteHandle *eh = cls;
     566             :   json_t *reason;
     567             :   const char *emsg;
     568             :   char *s;
     569             : 
     570          18 :   eh->aaih = NULL;
     571          18 :   emsg = NULL;
     572          18 :   if (NULL != json)
     573             :   {
     574          18 :     reason = json_object_get (json,
     575             :                               "reason");
     576          18 :     if (NULL != reason)
     577           0 :       emsg = json_string_value (reason);
     578             :   }
     579          18 :   if (NULL != emsg)
     580           0 :     GNUNET_asprintf (&s,
     581             :                      "%u (%s)",
     582             :                      http_status,
     583             :                      emsg);
     584             :   else
     585          18 :     GNUNET_asprintf (&s,
     586             :                      "%u",
     587             :                      http_status);
     588          18 :   eh->cc (eh->cc_cls,
     589             :           (MHD_HTTP_OK == http_status) ? GNUNET_OK : GNUNET_SYSERR,
     590             :           serial_id,
     591             :           (MHD_HTTP_OK == http_status) ? NULL : s);
     592          18 :   GNUNET_free (s);
     593          18 :   GNUNET_free (eh);
     594          18 : }
     595             : 
     596             : 
     597             : /**
     598             :  * Sign wire transfer details in the plugin-specific format.
     599             :  *
     600             :  * @param cls closure
     601             :  * @param in wire transfer details in JSON format
     602             :  * @param key private signing key to use
     603             :  * @param salt salt to add
     604             :  * @param[out] sig where to write the signature
     605             :  * @return #GNUNET_OK on success
     606             :  */
     607             : static int
     608           1 : test_sign_wire_details (void *cls,
     609             :                         const json_t *in,
     610             :                         const struct TALER_MasterPrivateKeyP *key,
     611             :                         const struct GNUNET_HashCode *salt,
     612             :                         struct TALER_MasterSignatureP *sig)
     613             : {
     614             :   struct TALER_MasterWireDetailsPS wsd;
     615             :   const char *bank_uri;
     616             :   const char *type;
     617             :   json_int_t account;
     618             :   json_error_t err;
     619             : 
     620           1 :   if (0 !=
     621           1 :       json_unpack_ex ((json_t *) in,
     622             :                       &err,
     623             :                       0 /* flags */,
     624             :                       "{s:s, s:s, s:I}",
     625             :                       "type", &type,
     626             :                       "bank_uri", &bank_uri,
     627             :                       "account_number", &account))
     628             :   {
     629           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     630             :                 "Failed to unpack JSON: %s (at %u)\n",
     631             :                 err.text,
     632             :                 err.position);
     633           0 :     return GNUNET_SYSERR;
     634             :   }
     635           1 :   if (0 != strcmp (type,
     636             :                    "test"))
     637             :   {
     638           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     639             :                 "`type' must be `test' for test wire details\n");
     640           0 :     return GNUNET_SYSERR;
     641             :   }
     642           1 :   compute_purpose (account,
     643             :                    bank_uri,
     644             :                    &wsd);
     645           1 :   GNUNET_CRYPTO_eddsa_sign (&key->eddsa_priv,
     646             :                             &wsd.purpose,
     647             :                             &sig->eddsa_signature);
     648           1 :   return GNUNET_OK;
     649             : }
     650             : 
     651             : 
     652             : /**
     653             :  * Execute a wire transfer.
     654             :  *
     655             :  * @param cls the @e cls of this struct with the plugin-specific state
     656             :  * @param buf buffer with the prepared execution details
     657             :  * @param buf_size number of bytes in @a buf
     658             :  * @param cc function to call upon success
     659             :  * @param cc_cls closure for @a cc
     660             :  * @return NULL on error
     661             :  */
     662             : static struct TALER_WIRE_ExecuteHandle *
     663          18 : test_execute_wire_transfer (void *cls,
     664             :                             const char *buf,
     665             :                             size_t buf_size,
     666             :                             TALER_WIRE_ConfirmationCallback cc,
     667             :                             void *cc_cls)
     668             : {
     669          18 :   struct TestClosure *tc = cls;
     670             :   struct TALER_WIRE_ExecuteHandle *eh;
     671             :   json_t *wire;
     672             :   json_error_t error;
     673             :   struct TALER_Amount amount;
     674             :   json_int_t account_no;
     675             :   struct BufFormatP bf;
     676             :   char *emsg;
     677             :   const char *json_s;
     678             :   const char *exchange_base_url;
     679             : 
     680          18 :   if (NULL == tc->ctx)
     681             :   {
     682           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     683             :                 "Bank not initialized, cannot do transfers!\n");
     684           0 :     return NULL; /* not initialized with configuration, cannot do transfers */
     685             :   }
     686          36 :   if ( (buf_size <= sizeof (struct BufFormatP)) ||
     687          18 :        ('\0' != buf[buf_size - 1]) )
     688             :   {
     689           0 :     GNUNET_break (0);
     690           0 :     return NULL;
     691             :   }
     692          18 :   json_s = &buf[sizeof (struct BufFormatP)];
     693          18 :   exchange_base_url = &json_s[strlen (json_s) + 1];
     694          18 :   if (exchange_base_url > &buf[buf_size - 1])
     695             :   {
     696           0 :     GNUNET_break (0);
     697           0 :     return NULL;
     698             :   }
     699          18 :   memcpy (&bf,
     700             :           buf,
     701             :           sizeof (bf));
     702          18 :   TALER_amount_ntoh (&amount,
     703             :                      &bf.amount);
     704          18 :   wire = json_loads (json_s,
     705             :                      JSON_REJECT_DUPLICATES,
     706             :                      NULL);
     707          18 :   if (NULL == wire)
     708             :   {
     709           0 :     GNUNET_break (0);
     710           0 :     return NULL;
     711             :   }
     712          18 :   GNUNET_assert (TALER_EC_NONE ==
     713             :                  test_wire_validate (tc,
     714             :                                      wire,
     715             :                                      NULL,
     716             :                                      &emsg));
     717          18 :   if (0 !=
     718          18 :       json_unpack_ex (wire,
     719             :                       &error,
     720             :                       0,
     721             :                       "{s:I}",
     722             :                       "account_number", &account_no))
     723             :   {
     724           0 :     GNUNET_break (0);
     725           0 :     return NULL;
     726             :   }
     727             : 
     728          18 :   eh = GNUNET_new (struct TALER_WIRE_ExecuteHandle);
     729          18 :   eh->cc = cc;
     730          18 :   eh->cc_cls = cc_cls;
     731          36 :   eh->aaih = TALER_BANK_admin_add_incoming (tc->ctx,
     732          18 :                                             tc->bank_uri,
     733          18 :                                             &tc->auth,
     734             :                                             exchange_base_url,
     735             :                                             &bf.wtid,
     736             :                                             &amount,
     737          18 :                                             (uint64_t) tc->exchange_account_no,
     738             :                                             (uint64_t) account_no,
     739             :                                             &execute_cb,
     740             :                                             eh);
     741          18 :   json_decref (wire);
     742          18 :   if (NULL == eh->aaih)
     743             :   {
     744           0 :     GNUNET_break (0);
     745           0 :     GNUNET_free (eh);
     746           0 :     return NULL;
     747             :   }
     748          18 :   return eh;
     749             : }
     750             : 
     751             : 
     752             : /**
     753             :  * Abort execution of a wire transfer. For example, because we are
     754             :  * shutting down.  Note that if an execution is aborted, it may or
     755             :  * may not still succeed. The caller MUST run @e
     756             :  * execute_wire_transfer again for the same request as soon as
     757             :  * possilbe, to ensure that the request either ultimately succeeds
     758             :  * or ultimately fails. Until this has been done, the transaction is
     759             :  * in limbo (i.e. may or may not have been committed).
     760             :  *
     761             :  * @param cls the @e cls of this struct with the plugin-specific state
     762             :  * @param eh execution to cancel
     763             :  */
     764             : static void
     765           0 : test_execute_wire_transfer_cancel (void *cls,
     766             :                                    struct TALER_WIRE_ExecuteHandle *eh)
     767             : {
     768           0 :   TALER_BANK_admin_add_incoming_cancel (eh->aaih);
     769           0 :   GNUNET_free (eh);
     770           0 : }
     771             : 
     772             : 
     773             : /**
     774             :  * Handle for a #test_get_history() request.
     775             :  */
     776             : struct TALER_WIRE_HistoryHandle
     777             : {
     778             : 
     779             :   /**
     780             :    * Function to call with results.
     781             :    */
     782             :   TALER_WIRE_HistoryResultCallback hres_cb;
     783             : 
     784             :   /**
     785             :    * Closure for @e hres_cb.
     786             :    */
     787             :   void *hres_cb_cls;
     788             : 
     789             :   /**
     790             :    * Request to the bank.
     791             :    */
     792             :   struct TALER_BANK_HistoryHandle *hh;
     793             : 
     794             : };
     795             : 
     796             : 
     797             : /**
     798             :  * Function called with results from the bank about the transaction history.
     799             :  *
     800             :  * @param cls the `struct TALER_WIRE_HistoryHandle`
     801             :  * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
     802             :  *                    0 if the bank's reply is bogus (fails to follow the protocol),
     803             :  *                    #MHD_HTTP_NO_CONTENT if there are no more results; on success the
     804             :  *                    last callback is always of this status (even if `abs(num_results)` were
     805             :  *                    already returned).
     806             :  * @param dir direction of the transfer
     807             :  * @param serial_id monotonically increasing counter corresponding to the transaction
     808             :  * @param details details about the wire transfer
     809             :  * @param json detailed response from the HTTPD, or NULL if reply was not in JSON
     810             :  */
     811             : static void
     812           3 : bhist_cb (void *cls,
     813             :           unsigned int http_status,
     814             :           enum TALER_BANK_Direction dir,
     815             :           uint64_t serial_id,
     816             :           const struct TALER_BANK_TransferDetails *details,
     817             :           const json_t *json)
     818             : {
     819           3 :   struct TALER_WIRE_HistoryHandle *whh = cls;
     820           3 :   uint64_t bserial_id = GNUNET_htonll (serial_id);
     821             :   struct TALER_WIRE_TransferDetails wd;
     822             : 
     823           3 :   switch (http_status) {
     824             :   case MHD_HTTP_OK:
     825             :     {
     826             :       char *subject;
     827             :       char *space;
     828             : 
     829           1 :       wd.amount = details->amount;
     830           1 :       wd.execution_date = details->execution_date;
     831           1 :       subject = GNUNET_strdup (details->wire_transfer_subject);
     832           1 :       space = strchr (subject, (int) ' ');
     833           1 :       if (NULL != space)
     834             :       {
     835             :         /* Space separates the actual wire transfer subject from the
     836             :            exchange base URL (if present, expected only for outgoing
     837             :            transactions).  So we cut the string off at the space. */
     838           1 :         *space = '\0';
     839             :       }
     840             :       /* NOTE: For a real bank, the subject should include a checksum! */
     841           1 :       if (GNUNET_OK !=
     842           1 :           GNUNET_STRINGS_string_to_data (subject,
     843             :                                          strlen (subject),
     844             :                                          &wd.wtid,
     845             :                                          sizeof (wd.wtid)))
     846             :       {
     847             :         /* Ill-formed wire subject, set binary version to all zeros
     848             :            and pass as a string, this time including the part after
     849             :            the space. */
     850           0 :         memset (&wd.wtid,
     851             :                 0,
     852             :                 sizeof (wd.wtid));
     853           0 :         wd.wtid_s = details->wire_transfer_subject;
     854             :       }
     855           1 :       GNUNET_free (subject);
     856           1 :       wd.account_details = details->account_details;
     857             : 
     858           2 :       if ( (NULL != whh->hres_cb) &&
     859             :            (GNUNET_OK !=
     860           1 :             whh->hres_cb (whh->hres_cb_cls,
     861             :                           dir,
     862             :                           &bserial_id,
     863             :                           sizeof (bserial_id),
     864             :                           &wd)) )
     865           0 :         whh->hres_cb = NULL;
     866           1 :       break;
     867             :     }
     868             :   case MHD_HTTP_NO_CONTENT:
     869           2 :     if (NULL != whh->hres_cb)
     870           2 :       (void) whh->hres_cb (whh->hres_cb_cls,
     871             :                            TALER_BANK_DIRECTION_NONE,
     872             :                            NULL,
     873             :                            0,
     874             :                            NULL);
     875           2 :     GNUNET_free (whh);
     876           2 :     break;
     877             :   default:
     878             :     /* FIXME: consider modifying API to pass more specific error code(s)
     879             :        back to the application. */
     880           0 :     GNUNET_break (0);
     881           0 :     if (NULL != whh->hres_cb)
     882           0 :       (void) whh->hres_cb (whh->hres_cb_cls,
     883             :                            TALER_BANK_DIRECTION_NONE,
     884             :                            NULL,
     885             :                            0,
     886             :                            NULL);
     887           0 :     GNUNET_free (whh);
     888           0 :     break;
     889             :   }
     890           3 : }
     891             : 
     892             : 
     893             : /**
     894             :  * Query transfer history of an account.  We use the variable-size
     895             :  * @a start_off to indicate which transfers we are interested in as
     896             :  * different banking systems may have different ways to identify
     897             :  * transfers.  The @a start_off value must thus match the value of
     898             :  * a `row_off` argument previously given to the @a hres_cb.  Use
     899             :  * NULL to query transfers from the beginning of time (with
     900             :  * positive @a num_results) or from the latest committed transfers
     901             :  * (with negative @a num_results).
     902             :  *
     903             :  * @param cls the @e cls of this struct with the plugin-specific state
     904             :  * @param direction what kinds of wire transfers should be returned
     905             :  * @param start_off from which row on do we want to get results, use NULL for the latest; exclusive
     906             :  * @param start_off_len number of bytes in @a start_off; must be `sizeof(uint64_t)`.
     907             :  * @param num_results how many results do we want; negative numbers to go into the past,
     908             :  *                    positive numbers to go into the future starting at @a start_row;
     909             :  *                    must not be zero.
     910             :  * @param hres_cb the callback to call with the transaction history
     911             :  * @param hres_cb_cls closure for the above callback
     912             :  */
     913             : static struct TALER_WIRE_HistoryHandle *
     914           2 : test_get_history (void *cls,
     915             :                   enum TALER_BANK_Direction direction,
     916             :                   const void *start_off,
     917             :                   size_t start_off_len,
     918             :                   int64_t num_results,
     919             :                   TALER_WIRE_HistoryResultCallback hres_cb,
     920             :                   void *hres_cb_cls)
     921             : {
     922           2 :   struct TestClosure *tc = cls;
     923             :   struct TALER_WIRE_HistoryHandle *whh;
     924             :   const uint64_t *start_off_b64;
     925             :   uint64_t start_row;
     926             : 
     927           2 :   if (0 == num_results)
     928             :   {
     929           0 :     GNUNET_break (0);
     930           0 :     return NULL;
     931             :   }
     932           2 :   if (TALER_BANK_DIRECTION_NONE == direction)
     933             :   {
     934           0 :     GNUNET_break (0);
     935           0 :     return NULL;
     936             :   }
     937           2 :   if ( (NULL != start_off) &&
     938             :        (sizeof (uint64_t) != start_off_len) )
     939             :   {
     940           0 :     GNUNET_break (0);
     941           0 :     return NULL;
     942             :   }
     943           2 :   if (NULL == start_off)
     944             :   {
     945           2 :     start_row = UINT64_MAX; /* no start row */
     946             :   }
     947             :   else
     948             :   {
     949           0 :     start_off_b64 = start_off;
     950           0 :     start_row = GNUNET_ntohll (*start_off_b64);
     951             :   }
     952             : 
     953           2 :   whh = GNUNET_new (struct TALER_WIRE_HistoryHandle);
     954           2 :   whh->hres_cb = hres_cb;
     955           2 :   whh->hres_cb_cls = hres_cb_cls;
     956           2 :   whh->hh = TALER_BANK_history (tc->ctx,
     957           2 :                                 tc->bank_uri,
     958           2 :                                 &tc->auth,
     959           2 :                                 (uint64_t) tc->exchange_account_no,
     960             :                                 direction,
     961             :                                 start_row,
     962             :                                 num_results,
     963             :                                 &bhist_cb,
     964             :                                 whh);
     965           2 :   if (NULL == whh->hh)
     966             :   {
     967           0 :     GNUNET_break (0);
     968           0 :     GNUNET_free (whh);
     969           0 :     return NULL;
     970             :   }
     971             : 
     972           2 :   return whh;
     973             : }
     974             : 
     975             : 
     976             : /**
     977             :  * Cancel going over the account's history.
     978             :  *
     979             :  * @param cls the @e cls of this struct with the plugin-specific state
     980             :  * @param whh operation to cancel
     981             :  */
     982             : static void
     983           0 : test_get_history_cancel (void *cls,
     984             :                          struct TALER_WIRE_HistoryHandle *whh)
     985             : {
     986           0 :   TALER_BANK_history_cancel (whh->hh);
     987           0 :   GNUNET_free (whh);
     988           0 : }
     989             : 
     990             : 
     991             : /**
     992             :  * Context for a rejection operation.
     993             :  */
     994             : struct TALER_WIRE_RejectHandle
     995             : {
     996             :   /**
     997             :    * Function to call with the result.
     998             :    */
     999             :   TALER_WIRE_RejectTransferCallback rej_cb;
    1000             : 
    1001             :   /**
    1002             :    * Closure for @e rej_cb.
    1003             :    */
    1004             :   void *rej_cb_cls;
    1005             : 
    1006             :   /**
    1007             :    * Handle to task for timeout of operation.
    1008             :    */
    1009             :   struct GNUNET_SCHEDULER_Task *timeout_task;
    1010             : };
    1011             : 
    1012             : 
    1013             : /**
    1014             :  * Rejection operation failed with timeout, notify callback
    1015             :  * and clean up.
    1016             :  *
    1017             :  * @param cls closure with `struct TALER_WIRE_RejectHandle`
    1018             :  */
    1019             : static void
    1020           0 : timeout_reject (void *cls)
    1021             : {
    1022           0 :   struct TALER_WIRE_RejectHandle *rh = cls;
    1023             : 
    1024           0 :   rh->timeout_task = NULL;
    1025           0 :   rh->rej_cb (rh->rej_cb_cls,
    1026             :               TALER_EC_NOT_IMPLEMENTED /* in the future: TALER_EC_TIMEOUT */);
    1027           0 :   GNUNET_free (rh);
    1028           0 : }
    1029             : 
    1030             : 
    1031             : /**
    1032             :  * Reject an incoming wire transfer that was obtained from the
    1033             :  * history. This function can be used to transfer funds back to
    1034             :  * the sender if the WTID was malformed (i.e. due to a typo).
    1035             :  *
    1036             :  * Calling `reject_transfer` twice on the same wire transfer should
    1037             :  * be idempotent, i.e. not cause the funds to be wired back twice.
    1038             :  * Furthermore, the transfer should henceforth be removed from the
    1039             :  * results returned by @e get_history.
    1040             :  *
    1041             :  * @param cls plugin's closure
    1042             :  * @param start_off offset of the wire transfer in plugin-specific format
    1043             :  * @param start_off_len number of bytes in @a start_off
    1044             :  * @param rej_cb function to call with the result of the operation
    1045             :  * @param rej_cb_cls closure for @a rej_cb
    1046             :  * @return handle to cancel the operation
    1047             :  */
    1048             : static struct TALER_WIRE_RejectHandle *
    1049           0 : test_reject_transfer (void *cls,
    1050             :                       const void *start_off,
    1051             :                       size_t start_off_len,
    1052             :                       TALER_WIRE_RejectTransferCallback rej_cb,
    1053             :                       void *rej_cb_cls)
    1054             : {
    1055             :   struct TALER_WIRE_RejectHandle *rh;
    1056             : 
    1057           0 :   GNUNET_break (0); /* not implemented, just a stub! */
    1058           0 :   rh = GNUNET_new (struct TALER_WIRE_RejectHandle);
    1059           0 :   rh->rej_cb = rej_cb;
    1060           0 :   rh->rej_cb_cls = rej_cb_cls;
    1061           0 :   rh->timeout_task = GNUNET_SCHEDULER_add_now (&timeout_reject,
    1062             :                                                rh);
    1063           0 :   return rh;
    1064             : }
    1065             : 
    1066             : 
    1067             : /**
    1068             :  * Cancel ongoing reject operation.  Note that the rejection may still
    1069             :  * proceed. Basically, if this function is called, the rejection may
    1070             :  * have happened or not.  This function is usually used during shutdown
    1071             :  * or system upgrades.  At a later point, the application must call
    1072             :  * @e reject_transfer again for this wire transfer, unless the
    1073             :  * @e get_history shows that the wire transfer no longer exists.
    1074             :  *
    1075             :  * @param cls plugins' closure
    1076             :  * @param rh operation to cancel
    1077             :  * @return closure of the callback of the operation
    1078             :  */
    1079             : static void *
    1080           0 : test_reject_transfer_cancel (void *cls,
    1081             :                              struct TALER_WIRE_RejectHandle *rh)
    1082             : {
    1083           0 :   void *ret = rh->rej_cb_cls;
    1084             : 
    1085           0 :   GNUNET_SCHEDULER_cancel (rh->timeout_task);
    1086           0 :   GNUNET_free (rh);
    1087           0 :   return ret;
    1088             : }
    1089             : 
    1090             : 
    1091             : /**
    1092             :  * Initialize test-wire subsystem.
    1093             :  *
    1094             :  * @param cls a configuration instance
    1095             :  * @return NULL on error, otherwise a `struct TALER_WIRE_Plugin`
    1096             :  */
    1097             : void *
    1098          25 : libtaler_plugin_wire_test_init (void *cls)
    1099             : {
    1100          25 :   struct GNUNET_CONFIGURATION_Handle *cfg = cls;
    1101             :   struct TestClosure *tc;
    1102             :   struct TALER_WIRE_Plugin *plugin;
    1103             :   char *user;
    1104             :   char *pass;
    1105             : 
    1106          25 :   tc = GNUNET_new (struct TestClosure);
    1107          25 :   if (NULL != cfg)
    1108             :   {
    1109          23 :     if (GNUNET_OK !=
    1110          23 :         GNUNET_CONFIGURATION_get_value_string (cfg,
    1111             :                                                "exchange-wire-test",
    1112             :                                                "BANK_URI",
    1113             :                                                &tc->bank_uri))
    1114             :     {
    1115           0 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1116             :                                  "exchange-wire-test",
    1117             :                                  "BANK_URI");
    1118           0 :       GNUNET_free (tc);
    1119           0 :       return NULL;
    1120             :     }
    1121          23 :     if (GNUNET_OK !=
    1122          23 :         GNUNET_CONFIGURATION_get_value_number (cfg,
    1123             :                                                "exchange-wire-test",
    1124             :                                                "EXCHANGE_ACCOUNT_NUMBER",
    1125             :                                                &tc->exchange_account_no))
    1126             :     {
    1127           0 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1128             :                                  "exchange-wire-test",
    1129             :                                  "EXCHANGE_ACCOUNT_NUMBER");
    1130           0 :       GNUNET_free (tc->bank_uri);
    1131           0 :       GNUNET_free (tc);
    1132           0 :       return NULL;
    1133             :     }
    1134          23 :     if (GNUNET_OK !=
    1135          23 :         GNUNET_CONFIGURATION_get_value_string (cfg,
    1136             :                                                "taler",
    1137             :                                                "CURRENCY",
    1138             :                                                &tc->currency))
    1139             :     {
    1140           0 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1141             :                                  "taler",
    1142             :                                  "CURRENCY");
    1143           0 :       GNUNET_free (tc->bank_uri);
    1144           0 :       GNUNET_free (tc);
    1145           0 :       return NULL;
    1146             :     }
    1147          23 :     if (GNUNET_OK !=
    1148          23 :         GNUNET_CONFIGURATION_get_value_string (cfg,
    1149             :                                                "exchange-wire-test",
    1150             :                                                "USERNAME",
    1151             :                                                &user))
    1152             :     {
    1153           0 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1154             :                                  "exchange-wire-test",
    1155             :                                  "USERNAME");
    1156           0 :       GNUNET_free (tc->bank_uri);
    1157           0 :       GNUNET_free (tc);
    1158           0 :       return NULL;
    1159             :     }
    1160          23 :     if (GNUNET_OK !=
    1161          23 :         GNUNET_CONFIGURATION_get_value_string (cfg,
    1162             :                                                "exchange-wire-test",
    1163             :                                                "PASSWORD",
    1164             :                                                &pass))
    1165             :     {
    1166           0 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1167             :                                  "exchange-wire-test",
    1168             :                                  "PASSWORD");
    1169           0 :       GNUNET_free (tc->bank_uri);
    1170           0 :       GNUNET_free (tc);
    1171           0 :       GNUNET_free (user);
    1172           0 :       return NULL;
    1173             :     }
    1174          23 :     tc->auth.method = TALER_BANK_AUTH_BASIC;
    1175          23 :     tc->auth.details.basic.username = user;
    1176          23 :     tc->auth.details.basic.password = pass;
    1177          23 :     tc->ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
    1178          23 :                                 &tc->rc);
    1179          23 :     tc->rc = GNUNET_CURL_gnunet_rc_create (tc->ctx);
    1180          23 :     if (NULL == tc->ctx)
    1181             :     {
    1182           0 :       GNUNET_break (0);
    1183           0 :       GNUNET_free (tc->currency);
    1184           0 :       GNUNET_free (tc->bank_uri);
    1185           0 :       GNUNET_free (tc->auth.details.basic.username);
    1186           0 :       GNUNET_free (tc->auth.details.basic.password);
    1187           0 :       GNUNET_free (tc);
    1188           0 :       return NULL;
    1189             :     }
    1190             :   }
    1191          25 :   plugin = GNUNET_new (struct TALER_WIRE_Plugin);
    1192          25 :   plugin->cls = tc;
    1193          25 :   plugin->amount_round = &test_amount_round;
    1194          25 :   plugin->get_wire_details = &test_get_wire_details;
    1195          25 :   plugin->sign_wire_details = &test_sign_wire_details;
    1196          25 :   plugin->wire_validate = &test_wire_validate;
    1197          25 :   plugin->prepare_wire_transfer = &test_prepare_wire_transfer;
    1198          25 :   plugin->prepare_wire_transfer_cancel = &test_prepare_wire_transfer_cancel;
    1199          25 :   plugin->execute_wire_transfer = &test_execute_wire_transfer;
    1200          25 :   plugin->execute_wire_transfer_cancel = &test_execute_wire_transfer_cancel;
    1201          25 :   plugin->get_history = &test_get_history;
    1202          25 :   plugin->get_history_cancel = &test_get_history_cancel;
    1203          25 :   plugin->reject_transfer = &test_reject_transfer;
    1204          25 :   plugin->reject_transfer_cancel = &test_reject_transfer_cancel;
    1205          25 :   return plugin;
    1206             : }
    1207             : 
    1208             : 
    1209             : /**
    1210             :  * Shutdown Test wire subsystem.
    1211             :  *
    1212             :  * @param cls a `struct TALER_WIRE_Plugin`
    1213             :  * @return NULL (always)
    1214             :  */
    1215             : void *
    1216          24 : libtaler_plugin_wire_test_done (void *cls)
    1217             : {
    1218          24 :   struct TALER_WIRE_Plugin *plugin = cls;
    1219          24 :   struct TestClosure *tc = plugin->cls;
    1220             : 
    1221          24 :   if (NULL != tc->ctx)
    1222             :   {
    1223          22 :     GNUNET_CURL_fini (tc->ctx);
    1224          22 :     tc->ctx = NULL;
    1225             :   }
    1226          24 :   if (NULL != tc->rc)
    1227             :   {
    1228          22 :     GNUNET_CURL_gnunet_rc_destroy (tc->rc);
    1229          22 :     tc->rc = NULL;
    1230             :   }
    1231          24 :   switch (tc->auth.method)
    1232             :   {
    1233             :   case TALER_BANK_AUTH_NONE:
    1234           2 :     break;
    1235             :   case TALER_BANK_AUTH_BASIC:
    1236          22 :     if (NULL != tc->auth.details.basic.username)
    1237             :     {
    1238          22 :       GNUNET_free (tc->auth.details.basic.username);
    1239          22 :       tc->auth.details.basic.username = NULL;
    1240             :     }
    1241          22 :     if (NULL != tc->auth.details.basic.password)
    1242             :     {
    1243          22 :       GNUNET_free (tc->auth.details.basic.password);
    1244          22 :       tc->auth.details.basic.password = NULL;
    1245             :     }
    1246          22 :     break;
    1247             :   }
    1248          24 :   GNUNET_free_non_null (tc->currency);
    1249          24 :   GNUNET_free_non_null (tc->bank_uri);
    1250          24 :   GNUNET_free (tc);
    1251          24 :   GNUNET_free (plugin);
    1252          24 :   return NULL;
    1253             : }
    1254             : 
    1255             : /* end of plugin_wire_test.c */

Generated by: LCOV version 1.13