From 7db73b58174f467b221f1f1f9170ee9dc22e2c23 Mon Sep 17 00:00:00 2001 From: Matthew Wolter Date: Sat, 11 Apr 2026 20:25:26 -0700 Subject: [PATCH] =?UTF-8?q?G4:=20N04=20=E2=80=94=20move=20TCP=20receive=20?= =?UTF-8?q?counter=20from=20data=5Freceived=20to=20handle=5Frx?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/meshcore/tcp_cx.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/meshcore/tcp_cx.py b/src/meshcore/tcp_cx.py index cce0a6b..6636d57 100644 --- a/src/meshcore/tcp_cx.py +++ b/src/meshcore/tcp_cx.py @@ -38,7 +38,6 @@ class TCPConnection: def data_received(self, data): logger.debug("data received") - self.cx._receive_count += 1 self.cx.handle_rx(data) def error_received(self, exc): @@ -106,6 +105,10 @@ class TCPConnection: self.inframe = self.inframe + data[0: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: # feed meshcore reader asyncio.create_task(self.reader.handle_rx(self.inframe))