ITADN

Server-Initiated Bidirectional Streams Not Received by Client

#125Openmondain 创建于 2025-11-16
M
mondaincommented
## Environment - **web-transport-quinn version**: 0.10 - **quinn version**: 0.11 - **Platform**: Linux x86_64 - **Client**: moq-clock (moq-rs) publisher using web-transport-quinn 0.10 ## Issue Description Server-initiated bidirectional streams created via `Session::open_bi()` are successfully opened and written to on the server side, but never arrive at the client's `accept_bi()` loop. ## Expected Behavior When the server calls `session.open_bi()`, writes data immediately, and flushes the stream (following Quinn's documented requirement), the client should be notified and able to accept the stream via its `accept_bi()` loop. ## Actual Behavior The server successfully: - Opens bidirectional stream via `session.open_bi()` - Writes data immediately (2 bytes: `01 00`) - Flushes the stream - Spawns receive handler for incoming data - Logs "Bidirectional stream fully initialized and ready" However, the client: - Never receives notification of the new stream - `accept_bi()` loop never yields the stream - No logs about incoming bidirectional stream - No errors on either side ## Reproduction ### Server Code (Rust with JNI bridge) ```rust // Open bidirectional stream let (send, recv) = session.open_bi().await .map_err(|e| anyhow!("Failed to open WebTransport bidirectional stream: {}", e))?; info!("Successfully opened WebTransport bidirectional stream (synthetic ID: {})", stream_id); // Register and write data IMMEDIATELY (per Quinn requirement) let handle = SendStreamHandle::WebTransport(tokio::sync::Mutex::new(send)); let handle_arc = Arc::new(handle); match handle_arc.as_ref() { SendStreamHandle::WebTransport(send_mutex) => { let mut send = send_mutex.lock().await; send.write_all(&data_vec).await .map_err(|e| anyhow!("Failed to write to WebTransport stream: {}", e))?; // CRITICAL: Flush to ensure data is sent to network send.flush().await .map_err(|e| anyhow!("Failed to flush WebTransport stream: {}", e))?; } _ => unreachable!(), } info!("Wrote and flushed {} bytes of initial data to bidirectional stream {}", data_vec.len(), stream_id); // Spawn receive task tokio::spawn(handle_bidirectional_receive(session_id, stream_id, recv, callback.clone())); ``` ### Client Code (moq-rs/moq-clock) ```rust // moq/src/lite/publisher.rs lines 25-41 pub async fn run(mut self) -> Result<(), Error> { loop { let mut stream = Stream::accept(&self.session).await?; // <-- Never receives stream let kind = stream.reader.decode().await?; if let Err(err) = match kind { lite::ControlType::Announce => self.recv_announce(stream).await, lite::ControlType::Subscribe => self.recv_subscribe(stream).await, _ => Err(Error::UnexpectedStream), } { tracing::warn!(%err, "control stream error"); } } } ``` ### Server Logs (Success on Server Side) ``` INFO quinn-jni - Opening WebTransport bidirectional stream (synthetic ID: 100000) via session.open_bi() INFO quinn-jni - Successfully opened WebTransport bidirectional stream (synthetic ID: 100000) INFO quinn-jni - Registered bidirectional stream 100000 send side in SEND_STREAMS INFO quinn-jni - Wrote and flushed 2 bytes of initial data to bidirectional stream 100000 INFO quinn-jni - Flushing 0 pending writes for stream 100000 INFO quinn-jni - Flushed 0 pending writes successfully INFO quinn-jni - Spawned receive handler task for bidirectional stream 100000, task ID: Id(26) INFO quinn-jni - Bidirectional stream 100000 fully initialized and ready INFO quinn-jni - Starting receive handler for WebTransport bidirectional stream 100000 on session 1 ``` ### Client Logs (No Stream Received) ``` TRACE moq_lite::session - sending client setup TRACE moq_lite::session - received server setup DEBUG moq_lite::session - connected version=4279086337 ``` No mention of any incoming bidirectional stream. ## Investigation Results 1. **Quinn Requirement Met**: Per Quinn documentation, "The Connection that calls open_bi() must write to its SendStream before the other Connection is able to accept_bi()." Our code writes data immediately after `open_bi()` and flushes. 2. **No Errors**: Neither server nor client logs show any errors related to stream creation or delivery. 3. **Client Accept Loop Working**: The same client successfully accepts bidirectional streams initiated by itself (client-to-server direction works fine). 4. **Session Valid**: The WebTransport session is active and healthy (control stream 0 works bidirectionally). ## Hypothesis There may be an issue in web-transport-quinn's handling of server-initiated bidirectional streams where: - The HTTP/3 layer doesn't properly notify the peer about the new stream - Stream multiplexing for server-initiated streams has a bug - There's a missing handshake or acknowledgment step ## Workaround Send messages on the existing control stream (stream 0) instead of creating new bidirectional streams. This aligns with MoQ Transport's approach of using a single persistent bidirectional control stream. ## Additional Context - Client-initiated bidirectional streams work fine in both directions - Unidirectional streams work fine in both directions - QUIC datagrams work fine - This is blocking MoQ Lite relay implementation where the relay needs to send ANNOUNCE_PLEASE to publishers - The same code pattern works with native Quinn connections (not WebTransport) ## Questions 1. Does web-transport-quinn v0.10 officially support server-initiated bidirectional streams? 2. Are there any known limitations or additional requirements beyond Quinn's standard `open_bi()` + immediate write pattern? 3. Is there HTTP/3 or WebTransport protocol-specific handling needed for server-initiated streams? ## Request Please clarify if this is a known limitation, a bug, or if additional implementation steps are required for server-initiated bidirectional streams in web-transport-quinn.
0 条评论