fix(mesh): close data-plane race that dropped early TcpData frames (#1086)

The tcp_open and tcp_open_reverse receivers registered their stream
entry only after awaiting resolveTarget / resolveContainerIp. The
peer, which is free to send TcpData immediately after the open frame,
hit the lookup-miss path in handleBinaryFrame and the bytes were
silently dropped. Probes passed because they only exercise the
handshake; real HTTP hung with 0 bytes received.

Reserve the stream entry synchronously, buffer early TcpData in a
per-stream pendingData queue capped at 1 MiB, and flush onto the
local socket inside the connect handler before sending tcp_open_ack.
The payload is copied because decodeBinaryFrame returns a subarray
view of the WS receive buffer; holding the view would pin the parent
buffer past its lifecycle.

Both sides of the data plane are patched:
- tcpStreamSwitchboard.onTcpOpen (forward, agent + proxy-mode peer)
- PilotTunnelBridge.handleTcpOpenReverse / acceptReverseLocal
  (reverse, primary acting as the local dial target)

Adds unit coverage for the race window and for the overflow path.
The cap constant lives in pilot/protocol.ts alongside the other
per-stream limits.
This commit is contained in:
Anso
2026-05-17 14:01:39 -04:00
committed by GitHub
parent 50b89db3b8
commit a318e6b3c1
5 changed files with 303 additions and 15 deletions
+11
View File
@@ -50,6 +50,17 @@ export const MAX_STREAMS_PER_TUNNEL = 1024;
*/
export const STREAM_IDLE_TIMEOUT_MS = 10 * 60 * 1000;
/**
* Per-stream cap on inbound `TcpData` bytes that a receiver buffers while
* waiting for its local socket to connect. `tcp_open` and `tcp_open_reverse`
* both trigger an async dial (resolveTarget + TCP handshake), and the
* protocol allows the peer to send data immediately. Anything received in
* that window is held in `pendingData` until the socket is ready; over
* this cap the stream is dropped and a `tcp_close` is sent back so a
* misbehaving (or compromised) peer cannot OOM the receiver.
*/
export const STREAM_PENDING_DATA_MAX_BYTES = 1024 * 1024;
// --- Binary frame types (first byte of a binary WS frame) ---
export enum BinaryFrameType {