-
Notifications
You must be signed in to change notification settings - Fork 997
fix: connection level flow control accounting for empty, non-fin frames #2491
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -122,7 +122,12 @@ impl RecvBuf { | |||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| // No need to store empty buffer that doesn't carry the fin flag. | ||||||||||||||
| // However, we must still advance the max received offset. A | ||||||||||||||
| // zero-length non-FIN STREAM frame at offset N implies the peer has | ||||||||||||||
| // data at that offset. | ||||||||||||||
| // NOTE: connection level flow control accounting also expects this. | ||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit:
Suggested change
|
||||||||||||||
| if !buf.fin() && buf.is_empty() { | ||||||||||||||
| self.len = cmp::max(self.len, buf.max_off()); | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this update happen unconditionally before the first
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the only That whole |
||||||||||||||
| return Ok(()); | ||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should See following test case which fails on this branch: #[rstest]
/// Tests that empty non-FIN STREAM frames on a draining stream are not counted
/// again when the same final size is later received in a RESET_STREAM frame.
fn flow_control_drain_empty_stream_frame_reset(
#[values("cubic", "bbr2_gcongestion")] cc_algorithm_name: &str,
) {
let mut buf = [0; 65536];
let mut pipe = test_utils::Pipe::new(cc_algorithm_name).unwrap();
assert_eq!(pipe.handshake(), Ok(()));
assert_eq!(pipe.client.stream_send(4, b"aaaaa", false), Ok(5));
assert_eq!(pipe.advance(), Ok(()));
assert_eq!(pipe.server.rx_data, 5);
assert_eq!(pipe.server.flow_control.consumed(), 0);
assert_eq!(pipe.server.stream_shutdown(4, Shutdown::Read, 42), Ok(()));
assert_eq!(pipe.server.rx_data, 5);
assert_eq!(pipe.server.flow_control.consumed(), 5);
let frames = [frame::Frame::Stream {
stream_id: 4,
data: RangeBuf::from(&[], 10, false),
}];
let written =
test_utils::encode_pkt(&mut pipe.client, Type::Short, &frames, &mut buf)
.unwrap();
assert_eq!(pipe.server_recv(&mut buf[..written]), Ok(written));
assert_eq!(pipe.server.rx_data, 10);
assert_eq!(pipe.server.flow_control.consumed(), 10);
let frames = [frame::Frame::ResetStream {
stream_id: 4,
error_code: 42,
final_size: 10,
}];
let written =
test_utils::encode_pkt(&mut pipe.client, Type::Short, &frames, &mut buf)
.unwrap();
assert_eq!(pipe.server_recv(&mut buf[..written]), Ok(written));
assert_eq!(pipe.server.rx_data, 10);
assert_eq!(pipe.server.flow_control.consumed(), 10);
}So I think we need something like in https://github.com/cloudflare/quiche/blob/master/quiche/src/stream/recv_buf.rs#L194:
Suggested change
|
||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
|
|
@@ -510,16 +515,31 @@ mod tests { | |||||||||||||
|
|
||||||||||||||
| assert_emit_discard(&mut recv, emit, 32, 5, false, None); | ||||||||||||||
|
|
||||||||||||||
| // Don't store non-fin empty buffer. | ||||||||||||||
| // Empty non-FIN frame advances the high-water mark but stores no data. | ||||||||||||||
| let buf = RangeBuf::from(b"", 10, false); | ||||||||||||||
| assert!(recv.write(buf).is_ok()); | ||||||||||||||
| assert_eq!(recv.len, 5); | ||||||||||||||
| assert_eq!(recv.len, 10); | ||||||||||||||
| assert_eq!(recv.off, 5); | ||||||||||||||
| assert_eq!(recv.data.len(), 0); | ||||||||||||||
|
|
||||||||||||||
| // Check flow control for empty buffer. | ||||||||||||||
| // Check flow control for empty non-FIN buffer past the limit. | ||||||||||||||
| let buf = RangeBuf::from(b"", 16, false); | ||||||||||||||
| assert_eq!(recv.write(buf), Err(Error::FlowControl)); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| #[rstest] | ||||||||||||||
| fn empty_fin_stream_frame(#[values(true, false)] emit: bool) { | ||||||||||||||
| let mut recv = | ||||||||||||||
| RecvBuf::new(15, DEFAULT_STREAM_WINDOW, DEFAULT_STREAM_WINDOW); | ||||||||||||||
| assert_eq!(recv.len, 0); | ||||||||||||||
|
|
||||||||||||||
| let buf = RangeBuf::from(b"hello", 0, false); | ||||||||||||||
| assert!(recv.write(buf).is_ok()); | ||||||||||||||
| assert_eq!(recv.len, 5); | ||||||||||||||
| assert_eq!(recv.off, 0); | ||||||||||||||
| assert_eq!(recv.data.len(), 1); | ||||||||||||||
|
|
||||||||||||||
| assert_emit_discard(&mut recv, emit, 32, 5, false, None); | ||||||||||||||
|
|
||||||||||||||
| // Store fin empty buffer. | ||||||||||||||
| let buf = RangeBuf::from(b"", 5, true); | ||||||||||||||
|
|
||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: