LCOV - code coverage report
Current view: top level - exchange - taler-exchange-httpd_refresh_link.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 62 77 80.5 %
Date: 2017-09-17 17:24:28 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014-2017 Inria & GNUnet e.V.
       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_refresh_link.c
      18             :  * @brief Handle /refresh/link requests
      19             :  * @author Florian Dold
      20             :  * @author Benedikt Mueller
      21             :  * @author Christian Grothoff
      22             :  */
      23             : #include "platform.h"
      24             : #include <gnunet/gnunet_util_lib.h>
      25             : #include <jansson.h>
      26             : #include <microhttpd.h>
      27             : #include "taler-exchange-httpd_parsing.h"
      28             : #include "taler-exchange-httpd_mhd.h"
      29             : #include "taler-exchange-httpd_refresh_link.h"
      30             : #include "taler-exchange-httpd_responses.h"
      31             : #include "taler-exchange-httpd_keystate.h"
      32             : 
      33             : 
      34             : /**
      35             :  * @brief Information for each session a coin was melted into.
      36             :  */
      37             : struct TEH_RESPONSE_LinkSessionInfo
      38             : {
      39             :   /**
      40             :    * Transfer public key of the coin.
      41             :    */
      42             :   struct TALER_TransferPublicKeyP transfer_pub;
      43             : 
      44             :   /**
      45             :    * Linked data of coins being created in the session.
      46             :    */
      47             :   struct TALER_EXCHANGEDB_LinkDataList *ldl;
      48             : 
      49             : };
      50             : 
      51             : 
      52             : /**
      53             :  * Closure for #handle_transfer_data().
      54             :  */
      55             : struct HTD_Context
      56             : {
      57             : 
      58             :   /**
      59             :    * Public key of the coin that we are tracing.
      60             :    */
      61             :   struct TALER_CoinSpendPublicKeyP coin_pub;
      62             : 
      63             :   /**
      64             :    * Session link data we collect.
      65             :    */
      66             :   struct TEH_RESPONSE_LinkSessionInfo *sessions;
      67             : 
      68             :   /**
      69             :    * Database session. Nothing to do with @a sessions.
      70             :    */
      71             :   struct TALER_EXCHANGEDB_Session *session;
      72             : 
      73             :   /**
      74             :    * MHD connection, for queueing replies.
      75             :    */
      76             :   struct MHD_Connection *connection;
      77             : 
      78             :   /**
      79             :    * Number of sessions the coin was melted into.
      80             :    */
      81             :   unsigned int num_sessions;
      82             : 
      83             :   /**
      84             :    * How are we expected to proceed. #GNUNET_SYSERR if we
      85             :    * failed to return an error (should return #MHD_NO).
      86             :    * #GNUNET_NO if we succeeded in queueing an MHD error
      87             :    * (should return #MHD_YES from #TEH_execute_refresh_link),
      88             :    * #GNUNET_OK if we should call #reply_refresh_link_success().
      89             :    */
      90             :   int status;
      91             : };
      92             : 
      93             : 
      94             : /**
      95             :  * Send a response for "/refresh/link".
      96             :  *
      97             :  * @param connection the connection to send the response to
      98             :  * @param num_sessions number of sessions the coin was used in
      99             :  * @param sessions array of @a num_session entries with
     100             :  *                  information for each session
     101             :  * @return a MHD result code
     102             :  */
     103             : static int
     104           1 : reply_refresh_link_success (struct MHD_Connection *connection,
     105             :                             unsigned int num_sessions,
     106             :                             const struct TEH_RESPONSE_LinkSessionInfo *sessions)
     107             : {
     108             :   json_t *mlist;
     109             :   int res;
     110             : 
     111           1 :   mlist = json_array ();
     112           2 :   for (unsigned int i=0;i<num_sessions;i++)
     113             :   {
     114           1 :     json_t *list = json_array ();
     115             :     json_t *root;
     116             : 
     117          19 :     for (const struct TALER_EXCHANGEDB_LinkDataList *pos = sessions[i].ldl;
     118             :          NULL != pos;
     119          17 :          pos = pos->next)
     120             :     {
     121             :       json_t *obj;
     122             : 
     123          17 :       obj = json_object ();
     124          17 :       json_object_set_new (obj,
     125             :                            "denom_pub",
     126          17 :                            GNUNET_JSON_from_rsa_public_key (pos->denom_pub.rsa_public_key));
     127          17 :       json_object_set_new (obj,
     128             :                            "ev_sig",
     129          17 :                            GNUNET_JSON_from_rsa_signature (pos->ev_sig.rsa_signature));
     130          17 :       GNUNET_assert (0 ==
     131             :                      json_array_append_new (list,
     132             :                                             obj));
     133             :     }
     134           1 :     root = json_object ();
     135           1 :     json_object_set_new (root,
     136             :                          "new_coins",
     137             :                          list);
     138           1 :     json_object_set_new (root,
     139             :                          "transfer_pub",
     140           1 :                          GNUNET_JSON_from_data_auto (&sessions[i].transfer_pub));
     141           1 :     GNUNET_assert (0 ==
     142             :                    json_array_append_new (mlist,
     143             :                                           root));
     144             :   }
     145           1 :   res = TEH_RESPONSE_reply_json (connection,
     146             :                                  mlist,
     147             :                                  MHD_HTTP_OK);
     148           1 :   json_decref (mlist);
     149           1 :   return res;
     150             : }
     151             : 
     152             : 
     153             : /**
     154             :  * Function called with the session hashes and transfer secret
     155             :  * information for a given coin.  Gets the linkage data and
     156             :  * builds the reply for the client.
     157             :  *
     158             :  *
     159             :  * @param cls closure, a `struct HTD_Context`
     160             :  * @param session_hash a session the coin was melted in
     161             :  * @param transfer_pub public transfer key for the session
     162             :  */
     163             : static void
     164           1 : handle_transfer_data (void *cls,
     165             :                       const struct GNUNET_HashCode *session_hash,
     166             :                       const struct TALER_TransferPublicKeyP *transfer_pub)
     167             : {
     168           1 :   struct HTD_Context *ctx = cls;
     169             :   struct TALER_EXCHANGEDB_LinkDataList *ldl;
     170             :   struct TEH_RESPONSE_LinkSessionInfo *lsi;
     171             :   enum GNUNET_DB_QueryStatus qs;
     172             : 
     173           1 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != ctx->status)
     174           0 :     return;
     175           1 :   ldl = NULL;
     176           1 :   qs = TEH_plugin->get_link_data_list (TEH_plugin->cls,
     177             :                                        ctx->session,
     178             :                                        session_hash,
     179             :                                        &ldl);
     180           1 :   if (qs <= 0) 
     181             :   {
     182           0 :     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
     183           0 :       ctx->status = GNUNET_DB_STATUS_HARD_ERROR;
     184             :     else
     185           0 :       ctx->status = qs;
     186           0 :     return;
     187             :   }
     188           1 :   GNUNET_assert (NULL != ldl);
     189           1 :   GNUNET_array_grow (ctx->sessions,
     190             :                      ctx->num_sessions,
     191             :                      ctx->num_sessions + 1);
     192           1 :   lsi = &ctx->sessions[ctx->num_sessions - 1];
     193           1 :   lsi->transfer_pub = *transfer_pub;
     194           1 :   lsi->ldl = ldl;
     195             : }
     196             : 
     197             : 
     198             : /**
     199             :  * Free session data kept in @a ctx
     200             :  *
     201             :  * @param ctx context to clean up
     202             :  */
     203             : static void
     204           1 : purge_context (struct HTD_Context *ctx)
     205             : {
     206           2 :   for (unsigned int i=0;i<ctx->num_sessions;i++)
     207           2 :     TEH_plugin->free_link_data_list (TEH_plugin->cls,
     208           1 :                                      ctx->sessions[i].ldl);
     209           1 :   GNUNET_free_non_null (ctx->sessions);
     210           1 :   ctx->sessions = NULL;
     211           1 :   ctx->num_sessions = 0;
     212           1 : }
     213             : 
     214             : 
     215             : /**
     216             :  * Execute a "/refresh/link".  Returns the linkage information that
     217             :  * will allow the owner of a coin to follow the refresh trail to
     218             :  * the refreshed coin.
     219             :  *
     220             :  * If it returns a non-error code, the transaction logic MUST
     221             :  * NOT queue a MHD response.  IF it returns an hard error, the
     222             :  * transaction logic MUST queue a MHD response and set @a mhd_ret.  IF
     223             :  * it returns the soft error code, the function MAY be called again to
     224             :  * retry and MUST not queue a MHD response.
     225             :  *
     226             :  * @param cls closure
     227             :  * @param connection MHD request which triggered the transaction
     228             :  * @param session database session to use
     229             :  * @param[out] mhd_ret set to MHD response status for @a connection,
     230             :  *             if transaction failed (!)
     231             :  * @return transaction status
     232             :  */
     233             : static enum GNUNET_DB_QueryStatus
     234           1 : refresh_link_transaction (void *cls,
     235             :                           struct MHD_Connection *connection,
     236             :                           struct TALER_EXCHANGEDB_Session *session,
     237             :                           int *mhd_ret)
     238             : {
     239           1 :   struct HTD_Context *ctx = cls;
     240             :   enum GNUNET_DB_QueryStatus qs;
     241             : 
     242           1 :   ctx->session = session;
     243           1 :   ctx->status = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
     244           2 :   qs = TEH_plugin->get_transfer (TEH_plugin->cls,
     245             :                                  session,
     246           1 :                                  &ctx->coin_pub,
     247             :                                  &handle_transfer_data,
     248             :                                  ctx);
     249           1 :   ctx->session = NULL;
     250           1 :   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
     251             :   {
     252           0 :     *mhd_ret = TEH_RESPONSE_reply_arg_unknown (connection,
     253             :                                                TALER_EC_REFRESH_LINK_COIN_UNKNOWN,
     254             :                                                "coin_pub");
     255           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
     256             :   }
     257           1 :   if (0 < qs)
     258             :   {
     259           1 :     qs = ctx->status;
     260           1 :     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
     261             :     {
     262           0 :       *mhd_ret = TEH_RESPONSE_reply_json_pack (ctx->connection,
     263             :                                                MHD_HTTP_NOT_FOUND,
     264             :                                                "{s:s}",
     265             :                                                "error",
     266             :                                                "link data not found (link)");
     267           0 :       return GNUNET_DB_STATUS_HARD_ERROR;
     268             :     }
     269           1 :     return qs;
     270             :   }
     271           0 :   purge_context (ctx);
     272           0 :   return qs;
     273             : }
     274             : 
     275             : 
     276             : /**
     277             :  * Handle a "/refresh/link" request.  Note that for "/refresh/link"
     278             :  * we do use a simple HTTP GET, and a HTTP POST!
     279             :  *
     280             :  * @param rh context of the handler
     281             :  * @param connection the MHD connection to handle
     282             :  * @param[in,out] connection_cls the connection's closure (can be updated)
     283             :  * @param upload_data upload data
     284             :  * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
     285             :  * @return MHD result code
     286             :   */
     287             : int
     288           1 : TEH_REFRESH_handler_refresh_link (struct TEH_RequestHandler *rh,
     289             :                                   struct MHD_Connection *connection,
     290             :                                   void **connection_cls,
     291             :                                   const char *upload_data,
     292             :                                   size_t *upload_data_size)
     293             : {
     294             :   int mhd_ret;
     295             :   int res;
     296             :   struct HTD_Context ctx;
     297             : 
     298           1 :   memset (&ctx,
     299             :           0,
     300             :           sizeof (ctx));
     301           1 :   res = TEH_PARSE_mhd_request_arg_data (connection,
     302             :                                         "coin_pub",
     303             :                                         &ctx.coin_pub,
     304             :                                         sizeof (struct TALER_CoinSpendPublicKeyP));
     305           1 :   if (GNUNET_SYSERR == res)
     306           0 :     return MHD_NO;
     307           1 :   if (GNUNET_OK != res)
     308           0 :     return MHD_YES;
     309           1 :   if (GNUNET_OK !=
     310           1 :       TEH_DB_run_transaction (connection,
     311             :                               &mhd_ret,
     312             :                               &refresh_link_transaction,
     313             :                               &ctx))
     314             :   {
     315           0 :     purge_context (&ctx);
     316           0 :     return mhd_ret;
     317             :   }
     318           1 :   mhd_ret = reply_refresh_link_success (connection,
     319             :                                         ctx.num_sessions,
     320           1 :                                         ctx.sessions);
     321           1 :   purge_context (&ctx);
     322           1 :   return mhd_ret;
     323             : }
     324             : 
     325             : 
     326             : /* end of taler-exchange-httpd_refresh_link.c */

Generated by: LCOV version 1.13