G4: N04 — move TCP receive counter from data_received to handle_rx

Why: _receive_count incremented inside data_received(), which fires
once per TCP read — not once per completed MeshCore frame. Under TCP
fragmentation a single frame can arrive in multiple segments, inflating
_receive_count relative to _send_count. The disconnect-detection
heuristic (send_count - receive_count >= 5) then never fires because
the receive side is over-counted. Moving the increment into handle_rx
after a complete frame is assembled makes the counter semantically
correct: one increment per MeshCore frame dispatched to the reader.
Refs: Forensics report finding N04
This commit is contained in:
Matthew Wolter
2026-04-11 20:25:26 -07:00
parent 76e2e54157
commit 7db73b5817

View File

@@ -38,7 +38,6 @@ class TCPConnection:
def data_received(self, data): def data_received(self, data):
logger.debug("data received") logger.debug("data received")
self.cx._receive_count += 1
self.cx.handle_rx(data) self.cx.handle_rx(data)
def error_received(self, exc): def error_received(self, exc):
@@ -106,6 +105,10 @@ class TCPConnection:
self.inframe = self.inframe + data[0:upbound] self.inframe = self.inframe + data[0:upbound]
data = data[upbound:] data = data[upbound:]
# Increment per completed MeshCore frame, not per TCP segment (N04).
# The threshold heuristic in send() compares _send_count vs
# _receive_count — counting per-segment skews it under fragmentation.
self._receive_count += 1
if self.reader is not None: if self.reader is not None:
# feed meshcore reader # feed meshcore reader
asyncio.create_task(self.reader.handle_rx(self.inframe)) asyncio.create_task(self.reader.handle_rx(self.inframe))