From 018361b16e655be613955e25fe1f1b90dda73508 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Tue, 16 Apr 2024 16:22:59 +0200 Subject: [PATCH] fix(SendMessage): always use available send space Always use up send space on QUIC layer to ensure receiving `ConnectionEvent::SendStreamWritable` event when more send space is available. See https://github.com/mozilla/neqo/issues/1819 for details. This commit implements option 2. Fixes https://github.com/mozilla/neqo/issues/1819. --- neqo-http3/src/send_message.rs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/neqo-http3/src/send_message.rs b/neqo-http3/src/send_message.rs index 15965c44f6..6e6074d682 100644 --- a/neqo-http3/src/send_message.rs +++ b/neqo-http3/src/send_message.rs @@ -6,7 +6,7 @@ use std::{cell::RefCell, cmp::min, fmt::Debug, rc::Rc}; -use neqo_common::{qdebug, qtrace, Encoder, Header, MessageType}; +use neqo_common::{qdebug, qerror, qtrace, Encoder, Header, MessageType}; use neqo_qpack::encoder::QPackEncoder; use neqo_transport::{Connection, StreamId}; @@ -166,7 +166,12 @@ impl Stream for SendMessage { } impl SendStream for SendMessage { fn send_data(&mut self, conn: &mut Connection, buf: &[u8]) -> Res { - qtrace!([self], "send_body: len={}", buf.len()); + qtrace!([self], "send_data: len={}", buf.len()); + + if buf.is_empty() { + qerror!([self], "zero-length send_data"); + return Err(Error::InvalidInput); + } self.state.new_data()?; @@ -177,8 +182,20 @@ impl SendStream for SendMessage { let available = conn .stream_avail_send_space(self.stream_id()) .map_err(|e| Error::map_stream_send_errors(&e.into()))?; - if available <= 2 { + if available == 0 { return Ok(0); + } else if available <= 2 { + // Rare case, where available send space at most fits the data frame + // header (min 2 bytes), but no data. Don't return `Ok(0)`, but + // instead use up `available` anyways, with a small but non-zero + // data frame, buffering the remainder, thereby signaling to the + // QUIC layer that more is needed, and thus ensure to receive + // [`neqo_transport::ConnectionEvent::SendStreamWritable`] when more + // send space is available. + const MIN_DATA: usize = 1; // arbitrary small value, larger zero + return self + .send_data_atomic(conn, &buf[..MIN_DATA]) + .map(|()| MIN_DATA); } let to_send = if available <= MAX_DATA_HEADER_SIZE_2_LIMIT { // 63 + 3