LCOV - code coverage report
Current view: top level - bank-lib - fakebank.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 191 254 75.2 %
Date: 2017-09-17 17:24:28 Functions: 11 11 100.0 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   (C) 2016, 2017 Inria and GNUnet e.V.
       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 bank-lib/fakebank.c
      19             :  * @brief library that fakes being a Taler bank for testcases
      20             :  * @author Christian Grothoff <christian@grothoff.org>
      21             :  */
      22             : 
      23             : #include "platform.h"
      24             : #include "taler_fakebank_lib.h"
      25             : #include "taler_bank_service.h"
      26             : 
      27             : /**
      28             :  * Maximum POST request size (for /admin/add/incoming)
      29             :  */
      30             : #define REQUEST_BUFFER_MAX (4*1024)
      31             : 
      32             : 
      33             : 
      34             : /**
      35             :  * Details about a transcation we (as the simulated bank) received.
      36             :  */
      37             : struct Transaction
      38             : {
      39             : 
      40             :   /**
      41             :    * We store transactions in a DLL.
      42             :    */
      43             :   struct Transaction *next;
      44             : 
      45             :   /**
      46             :    * We store transactions in a DLL.
      47             :    */
      48             :   struct Transaction *prev;
      49             : 
      50             :   /**
      51             :    * Amount to be transferred.
      52             :    */
      53             :   struct TALER_Amount amount;
      54             : 
      55             :   /**
      56             :    * Account to debit.
      57             :    */
      58             :   uint64_t debit_account;
      59             : 
      60             :   /**
      61             :    * Account to credit.
      62             :    */
      63             :   uint64_t credit_account;
      64             : 
      65             :   /**
      66             :    * Subject of the transfer.
      67             :    */
      68             :   char *subject;
      69             : 
      70             :   /**
      71             :    * Base URL of the exchange.
      72             :    */
      73             :   char *exchange_base_url;
      74             : 
      75             :   /**
      76             :    * When did the transaction happen?
      77             :    */
      78             :   struct GNUNET_TIME_Absolute date;
      79             : 
      80             :   /**
      81             :    * Number of this transaction.
      82             :    */
      83             :   uint64_t serial_id;
      84             : };
      85             : 
      86             : 
      87             : /**
      88             :  * Handle for the fake bank.
      89             :  */
      90             : struct TALER_FAKEBANK_Handle
      91             : {
      92             :   /**
      93             :    * We store transactions in a DLL.
      94             :    */
      95             :   struct Transaction *transactions_head;
      96             : 
      97             :   /**
      98             :    * We store transactions in a DLL.
      99             :    */
     100             :   struct Transaction *transactions_tail;
     101             : 
     102             :   /**
     103             :    * HTTP server we run to pretend to be the "test" bank.
     104             :    */
     105             :   struct MHD_Daemon *mhd_bank;
     106             : 
     107             :   /**
     108             :    * Task running HTTP server for the "test" bank.
     109             :    */
     110             :   struct GNUNET_SCHEDULER_Task *mhd_task;
     111             : 
     112             :   /**
     113             :    * Number of transactions.
     114             :    */
     115             :   uint64_t serial_counter;
     116             : };
     117             : 
     118             : 
     119             : /**
     120             :  * Check that the @a want_amount was transferred from
     121             :  * the @a want_debit to the @a want_credit account.  If
     122             :  * so, set the @a subject to the transfer identifier.
     123             :  * If not, return #GNUNET_SYSERR.
     124             :  *
     125             :  * @param h bank instance
     126             :  * @param want_amount transfer amount desired
     127             :  * @param want_debit account that should have been debited
     128             :  * @param want_credit account that should have been credited
     129             :  * @param exchange_base_url expected base URL of the exchange
     130             :  *        i.e. "https://example.com/"; may include a port
     131             :  * @param[out] subject set to the wire transfer identifier
     132             :  * @return #GNUNET_OK on success
     133             :  */
     134             : int
     135          22 : TALER_FAKEBANK_check (struct TALER_FAKEBANK_Handle *h,
     136             :                       const struct TALER_Amount *want_amount,
     137             :                       uint64_t want_debit,
     138             :                       uint64_t want_credit,
     139             :                       const char *exchange_base_url,
     140             :                       char **subject)
     141             : {
     142          26 :   for (struct Transaction *t = h->transactions_head; NULL != t; t = t->next)
     143             :   {
     144          50 :     if ( (want_debit == t->debit_account) &&
     145          46 :          (want_credit == t->credit_account) &&
     146          22 :          (0 == TALER_amount_cmp (want_amount,
     147          44 :                                  &t->amount)) &&
     148          22 :          (0 == strcasecmp (exchange_base_url,
     149          22 :                            t->exchange_base_url)) )
     150             :     {
     151          22 :       GNUNET_CONTAINER_DLL_remove (h->transactions_head,
     152             :                                    h->transactions_tail,
     153             :                                    t);
     154          22 :       *subject = t->subject;
     155          22 :       GNUNET_free (t->exchange_base_url);
     156          22 :       GNUNET_free (t);
     157          22 :       return GNUNET_OK;
     158             :     }
     159             :   }
     160           0 :   fprintf (stderr,
     161             :            "Did not find matching transaction!\nI have:\n");
     162           0 :   for (struct Transaction *t = h->transactions_head; NULL != t; t = t->next)
     163             :   {
     164             :     char *s;
     165             : 
     166           0 :     s = TALER_amount_to_string (&t->amount);
     167           0 :     fprintf (stderr,
     168             :              "%llu -> %llu (%s) from %s\n",
     169           0 :              (unsigned long long) t->debit_account,
     170           0 :              (unsigned long long) t->credit_account,
     171             :              s,
     172             :              t->exchange_base_url);
     173           0 :     GNUNET_free (s);
     174             :   }
     175           0 :   return GNUNET_SYSERR;
     176             : }
     177             : 
     178             : 
     179             : /**
     180             :  * Tell the fakebank to create another wire transfer.
     181             :  *
     182             :  * @param h fake bank handle
     183             :  * @param debit_account account to debit
     184             :  * @param credit_account account to credit
     185             :  * @param amount amount to transfer
     186             :  * @param subject wire transfer subject to use
     187             :  * @param exchange_base_url exchange URL
     188             :  * @return serial_id of the transfer
     189             :  */
     190             : uint64_t
     191          22 : TALER_FAKEBANK_make_transfer (struct TALER_FAKEBANK_Handle *h,
     192             :                               uint64_t debit_account,
     193             :                               uint64_t credit_account,
     194             :                               const struct TALER_Amount *amount,
     195             :                               const char *subject,
     196             :                               const char *exchange_base_url)
     197             : {
     198             :   struct Transaction *t;
     199             : 
     200          22 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     201             :               "Making transfer from %llu to %llu over %s and subject %s\n",
     202             :               (unsigned long long) debit_account,
     203             :               (unsigned long long) credit_account,
     204             :               TALER_amount2s (amount),
     205             :               subject);
     206          22 :   t = GNUNET_new (struct Transaction);
     207          22 :   t->debit_account = debit_account;
     208          22 :   t->credit_account = credit_account;
     209          22 :   t->amount = *amount;
     210          22 :   t->exchange_base_url = GNUNET_strdup (exchange_base_url);
     211          22 :   t->serial_id = ++h->serial_counter;
     212          22 :   t->date = GNUNET_TIME_absolute_get ();
     213          22 :   t->subject = GNUNET_strdup (subject);
     214          22 :   GNUNET_TIME_round_abs (&t->date);
     215          22 :   GNUNET_CONTAINER_DLL_insert_tail (h->transactions_head,
     216             :                                     h->transactions_tail,
     217             :                                     t);
     218          22 :   return t->serial_id;
     219             : }
     220             : 
     221             : 
     222             : /**
     223             :  * Check that no wire transfers were ordered (or at least none
     224             :  * that have not been taken care of via #TALER_FAKEBANK_check()).
     225             :  * If any transactions are onrecord, return #GNUNET_SYSERR.
     226             :  *
     227             :  * @param h bank instance
     228             :  * @return #GNUNET_OK on success
     229             :  */
     230             : int
     231          22 : TALER_FAKEBANK_check_empty (struct TALER_FAKEBANK_Handle *h)
     232             : {
     233             :   struct Transaction *t;
     234             : 
     235          22 :   if (NULL == h->transactions_head)
     236          22 :     return GNUNET_OK;
     237             : 
     238           0 :   fprintf (stderr,
     239             :            "Expected empty transaction set, but I have:\n");
     240           0 :   for (t = h->transactions_head; NULL != t; t = t->next)
     241             :   {
     242             :     char *s;
     243             : 
     244           0 :     s = TALER_amount_to_string (&t->amount);
     245           0 :     fprintf (stderr,
     246             :              "%llu -> %llu (%s) from %s\n",
     247           0 :              (unsigned long long) t->debit_account,
     248           0 :              (unsigned long long) t->credit_account,
     249             :              s,
     250             :              t->exchange_base_url);
     251           0 :     GNUNET_free (s);
     252             :   }
     253           0 :   return GNUNET_SYSERR;
     254             : }
     255             : 
     256             : 
     257             : /**
     258             :  * Stop running the fake bank.
     259             :  *
     260             :  * @param h bank to stop
     261             :  */
     262             : void
     263           4 : TALER_FAKEBANK_stop (struct TALER_FAKEBANK_Handle *h)
     264             : {
     265             :   struct Transaction *t;
     266             : 
     267           8 :   while (NULL != (t = h->transactions_head))
     268             :   {
     269           0 :     GNUNET_CONTAINER_DLL_remove (h->transactions_head,
     270             :                                  h->transactions_tail,
     271             :                                  t);
     272           0 :     GNUNET_free (t->subject);
     273           0 :     GNUNET_free (t->exchange_base_url);
     274           0 :     GNUNET_free (t);
     275             :   }
     276           4 :   if (NULL != h->mhd_task)
     277             :   {
     278           4 :     GNUNET_SCHEDULER_cancel (h->mhd_task);
     279           4 :     h->mhd_task = NULL;
     280             :   }
     281           4 :   if (NULL != h->mhd_bank)
     282             :   {
     283           4 :     MHD_stop_daemon (h->mhd_bank);
     284           4 :     h->mhd_bank = NULL;
     285             :   }
     286           4 :   GNUNET_free (h);
     287           4 : }
     288             : 
     289             : 
     290             : /**
     291             :  * Function called whenever MHD is done with a request.  If the
     292             :  * request was a POST, we may have stored a `struct Buffer *` in the
     293             :  * @a con_cls that might still need to be cleaned up.  Call the
     294             :  * respective function to free the memory.
     295             :  *
     296             :  * @param cls client-defined closure
     297             :  * @param connection connection handle
     298             :  * @param con_cls value as set by the last call to
     299             :  *        the #MHD_AccessHandlerCallback
     300             :  * @param toe reason for request termination
     301             :  * @see #MHD_OPTION_NOTIFY_COMPLETED
     302             :  * @ingroup request
     303             :  */
     304             : static void
     305          28 : handle_mhd_completion_callback (void *cls,
     306             :                                 struct MHD_Connection *connection,
     307             :                                 void **con_cls,
     308             :                                 enum MHD_RequestTerminationCode toe)
     309             : {
     310             :   /*  struct TALER_FAKEBANK_Handle *h = cls; */
     311             : 
     312          28 :   GNUNET_JSON_post_parser_cleanup (*con_cls);
     313          28 :   *con_cls = NULL;
     314          28 : }
     315             : 
     316             : 
     317             : /**
     318             :  * Handle incoming HTTP request for /admin/add/incoming.
     319             :  *
     320             :  * @param h the fakebank handle
     321             :  * @param connection the connection
     322             :  * @param upload_data request data
     323             :  * @param upload_data_size size of @a upload_data in bytes
     324             :  * @param con_cls closure for request (a `struct Buffer *`)
     325             :  * @return MHD result code
     326             :  */
     327             : static int
     328          63 : handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h,
     329             :                            struct MHD_Connection *connection,
     330             :                            const char *upload_data,
     331             :                            size_t *upload_data_size,
     332             :                            void **con_cls)
     333             : {
     334             :   enum GNUNET_JSON_PostResult pr;
     335             :   json_t *json;
     336             :   struct MHD_Response *resp;
     337             :   int ret;
     338             :   uint64_t serial_id;
     339             : 
     340          63 :   pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
     341             :                                 con_cls,
     342             :                                 upload_data,
     343             :                                 upload_data_size,
     344             :                                 &json);
     345          63 :   switch (pr)
     346             :   {
     347             :   case GNUNET_JSON_PR_OUT_OF_MEMORY:
     348           0 :     GNUNET_break (0);
     349           0 :     return MHD_NO;
     350             :   case GNUNET_JSON_PR_CONTINUE:
     351          42 :     return MHD_YES;
     352             :   case GNUNET_JSON_PR_REQUEST_TOO_LARGE:
     353           0 :     GNUNET_break (0);
     354           0 :     return MHD_NO;
     355             :   case GNUNET_JSON_PR_JSON_INVALID:
     356           0 :     GNUNET_break (0);
     357           0 :     return MHD_NO;
     358             :   case GNUNET_JSON_PR_SUCCESS:
     359          21 :     break;
     360             :   }
     361             :   {
     362             :     const char *wtid;
     363             :     uint64_t debit_account;
     364             :     uint64_t credit_account;
     365             :     const char *base_url;
     366             :     struct TALER_Amount amount;
     367          21 :     struct GNUNET_JSON_Specification spec[] = {
     368             :       GNUNET_JSON_spec_string ("wtid", &wtid),
     369             :       GNUNET_JSON_spec_uint64 ("debit_account", &debit_account),
     370             :       GNUNET_JSON_spec_uint64 ("credit_account", &credit_account),
     371             :       TALER_JSON_spec_amount ("amount", &amount),
     372             :       GNUNET_JSON_spec_string ("exchange_url", &base_url),
     373             :       GNUNET_JSON_spec_end ()
     374             :     };
     375          21 :     if (GNUNET_OK !=
     376          21 :         GNUNET_JSON_parse (json,
     377             :                            spec,
     378             :                            NULL, NULL))
     379             :     {
     380           0 :       GNUNET_break (0);
     381           0 :       json_decref (json);
     382           0 :       return MHD_NO;
     383             :     }
     384          21 :     serial_id = TALER_FAKEBANK_make_transfer (h,
     385             :                                               debit_account,
     386             :                                               credit_account,
     387             :                                               &amount,
     388             :                                               wtid,
     389             :                                               base_url);
     390          21 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     391             :                 "Receiving incoming wire transfer: %llu->%llu from %s\n",
     392             :                 (unsigned long long) debit_account,
     393             :                 (unsigned long long) credit_account,
     394             :                 base_url);
     395             :   }
     396          21 :   json_decref (json);
     397             : 
     398             :   /* Finally build response object */
     399             :   {
     400             :     void *json_str;
     401             :     size_t json_len;
     402             : 
     403          21 :     json = json_pack ("{s:I}",
     404             :                       "serial_id",
     405             :                       (json_int_t) serial_id);
     406          21 :     json_str = json_dumps (json,
     407             :                            JSON_INDENT(2));
     408          21 :     json_decref (json);
     409          21 :     if (NULL == json_str)
     410             :     {
     411           0 :       GNUNET_break (0);
     412           0 :       return MHD_NO;
     413             :     }
     414          21 :     json_len = strlen (json_str);
     415          21 :     resp = MHD_create_response_from_buffer (json_len,
     416             :                                             json_str,
     417             :                                             MHD_RESPMEM_MUST_FREE);
     418          21 :     if (NULL == resp)
     419             :     {
     420           0 :       GNUNET_break (0);
     421           0 :       free (json_str);
     422           0 :       return MHD_NO;
     423             :     }
     424          21 :     (void) MHD_add_response_header (resp,
     425             :                                     MHD_HTTP_HEADER_CONTENT_TYPE,
     426             :                                     "application/json");
     427             :   }
     428          21 :   ret = MHD_queue_response (connection,
     429             :                             MHD_HTTP_OK,
     430             :                             resp);
     431          21 :   MHD_destroy_response (resp);
     432          21 :   return ret;
     433             : }
     434             : 
     435             : 
     436             : /**
     437             :  * Handle incoming HTTP request for /history
     438             :  *
     439             :  * @param h the fakebank handle
     440             :  * @param connection the connection
     441             :  * @param con_cls place to store state, not used
     442             :  * @return MHD result code
     443             :  */
     444             : static int
     445           7 : handle_history (struct TALER_FAKEBANK_Handle *h,
     446             :                 struct MHD_Connection *connection,
     447             :                 void **con_cls)
     448             : {
     449             :   const char *auth;
     450             :   const char *delta;
     451             :   const char *start;
     452             :   const char *dir;
     453             :   const char *acc;
     454             :   unsigned long long account_number;
     455             :   unsigned long long start_number;
     456             :   long long count;
     457             :   enum TALER_BANK_Direction direction;
     458             :   struct Transaction *pos;
     459             :   json_t *history;
     460             :   json_t *jresponse;
     461             :   int ret;
     462             : 
     463           7 :   auth = MHD_lookup_connection_value (connection,
     464             :                                       MHD_GET_ARGUMENT_KIND,
     465             :                                       "auth");
     466           7 :   delta = MHD_lookup_connection_value (connection,
     467             :                                        MHD_GET_ARGUMENT_KIND,
     468             :                                        "delta");
     469           7 :   dir = MHD_lookup_connection_value (connection,
     470             :                                      MHD_GET_ARGUMENT_KIND,
     471             :                                      "direction");
     472           7 :   start = MHD_lookup_connection_value (connection,
     473             :                                        MHD_GET_ARGUMENT_KIND,
     474             :                                        "start");
     475           7 :   acc = MHD_lookup_connection_value (connection,
     476             :                                      MHD_GET_ARGUMENT_KIND,
     477             :                                      "account_number");
     478          14 :   if ( (NULL == auth) ||
     479           7 :        (0 != strcasecmp (auth,
     480           7 :                          "basic")) ||
     481           7 :        (NULL == acc) ||
     482             :        (NULL == delta) )
     483             :   {
     484             :     /* Invalid request, given that this is fakebank we impolitely just
     485             :        kill the connection instead of returning a nice error. */
     486           0 :     GNUNET_break (0);
     487           0 :     return MHD_NO;
     488             :   }
     489           7 :   if ( (1 != sscanf (delta,
     490             :                      "%lld",
     491           7 :                      &count)) ||
     492           7 :        (1 != sscanf (acc,
     493             :                      "%llu",
     494           7 :                      &account_number)) ||
     495           1 :        ( (NULL != start) &&
     496           1 :          (1 != sscanf (start,
     497             :                        "%llu",
     498           7 :                        &start_number)) ) ||
     499           4 :        ( (NULL != dir) &&
     500           4 :          (0 != strcasecmp (dir,
     501           1 :                            "CREDIT")) &&
     502           1 :          (0 != strcasecmp (dir,
     503             :                            "DEBIT")) ) )
     504             :   {
     505             :     /* Invalid request, given that this is fakebank we impolitely just
     506             :        kill the connection instead of returning a nice error. */
     507           0 :     GNUNET_break (0);
     508           0 :     return MHD_NO;
     509             :   }
     510           7 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     511             :               "Client asked for up to %lld results of type %s for account %llu starting at %s\n",
     512             :               count,
     513             :               dir,
     514             :               (unsigned long long) account_number,
     515             :               start);
     516           7 :   if (NULL == dir)
     517           3 :     direction = TALER_BANK_DIRECTION_BOTH;
     518           4 :   else if (0 == strcasecmp (dir,
     519             :                             "CREDIT"))
     520           3 :     direction = TALER_BANK_DIRECTION_CREDIT;
     521             :   else
     522           1 :     direction = TALER_BANK_DIRECTION_DEBIT;
     523           7 :   if (NULL == start)
     524             :   {
     525           6 :     if (count > 0)
     526           6 :       pos = h->transactions_head;
     527             :     else
     528           0 :       pos = h->transactions_tail;
     529             :   }
     530           1 :   else if (NULL != h->transactions_head)
     531             :   {
     532           2 :     for (pos = h->transactions_head;
     533             :          NULL != pos;
     534           0 :          pos = pos->next)
     535           1 :       if (pos->serial_id == start_number)
     536           1 :         break;
     537           1 :     if (NULL == pos)
     538             :     {
     539           0 :       GNUNET_break (0);
     540           0 :       return MHD_NO;
     541             :     }
     542             :     /* range is exclusive, skip the matching entry */
     543           1 :     if (count > 0)
     544           1 :       pos = pos->next;
     545           1 :     if (count < 0)
     546           0 :       pos = pos->prev;
     547             :   }
     548             :   else
     549             :   {
     550             :     /* list is empty */
     551           0 :     pos = NULL;
     552             :   }
     553             : 
     554           7 :   history = json_array ();
     555          30 :   while ( (NULL != pos) &&
     556           8 :           (0 != count) )
     557             :   {
     558             :     json_t *trans;
     559             :     char *subject;
     560             : 
     561           8 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     562             :                 "Found transaction over %s from %llu to %llu\n",
     563             :                 TALER_amount2s (&pos->amount),
     564             :                 (unsigned long long) pos->debit_account,
     565             :                 (unsigned long long) pos->credit_account);
     566             : 
     567          16 :     if (! ( ( (account_number == pos->debit_account) &&
     568           3 :               (0 != (direction & TALER_BANK_DIRECTION_DEBIT)) ) ||
     569          10 :             ( (account_number == pos->credit_account) &&
     570           5 :               (0 != (direction & TALER_BANK_DIRECTION_CREDIT) ) ) ) )
     571             :     {
     572           1 :       if (count > 0)
     573           1 :         pos = pos->next;
     574           1 :       if (count < 0)
     575           0 :         pos = pos->prev;
     576           1 :       continue;
     577             :     }
     578             : 
     579           7 :     GNUNET_asprintf (&subject,
     580             :                      "%s %s",
     581             :                      pos->subject,
     582             :                      pos->exchange_base_url);
     583          42 :     trans = json_pack ("{s:I, s:o, s:o, s:s, s:I, s:s}",
     584           7 :                        "row_id", (json_int_t) pos->serial_id,
     585             :                        "date", GNUNET_JSON_from_time_abs (pos->date),
     586           7 :                        "amount", TALER_JSON_from_amount (&pos->amount),
     587           7 :                        "sign", (account_number == pos->debit_account) ? "-" : "+",
     588           7 :                        "counterpart", (json_int_t) ( (account_number == pos->debit_account)
     589           3 :                                                      ? pos->credit_account
     590           4 :                                                      : pos->debit_account),
     591             :                        "wt_subject", subject);
     592           7 :     GNUNET_free (subject);
     593           7 :     json_array_append (history,
     594             :                        trans);
     595           7 :     if (count > 0)
     596             :     {
     597           7 :       pos = pos->next;
     598           7 :       count--;
     599             :     }
     600           7 :     if (count < 0)
     601             :     {
     602           0 :       pos = pos->prev;
     603           0 :       count++;
     604             :     }
     605             :   }
     606           7 :   if (0 == json_array_size (history))
     607             :   {
     608             :     struct MHD_Response *resp;
     609             : 
     610           3 :     json_decref (history);
     611           3 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     612             :                 "Returning empty transaction history\n");
     613           3 :     resp = MHD_create_response_from_buffer (0,
     614             :                                             "",
     615             :                                             MHD_RESPMEM_PERSISTENT);
     616           3 :     ret = MHD_queue_response (connection,
     617             :                               MHD_HTTP_NO_CONTENT,
     618             :                               resp);
     619           3 :     MHD_destroy_response (resp);
     620           3 :     return ret;
     621             :   }
     622             : 
     623           4 :   jresponse = json_pack ("{s:o}",
     624             :                          "data", history);
     625           4 :   if (NULL == jresponse)
     626             :   {
     627           0 :     GNUNET_break (0);
     628           0 :     return MHD_NO;
     629             :   }
     630             : 
     631             :   /* Finally build response object */
     632             :   {
     633             :     struct MHD_Response *resp;
     634             :     void *json_str;
     635             :     size_t json_len;
     636             : 
     637           4 :     json_str = json_dumps (jresponse,
     638             :                            JSON_INDENT(2));
     639           4 :     json_decref (jresponse);
     640           4 :     if (NULL == json_str)
     641             :     {
     642           0 :       GNUNET_break (0);
     643           0 :       return MHD_NO;
     644             :     }
     645           4 :     json_len = strlen (json_str);
     646           4 :     resp = MHD_create_response_from_buffer (json_len,
     647             :                                             json_str,
     648             :                                             MHD_RESPMEM_MUST_FREE);
     649           4 :     if (NULL == resp)
     650             :     {
     651           0 :       GNUNET_break (0);
     652           0 :       free (json_str);
     653           0 :       return MHD_NO;
     654             :     }
     655           4 :     (void) MHD_add_response_header (resp,
     656             :                                     MHD_HTTP_HEADER_CONTENT_TYPE,
     657             :                                     "application/json");
     658           4 :     ret = MHD_queue_response (connection,
     659             :                               MHD_HTTP_OK,
     660             :                               resp);
     661           4 :     MHD_destroy_response (resp);
     662             :   }
     663           4 :   return ret;
     664             : }
     665             : 
     666             : 
     667             : /**
     668             :  * Handle incoming HTTP request.
     669             :  *
     670             :  * @param cls a `struct TALER_FAKEBANK_Handle`
     671             :  * @param connection the connection
     672             :  * @param url the requested url
     673             :  * @param method the method (POST, GET, ...)
     674             :  * @param version HTTP version (ignored)
     675             :  * @param upload_data request data
     676             :  * @param upload_data_size size of @a upload_data in bytes
     677             :  * @param con_cls closure for request (a `struct Buffer *`)
     678             :  * @return MHD result code
     679             :  */
     680             : static int
     681          70 : handle_mhd_request (void *cls,
     682             :                     struct MHD_Connection *connection,
     683             :                     const char *url,
     684             :                     const char *method,
     685             :                     const char *version,
     686             :                     const char *upload_data,
     687             :                     size_t *upload_data_size,
     688             :                     void **con_cls)
     689             : {
     690          70 :   struct TALER_FAKEBANK_Handle *h = cls;
     691             : 
     692          70 :   if ( (0 == strcasecmp (url,
     693          63 :                          "/admin/add/incoming")) &&
     694          63 :        (0 == strcasecmp (method,
     695             :                          MHD_HTTP_METHOD_POST)) )
     696          63 :     return handle_admin_add_incoming (h,
     697             :                                       connection,
     698             :                                       upload_data,
     699             :                                       upload_data_size,
     700             :                                       con_cls);
     701           7 :   if ( (0 == strcasecmp (url,
     702           7 :                          "/history")) &&
     703           7 :        (0 == strcasecmp (method,
     704             :                          MHD_HTTP_METHOD_GET)) )
     705           7 :     return handle_history (h,
     706             :                            connection,
     707             :                            con_cls);
     708             : 
     709             :   /* Unexpected URI path, just close the connection. */
     710             :   /* we're rather impolite here, but it's a testcase. */
     711           0 :   GNUNET_break_op (0);
     712           0 :   return MHD_NO;
     713             : }
     714             : 
     715             : 
     716             : /**
     717             :  * Task run whenever HTTP server operations are pending.
     718             :  *
     719             :  * @param cls the `struct TALER_FAKEBANK_Handle`
     720             :  */
     721             : static void
     722             : run_mhd (void *cls);
     723             : 
     724             : 
     725             : /**
     726             :  * Schedule MHD.  This function should be called initially when an
     727             :  * MHD is first getting its client socket, and will then automatically
     728             :  * always be called later whenever there is work to be done.
     729             :  */
     730             : static void
     731          63 : schedule_httpd (struct TALER_FAKEBANK_Handle *h)
     732             : {
     733             :   fd_set rs;
     734             :   fd_set ws;
     735             :   fd_set es;
     736             :   struct GNUNET_NETWORK_FDSet *wrs;
     737             :   struct GNUNET_NETWORK_FDSet *wws;
     738             :   int max;
     739             :   int haveto;
     740             :   MHD_UNSIGNED_LONG_LONG timeout;
     741             :   struct GNUNET_TIME_Relative tv;
     742             : 
     743          63 :   FD_ZERO (&rs);
     744          63 :   FD_ZERO (&ws);
     745          63 :   FD_ZERO (&es);
     746          63 :   max = -1;
     747          63 :   if (MHD_YES != MHD_get_fdset (h->mhd_bank, &rs, &ws, &es, &max))
     748             :   {
     749           0 :     GNUNET_assert (0);
     750             :     return;
     751             :   }
     752          63 :   haveto = MHD_get_timeout (h->mhd_bank, &timeout);
     753          63 :   if (MHD_YES == haveto)
     754           0 :     tv.rel_value_us = (uint64_t) timeout * 1000LL;
     755             :   else
     756          63 :     tv = GNUNET_TIME_UNIT_FOREVER_REL;
     757          63 :   if (-1 != max)
     758             :   {
     759          63 :     wrs = GNUNET_NETWORK_fdset_create ();
     760          63 :     wws = GNUNET_NETWORK_fdset_create ();
     761          63 :     GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
     762          63 :     GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
     763             :   }
     764             :   else
     765             :   {
     766           0 :     wrs = NULL;
     767           0 :     wws = NULL;
     768             :   }
     769          63 :   if (NULL != h->mhd_task)
     770           0 :     GNUNET_SCHEDULER_cancel (h->mhd_task);
     771          63 :   h->mhd_task =
     772          63 :     GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
     773             :                                  tv,
     774             :                                  wrs,
     775             :                                  wws,
     776             :                                  &run_mhd, h);
     777          63 :   if (NULL != wrs)
     778          63 :     GNUNET_NETWORK_fdset_destroy (wrs);
     779          63 :   if (NULL != wws)
     780          63 :     GNUNET_NETWORK_fdset_destroy (wws);
     781             : }
     782             : 
     783             : 
     784             : /**
     785             :  * Task run whenever HTTP server operations are pending.
     786             :  *
     787             :  * @param cls the `struct TALER_FAKEBANK_Handle`
     788             :  */
     789             : static void
     790          59 : run_mhd (void *cls)
     791             : {
     792          59 :   struct TALER_FAKEBANK_Handle *h = cls;
     793             : 
     794          59 :   h->mhd_task = NULL;
     795          59 :   MHD_run (h->mhd_bank);
     796          59 :   schedule_httpd (h);
     797          59 : }
     798             : 
     799             : 
     800             : /**
     801             :  * Start the fake bank.
     802             :  *
     803             :  * @param port port to listen to
     804             :  * @return NULL on error
     805             :  */
     806             : struct TALER_FAKEBANK_Handle *
     807           4 : TALER_FAKEBANK_start (uint16_t port)
     808             : {
     809             :   struct TALER_FAKEBANK_Handle *h;
     810             : 
     811           4 :   h = GNUNET_new (struct TALER_FAKEBANK_Handle);
     812           4 :   h->mhd_bank = MHD_start_daemon (MHD_USE_DEBUG,
     813             :                                   port,
     814             :                                   NULL, NULL,
     815             :                                   &handle_mhd_request, h,
     816             :                                   MHD_OPTION_NOTIFY_COMPLETED,
     817             :                                   &handle_mhd_completion_callback, h,
     818             :                                   MHD_OPTION_END);
     819           4 :   if (NULL == h->mhd_bank)
     820             :   {
     821           0 :     GNUNET_free (h);
     822           0 :     return NULL;
     823             :   }
     824           4 :   schedule_httpd (h);
     825           4 :   return h;
     826             : }
     827             : 
     828             : 
     829             : /* end of fakebank.c */

Generated by: LCOV version 1.13