diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/taler-merchant-httpd_private-delete-transfers-ID.c | 2 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_private-post-transfers.c | 154 |
2 files changed, 141 insertions, 15 deletions
diff --git a/src/backend/taler-merchant-httpd_private-delete-transfers-ID.c b/src/backend/taler-merchant-httpd_private-delete-transfers-ID.c index fd5c968a..93656f4a 100644 --- a/src/backend/taler-merchant-httpd_private-delete-transfers-ID.c +++ b/src/backend/taler-merchant-httpd_private-delete-transfers-ID.c @@ -24,7 +24,7 @@ /** - * Handle a DELETE "/transfers/$ID" request. + * Handle a DELETE "/private/transfers/$ID" request. * * @param rh context of the handler * @param connection the MHD connection to handle diff --git a/src/backend/taler-merchant-httpd_private-post-transfers.c b/src/backend/taler-merchant-httpd_private-post-transfers.c index 4fd0819d..5ac4ec9d 100644 --- a/src/backend/taler-merchant-httpd_private-post-transfers.c +++ b/src/backend/taler-merchant-httpd_private-post-transfers.c @@ -146,6 +146,10 @@ struct PostTransfersContext */ bool downloaded; + /** + * Are we currently suspended? + */ + bool suspended; }; @@ -170,6 +174,7 @@ TMH_force_post_transfers_resume () GNUNET_CONTAINER_DLL_remove (ptc_head, ptc_tail, ptc); + ptc->suspended = false; MHD_resume_connection (ptc->connection); if (NULL != ptc->timeout_task) { @@ -207,6 +212,7 @@ resume_transfer_with_response (struct PostTransfersContext *ptc, GNUNET_CONTAINER_DLL_remove (ptc_head, ptc_tail, ptc); + ptc->suspended = false; MHD_resume_connection (ptc->connection); TMH_trigger_daemon (); /* we resumed, kick MHD */ } @@ -468,8 +474,22 @@ wire_transfer_cb (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got response code %u from exchange for GET /transfers/$WTID\n", hr->http_status); - if (MHD_HTTP_OK != hr->http_status) + switch (hr->http_status) { + case MHD_HTTP_OK: + break; + case MHD_HTTP_NOT_FOUND: + resume_transfer_with_response ( + ptc, + MHD_HTTP_BAD_GATEWAY, + TALER_MHD_make_json_pack ( + "{s:I, s:I, s:I}", + "code", + (json_int_t) TALER_EC_MERCHANT_PRIVATE_POST_TRANSFERS_EXCHANGE_UNKNOWN, + "exchange_code", (json_int_t) hr->ec, + "exchange_http_status", (json_int_t) hr->http_status)); + return; + default: resume_transfer_with_response ( ptc, MHD_HTTP_BAD_GATEWAY, @@ -482,7 +502,6 @@ wire_transfer_cb (void *cls, "exchange_reply", hr->reply)); return; } - TMH_db->preflight (TMH_db->cls); /* Ok, exchange answer is acceptable, store it */ qs = TMH_db->insert_transfer_details (TMH_db->cls, @@ -504,6 +523,29 @@ wire_transfer_cb (void *cls, NULL); return; } + if (0 == qs) + { + GNUNET_break (0); + resume_transfer_with_error ( + ptc, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_STORE_FAILED, + "insert-transfer-details"); + return; + } + if (0 != + TALER_amount_cmp (&td->total_amount, + &ptc->amount)) + { + resume_transfer_with_error ( + ptc, + MHD_HTTP_CONFLICT, + TALER_EC_MERCHANT_PRIVATE_POST_TRANSFERS_CONFLICTING_TRANSFERS, + NULL); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Transfer details inserted, resuming request...\n"); /* resume processing, main function will build the response */ resume_transfer_with_response (ptc, 0, @@ -536,6 +578,8 @@ process_transfer_with_exchange (void *cls, ptc->fo = NULL; if (NULL == hr) { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Exchange failed to respond!\n"); resume_transfer_with_response ( ptc, MHD_HTTP_GATEWAY_TIMEOUT, @@ -584,6 +628,8 @@ process_transfer_with_exchange (void *cls, ptc->master_pub = keys->master_pub; } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Requesting transfer details from exchange\n"); ptc->wdh = TALER_EXCHANGE_transfers_get (eh, &ptc->wtid, &wire_transfer_cb, @@ -664,7 +710,7 @@ verify_exchange_claim_cb (void *cls, ptc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; ptc->response = TALER_MHD_make_error (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, - "check_transfer_result must not be NULL"); + "check_transfer_result must not be GNUNET_NO"); return; case GNUNET_SYSERR: /* #check_transfer() failed, report conflict! */ @@ -864,6 +910,7 @@ download (struct PostTransfersContext *ptc) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Suspending POST /private/transfers handling while working with exchange\n"); MHD_suspend_connection (ptc->connection); + ptc->suspended = true; GNUNET_CONTAINER_DLL_insert (ptc_head, ptc_tail, ptc); @@ -895,12 +942,14 @@ TMH_private_post_transfers (const struct TMH_RequestHandler *rh, hc->ctx = ptc; hc->cc = &transfer_cleanup; } + /* resume logic: did we get resumed after a reply was built? */ if (0 != ptc->response_code) return queue (ptc); if ( (NULL != ptc->fo) || (NULL != ptc->wdh) ) { /* likely old MHD version causing spurious wake-up */ + GNUNET_break (ptc->suspended); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not sure why we are here, should be suspended\n"); return MHD_YES; /* still work in progress */ @@ -939,6 +988,11 @@ TMH_private_post_transfers (const struct TMH_RequestHandler *rh, TALER_EC_GENERIC_CURRENCY_MISMATCH, TMH_currency); } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "New inbound wire transfer over %s to %s from %s\n", + TALER_amount2s (&ptc->amount), + ptc->payto_uri, + ptc->exchange_url); } /* Check if transfer data is in database, if not, add it. */ @@ -946,8 +1000,10 @@ TMH_private_post_transfers (const struct TMH_RequestHandler *rh, { struct GNUNET_TIME_Absolute execution_time; struct TALER_Amount total_amount; + struct TALER_Amount exchange_amount; struct TALER_Amount wire_fee; bool verified; + bool have_exchange_sig; TMH_db->preflight (TMH_db->cls); if (GNUNET_OK != @@ -966,7 +1022,9 @@ TMH_private_post_transfers (const struct TMH_RequestHandler *rh, &ptc->wtid, &total_amount, &wire_fee, + &exchange_amount, &execution_time, + &have_exchange_sig, &verified); switch (qs) { @@ -982,7 +1040,9 @@ TMH_private_post_transfers (const struct TMH_RequestHandler *rh, TMH_db->rollback (TMH_db->cls); continue; case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - /* Transfer so far unknown */ + /* Transfer so far unknown; try to persist the wire transfer information + we have received in the database (it is not yet present). Upon + success, try to download the transfer details from the exchange. */ { uint64_t account_serial; @@ -1019,6 +1079,8 @@ TMH_private_post_transfers (const struct TMH_RequestHandler *rh, break; } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Inserting new transfer\n"); qs = TMH_db->insert_transfer (TMH_db->cls, ptc->hc->instance->settings.id, ptc->exchange_url, @@ -1030,6 +1092,8 @@ TMH_private_post_transfers (const struct TMH_RequestHandler *rh, { case GNUNET_DB_STATUS_SOFT_ERROR: TMH_db->rollback (TMH_db->cls); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Soft error, retrying...\n"); continue; case GNUNET_DB_STATUS_HARD_ERROR: GNUNET_break (0); @@ -1039,12 +1103,13 @@ TMH_private_post_transfers (const struct TMH_RequestHandler *rh, TALER_EC_GENERIC_DB_STORE_FAILED, "transfer"); case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - /* transfer present, but transfer _details_ - missing (hence the SELECT returned an empty - set after intersection via USING part of the - query). Fine, we still need to talk to the - exchange! */ - break; + TMH_db->rollback (TMH_db->cls); + /* Should not happen: we checked earlier! */ + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_CONFLICT, + TALER_EC_GENERIC_DB_STORE_FAILED, + "not unique"); case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: break; } @@ -1069,21 +1134,36 @@ TMH_private_post_transfers (const struct TMH_RequestHandler *rh, break; } download (ptc); - return MHD_YES; + return MHD_YES; /* download() always suspends */ } case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: /* Transfer exists */ GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Transfer exists in DB\n"); + "Transfer exists in DB (verified: %s, exchange signature: %s)\n", + verified ? "true" : "false", + have_exchange_sig ? "true" : "false"); if (! verified) { - if (! ptc->downloaded) + if ( (! ptc->downloaded) && + (! have_exchange_sig) ) { /* We may have previously attempted and failed to download the exchange data, do it again! */ TMH_db->rollback (TMH_db->cls); download (ptc); - return MHD_YES; + return MHD_YES; /* download always suspends */ + } + if (! have_exchange_sig) + { + /* We tried to download and still failed to get + an exchange signture. Still, that should have + been handled there. */ + TMH_db->rollback (TMH_db->cls); + GNUNET_break (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "download but no exchange signature and no error"); } /* verify */ if (GNUNET_SYSERR == @@ -1135,6 +1215,52 @@ TMH_private_post_transfers (const struct TMH_RequestHandler *rh, TMH_db->rollback (TMH_db->cls); continue; } + + { + struct TALER_Amount delta; + + if (0 > + TALER_amount_subtract (&delta, + &total_amount, + &wire_fee)) + { + GNUNET_break (0); + return TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + NULL); + } + if (0 != + TALER_amount_cmp (&exchange_amount, + &delta)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Amount of expected was %s\n", + TALER_amount2s (&delta)); + return TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_CONFLICT, + TALER_EC_MERCHANT_PRIVATE_POST_TRANSFERS_CONFLICTING_TRANSFERS, + TALER_amount2s (&exchange_amount)); + } + if ( (GNUNET_OK != + TALER_amount_cmp_currency (&ptc->amount, + &delta)) || + (0 != + TALER_amount_cmp (&ptc->amount, + &delta)) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Amount submitted was %s\n", + TALER_amount2s (&ptc->amount)); + return TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_CONFLICT, + TALER_EC_MERCHANT_PRIVATE_POST_TRANSFERS_CONFLICTING_SUBMISSION, + TALER_amount2s (&exchange_amount)); + } + } verified = true; qs = TMH_db->set_transfer_status_to_verified (TMH_db->cls, ptc->exchange_url, |