You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by as...@apache.org on 2026/06/10 22:22:17 UTC
(qpid-proton) 07/10: PROTON-1442: Make sure we only respond if we are in a transaction
This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-proton.git
commit 329edf8e1e281806f024c9f79ea8f7e86c067c67
Author: Andrew Stitcher <as...@apache.org>
AuthorDate: Thu May 21 16:12:56 2026 -0400
PROTON-1442: Make sure we only respond if we are in a transaction
If the peer is misbehaved it could send us a transactioned disposition
when we're not in a transaction or it could be for a different
transaction.
This code was written with the assistance of Cursor.
---
cpp/src/messaging_adapter.cpp | 22 +++++++++++++++++++++-
cpp/src/transaction_options.cpp | 4 +++-
2 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/cpp/src/messaging_adapter.cpp b/cpp/src/messaging_adapter.cpp
index e4812d7d3..0e22b142f 100644
--- a/cpp/src/messaging_adapter.cpp
+++ b/cpp/src/messaging_adapter.cpp
@@ -114,9 +114,14 @@ bool transaction_coordinator_sender(const sender& s) {
return txn_context && (txn_context->coordinator == unwrap(s));
}
+void transaction_protocol_error(session_context& /*sctx*/, const char* /*message*/) {
+ // TODO: decide how to handle transactional protocol errors
+}
+
void handle_outgoing_committed_deliveries(messaging_handler& handler, session &s) {
auto session = unwrap(s);
auto& transaction_context = session_context::get(session).transaction_context_;
+ assert(transaction_context);
for (auto t : transaction_context->provisional_outcomes) {
auto disposition = pn_delivery_remote(unwrap(t));
auto trans_disp = pn_transactional_disposition(disposition);
@@ -151,6 +156,7 @@ void settle_outgoing_deliveries(session& s) {
// scope our transactions to a session, we will settle all outgoing deliveries for the session.
auto session = unwrap(s);
auto& transaction_context = session_context::get(session).transaction_context_;
+ assert(transaction_context);
auto coordinator = transaction_context->coordinator;
for (auto link = pn_link_head(pn_session_connection(session), 0);
link;
@@ -210,6 +216,7 @@ void handle_transaction_coordinator_outcome(messaging_handler& handler, const tr
auto session = t.session();
auto& session_context = session_context::get(unwrap(session));
auto& transaction_context = session_context.transaction_context_;
+ assert(transaction_context);
auto state = transaction_context->state;
auto disposition = pn_delivery_remote(unwrap(t));
if (auto *declared_disp = pn_declared_disposition(disposition); declared_disp) {
@@ -291,6 +298,20 @@ void handle_transaction_coordinator_outcome(messaging_handler& handler, const tr
void handle_transacted_delivery_outcome(messaging_handler& handler, pn_delivery_t* d, tracker& t) {
auto& session_context = session_context::get(unwrap(t.session()));
auto& transaction_context = session_context.transaction_context_;
+ if (!transaction_context) {
+ transaction_protocol_error(session_context, "Received transactional disposition when not in a transaction");
+ return;
+ }
+
+ auto disposition = pn_transactional_disposition(pn_delivery_remote(d));
+ if (!disposition) {
+ transaction_protocol_error(session_context, "Received transactional disposition without transactional state");
+ return;
+ }
+ if (bin(pn_transactional_disposition_get_id(disposition)) != transaction_context->transaction_id) {
+ transaction_protocol_error(session_context, "Received transactional disposition with invalid transaction id");
+ return;
+ }
// We should hold on to tracker here so that we can call the non transactional handlers if the transaction
// commits without error. We can't do this triggered by the the incoming settlement later as it will happen before
@@ -304,7 +325,6 @@ void handle_transacted_delivery_outcome(messaging_handler& handler, pn_delivery_
return;
}
- auto disposition = pn_transactional_disposition(pn_delivery_remote(d));
auto outcome_type = pn_transactional_disposition_get_outcome_type(disposition);
switch (outcome_type) {
case PN_ACCEPTED:
diff --git a/cpp/src/transaction_options.cpp b/cpp/src/transaction_options.cpp
index 9258a3d3a..ae7b8ef36 100644
--- a/cpp/src/transaction_options.cpp
+++ b/cpp/src/transaction_options.cpp
@@ -26,6 +26,8 @@
#include "contexts.hpp"
#include "proton_bits.hpp"
+#include <assert.h>
+
namespace proton {
namespace {
@@ -48,7 +50,7 @@ class transaction_options::impl {
void apply(session& s) {
auto& session_context = session_context::get(unwrap(s));
auto& transaction_context = session_context.transaction_context_;
-
+ assert(transaction_context);
if (auto_modify_on_abort.set) transaction_context->auto_modify_on_abort = auto_modify_on_abort.value;
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org