summaryrefslogtreecommitdiff
path: root/src/backend/taler-merchant-httpd_private-post-reserves.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/taler-merchant-httpd_private-post-reserves.c')
-rw-r--r--src/backend/taler-merchant-httpd_private-post-reserves.c288
1 files changed, 288 insertions, 0 deletions
diff --git a/src/backend/taler-merchant-httpd_private-post-reserves.c b/src/backend/taler-merchant-httpd_private-post-reserves.c
new file mode 100644
index 00000000..abb6d0b5
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_private-post-reserves.c
@@ -0,0 +1,288 @@
+/*
+ This file is part of TALER
+ (C) 2020 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation; either version 3,
+ or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not,
+ see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file backend/taler-merchant-httpd_private-post-reserves.c
+ * @brief implementing POST /reserves request handling
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler-merchant-httpd_exchanges.h"
+#include "taler-merchant-httpd_private-post-reserves.h"
+#include <taler/taler_json_lib.h>
+
+
+/**
+ * Information we keep for an individual call to the POST /reserves handler.
+ */
+struct PostReserveContext
+{
+
+ /**
+ * Stored in a DLL.
+ */
+ struct PostReserveContext *next;
+
+ /**
+ * Stored in a DLL.
+ */
+ struct PostReserveContext *prev;
+
+ /**
+ * Array with @e coins_cnt coins we are despositing.
+ */
+ struct DepositConfirmation *dc;
+
+ /**
+ * MHD connection to return to
+ */
+ struct MHD_Connection *connection;
+
+ /**
+ * Details about the client's request.
+ */
+ struct TMH_HandlerContext *hc;
+
+ /**
+ * URL of the exchange.
+ */
+ const char *exchange_url;
+
+ /**
+ * URI of the exchange where the payment needs to be made to.
+ */
+ char *payto_uri;
+
+ /**
+ * Handle for contacting the exchange.
+ */
+ struct TMH_EXCHANGES_FindOperation *fo;
+
+ /**
+ * Initial balance of the reserve.
+ */
+ struct TALER_Amount initial_balance;
+
+ /**
+ * When will the reserve expire.
+ */
+ struct GNUNET_TIME_Absolute reserve_expiration;
+
+ /**
+ * Are we suspended?
+ */
+ bool suspended;
+};
+
+
+/**
+ * Stored in a DLL.
+ */
+static struct PostReserveContext *rc_head;
+
+/**
+ * Stored in a DLL.
+ */
+static struct PostReserveContext *rc_tail;
+
+
+/**
+ * Force all post reserve contexts to be resumed as we are about
+ * to shut down MHD.
+ */
+void
+TMH_force_rc_resume ()
+{
+ for (struct PostReserveContext *rc = rc_head;
+ NULL != rc;
+ rc = rc->next)
+ {
+ if (rc->suspended)
+ {
+ rc->suspended = false;
+ MHD_resume_connection (rc->connection);
+ GNUNET_CONTAINER_DLL_remove (rc_head,
+ rc_tail,
+ rc);
+ }
+ if (NULL != rc->fo)
+ {
+ TMH_EXCHANGES_find_exchange_cancel (rc->fo);
+ rc->fo = NULL;
+ }
+ }
+}
+
+
+/**
+ * Custom cleanup routine for a `struct PostReserveContext`.
+ *
+ * @param cls the `struct PostReserveContext` to clean up.
+ */
+static void
+reserve_context_cleanup (void *cls)
+{
+ struct PostReserveContext *rc = cls;
+
+ if (NULL != rc->fo)
+ {
+ TMH_EXCHANGES_find_exchange_cancel (rc->fo);
+ rc->fo = NULL;
+ }
+ GNUNET_assert (! rc->suspended);
+ GNUNET_free_non_null (rc->payto_uri);
+ GNUNET_free (rc);
+}
+
+
+/**
+ * Function called with the result of a #TMH_EXCHANGES_find_exchange()
+ * operation.
+ *
+ * @param cls closure with our `struct PostReserveContext *`
+ * @param hr HTTP response details
+ * @param payto_uri URI of the exchange for the wire transfer, NULL on errors
+ * @param eh handle to the exchange context
+ * @param wire_fee current applicable wire fee for dealing with @a eh, NULL if not available
+ * @param exchange_trusted true if this exchange is trusted by config
+ */
+static void
+handle_exchange (void *cls,
+ const struct TALER_EXCHANGE_HttpResponse *hr,
+ struct TALER_EXCHANGE_Handle *eh,
+ const char *payto_uri,
+ const struct TALER_Amount *wire_fee,
+ bool exchange_trusted)
+{
+ struct PostReserveContext *rc = cls;
+ const struct TALER_EXCHANGE_Keys *keys;
+
+ rc->suspended = false;
+ MHD_resume_connection (rc->connection);
+ keys = TALER_EXCHANGE_get_keys (eh);
+ if ( (NULL != keys) &&
+ (NULL != payto_uri) )
+ {
+ rc->reserve_expiration
+ = GNUNET_TIME_relative_to_absolute (keys->reserve_closing_delay);
+ rc->payto_uri = GNUNET_strdup (payto_uri);
+ }
+}
+
+
+/**
+ * Generate a reserve, given its keys and balance.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] hc context with further information about the request
+ * @return MHD result code
+ */
+MHD_RESULT
+TMH_private_post_reserves (const struct TMH_RequestHandler *rh,
+ struct MHD_Connection *connection,
+ struct TMH_HandlerContext *hc)
+{
+ struct PostReserveContext *rc = hc->ctx;
+ struct TMH_MerchantInstance *mi = hc->instance;
+
+ GNUNET_assert (NULL != mi);
+ if (NULL == rc)
+ {
+ const char *wire_method;
+
+ rc = GNUNET_new (struct PostReserveContext);
+ rc->connection = connection;
+ rc->hc = hc;
+ hc->ctx = rc;
+ hc->cc = &reserve_context_cleanup;
+
+ {
+ enum GNUNET_GenericReturnValue res;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("exchange_url",
+ &rc->exchange_url),
+ GNUNET_JSON_spec_string ("wire_method",
+ &wire_method),
+ TALER_JSON_spec_amount ("initial_balance",
+ &rc->initial_balance),
+ GNUNET_JSON_spec_end ()
+ };
+ res = TALER_MHD_parse_json_data (connection,
+ hc->request_body,
+ spec);
+ if (GNUNET_OK != res)
+ return (GNUNET_NO == res)
+ ? MHD_YES
+ : MHD_NO;
+ }
+ rc->fo = TMH_EXCHANGES_find_exchange (rc->exchange_url,
+ wire_method,
+ GNUNET_NO,
+ &handle_exchange,
+ rc);
+ rc->suspended = true;
+ GNUNET_CONTAINER_DLL_insert (rc_head,
+ rc_tail,
+ rc);
+ MHD_suspend_connection (connection);
+ return MHD_YES;
+ }
+
+ GNUNET_assert (! rc->suspended);
+ if (NULL == rc->payto_uri)
+ {
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_RESERVES_POST_UNSUPPORTED_WIRE_METHOD,
+ "Exchange does not support wire method");
+ }
+ {
+ struct TALER_ReservePublicKeyP reserve_pub;
+ struct TALER_ReservePrivateKeyP reserve_priv;
+ enum GNUNET_DB_QueryStatus qs;
+
+ GNUNET_CRYPTO_eddsa_key_create (&reserve_priv.eddsa_priv);
+ GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv.eddsa_priv,
+ &reserve_pub.eddsa_pub);
+ qs = TMH_db->insert_reserve (TMH_db->cls,
+ mi->settings.id,
+ &reserve_priv,
+ &reserve_pub,
+ rc->exchange_url,
+ &rc->initial_balance,
+ rc->reserve_expiration);
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
+ if (qs < 0)
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_RESERVES_POST_DB_COMMIT_HARD_ERROR,
+ "Failed to commit transaction");
+ return TALER_MHD_reply_json_pack (connection,
+ MHD_HTTP_OK,
+ "{s:o,s:s}",
+ "reserve_pub",
+ GNUNET_JSON_from_data_auto (&reserve_pub),
+ "payto_uri",
+ rc->payto_uri);
+ }
+}
+
+
+/* end of taler-merchant-httpd_private-post-reserves.c */