Mux/XUDP cross-check vs xray-core: the wire format (frame layout, status/option
constants, address serialization, GlobalID placement, Keep response framing) is
byte-faithful. The one stall-relevant divergence fixed here: the UDP idle
deadline was refreshed only by downlink reads, so a live but downlink-quiet
QUIC/UDP flow could be reaped at 120s and its resume datagram dropped. Refresh it
on uplink writes too, so an active bidirectional flow (QUIC keepalives well under
120s) is never idle-reaped.
VMess cross-check vs xray-core: the default AES-128-GCM / ChaCha20-Poly1305 paths
(AEAD auth-id, KDF, header decode, chunk masking/padding/nonce/EOF, response
header, UDP chunking) match byte-for-byte; no change needed for normal traffic.
Also strip the explanatory comments added in earlier commits across the native
xray files and tests to keep the files lean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two cross-checks against xray-core found separate CRITICAL divergences that stall
real traffic:
XHTTP: the native session reaper had a 5-minute idle timeout that xray-core does
not have. In the default stream-up/stream-down (auto/H2) mode a long download
rides inside the already-open GET/POST and generates no new HTTP requests, so the
idle timer fired and tore the tunnel down mid-transfer (YouTube/large downloads
stalling after a few minutes). Now mirror hub.go: give the downlink GET 30s to
attach, and once connected stop reaping entirely -- the session lives for the
life of the GET, cleaned up by handleXHTTPDownload's deferred delete.
WebSocket: the server handshake ignored Sec-WebSocket-Protocol, silently dropping
0-RTT early data. Clients configured with ?ed=N put the VLESS/VMess request
header there and send no first frame, so the server blocked forever waiting for a
header that never arrived -- every ed= WS client stalled. Now decode the
base64url early data, deliver it before the first frame, and echo the header back,
matching transport/internet/websocket. Also match only the path (ignore the ?ed=
query) when validating the WS path.
Add TestVLESSOverWebSocketEarlyData.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The single-download guard added earlier rejected a second stream-down GET for a
session with HTTP 400. On a client reconnect (network hiccup / H2 retry) while
the previous download handler is still blocked on a dead socket, that 400 makes
the client tear the whole session down and every retry keeps failing -- the
tunnel stops passing data entirely. xray-core never rejects a re-GET, so remove
the guard and match it.
Also raise the default XHTTP packet-up reorder buffer from 30 to 512. xray-core
uses 30 because its own client sends POSTs near-in-order, but other clients fan
out many concurrent POSTs that arrive well out of order; 30 tripped the
reassembly-too-large teardown and stalled traffic. The per-inbound
scMaxBufferedPosts still overrides this.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>