qmux: StreamTransport recv is not cancellation-safe
## Problem
`SessionState::run()` uses `tokio::select!` which can cancel the `transport.recv()` future mid-read. For `StreamTransport` (TCP/TLS), this drops partially-consumed bytes from the underlying reader, desynchronizing the stream on the next `recv()` call.
WebSocket transport is unaffected since each message is atomic.
## Fix
Buffer reads internally in `StreamTransport` using a `BytesMut`. Instead of reading directly from the TCP stream with `read_u8()`/`read_exact()` (which consume bytes on cancel), use `reader.read_buf(&mut self.buf)` to fill the buffer, then parse complete frames from it. If the future is cancelled between reads, the buffer retains partial data.
The frame delimiter logic (`try_frame_len`) would peek at the buffer without consuming, and only split off bytes when a complete frame is found.
## Current mitigation
The `select!` is `biased` so `recv` is polled first, but other branches can still win when `recv` is pending on I/O.
1 条评论