#2 Tighten reply correlation: match (sys_bytes, stream, function) exactly

The previous heuristic ("function % 2 == 0 && pending_requests_.count(sys)")
worked in practice but was wrong in principle — SECS-II doesn't enforce
function parity, and a peer protocol violation (replying with the wrong
SxFy) would have been silently treated as a primary message.

Now PendingRequest carries the expected reply stream + function (computed
from request.stream / request.function+1 per SECS-II convention) at
send_request time.  handle_data matches on all three:

  it->second.expected_stream == h.stream() &&
  it->second.expected_function == h.function()

If sys_bytes matches but stream/function doesn't, the Connection logs
a diagnostic ("!! unexpected SxFy for pending sys=N (expected ...)")
and treats the message as a primary so the application handler can
still respond.  The pending request stays open until T3.

No behaviour change on the happy path; the demo and all 69 tests still
pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-02 09:53:37 +02:00
parent 711ee1b40f
commit 41accc3263
2 changed files with 29 additions and 5 deletions
+5 -1
View File
@@ -108,8 +108,12 @@ class Connection : public std::enable_shared_from_this<Connection> {
uint32_t next_system_bytes_ = 1;
// outstanding data request transactions, keyed by system bytes
// outstanding data request transactions, keyed by system bytes.
// We track the EXPECTED reply stream/function so we can match exactly
// instead of inferring "this is a reply" from function parity.
struct PendingRequest {
uint8_t expected_stream;
uint8_t expected_function;
ReplyHandler cb;
std::shared_ptr<asio::steady_timer> t3;
};