From e03ff8a8264120c6330c53306d0e83eeeec4c03c Mon Sep 17 00:00:00 2001 From: Florentin Rochet Date: Tue, 9 Jan 2024 11:21:26 +0100 Subject: [PATCH] starting the work on Zerocopy receiver --- Cargo.toml | 7 + apps/src/args.rs | 5 +- apps/src/bin/quiche-server.rs | 38 +- apps/src/client.rs | 38 +- apps/src/common.rs | 237 +- bench_i71165.sh | 12 + bench_ryzen7.sh | 12 + bench_xeongold.sh | 12 + octets/src/lib.rs | 70 +- quiche/Cargo.toml | 18 + quiche/benches/bench_util.rs | 127 + quiche/benches/h3_benchmarks.rs | 322 ++ quiche/benches/initial_cwin_bench.rs | 166 + quiche/benches/quic_benchmarks.rs | 175 ++ quiche/examples/client.rs | 20 +- quiche/examples/http3-client.rs | 19 +- quiche/examples/http3-server.rs | 19 +- quiche/examples/server.rs | 84 +- quiche/src/crypto/boringssl.rs | 38 + quiche/src/crypto/mod.rs | 8 +- quiche/src/crypto/openssl_quictls.rs | 111 + quiche/src/flowcontrol.rs | 4 +- quiche/src/frame.rs | 930 +++++- quiche/src/h3/mod.rs | 1801 +++++++++-- quiche/src/h3/stream.rs | 1056 ++++++- quiche/src/lib.rs | 4305 ++++++++++++++++++++------ quiche/src/packet.rs | 534 ++-- quiche/src/recovery/mod.rs | 12 +- quiche/src/stream/app_recv_buf.rs | 540 ++++ quiche/src/stream/mod.rs | 835 +++-- quiche/src/stream/recv_buf.rs | 1233 ++++++-- 31 files changed, 10378 insertions(+), 2410 deletions(-) create mode 100755 bench_i71165.sh create mode 100755 bench_ryzen7.sh create mode 100755 bench_xeongold.sh create mode 100644 quiche/benches/bench_util.rs create mode 100644 quiche/benches/h3_benchmarks.rs create mode 100644 quiche/benches/initial_cwin_bench.rs create mode 100644 quiche/benches/quic_benchmarks.rs create mode 100644 quiche/src/stream/app_recv_buf.rs diff --git a/Cargo.toml b/Cargo.toml index 167d4a75..e65fb610 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,10 @@ debug = true [profile.release] debug = true + +[profile.performance] +inherits = "release" +lto = "fat" +codegen-units = 1 +incremental = false + diff --git a/apps/src/args.rs b/apps/src/args.rs index 18f1da1a..d756e6c7 100644 --- a/apps/src/args.rs +++ b/apps/src/args.rs @@ -91,8 +91,9 @@ impl Args for CommonArgs { let (alpns, dgrams_enabled) = match (http_version, dgram_proto) { ("HTTP/0.9", "none") => (alpns::HTTP_09.to_vec(), false), - ("HTTP/0.9", _) => - panic!("Unsupported HTTP version and DATAGRAM protocol."), + ("HTTP/0.9", _) => { + panic!("Unsupported HTTP version and DATAGRAM protocol.") + }, ("HTTP/3", "none") => (alpns::HTTP_3.to_vec(), false), diff --git a/apps/src/bin/quiche-server.rs b/apps/src/bin/quiche-server.rs index 50e2e478..33f2da69 100644 --- a/apps/src/bin/quiche-server.rs +++ b/apps/src/bin/quiche-server.rs @@ -50,6 +50,7 @@ use quiche_apps::common::*; use quiche_apps::sendto::*; const MAX_BUF_SIZE: usize = 65507; +const MAX_FLUSH_SIZE: usize = 256_000; const MAX_DATAGRAM_SIZE: usize = 1350; @@ -377,7 +378,7 @@ fn main() { let client_id = next_client_id; - let client = Client { + let mut client = Client { conn, http_conn: None, client_id, @@ -387,8 +388,19 @@ fn main() { max_datagram_size, loss_rate: 0.0, max_send_burst: MAX_BUF_SIZE, + app_buffers: quiche::AppRecvBufMap::new( + 3, + conn_args.max_stream_window, + conn_args.max_streams_bidi, + conn_args.max_streams_uni, + ), }; + client + .app_buffers + .set_expected_chunklen_to_consume(MAX_FLUSH_SIZE as u64) + .unwrap(); + clients.insert(client_id, client); clients_ids.insert(scid.clone(), client_id); @@ -411,7 +423,11 @@ fn main() { }; // Process potentially coalesced packets. - let read = match client.conn.recv(pkt_buf, recv_info) { + let read = match client.conn.recv( + pkt_buf, + &mut client.app_buffers, + recv_info, + ) { Ok(v) => v, Err(e) => { @@ -487,7 +503,22 @@ fn main() { http_conn.handle_writable(conn, partial_responses, stream_id); } - if http_conn + if conn.version() == quiche::PROTOCOL_VERSION_V3 { + if http_conn + .handle_requests( + conn, + &mut client.partial_requests, + partial_responses, + &args.root, + &args.index, + &mut buf, + Some(&mut client.app_buffers), + ) + .is_err() + { + continue 'read; + } + } else if http_conn .handle_requests( conn, &mut client.partial_requests, @@ -495,6 +526,7 @@ fn main() { &args.root, &args.index, &mut buf, + None, ) .is_err() { diff --git a/apps/src/client.rs b/apps/src/client.rs index 86fb6507..13834df6 100644 --- a/apps/src/client.rs +++ b/apps/src/client.rs @@ -26,6 +26,7 @@ use crate::args::*; use crate::common::*; +use quiche::AppRecvBufMap; use std::net::ToSocketAddrs; @@ -38,6 +39,7 @@ use std::cell::RefCell; use ring::rand::*; const MAX_DATAGRAM_SIZE: usize = 1350; +pub const MAX_FLUSH_SIZE: usize = 256_000; #[derive(Debug)] pub enum ClientError { @@ -178,6 +180,16 @@ pub fn connect( let local_addr = socket.local_addr().unwrap(); + let mut app_buffers = AppRecvBufMap::new( + 3, + conn_args.max_stream_window, + conn_args.max_streams_bidi, + conn_args.max_streams_uni, + ); + app_buffers + .set_expected_chunklen_to_consume(MAX_FLUSH_SIZE as u64) + .unwrap(); + // Create a QUIC connection and initiate handshake. let mut conn = quiche::connect( connect_url.domain(), @@ -310,14 +322,16 @@ pub fn connect( }; // Process potentially coalesced packets. - let read = match conn.recv(&mut buf[..len], recv_info) { - Ok(v) => v, + let read = + match conn.recv(&mut buf[..len], &mut app_buffers, recv_info) + { + Ok(v) => v, - Err(e) => { - error!("{}: recv failed: {:?}", local_addr, e); - continue 'read; - }, - }; + Err(e) => { + error!("{}: recv failed: {:?}", local_addr, e); + continue 'read; + }, + }; trace!("{}: processed {} bytes", local_addr, read); } @@ -415,7 +429,15 @@ pub fn connect( // process received data. if let Some(h_conn) = http_conn.as_mut() { h_conn.send_requests(&mut conn, &args.dump_response_path); - h_conn.handle_responses(&mut conn, &mut buf, &app_data_start); + if conn.version() == quiche::PROTOCOL_VERSION_V3 { + h_conn.handle_responses_on_quic_v3( + &mut conn, + &mut app_buffers, + &app_data_start, + ); + } else { + h_conn.handle_responses(&mut conn, &mut buf, &app_data_start); + } } // Handle path events. diff --git a/apps/src/common.rs b/apps/src/common.rs index 746e27a7..5116dca5 100644 --- a/apps/src/common.rs +++ b/apps/src/common.rs @@ -98,6 +98,8 @@ pub struct Client { pub loss_rate: f64, pub max_send_burst: usize, + + pub app_buffers: quiche::AppRecvBufMap, } pub type ClientIdMap = HashMap, ClientId>; @@ -343,6 +345,11 @@ pub trait HttpConn { req_start: &std::time::Instant, ); + fn handle_responses_on_quic_v3( + &mut self, conn: &mut quiche::Connection, + app_buffers: &mut quiche::AppRecvBufMap, req_start: &std::time::Instant, + ); + fn report_incomplete(&self, start: &std::time::Instant) -> bool; fn handle_requests( @@ -350,6 +357,13 @@ pub trait HttpConn { partial_requests: &mut HashMap, partial_responses: &mut HashMap, root: &str, index: &str, buf: &mut [u8], + app_buffers: Option<&mut quiche::AppRecvBufMap>, + ) -> quiche::h3::Result<()>; + + fn handle_requests_on_quic_v3( + &mut self, conn: &mut quiche::Connection, + partial_responses: &mut HashMap, root: &str, + index: &str, app_buffers: &mut quiche::AppRecvBufMap, ) -> quiche::h3::Result<()>; fn handle_writable( @@ -475,6 +489,14 @@ impl HttpConn for Http09Conn { self.reqs_sent += reqs_done; } + fn handle_responses_on_quic_v3( + &mut self, _conn: &mut quiche::Connection, + _app_buffers: &mut quiche::AppRecvBufMap, + _req_start: &std::time::Instant, + ) { + unimplemented!() + } + fn handle_responses( &mut self, conn: &mut quiche::Connection, buf: &mut [u8], req_start: &std::time::Instant, @@ -562,11 +584,20 @@ impl HttpConn for Http09Conn { false } + fn handle_requests_on_quic_v3( + &mut self, _conn: &mut quiche::Connection, + _partial_responses: &mut HashMap, _root: &str, + _index: &str, _app_buffers: &mut quiche::AppRecvBufMap, + ) -> quiche::h3::Result<()> { + unimplemented!() + } + fn handle_requests( &mut self, conn: &mut quiche::Connection, partial_requests: &mut HashMap, partial_responses: &mut HashMap, root: &str, index: &str, buf: &mut [u8], + _app_buffers: Option<&mut quiche::AppRecvBufMap>, ) -> quiche::h3::Result<()> { // Process all readable streams. for s in conn.readable() { @@ -887,6 +918,19 @@ impl Http3Conn { Ok(Box::new(h_conn)) } + /// poll the h3_conn with either poll() or poll_v3() depending on the + /// connection context. + fn poll_internal( + &mut self, conn: &mut quiche::Connection, + app_buffers: &mut Option<&mut quiche::AppRecvBufMap>, + ) -> quiche::h3::Result<(u64, quiche::h3::Event)> { + if let Some(ref mut app_buffers) = app_buffers { + self.h3_conn.poll_v3(conn, app_buffers) + } else { + self.h3_conn.poll(conn) + } + } + /// Builds an HTTP/3 response given a request. fn build_h3_response( root: &str, index: &str, request: &[quiche::h3::Header], @@ -1214,6 +1258,165 @@ impl HttpConn for Http3Conn { } } + fn handle_responses_on_quic_v3( + &mut self, conn: &mut quiche::Connection, + app_buffers: &mut quiche::AppRecvBufMap, req_start: &std::time::Instant, + ) { + loop { + match self.h3_conn.poll_v3(conn, app_buffers) { + Ok((stream_id, quiche::h3::Event::Headers { list, .. })) => { + debug!( + "got response headers {:?} on stream id {}", + hdrs_to_strings(&list), + stream_id + ); + + let req = self + .reqs + .iter_mut() + .find(|r| r.stream_id == Some(stream_id)) + .unwrap(); + + req.response_hdrs = list; + }, + + Ok((stream_id, quiche::h3::Event::Data)) => { + let (b, tot_exp_len) = match self.h3_conn.recv_body_v3( + conn, + stream_id, + app_buffers, + ) { + Ok((b, tot_exp_len)) => { + debug!( + "got {} bytes of response data on stream {}. Total expected will be {}", + b.len(), stream_id, tot_exp_len + ); + + (b, tot_exp_len) + }, + + Err(quiche::h3::Error::Done) => panic!("Error::Done"), + + Err(e) => panic!("Error reading conn: {:?}", e), + }; + + // If this condition is not satified, we can conn.recv() more + // before processing what we already have. + // As long as MAX_FLUSH_SIZE < --max-data/2; this is okay. + if b.len() >= crate::client::MAX_FLUSH_SIZE || + b.len() == tot_exp_len + { + let req = self + .reqs + .iter_mut() + .find(|r| r.stream_id == Some(stream_id)) + .unwrap(); + + match &mut req.response_writer { + Some(rw) => { + rw.write_all(b).ok(); + self.h3_conn + .body_consumed( + conn, + stream_id, + b.len(), + app_buffers, + ) + .unwrap(); + }, + None => { + self.h3_conn + .body_consumed( + conn, + stream_id, + b.len(), + app_buffers, + ) + .unwrap(); + }, + } + } + }, + + Ok((_stream_id, quiche::h3::Event::Finished)) => { + self.reqs_complete += 1; + let reqs_count = self.reqs.len(); + debug!( + "{}/{} responses received", + self.reqs_complete, reqs_count + ); + + if self.reqs_complete == reqs_count { + info!( + "{}/{} response(s) received in {:?}, closing...", + self.reqs_complete, + reqs_count, + req_start.elapsed() + ); + + if self.dump_json { + dump_json( + &self.reqs, + &mut *self.output_sink.borrow_mut(), + ); + } + + match conn.close(true, 0x100, b"kthxbye") { + // Already closed. + Ok(_) | Err(quiche::Error::Done) => (), + + Err(e) => panic!("error closing conn: {:?}", e), + } + + break; + } + }, + + Ok((_stream_id, quiche::h3::Event::Reset(e))) => { + error!("request was reset by peer with {}, closing...", e); + + match conn.close(true, 0x100, b"kthxbye") { + // Already closed. + Ok(_) | Err(quiche::Error::Done) => (), + + Err(e) => panic!("error closing conn: {:?}", e), + } + + break; + }, + + Ok(( + prioritized_element_id, + quiche::h3::Event::PriorityUpdate, + )) => { + info!( + "{} PRIORITY_UPDATE triggered for element ID={}", + conn.trace_id(), + prioritized_element_id + ); + }, + + Ok((goaway_id, quiche::h3::Event::GoAway)) => { + info!( + "{} got GOAWAY with ID {} ", + conn.trace_id(), + goaway_id + ); + }, + + Err(quiche::h3::Error::Done) => { + break; + }, + + Err(e) => { + error!("HTTP/3 processing failed: {:?}", e); + + break; + }, + } + } + } + fn handle_responses( &mut self, conn: &mut quiche::Connection, buf: &mut [u8], req_start: &std::time::Instant, @@ -1258,17 +1461,18 @@ impl HttpConn for Http3Conn { req.response_body.extend_from_slice(&buf[..len]); match &mut req.response_writer { - Some(rw) => { - rw.write_all(&buf[..read]).ok(); + Some(_rw) => { + // for fair comparison + // rw.write_all(&buf[..read]).ok(); }, None => if !self.dump_json { - self.output_sink.borrow_mut()(unsafe { - String::from_utf8_unchecked( - buf[..read].to_vec(), - ) - }); + // self.output_sink.borrow_mut()(unsafe { + // String::from_utf8_unchecked( + // buf[..read].to_vec(), + //) + //}); }, } } @@ -1386,15 +1590,32 @@ impl HttpConn for Http3Conn { false } + fn handle_requests_on_quic_v3( + &mut self, conn: &mut quiche::Connection, + partial_responses: &mut HashMap, root: &str, + index: &str, app_buffers: &mut quiche::AppRecvBufMap, + ) -> quiche::h3::Result<()> { + self.handle_requests( + conn, + &mut HashMap::new(), + partial_responses, + root, + index, + &mut [0; 0], + Some(app_buffers), + ) + } + fn handle_requests( &mut self, conn: &mut quiche::Connection, _partial_requests: &mut HashMap, partial_responses: &mut HashMap, root: &str, index: &str, buf: &mut [u8], + mut app_buffers: Option<&mut quiche::AppRecvBufMap>, ) -> quiche::h3::Result<()> { // Process HTTP stream-related events. loop { - match self.h3_conn.poll(conn) { + match self.poll_internal(conn, &mut app_buffers) { Ok((stream_id, quiche::h3::Event::Headers { list, .. })) => { info!( "{} got request {:?} on stream id {}", diff --git a/bench_i71165.sh b/bench_i71165.sh new file mode 100755 index 00000000..139bcff1 --- /dev/null +++ b/bench_i71165.sh @@ -0,0 +1,12 @@ +MIN=400MHz +MAX=4700MHz +SET_MIN=2799MHz +SET_MAX=2800MHz +BENCH=$1 +PROFILE=$2 + +sudo cpupower -c 0 frequency-set -d $SET_MIN -u $SET_MAX -g performance +taskset -c 0 cargo bench --bench $BENCH --profile $PROFILE +sudo cpupower -c 0 frequency-set -d $MIN -u $MAX -g powersave + + diff --git a/bench_ryzen7.sh b/bench_ryzen7.sh new file mode 100755 index 00000000..57416ef9 --- /dev/null +++ b/bench_ryzen7.sh @@ -0,0 +1,12 @@ +MIN=2200MHz +MAX=4300MHz +SET_MIN=2200MHz +SET_MAX=2200MHz +BENCH=$1 +PROFILE=$2 + +sudo cpupower frequency-set -d $SET_MIN -u $SET_MAX -g performance +taskset -c 0 cargo bench --bench $BENCH --profile $PROFILE +sudo cpupower frequency-set -d $MIN -u $MAX -g schedutil + + diff --git a/bench_xeongold.sh b/bench_xeongold.sh new file mode 100755 index 00000000..723705ea --- /dev/null +++ b/bench_xeongold.sh @@ -0,0 +1,12 @@ +MIN=800MHz +MAX=3200MHz +SET_MIN=2000MHz +SET_MAX=2000MHz +BENCH=$1 +PROFILE=$2 + +sudo cpupower -c 0 frequency-set -d $SET_MIN -u $SET_MAX -g performance +taskset -c 0 cargo bench --bench $BENCH --profile $PROFILE +sudo cpupower -c 0 frequency-set -d $MIN -u $MAX -g powersave + + diff --git a/octets/src/lib.rs b/octets/src/lib.rs index 36f24667..f15a0067 100644 --- a/octets/src/lib.rs +++ b/octets/src/lib.rs @@ -24,10 +24,10 @@ // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +use likely_stable::if_unlikely; /// Zero-copy abstraction for parsing and constructing network packets. use std::mem; use std::ptr; -use likely_stable::if_unlikely; /// A specialized [`Result`] type for [`OctetsMut`] operations. /// @@ -99,7 +99,6 @@ macro_rules! peek_u_buflen_guaranteed { }}; } - macro_rules! get_u { ($b:expr, $ty:ty, $len:expr) => {{ let out = peek_u!($b, $ty, $len); @@ -112,7 +111,7 @@ macro_rules! get_u { macro_rules! peek_u_reverse { ($b:expr, $ty:ty, $len:expr) => {{ - if_unlikely!{ $b.off < $len => { + if_unlikely! { $b.off < $len => { return Err(BufferError::BufferProtocolError); } else { $b.off -= $len; @@ -127,12 +126,12 @@ macro_rules! peek_u_reverse { /// in the reverse direction, from the end to the beginning, like reading /// a Manga. /// -/// For example, we start at offset = buf.len(); then rewind 1 byte to read 1 byte. -/// The buffer offset keeps moving backward while reading information with the set of -/// [..]_reverse() functions. +/// For example, we start at offset = buf.len(); then rewind 1 byte to read 1 +/// byte. The buffer offset keeps moving backward while reading information with +/// the set of [..]_reverse() functions. macro_rules! get_u_reverse { ($b:expr, $ty:ty, $len:expr) => {{ - if_unlikely!{ $b.off < $len => { + if_unlikely! { $b.off < $len => { // This is protocol-level bug -- Could happen if received frames // are missing elements. // Or if we're reading things we should not. In that case, it is @@ -284,11 +283,12 @@ impl<'a> Octets<'a> { Ok(out) } - /// On PROTOCOL_VERSION_V3, variable length integers also need to be "reversed", with the - /// 2-bits length indicator at the end of the last byte. + /// On PROTOCOL_VERSION_V3, variable length integers also need to be + /// "reversed", with the 2-bits length indicator at the end of the last + /// byte. pub fn get_varint_reverse(&mut self) -> Result { - if_unlikely!{ self.off == 0 => { - return Err(BufferError::BufferProtocolError); + if_unlikely! { self.off == 0 => { + Err(BufferError::BufferProtocolError) } else { self.off -= 1; // This checks buffer size while we don't need it. @@ -308,8 +308,8 @@ impl<'a> Octets<'a> { _ => unreachable!(), }; - return Ok(out); - }}; + Ok(out) + }} } /// Reads `len` bytes from the current offset without copying and advances @@ -332,8 +332,8 @@ impl<'a> Octets<'a> { /// Rewind the buffer of `len` bytes from the current offset and then /// read without copying. pub fn get_bytes_reverse(&mut self, len: usize) -> Result> { - if_unlikely!{ self.off < len => { - return Err(BufferError::BufferProtocolError); + if_unlikely! { self.off < len => { + Err(BufferError::BufferProtocolError) } else { self.off -= len; let out = Octets { @@ -341,12 +341,13 @@ impl<'a> Octets<'a> { off: 0, }; - return Ok(out); - }}; + Ok(out) + }} } - /// Reads `len` + 1 bytes from the current offset without copying and advances - /// the buffer, where `len` is an unsigned 8-bit integer prefix. + /// Reads `len` + 1 bytes from the current offset without copying and + /// advances the buffer, where `len` is an unsigned 8-bit integer + /// prefix. pub fn get_bytes_with_u8_length(&mut self) -> Result> { let len = self.get_u8()?; self.get_bytes(len as usize) @@ -366,7 +367,8 @@ impl<'a> Octets<'a> { self.get_bytes(len as usize) } - /// Rewind the buffer of `len`+ 2 bytes and read `len` bytes without copying. + /// Rewind the buffer of `len`+ 2 bytes and read `len` bytes without + /// copying. pub fn get_bytes_with_u16_length_reverse(&mut self) -> Result> { let len = self.get_u16_reverse()?; self.get_bytes_reverse(len as usize) @@ -380,7 +382,8 @@ impl<'a> Octets<'a> { self.get_bytes(len as usize) } - /// Rewind the buffer of `len`+ varint bytes and read `len` bytes without copying. + /// Rewind the buffer of `len`+ varint bytes and read `len` bytes without + /// copying. pub fn get_bytes_with_varint_length_reverse(&mut self) -> Result> { let len = self.get_varint_reverse()?; self.get_bytes_reverse(len as usize) @@ -431,6 +434,17 @@ impl<'a> Octets<'a> { Ok(()) } + /// Rewind the buffer's offset. + pub fn rewind(&mut self, rewind: usize) -> Result<()> { + if self.off < rewind { + return Err(BufferError::BufferTooShortError); + } + + self.off -= rewind; + + Ok(()) + } + /// Returns the remaining capacity in the buffer. pub fn cap(&self) -> usize { self.buf.len() - self.off @@ -637,28 +651,25 @@ impl<'a> OctetsMut<'a> { pub fn put_varint_with_len_reverse( &mut self, v: u64, len: usize, ) -> Result<&mut [u8]> { - if self.cap() < len { return Err(BufferError::BufferTooShortError); } let buf = match len { - 1 => { - self.put_u8((v<<2) as u8)? - }, + 1 => self.put_u8((v << 2) as u8)?, 2 => { - let buf = self.put_u16((v<<2) as u16)?; + let buf = self.put_u16((v << 2) as u16)?; buf[1] |= 0x1; buf }, 4 => { - let buf = self.put_u32((v<<2) as u32)?; + let buf = self.put_u32((v << 2) as u32)?; buf[3] |= 0x2; buf - } + }, 8 => { - let buf = self.put_u64(v<<2)?; + let buf = self.put_u64(v << 2)?; buf[7] |= 0x3; buf }, @@ -1184,7 +1195,6 @@ mod tests { b.skip(8).expect("skip issue"); assert_eq!(b.get_varint_reverse().unwrap(), 464037470360126853); assert_eq!(b.off(), 0); - } #[test] fn get_varint_mut() { diff --git a/quiche/Cargo.toml b/quiche/Cargo.toml index 357d0267..61e31a5d 100644 --- a/quiche/Cargo.toml +++ b/quiche/Cargo.toml @@ -76,6 +76,8 @@ qlog = { version = "0.12", path = "../qlog", optional = true } sfv = { version = "0.9", optional = true } smallvec = { version = "1.10", features = ["serde", "union"] } likely_stable = "0.1.2" +cpu-time = "1.0.0" +itertools = "0.12.1" [target."cfg(windows)".dependencies] winapi = { version = "0.3", features = ["wincrypt", "ws2def", "ws2ipdef", "ws2tcpip"] } @@ -83,6 +85,22 @@ winapi = { version = "0.3", features = ["wincrypt", "ws2def", "ws2ipdef", "ws2tc [dev-dependencies] mio = { version = "0.8", features = ["net", "os-poll"] } url = "2.5" +pprof = { version = "0.13.0", features = ["flamegraph", "criterion"] } +# criterion = { version = "0.5.1", features = ["html_reports"] } +criterion = { version = "0.5.1"} [lib] crate-type = ["lib", "staticlib", "cdylib"] + + +[[bench]] +name = "quic_benchmarks" +harness = false + +[[bench]] +name = "initial_cwin_bench" +harness = false + +[[bench]] +name = "h3_benchmarks" +harness = false diff --git a/quiche/benches/bench_util.rs b/quiche/benches/bench_util.rs new file mode 100644 index 00000000..1a629718 --- /dev/null +++ b/quiche/benches/bench_util.rs @@ -0,0 +1,127 @@ +use cpu_time::ProcessTime; +use criterion::measurement::Measurement; +use criterion::measurement::ValueFormatter; +use criterion::Throughput; +use std::time::Duration; + +const NANOS_PER_SEC: u64 = 1_000_000_000; + + +/// Keeps track of QUIC streams and enforces stream limits. + +pub struct CPUTime; +impl Measurement for CPUTime { + type Intermediate = ProcessTime; + type Value = Duration; + + fn start(&self) -> Self::Intermediate { + ProcessTime::now() + } + + fn end(&self, i: Self::Intermediate) -> Self::Value { + i.elapsed() + } + + fn add(&self, v1: &Self::Value, v2: &Self::Value) -> Self::Value { + *v1 + *v2 + } + + fn zero(&self) -> Self::Value { + Duration::from_secs(0) + } + + fn to_f64(&self, val: &Self::Value) -> f64 { + let nanos = val.as_secs() * NANOS_PER_SEC + u64::from(val.subsec_nanos()); + nanos as f64 + } + + fn formatter(&self) -> &dyn ValueFormatter { + &DurationFormatter + } +} + +pub struct DurationFormatter; +impl DurationFormatter { + fn bytes_per_second( + &self, bytes: f64, typical: f64, values: &mut [f64], + ) -> &'static str { + let bytes_per_second = bytes * (1e9 / typical); + let (denominator, unit) = if bytes_per_second < 1024.0 { + (1.0, " B/s") + } else if bytes_per_second < 1024.0 * 1024.0 { + (1024.0, "KiB/s") + } else if bytes_per_second < 1024.0 * 1024.0 * 1024.0 { + (1024.0 * 1024.0, "MiB/s") + } else { + (1024.0 * 1024.0 * 1024.0, "GiB/s") + }; + + for val in values { + let bytes_per_second = bytes * (1e9 / *val); + *val = bytes_per_second / denominator; + } + + unit + } + + fn elements_per_second( + &self, elems: f64, typical: f64, values: &mut [f64], + ) -> &'static str { + let elems_per_second = elems * (1e9 / typical); + let (denominator, unit) = if elems_per_second < 1000.0 { + (1.0, " elem/s") + } else if elems_per_second < 1000.0 * 1000.0 { + (1000.0, "Kelem/s") + } else if elems_per_second < 1000.0 * 1000.0 * 1000.0 { + (1000.0 * 1000.0, "Melem/s") + } else { + (1000.0 * 1000.0 * 1000.0, "Gelem/s") + }; + + for val in values { + let elems_per_second = elems * (1e9 / *val); + *val = elems_per_second / denominator; + } + + unit + } +} + +impl ValueFormatter for DurationFormatter { + fn scale_values(&self, ns: f64, values: &mut [f64]) -> &'static str { + let (factor, unit) = if ns < 10f64.powi(0) { + (10f64.powi(3), "ps") + } else if ns < 10f64.powi(3) { + (10f64.powi(0), "ns") + } else if ns < 10f64.powi(6) { + (10f64.powi(-3), "us") + } else if ns < 10f64.powi(9) { + (10f64.powi(-6), "ms") + } else { + (10f64.powi(-9), "s") + }; + + for val in values { + *val *= factor; + } + + unit + } + + fn scale_throughputs( + &self, typical: f64, throughput: &Throughput, values: &mut [f64], + ) -> &'static str { + match *throughput { + Throughput::Bytes(bytes) => + self.bytes_per_second(bytes as f64, typical, values), + Throughput::Elements(elems) => + self.elements_per_second(elems as f64, typical, values), + Throughput::BytesDecimal(_) => todo!(), + } + } + + fn scale_for_machines(&self, _values: &mut [f64]) -> &'static str { + // no scaling is needed + "ns" + } +} diff --git a/quiche/benches/h3_benchmarks.rs b/quiche/benches/h3_benchmarks.rs new file mode 100644 index 00000000..22744128 --- /dev/null +++ b/quiche/benches/h3_benchmarks.rs @@ -0,0 +1,322 @@ +mod bench_util; +use criterion::black_box; +use criterion::criterion_group; +use criterion::criterion_main; +use criterion::BatchSize; +use criterion::BenchmarkId; +use criterion::Criterion; +use criterion::Throughput; +use quiche::h3::testing::Session; +use quiche::h3::Header; +use quiche::h3::NameValue; +use itertools::Itertools; + +use bench_util::*; + +const NUMBER_OF_REQUESTS: u32 = 80; +const MAX_DATAGRAM_SIZE: usize = 1350; + +#[derive(Default)] +pub struct StreamIdHasher { + id: u64, +} + +impl std::hash::Hasher for StreamIdHasher { + #[inline] + fn finish(&self) -> u64 { + self.id + } + + #[inline] + fn write_u64(&mut self, id: u64) { + self.id = id; + } + + #[inline] + fn write(&mut self, _: &[u8]) { + // We need a default write() for the trait but stream IDs will always + // be a u64 so we just delegate to write_u64. + unimplemented!() + } +} + +type BuildStreamIdHasher = std::hash::BuildHasherDefault; + +type StreamIdHashMap = + std::collections::HashMap; + +// Process 157 packets at a time to roughly match the MAX RCV_BUF +pub const BATCH_PACKETS_SIZE: usize = 157; + +fn bench_h3( + s: &mut Session, flight: &mut Vec<(Vec, quiche::SendInfo)>, + response_map: &mut StreamIdHashMap>, +) { + // Simulate the receiver receiving BATCH_PACKETS_SIZE + // from the OS, and then feeding it to QUIC, and eventually + // polling HTTP/3 data. + for chunk in &flight.into_iter().chunks(BATCH_PACKETS_SIZE) { + for &mut (ref mut pkt, ref mut si) in chunk { + let info = quiche::RecvInfo { + to: si.to, + from: si.from, + }; + s.pipe + .client + .recv(pkt, &mut s.pipe.client_app_buffers, info) + .unwrap(); + } + // polling! + let mut res_count = 0; + + loop { + match s.client.poll(&mut s.pipe.client) { + Ok((stream_id, quiche::h3::Event::Headers { list, .. })) => { + let s = std::str::from_utf8(list[2].value()).unwrap(); + let content_length = s.parse().unwrap(); + // update the map with a fully allocated app receive buffer. + response_map.insert(stream_id, vec![0; content_length]); + }, + Ok((stream_id, quiche::h3::Event::Data)) => { + s.recv_body_client( + stream_id, + response_map.get_mut(&stream_id).unwrap(), + ) + .unwrap(); + black_box(response_map.get(&stream_id).unwrap()); + }, + Ok((_, quiche::h3::Event::Finished)) => { + res_count += 1; + if res_count == NUMBER_OF_REQUESTS { + break; // we're done. + } + }, + Err(quiche::h3::Error::Done) => { + res_count += 1; + if res_count == NUMBER_OF_REQUESTS { + break; // we're done. + } + } + _ => (), + } + } + } +} + +fn bench_h3_quicv3( + s: &mut Session, flight: &mut Vec<(Vec, quiche::SendInfo)>, +) { + for chunk in &flight.into_iter().chunks(BATCH_PACKETS_SIZE) { + for &mut (ref mut pkt, ref mut si) in chunk { + let info = quiche::RecvInfo { + to: si.to, + from: si.from, + }; + s.pipe + .client + .recv(pkt, &mut s.pipe.client_app_buffers, info) + .unwrap(); + } + // polling! + let mut res_count = 0; + + loop { + match s + .client + .poll_v3(&mut s.pipe.client, &mut s.pipe.client_app_buffers) + { + Ok((stream_id, quiche::h3::Event::Data)) => { + let (b, tot_exp_len) = s.recv_body_v3_client(stream_id).unwrap(); + let len = b.len(); + s.body_consumed_client(stream_id, len).unwrap(); + }, + Ok((_, quiche::h3::Event::Finished)) => { + res_count += 1; + if res_count == NUMBER_OF_REQUESTS { + break; // we're done. + } + }, + Err(quiche::h3::Error::Done) => { + res_count += 1; + if res_count == NUMBER_OF_REQUESTS { + break; // we're done. + } + } + _ => (), + } + } + } +} + +fn criterion_benchmark(c: &mut Criterion) { + let mut config_v1 = quiche::Config::new(quiche::PROTOCOL_VERSION_V1).unwrap(); + let mut config_v3 = quiche::Config::new(quiche::PROTOCOL_VERSION_V3).unwrap(); + config_v1 + .load_cert_chain_from_pem_file("examples/cert.crt") + .unwrap(); + config_v1 + .load_priv_key_from_pem_file("examples/cert.key") + .unwrap(); + config_v1 + .set_application_protos(&[b"proto1", b"proto2"]) + .unwrap(); + config_v1.set_max_recv_udp_payload_size(MAX_DATAGRAM_SIZE); + config_v1.set_max_send_udp_payload_size(MAX_DATAGRAM_SIZE); + config_v1.set_initial_max_data(10_000_000_000); + config_v1.set_max_stream_window(25_165_824); + config_v1.set_initial_max_stream_data_uni(10_000_000_000); + config_v1.set_initial_max_streams_bidi(10_000_000_000); + config_v1.set_initial_max_stream_data_bidi_local(10_000_000_000); + config_v1.set_initial_max_stream_data_bidi_remote(10_000_000_000); + config_v1.set_initial_max_streams_bidi(10000); + config_v1.set_initial_max_streams_uni(10000); + config_v1.set_initial_congestion_window_packets(1_000_000); // Dr.Evil's choice + config_v1.verify_peer(false); + + config_v3 + .load_cert_chain_from_pem_file("examples/cert.crt") + .unwrap(); + config_v3 + .load_priv_key_from_pem_file("examples/cert.key") + .unwrap(); + config_v3 + .set_application_protos(&[b"proto1", b"proto2"]) + .unwrap(); + config_v3.set_max_recv_udp_payload_size(MAX_DATAGRAM_SIZE); + config_v3.set_max_send_udp_payload_size(MAX_DATAGRAM_SIZE); + config_v3.set_initial_max_data(10_000_000_000); + config_v3.set_max_stream_window(25_165_824); + config_v3.set_initial_max_stream_data_uni(10_000_000_000); + config_v3.set_initial_max_streams_bidi(10_000_000_000); + config_v3.set_initial_max_stream_data_bidi_local(10_000_000_000); + config_v3.set_initial_max_stream_data_bidi_remote(10_000_000_000); + config_v3.set_initial_max_streams_bidi(10_000); + config_v3.set_initial_max_streams_uni(10_000); + config_v3.set_initial_congestion_window_packets(1_000_000); + config_v3.verify_peer(false); + + let h3_config = quiche::h3::Config::new().unwrap(); + + let mut group = c.benchmark_group("H3_Recv_path"); + let sendbuf = vec![0; 31250]; + group.throughput(Throughput::Bytes(2_500_000)); + + group.bench_with_input( + BenchmarkId::new("H3_with_QUIC_V3", 2_500_000), + &sendbuf, + |b, sendbuf| { + b.iter_batched_ref( + || { + // init called for each run + let mut s = Session::with_configs(&mut config_v3, &h3_config) + .unwrap(); + s.handshake().unwrap(); + let mut response_map = StreamIdHashMap::default(); + let resp = vec![ + Header::new(b":status", b"200"), + Header::new(b"server", b"quiche-test"), + Header::new(b"content-length", b"31250"), + ]; + + for _ in 0..NUMBER_OF_REQUESTS { + let (stream_id, _) = s.send_request(true).unwrap(); + response_map.insert(stream_id, Vec::::new()); + s.poll_server().unwrap(); // headers + s.poll_server().unwrap(); // finished event + } + + for stream_id in response_map.keys() { + s.server + .send_response( + &mut s.pipe.server, + *stream_id, + &resp, + false, + ) + .unwrap(); + s.server + .send_body( + &mut s.pipe.server, + *stream_id, + &sendbuf, + true, + ) + .unwrap(); + } + // let's catch flying packets + let flight = + quiche::testing::emit_flight(&mut s.pipe.server).unwrap(); + (s, flight) + }, + // Benched code for each sample + |(ref mut s, flight)| bench_h3_quicv3(s, flight), + BatchSize::SmallInput, + ) + }, + ); + + group.bench_with_input( + BenchmarkId::new("H3", 2_500_000), + &sendbuf, + |b, sendbuf| { + b.iter_batched_ref( + || { + // init called for each run + let mut s = Session::with_configs(&mut config_v1, &h3_config) + .unwrap(); + s.handshake().unwrap(); + let mut response_map = StreamIdHashMap::default(); + let resp = vec![ + Header::new(b":status", b"200"), + Header::new(b"server", b"quiche-test"), + Header::new(b"content-length", b"31250"), + ]; + for _ in 0..NUMBER_OF_REQUESTS { + let (stream_id, _) = s.send_request(true).unwrap(); + response_map.insert(stream_id, Vec::::new()); + s.poll_server().unwrap(); // headers + s.poll_server().unwrap(); // finished event + } + for stream_id in response_map.keys() { + s.server + .send_response( + &mut s.pipe.server, + *stream_id, + &resp, + false, + ) + .unwrap(); + s.server + .send_body( + &mut s.pipe.server, + *stream_id, + &sendbuf, + true, + ) + .unwrap(); + } + // let's catch flying packets + let flight = + quiche::testing::emit_flight(&mut s.pipe.server).unwrap(); + (s, flight, response_map) + }, + |(ref mut s, flight, response_map)| { + bench_h3(s, flight, response_map) + }, + BatchSize::SmallInput, + ) + }, + ); + group.finish(); +} + +criterion_group! { + name = h3_quicv1_vs_h3_quicv3; + config = Criterion::default() + .measurement_time(std::time::Duration::from_secs(1)) + .with_measurement(CPUTime) + .sample_size(5000); + targets = criterion_benchmark +} + +criterion_main!(h3_quicv1_vs_h3_quicv3); diff --git a/quiche/benches/initial_cwin_bench.rs b/quiche/benches/initial_cwin_bench.rs new file mode 100644 index 00000000..f3c64bb9 --- /dev/null +++ b/quiche/benches/initial_cwin_bench.rs @@ -0,0 +1,166 @@ +mod bench_util; +use bench_util::*; +use criterion::black_box; +use criterion::criterion_group; +use criterion::criterion_main; +use criterion::BatchSize; +use criterion::BenchmarkId; +use criterion::Criterion; +use criterion::Throughput; +use quiche::testing::Pipe; + +const MAX_DATAGRAM_SIZE: usize = 1350; + +fn bench_v1_receive( + pipe: &mut Pipe, flight: &mut Vec<(Vec, quiche::SendInfo)>, + buf: &mut [u8], +) { + for &mut (ref mut pkt, ref mut si) in flight.iter_mut() { + let info = quiche::RecvInfo { + to: si.to, + from: si.from, + }; + pipe.client + .recv(pkt, &mut pipe.client_app_buffers, info) + .unwrap(); + } + let (..) = pipe.client.stream_recv(1, buf).unwrap(); + + black_box(buf); +} + +fn bench_v3_receive( + pipe: &mut Pipe, flight: &mut Vec<(Vec, quiche::SendInfo)>, +) { + for &mut (ref mut pkt, ref mut si) in flight.iter_mut() { + let info = quiche::RecvInfo { + to: si.to, + from: si.from, + }; + pipe.client + .recv(pkt, &mut pipe.client_app_buffers, info) + .unwrap(); + } + let (b, ..) = pipe + .client + .stream_recv_v3(1, &mut pipe.client_app_buffers) + .unwrap(); + + black_box(b); +} + +fn criterion_benchmark(c: &mut Criterion) { + let mut config_v1 = quiche::Config::new(quiche::PROTOCOL_VERSION_V1).unwrap(); + let mut config_v3 = quiche::Config::new(quiche::PROTOCOL_VERSION_V3).unwrap(); + + config_v1 + .load_cert_chain_from_pem_file("examples/cert.crt") + .unwrap(); + config_v1 + .load_priv_key_from_pem_file("examples/cert.key") + .unwrap(); + config_v1 + .set_application_protos(&[b"proto1", b"proto2"]) + .unwrap(); + config_v1.set_max_recv_udp_payload_size(MAX_DATAGRAM_SIZE); + config_v1.set_max_send_udp_payload_size(MAX_DATAGRAM_SIZE); + config_v1.set_initial_max_data(10_000_000_000); + config_v1.set_max_stream_window(25_165_824); + config_v1.set_initial_max_stream_data_uni(10_000_000_000); + config_v1.set_initial_max_streams_bidi(10_000_000_000); + config_v1.set_initial_max_stream_data_bidi_local(10_000_000_000); + config_v1.set_initial_max_stream_data_bidi_remote(10_000_000_000); + config_v1.verify_peer(false); + + config_v3 + .load_cert_chain_from_pem_file("examples/cert.crt") + .unwrap(); + config_v3 + .load_priv_key_from_pem_file("examples/cert.key") + .unwrap(); + config_v3 + .set_application_protos(&[b"proto1", b"proto2"]) + .unwrap(); + config_v3.set_max_recv_udp_payload_size(MAX_DATAGRAM_SIZE); + config_v3.set_max_send_udp_payload_size(MAX_DATAGRAM_SIZE); + config_v3.set_initial_max_data(10_000_000_000); + config_v3.set_max_stream_window(25_165_824); + config_v3.set_initial_max_stream_data_uni(10_000_000_000); + config_v3.set_initial_max_streams_bidi(10_000_000_000); + config_v3.set_initial_max_stream_data_bidi_local(10_000_000_000); + config_v3.set_initial_max_stream_data_bidi_remote(10_000_000_000); + config_v3.verify_peer(false); + + let mut group = c.benchmark_group("Quiche_Recv_path"); + let sendbuf = vec![0; 10000]; + group.throughput(Throughput::Bytes(10000)); + + // We only Micro-benchmark processing the QUIC packets and emitting them to + // the application through the stream_recv() call in V1 or the + // stream_recv_v3() call in V3. We do this for a full cwnd. + group.bench_with_input( + BenchmarkId::new("Quic_V3_Recv_Path", 10000), + &sendbuf, + |b, sendbuf| { + b.iter_batched_ref( + || { + let mut pipe_v3 = Pipe::with_config(&mut config_v3).unwrap(); + pipe_v3.handshake().unwrap(); + // designed to avoid having the receiver's buffer being + // initialized as part of the benchmark. + pipe_v3.server.stream_send(1, b"init", false).unwrap(); + pipe_v3.advance().unwrap(); + pipe_v3 + .client + .stream_recv_v3(1, &mut pipe_v3.client_app_buffers) + .unwrap(); + pipe_v3 + .client + .stream_consumed(1, 4, &mut pipe_v3.client_app_buffers) + .unwrap(); + pipe_v3.server.stream_send(1, sendbuf, false).unwrap(); + let flight = + quiche::testing::emit_flight(&mut pipe_v3.server) + .unwrap(); + (pipe_v3, flight) + }, + |(ref mut pipe, flight)| bench_v3_receive(pipe, flight), + BatchSize::SmallInput, + ) + }, + ); + group.bench_with_input( + BenchmarkId::new("Quic_V1_Recv_path", 10000), + &sendbuf, + |b, sendbuf| { + // recv buffer initialization + let mut buf = vec![0; 32768]; + b.iter_batched_ref( + || { + let mut pipe_v1 = Pipe::with_config(&mut config_v1).unwrap(); + pipe_v1.handshake().unwrap(); + pipe_v1.server.stream_send(1, sendbuf, false).unwrap(); + let flight = + quiche::testing::emit_flight(&mut pipe_v1.server) + .unwrap(); + (pipe_v1, flight) + }, + |(ref mut pipe, flight)| bench_v1_receive(pipe, flight, &mut buf), + BatchSize::SmallInput, + ) + }, + ); + group.finish(); +} + +criterion_group! { + name = quicv1_vs_quicv3_cwin; + config = Criterion::default() + //.with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))) + .measurement_time(std::time::Duration::from_secs(1)) + .with_measurement(CPUTime) + .sample_size(5000); + targets = criterion_benchmark +} + +criterion_main!(quicv1_vs_quicv3_cwin); diff --git a/quiche/benches/quic_benchmarks.rs b/quiche/benches/quic_benchmarks.rs new file mode 100644 index 00000000..1312d4cb --- /dev/null +++ b/quiche/benches/quic_benchmarks.rs @@ -0,0 +1,175 @@ +mod bench_util; +use bench_util::*; +use criterion::black_box; +use criterion::criterion_group; +use criterion::criterion_main; +use criterion::BatchSize; +use criterion::BenchmarkId; +use criterion::Criterion; +use criterion::Throughput; +use quiche::testing::Pipe; + +fn bench_v1_receive( + pipe: &mut Pipe, flight: &mut Vec<(Vec, quiche::SendInfo)>, + buf: &mut [u8], +) { + for &mut (ref mut pkt, ref mut si) in flight.iter_mut() { + let info = quiche::RecvInfo { + to: si.to, + from: si.from, + }; + pipe.client + .recv(pkt, &mut pipe.client_app_buffers, info) + .unwrap(); + } + let (..) = pipe.client.stream_recv(1, buf).unwrap(); + + black_box(buf); +} + +fn bench_v3_receive( + pipe: &mut Pipe, flight: &mut Vec<(Vec, quiche::SendInfo)>, +) { + for &mut (ref mut pkt, ref mut si) in flight.iter_mut() { + let info = quiche::RecvInfo { + to: si.to, + from: si.from, + }; + pipe.client + .recv(pkt, &mut pipe.client_app_buffers, info) + .unwrap(); + } + let (b, ..) = pipe + .client + .stream_recv_v3(1, &mut pipe.client_app_buffers) + .unwrap(); + + black_box(b); +} + +fn criterion_benchmark(c: &mut Criterion) { + let mut config_v1 = quiche::Config::new(quiche::PROTOCOL_VERSION_V1).unwrap(); + let mut config_v3 = quiche::Config::new(quiche::PROTOCOL_VERSION_V3).unwrap(); + static MAX_DATAGRAM_SIZE: usize = 1350; + + config_v1 + .load_cert_chain_from_pem_file("examples/cert.crt") + .unwrap(); + config_v1 + .load_priv_key_from_pem_file("examples/cert.key") + .unwrap(); + config_v1 + .set_application_protos(&[b"proto1", b"proto2"]) + .unwrap(); + config_v1.set_max_recv_udp_payload_size(MAX_DATAGRAM_SIZE); + config_v1.set_max_send_udp_payload_size(MAX_DATAGRAM_SIZE); + config_v1.set_initial_max_data(10_000_000_000); + config_v1.set_max_stream_window(25_165_824); + config_v1.set_initial_max_stream_data_uni(10_000_000_000); + config_v1.set_initial_max_streams_bidi(10_000_000_000); + config_v1.set_initial_max_stream_data_bidi_local(10_000_000_000); + config_v1.set_initial_max_stream_data_bidi_remote(10_000_000_000); + config_v1.set_initial_congestion_window_packets(1_000_000); + config_v1.verify_peer(false); + + config_v3 + .load_cert_chain_from_pem_file("examples/cert.crt") + .unwrap(); + config_v3 + .load_priv_key_from_pem_file("examples/cert.key") + .unwrap(); + config_v3 + .set_application_protos(&[b"proto1", b"proto2"]) + .unwrap(); + config_v3.set_max_recv_udp_payload_size(MAX_DATAGRAM_SIZE); + config_v3.set_max_send_udp_payload_size(MAX_DATAGRAM_SIZE); + config_v3.set_initial_max_data(10_000_000_000); + config_v3.set_max_stream_window(25_165_824); + config_v3.set_initial_max_stream_data_uni(10_000_000_000); + config_v3.set_initial_max_streams_bidi(10_000_000_000); + config_v3.set_initial_max_stream_data_bidi_local(10_000_000_000); + config_v3.set_initial_max_stream_data_bidi_remote(10_000_000_000); + config_v3.set_initial_congestion_window_packets(1_000_000); + config_v3.verify_peer(false); + + let mut group = c.benchmark_group("Quiche_Recv_path"); + + static MAX_RCV_BUF_SIZE: usize = 212992; + let mut steps: Vec = (10*MAX_DATAGRAM_SIZE..50*MAX_DATAGRAM_SIZE).step_by(5*MAX_DATAGRAM_SIZE).collect(); + let secondsteps: Vec = (50*MAX_DATAGRAM_SIZE..MAX_RCV_BUF_SIZE).step_by(20*MAX_DATAGRAM_SIZE).collect(); + steps.extend(secondsteps); + + for size in steps { + let sendbuf = vec![0; size]; + group.throughput(Throughput::Bytes(size as u64)); + + // We only Micro-benchmark processing the QUIC packets and emitting them to + // the application through the stream_recv() call in V1 or the + // stream_recv_v3() call in V3. We do this for a full cwnd. + group.bench_with_input( + BenchmarkId::new("Quic_V3_Recv_Path", size), + &sendbuf, + |b, sendbuf| { + b.iter_batched_ref( + || { + let mut pipe_v3 = Pipe::with_config(&mut config_v3).unwrap(); + pipe_v3.handshake().unwrap(); + // designed to avoid having the receiver's buffer being + // initialized as part of the benchmark. + pipe_v3.server.stream_send(1, b"init", false).unwrap(); + pipe_v3.advance().unwrap(); + pipe_v3 + .client + .stream_recv_v3(1, &mut pipe_v3.client_app_buffers) + .unwrap(); + pipe_v3 + .client + .stream_consumed(1, 4, &mut pipe_v3.client_app_buffers) + .unwrap(); + pipe_v3.server.stream_send(1, sendbuf, false).unwrap(); + let flight = + quiche::testing::emit_flight(&mut pipe_v3.server) + .unwrap(); + (pipe_v3, flight) + }, + |(ref mut pipe, flight)| bench_v3_receive(pipe, flight), + BatchSize::SmallInput, + ) + }, + ); + group.bench_with_input( + BenchmarkId::new("Quic_V1_Recv_path", size), + &sendbuf, + |b, sendbuf| { + // recv buffer initialization + let mut buf = vec![0; MAX_RCV_BUF_SIZE]; + b.iter_batched_ref( + || { + let mut pipe_v1 = Pipe::with_config(&mut config_v1).unwrap(); + pipe_v1.handshake().unwrap(); + pipe_v1.server.stream_send(1, sendbuf, false).unwrap(); + let flight = + quiche::testing::emit_flight(&mut pipe_v1.server) + .unwrap(); + (pipe_v1, flight) + }, + |(ref mut pipe, flight)| bench_v1_receive(pipe, flight, &mut buf), + BatchSize::SmallInput, + ) + }, + ); + } + group.finish(); +} + +criterion_group! { + name = quicv1_vs_quicv3; + config = Criterion::default() + //.with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))) + .measurement_time(std::time::Duration::from_secs(1)) + .with_measurement(CPUTime) + .sample_size(5000); + targets = criterion_benchmark +} + +criterion_main!(quicv1_vs_quicv3); diff --git a/quiche/examples/client.rs b/quiche/examples/client.rs index 9a5fb395..244c97a8 100644 --- a/quiche/examples/client.rs +++ b/quiche/examples/client.rs @@ -29,6 +29,8 @@ extern crate log; use ring::rand::*; +use quiche::AppRecvBufMap; + const MAX_DATAGRAM_SIZE: usize = 1350; const HTTP_REQ_STREAM_ID: u64 = 4; @@ -135,6 +137,7 @@ fn main() { let req_start = std::time::Instant::now(); let mut req_sent = false; + let mut app_buffers = AppRecvBufMap::new(3, 10_000_000, 100, 100); loop { poll.poll(&mut events, conn.timeout()).unwrap(); @@ -175,14 +178,15 @@ fn main() { }; // Process potentially coalesced packets. - let read = match conn.recv(&mut buf[..len], recv_info) { - Ok(v) => v, - - Err(e) => { - error!("recv failed: {:?}", e); - continue 'read; - }, - }; + let read = + match conn.recv(&mut buf[..len], &mut app_buffers, recv_info) { + Ok(v) => v, + + Err(e) => { + error!("recv failed: {:?}", e); + continue 'read; + }, + }; debug!("processed {} bytes", read); } diff --git a/quiche/examples/http3-client.rs b/quiche/examples/http3-client.rs index 92646e0d..c4f8c588 100644 --- a/quiche/examples/http3-client.rs +++ b/quiche/examples/http3-client.rs @@ -29,6 +29,8 @@ extern crate log; use quiche::h3::NameValue; +use quiche::AppRecvBufMap; + use ring::rand::*; const MAX_DATAGRAM_SIZE: usize = 1350; @@ -154,6 +156,8 @@ fn main() { let mut req_sent = false; + let mut app_buffers = AppRecvBufMap::new(3, 10_000_000, 100, 100); + loop { poll.poll(&mut events, conn.timeout()).unwrap(); @@ -194,14 +198,15 @@ fn main() { }; // Process potentially coalesced packets. - let read = match conn.recv(&mut buf[..len], recv_info) { - Ok(v) => v, + let read = + match conn.recv(&mut buf[..len], &mut app_buffers, recv_info) { + Ok(v) => v, - Err(e) => { - error!("recv failed: {:?}", e); - continue 'read; - }, - }; + Err(e) => { + error!("recv failed: {:?}", e); + continue 'read; + }, + }; debug!("processed {} bytes", read); } diff --git a/quiche/examples/http3-server.rs b/quiche/examples/http3-server.rs index 3314e507..7e3344c1 100644 --- a/quiche/examples/http3-server.rs +++ b/quiche/examples/http3-server.rs @@ -35,6 +35,8 @@ use ring::rand::*; use quiche::h3::NameValue; +use quiche::AppRecvBufMap; + const MAX_DATAGRAM_SIZE: usize = 1350; struct PartialResponse { @@ -116,6 +118,8 @@ fn main() { let local_addr = socket.local_addr().unwrap(); + let mut app_buffers = AppRecvBufMap::new(3, 10_000_000, 100, 100); + loop { // Find the shorter timeout from all the active connections. // @@ -295,14 +299,15 @@ fn main() { }; // Process potentially coalesced packets. - let read = match client.conn.recv(pkt_buf, recv_info) { - Ok(v) => v, + let read = + match client.conn.recv(pkt_buf, &mut app_buffers, recv_info) { + Ok(v) => v, - Err(e) => { - error!("{} recv failed: {:?}", client.conn.trace_id(), e); - continue 'read; - }, - }; + Err(e) => { + error!("{} recv failed: {:?}", client.conn.trace_id(), e); + continue 'read; + }, + }; debug!("{} processed {} bytes", client.conn.trace_id(), read); diff --git a/quiche/examples/server.rs b/quiche/examples/server.rs index 496b51ca..315bd898 100644 --- a/quiche/examples/server.rs +++ b/quiche/examples/server.rs @@ -33,6 +33,8 @@ use std::collections::HashMap; use ring::rand::*; +use quiche::AppRecvBufMap; + const MAX_DATAGRAM_SIZE: usize = 1350; struct PartialResponse { @@ -114,6 +116,8 @@ fn main() { let local_addr = socket.local_addr().unwrap(); + let mut app_buffers = AppRecvBufMap::new(3, 10_000_000, 100, 100); + loop { // Find the shorter timeout from all the active connections. // @@ -292,14 +296,15 @@ fn main() { }; // Process potentially coalesced packets. - let read = match client.conn.recv(pkt_buf, recv_info) { - Ok(v) => v, + let read = + match client.conn.recv(pkt_buf, &mut app_buffers, recv_info) { + Ok(v) => v, - Err(e) => { - error!("{} recv failed: {:?}", client.conn.trace_id(), e); - continue 'read; - }, - }; + Err(e) => { + error!("{} recv failed: {:?}", client.conn.trace_id(), e); + continue 'read; + }, + }; debug!("{} processed {} bytes", client.conn.trace_id(), read); @@ -310,27 +315,50 @@ fn main() { } // Process all readable streams. - for s in client.conn.readable() { - while let Ok((read, fin)) = - client.conn.stream_recv(s, &mut buf) - { - debug!( - "{} received {} bytes", - client.conn.trace_id(), - read - ); - - let stream_buf = &buf[..read]; - - debug!( - "{} stream {} has {} bytes (fin? {})", - client.conn.trace_id(), - s, - stream_buf.len(), - fin - ); - - handle_stream(client, s, stream_buf, "examples/root"); + if client.conn.version() == quiche::PROTOCOL_VERSION_V1 { + for s in client.conn.readable() { + while let Ok((read, fin)) = + client.conn.stream_recv(s, &mut buf) + { + debug!( + "{} received {} bytes", + client.conn.trace_id(), + read + ); + + let stream_buf = &buf[..read]; + + debug!( + "{} stream {} has {} bytes (fin? {})", + client.conn.trace_id(), + s, + stream_buf.len(), + fin + ); + + handle_stream(client, s, stream_buf, "examples/root"); + } + } + } else { + for s in client.conn.readable() { + while let Ok((stream_buf, read, fin)) = + client.conn.stream_recv_v3(s, &mut app_buffers) + { + debug!( + "{} received {} bytes", + client.conn.trace_id(), + read + ); + debug!( + "{} stream {} has {} bytes (fin? {})", + client.conn.trace_id(), + s, + stream_buf.len(), + fin + ); + + handle_stream(client, s, stream_buf, "examples/root"); + } } } } diff --git a/quiche/src/crypto/boringssl.rs b/quiche/src/crypto/boringssl.rs index 7d59bed7..13c92d1f 100644 --- a/quiche/src/crypto/boringssl.rs +++ b/quiche/src/crypto/boringssl.rs @@ -66,6 +66,44 @@ impl Open { } Ok(out_len) } + + pub fn open_with_u64_counter_into( + &self, counter: u64, ad: &[u8], buf: &[u8], into: &mut [u8], + ) -> Result { + if cfg!(feature = "fuzzing") { + return Ok(buf.len()); + } + let tag_len = self.alg().tag_len(); + + let mut out_len = match buf.len().checked_sub(tag_len) { + Some(n) => n, + None => return Err(Error::CryptoFail), + }; + let max_out_len = out_len; + + let nonce = make_nonce(&self.packet.nonce, counter); + + let rc = unsafe { + EVP_AEAD_CTX_open( + &self.packet.ctx, // ctx + into.as_mut_ptr(), // out + &mut out_len, // out_len + max_out_len, // max_out_len + nonce[..].as_ptr(), // nonce + nonce.len(), // nonce_len + buf.as_ptr(), // inp + buf.len(), // in_len + ad.as_ptr(), // ad + ad.len(), // ad_len + ) + }; + + if rc != 1 { + return Err(Error::CryptoFail); + } + + Ok(out_len) + } } impl Seal { diff --git a/quiche/src/crypto/mod.rs b/quiche/src/crypto/mod.rs index c15973c4..a2b17d4a 100644 --- a/quiche/src/crypto/mod.rs +++ b/quiche/src/crypto/mod.rs @@ -163,6 +163,10 @@ impl Open { }) } + pub fn alg(&self) -> Algorithm { + self.alg + } + pub fn new_mask(&self, sample: &[u8]) -> Result<[u8; 5]> { if cfg!(feature = "fuzzing") { return Ok(<[u8; 5]>::default()); @@ -190,10 +194,6 @@ impl Open { Ok(mask) } - pub fn alg(&self) -> Algorithm { - self.alg - } - pub fn derive_next_packet_key(&self) -> Result { let next_secret = derive_next_secret(self.alg, &self.secret)?; diff --git a/quiche/src/crypto/openssl_quictls.rs b/quiche/src/crypto/openssl_quictls.rs index 3db183c3..12938f50 100644 --- a/quiche/src/crypto/openssl_quictls.rs +++ b/quiche/src/crypto/openssl_quictls.rs @@ -142,6 +142,117 @@ impl Open { Ok(plaintext_len + olen as usize) } + + pub fn open_with_u64_counter_into( + &self, counter: u64, ad: &[u8], buf: &[u8], into: &mut [u8], + ) -> Result { + if cfg!(feature = "fuzzing") { + return Ok(buf.len()); + } + + let tag_len = self.alg().tag_len(); + + let mut cipher_len = buf.len(); + + let nonce = make_nonce(&self.packet.nonce, counter); + + // Set the IV len. + const EVP_CTRL_AEAD_SET_IVLEN: i32 = 0x9; + let mut rc = unsafe { + EVP_CIPHER_CTX_ctrl( + self.packet.ctx, + EVP_CTRL_AEAD_SET_IVLEN, + nonce.len() as i32, + std::ptr::null_mut(), + ) + }; + if rc != 1 { + return Err(Error::CryptoFail); + } + + rc = unsafe { + EVP_CipherInit_ex2( + self.packet.ctx, + std::ptr::null_mut(), // already set + self.packet.key.as_ptr(), + nonce[..].as_ptr(), + Self::DECRYPT as i32, + std::ptr::null(), + ) + }; + + if rc != 1 { + return Err(Error::CryptoFail); + } + + let mut olen: i32 = 0; + + if !ad.is_empty() { + rc = unsafe { + EVP_CipherUpdate( + self.packet.ctx, + std::ptr::null_mut(), + &mut olen, + ad.as_ptr(), + ad.len() as i32, + ) + }; + + if rc != 1 { + return Err(Error::CryptoFail); + } + } + + if cipher_len < tag_len { + return Err(Error::CryptoFail); + } + + cipher_len -= tag_len; + + rc = unsafe { + EVP_CipherUpdate( + self.packet.ctx, + into.as_mut_ptr(), + &mut olen, + buf.as_ptr(), + cipher_len as i32, + ) + }; + + if rc != 1 { + return Err(Error::CryptoFail); + } + + let plaintext_len = olen as usize; + + const EVP_CTRL_AEAD_SET_TAG: i32 = 0x11; + rc = unsafe { + EVP_CIPHER_CTX_ctrl( + self.packet.ctx, + EVP_CTRL_AEAD_SET_TAG, + tag_len as i32, + into[cipher_len..].as_mut_ptr() as *mut c_void, + ) + }; + + if rc != 1 { + return Err(Error::CryptoFail); + } + + rc = unsafe { + EVP_CipherFinal_ex( + self.packet.ctx, + into[plaintext_len..].as_mut_ptr(), + &mut olen, + ) + }; + + if rc != 1 { + return Err(Error::CryptoFail); + } + + Ok(plaintext_len + olen as usize) + } } impl Seal { diff --git a/quiche/src/flowcontrol.rs b/quiche/src/flowcontrol.rs index f764bf9a..cf7424ee 100644 --- a/quiche/src/flowcontrol.rs +++ b/quiche/src/flowcontrol.rs @@ -106,15 +106,17 @@ impl FlowControl { /// Autotune the window size. When there is an another update /// within RTT x 2, bump the window x 1.5, capped by /// max_window. - pub fn autotune_window(&mut self, now: Instant, rtt: Duration) { + pub fn autotune_window(&mut self, now: Instant, rtt: Duration) -> bool { if let Some(last_update) = self.last_update { if now - last_update < rtt * WINDOW_TRIGGER_FACTOR { self.window = std::cmp::min( self.window * WINDOW_INCREASE_FACTOR, self.max_window, ); + return true; } } + false } /// Make sure the lower bound of the window is same to diff --git a/quiche/src/frame.rs b/quiche/src/frame.rs index 3c8621b1..a19fa63d 100644 --- a/quiche/src/frame.rs +++ b/quiche/src/frame.rs @@ -105,6 +105,11 @@ pub enum Frame { data: stream::RangeBuf, }, + StreamV3 { + stream_id: u64, + metadata: stream::RecvBufInfo, + }, + StreamHeader { stream_id: u64, offset: u64, @@ -189,24 +194,23 @@ pub enum Frame { impl Frame { pub fn from_bytes( - b: &mut octets::Octets, pkt: packet::Type, - version: u32, + b: &mut octets::Octets, pkt: packet::Type, version: u32, ) -> Result { - - let frame_type = if_likely!{version == crate::PROTOCOL_VERSION_V3 => { + let frame_type = if_likely! {version == crate::PROTOCOL_VERSION_V3 => { b.get_varint_reverse()? } else { b.get_varint()? }}; - // Parse frames according either to the V3 format or to the previous Quic format. - // In V3, frames are reversed, meaning that: + // Parse frames according either to the V3 format or to the previous Quic + // format. In V3, frames are reversed, meaning that: // - Elements order is reversed - // - Elements are encoded and decoded with the set of [..]_reverse() Octets functions to - // enable reading them from the back of the buffer towards the beginning (Manga-like). + // - Elements are encoded and decoded with the set of [..]_reverse() + // Octets functions to enable reading them from the back of the buffer + // towards the beginning (Manga-like). let frame: Frame = match frame_type { 0x00 => { let mut len = 1; - if_likely!{version == crate::PROTOCOL_VERSION_V3 => { + if_likely! {version == crate::PROTOCOL_VERSION_V3 => { while b.peek_u8_reverse() == Ok(0x00) { b.get_u8_reverse()?; @@ -227,7 +231,7 @@ impl Frame { 0x02..=0x03 => parse_ack_frame(frame_type, b, version)?, - 0x04 => if_likely!{version == crate::PROTOCOL_VERSION_V3 => { + 0x04 => if_likely! {version == crate::PROTOCOL_VERSION_V3 => { Frame::ResetStream { stream_id: b.get_varint_reverse()?, error_code: b.get_varint_reverse()?, @@ -241,7 +245,7 @@ impl Frame { } }}, - 0x05 => if_likely!{version == crate::PROTOCOL_VERSION_V3 => { + 0x05 => if_likely! {version == crate::PROTOCOL_VERSION_V3 => { Frame::StopSending { stream_id: b.get_varint_reverse()?, error_code: b.get_varint_reverse()?, @@ -254,7 +258,7 @@ impl Frame { }}, 0x06 => { - let (offset, data) = if_likely!{version == crate::PROTOCOL_VERSION_V3 => { + let (offset, data) = if_likely! {version == crate::PROTOCOL_VERSION_V3 => { (b.get_varint_reverse()?, b.get_bytes_with_varint_length_reverse()?) } else { @@ -268,7 +272,7 @@ impl Frame { }, 0x07 => Frame::NewToken { - token: if_likely!{version == crate::PROTOCOL_VERSION_V3 => { + token: if_likely! {version == crate::PROTOCOL_VERSION_V3 => { let len = b.get_varint_reverse()?; if len == 0 { return Err(Error::InvalidFrame); @@ -280,20 +284,20 @@ impl Frame { return Err(Error::InvalidFrame); } b.get_bytes(len as usize)?.to_vec() - }} + }}, }, 0x08..=0x0f => parse_stream_frame(frame_type, b, version)?, 0x10 => Frame::MaxData { - max: if_likely!{version == crate::PROTOCOL_VERSION_V3 => { + max: if_likely! {version == crate::PROTOCOL_VERSION_V3 => { b.get_varint_reverse()? } else { b.get_varint()? - }} + }}, }, - 0x11 => if_likely!{version == crate::PROTOCOL_VERSION_V3 => { + 0x11 => if_likely! {version == crate::PROTOCOL_VERSION_V3 => { Frame::MaxStreamData { stream_id: b.get_varint_reverse()?, max: b.get_varint_reverse()?, @@ -306,27 +310,27 @@ impl Frame { }}, 0x12 => Frame::MaxStreamsBidi { - max: if_likely!{version == crate::PROTOCOL_VERSION_V3 => { + max: if_likely! {version == crate::PROTOCOL_VERSION_V3 => { b.get_varint_reverse()? } else { b.get_varint()? - }} + }}, }, 0x13 => Frame::MaxStreamsUni { - max: if_likely!{version == crate::PROTOCOL_VERSION_V3 => { + max: if_likely! {version == crate::PROTOCOL_VERSION_V3 => { b.get_varint_reverse()? } else { b.get_varint()? - }} + }}, }, 0x14 => Frame::DataBlocked { - limit: if_likely!{version == crate::PROTOCOL_VERSION_V3 => { + limit: if_likely! {version == crate::PROTOCOL_VERSION_V3 => { b.get_varint_reverse()? } else { b.get_varint()? - }} + }}, }, 0x15 => if_likely! {version == crate::PROTOCOL_VERSION_V3 => { @@ -342,22 +346,22 @@ impl Frame { }}, 0x16 => Frame::StreamsBlockedBidi { - limit: if_likely!{version == crate::PROTOCOL_VERSION_V3 => { + limit: if_likely! {version == crate::PROTOCOL_VERSION_V3 => { b.get_varint_reverse()? } else { b.get_varint()? - }} + }}, }, 0x17 => Frame::StreamsBlockedUni { - limit: if_likely!{version == crate::PROTOCOL_VERSION_V3 => { + limit: if_likely! {version == crate::PROTOCOL_VERSION_V3 => { b.get_varint_reverse()? } else { b.get_varint()? - }} + }}, }, - 0x18 => if_likely!{ version == crate::PROTOCOL_VERSION_V3 => { + 0x18 => if_likely! { version == crate::PROTOCOL_VERSION_V3 => { let seq_num = b.get_varint_reverse()?; let retire_prior_to = b.get_varint_reverse()?; let conn_id_len = b.get_u8_reverse()?; @@ -398,7 +402,7 @@ impl Frame { }}, 0x19 => Frame::RetireConnectionId { - seq_num: if_likely!{version == crate::PROTOCOL_VERSION_V3 => { + seq_num: if_likely! {version == crate::PROTOCOL_VERSION_V3 => { b.get_varint_reverse()? } else { b.get_varint()? @@ -406,7 +410,7 @@ impl Frame { }, 0x1a => Frame::PathChallenge { - data: if_likely!{version == crate::PROTOCOL_VERSION_V3 =>{ + data: if_likely! {version == crate::PROTOCOL_VERSION_V3 =>{ b .get_bytes_reverse(8)? .buf() @@ -422,7 +426,7 @@ impl Frame { }, 0x1b => Frame::PathResponse { - data: if_likely!{version == crate::PROTOCOL_VERSION_V3 =>{ + data: if_likely! {version == crate::PROTOCOL_VERSION_V3 =>{ b .get_bytes_reverse(8)? .buf() @@ -451,7 +455,7 @@ impl Frame { } }}, - 0x1d => if_likely! {version == crate::PROTOCOL_VERSION_V3 => { + 0x1d => if_likely! {version == crate::PROTOCOL_VERSION_V3 => { Frame::ApplicationClose { error_code: b.get_varint_reverse()?, reason: b.get_bytes_with_varint_length_reverse()?.to_vec(), @@ -505,10 +509,9 @@ impl Frame { Ok(frame) } - pub fn to_bytes(&self, - b: &mut octets::OctetsMut, - version: u32 - ) -> Result { + pub fn to_bytes( + &self, b: &mut octets::OctetsMut, version: u32, + ) -> Result { let before = b.cap(); match self { @@ -516,7 +519,7 @@ impl Frame { let mut left = *len; while left > 0 { - if_likely!{version == crate::PROTOCOL_VERSION_V3 => { + if_likely! {version == crate::PROTOCOL_VERSION_V3 => { b.put_varint_reverse(0x00)?; } else { b.put_varint(0x00)?; @@ -526,7 +529,7 @@ impl Frame { }, Frame::Ping { .. } => { - if_likely!{version == crate::PROTOCOL_VERSION_V3 => { + if_likely! {version == crate::PROTOCOL_VERSION_V3 => { b.put_varint_reverse(0x01)?; } else { b.put_varint(0x01)?; @@ -691,8 +694,11 @@ impl Frame { }}; }, + // We don't use it to send data; we only use that for some test. + Frame::StreamV3 { .. } => (), + Frame::Stream { stream_id, data } => { - if_likely!{version == crate::PROTOCOL_VERSION_V3 => { + if_likely! {version == crate::PROTOCOL_VERSION_V3 => { b.put_bytes(data)?; encode_stream_footer( @@ -929,7 +935,7 @@ impl Frame { if_likely! {version == crate::PROTOCOL_VERSION_V3 => { b.put_bytes(data.as_ref())?; - encode_dgram_footer(data.len() as u64, b)?; + encode_dgram_footer(data.len() as u64, b)?; } else { encode_dgram_header(data.len() as u64, b)?; @@ -1025,6 +1031,17 @@ impl Frame { octets::varint_len(token.len() as u64) + // token length token.len() // token }, + // Only used in the received pipeline + Frame::StreamV3 { + stream_id, + metadata, + } => { + 1 + // frame type + octets::varint_len(*stream_id) + // stream_id + octets::varint_len(metadata.off()) + // offset + 2 + // length, always encode as 2-byte varint + metadata.len() // data + }, Frame::Stream { stream_id, data } => { 1 + // frame type @@ -1253,6 +1270,17 @@ impl Frame { }, }, + Frame::StreamV3 { + stream_id, + metadata, + } => QuicFrame::Stream { + stream_id: *stream_id, + offset: metadata.off(), + length: metadata.len() as u64, + fin: metadata.fin().then_some(true), + raw: None, + }, + Frame::Stream { stream_id, data } => QuicFrame::Stream { stream_id: *stream_id, offset: data.off(), @@ -1345,14 +1373,15 @@ impl Frame { trigger_frame_type: None, // don't know trigger type }, - Frame::ApplicationClose { error_code, reason } => + Frame::ApplicationClose { error_code, reason } => { QuicFrame::ConnectionClose { error_space: Some(ErrorSpace::ApplicationError), error_code: Some(*error_code), error_code_value: None, // raw error is no different for us reason: Some(String::from_utf8_lossy(reason).into_owned()), trigger_frame_type: None, // don't know trigger type - }, + } + }, Frame::HandshakeDone => QuicFrame::HandshakeDone, @@ -1421,6 +1450,20 @@ impl std::fmt::Debug for Frame { write!(f, "NEW_TOKEN len={}", token.len())?; }, + Frame::StreamV3 { + stream_id, + metadata, + } => { + write!( + f, + "STREAMV3 id={} off={} len={} fin={}", + stream_id, + metadata.off(), + metadata.len(), + metadata.fin() + )?; + }, + Frame::Stream { stream_id, data } => { write!( f, @@ -1538,7 +1581,9 @@ impl std::fmt::Debug for Frame { } } -fn parse_ack_frame(ty: u64, b: &mut octets::Octets, version: u32) -> Result { +fn parse_ack_frame( + ty: u64, b: &mut octets::Octets, version: u32, +) -> Result { let first = ty as u8; let mut ranges = ranges::RangeSet::default(); @@ -1557,7 +1602,7 @@ fn parse_ack_frame(ty: u64, b: &mut octets::Octets, version: u32) -> Result { + let gap = if_likely! {version == crate::PROTOCOL_VERSION_V3 => { b.get_varint_reverse()? } else { b.get_varint()? @@ -1580,12 +1625,11 @@ fn parse_ack_frame(ty: u64, b: &mut octets::Octets, version: u32) -> Result { + let ecn = if_likely! {version == crate::PROTOCOL_VERSION_V3 => { EcnCounts { ect0_count: b.get_varint_reverse()?, ect1_count: b.get_varint_reverse()?, @@ -1679,7 +1723,6 @@ pub fn encode_stream_footer( b.put_varint_reverse(u64::from(ty))?; - Ok(()) } @@ -1709,10 +1752,12 @@ pub fn encode_dgram_header(length: u64, b: &mut octets::OctetsMut) -> Result<()> Ok(()) } -fn parse_stream_frame(ty: u64, b: &mut octets::Octets, version: u32) -> Result { +fn parse_stream_frame( + ty: u64, b: &mut octets::Octets, version: u32, +) -> Result { let first = ty as u8; - if_likely!{ version == crate::PROTOCOL_VERSION_V3 => { + if_likely! { version == crate::PROTOCOL_VERSION_V3 => { let stream_id = b.get_varint_reverse()?; @@ -1734,11 +1779,11 @@ fn parse_stream_frame(ty: u64, b: &mut octets::Octets, version: u32) -> Result Result Result { let first = ty as u8; @@ -1821,25 +1864,47 @@ mod tests { if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_ok()); } #[test] @@ -1863,25 +1928,47 @@ mod tests { if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_ok()); } #[test] @@ -1911,25 +1998,47 @@ mod tests { if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_ok()); } #[test] @@ -1965,25 +2074,47 @@ mod tests { if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_ok()); } #[test] @@ -2007,25 +2138,47 @@ mod tests { if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_err()); } #[test] @@ -2048,25 +2201,47 @@ mod tests { if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_err()); } #[test] @@ -2090,25 +2265,47 @@ mod tests { if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_ok()); } #[test] @@ -2130,25 +2327,47 @@ mod tests { if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_err()); } #[test] @@ -2157,6 +2376,10 @@ mod tests { let _d2 = [42; 128]; let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + let framev3 = Frame::StreamV3 { + stream_id: 32, + metadata: stream::RecvBufInfo::from(1230976, 12, true), + }; let frame = Frame::Stream { stream_id: 32, data: stream::RangeBuf::from(&data, 1230976, true), @@ -2172,26 +2395,57 @@ mod tests { let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(framev3) + ); + } else { + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_err()); } #[test] @@ -2217,9 +2471,13 @@ mod tests { b.skip(wire_len).expect("skip issue"); } assert_eq!( - Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), Err(Error::InvalidFrame) - ); + ); } #[test] @@ -2239,25 +2497,47 @@ mod tests { if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_err()); } #[test] @@ -2280,25 +2560,47 @@ mod tests { if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_err()); } #[test] @@ -2310,7 +2612,6 @@ mod tests { let wire_len = { let mut b = octets::OctetsMut::with_slice(&mut d); frame.to_bytes(&mut b, crate::PROTOCOL_VERSION).unwrap() - }; assert_eq!(wire_len, 5); @@ -2318,25 +2619,47 @@ mod tests { if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_err()); } #[test] @@ -2356,25 +2679,47 @@ mod tests { if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_err()); } #[test] @@ -2394,25 +2739,47 @@ mod tests { if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_err()); } #[test] @@ -2435,25 +2802,47 @@ mod tests { if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_err()); } #[test] @@ -2473,25 +2862,47 @@ mod tests { if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_err()); } #[test] @@ -2511,25 +2922,47 @@ mod tests { if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_err()); } #[test] @@ -2554,25 +2987,47 @@ mod tests { if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_err()); } #[test] @@ -2592,25 +3047,47 @@ mod tests { if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_err()); } #[test] @@ -2632,25 +3109,47 @@ mod tests { if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_err()); } #[test] @@ -2672,25 +3171,47 @@ mod tests { if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_err()); } #[test] @@ -2714,25 +3235,47 @@ mod tests { if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_ok()); } #[test] @@ -2756,25 +3299,47 @@ mod tests { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_err()); } #[test] @@ -2795,25 +3360,47 @@ mod tests { b.skip(wire_len).expect("skip issue"); } - assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), Ok(frame)); + assert_eq!( + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), + Ok(frame) + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_err()); } #[test] @@ -2836,27 +3423,46 @@ mod tests { b.skip(wire_len).expect("skip issue"); } assert_eq!( - Frame::from_bytes(&mut b, packet::Type::Short, crate::PROTOCOL_VERSION), + Frame::from_bytes( + &mut b, + packet::Type::Short, + crate::PROTOCOL_VERSION + ), Ok(frame.clone()) - ); + ); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Initial, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Initial, + crate::PROTOCOL_VERSION + ) + .is_err()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::ZeroRTT, crate::PROTOCOL_VERSION).is_ok()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::ZeroRTT, + crate::PROTOCOL_VERSION + ) + .is_ok()); let mut b = octets::Octets::with_slice(&d); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { b.skip(wire_len).expect("skip issue"); } - assert!(Frame::from_bytes(&mut b, packet::Type::Handshake, crate::PROTOCOL_VERSION).is_err()); + assert!(Frame::from_bytes( + &mut b, + packet::Type::Handshake, + crate::PROTOCOL_VERSION + ) + .is_err()); let frame_data = match &frame { Frame::Datagram { data } => data.clone(), diff --git a/quiche/src/h3/mod.rs b/quiche/src/h3/mod.rs index 39f8b67c..a71d64b1 100644 --- a/quiche/src/h3/mod.rs +++ b/quiche/src/h3/mod.rs @@ -391,6 +391,12 @@ pub enum Error { /// Frame violated layout or size rules. FrameError, + /// Since QUIC v3 introduces a new API, we reflect these + /// changes to the H3 module, leading to different + /// function to be called depending on usage of the QUIC + /// protocol version. + InvalidAPICall(&'static str), + /// QPACK Header block decompression failure. QpackDecompressionFailed, @@ -450,6 +456,7 @@ impl Error { Error::MessageError => 0x10E, Error::ConnectError => 0x10F, Error::VersionFallback => 0x110, + Error::InvalidAPICall(_) => 0x102, // TODO change this? } } @@ -508,7 +515,8 @@ impl std::convert::From for Error { fn from(err: octets::BufferError) -> Self { match err { octets::BufferError::BufferTooShortError => Error::BufferTooShort, - octets::BufferError::BufferProtocolError => Error::BufferProtocolError, + octets::BufferError::BufferProtocolError => + Error::BufferProtocolError, } } } @@ -905,11 +913,17 @@ impl Connection { ) -> Result { let initial_uni_stream_id = if is_server { 0x3 } else { 0x2 }; let h3_datagram = if enable_dgram { Some(1) } else { None }; + let next_request_stream_id = + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 0x4 + } else { + 0 + }; Ok(Connection { is_server, - next_request_stream_id: 0, + next_request_stream_id, next_uni_stream_id: initial_uni_stream_id, @@ -1040,8 +1054,10 @@ impl Connection { let stream_id = self.next_request_stream_id; - self.streams - .insert(stream_id, stream::Stream::new(stream_id, true)); + self.streams.insert( + stream_id, + stream::Stream::new(stream_id, true, conn.version), + ); // The underlying QUIC stream does not exist yet, so calls to e.g. // stream_capacity() will fail. By writing a 0-length buffer, we force @@ -1252,7 +1268,9 @@ impl Connection { let mut b = octets::OctetsMut::with_slice(&mut d); // Validate that it is sane to send data on the stream. - if stream_id % 4 != 0 { + if stream_id % 4 != 0 || + (stream_id == 0 && conn.version == crate::PROTOCOL_VERSION_V3) + { return Err(Error::FrameUnexpected); } @@ -1375,6 +1393,100 @@ impl Connection { self.peer_settings.connect_protocol_enabled == Some(1) } + /// Reads request or response body data and returns a slice to the + /// data and the total bytes to expect before body_consumed() must + /// be called. + /// + /// Applications should call this method whenever the [`poll()`] method + /// returns a [`Data`] event + /// + /// On success, a slice is returned and the total bytes to expect before + /// body_consumed() has to be called, or [`Done`] if there is no data to + /// read. + /// + /// [`recv_body_v3()`] may be called several times until the slice is + /// eventually containing all promised bytes. On the meantime, if the + /// application wishes to consume the current data, it can do it and + /// then calls body_consumed() to tell how much of the data was + /// consumed. The next call to [`recv_body_v3()`] would then returns the + /// remaining slice, and the total remaining bytes to expect before + /// [`body_consumed()`] must be called. + pub fn recv_body_v3<'a>( + &mut self, conn: &mut super::Connection, stream_id: u64, + app_buf: &'a mut crate::AppRecvBufMap, + ) -> Result<(&'a [u8], usize)> { + if conn.version != crate::PROTOCOL_VERSION_V3 { + return Err(Error::InvalidAPICall( + "This function should be called on a \ + PROTOCOL_VERSION_V3 connection version", + )); + } + + let stream = self.streams.get_mut(&stream_id).ok_or(Error::Done)?; + + if stream.state() != stream::State::Data { + return Err(Error::Done); + } + + let (b, len, _) = stream.try_acquire_data(conn, app_buf)?; + + if len == 0 { + return Err(Error::Done); + } + // TODO should we keep returning the total data, or do we update it + // accounting to what was consumed? + Ok((b, stream.get_state_len() - stream.get_state_off())) + } + + /// Marks the data acquired by the application as consumed by it. + /// + /// Applications should call this method once they processed data from + /// [`recv_body_v3()`], and doesn't need it to stay available. That is, + /// application should always consume the data from [`recv_body_v3()`] + /// either through a copy, or by processing it. Ideally, the stream + /// capacity is large enough such that the whole data can be processed right + /// away without requiring a copy on the application. + /// + /// Not calling this method could result in the underlying QUIC stream to + /// block on its receiving capacity, and the HTTP/3 to not change its + /// processing state. + pub fn body_consumed( + &mut self, conn: &mut super::Connection, stream_id: u64, consumed: usize, + app_buf: &mut crate::AppRecvBufMap, + ) -> Result<()> { + if conn.version != crate::PROTOCOL_VERSION_V3 { + return Err(Error::InvalidAPICall( + "This function should be called on a \ + PROTOCOL_VERSION_V3 connection version", + )); + } + + let stream = self.streams.get_mut(&stream_id).ok_or(Error::Done)?; + + stream.mark_data_consumed(conn, app_buf, consumed)?; + + // While body is being received, the stream is marked as finished only + // when all data is read by the application. + if conn.stream_finished_v3(stream_id, app_buf) { + self.process_finished_stream(stream_id); + } else { + // parse the next frame if any + match self.process_readable_stream( + conn, + stream_id, + false, + &mut Some(app_buf), + ) { + Ok(_) => unreachable!(), + + Err(Error::Done) => (), + + Err(e) => return Err(e), + }; + } + Ok(()) + } + /// Reads request or response body data into the provided buffer. /// /// Applications should call this method whenever the [`poll()`] method @@ -1389,6 +1501,12 @@ impl Connection { pub fn recv_body( &mut self, conn: &mut super::Connection, stream_id: u64, out: &mut [u8], ) -> Result { + if conn.version != crate::PROTOCOL_VERSION_V1 { + return Err(Error::InvalidAPICall( + "This function should be called on a \ + PROTOCOL_VERSION_V1 connection version", + )); + } let mut total = 0; // Try to consume all buffered data for the stream, even across multiple @@ -1420,7 +1538,8 @@ impl Connection { // DATA frame was consumed, and another one is queued behind it, // this will ensure the additional data will also be returned to // the application. - match self.process_readable_stream(conn, stream_id, false) { + match self.process_readable_stream(conn, stream_id, false, &mut None) + { Ok(_) => unreachable!(), Err(Error::Done) => (), @@ -1476,6 +1595,10 @@ impl Connection { return Err(Error::FrameUnexpected); } + if conn.version == crate::PROTOCOL_VERSION_V3 && stream_id == 0 { + return Err(Error::FrameUnexpected); + } + let control_stream_id = self.control_stream_id.ok_or(Error::FrameUnexpected)?; @@ -1610,6 +1733,65 @@ impl Connection { /// [`take_last_priority_update()`]: struct.Connection.html#method.take_last_priority_update /// [`close()`]: ../struct.Connection.html#method.close pub fn poll(&mut self, conn: &mut super::Connection) -> Result<(u64, Event)> { + if conn.version != crate::PROTOCOL_VERSION_V1 { + return Err(Error::InvalidAPICall( + "This function should be called on a \ + PROTOCOL_VERSION_V1 connection version", + )); + } + self.poll_internal(conn, None) + } + + /// Processes HTTP/3 data received from the peer. + /// + /// On success it returns an [`Event`] and an ID, or [`Done`] when there are + /// no events to report. + /// + /// Note that all events are edge-triggered, meaning that once reported they + /// will not be reported again by calling this method again, until the event + /// is re-armed. + /// + /// The events [`Headers`], [`Data`] and [`Finished`] return a stream ID, + /// which is used in methods [`recv_body_v3()`], [`body_consumed()`], + /// [`send_response()`] or [`send_body()`]. + /// + /// The event [`GoAway`] returns an ID that depends on the connection role. + /// A client receives the largest processed stream ID. A server receives the + /// the largest permitted push ID. + /// + /// The event [`PriorityUpdate`] only occurs at servers. It returns a + /// prioritized element ID that is used in the method + /// [`take_last_priority_update()`], which rearms the event for that ID. + /// + /// If an error occurs while processing data, the connection is closed with + /// the appropriate error code, using the transport's [`close()`] method. + /// + /// [`Event`]: enum.Event.html + /// [`Done`]: enum.Error.html#variant.Done + /// [`Headers`]: enum.Event.html#variant.Headers + /// [`Data`]: enum.Event.html#variant.Data + /// [`Finished`]: enum.Event.html#variant.Finished + /// [`GoAway`]: enum.Event.html#variant.GoAWay + /// [`PriorityUpdate`]: enum.Event.html#variant.PriorityUpdate + /// [`recv_body_v3()`]: struct.Connection.html#method.recv_body_v3 + /// [`body_consumed()`]: struct.Connection.html#method.body_consumed + /// [`send_response()`]: struct.Connection.html#method.send_response + /// [`send_body()`]: struct.Connection.html#method.send_body + /// [`recv_dgram()`]: struct.Connection.html#method.recv_dgram + /// [`take_last_priority_update()`]: struct.Connection.html#method.take_last_priority_update + /// [`close()`]: ../struct.Connection.html#method.close + pub fn poll_v3( + &mut self, conn: &mut super::Connection, + app_buf: &mut crate::AppRecvBufMap, + ) -> Result<(u64, Event)> { + self.poll_internal(conn, Some(app_buf)) + } + + #[inline(always)] + fn poll_internal( + &mut self, conn: &mut super::Connection, + mut app_buf: Option<&mut crate::AppRecvBufMap>, + ) -> Result<(u64, Event)> { // When connection close is initiated by the local application (e.g. due // to a protocol error), the connection itself might be in a broken // state, so return early. @@ -1619,7 +1801,7 @@ impl Connection { // Process control streams first. if let Some(stream_id) = self.peer_control_stream_id { - match self.process_control_stream(conn, stream_id) { + match self.process_control_stream(conn, stream_id, &mut app_buf) { Ok(ev) => return Ok(ev), Err(Error::Done) => (), @@ -1629,7 +1811,7 @@ impl Connection { } if let Some(stream_id) = self.peer_qpack_streams.encoder_stream_id { - match self.process_control_stream(conn, stream_id) { + match self.process_control_stream(conn, stream_id, &mut app_buf) { Ok(ev) => return Ok(ev), Err(Error::Done) => (), @@ -1639,7 +1821,7 @@ impl Connection { } if let Some(stream_id) = self.peer_qpack_streams.decoder_stream_id { - match self.process_control_stream(conn, stream_id) { + match self.process_control_stream(conn, stream_id, &mut app_buf) { Ok(ev) => return Ok(ev), Err(Error::Done) => (), @@ -1657,20 +1839,26 @@ impl Connection { for s in conn.readable() { trace!("{} stream id {} is readable", conn.trace_id(), s); - let ev = match self.process_readable_stream(conn, s, true) { - Ok(v) => Some(v), + let ev = + match self.process_readable_stream(conn, s, true, &mut app_buf) { + Ok(v) => Some(v), - Err(Error::Done) => None, + Err(Error::Done) => None, - // Return early if the stream was reset, to avoid returning - // a Finished event later as well. - Err(Error::TransportError(crate::Error::StreamReset(e))) => - return Ok((s, Event::Reset(e))), + // Return early if the stream was reset, to avoid returning + // a Finished event later as well. + Err(Error::TransportError(crate::Error::StreamReset(e))) => + return Ok((s, Event::Reset(e))), - Err(e) => return Err(e), - }; + Err(e) => return Err(e), + }; - if conn.stream_finished(s) { + if let Some(ref mut app_buf) = app_buf { + // called from poll_v3 + if conn.stream_finished_v3(s, app_buf) { + self.process_finished_stream(s); + } + } else if conn.stream_finished(s) { self.process_finished_stream(s); } @@ -1709,8 +1897,10 @@ impl Connection { // TODO: server push // // In the meantime always send 0 from client. - if !self.is_server { + if !self.is_server && conn.version == crate::PROTOCOL_VERSION_V1 { id = 0; + } else if !self.is_server && conn.version == crate::PROTOCOL_VERSION_V3 { + id = 4; } if self.is_server && id % 4 != 0 { @@ -2063,8 +2253,15 @@ impl Connection { fn process_control_stream( &mut self, conn: &mut super::Connection, stream_id: u64, + app_buf: &mut Option<&mut crate::AppRecvBufMap>, ) -> Result<(u64, Event)> { - if conn.stream_finished(stream_id) { + let is_finished = if conn.version == crate::PROTOCOL_VERSION_V3 { + let app_buf = app_buf.as_mut().unwrap(); + conn.stream_finished_v3(stream_id, app_buf) + } else { + conn.stream_finished(stream_id) + }; + if is_finished { conn.close( true, Error::ClosedCriticalStream.to_wire(), @@ -2074,7 +2271,7 @@ impl Connection { return Err(Error::ClosedCriticalStream); } - match self.process_readable_stream(conn, stream_id, true) { + match self.process_readable_stream(conn, stream_id, true, app_buf) { Ok(ev) => return Ok(ev), Err(Error::Done) => (), @@ -2082,7 +2279,14 @@ impl Connection { Err(e) => return Err(e), }; - if conn.stream_finished(stream_id) { + let is_finished = if conn.version == crate::PROTOCOL_VERSION_V3 { + let app_buf = app_buf.as_mut().unwrap(); + conn.stream_finished_v3(stream_id, app_buf) + } else { + conn.stream_finished(stream_id) + }; + + if is_finished { conn.close( true, Error::ClosedCriticalStream.to_wire(), @@ -2097,10 +2301,11 @@ impl Connection { fn process_readable_stream( &mut self, conn: &mut super::Connection, stream_id: u64, polling: bool, + app_buf: &mut Option<&mut crate::AppRecvBufMap>, ) -> Result<(u64, Event)> { - self.streams - .entry(stream_id) - .or_insert_with(|| stream::Stream::new(stream_id, false)); + self.streams.entry(stream_id).or_insert_with(|| { + stream::Stream::new(stream_id, false, conn.version) + }); // We need to get a fresh reference to the stream for each // iteration, to avoid borrowing `self` for the entire duration @@ -2109,12 +2314,30 @@ impl Connection { while let Some(stream) = self.streams.get_mut(&stream_id) { match stream.state() { stream::State::StreamType => { - stream.try_fill_buffer(conn)?; + let varint = if conn.version == crate::PROTOCOL_VERSION_V3 { + let app_buf = app_buf.as_mut().unwrap(); + let b = stream.try_acquire_state_buffer(conn, app_buf)?; + + let varint = match stream.try_consume_varint_from_buf(b) { + Ok(v) => v, - let varint = match stream.try_consume_varint() { - Ok(v) => v, + Err(_) => { + return Err(Error::Done); + }, + }; + stream.mark_state_buffer_consumed( + conn, + stream.get_state_len(), + app_buf, + )?; + varint + } else { + stream.try_fill_buffer(conn)?; + match stream.try_consume_varint() { + Ok(v) => v, - Err(_) => continue, + Err(_) => continue, + } }; let ty = stream::Type::deserialize(varint)?; @@ -2222,12 +2445,28 @@ impl Connection { }, stream::State::PushId => { - stream.try_fill_buffer(conn)?; + let varint = if conn.version == crate::PROTOCOL_VERSION_V3 { + let app_buf = app_buf.as_mut().unwrap(); + let b = stream.try_acquire_state_buffer(conn, app_buf)?; + + let varint = match stream.try_consume_varint_from_buf(b) { + Ok(v) => v, - let varint = match stream.try_consume_varint() { - Ok(v) => v, + Err(_) => return Err(Error::Done), + }; + stream.mark_state_buffer_consumed( + conn, + stream.get_state_len(), + app_buf, + )?; + varint + } else { + stream.try_fill_buffer(conn)?; + match stream.try_consume_varint() { + Ok(v) => v, - Err(_) => continue, + Err(_) => continue, + } }; if let Err(e) = stream.set_push_id(varint) { @@ -2237,12 +2476,30 @@ impl Connection { }, stream::State::FrameType => { - stream.try_fill_buffer(conn)?; + let varint = if conn.version == crate::PROTOCOL_VERSION_V3 { + let app_buf = app_buf.as_mut().unwrap(); + let b = stream.try_acquire_state_buffer(conn, app_buf)?; + + let varint = match stream.try_consume_varint_from_buf(b) { + Ok(v) => v, - let varint = match stream.try_consume_varint() { - Ok(v) => v, + Err(_) => { + return Err(Error::Done); + }, + }; + stream.mark_state_buffer_consumed( + conn, + stream.get_state_len(), + app_buf, + )?; + varint + } else { + stream.try_fill_buffer(conn)?; + match stream.try_consume_varint() { + Ok(v) => v, - Err(_) => continue, + Err(_) => continue, + } }; match stream.set_frame_type(varint) { @@ -2273,12 +2530,32 @@ impl Connection { }, stream::State::FramePayloadLen => { - stream.try_fill_buffer(conn)?; + let payload_len = if conn.version == + crate::PROTOCOL_VERSION_V3 + { + let app_buf = app_buf.as_mut().unwrap(); + let b = stream.try_acquire_state_buffer(conn, app_buf)?; - let payload_len = match stream.try_consume_varint() { - Ok(v) => v, + let varint = match stream.try_consume_varint_from_buf(b) { + Ok(v) => v, + + Err(_) => { + return Err(Error::Done); + }, + }; + stream.mark_state_buffer_consumed( + conn, + stream.get_state_len(), + app_buf, + )?; + varint + } else { + stream.try_fill_buffer(conn)?; + match stream.try_consume_varint() { + Ok(v) => v, - Err(_) => continue, + Err(_) => continue, + } }; // DATA frames are handled uniquely. After this point we lose @@ -2318,26 +2595,85 @@ impl Connection { break; } - stream.try_fill_buffer(conn)?; + let (frame, payload_len) = if conn.version == + crate::PROTOCOL_VERSION_V3 + { + let app_buf = app_buf.as_mut().unwrap(); + let b = match stream + .try_acquire_state_buffer(conn, app_buf) + { + Ok(b) => b, + Err(e) => { + // Handle empty frame -- i.e., we get a + // Error::Done + // from above since we read everything. In V1, the + // code + // still parse an empty state_buf and then parse + // an empty + // frame (e.g., settings). This copies the + // behavior. + match app_buf.get(stream_id) { + Some(buf) => { + if buf.len() > stream.get_state_len() { + &buf[..stream.get_state_len()] + } else { + buf + } + }, + None => return Err(e), + } + }, + }; - let (frame, payload_len) = match stream.try_consume_frame() { - Ok(frame) => frame, + match stream.try_consume_frame_from_buf(b) { + Ok((frame, payload_len)) => { + stream.mark_state_buffer_consumed( + conn, + payload_len as usize, + app_buf, + )?; + (frame, payload_len) + }, - Err(Error::Done) => return Err(Error::Done), + Err(Error::Done) => return Err(Error::Done), - Err(e) => { - conn.close( - true, - e.to_wire(), - b"Error handling frame.", - )?; + Err(e) => { + conn.close( + true, + e.to_wire(), + b"Error handling frame.", + )?; - return Err(e); - }, + return Err(e); + }, + } + } else { + stream.try_fill_buffer(conn)?; + + match stream.try_consume_frame() { + Ok(frame) => frame, + + Err(Error::Done) => return Err(Error::Done), + + Err(e) => { + conn.close( + true, + e.to_wire(), + b"Error handling frame.", + )?; + + return Err(e); + }, + } }; - match self.process_frame(conn, stream_id, frame, payload_len) - { + match self.process_frame( + conn, + stream_id, + frame, + payload_len, + app_buf, + ) { Ok(ev) => return Ok(ev), Err(Error::Done) => { @@ -2345,7 +2681,14 @@ impl Connection { // without needing to bubble up to the user as an // event. Check whether the frame has FIN'd by QUIC // to prevent trying to read again on a closed stream. - if conn.stream_finished(stream_id) { + let is_finished = + if conn.version == crate::PROTOCOL_VERSION_V3 { + let app_buf = app_buf.as_mut().unwrap(); + conn.stream_finished_v3(stream_id, app_buf) + } else { + conn.stream_finished(stream_id) + }; + if is_finished { break; } }, @@ -2368,11 +2711,26 @@ impl Connection { }, stream::State::QpackInstruction => { - let mut d = [0; 4096]; + if conn.version == crate::PROTOCOL_VERSION_V3 { + // Read data from the stream and discard immediately. + let app_buf = app_buf.as_mut().unwrap(); + loop { + // TODO check whether an error in stremv_rcv_v3 does + // not result + // into a memory leak (ideally, we want to collect the + // stream here, + // and its stream buffer within app_buf + let (_, read, _) = + conn.stream_recv_v3(stream_id, app_buf)?; + conn.stream_consumed(stream_id, read, app_buf)?; + } + } else { + let mut d = [0; 4096]; - // Read data from the stream and discard immediately. - loop { - conn.stream_recv(stream_id, &mut d)?; + // Read data from the stream and discard immediately. + loop { + conn.stream_recv(stream_id, &mut d)?; + } } }, @@ -2419,6 +2777,7 @@ impl Connection { fn process_frame( &mut self, conn: &mut super::Connection, stream_id: u64, frame: frame::Frame, payload_len: u64, + app_buf: &mut Option<&mut crate::AppRecvBufMap>, ) -> Result<(u64, Event)> { trace!( "{} rx frm {:?} stream={} payload_len={}", @@ -2539,12 +2898,16 @@ impl Connection { q.add_event_data_now(ev_data).ok(); }); - - let has_body = !conn.stream_finished(stream_id); + let is_finished = if conn.version == crate::PROTOCOL_VERSION_V3 { + let app_buf = app_buf.as_mut().unwrap(); + conn.stream_finished_v3(stream_id, app_buf) + } else { + conn.stream_finished(stream_id) + }; return Ok((stream_id, Event::Headers { list: headers, - has_body, + has_body: !is_finished, })); }, @@ -2706,6 +3069,18 @@ impl Connection { return Err(Error::FrameUnexpected); } + if prioritized_element_id == 0 && + conn.version == crate::PROTOCOL_VERSION_V3 + { + conn.close( + true, + Error::FrameUnexpected.to_wire(), + b"PRIORITY_UPDATE with stream_id 0 is invalid on v3", + )?; + + return Err(Error::FrameUnexpected); + } + if prioritized_element_id > conn.streams.max_streams_bidi() * 4 { conn.close( true, @@ -2727,10 +3102,16 @@ impl Connection { } // If the stream did not yet exist, create it and store. - let stream = - self.streams.entry(prioritized_element_id).or_insert_with( - || stream::Stream::new(prioritized_element_id, false), - ); + let stream = self + .streams + .entry(prioritized_element_id) + .or_insert_with(|| { + stream::Stream::new( + prioritized_element_id, + false, + conn.version, + ) + }); let had_priority_update = stream.has_last_priority_update(); stream.set_last_priority_update(Some(priority_field_value)); @@ -2893,12 +3274,36 @@ pub mod testing { self.advance().ok(); - while self.client.poll(&mut self.pipe.client).is_ok() { - // Do nothing. - } + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + while self + .client + .poll_v3( + &mut self.pipe.client, + &mut self.pipe.client_app_buffers, + ) + .is_ok() + { + // Do nothing. + } + + while self + .server + .poll_v3( + &mut self.pipe.server, + &mut self.pipe.server_app_buffers, + ) + .is_ok() + { + // Do nothing + } + } else { + while self.client.poll(&mut self.pipe.client).is_ok() { + // Do nothing. + } - while self.server.poll(&mut self.pipe.server).is_ok() { - // Do nothing. + while self.server.poll(&mut self.pipe.server).is_ok() { + // Do nothing. + } } Ok(()) @@ -2911,12 +3316,26 @@ pub mod testing { /// Polls the client for events. pub fn poll_client(&mut self) -> Result<(u64, Event)> { - self.client.poll(&mut self.pipe.client) + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + self.client.poll_v3( + &mut self.pipe.client, + &mut self.pipe.client_app_buffers, + ) + } else { + self.client.poll(&mut self.pipe.client) + } } /// Polls the server for events. pub fn poll_server(&mut self) -> Result<(u64, Event)> { - self.server.poll(&mut self.pipe.server) + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + self.server.poll_v3( + &mut self.pipe.server, + &mut self.pipe.server_app_buffers, + ) + } else { + self.server.poll(&mut self.pipe.server) + } } /// Sends a request from client with default headers. @@ -2978,6 +3397,31 @@ pub mod testing { Ok(bytes) } + /// Fetches DATA payload from the server + /// + /// On success, it returns a slice of the DATA payload + pub fn recv_body_v3_client( + &mut self, stream: u64, + ) -> Result<(&[u8], usize)> { + self.client.recv_body_v3( + &mut self.pipe.client, + stream, + &mut self.pipe.client_app_buffers, + ) + } + + /// Tells HTTP/3 module that the client data is consumed + pub fn body_consumed_client( + &mut self, stream: u64, consumed: usize, + ) -> Result<()> { + self.client.body_consumed( + &mut self.pipe.client, + stream, + consumed, + &mut self.pipe.client_app_buffers, + ) + } + /// Fetches DATA payload from the server. /// /// On success it returns the number of bytes received. @@ -3003,6 +3447,31 @@ pub mod testing { Ok(bytes) } + /// Fetches DATA payload from the client + /// + /// On success, it returns a slice of the DATA payload + pub fn recv_body_v3_server( + &mut self, stream: u64, + ) -> Result<(&[u8], usize)> { + self.server.recv_body_v3( + &mut self.pipe.server, + stream, + &mut self.pipe.server_app_buffers, + ) + } + + /// Tells HTTP/3 module that the server data is consumed + pub fn body_consumed_server( + &mut self, stream: u64, consumed: usize, + ) -> Result<()> { + self.server.body_consumed( + &mut self.pipe.server, + stream, + consumed, + &mut self.pipe.server_app_buffers, + ) + } + /// Fetches DATA payload from the client. /// /// On success it returns the number of bytes received. @@ -3210,7 +3679,7 @@ mod tests { }]; assert_eq!( - pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, Some(6)), Ok(1200) ); @@ -3221,9 +3690,22 @@ mod tests { assert_eq!(r.next(), Some(6)); assert_eq!(r.next(), None); - let mut b = [0; 15]; - assert_eq!(pipe.server.stream_recv(6, &mut b), Ok((5, true))); - assert_eq!(&b[..5], b"aaaaa"); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + let mut b = [0; 15]; + assert_eq!(pipe.server.stream_recv(6, &mut b), Ok((5, true))); + assert_eq!(&b[..5], b"aaaaa"); + } else { + let (b, read, fin) = pipe + .server + .stream_recv_v3(6, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((read, fin), (5, true)); + assert_eq!(&b[..5], b"aaaaa"); + assert!(pipe + .server + .stream_consumed(6, read, &mut pipe.server_app_buffers) + .is_ok()); + } } #[test] @@ -3231,10 +3713,15 @@ mod tests { fn request_no_body_response_no_body() { let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; let (stream, req) = s.send_request(true).unwrap(); - assert_eq!(stream, 0); + assert_eq!(stream, 0 + off_by); let ev_headers = Event::Headers { list: req, @@ -3261,9 +3748,14 @@ mod tests { fn request_no_body_response_one_chunk() { let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; let (stream, req) = s.send_request(true).unwrap(); - assert_eq!(stream, 0); + assert_eq!(stream, 0 + off_by); let ev_headers = Event::Headers { list: req, @@ -3288,7 +3780,15 @@ mod tests { assert_eq!(s.poll_client(), Ok((stream, ev_headers))); assert_eq!(s.poll_client(), Ok((stream, Event::Data))); - assert_eq!(s.recv_body_client(stream, &mut recv_buf), Ok(body.len())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (b, tot_exp_len) = s.recv_body_v3_client(stream).unwrap(); + assert_eq!(b.len(), body.len()); + assert_eq!(tot_exp_len, b.len()); + let len = b.len(); + assert_eq!(s.body_consumed_client(stream, len), Ok(())); + } else { + assert_eq!(s.recv_body_client(stream, &mut recv_buf), Ok(body.len())); + } assert_eq!(s.poll_client(), Ok((stream, Event::Finished))); assert_eq!(s.poll_client(), Err(Error::Done)); @@ -3332,13 +3832,77 @@ mod tests { assert_eq!(s.poll_client(), Err(Error::Done)); for _ in 0..total_data_frames { - assert_eq!(s.recv_body_client(stream, &mut recv_buf), Ok(body.len())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (b, tot_exp_len) = s.recv_body_v3_client(stream).unwrap(); + assert_eq!(b.len(), body.len()); + assert_eq!(tot_exp_len, body.len()); + assert!(s.body_consumed_client(stream, body.len()).is_ok()); + } else { + assert_eq!( + s.recv_body_client(stream, &mut recv_buf), + Ok(body.len()) + ); + } } assert_eq!(s.poll_client(), Ok((stream, Event::Finished))); assert_eq!(s.poll_client(), Err(Error::Done)); } + #[test] + /// Send a request with no body, get a response with multiple DATA frames + /// which we partially consume. + fn request_no_body_response_many_chunks_partially_consumed_v3_only() { + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let mut s = Session::new().unwrap(); + s.handshake().unwrap(); + + let (stream, req) = s.send_request(true).unwrap(); + + let ev_headers = Event::Headers { + list: req, + has_body: false, + }; + + assert_eq!(s.poll_server(), Ok((stream, ev_headers))); + assert_eq!(s.poll_server(), Ok((stream, Event::Finished))); + + let total_data_frames = 4; + + let resp = s.send_response(stream, false).unwrap(); + + for _ in 0..total_data_frames - 1 { + s.send_body_server(stream, false).unwrap(); + } + + let body = s.send_body_server(stream, true).unwrap(); + + let ev_headers = Event::Headers { + list: resp, + has_body: true, + }; + + assert_eq!(s.poll_client(), Ok((stream, ev_headers))); + assert_eq!(s.poll_client(), Ok((stream, Event::Data))); + assert_eq!(s.poll_client(), Err(Error::Done)); + // Consume in two parts. + for _ in 0..total_data_frames - 1 { + let (b, _) = s.recv_body_v3_client(stream).unwrap(); + assert_eq!(b.len(), body.len()); + assert!(s.body_consumed_client(stream, body.len() - 1).is_ok()); + assert!(s.body_consumed_client(stream, 1).is_ok()); + } + // Read and consume body.len()-1 + let (b, _) = s.recv_body_v3_client(stream).unwrap(); + assert_eq!(b.len(), body.len()); + assert!(s.body_consumed_client(stream, body.len() - 1).is_ok()); + // Read and consume the last byte + let (b, _) = s.recv_body_v3_client(stream).unwrap(); + assert_eq!(b.len(), 1); + assert!(s.body_consumed_client(stream, 1).is_ok()); + } + } + #[test] /// Send a request with one DATA frame, get a response with no body. fn request_one_chunk_response_no_body() { @@ -3359,7 +3923,14 @@ mod tests { assert_eq!(s.poll_server(), Ok((stream, ev_headers))); assert_eq!(s.poll_server(), Ok((stream, Event::Data))); - assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (b, tot_exp_len) = s.recv_body_v3_server(stream).unwrap(); + assert_eq!(b.len(), body.len()); + assert_eq!(tot_exp_len, body.len()); + assert!(s.body_consumed_server(stream, body.len()).is_ok()); + } else { + assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len())); + } assert_eq!(s.poll_server(), Ok((stream, Event::Finished))); @@ -3402,7 +3973,17 @@ mod tests { assert_eq!(s.poll_server(), Err(Error::Done)); for _ in 0..total_data_frames { - assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (b, tot_exp_len) = s.recv_body_v3_server(stream).unwrap(); + assert_eq!(b.len(), body.len()); + assert_eq!(tot_exp_len, body.len()); + assert!(s.body_consumed_server(stream, body.len()).is_ok()); + } else { + assert_eq!( + s.recv_body_server(stream, &mut recv_buf), + Ok(body.len()) + ); + } } assert_eq!(s.poll_server(), Ok((stream, Event::Finished))); @@ -3426,17 +4007,22 @@ mod tests { s.handshake().unwrap(); let mut reqs = Vec::new(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; let (stream1, req1) = s.send_request(false).unwrap(); - assert_eq!(stream1, 0); + assert_eq!(stream1, 0 + off_by); reqs.push(req1); let (stream2, req2) = s.send_request(false).unwrap(); - assert_eq!(stream2, 4); + assert_eq!(stream2, 4 + off_by); reqs.push(req2); let (stream3, req3) = s.send_request(false).unwrap(); - assert_eq!(stream3, 8); + assert_eq!(stream3, 8 + off_by); reqs.push(req3); let body = s.send_body_client(stream1, false).unwrap(); @@ -3472,23 +4058,53 @@ mod tests { }; assert_eq!(ev, ev_headers); - assert_eq!(s.poll_server(), Ok((0, Event::Data))); - assert_eq!(s.recv_body_server(0, &mut recv_buf), Ok(body.len())); + assert_eq!(s.poll_server(), Ok((0 + off_by, Event::Data))); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!(s.recv_body_v3_server(4).unwrap().0.len(), body.len()); + assert!(s.body_consumed_server(4, body.len()).is_ok()); + } else { + assert_eq!(s.recv_body_server(0, &mut recv_buf), Ok(body.len())); + } assert_eq!(s.poll_client(), Err(Error::Done)); - assert_eq!(s.recv_body_server(0, &mut recv_buf), Ok(body.len())); - assert_eq!(s.poll_server(), Ok((0, Event::Finished))); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!(s.recv_body_v3_server(4).unwrap().0.len(), body.len()); + assert!(s.body_consumed_server(4, body.len()).is_ok()); + } else { + assert_eq!(s.recv_body_server(0, &mut recv_buf), Ok(body.len())); + } + assert_eq!(s.poll_server(), Ok((0 + off_by, Event::Finished))); + assert_eq!(s.poll_server(), Ok((4 + off_by, Event::Data))); - assert_eq!(s.poll_server(), Ok((4, Event::Data))); - assert_eq!(s.recv_body_server(4, &mut recv_buf), Ok(body.len())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!(s.recv_body_v3_server(8).unwrap().0.len(), body.len()); + assert!(s.body_consumed_server(8, body.len()).is_ok()); + } else { + assert_eq!(s.recv_body_server(4, &mut recv_buf), Ok(body.len())); + } assert_eq!(s.poll_client(), Err(Error::Done)); - assert_eq!(s.recv_body_server(4, &mut recv_buf), Ok(body.len())); - assert_eq!(s.poll_server(), Ok((4, Event::Finished))); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!(s.recv_body_v3_server(8).unwrap().0.len(), body.len()); + assert!(s.body_consumed_server(8, body.len()).is_ok()); + } else { + assert_eq!(s.recv_body_server(4, &mut recv_buf), Ok(body.len())); + } + assert_eq!(s.poll_server(), Ok((4 + off_by, Event::Finished))); + assert_eq!(s.poll_server(), Ok((8 + off_by, Event::Data))); - assert_eq!(s.poll_server(), Ok((8, Event::Data))); - assert_eq!(s.recv_body_server(8, &mut recv_buf), Ok(body.len())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!(s.recv_body_v3_server(12).unwrap().0.len(), body.len()); + assert!(s.body_consumed_server(12, body.len()).is_ok()); + } else { + assert_eq!(s.recv_body_server(8, &mut recv_buf), Ok(body.len())); + } assert_eq!(s.poll_client(), Err(Error::Done)); - assert_eq!(s.recv_body_server(8, &mut recv_buf), Ok(body.len())); - assert_eq!(s.poll_server(), Ok((8, Event::Finished))); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!(s.recv_body_v3_server(12).unwrap().0.len(), body.len()); + assert!(s.body_consumed_server(12, body.len()).is_ok()); + } else { + assert_eq!(s.recv_body_server(8, &mut recv_buf), Ok(body.len())); + } + assert_eq!(s.poll_server(), Ok((8 + off_by, Event::Finished))); assert_eq!(s.poll_server(), Err(Error::Done)); @@ -3506,7 +4122,7 @@ mod tests { for _ in 0..resps.len() { let (stream, ev) = s.poll_client().unwrap(); let ev_headers = Event::Headers { - list: resps[(stream / 4) as usize].clone(), + list: resps[((stream - off_by) / 4) as usize].clone(), has_body: false, }; assert_eq!(ev, ev_headers); @@ -3547,7 +4163,15 @@ mod tests { assert_eq!(s.poll_client(), Ok((stream, ev_headers))); assert_eq!(s.poll_client(), Ok((stream, Event::Data))); - assert_eq!(s.recv_body_client(stream, &mut recv_buf), Ok(body.len())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + s.recv_body_v3_client(stream).unwrap().0.len(), + body.len() + ); + assert!(s.body_consumed_client(stream, body.len()).is_ok()); + } else { + assert_eq!(s.recv_body_client(stream, &mut recv_buf), Ok(body.len())); + } assert_eq!(s.pipe.server.stream_send(stream, &[], true), Ok(0)); s.advance().ok(); @@ -3563,9 +4187,15 @@ mod tests { let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; + let (stream, req) = s.send_request(true).unwrap(); - assert_eq!(stream, 0); + assert_eq!(stream, 0 + off_by); let ev_headers = Event::Headers { list: req, @@ -3590,12 +4220,18 @@ mod tests { let mut b = octets::OctetsMut::with_slice(&mut d); let frame_type = b.put_varint(148_764_065_110_560_899).unwrap(); - s.pipe.server.stream_send(0, frame_type, false).unwrap(); - + s.pipe + .server + .stream_send(0 + off_by, frame_type, false) + .unwrap(); + let frame_len = b.put_varint(10).unwrap(); - s.pipe.server.stream_send(0, frame_len, false).unwrap(); + s.pipe + .server + .stream_send(0 + off_by, frame_len, false) + .unwrap(); - s.pipe.server.stream_send(0, &d, true).unwrap(); + s.pipe.server.stream_send(0 + off_by, &d, true).unwrap(); s.advance().ok(); @@ -3609,9 +4245,14 @@ mod tests { fn body_response_before_headers() { let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; let (stream, req) = s.send_request(true).unwrap(); - assert_eq!(stream, 0); + assert_eq!(stream, 0 + off_by); let ev_headers = Event::Headers { list: req, @@ -3637,7 +4278,16 @@ mod tests { let mut s = Session::new().unwrap(); s.handshake().unwrap(); - assert_eq!(s.send_body_client(0, true), Err(Error::FrameUnexpected)); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; + + assert_eq!( + s.send_body_client(0 + off_by, true), + Err(Error::FrameUnexpected) + ); assert_eq!( s.send_body_client(s.client.control_stream_id.unwrap(), true), @@ -3688,8 +4338,16 @@ mod tests { fn send_body_invalid_server_stream() { let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; - assert_eq!(s.send_body_server(0, true), Err(Error::FrameUnexpected)); + assert_eq!( + s.send_body_server(0 + off_by, true), + Err(Error::FrameUnexpected) + ); assert_eq!( s.send_body_server(s.server.control_stream_id.unwrap(), true), @@ -3904,13 +4562,18 @@ mod tests { fn goaway_from_client_good() { let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; s.client.send_goaway(&mut s.pipe.client, 100).unwrap(); s.advance().ok(); // TODO: server push - assert_eq!(s.poll_server(), Ok((0, Event::GoAway))); + assert_eq!(s.poll_server(), Ok((0 + off_by, Event::GoAway))); } #[test] @@ -3963,22 +4626,27 @@ mod tests { fn goaway_from_server_increase_id() { let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; s.send_frame_server( - frame::Frame::GoAway { id: 0 }, + frame::Frame::GoAway { id: 0 + off_by }, s.server.control_stream_id.unwrap(), false, ) .unwrap(); s.send_frame_server( - frame::Frame::GoAway { id: 4 }, + frame::Frame::GoAway { id: 4 + off_by }, s.server.control_stream_id.unwrap(), false, ) .unwrap(); - assert_eq!(s.poll_client(), Ok((0, Event::GoAway))); + assert_eq!(s.poll_client(), Ok((0 + off_by, Event::GoAway))); assert_eq!(s.poll_client(), Err(Error::IdError)); } @@ -4074,16 +4742,25 @@ mod tests { fn priority_update_request() { let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; s.client - .send_priority_update_for_request(&mut s.pipe.client, 0, &Priority { - urgency: 3, - incremental: false, - }) + .send_priority_update_for_request( + &mut s.pipe.client, + 0 + off_by, + &Priority { + urgency: 3, + incremental: false, + }, + ) .unwrap(); s.advance().ok(); - assert_eq!(s.poll_server(), Ok((0, Event::PriorityUpdate))); + assert_eq!(s.poll_server(), Ok((0 + off_by, Event::PriorityUpdate))); assert_eq!(s.poll_server(), Err(Error::Done)); } @@ -4092,23 +4769,36 @@ mod tests { fn priority_update_single_stream_rearm() { let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; s.client - .send_priority_update_for_request(&mut s.pipe.client, 0, &Priority { - urgency: 3, - incremental: false, - }) + .send_priority_update_for_request( + &mut s.pipe.client, + 0 + off_by, + &Priority { + urgency: 3, + incremental: false, + }, + ) .unwrap(); s.advance().ok(); - assert_eq!(s.poll_server(), Ok((0, Event::PriorityUpdate))); + assert_eq!(s.poll_server(), Ok((0 + off_by, Event::PriorityUpdate))); assert_eq!(s.poll_server(), Err(Error::Done)); s.client - .send_priority_update_for_request(&mut s.pipe.client, 0, &Priority { - urgency: 5, - incremental: false, - }) + .send_priority_update_for_request( + &mut s.pipe.client, + 0 + off_by, + &Priority { + urgency: 5, + incremental: false, + }, + ) .unwrap(); s.advance().ok(); @@ -4116,22 +4806,38 @@ mod tests { // There is only one PRIORITY_UPDATE frame to read. Once read, the event // will rearm ready for more. - assert_eq!(s.server.take_last_priority_update(0), Ok(b"u=5".to_vec())); - assert_eq!(s.server.take_last_priority_update(0), Err(Error::Done)); + assert_eq!( + s.server.take_last_priority_update(0 + off_by), + Ok(b"u=5".to_vec()) + ); + assert_eq!( + s.server.take_last_priority_update(0 + off_by), + Err(Error::Done) + ); s.client - .send_priority_update_for_request(&mut s.pipe.client, 0, &Priority { - urgency: 7, - incremental: false, - }) + .send_priority_update_for_request( + &mut s.pipe.client, + 0 + off_by, + &Priority { + urgency: 7, + incremental: false, + }, + ) .unwrap(); s.advance().ok(); - assert_eq!(s.poll_server(), Ok((0, Event::PriorityUpdate))); + assert_eq!(s.poll_server(), Ok((0 + off_by, Event::PriorityUpdate))); assert_eq!(s.poll_server(), Err(Error::Done)); - assert_eq!(s.server.take_last_priority_update(0), Ok(b"u=7".to_vec())); - assert_eq!(s.server.take_last_priority_update(0), Err(Error::Done)); + assert_eq!( + s.server.take_last_priority_update(0 + off_by), + Ok(b"u=7".to_vec()) + ); + assert_eq!( + s.server.take_last_priority_update(0 + off_by), + Err(Error::Done) + ); } #[test] @@ -4140,44 +4846,73 @@ mod tests { fn priority_update_request_multiple_stream_arm_multiple_flights() { let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; s.client - .send_priority_update_for_request(&mut s.pipe.client, 0, &Priority { - urgency: 3, - incremental: false, - }) + .send_priority_update_for_request( + &mut s.pipe.client, + 0 + off_by, + &Priority { + urgency: 3, + incremental: false, + }, + ) .unwrap(); s.advance().ok(); - assert_eq!(s.poll_server(), Ok((0, Event::PriorityUpdate))); + assert_eq!(s.poll_server(), Ok((0 + off_by, Event::PriorityUpdate))); assert_eq!(s.poll_server(), Err(Error::Done)); s.client - .send_priority_update_for_request(&mut s.pipe.client, 4, &Priority { - urgency: 1, - incremental: false, - }) + .send_priority_update_for_request( + &mut s.pipe.client, + 4 + off_by, + &Priority { + urgency: 1, + incremental: false, + }, + ) .unwrap(); s.advance().ok(); - assert_eq!(s.poll_server(), Ok((4, Event::PriorityUpdate))); + assert_eq!(s.poll_server(), Ok((4 + off_by, Event::PriorityUpdate))); assert_eq!(s.poll_server(), Err(Error::Done)); s.client - .send_priority_update_for_request(&mut s.pipe.client, 8, &Priority { - urgency: 2, - incremental: false, - }) + .send_priority_update_for_request( + &mut s.pipe.client, + 8 + off_by, + &Priority { + urgency: 2, + incremental: false, + }, + ) .unwrap(); s.advance().ok(); - assert_eq!(s.poll_server(), Ok((8, Event::PriorityUpdate))); + assert_eq!(s.poll_server(), Ok((8 + off_by, Event::PriorityUpdate))); assert_eq!(s.poll_server(), Err(Error::Done)); - assert_eq!(s.server.take_last_priority_update(0), Ok(b"u=3".to_vec())); - assert_eq!(s.server.take_last_priority_update(4), Ok(b"u=1".to_vec())); - assert_eq!(s.server.take_last_priority_update(8), Ok(b"u=2".to_vec())); - assert_eq!(s.server.take_last_priority_update(0), Err(Error::Done)); + assert_eq!( + s.server.take_last_priority_update(0 + off_by), + Ok(b"u=3".to_vec()) + ); + assert_eq!( + s.server.take_last_priority_update(4 + off_by), + Ok(b"u=1".to_vec()) + ); + assert_eq!( + s.server.take_last_priority_update(8 + off_by), + Ok(b"u=2".to_vec()) + ); + assert_eq!( + s.server.take_last_priority_update(0 + off_by), + Err(Error::Done) + ); } #[test] @@ -4186,23 +4921,28 @@ mod tests { fn priority_update_request_multiple_stream_arm_single_flight() { let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; let mut d = [42; 65535]; let mut b = octets::OctetsMut::with_slice(&mut d); let p1 = frame::Frame::PriorityUpdateRequest { - prioritized_element_id: 0, + prioritized_element_id: 0 + off_by, priority_field_value: b"u=3".to_vec(), }; let p2 = frame::Frame::PriorityUpdateRequest { - prioritized_element_id: 4, + prioritized_element_id: 4 + off_by, priority_field_value: b"u=3".to_vec(), }; let p3 = frame::Frame::PriorityUpdateRequest { - prioritized_element_id: 8, + prioritized_element_id: 8 + off_by, priority_field_value: b"u=3".to_vec(), }; @@ -4218,16 +4958,28 @@ mod tests { s.advance().ok(); - assert_eq!(s.poll_server(), Ok((0, Event::PriorityUpdate))); - assert_eq!(s.poll_server(), Ok((4, Event::PriorityUpdate))); - assert_eq!(s.poll_server(), Ok((8, Event::PriorityUpdate))); + assert_eq!(s.poll_server(), Ok((0 + off_by, Event::PriorityUpdate))); + assert_eq!(s.poll_server(), Ok((4 + off_by, Event::PriorityUpdate))); + assert_eq!(s.poll_server(), Ok((8 + off_by, Event::PriorityUpdate))); assert_eq!(s.poll_server(), Err(Error::Done)); - assert_eq!(s.server.take_last_priority_update(0), Ok(b"u=3".to_vec())); - assert_eq!(s.server.take_last_priority_update(4), Ok(b"u=3".to_vec())); - assert_eq!(s.server.take_last_priority_update(8), Ok(b"u=3".to_vec())); + assert_eq!( + s.server.take_last_priority_update(0 + off_by), + Ok(b"u=3".to_vec()) + ); + assert_eq!( + s.server.take_last_priority_update(4 + off_by), + Ok(b"u=3".to_vec()) + ); + assert_eq!( + s.server.take_last_priority_update(8 + off_by), + Ok(b"u=3".to_vec()) + ); - assert_eq!(s.server.take_last_priority_update(0), Err(Error::Done)); + assert_eq!( + s.server.take_last_priority_update(0 + off_by), + Err(Error::Done) + ); } #[test] @@ -4236,12 +4988,21 @@ mod tests { fn priority_update_request_collected_completed() { let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; s.client - .send_priority_update_for_request(&mut s.pipe.client, 0, &Priority { - urgency: 3, - incremental: false, - }) + .send_priority_update_for_request( + &mut s.pipe.client, + 0 + off_by, + &Priority { + urgency: 3, + incremental: false, + }, + ) .unwrap(); s.advance().ok(); @@ -4252,13 +5013,19 @@ mod tests { }; // Priority event is generated before request headers. - assert_eq!(s.poll_server(), Ok((0, Event::PriorityUpdate))); + assert_eq!(s.poll_server(), Ok((0 + off_by, Event::PriorityUpdate))); assert_eq!(s.poll_server(), Ok((stream, ev_headers))); assert_eq!(s.poll_server(), Ok((stream, Event::Finished))); assert_eq!(s.poll_server(), Err(Error::Done)); - assert_eq!(s.server.take_last_priority_update(0), Ok(b"u=3".to_vec())); - assert_eq!(s.server.take_last_priority_update(0), Err(Error::Done)); + assert_eq!( + s.server.take_last_priority_update(0 + off_by), + Ok(b"u=3".to_vec()) + ); + assert_eq!( + s.server.take_last_priority_update(0 + off_by), + Err(Error::Done) + ); let resp = s.send_response(stream, true).unwrap(); @@ -4273,10 +5040,14 @@ mod tests { // Now send a PRIORITY_UPDATE for the completed request stream. s.client - .send_priority_update_for_request(&mut s.pipe.client, 0, &Priority { - urgency: 3, - incremental: false, - }) + .send_priority_update_for_request( + &mut s.pipe.client, + 0 + off_by, + &Priority { + urgency: 3, + incremental: false, + }, + ) .unwrap(); s.advance().ok(); @@ -4290,12 +5061,21 @@ mod tests { fn priority_update_request_collected_stopped() { let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; s.client - .send_priority_update_for_request(&mut s.pipe.client, 0, &Priority { - urgency: 3, - incremental: false, - }) + .send_priority_update_for_request( + &mut s.pipe.client, + 0 + off_by, + &Priority { + urgency: 3, + incremental: false, + }, + ) .unwrap(); s.advance().ok(); @@ -4306,12 +5086,18 @@ mod tests { }; // Priority event is generated before request headers. - assert_eq!(s.poll_server(), Ok((0, Event::PriorityUpdate))); + assert_eq!(s.poll_server(), Ok((0 + off_by, Event::PriorityUpdate))); assert_eq!(s.poll_server(), Ok((stream, ev_headers))); assert_eq!(s.poll_server(), Err(Error::Done)); - assert_eq!(s.server.take_last_priority_update(0), Ok(b"u=3".to_vec())); - assert_eq!(s.server.take_last_priority_update(0), Err(Error::Done)); + assert_eq!( + s.server.take_last_priority_update(0 + off_by), + Ok(b"u=3".to_vec()) + ); + assert_eq!( + s.server.take_last_priority_update(0 + off_by), + Err(Error::Done) + ); s.pipe .client @@ -4324,15 +5110,19 @@ mod tests { s.advance().ok(); - assert_eq!(s.poll_server(), Ok((0, Event::Reset(0x100)))); + assert_eq!(s.poll_server(), Ok((0 + off_by, Event::Reset(0x100)))); assert_eq!(s.poll_server(), Err(Error::Done)); // Now send a PRIORITY_UPDATE for the closed request stream. s.client - .send_priority_update_for_request(&mut s.pipe.client, 0, &Priority { - urgency: 3, - incremental: false, - }) + .send_priority_update_for_request( + &mut s.pipe.client, + 0 + off_by, + &Priority { + urgency: 3, + incremental: false, + }, + ) .unwrap(); s.advance().ok(); @@ -4379,6 +5169,34 @@ mod tests { assert_eq!(s.poll_server(), Err(Error::FrameUnexpected)); } + #[test] + /// Send a PRIORITY_UPDATE for request stream from client buf for + /// a stream ID 0, which is incorrect stream type in v3 + fn priority_update_resquest_stream_0_on_v3() { + // Rust does not seem to support managing tests based on const value known + // at compile time. I suppose the reason behind is that macros + // from cargo test are managed before the const can be evaluated. + // So I have no better idea than the following ugliness to test a + // behavior only existing if we have crate::PROTOCOL_VERSION_V3. + // XXX Todo if a better idea comes. + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let mut s = Session::new().unwrap(); + s.handshake().unwrap(); + + s.send_frame_client( + frame::Frame::PriorityUpdateRequest { + prioritized_element_id: 0, + priority_field_value: b"u=3".to_vec(), + }, + s.client.control_stream_id.unwrap(), + false, + ) + .unwrap(); + + assert_eq!(s.poll_server(), Err(Error::FrameUnexpected)); + } + } + #[test] /// Send a PRIORITY_UPDATE for push stream from the client but for an /// incorrect stream type. @@ -4423,10 +5241,15 @@ mod tests { fn priority_update_push_from_server() { let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; s.send_frame_server( frame::Frame::PriorityUpdatePush { - prioritized_element_id: 0, + prioritized_element_id: 0 + off_by, priority_field_value: b"u=3".to_vec(), }, s.server.control_stream_id.unwrap(), @@ -4490,7 +5313,7 @@ mod tests { .unwrap(); loop { - match s.server.poll(&mut s.pipe.server) { + match s.poll_server() { Ok(_) => (), Err(Error::Done) => { @@ -4526,7 +5349,7 @@ mod tests { s.advance().ok(); loop { - match s.server.poll(&mut s.pipe.server) { + match s.poll_server() { Ok(_) => (), Err(Error::Done) => { @@ -4564,7 +5387,7 @@ mod tests { s.advance().ok(); loop { - match s.server.poll(&mut s.pipe.server) { + match s.poll_server() { Ok(_) => (), Err(Error::Done) => { @@ -4583,6 +5406,11 @@ mod tests { fn max_state_buf_size() { let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; let req = vec![ Header::new(b":method", b"GET"), @@ -4594,7 +5422,7 @@ mod tests { assert_eq!( s.client.send_request(&mut s.pipe.client, &req, false), - Ok(0) + Ok(0 + off_by) ); s.advance().ok(); @@ -4604,23 +5432,29 @@ mod tests { has_body: true, }; - assert_eq!(s.server.poll(&mut s.pipe.server), Ok((0, ev_headers))); + assert_eq!(s.poll_server(), Ok((0 + off_by, ev_headers))); // DATA frames don't consume the state buffer, so can be of any size. let mut d = [42; 128]; let mut b = octets::OctetsMut::with_slice(&mut d); let frame_type = b.put_varint(frame::DATA_FRAME_TYPE_ID).unwrap(); - s.pipe.client.stream_send(0, frame_type, false).unwrap(); + s.pipe + .client + .stream_send(0 + off_by, frame_type, false) + .unwrap(); let frame_len = b.put_varint(1 << 24).unwrap(); - s.pipe.client.stream_send(0, frame_len, false).unwrap(); + s.pipe + .client + .stream_send(0 + off_by, frame_len, false) + .unwrap(); - s.pipe.client.stream_send(0, &d, false).unwrap(); + s.pipe.client.stream_send(0 + off_by, &d, false).unwrap(); s.advance().ok(); - assert_eq!(s.server.poll(&mut s.pipe.server), Ok((0, Event::Data))); + assert_eq!(s.poll_server(), Ok((0 + off_by, Event::Data))); // GREASE frames consume the state buffer, so need to be limited. let mut s = Session::new().unwrap(); @@ -4630,16 +5464,22 @@ mod tests { let mut b = octets::OctetsMut::with_slice(&mut d); let frame_type = b.put_varint(148_764_065_110_560_899).unwrap(); - s.pipe.client.stream_send(0, frame_type, false).unwrap(); + s.pipe + .client + .stream_send(0 + off_by, frame_type, false) + .unwrap(); let frame_len = b.put_varint(1 << 24).unwrap(); - s.pipe.client.stream_send(0, frame_len, false).unwrap(); + s.pipe + .client + .stream_send(0 + off_by, frame_len, false) + .unwrap(); - s.pipe.client.stream_send(0, &d, false).unwrap(); + s.pipe.client.stream_send(0 + off_by, &d, false).unwrap(); s.advance().ok(); - assert_eq!(s.server.poll(&mut s.pipe.server), Err(Error::ExcessiveLoad)); + assert_eq!(s.poll_server(), Err(Error::ExcessiveLoad)); } #[test] @@ -4684,17 +5524,33 @@ mod tests { assert_eq!(s.poll_server(), Err(Error::Done)); for _ in 0..total_data_frames { + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + s.recv_body_v3_server(stream).unwrap().0.len(), + bytes.len() + ); + assert!(s.body_consumed_server(stream, bytes.len()).is_ok()); + } else { + assert_eq!( + s.recv_body_server(stream, &mut recv_buf), + Ok(bytes.len()) + ); + } + } + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + s.recv_body_v3_server(stream).unwrap().0.len(), + bytes.len() - 2 + ); + assert!(s.body_consumed_server(stream, bytes.len() - 2).is_ok()); + } else { assert_eq!( s.recv_body_server(stream, &mut recv_buf), - Ok(bytes.len()) + Ok(bytes.len() - 2) ); } - assert_eq!( - s.recv_body_server(stream, &mut recv_buf), - Ok(bytes.len() - 2) - ); - // Fin flag from last send_body() call was not sent as the buffer was // only partially written. assert_eq!(s.poll_server(), Err(Error::Done)); @@ -4725,6 +5581,11 @@ mod tests { let mut s = Session::with_configs(&mut config, &h3_config).unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; let req = vec![ Header::new(b":method", b"GET"), @@ -4741,7 +5602,7 @@ mod tests { s.advance().ok(); - assert_eq!(stream, 0); + assert_eq!(stream, 0 + off_by); assert_eq!(s.poll_server(), Err(Error::ExcessiveLoad)); @@ -4756,6 +5617,11 @@ mod tests { fn transport_error() { let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; let req = vec![ Header::new(b":method", b"GET"), @@ -4769,16 +5635,25 @@ mod tests { // Session::send_request() method because it also calls advance(), // otherwise the server would send a MAX_STREAMS frame and the client // wouldn't hit the streams limit. - assert_eq!(s.client.send_request(&mut s.pipe.client, &req, true), Ok(0)); - assert_eq!(s.client.send_request(&mut s.pipe.client, &req, true), Ok(4)); - assert_eq!(s.client.send_request(&mut s.pipe.client, &req, true), Ok(8)); assert_eq!( s.client.send_request(&mut s.pipe.client, &req, true), - Ok(12) + Ok(0 + off_by) + ); + assert_eq!( + s.client.send_request(&mut s.pipe.client, &req, true), + Ok(4 + off_by) + ); + assert_eq!( + s.client.send_request(&mut s.pipe.client, &req, true), + Ok(8 + off_by) + ); + assert_eq!( + s.client.send_request(&mut s.pipe.client, &req, true), + Ok(12 + off_by) ); assert_eq!( s.client.send_request(&mut s.pipe.client, &req, true), - Ok(16) + Ok(16 + off_by) ); assert_eq!( @@ -4792,24 +5667,35 @@ mod tests { fn data_before_headers() { let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; let mut d = [42; 128]; let mut b = octets::OctetsMut::with_slice(&mut d); let frame_type = b.put_varint(frame::DATA_FRAME_TYPE_ID).unwrap(); - s.pipe.client.stream_send(0, frame_type, false).unwrap(); + s.pipe + .client + .stream_send(0 + off_by, frame_type, false) + .unwrap(); let frame_len = b.put_varint(5).unwrap(); - s.pipe.client.stream_send(0, frame_len, false).unwrap(); + s.pipe + .client + .stream_send(0 + off_by, frame_len, false) + .unwrap(); - s.pipe.client.stream_send(0, b"hello", false).unwrap(); + s.pipe + .client + .stream_send(0 + off_by, b"hello", false) + .unwrap(); s.advance().ok(); - assert_eq!( - s.server.poll(&mut s.pipe.server), - Err(Error::FrameUnexpected) - ); + assert_eq!(s.poll_server(), Err(Error::FrameUnexpected)); } #[test] @@ -4817,24 +5703,35 @@ mod tests { fn poll_after_error() { let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; let mut d = [42; 128]; let mut b = octets::OctetsMut::with_slice(&mut d); let frame_type = b.put_varint(148_764_065_110_560_899).unwrap(); - s.pipe.client.stream_send(0, frame_type, false).unwrap(); + s.pipe + .client + .stream_send(0 + off_by, frame_type, false) + .unwrap(); let frame_len = b.put_varint(1 << 24).unwrap(); - s.pipe.client.stream_send(0, frame_len, false).unwrap(); + s.pipe + .client + .stream_send(0 + off_by, frame_len, false) + .unwrap(); - s.pipe.client.stream_send(0, &d, false).unwrap(); + s.pipe.client.stream_send(0 + off_by, &d, false).unwrap(); s.advance().ok(); - assert_eq!(s.server.poll(&mut s.pipe.server), Err(Error::ExcessiveLoad)); + assert_eq!(s.poll_server(), Err(Error::ExcessiveLoad)); // Try to call poll() again after an error occurred. - assert_eq!(s.server.poll(&mut s.pipe.server), Err(Error::Done)); + assert_eq!(s.poll_server(), Err(Error::Done)); } #[test] @@ -4861,6 +5758,11 @@ mod tests { let mut s = Session::with_configs(&mut config, &h3_config).unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; let req = vec![ Header::new(b":method", b"GET"), @@ -4869,7 +5771,10 @@ mod tests { Header::new(b":path", b"/test"), ]; - assert_eq!(s.client.send_request(&mut s.pipe.client, &req, true), Ok(0)); + assert_eq!( + s.client.send_request(&mut s.pipe.client, &req, true), + Ok(0 + off_by) + ); assert_eq!( s.client.send_request(&mut s.pipe.client, &req, true), @@ -4886,8 +5791,11 @@ mod tests { // Once the server gives flow control credits back, we can send the // request. - assert_eq!(s.pipe.client.stream_writable_next(), Some(4)); - assert_eq!(s.client.send_request(&mut s.pipe.client, &req, true), Ok(4)); + assert_eq!(s.pipe.client.stream_writable_next(), Some(4 + off_by)); + assert_eq!( + s.client.send_request(&mut s.pipe.client, &req, true), + Ok(4 + off_by) + ); } #[test] @@ -4914,6 +5822,11 @@ mod tests { let mut s = Session::with_configs(&mut config, &h3_config).unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; // After the HTTP handshake, some bytes of connection flow control have // been consumed. Fill the connection with more grease data on the control @@ -4945,7 +5858,10 @@ mod tests { // Now we can send the request. assert_eq!(s.pipe.client.stream_writable_next(), Some(2)); assert_eq!(s.pipe.client.stream_writable_next(), Some(6)); - assert_eq!(s.client.send_request(&mut s.pipe.client, &req, true), Ok(0)); + assert_eq!( + s.client.send_request(&mut s.pipe.client, &req, true), + Ok(0 + off_by) + ); } #[test] @@ -4975,6 +5891,11 @@ mod tests { let mut s = Session::with_configs(&mut config, &h3_config).unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; let (stream, req) = s.send_request(true).unwrap(); @@ -5014,14 +5935,19 @@ mod tests { let mut buf = [0; 65535]; let (len, _) = s.pipe.server.send(&mut buf).unwrap(); - let frames = decode_pkt(&mut s.pipe.client, &mut buf[..len]).unwrap(); + let frames = decode_pkt( + &mut s.pipe.client, + &mut buf[..len], + &mut s.pipe.client_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); assert_eq!( iter.next(), Some(&crate::frame::Frame::StreamDataBlocked { - stream_id: 0, + stream_id: 0 + off_by, limit: 80, }) ); @@ -5045,19 +5971,19 @@ mod tests { // Now update the client's max offset manually. let frames = [crate::frame::Frame::MaxStreamData { - stream_id: 0, + stream_id: 0 + off_by, max: 100, }]; let pkt_type = crate::packet::Type::Short; if s.pipe.client.version == crate::PROTOCOL_VERSION_V3 { assert_eq!( - s.pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + s.pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), Ok(48), ); } else { assert_eq!( - s.pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + s.pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), Ok(39), ); } @@ -5079,14 +6005,19 @@ mod tests { let (len, _) = s.pipe.server.send(&mut buf).unwrap(); - let frames = decode_pkt(&mut s.pipe.client, &mut buf[..len]).unwrap(); + let frames = decode_pkt( + &mut s.pipe.client, + &mut buf[..len], + &mut s.pipe.client_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); assert_eq!( iter.next(), Some(&crate::frame::Frame::StreamDataBlocked { - stream_id: 0, + stream_id: 0 + off_by, limit: 100, }) ); @@ -5116,6 +6047,11 @@ mod tests { let mut s = Session::with_configs(&mut config, &h3_config).unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; let (stream, req) = s.send_request(true).unwrap(); @@ -5153,7 +6089,12 @@ mod tests { let mut recv_buf = [42; 80000]; assert!(s.poll_client().is_ok()); assert_eq!(s.poll_client(), Ok((stream, Event::Data))); - assert_eq!(s.recv_body_client(stream, &mut recv_buf), Ok(11995)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!(s.recv_body_v3_client(stream).unwrap().0.len(), 11995); + assert!(s.body_consumed_client(stream, 11995).is_ok()); + } else { + assert_eq!(s.recv_body_client(stream, &mut recv_buf), Ok(11995)); + } s.advance().ok(); @@ -5161,7 +6102,7 @@ mod tests { assert!(s.pipe.server.tx_cap < send_buf.len() - sent); // Once the server cwnd opens up, we can send more body. - assert_eq!(s.pipe.server.stream_writable_next(), Some(0)); + assert_eq!(s.pipe.server.stream_writable_next(), Some(0 + off_by)); } #[test] @@ -5188,6 +6129,11 @@ mod tests { let mut s = Session::with_configs(&mut config, &h3_config).unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; let (stream, req) = s.send_request(true).unwrap(); @@ -5234,12 +6180,17 @@ mod tests { let mut recv_buf = [42; 80000]; assert!(s.poll_client().is_ok()); assert_eq!(s.poll_client(), Ok((stream, Event::Data))); - assert_eq!(s.recv_body_client(stream, &mut recv_buf), Ok(11994)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!(s.recv_body_v3_client(stream).unwrap().0.len(), 11994); + assert!(s.body_consumed_client(stream, 11994).is_ok()); + } else { + assert_eq!(s.recv_body_client(stream, &mut recv_buf), Ok(11994)); + } s.advance().ok(); // Once the server cwnd opens up, we can send more body. - assert_eq!(s.pipe.server.stream_writable_next(), Some(0)); + assert_eq!(s.pipe.server.stream_writable_next(), Some(0 + off_by)); } #[test] @@ -5247,14 +6198,24 @@ mod tests { fn zero_length_data() { let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; let (stream, req) = s.send_request(false).unwrap(); assert_eq!( - s.client.send_body(&mut s.pipe.client, 0, b"", false), + s.client + .send_body(&mut s.pipe.client, 0 + off_by, b"", false), Err(Error::Done) ); - assert_eq!(s.client.send_body(&mut s.pipe.client, 0, b"", true), Ok(0)); + assert_eq!( + s.client + .send_body(&mut s.pipe.client, 0 + off_by, b"", true), + Ok(0) + ); s.advance().ok(); @@ -5268,7 +6229,14 @@ mod tests { assert_eq!(s.poll_server(), Ok((stream, ev_headers))); assert_eq!(s.poll_server(), Ok((stream, Event::Data))); - assert_eq!(s.recv_body_server(stream, &mut recv_buf), Err(Error::Done)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!(s.recv_body_v3_server(stream), Err(Error::Done)); + } else { + assert_eq!( + s.recv_body_server(stream, &mut recv_buf), + Err(Error::Done) + ); + } assert_eq!(s.poll_server(), Ok((stream, Event::Finished))); assert_eq!(s.poll_server(), Err(Error::Done)); @@ -5276,10 +6244,15 @@ mod tests { let resp = s.send_response(stream, false).unwrap(); assert_eq!( - s.server.send_body(&mut s.pipe.server, 0, b"", false), + s.server + .send_body(&mut s.pipe.server, 0 + off_by, b"", false), Err(Error::Done) ); - assert_eq!(s.server.send_body(&mut s.pipe.server, 0, b"", true), Ok(0)); + assert_eq!( + s.server + .send_body(&mut s.pipe.server, 0 + off_by, b"", true), + Ok(0) + ); s.advance().ok(); @@ -5291,7 +6264,14 @@ mod tests { assert_eq!(s.poll_client(), Ok((stream, ev_headers))); assert_eq!(s.poll_client(), Ok((stream, Event::Data))); - assert_eq!(s.recv_body_client(stream, &mut recv_buf), Err(Error::Done)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!(s.recv_body_v3_client(stream), Err(Error::Done)); + } else { + assert_eq!( + s.recv_body_client(stream, &mut recv_buf), + Err(Error::Done) + ); + } assert_eq!(s.poll_client(), Ok((stream, Event::Finished))); assert_eq!(s.poll_client(), Err(Error::Done)); @@ -5321,6 +6301,11 @@ mod tests { let mut s = Session::with_configs(&mut config, &h3_config).unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; let req = vec![ Header::new(b":method", b"GET"), @@ -5331,11 +6316,12 @@ mod tests { assert_eq!( s.client.send_request(&mut s.pipe.client, &req, false), - Ok(0) + Ok(0 + off_by) ); assert_eq!( - s.client.send_body(&mut s.pipe.client, 0, b"", true), + s.client + .send_body(&mut s.pipe.client, 0 + off_by, b"", true), Err(Error::Done) ); @@ -5348,8 +6334,12 @@ mod tests { s.advance().ok(); // Once the server gives flow control credits back, we can send the body. - assert_eq!(s.pipe.client.stream_writable_next(), Some(0)); - assert_eq!(s.client.send_body(&mut s.pipe.client, 0, b"", true), Ok(0)); + assert_eq!(s.pipe.client.stream_writable_next(), Some(0 + off_by)); + assert_eq!( + s.client + .send_body(&mut s.pipe.client, 0 + off_by, b"", true), + Ok(0) + ); } #[test] @@ -5415,14 +6405,14 @@ mod tests { assert!(!s.server.dgram_enabled_by_peer(&s.pipe.server)); // When everything is ok, poll returns Done and DATAGRAM is enabled. - assert_eq!(s.server.poll(&mut s.pipe.server), Err(Error::Done)); + assert_eq!(s.poll_server(), Err(Error::Done)); assert!(s.server.dgram_enabled_by_peer(&s.pipe.server)); // Now detect things on the client s.server.send_settings(&mut s.pipe.server).unwrap(); assert_eq!(s.pipe.advance(), Ok(())); assert!(!s.client.dgram_enabled_by_peer(&s.pipe.client)); - assert_eq!(s.client.poll(&mut s.pipe.client), Err(Error::Done)); + assert_eq!(s.poll_client(), Err(Error::Done)); assert!(s.client.dgram_enabled_by_peer(&s.pipe.client)); } @@ -5476,7 +6466,7 @@ mod tests { assert_eq!(s.pipe.advance(), Ok(())); - assert_eq!(s.server.poll(&mut s.pipe.server), Err(Error::SettingsError)); + assert_eq!(s.poll_server(), Err(Error::SettingsError)); } #[test] @@ -5545,9 +6535,9 @@ mod tests { assert_eq!(s.pipe.advance(), Ok(())); - assert_eq!(s.server.poll(&mut s.pipe.server), Err(Error::SettingsError)); + assert_eq!(s.poll_server(), Err(Error::SettingsError)); - assert_eq!(s.client.poll(&mut s.pipe.client), Err(Error::SettingsError)); + assert_eq!(s.poll_client(), Err(Error::SettingsError)); } #[test] @@ -5621,11 +6611,11 @@ mod tests { s.client.send_settings(&mut s.pipe.client).unwrap(); assert_eq!(s.pipe.advance(), Ok(())); - assert_eq!(s.server.poll(&mut s.pipe.server), Err(Error::Done)); + assert_eq!(s.poll_server(), Err(Error::Done)); s.server.send_settings(&mut s.pipe.server).unwrap(); assert_eq!(s.pipe.advance(), Ok(())); - assert_eq!(s.client.poll(&mut s.pipe.client), Err(Error::Done)); + assert_eq!(s.poll_client(), Err(Error::Done)); assert_eq!( s.server.peer_settings_raw(), @@ -5643,16 +6633,21 @@ mod tests { let mut buf = [0; 65535]; let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; // We'll send default data of 10 bytes on flow ID 0. - let result = (11, 0, 1); + let result = (11, 0 + off_by, 1); - s.send_dgram_client(0).unwrap(); + s.send_dgram_client(0 + off_by).unwrap(); assert_eq!(s.poll_server(), Err(Error::Done)); assert_eq!(s.recv_dgram_server(&mut buf), Ok(result)); - s.send_dgram_server(0).unwrap(); + s.send_dgram_server(0 + off_by).unwrap(); assert_eq!(s.poll_client(), Err(Error::Done)); assert_eq!(s.recv_dgram_client(&mut buf), Ok(result)); } @@ -5663,13 +6658,18 @@ mod tests { let mut buf = [0; 65535]; let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; // We'll send default data of 10 bytes on flow ID 0. - let result = (11, 0, 1); + let result = (11, 0 + off_by, 1); - s.send_dgram_client(0).unwrap(); - s.send_dgram_client(0).unwrap(); - s.send_dgram_client(0).unwrap(); + s.send_dgram_client(0 + off_by).unwrap(); + s.send_dgram_client(0 + off_by).unwrap(); + s.send_dgram_client(0 + off_by).unwrap(); assert_eq!(s.poll_server(), Err(Error::Done)); assert_eq!(s.recv_dgram_server(&mut buf), Ok(result)); @@ -5677,9 +6677,9 @@ mod tests { assert_eq!(s.recv_dgram_server(&mut buf), Ok(result)); assert_eq!(s.recv_dgram_server(&mut buf), Err(Error::Done)); - s.send_dgram_server(0).unwrap(); - s.send_dgram_server(0).unwrap(); - s.send_dgram_server(0).unwrap(); + s.send_dgram_server(0 + off_by).unwrap(); + s.send_dgram_server(0 + off_by).unwrap(); + s.send_dgram_server(0 + off_by).unwrap(); assert_eq!(s.poll_client(), Err(Error::Done)); assert_eq!(s.recv_dgram_client(&mut buf), Ok(result)); @@ -5694,16 +6694,21 @@ mod tests { let mut buf = [0; 65535]; let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; // We'll send default data of 10 bytes on flow ID 0. - let result = (11, 0, 1); + let result = (11, 0 + off_by, 1); // Five DATAGRAMs - s.send_dgram_client(0).unwrap(); - s.send_dgram_client(0).unwrap(); - s.send_dgram_client(0).unwrap(); - s.send_dgram_client(0).unwrap(); - s.send_dgram_client(0).unwrap(); + s.send_dgram_client(0 + off_by).unwrap(); + s.send_dgram_client(0 + off_by).unwrap(); + s.send_dgram_client(0 + off_by).unwrap(); + s.send_dgram_client(0 + off_by).unwrap(); + s.send_dgram_client(0 + off_by).unwrap(); // Only 3 independent DATAGRAMs to read events will fire. assert_eq!(s.poll_server(), Err(Error::Done)); @@ -5736,6 +6741,11 @@ mod tests { let h3_config = Config::new().unwrap(); let mut s = Session::with_configs(&mut config, &h3_config).unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; // Send request followed by DATAGRAM on client side. let (stream, req) = s.send_request(false).unwrap(); @@ -5747,7 +6757,7 @@ mod tests { has_body: true, }; - s.send_dgram_client(0).unwrap(); + s.send_dgram_client(0 + off_by).unwrap(); assert_eq!(s.poll_server(), Ok((stream, ev_headers))); assert_eq!(s.poll_server(), Ok((stream, Event::Data))); @@ -5780,9 +6790,14 @@ mod tests { let h3_config = Config::new().unwrap(); let mut s = Session::with_configs(&mut config, &h3_config).unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; // We'll send default data of 10 bytes on flow ID 0. - let result = (11, 0, 1); + let result = (11, 0 + off_by, 1); // Send request followed by DATAGRAM on client side. let (stream, req) = s.send_request(false).unwrap(); @@ -5796,7 +6811,7 @@ mod tests { has_body: true, }; - s.send_dgram_client(0).unwrap(); + s.send_dgram_client(0 + off_by).unwrap(); assert_eq!(s.poll_server(), Ok((stream, ev_headers))); assert_eq!(s.poll_server(), Ok((stream, Event::Data))); @@ -5807,7 +6822,15 @@ mod tests { assert_eq!(s.poll_server(), Err(Error::Done)); - assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + s.recv_body_v3_server(stream).unwrap().0.len(), + body.len() + ); + assert!(s.body_consumed_server(stream, body.len()).is_ok()); + } else { + assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len())); + } assert_eq!(s.poll_server(), Ok((stream, Event::Finished))); assert_eq!(s.poll_server(), Err(Error::Done)); @@ -5823,7 +6846,7 @@ mod tests { has_body: true, }; - s.send_dgram_server(0).unwrap(); + s.send_dgram_server(0 + off_by).unwrap(); assert_eq!(s.poll_client(), Ok((stream, ev_headers))); assert_eq!(s.poll_client(), Ok((stream, Event::Data))); @@ -5834,7 +6857,15 @@ mod tests { assert_eq!(s.poll_client(), Err(Error::Done)); - assert_eq!(s.recv_body_client(stream, &mut recv_buf), Ok(body.len())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + s.recv_body_v3_client(stream).unwrap().0.len(), + body.len() + ); + assert!(s.body_consumed_client(stream, body.len()).is_ok()); + } else { + assert_eq!(s.recv_body_client(stream, &mut recv_buf), Ok(body.len())); + } assert_eq!(s.poll_client(), Ok((stream, Event::Finished))); assert_eq!(s.poll_client(), Err(Error::Done)); @@ -5865,9 +6896,14 @@ mod tests { let h3_config = Config::new().unwrap(); let mut s = Session::with_configs(&mut config, &h3_config).unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; // 10 bytes on flow ID 0 and 2. - let flow_0_result = (11, 0, 1); + let flow_0_result = (11, 0 + off_by, 1); let flow_2_result = (11, 2, 1); // Send requests followed by DATAGRAMs on client side. @@ -5882,11 +6918,11 @@ mod tests { has_body: true, }; - s.send_dgram_client(0).unwrap(); - s.send_dgram_client(0).unwrap(); - s.send_dgram_client(0).unwrap(); - s.send_dgram_client(0).unwrap(); - s.send_dgram_client(0).unwrap(); + s.send_dgram_client(0 + off_by).unwrap(); + s.send_dgram_client(0 + off_by).unwrap(); + s.send_dgram_client(0 + off_by).unwrap(); + s.send_dgram_client(0 + off_by).unwrap(); + s.send_dgram_client(0 + off_by).unwrap(); s.send_dgram_client(2).unwrap(); s.send_dgram_client(2).unwrap(); s.send_dgram_client(2).unwrap(); @@ -5906,7 +6942,15 @@ mod tests { assert_eq!(s.recv_dgram_server(&mut buf), Ok(flow_0_result)); assert_eq!(s.poll_server(), Err(Error::Done)); - assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + s.recv_body_v3_server(stream).unwrap().0.len(), + body.len() + ); + assert!(s.body_consumed_server(stream, body.len()).is_ok()); + } else { + assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len())); + } assert_eq!(s.poll_server(), Ok((stream, Event::Finished))); assert_eq!(s.poll_server(), Err(Error::Done)); @@ -5939,11 +6983,11 @@ mod tests { has_body: true, }; - s.send_dgram_server(0).unwrap(); - s.send_dgram_server(0).unwrap(); - s.send_dgram_server(0).unwrap(); - s.send_dgram_server(0).unwrap(); - s.send_dgram_server(0).unwrap(); + s.send_dgram_server(0 + off_by).unwrap(); + s.send_dgram_server(0 + off_by).unwrap(); + s.send_dgram_server(0 + off_by).unwrap(); + s.send_dgram_server(0 + off_by).unwrap(); + s.send_dgram_server(0 + off_by).unwrap(); s.send_dgram_server(2).unwrap(); s.send_dgram_server(2).unwrap(); s.send_dgram_server(2).unwrap(); @@ -5963,7 +7007,15 @@ mod tests { assert_eq!(s.recv_dgram_client(&mut buf), Ok(flow_0_result)); assert_eq!(s.poll_client(), Err(Error::Done)); - assert_eq!(s.recv_body_client(stream, &mut recv_buf), Ok(body.len())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + s.recv_body_v3_client(stream).unwrap().0.len(), + body.len() + ); + assert!(s.body_consumed_client(stream, body.len()).is_ok()); + } else { + assert_eq!(s.recv_body_client(stream, &mut recv_buf), Ok(body.len())); + } assert_eq!(s.poll_client(), Ok((stream, Event::Finished))); assert_eq!(s.poll_client(), Err(Error::Done)); @@ -6021,10 +7073,25 @@ mod tests { assert_eq!(s.poll_server(), Ok((stream, ev_headers))); assert_eq!(s.poll_server(), Ok((stream, Event::Data))); - assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + s.recv_body_v3_server(stream).unwrap().0.len(), + body.len() + ); + assert!(s.body_consumed_server(stream, body.len()).is_ok()); + } else { + assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len())); + } assert_eq!(s.poll_server(), Ok((stream, Event::Finished))); - assert_eq!(s.recv_body_server(stream, &mut recv_buf), Err(Error::Done)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!(s.recv_body_v3_server(stream), Err(Error::Done)); + } else { + assert_eq!( + s.recv_body_server(stream, &mut recv_buf), + Err(Error::Done) + ); + } assert_eq!(s.poll_server(), Err(Error::Done)); } @@ -6069,7 +7136,14 @@ mod tests { assert_eq!(s.poll_server(), Err(Error::Done)); // Read the available body data. - assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(5)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (b, tot_exp_len) = s.recv_body_v3_server(stream).unwrap(); + assert_eq!(b.len(), 5); + assert_eq!(tot_exp_len, 10); + assert!(s.body_consumed_server(stream, 5).is_ok()); + } else { + assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(5)); + } // Send the remaining DATA payload. assert_eq!(s.pipe.client.stream_send(stream, &bytes[5..], false), Ok(5)); @@ -6079,7 +7153,14 @@ mod tests { assert_eq!(s.poll_server(), Err(Error::Done)); // Read the rest of the body data. - assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(5)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (b, tot_exp_len) = s.recv_body_v3_server(stream).unwrap(); + assert_eq!(b.len(), 5); + assert_eq!(tot_exp_len, 5); + assert!(s.body_consumed_server(stream, 5).is_ok()); + } else { + assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(5)); + } assert_eq!(s.poll_server(), Err(Error::Done)); // Send more data. @@ -6088,7 +7169,15 @@ mod tests { assert_eq!(s.poll_server(), Ok((stream, Event::Data))); assert_eq!(s.poll_server(), Err(Error::Done)); - assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + s.recv_body_v3_server(stream).unwrap().0.len(), + body.len() + ); + assert!(s.body_consumed_server(stream, body.len()).is_ok()); + } else { + assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len())); + } // Send more data, then HEADERS, then more data. let body = s.send_body_client(stream, false).unwrap(); @@ -6109,12 +7198,28 @@ mod tests { s.send_body_client(stream, false).unwrap(); assert_eq!(s.poll_server(), Ok((stream, Event::Data))); - assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + s.recv_body_v3_server(stream).unwrap().0.len(), + body.len() + ); + assert!(s.body_consumed_server(stream, body.len()).is_ok()); + } else { + assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len())); + } assert_eq!(s.poll_server(), Ok((stream, ev_trailers))); assert_eq!(s.poll_server(), Ok((stream, Event::Data))); - assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + s.recv_body_v3_server(stream).unwrap().0.len(), + body.len() + ); + assert!(s.body_consumed_server(stream, body.len()).is_ok()); + } else { + assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len())); + } let (stream, req) = s.send_request(false).unwrap(); @@ -6140,7 +7245,14 @@ mod tests { assert_eq!(s.poll_server(), Ok((stream, Event::Data))); assert_eq!(s.poll_server(), Err(Error::Done)); - assert_eq!(s.recv_body_server(stream, &mut recv_buf), Err(Error::Done)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!(s.recv_body_v3_server(stream), Err(Error::Done)); + } else { + assert_eq!( + s.recv_body_server(stream, &mut recv_buf), + Err(Error::Done) + ); + } assert_eq!(s.pipe.client.stream_send(stream, &bytes[..5], false), Ok(5)); @@ -6149,7 +7261,14 @@ mod tests { assert_eq!(s.poll_server(), Ok((stream, Event::Data))); assert_eq!(s.poll_server(), Err(Error::Done)); - assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(5)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (b, tot_exp_len) = s.recv_body_v3_server(stream).unwrap(); + assert_eq!(b.len(), 5); + assert_eq!(tot_exp_len, 10); + assert!(s.body_consumed_server(stream, 5).is_ok()); + } else { + assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(5)); + } assert_eq!(s.pipe.client.stream_send(stream, &bytes[5..], false), Ok(5)); s.advance().ok(); @@ -6157,7 +7276,14 @@ mod tests { assert_eq!(s.poll_server(), Ok((stream, Event::Data))); assert_eq!(s.poll_server(), Err(Error::Done)); - assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(5)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (b, tot_exp_len) = s.recv_body_v3_server(stream).unwrap(); + assert_eq!(b.len(), 5); + assert_eq!(tot_exp_len, 5); + assert!(s.body_consumed_server(stream, 5).is_ok()); + } else { + assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(5)); + } // Buffer multiple data frames. let body = s.send_body_client(stream, false).unwrap(); @@ -6181,10 +7307,21 @@ mod tests { let mut recv_buf = vec![0; bytes.len() * 3]; - assert_eq!( - s.recv_body_server(stream, &mut recv_buf), - Ok(body.len() * 3) - ); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + for _ in 0..3 { + // In V3 we process one DATA frame per recv by design of + // zero-copy. + let (b, tot_exp_len) = s.recv_body_v3_server(stream).unwrap(); + assert_eq!(b.len(), body.len()); + assert_eq!(tot_exp_len, body.len()); + assert!(s.body_consumed_server(stream, body.len()).is_ok()); + } + } else { + assert_eq!( + s.recv_body_server(stream, &mut recv_buf), + Ok(body.len() * 3) + ); + } } #[test] @@ -6212,9 +7349,14 @@ mod tests { let h3_config = Config::new().unwrap(); let mut s = Session::with_configs(&mut config, &h3_config).unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; // 10 bytes on flow ID 0 and 2. - let flow_0_result = (11, 0, 1); + let flow_0_result = (11, 0 + off_by, 1); let flow_2_result = (11, 2, 1); // Send requests followed by DATAGRAMs on client side. @@ -6229,8 +7371,8 @@ mod tests { has_body: true, }; - s.send_dgram_client(0).unwrap(); - s.send_dgram_client(0).unwrap(); + s.send_dgram_client(0 + off_by).unwrap(); + s.send_dgram_client(0 + off_by).unwrap(); s.send_dgram_client(2).unwrap(); s.send_dgram_client(2).unwrap(); @@ -6251,7 +7393,7 @@ mod tests { assert_eq!(s.poll_server(), Err(Error::Done)); - s.send_dgram_client(0).unwrap(); + s.send_dgram_client(0 + off_by).unwrap(); s.send_dgram_client(2).unwrap(); assert_eq!(s.poll_server(), Err(Error::Done)); @@ -6262,7 +7404,15 @@ mod tests { assert_eq!(s.recv_dgram_server(&mut buf), Ok(flow_2_result)); assert_eq!(s.poll_server(), Err(Error::Done)); - assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + s.recv_body_v3_server(stream).unwrap().0.len(), + body.len() + ); + assert!(s.body_consumed_server(stream, body.len()).is_ok()); + } else { + assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len())); + } assert_eq!(s.poll_server(), Ok((stream, Event::Finished))); } @@ -6306,12 +7456,12 @@ mod tests { let pkt_type = crate::packet::Type::Short; if s.pipe.client.version == crate::PROTOCOL_VERSION_V3 { assert_eq!( - s.pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + s.pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), Ok(48) ); } else { assert_eq!( - s.pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + s.pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), Ok(39) ); } @@ -6323,12 +7473,12 @@ mod tests { // Sending RESET_STREAM again shouldn't trigger another Reset event. if s.pipe.client.version == crate::PROTOCOL_VERSION_V3 { assert_eq!( - s.pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + s.pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), Ok(48) ); } else { assert_eq!( - s.pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + s.pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), Ok(39) ); } @@ -6340,13 +7490,20 @@ mod tests { fn reset_finished_at_server() { let mut s = Session::new().unwrap(); s.handshake().unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; // Client sends HEADERS and doesn't fin let (stream, _req) = s.send_request(false).unwrap(); // ..then Client sends RESET_STREAM assert_eq!( - s.pipe.client.stream_shutdown(0, crate::Shutdown::Write, 0), + s.pipe + .client + .stream_shutdown(0 + off_by, crate::Shutdown::Write, 0), Ok(()) ); @@ -6361,7 +7518,9 @@ mod tests { // ..then Client sends RESET_STREAM assert_eq!( - s.pipe.client.stream_shutdown(4, crate::Shutdown::Write, 0), + s.pipe + .client + .stream_shutdown(4 + off_by, crate::Shutdown::Write, 0), Ok(()) ); @@ -6441,12 +7600,12 @@ mod tests { let pkt_type = crate::packet::Type::Short; if s.pipe.client.version == crate::PROTOCOL_VERSION_V3 { assert_eq!( - s.pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + s.pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), Ok(48) ); } else { assert_eq!( - s.pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + s.pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), Ok(39) ); } diff --git a/quiche/src/h3/stream.rs b/quiche/src/h3/stream.rs index df0d05e4..4be1e3ee 100644 --- a/quiche/src/h3/stream.rs +++ b/quiche/src/h3/stream.rs @@ -28,6 +28,7 @@ use super::Error; use super::Result; use super::frame; +use crate::AppRecvBufMap; pub const HTTP3_CONTROL_STREAM_TYPE_ID: u64 = 0x0; pub const HTTP3_PUSH_STREAM_TYPE_ID: u64 = 0x1; @@ -156,6 +157,11 @@ pub struct Stream { /// The last `PRIORITY_UPDATE` frame encoded field value, if any. last_priority_update: Option>, + + /// The quic version being used. We need to keep track of this here + /// for semantic mapping between HTTP/3 stream and QUIC streams with + /// zero-cpy. + qversion: u32, } impl Stream { @@ -163,7 +169,7 @@ impl Stream { /// /// The `is_local` parameter indicates whether the stream was created by the /// local endpoint, or by the peer. - pub fn new(id: u64, is_local: bool) -> Stream { + pub fn new(id: u64, is_local: bool, qversion: u32) -> Stream { let (ty, state) = if crate::stream::is_bidi(id) { // All bidirectional streams are "request" streams, so we don't // need to read the stream type. @@ -180,7 +186,11 @@ impl Stream { state, // Pre-allocate a buffer to avoid multiple tiny early allocations. - state_buf: vec![0; 16], + state_buf: if qversion == crate::PROTOCOL_VERSION_V3 { + vec![] + } else { + vec![0; 16] + }, // Expect one byte for the initial state, to parse the initial // varint length. @@ -196,6 +206,7 @@ impl Stream { data_event_triggered: false, last_priority_update: None, + qversion, } } @@ -384,6 +395,61 @@ impl Stream { Err(Error::InternalError) } + /// Read the connection and acquire a reference to the data containing the + /// state + pub fn try_acquire_state_buffer<'a>( + &mut self, conn: &mut crate::Connection, app_buf: &'a mut AppRecvBufMap, + ) -> Result<&'a [u8]> { + // In v3, the state is kept mixed with data. We eventually + // give a slice to the upper layer containing the DATA from + // the data frame. + // + // This gives everything readable until it is explicitely + // marrked as consumed. + let b = match conn.stream_recv_v3(self.id, app_buf) { + Ok((b, len, _)) => { + // We read nothing form the QUIC stream + if len == 0 { + self.reset_data_event(); + + return Err(Error::Done); + } + // we acquired some data + b + }, + + Err(e) => { + // The stream is not readable anymore, so re-arm the Data event. + if e == crate::Error::Done { + self.reset_data_event(); + } + + return Err(e.into()); + }, + }; + + Ok(b) + } + + /// Mark the data acquired from the state buffer as consumed. + pub fn mark_state_buffer_consumed( + &mut self, conn: &mut crate::Connection, consumed: usize, + app_buf: &mut AppRecvBufMap, + ) -> Result<()> { + self.state_off += consumed; + + conn.stream_consumed(self.id, consumed, app_buf)?; + + trace!( + "{} consumed {} bytes on stream {}", + conn.trace_id(), + consumed, + self.id + ); + + Ok(()) + } + /// Tries to fill the state buffer by reading data from the corresponding /// transport stream. /// @@ -466,6 +532,74 @@ impl Stream { Ok(()) } + /// This is intended to replace `try_acquire_state_buffer()` in tests, in + /// order to avoid having to setup a transport connection. + #[cfg(test)] + fn try_acquire_state_buffer_for_tests<'a>( + &mut self, stream: &'a mut std::io::Cursor>, + ) -> Result<&'a [u8]> { + let buf = &stream.get_ref()[stream.position() as usize..]; + + Ok(buf) + } + + /// This is intended o replace `try_acquire_data()` in tests. Since the + /// state buffer isn't moved out of the app buffer in V3, this is the + /// same function than acquiring the state buffer. + #[cfg(test)] + fn try_acquire_data_for_tests<'a>( + &mut self, stream: &'a mut std::io::Cursor>, + ) -> Result<&'a [u8]> { + let buf = &stream.get_ref()[stream.position() as usize..]; + + let left = std::cmp::min(buf.len(), self.state_len - self.state_off); + Ok(&buf[..left]) + } + + #[cfg(test)] + fn mark_state_buffer_consumed_for_tests( + &mut self, consumed: usize, stream: &mut std::io::Cursor>, + ) -> Result<()> { + self.state_off += consumed; + + stream.set_position(stream.position() + consumed as u64); + Ok(()) + } + + #[cfg(test)] + fn mark_data_consumed_for_tests( + &mut self, consumed: usize, stream: &mut std::io::Cursor>, + ) -> Result<()> { + self.state_off += consumed; + + stream.set_position(stream.position() + consumed as u64); + + // We can transition if we consumed the whole data frame. + if self.state_buffer_complete() { + self.state_transition(State::FrameType, 1, true)?; + } + + Ok(()) + } + + /// Update the state length an tries to consume the varint. + pub fn try_consume_varint_from_buf( + &mut self, buf: &[u8], + ) -> Result { + // always parse the length + self.state_len = octets::varint_parse_len(buf[0]); + + // In case we don't have enough data pulled from QUIC. + if buf.len() < self.state_len { + self.reset_data_event(); + return Err(Error::Done); + } + + let varint = octets::Octets::with_slice(buf).get_varint()?; + + Ok(varint) + } + /// Tries to parse a varint (including length) from the state buffer. pub fn try_consume_varint(&mut self) -> Result { if self.state_off == 1 { @@ -484,6 +618,31 @@ impl Stream { Ok(varint) } + /// Tries to parse a frame from the provided buffer. + /// + /// If successful, returns the `frame::Frame` and the payload length. + pub fn try_consume_frame_from_buf( + &mut self, buf: &[u8], + ) -> Result<(frame::Frame, u64)> { + // if we don't have enough data to parse the frame, we return early. + if buf.len() < self.state_len { + self.reset_data_event(); + return Err(Error::Done); + } + + // Processing a frame other than DATA, so re-arm the Data event. + self.reset_data_event(); + + let payload_len = self.state_len as u64; + + let frame = + frame::Frame::from_bytes(self.frame_type.unwrap(), payload_len, buf)?; + + self.state_transition(State::FrameType, 1, true)?; + + Ok((frame, payload_len)) + } + /// Tries to parse a frame from the state buffer. /// /// If successful, returns the `frame::Frame` and the payload length. @@ -505,6 +664,33 @@ impl Stream { Ok((frame, payload_len)) } + /// Tries to get a reference to the DATA payload for the application to + /// eventually consume. + pub fn try_acquire_data<'a>( + &mut self, conn: &mut crate::Connection, app_buf: &'a mut AppRecvBufMap, + ) -> Result<(&'a [u8], usize, bool)> { + let (b, len, fin) = match conn.stream_recv_v3(self.id, app_buf) { + Ok(v) => v, + + Err(e) => { + // The stream is not readable anymore, so re-arm the Data event. + if e == crate::Error::Done { + self.reset_data_event(); + } + + return Err(e.into()); + }, + }; + let left = std::cmp::min(b.len(), self.state_len - self.state_off); + + // The stream is not readable anymore, so re-arm the Data event. + if !conn.stream_readable(self.id) { + self.reset_data_event(); + } + + Ok((&b[..left], len, fin)) + } + /// Tries to read DATA payload from the transport stream. pub fn try_consume_data( &mut self, conn: &mut crate::Connection, out: &mut [u8], @@ -538,6 +724,25 @@ impl Stream { Ok((len, fin)) } + /// Marks DATA payload read and consumed (up to `consumed`). + pub fn mark_data_consumed( + &mut self, conn: &mut crate::Connection, app_buf: &mut AppRecvBufMap, + consumed: usize, + ) -> Result<()> { + // Account for DATA consumed by the app + self.state_off += consumed; + + // Tell the underlying QUIC stream that we consumed part of the data. + conn.stream_consumed(self.id, consumed, app_buf)?; + + // We can transition if we consumed the whole data frame. + if self.state_buffer_complete() { + self.state_transition(State::FrameType, 1, true)?; + } + + Ok(()) + } + /// Marks the stream as finished. pub fn finished(&mut self) { let _ = self.state_transition(State::Finished, 0, false); @@ -598,9 +803,20 @@ impl Stream { self.last_priority_update.is_some() } + /// Returns the current state len + pub fn get_state_len(&self) -> usize { + self.state_len + } + + pub fn get_state_off(&self) -> usize { + self.state_off + } + /// Returns true if the state buffer has enough data to complete the state. fn state_buffer_complete(&self) -> bool { - self.state_off == self.state_len + // with stream_recv_v3, we may read more than the state buffer + // although it is not an issue since everything is zero-copy + self.state_off >= self.state_len } /// Transitions the stream to a new state, and optionally resets the state @@ -610,6 +826,7 @@ impl Stream { ) -> Result<()> { // Some states don't need the state buffer, so don't resize it if not // necessary. + // V3 does not use a local state buf, so we only touch it in V1. if resize { // A peer can influence the size of the state buffer (e.g. with the // payload size of a GREASE frame), so we need to limit the maximum @@ -618,7 +835,9 @@ impl Stream { return Err(Error::ExcessiveLoad); } - self.state_buf.resize(expected_len, 0); + if self.qversion == crate::PROTOCOL_VERSION_V1 { + self.state_buf.resize(expected_len, 0); + } } self.state = new_state; @@ -636,7 +855,7 @@ mod tests { use super::*; fn open_uni(b: &mut octets::OctetsMut, ty: u64) -> Result { - let stream = Stream::new(2, false); + let stream = Stream::new(2, false, crate::PROTOCOL_VERSION); assert_eq!(stream.state, State::StreamType); b.put_varint(ty)?; @@ -647,9 +866,21 @@ mod tests { fn parse_uni( stream: &mut Stream, ty: u64, cursor: &mut std::io::Cursor>, ) -> Result<()> { - stream.try_fill_buffer_for_tests(cursor)?; + let stream_ty = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream.try_acquire_state_buffer_for_tests(cursor)?; + + let varint = stream.try_consume_varint_from_buf(b)?; + stream.mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + cursor, + )?; + varint + } else { + stream.try_fill_buffer_for_tests(cursor)?; + + stream.try_consume_varint()? + }; - let stream_ty = stream.try_consume_varint()?; assert_eq!(stream_ty, ty); stream.set_ty(Type::deserialize(stream_ty).unwrap())?; @@ -660,24 +891,58 @@ mod tests { stream: &mut Stream, cursor: &mut std::io::Cursor>, ) -> Result<()> { // Parse the frame type. - stream.try_fill_buffer_for_tests(cursor)?; + let frame_ty = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream.try_acquire_state_buffer_for_tests(cursor)?; + + let frame_ty = stream.try_consume_varint_from_buf(b)?; + stream.mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + cursor, + )?; + frame_ty + } else { + stream.try_fill_buffer_for_tests(cursor)?; - let frame_ty = stream.try_consume_varint()?; + stream.try_consume_varint()? + }; stream.set_frame_type(frame_ty)?; assert_eq!(stream.state, State::FramePayloadLen); // Parse the frame payload length. - stream.try_fill_buffer_for_tests(cursor)?; + let frame_payload_len = + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream.try_acquire_state_buffer_for_tests(cursor)?; + + let frame_payload_len = stream.try_consume_varint_from_buf(b)?; + stream.mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + cursor, + )?; + frame_payload_len + } else { + stream.try_fill_buffer_for_tests(cursor)?; + + stream.try_consume_varint()? + }; - let frame_payload_len = stream.try_consume_varint()?; stream.set_frame_payload_len(frame_payload_len)?; assert_eq!(stream.state, State::FramePayload); // Parse the frame payload. - stream.try_fill_buffer_for_tests(cursor)?; + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream.try_acquire_state_buffer_for_tests(cursor)?; + + stream.try_consume_frame_from_buf(b)?; + stream.mark_state_buffer_consumed_for_tests( + frame_payload_len as usize, + cursor, + )?; + } else { + stream.try_fill_buffer_for_tests(cursor)?; - stream.try_consume_frame()?; + stream.try_consume_frame()?; + }; assert_eq!(stream.state, State::FrameType); Ok(()) @@ -716,26 +981,69 @@ mod tests { assert_eq!(stream.state, State::FrameType); // Parse the SETTINGS frame type. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + let frame_ty = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_ty = stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_ty + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let frame_ty = stream.try_consume_varint().unwrap(); + stream.try_consume_varint().unwrap() + }; assert_eq!(frame_ty, frame::SETTINGS_FRAME_TYPE_ID); stream.set_frame_type(frame_ty).unwrap(); assert_eq!(stream.state, State::FramePayloadLen); // Parse the SETTINGS frame payload length. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - - let frame_payload_len = stream.try_consume_varint().unwrap(); + let frame_payload_len = + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_payload_len = + stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_payload_len + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + + stream.try_consume_varint().unwrap() + }; assert_eq!(frame_payload_len, 6); stream.set_frame_payload_len(frame_payload_len).unwrap(); assert_eq!(stream.state, State::FramePayload); // Parse the SETTINGS frame payload. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + assert_eq!(stream.try_consume_frame_from_buf(b), Ok((frame, 6))); + assert!(stream + .mark_state_buffer_consumed_for_tests(6, &mut cursor) + .is_ok()); + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - assert_eq!(stream.try_consume_frame(), Ok((frame, 6))); + assert_eq!(stream.try_consume_frame(), Ok((frame, 6))); + } assert_eq!(stream.state, State::FrameType); } @@ -766,26 +1074,70 @@ mod tests { assert_eq!(stream.state, State::FrameType); // Parse the SETTINGS frame type. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + let frame_ty = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_ty = stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_ty + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let frame_ty = stream.try_consume_varint().unwrap(); + stream.try_consume_varint().unwrap() + }; assert_eq!(frame_ty, frame::SETTINGS_FRAME_TYPE_ID); stream.set_frame_type(frame_ty).unwrap(); assert_eq!(stream.state, State::FramePayloadLen); // Parse the SETTINGS frame payload length. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + let frame_payload_len = + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_payload_len = + stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_payload_len + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + + stream.try_consume_varint().unwrap() + }; - let frame_payload_len = stream.try_consume_varint().unwrap(); assert_eq!(frame_payload_len, 0); stream.set_frame_payload_len(frame_payload_len).unwrap(); assert_eq!(stream.state, State::FramePayload); // Parse the SETTINGS frame payload. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + assert_eq!(stream.try_consume_frame_from_buf(b), Ok((frame, 0))); + assert!(stream + .mark_state_buffer_consumed_for_tests(0, &mut cursor) + .is_ok()); + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - assert_eq!(stream.try_consume_frame(), Ok((frame, 0))); + assert_eq!(stream.try_consume_frame(), Ok((frame, 0))); + } assert_eq!(stream.state, State::FrameType); } @@ -823,32 +1175,90 @@ mod tests { assert_eq!(stream.state, State::FrameType); // Parse the SETTINGS frame type. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + let frame_ty = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_ty = stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_ty + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let frame_ty = stream.try_consume_varint().unwrap(); + stream.try_consume_varint().unwrap() + }; assert_eq!(frame_ty, frame::SETTINGS_FRAME_TYPE_ID); stream.set_frame_type(frame_ty).unwrap(); assert_eq!(stream.state, State::FramePayloadLen); // Parse the SETTINGS frame payload length. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - - let frame_payload_len = stream.try_consume_varint().unwrap(); + let frame_payload_len = + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_payload_len = + stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_payload_len + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + + stream.try_consume_varint().unwrap() + }; assert_eq!(frame_payload_len, 6); stream.set_frame_payload_len(frame_payload_len).unwrap(); assert_eq!(stream.state, State::FramePayload); // Parse the SETTINGS frame payload. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + assert_eq!(stream.try_consume_frame_from_buf(b), Ok((frame, 6))); + assert!(stream + .mark_state_buffer_consumed_for_tests(6, &mut cursor) + .is_ok()); + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - assert_eq!(stream.try_consume_frame(), Ok((frame, 6))); + assert_eq!(stream.try_consume_frame(), Ok((frame, 6))); + } assert_eq!(stream.state, State::FrameType); // Parse the second SETTINGS frame type. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + let frame_ty = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_ty = stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_ty + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let frame_ty = stream.try_consume_varint().unwrap(); + stream.try_consume_varint().unwrap() + }; assert_eq!(stream.set_frame_type(frame_ty), Err(Error::FrameUnexpected)); } @@ -888,9 +1298,24 @@ mod tests { assert_eq!(stream.state, State::FrameType); // Parse GOAWAY. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + let frame_ty = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_ty = stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_ty + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let frame_ty = stream.try_consume_varint().unwrap(); + stream.try_consume_varint().unwrap() + }; assert_eq!(stream.set_frame_type(frame_ty), Err(Error::MissingSettings)); } @@ -932,30 +1357,87 @@ mod tests { assert_eq!(stream.state, State::FrameType); // Parse first SETTINGS frame. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + let frame_ty = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_ty = stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_ty + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let frame_ty = stream.try_consume_varint().unwrap(); + stream.try_consume_varint().unwrap() + }; stream.set_frame_type(frame_ty).unwrap(); - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - - let frame_payload_len = stream.try_consume_varint().unwrap(); + let frame_payload_len = + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_payload_len = + stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_payload_len + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + + stream.try_consume_varint().unwrap() + }; stream.set_frame_payload_len(frame_payload_len).unwrap(); - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); - assert!(stream.try_consume_frame().is_ok()); + stream.try_consume_frame_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests(6, &mut cursor) + .is_ok()); + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + stream.try_consume_frame().unwrap(); + } // Parse HEADERS. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + let frame_ty = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_ty = stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_ty + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let frame_ty = stream.try_consume_varint().unwrap(); + stream.try_consume_varint().unwrap() + }; assert_eq!(stream.set_frame_type(frame_ty), Err(Error::FrameUnexpected)); } #[test] fn request_no_data() { - let mut stream = Stream::new(0, false); + let mut stream = Stream::new(0, false, crate::PROTOCOL_VERSION); assert_eq!(stream.ty, Some(Type::Request)); assert_eq!(stream.state, State::FrameType); @@ -965,7 +1447,7 @@ mod tests { #[test] fn request_good() { - let mut stream = Stream::new(0, false); + let mut stream = Stream::new(0, false, crate::PROTOCOL_VERSION); let mut d = vec![42; 128]; let mut b = octets::OctetsMut::with_slice(&mut d); @@ -983,54 +1465,142 @@ mod tests { let mut cursor = std::io::Cursor::new(d); // Parse the HEADERS frame type. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + let frame_ty = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_ty = stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_ty + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let frame_ty = stream.try_consume_varint().unwrap(); + stream.try_consume_varint().unwrap() + }; assert_eq!(frame_ty, frame::HEADERS_FRAME_TYPE_ID); stream.set_frame_type(frame_ty).unwrap(); assert_eq!(stream.state, State::FramePayloadLen); // Parse the HEADERS frame payload length. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - - let frame_payload_len = stream.try_consume_varint().unwrap(); + let frame_payload_len = + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_payload_len = + stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_payload_len + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + + stream.try_consume_varint().unwrap() + }; assert_eq!(frame_payload_len, 12); stream.set_frame_payload_len(frame_payload_len).unwrap(); assert_eq!(stream.state, State::FramePayload); // Parse the HEADERS frame. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + assert_eq!(stream.try_consume_frame_from_buf(b), Ok((hdrs, 12))); + assert!(stream + .mark_state_buffer_consumed_for_tests(12, &mut cursor) + .is_ok()); + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - assert_eq!(stream.try_consume_frame(), Ok((hdrs, 12))); + assert_eq!(stream.try_consume_frame(), Ok((hdrs, 12))); + } assert_eq!(stream.state, State::FrameType); // Parse the DATA frame type. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + let frame_ty = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_ty = stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_ty + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let frame_ty = stream.try_consume_varint().unwrap(); + stream.try_consume_varint().unwrap() + }; assert_eq!(frame_ty, frame::DATA_FRAME_TYPE_ID); stream.set_frame_type(frame_ty).unwrap(); assert_eq!(stream.state, State::FramePayloadLen); // Parse the DATA frame payload length. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - - let frame_payload_len = stream.try_consume_varint().unwrap(); + let frame_payload_len = + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_payload_len = + stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_payload_len + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + + stream.try_consume_varint().unwrap() + }; assert_eq!(frame_payload_len, 12); stream.set_frame_payload_len(frame_payload_len).unwrap(); assert_eq!(stream.state, State::Data); // Parse the DATA payload. - let mut recv_buf = vec![0; payload.len()]; - assert_eq!( - stream.try_consume_data_for_tests(&mut cursor, &mut recv_buf), - Ok(payload.len()) - ); - assert_eq!(payload, recv_buf); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + stream + .try_acquire_data_for_tests(&mut cursor) + .unwrap() + .len(), + payload.len() + ); + assert!(stream + .mark_data_consumed_for_tests(payload.len(), &mut cursor) + .is_ok()); + } else { + let mut recv_buf = vec![0; payload.len()]; + assert_eq!( + stream.try_consume_data_for_tests(&mut cursor, &mut recv_buf), + Ok(payload.len()) + ); + assert_eq!(payload, recv_buf); + } assert_eq!(stream.state, State::FrameType); } @@ -1058,64 +1628,166 @@ mod tests { assert_eq!(stream.state, State::PushId); // Parse push ID. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + let push_id = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let push_id = stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + push_id + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let push_id = stream.try_consume_varint().unwrap(); + stream.try_consume_varint().unwrap() + }; assert_eq!(push_id, 1); stream.set_push_id(push_id).unwrap(); assert_eq!(stream.state, State::FrameType); // Parse the HEADERS frame type. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + let frame_ty = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_ty = stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_ty + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let frame_ty = stream.try_consume_varint().unwrap(); + stream.try_consume_varint().unwrap() + }; assert_eq!(frame_ty, frame::HEADERS_FRAME_TYPE_ID); stream.set_frame_type(frame_ty).unwrap(); assert_eq!(stream.state, State::FramePayloadLen); // Parse the HEADERS frame payload length. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - - let frame_payload_len = stream.try_consume_varint().unwrap(); + let frame_payload_len = + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_payload_len = + stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_payload_len + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + + stream.try_consume_varint().unwrap() + }; assert_eq!(frame_payload_len, 12); stream.set_frame_payload_len(frame_payload_len).unwrap(); assert_eq!(stream.state, State::FramePayload); // Parse the HEADERS frame. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + assert_eq!(stream.try_consume_frame_from_buf(b), Ok((hdrs, 12))); + assert!(stream + .mark_state_buffer_consumed_for_tests(12, &mut cursor) + .is_ok()); + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - assert_eq!(stream.try_consume_frame(), Ok((hdrs, 12))); + assert_eq!(stream.try_consume_frame(), Ok((hdrs, 12))); + } assert_eq!(stream.state, State::FrameType); // Parse the DATA frame type. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + let frame_ty = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_ty = stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_ty + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let frame_ty = stream.try_consume_varint().unwrap(); + stream.try_consume_varint().unwrap() + }; assert_eq!(frame_ty, frame::DATA_FRAME_TYPE_ID); stream.set_frame_type(frame_ty).unwrap(); assert_eq!(stream.state, State::FramePayloadLen); // Parse the DATA frame payload length. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - - let frame_payload_len = stream.try_consume_varint().unwrap(); + let frame_payload_len = + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_payload_len = + stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_payload_len + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + + stream.try_consume_varint().unwrap() + }; assert_eq!(frame_payload_len, 12); stream.set_frame_payload_len(frame_payload_len).unwrap(); assert_eq!(stream.state, State::Data); // Parse the DATA payload. - let mut recv_buf = vec![0; payload.len()]; - assert_eq!( - stream.try_consume_data_for_tests(&mut cursor, &mut recv_buf), - Ok(payload.len()) - ); - assert_eq!(payload, recv_buf); - + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + stream + .try_acquire_data_for_tests(&mut cursor) + .unwrap() + .len(), + payload.len() + ); + assert!(stream + .mark_data_consumed_for_tests(payload.len(), &mut cursor) + .is_ok()); + } else { + let mut recv_buf = vec![0; payload.len()]; + assert_eq!( + stream.try_consume_data_for_tests(&mut cursor, &mut recv_buf), + Ok(payload.len()) + ); + assert_eq!(payload, recv_buf); + } assert_eq!(stream.state, State::FrameType); } @@ -1129,9 +1801,24 @@ mod tests { let mut cursor = std::io::Cursor::new(d); // Parse stream type. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + let stream_ty = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let stream_ty = stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + stream_ty + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let stream_ty = stream.try_consume_varint().unwrap(); + stream.try_consume_varint().unwrap() + }; assert_eq!(stream_ty, 33); stream .set_ty(Type::deserialize(stream_ty).unwrap()) @@ -1141,7 +1828,7 @@ mod tests { #[test] fn data_before_headers() { - let mut stream = Stream::new(0, false); + let mut stream = Stream::new(0, false, crate::PROTOCOL_VERSION); let mut d = vec![42; 128]; let mut b = octets::OctetsMut::with_slice(&mut d); @@ -1155,9 +1842,24 @@ mod tests { let mut cursor = std::io::Cursor::new(d); // Parse the DATA frame type. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + let frame_ty = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_ty = stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_ty + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let frame_ty = stream.try_consume_varint().unwrap(); + stream.try_consume_varint().unwrap() + }; assert_eq!(frame_ty, frame::DATA_FRAME_TYPE_ID); assert_eq!(stream.set_frame_type(frame_ty), Err(Error::FrameUnexpected)); @@ -1195,16 +1897,50 @@ mod tests { parse_skip_frame(&mut stream, &mut cursor).unwrap(); // Parse frame type. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let frame_ty = stream.try_consume_varint().unwrap(); + let frame_ty = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_ty = stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_ty + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + + stream.try_consume_varint().unwrap() + }; assert_eq!(frame_ty, frame::GOAWAY_FRAME_TYPE_ID); stream.set_frame_type(frame_ty).unwrap(); assert_eq!(stream.state, State::FramePayloadLen); // Parse frame payload length. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let frame_payload_len = stream.try_consume_varint().unwrap(); + let frame_payload_len = + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_payload_len = + stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_payload_len + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + + stream.try_consume_varint().unwrap() + }; assert_eq!( Err(Error::FrameError), stream.set_frame_payload_len(frame_payload_len) @@ -1216,7 +1952,7 @@ mod tests { let mut d = vec![42; 128]; let mut b = octets::OctetsMut::with_slice(&mut d); - let mut stream = Stream::new(0, false); + let mut stream = Stream::new(0, false, crate::PROTOCOL_VERSION); assert_eq!(stream.ty, Some(Type::Request)); assert_eq!(stream.state, State::FrameType); @@ -1228,16 +1964,50 @@ mod tests { let mut cursor = std::io::Cursor::new(d); // Parse frame type. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let frame_ty = stream.try_consume_varint().unwrap(); + let frame_ty = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_ty = stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_ty + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + + stream.try_consume_varint().unwrap() + }; assert_eq!(frame_ty, frame::PUSH_PROMISE_FRAME_TYPE_ID); stream.set_frame_type(frame_ty).unwrap(); assert_eq!(stream.state, State::FramePayloadLen); // Parse frame payload length. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let frame_payload_len = stream.try_consume_varint().unwrap(); + let frame_payload_len = + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_payload_len = + stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_payload_len + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + + stream.try_consume_varint().unwrap() + }; assert_eq!( Err(Error::FrameError), stream.set_frame_payload_len(frame_payload_len) @@ -1276,16 +2046,50 @@ mod tests { parse_skip_frame(&mut stream, &mut cursor).unwrap(); // Parse frame type. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let frame_ty = stream.try_consume_varint().unwrap(); + let frame_ty = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_ty = stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_ty + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + + stream.try_consume_varint().unwrap() + }; assert_eq!(frame_ty, frame::CANCEL_PUSH_FRAME_TYPE_ID); stream.set_frame_type(frame_ty).unwrap(); assert_eq!(stream.state, State::FramePayloadLen); // Parse frame payload length. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let frame_payload_len = stream.try_consume_varint().unwrap(); + let frame_payload_len = + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_payload_len = + stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_payload_len + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + + stream.try_consume_varint().unwrap() + }; assert_eq!( Err(Error::FrameError), stream.set_frame_payload_len(frame_payload_len) @@ -1324,16 +2128,50 @@ mod tests { parse_skip_frame(&mut stream, &mut cursor).unwrap(); // Parse frame type. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let frame_ty = stream.try_consume_varint().unwrap(); + let frame_ty = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_ty = stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_ty + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + + stream.try_consume_varint().unwrap() + }; assert_eq!(frame_ty, frame::MAX_PUSH_FRAME_TYPE_ID); stream.set_frame_type(frame_ty).unwrap(); assert_eq!(stream.state, State::FramePayloadLen); // Parse frame payload length. - stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); - let frame_payload_len = stream.try_consume_varint().unwrap(); + let frame_payload_len = + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let b = stream + .try_acquire_state_buffer_for_tests(&mut cursor) + .unwrap(); + + let frame_payload_len = + stream.try_consume_varint_from_buf(b).unwrap(); + assert!(stream + .mark_state_buffer_consumed_for_tests( + stream.get_state_len(), + &mut cursor + ) + .is_ok()); + frame_payload_len + } else { + stream.try_fill_buffer_for_tests(&mut cursor).unwrap(); + + stream.try_consume_varint().unwrap() + }; assert_eq!( Err(Error::FrameError), stream.set_frame_payload_len(frame_payload_len) diff --git a/quiche/src/lib.rs b/quiche/src/lib.rs index 32fa6297..74a7d117 100644 --- a/quiche/src/lib.rs +++ b/quiche/src/lib.rs @@ -42,7 +42,6 @@ //! //! ``` //! let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?; -//! config.set_application_protos(&[b"example-proto"]); //! //! // Additional configuration specific to application and use case... //! # Ok::<(), quiche::Error>(()) @@ -117,14 +116,15 @@ //! # let peer = "127.0.0.1:1234".parse().unwrap(); //! # let local = "127.0.0.1:4321".parse().unwrap(); //! # let mut conn = quiche::accept(&scid, None, local, peer, &mut config)?; -//! let to = socket.local_addr().unwrap(); +//! # let to = socket.local_addr().unwrap(); +//! # let mut app_buffers = quiche::AppRecvBufMap::new(3, 1024*1024*32, 100, 100); //! //! loop { //! let (read, from) = socket.recv_from(&mut buf).unwrap(); //! //! let recv_info = quiche::RecvInfo { from, to }; //! -//! let read = match conn.recv(&mut buf[..read], recv_info) { +//! let read = match conn.recv(&mut buf[..read], &mut app_buffers, recv_info) { //! Ok(v) => v, //! //! Err(quiche::Error::Done) => { @@ -417,17 +417,16 @@ use std::str::FromStr; use std::collections::HashSet; use std::collections::VecDeque; -use smallvec::SmallVec; use likely_stable::if_likely; - +use smallvec::SmallVec; /// The current QUIC wire version. pub const PROTOCOL_VERSION: u32 = PROTOCOL_VERSION_V3; /// Supported QUIC versions. -const PROTOCOL_VERSION_V1: u32 = 0x0000_0001; +pub const PROTOCOL_VERSION_V1: u32 = 0x0000_0001; /// QUIC version supporting Contiguous Zero-copy receiver. -const PROTOCOL_VERSION_V3: u32 = 0x0000_0003; +pub const PROTOCOL_VERSION_V3: u32 = 0x0000_0003; /// The maximum length of a connection ID. pub const MAX_CONN_ID_LEN: usize = crate::packet::MAX_CID_LEN as usize; @@ -440,8 +439,6 @@ const PAYLOAD_MIN_LEN: usize = 4; #[cfg(not(feature = "fuzzing"))] const PAYLOAD_MIN_LEN_V3: usize = 12; - - #[cfg(feature = "fuzzing")] // Due to the fact that in fuzzing mode we use a zero-length AEAD tag (which // would normally be 16 bytes), we need to adjust the minimum payload size to @@ -521,9 +518,14 @@ pub enum Error { /// The provided buffer is too short. BufferTooShort, - /// Protocol Reverso technique could read too much in reverse and throw this. + /// Protocol Reverso technique could read too much in reverse and throw + /// this. BufferProtocolError, + /// Trying to read a stream id for which the buffer has been collected. + /// You may have already read it to the end, or rather tell Quiche so. + AppRecvBufNotFound, + /// The provided packet cannot be parsed because its version is unknown. UnknownVersion, @@ -534,6 +536,11 @@ pub enum Error { /// The provided packet cannot be parsed. InvalidPacket, + /// V3 specific. The packet header contains an invalid offset. It is + /// possible some bits have been flipped on path. We should not even try + /// to decrypt the payload. + InvalidOffset, + /// The operation cannot be completed because the connection is in an /// invalid state. InvalidState, @@ -547,6 +554,14 @@ pub enum Error { /// The peer's transport params cannot be parsed. InvalidTransportParam, + /// V3 introduces a contiguous Zero-Copy stream_recv_v3() call. Calling the + /// previous stream_recv() when the connection is configured to use + /// PROTOCOL_VERSION_V3 should result to an InvalidAPICall error. This + /// is designed to properly enforce the migration. if the application + /// decides to use PROTOCOL_VERSION_V3. Calling stream_recv_v3() if + /// PROTOCOL_VERSION_V1 is used should result to the same error. + InvalidAPICall(&'static str), + /// A cryptographic operation failed. CryptoFail, @@ -651,7 +666,8 @@ impl std::convert::From for Error { fn from(_err: octets::BufferError) -> Self { match _err { octets::BufferError::BufferTooShortError => Error::BufferTooShort, - octets::BufferError::BufferProtocolError => Error::BufferProtocolError, + octets::BufferError::BufferProtocolError => + Error::BufferProtocolError, } } } @@ -1422,7 +1438,7 @@ pub struct Connection { expected_stream_id_len: usize, /// The length of the expected offset in the packet being sent - expected_offset_len: usize, + truncated_offset_len: usize, /// Whether this is a server-side connection. is_server: bool, @@ -1671,11 +1687,11 @@ pub fn version_is_supported(version: u32) -> bool { matches!(version, PROTOCOL_VERSION_V1 | PROTOCOL_VERSION_V3) } -/// Push frames to the output packet. Frames in $frames should already have their -/// wire_len() reserved. +/// Push frames to the output packet. Frames in $frames should already have +/// their wire_len() reserved. /// -/// Frames such as Stream, Crypto, etc. have already been written into the buffer -/// at their intended position. +/// Frames such as Stream, Crypto, etc. have already been written into the +/// buffer at their intended position. macro_rules! push_frames_to_pkt { ($out:expr, $frames:expr, $ver:expr) => {{ for frame in $frames.iter() { @@ -1722,7 +1738,6 @@ macro_rules! push_frame_to_vec { $cumul += wire_len; $frames.push($frame); - true } else { false @@ -1949,7 +1964,7 @@ impl Connection { expected_stream_id_len: 1, - expected_offset_len: 1, + truncated_offset_len: 1, derived_initial_secrets: false, @@ -2215,6 +2230,7 @@ impl Connection { /// # let peer = "127.0.0.1:1234".parse().unwrap(); /// # let local = socket.local_addr().unwrap(); /// # let mut conn = quiche::accept(&scid, None, local, peer, &mut config)?; + /// # let mut app_buffers = quiche::AppRecvBufMap::new(3, 1024*1024*32, 100, 100); /// loop { /// let (read, from) = socket.recv_from(&mut buf).unwrap(); /// @@ -2223,7 +2239,7 @@ impl Connection { /// to: local, /// }; /// - /// let read = match conn.recv(&mut buf[..read], recv_info) { + /// let read = match conn.recv(&mut buf[..read], &mut app_buffers, recv_info) { /// Ok(v) => v, /// /// Err(e) => { @@ -2234,7 +2250,10 @@ impl Connection { /// } /// # Ok::<(), quiche::Error>(()) /// ``` - pub fn recv(&mut self, buf: &mut [u8], info: RecvInfo) -> Result { + pub fn recv( + &mut self, buf: &mut [u8], app_buffers: &mut AppRecvBufMap, + info: RecvInfo, + ) -> Result { let len = buf.len(); if len == 0 { @@ -2279,6 +2298,7 @@ impl Connection { while left > 0 { let read = match self.recv_single( &mut buf[len - left..len], + app_buffers, &info, recv_pid, ) { @@ -2311,12 +2331,14 @@ impl Connection { // Even though the packet was previously "accepted", it // should be safe to forward the error, as it also comes // from the `recv()` method. - self.process_undecrypted_0rtt_packets()?; + self.process_undecrypted_0rtt_packets(app_buffers)?; Ok(done) } - fn process_undecrypted_0rtt_packets(&mut self) -> Result<()> { + fn process_undecrypted_0rtt_packets( + &mut self, app_buffers: &mut AppRecvBufMap, + ) -> Result<()> { // Process previously undecryptable 0-RTT packets if the decryption key // is now available. if self.pkt_num_spaces[packet::Epoch::Application] @@ -2325,7 +2347,7 @@ impl Connection { { while let Some((mut pkt, info)) = self.undecryptable_pkts.pop_front() { - if let Err(e) = self.recv(&mut pkt, info) { + if let Err(e) = self.recv(&mut pkt, app_buffers, info) { self.undecryptable_pkts.clear(); return Err(e); @@ -2374,9 +2396,11 @@ impl Connection { /// /// [`Done`]: enum.Error.html#variant.Done fn recv_single( - &mut self, buf: &mut [u8], info: &RecvInfo, recv_pid: Option, + &mut self, buf: &mut [u8], app_buffers: &mut AppRecvBufMap, + info: &RecvInfo, recv_pid: Option, ) -> Result { let now = time::Instant::now(); + let mut clean_on_dec_error = false; if buf.is_empty() { return Err(Error::Done); @@ -2575,7 +2599,6 @@ impl Connection { // ignore packets that don't match the connection's version. return Err(Error::Done); } - // Long header packets have an explicit payload length, but short // packets don't so just use the remaining capacity in the buffer. let payload_len = if hdr.ty == packet::Type::Short { @@ -2663,49 +2686,119 @@ impl Connection { let aead_tag_len = aead.alg().tag_len(); - packet::decrypt_hdr(&mut b, &mut hdr, aead, self.version).map_err(|e| { - drop_pkt_on_err(e, self.recv_count, self.is_server, &self.trace_id) - })?; + packet::decrypt_hdr(&mut b, &mut hdr, aead, self.version).map_err( + |e| { + drop_pkt_on_err( + e, + self.recv_count, + self.is_server, + &self.trace_id, + ) + }, + )?; - let pn = packet::decode_pkt_num( - self.pkt_num_spaces[epoch].largest_rx_pkt_num, - hdr.pkt_num, - hdr.pkt_num_len, - ); + let pn = if self.version == crate::PROTOCOL_VERSION_V3 { + packet::decode_pkt_num_v3( + self.pkt_num_spaces[epoch].largest_rx_pkt_num, + hdr.pkt_num, + hdr.pkt_num_len, + ) + } else { + packet::decode_pkt_num( + self.pkt_num_spaces[epoch].largest_rx_pkt_num, + hdr.pkt_num, + hdr.pkt_num_len, + ) + }; let pn_len = hdr.pkt_num_len; let mut enc_hdr_len = pn_len; - let offset = if_likely!{self.version == PROTOCOL_VERSION_V3 => { + let mut outbuf = if_likely! {self.version == PROTOCOL_VERSION_V3 => { // let's use this control flow to also add the true enc_hdr_len // on V3. enc_hdr_len += hdr.expected_stream_id_len; - enc_hdr_len += hdr.expected_offset_len; + enc_hdr_len += hdr.truncated_offset_len; // A stream_id 0 indicates no stream frame encrypted. if hdr.expected_stream_id > 0 { - let mut monotonic_offset = match - self.streams.get(hdr.expected_stream_id) { - Some(s) => s.get_monotonic_offset(), - None => 0, // This could have been touch by someone on the network. - // We should not create a stream now, and wait for valid - // decryption. - }; - monotonic_offset = packet::decode_pkt_offset(monotonic_offset, hdr.expected_offset, hdr.expected_offset_len); - monotonic_offset + match self.streams.get(hdr.expected_stream_id) { + Some(s) => { + let outbuf = app_buffers.get_or_create_stream_buffer(hdr.expected_stream_id)?; + let mut offset = s.recv.contiguous_off().saturating_sub(1); + offset = packet::decode_pkt_offset(offset, hdr.truncated_offset, hdr.truncated_offset_len); + trace!("Decoded offset={}", offset); + offset = outbuf.get_outbuf_offset(offset, payload_len-aead_tag_len, &s.recv).map_err(|e| { + // This could happen if the network flipped some bits in the QUIC + // header. + trace!( + "Dropping packet due to incorrect decoded offset {}, or due to a \ + buffer too short with capacity {}", offset, outbuf.outbuf.capacity(), + ); + drop_pkt_on_err(e, self.recv_count, self.is_server, &self.trace_id) + })?; + let oct_out = octets::OctetsMut::with_slice(&mut outbuf.get_mut()[offset as usize..]); + Some(oct_out) + }, + None => { + // This could have been touch by someone on the network. + // + // We should still create a buffer but we should clean it if the + // packet happens to be invalid. + let s = match self.streams.get_or_create( + hdr.expected_stream_id, + &self.local_transport_params, + &self.peer_transport_params, + false, + self.is_server, + self.version + ) { + Ok(v) => v, + Err(e) => { + trace!("Dropping packet due to stream creation issue {}", hdr.expected_stream_id); + return Err(drop_pkt_on_err(e, self.recv_count, self.is_server, &self.trace_id)); + }, + }; + let outbuf = app_buffers.get_or_create_stream_buffer(hdr.expected_stream_id)?; + let mut offset = s.recv.contiguous_off().saturating_sub(1); + offset = packet::decode_pkt_offset(offset, hdr.truncated_offset, hdr.truncated_offset_len); + offset = match outbuf.get_outbuf_offset(offset, payload_len-aead_tag_len, &s.recv) { + Ok(v) => v, + Err(e) => { + debug!( + "A new stream has been created for id {}, and the offset: {} is unexpected", + hdr.expected_stream_id, offset + ); + // This could happen if the network flipped some bits in the + // QUIC header. Let's clean the memory for that stream, and drop + // the packet. + self.streams.collect_on_recv_error(hdr.expected_stream_id); + app_buffers.collect(hdr.expected_stream_id); + return Err(drop_pkt_on_err(e, self.recv_count, self.is_server, &self.trace_id)); + } + }; + let oct_out = octets::OctetsMut::with_slice(&mut outbuf.get_mut()[offset as usize..]); + // We need to remember to collect buffer & stream in case the + // authentication of this packet fails. + clean_on_dec_error = true; + Some(oct_out) + }, + + } } else { - 0 + None } } else { - 0 + None }}; trace!( - "{} rx pkt {:?} len={} pn={} {}", + "{} rx pkt {:?} len={} pn={} pn_len={} {}", self.trace_id, hdr, payload_len, pn, + pn_len, AddrTupleFmt(info.from, info.to) ); @@ -2751,19 +2844,24 @@ impl Connection { } // update payload_len too, removing the QUIC AES-ECB header - let (mut payload, payload_len) = if_likely!{self.version == PROTOCOL_VERSION_V3 => { - packet::decrypt_pkt_v3( + let (mut payload, payload_len) = if_likely! {self.version == PROTOCOL_VERSION_V3 => { + match packet::decrypt_pkt_v3( &mut b, pn, enc_hdr_len, payload_len, - hdr.expected_stream_id, - offset, + outbuf.as_mut(), aead, - ) - .map_err(|e| { - drop_pkt_on_err(e, self.recv_count, self.is_server, &self.trace_id) - })? + ) { + Ok(v) => v, + Err(e) => { + if clean_on_dec_error { + app_buffers.collect(hdr.expected_stream_id); + self.streams.collect_on_recv_error(hdr.expected_stream_id); + } + return Err(drop_pkt_on_err(e, self.recv_count, self.is_server, &self.trace_id)); + } + } } else { packet::decrypt_pkt( &mut b, @@ -2778,8 +2876,7 @@ impl Connection { }}; if self.pkt_num_spaces[epoch].recv_pkt_num.contains(pn) { - - if_likely!{self.version == PROTOCOL_VERSION_V3 => { + if_likely! {self.version == PROTOCOL_VERSION_V3 => { // Rewind the appropriate buffer if the streamid != 0 self.streams.rewind_recv_buf(hdr.expected_stream_id, payload_len)?; }}; @@ -2802,7 +2899,7 @@ impl Connection { self.paths.get_active_path_id()? }; - // The key update is verified once a packet is successfully decrypted + // The key update is verified oce a packet is successfully decrypted // using the new keys. if let Some((open_next, seal_next)) = aead_next { if !self.pkt_num_spaces[epoch] @@ -2813,7 +2910,6 @@ impl Connection { // Peer has updated keys twice without awaiting confirmation. return Err(Error::KeyUpdate); } - trace!("{} key update verified", self.trace_id); let _ = self.pkt_num_spaces[epoch].crypto_seal.replace(seal_next); @@ -2909,7 +3005,7 @@ impl Connection { let mut probing = true; // Process packet payload. - if_likely!{ self.version == PROTOCOL_VERSION_V3 => { + if_likely! { self.version == PROTOCOL_VERSION_V3 => { //set the offset at the end let payload_start_offset = payload.off(); payload.skip(payload_len)?; @@ -2928,7 +3024,7 @@ impl Connection { probing = false; } - if let Err(e) = self.process_frame(frame, &hdr, recv_pid, epoch, now) + if let Err(e) = self.process_frame(frame, &hdr, &mut payload, recv_pid, epoch, now) { frame_processing_err = Some(e); break; @@ -2952,7 +3048,7 @@ impl Connection { probing = false; } - if let Err(e) = self.process_frame(frame, &hdr, recv_pid, epoch, now) + if let Err(e) = self.process_frame(frame, &hdr, &mut payload, recv_pid, epoch, now) { frame_processing_err = Some(e); break; @@ -3103,6 +3199,9 @@ impl Connection { if stream.is_complete() && !stream.is_readable() { let local = stream.local; self.streams.collect(stream_id, local); + if_likely! {self.version == crate::PROTOCOL_VERSION_V3 => { + app_buffers.collect(stream_id); + }}; } }, @@ -3120,13 +3219,15 @@ impl Connection { None => continue, }; - // Only collect the stream if it is complete and not // readable. If it is readable, it will get collected when // stream_recv() is used. if stream.is_complete() && !stream.is_readable() { let local = stream.local; self.streams.collect(stream_id, local); + if_likely! {self.version == crate::PROTOCOL_VERSION_V3 => { + app_buffers.collect(stream_id); + }}; } }, @@ -3423,7 +3524,7 @@ impl Connection { // // We simply fall-through to sending packets, which should // take care of terminating the connection as needed. - let _ = self.process_undecrypted_0rtt_packets(); + // let _ = self.process_undecrypted_0rtt_packets(); // There's no point in trying to send a packet if the Initial secrets // have not been derived yet, so return early. @@ -3546,8 +3647,7 @@ impl Connection { &mut self, out: &mut [u8], send_pid: usize, has_initial: bool, now: time::Instant, ) -> Result<(packet::Type, usize)> { - - let payload_min_len = if_likely!{self.version == PROTOCOL_VERSION_V3 => { + let payload_min_len = if_likely! {self.version == PROTOCOL_VERSION_V3 => { PAYLOAD_MIN_LEN_V3 } else { PAYLOAD_MIN_LEN @@ -3577,7 +3677,6 @@ impl Connection { let epoch = pkt_type.to_epoch()?; let pkt_space = &mut self.pkt_num_spaces[epoch]; - // Process lost frames. There might be several paths having lost frames. for (_, p) in self.paths.iter_mut() { for lost in p.recovery.lost[epoch].drain(..) { @@ -3676,7 +3775,6 @@ impl Connection { } } } - let is_app_limited = self.delivery_rate_check_if_app_limited(); let n_paths = self.paths.len(); let path = self.paths.get_mut(send_pid)?; @@ -3691,7 +3789,12 @@ impl Connection { }; let pn = pkt_space.next_pkt_num; - let pn_len = packet::pkt_num_len(pn)?; + let largest_acked_pkt = path.recovery.largest_acked_pkt[epoch]; + let pn_len = if_likely! { self.version == crate::PROTOCOL_VERSION_V3 => { + packet::pkt_num_len_v3(pn, largest_acked_pkt) + } else { + packet::pkt_num_len(pn, largest_acked_pkt) + }}; // The AEAD overhead at the current encryption level. let crypto_overhead = pkt_space.crypto_overhead().ok_or(Error::Done)?; @@ -3755,11 +3858,12 @@ impl Connection { // Calculate the space required for the packet, including the header // the payload length, the packet number and the AEAD overhead. // On V3: - // Assume 8 bytes overhead for the streamid and adjust "left" when - // we know. This may cause to trigger path.recovery.update_app_limited - // while we have just the right space left to send this packet. - // XXX Do we care? - let mut overhead = if_likely! {self.version == PROTOCOL_VERSION_V3 => { + // Assume 8 bytes overhead for the streamid and offset and adjust "left" + // when we know. This may cause to trigger + // path.recovery.update_app_limited while we have just the right + // space left to send this packet. we don't know the length of pn + // before + let mut overhead = if_likely! {self.version == PROTOCOL_VERSION_V3 => { b.off() + pn_len + crypto_overhead + 8 } else { b.off() + pn_len + crypto_overhead @@ -3817,27 +3921,20 @@ impl Connection { // We need to remember this in case we use Protocol Reverso let header_offset = b.off(); - // TODO open question: even encrypted, distinguishing dgrams from reliable QUIC - // packets becomes possible with DPI, as the AES-ECB mask isn't CPA-Secure. - // - // Note. It is already possible to observe and distinguish retransmissions, even - // if those are fresh re-encryption. - // Double check: The only point of doing AES-ECB and xoring - // it to this info is to make it bytewise uniformly random, and prevent ossification. - // Unpredictable header is not needed. - if_likely!{ self.version == PROTOCOL_VERSION_V3 => { - packet::encode_u64_num_and_nextelem_len(pn, 1, &mut b)?; + if_likely! { self.version == PROTOCOL_VERSION_V3 => { + packet::encode_pkt_num_v3(pn, pn_len, 1, &mut b)?; packet::encode_u64_num_and_nextelem_len(0, 1, &mut b)?; - packet::encode_offset_num(0, &mut b)?; + packet::encode_offset_num(0, 1, &mut b)?; } else { - packet::encode_pkt_num(pn, &mut b)?; + packet::encode_pkt_num(pn, pn_len, &mut b)?; }}; // We have encoded the quic header in b. let mut payload_offset = b.off(); - // Remember how much bytes should be added to buf from the control frames before adding the - // stream frame (in V3, we wait to know whether a Stream frame or Datagram frame is part - // of the packet before encoding control frames). + // Remember how much bytes should be added to buf from the control frames + // before adding the stream frame (in V3, we wait to know whether + // a Stream frame or Datagram frame is part of the packet before + // encoding control frames). let mut cumul = 0; let cwnd_available = @@ -3990,7 +4087,6 @@ impl Connection { let frame = frame::Frame::PathChallenge { data }; - //if push_frame_to_pkt!(b, frames, frame, left, self.version) { if push_frame_to_vec!(frames, frame, left, cumul) { // Let's notify the path once we know the packet size. challenge_data = Some(data); @@ -4060,7 +4156,7 @@ impl Connection { max: self.streams.max_streams_uni_next(), }; - //if push_frame_to_pkt!(b, frames, frame, left, self.version) { + // if push_frame_to_pkt!(b, frames, frame, left, self.version) { if push_frame_to_vec!(frames, frame, left, cumul) { self.streams.update_max_streams_uni(); @@ -4292,9 +4388,10 @@ impl Connection { { if let Some(max_dgram_payload) = max_dgram_len { while let Some(len) = self.dgram_send_queue.peek_front_len() { - // Ok, so we're trying to send a Datagram. V3's header overhead for Datagram is - // 2 bytes. We assumed it to be 8, we fix it now. - let hdr_off = if_likely!{self.version == PROTOCOL_VERSION_V3 => { + // Ok, so we're trying to send a Datagram. V3's header + // overhead for Datagram is 2 bytes. We + // assumed it to be 8, we fix it now. + let hdr_off = if_likely! {self.version == PROTOCOL_VERSION_V3 => { if !has_fixed_overhead { left += 6; has_fixed_overhead = true; @@ -4326,7 +4423,7 @@ impl Connection { // // Finally we go back and encode the frame // header with the now available information. - if_likely!{ self.version == PROTOCOL_VERSION_V3 => { + if_likely! { self.version == PROTOCOL_VERSION_V3 => { // Write stream data into the packet buffer; normally right // after the encrypted header. @@ -4369,11 +4466,15 @@ impl Connection { let frame = frame::Frame::DatagramHeader { length: len }; - // We always write data a the beginning the packet. - // If we use PROTOCOL_VERSION_V3, this can be leveraged to enable a - // zero-copy contiguous application buffer. If we don't use V3, - // it shouldn't matter where we put it in the packet. - if_likely!{self.version == PROTOCOL_VERSION_V3 => { + // We always write data a the beginning the + // packet. + // If we use PROTOCOL_VERSION_V3, this can be + // leveraged to enable a + // zero-copy contiguous application buffer. If we + // don't use V3, + // it shouldn't matter where we put it in the + // packet. + if_likely! {self.version == PROTOCOL_VERSION_V3 => { // we already know that left > frame.wire_len() let wire_len = frame.wire_len(); left -= wire_len; @@ -4401,7 +4502,8 @@ impl Connection { // This dgram frame will never fit. Let's purge it. self.dgram_send_queue.pop(); } else { - // Revert back the fixed overhead. We might try to send a Stream Frame. + // Revert back the fixed overhead. We might try to send a + // Stream Frame. if has_fixed_overhead { left -= 6; has_fixed_overhead = false; @@ -4419,8 +4521,9 @@ impl Connection { path.active() && !dgram_emitted { - let hdr_off = if_likely!{self.version == PROTOCOL_VERSION_V3 => { b.off() } else { - b.off() + cumul }}; + let hdr_off = if_likely! {self.version == PROTOCOL_VERSION_V3 => { b.off() } else { + b.off() + cumul }}; + let max_stream_window = self.streams.max_stream_window; while let Some(priority_key) = self.streams.peek_flushable() { let stream_id = priority_key.id; let stream = match self.streams.get_mut(stream_id) { @@ -4436,25 +4539,35 @@ impl Connection { }; let stream_off = stream.send.off_front(); + // let largest_off_acked = + // stream.send.ack_off(). + // saturating_sub(crate::stream::MAX_STREAM_WINDOW); + let largest_off_acked = + stream.send.ack_off().saturating_sub(max_stream_window); + trace!( + "stream_off: {}, Largest_acked-1:{}", + stream_off, + largest_off_acked + ); // if V3, we need to rewind a re-encode the QUIC header. // b.off is currently at payload_offset. - let fixed_overhead = if_likely!{ self.version == PROTOCOL_VERSION_V3 => { + let fixed_overhead = if_likely! { self.version == PROTOCOL_VERSION_V3 => { b.rewind(payload_offset-header_offset)?; self.expected_stream_id_len = packet::num_len_to_encode(stream_id) + 1; - packet::encode_u64_num_and_nextelem_len(pn, self.expected_stream_id_len, &mut b)?; - self.expected_offset_len = packet::offset_len_to_encode(u64::from(stream_off as u32))?; - packet::encode_u64_num_and_nextelem_len(stream_id, self.expected_offset_len, + packet::encode_pkt_num_v3(pn, pn_len, self.expected_stream_id_len, &mut b)?; + self.truncated_offset_len = packet::truncated_offset_len(stream_off, largest_off_acked); + packet::encode_u64_num_and_nextelem_len(stream_id, self.truncated_offset_len, &mut b)?; - packet::encode_offset_num(stream_off, &mut b)?; + packet::encode_offset_num(stream_off, self.truncated_offset_len, &mut b)?; payload_offset = b.off(); // adjust left that was computed based on a 8 bytes overhead - let fixed = match 8_usize.checked_sub(self.expected_stream_id_len+self.expected_offset_len) { + let fixed = match 8_usize.checked_sub(self.expected_stream_id_len+self.truncated_offset_len) { Some(v) => v, None => { - trace!("checked_sub underflow. expected_stream_id_len is {0}, expected_offset_len is {1}", - self.expected_stream_id_len, self.expected_offset_len); + trace!("checked_sub underflow. expected_stream_id_len is {0}, truncated_offset_len is {1}", + self.expected_stream_id_len, self.truncated_offset_len); // Should we panic? - 0 + panic!("this shouldn't happen"); } }; left += fixed; @@ -4476,7 +4589,6 @@ impl Connection { // Finally we go back and encode the frame header with the now // available information. - let hdr_len = 1 + // frame type octets::varint_len(stream_id) + // stream_id octets::varint_len(stream_off) + // offset @@ -4492,13 +4604,12 @@ impl Connection { has_fixed_overhead = false; } self.expected_stream_id_len = 1; - self.expected_offset_len = 1; + self.truncated_offset_len = 1; continue; }, }; - let (len, fin) = if_likely!{self.version == PROTOCOL_VERSION_V3 => { - + let (len, fin) = if_likely! {self.version == PROTOCOL_VERSION_V3 => { // Write stream data into the packet buffer; normally right after // the encrypted header. let (len, fin) = @@ -4554,7 +4665,7 @@ impl Connection { fin, }; - if_likely!{self.version == PROTOCOL_VERSION_V3 => { + if_likely! {self.version == PROTOCOL_VERSION_V3 => { // we already know that left > frame.wire_len() let wire_len = frame.wire_len(); left -= wire_len; @@ -4591,9 +4702,9 @@ impl Connection { // Create CRYPTO frame. if pkt_space.crypto_stream.is_flushable() && - left > frame::MAX_CRYPTO_OVERHEAD && - !is_closing && - path.active() + left > frame::MAX_CRYPTO_OVERHEAD && + !is_closing && + path.active() { let crypto_off = pkt_space.crypto_stream.send.off_front(); @@ -4614,8 +4725,9 @@ impl Connection { let hdr_len = 1 + // frame type octets::varint_len(crypto_off) + // offset 2; // length, always encode as 2-byte varint - //The overhead depends on whether or not we're going - //to include a stream frame in this packet. We assumed yes, but maybe we don't. + // The overhead depends on whether or not we're going + // to include a stream frame in this packet. We assumed yes, but maybe + // we don't. if_likely! {self.version == PROTOCOL_VERSION_V3 => { if !has_fixed_overhead { left += 6; @@ -4623,7 +4735,7 @@ impl Connection { } }}; if let Some(max_len) = left.checked_sub(hdr_len) { - let len = if_likely!{self.version == PROTOCOL_VERSION_V3 => { + let len = if_likely! {self.version == PROTOCOL_VERSION_V3 => { // located potentally after other control frames b.skip(cumul)?; let (len, _) = pkt_space @@ -4682,7 +4794,7 @@ impl Connection { } } - if_likely!{self.version == PROTOCOL_VERSION_V3 => { + if_likely! {self.version == PROTOCOL_VERSION_V3 => { // Todo check interplay with CWND availability if !has_fixed_overhead && left > 0 { // we only had 2 bytes of overhead for a 0 streamid and 0 offset @@ -4744,14 +4856,13 @@ impl Connection { } } - // Pad payload so that it's always at least 4 bytes if QUIC V1, or 12 bytes if QUIC V3. + // Pad payload so that it's always at least 4 bytes if QUIC V1, or 12 + // bytes if QUIC V3. if b.off() - payload_offset < payload_min_len { let payload_len = b.off() - payload_offset; - let len = payload_min_len- payload_len; + let len = payload_min_len - payload_len; - let frame = frame::Frame::Padding { - len, - }; + let frame = frame::Frame::Padding { len }; if payload_len + frame.wire_len() > left { // We need to bypass the cwnd restriction; or // we can't send this packed normally containing @@ -4768,23 +4879,25 @@ impl Connection { // Fill in payload length. if pkt_type != packet::Type::Short { - let len = if_likely!{self.version == crate::PROTOCOL_VERSION_V3 => { - pn_len + self.expected_stream_id_len + self.expected_offset_len + payload_len + crypto_overhead + let len = if_likely! {self.version == crate::PROTOCOL_VERSION_V3 => { + pn_len + self.expected_stream_id_len + self.truncated_offset_len + payload_len + crypto_overhead } else { pn_len + payload_len + crypto_overhead }}; - let (_, mut payload_with_len) = b.split_at(header_offset_for_length)?; + let (_, mut payload_with_len) = + b.split_at(header_offset_for_length)?; payload_with_len .put_varint_with_len(len as u64, PAYLOAD_LENGTH_LEN)?; } trace!( - "{} tx pkt {} len={} pn={} {}", + "{} tx pkt {} len={} pn={} pn_len={} {}", self.trace_id, hdr_trace.unwrap_or_default(), payload_len, pn, + pn_len, AddrTupleFmt(path.local_addr(), path.peer_addr()) ); @@ -4841,11 +4954,10 @@ impl Connection { }; let enc_hdr_len = if_likely! {self.version == crate::PROTOCOL_VERSION_V3 => { - pn_len + self.expected_stream_id_len + self.expected_offset_len + pn_len + self.expected_stream_id_len + self.truncated_offset_len } else { pn_len }}; - let written = packet::encrypt_pkt( &mut b, pn, @@ -4858,7 +4970,7 @@ impl Connection { )?; self.expected_stream_id_len = 1; - self.expected_offset_len = 1; + self.truncated_offset_len = 1; let sent_pkt = recovery::Sent { pkt_num: pn, @@ -4986,6 +5098,142 @@ impl Connection { .unwrap_or(0) } + /// Todo + #[inline] + pub fn stream_recv_v3<'b>( + &mut self, stream_id: u64, app_buffers: &'b mut AppRecvBufMap, + ) -> Result<(&'b [u8], usize, bool)> { + if self.version != PROTOCOL_VERSION_V3 { + return Err(Error::InvalidAPICall("This function should be called on a \ + PROTOCOL_VERSION_V3 connection version")); + } + + // We can't read on our own unidirectional streams. + if !stream::is_bidi(stream_id) && + stream::is_local(stream_id, self.is_server) + { + return Err(Error::InvalidStreamState(stream_id)); + } + + let stream = self + .streams + .get_mut(stream_id) + .ok_or(Error::InvalidStreamState(stream_id))?; + + if !stream.is_readable() && app_buffers.is_consumed(stream_id) { + return Err(Error::Done); + } + + let local = stream.local; + let priority_key = Arc::clone(&stream.priority_key); + + #[cfg(feature = "qlog")] + let offset = stream.recv.off_front(); + + if let Some(e) = stream.recv.has_error() { + // cleanup recv internals -- + // in fn stream_recv(), this is done by stream.recv.emit(). + stream.recv.heap.clear(); + stream.recv.deliver_fin = false; + if stream.is_complete() { + self.streams.collect(stream_id, local); + // TODO should we do that now or let the application decides? + // The application may still have data to read from a previous + // successful stream_recv_v3 call. + // + // The problem is that it isn't really intuitive to call + // stream_comsumed() on a stream_id that got a reset, but the + // application would have to do it to avoid a + // memory leak if we don't do it here. + app_buffers.collect(stream_id); + } + + self.streams.remove_readable(&priority_key); + return Err(Error::StreamReset(e)); + } + + // The stream is ready: we have a reference to some contiguous data + let outbuf = app_buffers.read_mut(stream_id, stream)?; + let read = outbuf.len(); + let fin = stream.recv.is_fin(); + + let almost_full = stream.recv.almost_full(); + + if !stream.is_readable() { + self.streams.remove_readable(&priority_key); + } + + if almost_full { + self.streams.insert_almost_full(stream_id); + } + + // TODO: we might actually want to change this event too? + qlog_with_type!(QLOG_DATA_MV, self.qlog, q, { + let ev_data = EventData::DataMoved(qlog::events::quic::DataMoved { + stream_id: Some(stream_id), + offset: Some(offset), + length: Some(read as u64), + from: Some(DataRecipient::Transport), + to: Some(DataRecipient::Application), + raw: None, + }); + + let now = time::Instant::now(); + q.add_event_data_with_instant(ev_data, now).ok(); + }); + + // if priority_key.incremental && readable && !complete { + //// Shuffle the incremental stream to the back of the queue. + // self.streams.remove_readable(&priority_key); + // self.streams.insert_readable(&priority_key); + //} + + Ok((outbuf, read, fin)) + } + + /// Todo + #[inline] + pub fn stream_consumed( + &mut self, stream_id: u64, consumed: usize, + app_buffers: &mut AppRecvBufMap, + ) -> Result<()> { + if self.version != PROTOCOL_VERSION_V3 { + return Err(Error::InvalidAPICall("This function should be called on a \ + PROTOCOL_VERSION_V3 connection version")); + } + + let stream = self.streams.get(stream_id); + + self.flow_control.add_consumed(consumed as u64); + + if self.should_update_max_data() { + self.almost_full = true; + } + + if app_buffers.has_consumed(stream_id, stream, consumed)? > 0 { + let priority_key = Arc::clone(&stream.unwrap().priority_key); + if priority_key.incremental { + self.streams.remove_readable(&priority_key); + self.streams.insert_readable(&priority_key); + } + } else if let Some(stream) = stream { + let local = stream.local; + if stream.is_complete() { + self.streams.collect(stream_id, local); + } else { + let priority_key = Arc::clone(&stream.priority_key); + if !stream.is_readable() { + self.streams.remove_readable(&priority_key); + } else if priority_key.incremental { + self.streams.remove_readable(&priority_key); + self.streams.insert_readable(&priority_key); + } + } + } + + Ok(()) + } + /// Reads contiguous data from a stream into the provided slice. /// /// The slice must be sized by the caller and will be populated up to its @@ -5019,6 +5267,11 @@ impl Connection { pub fn stream_recv( &mut self, stream_id: u64, out: &mut [u8], ) -> Result<(usize, bool)> { + if self.version == PROTOCOL_VERSION_V3 { + return Err(Error::InvalidAPICall("This function should not be called on a \ + PROTOCOL_VERSION_V3 connection version")); + } + // We can't read on our own unidirectional streams. if !stream::is_bidi(stream_id) && stream::is_local(stream_id, self.is_server) @@ -5380,6 +5633,11 @@ impl Connection { return Err(Error::InvalidStreamState(stream_id)); } + // Don't use stream_id 0 on v3 + if self.version == crate::PROTOCOL_VERSION_V3 && stream_id == 0 { + return Err(Error::InvalidStreamState(stream_id)); + } + // Get existing stream. let stream = self.streams.get_mut(stream_id).ok_or(Error::Done)?; @@ -5595,6 +5853,29 @@ impl Connection { Ok(false) } + /// Returns true if all the data has been consumed from the specified + /// stream. + /// + /// This instructs the application that all the data received from the + /// peer on the stream has been consumed, and there won't be anymore in the + /// future. + /// + /// Basically this returns true when the peer either set the `fin` flag + /// for the stream, or sent `RESET_STREAM`, and that all available data + /// was consumed by the application. + #[inline] + pub fn stream_finished_v3( + &self, stream_id: u64, app_buf: &mut AppRecvBufMap, + ) -> bool { + let stream = match self.streams.get(stream_id) { + Some(v) => v, + + None => return true, + }; + + stream.recv.is_fin() && app_buf.is_consumed(stream_id) + } + /// Returns true if all the data has been read from the specified stream. /// /// This instructs the application that all the data received from the @@ -6049,7 +6330,9 @@ impl Connection { // ...subtract the packet number (max len)... if self.version == crate::PROTOCOL_VERSION_V3 { // 1 byte for stream_id 0, and 1 bytes for offset 0. - max_len = max_len.saturating_sub(packet::MAX_PKT_NUM_LEN_STREAMID_OFFSET_LEN_FOR_DGRAM); + max_len = max_len.saturating_sub( + packet::MAX_PKT_NUM_LEN_STREAMID_OFFSET_LEN_FOR_DGRAM, + ); } else { max_len = max_len.saturating_sub(packet::MAX_PKT_NUM_LEN); } @@ -7197,13 +7480,15 @@ impl Connection { &self.peer_transport_params, local, self.is_server, + self.version, ) } /// Processes an incoming frame. fn process_frame( &mut self, frame: frame::Frame, hdr: &packet::Header, - recv_path_id: usize, epoch: packet::Epoch, now: time::Instant, + b: &mut octets::Octets, recv_path_id: usize, epoch: packet::Epoch, + now: time::Instant, ) -> Result<()> { trace!("{} rx frm {:?}", self.trace_id, frame); @@ -7369,7 +7654,8 @@ impl Connection { } // Push the data to the stream so it can be re-ordered. - // TODO Protocol Reverso: optimize away this buf allocation and 2 copies + // TODO Protocol Reverso: optimize away this buf allocation and 2 + // copies -- and enforce stream level integrity. self.pkt_num_spaces[epoch].crypto_stream.recv.write(data)?; // Feed crypto data to the TLS state, if there's data @@ -7396,6 +7682,115 @@ impl Connection { return Err(Error::InvalidPacket); }, + // TODO Fix code duplication between Stream and StreamV3 + frame::Frame::StreamV3 { + stream_id, + mut metadata, + } => { + // Peer can't send on our unidirectional streams. + if !stream::is_bidi(stream_id) && + stream::is_local(stream_id, self.is_server) + { + return Err(Error::InvalidStreamState(stream_id)); + } + + let max_rx_data_left = self.max_rx_data() - self.rx_data; + + // Get existing stream or create a new one, but if the stream + // has already been closed and collected, ignore the frame. + // + // This can happen if e.g. an ACK frame is lost, and the peer + // retransmits another frame before it realizes that the stream + // is gone. + // + // Note that it makes it impossible to check if the frame is + // illegal, since we have no state, but since we ignore the + // frame, it should be fine. + let stream = match self.get_or_create_stream(stream_id, false) { + Ok(v) => v, + + Err(Error::Done) => return Ok(()), + + Err(e) => return Err(e), + }; + + // Check for the connection-level flow control limit. + let max_off_delta = + metadata.max_off().saturating_sub(stream.recv.max_off()); + + if max_off_delta > max_rx_data_left { + return Err(Error::FlowControl); + } + + let was_readable = stream.is_readable(); + let priority_key = Arc::clone(&stream.priority_key); + + let was_draining = stream.recv.is_draining(); + + // Copy the frame data in case this frame is not received in + // order (i.e., the AppData preceeding it is not yet decrypted), + // because part of it (or all of it) could be + // overwritten by the trail of the QUIC packet + // containing a Stream frame with a offset lower than this one. + // + // There are ways to ensure we won't decrypt unordered data, + // meaning that this branch would not be taken, + // but this should require an overhaul of Quiche's API, + // and is out of scope of this work. However, this should be + // particularly important as soon as Multipath + // capacity are added, because multipath is causing out-of-order + // packets. + // + // In particular, we would need the stream & conn flow control to + // be moved to encrypted data layer instead. That + // is; we proceed the QUIC headers, reorder the + // packets by reference and decrypt *only* what we have in order. This is + // probably going to be one hell of a discussion + // if brought up to the QUIC working group, as it is + // making QUIC closer to a TCP/TLS1.3 userspace implementation; + // and even closer to TCPLS's abstraction. But + // common, this should have *huge* efficiency benefits. + // Note however that this assumes range overlap aren't authorized + // => Overlap prevents this optimization to work + // best. + // + if stream.recv.not_in_order(&metadata) { + let data = b.peek_bytes(metadata.len())?; + // This sucks since it copies; and should be avoided at all + // ("let's keep it flexible") cost. (see + // comments above). + trace!( + "Not in order: attaching a copy at offset {}", + metadata.off() + ); + metadata.attach_data(Vec::from(data.as_ref())); + } + // Maybe this packet allows previously unordered reception + // to be appended to the buffer, which would prevent a copy + // at the next QUIC packet processing. We should + // call AppRecvBufMap::read_mut() or make a similar function + // to do that here. + stream.recv.write_v3(metadata)?; + + if !was_readable && stream.is_readable() { + self.streams.insert_readable(&priority_key); + } + + self.rx_data += max_off_delta; + + if was_draining { + // When a stream is in draining state it will not queue + // incoming data for the application to read, so consider + // the received data as consumed, which might trigger a flow + // control update. + self.flow_control.add_consumed(max_off_delta); + + if self.should_update_max_data() { + self.almost_full = true; + } + } + }, + frame::Frame::Stream { stream_id, data } => { // Peer can't send on our unidirectional streams. if !stream::is_bidi(stream_id) && @@ -8067,6 +8462,11 @@ impl Connection { } self.closed = true; } + + /// Get this connection's version. + pub fn version(&self) -> u32 { + self.version + } } #[cfg(feature = "boringssl-boring-crate")] @@ -8103,7 +8503,7 @@ fn drop_pkt_on_err( if is_server && recv_count == 0 { return e; } - trace!("{} dropped invalid packet", trace_id); + trace!("{} dropped invalid packet with error {:?}", trace_id, e); // Ignore other invalid packets that haven't been authenticated to prevent // man-in-the-middle and man-on-the-side attacks. @@ -8631,6 +9031,8 @@ pub mod testing { pub struct Pipe { pub client: Connection, pub server: Connection, + pub client_app_buffers: AppRecvBufMap, + pub server_app_buffers: AppRecvBufMap, } impl Pipe { @@ -8671,6 +9073,17 @@ pub mod testing { let server_scid = ConnectionId::from_ref(&server_scid); let server_addr = Pipe::server_addr(); + let mut client_app_buffers = + AppRecvBufMap::new(3, stream::MAX_STREAM_WINDOW, 1000, 1000); + client_app_buffers + .set_expected_chunklen_to_consume(1000) + .unwrap(); + let mut server_app_buffers = + AppRecvBufMap::new(3, stream::MAX_STREAM_WINDOW, 1000, 1000); + server_app_buffers + .set_expected_chunklen_to_consume(1000) + .unwrap(); + Ok(Pipe { client: connect( Some("quic.tech"), @@ -8686,6 +9099,8 @@ pub mod testing { client_addr, config, )?, + client_app_buffers, + server_app_buffers, }) } @@ -8717,6 +9132,18 @@ pub mod testing { client_addr, config, )?, + client_app_buffers: AppRecvBufMap::new( + 3, + stream::MAX_STREAM_WINDOW, + 100, + 100, + ), + server_app_buffers: AppRecvBufMap::new( + 3, + stream::MAX_STREAM_WINDOW, + 100, + 100, + ), }) } @@ -8757,6 +9184,18 @@ pub mod testing { client_addr, &mut config, )?, + client_app_buffers: AppRecvBufMap::new( + 3, + stream::MAX_STREAM_WINDOW, + 100, + 100, + ), + server_app_buffers: AppRecvBufMap::new( + 3, + stream::MAX_STREAM_WINDOW, + 100, + 100, + ), }) } @@ -8795,6 +9234,18 @@ pub mod testing { client_addr, server_config, )?, + client_app_buffers: AppRecvBufMap::new( + 3, + stream::MAX_STREAM_WINDOW, + 100, + 100, + ), + server_app_buffers: AppRecvBufMap::new( + 3, + stream::MAX_STREAM_WINDOW, + 100, + 100, + ), }) } @@ -8826,16 +9277,36 @@ pub mod testing { client_addr, server_config, )?, + client_app_buffers: AppRecvBufMap::new( + 3, + stream::MAX_STREAM_WINDOW, + 100, + 100, + ), + server_app_buffers: AppRecvBufMap::new( + 3, + stream::MAX_STREAM_WINDOW, + 100, + 100, + ), }) } pub fn handshake(&mut self) -> Result<()> { while !self.client.is_established() || !self.server.is_established() { let flight = emit_flight(&mut self.client)?; - process_flight(&mut self.server, flight)?; + process_flight( + &mut self.server, + &mut self.server_app_buffers, + flight, + )?; let flight = emit_flight(&mut self.server)?; - process_flight(&mut self.client, flight)?; + process_flight( + &mut self.client, + &mut self.client_app_buffers, + flight, + )?; } Ok(()) @@ -8847,7 +9318,11 @@ pub mod testing { while !client_done || !server_done { match emit_flight(&mut self.client) { - Ok(flight) => process_flight(&mut self.server, flight)?, + Ok(flight) => process_flight( + &mut self.server, + &mut self.server_app_buffers, + flight, + )?, Err(Error::Done) => client_done = true, @@ -8855,7 +9330,11 @@ pub mod testing { }; match emit_flight(&mut self.server) { - Ok(flight) => process_flight(&mut self.client, flight)?, + Ok(flight) => process_flight( + &mut self.client, + &mut self.client_app_buffers, + flight, + )?, Err(Error::Done) => server_done = true, @@ -8873,7 +9352,7 @@ pub mod testing { from: server_path.local_addr(), }; - self.client.recv(buf, info) + self.client.recv(buf, &mut self.client_app_buffers, info) } pub fn server_recv(&mut self, buf: &mut [u8]) -> Result { @@ -8883,15 +9362,21 @@ pub mod testing { from: client_path.local_addr(), }; - self.server.recv(buf, info) + self.server.recv(buf, &mut self.server_app_buffers, info) } pub fn send_pkt_to_server( &mut self, pkt_type: packet::Type, frames: &[frame::Frame], - buf: &mut [u8], + buf: &mut [u8], stream_id: Option, ) -> Result { let written = encode_pkt(&mut self.client, pkt_type, frames, buf)?; - recv_send(&mut self.server, buf, written) + recv_send( + &mut self.server, + &mut self.server_app_buffers, + buf, + written, + stream_id, + ) } pub fn client_update_key(&mut self) -> Result<()> { @@ -8928,7 +9413,8 @@ pub mod testing { } pub fn recv_send( - conn: &mut Connection, buf: &mut [u8], len: usize, + conn: &mut Connection, app_buffers: &mut AppRecvBufMap, buf: &mut [u8], + len: usize, stream_id: Option, ) -> Result { let active_path = conn.paths.get_active()?; let info = RecvInfo { @@ -8936,31 +9422,46 @@ pub mod testing { from: active_path.peer_addr(), }; - conn.recv(&mut buf[..len], info)?; + conn.recv(&mut buf[..len], app_buffers, info)?; let mut off = 0; + match (stream_id, crate::PROTOCOL_VERSION) { + (Some(stream_id), crate::PROTOCOL_VERSION_V3) => { + // try to copy original behavior + let mut sendbuf = app_buffers + .get_mut(stream_id) + .unwrap_or(&mut buf[off..]) + .to_vec(); + match conn.send(&mut sendbuf) { + Ok((write, _)) => off += write, + + Err(Error::Done) => (), - match conn.send(&mut buf[off..]) { - Ok((write, _)) => off += write, + Err(e) => return Err(e), + } + }, + (..) => match conn.send(&mut buf[off..]) { + Ok((write, _)) => off += write, - Err(Error::Done) => (), + Err(Error::Done) => (), - Err(e) => return Err(e), + Err(e) => return Err(e), + }, } Ok(off) } pub fn process_flight( - conn: &mut Connection, flight: Vec<(Vec, SendInfo)>, + conn: &mut Connection, app_buffers: &mut AppRecvBufMap, + flight: Vec<(Vec, SendInfo)>, ) -> Result<()> { for (mut pkt, si) in flight { let info = RecvInfo { to: si.to, from: si.from, }; - - conn.recv(&mut pkt, info)?; + conn.recv(&mut pkt, app_buffers, info)?; } Ok(()) @@ -9058,40 +9559,41 @@ pub mod testing { }; if pkt_type != packet::Type::Short { - let len = hdr_enc_len + payload_len + space.crypto_overhead().unwrap(); + let len = + hdr_enc_len + payload_len + space.crypto_overhead().unwrap(); b.put_varint(len as u64)?; } if conn.version == PROTOCOL_VERSION_V3 { // We need to encode the streamid if any; and the offset - let (stream_id, offset) = match frames.iter().find(|frame| matches!(frame, frame::Frame::Stream { .. })) { - Some(frame::Frame::Stream { stream_id, ..}) => (*stream_id, 0), + let (stream_id, offset) = match frames + .iter() + .find(|frame| matches!(frame, frame::Frame::Stream { .. })) + { + Some(frame::Frame::Stream { stream_id, data }) => + (*stream_id, data.off()), _ => (0, 0), - }; - // 4 bytes pn, 4 bytes streamid and 4 bytes offset to not be bothered with - // padding. - // /!\ - // Note, this hacky function will only work if pn and stream_id are both <= 63 in the - // tests. - // - // TODO improve this instead of being lazy. - conn.expected_stream_id_len = 4; - packet::encode_u64_num_and_nextelem_len(0, 4, &mut b)?; - b.put_u24(pn as u32)?; - conn.expected_offset_len = 4; - packet::encode_u64_num_and_nextelem_len(0, 4, &mut b)?; - b.put_u24(stream_id as u32)?; - b.put_u32(offset as u32)?; - } - else { + }; + // 4 bytes pn, 4 bytes streamid and 4 bytes offset to not be bothered + // with padding. + // /!\ + // Note, this hacky function will only work if pn and stream_id are + // both <= 63 in the tests. + // + // TODO protocol_reverso: improve this instead of being lazy. + conn.expected_stream_id_len = 4; + packet::encode_u64_num_and_nextelem_len(0, 4, &mut b)?; + b.put_u24(pn as u32)?; + conn.truncated_offset_len = 4; + packet::encode_u64_num_and_nextelem_len(0, 4, &mut b)?; + b.put_u24(stream_id as u32)?; + b.put_u32(offset as u32)?; + } else { // Always encode packet number in 4 bytes, to allow encoding packets // with empty payloads. b.put_u32(pn as u32)?; }; - - - let payload_offset = b.off(); for frame in frames { frame.to_bytes(&mut b, conn.version)?; @@ -9119,7 +9621,7 @@ pub mod testing { } pub fn decode_pkt( - conn: &mut Connection, buf: &mut [u8], + conn: &mut Connection, buf: &mut [u8], app_buffers: &mut AppRecvBufMap, ) -> Result> { let mut b = octets::OctetsMut::with_slice(buf); @@ -9131,49 +9633,96 @@ pub mod testing { let payload_len = b.cap(); - packet::decrypt_hdr(&mut b, &mut hdr, aead, conn.version).unwrap(); - let pn = packet::decode_pkt_num( - conn.pkt_num_spaces[epoch].largest_rx_pkt_num, - hdr.pkt_num, - hdr.pkt_num_len, - ); + let pn = if conn.version == crate::PROTOCOL_VERSION_V3 { + packet::decode_pkt_num_v3( + conn.pkt_num_spaces[epoch].largest_rx_pkt_num, + hdr.pkt_num, + hdr.pkt_num_len, + ) + } else { + packet::decode_pkt_num( + conn.pkt_num_spaces[epoch].largest_rx_pkt_num, + hdr.pkt_num, + hdr.pkt_num_len, + ) + }; let pn_len = hdr.pkt_num_len; let mut enc_hdr_len = pn_len; - let offset = if_likely!{conn.version == PROTOCOL_VERSION_V3 => { + let mut outbuf = if_likely! {conn.version == PROTOCOL_VERSION_V3 => { // let's use this control flow to also add the true enc_hdr_len - // on V3 + // on V3. enc_hdr_len += hdr.expected_stream_id_len; - enc_hdr_len += hdr.expected_offset_len; + enc_hdr_len += hdr.truncated_offset_len; // A stream_id 0 indicates no stream frame encrypted. if hdr.expected_stream_id > 0 { - let mut monotonic_offset = match - conn.streams.get(hdr.expected_stream_id) { - Some(s) => s.get_monotonic_offset(), - None => 0, // This could have been touch by someone on the network. - // We should not create a stream now, and wait for valid - // decryption. - }; - monotonic_offset = packet::decode_pkt_offset(monotonic_offset, hdr.expected_offset, hdr.expected_offset_len); - monotonic_offset + match conn.streams.get(hdr.expected_stream_id) { + Some(s) => { + let outbuf = app_buffers.get_or_create_stream_buffer(hdr.expected_stream_id)?; + let mut offset = s.recv.contiguous_off().saturating_sub(1); + offset = packet::decode_pkt_offset(offset, hdr.truncated_offset, hdr.truncated_offset_len); + offset = outbuf.get_outbuf_offset(offset, payload_len-aead.alg().tag_len(), &s.recv) + .map_err(|e| { + // This could happen if the network flipped some bits in the + // header. Or in case of aggressive retransmission, lost ack, data + // duplication. + drop_pkt_on_err(e, conn.recv_count, conn.is_server, &conn.trace_id) + })?; + let oct_out = octets::OctetsMut::with_slice(&mut outbuf.get_mut()[offset as usize..]); + Some(oct_out) + } + None => { + // This could have been touch by someone on the network. + // We should not create a stream now, and wait for valid + // decryption. + let s = match conn.streams.get_or_create( + hdr.expected_stream_id, + &conn.local_transport_params, + &conn.peer_transport_params, + false, + conn.is_server, + conn.version + ) { + Ok(v) => v, + Err(e) => { + debug!("No stream {}", hdr.expected_stream_id); + return Err(drop_pkt_on_err(e, conn.recv_count, conn.is_server, &conn.trace_id)); + }, + }; + let outbuf = app_buffers.get_or_create_stream_buffer(hdr.expected_stream_id)?; + let mut offset = s.recv.contiguous_off().saturating_sub(1); + offset = packet::decode_pkt_offset(offset, hdr.truncated_offset, hdr.truncated_offset_len); + offset = match outbuf.get_outbuf_offset(offset, payload_len-aead.alg().tag_len(), &s.recv) { + Ok(v) => v, + Err(e) => { + // This could happen if the network flipped some bits in the + // header. + conn.streams.collect_on_recv_error(hdr.expected_stream_id); + app_buffers.collect(hdr.expected_stream_id); + return Err(drop_pkt_on_err(e, conn.recv_count, conn.is_server, &conn.trace_id)); + } + }; + let oct_out = octets::OctetsMut::with_slice(&mut outbuf.get_mut()[offset as usize..]); + Some(oct_out) + }, + } } else { - 0 + None } } else { - 0 + None }}; - let (mut payload, payload_len) = if_likely!{conn.version == PROTOCOL_VERSION_V3 => { + let (mut payload, payload_len) = if_likely! {conn.version == PROTOCOL_VERSION_V3 => { packet::decrypt_pkt_v3(&mut b, pn, enc_hdr_len, payload_len, - hdr.expected_stream_id, - offset, + outbuf.as_mut(), aead) .unwrap() } else { @@ -9182,7 +9731,7 @@ pub mod testing { }}; let mut frames = Vec::new(); - if_likely!{ conn.version == PROTOCOL_VERSION_V3 => { + if_likely! { conn.version == PROTOCOL_VERSION_V3 => { let payload_start_offset = payload.off(); payload.skip(payload_len)?; while payload.off() > payload_start_offset { @@ -9542,7 +10091,12 @@ mod tests { // Client sends initial flight. let flight = testing::emit_flight(&mut pipe.client).unwrap(); - testing::process_flight(&mut pipe.server, flight).unwrap(); + testing::process_flight( + &mut pipe.server, + &mut pipe.server_app_buffers, + flight, + ) + .unwrap(); // Server sends initial flight. let flight = testing::emit_flight(&mut pipe.server).unwrap(); @@ -9553,7 +10107,12 @@ mod tests { assert!(!pipe.server.is_established()); assert!(!pipe.server.handshake_confirmed); - testing::process_flight(&mut pipe.client, flight).unwrap(); + testing::process_flight( + &mut pipe.client, + &mut pipe.client_app_buffers, + flight, + ) + .unwrap(); // Client sends Handshake packet and completes handshake. let flight = testing::emit_flight(&mut pipe.client).unwrap(); @@ -9564,7 +10123,12 @@ mod tests { assert!(!pipe.server.is_established()); assert!(!pipe.server.handshake_confirmed); - testing::process_flight(&mut pipe.server, flight).unwrap(); + testing::process_flight( + &mut pipe.server, + &mut pipe.server_app_buffers, + flight, + ) + .unwrap(); // Server completes and confirms handshake, and sends HANDSHAKE_DONE. let flight = testing::emit_flight(&mut pipe.server).unwrap(); @@ -9575,7 +10139,12 @@ mod tests { assert!(pipe.server.is_established()); assert!(pipe.server.handshake_confirmed); - testing::process_flight(&mut pipe.client, flight).unwrap(); + testing::process_flight( + &mut pipe.client, + &mut pipe.client_app_buffers, + flight, + ) + .unwrap(); // Client acks 1-RTT packet, and confirms handshake. let flight = testing::emit_flight(&mut pipe.client).unwrap(); @@ -9586,7 +10155,12 @@ mod tests { assert!(pipe.server.is_established()); assert!(pipe.server.handshake_confirmed); - testing::process_flight(&mut pipe.server, flight).unwrap(); + testing::process_flight( + &mut pipe.server, + &mut pipe.server_app_buffers, + flight, + ) + .unwrap(); assert!(pipe.client.is_established()); assert!(pipe.client.handshake_confirmed); @@ -9735,7 +10309,7 @@ mod tests { }]; assert_eq!( - pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), Ok(1200) ); @@ -9747,8 +10321,21 @@ mod tests { assert_eq!(r.next(), None); let mut b = [0; 15]; - assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, true))); - assert_eq!(&b[..5], b"aaaaa"); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (b, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (5, true)); + assert_eq!(&b[..5], b"aaaaa"); + assert!(pipe + .server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .is_ok()); + } else { + assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, true))); + assert_eq!(&b[..5], b"aaaaa"); + } } #[cfg(not(feature = "openssl"))] // 0-RTT not supported when using openssl/quictls @@ -9819,8 +10406,17 @@ mod tests { assert_eq!(r.next(), None); let mut b = [0; 15]; - assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, true))); - assert_eq!(&b[..5], b"aaaaa"); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (b, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (5, true)); + assert_eq!(&b[..5], b"aaaaa"); + } else { + assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, true))); + assert_eq!(&b[..5], b"aaaaa"); + } } #[cfg(not(feature = "openssl"))] // 0-RTT not supported when using openssl/quictls @@ -9926,7 +10522,11 @@ mod tests { }; assert_eq!( - pipe.server.recv(&mut buf[..written], info), + pipe.server.recv( + &mut buf[..written], + &mut pipe.server_app_buffers, + info + ), Err(Error::CryptoBufferExceeded) ); @@ -9936,12 +10536,16 @@ mod tests { Err(_) => unreachable!(), }; - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..written]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..written], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { - iter.next(); //drop padding + iter.next(); // drop padding } assert_eq!( @@ -9971,7 +10575,12 @@ mod tests { let flight = testing::emit_flight(&mut pipe.client).unwrap(); let client_sent = flight.iter().fold(0, |out, p| out + p.0.len()); - testing::process_flight(&mut pipe.server, flight).unwrap(); + testing::process_flight( + &mut pipe.server, + &mut pipe.server_app_buffers, + flight, + ) + .unwrap(); let flight = testing::emit_flight(&mut pipe.server).unwrap(); let server_sent = flight.iter().fold(0, |out, p| out + p.0.len()); @@ -9994,13 +10603,243 @@ mod tests { assert_eq!(r.next(), None); let mut b = [0; 15]; - assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((12, true))); - assert_eq!(&b[..12], b"hello, world"); - + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (b, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (12, true)); + assert_eq!(&b[..12], b"hello, world"); + assert!(pipe + .server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .is_ok()); + } else { + assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((12, true))); + assert_eq!(&b[..12], b"hello, world"); + } assert!(pipe.server.stream_finished(4)); } #[cfg(not(feature = "openssl"))] // 0-RTT not supported when using openssl/quictls + #[test] + fn streamv3_partial_consume() { + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); + config + .load_cert_chain_from_pem_file("examples/cert.crt") + .unwrap(); + config + .load_priv_key_from_pem_file("examples/cert.key") + .unwrap(); + config + .set_application_protos(&[b"proto1", b"proto2"]) + .unwrap(); + config.set_initial_max_streams_bidi(3); + config.set_initial_max_stream_data_bidi_local(30); + config.set_initial_max_stream_data_bidi_remote(30); + config.set_initial_max_data(30); + let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); + assert_eq!(pipe.handshake(), Ok(())); + + assert_eq!( + pipe.client.stream_send(4, b"hello, world", false), + Ok(12) + ); + assert_eq!(pipe.advance(), Ok(())); + + assert!(!pipe.server.stream_finished(4)); + let mut r = pipe.server.readable(); + assert_eq!(r.next(), Some(4)); + assert_eq!(r.next(), None); + + let (b, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (12, false)); + assert_eq!(&b[..5], b"hello"); + assert!(pipe + .server + .stream_consumed(4, 5, &mut pipe.server_app_buffers) + .is_ok()); + // If we read again, the returned buffer should resume where it was + // consumed. + let (b, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (7, false)); + assert_eq!(&b[..7], b", world"); + // let's not consume them and wait for more data. + assert_eq!( + pipe.client.stream_send(4, b" and goodbye!", true), + Ok(13) + ); + assert_eq!(pipe.advance(), Ok(())); + + // Zero-copy recv of more stream data + let (b, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (20, true)); + assert_eq!(&b[..20], b", world and goodbye!"); + assert!(pipe + .server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .is_ok()); + assert!(pipe.server.stream_finished(4)); + assert!(pipe.server_app_buffers.is_consumed(4)); + } + } + + #[test] + fn streamv3_not_in_order() { + // Test whether unordered packets containing a Stream frame behave as + // expected. i.e., the first received packet is not in order; its + // data is copied internally into the library since the decryption + // of the next packets might override some of the app data. + // The 2 other packets arrive in order and no copy are involved. + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let mut buf = [0; 65535]; + let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); + config + .load_cert_chain_from_pem_file("examples/cert.crt") + .unwrap(); + config + .load_priv_key_from_pem_file("examples/cert.key") + .unwrap(); + config + .set_application_protos(&[b"proto1", b"proto2"]) + .unwrap(); + config.set_initial_max_streams_bidi(3); + config.set_initial_max_stream_data_bidi_local(30); + config.set_initial_max_stream_data_bidi_remote(30); + config.set_initial_max_data(30); + + let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); + assert_eq!(pipe.handshake(), Ok(())); + let frames = [ + frame::Frame::Stream { + stream_id: 4, + data: stream::RangeBuf::from(b"aaaaa", 0, false), + }, + frame::Frame::Stream { + stream_id: 4, + data: stream::RangeBuf::from(b"bbbbb", 5, false), + }, + frame::Frame::Stream { + stream_id: 4, + data: stream::RangeBuf::from(b"ccccc", 10, false), + }, + ]; + let pkt_type = packet::Type::Short; + + assert!(pipe + .send_pkt_to_server( + pkt_type, + &[frames[2].clone()], + &mut buf, + None + ) + .is_ok()); + // nothing to read yet on this new stream. + assert_eq!( + pipe.server.stream_recv_v3(4, &mut pipe.server_app_buffers), + Err(Error::Done) + ); + assert!(pipe + .send_pkt_to_server( + pkt_type, + &[frames[0].clone()], + &mut buf, + None + ) + .is_ok()); + let (b, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (5, false)); + assert_eq!(&b[..len], b"aaaaa"); + assert!(pipe + .send_pkt_to_server( + pkt_type, + &[frames[1].clone()], + &mut buf, + None + ) + .is_ok()); + let (b, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (15, false)); + assert_eq!(&b[..len], b"aaaaabbbbbccccc"); + assert!(pipe + .server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .is_ok()); + } + } + + #[test] + fn streamv3_large_chunks_send_recv() { + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let mut config = Config::new(crate::PROTOCOL_VERSION).unwrap(); + config + .load_cert_chain_from_pem_file("examples/cert.crt") + .unwrap(); + config + .load_priv_key_from_pem_file("examples/cert.key") + .unwrap(); + config + .set_application_protos(&[b"proto1", b"proto2"]) + .unwrap(); + config.set_initial_max_data(10 * 32 * 1024); + config.set_initial_max_streams_bidi(3); + config.set_initial_max_stream_data_bidi_local(10 * 32 * 1024); + config.set_initial_max_stream_data_bidi_remote(10 * 32 * 1024); + config.set_initial_max_streams_uni(10 * 32 * 1024); + config.set_initial_max_stream_data_uni(10 * 32 * 1024); + config.set_initial_max_data(10 * 32 * 1024); + + let datasize = 12000; + let sendbuf = [0; 12000]; + + let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); + assert_eq!(pipe.handshake(), Ok(())); + + for _ in 1..10 { + assert!(pipe.server.stream_send(1, &sendbuf, false).is_ok()); + assert_eq!(pipe.advance(), Ok(())); + + let (_, len, _) = pipe + .client + .stream_recv_v3(1, &mut pipe.client_app_buffers) + .unwrap(); + assert!(pipe + .client + .stream_consumed(1, len, &mut pipe.client_app_buffers) + .is_ok()); + } + + assert_eq!(pipe.server.stream_send(1, &sendbuf, true), Ok(datasize)); + assert_eq!(pipe.advance(), Ok(())); + + let (_, len, _) = pipe + .client + .stream_recv_v3(1, &mut pipe.client_app_buffers) + .unwrap(); + assert!(pipe + .client + .stream_consumed(1, len, &mut pipe.client_app_buffers) + .is_ok()); + assert!(pipe.client.stream_finished(1)); + } + } + #[test] fn zero_rtt() { let mut buf = [0; 65535]; @@ -10057,8 +10896,20 @@ mod tests { assert_eq!(r.next(), None); let mut b = [0; 15]; - assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((12, true))); - assert_eq!(&b[..12], b"hello, world"); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (b, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (12, true)); + assert_eq!(&b[..12], b"hello, world"); + pipe.server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((12, true))); + assert_eq!(&b[..12], b"hello, world"); + } } #[test] @@ -10107,32 +10958,69 @@ mod tests { let pkt_type = packet::Type::Short; if pipe.client.version == PROTOCOL_VERSION_V3 { - assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(48)); + assert_eq!( + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, Some(4)), + Ok(48) + ); } else { - assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(39)); + assert_eq!( + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, Some(4)), + Ok(39) + ); } let mut readable = pipe.server.readable(); assert_eq!(readable.next(), Some(4)); - assert_eq!(pipe.server.stream_recv(4, &mut buf), Ok((5, false))); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (5, false)); + assert_eq!( + pipe.server + .stream_consumed(4, len, &mut pipe.server_app_buffers), + Ok(()) + ); + } else { + assert_eq!(pipe.server.stream_recv(4, &mut buf), Ok((5, false))); + } let frames = [frame::Frame::Stream { stream_id: 4, data: stream::RangeBuf::from(b"", 5, true), }]; - let pkt_type = packet::Type::Short; if pipe.client.version == PROTOCOL_VERSION_V3 { - assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(48)); + assert_eq!( + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, Some(4)), + Ok(48) + ); } else { - assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(39)); + assert_eq!( + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, Some(4)), + Ok(39) + ); } let mut readable = pipe.server.readable(); assert_eq!(readable.next(), Some(4)); - assert_eq!(pipe.server.stream_recv(4, &mut buf), Ok((0, true))); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (0, true)); + assert_eq!( + pipe.server + .stream_consumed(4, len, &mut pipe.server_app_buffers), + Ok(()) + ); + } else { + assert_eq!(pipe.server.stream_recv(4, &mut buf), Ok((0, true))); + } let frames = [frame::Frame::Stream { stream_id: 4, @@ -10141,7 +11029,7 @@ mod tests { let pkt_type = packet::Type::Short; assert_eq!( - pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, Some(4)), Err(Error::FinalSize) ); } @@ -10163,8 +11051,22 @@ mod tests { let mut r = pipe.server.readable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); - assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, false))); - assert_eq!(&b[..5], b"hello"); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (b, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (5, false)); + assert_eq!(&b[..5], b"hello"); + assert_eq!( + pipe.server + .stream_consumed(4, len, &mut pipe.server_app_buffers), + Ok(()) + ); + } else { + assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, false))); + assert_eq!(&b[..5], b"hello"); + } // Ensure ACK for key update. assert!( @@ -10183,8 +11085,22 @@ mod tests { let mut r = pipe.client.readable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); - assert_eq!(pipe.client.stream_recv(4, &mut b), Ok((5, true))); - assert_eq!(&b[..5], b"world"); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (b, len, is_fin) = pipe + .client + .stream_recv_v3(4, &mut pipe.client_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (5, true)); + assert_eq!(&b[..5], b"world"); + assert_eq!( + pipe.client + .stream_consumed(4, len, &mut pipe.client_app_buffers), + Ok(()) + ); + } else { + assert_eq!(pipe.client.stream_recv(4, &mut b), Ok((5, true))); + assert_eq!(&b[..5], b"world"); + } } #[test] @@ -10195,17 +11111,26 @@ mod tests { assert_eq!(pipe.handshake(), Ok(())); assert_eq!(pipe.advance(), Ok(())); - let frames = [frame::Frame::Stream { - stream_id: 4, - data: stream::RangeBuf::from(b"hello", 0, false), - }]; + // On V3, sending twice the same offset would cause the second packet + // to be dropped before decryption; hence this test must use + // non-overlapping offset. + let frames = [ + frame::Frame::Stream { + stream_id: 4, + data: stream::RangeBuf::from(b"hello", 0, false), + }, + frame::Frame::Stream { + stream_id: 4, + data: stream::RangeBuf::from(b"hello", 5, false), + }, + ]; // Client sends stream frame with key update request. assert_eq!(pipe.client_update_key(), Ok(())); let written = testing::encode_pkt( &mut pipe.client, packet::Type::Short, - &frames, + &[frames[0].clone()], &mut buf, ) .unwrap(); @@ -10219,7 +11144,7 @@ mod tests { let written = testing::encode_pkt( &mut pipe.client, packet::Type::Short, - &frames, + &[frames[1].clone()], &mut buf, ) .unwrap(); @@ -10250,7 +11175,7 @@ mod tests { let pkt_type = packet::Type::Short; assert_eq!( - pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, Some(2)), Err(Error::InvalidStreamState(2)), ); } @@ -10265,7 +11190,7 @@ mod tests { // Send a packet with no frames. let pkt_type = packet::Type::Short; assert_eq!( - pipe.send_pkt_to_server(pkt_type, &[], &mut buf), + pipe.send_pkt_to_server(pkt_type, &[], &mut buf, None), Err(Error::InvalidPacket) ); } @@ -10293,8 +11218,7 @@ mod tests { if pipe.server.version == PROTOCOL_VERSION_V3 { // + 8 bytes * MAX_AMPLIFICATION_FACTOR for V3. assert_eq!(initial_path.max_send_bytes, 219); - } - else { + } else { assert_eq!(initial_path.max_send_bytes, 195); } @@ -10320,6 +11244,7 @@ mod tests { #[test] fn flow_control_limit() { + // TODO in V3, should we test this with 1 Stream Frame per packet instead? let mut buf = [0; 65535]; let mut pipe = testing::Pipe::new().unwrap(); @@ -10342,7 +11267,7 @@ mod tests { let pkt_type = packet::Type::Short; assert_eq!( - pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), Err(Error::FlowControl), ); } @@ -10357,12 +11282,12 @@ mod tests { let frames = [ // One byte less than stream limit. frame::Frame::Stream { - stream_id: 0, + stream_id: 4, data: stream::RangeBuf::from(b"aaaaaaaaaaaaaa", 0, false), }, // Same stream, but one byte more. frame::Frame::Stream { - stream_id: 0, + stream_id: 4, data: stream::RangeBuf::from(b"aaaaaaaaaaaaaaa", 0, false), }, frame::Frame::Stream { @@ -10372,7 +11297,36 @@ mod tests { ]; let pkt_type = packet::Type::Short; - assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert!(pipe + .send_pkt_to_server( + pkt_type, + &[frames[0].clone()], + &mut buf, + None + ) + .is_ok()); + assert!(pipe + .send_pkt_to_server( + pkt_type, + &[frames[1].clone()], + &mut buf, + None + ) + .is_ok()); + assert!(pipe + .send_pkt_to_server( + pkt_type, + &[frames[2].clone()], + &mut buf, + None + ) + .is_ok()); + } else { + assert!(pipe + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) + .is_ok()); + } } #[test] @@ -10384,21 +11338,56 @@ mod tests { let frames = [ frame::Frame::Stream { - stream_id: 0, + stream_id: 4, data: stream::RangeBuf::from(b"aaaaaaaaaaaaaaa", 0, false), }, frame::Frame::Stream { - stream_id: 4, + stream_id: 8, data: stream::RangeBuf::from(b"a", 0, false), }, ]; let pkt_type = packet::Type::Short; + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + // A single Stream Frame per packet on V3. + assert!(pipe + .send_pkt_to_server( + pkt_type, + &[frames[0].clone()], + &mut buf, + None + ) + .is_ok()); + assert!(pipe + .send_pkt_to_server( + pkt_type, + &[frames[1].clone()], + &mut buf, + None + ) + .is_ok()); - assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); - - pipe.server.stream_recv(0, &mut buf).unwrap(); - pipe.server.stream_recv(4, &mut buf).unwrap(); + let (_, len, _) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .unwrap(); + let (_, len, _) = pipe + .server + .stream_recv_v3(8, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(8, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + assert!(pipe + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) + .is_ok()); + pipe.server.stream_recv(4, &mut buf).unwrap(); + pipe.server.stream_recv(8, &mut buf).unwrap(); + } let frames = [frame::Frame::Stream { stream_id: 4, @@ -10406,29 +11395,31 @@ mod tests { }]; let len = pipe - .send_pkt_to_server(pkt_type, &frames, &mut buf) + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) .unwrap(); assert!(len > 0); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); if pipe.client.version == PROTOCOL_VERSION_V3 { - // Ignore padding + // Ignore ack iter.next().unwrap(); assert_eq!(iter.next(), Some(&frame::Frame::MaxData { max: 61 })); assert_eq!( iter.next(), Some(&frame::Frame::MaxStreamData { - stream_id: 0, + stream_id: 4, max: 30 }) ); - // Ignore ack - iter.next().unwrap(); } else { // Ignore ACK. iter.next().unwrap(); @@ -10436,7 +11427,7 @@ mod tests { assert_eq!( iter.next(), Some(&frame::Frame::MaxStreamData { - stream_id: 0, + stream_id: 4, max: 30 }) ); @@ -10492,7 +11483,7 @@ mod tests { let pkt_type = packet::Type::Short; assert_eq!( - pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), Err(Error::FlowControl), ); } @@ -10511,7 +11502,7 @@ mod tests { let pkt_type = packet::Type::Short; assert_eq!( - pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), Err(Error::FlowControl), ); } @@ -10530,9 +11521,21 @@ mod tests { let pkt_type = packet::Type::Short; - assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); + assert!(pipe + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) + .is_ok()); - pipe.server.stream_recv(4, &mut buf).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + pipe.server.stream_recv(4, &mut buf).unwrap(); + } let frames = [frame::Frame::Stream { stream_id: 4, @@ -10540,13 +11543,17 @@ mod tests { }]; let len = pipe - .send_pkt_to_server(pkt_type, &frames, &mut buf) + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) .unwrap(); assert!(len > 0); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); if pipe.client.version == PROTOCOL_VERSION_V3 { @@ -10586,7 +11593,9 @@ mod tests { let frames = [frame::Frame::MaxStreamsBidi { max: MAX_STREAM_ID }]; let pkt_type = packet::Type::Short; - assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); + assert!(pipe + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) + .is_ok()); assert_eq!(MAX_STREAM_ID - 3, pipe.server.peer_streams_left_bidi()); } @@ -10612,7 +11621,9 @@ mod tests { let frames = [frame::Frame::MaxStreamsUni { max: MAX_STREAM_ID }]; let pkt_type = packet::Type::Short; - assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); + assert!(pipe + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) + .is_ok()); assert_eq!(MAX_STREAM_ID - 3, pipe.server.peer_streams_left_uni()); } @@ -10657,7 +11668,7 @@ mod tests { let pkt_type = packet::Type::Short; assert_eq!( - pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), Err(Error::StreamLimit), ); } @@ -10672,7 +11683,9 @@ mod tests { let frames = [frame::Frame::MaxStreamsBidi { max: MAX_STREAM_ID }]; let pkt_type = packet::Type::Short; - assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); + assert!(pipe + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) + .is_ok()); let frames = [frame::Frame::MaxStreamsBidi { max: MAX_STREAM_ID + 1, @@ -10680,7 +11693,7 @@ mod tests { let pkt_type = packet::Type::Short; assert_eq!( - pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), Err(Error::InvalidFrame), ); } @@ -10725,7 +11738,7 @@ mod tests { let pkt_type = packet::Type::Short; assert_eq!( - pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), Err(Error::StreamLimit), ); } @@ -10740,7 +11753,9 @@ mod tests { let frames = [frame::Frame::MaxStreamsUni { max: MAX_STREAM_ID }]; let pkt_type = packet::Type::Short; - assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); + assert!(pipe + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) + .is_ok()); let frames = [frame::Frame::MaxStreamsUni { max: MAX_STREAM_ID + 1, @@ -10748,7 +11763,7 @@ mod tests { let pkt_type = packet::Type::Short; assert_eq!( - pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), Err(Error::InvalidFrame), ); } @@ -10763,39 +11778,53 @@ mod tests { assert_eq!(3, pipe.client.peer_streams_left_bidi()); assert_eq!(3, pipe.server.peer_streams_left_bidi()); - pipe.client.stream_send(0, b"a", false).ok(); + // in V3, bidirectional streams start at value 4. + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; + + pipe.client.stream_send(0 + off_by, b"a", false).ok(); assert_eq!(2, pipe.client.peer_streams_left_bidi()); - pipe.client.stream_send(4, b"a", false).ok(); + pipe.client.stream_send(4 + off_by, b"a", false).ok(); assert_eq!(1, pipe.client.peer_streams_left_bidi()); - pipe.client.stream_send(8, b"a", false).ok(); + pipe.client.stream_send(8 + off_by, b"a", false).ok(); assert_eq!(0, pipe.client.peer_streams_left_bidi()); // Client resets the stream. pipe.client - .stream_shutdown(0, Shutdown::Write, 1001) + .stream_shutdown(0 + off_by, Shutdown::Write, 1001) .unwrap(); pipe.advance().unwrap(); assert_eq!(0, pipe.client.peer_streams_left_bidi()); let mut r = pipe.server.readable(); - assert_eq!(Some(0), r.next()); - assert_eq!(Some(4), r.next()); - assert_eq!(Some(8), r.next()); + assert_eq!(Some(0 + off_by), r.next()); + assert_eq!(Some(4 + off_by), r.next()); + assert_eq!(Some(8 + off_by), r.next()); assert_eq!(None, r.next()); - assert_eq!( - pipe.server.stream_recv(0, &mut buf), - Err(Error::StreamReset(1001)) - ); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + pipe.server.stream_recv_v3(4, &mut pipe.server_app_buffers), + Err(Error::StreamReset(1001)) + ); + } else { + assert_eq!( + pipe.server.stream_recv(0, &mut buf), + Err(Error::StreamReset(1001)) + ); + } let mut r = pipe.server.readable(); - assert_eq!(Some(4), r.next()); - assert_eq!(Some(8), r.next()); + assert_eq!(Some(4 + off_by), r.next()); + assert_eq!(Some(8 + off_by), r.next()); assert_eq!(None, r.next()); // Server resets the stream in reaction. pipe.server - .stream_shutdown(0, Shutdown::Write, 1001) + .stream_shutdown(0 + off_by, Shutdown::Write, 1001) .unwrap(); pipe.advance().unwrap(); @@ -10803,36 +11832,46 @@ mod tests { // Repeat for the other 2 streams pipe.client - .stream_shutdown(4, Shutdown::Write, 1001) + .stream_shutdown(4 + off_by, Shutdown::Write, 1001) .unwrap(); pipe.client - .stream_shutdown(8, Shutdown::Write, 1001) + .stream_shutdown(8 + off_by, Shutdown::Write, 1001) .unwrap(); pipe.advance().unwrap(); let mut r = pipe.server.readable(); - assert_eq!(Some(4), r.next()); - assert_eq!(Some(8), r.next()); - assert_eq!(None, r.next()); - - assert_eq!( - pipe.server.stream_recv(4, &mut buf), - Err(Error::StreamReset(1001)) - ); - - assert_eq!( - pipe.server.stream_recv(8, &mut buf), - Err(Error::StreamReset(1001)) - ); - - let mut r = pipe.server.readable(); + assert_eq!(Some(4 + off_by), r.next()); + assert_eq!(Some(8 + off_by), r.next()); assert_eq!(None, r.next()); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + pipe.server.stream_recv_v3(8, &mut pipe.server_app_buffers), + Err(Error::StreamReset(1001)) + ); + assert_eq!( + pipe.server.stream_recv_v3(12, &mut pipe.server_app_buffers), + Err(Error::StreamReset(1001)) + ); + } else { + assert_eq!( + pipe.server.stream_recv(4, &mut buf), + Err(Error::StreamReset(1001)) + ); + assert_eq!( + pipe.server.stream_recv(8, &mut buf), + Err(Error::StreamReset(1001)) + ); + } + + let mut r = pipe.server.readable(); + assert_eq!(None, r.next()); + + pipe.server + .stream_shutdown(4 + off_by, Shutdown::Write, 1001) + .unwrap(); pipe.server - .stream_shutdown(4, Shutdown::Write, 1001) - .unwrap(); - pipe.server - .stream_shutdown(8, Shutdown::Write, 1001) + .stream_shutdown(8 + off_by, Shutdown::Write, 1001) .unwrap(); pipe.advance().unwrap(); @@ -10843,11 +11882,16 @@ mod tests { fn stream_reset_counts() { let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; - pipe.client.stream_send(0, b"a", false).ok(); + pipe.client.stream_send(0 + off_by, b"a", false).ok(); pipe.client.stream_send(2, b"a", false).ok(); - pipe.client.stream_send(4, b"a", false).ok(); - pipe.client.stream_send(8, b"a", false).ok(); + pipe.client.stream_send(4 + off_by, b"a", false).ok(); + pipe.client.stream_send(8 + off_by, b"a", false).ok(); pipe.advance().unwrap(); let stats = pipe.client.stats(); @@ -10855,7 +11899,7 @@ mod tests { // Client resets the stream. pipe.client - .stream_shutdown(0, Shutdown::Write, 1001) + .stream_shutdown(0 + off_by, Shutdown::Write, 1001) .unwrap(); pipe.advance().unwrap(); @@ -10868,7 +11912,7 @@ mod tests { // Server resets the stream in reaction. pipe.server - .stream_shutdown(0, Shutdown::Write, 1001) + .stream_shutdown(0 + off_by, Shutdown::Write, 1001) .unwrap(); pipe.advance().unwrap(); @@ -10884,18 +11928,18 @@ mod tests { .stream_shutdown(2, Shutdown::Write, 1001) .unwrap(); pipe.client - .stream_shutdown(4, Shutdown::Write, 1001) + .stream_shutdown(4 + off_by, Shutdown::Write, 1001) .unwrap(); pipe.client - .stream_shutdown(8, Shutdown::Write, 1001) + .stream_shutdown(8 + off_by, Shutdown::Write, 1001) .unwrap(); pipe.advance().unwrap(); pipe.server - .stream_shutdown(4, Shutdown::Write, 1001) + .stream_shutdown(4 + off_by, Shutdown::Write, 1001) .unwrap(); pipe.server - .stream_shutdown(8, Shutdown::Write, 1001) + .stream_shutdown(8 + off_by, Shutdown::Write, 1001) .unwrap(); pipe.advance().unwrap(); @@ -10911,11 +11955,16 @@ mod tests { fn stream_stop_counts() { let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; - pipe.client.stream_send(0, b"a", false).ok(); + pipe.client.stream_send(0 + off_by, b"a", false).ok(); pipe.client.stream_send(2, b"a", false).ok(); - pipe.client.stream_send(4, b"a", false).ok(); - pipe.client.stream_send(8, b"a", false).ok(); + pipe.client.stream_send(4 + off_by, b"a", false).ok(); + pipe.client.stream_send(8 + off_by, b"a", false).ok(); pipe.advance().unwrap(); let stats = pipe.client.stats(); @@ -10923,7 +11972,7 @@ mod tests { // Server stops the stream and client automatically resets. pipe.server - .stream_shutdown(0, Shutdown::Read, 1001) + .stream_shutdown(0 + off_by, Shutdown::Read, 1001) .unwrap(); pipe.advance().unwrap(); @@ -10944,10 +11993,10 @@ mod tests { .stream_shutdown(2, Shutdown::Read, 1001) .unwrap(); pipe.server - .stream_shutdown(4, Shutdown::Read, 1001) + .stream_shutdown(4 + off_by, Shutdown::Read, 1001) .unwrap(); pipe.server - .stream_shutdown(8, Shutdown::Read, 1001) + .stream_shutdown(8 + off_by, Shutdown::Read, 1001) .unwrap(); pipe.advance().unwrap(); @@ -10976,7 +12025,9 @@ mod tests { }]; let pkt_type = packet::Type::Short; - assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); + assert!(pipe + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) + .is_ok()); let frames = [frame::Frame::StreamsBlockedBidi { limit: MAX_STREAM_ID + 1, @@ -10984,7 +12035,7 @@ mod tests { let pkt_type = packet::Type::Short; assert_eq!( - pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), Err(Error::InvalidFrame), ); } @@ -11001,7 +12052,9 @@ mod tests { }]; let pkt_type = packet::Type::Short; - assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); + assert!(pipe + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) + .is_ok()); let frames = [frame::Frame::StreamsBlockedUni { limit: MAX_STREAM_ID + 1, @@ -11009,7 +12062,7 @@ mod tests { let pkt_type = packet::Type::Short; assert_eq!( - pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), Err(Error::InvalidFrame), ); } @@ -11023,34 +12076,93 @@ mod tests { let frames = [ frame::Frame::Stream { - stream_id: 0, + stream_id: 4, data: stream::RangeBuf::from(b"aaaaa", 0, false), }, frame::Frame::Stream { - stream_id: 0, + stream_id: 4, data: stream::RangeBuf::from(b"bbbbb", 3, false), }, frame::Frame::Stream { - stream_id: 0, + stream_id: 4, data: stream::RangeBuf::from(b"ccccc", 6, false), }, ]; let pkt_type = packet::Type::Short; - assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + // One stream frame per packet incentivized in V3. + assert!(pipe + .send_pkt_to_server( + pkt_type, + &[frames[0].clone()], + &mut buf, + None + ) + .is_ok()); + assert!(pipe + .send_pkt_to_server( + pkt_type, + &[frames[1].clone()], + &mut buf, + None + ) + .is_ok()); + assert!(pipe + .send_pkt_to_server( + pkt_type, + &[frames[2].clone()], + &mut buf, + None + ) + .is_ok()); + } else { + assert!(pipe + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) + .is_ok()); + } let mut b = [0; 15]; - assert_eq!(pipe.server.stream_recv(0, &mut b), Ok((11, false))); - // TODO: ask whether this overlap logic is correct. As currently written in - // stream::RangeBuf::write(), the resulting emited buffer depends in which order frames are - // received, and should therefore be not deterministic if overlapping frames are sent - // within different packets. We should probably better treat this as a protocol violation. - if pipe.client.version == PROTOCOL_VERSION_V3 { - // Stream frame are read from right to left in V3, - // and order matters for the overlap logic. - assert_eq!(&b[..11], b"aaabbbccccc"); - } - else { + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (b, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (5, false)); + // Open question: As currently written in stream::RangeBuf::write() + // (and QUIC's spec), the resulting emited buffer depends + // in which order frames are received, and should + // therefore be not deterministic if overlapping frames are sent + // within different packets. We should probably better + // treat this as a protocol violation in case the overwritten + // data is different? This behavior can probably lead to nasty + // security issues. Stream frame are read from right to + // left in V3, and order matters for the overlap logic. + assert_eq!(&b[..5], b"aaaaa"); + assert!(pipe + .server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .is_ok()); + let frames = [frame::Frame::Stream { + stream_id: 4, + data: stream::RangeBuf::from(b"b", 5, false), + }]; + // we re-send the wrong frame but with the correct offset :) + assert!(pipe + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) + .is_ok()); + let (b, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (6, false)); + assert_eq!(&b[..6], b"bccccc"); + assert!(pipe + .server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .is_ok()); + } else { + assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((11, false))); assert_eq!(&b[..11], b"aaaaabbbccc"); } } @@ -11064,30 +12176,68 @@ mod tests { let frames = [ frame::Frame::Stream { - stream_id: 0, + stream_id: 4, data: stream::RangeBuf::from(b"aaaaa", 0, false), }, frame::Frame::Stream { - stream_id: 0, + stream_id: 4, data: stream::RangeBuf::from(b"ccccc", 6, false), }, frame::Frame::Stream { - stream_id: 0, + stream_id: 4, data: stream::RangeBuf::from(b"bbbbb", 3, false), }, ]; let pkt_type = packet::Type::Short; - assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok()); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + // One stream frame per packet incentivized in V3. + assert!(pipe + .send_pkt_to_server( + pkt_type, + &[frames[0].clone()], + &mut buf, + None + ) + .is_ok()); + assert!(pipe + .send_pkt_to_server( + pkt_type, + &[frames[1].clone()], + &mut buf, + None + ) + .is_ok()); + assert!(pipe + .send_pkt_to_server( + pkt_type, + &[frames[2].clone()], + &mut buf, + None + ) + .is_ok()); + } else { + assert!(pipe + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) + .is_ok()); + } let mut b = [0; 15]; - assert_eq!(pipe.server.stream_recv(0, &mut b), Ok((11, false))); if pipe.client.version == PROTOCOL_VERSION_V3 { + let (b, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (5, false)); // Stream frame are read from right to left in V3, - // and order matters for the overlap logic. - assert_eq!(&b[..11], b"aaabbbbbccc"); - } - else { + // and we do not accept overlaps for perf reasons. + assert_eq!(&b[..5], b"aaaaa"); + assert!(pipe + .server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .is_ok()); + } else { + assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((11, false))); assert_eq!(&b[..11], b"aaaaabccccc"); } } @@ -11103,59 +12253,95 @@ mod tests { assert_eq!(pipe.handshake(), Ok(())); // Client sends some data. - assert_eq!(pipe.client.stream_send(0, b"hello", false), Ok(5)); + assert_eq!(pipe.client.stream_send(4, b"hello", false), Ok(5)); assert_eq!(pipe.advance(), Ok(())); // Server gets data and sends data back, closing stream. let mut r = pipe.server.readable(); - assert_eq!(r.next(), Some(0)); + assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); - assert_eq!(pipe.server.stream_recv(0, &mut b), Ok((5, false))); - assert!(!pipe.server.stream_finished(0)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (5, false)); + assert!(pipe + .server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .is_ok()); + } else { + assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, false))); + } + assert!(!pipe.server.stream_finished(4)); let mut r = pipe.server.readable(); assert_eq!(r.next(), None); - assert_eq!(pipe.server.stream_send(0, b"", true), Ok(0)); + assert_eq!(pipe.server.stream_send(4, b"", true), Ok(0)); assert_eq!(pipe.advance(), Ok(())); let mut r = pipe.client.readable(); - assert_eq!(r.next(), Some(0)); + assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); - assert_eq!(pipe.client.stream_recv(0, &mut b), Ok((0, true))); - assert!(pipe.client.stream_finished(0)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, is_fin) = pipe + .client + .stream_recv_v3(4, &mut pipe.client_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (0, true)); + assert!(pipe + .client + .stream_consumed(4, len, &mut pipe.client_app_buffers) + .is_ok()); + } else { + assert_eq!(pipe.client.stream_recv(4, &mut b), Ok((0, true))); + } + assert!(pipe.client.stream_finished(4)); // Client sends RESET_STREAM, closing stream. let frames = [frame::Frame::ResetStream { - stream_id: 0, + stream_id: 4, error_code: 42, final_size: 5, }]; let pkt_type = packet::Type::Short; if pipe.client.version == PROTOCOL_VERSION_V3 { - assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(48)); - } - else { - assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(39)); + assert_eq!( + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), + Ok(48) + ); + } else { + assert_eq!( + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), + Ok(39) + ); } // Server is notified of stream readability, due to reset. let mut r = pipe.server.readable(); - assert_eq!(r.next(), Some(0)); + assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); - assert_eq!( - pipe.server.stream_recv(0, &mut b), - Err(Error::StreamReset(42)) - ); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + pipe.server.stream_recv_v3(4, &mut pipe.server_app_buffers), + Err(Error::StreamReset(42)) + ); + } else { + assert_eq!( + pipe.server.stream_recv(4, &mut b), + Err(Error::StreamReset(42)) + ); + } - assert!(pipe.server.stream_finished(0)); + assert!(pipe.server.stream_finished(4)); // Sending RESET_STREAM again shouldn't make stream readable again. - pipe.send_pkt_to_server(pkt_type, &frames, &mut buf) + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None) .unwrap(); let mut r = pipe.server.readable(); @@ -11173,61 +12359,105 @@ mod tests { assert_eq!(pipe.handshake(), Ok(())); // Client sends some data. - assert_eq!(pipe.client.stream_send(0, b"h", false), Ok(1)); + assert_eq!(pipe.client.stream_send(4, b"h", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); // Server gets data and sends data back, closing stream. let mut r = pipe.server.readable(); - assert_eq!(r.next(), Some(0)); + assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); - - assert_eq!(pipe.server.stream_recv(0, &mut b), Ok((1, false))); - assert!(!pipe.server.stream_finished(0)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (1, false)); + assert!(pipe + .server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .is_ok()); + } else { + assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((1, false))); + } + assert!(!pipe.server.stream_finished(4)); let mut r = pipe.server.readable(); assert_eq!(r.next(), None); - assert_eq!(pipe.server.stream_send(0, b"", true), Ok(0)); + assert_eq!(pipe.server.stream_send(4, b"", true), Ok(0)); assert_eq!(pipe.advance(), Ok(())); let mut r = pipe.client.readable(); - assert_eq!(r.next(), Some(0)); + assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); - assert_eq!(pipe.client.stream_recv(0, &mut b), Ok((0, true))); - assert!(pipe.client.stream_finished(0)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, is_fin) = pipe + .client + .stream_recv_v3(4, &mut pipe.client_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (0, true)); + assert!(pipe + .client + .stream_consumed(4, len, &mut pipe.client_app_buffers) + .is_ok()); + } else { + assert_eq!(pipe.client.stream_recv(4, &mut b), Ok((0, true))); + } + assert!(pipe.client.stream_finished(4)); // Client sends RESET_STREAM, closing stream. let frames = [frame::Frame::ResetStream { - stream_id: 0, + stream_id: 4, error_code: 42, final_size: 5, }]; let pkt_type = packet::Type::Short; if pipe.client.version == PROTOCOL_VERSION_V3 { - assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(48)); + assert_eq!( + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), + Ok(48) + ); } else { - assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(39)); + assert_eq!( + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), + Ok(39) + ); } // Server is notified of stream readability, due to reset. let mut r = pipe.server.readable(); - assert_eq!(r.next(), Some(0)); + assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); - assert_eq!( - pipe.server.stream_recv(0, &mut b), - Err(Error::StreamReset(42)) - ); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + pipe.server.stream_recv_v3(4, &mut pipe.server_app_buffers), + Err(Error::StreamReset(42)) + ); + } else { + assert_eq!( + pipe.server.stream_recv(4, &mut b), + Err(Error::StreamReset(42)) + ); + } - assert!(pipe.server.stream_finished(0)); + assert!(pipe.server.stream_finished(4)); // Sending RESET_STREAM again shouldn't make stream readable again. if pipe.client.version == PROTOCOL_VERSION_V3 { - assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(48)); + assert_eq!( + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), + Ok(48) + ); } else { - assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(39)); + // There is 2 more bytes for the MAX_STREAM_BIDI Frame since we're + // using Stream_id 4. + assert_eq!( + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), + Ok(41) + ); } let mut r = pipe.server.readable(); @@ -11265,7 +12495,7 @@ mod tests { let pkt_type = packet::Type::Short; assert_eq!( - pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), Err(Error::FlowControl), ); } @@ -11293,7 +12523,7 @@ mod tests { let pkt_type = packet::Type::Short; assert_eq!( - pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), Err(Error::FlowControl), ); } @@ -11310,20 +12540,24 @@ mod tests { let pkt_type = packet::Type::Short; let len = pipe - .send_pkt_to_server(pkt_type, &frames, &mut buf) + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) .unwrap(); assert!(len > 0); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); - let mut iter: Box> = if pipe.client.version == PROTOCOL_VERSION_V3 { - // frames orders are reversed compared to V1 - Box::new(frames.iter().rev()) - } - else { - Box::new(frames.iter()) - }; + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); + let mut iter: Box> = + if pipe.client.version == PROTOCOL_VERSION_V3 { + // frames orders are reversed compared to V1 + Box::new(frames.iter().rev()) + } else { + Box::new(frames.iter()) + }; // Ignore ACK. iter.next().unwrap(); @@ -11345,11 +12579,21 @@ mod tests { // Client sends initial flight let flight = testing::emit_flight(&mut pipe.client).unwrap(); - testing::process_flight(&mut pipe.server, flight).unwrap(); + testing::process_flight( + &mut pipe.server, + &mut pipe.server_app_buffers, + flight, + ) + .unwrap(); // Server sends initial flight. let flight = testing::emit_flight(&mut pipe.server).unwrap(); - testing::process_flight(&mut pipe.client, flight).unwrap(); + testing::process_flight( + &mut pipe.client, + &mut pipe.client_app_buffers, + flight, + ) + .unwrap(); // Client sends Handshake packet. let flight = testing::emit_flight(&mut pipe.client).unwrap(); @@ -11400,7 +12644,12 @@ mod tests { ); // Process delayed packet. - testing::process_flight(&mut pipe.server, delayed).unwrap(); + testing::process_flight( + &mut pipe.server, + &mut pipe.server_app_buffers, + delayed, + ) + .unwrap(); assert!(pipe.server.is_established()); @@ -11421,27 +12670,38 @@ mod tests { assert_eq!(pipe.handshake(), Ok(())); // Client sends some data, and closes stream. - assert_eq!(pipe.client.stream_send(0, b"hello", true), Ok(5)); + assert_eq!(pipe.client.stream_send(4, b"hello", true), Ok(5)); assert_eq!(pipe.advance(), Ok(())); // Server gets data. let mut r = pipe.server.readable(); - assert_eq!(r.next(), Some(0)); + assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); - - assert_eq!(pipe.server.stream_recv(0, &mut b), Ok((5, true))); - assert!(pipe.server.stream_finished(0)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (5, true)); + assert!(pipe + .server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .is_ok()); + } else { + assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, true))); + } + assert!(pipe.server.stream_finished(4)); let mut r = pipe.server.readable(); assert_eq!(r.next(), None); // Server sends data, until blocked. let mut r = pipe.server.writable(); - assert_eq!(r.next(), Some(0)); + assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); loop { - if pipe.server.stream_send(0, b"world", false) == Err(Error::Done) { + if pipe.server.stream_send(4, b"world", false) == Err(Error::Done) { break; } @@ -11453,19 +12713,22 @@ mod tests { // Client sends STOP_SENDING. let frames = [frame::Frame::StopSending { - stream_id: 0, + stream_id: 4, error_code: 42, }]; let pkt_type = packet::Type::Short; let len = pipe - .send_pkt_to_server(pkt_type, &frames, &mut buf) + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) .unwrap(); // Server sent a RESET_STREAM frame in response. - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); - + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); // Skip ACK frame. @@ -11474,7 +12737,7 @@ mod tests { assert_eq!( iter.next(), Some(&frame::Frame::ResetStream { - stream_id: 0, + stream_id: 4, error_code: 42, final_size: 15, }) @@ -11482,11 +12745,11 @@ mod tests { // Stream is writable, but writing returns an error. let mut r = pipe.server.writable(); - assert_eq!(r.next(), Some(0)); + assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); assert_eq!( - pipe.server.stream_send(0, b"world", true), + pipe.server.stream_send(4, b"world", true), Err(Error::StreamStopped(42)), ); @@ -11502,23 +12765,40 @@ mod tests { ecn_counts: None, }]; - assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(0)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), + Ok(0) + ); + } else { + // Since we're using stream_id=4 (which lead to a stream_sequence = + // 2;); we receive from the peer a MAX_STREAMS_BIDI frame + // to increase to 4. + assert_eq!( + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), + Ok(38) + ); + } // Stream is collected on the server after RESET_STREAM is acked. assert_eq!(pipe.server.streams.len(), 0); // Sending STOP_SENDING again shouldn't trigger RESET_STREAM again. let frames = [frame::Frame::StopSending { - stream_id: 0, + stream_id: 4, error_code: 42, }]; let len = pipe - .send_pkt_to_server(pkt_type, &frames, &mut buf) + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) .unwrap(); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); if pipe.client.version == PROTOCOL_VERSION_V3 { @@ -11557,7 +12837,19 @@ mod tests { assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); - assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, true))); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (5, true)); + assert!(pipe + .server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .is_ok()); + } else { + assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, true))); + } assert!(pipe.server.stream_finished(4)); let mut r = pipe.server.readable(); @@ -11582,12 +12874,16 @@ mod tests { let pkt_type = packet::Type::Short; let len = pipe - .send_pkt_to_server(pkt_type, &frames, &mut buf) + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) .unwrap(); // Server sent a RESET_STREAM frame in response. - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); // Skip ACK frame on V1. Skip Padding on V3. @@ -11646,7 +12942,19 @@ mod tests { assert_eq!(r.next(), None); let mut b = [0; 30]; - assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((10, true))); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (10, true)); + assert!(pipe + .server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .is_ok()); + } else { + assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((10, true))); + } // Server sends some data. assert_eq!(pipe.server.stream_send(4, b"helloworld", false), Ok(10)); @@ -11659,9 +12967,9 @@ mod tests { pipe.server.stream_send(4, b"helloworld", false), Err(Error::Done) ); - //assert_eq!( - //pipe.server.stream_send(8, b"helloworld", false), - //Err(Error::Done) + // assert_eq!( + // pipe.server.stream_send(8, b"helloworld", false), + // Err(Error::Done) //); // Client sends STOP_SENDING. @@ -11671,7 +12979,7 @@ mod tests { }]; let pkt_type = packet::Type::Short; - pipe.send_pkt_to_server(pkt_type, &frames, &mut buf) + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None) .unwrap(); // Server can now send more data (on a different stream). @@ -11715,18 +13023,17 @@ mod tests { let mut dummy = buf[..len].to_vec(); - let frames = - testing::decode_pkt(&mut pipe.client, &mut dummy[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut dummy[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); - // Stop Sending frame consumes 3 bytes. We need a payload of 12 bytes min on V3; so we - // should expect 9 bytes of padding. + // Stop Sending frame consumes 3 bytes. We need a payload of 12 bytes min + // on V3; so we should expect 9 bytes of padding. if pipe.client.version == PROTOCOL_VERSION_V3 { - assert_eq!( - iter.next(), - Some(&frame::Frame::Padding { - len: 9, - }) - ); + assert_eq!(iter.next(), Some(&frame::Frame::Padding { len: 9 })); } assert_eq!( @@ -11761,8 +13068,18 @@ mod tests { assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); - assert_eq!(pipe.client.stream_recv(4, &mut buf), Ok((12, true))); - + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, is_fin) = pipe + .client + .stream_recv_v3(4, &mut pipe.client_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (12, true)); + pipe.client + .stream_consumed(4, len, &mut pipe.client_app_buffers) + .unwrap(); + } else { + assert_eq!(pipe.client.stream_recv(4, &mut buf), Ok((12, true))); + } // Stream is collected on both sides. assert_eq!(pipe.client.streams.len(), 0); assert_eq!(pipe.server.streams.len(), 0); @@ -11812,7 +13129,18 @@ mod tests { assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); - assert_eq!(pipe.client.stream_recv(4, &mut buf), Ok((12, true))); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, is_fin) = pipe + .client + .stream_recv_v3(4, &mut pipe.client_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (12, true)); + pipe.client + .stream_consumed(4, len, &mut pipe.client_app_buffers) + .unwrap(); + } else { + assert_eq!(pipe.client.stream_recv(4, &mut buf), Ok((12, true))); + } // Stream is collected on both sides. assert_eq!(pipe.client.streams.len(), 0); @@ -11847,11 +13175,22 @@ mod tests { let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); - assert_eq!(pipe.client.stream_send(0, b"a", false), Ok(1)); + assert_eq!(pipe.client.stream_send(4, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); - assert_eq!(pipe.server.stream_recv(0, &mut buf), Ok((1, false))); - assert_eq!(pipe.server.stream_shutdown(0, Shutdown::Read, 123), Ok(())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (1, false)); + pipe.server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + assert_eq!(pipe.server.stream_recv(4, &mut buf), Ok((1, false))); + } + assert_eq!(pipe.server.stream_shutdown(4, Shutdown::Read, 123), Ok(())); assert_eq!(pipe.server.rx_data, 1); assert_eq!(pipe.client.tx_data, 1); @@ -11859,12 +13198,12 @@ mod tests { assert_eq!( pipe.client - .stream_send(0, &buf[..pipe.client.tx_cap], false), + .stream_send(4, &buf[..pipe.client.tx_cap], false), Ok(29) ); assert_eq!(pipe.advance(), Ok(())); - assert!(!pipe.server.stream_readable(0)); // nothing can be consumed + assert!(!pipe.server.stream_readable(4)); // nothing can be consumed // The client has increased its tx_data, and server has received it, so // it increases flow control accordingly. @@ -11933,19 +13272,18 @@ mod tests { let mut dummy = buf[..len].to_vec(); - let frames = - testing::decode_pkt(&mut pipe.client, &mut dummy[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut dummy[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); - // ResetStream frame consumes 4 bytes. We need a payload of 12 bytes min on V3; so we - // should expect 8 bytes of padding. + // ResetStream frame consumes 4 bytes. We need a payload of 12 bytes min + // on V3; so we should expect 8 bytes of padding. if pipe.client.version == PROTOCOL_VERSION_V3 { - assert_eq!( - iter.next(), - Some(&frame::Frame::Padding { - len: 8, - }) - ); + assert_eq!(iter.next(), Some(&frame::Frame::Padding { len: 8 })); } assert_eq!( @@ -11976,17 +13314,35 @@ mod tests { assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); - assert_eq!(pipe.server.stream_recv(4, &mut buf), Ok((15, true))); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (15, true)); + pipe.server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + assert_eq!(pipe.server.stream_recv(4, &mut buf), Ok((15, true))); + } // Client processes readable streams. let mut r = pipe.client.readable(); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); - assert_eq!( - pipe.client.stream_recv(4, &mut buf), - Err(Error::StreamReset(42)) - ); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + pipe.client.stream_recv_v3(4, &mut pipe.client_app_buffers), + Err(Error::StreamReset(42)) + ); + } else { + assert_eq!( + pipe.client.stream_recv(4, &mut buf), + Err(Error::StreamReset(42)) + ); + } // Stream is collected on both sides. assert_eq!(pipe.client.streams.len(), 0); @@ -12031,7 +13387,18 @@ mod tests { assert_eq!(r.next(), None); let mut b = [0; 15]; - assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, true))); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (5, true)); + pipe.server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, true))); + } // Server sends some data. assert_eq!(pipe.server.stream_send(4, b"hello", false), Ok(5)); @@ -12074,54 +13441,111 @@ mod tests { let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); - // Sending 7 bytes to avoid having padding in the way on V3. - assert_eq!(pipe.client.stream_send(8, b"aaaaaaa", false), Ok(7)); - assert_eq!(pipe.client.stream_send(0, b"aaaaaaa", false), Ok(7)); - assert_eq!(pipe.client.stream_send(4, b"aaaaaaa", false), Ok(7)); - - let (len, _) = pipe.client.send(&mut buf).unwrap(); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; - let frames = - testing::decode_pkt(&mut pipe.server, &mut buf[..len]).unwrap(); + // Sending 7 bytes to avoid having padding in the way on V3. + assert_eq!( + pipe.client.stream_send(8 + off_by, b"aaaaaaa", false), + Ok(7) + ); + assert_eq!( + pipe.client.stream_send(0 + off_by, b"aaaaaaa", false), + Ok(7) + ); + assert_eq!( + pipe.client.stream_send(4 + off_by, b"aaaaaaa", false), + Ok(7) + ); + + let (len, _) = pipe.client.send(&mut buf).unwrap(); + + let frames = testing::decode_pkt( + &mut pipe.server, + &mut buf[..len], + &mut pipe.server_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); // Skip ACK frame. iter.next(); - assert_eq!( - iter.next(), - Some(&frame::Frame::Stream { - stream_id: 8, - data: stream::RangeBuf::from(b"aaaaaaa", 0, false), - }) - ); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + iter.next(), + Some(&frame::Frame::StreamV3 { + stream_id: 12, + metadata: stream::RecvBufInfo::from(0, 7, false), + }) + ); + } else { + assert_eq!( + iter.next(), + Some(&frame::Frame::Stream { + stream_id: 8, + data: stream::RangeBuf::from(b"aaaaaaa", 0, false), + }) + ); + } let (len, _) = pipe.client.send(&mut buf).unwrap(); - let frames = - testing::decode_pkt(&mut pipe.server, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.server, + &mut buf[..len], + &mut pipe.server_app_buffers, + ) + .unwrap(); - assert_eq!( - frames.first(), - Some(&frame::Frame::Stream { - stream_id: 0, - data: stream::RangeBuf::from(b"aaaaaaa", 0, false), - }) - ); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + frames.first(), + Some(&frame::Frame::StreamV3 { + stream_id: 4, + metadata: stream::RecvBufInfo::from(0, 7, false), + }) + ); + } else { + assert_eq!( + frames.first(), + Some(&frame::Frame::Stream { + stream_id: 0, + data: stream::RangeBuf::from(b"aaaaaaa", 0, false), + }) + ); + } let (len, _) = pipe.client.send(&mut buf).unwrap(); - let frames = - testing::decode_pkt(&mut pipe.server, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.server, + &mut buf[..len], + &mut pipe.server_app_buffers, + ) + .unwrap(); - assert_eq!( - frames.first(), - Some(&frame::Frame::Stream { - stream_id: 4, - data: stream::RangeBuf::from(b"aaaaaaa", 0, false), - }) - ); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + frames.first(), + Some(&frame::Frame::StreamV3 { + stream_id: 8, + metadata: stream::RecvBufInfo::from(0, 7, false), + }) + ); + } else { + assert_eq!( + frames.first(), + Some(&frame::Frame::Stream { + stream_id: 4, + data: stream::RangeBuf::from(b"aaaaaaa", 0, false), + }) + ); + } } #[test] @@ -12134,7 +13558,13 @@ mod tests { let mut r = pipe.client.readable(); assert_eq!(r.next(), None); - assert_eq!(pipe.client.stream_send(0, b"aaaaa", false), Ok(5)); + let off_by = if crate::PROTOCOL_VERSION == PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; + + assert_eq!(pipe.client.stream_send(0 + off_by, b"aaaaa", false), Ok(5)); let mut r = pipe.client.readable(); assert_eq!(r.next(), None); @@ -12146,22 +13576,33 @@ mod tests { // Server received stream. let mut r = pipe.server.readable(); - assert_eq!(r.next(), Some(0)); + assert_eq!(r.next(), Some(0 + off_by)); assert_eq!(r.next(), None); assert_eq!( - pipe.server.stream_send(0, b"aaaaaaaaaaaaaaa", false), + pipe.server + .stream_send(0 + off_by, b"aaaaaaaaaaaaaaa", false), Ok(15) ); assert_eq!(pipe.advance(), Ok(())); let mut r = pipe.client.readable(); - assert_eq!(r.next(), Some(0)); + assert_eq!(r.next(), Some(0 + off_by)); assert_eq!(r.next(), None); // Client drains stream. let mut b = [0; 15]; - pipe.client.stream_recv(0, &mut b).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .client + .stream_recv_v3(4, &mut pipe.client_app_buffers) + .unwrap(); + pipe.client + .stream_consumed(4, len, &mut pipe.client_app_buffers) + .unwrap(); + } else { + pipe.client.stream_recv(0, &mut b).unwrap(); + } assert_eq!(pipe.advance(), Ok(())); let mut r = pipe.client.readable(); @@ -12169,19 +13610,22 @@ mod tests { // Server shuts down stream. let mut r = pipe.server.readable(); - assert_eq!(r.next(), Some(0)); + assert_eq!(r.next(), Some(0 + off_by)); assert_eq!(r.next(), None); - assert_eq!(pipe.server.stream_shutdown(0, Shutdown::Read, 0), Ok(())); + assert_eq!( + pipe.server.stream_shutdown(0 + off_by, Shutdown::Read, 0), + Ok(()) + ); let mut r = pipe.server.readable(); assert_eq!(r.next(), None); // Client creates multiple streams. - assert_eq!(pipe.client.stream_send(4, b"aaaaa", false), Ok(5)); + assert_eq!(pipe.client.stream_send(4 + off_by, b"aaaaa", false), Ok(5)); assert_eq!(pipe.advance(), Ok(())); - assert_eq!(pipe.client.stream_send(8, b"aaaaa", false), Ok(5)); + assert_eq!(pipe.client.stream_send(8 + off_by, b"aaaaa", false), Ok(5)); assert_eq!(pipe.advance(), Ok(())); let mut r = pipe.server.readable(); @@ -12204,22 +13648,29 @@ mod tests { let mut w = pipe.client.writable(); assert_eq!(w.next(), None); - assert_eq!(pipe.client.stream_send(0, b"aaaaa", false), Ok(5)); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; + + assert_eq!(pipe.client.stream_send(0 + off_by, b"aaaaa", false), Ok(5)); // Client created stream. let mut w = pipe.client.writable(); - assert_eq!(w.next(), Some(0)); + assert_eq!(w.next(), Some(0 + off_by)); assert_eq!(w.next(), None); assert_eq!(pipe.advance(), Ok(())); // Server created stream. let mut w = pipe.server.writable(); - assert_eq!(w.next(), Some(0)); + assert_eq!(w.next(), Some(0 + off_by)); assert_eq!(w.next(), None); assert_eq!( - pipe.server.stream_send(0, b"aaaaaaaaaaaaaaa", false), + pipe.server + .stream_send(0 + off_by, b"aaaaaaaaaaaaaaa", false), Ok(15) ); @@ -12231,25 +13682,38 @@ mod tests { // Client drains stream. let mut b = [0; 15]; - pipe.client.stream_recv(0, &mut b).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .client + .stream_recv_v3(4, &mut pipe.client_app_buffers) + .unwrap(); + pipe.client + .stream_consumed(4, len, &mut pipe.client_app_buffers) + .unwrap(); + } else { + pipe.client.stream_recv(0, &mut b).unwrap(); + } assert_eq!(pipe.advance(), Ok(())); // Server stream is writable again. let mut w = pipe.server.writable(); - assert_eq!(w.next(), Some(0)); + assert_eq!(w.next(), Some(0 + off_by)); assert_eq!(w.next(), None); // Server shuts down stream. - assert_eq!(pipe.server.stream_shutdown(0, Shutdown::Write, 0), Ok(())); + assert_eq!( + pipe.server.stream_shutdown(0 + off_by, Shutdown::Write, 0), + Ok(()) + ); let mut w = pipe.server.writable(); assert_eq!(w.next(), None); // Client creates multiple streams. - assert_eq!(pipe.client.stream_send(4, b"aaaaa", false), Ok(5)); + assert_eq!(pipe.client.stream_send(4 + off_by, b"aaaaa", false), Ok(5)); assert_eq!(pipe.advance(), Ok(())); - assert_eq!(pipe.client.stream_send(8, b"aaaaa", false), Ok(5)); + assert_eq!(pipe.client.stream_send(8 + off_by, b"aaaaa", false), Ok(5)); assert_eq!(pipe.advance(), Ok(())); let mut w = pipe.server.writable(); @@ -12262,10 +13726,10 @@ mod tests { assert_eq!(w.len(), 0); // Server finishes stream. - assert_eq!(pipe.server.stream_send(8, b"aaaaa", true), Ok(5)); + assert_eq!(pipe.server.stream_send(8 + off_by, b"aaaaa", true), Ok(5)); let mut w = pipe.server.writable(); - assert_eq!(w.next(), Some(4)); + assert_eq!(w.next(), Some(4 + off_by)); assert_eq!(w.next(), None); } @@ -12292,16 +13756,16 @@ mod tests { // Client creates stream and sends some data. let send_buf = [0; 35]; - assert_eq!(pipe.client.stream_send(0, &send_buf, false), Ok(35)); + assert_eq!(pipe.client.stream_send(4, &send_buf, false), Ok(35)); // Stream is still writable as it still has capacity. - assert_eq!(pipe.client.stream_writable_next(), Some(0)); + assert_eq!(pipe.client.stream_writable_next(), Some(4)); assert_eq!(pipe.client.stream_writable_next(), None); // Client fills stream, which becomes unwritable due to connection // capacity. let send_buf = [0; 36]; - assert_eq!(pipe.client.stream_send(0, &send_buf, false), Ok(35)); + assert_eq!(pipe.client.stream_send(4, &send_buf, false), Ok(35)); assert_eq!(pipe.client.stream_writable_next(), None); @@ -12310,7 +13774,17 @@ mod tests { assert_eq!(pipe.advance(), Ok(())); let mut b = [0; 70]; - pipe.server.stream_recv(0, &mut b).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + pipe.server.stream_recv(4, &mut b).unwrap(); + } assert_eq!(pipe.advance(), Ok(())); @@ -12318,7 +13792,7 @@ mod tests { // again. assert_ne!(pipe.client.tx_cap, 0); - assert_eq!(pipe.client.stream_writable_next(), Some(0)); + assert_eq!(pipe.client.stream_writable_next(), Some(4)); assert_eq!(pipe.client.stream_writable_next(), None); } @@ -12413,12 +13887,10 @@ mod tests { // 8 more bytes pushed by encode_pkt() for 4 bytes stream_id and // 4 bytes offset assert_eq!(pipe.client_recv(&mut buf[..written]), Ok(79)); - } - else { + } else { assert_eq!(pipe.client_recv(&mut buf[..written]), Ok(71)); } - // The connection should be alive... assert!(!pipe.client.is_closed()); @@ -12438,7 +13910,12 @@ mod tests { let epoch = packet::Type::Initial.to_epoch().unwrap(); let pn = 0; - let pn_len = packet::pkt_num_len(pn).unwrap(); + let mut pn_len = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 + { + packet::pkt_num_len_v3(pn, 0) + } else { + packet::pkt_num_len(pn, 0) + }; let dcid = pipe.client.destination_id(); let scid = pipe.client.source_id(); @@ -12461,7 +13938,14 @@ mod tests { let len = pn_len + payload_len; b.put_varint(len as u64).unwrap(); - packet::encode_pkt_num(pn, &mut b).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + packet::encode_pkt_num_v3(pn, pn_len, 1, &mut b).unwrap(); + packet::encode_u64_num_and_nextelem_len(0, 1, &mut b).unwrap(); + packet::encode_offset_num(0, 1, &mut b).unwrap(); + pn_len += 2; + } else { + packet::encode_pkt_num(pn, pn_len, &mut b).unwrap(); + } let payload_offset = b.off(); @@ -12562,55 +14046,79 @@ mod tests { config.set_initial_max_streams_uni(0); config.verify_peer(false); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; + let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends stream data. - assert_eq!(pipe.client.stream_send(0, b"a", false), Ok(1)); + assert_eq!(pipe.client.stream_send(0 + off_by, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); - assert_eq!(pipe.client.stream_send(4, b"a", false), Ok(1)); + assert_eq!(pipe.client.stream_send(4 + off_by, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); - assert_eq!(pipe.client.stream_send(4, b"b", true), Ok(1)); + assert_eq!(pipe.client.stream_send(4 + off_by, b"b", true), Ok(1)); assert_eq!(pipe.advance(), Ok(())); - assert_eq!(pipe.client.stream_send(0, b"b", true), Ok(1)); + assert_eq!(pipe.client.stream_send(0 + off_by, b"b", true), Ok(1)); assert_eq!(pipe.advance(), Ok(())); // Server reads stream data. let mut b = [0; 15]; - pipe.server.stream_recv(0, &mut b).unwrap(); - pipe.server.stream_recv(4, &mut b).unwrap(); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .unwrap(); + let (_, len, _) = pipe + .server + .stream_recv_v3(8, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(8, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + pipe.server.stream_recv(0, &mut b).unwrap(); + pipe.server.stream_recv(4, &mut b).unwrap(); + } assert_eq!(pipe.advance(), Ok(())); // Server sends stream data, with fin. - assert_eq!(pipe.server.stream_send(0, b"a", false), Ok(1)); + assert_eq!(pipe.server.stream_send(0 + off_by, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); - assert_eq!(pipe.server.stream_send(4, b"a", false), Ok(1)); + assert_eq!(pipe.server.stream_send(4 + off_by, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); - assert_eq!(pipe.server.stream_send(4, b"b", true), Ok(1)); + assert_eq!(pipe.server.stream_send(4 + off_by, b"b", true), Ok(1)); assert_eq!(pipe.advance(), Ok(())); - assert_eq!(pipe.server.stream_send(0, b"b", true), Ok(1)); + assert_eq!(pipe.server.stream_send(0 + off_by, b"b", true), Ok(1)); // Server sends MAX_STREAMS. assert_eq!(pipe.advance(), Ok(())); // Client tries to create new streams. - assert_eq!(pipe.client.stream_send(8, b"a", false), Ok(1)); + assert_eq!(pipe.client.stream_send(8 + off_by, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); - assert_eq!(pipe.client.stream_send(12, b"a", false), Ok(1)); + assert_eq!(pipe.client.stream_send(12 + off_by, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); - assert_eq!(pipe.client.stream_send(16, b"a", false), Ok(1)); + assert_eq!(pipe.client.stream_send(16 + off_by, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); assert_eq!( - pipe.client.stream_send(20, b"a", false), + pipe.client.stream_send(20 + off_by, b"a", false), Err(Error::StreamLimit) ); @@ -12656,8 +14164,25 @@ mod tests { // Server reads stream data. let mut b = [0; 15]; - pipe.server.stream_recv(2, &mut b).unwrap(); - pipe.server.stream_recv(6, &mut b).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(2, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(2, len, &mut pipe.server_app_buffers) + .unwrap(); + let (_, len, _) = pipe + .server + .stream_recv_v3(6, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(6, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + pipe.server.stream_recv(2, &mut b).unwrap(); + pipe.server.stream_recv(6, &mut b).unwrap(); + } // Server sends MAX_STREAMS. assert_eq!(pipe.advance(), Ok(())); @@ -12689,34 +14214,54 @@ mod tests { assert_eq!(pipe.handshake(), Ok(())); assert_eq!( - pipe.client.stream_send(0, b"aaaaaaaaaaaaaaa", false), + pipe.client.stream_send(4, b"aaaaaaaaaaaaaaa", false), Ok(15) ); assert_eq!(pipe.advance(), Ok(())); let mut r = pipe.server.readable(); - assert_eq!(r.next(), Some(0)); + assert_eq!(r.next(), Some(4)); assert!(r.next().is_none()); let mut b = [0; 15]; - pipe.server.stream_recv(0, &mut b).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + pipe.server.stream_recv(4, &mut b).unwrap(); + } assert_eq!(pipe.advance(), Ok(())); // Client sends zero-length frame. - assert_eq!(pipe.client.stream_send(0, b"", true), Ok(0)); + assert_eq!(pipe.client.stream_send(4, b"", true), Ok(0)); assert_eq!(pipe.advance(), Ok(())); // Stream should be readable on the server after receiving empty fin. let mut r = pipe.server.readable(); - assert_eq!(r.next(), Some(0)); + assert_eq!(r.next(), Some(4)); assert!(r.next().is_none()); let mut b = [0; 15]; - pipe.server.stream_recv(0, &mut b).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + pipe.server.stream_recv(4, &mut b).unwrap(); + } assert_eq!(pipe.advance(), Ok(())); // Client sends zero-length frame (again). - assert_eq!(pipe.client.stream_send(0, b"", true), Ok(0)); + assert_eq!(pipe.client.stream_send(4, b"", true), Ok(0)); assert_eq!(pipe.advance(), Ok(())); // Stream should _not_ be readable on the server after receiving empty @@ -12734,38 +14279,58 @@ mod tests { assert_eq!(pipe.handshake(), Ok(())); assert_eq!( - pipe.client.stream_send(0, b"aaaaaaaaaaaaaaa", false), + pipe.client.stream_send(4, b"aaaaaaaaaaaaaaa", false), Ok(15) ); assert_eq!(pipe.advance(), Ok(())); let mut r = pipe.server.readable(); - assert_eq!(r.next(), Some(0)); + assert_eq!(r.next(), Some(4)); assert!(r.next().is_none()); let mut b = [0; 15]; - pipe.server.stream_recv(0, &mut b).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + pipe.server.stream_recv(4, &mut b).unwrap(); + } assert_eq!(pipe.advance(), Ok(())); // Client sends zero-length frame. - assert_eq!(pipe.client.stream_send(0, b"", true), Ok(0)); + assert_eq!(pipe.client.stream_send(4, b"", true), Ok(0)); assert_eq!(pipe.advance(), Ok(())); // Server sends zero-length frame. - assert_eq!(pipe.server.stream_send(0, b"", true), Ok(0)); + assert_eq!(pipe.server.stream_send(4, b"", true), Ok(0)); assert_eq!(pipe.advance(), Ok(())); // Stream should be readable on the server after receiving empty fin. let mut r = pipe.server.readable(); - assert_eq!(r.next(), Some(0)); + assert_eq!(r.next(), Some(4)); assert!(r.next().is_none()); let mut b = [0; 15]; - pipe.server.stream_recv(0, &mut b).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + pipe.server.stream_recv(4, &mut b).unwrap(); + } assert_eq!(pipe.advance(), Ok(())); // Client sends zero-length frame (again). - assert_eq!(pipe.client.stream_send(0, b"", true), Ok(0)); + assert_eq!(pipe.client.stream_send(4, b"", true), Ok(0)); assert_eq!(pipe.advance(), Ok(())); // Stream should _not_ be readable on the server after receiving empty @@ -12775,9 +14340,18 @@ mod tests { // Stream _is_readable on the client side. let mut r = pipe.client.readable(); - assert_eq!(r.next(), Some(0)); - - pipe.client.stream_recv(0, &mut b).unwrap(); + assert_eq!(r.next(), Some(4)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .client + .stream_recv_v3(4, &mut pipe.client_app_buffers) + .unwrap(); + pipe.client + .stream_consumed(4, len, &mut pipe.client_app_buffers) + .unwrap(); + } else { + pipe.client.stream_recv(4, &mut b).unwrap(); + } assert_eq!(pipe.advance(), Ok(())); // Stream is completed and _is not_ readable. @@ -12792,7 +14366,7 @@ mod tests { let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); - assert_eq!(pipe.client.stream_send(0, b"", false), Ok(0)); + assert_eq!(pipe.client.stream_send(4, b"", false), Ok(0)); // The stream now should have been created. assert_eq!(pipe.client.streams.len(), 1); @@ -12811,55 +14385,95 @@ mod tests { let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); + let mut stream_id = 0; + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + stream_id = 4; + } assert_eq!(pipe.client.streams.len(), 0); assert_eq!(pipe.server.streams.len(), 0); + assert_eq!(pipe.client.stream_send(stream_id, b"aaaaa", true), Ok(5)); - assert_eq!(pipe.client.stream_send(0, b"aaaaa", true), Ok(5)); assert_eq!(pipe.advance(), Ok(())); - assert!(!pipe.client.stream_finished(0)); - assert!(!pipe.server.stream_finished(0)); + assert!(!pipe.client.stream_finished(stream_id)); + assert!(!pipe.server.stream_finished(stream_id)); assert_eq!(pipe.client.streams.len(), 1); assert_eq!(pipe.server.streams.len(), 1); let mut b = [0; 5]; - pipe.server.stream_recv(0, &mut b).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(stream_id, &mut pipe.server_app_buffers) + .unwrap(); + // drop the data and tell we read them + pipe.server + .stream_consumed(stream_id, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + pipe.server.stream_recv(stream_id, &mut b).unwrap(); + } assert_eq!(pipe.advance(), Ok(())); - assert_eq!(pipe.server.stream_send(0, b"aaaaa", true), Ok(5)); + assert_eq!(pipe.server.stream_send(stream_id, b"aaaaa", true), Ok(5)); assert_eq!(pipe.advance(), Ok(())); - assert!(!pipe.client.stream_finished(0)); - assert!(pipe.server.stream_finished(0)); + assert!(!pipe.client.stream_finished(stream_id)); + assert!(pipe.server.stream_finished(stream_id)); assert_eq!(pipe.client.streams.len(), 1); assert_eq!(pipe.server.streams.len(), 0); let mut b = [0; 5]; - pipe.client.stream_recv(0, &mut b).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .client + .stream_recv_v3(stream_id, &mut pipe.client_app_buffers) + .unwrap(); + pipe.client + .stream_consumed(stream_id, len, &mut pipe.client_app_buffers) + .unwrap(); + } else { + pipe.client.stream_recv(stream_id, &mut b).unwrap(); + } assert_eq!(pipe.advance(), Ok(())); assert_eq!(pipe.client.streams.len(), 0); assert_eq!(pipe.server.streams.len(), 0); - assert!(pipe.client.stream_finished(0)); - assert!(pipe.server.stream_finished(0)); + assert!(pipe.client.stream_finished(stream_id)); + assert!(pipe.server.stream_finished(stream_id)); - assert_eq!(pipe.client.stream_send(0, b"", true), Err(Error::Done)); + assert_eq!( + pipe.client.stream_send(stream_id, b"", true), + Err(Error::Done) + ); let frames = [frame::Frame::Stream { - stream_id: 0, + stream_id, data: stream::RangeBuf::from(b"aa", 0, false), }]; let pkt_type = packet::Type::Short; if pipe.server.version == PROTOCOL_VERSION_V3 { - assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(48)); - } - else { - assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(39)); + // On a finished stream, the buffer should have been cleared V3. The + // server shouldn't send back anything, right? + assert_eq!( + pipe.send_pkt_to_server( + pkt_type, + &frames, + &mut buf, + Some(stream_id) + ), + Ok(0) + ); + } else { + assert_eq!( + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), + Ok(39) + ); } } @@ -13033,7 +14647,11 @@ mod tests { let flight = testing::emit_flight(&mut pipe.server).unwrap(); assert_eq!( - testing::process_flight(&mut pipe.client, flight), + testing::process_flight( + &mut pipe.client, + &mut pipe.client_app_buffers, + flight + ), Err(Error::InvalidTransportParam) ); } @@ -13099,7 +14717,11 @@ mod tests { let flight = testing::emit_flight(&mut pipe.server).unwrap(); assert_eq!( - testing::process_flight(&mut pipe.client, flight), + testing::process_flight( + &mut pipe.client, + &mut pipe.client_app_buffers, + flight + ), Err(Error::InvalidTransportParam) ); } @@ -13199,20 +14821,38 @@ mod tests { let (len, _) = pipe.client.send(&mut buf).unwrap(); assert_eq!(pipe.client.blocked_limit, None); - let frames = - testing::decode_pkt(&mut pipe.server, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.server, + &mut buf[..len], + &mut pipe.server_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); assert_eq!(iter.next(), Some(&frame::Frame::DataBlocked { limit: 30 })); - assert_eq!( - iter.next(), - Some(&frame::Frame::Stream { - stream_id: 8, - data: stream::RangeBuf::from(b"aaaaaaaaaa", 0, false), + if crate::PROTOCOL_VERSION == PROTOCOL_VERSION_V3 { + // On the receive code path, a stream frame is unpacked as a StreamV3 + // Frame, which optionally contains a Vec with a copy of + // the data when it is not received in order. (In V1, it + // *always* contains a copy) + assert_eq!( + iter.next(), + Some(&frame::Frame::StreamV3 { + stream_id: 8, + metadata: stream::RecvBufInfo::from(0, 10, false), }) - ); + ); + } else { + assert_eq!( + iter.next(), + Some(&frame::Frame::Stream { + stream_id: 8, + data: stream::RangeBuf::from(b"aaaaaaaaaa", 0, false), + }) + ); + } assert_eq!(iter.next(), None); } @@ -13224,20 +14864,24 @@ mod tests { let mut pipe = testing::Pipe::new().unwrap(); assert_eq!(pipe.handshake(), Ok(())); - assert_eq!(pipe.client.stream_send(0, b"aaaaa", false), Ok(5)); + assert_eq!(pipe.client.stream_send(4, b"aaaaa", false), Ok(5)); assert_eq!(pipe.client.streams.blocked().len(), 0); - assert_eq!(pipe.client.stream_send(0, b"aaaaa", false), Ok(5)); + assert_eq!(pipe.client.stream_send(4, b"aaaaa", false), Ok(5)); assert_eq!(pipe.client.streams.blocked().len(), 0); - assert_eq!(pipe.client.stream_send(0, b"aaaaaa", false), Ok(5)); + assert_eq!(pipe.client.stream_send(4, b"aaaaaa", false), Ok(5)); assert_eq!(pipe.client.streams.blocked().len(), 1); let (len, _) = pipe.client.send(&mut buf).unwrap(); assert_eq!(pipe.client.streams.blocked().len(), 0); - let frames = - testing::decode_pkt(&mut pipe.server, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.server, + &mut buf[..len], + &mut pipe.server_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); @@ -13249,13 +14893,12 @@ mod tests { assert_eq!( iter.next(), Some(&frame::Frame::StreamDataBlocked { - stream_id: 0, + stream_id: 4, limit: 15, }) ); // Skip ACK frame. iter.next(); - } else { // Skip ACK frame. iter.next(); @@ -13263,31 +14906,45 @@ mod tests { assert_eq!( iter.next(), Some(&frame::Frame::StreamDataBlocked { - stream_id: 0, + stream_id: 4, limit: 15, }) ); } - assert_eq!( - iter.next(), - Some(&frame::Frame::Stream { - stream_id: 0, - data: stream::RangeBuf::from(b"aaaaaaaaaaaaaaa", 0, false), - }) - ); - + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + iter.next(), + Some(&frame::Frame::StreamV3 { + stream_id: 4, + metadata: stream::RecvBufInfo::from(0, 15, false), + }) + ); + } else { + assert_eq!( + iter.next(), + Some(&frame::Frame::Stream { + stream_id: 4, + data: stream::RangeBuf::from(b"aaaaaaaaaaaaaaa", 0, false), + }) + ); + } + assert_eq!(iter.next(), None); // Send from another stream, make sure we don't send STREAM_DATA_BLOCKED // again. - assert_eq!(pipe.client.stream_send(4, b"a", false), Ok(1)); + assert_eq!(pipe.client.stream_send(8, b"a", false), Ok(1)); let (len, _) = pipe.client.send(&mut buf).unwrap(); assert_eq!(pipe.client.streams.blocked().len(), 0); - let frames = - testing::decode_pkt(&mut pipe.server, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.server, + &mut buf[..len], + &mut pipe.server_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); @@ -13296,20 +14953,30 @@ mod tests { iter.next().unwrap(); } - assert_eq!( - iter.next(), - Some(&frame::Frame::Stream { - stream_id: 4, - data: stream::RangeBuf::from(b"a", 0, false), - }) - ); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + iter.next(), + Some(&frame::Frame::StreamV3 { + stream_id: 8, + metadata: stream::RecvBufInfo::from(0, 1, false), + }) + ); + } else { + assert_eq!( + iter.next(), + Some(&frame::Frame::Stream { + stream_id: 8, + data: stream::RangeBuf::from(b"a", 0, false), + }) + ); + } assert_eq!(iter.next(), None); // Send again from blocked stream and make sure it is not marked as // blocked again. assert_eq!( - pipe.client.stream_send(0, b"aaaaaaaa", false), + pipe.client.stream_send(4, b"aaaaaaaa", false), Err(Error::Done) ); assert_eq!(pipe.client.streams.blocked().len(), 0); @@ -13323,7 +14990,7 @@ mod tests { assert_eq!(pipe.handshake(), Ok(())); assert_eq!( - pipe.client.stream_send(0, b"aaaaaaaaaaaaaaah", false), + pipe.client.stream_send(4, b"aaaaaaaaaaaaaaah", false), Ok(15) ); assert_eq!(pipe.client.streams.blocked().len(), 1); @@ -13332,52 +14999,91 @@ mod tests { // Send again on blocked stream. It's blocked at the same offset as // previously, so it should not be marked as blocked again. - assert_eq!(pipe.client.stream_send(0, b"h", false), Err(Error::Done)); + assert_eq!(pipe.client.stream_send(4, b"h", false), Err(Error::Done)); assert_eq!(pipe.client.streams.blocked().len(), 0); // No matter how many times we try to write stream data tried, no // packets containing STREAM_BLOCKED should be emitted. - assert_eq!(pipe.client.stream_send(0, b"h", false), Err(Error::Done)); + assert_eq!(pipe.client.stream_send(4, b"h", false), Err(Error::Done)); assert_eq!(pipe.client.send(&mut buf), Err(Error::Done)); - assert_eq!(pipe.client.stream_send(0, b"h", false), Err(Error::Done)); + assert_eq!(pipe.client.stream_send(4, b"h", false), Err(Error::Done)); assert_eq!(pipe.client.send(&mut buf), Err(Error::Done)); - assert_eq!(pipe.client.stream_send(0, b"h", false), Err(Error::Done)); + assert_eq!(pipe.client.stream_send(4, b"h", false), Err(Error::Done)); assert_eq!(pipe.client.send(&mut buf), Err(Error::Done)); // Now read some data at the server to release flow control. let mut r = pipe.server.readable(); - assert_eq!(r.next(), Some(0)); + assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), None); let mut b = [0; 10]; - assert_eq!(pipe.server.stream_recv(0, &mut b), Ok((10, false))); - assert_eq!(&b[..10], b"aaaaaaaaaa"); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (b, ..) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + // The buffer isn't sized by the app. It means that stream_recv_v3 + // would "read" as many bytes as it can (up to the stream + // window) and tell the app "len" bytes are available. + // assert_eq!((len, is_fin), (15, false)); + // + // Let's consume 10 bytes only (this impacts the overall connection + // control flow, but not the stream's control flow) + assert_eq!(&b[..10], b"aaaaaaaaaa"); + assert!(pipe + .server + .stream_consumed(4, 10, &mut pipe.server_app_buffers) + .is_ok()); + } else { + assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((10, false))); + assert_eq!(&b[..10], b"aaaaaaaaaa"); + } assert_eq!(pipe.advance(), Ok(())); - assert_eq!(pipe.client.stream_send(0, b"hhhhhhhhhh!", false), Ok(10)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + // we'll hit the stream's control flow limit in v3 only if we send + // this. + assert_eq!(pipe.client.stream_send(4, b"hhhhhhhhhh", false), Ok(10)); + assert_eq!(pipe.client.stream_send(4, b"hhhhh!", false), Ok(5)); + } else { + assert_eq!(pipe.client.stream_send(4, b"hhhhhhhhhh!", false), Ok(10)); + } assert_eq!(pipe.client.streams.blocked().len(), 1); let (len, _) = pipe.client.send(&mut buf).unwrap(); assert_eq!(pipe.client.streams.blocked().len(), 0); - let frames = - testing::decode_pkt(&mut pipe.server, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.server, + &mut buf[..len], + &mut pipe.server_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); - - assert_eq!( - iter.next(), - Some(&frame::Frame::StreamDataBlocked { - stream_id: 0, - limit: 25, - }) - ); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + iter.next(), + Some(&frame::Frame::StreamDataBlocked { + stream_id: 4, + limit: 30, // blocked on max_connection_data + }) + ); + } else { + assert_eq!( + iter.next(), + Some(&frame::Frame::StreamDataBlocked { + stream_id: 4, + limit: 25, + }) + ); + } // don't care about remaining received frames - assert_eq!(pipe.client.stream_send(0, b"!", false), Err(Error::Done)); + assert_eq!(pipe.client.stream_send(4, b"!", false), Err(Error::Done)); assert_eq!(pipe.client.streams.blocked().len(), 0); assert_eq!(pipe.client.send(&mut buf), Err(Error::Done)); } @@ -13393,22 +15099,39 @@ mod tests { config.set_initial_max_stream_data_bidi_remote(50000); config.set_max_recv_udp_payload_size(1200); config.verify_peer(false); + let mut stream_id = 0; + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + stream_id = 4; + } let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends stream data. - assert_eq!(pipe.client.stream_send(0, b"a", true), Ok(1)); + assert_eq!(pipe.client.stream_send(stream_id, b"a", true), Ok(1)); assert_eq!(pipe.advance(), Ok(())); // Server reads stream data. let mut b = [0; 15]; - pipe.server.stream_recv(0, &mut b).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(stream_id, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(stream_id, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + pipe.server.stream_recv(stream_id, &mut b).unwrap(); + } assert_eq!(pipe.advance(), Ok(())); // Server sends stream data smaller than cwnd. let send_buf = [0; 10000]; - assert_eq!(pipe.server.stream_send(0, &send_buf, false), Ok(10000)); + assert_eq!( + pipe.server.stream_send(stream_id, &send_buf, false), + Ok(10000) + ); assert_eq!(pipe.advance(), Ok(())); // app_limited should be true because we send less than cwnd. @@ -13437,17 +15160,23 @@ mod tests { assert_eq!(pipe.handshake(), Ok(())); // Client sends stream data. - assert_eq!(pipe.client.stream_send(0, b"a", true), Ok(1)); + assert_eq!(pipe.client.stream_send(4, b"a", true), Ok(1)); assert_eq!(pipe.advance(), Ok(())); // Server reads stream data. let mut b = [0; 15]; - pipe.server.stream_recv(0, &mut b).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + pipe.server.stream_recv(4, &mut b).unwrap(); + } else { + pipe.server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + } assert_eq!(pipe.advance(), Ok(())); // Server sends stream data bigger than cwnd. let send_buf1 = [0; 20000]; - assert_eq!(pipe.server.stream_send(0, &send_buf1, false), Ok(12000)); + assert_eq!(pipe.server.stream_send(4, &send_buf1, false), Ok(12000)); testing::emit_flight(&mut pipe.server).ok(); @@ -13500,6 +15229,7 @@ mod tests { testing::process_flight( &mut pipe.client, + &mut pipe.client_app_buffers, testing::emit_flight(&mut pipe.server).unwrap(), ) .unwrap(); @@ -13516,15 +15246,18 @@ mod tests { assert_ne!(sent, 0, "the client should at least send a pure ACK packet"); - let frames = - testing::decode_pkt(&mut pipe.server, &mut buf[..sent]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.server, + &mut buf[..sent], + &mut pipe.server_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); if pipe.server.version == PROTOCOL_VERSION_V3 { // removing padding. iter.next().unwrap(); - } - else { + } else { assert_eq!(1, frames.len()); } assert!( @@ -13593,8 +15326,12 @@ mod tests { "the client should at least send a pure ACK packet" ); - let frames = - testing::decode_pkt(&mut pipe.server, &mut buf[..sent]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.server, + &mut buf[..sent], + &mut pipe.server_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); @@ -13631,21 +15368,39 @@ mod tests { config.set_max_recv_udp_payload_size(1405); config.verify_peer(false); + let mut stream_id = 0; + if crate::PROTOCOL_VERSION == PROTOCOL_VERSION_V3 { + stream_id = 4; + } + let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends stream data. - assert_eq!(pipe.client.stream_send(0, b"a", true), Ok(1)); + assert_eq!(pipe.client.stream_send(stream_id, b"a", true), Ok(1)); assert_eq!(pipe.advance(), Ok(())); // Server reads stream data. let mut b = [0; 15]; - pipe.server.stream_recv(0, &mut b).unwrap(); + if crate::PROTOCOL_VERSION == PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(stream_id, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(stream_id, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + pipe.server.stream_recv(stream_id, &mut b).unwrap(); + } assert_eq!(pipe.advance(), Ok(())); // Server sends stream data bigger than cwnd. let send_buf1 = [0; 20000]; - assert_eq!(pipe.server.stream_send(0, &send_buf1, false), Ok(12000)); + assert_eq!( + pipe.server.stream_send(stream_id, &send_buf1, false), + Ok(12000) + ); testing::emit_flight(&mut pipe.server).ok(); @@ -13672,21 +15427,39 @@ mod tests { config.set_max_recv_udp_payload_size(1406); config.verify_peer(false); + let mut stream_id = 0; + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + stream_id = 4; + } + let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends stream data. - assert_eq!(pipe.client.stream_send(0, b"a", true), Ok(1)); + assert_eq!(pipe.client.stream_send(stream_id, b"a", true), Ok(1)); assert_eq!(pipe.advance(), Ok(())); // Server reads stream data. let mut b = [0; 15]; - pipe.server.stream_recv(0, &mut b).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(stream_id, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(stream_id, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + pipe.server.stream_recv(stream_id, &mut b).unwrap(); + } assert_eq!(pipe.advance(), Ok(())); // Server sends stream data bigger than cwnd. let send_buf1 = [0; 20000]; - assert_eq!(pipe.server.stream_send(0, &send_buf1, false), Ok(12000)); + assert_eq!( + pipe.server.stream_send(stream_id, &send_buf1, false), + Ok(12000) + ); testing::emit_flight(&mut pipe.server).ok(); @@ -13712,17 +15485,27 @@ mod tests { config.set_initial_max_stream_data_bidi_remote(50000); config.set_max_recv_udp_payload_size(1200); config.verify_peer(false); + let mut stream_id = 0; + if crate::PROTOCOL_VERSION == PROTOCOL_VERSION_V3 { + stream_id = 4; + } let mut pipe = testing::Pipe::with_client_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); // Client sends stream data. - assert_eq!(pipe.client.stream_send(0, b"a", true), Ok(1)); + assert_eq!(pipe.client.stream_send(stream_id, b"a", true), Ok(1)); assert_eq!(pipe.advance(), Ok(())); // Server reads stream data. let mut b = [0; 15]; - pipe.server.stream_recv(0, &mut b).unwrap(); + if crate::PROTOCOL_VERSION == PROTOCOL_VERSION_V3 { + pipe.server + .stream_recv_v3(stream_id, &mut pipe.server_app_buffers) + .unwrap(); + } else { + pipe.server.stream_recv(stream_id, &mut b).unwrap(); + } assert_eq!(pipe.advance(), Ok(())); // Client's app_limited is true because its bytes-in-flight @@ -13773,7 +15556,7 @@ mod tests { last_packet_sent = pipe.client.pkt_num_spaces[epoch].next_pkt_num; - pipe.send_pkt_to_server(pkt_type, &frames, &mut buf) + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None) .unwrap(); assert_eq!(pipe.server.recv_count, recv_count + 1); @@ -13801,9 +15584,15 @@ mod tests { #[test] /// Tests that streams are correctly scheduled based on their priority. fn stream_priority() { - // Limit 1-RTT packet size to avoid congestion control interference. On V3, packets have - // a larger encrypted header, and we need a larger output buf to flush streams. - const MAX_TEST_PACKET_SIZE: usize = if PROTOCOL_VERSION == PROTOCOL_VERSION_V3 { 543 } else { 540 }; + // Limit 1-RTT packet size to avoid congestion control interference. On + // V3, packets have a larger encrypted header, and we need a + // larger output buf to flush streams. + const MAX_TEST_PACKET_SIZE: usize = + if PROTOCOL_VERSION == PROTOCOL_VERSION_V3 { + 543 + } else { + 540 + }; let mut buf = [0; 65535]; @@ -13828,88 +15617,166 @@ mod tests { let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); - assert_eq!(pipe.client.stream_send(0, b"a", false), Ok(1)); + let off_by = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + 4 + } else { + 0 + }; + + assert_eq!(pipe.client.stream_send(0 + off_by, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); - assert_eq!(pipe.client.stream_send(4, b"a", false), Ok(1)); + assert_eq!(pipe.client.stream_send(4 + off_by, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); - assert_eq!(pipe.client.stream_send(8, b"a", false), Ok(1)); + assert_eq!(pipe.client.stream_send(8 + off_by, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); - assert_eq!(pipe.client.stream_send(12, b"a", false), Ok(1)); + assert_eq!(pipe.client.stream_send(12 + off_by, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); - assert_eq!(pipe.client.stream_send(16, b"a", false), Ok(1)); + assert_eq!(pipe.client.stream_send(16 + off_by, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); - assert_eq!(pipe.client.stream_send(20, b"a", false), Ok(1)); + assert_eq!(pipe.client.stream_send(20 + off_by, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); let mut b = [0; 1]; let out = [b'b'; 500]; - // Server prioritizes streams as follows: + // Server prioritizes streams as follows (all + off_by): // * Stream 8 and 16 have the same priority but are non-incremental. // * Stream 4, 12 and 20 have the same priority but 20 is non-incremental // and 4 and 12 are incremental. // * Stream 0 is on its own. - pipe.server.stream_recv(0, &mut b).unwrap(); - assert_eq!(pipe.server.stream_priority(0, 255, true), Ok(())); - pipe.server.stream_send(0, &out, false).unwrap(); - pipe.server.stream_send(0, &out, false).unwrap(); - pipe.server.stream_send(0, &out, false).unwrap(); - - pipe.server.stream_recv(12, &mut b).unwrap(); - assert_eq!(pipe.server.stream_priority(12, 42, true), Ok(())); - pipe.server.stream_send(12, &out, false).unwrap(); - pipe.server.stream_send(12, &out, false).unwrap(); - pipe.server.stream_send(12, &out, false).unwrap(); - - pipe.server.stream_recv(16, &mut b).unwrap(); - assert_eq!(pipe.server.stream_priority(16, 10, false), Ok(())); - pipe.server.stream_send(16, &out, false).unwrap(); - pipe.server.stream_send(16, &out, false).unwrap(); - pipe.server.stream_send(16, &out, false).unwrap(); - - pipe.server.stream_recv(4, &mut b).unwrap(); - assert_eq!(pipe.server.stream_priority(4, 42, true), Ok(())); - pipe.server.stream_send(4, &out, false).unwrap(); - pipe.server.stream_send(4, &out, false).unwrap(); - pipe.server.stream_send(4, &out, false).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + pipe.server.stream_recv(0, &mut b).unwrap(); + } + assert_eq!(pipe.server.stream_priority(0 + off_by, 255, true), Ok(())); + pipe.server.stream_send(0 + off_by, &out, false).unwrap(); + pipe.server.stream_send(0 + off_by, &out, false).unwrap(); + pipe.server.stream_send(0 + off_by, &out, false).unwrap(); - pipe.server.stream_recv(8, &mut b).unwrap(); - assert_eq!(pipe.server.stream_priority(8, 10, false), Ok(())); - pipe.server.stream_send(8, &out, false).unwrap(); - pipe.server.stream_send(8, &out, false).unwrap(); - pipe.server.stream_send(8, &out, false).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(16, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(16, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + pipe.server.stream_recv(12, &mut b).unwrap(); + } + assert_eq!(pipe.server.stream_priority(12 + off_by, 42, true), Ok(())); + pipe.server.stream_send(12 + off_by, &out, false).unwrap(); + pipe.server.stream_send(12 + off_by, &out, false).unwrap(); + pipe.server.stream_send(12 + off_by, &out, false).unwrap(); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(20, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(20, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + pipe.server.stream_recv(16, &mut b).unwrap(); + } + assert_eq!(pipe.server.stream_priority(16 + off_by, 10, false), Ok(())); + pipe.server.stream_send(16 + off_by, &out, false).unwrap(); + pipe.server.stream_send(16 + off_by, &out, false).unwrap(); + pipe.server.stream_send(16 + off_by, &out, false).unwrap(); - pipe.server.stream_recv(20, &mut b).unwrap(); - assert_eq!(pipe.server.stream_priority(20, 42, false), Ok(())); - pipe.server.stream_send(20, &out, false).unwrap(); - pipe.server.stream_send(20, &out, false).unwrap(); - pipe.server.stream_send(20, &out, false).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(8, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(8, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + pipe.server.stream_recv(4, &mut b).unwrap(); + } + assert_eq!(pipe.server.stream_priority(4 + off_by, 42, true), Ok(())); + pipe.server.stream_send(4 + off_by, &out, false).unwrap(); + pipe.server.stream_send(4 + off_by, &out, false).unwrap(); + pipe.server.stream_send(4 + off_by, &out, false).unwrap(); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(12, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(12, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + pipe.server.stream_recv(8, &mut b).unwrap(); + } + assert_eq!(pipe.server.stream_priority(8 + off_by, 10, false), Ok(())); + pipe.server.stream_send(8 + off_by, &out, false).unwrap(); + pipe.server.stream_send(8 + off_by, &out, false).unwrap(); + pipe.server.stream_send(8 + off_by, &out, false).unwrap(); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(24, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(24, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + pipe.server.stream_recv(20, &mut b).unwrap(); + } + assert_eq!(pipe.server.stream_priority(20 + off_by, 42, false), Ok(())); + pipe.server.stream_send(20 + off_by, &out, false).unwrap(); + pipe.server.stream_send(20 + off_by, &out, false).unwrap(); + pipe.server.stream_send(20 + off_by, &out, false).unwrap(); - // First is stream 8. + // First is stream 8+off_by. let mut off = 0; for _ in 1..=3 { let (len, _) = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap(); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let stream = frames.first().unwrap(); - assert_eq!(stream, &frame::Frame::Stream { - stream_id: 8, - data: stream::RangeBuf::from(&out, off, false), - }); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!(stream, &frame::Frame::StreamV3 { + stream_id: 12, + metadata: stream::RecvBufInfo::from(off, out.len(), false), + }); + } else { + assert_eq!(stream, &frame::Frame::Stream { + stream_id: 8, + data: stream::RangeBuf::from(&out, off, false), + }); + } off = match stream { frame::Frame::Stream { data, .. } => data.max_off(), + frame::Frame::StreamV3 { metadata, .. } => metadata.max_off(), _ => unreachable!(), }; @@ -13922,17 +15789,29 @@ mod tests { let (len, _) = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap(); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let stream = frames.first().unwrap(); - assert_eq!(stream, &frame::Frame::Stream { - stream_id: 16, - data: stream::RangeBuf::from(&out, off, false), - }); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!(stream, &frame::Frame::StreamV3 { + stream_id: 20, + metadata: stream::RecvBufInfo::from(off, out.len(), false), + }); + } else { + assert_eq!(stream, &frame::Frame::Stream { + stream_id: 16, + data: stream::RangeBuf::from(&out, off, false), + }); + } off = match stream { frame::Frame::Stream { data, .. } => data.max_off(), + frame::Frame::StreamV3 { metadata, .. } => metadata.max_off(), _ => unreachable!(), }; @@ -13945,17 +15824,29 @@ mod tests { let (len, _) = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap(); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let stream = frames.first().unwrap(); - assert_eq!(stream, &frame::Frame::Stream { - stream_id: 20, - data: stream::RangeBuf::from(&out, off, false), - }); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!(stream, &frame::Frame::StreamV3 { + stream_id: 24, + metadata: stream::RecvBufInfo::from(off, out.len(), false), + }); + } else { + assert_eq!(stream, &frame::Frame::Stream { + stream_id: 20, + data: stream::RangeBuf::from(&out, off, false), + }); + } off = match stream { frame::Frame::Stream { data, .. } => data.max_off(), + frame::Frame::StreamV3 { metadata, .. } => metadata.max_off(), _ => unreachable!(), }; @@ -13968,32 +15859,62 @@ mod tests { let (len, _) = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap(); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); - assert_eq!( - frames.first(), - Some(&frame::Frame::Stream { - stream_id: 12, - data: stream::RangeBuf::from(&out, off, false), - }) - ); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + frames.first(), + Some(&frame::Frame::StreamV3 { + stream_id: 16, + metadata: stream::RecvBufInfo::from( + off, + out.len(), + false + ), + }) + ); + } else { + assert_eq!( + frames.first(), + Some(&frame::Frame::Stream { + stream_id: 12, + data: stream::RangeBuf::from(&out, off, false), + }) + ); + } let (len, _) = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap(); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let stream = frames.first().unwrap(); - assert_eq!(stream, &frame::Frame::Stream { - stream_id: 4, - data: stream::RangeBuf::from(&out, off, false), - }); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!(stream, &frame::Frame::StreamV3 { + stream_id: 8, + metadata: stream::RecvBufInfo::from(off, out.len(), false), + }); + } else { + assert_eq!(stream, &frame::Frame::Stream { + stream_id: 4, + data: stream::RangeBuf::from(&out, off, false), + }); + } off = match stream { frame::Frame::Stream { data, .. } => data.max_off(), + frame::Frame::StreamV3 { metadata, .. } => metadata.max_off(), _ => unreachable!(), }; @@ -14006,17 +15927,29 @@ mod tests { let (len, _) = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap(); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let stream = frames.first().unwrap(); - assert_eq!(stream, &frame::Frame::Stream { - stream_id: 0, - data: stream::RangeBuf::from(&out, off, false), - }); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!(stream, &frame::Frame::StreamV3 { + stream_id: 4, + metadata: stream::RecvBufInfo::from(off, out.len(), false), + }); + } else { + assert_eq!(stream, &frame::Frame::Stream { + stream_id: 0, + data: stream::RangeBuf::from(&out, off, false), + }); + } off = match stream { frame::Frame::Stream { data, .. } => data.max_off(), + frame::Frame::StreamV3 { metadata, .. } => metadata.max_off(), _ => unreachable!(), }; @@ -14051,9 +15984,6 @@ mod tests { let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); - assert_eq!(pipe.client.stream_send(0, b"a", false), Ok(1)); - assert_eq!(pipe.advance(), Ok(())); - assert_eq!(pipe.client.stream_send(4, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); @@ -14063,120 +15993,193 @@ mod tests { assert_eq!(pipe.client.stream_send(12, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); + assert_eq!(pipe.client.stream_send(16, b"a", false), Ok(1)); + assert_eq!(pipe.advance(), Ok(())); + let mut b = [0; 1]; - pipe.server.stream_recv(0, &mut b).unwrap(); - assert_eq!(pipe.server.stream_priority(0, 255, true), Ok(())); - pipe.server.stream_send(0, b"b", false).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert!(pipe + .server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .is_ok()); + } else { + pipe.server.stream_recv(4, &mut b).unwrap(); + } + assert_eq!(pipe.server.stream_priority(4, 255, true), Ok(())); + pipe.server.stream_send(4, b"b", false).unwrap(); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(16, &mut pipe.server_app_buffers) + .unwrap(); + assert!(pipe + .server + .stream_consumed(16, len, &mut pipe.server_app_buffers) + .is_ok()); + } else { + pipe.server.stream_recv(16, &mut b).unwrap(); + } + assert_eq!(pipe.server.stream_priority(16, 42, true), Ok(())); + pipe.server.stream_send(16, b"b", false).unwrap(); - pipe.server.stream_recv(12, &mut b).unwrap(); - assert_eq!(pipe.server.stream_priority(12, 42, true), Ok(())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(12, &mut pipe.server_app_buffers) + .unwrap(); + assert!(pipe + .server + .stream_consumed(12, len, &mut pipe.server_app_buffers) + .is_ok()); + } else { + pipe.server.stream_recv(12, &mut b).unwrap(); + } + assert_eq!(pipe.server.stream_priority(12, 10, true), Ok(())); pipe.server.stream_send(12, b"b", false).unwrap(); - pipe.server.stream_recv(8, &mut b).unwrap(); - assert_eq!(pipe.server.stream_priority(8, 10, true), Ok(())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(8, &mut pipe.server_app_buffers) + .unwrap(); + assert!(pipe + .server + .stream_consumed(8, len, &mut pipe.server_app_buffers) + .is_ok()); + } else { + pipe.server.stream_recv(8, &mut b).unwrap(); + } + assert_eq!(pipe.server.stream_priority(8, 42, true), Ok(())); pipe.server.stream_send(8, b"b", false).unwrap(); - pipe.server.stream_recv(4, &mut b).unwrap(); - assert_eq!(pipe.server.stream_priority(4, 42, true), Ok(())); - pipe.server.stream_send(4, b"b", false).unwrap(); + // Stream 4 is re-prioritized!!! + assert_eq!(pipe.server.stream_priority(4, 20, true), Ok(())); - // Stream 0 is re-prioritized!!! - assert_eq!(pipe.server.stream_priority(0, 20, true), Ok(())); - - // First is stream 8. + // First is stream 16. let (len, _) = pipe.server.send(&mut buf).unwrap(); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); if pipe.client.version == PROTOCOL_VERSION_V3 { // A minimum QUIC packet should have 12 bytes in the payload in V3. + assert_eq!(iter.next(), Some(&frame::Frame::Padding { len: 6 })); assert_eq!( iter.next(), - Some(&frame::Frame::Padding { - len: 6, + Some(&frame::Frame::StreamV3 { + stream_id: 12, + metadata: stream::RecvBufInfo::from(0, 1, false), + }) + ); + } else { + assert_eq!( + iter.next(), + Some(&frame::Frame::Stream { + stream_id: 12, + data: stream::RangeBuf::from(b"b", 0, false), }) ); } - assert_eq!( - iter.next(), - Some(&frame::Frame::Stream { - stream_id: 8, - data: stream::RangeBuf::from(b"b", 0, false), - }) - ); - - // Then is stream 0. + // Then is stream 4. let (len, _) = pipe.server.send(&mut buf).unwrap(); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); if pipe.server.version == PROTOCOL_VERSION_V3 { + assert_eq!(iter.next(), Some(&frame::Frame::Padding { len: 6 })); assert_eq!( iter.next(), - Some(&frame::Frame::Padding { - len: 6, + Some(&frame::Frame::StreamV3 { + stream_id: 4, + metadata: stream::RecvBufInfo::from(0, 1, false), + }) + ); + } else { + assert_eq!( + iter.next(), + Some(&frame::Frame::Stream { + stream_id: 4, + data: stream::RangeBuf::from(b"b", 0, false), }) ); } - assert_eq!( - iter.next(), - Some(&frame::Frame::Stream { - stream_id: 0, - data: stream::RangeBuf::from(b"b", 0, false), - }) - ); - // Then are stream 12 and 4, with the same priority. + // Then are stream 16 and 8, with the same priority. let (len, _) = pipe.server.send(&mut buf).unwrap(); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); if pipe.server.version == PROTOCOL_VERSION_V3 { + assert_eq!(iter.next(), Some(&frame::Frame::Padding { len: 6 })); assert_eq!( iter.next(), - Some(&frame::Frame::Padding { - len: 6, + Some(&frame::Frame::StreamV3 { + stream_id: 16, + metadata: stream::RecvBufInfo::from(0, 1, false), + }) + ); + } else { + assert_eq!( + iter.next(), + Some(&frame::Frame::Stream { + stream_id: 16, + data: stream::RangeBuf::from(b"b", 0, false), }) ); } - assert_eq!( - iter.next(), - Some(&frame::Frame::Stream { - stream_id: 12, - data: stream::RangeBuf::from(b"b", 0, false), - }) - ); let (len, _) = pipe.server.send(&mut buf).unwrap(); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); if pipe.server.version == PROTOCOL_VERSION_V3 { + assert_eq!(iter.next(), Some(&frame::Frame::Padding { len: 6 })); + assert_eq!( + iter.next(), + Some(&frame::Frame::StreamV3 { + stream_id: 8, + metadata: stream::RecvBufInfo::from(0, 1, false), + }) + ); + } else { assert_eq!( iter.next(), - Some(&frame::Frame::Padding { - len: 6, + Some(&frame::Frame::Stream { + stream_id: 8, + data: stream::RangeBuf::from(b"b", 0, false), }) ); } - assert_eq!( - iter.next(), - Some(&frame::Frame::Stream { - stream_id: 4, - data: stream::RangeBuf::from(b"b", 0, false), - }) - ); - assert_eq!(pipe.server.send(&mut buf), Err(Error::Done)); } @@ -14210,10 +16213,10 @@ mod tests { let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); - assert_eq!(pipe.client.stream_send(0, b"a", false), Ok(1)); + assert_eq!(pipe.client.stream_send(4, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); - assert_eq!(pipe.client.stream_send(4, b"a", false), Ok(1)); + assert_eq!(pipe.client.stream_send(8, b"a", false), Ok(1)); assert_eq!(pipe.advance(), Ok(())); let mut b = [0; 1]; @@ -14226,17 +16229,27 @@ mod tests { // STREAM frames. So we'll expect a mix of frame types regardless // of the order that the application writes things in. - pipe.server.stream_recv(0, &mut b).unwrap(); - assert_eq!(pipe.server.stream_priority(0, 255, true), Ok(())); - pipe.server.stream_send(0, &out, false).unwrap(); - pipe.server.stream_send(0, &out, false).unwrap(); - pipe.server.stream_send(0, &out, false).unwrap(); - + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + pipe.server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .unwrap(); + } else { + pipe.server.stream_recv(4, &mut b).unwrap(); + } assert_eq!(pipe.server.stream_priority(4, 255, true), Ok(())); pipe.server.stream_send(4, &out, false).unwrap(); pipe.server.stream_send(4, &out, false).unwrap(); pipe.server.stream_send(4, &out, false).unwrap(); + assert_eq!(pipe.server.stream_priority(8, 255, true), Ok(())); + pipe.server.stream_send(8, &out, false).unwrap(); + pipe.server.stream_send(8, &out, false).unwrap(); + pipe.server.stream_send(8, &out, false).unwrap(); + for _ in 1..=6 { assert_eq!(pipe.server.dgram_send(&out), Ok(())); } @@ -14249,8 +16262,12 @@ mod tests { let (len, _) = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap(); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut frame_iter = frames.iter(); assert_eq!(frame_iter.next().unwrap(), &frame::Frame::Datagram { @@ -14258,22 +16275,34 @@ mod tests { }); assert_eq!(frame_iter.next(), None); - // STREAM 0 + // STREAM 4 let (len, _) = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap(); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut frame_iter = frames.iter(); let stream = frame_iter.next().unwrap(); - assert_eq!(stream, &frame::Frame::Stream { - stream_id: 0, - data: stream::RangeBuf::from(&out, off_0, false), - }); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!(stream, &frame::Frame::StreamV3 { + stream_id: 4, + metadata: stream::RecvBufInfo::from(off_0, out.len(), false), + }); + } else { + assert_eq!(stream, &frame::Frame::Stream { + stream_id: 4, + data: stream::RangeBuf::from(&out, off_0, false), + }); + } off_0 = match stream { frame::Frame::Stream { data, .. } => data.max_off(), + frame::Frame::StreamV3 { metadata, .. } => metadata.max_off(), _ => unreachable!(), }; @@ -14283,8 +16312,12 @@ mod tests { let (len, _) = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap(); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut frame_iter = frames.iter(); assert_eq!(frame_iter.next().unwrap(), &frame::Frame::Datagram { @@ -14292,22 +16325,34 @@ mod tests { }); assert_eq!(frame_iter.next(), None); - // STREAM 4 + // STREAM 8 let (len, _) = pipe.server.send(&mut buf[..MAX_TEST_PACKET_SIZE]).unwrap(); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut frame_iter = frames.iter(); let stream = frame_iter.next().unwrap(); - assert_eq!(stream, &frame::Frame::Stream { - stream_id: 4, - data: stream::RangeBuf::from(&out, off_4, false), - }); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!(stream, &frame::Frame::StreamV3 { + stream_id: 8, + metadata: stream::RecvBufInfo::from(off_4, out.len(), false), + }); + } else { + assert_eq!(stream, &frame::Frame::Stream { + stream_id: 8, + data: stream::RangeBuf::from(&out, off_4, false), + }); + } off_4 = match stream { frame::Frame::Stream { data, .. } => data.max_off(), + frame::Frame::StreamV3 { metadata, .. } => metadata.max_off(), _ => unreachable!(), }; @@ -14360,21 +16405,35 @@ mod tests { 0, ); - let frames = - testing::decode_pkt(&mut pipe.server, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.server, + &mut buf[..len], + &mut pipe.server_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); // Skip ACK frame. iter.next(); - assert_eq!( - iter.next(), - Some(&frame::Frame::Stream { - stream_id: 4, - data: stream::RangeBuf::from(b"b", 0, false), - }) - ); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert_eq!( + iter.next(), + Some(&frame::Frame::StreamV3 { + stream_id: 4, + metadata: stream::RecvBufInfo::from(0, 1, false), + }) + ); + } else { + assert_eq!( + iter.next(), + Some(&frame::Frame::Stream { + stream_id: 4, + data: stream::RangeBuf::from(b"b", 0, false), + }) + ); + } assert_eq!(pipe.client.stats().retrans, 1); } @@ -14534,7 +16593,12 @@ mod tests { // Client receives the server flight and sends Handshake ACK, but it is // lost. - testing::process_flight(&mut pipe.client, flight).unwrap(); + testing::process_flight( + &mut pipe.client, + &mut pipe.client_app_buffers, + flight, + ) + .unwrap(); testing::emit_flight(&mut pipe.client).unwrap(); assert!(pipe.client.handshake_status().has_handshake_keys); @@ -14562,7 +16626,12 @@ mod tests { assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len)); let flight = testing::emit_flight(&mut pipe.server).unwrap(); - testing::process_flight(&mut pipe.client, flight).unwrap(); + testing::process_flight( + &mut pipe.client, + &mut pipe.client_app_buffers, + flight, + ) + .unwrap(); // Client sends Initial packet with ACK. let active_pid = @@ -14659,10 +16728,20 @@ mod tests { assert_eq!(pipe.server_recv(&mut buf[..len]), Ok(len)); let flight = testing::emit_flight(&mut pipe.client).unwrap(); - testing::process_flight(&mut pipe.server, flight).unwrap(); + testing::process_flight( + &mut pipe.server, + &mut pipe.server_app_buffers, + flight, + ) + .unwrap(); let flight = testing::emit_flight(&mut pipe.server).unwrap(); - testing::process_flight(&mut pipe.client, flight).unwrap(); + testing::process_flight( + &mut pipe.client, + &mut pipe.client_app_buffers, + flight, + ) + .unwrap(); assert_ne!(pipe.client.dgram_send_queue.byte_size(), 0); assert_ne!(pipe.client.dgram_send_queue.byte_size(), 1_000_000); @@ -14913,8 +16992,9 @@ mod tests { let max_dgram_size = pipe.client.dgram_max_writable_len().unwrap(); if pipe.client.version == PROTOCOL_VERSION_V3 { - // Tests use a 16-byte connection ID, so the max datagram frame payload - // size is (1200 byte-long packet - 42 bytes overhead) + // Tests use a 16-byte connection ID, so the max datagram frame + // payload size is (1200 byte-long packet - 42 bytes + // overhead) assert_eq!(max_dgram_size, 1158); } else { // size is (1200 byte-long packet - 40 bytes overhead) @@ -14985,7 +17065,17 @@ mod tests { // Client drains stream. let mut b = [0; 15]; - pipe.client.stream_recv(4, &mut b).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .client + .stream_recv_v3(4, &mut pipe.client_app_buffers) + .unwrap(); + pipe.client + .stream_consumed(4, len, &mut pipe.client_app_buffers) + .unwrap(); + } else { + pipe.client.stream_recv(4, &mut b).unwrap(); + } assert_eq!(pipe.advance(), Ok(())); assert!(!pipe.client.is_readable()); @@ -15035,27 +17125,22 @@ mod tests { let (len, _) = pipe.client.send(&mut buf).unwrap(); - let frames = - testing::decode_pkt(&mut pipe.server, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.server, + &mut buf[..len], + &mut pipe.server_app_buffers, + ) + .unwrap(); if pipe.server.version == PROTOCOL_VERSION_V3 { // Since we need 12 bytes min on V3 payload, // this test generates 2 padding bytes on V3. - assert_eq!( - frames[0], - frame::Frame::Padding { - len: 1, - } - ); - assert_eq!( - frames[1], - frame::Frame::ConnectionClose { - error_code: 0x1234, - frame_type: 0, - reason: b"hello?".to_vec(), - } - ); - } - else { + assert_eq!(frames[0], frame::Frame::Padding { len: 1 }); + assert_eq!(frames[1], frame::Frame::ConnectionClose { + error_code: 0x1234, + frame_type: 0, + reason: b"hello?".to_vec(), + }); + } else { assert_eq!( frames.first(), Some(&frame::Frame::ConnectionClose { @@ -15080,27 +17165,22 @@ mod tests { let (len, _) = pipe.client.send(&mut buf).unwrap(); - let frames = - testing::decode_pkt(&mut pipe.server, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.server, + &mut buf[..len], + &mut pipe.server_app_buffers, + ) + .unwrap(); if pipe.server.version == PROTOCOL_VERSION_V3 { // Since we need 12 bytes min on V3 payload, // this test generates 2 padding bytes on V3. - assert_eq!( - frames[0], - frame::Frame::Padding { - len: 2, - } - ); - assert_eq!( - frames[1], - frame::Frame::ApplicationClose { - error_code: 0x1234, - reason: b"hello!".to_vec(), - } - ); - } - else { + assert_eq!(frames[0], frame::Frame::Padding { len: 2 }); + assert_eq!(frames[1], frame::Frame::ApplicationClose { + error_code: 0x1234, + reason: b"hello!".to_vec(), + }); + } else { assert_eq!( frames.first(), Some(&frame::Frame::ApplicationClose { @@ -15122,7 +17202,11 @@ mod tests { // Client sends initial flight. let flight = testing::emit_flight(&mut pipe.client).unwrap(); assert_eq!( - testing::process_flight(&mut pipe.server, flight), + testing::process_flight( + &mut pipe.server, + &mut pipe.server_app_buffers, + flight + ), Err(Error::TlsFail) ); @@ -15138,7 +17222,12 @@ mod tests { Err(Error::Done) ); - testing::process_flight(&mut pipe.client, flight).unwrap(); + testing::process_flight( + &mut pipe.client, + &mut pipe.client_app_buffers, + flight, + ) + .unwrap(); // Connection should already be closed due the failure during key signing. assert_eq!( @@ -15177,7 +17266,12 @@ mod tests { // Client sends initial flight. let flight = testing::emit_flight(&mut pipe.client).unwrap(); - testing::process_flight(&mut pipe.server, flight).unwrap(); + testing::process_flight( + &mut pipe.server, + &mut pipe.server_app_buffers, + flight, + ) + .unwrap(); let flight = testing::emit_flight(&mut pipe.server).unwrap(); @@ -15187,16 +17281,26 @@ mod tests { // Server closes before connection is established. pipe.server.close(true, 123, b"fail whale").unwrap(); - testing::process_flight(&mut pipe.client, flight).unwrap(); + testing::process_flight( + &mut pipe.client, + &mut pipe.client_app_buffers, + flight, + ) + .unwrap(); // Connection is established on the client. assert!(pipe.client.is_established()); // Client sends after connection is established. - pipe.client.stream_send(0, b"badauthtoken", true).unwrap(); + pipe.client.stream_send(4, b"badauthtoken", true).unwrap(); let flight = testing::emit_flight(&mut pipe.client).unwrap(); - testing::process_flight(&mut pipe.server, flight).unwrap(); + testing::process_flight( + &mut pipe.server, + &mut pipe.server_app_buffers, + flight, + ) + .unwrap(); // Connection is not established on the server (and never will be) assert!(!pipe.server.is_established()); @@ -15227,28 +17331,42 @@ mod tests { // Client sends initial flight. let flight = testing::emit_flight(&mut pipe.client).unwrap(); - testing::process_flight(&mut pipe.server, flight).unwrap(); + testing::process_flight( + &mut pipe.server, + &mut pipe.server_app_buffers, + flight, + ) + .unwrap(); let flight = testing::emit_flight(&mut pipe.server).unwrap(); // Both connections are not established. assert!(!pipe.client.is_established() && !pipe.server.is_established()); - testing::process_flight(&mut pipe.client, flight).unwrap(); + testing::process_flight( + &mut pipe.client, + &mut pipe.client_app_buffers, + flight, + ) + .unwrap(); // Connection is established on the client. assert!(pipe.client.is_established()); // Client sends after connection is established. - if pipe.client.version == PROTOCOL_VERSION_V3 { - pipe.client.stream_send(2, b"badauthtoken", true).unwrap(); - } - else { + if pipe.client.version == PROTOCOL_VERSION_V3 { + pipe.client.stream_send(4, b"badauthtoken", true).unwrap(); + } else { pipe.client.stream_send(0, b"badauthtoken", true).unwrap(); } let flight = testing::emit_flight(&mut pipe.client).unwrap(); - testing::process_flight(&mut pipe.server, flight).unwrap(); + testing::process_flight( + &mut pipe.server, + &mut pipe.server_app_buffers, + flight, + ) + .unwrap(); // Connection is established on the server but the Handshake ACK has not // been sent yet. @@ -15387,6 +17505,18 @@ mod tests { &mut server_config, ) .unwrap(), + client_app_buffers: AppRecvBufMap::new( + 3, + stream::MAX_STREAM_WINDOW, + 100, + 100, + ), + server_app_buffers: AppRecvBufMap::new( + 3, + stream::MAX_STREAM_WINDOW, + 100, + 100, + ), }; // Before handshake @@ -15449,9 +17579,6 @@ mod tests { let mut pipe = testing::Pipe::with_config(&mut config).unwrap(); assert_eq!(pipe.handshake(), Ok(())); - assert_eq!(pipe.client.stream_send(0, b"hello!", true), Ok(6)); - assert_eq!(pipe.advance(), Ok(())); - assert_eq!(pipe.client.stream_send(4, b"hello!", true), Ok(6)); assert_eq!(pipe.advance(), Ok(())); @@ -15461,27 +17588,44 @@ mod tests { assert_eq!(pipe.client.stream_send(12, b"hello!", true), Ok(6)); assert_eq!(pipe.advance(), Ok(())); + assert_eq!(pipe.client.stream_send(16, b"hello!", true), Ok(6)); + assert_eq!(pipe.advance(), Ok(())); + let mut r = pipe.server.readable().collect::>(); assert_eq!(r.len(), 4); r.sort(); - assert_eq!(r, [0, 4, 8, 12]); + assert_eq!(r, [4, 8, 12, 16]); - assert_eq!(pipe.server.stream_recv(0, &mut buf), Ok((6, true))); - assert_eq!(pipe.server.stream_recv(4, &mut buf), Ok((6, true))); - assert_eq!(pipe.server.stream_recv(8, &mut buf), Ok((6, true))); - assert_eq!(pipe.server.stream_recv(12, &mut buf), Ok((6, true))); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + for i in (4..16).step_by(4) { + let (_, len, is_fin) = pipe + .server + .stream_recv_v3(i, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (6, true)); + assert!(pipe + .server + .stream_consumed(i, len, &mut pipe.server_app_buffers) + .is_ok()); + } + } else { + assert_eq!(pipe.server.stream_recv(4, &mut buf), Ok((6, true))); + assert_eq!(pipe.server.stream_recv(8, &mut buf), Ok((6, true))); + assert_eq!(pipe.server.stream_recv(12, &mut buf), Ok((6, true))); + assert_eq!(pipe.server.stream_recv(16, &mut buf), Ok((6, true))); + } assert_eq!(pipe.server.tx_cap, 12000); - assert_eq!(pipe.server.stream_send(0, &buf[..5000], false), Ok(5000)); assert_eq!(pipe.server.stream_send(4, &buf[..5000], false), Ok(5000)); - assert_eq!(pipe.server.stream_send(8, &buf[..5000], false), Ok(2000)); + assert_eq!(pipe.server.stream_send(8, &buf[..5000], false), Ok(5000)); + assert_eq!(pipe.server.stream_send(12, &buf[..5000], false), Ok(2000)); // No more connection send capacity. assert_eq!( - pipe.server.stream_send(12, &buf[..5000], false), + pipe.server.stream_send(16, &buf[..5000], false), Err(Error::Done) ); assert_eq!(pipe.server.tx_cap, 0); @@ -15582,7 +17726,18 @@ mod tests { // Server reads stream data. let mut b = [0; 15]; - pipe.server.stream_recv(4, &mut b).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert!(pipe + .server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .is_ok()); + } else { + pipe.server.stream_recv(4, &mut b).unwrap(); + } // Server sends stream data close to cwnd (12000). let buf = [0; 10000]; @@ -15616,7 +17771,7 @@ mod tests { }]; let pkt_type = packet::Type::Short; - pipe.send_pkt_to_server(pkt_type, &frames, &mut buf) + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, Some(4)) .unwrap(); } @@ -15725,7 +17880,11 @@ mod tests { }; assert_eq!( - pipe.server.recv(&mut buf[..written], info), + pipe.server.recv( + &mut buf[..written], + &mut pipe.server_app_buffers, + info + ), Err(Error::InvalidFrame) ); @@ -15735,8 +17894,12 @@ mod tests { Err(_) => unreachable!(), }; - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..written]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..written], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { @@ -15800,7 +17963,11 @@ mod tests { }; assert_eq!( - pipe.server.recv(&mut buf[..written], info), + pipe.server.recv( + &mut buf[..written], + &mut pipe.server_app_buffers, + info + ), Err(Error::InvalidFrame) ); @@ -15810,8 +17977,12 @@ mod tests { Err(_) => unreachable!(), }; - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..written]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..written], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { @@ -16081,7 +18252,11 @@ mod tests { }; assert_eq!( - pipe.server.recv(&mut buf[..written], info), + pipe.server.recv( + &mut buf[..written], + &mut pipe.server_app_buffers, + info + ), Err(Error::IdLimit) ); @@ -16091,12 +18266,16 @@ mod tests { Err(_) => unreachable!(), }; - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..written]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..written], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { - iter.next(); //drop padding + iter.next(); // drop padding } assert_eq!( @@ -16400,7 +18579,14 @@ mod tests { flight .iter_mut() .for_each(|(_, si)| si.from = "127.0.0.1:9292".parse().unwrap()); - assert_eq!(testing::process_flight(&mut pipe.client, flight), Ok(())); + assert_eq!( + testing::process_flight( + &mut pipe.client, + &mut pipe.client_app_buffers, + flight + ), + Ok(()) + ); assert_eq!(pipe.client.paths.len(), 1); } @@ -16427,6 +18613,7 @@ mod tests { // Limited MTU of 1199 bytes for some reason. testing::process_flight( &mut pipe.server, + &mut pipe.server_app_buffers, testing::emit_flight_with_max_buffer( &mut pipe.client, 1199, @@ -16438,6 +18625,7 @@ mod tests { .expect("error when processing client packets"); testing::process_flight( &mut pipe.client, + &mut pipe.client_app_buffers, testing::emit_flight(&mut pipe.server).expect("no packet"), ) .expect("error when processing client packets"); @@ -16509,8 +18697,12 @@ mod tests { flight .iter_mut() .for_each(|(_, si)| si.from = client_addr_3); - testing::process_flight(&mut pipe.server, flight) - .expect("failed to process"); + testing::process_flight( + &mut pipe.server, + &mut pipe.server_app_buffers, + flight, + ) + .expect("failed to process"); assert_eq!(pipe.server.paths.len(), 2); assert_eq!( pipe.server.path_event_next(), @@ -16596,7 +18788,11 @@ mod tests { to: si.to, from: si.from, }; - assert_eq!(pipe.server.recv(&mut buf[..sent], ri), Ok(sent)); + assert_eq!( + pipe.server + .recv(&mut buf[..sent], &mut pipe.server_app_buffers, ri), + Ok(sent) + ); let stats = pipe.server.stats(); assert_eq!(stats.path_challenge_rx_count, 1); @@ -16640,7 +18836,11 @@ mod tests { to: si.to, from: si.from, }; - assert_eq!(pipe.server.recv(&mut buf[..sent], ri), Ok(sent)); + assert_eq!( + pipe.server + .recv(&mut buf[..sent], &mut pipe.server_app_buffers, ri), + Ok(sent) + ); let stats = pipe.server.stats(); assert_eq!(stats.path_challenge_rx_count, 2); @@ -16657,7 +18857,11 @@ mod tests { to: si.to, from: si.from, }; - assert_eq!(pipe.server.recv(&mut buf[..sent], ri), Ok(sent)); + assert_eq!( + pipe.server + .recv(&mut buf[..sent], &mut pipe.server_app_buffers, ri), + Ok(sent) + ); let stats = pipe.server.stats(); assert_eq!(stats.path_challenge_rx_count, 2); @@ -16675,7 +18879,11 @@ mod tests { to: si.to, from: si.from, }; - assert_eq!(pipe.server.recv(&mut buf[..sent], ri), Ok(sent)); + assert_eq!( + pipe.server + .recv(&mut buf[..sent], &mut pipe.server_app_buffers, ri), + Ok(sent) + ); let stats = pipe.server.stats(); assert_eq!(stats.path_challenge_rx_count, 3); @@ -16692,7 +18900,11 @@ mod tests { to: si.to, from: si.from, }; - assert_eq!(pipe.server.recv(&mut buf[..sent], ri), Ok(sent)); + assert_eq!( + pipe.server + .recv(&mut buf[..sent], &mut pipe.server_app_buffers, ri), + Ok(sent) + ); // No more data to exchange leads to Error::Done. assert_eq!( @@ -17075,8 +19287,22 @@ mod tests { assert_eq!(pipe.client.stream_send(4, b"data", true), Ok(4)); let second = testing::emit_flight(&mut pipe.client).unwrap(); // Second flight is received before first one. - assert_eq!(testing::process_flight(&mut pipe.server, second), Ok(())); - assert_eq!(testing::process_flight(&mut pipe.server, first), Ok(())); + assert_eq!( + testing::process_flight( + &mut pipe.server, + &mut pipe.server_app_buffers, + second + ), + Ok(()) + ); + assert_eq!( + testing::process_flight( + &mut pipe.server, + &mut pipe.server_app_buffers, + first + ), + Ok(()) + ); // Server does not perform connection migration because of packet // reordering. @@ -17123,11 +19349,24 @@ mod tests { assert_eq!( testing::process_flight( &mut pipe.client, + &mut pipe.client_app_buffers, testing::emit_flight(&mut pipe.server).unwrap() ), Ok(()) ); - let (rcv_data_1, _) = pipe.client.stream_recv(1, &mut recv_buf).unwrap(); + let (rcv_data_1, _) = + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, _) = pipe + .client + .stream_recv_v3(1, &mut pipe.client_app_buffers) + .unwrap(); + pipe.client + .stream_consumed(1, len, &mut pipe.client_app_buffers) + .unwrap(); + (len, false) + } else { + pipe.client.stream_recv(1, &mut recv_buf).unwrap() + }; // Fake the source address of client. let mut faked_addr_flight = @@ -17136,7 +19375,11 @@ mod tests { .iter_mut() .for_each(|(_, si)| si.from = spoofed_client_addr); assert_eq!( - testing::process_flight(&mut pipe.server, faked_addr_flight), + testing::process_flight( + &mut pipe.server, + &mut pipe.server_app_buffers, + faked_addr_flight + ), Ok(()) ); assert_eq!(pipe.server.stream_send(1, &buf[12000..], true), Ok(12000)); @@ -17211,7 +19454,18 @@ mod tests { assert_eq!(server_active_path.peer_addr(), client_addr); assert_eq!(pipe.advance(), Ok(())); let (rcv_data_2, fin) = - pipe.client.stream_recv(1, &mut recv_buf).unwrap(); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, is_fin) = pipe + .client + .stream_recv_v3(1, &mut pipe.client_app_buffers) + .unwrap(); + pipe.client + .stream_consumed(1, len, &mut pipe.client_app_buffers) + .unwrap(); + (len, is_fin) + } else { + pipe.client.stream_recv(1, &mut recv_buf).unwrap() + }; assert!(fin); assert_eq!(rcv_data_1 + rcv_data_2, DATA_BYTES); } @@ -17229,38 +19483,46 @@ mod tests { let pkt_type = packet::Type::Short; for _ in 0..24 { let len = pipe - .send_pkt_to_server(pkt_type, &frames, &mut buf) + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) .unwrap(); assert!(len > 0); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); if pipe.client.version == PROTOCOL_VERSION_V3 { assert!( - frames - .iter() - .all(|frame| matches!(frame, frame::Frame::ACK { .. } | - frame::Frame::Padding { .. })), - "ACK and Padding only" + frames.iter().all(|frame| matches!( + frame, + frame::Frame::ACK { .. } | frame::Frame::Padding { .. } + )), + "ACK and Padding only" ); } else { assert!( frames .iter() .all(|frame| matches!(frame, frame::Frame::ACK { .. })), - "ACK only" + "ACK only" ); } } // After 24 non-ack-eliciting, an ACK is explicitly elicited with a PING let len = pipe - .send_pkt_to_server(pkt_type, &frames, &mut buf) + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) .unwrap(); assert!(len > 0); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); assert!( frames .iter() @@ -17284,8 +19546,12 @@ mod tests { let mut buf = [0; 1500]; let (len, _) = pipe.server.send(&mut buf).unwrap(); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); if pipe.client.version == PROTOCOL_VERSION_V3 { // Skip the padding @@ -17312,8 +19578,12 @@ mod tests { let mut buf = [0; 1500]; let (len, _) = pipe.server.send(&mut buf).unwrap(); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); if pipe.client.version == PROTOCOL_VERSION_V3 { @@ -17321,13 +19591,24 @@ mod tests { // to match the 12 payload bytes requirement. iter.next().unwrap(); } - assert!(matches!( - iter.next(), - Some(&frame::Frame::Stream { - stream_id: 1, - data: _ - }) - )); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert!(matches!( + iter.next(), + Some(&frame::Frame::StreamV3 { + stream_id: 1, + metadata: _ + }) + )); + } else { + assert!(matches!( + iter.next(), + Some(&frame::Frame::Stream { + stream_id: 1, + data: _ + }) + )); + } assert!(iter.next().is_none()); } @@ -17365,7 +19646,6 @@ mod tests { assert_eq!(pipe.server.writable().len(), 0); // Client opens a load of streams - assert_eq!(pipe.client.stream_send(0, b"hello", true), Ok(5)); assert_eq!(pipe.client.stream_send(4, b"hello", true), Ok(5)); assert_eq!(pipe.client.stream_send(8, b"hello", true), Ok(5)); assert_eq!(pipe.client.stream_send(12, b"hello", true), Ok(5)); @@ -17375,12 +19655,12 @@ mod tests { assert_eq!(pipe.client.stream_send(28, b"hello", true), Ok(5)); assert_eq!(pipe.client.stream_send(32, b"hello", true), Ok(5)); assert_eq!(pipe.client.stream_send(36, b"hello", true), Ok(5)); + assert_eq!(pipe.client.stream_send(40, b"hello", true), Ok(5)); assert_eq!(pipe.advance(), Ok(())); // Server iterators are populated let mut r = pipe.server.readable(); assert_eq!(r.len(), 10); - assert_eq!(r.next(), Some(0)); assert_eq!(r.next(), Some(4)); assert_eq!(r.next(), Some(8)); assert_eq!(r.next(), Some(12)); @@ -17390,12 +19670,12 @@ mod tests { assert_eq!(r.next(), Some(28)); assert_eq!(r.next(), Some(32)); assert_eq!(r.next(), Some(36)); + assert_eq!(r.next(), Some(40)); assert_eq!(r.next(), None); let mut w = pipe.server.writable(); assert_eq!(w.len(), 10); - assert_eq!(w.next(), Some(0)); assert_eq!(w.next(), Some(4)); assert_eq!(w.next(), Some(8)); assert_eq!(w.next(), Some(12)); @@ -17405,20 +19685,33 @@ mod tests { assert_eq!(w.next(), Some(28)); assert_eq!(w.next(), Some(32)); assert_eq!(w.next(), Some(36)); + assert_eq!(w.next(), Some(40)); assert_eq!(w.next(), None); // Read one stream - assert_eq!(pipe.server.stream_recv(0, &mut b), Ok((5, true))); - assert!(pipe.server.stream_finished(0)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + let (_, len, is_fin) = pipe + .server + .stream_recv_v3(4, &mut pipe.server_app_buffers) + .unwrap(); + assert_eq!((len, is_fin), (5, true)); + assert!(pipe + .server + .stream_consumed(4, len, &mut pipe.server_app_buffers) + .is_ok()); + } else { + assert_eq!(pipe.server.stream_recv(4, &mut b), Ok((5, true))); + } + assert!(pipe.server.stream_finished(4)); assert_eq!(pipe.server.readable().len(), 9); assert_eq!(pipe.server.writable().len(), 10); - assert_eq!(pipe.server.stream_writable(0, 0), Ok(true)); + assert_eq!(pipe.server.stream_writable(4, 0), Ok(true)); - // Server sends data on stream 0, until blocked. + // Server sends data on stream 4, until blocked. loop { - if pipe.server.stream_send(0, b"world", false) == Err(Error::Done) { + if pipe.server.stream_send(4, b"world", false) == Err(Error::Done) { break; } @@ -17426,22 +19719,26 @@ mod tests { } assert_eq!(pipe.server.writable().len(), 9); - assert_eq!(pipe.server.stream_writable(0, 0), Ok(true)); + assert_eq!(pipe.server.stream_writable(4, 0), Ok(true)); // Client sends STOP_SENDING. let frames = [frame::Frame::StopSending { - stream_id: 0, + stream_id: 4, error_code: 42, }]; let pkt_type = packet::Type::Short; let len = pipe - .send_pkt_to_server(pkt_type, &frames, &mut buf) + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) .unwrap(); // Server sent a RESET_STREAM frame in response. - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); @@ -17451,20 +19748,20 @@ mod tests { assert_eq!( iter.next(), Some(&frame::Frame::ResetStream { - stream_id: 0, + stream_id: 4, error_code: 42, final_size: 30, }) ); - // Stream 0 is now writable in order to make apps aware of STOP_SENDING + // Stream 4 is now writable in order to make apps aware of STOP_SENDING // via returning an error. let mut w = pipe.server.writable(); assert_eq!(w.len(), 10); - assert!(w.any(|s| s == 0)); + assert!(w.any(|s| s == 4)); assert_eq!( - pipe.server.stream_writable(0, 1), + pipe.server.stream_writable(4, 1), Err(Error::StreamStopped(42)) ); @@ -17481,30 +19778,36 @@ mod tests { ecn_counts: None, }]; - assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), Ok(0)); + assert_eq!( + pipe.send_pkt_to_server(pkt_type, &frames, &mut buf, None), + Ok(0) + ); // Stream is collected on the server after RESET_STREAM is acked. assert_eq!(pipe.server.streams.len(), 9); // Sending STOP_SENDING again shouldn't trigger RESET_STREAM again. let frames = [frame::Frame::StopSending { - stream_id: 0, + stream_id: 4, error_code: 42, }]; let len = pipe - .send_pkt_to_server(pkt_type, &frames, &mut buf) + .send_pkt_to_server(pkt_type, &frames, &mut buf, None) .unwrap(); - let frames = - testing::decode_pkt(&mut pipe.client, &mut buf[..len]).unwrap(); + let frames = testing::decode_pkt( + &mut pipe.client, + &mut buf[..len], + &mut pipe.client_app_buffers, + ) + .unwrap(); let mut iter = frames.iter(); if pipe.client.version == PROTOCOL_VERSION_V3 { assert_eq!(frames.len(), 2); iter.next().unwrap(); - } - else { + } else { assert_eq!(frames.len(), 1); } @@ -17516,14 +19819,14 @@ mod tests { assert_eq!(pipe.server.streams.len(), 9); - // Stream 0 has been collected and must not be writable anymore. + // Stream 4 has been collected and must not be writable anymore. let mut w = pipe.server.writable(); assert_eq!(w.len(), 9); assert!(!w.any(|s| s == 0)); // If we called send before the client ACK of reset stream, it would // have failed with StreamStopped. - assert_eq!(pipe.server.stream_send(0, b"world", true), Err(Error::Done),); + assert_eq!(pipe.server.stream_send(4, b"world", true), Err(Error::Done),); // Stream 0 is still not writable. let mut w = pipe.server.writable(); @@ -17600,7 +19903,9 @@ mod tests { let payload_offset = b.off(); for frame in frames { - frame.to_bytes(&mut b, pipe.client.version).expect("encode frames"); + frame + .to_bytes(&mut b, pipe.client.version) + .expect("encode frames"); } let aead = space.crypto_seal.as_ref().expect("crypto seal"); @@ -17613,16 +19918,20 @@ mod tests { payload_offset, None, aead, - pipe.client.version + pipe.client.version, ) .expect("packet encrypt"); space.next_pkt_num += 1; pipe.server - .recv(&mut pkt_buf[..written], RecvInfo { - to: server_addr, - from: client_addr_2, - }) + .recv( + &mut pkt_buf[..written], + &mut pipe.server_app_buffers, + RecvInfo { + to: server_addr, + from: client_addr_2, + }, + ) .expect("server receive path challenge"); // Show that the new path is not considered a destination path by quiche @@ -17744,6 +20053,8 @@ pub use crate::recovery::CongestionControlAlgorithm; pub use crate::stream::StreamIter; +pub use crate::stream::app_recv_buf::AppRecvBufMap; + mod cid; mod crypto; mod dgram; diff --git a/quiche/src/packet.rs b/quiche/src/packet.rs index fc778a45..1772c0b9 100644 --- a/quiche/src/packet.rs +++ b/quiche/src/packet.rs @@ -64,7 +64,7 @@ pub enum Epoch { } static EPOCHS: [Epoch; 3] = -[Epoch::Initial, Epoch::Handshake, Epoch::Application]; + [Epoch::Initial, Epoch::Handshake, Epoch::Application]; impl Epoch { /// Returns an ordered slice containing the `Epoch`s that fit in the @@ -92,7 +92,7 @@ impl From for usize { impl Index for [T] where -T: Sized, + T: Sized, { type Output = T; @@ -103,7 +103,7 @@ T: Sized, impl IndexMut for [T] where -T: Sized, + T: Sized, { fn index_mut(&mut self, index: Epoch) -> &mut Self::Output { self.index_mut(usize::from(index)) @@ -111,9 +111,10 @@ T: Sized, } /// QUIC packet type. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] pub enum Type { /// Initial packet. + #[default] Initial, /// Retry packet. @@ -176,10 +177,6 @@ impl Type { } } -impl Default for Type { - fn default() -> Self { Type::Initial } -} - /// A QUIC connection ID. pub struct ConnectionId<'a>(ConnectionIdInner<'a>); @@ -311,21 +308,23 @@ pub struct Header<'a> { /// protection is removed. pub(crate) pkt_num_len: usize, - /// The expected Streamid of the leftmost stream frame within the packet, if any. - /// It's only meaningful if version is PROTOCOL_VERSION_V3 and after the - /// header protection is removed. + /// The expected Streamid of the leftmost stream frame within the packet, if + /// any. It's only meaningful if version is PROTOCOL_VERSION_V3 and + /// after the header protection is removed. pub(crate) expected_stream_id: u64, - /// The expected offset of the data within the leftmost stream frame within the packet. - /// It is only meaningful if version is PROTOCOL_VERSION_V3, and if the packets contains - /// a stream frame matching expected_stream_id. - pub(crate) expected_offset: u64, + /// The expected offset of the data within the leftmost stream frame within + /// the packet. It is only meaningful if version is PROTOCOL_VERSION_V3, + /// and if the packets contains a stream frame matching + /// expected_stream_id. + pub(crate) truncated_offset: u64, /// The length of the offset number. It's only meaningful after the header /// protection is removed. - pub(crate) expected_offset_len: usize, + pub(crate) truncated_offset_len: usize, - /// The length of the stream_id. It's only meaningful after header decryption. + /// The length of the stream_id. It's only meaningful after header + /// decryption. pub(crate) expected_stream_id_len: usize, /// The address verification token of the packet. Only present in `Initial` @@ -362,14 +361,14 @@ impl<'a> Header<'a> { #[inline] pub fn from_slice<'b>( buf: &'b mut [u8], dcid_len: usize, - ) -> Result> { + ) -> Result> { let mut b = octets::OctetsMut::with_slice(buf); Header::from_bytes(&mut b, dcid_len) } pub(crate) fn from_bytes<'b>( b: &'b mut octets::OctetsMut, dcid_len: usize, - ) -> Result> { + ) -> Result> { let first = b.get_u8()?; if !Header::is_long(first) { @@ -576,41 +575,45 @@ impl<'a> std::fmt::Debug for Header<'a> { /// bits are containing information for the length of the next /// element. pub fn num_len_to_encode(num: u64) -> usize { - if num <= 63 { - 0 - } else if num < 16383 { - 1 - } else if num < 1_073_741_823 { - 2 - } else { - 3 - } + if num <= 63u64 { + 0 + } else if num < 16_383u64 { + 1 + } else if num < 1_073_741_823u64 { + 2 + } else { + 3 + } } -/// This should be base10 binary encoding of the 4 possible byte lengths, 1, 2, 3 or 4. -/// so it should returns 0,1,2 or 3 +/// Works as QUIC V1 pkt_num_len to encode the offset in maximum 4 bytes. #[inline] -pub fn offset_len_to_encode(offset: u64) -> Result { - pkt_num_len(offset) +pub fn truncated_offset_len(offset: u64, largest_offset_acked: u64) -> usize { + pkt_num_len(offset, largest_offset_acked) } #[inline] -pub fn pkt_num_len(pn: u64) -> Result { - let len = if pn < u64::from(u8::MAX) { - 1 - } else if pn < u64::from(u16::MAX) { - 2 - } else if pn < 16_777_215u64 { - 3 - } else if pn < u64::from(u32::MAX) { - 4 - } else { - return Err(Error::InvalidPacket); - }; - Ok(len) +pub fn pkt_num_len(pn: u64, largest_acked: u64) -> usize { + let num_unacked: u64 = pn.saturating_sub(largest_acked); + // computes ceil of num_unacked.log2() + let min_bits = u64::BITS - num_unacked.leading_zeros() + 1; + // get the num len in bytes + (min_bits as f32 / 8.).ceil() as usize } + +/// In Reverso, 2 bits of the pn are reserved to indicate length of the stream +/// id. #[inline] -pub fn unpack_var_int_in_hdr(len: usize, b: &mut octets::Octets) -> Result{ +pub fn pkt_num_len_v3(pn: u64, largest_acked: u64) -> usize { + let num_unacked: u64 = pn.saturating_sub(largest_acked) + 1; + // computes ceil of num_unacked.log2() + let min_bits = u64::BITS - num_unacked.leading_zeros() + 2; + // get the num len in bytes + (min_bits as f32 / 8.).ceil() as usize +} + +#[inline] +pub fn unpack_var_int_in_hdr(len: usize, b: &mut octets::Octets) -> Result { let val = match len { 1 => u64::from(b.get_u8()?), @@ -627,13 +630,13 @@ pub fn unpack_var_int_in_hdr(len: usize, b: &mut octets::Octets) -> Result{ pub fn decrypt_hdr( b: &mut octets::OctetsMut, hdr: &mut Header, aead: &crypto::Open, version: u32, - ) -> Result<()> { +) -> Result<()> { let mut first = { let (first_buf, _) = b.split_at(1)?; first_buf.as_ref()[0] }; - if_likely!{version == crate::PROTOCOL_VERSION_V3 => { + if_likely! {version == crate::PROTOCOL_VERSION_V3 => { let mut pn_stream_and_sample = b.peek_bytes_mut(MAX_PKT_NUM_STREAMID_OFFSET_LEN + SAMPLE_LEN)?; let (mut ciphertext, sample) = pn_stream_and_sample.split_at(MAX_PKT_NUM_STREAMID_OFFSET_LEN)?; @@ -686,8 +689,8 @@ pub fn decrypt_hdr( first_buf.as_mut()[0] = first; hdr.expected_stream_id = stream_id; hdr.expected_stream_id_len = streamid_len; - hdr.expected_offset = offset; - hdr.expected_offset_len = offset_len; + hdr.truncated_offset = offset; + hdr.truncated_offset_len = offset_len; hdr.pkt_num = pn; hdr.pkt_num_len = pn_len; @@ -752,7 +755,7 @@ pub fn decrypt_hdr( } #[inline] -pub fn decode_num_and_nextelem_len(num: u64, num_len: usize) -> (u64, usize) { +pub fn decode_num_and_nextelem_len(num: u64, num_len: usize) -> (u64, usize) { let (num, nextelem_len) = match num_len { 1 => (num & 0x3f, (num >> 6) as usize), 2 => (num & 0x3fff, (num >> 14) as usize), @@ -760,11 +763,46 @@ pub fn decode_num_and_nextelem_len(num: u64, num_len: usize) -> (u64, usize) { 4 => (num & 0x3fffffff, (num >> 30) as usize), _ => panic!("Unvalid num_len"), // Internal bug }; - (num, nextelem_len+1) + (num, nextelem_len + 1) +} + +#[inline] +pub fn decode_pkt_num_v3( + largest_pn: u64, truncated_pn: u64, pn_len: usize, +) -> u64 { + trace!( + "Decoding with Largest: {}, truncated: {}, len: {}", + largest_pn, + truncated_pn, + pn_len + ); + let pn_nbits = pn_len * 8 - 2; + let expected_pn = largest_pn + 1; + let pn_win = 1 << pn_nbits; + let pn_hwin = pn_win / 2; + let pn_mask = pn_win - 1; + let candidate_pn = (expected_pn & !pn_mask) | truncated_pn; + + if candidate_pn + pn_hwin <= expected_pn && candidate_pn < (1 << 60) - pn_win + { + return candidate_pn + pn_win; + } + + if candidate_pn > expected_pn + pn_hwin && candidate_pn >= pn_win { + return candidate_pn - pn_win; + } + + candidate_pn } #[inline] pub fn decode_pkt_num(largest_pn: u64, truncated_pn: u64, pn_len: usize) -> u64 { + trace!( + "Decoding with Largest: {}, truncated: {}, len: {}", + largest_pn, + truncated_pn, + pn_len + ); let pn_nbits = pn_len * 8; let expected_pn = largest_pn + 1; let pn_win = 1 << pn_nbits; @@ -783,15 +821,19 @@ pub fn decode_pkt_num(largest_pn: u64, truncated_pn: u64, pn_len: usize) -> u64 candidate_pn } + #[inline] -pub fn decode_pkt_offset(current_offset: u64, truncated_offset: u64, offset_len: usize) -> u64 { - decode_pkt_num(current_offset, truncated_offset, offset_len) +pub fn decode_pkt_offset( + largest_offset: u64, truncated_offset: u64, offset_len: usize, +) -> u64 { + decode_pkt_num(largest_offset, truncated_offset, offset_len) } pub fn decrypt_pkt_v3<'a>( - b: &'a mut octets::OctetsMut, pn: u64, hdr_enc_len: usize, payload_len: usize, - _stream_id: u64, _offset: u64, aead: &crypto::Open, - ) -> Result<(octets::Octets<'a>, usize)> { + b: &'a mut octets::OctetsMut, pn: u64, hdr_enc_len: usize, + payload_len: usize, outbuf: Option<&'a mut octets::OctetsMut>, + aead: &crypto::Open, +) -> Result<(octets::Octets<'a>, usize)> { // PROTOCOL_REVERSO: temporary for testing let payload_offset = b.off(); @@ -802,23 +844,28 @@ pub fn decrypt_pkt_v3<'a>( .ok_or(Error::InvalidPacket)?; let mut ciphertext = payload.peek_bytes_mut(payload_len_enc)?; - - let payload_len = - aead.open_with_u64_counter(pn, header.as_ref(), ciphertext.as_mut())?; - - let mut bytestring = String::new(); - for &byte in &b.as_ref()[..payload_len] { - let part: Vec = std::ascii::escape_default(byte).collect(); - bytestring.push_str(std::str::from_utf8(&part).unwrap()); + if let Some(outbuf) = outbuf { + let payload_len = aead.open_with_u64_counter_into( + pn, + header.as_ref(), + ciphertext.as_ref(), + outbuf.as_mut(), + )?; + // Number of read bytes is computed from b's offset. We need skip since + // we process the frame from another buffer in V3. + b.skip(payload_len)?; + Ok((outbuf.get_bytes(payload_len)?, payload_len)) + } else { + let payload_len = + aead.open_with_u64_counter(pn, header.as_ref(), ciphertext.as_mut())?; + Ok((b.get_bytes(payload_len)?, payload_len)) } - - Ok((b.get_bytes(payload_len)?, payload_len)) } pub fn decrypt_pkt<'a>( b: &'a mut octets::OctetsMut, pn: u64, pn_len: usize, payload_len: usize, aead: &crypto::Open, - ) -> Result<(octets::Octets<'a>, usize)> { +) -> Result<(octets::Octets<'a>, usize)> { let payload_offset = b.off(); let (header, mut payload) = b.split_at(payload_offset)?; @@ -831,28 +878,19 @@ pub fn decrypt_pkt<'a>( let payload_len = aead.open_with_u64_counter(pn, header.as_ref(), ciphertext.as_mut())?; - let mut bytestring = String::new(); - for &byte in &b.as_ref()[..payload_len] { - let part: Vec = std::ascii::escape_default(byte).collect(); - bytestring.push_str(std::str::from_utf8(&part).unwrap()); - } Ok((b.get_bytes(payload_len)?, payload_len)) } pub fn encrypt_hdr( - b: &mut octets::OctetsMut, - enc_len: usize, - payload: &[u8], - aead: &crypto::Seal, - version: u32, - ) -> Result<()> { - + b: &mut octets::OctetsMut, enc_len: usize, payload: &[u8], + aead: &crypto::Seal, version: u32, +) -> Result<()> { let sample; let (mut first, mut rest) = b.split_at(1)?; let first = first.as_mut(); - if_likely!{version == crate::PROTOCOL_VERSION_V3 => { + if_likely! {version == crate::PROTOCOL_VERSION_V3 => { // considering max 4 bytes for the streamid and 4 bytes for the buffer offset. // for which the encoding/decoding would work in a similar fashion than for the packet number. sample = &payload @@ -891,7 +929,7 @@ pub fn encrypt_pkt( b: &mut octets::OctetsMut, pn: u64, hdr_enc_len: usize, payload_len: usize, payload_offset: usize, extra_in: Option<&[u8]>, aead: &crypto::Seal, version: u32, - ) -> Result { +) -> Result { let (mut header, mut payload) = b.split_at(payload_offset)?; let ciphertext_len = aead.seal_with_u64_counter( @@ -900,43 +938,79 @@ pub fn encrypt_pkt( payload.as_mut(), payload_len, extra_in, - )?; + )?; encrypt_hdr(&mut header, hdr_enc_len, payload.as_ref(), aead, version)?; Ok(payload_offset + ciphertext_len) } - - /// Encode a u64 value with its most significant two bits indicating the length /// of the next element to be encoded. #[inline] pub fn encode_u64_num_and_nextelem_len( - num: u64, - nextelem_len: usize, - b: &mut octets::OctetsMut - ) -> Result<()> { + num: u64, nextelem_len: usize, b: &mut octets::OctetsMut, +) -> Result<()> { match num { - 0..=63 => b.put_u8((num | ((nextelem_len-1) << 6) as u64) as u8)?, - 64..=16_383 => b.put_u16((num | ((nextelem_len-1) << 14) as u64) as u16)?, - 16384..=4_194_303 => b.put_u24((num | ((nextelem_len-1) << 22) as u64) as u32)?, - 4_194_304..=1_073_741_823 => b.put_u32((num | ((nextelem_len-1) << 30) as u64) as u32)?, + 0..=63 => b.put_u8((num | ((nextelem_len - 1) << 6) as u64) as u8)?, + 64..=16_383 => + b.put_u16((num | ((nextelem_len - 1) << 14) as u64) as u16)?, + 16384..=4_194_303 => + b.put_u24((num | ((nextelem_len - 1) << 22) as u64) as u32)?, + 4_194_304..=1_073_741_823 => + b.put_u32((num | ((nextelem_len - 1) << 30) as u64) as u32)?, _ => return Err(Error::InvalidPacket), }; Ok(()) } +fn bit_clear(num: u64, num_len: usize) -> Result { + let res = match num_len { + 1 => num & !(1 << 6) & !(1 << 7), + 2 => num & !(1 << 14) & !(1 << 15), + 3 => num & !(1 << 22) & !(1 << 23), + 4 => num & !(1 << 30) & !(1 << 31), + _ => return Err(Error::InvalidPacket), + }; + Ok(res) +} + +/// Encode the pkt num in v3. The most significant bits contains the length +/// of the stream id following. #[inline] -pub fn encode_offset_num(offset: u64, b: &mut octets::OctetsMut) -> Result<()> { - encode_pkt_num(offset, b) +pub fn encode_pkt_num_v3( + num: u64, num_len: usize, nextelem_len: usize, b: &mut octets::OctetsMut, +) -> Result<()> { + match num_len { + 1 => b.put_u8( + (bit_clear(num, num_len)? | ((nextelem_len - 1) << 6) as u64) as u8, + )?, + 2 => b.put_u16( + (bit_clear(num, num_len)? | ((nextelem_len - 1) << 14) as u64) as u16, + )?, + 3 => b.put_u24( + (bit_clear(num, num_len)? | ((nextelem_len - 1) << 22) as u64) as u32, + )?, + 4 => b.put_u32( + (bit_clear(num, num_len)? | ((nextelem_len - 1) << 30) as u64) as u32, + )?, + _ => return Err(Error::InvalidPacket), + }; + Ok(()) } #[inline] -pub fn encode_pkt_num(pn: u64, b: &mut octets::OctetsMut) -> Result<()> { - let len = pkt_num_len(pn)?; +pub fn encode_offset_num( + offset: u64, offset_len: usize, b: &mut octets::OctetsMut, +) -> Result<()> { + encode_pkt_num(offset, offset_len, b) +} - match len { +#[inline] +pub fn encode_pkt_num( + pn: u64, pn_len: usize, b: &mut octets::OctetsMut, +) -> Result<()> { + match pn_len { 1 => b.put_u8(pn as u8)?, 2 => b.put_u16(pn as u16)?, @@ -953,7 +1027,7 @@ pub fn encode_pkt_num(pn: u64, b: &mut octets::OctetsMut) -> Result<()> { pub fn negotiate_version( scid: &[u8], dcid: &[u8], out: &mut [u8], - ) -> Result { +) -> Result { let mut b = octets::OctetsMut::with_slice(out); let first = rand::rand_u8() | FORM_BIT; @@ -974,7 +1048,7 @@ pub fn negotiate_version( pub fn retry( scid: &[u8], dcid: &[u8], new_scid: &[u8], token: &[u8], version: u32, out: &mut [u8], - ) -> Result { +) -> Result { let mut b = octets::OctetsMut::with_slice(out); if !crate::version_is_supported(version) { @@ -1001,21 +1075,21 @@ pub fn retry( pub fn verify_retry_integrity( b: &octets::OctetsMut, odcid: &[u8], version: u32, - ) -> Result<()> { +) -> Result<()> { let tag = compute_retry_integrity_tag(b, odcid, version)?; ring::constant_time::verify_slices_are_equal( &b.as_ref()[..aead::AES_128_GCM.tag_len()], tag.as_ref(), - ) - .map_err(|_| Error::CryptoFail)?; + ) + .map_err(|_| Error::CryptoFail)?; Ok(()) } fn compute_retry_integrity_tag( b: &octets::OctetsMut, odcid: &[u8], version: u32, - ) -> Result { +) -> Result { const RETRY_INTEGRITY_KEY_V1: [u8; 16] = [ 0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a, 0x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e, @@ -1044,8 +1118,8 @@ fn compute_retry_integrity_tag( let key = aead::LessSafeKey::new( aead::UnboundKey::new(&aead::AES_128_GCM, key) - .map_err(|_| Error::CryptoFail)?, - ); + .map_err(|_| Error::CryptoFail)?, + ); let nonce = aead::Nonce::assume_unique_for_key(nonce); @@ -1099,6 +1173,7 @@ pub struct PktNumSpace { impl PktNumSpace { pub fn new() -> PktNumSpace { + // TODO. For the moment, the CRYPTO stream is V1 PktNumSpace { largest_rx_pkt_num: 0, @@ -1128,8 +1203,10 @@ impl PktNumSpace { u64::MAX, true, true, + // FIXME: use the configured stream window instead stream::MAX_STREAM_WINDOW, - ), + crate::PROTOCOL_VERSION_V1, + ), } } @@ -1141,7 +1218,8 @@ impl PktNumSpace { true, true, stream::MAX_STREAM_WINDOW, - ); + crate::PROTOCOL_VERSION_V1, + ); self.ack_elicited = false; } @@ -1217,9 +1295,9 @@ mod tests { version: 0xafafafaf, dcid: vec![0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba] .into(), - scid: vec![0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb].into(), - token: Some(vec![0xba; 24]), - ..Default::default() + scid: vec![0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb].into(), + token: Some(vec![0xba; 24]), + ..Default::default() }; let mut d = [0; 63]; @@ -1241,9 +1319,9 @@ mod tests { version: 0xafafafaf, dcid: vec![0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba] .into(), - scid: vec![0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb].into(), - token: Some(vec![0x05, 0x06, 0x07, 0x08]), - ..Default::default() + scid: vec![0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb].into(), + token: Some(vec![0x05, 0x06, 0x07, 0x08]), + ..Default::default() }; let mut d = [0; 50]; @@ -1264,10 +1342,10 @@ mod tests { 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, ] - .into(), - scid: vec![0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb].into(), - token: Some(vec![0x05, 0x06, 0x07, 0x08]), - ..Default::default() + .into(), + scid: vec![0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb].into(), + token: Some(vec![0x05, 0x06, 0x07, 0x08]), + ..Default::default() }; let mut d = [0; 50]; @@ -1286,13 +1364,13 @@ mod tests { version: crate::PROTOCOL_VERSION, dcid: vec![0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba] .into(), - scid: vec![ - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - ] - .into(), - token: Some(vec![0x05, 0x06, 0x07, 0x08]), - ..Default::default() + scid: vec![ + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + ] + .into(), + token: Some(vec![0x05, 0x06, 0x07, 0x08]), + ..Default::default() }; let mut d = [0; 50]; @@ -1311,13 +1389,13 @@ mod tests { version: 0xafafafaf, dcid: vec![0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba] .into(), - scid: vec![ - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - ] - .into(), - token: Some(vec![0x05, 0x06, 0x07, 0x08]), - ..Default::default() + scid: vec![ + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + ] + .into(), + token: Some(vec![0x05, 0x06, 0x07, 0x08]), + ..Default::default() }; let mut d = [0; 50]; @@ -1336,8 +1414,8 @@ mod tests { version: 0xafafafaf, dcid: vec![0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba] .into(), - scid: vec![0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb].into(), - ..Default::default() + scid: vec![0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb].into(), + ..Default::default() }; let mut d = [0; 50]; @@ -1368,9 +1446,96 @@ mod tests { } #[test] - fn pkt_num_decode() { - let pn = decode_pkt_num(0xa82f30ea, 0x9b32, 2); - assert_eq!(pn, 0xa82f9b32); + fn pkt_num_encode_decode() { + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + let num_len = pkt_num_len(0, 0); + assert_eq!(num_len, 1); + let pn = decode_pkt_num(0xa82f30ea, 0x9b32, 2); + assert_eq!(pn, 0xa82f9b32); + let mut d = [0; 10]; + let mut b = octets::OctetsMut::with_slice(&mut d); + let num_len = pkt_num_len(0xac5c02, 0xabe8b3); + assert_eq!(num_len, 2); + encode_pkt_num(0xac5c02, num_len, &mut b).unwrap(); + // reading + let mut b = octets::OctetsMut::with_slice(&mut d); + let hdr_num = u64::from(b.get_u16().unwrap()); + let pn = decode_pkt_num(0xac5c01, hdr_num, num_len); + assert_eq!(pn, 0xac5c02); + // sending 0xace8fe while having 0xabe8b3 acked + let num_len = pkt_num_len(0xace9fe, 0xabe8b3); + assert_eq!(num_len, 3); + let mut b = octets::OctetsMut::with_slice(&mut d); + encode_pkt_num(0xace9fe, num_len, &mut b).unwrap(); + // reading + let mut b = octets::OctetsMut::with_slice(&mut d); + let hdr_num = u64::from(b.get_u24().unwrap()); + let pn = decode_pkt_num(0xace9fa, hdr_num, num_len); + assert_eq!(pn, 0xace9fe); + } else { + // V3 + // We would need 4x4x4 (pn x stream_id x offset) tests to cover + // all encode/code code paths. + let mut d = [0; 10]; + let num_len = pkt_num_len_v3(0, 0); + assert_eq!(num_len, 1); + // Let's encode / decode 64 pn, 4 stream_id and 100,000 offset + { + // Encode the pn with the stream_length + let mut b = octets::OctetsMut::with_slice(&mut d); + let num_len = pkt_num_len_v3(64, 0); + assert_eq!(num_len, 2); + let streamid_len = num_len_to_encode(4) + 1; + assert_eq!(streamid_len, 1); + encode_pkt_num_v3(64, num_len, streamid_len, &mut b).unwrap(); + let expected_wire_data = [0x00, 0x40]; + assert_eq!(expected_wire_data, &d[0..2]); + } + { + let mut b = octets::OctetsMut::with_slice(&mut d); + encode_pkt_num_v3(64, 2, 1, &mut b).unwrap(); + let truncated_offset_len = truncated_offset_len(100_000, 70_000); + assert_eq!(truncated_offset_len, 2); + encode_u64_num_and_nextelem_len(4, truncated_offset_len, &mut b) + .unwrap(); + let expected_wire_data = [0x00, 0x40, 0x44]; + assert_eq!(expected_wire_data, &d[0..3]); + } + { + let mut b = octets::OctetsMut::with_slice(&mut d); + encode_pkt_num_v3(64, 2, 1, &mut b).unwrap(); + // Encode stream_id 4 with 3 byte length for offset + encode_u64_num_and_nextelem_len(4, 2, &mut b).unwrap(); + // Encode the offset in 3 bytes + encode_offset_num(100_000, 2, &mut b).unwrap(); + let expected_wire_data = [0x00, 0x40, 0x44, 0x86, 0xa0]; + assert_eq!(expected_wire_data, &d[0..5]); + + // Let's decode. + let mut b = octets::Octets::with_slice(&mut d); + let pn_with_streamid_len = + unpack_var_int_in_hdr(2, &mut b).unwrap(); + let (_, streamid_len) = + decode_num_and_nextelem_len(pn_with_streamid_len, 2); + assert_eq!(streamid_len, 1); + let pn = decode_pkt_num_v3(63, 64, 2); + assert_eq!(pn, 64); + let stream_id_with_offset_len = + unpack_var_int_in_hdr(streamid_len, &mut b).unwrap(); + + let (stream_id, offset_len) = decode_num_and_nextelem_len( + stream_id_with_offset_len, + streamid_len, + ); + assert_eq!(stream_id, 4); + assert_eq!(offset_len, 2); + let truncated_offset = + unpack_var_int_in_hdr(offset_len, &mut b).unwrap(); + let offset = + decode_pkt_offset(70000, truncated_offset, offset_len); + assert_eq!(offset, 100_000); + } + } } #[test] @@ -1482,7 +1647,7 @@ mod tests { fn assert_decrypt_initial_pkt( pkt: &mut [u8], dcid: &[u8], is_server: bool, expected_frames: &[u8], expected_pn: u64, expected_pn_len: usize, - ) { + ) { let mut b = octets::OctetsMut::with_slice(pkt); let mut hdr = Header::from_bytes(&mut b, 0).unwrap(); @@ -1492,7 +1657,7 @@ mod tests { let (aead, _) = crypto::derive_initial_key_material(dcid, hdr.version, is_server) - .unwrap(); + .unwrap(); decrypt_hdr(&mut b, &mut hdr, &aead, crate::PROTOCOL_VERSION).unwrap(); assert_eq!(hdr.pkt_num_len, expected_pn_len); @@ -1621,7 +1786,7 @@ mod tests { 0xd4, 0xa9, 0xa7, 0xf9, 0x47, 0x42, 0x41, 0x10, 0x92, 0xab, 0xbd, 0xf8, 0xb8, 0x89, 0xe5, 0xc1, 0x99, 0xd0, 0x96, 0xe3, 0xf2, 0x47, 0x88, - ]; + ]; let dcid = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08]; @@ -1649,7 +1814,7 @@ mod tests { 0x01, 0x04, 0x80, 0x00, 0x75, 0x30, 0x09, 0x01, 0x10, 0x0f, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08, 0x06, 0x04, 0x80, 0x00, 0xff, 0xff, - ]; + ]; assert_decrypt_initial_pkt(&mut pkt, &dcid, true, &frames, 2, 4); } @@ -1732,7 +1897,7 @@ mod tests { fn assert_encrypt_initial_pkt( header: &mut [u8], dcid: &[u8], frames: &[u8], pn: u64, pn_len: usize, is_server: bool, expected_pkt: &[u8], - ) { + ) { let mut b = octets::OctetsMut::with_slice(header); let hdr = Header::from_bytes(&mut b, 0).unwrap(); @@ -1745,7 +1910,7 @@ mod tests { let (_, aead) = crypto::derive_initial_key_material(dcid, hdr.version, is_server) - .unwrap(); + .unwrap(); let payload_len = frames.len(); @@ -1762,8 +1927,8 @@ mod tests { None, &aead, crate::PROTOCOL_VERSION_V1, - ) - .unwrap(); + ) + .unwrap(); assert_eq!(written, expected_pkt.len()); assert_eq!(&out[..written], expected_pkt); @@ -1885,7 +2050,7 @@ mod tests { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; + ]; let pkt = [ 0xc0, 0x00, 0x00, 0x00, 0x01, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e, @@ -1998,7 +2163,7 @@ mod tests { 0xd4, 0xa9, 0xa7, 0xf9, 0x47, 0x42, 0x41, 0x10, 0x92, 0xab, 0xbd, 0xf8, 0xb8, 0x89, 0xe5, 0xc1, 0x99, 0xd0, 0x96, 0xe3, 0xf2, 0x47, 0x88, - ]; + ]; assert_encrypt_initial_pkt( &mut header, @@ -2008,7 +2173,7 @@ mod tests { 4, false, &pkt, - ); + ); } #[test] @@ -2051,73 +2216,6 @@ mod tests { assert_encrypt_initial_pkt(&mut header, &dcid, &frames, 1, 2, true, &pkt); } - #[test] - fn encode_decode_pkt_num() { - use core::convert::TryInto; - - // This is not exaustive test cases (we would need 4x4x2 "block" to cover - // all pn ranges and streamid ranges -- we cover one range of each independently) - let mut header_part = [0x40, 0x00]; - let pn = 42; // it is below 63. Should be encoded with 1 byte - { - let mut b = octets::OctetsMut::with_slice(&mut header_part); - b.skip(1).expect("skip issue"); - assert!(crate::packet::encode_u64_num_and_nextelem_len(pn, 2, &mut b).is_ok()); - let expected_header_part = [0x40, 0x6a]; - assert_eq!(&header_part, &expected_header_part); - let header_pn = header_part[1] as u64; - let (expected_pn, num_len) = crate::packet::decode_num_and_nextelem_len(header_pn, 1); - let expected_pn = crate::packet::decode_pkt_num(41, expected_pn, 1); - assert_eq!(expected_pn, pn); - assert_eq!(num_len, 2); - } - let mut header_part = [0x40, 0xaa, 0x00, 0x00]; - { - let mut b = octets::OctetsMut::with_slice(&mut header_part); - b.skip(2).expect("skip issue"); - let offset_len = offset_len_to_encode(234_232_223).expect("number issue"); - assert!(crate::packet::encode_u64_num_and_nextelem_len(10000, offset_len, &mut b).is_ok()); - let expected_header_part = [0x40, 0xaa, 0xe7, 0x10]; - assert_eq!(&header_part, &expected_header_part); - } - let mut header_part = [0x40, 0x00, 0x00]; - let pn = 72; // it is [64:255]. Should be encoded with 2 bytes - { - let mut b = octets::OctetsMut::with_slice(&mut header_part); - b.skip(1).expect("skip issue"); - assert!(crate::packet::encode_u64_num_and_nextelem_len(pn, 2, &mut b).is_ok()); - let expected_header_part = [0x40, 0x40, 0x48]; - assert_eq!(&header_part, &expected_header_part); - let header_pn = u16::from_be_bytes(header_part[1..=2].try_into().unwrap()) as u64; - let (expected_pn, num_len) = crate::packet::decode_num_and_nextelem_len(header_pn, 2); - let expected_pn = crate::packet::decode_pkt_num(71, expected_pn, 2); - assert_eq!(expected_pn, pn); - assert_eq!(num_len, 2); - } - let mut header_part = [0x40, 0x40, 0x48, 0x00]; - { - let mut b = octets::OctetsMut::with_slice(&mut header_part); - b.skip(3).expect("skip issue"); - let offset_len = offset_len_to_encode(13_000).expect("number issue"); - assert!(crate::packet::encode_u64_num_and_nextelem_len(1, offset_len, &mut b).is_ok()); - let expected_header_part = [0x40, 0x40, 0x48, 0x41]; - assert_eq!(&header_part, &expected_header_part); - } - let mut header_part = [0x40, 0x40, 0x48, 0x41, 0x00, 0x00]; - { - let mut b = octets::OctetsMut::with_slice(&mut header_part); - b.skip(4).expect("skip issue"); - assert!(crate::packet::encode_offset_num(13_000, &mut b).is_ok()); - let expected_header_part = [0x40, 0x40, 0x48, 0x41, 0x32, 0xc8]; - assert_eq!(&header_part, &expected_header_part); - let header_num = header_part[3] as u64; - let (num, next_elem_len) = crate::packet::decode_num_and_nextelem_len(header_num, 1); - assert_eq!(num, 1); - assert_eq!(next_elem_len, 2); - } - - } - #[test] fn encrypt_chacha20() { // TODO Make one for V3. @@ -2169,8 +2267,8 @@ mod tests { None, &aead, crate::PROTOCOL_VERSION_V1, - ) - .unwrap(); + ) + .unwrap(); assert_eq!(written, expected_pkt.len()); } @@ -2198,7 +2296,7 @@ mod tests { assert_eq!( decrypt_pkt(&mut b, 0, 1, payload_len, &aead), Err(Error::InvalidPacket) - ); + ); } #[test] diff --git a/quiche/src/recovery/mod.rs b/quiche/src/recovery/mod.rs index dd89ecb7..cf809f21 100644 --- a/quiche/src/recovery/mod.rs +++ b/quiche/src/recovery/mod.rs @@ -81,7 +81,7 @@ pub struct Recovery { time_of_last_sent_ack_eliciting_pkt: [Option; packet::Epoch::count()], - largest_acked_pkt: [u64; packet::Epoch::count()], + pub largest_acked_pkt: [u64; packet::Epoch::count()], largest_sent_pkt: [u64; packet::Epoch::count()], @@ -210,7 +210,7 @@ impl Recovery { time_of_last_sent_ack_eliciting_pkt: [None; packet::Epoch::count()], - largest_acked_pkt: [u64::MAX; packet::Epoch::count()], + largest_acked_pkt: [0; packet::Epoch::count()], largest_sent_pkt: [0; packet::Epoch::count()], @@ -449,12 +449,8 @@ impl Recovery { // a validating path, then receives an acknowledgment for that packet on // the active one. - if self.largest_acked_pkt[epoch] == u64::MAX { - self.largest_acked_pkt[epoch] = largest_acked; - } else { - self.largest_acked_pkt[epoch] = - cmp::max(self.largest_acked_pkt[epoch], largest_acked); - } + self.largest_acked_pkt[epoch] = + cmp::max(self.largest_acked_pkt[epoch], largest_acked); let mut has_ack_eliciting = false; diff --git a/quiche/src/stream/app_recv_buf.rs b/quiche/src/stream/app_recv_buf.rs new file mode 100644 index 00000000..7c704797 --- /dev/null +++ b/quiche/src/stream/app_recv_buf.rs @@ -0,0 +1,540 @@ +use super::recv_buf::RecvBuf; +use super::Stream; +use super::DEFAULT_STREAM_WINDOW; +use std::collections::hash_map; +use std::collections::VecDeque; + +use crate::Error; +use crate::Result; + +/// Buffer map containing the stream buffers +#[derive(Default)] +pub struct AppRecvBufMap { + /// The stream buffers. + buffers: crate::stream::StreamIdHashMap, + + /// Contains heap-allocated AppRecvBuf that could be recycled if needed. + recycled_buffers: VecDeque, + + /// Max quantity of data that the buffer can hold. Default to + /// max_streams_data. + max_buffer_data: u64, + + /// Maximum number of bidi buffers that could exist at anytime. + max_streams_bidi: u64, + + /// Maximum number of peer uni buffers that could exist at anytime. + max_streams_uni_remote: u64, + + current_bidi: u64, + current_remote: u64, + + /// The application tells us how much it expects to read before consuming. + chunklen: Option, + + /// If this option is set, when collected, a buffer would be truncated if + /// its memory is larger than max_recycled_buffer_size. + max_recycled_buffer_size: Option, +} + +impl AppRecvBufMap { + /// new map passing config information about stream management + pub fn new( + recycled_capacity: usize, max_buffer_data: u64, max_streams_bidi: u64, + max_streams_uni_remote: u64, + ) -> AppRecvBufMap { + AppRecvBufMap { + recycled_buffers: VecDeque::with_capacity(recycled_capacity), + max_buffer_data, + max_streams_bidi, + max_streams_uni_remote, + ..Default::default() + } + } + + /// The application should set the expected chunklen they expect to consume + /// after one or more `stream_recv_v3()` are called. + #[inline] + pub fn set_expected_chunklen_to_consume( + &mut self, chunklen: u64, + ) -> Result<()> { + if chunklen > self.max_buffer_data / 2 { + return Err(Error::InvalidAPICall("chunklen cannot be greater \ + than half of the configured max data for streams")); + } + self.chunklen = Some(chunklen); + + Ok(()) + } + + /// truncate recycled buffers to the specified size. + #[inline] + pub fn set_max_recycled_buffer_size( + &mut self, max_recycled_buffer_size: usize, + ) { + self.max_recycled_buffer_size = Some(max_recycled_buffer_size); + } + + /// Maximum data that can be buffered in a given stream buffer. This can be + /// made higher than the stream_max_data, but this the expected value. + #[inline] + pub fn set_max_buffer_data(&mut self, max_buffer_data: u64) { + self.max_buffer_data = max_buffer_data; + } + + /// retrieve or create a stream buffer for a given stream_id + pub(crate) fn get_or_create_stream_buffer( + &mut self, stream_id: u64, + ) -> Result<&mut AppRecvBuf> { + match self.buffers.entry(stream_id) { + hash_map::Entry::Vacant(v) => { + let buf = if let Some(mut buf) = self.recycled_buffers.pop_front() + { + buf.stream_id = stream_id; + buf + } else { + if super::is_bidi(stream_id) { + self.current_bidi += 1; + } else if !super::is_even(stream_id) { + // Todo change this to check is_remote_uni + self.current_remote += 1; + } + + if self.current_bidi > self.max_streams_bidi || + self.current_remote > self.max_streams_uni_remote + { + return Err(Error::IdLimit); + } + + AppRecvBuf::new( + stream_id, + None, + self.chunklen.unwrap_or(super::DEFAULT_STREAM_WINDOW), + self.max_buffer_data, + ) + }; + Ok(v.insert(buf)) + }, + hash_map::Entry::Occupied(v) => Ok(v.into_mut()), + } + } + + /// get the stream_id's buffer starting at the first non-consumed byte. + pub fn get(&self, stream_id: u64) -> Option<&[u8]> { + match self.buffers.get(&stream_id) { + Some(buf) => Some(buf.get_consumed()), + None => None, + } + } + + /// get a mutable reference to the stream_id's buffer starting at the first + /// non-consumed byte. + pub fn get_mut(&mut self, stream_id: u64) -> Option<&mut [u8]> { + match self.buffers.get_mut(&stream_id) { + Some(buf) => Some(buf.get_mut_consumed()), + None => None, + } + } + + pub(crate) fn read_mut( + &mut self, stream_id: u64, stream: &mut Stream, + ) -> Result<&mut [u8]> { + let buf = match self.buffers.entry(stream_id) { + hash_map::Entry::Vacant(_v) => { + return Err(Error::AppRecvBufNotFound); + }, + hash_map::Entry::Occupied(v) => + v.into_mut().read_mut(&mut stream.recv)?, + }; + Ok(buf) + } + + pub(crate) fn has_consumed( + &mut self, stream_id: u64, stream: Option<&Stream>, consumed: usize, + ) -> Result { + match self.buffers.entry(stream_id) { + hash_map::Entry::Occupied(v) => { + // Registers how much the app has read on this stream buffer. If + // we don't have a stream, it means it has been + // collected. We need to collect our stream buffer + // as well assuming the application has read everything that was + // readable. + let (to_collect, remaining_data) = + v.into_mut().has_consumed(stream, consumed)?; + if to_collect { + self.collect(stream_id); + } + Ok(remaining_data) + }, + _ => Ok(0), + } + } + + pub(crate) fn is_consumed(&self, stream_id: u64) -> bool { + match self.buffers.get(&stream_id) { + Some(v) => v.is_consumed(), + _ => true, + } + } + + pub(crate) fn collect(&mut self, stream_id: u64) { + if let Some(mut buf) = self.buffers.remove(&stream_id) { + if self.recycled_buffers.len() < self.recycled_buffers.capacity() { + if let Some(max_recycled_buffer_size) = + self.max_recycled_buffer_size + { + if max_recycled_buffer_size < buf.outbuf.capacity() { + buf.outbuf.truncate(max_recycled_buffer_size); + } + } + buf.clear(); + self.recycled_buffers.push_back(buf); + } + } + } +} + +/// A stream buffer. This is where received data gets decrypted. +#[derive(Default)] +pub struct AppRecvBuf { + /// Stream data gets decrypted within this buffer instead of inplace + /// decryption+copy. V3 specific. A slice of this buffer is what is recv + /// by the application. + pub outbuf: Vec, + + /// Keep track by how much the output's offsets have been rewinded. + /// Typically, this happens when the application reads all available + /// data within outbuf. Rewinding then does only require changing + /// output_off to 0 and adding its previous value to tot_rewind. + /// If there's still data info within the heap; we need to memmove the whole + /// remaining window back to 0, and add the offset difference to + /// tot_rewind. Hopefully this only happens under bad networking + /// conditions (e.g., intense loss over high-bandwidth), when the window has + /// already been maxed. V3 specific. + tot_rewind: u64, + + /// indicates to which offset data within outbuf has already been marked + /// consumed by the application. V3 specific. + consumed: usize, + + /// Track the offset of contiguous data within outbuf. + output_off: u64, + + /// Stream id of the stream linked to this buffer. + stream_id: u64, + + /// Max authorized size for this buffer. + max_buffer_data: usize, + + /// Configured by the application -- depends on the application's choice of + /// size of consumed recv data + almost_full_window: u64, +} + +impl AppRecvBuf { + pub fn new( + stream_id: u64, capacity: Option, app_chunklen: u64, + max_buffer_data: u64, + ) -> AppRecvBuf { + if let Some(capacity) = capacity { + let mut appbuf = AppRecvBuf { + stream_id, + outbuf: vec![0; capacity], + max_buffer_data: max_buffer_data as usize, + almost_full_window: app_chunklen, + ..Default::default() + }; + // set_len is safe assuming + // 1) the data is initialized + // 2) the new len is <= capacity + unsafe { appbuf.outbuf.set_len(capacity) }; + appbuf + } else { + let mut appbuf = AppRecvBuf { + stream_id, + outbuf: vec![0; DEFAULT_STREAM_WINDOW as usize], + max_buffer_data: max_buffer_data as usize, + almost_full_window: app_chunklen, + ..Default::default() + }; + unsafe { appbuf.outbuf.set_len(DEFAULT_STREAM_WINDOW as usize) }; + appbuf + } + } + + /// get a mutable reference to the stream buffer. + pub fn get_mut(&mut self) -> &mut [u8] { + &mut self.outbuf + } + + /// get a reference to the non-consumed bytes within the stream buffer. + pub fn get_consumed(&self) -> &[u8] { + &self.outbuf[self.consumed..] + } + + /// get a mutable reference to the non-consumed bytes within the stream + /// buffer. + pub fn get_mut_consumed(&mut self) -> &mut [u8] { + &mut self.outbuf[self.consumed..] + } + + /// gives ontiguous bytes as a mutable slice from the stream buffer. + #[inline] + pub fn read_mut(&mut self, recv: &mut RecvBuf) -> Result<&mut [u8]> { + let mut len = 0; + // We have received data in order, we can read it right away. + if recv.contiguous_off > recv.off { + len += recv.contiguous_off - recv.off; + recv.off += len; + self.output_off += len; + } + + if recv.is_fin() && recv.deliver_fin { + recv.deliver_fin = false; + } + + let mut max_off = recv.off; + while recv.ready() { + // ready() already ensures we have something to pop() + let entry = recv.heap.first_entry().unwrap(); + let recvbufinfo = entry.remove(); + // packets received not in order created a "full" overlap that we + // might simply just safely ignore. I.e., the lower offest + // info was last to be decrypted for this entry to be + // there. + if recvbufinfo.max_off() < max_off { + // not <= to allow handling 0bytes FIN + continue; + } + max_off = recvbufinfo.max_off(); + let mut this_len = recvbufinfo.len as u64; + let mut this_offset = recvbufinfo.start_off; + // This was already checked before, and should be safe. + this_offset -= self.tot_rewind; + // We need to copy in case some out of order packet decryption + // happened :'( Hopefully rare event; altough this can be improved + // by changing the API (we need ownership on bytes read from the udp + // socket). + if let Some(buf) = recvbufinfo.data() { + trace!("Packet wasn't received in order; a copy is necessary",); + self.outbuf[this_offset as usize.. + this_offset as usize + recvbufinfo.len] + .copy_from_slice(&buf[..recvbufinfo.len]); + } + if this_offset < self.output_off { + // We have a partial overlap. This could be caused by a + // retransmission? + this_len = this_len + .saturating_sub(self.output_off - this_offset); + } + len += this_len; + recv.off += this_len; + self.output_off += this_len; + } + + recv.flow_control.add_consumed(len); + + Ok(&mut self.outbuf[self.consumed..self.output_off as usize]) + } + + /// This function needs to be called to tell how much of the stream's buffer + /// has been consumed by the application. It returns whether the buffer + /// can be collected, and how many bytes are available for read. + #[inline] + pub fn has_consumed( + &mut self, stream: Option<&Stream>, consumed: usize, + ) -> Result<(bool, usize)> { + self.consumed = self.consumed.saturating_add(consumed); + if let Some(stream) = stream { + if stream.recv.heap.is_empty() && + self.consumed as u64 == self.output_off && + !stream.recv.is_fin() + { + self.tot_rewind = + self.tot_rewind.saturating_add(self.consumed as u64); + self.consumed = 0; + self.output_off = 0; + // we don't want to collect our buffer. + Ok((false, 0)) + } else { + // either the stream is_fin() but the app didn't fully read it + // yet. Or the stream !is_fin() and the app didn't + // fully read what was available. In either case, the + // buffer needs to remain available for the application. + Ok(( + false, + self.output_off.checked_sub(self.consumed as u64).ok_or( + Error::InvalidAPICall( + "You may have consumed more than what was \ + available to read", + ), + )? as usize, + )) + } + } else if self.consumed as u64 == self.output_off { + // The stream has been collected, and the application has read + // everything. We can collect the buffer as well. + Ok((true, 0)) + } else { + // The stream has been collected but the application didn't fully read + // the available data yet. + Ok(( + false, + self.output_off.checked_sub(self.consumed as u64).ok_or( + Error::InvalidAPICall( + "You may have consumed more than what was + available to read", + ), + )? as usize, + )) + } + // TODO should we memmove the data in self.outbuf in the case where + // self.consumed == self.output_off_end but the heap isn't + // empty? + } + + #[inline] + pub fn is_consumed(&self) -> bool { + self.consumed as u64 == self.output_off + } + + /// Returns the offset to where the packet should be decrypted in + /// PROTOCOL_VERSION_V3. + /// Make sure that this offset is within our outbuf's range. + /// Make sure we didn't already received contiguous data above + /// stream_offset. if that's the case, decrypting this packet could lead + /// to overwrite contiguous data not yet read by the application. + #[inline] + pub fn get_outbuf_offset( + &mut self, stream_offset: u64, to_reserve: usize, recv: &RecvBuf, + ) -> Result { + if stream_offset < recv.contiguous_off { + trace!( + "We've received a packet holding an offset {} already \ + in our contiguous buffer but not yet read by the application. \ + consumed index is {} and output offset is {}", + stream_offset, + self.consumed, + self.output_off + ); + // In V3, we do not accept a packet that would overlap a contiguous + // range of data already processed but not yet read by the + // application. This could happen due to aggressive + // retransmission; or intentional duplication. The packet is + // dropped before payload decryption. + return Err(Error::InvalidOffset); + } + + let mut outbuf_off = stream_offset + .checked_sub(self.tot_rewind) + .ok_or(Error::InvalidOffset)?; + + if self.is_almost_full(outbuf_off)? && self.consumed > 0 { + trace!( + "We're almost full! memmoving {} bytes", + self.max_buffer_data as u64 - outbuf_off, + ); + self.outbuf + .copy_within(self.consumed..outbuf_off as usize, 0); + self.tot_rewind = + self.tot_rewind.saturating_add(self.consumed as u64); + self.output_off -= self.consumed as u64; + outbuf_off -= self.consumed as u64; + self.consumed = 0; + } + + // If this triggers a BufferToShort Error, it may be sign the application + // didn't consume. We lose the packet and return the error to the + // application. This would returns a BufferTooShort error. Should + // we return something more specific? XXX + self.ensures_size(outbuf_off as usize + to_reserve)?; + + Ok(outbuf_off) + } + + /// Check that the stream buffer's capacity is large enough to old the + /// packet about to be decrypted. If not, and if we have room, double + /// the buffer's capacity. + fn ensures_size(&mut self, size: usize) -> Result<()> { + if self.outbuf.capacity() < size && size <= self.max_buffer_data { + // In case we don't have enough room to store the data; we double the + // size of outbuf, or set to size + let minmax = std::cmp::min( + std::cmp::max(self.outbuf.capacity() * 2, size), + self.max_buffer_data, + ); + trace!( + "Resizing the output buffer of stream {} to {}", + self.stream_id, + minmax, + ); + self.outbuf.resize(minmax, 0); + unsafe { self.outbuf.set_len(minmax) }; + } else if size > self.max_buffer_data { + trace!( + "BUG: asking for a size bigger than {}", + self.max_buffer_data + ); + return Err(Error::BufferTooShort); + } + + Ok(()) + } + + /// Check wether we're almost full. This depends on the choice of the + /// application's maximum chunk to keep buffered before consuming. + fn is_almost_full(&self, output_off: u64) -> Result { + let available_space = (self.max_buffer_data as u64) + .checked_sub(output_off) + .ok_or(Error::InvalidOffset)?; + + // The notion of "almost full" for the application buffer depends + // on the chunk size that the application consumes. The application should + // set almost_full_window to their larger chunk size they could be waiting + // on. + Ok(available_space < self.almost_full_window) + } + + /// Clear the buffer meta-data + #[inline] + pub fn clear(&mut self) { + self.tot_rewind = 0; + self.consumed = 0; + self.output_off = 0; + self.stream_id = 0; + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::stream::RecvBufInfo; + + #[test] + fn create_and_collect_bufs() { + let mut app_buf = AppRecvBufMap::new(3, 100, 10, 10); + let _buf_stream_4 = app_buf.get_or_create_stream_buffer(4).unwrap(); + + app_buf.collect(4); + assert_eq!(app_buf.recycled_buffers.len(), 1); + let _buf_stream_8 = app_buf.get_or_create_stream_buffer(8).unwrap(); + // use a collected buffer. + assert_eq!(app_buf.recycled_buffers.len(), 0); + } + + #[test] + fn appbuf_streambuffer_read() { + let mut recv = + RecvBuf::new(100, DEFAULT_STREAM_WINDOW, crate::PROTOCOL_VERSION_V3); + let mut app_buf = AppRecvBufMap::new(3, 100, 10, 10); + let buf_stream_4 = app_buf.get_or_create_stream_buffer(4).unwrap(); + + let writeinfo = RecvBufInfo::from(0, 5, false); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V3 { + assert!(recv.write_v3(writeinfo).is_ok()); + assert_eq!(buf_stream_4.read_mut(&mut recv).unwrap().len(), 5); + } + } + // TODO write actual good testing. This ain't gonna help getting published + // but it is the way. *sigh*. +} diff --git a/quiche/src/stream/mod.rs b/quiche/src/stream/mod.rs index 69b8820c..a4870c87 100644 --- a/quiche/src/stream/mod.rs +++ b/quiche/src/stream/mod.rs @@ -160,7 +160,7 @@ pub struct StreamMap { stopped: StreamIdHashMap, /// The maximum size of a stream window. - max_stream_window: u64, + pub max_stream_window: u64, } impl StreamMap { @@ -205,6 +205,7 @@ impl StreamMap { pub(crate) fn get_or_create( &mut self, id: u64, local_params: &crate::TransportParams, peer_params: &crate::TransportParams, local: bool, is_server: bool, + version: u32, ) -> Result<&mut Stream> { let (stream, is_new_and_writable) = match self.streams.entry(id) { hash_map::Entry::Vacant(v) => { @@ -241,7 +242,16 @@ impl StreamMap { // The two least significant bits from a stream id identify the // type of stream. Truncate those bits to get the sequence for // that stream type. - let stream_sequence = id >> 2; + // Note, in V3, client's bidi stream start at 4. + let stream_sequence = if version == crate::PROTOCOL_VERSION_V3 { + if is_bidi(id) && is_even(id) { + (id >> 2).saturating_sub(1) + } else { + id >> 2 + } + } else { + id >> 2 + }; // Enforce stream count limits. match (is_local(id, is_server), is_bidi(id)) { @@ -305,6 +315,7 @@ impl StreamMap { is_bidi(id), local, self.max_stream_window, + version, ); let is_writable = s.is_writable(); @@ -551,6 +562,16 @@ impl StreamMap { self.collected.insert(stream_id); } + /// In case a stream is created before the packet could have been + /// authenticated; we need to collect it without remembering it. + pub fn collect_on_recv_error(&mut self, stream_id: u64) { + let s = self.streams.remove(&stream_id).unwrap(); + + self.remove_readable(&s.priority_key); + self.remove_writable(&s.priority_key); + self.remove_flushable(&s.priority_key); + } + /// Creates an iterator over streams that have outstanding data to read. pub fn readable(&self) -> StreamIter { StreamIter { @@ -644,9 +665,12 @@ impl StreamMap { pub fn len(&self) -> usize { self.streams.len() } - //TODO PROTOCOL_REVERSO + + // TODO PROTOCOL_REVERSO /// Rewind the Stream_id's receive buffer of num bytes - pub fn rewind_recv_buf(&mut self, _stream_id: u64, _num: usize) -> Result<()> { + pub fn rewind_recv_buf( + &mut self, _stream_id: u64, _num: usize, + ) -> Result<()> { Ok(()) } } @@ -680,7 +704,7 @@ impl Stream { /// Creates a new stream with the given flow control limits. pub fn new( id: u64, max_rx_data: u64, max_tx_data: u64, bidi: bool, local: bool, - max_window: u64, + max_window: u64, version: u32, ) -> Stream { let priority_key = Arc::new(StreamPriorityKey { id, @@ -688,7 +712,7 @@ impl Stream { }); Stream { - recv: recv_buf::RecvBuf::new(max_rx_data, max_window), + recv: recv_buf::RecvBuf::new(max_rx_data, max_window, version), send: send_buf::SendBuf::new(max_tx_data), send_lowat: 1, bidi, @@ -747,13 +771,6 @@ impl Stream { (false, false) => self.recv.is_fin(), } } - //TODO - pub fn get_monotonic_offset(&self) -> u64 { - 42 - } - #[allow(dead_code)] - pub fn update_monotonic_offset(&mut self, _offset: u64) { - } } /// Returns true if the stream was created locally. @@ -766,6 +783,11 @@ pub fn is_bidi(stream_id: u64) -> bool { (stream_id & 0x2) == 0 } +/// Returns true is the stream is even. +pub fn is_even(stream_id: u64) -> bool { + (stream_id & 0x01) == 0 +} + #[derive(Clone, Debug)] pub struct StreamPriorityKey { pub urgency: u8, @@ -905,6 +927,74 @@ impl ExactSizeIterator for StreamIter { } } +/// TODO document +#[derive(Clone, Eq, Debug)] +pub struct RecvBufInfo { + start_off: u64, + len: usize, + fin: bool, + // Used in case of this data is received before + // the previous packet. + data: Option>, +} + +impl RecvBufInfo { + pub fn from(start_off: u64, len: usize, fin: bool) -> RecvBufInfo { + RecvBufInfo { + start_off, + len, + fin, + data: None, + } + } + + pub fn max_off(&self) -> u64 { + self.start_off + self.len as u64 + } + + pub fn fin(&self) -> bool { + self.fin + } + + pub fn is_empty(&self) -> bool { + self.len == 0 + } + + pub fn off(&self) -> u64 { + self.start_off + } + + pub fn len(&self) -> usize { + self.len + } + + pub fn attach_data(&mut self, data: Vec) { + self.data = Some(data); + } + + pub fn data(&self) -> Option<&[u8]> { + self.data.as_deref() + } +} + +impl Ord for RecvBufInfo { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.start_off.cmp(&other.start_off) + } +} + +impl PartialOrd for RecvBufInfo { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl PartialEq for RecvBufInfo { + fn eq(&self, other: &Self) -> bool { + self.start_off == other.start_off + } +} + /// Buffer holding data at a specific offset. /// /// The data is stored in a `Vec` in such a way that it can be shared @@ -1043,27 +1133,51 @@ impl PartialEq for RangeBuf { #[cfg(test)] mod tests { use super::*; + use app_recv_buf::*; #[test] fn recv_flow_control() { - let mut stream = Stream::new(0, 15, 0, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 15, + 0, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); + let mut app_buf = AppRecvBuf::new(1, Some(42), 100, 1000); assert!(!stream.recv.almost_full()); let mut buf = [0; 32]; let first = RangeBuf::from(b"hello", 0, false); + let firstinfo = RecvBufInfo::from(0, 5, false); let second = RangeBuf::from(b"world", 5, false); + let secondinfo = RecvBufInfo::from(5, 5, false); let third = RangeBuf::from(b"something", 10, false); - - assert_eq!(stream.recv.write(second), Ok(())); - assert_eq!(stream.recv.write(first), Ok(())); + let thirdinfo = RecvBufInfo::from(10, 9, false); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(stream.recv.write(second), Ok(())); + assert_eq!(stream.recv.write(first), Ok(())); + } else { + assert_eq!(stream.recv.write_v3(secondinfo), Ok(())); + assert_eq!(stream.recv.write_v3(firstinfo), Ok(())); + } assert!(!stream.recv.almost_full()); - assert_eq!(stream.recv.write(third), Err(Error::FlowControl)); - - let (len, fin) = stream.recv.emit(&mut buf).unwrap(); - assert_eq!(&buf[..len], b"helloworld"); - assert!(!fin); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(stream.recv.write(third), Err(Error::FlowControl)); + let (len, fin) = stream.recv.emit(&mut buf).unwrap(); + assert_eq!(&buf[..len], b"helloworld"); + assert_eq!(fin, false); + } else { + assert_eq!(stream.recv.write_v3(thirdinfo), Err(Error::FlowControl)); + assert_eq!(app_buf.read_mut(&mut stream.recv).unwrap().len(), 10); + assert!(app_buf.has_consumed(None, 10).is_ok()); + assert!(!stream.recv.is_fin()); + } assert!(stream.recv.almost_full()); @@ -1072,54 +1186,114 @@ mod tests { assert!(!stream.recv.almost_full()); let third = RangeBuf::from(b"something", 10, false); - assert_eq!(stream.recv.write(third), Ok(())); + let thirdinfo = RecvBufInfo::from(10, 5, false); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(stream.recv.write(third), Ok(())); + } else { + assert_eq!(stream.recv.write_v3(thirdinfo), Ok(())); + } } #[test] fn recv_past_fin() { - let mut stream = Stream::new(0, 15, 0, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 15, + 0, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); assert!(!stream.recv.almost_full()); let first = RangeBuf::from(b"hello", 0, true); + let firstinfo = RecvBufInfo::from(0, 5, true); let second = RangeBuf::from(b"world", 5, false); - - assert_eq!(stream.recv.write(first), Ok(())); - assert_eq!(stream.recv.write(second), Err(Error::FinalSize)); + let secondinfo = RecvBufInfo::from(5, 5, false); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(stream.recv.write(first), Ok(())); + assert_eq!(stream.recv.write(second), Err(Error::FinalSize)); + } else { + assert_eq!(stream.recv.write_v3(firstinfo), Ok(())); + assert_eq!(stream.recv.write_v3(secondinfo), Err(Error::FinalSize)); + } } #[test] fn recv_fin_dup() { - let mut stream = Stream::new(0, 15, 0, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 15, + 0, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); + let mut app_buf = AppRecvBuf::new(1, Some(42), 100, 1000); assert!(!stream.recv.almost_full()); let first = RangeBuf::from(b"hello", 0, true); + let firstinfo = RecvBufInfo::from(0, 5, false); let second = RangeBuf::from(b"hello", 0, true); - - assert_eq!(stream.recv.write(first), Ok(())); - assert_eq!(stream.recv.write(second), Ok(())); + let secondinfo = RecvBufInfo::from(5, 5, true); let mut buf = [0; 32]; - let (len, fin) = stream.recv.emit(&mut buf).unwrap(); - assert_eq!(&buf[..len], b"hello"); - assert!(fin); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(stream.recv.write(first), Ok(())); + assert_eq!(stream.recv.write(second), Ok(())); + let (len, fin) = stream.recv.emit(&mut buf).unwrap(); + assert_eq!(fin, true); + assert_eq!(&buf[..len], b"hello"); + } else { + assert_eq!(stream.recv.write_v3(firstinfo), Ok(())); + assert_eq!(stream.recv.write_v3(secondinfo), Ok(())); + assert_eq!(app_buf.read_mut(&mut stream.recv).unwrap().len(), 10); + assert!(stream.recv.is_fin()); + } } #[test] fn recv_fin_change() { - let mut stream = Stream::new(0, 15, 0, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 15, + 0, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); assert!(!stream.recv.almost_full()); let first = RangeBuf::from(b"hello", 0, true); + let firstinfo = RecvBufInfo::from(0, 5, true); let second = RangeBuf::from(b"world", 5, true); - - assert_eq!(stream.recv.write(second), Ok(())); - assert_eq!(stream.recv.write(first), Err(Error::FinalSize)); + let secondinfo = RecvBufInfo::from(5, 5, true); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(stream.recv.write(second), Ok(())); + assert_eq!(stream.recv.write(first), Err(Error::FinalSize)); + } else { + assert_eq!(stream.recv.write_v3(secondinfo), Ok(())); + assert_eq!(stream.recv.write_v3(firstinfo), Err(Error::FinalSize)); + } } #[test] fn recv_fin_lower_than_received() { - let mut stream = Stream::new(0, 15, 0, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 15, + 0, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); assert!(!stream.recv.almost_full()); let first = RangeBuf::from(b"hello", 0, true); @@ -1131,67 +1305,137 @@ mod tests { #[test] fn recv_fin_flow_control() { - let mut stream = Stream::new(0, 15, 0, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 15, + 0, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); + let mut app_buf = AppRecvBuf::new(1, Some(42), 100, 1000); assert!(!stream.recv.almost_full()); let mut buf = [0; 32]; let first = RangeBuf::from(b"hello", 0, false); + let firstinfo = RecvBufInfo::from(0, 5, false); let second = RangeBuf::from(b"world", 5, true); - - assert_eq!(stream.recv.write(first), Ok(())); - assert_eq!(stream.recv.write(second), Ok(())); - - let (len, fin) = stream.recv.emit(&mut buf).unwrap(); - assert_eq!(&buf[..len], b"helloworld"); - assert!(fin); + let secondinfo = RecvBufInfo::from(5, 5, true); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(stream.recv.write(first), Ok(())); + assert_eq!(stream.recv.write(second), Ok(())); + let (len, fin) = stream.recv.emit(&mut buf).unwrap(); + assert_eq!(&buf[..len], b"helloworld"); + assert_eq!(fin, true); + } else { + assert_eq!(stream.recv.write_v3(firstinfo), Ok(())); + assert_eq!(stream.recv.write_v3(secondinfo), Ok(())); + assert_eq!(app_buf.read_mut(&mut stream.recv).unwrap().len(), 10); + assert!(stream.recv.is_fin()); + } assert!(!stream.recv.almost_full()); } #[test] fn recv_fin_reset_mismatch() { - let mut stream = Stream::new(0, 15, 0, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 15, + 0, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); assert!(!stream.recv.almost_full()); let first = RangeBuf::from(b"hello", 0, true); + let firstinfo = RecvBufInfo::from(0, 5, true); - assert_eq!(stream.recv.write(first), Ok(())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(stream.recv.write(first), Ok(())); + } else { + assert_eq!(stream.recv.write_v3(firstinfo), Ok(())); + } assert_eq!(stream.recv.reset(0, 10), Err(Error::FinalSize)); } #[test] fn recv_reset_dup() { - let mut stream = Stream::new(0, 15, 0, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 15, + 0, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); assert!(!stream.recv.almost_full()); let first = RangeBuf::from(b"hello", 0, false); + let firstinfo = RecvBufInfo::from(0, 5, false); - assert_eq!(stream.recv.write(first), Ok(())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(stream.recv.write(first), Ok(())); + } else { + assert_eq!(stream.recv.write_v3(firstinfo), Ok(())); + } assert_eq!(stream.recv.reset(0, 5), Ok(0)); assert_eq!(stream.recv.reset(0, 5), Ok(0)); } #[test] fn recv_reset_change() { - let mut stream = Stream::new(0, 15, 0, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 15, + 0, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); assert!(!stream.recv.almost_full()); let first = RangeBuf::from(b"hello", 0, false); + let firstinfo = RecvBufInfo::from(0, 5, false); - assert_eq!(stream.recv.write(first), Ok(())); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(stream.recv.write(first), Ok(())); + } else { + assert_eq!(stream.recv.write_v3(firstinfo), Ok(())); + } assert_eq!(stream.recv.reset(0, 5), Ok(0)); assert_eq!(stream.recv.reset(0, 10), Err(Error::FinalSize)); } #[test] fn recv_reset_lower_than_received() { - let mut stream = Stream::new(0, 15, 0, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 15, + 0, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); assert!(!stream.recv.almost_full()); let first = RangeBuf::from(b"hello", 0, false); + let firstinfo = RecvBufInfo::from(0, 5, false); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(stream.recv.write(first), Ok(())); + } else { + assert_eq!(stream.recv.write_v3(firstinfo), Ok(())); + } - assert_eq!(stream.recv.write(first), Ok(())); assert_eq!(stream.recv.reset(0, 4), Err(Error::FinalSize)); } @@ -1199,7 +1443,15 @@ mod tests { fn send_flow_control() { let mut buf = [0; 25]; - let mut stream = Stream::new(0, 0, 15, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 0, + 15, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); let first = b"hello"; let second = b"world"; @@ -1242,7 +1494,15 @@ mod tests { #[test] fn send_past_fin() { - let mut stream = Stream::new(0, 0, 15, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 0, + 15, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); let first = b"hello"; let second = b"world"; @@ -1258,7 +1518,15 @@ mod tests { #[test] fn send_fin_dup() { - let mut stream = Stream::new(0, 0, 15, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 0, + 15, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); assert_eq!(stream.send.write(b"hello", true), Ok(5)); assert!(stream.send.is_fin()); @@ -1269,7 +1537,15 @@ mod tests { #[test] fn send_undo_fin() { - let mut stream = Stream::new(0, 0, 15, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 0, + 15, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); assert_eq!(stream.send.write(b"hello", true), Ok(5)); assert!(stream.send.is_fin()); @@ -1284,7 +1560,15 @@ mod tests { fn send_fin_max_data_match() { let mut buf = [0; 15]; - let mut stream = Stream::new(0, 0, 15, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 0, + 15, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); let slice = b"hellohellohello"; @@ -1300,7 +1584,15 @@ mod tests { fn send_fin_zero_length() { let mut buf = [0; 5]; - let mut stream = Stream::new(0, 0, 15, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 0, + 15, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); assert_eq!(stream.send.write(b"hello", false), Ok(5)); assert_eq!(stream.send.write(b"", true), Ok(0)); @@ -1316,7 +1608,15 @@ mod tests { fn send_ack() { let mut buf = [0; 5]; - let mut stream = Stream::new(0, 0, 15, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 0, + 15, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); assert_eq!(stream.send.write(b"hello", false), Ok(5)); assert_eq!(stream.send.write(b"world", false), Ok(5)); @@ -1346,7 +1646,15 @@ mod tests { fn send_ack_reordering() { let mut buf = [0; 5]; - let mut stream = Stream::new(0, 0, 15, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 0, + 15, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); assert_eq!(stream.send.write(b"hello", false), Ok(5)); assert_eq!(stream.send.write(b"world", false), Ok(5)); @@ -1383,30 +1691,54 @@ mod tests { #[test] fn recv_data_below_off() { - let mut stream = Stream::new(0, 15, 0, true, true, DEFAULT_STREAM_WINDOW); + // Receiving data below off() is a violation in V3. Indeed, this MUST not + // happen, or the stream would not be AE-Secure. In Quic V1, to + // maintain AE-Security, the receiver should always retain + // previous received packets and memcmp() to the content of the new one if + // below_off() is true (the overlap MUST be the same data). This is too + // expensive to be an thing, so we work around this in V3. + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + let mut stream = Stream::new( + 0, + 15, + 0, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); - let first = RangeBuf::from(b"hello", 0, false); + let first = RangeBuf::from(b"hello", 0, false); - assert_eq!(stream.recv.write(first), Ok(())); + assert_eq!(stream.recv.write(first), Ok(())); - let mut buf = [0; 10]; + let mut buf = [0; 10]; - let (len, fin) = stream.recv.emit(&mut buf).unwrap(); - assert_eq!(&buf[..len], b"hello"); - assert!(!fin); + let (len, fin) = stream.recv.emit(&mut buf).unwrap(); + assert_eq!(&buf[..len], b"hello"); + assert!(!fin); - let first = RangeBuf::from(b"elloworld", 1, true); - assert_eq!(stream.recv.write(first), Ok(())); + let first = RangeBuf::from(b"elloworld", 1, true); + assert_eq!(stream.recv.write(first), Ok(())); - let (len, fin) = stream.recv.emit(&mut buf).unwrap(); - assert_eq!(&buf[..len], b"world"); - assert!(fin); + let (len, fin) = stream.recv.emit(&mut buf).unwrap(); + assert_eq!(&buf[..len], b"world"); + assert!(fin); + } } #[test] fn stream_complete() { - let mut stream = - Stream::new(0, 30, 30, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 30, + 30, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); + let mut app_buf = AppRecvBuf::new(1, Some(42), 100, 1000); assert_eq!(stream.send.write(b"hello", false), Ok(5)); assert_eq!(stream.send.write(b"world", false), Ok(5)); @@ -1420,36 +1752,61 @@ mod tests { assert!(stream.send.is_fin()); let buf = RangeBuf::from(b"hello", 0, true); - assert!(stream.recv.write(buf).is_ok()); + let bufinfo = RecvBufInfo::from(0, 5, true); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(stream.recv.write(buf).is_ok()); + } else { + assert!(stream.recv.write_v3(bufinfo).is_ok()); + } assert!(!stream.recv.is_fin()); stream.send.ack(6, 4); assert!(!stream.send.is_complete()); let mut buf = [0; 2]; - assert_eq!(stream.recv.emit(&mut buf), Ok((2, false))); - assert!(!stream.recv.is_fin()); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(stream.recv.emit(&mut buf), Ok((2, false))); - stream.send.ack(1, 5); - assert!(!stream.send.is_complete()); + assert!(!stream.recv.is_fin()); + + stream.send.ack(1, 5); + assert!(!stream.send.is_complete()); - stream.send.ack(0, 1); - assert!(stream.send.is_complete()); + stream.send.ack(0, 1); + assert!(stream.send.is_complete()); - assert!(!stream.is_complete()); + assert!(!stream.is_complete()); - let mut buf = [0; 3]; - assert_eq!(stream.recv.emit(&mut buf), Ok((3, true))); - assert!(stream.recv.is_fin()); + let mut buf = [0; 3]; + assert_eq!(stream.recv.emit(&mut buf), Ok((3, true))); + assert!(stream.recv.is_fin()); - assert!(stream.is_complete()); + assert!(stream.is_complete()); + } else { + app_buf.read_mut(&mut stream.recv).unwrap(); + + stream.send.ack(0, 6); + assert!(stream.send.is_complete()); + + assert!(stream.recv.is_fin()); + + assert!(stream.is_complete()); + } } #[test] fn send_fin_zero_length_output() { let mut buf = [0; 5]; - let mut stream = Stream::new(0, 0, 15, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 0, + 15, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); assert_eq!(stream.send.write(b"hello", false), Ok(5)); assert_eq!(stream.send.off_front(), 0); @@ -1479,7 +1836,15 @@ mod tests { fn send_emit() { let mut buf = [0; 5]; - let mut stream = Stream::new(0, 0, 20, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 0, + 20, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); assert_eq!(stream.send.write(b"hello", false), Ok(5)); assert_eq!(stream.send.write(b"world", false), Ok(5)); @@ -1531,7 +1896,15 @@ mod tests { fn send_emit_ack() { let mut buf = [0; 5]; - let mut stream = Stream::new(0, 0, 20, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 0, + 20, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); assert_eq!(stream.send.write(b"hello", false), Ok(5)); assert_eq!(stream.send.write(b"world", false), Ok(5)); @@ -1598,7 +1971,15 @@ mod tests { fn send_emit_retransmit() { let mut buf = [0; 5]; - let mut stream = Stream::new(0, 0, 20, true, true, DEFAULT_STREAM_WINDOW); + let mut stream = Stream::new( + 0, + 0, + 20, + true, + true, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); assert_eq!(stream.send.write(b"hello", false), Ok(5)); assert_eq!(stream.send.write(b"world", false), Ok(5)); @@ -1835,7 +2216,14 @@ mod tests { assert!(is_bidi(stream_id), "stream id is bidirectional"); assert_eq!( streams - .get_or_create(stream_id, &local_tp, &peer_tp, false, true) + .get_or_create( + stream_id, + &local_tp, + &peer_tp, + false, + true, + crate::PROTOCOL_VERSION + ) .err(), Some(Error::StreamLimit), "stream limit should be exceeded" @@ -1855,7 +2243,14 @@ mod tests { assert!(is_local(stream_id, false), "stream id is client initiated"); assert!(is_bidi(stream_id), "stream id is bidirectional"); assert!(streams - .get_or_create(stream_id, &local_tp, &peer_tp, false, true) + .get_or_create( + stream_id, + &local_tp, + &peer_tp, + false, + true, + crate::PROTOCOL_VERSION + ) .is_ok()); } } @@ -1869,16 +2264,38 @@ mod tests { let mut streams = StreamMap::new(3, 3, 3); // Highest permitted - let stream_id = 8; + let stream_id = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + 8 + } else { + 12 + }; assert!(streams - .get_or_create(stream_id, &local_tp, &peer_tp, false, true) + .get_or_create( + stream_id, + &local_tp, + &peer_tp, + false, + true, + crate::PROTOCOL_VERSION + ) .is_ok()); // One more than highest permitted - let stream_id = 12; + let stream_id = if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + 12 + } else { + 16 + }; assert_eq!( streams - .get_or_create(stream_id, &local_tp, &peer_tp, false, true) + .get_or_create( + stream_id, + &local_tp, + &peer_tp, + false, + true, + crate::PROTOCOL_VERSION + ) .err(), Some(Error::StreamLimit) ); @@ -1900,9 +2317,16 @@ mod tests { let mut streams = StreamMap::new(100, 100, 100); - for id in [0, 4, 8, 12] { + for id in [4, 8, 12, 16] { assert!(streams - .get_or_create(id, &local_tp, &peer_tp, false, true) + .get_or_create( + id, + &local_tp, + &peer_tp, + false, + true, + crate::PROTOCOL_VERSION + ) .is_ok()); } @@ -1918,11 +2342,11 @@ mod tests { // All streams are non-incremental and same urgency by default. Multiple // visits shuffle their order. - assert_eq!(walk_1, vec![0, 4, 8, 12]); - assert_eq!(walk_2, vec![4, 8, 12, 0]); - assert_eq!(walk_3, vec![8, 12, 0, 4]); - assert_eq!(walk_4, vec![12, 0, 4, 8,]); - assert_eq!(walk_5, vec![0, 4, 8, 12]); + assert_eq!(walk_1, vec![4, 8, 12, 16]); + assert_eq!(walk_2, vec![8, 12, 16, 4]); + assert_eq!(walk_3, vec![12, 16, 4, 8]); + assert_eq!(walk_4, vec![16, 4, 8, 12,]); + assert_eq!(walk_5, vec![4, 8, 12, 16]); } #[test] @@ -1938,9 +2362,16 @@ mod tests { // Inserting same-urgency incremental streams in a "random" order yields // same order to start with. - for id in [12, 4, 8, 0] { + for id in [16, 8, 12, 4] { assert!(streams - .get_or_create(id, &local_tp, &peer_tp, false, true) + .get_or_create( + id, + &local_tp, + &peer_tp, + false, + true, + crate::PROTOCOL_VERSION + ) .is_ok()); } @@ -1953,11 +2384,11 @@ mod tests { let walk_4: Vec = streams.writable().collect(); cycle_stream_priority(*walk_4.first().unwrap(), &mut streams); let walk_5: Vec = streams.writable().collect(); - assert_eq!(walk_1, vec![12, 4, 8, 0]); - assert_eq!(walk_2, vec![4, 8, 0, 12]); - assert_eq!(walk_3, vec![8, 0, 12, 4,]); - assert_eq!(walk_4, vec![0, 12, 4, 8]); - assert_eq!(walk_5, vec![12, 4, 8, 0]); + assert_eq!(walk_1, vec![16, 8, 12, 4]); + assert_eq!(walk_2, vec![8, 12, 4, 16]); + assert_eq!(walk_3, vec![12, 4, 16, 8,]); + assert_eq!(walk_4, vec![4, 16, 8, 12]); + assert_eq!(walk_5, vec![16, 8, 12, 4]); } #[test] @@ -1974,24 +2405,31 @@ mod tests { // Streams where the urgency descends (becomes more important). No stream // shares an urgency. let input = vec![ - (0, 100), - (4, 90), - (8, 80), - (12, 70), - (16, 60), - (20, 50), - (24, 40), - (28, 30), - (32, 20), - (36, 10), - (40, 0), + (4, 100), + (8, 90), + (12, 80), + (16, 70), + (20, 60), + (24, 50), + (28, 40), + (32, 30), + (36, 20), + (40, 10), + (44, 0), ]; for (id, urgency) in input.clone() { // this duplicates some code from stream_priority in order to access // streams and the collection they're in let stream = streams - .get_or_create(id, &local_tp, &peer_tp, false, true) + .get_or_create( + id, + &local_tp, + &peer_tp, + false, + true, + crate::PROTOCOL_VERSION, + ) .unwrap(); stream.urgency = urgency; @@ -2012,14 +2450,21 @@ mod tests { } let walk_1: Vec = streams.writable().collect(); - assert_eq!(walk_1, vec![40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0]); + assert_eq!(walk_1, vec![44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4]); // Re-applying priority to a stream does not cause duplication. for (id, urgency) in input { // this duplicates some code from stream_priority in order to access // streams and the collection they're in let stream = streams - .get_or_create(id, &local_tp, &peer_tp, false, true) + .get_or_create( + id, + &local_tp, + &peer_tp, + false, + true, + crate::PROTOCOL_VERSION, + ) .unwrap(); stream.urgency = urgency; @@ -2040,27 +2485,34 @@ mod tests { } let walk_2: Vec = streams.writable().collect(); - assert_eq!(walk_2, vec![40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0]); + assert_eq!(walk_2, vec![44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4]); // Removing streams doesn't break expected ordering. streams.collect(24, true); let walk_3: Vec = streams.writable().collect(); - assert_eq!(walk_3, vec![40, 36, 32, 28, 20, 16, 12, 8, 4, 0]); + assert_eq!(walk_3, vec![44, 40, 36, 32, 28, 20, 16, 12, 8, 4]); streams.collect(40, true); - streams.collect(0, true); + streams.collect(4, true); let walk_4: Vec = streams.writable().collect(); - assert_eq!(walk_4, vec![36, 32, 28, 20, 16, 12, 8, 4]); + assert_eq!(walk_4, vec![44, 36, 32, 28, 20, 16, 12, 8]); // Adding streams doesn't break expected ordering. streams - .get_or_create(44, &local_tp, &peer_tp, false, true) + .get_or_create( + 48, + &local_tp, + &peer_tp, + false, + true, + crate::PROTOCOL_VERSION, + ) .unwrap(); let walk_5: Vec = streams.writable().collect(); - assert_eq!(walk_5, vec![36, 32, 28, 20, 16, 12, 8, 4, 44]); + assert_eq!(walk_5, vec![44, 36, 32, 28, 20, 16, 12, 8, 48]); } #[test] @@ -2076,24 +2528,31 @@ mod tests { // Streams that share some urgency level let input = vec![ - (0, 100), - (4, 20), - (8, 100), - (12, 20), - (16, 90), - (20, 25), - (24, 90), - (28, 30), - (32, 80), - (36, 20), - (40, 0), + (4, 100), + (8, 20), + (12, 100), + (16, 20), + (20, 90), + (24, 25), + (28, 90), + (32, 30), + (36, 80), + (40, 20), + (44, 0), ]; for (id, urgency) in input.clone() { // this duplicates some code from stream_priority in order to access // streams and the collection they're in let stream = streams - .get_or_create(id, &local_tp, &peer_tp, false, true) + .get_or_create( + id, + &local_tp, + &peer_tp, + false, + true, + crate::PROTOCOL_VERSION, + ) .unwrap(); stream.urgency = urgency; @@ -2114,61 +2573,68 @@ mod tests { } let walk_1: Vec = streams.writable().collect(); + cycle_stream_priority(8, &mut streams); + cycle_stream_priority(20, &mut streams); cycle_stream_priority(4, &mut streams); - cycle_stream_priority(16, &mut streams); - cycle_stream_priority(0, &mut streams); let walk_2: Vec = streams.writable().collect(); + cycle_stream_priority(16, &mut streams); + cycle_stream_priority(28, &mut streams); cycle_stream_priority(12, &mut streams); - cycle_stream_priority(24, &mut streams); - cycle_stream_priority(8, &mut streams); let walk_3: Vec = streams.writable().collect(); - cycle_stream_priority(36, &mut streams); - cycle_stream_priority(16, &mut streams); - cycle_stream_priority(0, &mut streams); - let walk_4: Vec = streams.writable().collect(); + cycle_stream_priority(40, &mut streams); + cycle_stream_priority(20, &mut streams); cycle_stream_priority(4, &mut streams); - cycle_stream_priority(24, &mut streams); + let walk_4: Vec = streams.writable().collect(); cycle_stream_priority(8, &mut streams); - let walk_5: Vec = streams.writable().collect(); + cycle_stream_priority(28, &mut streams); cycle_stream_priority(12, &mut streams); + let walk_5: Vec = streams.writable().collect(); cycle_stream_priority(16, &mut streams); - cycle_stream_priority(0, &mut streams); + cycle_stream_priority(20, &mut streams); + cycle_stream_priority(4, &mut streams); let walk_6: Vec = streams.writable().collect(); - cycle_stream_priority(36, &mut streams); - cycle_stream_priority(24, &mut streams); - cycle_stream_priority(8, &mut streams); + cycle_stream_priority(40, &mut streams); + cycle_stream_priority(28, &mut streams); + cycle_stream_priority(12, &mut streams); let walk_7: Vec = streams.writable().collect(); + cycle_stream_priority(8, &mut streams); + cycle_stream_priority(20, &mut streams); cycle_stream_priority(4, &mut streams); - cycle_stream_priority(16, &mut streams); - cycle_stream_priority(0, &mut streams); let walk_8: Vec = streams.writable().collect(); + cycle_stream_priority(16, &mut streams); + cycle_stream_priority(28, &mut streams); cycle_stream_priority(12, &mut streams); - cycle_stream_priority(24, &mut streams); - cycle_stream_priority(8, &mut streams); let walk_9: Vec = streams.writable().collect(); - cycle_stream_priority(36, &mut streams); - cycle_stream_priority(16, &mut streams); - cycle_stream_priority(0, &mut streams); - - assert_eq!(walk_1, vec![40, 4, 12, 36, 20, 28, 32, 16, 24, 0, 8]); - assert_eq!(walk_2, vec![40, 12, 36, 4, 20, 28, 32, 24, 16, 8, 0]); - assert_eq!(walk_3, vec![40, 36, 4, 12, 20, 28, 32, 16, 24, 0, 8]); - assert_eq!(walk_4, vec![40, 4, 12, 36, 20, 28, 32, 24, 16, 8, 0]); - assert_eq!(walk_5, vec![40, 12, 36, 4, 20, 28, 32, 16, 24, 0, 8]); - assert_eq!(walk_6, vec![40, 36, 4, 12, 20, 28, 32, 24, 16, 8, 0]); - assert_eq!(walk_7, vec![40, 4, 12, 36, 20, 28, 32, 16, 24, 0, 8]); - assert_eq!(walk_8, vec![40, 12, 36, 4, 20, 28, 32, 24, 16, 8, 0]); - assert_eq!(walk_9, vec![40, 36, 4, 12, 20, 28, 32, 16, 24, 0, 8]); + cycle_stream_priority(40, &mut streams); + cycle_stream_priority(20, &mut streams); + cycle_stream_priority(4, &mut streams); + + assert_eq!(walk_1, vec![44, 8, 16, 40, 24, 32, 36, 20, 28, 4, 12]); + assert_eq!(walk_2, vec![44, 16, 40, 8, 24, 32, 36, 28, 20, 12, 4]); + assert_eq!(walk_3, vec![44, 40, 8, 16, 24, 32, 36, 20, 28, 4, 12]); + assert_eq!(walk_4, vec![44, 8, 16, 40, 24, 32, 36, 28, 20, 12, 4]); + assert_eq!(walk_5, vec![44, 16, 40, 8, 24, 32, 36, 20, 28, 4, 12]); + assert_eq!(walk_6, vec![44, 40, 8, 16, 24, 32, 36, 28, 20, 12, 4]); + assert_eq!(walk_7, vec![44, 8, 16, 40, 24, 32, 36, 20, 28, 4, 12]); + assert_eq!(walk_8, vec![44, 16, 40, 8, 24, 32, 36, 28, 20, 12, 4]); + assert_eq!(walk_9, vec![44, 40, 8, 16, 24, 32, 36, 20, 28, 4, 12]); // Removing streams doesn't break expected ordering. streams.collect(20, true); let walk_10: Vec = streams.writable().collect(); - assert_eq!(walk_10, vec![40, 4, 12, 36, 28, 32, 24, 16, 8, 0]); + assert_eq!(walk_10, vec![44, 8, 16, 40, 24, 32, 36, 28, 12, 4]); // Adding streams doesn't break expected ordering. let stream = streams - .get_or_create(44, &local_tp, &peer_tp, false, true) + .get_or_create( + 48, + &local_tp, + &peer_tp, + false, + true, + crate::PROTOCOL_VERSION, + ) .unwrap(); stream.urgency = 20; @@ -2177,7 +2643,7 @@ mod tests { let new_priority_key = Arc::new(StreamPriorityKey { urgency: stream.urgency, incremental: stream.incremental, - id: 44, + id: 48, ..Default::default() }); @@ -2187,7 +2653,7 @@ mod tests { streams.update_priority(&old_priority_key, &new_priority_key); let walk_11: Vec = streams.writable().collect(); - assert_eq!(walk_11, vec![40, 4, 12, 36, 44, 28, 32, 24, 16, 8, 0]); + assert_eq!(walk_11, vec![44, 8, 16, 40, 48, 24, 32, 36, 28, 12, 4]); } #[test] @@ -2195,7 +2661,7 @@ mod tests { let mut prioritized_writable: RBTree = Default::default(); - for id in [0, 4, 8, 12] { + for id in [4, 8, 12, 16] { let s = Arc::new(StreamPriorityKey { urgency: 0, incremental: false, @@ -2208,11 +2674,11 @@ mod tests { let walk_1: Vec = prioritized_writable.iter().map(|s| s.id).collect(); - assert_eq!(walk_1, vec![0, 4, 8, 12]); + assert_eq!(walk_1, vec![4, 8, 12, 16]); // Default keys could cause duplicate entries, this is normally protected // against via StreamMap. - for id in [0, 4, 8, 12] { + for id in [4, 8, 12, 16] { let s = Arc::new(StreamPriorityKey { urgency: 0, incremental: false, @@ -2225,9 +2691,10 @@ mod tests { let walk_2: Vec = prioritized_writable.iter().map(|s| s.id).collect(); - assert_eq!(walk_2, vec![0, 0, 4, 4, 8, 8, 12, 12]); + assert_eq!(walk_2, vec![4, 4, 8, 8, 12, 12, 16, 16]); } } +pub mod app_recv_buf; mod recv_buf; mod send_buf; diff --git a/quiche/src/stream/recv_buf.rs b/quiche/src/stream/recv_buf.rs index 56356f83..deb5b57d 100644 --- a/quiche/src/stream/recv_buf.rs +++ b/quiche/src/stream/recv_buf.rs @@ -36,8 +36,11 @@ use crate::Result; use crate::flowcontrol; use super::RangeBuf; +use super::RecvBufInfo; use super::DEFAULT_STREAM_WINDOW; +use likely_stable::if_likely; + /// Receive-side stream buffer. /// /// Stream data received by the peer is buffered in a list of data chunks @@ -45,38 +48,52 @@ use super::DEFAULT_STREAM_WINDOW; /// into a slice. #[derive(Debug, Default)] pub struct RecvBuf { + /// Todo -- compare speed with BTreeMap + // heap: BinaryHeap>, + pub heap: BTreeMap, /// Chunks of data received from the peer that have not yet been read by /// the application, ordered by offset. data: BTreeMap, /// The lowest data offset that has yet to be read by the application. - off: u64, + pub off: u64, + + /// The highest contiguous data offset that has yet to be read by the + /// application. + pub contiguous_off: u64, /// The total length of data received on this stream. len: u64, /// Receiver flow controller. - flow_control: flowcontrol::FlowControl, + pub flow_control: flowcontrol::FlowControl, /// The final stream offset received from the peer, if any. fin_off: Option, + /// In v3, set to true if we have to deliver the fin bit to the + /// application without any data. + pub deliver_fin: bool, + /// The error code received via RESET_STREAM. error: Option, /// Whether incoming data is validated but not buffered. drain: bool, + + pub version: u32, } impl RecvBuf { /// Creates a new receive buffer. - pub fn new(max_data: u64, max_window: u64) -> RecvBuf { + pub fn new(max_data: u64, max_window: u64, version: u32) -> RecvBuf { RecvBuf { flow_control: flowcontrol::FlowControl::new( max_data, cmp::min(max_data, DEFAULT_STREAM_WINDOW), max_window, ), + version, ..RecvBuf::default() } } @@ -192,6 +209,87 @@ impl RecvBuf { Ok(()) } + pub fn write_v3(&mut self, mut buf: RecvBufInfo) -> Result<()> { + if buf.max_off() > self.max_data() { + return Err(Error::FlowControl); + } + if let Some(fin_off) = self.fin_off { + // Stream's size is known, forbid data beyond that point. + if buf.max_off() > fin_off { + return Err(Error::FinalSize); + } + + // Stream's size is already known, forbid changing it. + if buf.fin() && fin_off != buf.max_off() { + return Err(Error::FinalSize); + } + } + // Stream's known size is lower than data already received. + if buf.fin() && buf.max_off() < self.len { + return Err(Error::FinalSize); + } + + // We already saved the final offset, so there's nothing else we + // need to keep from the RangeBuf if it's empty. + if self.fin_off.is_some() && buf.is_empty() { + return Ok(()); + } + + if buf.fin() { + self.fin_off = Some(buf.max_off()); + if buf.is_empty() && !self.drain { + self.deliver_fin = true; + } + } + + // No need to store empty buffer that doesn't carry the fin flag. + if !buf.fin() && buf.is_empty() { + return Ok(()); + } + + // Check if data is fully duplicate, that is the buffer's max offset is + // lower or equal to the offset already stored in the recv buffer. + if self.off >= buf.max_off() { + // An exception is applied to empty range buffers, because an empty + // buffer's max offset matches the max offset of the recv buffer. + // + // By this point all spurious empty buffers should have already been + // discarded, so allowing empty buffers here should be safe. + if !buf.is_empty() { + return Ok(()); + } + } + + if buf.start_off < self.contiguous_off { + // overlap with contiguous received data not yet read. + // This should not happen because the overlap is checked before + // decryption, and the packet is dropped. + return Err(Error::InvalidOffset); + } + + // Should overlapping ranges be treated as PROTOCOL_VIOLATION? This + // likely can get abused by middleboxes. Indeed, Stream DATA isn't + // globally AE-Secure because of this, which could be considered a + // missuse of the AEAD primitive. Note: this is not particularly + // an issue of quiche, but rather something silly in the Quic design + // itself, due to UDP. + + if self.off_front() > buf.off() && self.off_front() < buf.max_off() { + buf.len = (buf.off() + buf.len as u64 - self.off_front()) as usize; + buf.start_off = self.off_front(); + } + + self.len = cmp::max(self.len, buf.max_off()); + + if !self.drain && self.contiguous_off != buf.start_off { + self.heap.insert(buf.start_off, buf); + } else if self.contiguous_off == buf.start_off { + self.contiguous_off += buf.len as u64; + } + + Ok(()) + } + /// Writes data from the receive buffer into the given output buffer. /// /// Only contiguous data is written to the output buffer, starting from @@ -276,16 +374,33 @@ impl RecvBuf { // Clear all data already buffered. self.off = final_size; - self.data.clear(); + if_likely! { self.version == crate::PROTOCOL_VERSION_V3 => { + self.contiguous_off = final_size; + self.heap.clear(); + + let bufinfo = RecvBufInfo::from(final_size, 0, true); + self.write_v3(bufinfo)?; + } else { + self.data.clear(); - // In order to ensure the application is notified when the stream is - // reset, enqueue a zero-length buffer at the final size offset. - let buf = RangeBuf::from(b"", final_size, true); - self.write(buf)?; + // In order to ensure the application is notified when the stream is + // reset, enqueue a zero-length buffer at the final size offset. + let buf = RangeBuf::from(b"", final_size, true); + self.write(buf)?; + }}; Ok(max_data_delta as usize) } + /// Check whether the incoming data is in order. + pub fn not_in_order(&mut self, metadata: &RecvBufInfo) -> bool { + metadata.start_off > self.contiguous_off + } + + pub fn has_error(&self) -> Option { + self.error + } + /// Commits the new max_data limit. pub fn update_max_data(&mut self, now: time::Instant) { self.flow_control.update_max_data(now); @@ -319,7 +434,13 @@ impl RecvBuf { self.drain = true; - self.data.clear(); + if_likely! {self.version == crate::PROTOCOL_VERSION_V3 => { + self.heap.clear(); + self.deliver_fin = false; + self.contiguous_off = self.max_off(); + } else { + self.data.clear(); + }}; self.off = self.max_off(); @@ -331,6 +452,12 @@ impl RecvBuf { self.off } + /// Returns the highest contiguous offset that has yet to be read by + /// the application. + pub fn contiguous_off(&self) -> u64 { + self.contiguous_off + } + /// Returns true if we need to update the local flow control limit. pub fn almost_full(&self) -> bool { self.fin_off.is_none() && self.flow_control.should_update_max_data() @@ -360,22 +487,34 @@ impl RecvBuf { /// Returns true if the stream has data to be read. pub fn ready(&self) -> bool { - let (_, buf) = match self.data.first_key_value() { - Some(v) => v, - None => return false, - }; - - buf.off() == self.off + let ready = if_likely! {self.version == crate::PROTOCOL_VERSION_V3 => { + match self.heap.first_key_value() { + Some((_, recvinfo)) => self.contiguous_off > self.off || recvinfo.start_off <= self.off, + None => self.contiguous_off > self.off || self.deliver_fin, + } + } else { + let (_, buf) = match self.data.first_key_value() { + Some(v) => v, + None => return false, + }; + buf.off() == self.off + }}; + ready } } #[cfg(test)] mod tests { use super::*; + use crate::stream::app_recv_buf::AppRecvBuf; #[test] fn empty_read() { - let mut recv = RecvBuf::new(u64::MAX, DEFAULT_STREAM_WINDOW); + let mut recv = RecvBuf::new( + u64::MAX, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); assert_eq!(recv.len, 0); let mut buf = [0; 32]; @@ -385,595 +524,1079 @@ mod tests { #[test] fn empty_stream_frame() { - let mut recv = RecvBuf::new(15, DEFAULT_STREAM_WINDOW); + let mut recv = + RecvBuf::new(15, DEFAULT_STREAM_WINDOW, crate::PROTOCOL_VERSION); assert_eq!(recv.len, 0); let buf = RangeBuf::from(b"hello", 0, false); - assert!(recv.write(buf).is_ok()); + let bufinfo = RecvBufInfo::from(0, 5, false); + let mut app_buf = AppRecvBuf::new(1, Some(42), 100, 1000); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(buf).is_ok()); + assert_eq!(recv.data.len(), 1); + } else { + assert!(recv.write_v3(bufinfo).is_ok()); + assert_eq!(recv.heap.len(), 0); + } assert_eq!(recv.len, 5); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 1); let mut buf = [0; 32]; - assert_eq!(recv.emit(&mut buf), Ok((5, false))); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(recv.emit(&mut buf), Ok((5, false))); + } else { + assert_eq!( + (app_buf.read_mut(&mut recv).unwrap().len(), recv.is_fin()), + (5, false) + ); + assert!(app_buf.has_consumed(None, 5).is_ok()); + } // Don't store non-fin empty buffer. let buf = RangeBuf::from(b"", 10, false); - assert!(recv.write(buf).is_ok()); + let bufinfo = RecvBufInfo::from(10, 0, false); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(buf).is_ok()); + assert_eq!(recv.data.len(), 0); + } else { + assert!(recv.write_v3(bufinfo).is_ok()); + assert_eq!(recv.heap.len(), 0); + } assert_eq!(recv.len, 5); assert_eq!(recv.off, 5); - assert_eq!(recv.data.len(), 0); // Check flow control for empty buffer. let buf = RangeBuf::from(b"", 16, false); - assert_eq!(recv.write(buf), Err(Error::FlowControl)); + let bufinfo = RecvBufInfo::from(16, 0, false); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(recv.write(buf), Err(Error::FlowControl)); + } else { + assert_eq!(recv.write_v3(bufinfo), Err(Error::FlowControl)); + } // Store fin empty buffer. let buf = RangeBuf::from(b"", 5, true); - assert!(recv.write(buf).is_ok()); + let bufinfo = RecvBufInfo::from(5, 0, true); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(buf).is_ok()); + assert_eq!(recv.data.len(), 1); + } else { + // In v3 we don't store it if it is in order, but we mark the stream + // as fin. + assert!(recv.write_v3(bufinfo).is_ok()); + assert_eq!(recv.heap.len(), 0); + } assert_eq!(recv.len, 5); assert_eq!(recv.off, 5); - assert_eq!(recv.data.len(), 1); // Don't store additional fin empty buffers. let buf = RangeBuf::from(b"", 5, true); - assert!(recv.write(buf).is_ok()); + let bufinfo = RecvBufInfo::from(5, 0, true); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(buf).is_ok()); + assert_eq!(recv.data.len(), 1); + } else { + assert!(recv.write_v3(bufinfo).is_ok()); + assert_eq!(recv.heap.len(), 0); + } assert_eq!(recv.len, 5); assert_eq!(recv.off, 5); - assert_eq!(recv.data.len(), 1); // Don't store additional fin non-empty buffers. let buf = RangeBuf::from(b"aa", 3, true); - assert!(recv.write(buf).is_ok()); + let bufinfo = RecvBufInfo::from(3, 2, true); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(buf).is_ok()); + assert_eq!(recv.data.len(), 1); + } else { + assert!(recv.write_v3(bufinfo).is_ok()); + assert_eq!(recv.heap.len(), 0); + } assert_eq!(recv.len, 5); assert_eq!(recv.off, 5); - assert_eq!(recv.data.len(), 1); // Validate final size with fin empty buffers. - let buf = RangeBuf::from(b"", 6, true); - assert_eq!(recv.write(buf), Err(Error::FinalSize)); - let buf = RangeBuf::from(b"", 4, true); - assert_eq!(recv.write(buf), Err(Error::FinalSize)); - - let mut buf = [0; 32]; - assert_eq!(recv.emit(&mut buf), Ok((0, true))); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + let buf = RangeBuf::from(b"", 6, true); + assert_eq!(recv.write(buf), Err(Error::FinalSize)); + let buf = RangeBuf::from(b"", 4, true); + assert_eq!(recv.write(buf), Err(Error::FinalSize)); + let mut buf = [0; 32]; + assert_eq!(recv.emit(&mut buf), Ok((0, true))); + } else { + let bufinfo = RecvBufInfo::from(6, 0, true); + assert_eq!(recv.write_v3(bufinfo), Err(Error::FinalSize)); + let bufinfo = RecvBufInfo::from(4, 0, true); + assert_eq!(recv.write_v3(bufinfo), Err(Error::FinalSize)); + assert_eq!( + (app_buf.read_mut(&mut recv).unwrap().len(), recv.is_fin()), + (0, true) + ); + } } #[test] fn ordered_read() { - let mut recv = RecvBuf::new(u64::MAX, DEFAULT_STREAM_WINDOW); + let mut recv = RecvBuf::new( + u64::MAX, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); assert_eq!(recv.len, 0); let mut buf = [0; 32]; + let mut app_buf = AppRecvBuf::new(1, Some(42), 100, 1000); let first = RangeBuf::from(b"hello", 0, false); + let firstinfo = RecvBufInfo::from(0, 5, false); let second = RangeBuf::from(b"world", 5, false); + let secondinfo = RecvBufInfo::from(5, 5, false); let third = RangeBuf::from(b"something", 10, true); - - assert!(recv.write(second).is_ok()); + let thirdinfo = RecvBufInfo::from(10, 9, false); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(second).is_ok()); + assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + } else { + // If we have nothing to read, we return a 0 length slice + assert!(recv.write_v3(secondinfo).is_ok()); + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 0); + } assert_eq!(recv.len, 10); assert_eq!(recv.off, 0); - assert_eq!(recv.emit(&mut buf), Err(Error::Done)); - - assert!(recv.write(third).is_ok()); - assert_eq!(recv.len, 19); - assert_eq!(recv.off, 0); - - assert_eq!(recv.emit(&mut buf), Err(Error::Done)); - - assert!(recv.write(first).is_ok()); - assert_eq!(recv.len, 19); - assert_eq!(recv.off, 0); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(third).is_ok()); + assert_eq!(recv.len, 19); + assert_eq!(recv.off, 0); + assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + } else { + assert!(recv.write_v3(thirdinfo).is_ok()); + assert_eq!(recv.len, 19); + assert_eq!(recv.off, 0); + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 0); + } - let (len, fin) = recv.emit(&mut buf).unwrap(); - assert_eq!(len, 19); - assert!(fin); - assert_eq!(&buf[..len], b"helloworldsomething"); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(first).is_ok()); + assert_eq!(recv.len, 19); + assert_eq!(recv.off, 0); + let (len, fin) = recv.emit(&mut buf).unwrap(); + assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + assert_eq!(len, 19); + assert_eq!(fin, true); + assert_eq!(&buf[..len], b"helloworldsomething"); + } else { + assert!(recv.write_v3(firstinfo).is_ok()); + assert_eq!(recv.len, 19); + assert_eq!(recv.off, 0); + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 19); + } assert_eq!(recv.len, 19); assert_eq!(recv.off, 19); - - assert_eq!(recv.emit(&mut buf), Err(Error::Done)); } #[test] fn split_read() { - let mut recv = RecvBuf::new(u64::MAX, DEFAULT_STREAM_WINDOW); - assert_eq!(recv.len, 0); - - let mut buf = [0; 32]; - - let first = RangeBuf::from(b"something", 0, false); - let second = RangeBuf::from(b"helloworld", 9, true); - - assert!(recv.write(first).is_ok()); - assert_eq!(recv.len, 9); - assert_eq!(recv.off, 0); - - assert!(recv.write(second).is_ok()); - assert_eq!(recv.len, 19); - assert_eq!(recv.off, 0); - - let (len, fin) = recv.emit(&mut buf[..10]).unwrap(); - assert_eq!(len, 10); - assert!(!fin); - assert_eq!(&buf[..len], b"somethingh"); - assert_eq!(recv.len, 19); - assert_eq!(recv.off, 10); - - let (len, fin) = recv.emit(&mut buf[..5]).unwrap(); - assert_eq!(len, 5); - assert!(!fin); - assert_eq!(&buf[..len], b"ellow"); - assert_eq!(recv.len, 19); - assert_eq!(recv.off, 15); - - let (len, fin) = recv.emit(&mut buf[..10]).unwrap(); - assert_eq!(len, 4); - assert!(fin); - assert_eq!(&buf[..len], b"orld"); - assert_eq!(recv.len, 19); - assert_eq!(recv.off, 19); + // TODO Double check; we don't need split logic in V3. + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + let mut recv = RecvBuf::new( + u64::MAX, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); + assert_eq!(recv.len, 0); + + let mut buf = [0; 32]; + + let first = RangeBuf::from(b"something", 0, false); + let second = RangeBuf::from(b"helloworld", 9, true); + + assert!(recv.write(first).is_ok()); + assert_eq!(recv.len, 9); + assert_eq!(recv.off, 0); + + assert!(recv.write(second).is_ok()); + assert_eq!(recv.len, 19); + assert_eq!(recv.off, 0); + + let (len, fin) = recv.emit(&mut buf[..10]).unwrap(); + assert_eq!(len, 10); + assert!(!fin); + assert_eq!(&buf[..len], b"somethingh"); + assert_eq!(recv.len, 19); + assert_eq!(recv.off, 10); + + let (len, fin) = recv.emit(&mut buf[..5]).unwrap(); + assert_eq!(len, 5); + assert!(!fin); + assert_eq!(&buf[..len], b"ellow"); + assert_eq!(recv.len, 19); + assert_eq!(recv.off, 15); + + let (len, fin) = recv.emit(&mut buf[..10]).unwrap(); + assert_eq!(len, 4); + assert!(fin); + assert_eq!(&buf[..len], b"orld"); + assert_eq!(recv.len, 19); + assert_eq!(recv.off, 19); + } } #[test] fn incomplete_read() { - let mut recv = RecvBuf::new(u64::MAX, DEFAULT_STREAM_WINDOW); + let mut recv = RecvBuf::new( + u64::MAX, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); assert_eq!(recv.len, 0); let mut buf = [0; 32]; + let mut app_buf = AppRecvBuf::new(1, Some(42), 100, 1000); let first = RangeBuf::from(b"something", 0, false); + let firstinfo = RecvBufInfo::from(0, 9, false); let second = RangeBuf::from(b"helloworld", 9, true); + let secondinfo = RecvBufInfo::from(9, 10, true); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(second).is_ok()); + assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + } else { + assert!(recv.write_v3(secondinfo).is_ok()); + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 0); + } - assert!(recv.write(second).is_ok()); - assert_eq!(recv.len, 19); - assert_eq!(recv.off, 0); - - assert_eq!(recv.emit(&mut buf), Err(Error::Done)); - - assert!(recv.write(first).is_ok()); assert_eq!(recv.len, 19); assert_eq!(recv.off, 0); - let (len, fin) = recv.emit(&mut buf).unwrap(); - assert_eq!(len, 19); - assert!(fin); - assert_eq!(&buf[..len], b"somethinghelloworld"); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(first).is_ok()); + assert_eq!(recv.len, 19); + assert_eq!(recv.off, 0); + let (len, fin) = recv.emit(&mut buf).unwrap(); + assert_eq!(len, 19); + assert_eq!(fin, true); + assert_eq!(&buf[..len], b"somethinghelloworld"); + } else { + assert!(recv.write_v3(firstinfo).is_ok()); + assert_eq!(recv.len, 19); + assert_eq!(recv.off, 0); + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 19); + assert_eq!(recv.is_fin(), true); + } assert_eq!(recv.len, 19); assert_eq!(recv.off, 19); } #[test] fn zero_len_read() { - let mut recv = RecvBuf::new(u64::MAX, DEFAULT_STREAM_WINDOW); + let mut recv = RecvBuf::new( + u64::MAX, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); assert_eq!(recv.len, 0); let mut buf = [0; 32]; + let mut app_buf = AppRecvBuf::new(1, Some(42), 100, 1000); let first = RangeBuf::from(b"something", 0, false); + let firstinfo = RecvBufInfo::from(0, 9, false); let second = RangeBuf::from(b"", 9, true); - - assert!(recv.write(first).is_ok()); + let secondinfo = RecvBufInfo::from(9, 0, true); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(first).is_ok()); + assert_eq!(recv.data.len(), 1); + } else { + assert!(recv.write_v3(firstinfo).is_ok()); + // contiguous, hence not stored in the heap. + assert_eq!(recv.heap.len(), 0); + } assert_eq!(recv.len, 9); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 1); - assert!(recv.write(second).is_ok()); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(second).is_ok()); + assert_eq!(recv.data.len(), 1); + } else { + assert!(recv.write_v3(secondinfo).is_ok()); + assert_eq!(recv.heap.len(), 0); + } assert_eq!(recv.len, 9); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 1); - let (len, fin) = recv.emit(&mut buf).unwrap(); - assert_eq!(len, 9); - assert!(fin); - assert_eq!(&buf[..len], b"something"); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + let (len, fin) = recv.emit(&mut buf).unwrap(); + assert_eq!(len, 9); + assert_eq!(fin, true); + assert_eq!(&buf[..len], b"something"); + } else { + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 9); + assert_eq!(recv.is_fin(), true); + } assert_eq!(recv.len, 9); assert_eq!(recv.off, 9); } #[test] fn past_read() { - let mut recv = RecvBuf::new(u64::MAX, DEFAULT_STREAM_WINDOW); + let mut recv = RecvBuf::new( + u64::MAX, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); assert_eq!(recv.len, 0); let mut buf = [0; 32]; + let mut app_buf = AppRecvBuf::new(1, Some(42), 100, 1000); let first = RangeBuf::from(b"something", 0, false); + let firstinfo = RecvBufInfo::from(0, 9, false); let second = RangeBuf::from(b"hello", 3, false); + let secondinfo = RecvBufInfo::from(3, 5, false); let third = RangeBuf::from(b"ello", 4, true); + let thirdinfo = RecvBufInfo::from(4, 4, true); let fourth = RangeBuf::from(b"ello", 5, true); + let fourthinfo = RecvBufInfo::from(5, 4, true); + + if crate::PROTOCOL_VERSION != crate::PROTOCOL_VERSION_V3 { + assert!(recv.write(first).is_ok()); + assert_eq!(recv.len, 9); + assert_eq!(recv.off, 0); + assert_eq!(recv.data.len(), 1); + let (len, fin) = recv.emit(&mut buf).unwrap(); + assert_eq!(len, 9); + assert_eq!(fin, false); + assert_eq!(&buf[..len], b"something"); + } else { + assert!(recv.write_v3(firstinfo).is_ok()); + assert_eq!(recv.len, 9); + assert_eq!(recv.off, 0); + assert_eq!(recv.heap.len(), 0); + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 9); + assert!(app_buf.has_consumed(None, 9).is_ok()); + assert_eq!(recv.is_fin(), false); + } - assert!(recv.write(first).is_ok()); - assert_eq!(recv.len, 9); - assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 1); - - let (len, fin) = recv.emit(&mut buf).unwrap(); - assert_eq!(len, 9); - assert!(!fin); - assert_eq!(&buf[..len], b"something"); assert_eq!(recv.len, 9); assert_eq!(recv.off, 9); - assert!(recv.write(second).is_ok()); + if crate::PROTOCOL_VERSION != crate::PROTOCOL_VERSION_V3 { + assert!(recv.write(second).is_ok()); + assert_eq!(recv.data.len(), 0); + } else { + assert!(recv.write_v3(secondinfo).is_ok()); + assert_eq!(recv.heap.len(), 0); + } assert_eq!(recv.len, 9); assert_eq!(recv.off, 9); - assert_eq!(recv.data.len(), 0); - assert_eq!(recv.write(third), Err(Error::FinalSize)); - - assert!(recv.write(fourth).is_ok()); - assert_eq!(recv.len, 9); - assert_eq!(recv.off, 9); - assert_eq!(recv.data.len(), 0); + if crate::PROTOCOL_VERSION != crate::PROTOCOL_VERSION_V3 { + assert_eq!(recv.write(third), Err(Error::FinalSize)); + } else { + assert_eq!(recv.write_v3(thirdinfo), Err(Error::FinalSize)); + } - assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + if crate::PROTOCOL_VERSION != crate::PROTOCOL_VERSION_V3 { + assert!(recv.write(fourth).is_ok()); + assert_eq!(recv.len, 9); + assert_eq!(recv.off, 9); + assert_eq!(recv.data.len(), 0); + assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + } else { + assert!(recv.write_v3(fourthinfo).is_ok()); + assert_eq!(recv.len, 9); + assert_eq!(recv.off, 9); + assert_eq!(recv.heap.len(), 0); + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 0); + } } #[test] fn fully_overlapping_read() { - let mut recv = RecvBuf::new(u64::MAX, DEFAULT_STREAM_WINDOW); + let mut recv = RecvBuf::new( + u64::MAX, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); + let mut app_buf = AppRecvBuf::new(1, Some(42), 100, 1000); assert_eq!(recv.len, 0); let mut buf = [0; 32]; let first = RangeBuf::from(b"something", 0, false); + let firstinfo = RecvBufInfo::from(0, 9, false); let second = RangeBuf::from(b"hello", 4, false); - - assert!(recv.write(first).is_ok()); - assert_eq!(recv.len, 9); - assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 1); - - assert!(recv.write(second).is_ok()); + let secondinfo = RecvBufInfo::from(4, 5, false); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(first).is_ok()); + assert_eq!(recv.data.len(), 1); + } else { + assert!(recv.write_v3(firstinfo).is_ok()); + assert_eq!(recv.heap.len(), 0); + } assert_eq!(recv.len, 9); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 1); - let (len, fin) = recv.emit(&mut buf).unwrap(); - assert_eq!(len, 9); - assert!(!fin); - assert_eq!(&buf[..len], b"something"); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(second).is_ok()); + assert_eq!(recv.len, 9); + assert_eq!(recv.off, 0); + assert_eq!(recv.data.len(), 1); + let (len, fin) = recv.emit(&mut buf).unwrap(); + assert_eq!(len, 9); + assert_eq!(fin, false); + assert_eq!(&buf[..len], b"something"); + assert_eq!(recv.data.len(), 0); + } else { + assert!(recv.write_v3(secondinfo).is_err()); + assert_eq!(recv.len, 9); + assert_eq!(recv.off, 0); + assert_eq!(recv.heap.len(), 0); + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 9); + assert!(app_buf.has_consumed(None, 9).is_ok()); + assert_eq!(recv.heap.len(), 0); + } assert_eq!(recv.len, 9); assert_eq!(recv.off, 9); - assert_eq!(recv.data.len(), 0); - assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + } else { + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 0); + } } #[test] fn fully_overlapping_read2() { - let mut recv = RecvBuf::new(u64::MAX, DEFAULT_STREAM_WINDOW); + let mut recv = RecvBuf::new( + u64::MAX, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); + let mut app_buf = AppRecvBuf::new(1, Some(42), 100, 1000); assert_eq!(recv.len, 0); let mut buf = [0; 32]; let first = RangeBuf::from(b"something", 0, false); + let firstinfo = RecvBufInfo::from(0, 9, false); let second = RangeBuf::from(b"hello", 4, false); - - assert!(recv.write(second).is_ok()); - assert_eq!(recv.len, 9); - assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 1); - - assert!(recv.write(first).is_ok()); + let secondinfo = RecvBufInfo::from(4, 5, false); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(second).is_ok()); + assert_eq!(recv.data.len(), 1); + } else { + assert!(recv.write_v3(secondinfo).is_ok()); + assert_eq!(recv.heap.len(), 1); + } assert_eq!(recv.len, 9); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 2); - let (len, fin) = recv.emit(&mut buf).unwrap(); - assert_eq!(len, 9); - assert!(!fin); - assert_eq!(&buf[..len], b"somehello"); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(first).is_ok()); + assert_eq!(recv.len, 9); + assert_eq!(recv.off, 0); + assert_eq!(recv.data.len(), 2); + let (len, fin) = recv.emit(&mut buf).unwrap(); + assert_eq!(len, 9); + assert_eq!(fin, false); + assert_eq!(&buf[..len], b"somehello"); + assert_eq!(recv.data.len(), 0); + } else { + assert!(recv.write_v3(firstinfo).is_ok()); + assert_eq!(recv.len, 9); + assert_eq!(recv.off, 0); + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 9); + assert!(app_buf.has_consumed(None, 9).is_ok()); + assert!(!recv.is_fin()); + assert_eq!(recv.heap.len(), 0); + } assert_eq!(recv.len, 9); assert_eq!(recv.off, 9); - assert_eq!(recv.data.len(), 0); - assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + } else { + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 0); + } } #[test] fn fully_overlapping_read3() { - let mut recv = RecvBuf::new(u64::MAX, DEFAULT_STREAM_WINDOW); + let mut recv = RecvBuf::new( + u64::MAX, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); + let mut app_buf = AppRecvBuf::new(1, Some(42), 100, 1000); assert_eq!(recv.len, 0); let mut buf = [0; 32]; let first = RangeBuf::from(b"something", 0, false); + let firstinfo = RecvBufInfo::from(0, 9, false); let second = RangeBuf::from(b"hello", 3, false); + let secondinfo = RecvBufInfo::from(3, 5, false); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(second).is_ok()); + assert_eq!(recv.data.len(), 1); + } else { + assert!(recv.write_v3(secondinfo).is_ok()); + assert_eq!(recv.heap.len(), 1); + } - assert!(recv.write(second).is_ok()); assert_eq!(recv.len, 8); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 1); - assert!(recv.write(first).is_ok()); - assert_eq!(recv.len, 9); - assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 3); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(first).is_ok()); + assert_eq!(recv.len, 9); + assert_eq!(recv.off, 0); + assert_eq!(recv.data.len(), 3); + let (len, fin) = recv.emit(&mut buf).unwrap(); + assert_eq!(len, 9); + assert_eq!(fin, false); + assert_eq!(&buf[..len], b"somhellog"); + assert_eq!(recv.data.len(), 0); + } else { + assert!(recv.write_v3(firstinfo).is_ok()); + assert_eq!(recv.len, 9); + assert_eq!(recv.off, 0); + assert_eq!(recv.heap.len(), 1); + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 9); + assert!(app_buf.has_consumed(None, 9).is_ok()); + assert_eq!(recv.heap.len(), 0); + } - let (len, fin) = recv.emit(&mut buf).unwrap(); - assert_eq!(len, 9); - assert!(!fin); - assert_eq!(&buf[..len], b"somhellog"); assert_eq!(recv.len, 9); assert_eq!(recv.off, 9); - assert_eq!(recv.data.len(), 0); - assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + } else { + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 0); + } } #[test] fn fully_overlapping_read_multi() { - let mut recv = RecvBuf::new(u64::MAX, DEFAULT_STREAM_WINDOW); + let mut recv = RecvBuf::new( + u64::MAX, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); + let mut app_buf = AppRecvBuf::new(1, Some(42), 100, 1000); assert_eq!(recv.len, 0); let mut buf = [0; 32]; let first = RangeBuf::from(b"somethingsomething", 0, false); + let firstinfo = RecvBufInfo::from(0, 18, false); let second = RangeBuf::from(b"hello", 3, false); + let secondinfo = RecvBufInfo::from(3, 5, false); let third = RangeBuf::from(b"hello", 12, false); - - assert!(recv.write(second).is_ok()); + let thirdinfo = RecvBufInfo::from(12, 5, false); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(second).is_ok()); + assert_eq!(recv.data.len(), 1); + } else { + assert!(recv.write_v3(secondinfo).is_ok()); + assert_eq!(recv.heap.len(), 1); + } assert_eq!(recv.len, 8); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 1); - assert!(recv.write(third).is_ok()); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(third).is_ok()); + assert_eq!(recv.data.len(), 2); + } else { + assert!(recv.write_v3(thirdinfo).is_ok()); + assert_eq!(recv.heap.len(), 2); + } assert_eq!(recv.len, 17); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 2); - - assert!(recv.write(first).is_ok()); - assert_eq!(recv.len, 18); - assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 5); - let (len, fin) = recv.emit(&mut buf).unwrap(); - assert_eq!(len, 18); - assert!(!fin); - assert_eq!(&buf[..len], b"somhellogsomhellog"); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(first).is_ok()); + assert_eq!(recv.len, 18); + assert_eq!(recv.off, 0); + assert_eq!(recv.data.len(), 5); + let (len, fin) = recv.emit(&mut buf).unwrap(); + assert_eq!(len, 18); + assert_eq!(fin, false); + assert_eq!(&buf[..len], b"somhellogsomhellog"); + assert_eq!(recv.data.len(), 0); + } else { + assert!(recv.write_v3(firstinfo).is_ok()); + assert_eq!(recv.len, 18); + assert_eq!(recv.off, 0); + // firstinfo is contiguous; it does not go through the heap. + assert_eq!(recv.heap.len(), 2); + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 18); + assert!(app_buf.has_consumed(None, 18).is_ok()); + assert_eq!(recv.heap.len(), 0); + } assert_eq!(recv.len, 18); assert_eq!(recv.off, 18); - assert_eq!(recv.data.len(), 0); - assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + } else { + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 0); + } } #[test] fn overlapping_start_read() { - let mut recv = RecvBuf::new(u64::MAX, DEFAULT_STREAM_WINDOW); + let mut recv = RecvBuf::new( + u64::MAX, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); + let mut app_buf = AppRecvBuf::new(1, Some(42), 100, 1000); assert_eq!(recv.len, 0); let mut buf = [0; 32]; let first = RangeBuf::from(b"something", 0, false); + let firstinfo = RecvBufInfo::from(0, 9, false); let second = RangeBuf::from(b"hello", 8, true); - - assert!(recv.write(first).is_ok()); + let secondinfo = RecvBufInfo::from(8, 5, true); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(first).is_ok()); + assert_eq!(recv.data.len(), 1); + } else { + assert!(recv.write_v3(firstinfo).is_ok()); + assert_eq!(recv.heap.len(), 0); + } assert_eq!(recv.len, 9); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 1); - - assert!(recv.write(second).is_ok()); - assert_eq!(recv.len, 13); - assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 2); - - let (len, fin) = recv.emit(&mut buf).unwrap(); - assert_eq!(len, 13); - assert!(fin); - assert_eq!(&buf[..len], b"somethingello"); - assert_eq!(recv.len, 13); - assert_eq!(recv.off, 13); - assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(second).is_ok()); + assert_eq!(recv.len, 13); + assert_eq!(recv.off, 0); + assert_eq!(recv.data.len(), 2); + let (len, fin) = recv.emit(&mut buf).unwrap(); + assert_eq!(len, 13); + assert_eq!(fin, true); + assert_eq!(&buf[..len], b"somethingello"); + assert_eq!(recv.len, 13); + assert_eq!(recv.off, 13); + } else { + // That sort of overlap can't happen in v3 + // because the second packet would not be decrypted + assert!(recv.write_v3(secondinfo).is_err()); + assert_eq!(recv.len, 9); + assert_eq!(recv.off, 0); + assert_eq!(recv.heap.len(), 0); + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 9); + assert!(app_buf.has_consumed(None, 9).is_ok()); + assert!(!recv.is_fin()); + assert_eq!(recv.len, 9); + assert_eq!(recv.off, 9); + } + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + } else { + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 0); + } } #[test] fn overlapping_end_read() { - let mut recv = RecvBuf::new(u64::MAX, DEFAULT_STREAM_WINDOW); + let mut recv = RecvBuf::new( + u64::MAX, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); + let mut app_buf = AppRecvBuf::new(1, Some(42), 100, 1000); assert_eq!(recv.len, 0); let mut buf = [0; 32]; let first = RangeBuf::from(b"hello", 0, false); + let firstinfo = RecvBufInfo::from(0, 5, false); let second = RangeBuf::from(b"something", 3, true); - - assert!(recv.write(second).is_ok()); - assert_eq!(recv.len, 12); - assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 1); - - assert!(recv.write(first).is_ok()); + let secondinfo = RecvBufInfo::from(3, 9, true); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(second).is_ok()); + assert_eq!(recv.data.len(), 1); + } else { + assert!(recv.write_v3(secondinfo).is_ok()); + assert_eq!(recv.heap.len(), 1); + } assert_eq!(recv.len, 12); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 2); - let (len, fin) = recv.emit(&mut buf).unwrap(); - assert_eq!(len, 12); - assert!(fin); - assert_eq!(&buf[..len], b"helsomething"); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(first).is_ok()); + assert_eq!(recv.len, 12); + assert_eq!(recv.off, 0); + assert_eq!(recv.data.len(), 2); + let (len, fin) = recv.emit(&mut buf).unwrap(); + assert_eq!(len, 12); + assert_eq!(fin, true); + assert_eq!(&buf[..len], b"helsomething"); + } else { + assert!(recv.write_v3(firstinfo).is_ok()); + assert_eq!(recv.len, 12); + assert_eq!(recv.off, 0); + assert_eq!(recv.heap.len(), 1); + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 12); + assert!(app_buf.has_consumed(None, 12).is_ok()); + assert!(recv.is_fin()); + } assert_eq!(recv.len, 12); assert_eq!(recv.off, 12); - assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + } else { + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 0); + } } #[test] fn overlapping_end_twice_read() { - let mut recv = RecvBuf::new(u64::MAX, DEFAULT_STREAM_WINDOW); + let mut recv = RecvBuf::new( + u64::MAX, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); + let mut app_buf = AppRecvBuf::new(1, Some(42), 100, 1000); assert_eq!(recv.len, 0); let mut buf = [0; 32]; let first = RangeBuf::from(b"he", 0, false); + let firstinfo = RecvBufInfo::from(0, 2, false); let second = RangeBuf::from(b"ow", 4, false); + let secondinfo = RecvBufInfo::from(4, 2, false); let third = RangeBuf::from(b"rl", 7, false); + let thirdinfo = RecvBufInfo::from(7, 2, false); let fourth = RangeBuf::from(b"helloworld", 0, true); - - assert!(recv.write(third).is_ok()); + let fourthinfo = RecvBufInfo::from(0, 10, false); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(third).is_ok()); + assert_eq!(recv.data.len(), 1); + } else { + assert!(recv.write_v3(thirdinfo).is_ok()); + assert_eq!(recv.heap.len(), 1); + } assert_eq!(recv.len, 9); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 1); - assert!(recv.write(second).is_ok()); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(second).is_ok()); + assert_eq!(recv.data.len(), 2); + } else { + assert!(recv.write_v3(secondinfo).is_ok()); + assert_eq!(recv.heap.len(), 2); + } assert_eq!(recv.len, 9); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 2); - assert!(recv.write(first).is_ok()); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(first).is_ok()); + assert_eq!(recv.data.len(), 3); + } else { + assert!(recv.write_v3(firstinfo).is_ok()); + assert_eq!(recv.heap.len(), 2); + } assert_eq!(recv.len, 9); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 3); - assert!(recv.write(fourth).is_ok()); - assert_eq!(recv.len, 10); - assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 6); - - let (len, fin) = recv.emit(&mut buf).unwrap(); - assert_eq!(len, 10); - assert!(fin); - assert_eq!(&buf[..len], b"helloworld"); - assert_eq!(recv.len, 10); - assert_eq!(recv.off, 10); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(fourth).is_ok()); + assert_eq!(recv.len, 10); + assert_eq!(recv.off, 0); + assert_eq!(recv.data.len(), 6); + let (len, fin) = recv.emit(&mut buf).unwrap(); + assert_eq!(len, 10); + assert_eq!(fin, true); + assert_eq!(&buf[..len], b"helloworld"); + assert_eq!(recv.len, 10); + assert_eq!(recv.off, 10); + } else { + assert!(recv.write_v3(fourthinfo).is_err()); + assert_eq!(recv.len, 9); + assert_eq!(recv.off, 0); + assert_eq!(recv.heap.len(), 2); + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 2); + assert!(app_buf.has_consumed(None, 2).is_ok()); + assert!(!recv.is_fin()); + } - assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + } else { + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 0); + } } #[test] fn overlapping_end_twice_and_contained_read() { - let mut recv = RecvBuf::new(u64::MAX, DEFAULT_STREAM_WINDOW); + let mut recv = RecvBuf::new( + u64::MAX, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); + let mut app_buf = AppRecvBuf::new(1, Some(42), 100, 1000); assert_eq!(recv.len, 0); let mut buf = [0; 32]; let first = RangeBuf::from(b"hellow", 0, false); + let firstinfo = RecvBufInfo::from(0, 5, false); let second = RangeBuf::from(b"barfoo", 10, true); + let secondinfo = RecvBufInfo::from(10, 6, true); let third = RangeBuf::from(b"rl", 7, false); + let thirdinfo = RecvBufInfo::from(7, 2, false); let fourth = RangeBuf::from(b"elloworldbarfoo", 1, true); - - assert!(recv.write(third).is_ok()); + let fourthinfo = RecvBufInfo::from(1, 15, true); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(third).is_ok()); + assert_eq!(recv.data.len(), 1); + } else { + assert!(recv.write_v3(thirdinfo).is_ok()); + assert_eq!(recv.heap.len(), 1); + } assert_eq!(recv.len, 9); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 1); - assert!(recv.write(second).is_ok()); - assert_eq!(recv.len, 16); - assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 2); - - assert!(recv.write(first).is_ok()); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(second).is_ok()); + assert_eq!(recv.data.len(), 2); + } else { + assert!(recv.write_v3(secondinfo).is_ok()); + assert_eq!(recv.heap.len(), 2); + } assert_eq!(recv.len, 16); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 3); - assert!(recv.write(fourth).is_ok()); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(first).is_ok()); + assert_eq!(recv.data.len(), 3); + } else { + assert!(recv.write_v3(firstinfo).is_ok()); + assert_eq!(recv.heap.len(), 2); + } assert_eq!(recv.len, 16); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 5); - let (len, fin) = recv.emit(&mut buf).unwrap(); - assert_eq!(len, 16); - assert!(fin); - assert_eq!(&buf[..len], b"helloworldbarfoo"); - assert_eq!(recv.len, 16); - assert_eq!(recv.off, 16); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(fourth).is_ok()); + assert_eq!(recv.len, 16); + assert_eq!(recv.off, 0); + assert_eq!(recv.data.len(), 5); + let (len, fin) = recv.emit(&mut buf).unwrap(); + assert_eq!(len, 16); + assert_eq!(fin, true); + assert_eq!(&buf[..len], b"helloworldbarfoo"); + assert_eq!(recv.len, 16); + assert_eq!(recv.off, 16); + } else { + assert!(recv.write_v3(fourthinfo).is_err()); + assert_eq!(recv.len, 16); + assert_eq!(recv.off, 0); + assert_eq!(recv.heap.len(), 2); + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 5); + assert!(app_buf.has_consumed(None, 5).is_ok()); + assert!(!recv.is_fin()); + assert_eq!(recv.len, 16); + assert_eq!(recv.off, 5); + } - assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + } else { + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 0); + } } #[test] fn partially_multi_overlapping_reordered_read() { - let mut recv = RecvBuf::new(u64::MAX, DEFAULT_STREAM_WINDOW); + let mut recv = RecvBuf::new( + u64::MAX, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); + let mut app_buf = AppRecvBuf::new(1, Some(42), 100, 1000); assert_eq!(recv.len, 0); let mut buf = [0; 32]; let first = RangeBuf::from(b"hello", 8, false); + let firstinfo = RecvBufInfo::from(8, 5, false); let second = RangeBuf::from(b"something", 0, false); + let secondinfo = RecvBufInfo::from(0, 9, false); let third = RangeBuf::from(b"moar", 11, true); - - assert!(recv.write(first).is_ok()); + let thirdinfo = RecvBufInfo::from(11, 4, true); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(first).is_ok()); + assert_eq!(recv.data.len(), 1); + } else { + assert!(recv.write_v3(firstinfo).is_ok()); + assert_eq!(recv.heap.len(), 1); + } assert_eq!(recv.len, 13); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 1); - assert!(recv.write(second).is_ok()); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(second).is_ok()); + assert_eq!(recv.data.len(), 2); + } else { + assert!(recv.write_v3(secondinfo).is_ok()); + assert_eq!(recv.heap.len(), 1); + } assert_eq!(recv.len, 13); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 2); - assert!(recv.write(third).is_ok()); - assert_eq!(recv.len, 15); - assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 3); - - let (len, fin) = recv.emit(&mut buf).unwrap(); - assert_eq!(len, 15); - assert!(fin); - assert_eq!(&buf[..len], b"somethinhelloar"); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(third).is_ok()); + assert_eq!(recv.len, 15); + assert_eq!(recv.off, 0); + assert_eq!(recv.data.len(), 3); + let (len, fin) = recv.emit(&mut buf).unwrap(); + assert_eq!(len, 15); + assert_eq!(fin, true); + assert_eq!(&buf[..len], b"somethinhelloar"); + assert_eq!(recv.data.len(), 0); + } else { + assert!(recv.write_v3(thirdinfo).is_ok()); + assert_eq!(recv.len, 15); + assert_eq!(recv.off, 0); + assert_eq!(recv.heap.len(), 2); + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 15); + assert!(app_buf.has_consumed(None, 15).is_ok()); + assert!(recv.is_fin()); + } assert_eq!(recv.len, 15); assert_eq!(recv.off, 15); - assert_eq!(recv.data.len(), 0); - assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + } else { + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 0); + } } #[test] fn partially_multi_overlapping_reordered_read2() { - let mut recv = RecvBuf::new(u64::MAX, DEFAULT_STREAM_WINDOW); + let mut recv = RecvBuf::new( + u64::MAX, + DEFAULT_STREAM_WINDOW, + crate::PROTOCOL_VERSION, + ); + let mut app_buf = AppRecvBuf::new(1, Some(42), 100, 1000); assert_eq!(recv.len, 0); let mut buf = [0; 32]; let first = RangeBuf::from(b"aaa", 0, false); + let firstinfo = RecvBufInfo::from(0, 3, false); let second = RangeBuf::from(b"bbb", 2, false); + let secondinfo = RecvBufInfo::from(2, 3, false); let third = RangeBuf::from(b"ccc", 4, false); + let thirdinfo = RecvBufInfo::from(4, 3, false); let fourth = RangeBuf::from(b"ddd", 6, false); + let fourthinfo = RecvBufInfo::from(6, 3, false); let fifth = RangeBuf::from(b"eee", 9, false); + let fifthinfo = RecvBufInfo::from(9, 3, false); let sixth = RangeBuf::from(b"fff", 11, false); - - assert!(recv.write(second).is_ok()); + let sixthinfo = RecvBufInfo::from(11, 3, false); + + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(second).is_ok()); + assert_eq!(recv.data.len(), 1); + } else { + assert!(recv.write_v3(secondinfo).is_ok()); + assert_eq!(recv.heap.len(), 1); + } assert_eq!(recv.len, 5); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 1); - assert!(recv.write(fourth).is_ok()); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(fourth).is_ok()); + assert_eq!(recv.data.len(), 2); + } else { + assert!(recv.write_v3(fourthinfo).is_ok()); + assert_eq!(recv.heap.len(), 2); + } assert_eq!(recv.len, 9); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 2); - assert!(recv.write(third).is_ok()); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(third).is_ok()); + assert_eq!(recv.data.len(), 3); + } else { + assert!(recv.write_v3(thirdinfo).is_ok()); + assert_eq!(recv.heap.len(), 3); + } assert_eq!(recv.len, 9); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 3); - assert!(recv.write(first).is_ok()); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(first).is_ok()); + assert_eq!(recv.data.len(), 4); + } else { + assert!(recv.write_v3(firstinfo).is_ok()); + assert_eq!(recv.heap.len(), 3); + } assert_eq!(recv.len, 9); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 4); - - assert!(recv.write(sixth).is_ok()); - assert_eq!(recv.len, 14); - assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 5); - assert!(recv.write(fifth).is_ok()); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(sixth).is_ok()); + assert_eq!(recv.data.len(), 5); + } else { + assert!(recv.write_v3(sixthinfo).is_ok()); + assert_eq!(recv.heap.len(), 4); + } assert_eq!(recv.len, 14); assert_eq!(recv.off, 0); - assert_eq!(recv.data.len(), 6); - let (len, fin) = recv.emit(&mut buf).unwrap(); - assert_eq!(len, 14); - assert!(!fin); - assert_eq!(&buf[..len], b"aabbbcdddeefff"); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert!(recv.write(fifth).is_ok()); + assert_eq!(recv.len, 14); + assert_eq!(recv.off, 0); + assert_eq!(recv.data.len(), 6); + let (len, fin) = recv.emit(&mut buf).unwrap(); + assert_eq!(len, 14); + assert_eq!(fin, false); + assert_eq!(&buf[..len], b"aabbbcdddeefff"); + assert_eq!(recv.data.len(), 0); + } else { + assert!(recv.write_v3(fifthinfo).is_ok()); + assert_eq!(recv.len, 14); + assert_eq!(recv.off, 0); + assert_eq!(recv.heap.len(), 5); + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 14); + assert!(app_buf.has_consumed(None, 14).is_ok()); + assert!(!recv.is_fin()); + assert_eq!(recv.heap.len(), 0); + } assert_eq!(recv.len, 14); assert_eq!(recv.off, 14); - assert_eq!(recv.data.len(), 0); - - assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + if crate::PROTOCOL_VERSION == crate::PROTOCOL_VERSION_V1 { + assert_eq!(recv.emit(&mut buf), Err(Error::Done)); + } else { + assert_eq!(app_buf.read_mut(&mut recv).unwrap().len(), 0); + } } }