diff options
Diffstat (limited to 'src/backend/taler-merchant-httpd_pay.c')
-rw-r--r-- | src/backend/taler-merchant-httpd_pay.c | 681 |
1 files changed, 314 insertions, 367 deletions
diff --git a/src/backend/taler-merchant-httpd_pay.c b/src/backend/taler-merchant-httpd_pay.c index 23aa178d..a8d85cc2 100644 --- a/src/backend/taler-merchant-httpd_pay.c +++ b/src/backend/taler-merchant-httpd_pay.c @@ -32,29 +32,65 @@ #include "taler-merchant-httpd_parsing.h" #include "taler-merchant-httpd_responses.h" #include "taler-merchant-httpd_mhd.h" +#include "taler-merchant-httpd_mints.h" #include "taler_merchantdb_lib.h" /** - * Outcome of a /deposit request for a coin. Typically forming an array enclosed - * into the unique PayContext + * Information we keep for an individual call to the /pay handler. + */ +struct PayContext; + + +/** + * Information kept during a /pay request for each coin. */ struct MERCHANT_DepositConfirmation { + + /** + * Reference to the main PayContext + */ + struct PayContext *pc; + /** - * Reference to the per-deposit-handler Context. Needed by the - * cleanup function to get it freed + * */ - struct DepositCallbackContext *dcc; + struct TALER_MINT_DepositHandle *dh; /** * The mint's response body (JSON). Mainly useful in case * some callback needs to send back to the to the wallet the - * outcome of an erroneous coin + * outcome of an erroneous coin. DEAD? */ json_t *proof; /** + * Denomination for this coin. + */ + struct TALER_DenominationPublicKey denom; + + /** + * + */ + struct TALER_Amount percoin_amount; + + /** + * + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + + /** + * + */ + struct TALER_DenominationSignature ub_sig; + + /** + * + */ + struct TALER_CoinSpendSignatureP coin_sig; + + /** * True if this coin's outcome has been read from * its cb */ @@ -65,61 +101,12 @@ struct MERCHANT_DepositConfirmation */ unsigned int exit_status; -}; - - - -/** - * Fetch the deposit fee related to the given coin aggregate. - * @param connection the connection to send an error response to - * @param coin_aggregate a coin "aggregate" is the JSON set of - * values contained in a single cell of the 'coins' array sent - * in a payment - * @param deposit_fee where to store the resulting deposit fee - * @param mint_index the index which points the chosen mint within - * the global 'mints' array - * @return GNUNET_OK if successful, GNUNET_NO if the data supplied - * is invalid (including the case when the key is not found), - * GNUNET_SYSERR upon internal errors - */ -static int -deposit_fee_from_coin_aggregate (struct MHD_Connection *connection, - json_t *coin_aggregate, - struct TALER_Amount *deposit_fee, - unsigned int mint_index) -{ - int res; - const struct TALER_MINT_Keys *keys; - const struct TALER_MINT_DenomPublicKey *denom_details; - struct TALER_DenominationPublicKey denom; + /** + * Offset of this coin into the array of all coins outcomes + */ + unsigned int index; - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_denomination_public_key ("denom_pub", &denom), - TMH_PARSE_MEMBER_END - }; - - res = TMH_PARSE_json_data (connection, - coin_aggregate, - spec); - if (GNUNET_OK != res) - return res; /* may return GNUNET_NO */ - - if (1 == mints[mint_index]->pending) - return GNUNET_SYSERR; - keys = TALER_MINT_get_keys (mints[mint_index]->conn); - denom_details = TALER_MINT_get_denomination_key (keys, &denom); - if (NULL == denom_details) - { - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:o}", - "hint", "unknown denom to mint", - "denom_pub", TALER_json_from_rsa_public_key (denom.rsa_public_key)); - return GNUNET_NO; - } - *deposit_fee = denom_details->fee_deposit; - return GNUNET_OK; -} +}; /** @@ -149,132 +136,260 @@ struct PayContext void *json_parse_context; /** - * Response to return, NULL if we don't have one yet. + * Root node of the request body in JSON. */ - struct MHD_Response *response; + json_t *root; /** - * Transaction id + * Coins included in @e root. + */ + json_t *coins; + + /** + * Mint URI given in @e root. + */ + char *chosen_mint; + + /** + * Transaction ID given in @e root. */ uint64_t transaction_id; /** - * How many coins this paymen is made of. + * Maximum fee from @e root. */ - unsigned int coins_cnt; + struct TALER_Amount max_fee; /** - * HTTP status code to use for the reply, i.e 200 for "OK". - * Special value UINT_MAX is used to indicate hard errors - * (no reply, return MHD_NO). + * Amount from @e root. */ - unsigned int response_code; + struct TALER_Amount amount; -}; + /** + * Timestamp from @e root. + */ + struct GNUNET_TIME_Absolute timestamp; -/** - * Information needed by a single /deposit callback to refer to its - * own coin inside the confirmations array, namely `struct MERCHANT_DepositConfirmation *dc` - * above. Note: this information can NOT be shared between all the callbacks. - */ -struct DepositCallbackContext -{ + /** + * Refund deadline from @e root. + */ + struct GNUNET_TIME_Absolute refund_deadline; /** - * Offset of this coin into the array of all coins outcomes + * "H_contract" from @e root. */ - unsigned int index; + struct GNUNET_HashCode h_contract; /** - * Reference to the main PayContext + * */ - struct PayContext *pc; + struct GNUNET_TIME_Absolute edate; + + /** + * Response to return, NULL if we don't have one yet. + */ + struct MHD_Response *response; + + /** + * Number of coins this payment is made of. + */ + unsigned int coins_cnt; + + /** + * Number of transactions still pending. + */ + unsigned int pending; + + /** + * HTTP status code to use for the reply, i.e 200 for "OK". + * Special value UINT_MAX is used to indicate hard errors + * (no reply, return MHD_NO). + */ + unsigned int response_code; }; + /** * Callback to handle a deposit permission's response. * - * @param cls see `struct MERCHANT_DepositConfirmationCls` (i.e. a poinetr to the global - * array of confirmations and an index for this call in that array). That way, the last - * executed callback can detect that no other confirmations are on the way, and can pack - * a response for the wallet - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful deposit; - * 0 if the mint's reply is bogus (fails to follow the protocol) - * @param proof the received JSON reply, should be kept as proof (and, in case of errors, - * be forwarded to the customer) + * @param cls a `struct MERCHANT_DepositConfirmation` (i.e. a pointer + * into the global array of confirmations and an index for this call + * in that array). That way, the last executed callback can detect + * that no other confirmations are on the way, and can pack a response + * for the wallet + * @param http_status HTTP response code, #MHD_HTTP_OK + * (200) for successful deposit; 0 if the mint's reply is bogus (fails + * to follow the protocol) + * @param proof the received JSON reply, + * should be kept as proof (and, in case of errors, be forwarded to + * the customer) */ static void deposit_cb (void *cls, unsigned int http_status, json_t *proof) { - struct DepositCallbackContext *dcc = cls; - int i; - - /*FIXME the index is the same for every individual cb */ - if (GNUNET_SYSERR == - TALER_MERCHANTDB_deposit_permission_update (db_conn, - dcc->pc->transaction_id, - 0)) - /* TODO */ - printf ("db error\n"); - dcc->pc->dc[dcc->index].ackd = 1; - dcc->pc->dc[dcc->index].exit_status = http_status; - dcc->pc->dc[dcc->index].proof = proof; - - /* loop through the confirmation array and return accordingly */ - for (i = 0; i < dcc->pc->coins_cnt; i++) - { - /* just return if there is at least one coin to be still - confirmed */ - if (! dcc->pc->dc[i].ackd) - { - printf ("still vacant coins\n"); - return; - } - } - - printf ("All /deposit(s) ack'd\n"); - - dcc->pc->response = MHD_create_response_from_buffer (strlen ("All coins ack'd by the mint\n"), - "All coins ack'd by the mint\n", - MHD_RESPMEM_MUST_COPY); - dcc->pc->response_code = MHD_HTTP_OK; - /* Clean up what we can already */ - MHD_resume_connection (dcc->pc->connection); - TM_trigger_daemon (); /* we resumed, kick MHD */ + struct MERCHANT_DepositConfirmation *dc = cls; + struct PayContext *pc = dc->pc; + + /* FIXME: store to DB! */ + dc->ackd = 1; + dc->exit_status = http_status; + dc->proof = proof; /* FIXME: needs rc+1 */ + pc->pending--; + if (0 != pc->pending) + return; /* still more to do */ + + pc->response + = MHD_create_response_from_buffer (strlen ("All coins ack'd by the mint\n"), + "All coins ack'd by the mint\n", + MHD_RESPMEM_MUST_COPY); + /* FIXME: move this logic into a function: */ + pc->response_code = MHD_HTTP_OK; + MHD_resume_connection (pc->connection); + TMH_trigger_daemon (); /* we resumed, kick MHD */ } +/** + * Custom cleanup routine for a `struct PayContext`. + * + * @param hc the `struct PayContext` to clean up. + */ static void pay_context_cleanup (struct TM_HandlerContext *hc) { - int i; struct PayContext *pc = (struct PayContext *) hc; - - for (i = 0; i < pc->coins_cnt; i++) - GNUNET_free_non_null (pc->dc[i].dcc); + unsigned int i; TMH_PARSE_post_cleanup_callback (pc->json_parse_context); + for (i=0;i<pc->coins_cnt;i++) + { + struct MERCHANT_DepositConfirmation *dc = &pc->dc[i]; - #if 0 + /* FIXME: clean up 'dc'! */ + } + GNUNET_free_non_null (pc->dc); if (NULL != pc->response) { - /* undestroyable regardless of the other MHD_destroy_response called - in this source, FIXME */ - MHD_destroy_response (pc->response); pc->response = NULL; } - #endif - - GNUNET_free_non_null (pc->dc); GNUNET_free (pc); } /** + * Function called with the result of our mint lookup. + * + * @param cls the `struct PayContext` + * @param mint NULL if mint was not found to be acceptable + * @param mh NULL if mint was not found to be acceptable + */ +static void +process_pay_with_mint (void *cls, + struct MERCHANT_Mint *mint, + struct TALER_MINT_Handle *mh) +{ + struct PayContext *pc = cls; + struct TALER_Amount acc_fee; + struct TALER_Amount coin_fee; + const struct TALER_MINT_Keys *keys; + unsigned int i; + + if (NULL == mint) + { + /* The mint on offer is not in the set of our (trusted) + mints. Reject the payment. */ + MHD_resume_connection (pc->connection); + pc->response_code = 403; + pc->response = TMH_RESPONSE_make_external_error ("unknown mint"); + TMH_trigger_daemon (); + return; + } + + keys = TALER_MINT_get_keys (mh); + if (NULL == keys) + { + GNUNET_break (0); + pc->response_code = UINT_MAX; + pc->response = TMH_RESPONSE_make_internal_error ("no keys"); + TMH_trigger_daemon (); + return; + } + + /* FIXME: do not just total up the fees, but also + the value of the deposited coins! */ + for (i=0;i<pc->coins_cnt;i++) + { + struct MERCHANT_DepositConfirmation *dc = &pc->dc[i]; + const struct TALER_MINT_DenomPublicKey *denom_details; + + denom_details = TALER_MINT_get_denomination_key (keys, + &dc->denom); + if (NULL == denom_details) + { + pc->response_code = MHD_HTTP_BAD_REQUEST; + pc->response + = TMH_RESPONSE_make_json_pack ("{s:s, s:o}", + "hint", "unknown denom to mint", + "denom_pub", TALER_json_from_rsa_public_key (dc->denom.rsa_public_key)); + TMH_trigger_daemon (); + return; + } + if (0 == i) + acc_fee = denom_details->fee_deposit; + else + TALER_amount_add (&acc_fee, + &denom_details->fee_deposit, + &coin_fee); + } + + if (-1 == TALER_amount_cmp (&pc->max_fee, + &acc_fee)) + { + pc->response_code = MHD_HTTP_NOT_ACCEPTABLE; + pc->response = TMH_RESPONSE_make_external_error ("fees too high"); + TMH_trigger_daemon (); + return; + } + + /* Initiate /deposit operation for all coins */ + for (i=0;i<pc->coins_cnt;i++) + { + struct MERCHANT_DepositConfirmation *dc = &pc->dc[i]; + + dc->dh = TALER_MINT_deposit (mh, + &dc->percoin_amount, + pc->edate, + j_wire, + &pc->h_contract, + &dc->coin_pub, + &dc->ub_sig, + &dc->denom, + pc->timestamp, + pc->transaction_id, + &pubkey, + pc->refund_deadline, + &dc->coin_sig, + &deposit_cb, + dc); + if (NULL == dc->dh) + { + MHD_resume_connection (pc->connection); + pc->response_code = MHD_HTTP_SERVICE_UNAVAILABLE; + pc->response = TMH_RESPONSE_make_json_pack ("{s:s, s:i}", + "mint", pc->chosen_mint, + "transaction_id", pc->transaction_id); + TMH_trigger_daemon (); + return; + } + } +} + + +/** * Accomplish this payment. * * @param rh context of the handler @@ -294,52 +409,9 @@ MH_handler_pay (struct TMH_RequestHandler *rh, size_t *upload_data_size) { struct PayContext *pc; - json_t *root; - json_t *coins; - char *chosen_mint; - json_t *coin_aggregate; - unsigned int mint_index; /*a cell in the global array*/ - unsigned int coins_index; - unsigned int coins_cnt; - uint64_t transaction_id; int res; - struct TALER_MINT_DepositHandle *dh; - struct TALER_Amount max_fee; - struct TALER_Amount acc_fee; - struct TALER_Amount coin_fee; - struct TALER_Amount amount; - struct TALER_Amount percoin_amount; - struct GNUNET_TIME_Absolute edate; - struct GNUNET_TIME_Absolute timestamp; - struct GNUNET_TIME_Absolute refund_deadline; - struct TALER_MerchantPublicKeyP pubkey; - struct TALER_CoinSpendPublicKeyP coin_pub; - struct TALER_DenominationPublicKey denom_pub; - struct TALER_DenominationSignature ub_sig; - struct TALER_CoinSpendSignatureP coin_sig; - struct GNUNET_HashCode h_contract; - struct MERCHANT_DepositConfirmation *dc; - - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_array ("coins", &coins), - TMH_PARSE_member_string ("mint", &chosen_mint), - TMH_PARSE_member_amount ("max_fee", &max_fee), - TMH_PARSE_member_amount ("amount", &amount), - TMH_PARSE_member_time_abs ("timestamp", ×tamp), - TMH_PARSE_member_time_abs ("refund_deadline", &refund_deadline), - TMH_PARSE_member_uint64 ("transaction_id", &transaction_id), - TMH_PARSE_member_fixed ("H_contract", &h_contract), - TMH_PARSE_MEMBER_END - }; - - struct TMH_PARSE_FieldSpecification coin_aggregate_spec[] = { - TMH_PARSE_member_amount ("f", &percoin_amount), - TMH_PARSE_member_fixed ("coin_pub", &coin_pub.eddsa_pub), - TMH_PARSE_member_denomination_public_key ("denom_pub", &denom_pub), - TMH_PARSE_member_denomination_signature ("ub_sig", &ub_sig), - TMH_PARSE_member_fixed ("coin_sig", &coin_sig.eddsa_signature), - TMH_PARSE_MEMBER_END - }; + json_t *coin; + unsigned int coins_index; if (NULL == *connection_cls) { @@ -355,21 +427,17 @@ MH_handler_pay (struct TMH_RequestHandler *rh, } if (0 != pc->response_code) { + /* We are *done* processing the request, just queue the response (!) */ if (UINT_MAX == pc->response_code) return MHD_NO; /* hard error */ - /* We are *done* processing the request, just queue the response (!) */ res = MHD_queue_response (connection, pc->response_code, pc->response); - #if 0 - if (pc->response != NULL) + if (NULL != pc->response) { - /* undestroyable regardless of the other MHD_destroy_response called - in this source, FIXME */ MHD_destroy_response (pc->response); pc->response = NULL; } - #endif return res; } @@ -377,202 +445,81 @@ MH_handler_pay (struct TMH_RequestHandler *rh, &pc->json_parse_context, upload_data, upload_data_size, - &root); + &pc->root); if (GNUNET_SYSERR == res) - return MHD_NO; - /* the POST's body has to be further fetched */ - if ((GNUNET_NO == res) || (NULL == root)) - return MHD_YES; - - res = TMH_PARSE_json_data (connection, - root, - spec); + return MHD_NO; /* error parsing JSON */ + if ((GNUNET_NO == res) || (NULL == pc->root)) + return MHD_YES; /* the POST's body has to be further fetched */ - if (GNUNET_YES != res) - return (GNUNET_NO == res) ? MHD_YES : MHD_NO; - - /* 1 Check if the chosen mint is among the merchant's preferred. - - An error in this case could be due to: - - * the wallet indicated a non existent mint - * the wallet indicated a non trusted mint - - NOTE: by preventively checking this, the merchant - avoids getting HTTP response codes from random - websites that may mislead the wallet in the way - of managing the error. Of course, that protect the - merchant from POSTing coins to untrusted mints. - - */ + /* Got the JSON upload, parse it (FIXME: all of this here?) */ - for (mint_index = 0; mint_index <= nmints; mint_index++) + /* We got no 'edate' from frontend. Generate it here; it will be + timestamp plus the edate_delay supplied in config file */ + if (NULL == json_object_get (pc->root, "edate")) { - /* no mint found in array */ - if (mint_index == nmints) - { - mint_index = -1; - break; - } - - /* test it by checking public key */ - if (0 == strcmp (mints[mint_index]->hostname, - chosen_mint)) - break; - - } - - if (-1 == mint_index) - return TMH_RESPONSE_reply_external_error (connection, "unknown mint"); - - /* no 'edate' from frontend. Generate it here; it will be timestamp - + a edate delay supplied in config file */ - if (NULL == json_object_get (root, "edate")) - { - edate = GNUNET_TIME_absolute_add (timestamp, edate_delay); - if (-1 == json_object_set (root, "edate", TALER_json_from_abs (edate))) + pc->edate = GNUNET_TIME_absolute_add (pc->timestamp, // FIXME: uninit! + edate_delay); + if (-1 == json_object_set (pc->root, + "edate", + TALER_json_from_abs (pc->edate))) return MHD_NO; } - coins_cnt = json_array_size (coins); - - if (0 == coins_cnt) - return TMH_RESPONSE_reply_external_error (connection, "no coins given"); - - json_array_foreach (coins, coins_index, coin_aggregate) { - res = deposit_fee_from_coin_aggregate (connection, - coin_aggregate, - &coin_fee, - mint_index); - if (GNUNET_NO == res) - return MHD_YES; - if (GNUNET_SYSERR == res) - return MHD_NO; + struct TMH_PARSE_FieldSpecification spec[] = { + TMH_PARSE_member_array ("coins", &pc->coins), + TMH_PARSE_member_string ("mint", &pc->chosen_mint), + TMH_PARSE_member_amount ("max_fee", &pc->max_fee), + TMH_PARSE_member_amount ("amount", &pc->amount), + TMH_PARSE_member_time_abs ("edate", &pc->edate), + TMH_PARSE_member_time_abs ("timestamp", &pc->timestamp), + TMH_PARSE_member_time_abs ("refund_deadline", &pc->refund_deadline), + TMH_PARSE_member_uint64 ("transaction_id", &pc->transaction_id), + TMH_PARSE_member_fixed ("H_contract", &pc->h_contract), + TMH_PARSE_MEMBER_END + }; - if (0 == coins_index) - acc_fee = coin_fee; - else - TALER_amount_add (&acc_fee, - &acc_fee, - &coin_fee); + res = TMH_PARSE_json_data (connection, + pc->root, + spec); + if (GNUNET_YES != res) + return (GNUNET_NO == res) ? MHD_YES : MHD_NO; + + if (0 == json_array_size (pc->coins)) + return TMH_RESPONSE_reply_external_error (connection, + "no coins given"); } + pc->dc = GNUNET_new_array (json_array_size (pc->coins), + struct MERCHANT_DepositConfirmation); - - if (-1 == TALER_amount_cmp (&max_fee, &acc_fee)) - return MHD_HTTP_NOT_ACCEPTABLE; - - /* cutting off unneeded fields from deposit permission as - gotten from the wallet */ - if (-1 == json_object_del (root, "mint")) - return TMH_RESPONSE_reply_external_error (connection, - "malformed/non-existent 'mint' field"); - if (-1 == json_object_del (root, "coins")) - return TMH_RESPONSE_reply_external_error (connection, - "malformed/non-existent 'coins' field"); - - /* adding our public key to deposit permission */ - GNUNET_CRYPTO_eddsa_key_get_public (privkey, &pubkey.eddsa_pub); - json_object_set_new (root, - "merchant_pub", - TALER_json_from_data (&pubkey, sizeof (pubkey))); - - /* since memory is zero'd out by GNUNET_malloc, any 'ackd' field will be - (implicitly) set to false */ - dc = GNUNET_malloc (coins_cnt * sizeof (struct MERCHANT_DepositConfirmation)); - if (NULL == dc) - return TMH_RESPONSE_reply_internal_error (connection, "memory failure"); - - /* DEBUG CHECKPOINT: return a provisory fullfilment page to the wallet - to test the reception of coins array */ - - #ifdef COINSCHECKPOINT - rh->data = "Coins received\n"; - return TMH_MHD_handler_static_response (rh, - connection, - connection_cls, - upload_data, - upload_data_size); - - #endif - - /* suspend connection until the last coin has been ack'd to the cb. - That last cb will finally resume the connection and send back a response */ - MHD_suspend_connection (connection); - - pc->dc = dc; - pc->coins_cnt = coins_cnt; - pc->transaction_id = transaction_id; - - - json_array_foreach (coins, coins_index, coin_aggregate) + json_array_foreach (pc->coins, coins_index, coin) { + struct MERCHANT_DepositConfirmation *dc = &pc->dc[coins_index]; + struct TMH_PARSE_FieldSpecification spec[] = { + TMH_PARSE_member_denomination_public_key ("denom_pub", &dc->denom), + TMH_PARSE_member_amount ("f", &dc->percoin_amount), + TMH_PARSE_member_fixed ("coin_pub", &dc->coin_pub), + TMH_PARSE_member_denomination_signature ("ub_sig", &dc->ub_sig), + TMH_PARSE_member_fixed ("coin_sig", &dc->coin_sig), + TMH_PARSE_MEMBER_END + }; - /* 3 For each coin in DB - - a. Generate a deposit permission - b. store it in DB - c. POST to the mint (see mint-lib for this) - (retry until getting a persisten state) - */ - - /* a */ - if (-1 == json_object_update (root, coin_aggregate)) - return TMH_RESPONSE_reply_internal_error (connection, - "deposit permission not generated for storing"); - - /* b */ - char *deposit_permission_str = json_dumps (root, JSON_COMPACT); - if (GNUNET_OK != TALER_MERCHANTDB_deposit_permission_store (db_conn, - deposit_permission_str, - transaction_id, - 1, - mints[mint_index]->hostname)) - return TMH_RESPONSE_reply_internal_error (connection, "internal DB failure"); res = TMH_PARSE_json_data (connection, - coin_aggregate, - coin_aggregate_spec); - if (GNUNET_OK != res) - return res; /* may return GNUNET_NO */ - - /* c */ - struct DepositCallbackContext *percoin_dcc = GNUNET_new (struct DepositCallbackContext); - pc->dc[coins_index].dcc = percoin_dcc; - percoin_dcc->index = coins_index; - percoin_dcc->pc = pc; - - dh = TALER_MINT_deposit (mints[mint_index]->conn, - &percoin_amount, - edate, - j_wire, - &h_contract, - &coin_pub, - &ub_sig, - &denom_pub, - timestamp, - transaction_id, - &pubkey, - refund_deadline, - &coin_sig, - &deposit_cb, - percoin_dcc); /*FIXME TODO instantiate an individual cls for each - cb: each of them needs an index which points the - array of all the confirmations */ - if (NULL == dh) - { - MHD_resume_connection (connection); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_SERVICE_UNAVAILABLE, - "{s:s, s:i}", - "mint", mints[mint_index]->hostname, - "transaction_id", transaction_id); - } + coin, + spec); + if (GNUNET_YES != res) + return (GNUNET_NO == res) ? MHD_YES : MHD_NO; + + } - GNUNET_SCHEDULER_cancel (mints[mint_index]->poller_task); - GNUNET_SCHEDULER_add_now (context_task, mints[mint_index]->ctx); + /* Find the responsible mint, this may take a while... */ + TMH_MINTS_find_mint (pc->chosen_mint, + &process_pay_with_mint, + pc); + /* Suspend connection until the last coin has been ack'd or + until we have encountered a hard error. + Eventually, we will resume the connection and send back a response. */ + MHD_suspend_connection (connection); return MHD_YES; - - /* 4 Return response code: success, or whatever data the - mint sent back regarding some bad coin */ } |