add credit based mux window
This commit is contained in:
+54
-7
@@ -140,8 +140,16 @@ Magic : u8 # 0x01 = control session, 0x02 = worker conn
|
||||
RandLen : VarInt # 8 ≤ RandLen ≤ 64
|
||||
Rand : Bytes[RandLen] # cryptographically random
|
||||
Timestamp : I64 # client's epoch milliseconds
|
||||
Flags : VarInt # feature flags; bit 0x01 (STREAM_FC) MUST be set
|
||||
RecvWindow: VarInt # client's per-stream receive window, bytes (§7.3)
|
||||
```
|
||||
|
||||
`Flags` is a bitfield of features. Bit `0x01` (STREAM_FC) declares
|
||||
**per-stream flow control** (§7.3) and is mandatory: `RecvWindow` advertises
|
||||
the client's per-stream receive window in bytes and must be positive. The hub
|
||||
closes the connection if the flag is missing, `RecvWindow` is absent or
|
||||
non-positive, or the fields are malformed.
|
||||
|
||||
The hub:
|
||||
|
||||
1. Decrypts frame 1 with Phase A.
|
||||
@@ -158,9 +166,13 @@ frame (both directions) is Phase B, counters reset to 0.
|
||||
The hub then sends one Phase-B frame to confirm success:
|
||||
|
||||
```
|
||||
SessionReady : payload = [ 0x00 ]
|
||||
SessionReady : payload = [ 0x00, Flags: VarInt, RecvWindow: VarInt ]
|
||||
```
|
||||
|
||||
The hub echoes the accepted flags (STREAM_FC set) followed by its own
|
||||
per-stream receive window. A client must reject a SessionReady without the
|
||||
STREAM_FC flag or without a positive window (an unsupported hub).
|
||||
|
||||
A hub that rejects the session simply closes the TCP connection (optionally
|
||||
after a Phase-B `Error` frame, §6). After `SessionReady`:
|
||||
|
||||
@@ -258,6 +270,7 @@ Data : Bytes[...] # remainder of the frame payload
|
||||
| `0x01` | DATA | both | raw tunneled bytes for the stream. |
|
||||
| `0x02` | FIN | both | *(empty)* — graceful close of the stream (both directions). This is the "disconnect" the hub sends when the player leaves. |
|
||||
| `0x03` | RST | both | *(optional 1 byte reason)* — abnormal close (e.g. CID unknown/expired, destination dial failed). |
|
||||
| `0x04` | WND | both | `Delta: VarInt` — flow-control credit grant (§7.3). |
|
||||
|
||||
There is no explicit SYN-ACK: success is implied by the hub forwarding the
|
||||
buffered Handshake as the stream's first `DATA`; failure is an `RST`.
|
||||
@@ -294,11 +307,33 @@ configurable, `1..8`). To place a new stream:
|
||||
closes the destination. When the destination closes, the client sends `FIN`;
|
||||
the hub closes the player socket. `RST` is treated the same way (hard close).
|
||||
|
||||
Data on a worker conn is subject to that TCP connection's back-pressure. Each
|
||||
stream has a bounded outbound queue on the receiving side; overflow resets the
|
||||
stream (`RST`). (This is a deliberate simplification — no per-stream credit
|
||||
windows — acceptable for the interactive, low-throughput Minecraft handshake +
|
||||
gameplay traffic pattern.)
|
||||
Data on a worker conn is subject to that TCP connection's back-pressure for
|
||||
its **aggregate** bandwidth; *per-stream* fairness is governed by the credit
|
||||
windows of §7.3.
|
||||
|
||||
### 7.3 Per-stream flow control
|
||||
|
||||
Every stream carries an independent credit window per direction:
|
||||
|
||||
* Each side advertised its **receive window** W (bytes) at session setup. A
|
||||
sender may have at most W un-credited DATA bytes outstanding per stream; the
|
||||
initial budget is W, spent as DATA is sent (`Data` length only — SYN/FIN/RST
|
||||
frames are free) starting with the very first DATA on the stream (including
|
||||
the hub's forwarded handshake).
|
||||
* The receiver returns credit with `WND(Delta)` once bytes are **delivered to
|
||||
the terminal socket** (written to the player / destination connection), not
|
||||
when they are merely buffered. Receivers should batch grants (the reference
|
||||
implementations send one `WND` per W/2 bytes consumed).
|
||||
* A sender whose window is exhausted pauses reading **that stream's source
|
||||
socket only**; the shared worker conn is never paused because of a single
|
||||
stream. A receiver that observes more than W un-credited bytes on a stream
|
||||
may reset it (`RST`) as a protocol violation.
|
||||
* Senders should also cap individual DATA payloads (the reference
|
||||
implementations use 32 KiB) so one stream cannot monopolize the link for a
|
||||
full 1-MiB frame.
|
||||
|
||||
Both windows may differ (each side enforces the one its peer advertised).
|
||||
`Delta` must be positive; a `WND` for an unknown stream id is ignored.
|
||||
|
||||
## 8. HAProxy protocol v2 (optional)
|
||||
|
||||
@@ -327,10 +362,14 @@ big-endian.
|
||||
"listen": "0.0.0.0:25565",
|
||||
"psk": "change-me",
|
||||
"timestampWindowMs": 30000,
|
||||
"pendingTimeoutMs": 10000
|
||||
"pendingTimeoutMs": 10000,
|
||||
"streamWindowBytes": 262144
|
||||
}
|
||||
```
|
||||
|
||||
`streamWindowBytes` (optional, default 262144, clamped to [32768, 8388608]) is
|
||||
the hub's advertised per-stream receive window (§7.3).
|
||||
|
||||
### 9.2 Client — JSON
|
||||
|
||||
```json
|
||||
@@ -339,12 +378,16 @@ big-endian.
|
||||
"psk": "change-me",
|
||||
"maxConn": 4,
|
||||
"pingIntervalMs": 20000,
|
||||
"streamWindowBytes": 262144,
|
||||
"mappings": [
|
||||
{ "pattern": "mc\\.example\\.com", "destination": "127.0.0.1:25566", "proxyProtocol": true }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`streamWindowBytes` (optional, default 262144, clamped to [32768, 8388608]) is
|
||||
the client's advertised per-stream receive window (§7.3).
|
||||
|
||||
Each `pattern` is a regular expression (§5.1) matched against the whole
|
||||
normalized player hostname, case-insensitively. Escape literal dots (`mc\.example\.com`,
|
||||
which is `mc\\.example\\.com` in JSON); an unescaped `.` matches any character.
|
||||
@@ -369,4 +412,8 @@ subdomain or `(alpha|beta)\.mc\.net` for a fixed set.
|
||||
| max frame payload | 1 MiB |
|
||||
| saturation threshold | active streams `> 8` |
|
||||
| max worker conns | `max_conn ∈ [1,8]` |
|
||||
| feature flag: per-stream flow control | `0x01` |
|
||||
| stream window default / bounds | 256 KiB, clamped to [32 KiB, 8 MiB] |
|
||||
| WND grant batching (reference) | one grant per window/2 consumed |
|
||||
| DATA chunk cap (reference) | 32 KiB |
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user