LCOV - code coverage report
Current view: top level - exchange - taler-exchange-httpd_wire.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 0 181 0.0 %
Date: 2022-08-25 06:15:09 Functions: 0 11 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2015-2022 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU Affero 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 Affero General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU Affero General Public License along with
      14             :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : /**
      17             :  * @file taler-exchange-httpd_wire.c
      18             :  * @brief Handle /wire requests
      19             :  * @author Christian Grothoff
      20             :  */
      21             : #include "platform.h"
      22             : #include <gnunet/gnunet_json_lib.h>
      23             : #include "taler_dbevents.h"
      24             : #include "taler-exchange-httpd_responses.h"
      25             : #include "taler-exchange-httpd_keys.h"
      26             : #include "taler-exchange-httpd_wire.h"
      27             : #include "taler_json_lib.h"
      28             : #include "taler_mhd_lib.h"
      29             : #include <jansson.h>
      30             : 
      31             : /**
      32             :  * Information we track about wire fees.
      33             :  */
      34             : struct WireFeeSet
      35             : {
      36             : 
      37             :   /**
      38             :    * Kept in a DLL.
      39             :    */
      40             :   struct WireFeeSet *next;
      41             : 
      42             :   /**
      43             :    * Kept in a DLL.
      44             :    */
      45             :   struct WireFeeSet *prev;
      46             : 
      47             :   /**
      48             :    * Actual fees.
      49             :    */
      50             :   struct TALER_WireFeeSet fees;
      51             : 
      52             :   /**
      53             :    * Start date of fee validity (inclusive).
      54             :    */
      55             :   struct GNUNET_TIME_Timestamp start_date;
      56             : 
      57             :   /**
      58             :    * End date of fee validity (exclusive).
      59             :    */
      60             :   struct GNUNET_TIME_Timestamp end_date;
      61             : 
      62             :   /**
      63             :    * Wire method the fees apply to.
      64             :    */
      65             :   char *method;
      66             : };
      67             : 
      68             : 
      69             : /**
      70             :  * State we keep per thread to cache the /wire response.
      71             :  */
      72             : struct WireStateHandle
      73             : {
      74             :   /**
      75             :    * Cached reply for /wire response.
      76             :    */
      77             :   struct MHD_Response *wire_reply;
      78             : 
      79             :   /**
      80             :    * ETag for this response (if any).
      81             :    */
      82             :   char *etag;
      83             : 
      84             :   /**
      85             :    * head of DLL of wire fees.
      86             :    */
      87             :   struct WireFeeSet *wfs_head;
      88             : 
      89             :   /**
      90             :    * Tail of DLL of wire fees.
      91             :    */
      92             :   struct WireFeeSet *wfs_tail;
      93             : 
      94             :   /**
      95             :    * Earliest timestamp of all the wire methods when we have no more fees.
      96             :    */
      97             :   struct GNUNET_TIME_Absolute cache_expiration;
      98             : 
      99             :   /**
     100             :    * @e cache_expiration time, formatted.
     101             :    */
     102             :   char dat[128];
     103             : 
     104             :   /**
     105             :    * For which (global) wire_generation was this data structure created?
     106             :    * Used to check when we are outdated and need to be re-generated.
     107             :    */
     108             :   uint64_t wire_generation;
     109             : 
     110             :   /**
     111             :    * HTTP status to return with this response.
     112             :    */
     113             :   unsigned int http_status;
     114             : 
     115             : };
     116             : 
     117             : 
     118             : /**
     119             :  * Stores the latest generation of our wire response.
     120             :  */
     121             : static struct WireStateHandle *wire_state;
     122             : 
     123             : /**
     124             :  * Handler listening for wire updates by other exchange
     125             :  * services.
     126             :  */
     127             : static struct GNUNET_DB_EventHandler *wire_eh;
     128             : 
     129             : /**
     130             :  * Counter incremented whenever we have a reason to re-build the #wire_state
     131             :  * because something external changed.
     132             :  */
     133             : static uint64_t wire_generation;
     134             : 
     135             : 
     136             : /**
     137             :  * Free memory associated with @a wsh
     138             :  *
     139             :  * @param[in] wsh wire state to destroy
     140             :  */
     141             : static void
     142           0 : destroy_wire_state (struct WireStateHandle *wsh)
     143             : {
     144             :   struct WireFeeSet *wfs;
     145             : 
     146           0 :   while (NULL != (wfs = wsh->wfs_head))
     147             :   {
     148           0 :     GNUNET_CONTAINER_DLL_remove (wsh->wfs_head,
     149             :                                  wsh->wfs_tail,
     150             :                                  wfs);
     151           0 :     GNUNET_free (wfs->method);
     152           0 :     GNUNET_free (wfs);
     153             :   }
     154           0 :   MHD_destroy_response (wsh->wire_reply);
     155           0 :   GNUNET_free (wsh->etag);
     156           0 :   GNUNET_free (wsh);
     157           0 : }
     158             : 
     159             : 
     160             : /**
     161             :  * Function called whenever another exchange process has updated
     162             :  * the wire data in the database.
     163             :  *
     164             :  * @param cls NULL
     165             :  * @param extra unused
     166             :  * @param extra_size number of bytes in @a extra unused
     167             :  */
     168             : static void
     169           0 : wire_update_event_cb (void *cls,
     170             :                       const void *extra,
     171             :                       size_t extra_size)
     172             : {
     173             :   (void) cls;
     174             :   (void) extra;
     175             :   (void) extra_size;
     176           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     177             :               "Received /wire update event\n");
     178           0 :   TEH_check_invariants ();
     179           0 :   wire_generation++;
     180           0 : }
     181             : 
     182             : 
     183             : enum GNUNET_GenericReturnValue
     184           0 : TEH_wire_init ()
     185             : {
     186           0 :   struct GNUNET_DB_EventHeaderP es = {
     187           0 :     .size = htons (sizeof (es)),
     188           0 :     .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED),
     189             :   };
     190             : 
     191           0 :   wire_eh = TEH_plugin->event_listen (TEH_plugin->cls,
     192           0 :                                       GNUNET_TIME_UNIT_FOREVER_REL,
     193             :                                       &es,
     194             :                                       &wire_update_event_cb,
     195             :                                       NULL);
     196           0 :   if (NULL == wire_eh)
     197             :   {
     198           0 :     GNUNET_break (0);
     199           0 :     return GNUNET_SYSERR;
     200             :   }
     201           0 :   return GNUNET_OK;
     202             : }
     203             : 
     204             : 
     205             : void
     206           0 : TEH_wire_done ()
     207             : {
     208           0 :   if (NULL != wire_state)
     209             :   {
     210           0 :     destroy_wire_state (wire_state);
     211           0 :     wire_state = NULL;
     212             :   }
     213           0 :   if (NULL != wire_eh)
     214             :   {
     215           0 :     TEH_plugin->event_listen_cancel (TEH_plugin->cls,
     216             :                                      wire_eh);
     217           0 :     wire_eh = NULL;
     218             :   }
     219           0 : }
     220             : 
     221             : 
     222             : /**
     223             :  * Add information about a wire account to @a cls.
     224             :  *
     225             :  * @param cls a `json_t *` object to expand with wire account details
     226             :  * @param payto_uri the exchange bank account URI to add
     227             :  * @param master_sig master key signature affirming that this is a bank
     228             :  *                   account of the exchange (of purpose #TALER_SIGNATURE_MASTER_WIRE_DETAILS)
     229             :  */
     230             : static void
     231           0 : add_wire_account (void *cls,
     232             :                   const char *payto_uri,
     233             :                   const struct TALER_MasterSignatureP *master_sig)
     234             : {
     235           0 :   json_t *a = cls;
     236             : 
     237           0 :   if (0 !=
     238           0 :       json_array_append_new (
     239             :         a,
     240           0 :         GNUNET_JSON_PACK (
     241             :           GNUNET_JSON_pack_string ("payto_uri",
     242             :                                    payto_uri),
     243             :           GNUNET_JSON_pack_data_auto ("master_sig",
     244             :                                       master_sig))))
     245             :   {
     246           0 :     GNUNET_break (0);   /* out of memory!? */
     247           0 :     return;
     248             :   }
     249             : }
     250             : 
     251             : 
     252             : /**
     253             :  * Closure for #add_wire_fee().
     254             :  */
     255             : struct AddContext
     256             : {
     257             :   /**
     258             :    * Wire method the fees are for.
     259             :    */
     260             :   char *wire_method;
     261             : 
     262             :   /**
     263             :    * Wire state we are building.
     264             :    */
     265             :   struct WireStateHandle *wsh;
     266             : 
     267             :   /**
     268             :    * Array to append the fee to.
     269             :    */
     270             :   json_t *a;
     271             : 
     272             :   /**
     273             :    * Context we hash "everything" we add into. This is used
     274             :    * to compute the etag. Technically, we only hash the
     275             :    * master_sigs, as they imply the rest.
     276             :    */
     277             :   struct GNUNET_HashContext *hc;
     278             : 
     279             :   /**
     280             :    * Set to the maximum end-date seen.
     281             :    */
     282             :   struct GNUNET_TIME_Absolute max_seen;
     283             : };
     284             : 
     285             : 
     286             : /**
     287             :  * Add information about a wire account to @a cls.
     288             :  *
     289             :  * @param cls a `struct AddContext`
     290             :  * @param fees the wire fees we charge
     291             :  * @param start_date from when are these fees valid (start date)
     292             :  * @param end_date until when are these fees valid (end date, exclusive)
     293             :  * @param master_sig master key signature affirming that this is the correct
     294             :  *                   fee (of purpose #TALER_SIGNATURE_MASTER_WIRE_FEES)
     295             :  */
     296             : static void
     297           0 : add_wire_fee (void *cls,
     298             :               const struct TALER_WireFeeSet *fees,
     299             :               struct GNUNET_TIME_Timestamp start_date,
     300             :               struct GNUNET_TIME_Timestamp end_date,
     301             :               const struct TALER_MasterSignatureP *master_sig)
     302             : {
     303           0 :   struct AddContext *ac = cls;
     304             :   struct WireFeeSet *wfs;
     305             : 
     306           0 :   GNUNET_CRYPTO_hash_context_read (ac->hc,
     307             :                                    master_sig,
     308             :                                    sizeof (*master_sig));
     309           0 :   ac->max_seen = GNUNET_TIME_absolute_max (ac->max_seen,
     310             :                                            end_date.abs_time);
     311           0 :   wfs = GNUNET_new (struct WireFeeSet);
     312           0 :   wfs->start_date = start_date;
     313           0 :   wfs->end_date = end_date;
     314           0 :   wfs->fees = *fees;
     315           0 :   wfs->method = GNUNET_strdup (ac->wire_method);
     316           0 :   GNUNET_CONTAINER_DLL_insert (ac->wsh->wfs_head,
     317             :                                ac->wsh->wfs_tail,
     318             :                                wfs);
     319           0 :   if (0 !=
     320           0 :       json_array_append_new (
     321             :         ac->a,
     322           0 :         GNUNET_JSON_PACK (
     323             :           TALER_JSON_pack_amount ("wire_fee",
     324             :                                   &fees->wire),
     325             :           TALER_JSON_pack_amount ("wad_fee",
     326             :                                   &fees->wad),
     327             :           TALER_JSON_pack_amount ("closing_fee",
     328             :                                   &fees->closing),
     329             :           GNUNET_JSON_pack_timestamp ("start_date",
     330             :                                       start_date),
     331             :           GNUNET_JSON_pack_timestamp ("end_date",
     332             :                                       end_date),
     333             :           GNUNET_JSON_pack_data_auto ("sig",
     334             :                                       master_sig))))
     335             :   {
     336           0 :     GNUNET_break (0);   /* out of memory!? */
     337           0 :     return;
     338             :   }
     339             : }
     340             : 
     341             : 
     342             : /**
     343             :  * Create the /wire response from our database state.
     344             :  *
     345             :  * @return NULL on error
     346             :  */
     347             : static struct WireStateHandle *
     348           0 : build_wire_state (void)
     349             : {
     350             :   json_t *wire_accounts_array;
     351             :   json_t *wire_fee_object;
     352           0 :   uint64_t wg = wire_generation; /* must be obtained FIRST */
     353             :   enum GNUNET_DB_QueryStatus qs;
     354             :   struct WireStateHandle *wsh;
     355             :   struct GNUNET_HashContext *hc;
     356             : 
     357           0 :   wsh = GNUNET_new (struct WireStateHandle);
     358           0 :   wsh->wire_generation = wg;
     359           0 :   wire_accounts_array = json_array ();
     360           0 :   GNUNET_assert (NULL != wire_accounts_array);
     361           0 :   qs = TEH_plugin->get_wire_accounts (TEH_plugin->cls,
     362             :                                       &add_wire_account,
     363             :                                       wire_accounts_array);
     364           0 :   if (0 > qs)
     365             :   {
     366           0 :     GNUNET_break (0);
     367           0 :     json_decref (wire_accounts_array);
     368           0 :     wsh->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
     369             :     wsh->wire_reply
     370           0 :       = TALER_MHD_make_error (TALER_EC_GENERIC_DB_FETCH_FAILED,
     371             :                               "get_wire_accounts");
     372           0 :     return wsh;
     373             :   }
     374           0 :   if (0 == json_array_size (wire_accounts_array))
     375             :   {
     376           0 :     json_decref (wire_accounts_array);
     377           0 :     wsh->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
     378             :     wsh->wire_reply
     379           0 :       = TALER_MHD_make_error (TALER_EC_EXCHANGE_WIRE_NO_ACCOUNTS_CONFIGURED,
     380             :                               NULL);
     381           0 :     return wsh;
     382             :   }
     383           0 :   wire_fee_object = json_object ();
     384           0 :   GNUNET_assert (NULL != wire_fee_object);
     385           0 :   wsh->cache_expiration = GNUNET_TIME_UNIT_FOREVER_ABS;
     386           0 :   hc = GNUNET_CRYPTO_hash_context_start ();
     387             :   {
     388             :     json_t *account;
     389             :     size_t index;
     390             : 
     391           0 :     json_array_foreach (wire_accounts_array, index, account) {
     392             :       char *wire_method;
     393           0 :       const char *payto_uri = json_string_value (json_object_get (account,
     394             :                                                                   "payto_uri"));
     395             : 
     396           0 :       GNUNET_assert (NULL != payto_uri);
     397           0 :       wire_method = TALER_payto_get_method (payto_uri);
     398           0 :       if (NULL == wire_method)
     399             :       {
     400           0 :         wsh->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
     401             :         wsh->wire_reply
     402           0 :           = TALER_MHD_make_error (
     403             :               TALER_EC_EXCHANGE_WIRE_INVALID_PAYTO_CONFIGURED,
     404             :               payto_uri);
     405           0 :         json_decref (wire_accounts_array);
     406           0 :         json_decref (wire_fee_object);
     407           0 :         GNUNET_CRYPTO_hash_context_abort (hc);
     408           0 :         return wsh;
     409             :       }
     410           0 :       if (NULL == json_object_get (wire_fee_object,
     411             :                                    wire_method))
     412             :       {
     413           0 :         struct AddContext ac = {
     414             :           .wire_method = wire_method,
     415             :           .wsh = wsh,
     416           0 :           .a = json_array (),
     417             :           .hc = hc
     418             :         };
     419             : 
     420           0 :         GNUNET_assert (NULL != ac.a);
     421           0 :         qs = TEH_plugin->get_wire_fees (TEH_plugin->cls,
     422             :                                         wire_method,
     423             :                                         &add_wire_fee,
     424             :                                         &ac);
     425           0 :         if (0 > qs)
     426             :         {
     427           0 :           GNUNET_break (0);
     428           0 :           json_decref (ac.a);
     429           0 :           json_decref (wire_fee_object);
     430           0 :           json_decref (wire_accounts_array);
     431           0 :           GNUNET_free (wire_method);
     432           0 :           wsh->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
     433             :           wsh->wire_reply
     434           0 :             = TALER_MHD_make_error (TALER_EC_GENERIC_DB_FETCH_FAILED,
     435             :                                     "get_wire_fees");
     436           0 :           GNUNET_CRYPTO_hash_context_abort (hc);
     437           0 :           return wsh;
     438             :         }
     439           0 :         if (0 == json_array_size (ac.a))
     440             :         {
     441           0 :           json_decref (ac.a);
     442           0 :           json_decref (wire_accounts_array);
     443           0 :           json_decref (wire_fee_object);
     444           0 :           wsh->http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
     445             :           wsh->wire_reply
     446           0 :             = TALER_MHD_make_error (TALER_EC_EXCHANGE_WIRE_FEES_NOT_CONFIGURED,
     447             :                                     wire_method);
     448           0 :           GNUNET_free (wire_method);
     449           0 :           GNUNET_CRYPTO_hash_context_abort (hc);
     450           0 :           return wsh;
     451             :         }
     452           0 :         wsh->cache_expiration = GNUNET_TIME_absolute_min (ac.max_seen,
     453             :                                                           wsh->cache_expiration);
     454           0 :         GNUNET_assert (0 ==
     455             :                        json_object_set_new (wire_fee_object,
     456             :                                             wire_method,
     457             :                                             ac.a));
     458             :       }
     459           0 :       GNUNET_free (wire_method);
     460             :     }
     461             :   }
     462             : 
     463             : 
     464           0 :   wsh->wire_reply = TALER_MHD_MAKE_JSON_PACK (
     465             :     GNUNET_JSON_pack_array_steal ("accounts",
     466             :                                   wire_accounts_array),
     467             :     GNUNET_JSON_pack_object_steal ("fees",
     468             :                                    wire_fee_object),
     469             :     GNUNET_JSON_pack_data_auto ("master_public_key",
     470             :                                 &TEH_master_public_key));
     471             :   {
     472             :     struct GNUNET_TIME_Timestamp m;
     473             : 
     474           0 :     m = GNUNET_TIME_absolute_to_timestamp (wsh->cache_expiration);
     475           0 :     TALER_MHD_get_date_string (m.abs_time,
     476           0 :                                wsh->dat);
     477           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     478             :                 "Setting 'Expires' header for '/wire' to '%s'\n",
     479             :                 wsh->dat);
     480           0 :     GNUNET_break (MHD_YES ==
     481             :                   MHD_add_response_header (wsh->wire_reply,
     482             :                                            MHD_HTTP_HEADER_EXPIRES,
     483             :                                            wsh->dat));
     484             :   }
     485             :   /* Set cache control headers: our response varies depending on these headers */
     486           0 :   GNUNET_break (MHD_YES ==
     487             :                 MHD_add_response_header (wsh->wire_reply,
     488             :                                          MHD_HTTP_HEADER_VARY,
     489             :                                          MHD_HTTP_HEADER_ACCEPT_ENCODING));
     490             :   /* Information is always public, revalidate after 1 day */
     491           0 :   GNUNET_break (MHD_YES ==
     492             :                 MHD_add_response_header (wsh->wire_reply,
     493             :                                          MHD_HTTP_HEADER_CACHE_CONTROL,
     494             :                                          "public,max-age=86400"));
     495             : 
     496             :   {
     497             :     struct GNUNET_HashCode h;
     498             :     char etag[sizeof (h) * 2];
     499             :     char *end;
     500             : 
     501           0 :     GNUNET_CRYPTO_hash_context_finish (hc,
     502             :                                        &h);
     503           0 :     end = GNUNET_STRINGS_data_to_string (&h,
     504             :                                          sizeof (h),
     505             :                                          etag,
     506             :                                          sizeof (etag));
     507           0 :     *end = '\0';
     508           0 :     wsh->etag = GNUNET_strdup (etag);
     509           0 :     GNUNET_break (MHD_YES ==
     510             :                   MHD_add_response_header (wsh->wire_reply,
     511             :                                            MHD_HTTP_HEADER_ETAG,
     512             :                                            etag));
     513             :   }
     514           0 :   wsh->http_status = MHD_HTTP_OK;
     515           0 :   return wsh;
     516             : }
     517             : 
     518             : 
     519             : void
     520           0 : TEH_wire_update_state (void)
     521             : {
     522           0 :   struct GNUNET_DB_EventHeaderP es = {
     523           0 :     .size = htons (sizeof (es)),
     524           0 :     .type = htons (TALER_DBEVENT_EXCHANGE_WIRE_UPDATED),
     525             :   };
     526             : 
     527           0 :   TEH_plugin->event_notify (TEH_plugin->cls,
     528             :                             &es,
     529             :                             NULL,
     530             :                             0);
     531           0 :   wire_generation++;
     532           0 : }
     533             : 
     534             : 
     535             : /**
     536             :  * Return the current key state for this thread.  Possibly
     537             :  * re-builds the key state if we have reason to believe
     538             :  * that something changed.
     539             :  *
     540             :  * @return NULL on error
     541             :  */
     542             : struct WireStateHandle *
     543           0 : get_wire_state (void)
     544             : {
     545             :   struct WireStateHandle *old_wsh;
     546             : 
     547           0 :   old_wsh = wire_state;
     548           0 :   if ( (NULL == old_wsh) ||
     549           0 :        (old_wsh->wire_generation < wire_generation) )
     550             :   {
     551             :     struct WireStateHandle *wsh;
     552             : 
     553           0 :     TEH_check_invariants ();
     554           0 :     wsh = build_wire_state ();
     555           0 :     wire_state = wsh;
     556           0 :     if (NULL != old_wsh)
     557           0 :       destroy_wire_state (old_wsh);
     558           0 :     TEH_check_invariants ();
     559           0 :     return wsh;
     560             :   }
     561           0 :   return old_wsh;
     562             : }
     563             : 
     564             : 
     565             : MHD_RESULT
     566           0 : TEH_handler_wire (struct TEH_RequestContext *rc,
     567             :                   const char *const args[])
     568             : {
     569             :   struct WireStateHandle *wsh;
     570             : 
     571             :   (void) args;
     572           0 :   wsh = get_wire_state ();
     573           0 :   if (NULL == wsh)
     574           0 :     return TALER_MHD_reply_with_error (rc->connection,
     575             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
     576             :                                        TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION,
     577             :                                        NULL);
     578             :   {
     579             :     const char *etag;
     580             : 
     581           0 :     etag = MHD_lookup_connection_value (rc->connection,
     582             :                                         MHD_HEADER_KIND,
     583             :                                         MHD_HTTP_HEADER_IF_NONE_MATCH);
     584           0 :     if ( (NULL != etag) &&
     585           0 :          (MHD_HTTP_OK == wsh->http_status) &&
     586           0 :          (NULL != wsh->etag) &&
     587           0 :          (0 == strcmp (etag,
     588           0 :                        wsh->etag)) )
     589             :     {
     590             :       MHD_RESULT ret;
     591             :       struct MHD_Response *resp;
     592             : 
     593           0 :       resp = MHD_create_response_from_buffer (0,
     594             :                                               NULL,
     595             :                                               MHD_RESPMEM_PERSISTENT);
     596           0 :       TALER_MHD_add_global_headers (resp);
     597           0 :       GNUNET_break (MHD_YES ==
     598             :                     MHD_add_response_header (resp,
     599             :                                              MHD_HTTP_HEADER_EXPIRES,
     600             :                                              wsh->dat));
     601           0 :       GNUNET_break (MHD_YES ==
     602             :                     MHD_add_response_header (resp,
     603             :                                              MHD_HTTP_HEADER_ETAG,
     604             :                                              wsh->etag));
     605           0 :       ret = MHD_queue_response (rc->connection,
     606             :                                 MHD_HTTP_NOT_MODIFIED,
     607             :                                 resp);
     608           0 :       GNUNET_break (MHD_YES == ret);
     609           0 :       MHD_destroy_response (resp);
     610           0 :       return ret;
     611             :     }
     612             :   }
     613           0 :   return MHD_queue_response (rc->connection,
     614             :                              wsh->http_status,
     615             :                              wsh->wire_reply);
     616             : }
     617             : 
     618             : 
     619             : const struct TALER_WireFeeSet *
     620           0 : TEH_wire_fees_by_time (
     621             :   struct GNUNET_TIME_Timestamp ts,
     622             :   const char *method)
     623             : {
     624           0 :   struct WireStateHandle *wsh = get_wire_state ();
     625             : 
     626           0 :   for (struct WireFeeSet *wfs = wsh->wfs_head;
     627             :        NULL != wfs;
     628           0 :        wfs = wfs->next)
     629             :   {
     630           0 :     if (0 != strcmp (method,
     631           0 :                      wfs->method))
     632           0 :       continue;
     633           0 :     if ( (GNUNET_TIME_timestamp_cmp (wfs->start_date,
     634             :                                      >,
     635           0 :                                      ts)) ||
     636           0 :          (GNUNET_TIME_timestamp_cmp (ts,
     637             :                                      >=,
     638             :                                      wfs->end_date)) )
     639           0 :       continue;
     640           0 :     return &wfs->fees;
     641             :   }
     642           0 :   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     643             :               "No wire fees for method `%s' at %s configured\n",
     644             :               method,
     645             :               GNUNET_TIME_timestamp2s (ts));
     646           0 :   return NULL;
     647             : }
     648             : 
     649             : 
     650             : /* end of taler-exchange-httpd_wire.c */

Generated by: LCOV version 1.14