summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2020-09-09 23:11:51 +0200
committerChristian Grothoff <christian@grothoff.org>2020-09-09 23:11:51 +0200
commite12f64d45b2f58b716497aab6fd6273b8f92b740 (patch)
tree06edf6f0faf5839dde351aca7f9fd275eedfe7cd /src/backend
parent7302e0cc35bd3de6e84fa1310be094243372a3bc (diff)
downloadmerchant-e12f64d45b2f58b716497aab6fd6273b8f92b740.tar.gz
merchant-e12f64d45b2f58b716497aab6fd6273b8f92b740.tar.bz2
merchant-e12f64d45b2f58b716497aab6fd6273b8f92b740.zip
likely fix for #6581, still needs testcase
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/taler-merchant-httpd.c136
-rw-r--r--src/backend/taler-merchant-httpd.h29
-rw-r--r--src/backend/taler-merchant-httpd_get-orders-ID.c2
-rw-r--r--src/backend/taler-merchant-httpd_post-orders-ID-paid.c13
-rw-r--r--src/backend/taler-merchant-httpd_post-orders-ID-pay.c22
-rw-r--r--src/backend/taler-merchant-httpd_private-get-orders-ID.c2
6 files changed, 196 insertions, 8 deletions
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c
index 22e11d74..a6a45928 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -291,6 +291,40 @@ compute_pay_key (const char *order_id,
/**
+ * Compute @a key to use for @a session_id and @a fulfillment_url in our
+ * #payment_trigger_map.
+ *
+ * @param session_id the session for which @a fulfillment_url matters
+ * @param fulfillment_url fullfillment URL of an order
+ * @param key[out] set to the hash map key to use
+ */
+static void
+compute_pay_key2 (const char *session_id,
+ const char *fulfillment_url,
+ struct GNUNET_HashCode *key)
+{
+ size_t slen = strlen (session_id) + 1;
+ size_t ulen = strlen (fulfillment_url) + 1;
+ char buf[slen + ulen];
+
+ memcpy (buf,
+ session_id,
+ slen);
+ memcpy (&buf[slen],
+ fulfillment_url,
+ ulen);
+ GNUNET_CRYPTO_hash (buf,
+ sizeof (buf),
+ key);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Pay key for %s/%s is %s\n",
+ session_id,
+ fulfillment_url,
+ GNUNET_h2s (key));
+}
+
+
+/**
* Resume processing all suspended connections past timeout.
*
* @param cls unused
@@ -318,6 +352,11 @@ do_resume (void *cls)
GNUNET_CONTAINER_multihashmap_remove (payment_trigger_map,
&sc->key,
sc));
+ if (sc->has_key2)
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (payment_trigger_map,
+ &sc->key2,
+ sc));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Resuming long polled job due to timeout\n");
MHD_resume_connection (sc->con);
@@ -333,6 +372,8 @@ do_resume (void *cls)
* Suspend connection from @a sc until payment has been received.
*
* @param order_id the order that we are waiting on
+ * @param session_id session ID of the requester
+ * @param fulfillment_url fulfillment URL of the contract
* @param mi the merchant instance we are waiting on
* @param sc connection to suspend
* @param min_refund refund amount we are waiting on to be exceeded before resuming,
@@ -340,6 +381,8 @@ do_resume (void *cls)
*/
void
TMH_long_poll_suspend (const char *order_id,
+ const char *session_id,
+ const char *fulfillment_url,
const struct TMH_MerchantInstance *mi,
struct TMH_SuspendedConnection *sc,
const struct TALER_Amount *min_refund)
@@ -355,6 +398,22 @@ TMH_long_poll_suspend (const char *order_id,
&sc->key,
sc,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
+ if ( (NULL != session_id) &&
+ (NULL != fulfillment_url) )
+ {
+ sc->has_key2 = true;
+ compute_pay_key (order_id,
+ &mi->merchant_pub,
+ &sc->key2);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Suspending operation on key2 %s\n",
+ GNUNET_h2s (&sc->key2));
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_put (payment_trigger_map,
+ &sc->key2,
+ sc,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
+ }
if (NULL != min_refund)
{
sc->awaiting_refund = true;
@@ -392,6 +451,9 @@ resume_operation (void *cls,
const struct ResumeData *rd = cls;
struct TMH_SuspendedConnection *sc = value;
+ GNUNET_assert (0 ==
+ GNUNET_memcmp (key,
+ &sc->key));
/* If the conditions are satisfied partially, turn them off for future
calls. */
if ( (sc->awaiting_refund_obtained) &&
@@ -427,6 +489,11 @@ resume_operation (void *cls,
GNUNET_CONTAINER_multihashmap_remove (payment_trigger_map,
key,
sc));
+ if (sc->has_key2)
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (payment_trigger_map,
+ &sc->key2,
+ sc));
GNUNET_assert (sc ==
GNUNET_CONTAINER_heap_remove_node (sc->hn));
sc->hn = NULL;
@@ -476,6 +543,75 @@ TMH_long_poll_resume (const char *order_id,
/**
+ * Function called to resume suspended connections.
+ *
+ * @param cls NULL
+ * @param key key in the #payment_trigger_map
+ * @param value a `struct TMH_SuspendedConnection` to resume
+ * @return #GNUNET_OK (continue to iterate)
+ */
+static int
+resume_operation2 (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
+{
+ struct TMH_SuspendedConnection *sc = value;
+
+ GNUNET_assert (sc->has_key2);
+ GNUNET_assert (0 == GNUNET_memcmp (key,
+ &sc->key2));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Resuming operation suspended pending payment on key %s\n",
+ GNUNET_h2s (key));
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (payment_trigger_map,
+ &sc->key,
+ sc));
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (payment_trigger_map,
+ &sc->key2,
+ sc));
+ GNUNET_assert (sc ==
+ GNUNET_CONTAINER_heap_remove_node (sc->hn));
+ sc->hn = NULL;
+ MHD_resume_connection (sc->con);
+ TMH_trigger_daemon ();
+ return GNUNET_OK;
+}
+
+
+/**
+ * Find out if we have any clients long-polling for @a order_id to be
+ * confirmed at merchant @a mpub, and if so, tell them to resume.
+ *
+ * @param session_id the session for which @a fulfillment_url became paid
+ * @param fulfillment_url fullfillment URL of which an order was paid
+ */
+void
+TMH_long_poll_resume2 (const char *session_id,
+ const char *fulfillment_url)
+{
+ struct GNUNET_HashCode key;
+ int ret;
+
+ compute_pay_key2 (session_id,
+ fulfillment_url,
+ &key);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Resuming operations suspended pending payment on key %s\n",
+ GNUNET_h2s (&key));
+ ret = GNUNET_CONTAINER_multihashmap_get_multiple (payment_trigger_map,
+ &key,
+ &resume_operation2,
+ NULL);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "%u operations remain suspended pending payment (%d)\n",
+ GNUNET_CONTAINER_multihashmap_size (payment_trigger_map),
+ ret);
+}
+
+
+/**
* Shutdown task (magically invoked when the application is being
* quit)
*
diff --git a/src/backend/taler-merchant-httpd.h b/src/backend/taler-merchant-httpd.h
index 0d78312e..c631729d 100644
--- a/src/backend/taler-merchant-httpd.h
+++ b/src/backend/taler-merchant-httpd.h
@@ -344,6 +344,13 @@ struct TMH_SuspendedConnection
struct GNUNET_HashCode key;
/**
+ * Optional session/fulfillment URI-based key
+ * of this entry in the #payment_trigger_map. Used internally by
+ * TMH_long_poll_resume2().
+ */
+ struct GNUNET_HashCode key2;
+
+ /**
* At what time does this request expire? If set in the future, we
* may wait this long for a payment to arrive before responding.
*/
@@ -355,7 +362,7 @@ struct TMH_SuspendedConnection
struct TALER_Amount refund_expected;
/**
- * #GNUNET_YES if we are waiting for a refund.
+ * true if we are waiting for a refund.
*/
bool awaiting_refund;
@@ -364,6 +371,10 @@ struct TMH_SuspendedConnection
*/
bool awaiting_refund_obtained;
+ /**
+ * True if @a key2 is set.
+ */
+ bool has_key2;
};
@@ -411,6 +422,8 @@ TMH_trigger_daemon (void);
* Suspend connection from @a sc until payment has been received.
*
* @param order_id the order that we are waiting on
+ * @param session_id session ID of the requester
+ * @param fulfillment_url fulfillment URL of the contract
* @param mi the merchant instance we are waiting on
* @param sc connection to suspend
* @param min_refund refund amount we are waiting on to be exceeded before resuming,
@@ -418,6 +431,8 @@ TMH_trigger_daemon (void);
*/
void
TMH_long_poll_suspend (const char *order_id,
+ const char *session_id,
+ const char *fulfillment_url,
const struct TMH_MerchantInstance *mi,
struct TMH_SuspendedConnection *sc,
const struct TALER_Amount *min_refund);
@@ -440,6 +455,18 @@ TMH_long_poll_resume (const char *order_id,
/**
+ * Find out if we have any clients long-polling for @a order_id to be
+ * confirmed at merchant @a mpub, and if so, tell them to resume.
+ *
+ * @param session_id the session for which @a fulfillment_url became paid
+ * @param fulfillment_url fullfillment URL of which an order was paid
+ */
+void
+TMH_long_poll_resume2 (const char *session_id,
+ const char *fulfillment_url);
+
+
+/**
* Decrement reference counter of @a mi, and free if it hits zero.
*
* @param[in,out] mi merchant instance to update and possibly free
diff --git a/src/backend/taler-merchant-httpd_get-orders-ID.c b/src/backend/taler-merchant-httpd_get-orders-ID.c
index 82d74f48..e875a3be 100644
--- a/src/backend/taler-merchant-httpd_get-orders-ID.c
+++ b/src/backend/taler-merchant-httpd_get-orders-ID.c
@@ -192,6 +192,8 @@ suspend_god (struct GetOrderData *god)
"Suspending GET /orders/%s\n",
god->order_id);
TMH_long_poll_suspend (god->order_id,
+ god->session_id,
+ god->fulfillment_url,
god->hc->instance,
&god->sc,
god->sc.awaiting_refund
diff --git a/src/backend/taler-merchant-httpd_post-orders-ID-paid.c b/src/backend/taler-merchant-httpd_post-orders-ID-paid.c
index bcb9aa07..bd2c555a 100644
--- a/src/backend/taler-merchant-httpd_post-orders-ID-paid.c
+++ b/src/backend/taler-merchant-httpd_post-orders-ID-paid.c
@@ -180,11 +180,16 @@ TMH_post_orders_ID_paid (const struct TMH_RequestHandler *rh,
NULL);
}
}
+ if (NULL != session_id)
{
- // FIXME-#6581: extract fulfillment_url from contract_terms.
- // IF present, *ALSO* resume long-polling clients for the
- // same fulfillment URL + session_id!
- // NOTE: also should do the same in the pay handler!
+ const char *fulfillment_url;
+
+ fulfillment_url
+ = json_string_value (json_object_get (contract_terms,
+ "fulfillment_url"));
+ if (NULL != fulfillment_url)
+ TMH_long_poll_resume2 (session_id,
+ fulfillment_url);
}
json_decref (contract_terms);
diff --git a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c
index 9c75e487..fd6cc7ab 100644
--- a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c
+++ b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c
@@ -199,6 +199,11 @@ struct PayContext
char *order_id;
/**
+ * Fulfillment URL from the contract, or NULL if we don't have one.
+ */
+ char *fulfillment_url;
+
+ /**
* Serial number of this order in the database (set once we did the lookup).
*/
uint64_t order_serial;
@@ -521,6 +526,7 @@ pay_context_cleanup (void *cls)
pc->response = NULL;
}
GNUNET_free (pc->order_id);
+ GNUNET_free (pc->fulfillment_url);
GNUNET_free (pc->session_id);
GNUNET_CONTAINER_DLL_remove (pc_head,
pc_tail,
@@ -1443,6 +1449,10 @@ begin_transaction (struct PayContext *pc)
}
/* Notify clients that have been waiting for the payment to succeed */
+ if ( (NULL != pc->session_id) &&
+ (NULL != pc->fulfillment_url) )
+ TMH_long_poll_resume2 (pc->session_id,
+ pc->fulfillment_url);
TMH_long_poll_resume (pc->order_id,
hc->instance,
NULL,
@@ -1729,10 +1739,16 @@ parse_pay (struct MHD_Connection *connection,
GNUNET_JSON_spec_end ()
};
enum GNUNET_GenericReturnValue res;
+ const char *fulfillment_url;
res = TALER_MHD_parse_internal_json_data (connection,
contract_terms,
espec);
+ fulfillment_url
+ = json_string_value (json_object_get (contract_terms,
+ "fulfillment_url"));
+ if (NULL != fulfillment_url)
+ pc->fulfillment_url = GNUNET_strdup (fulfillment_url);
json_decref (contract_terms);
if (GNUNET_YES != res)
{
@@ -1884,9 +1900,9 @@ TMH_post_orders_ID_pay (const struct TMH_RequestHandler *rh,
"Suspending pay handling while working with the exchange\n");
GNUNET_assert (NULL == pc->timeout_task);
pc->timeout_task =
- GNUNET_SCHEDULER_add_delayed (get_pay_timeout (pc->coins_cnt),
- &handle_pay_timeout,
- pc);
+ GNUNET_SCHEDULER_add_delayed (get_pay_timeout (pc->coins_cnt),
+ &handle_pay_timeout,
+ pc);
begin_transaction (pc);
return MHD_YES;
}
diff --git a/src/backend/taler-merchant-httpd_private-get-orders-ID.c b/src/backend/taler-merchant-httpd_private-get-orders-ID.c
index 5c43416b..d3413614 100644
--- a/src/backend/taler-merchant-httpd_private-get-orders-ID.c
+++ b/src/backend/taler-merchant-httpd_private-get-orders-ID.c
@@ -1035,6 +1035,8 @@ TMH_private_get_orders_ID (const struct TMH_RequestHandler *rh,
"Suspending GET /private/orders/%s\n",
hc->infix);
TMH_long_poll_suspend (hc->infix,
+ gorc->session_id,
+ gorc->fulfillment_url,
hc->instance,
&gorc->sc,
NULL);