mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-21 07:36:40 +00:00
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:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user