Merge tag '0.1.0' into master
quiche 0.1.0
Change-Id: I25c9bd0cf0339b2d31d3570a8ad002c691b3b915
diff --git a/.travis.yml b/.travis.yml
index 2dbe3ba..5865e9e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,6 +7,7 @@
packages:
- golang-go
- libev-dev
+ - protobuf-compiler
- uthash-dev
matrix:
@@ -20,21 +21,43 @@
- cargo clippy --examples -- -D warnings
- cargo doc --no-deps
- make -C examples
+ # http3_test
+ - RUSTFLAGS="-D warnings" cargo test --no-run --verbose --manifest-path tools/http3_test/Cargo.toml
+ - cargo clippy --manifest-path tools/http3_test/Cargo.toml -- -D warnings
+ # quic-trace-log
+ - RUSTFLAGS="-D warnings" cargo build --release --verbose --manifest-path tools/quic-trace-log/Cargo.toml
+ - cargo clippy --manifest-path tools/quic-trace-log/Cargo.toml -- -D warnings
- rust: beta
script:
- RUSTFLAGS="-D warnings" cargo build --release --verbose
- RUSTFLAGS="-D warnings" cargo test --verbose
- cargo doc --no-deps
- make -C examples
+ # http3_test
+ - RUSTFLAGS="-D warnings" cargo test --no-run --verbose --manifest-path tools/http3_test/Cargo.toml
+ # quic-trace-log
+ - RUSTFLAGS="-D warnings" cargo build --release --verbose --manifest-path tools/quic-trace-log/Cargo.toml
- rust: nightly
install:
- rustup component add rustfmt
+ - cargo install cargo-fuzz
script:
- RUSTFLAGS="-D warnings" cargo build --release --verbose
- RUSTFLAGS="-D warnings" cargo test --verbose
- cargo fmt -- --check
- cargo doc --no-deps
- make -C examples
+ # fuzzers
+ - RUSTFLAGS="-D warnings" cargo fuzz run packet_recv_client -- -runs=1
+ - RUSTFLAGS="-D warnings" cargo fuzz run packet_recv_server -- -runs=1
+ - RUSTFLAGS="-D warnings" cargo fuzz run qpack_decode -- -runs=1
+ - cargo fmt --manifest-path fuzz/Cargo.toml -- --check
+ # http3_test
+ - RUSTFLAGS="-D warnings" cargo test --no-run --verbose --manifest-path tools/http3_test/Cargo.toml
+ - cargo fmt --manifest-path tools/http3_test/Cargo.toml -- --check
+ # quic-trace-log
+ - RUSTFLAGS="-D warnings" cargo build --release --verbose --manifest-path tools/quic-trace-log/Cargo.toml
+ - cargo fmt --manifest-path tools/quic-trace-log/Cargo.toml -- --check
deploy:
provider: pages
diff --git a/Cargo.toml b/Cargo.toml
index 5eaef43..82fb76b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "quiche"
-version = "0.1.0-alpha4"
+version = "0.1.0"
authors = ["Alessandro Ghedini <alessandro@ghedini.me>"]
edition = "2018"
build = "src/build.rs"
@@ -15,34 +15,43 @@
"deps/boringssl/crypto/**/*_tests.txt",
"deps/boringssl/**/nist_cavp/*.txt",
"deps/boringssl/fuzz/*",
+ "deps/boringssl/go.mod",
"deps/boringssl/ssl/test/runner/*",
"deps/boringssl/third_party/wycheproof_testvectors/*",
+ "fuzz/*",
+ "tools/*",
]
[features]
-no_bssl = []
+default = ["boringssl-vendored"]
+
+# Build vendored BoringSSL library.
+boringssl-vendored = []
+
+# Generate pkg-config metadata file for libquiche.
+pkg-config-meta = []
[package.metadata.docs.rs]
-features = ["no_bssl"]
+default-features = false
[build-dependencies]
-cmake = "0"
+cmake = "0.1"
[dependencies]
-log = "0"
-libc = "0"
-ring = "0.14"
+log = { version = "0.4", features = ["std"] }
+libc = "0.2"
+ring = "0.16"
lazy_static = "1"
[target."cfg(windows)".dependencies]
-winapi = {version = "0", features = ["wincrypt"] }
+winapi = { version = "0.3", features = ["wincrypt"] }
[dev-dependencies]
-mio = "0"
+mio = "0.6"
url = "1"
docopt = "1"
-criterion = "0"
-env_logger = "0"
+criterion = "0.3"
+env_logger = "0.6"
[profile.bench]
debug = true
diff --git a/README.md b/README.md
index 3579d92..d660829 100644
--- a/README.md
+++ b/README.md
@@ -158,9 +158,7 @@
```rust
if conn.is_established() {
// Iterate over readable streams.
- let streams: Vec<u64> = conn.readable().collect();
-
- for stream_id in streams {
+ for stream_id in conn.readable() {
// Stream is readable, read until there's no more data.
while let Ok((read, fin)) = conn.stream_recv(stream_id, &mut buf) {
println!("Got {} bytes on stream {}", read, stream_id);
@@ -208,7 +206,7 @@
Building
--------
-quiche requires Rust 1.35 or later to build. The latest stable Rust release can
+quiche requires Rust 1.38 or later to build. The latest stable Rust release can
be installed using [rustup](https://rustup.rs/).
Once the Rust build environment is setup, the quiche source code can be fetched
diff --git a/benches/benches.rs b/benches/benches.rs
index b9c21d8..039affe 100755
--- a/benches/benches.rs
+++ b/benches/benches.rs
@@ -93,7 +93,7 @@
let mut config = make_bench_config();
- let mut h3_config = quiche::h3::Config::new(0, 1024, 0, 0).unwrap();
+ let h3_config = quiche::h3::Config::new().unwrap();
let mut s =
quiche::h3::testing::Session::with_configs(&mut config, &mut h3_config)
diff --git a/clippy.toml b/clippy.toml
index 9543cc2..d2939b9 100644
--- a/clippy.toml
+++ b/clippy.toml
@@ -1 +1 @@
-cognitive-complexity-threshold = 55
+cognitive-complexity-threshold = 70
diff --git a/examples/Makefile b/examples/Makefile
index 18fdf8d..bb75e7d 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -17,7 +17,7 @@
LDFLAGS = -L$(LIBCRYPTO_DIR) -L$(LIBSSL_DIR) -L$(LIB_DIR)
-LIBS = -l:libquiche.a -lev -ldl -pthread
+LIBS = $(LIB_DIR)/libquiche.a -lev -ldl -pthread
all: client server http3-client http3-server
@@ -33,7 +33,7 @@
http3-server: http3-server.c $(INCLUDE_DIR)/quiche.h $(LIB_DIR)/libquiche.a
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(INCS) $(LIBS)
-$(LIB_DIR)/libquiche.a: $(SOURCE_DIR)/**/*.rs
+$(LIB_DIR)/libquiche.a: $(shell find $(SOURCE_DIR) -type f -name '*.rs')
cd .. && cargo build --target-dir $(BUILD_DIR)
clean:
diff --git a/examples/client.c b/examples/client.c
index b8eef1b..2f24cc1 100644
--- a/examples/client.c
+++ b/examples/client.c
@@ -71,7 +71,7 @@
}
if (written < 0) {
- fprintf(stderr, "failed to create packet: %ld\n", written);
+ fprintf(stderr, "failed to create packet: %zd\n", written);
return;
}
@@ -81,7 +81,7 @@
return;
}
- fprintf(stderr, "sent %lu bytes\n", sent);
+ fprintf(stderr, "sent %zd bytes\n", sent);
}
double t = quiche_conn_timeout_as_nanos(conn_io->conn) / 1e9f;
@@ -121,7 +121,7 @@
return;
}
- fprintf(stderr, "recv %lu bytes\n", done);
+ fprintf(stderr, "recv %zd bytes\n", done);
}
if (quiche_conn_is_closed(conn_io->conn)) {
@@ -132,7 +132,7 @@
}
if (quiche_conn_is_established(conn_io->conn) && !req_sent) {
- uint8_t *app_proto;
+ const uint8_t *app_proto;
size_t app_proto_len;
quiche_conn_application_proto(conn_io->conn, &app_proto, &app_proto_len);
@@ -154,7 +154,9 @@
if (quiche_conn_is_established(conn_io->conn)) {
uint64_t s = 0;
- while (quiche_readable_next(conn_io->conn, &s)) {
+ quiche_stream_iter *readable = quiche_conn_readable(conn_io->conn);
+
+ while (quiche_stream_iter_next(readable, &s)) {
fprintf(stderr, "stream %" PRIu64 " is readable\n", s);
bool fin = false;
@@ -173,6 +175,8 @@
}
}
}
+
+ quiche_stream_iter_free(readable);
}
flush_egress(loop, conn_io);
@@ -191,7 +195,7 @@
quiche_conn_stats(conn_io->conn, &stats);
- fprintf(stderr, "connection closed, recv=%" PRIu64 " sent=%" PRIu64 " lost=%" PRIu64 " rtt=%" PRIu64 "ns\n",
+ fprintf(stderr, "connection closed, recv=%zu sent=%zu lost=%zu rtt=%" PRIu64 "ns\n",
stats.recv, stats.sent, stats.lost, stats.rtt);
ev_break(EV_A_ EVBREAK_ONE);
@@ -240,17 +244,20 @@
}
quiche_config_set_application_protos(config,
- (uint8_t *) "\x05hq-20\x08http/0.9", 15);
+ (uint8_t *) "\x05hq-23\x08http/0.9", 15);
quiche_config_set_idle_timeout(config, 5000);
quiche_config_set_max_packet_size(config, MAX_DATAGRAM_SIZE);
- quiche_config_set_max_packet_size(config, 1460);
quiche_config_set_initial_max_data(config, 10000000);
quiche_config_set_initial_max_stream_data_bidi_local(config, 1000000);
quiche_config_set_initial_max_stream_data_uni(config, 1000000);
quiche_config_set_initial_max_streams_bidi(config, 100);
quiche_config_set_initial_max_streams_uni(config, 100);
- quiche_config_set_disable_migration(config, true);
+ quiche_config_set_disable_active_migration(config, true);
+
+ if (getenv("SSLKEYLOGFILE")) {
+ quiche_config_log_keys(config);
+ }
uint8_t scid[LOCAL_CONN_ID_LEN];
int rng = open("/dev/urandom", O_RDONLY);
diff --git a/examples/client.rs b/examples/client.rs
index 50750e4..559f3be 100644
--- a/examples/client.rs
+++ b/examples/client.rs
@@ -77,7 +77,6 @@
// Resolve server address.
let peer_addr = url.to_socket_addrs().unwrap().next().unwrap();
- info!("connecting to {:}", peer_addr);
// Bind to INADDR_ANY or IN6ADDR_ANY depending on the IP family of the
// server address. This is needed on macOS and BSD variants that don't
@@ -107,7 +106,7 @@
config.verify_peer(true);
config
- .set_application_protos(b"\x05hq-20\x08http/0.9")
+ .set_application_protos(b"\x05hq-23\x08http/0.9")
.unwrap();
config.set_idle_timeout(5000);
@@ -117,7 +116,7 @@
config.set_initial_max_stream_data_bidi_remote(max_stream_data);
config.set_initial_max_streams_bidi(100);
config.set_initial_max_streams_uni(100);
- config.set_disable_migration(true);
+ config.set_disable_active_migration(true);
if args.get_bool("--no-verify") {
config.verify_peer(false);
@@ -134,11 +133,14 @@
// Create a QUIC connection and initiate handshake.
let mut conn = quiche::connect(url.domain(), &scid, &mut config).unwrap();
- let write = match conn.send(&mut out) {
- Ok(v) => v,
+ info!(
+ "connecting to {:} from {:} with scid {}",
+ peer_addr,
+ socket.local_addr().unwrap(),
+ hex_dump(&scid)
+ );
- Err(e) => panic!("initial send failed: {:?}", e),
- };
+ let write = conn.send(&mut out).expect("initial send failed");
while let Err(e) = socket.send(&out[..write]) {
if e.kind() == std::io::ErrorKind::WouldBlock {
@@ -168,7 +170,6 @@
debug!("timed out");
conn.on_timeout();
-
break 'read;
}
@@ -224,8 +225,7 @@
}
// Process all readable streams.
- let streams: Vec<u64> = conn.readable().collect();
- for s in streams {
+ for s in conn.readable() {
while let Ok((read, fin)) = conn.stream_recv(s, &mut buf) {
debug!("received {} bytes", read);
@@ -268,6 +268,7 @@
Err(e) => {
error!("send failed: {:?}", e);
+
conn.close(false, 0x1, b"fail").ok();
break;
},
@@ -291,3 +292,9 @@
}
}
}
+
+fn hex_dump(buf: &[u8]) -> String {
+ let vec: Vec<String> = buf.iter().map(|b| format!("{:02x}", b)).collect();
+
+ vec.join("")
+}
diff --git a/examples/http3-client.c b/examples/http3-client.c
index d465e5f..1d65d82 100644
--- a/examples/http3-client.c
+++ b/examples/http3-client.c
@@ -49,6 +49,8 @@
struct conn_io {
ev_timer timer;
+ const char *host;
+
int sock;
quiche_conn *conn;
@@ -72,7 +74,7 @@
}
if (written < 0) {
- fprintf(stderr, "failed to create packet: %ld\n", written);
+ fprintf(stderr, "failed to create packet: %zd\n", written);
return;
}
@@ -82,7 +84,7 @@
return;
}
- fprintf(stderr, "sent %lu bytes\n", sent);
+ fprintf(stderr, "sent %zd bytes\n", sent);
}
double t = quiche_conn_timeout_as_nanos(conn_io->conn) / 1e9f;
@@ -127,11 +129,11 @@
}
if (done < 0) {
- fprintf(stderr, "failed to process packet: %ld\n", done);
+ fprintf(stderr, "failed to process packet: %zd\n", done);
return;
}
- fprintf(stderr, "recv %lu bytes\n", done);
+ fprintf(stderr, "recv %zd bytes\n", done);
}
if (quiche_conn_is_closed(conn_io->conn)) {
@@ -142,7 +144,7 @@
}
if (quiche_conn_is_established(conn_io->conn) && !req_sent) {
- uint8_t *app_proto;
+ const uint8_t *app_proto;
size_t app_proto_len;
quiche_conn_application_proto(conn_io->conn, &app_proto, &app_proto_len);
@@ -150,7 +152,7 @@
fprintf(stderr, "connection established: %.*s\n",
(int) app_proto_len, app_proto);
- quiche_h3_config *config = quiche_h3_config_new(0, 1024, 0, 0);
+ quiche_h3_config *config = quiche_h3_config_new();
if (config == NULL) {
fprintf(stderr, "failed to create HTTP/3 config\n");
return;
@@ -185,8 +187,8 @@
.name = (const uint8_t *) ":authority",
.name_len = sizeof(":authority") - 1,
- .value = (const uint8_t *) "quich.tech",
- .value_len = sizeof("quich.tech") - 1,
+ .value = (const uint8_t *) conn_io->host,
+ .value_len = strlen(conn_io->host),
},
{
@@ -278,7 +280,7 @@
quiche_conn_stats(conn_io->conn, &stats);
- fprintf(stderr, "connection closed, recv=%" PRIu64 " sent=%" PRIu64 " lost=%" PRIu64 " rtt=%" PRIu64 "ns\n",
+ fprintf(stderr, "connection closed, recv=%zu sent=%zu lost=%zu rtt=%" PRIu64 "ns\n",
stats.recv, stats.sent, stats.lost, stats.rtt);
ev_break(EV_A_ EVBREAK_ONE);
@@ -338,7 +340,11 @@
quiche_config_set_initial_max_stream_data_uni(config, 1000000);
quiche_config_set_initial_max_streams_bidi(config, 100);
quiche_config_set_initial_max_streams_uni(config, 100);
- quiche_config_set_disable_migration(config, true);
+ quiche_config_set_disable_active_migration(config, true);
+
+ if (getenv("SSLKEYLOGFILE")) {
+ quiche_config_log_keys(config);
+ }
// ABC: old config creation here
@@ -370,6 +376,7 @@
conn_io->sock = sock;
conn_io->conn = conn;
+ conn_io->host = host;
ev_io watcher;
diff --git a/examples/http3-client.rs b/examples/http3-client.rs
index 2a39766..5e4366c 100644
--- a/examples/http3-client.rs
+++ b/examples/http3-client.rs
@@ -87,7 +87,6 @@
// Resolve server address.
let peer_addr = url.to_socket_addrs().unwrap().next().unwrap();
- info!("connecting to {:}", peer_addr);
// Bind to INADDR_ANY or IN6ADDR_ANY depending on the IP family of the
// server address. This is needed on macOS and BSD variants that don't
@@ -128,7 +127,7 @@
config.set_initial_max_stream_data_uni(max_stream_data);
config.set_initial_max_streams_bidi(100);
config.set_initial_max_streams_uni(100);
- config.set_disable_migration(true);
+ config.set_disable_active_migration(true);
let mut http3_conn = None;
@@ -151,11 +150,14 @@
// Create a QUIC connection and initiate handshake.
let mut conn = quiche::connect(url.domain(), &scid, &mut config).unwrap();
- let write = match conn.send(&mut out) {
- Ok(v) => v,
+ info!(
+ "connecting to {:} from {:} with scid {}",
+ peer_addr,
+ socket.local_addr().unwrap(),
+ hex_dump(&scid)
+ );
- Err(e) => panic!("initial send failed: {:?}", e),
- };
+ let write = conn.send(&mut out).expect("initial send failed");
while let Err(e) = socket.send(&out[..write]) {
if e.kind() == std::io::ErrorKind::WouldBlock {
@@ -224,13 +226,19 @@
if conn.is_closed() {
info!("connection closed, {:?}", conn.stats());
+
+ if reqs_complete != reqs_count {
+ error!("connection timed out after {:?} and only completed {}/{} requests",
+ req_start.elapsed(), reqs_complete, reqs_count);
+ }
+
break;
}
// Create a new HTTP/3 connection and end an HTTP request as soon as
// the QUIC connection is established.
if conn.is_established() && http3_conn.is_none() {
- let h3_config = quiche::h3::Config::new(0, 1024, 0, 0).unwrap();
+ let h3_config = quiche::h3::Config::new().unwrap();
let mut h3_conn =
quiche::h3::Connection::with_transport(&mut conn, &h3_config)
@@ -282,7 +290,7 @@
let s =
match h3_conn.send_request(&mut conn, &req, body.is_none()) {
- Ok(stream_id) => stream_id,
+ Ok(v) => v,
Err(e) => {
error!("failed to send request {:?}", e);
@@ -380,6 +388,7 @@
Err(e) => {
error!("send failed: {:?}", e);
+
conn.close(false, 0x1, b"fail").ok();
break;
},
@@ -399,7 +408,19 @@
if conn.is_closed() {
info!("connection closed, {:?}", conn.stats());
+
+ if reqs_complete != reqs_count {
+ error!("connection timed out after {:?} and only completed {}/{} requests",
+ req_start.elapsed(), reqs_complete, reqs_count);
+ }
+
break;
}
}
}
+
+fn hex_dump(buf: &[u8]) -> String {
+ let vec: Vec<String> = buf.iter().map(|b| format!("{:02x}", b)).collect();
+
+ vec.join("")
+}
diff --git a/examples/http3-server.c b/examples/http3-server.c
index f32b44b..4bb7a39 100644
--- a/examples/http3-server.c
+++ b/examples/http3-server.c
@@ -98,7 +98,7 @@
}
if (written < 0) {
- fprintf(stderr, "failed to create packet: %ld\n", written);
+ fprintf(stderr, "failed to create packet: %zd\n", written);
return;
}
@@ -110,7 +110,7 @@
return;
}
- fprintf(stderr, "sent %lu bytes\n", sent);
+ fprintf(stderr, "sent %zd bytes\n", sent);
}
double t = quiche_conn_timeout_as_nanos(conn_io->conn) / 1e9f;
@@ -263,7 +263,7 @@
out, sizeof(out));
if (written < 0) {
- fprintf(stderr, "failed to create vneg packet: %ld\n",
+ fprintf(stderr, "failed to create vneg packet: %zd\n",
written);
return;
}
@@ -276,7 +276,7 @@
return;
}
- fprintf(stderr, "sent %lu bytes\n", sent);
+ fprintf(stderr, "sent %zd bytes\n", sent);
return;
}
@@ -293,7 +293,7 @@
out, sizeof(out));
if (written < 0) {
- fprintf(stderr, "failed to create retry packet: %ld\n",
+ fprintf(stderr, "failed to create retry packet: %zd\n",
written);
return;
}
@@ -306,7 +306,7 @@
return;
}
- fprintf(stderr, "sent %lu bytes\n", sent);
+ fprintf(stderr, "sent %zd bytes\n", sent);
return;
}
@@ -334,11 +334,11 @@
}
if (done < 0) {
- fprintf(stderr, "failed to process packet: %ld\n", done);
+ fprintf(stderr, "failed to process packet: %zd\n", done);
return;
}
- fprintf(stderr, "recv %lu bytes\n", done);
+ fprintf(stderr, "recv %zd bytes\n", done);
if (quiche_conn_is_established(conn_io->conn)) {
quiche_h3_event *ev;
@@ -508,15 +508,14 @@
quiche_config_set_initial_max_stream_data_uni(config, 1000000);
quiche_config_set_initial_max_streams_bidi(config, 100);
quiche_config_set_initial_max_streams_uni(config, 100);
- quiche_config_set_disable_migration(config, true);
+ quiche_config_set_disable_active_migration(config, true);
- http3_config = quiche_h3_config_new(0, 1024, 0, 0);
- if (config == NULL) {
+ http3_config = quiche_h3_config_new();
+ if (http3_config == NULL) {
fprintf(stderr, "failed to create HTTP/3 config\n");
return -1;
}
-
struct connections c;
c.sock = sock;
c.h = NULL;
diff --git a/examples/http3-server.rs b/examples/http3-server.rs
index 7d6d01a..f898643 100644
--- a/examples/http3-server.rs
+++ b/examples/http3-server.rs
@@ -40,19 +40,30 @@
http3-server -h | --help
Options:
- --listen <addr> Listen on the given IP:port [default: 127.0.0.1:4433]
- --cert <file> TLS certificate path [default: examples/cert.crt]
- --key <file> TLS certificate key path [default: examples/cert.key]
- --root <dir> Root directory [default: examples/root/]
- --name <str> Name of the server [default: quic.tech]
- --no-retry Disable stateless retry.
- --no-grease Don't send GREASE.
- -h --help Show this screen.
+ --listen <addr> Listen on the given IP:port [default: 127.0.0.1:4433]
+ --cert <file> TLS certificate path [default: examples/cert.crt]
+ --key <file> TLS certificate key path [default: examples/cert.key]
+ --root <dir> Root directory [default: examples/root/]
+ --name <str> Name of the server [default: quic.tech]
+ --max-data BYTES Connection-wide flow control limit [default: 10000000].
+ --max-stream-data BYTES Per-stream flow control limit [default: 1000000].
+ --no-retry Disable stateless retry.
+ --no-grease Don't send GREASE.
+ -h --help Show this screen.
";
+struct PartialResponse {
+ body: Vec<u8>,
+
+ written: usize,
+}
+
struct Client {
conn: Box<quiche::Connection>,
+
http3_conn: Option<quiche::h3::Connection>,
+
+ partial_responses: HashMap<u64, PartialResponse>,
}
type ClientMap = HashMap<Vec<u8>, (net::SocketAddr, Client)>;
@@ -69,6 +80,12 @@
.and_then(|dopt| dopt.parse())
.unwrap_or_else(|e| e.exit());
+ let max_data = args.get_str("--max-data");
+ let max_data = u64::from_str_radix(max_data, 10).unwrap();
+
+ let max_stream_data = args.get_str("--max-stream-data");
+ let max_stream_data = u64::from_str_radix(max_stream_data, 10).unwrap();
+
// Setup the event loop.
let poll = mio::Poll::new().unwrap();
let mut events = mio::Events::with_capacity(1024);
@@ -101,13 +118,13 @@
config.set_idle_timeout(5000);
config.set_max_packet_size(MAX_DATAGRAM_SIZE as u64);
- config.set_initial_max_data(10_000_000);
- config.set_initial_max_stream_data_bidi_local(1_000_000);
- config.set_initial_max_stream_data_bidi_remote(1_000_000);
- config.set_initial_max_stream_data_uni(1_000_000);
+ config.set_initial_max_data(max_data);
+ config.set_initial_max_stream_data_bidi_local(max_stream_data);
+ config.set_initial_max_stream_data_bidi_remote(max_stream_data);
+ config.set_initial_max_stream_data_uni(max_stream_data);
config.set_initial_max_streams_bidi(100);
config.set_initial_max_streams_uni(5);
- config.set_disable_migration(true);
+ config.set_disable_active_migration(true);
if std::env::var_os("SSLKEYLOGFILE").is_some() {
config.log_keys();
@@ -117,7 +134,7 @@
config.grease(false);
}
- let h3_config = quiche::h3::Config::new(16, 1024, 0, 0).unwrap();
+ let h3_config = quiche::h3::Config::new().unwrap();
let mut clients = ClientMap::new();
@@ -253,6 +270,11 @@
continue;
}
+ if scid.len() != hdr.dcid.len() {
+ error!("Invalid destination connection ID");
+ continue;
+ }
+
// Reuse the source connection ID we sent in the Retry
// packet, instead of changing it again.
scid.copy_from_slice(&hdr.dcid);
@@ -269,6 +291,7 @@
let client = Client {
conn,
http3_conn: None,
+ partial_responses: HashMap::new(),
};
clients.insert(scid.to_vec(), (src, client));
@@ -319,14 +342,20 @@
client.http3_conn = Some(h3_conn);
}
- if let Some(http3_conn) = &mut client.http3_conn {
+ if client.http3_conn.is_some() {
+ // Handle writable streams.
+ for stream_id in client.conn.writable() {
+ handle_writable(client, stream_id);
+ }
+
// Process HTTP/3 events.
loop {
+ let http3_conn = client.http3_conn.as_mut().unwrap();
+
match http3_conn.poll(client.conn.as_mut()) {
Ok((stream_id, quiche::h3::Event::Headers(headers))) => {
handle_request(
- &mut client.conn,
- http3_conn,
+ client,
stream_id,
&headers,
args.get_str("--root"),
@@ -376,6 +405,7 @@
Err(e) => {
error!("{} send failed: {:?}", client.conn.trace_id(), e);
+
client.conn.close(false, 0x1, b"fail").ok();
break;
},
@@ -472,9 +502,12 @@
/// Handles incoming HTTP/3 requests.
fn handle_request(
- conn: &mut quiche::Connection, http3_conn: &mut quiche::h3::Connection,
- stream_id: u64, headers: &[quiche::h3::Header], root: &str,
+ client: &mut Client, stream_id: u64, headers: &[quiche::h3::Header],
+ root: &str,
) {
+ let conn = &mut client.conn;
+ let http3_conn = &mut client.http3_conn.as_mut().unwrap();
+
info!(
"{} got request {:?} on stream id {}",
conn.trace_id(),
@@ -482,31 +515,42 @@
stream_id
);
- match build_response(root, headers) {
- Ok((headers, body)) => {
- if let Err(e) =
- http3_conn.send_response(conn, stream_id, &headers, false)
- {
- error!("{} stream send failed {:?}", conn.trace_id(), e);
- }
+ // We decide the response based on headers alone, so stop reading the
+ // request stream so that any body is ignored and pointless Data events
+ // are not generated.
+ conn.stream_shutdown(stream_id, quiche::Shutdown::Read, 0)
+ .unwrap();
- if let Err(e) = http3_conn.send_body(conn, stream_id, &body, true) {
- error!("{} stream send failed {:?}", conn.trace_id(), e);
- }
- },
+ let (headers, body) = build_response(root, headers);
+
+ if let Err(e) = http3_conn.send_response(conn, stream_id, &headers, false) {
+ error!("{} stream send failed {:?}", conn.trace_id(), e);
+ }
+
+ let written = match http3_conn.send_body(conn, stream_id, &body, true) {
+ Ok(v) => v,
+
+ Err(quiche::h3::Error::Done) => 0,
Err(e) => {
- error!("{} failed to build response {:?}", conn.trace_id(), e);
+ error!("{} stream send failed {:?}", conn.trace_id(), e);
+ return;
},
+ };
+
+ if written < body.len() {
+ let response = PartialResponse { body, written };
+ client.partial_responses.insert(stream_id, response);
}
}
/// Builds an HTTP/3 response given a request.
fn build_response(
root: &str, request: &[quiche::h3::Header],
-) -> Result<(std::vec::Vec<quiche::h3::Header>, std::vec::Vec<u8>), ()> {
+) -> (Vec<quiche::h3::Header>, Vec<u8>) {
let mut file_path = std::path::PathBuf::from(root);
let mut path = std::path::Path::new("");
+ let mut method = "";
// Look for the request's path and method.
for hdr in request {
@@ -515,35 +559,71 @@
path = std::path::Path::new(hdr.value());
},
- ":method" =>
- if hdr.value() != "GET" {
- return Err(());
- },
+ ":method" => {
+ method = hdr.value();
+ },
_ => (),
}
}
- for c in path.components() {
- if let std::path::Component::Normal(v) = c {
- file_path.push(v)
- }
- }
+ let (status, body) = match method {
+ "GET" => {
+ for c in path.components() {
+ if let std::path::Component::Normal(v) = c {
+ file_path.push(v)
+ }
+ }
- let (status, body) = match std::fs::read(file_path.as_path()) {
- Ok(data) => (200, data),
+ match std::fs::read(file_path.as_path()) {
+ Ok(data) => (200, data),
- Err(_) => (404, b"Not Found!".to_vec()),
+ Err(_) => (404, b"Not Found!".to_vec()),
+ }
+ },
+
+ _ => (405, Vec::new()),
};
- Ok((
- vec![
- quiche::h3::Header::new(":status", &status.to_string()),
- quiche::h3::Header::new("server", "quiche"),
- quiche::h3::Header::new("content-length", &body.len().to_string()),
- ],
- body,
- ))
+ let headers = vec![
+ quiche::h3::Header::new(":status", &status.to_string()),
+ quiche::h3::Header::new("server", "quiche"),
+ quiche::h3::Header::new("content-length", &body.len().to_string()),
+ ];
+
+ (headers, body)
+}
+
+/// Handles newly writable streams.
+fn handle_writable(client: &mut Client, stream_id: u64) {
+ let conn = &mut client.conn;
+ let http3_conn = &mut client.http3_conn.as_mut().unwrap();
+
+ debug!("{} stream {} is writable", conn.trace_id(), stream_id);
+
+ if !client.partial_responses.contains_key(&stream_id) {
+ return;
+ }
+
+ let resp = client.partial_responses.get_mut(&stream_id).unwrap();
+ let body = &resp.body[resp.written..];
+
+ let written = match http3_conn.send_body(conn, stream_id, body, true) {
+ Ok(v) => v,
+
+ Err(quiche::h3::Error::Done) => 0,
+
+ Err(e) => {
+ error!("{} stream send failed {:?}", conn.trace_id(), e);
+ return;
+ },
+ };
+
+ resp.written += written;
+
+ if resp.written == resp.body.len() {
+ client.partial_responses.remove(&stream_id);
+ }
}
fn hex_dump(buf: &[u8]) -> String {
diff --git a/examples/qpack-decode.rs b/examples/qpack-decode.rs
index c1b4e22..6a2714b 100644
--- a/examples/qpack-decode.rs
+++ b/examples/qpack-decode.rs
@@ -79,7 +79,7 @@
continue;
}
- for hdr in dec.decode(&mut data[..len]).unwrap() {
+ for hdr in dec.decode(&mut data[..len], std::u64::MAX).unwrap() {
println!("{}\t{}", hdr.name(), hdr.value());
}
diff --git a/examples/server.c b/examples/server.c
index 8174ee8..2b473df 100644
--- a/examples/server.c
+++ b/examples/server.c
@@ -96,7 +96,7 @@
}
if (written < 0) {
- fprintf(stderr, "failed to create packet: %ld\n", written);
+ fprintf(stderr, "failed to create packet: %zd\n", written);
return;
}
@@ -108,7 +108,7 @@
return;
}
- fprintf(stderr, "sent %lu bytes\n", sent);
+ fprintf(stderr, "sent %zd bytes\n", sent);
}
double t = quiche_conn_timeout_as_nanos(conn_io->conn) / 1e9f;
@@ -252,7 +252,7 @@
out, sizeof(out));
if (written < 0) {
- fprintf(stderr, "failed to create vneg packet: %ld\n",
+ fprintf(stderr, "failed to create vneg packet: %zd\n",
written);
return;
}
@@ -265,7 +265,7 @@
return;
}
- fprintf(stderr, "sent %lu bytes\n", sent);
+ fprintf(stderr, "sent %zd bytes\n", sent);
return;
}
@@ -282,7 +282,7 @@
out, sizeof(out));
if (written < 0) {
- fprintf(stderr, "failed to create retry packet: %ld\n",
+ fprintf(stderr, "failed to create retry packet: %zd\n",
written);
return;
}
@@ -295,7 +295,7 @@
return;
}
- fprintf(stderr, "sent %lu bytes\n", sent);
+ fprintf(stderr, "sent %zd bytes\n", sent);
return;
}
@@ -323,16 +323,18 @@
}
if (done < 0) {
- fprintf(stderr, "failed to process packet: %ld\n", done);
+ fprintf(stderr, "failed to process packet: %zd\n", done);
return;
}
- fprintf(stderr, "recv %lu bytes\n", done);
+ fprintf(stderr, "recv %zd bytes\n", done);
if (quiche_conn_is_established(conn_io->conn)) {
uint64_t s = 0;
- while (quiche_readable_next(conn_io->conn, &s)) {
+ quiche_stream_iter *readable = quiche_conn_readable(conn_io->conn);
+
+ while (quiche_stream_iter_next(readable, &s)) {
fprintf(stderr, "stream %" PRIu64 " is readable\n", s);
bool fin = false;
@@ -349,6 +351,8 @@
5, true);
}
}
+
+ quiche_stream_iter_free(readable);
}
}
@@ -430,7 +434,7 @@
quiche_config_load_priv_key_from_pem_file(config, "examples/cert.key");
quiche_config_set_application_protos(config,
- (uint8_t *) "\x05hq-20\x08http/0.9", 15);
+ (uint8_t *) "\x05hq-23\x08http/0.9", 15);
quiche_config_set_idle_timeout(config, 5000);
quiche_config_set_max_packet_size(config, MAX_DATAGRAM_SIZE);
diff --git a/examples/server.rs b/examples/server.rs
index f17f9e3..a9c430d 100644
--- a/examples/server.rs
+++ b/examples/server.rs
@@ -41,16 +41,30 @@
server -h | --help
Options:
- --listen <addr> Listen on the given IP:port [default: 127.0.0.1:4433]
- --cert <file> TLS certificate path [default: examples/cert.crt]
- --key <file> TLS certificate key path [default: examples/cert.key]
- --root <dir> Root directory [default: examples/root/]
- --name <str> Name of the server [default: quic.tech]
- --no-retry Disable stateless retry.
- -h --help Show this screen.
+ --listen <addr> Listen on the given IP:port [default: 127.0.0.1:4433]
+ --cert <file> TLS certificate path [default: examples/cert.crt]
+ --key <file> TLS certificate key path [default: examples/cert.key]
+ --root <dir> Root directory [default: examples/root/]
+ --name <str> Name of the server [default: quic.tech]
+ --max-data BYTES Connection-wide flow control limit [default: 10000000].
+ --max-stream-data BYTES Per-stream flow control limit [default: 1000000].
+ --no-retry Disable stateless retry.
+ -h --help Show this screen.
";
-type ConnMap = HashMap<Vec<u8>, (net::SocketAddr, Box<quiche::Connection>)>;
+struct PartialResponse {
+ body: Vec<u8>,
+
+ written: usize,
+}
+
+struct Client {
+ conn: Box<quiche::Connection>,
+
+ partial_responses: HashMap<u64, PartialResponse>,
+}
+
+type ClientMap = HashMap<Vec<u8>, (net::SocketAddr, Client)>;
fn main() {
let mut buf = [0; 65535];
@@ -64,6 +78,12 @@
.and_then(|dopt| dopt.parse())
.unwrap_or_else(|e| e.exit());
+ let max_data = args.get_str("--max-data");
+ let max_data = u64::from_str_radix(max_data, 10).unwrap();
+
+ let max_stream_data = args.get_str("--max-stream-data");
+ let max_stream_data = u64::from_str_radix(max_stream_data, 10).unwrap();
+
// Setup the event loop.
let poll = mio::Poll::new().unwrap();
let mut events = mio::Events::with_capacity(1024);
@@ -91,30 +111,31 @@
.unwrap();
config
- .set_application_protos(b"\x05hq-20\x08http/0.9")
+ .set_application_protos(b"\x05hq-23\x08http/0.9")
.unwrap();
config.set_idle_timeout(5000);
config.set_max_packet_size(MAX_DATAGRAM_SIZE as u64);
- config.set_initial_max_data(10_000_000);
- config.set_initial_max_stream_data_bidi_local(1_000_000);
- config.set_initial_max_stream_data_bidi_remote(1_000_000);
- config.set_initial_max_stream_data_uni(1_000_000);
+ config.set_initial_max_data(max_data);
+ config.set_initial_max_stream_data_bidi_local(max_stream_data);
+ config.set_initial_max_stream_data_bidi_remote(max_stream_data);
+ config.set_initial_max_stream_data_uni(max_stream_data);
config.set_initial_max_streams_bidi(100);
config.set_initial_max_streams_uni(5);
- config.set_disable_migration(true);
+ config.set_disable_active_migration(true);
if std::env::var_os("SSLKEYLOGFILE").is_some() {
config.log_keys();
}
- let mut connections = ConnMap::new();
+ let mut clients = ClientMap::new();
loop {
// Find the shorter timeout from all the active connections.
//
// TODO: use event loop that properly supports timers
- let timeout = connections.values().filter_map(|(_, c)| c.timeout()).min();
+ let timeout =
+ clients.values().filter_map(|(_, c)| c.conn.timeout()).min();
poll.poll(&mut events, timeout).unwrap();
@@ -127,7 +148,7 @@
if events.is_empty() {
debug!("timed out");
- connections.values_mut().for_each(|(_, c)| c.on_timeout());
+ clients.values_mut().for_each(|(_, c)| c.conn.on_timeout());
break 'read;
}
@@ -173,7 +194,7 @@
// Lookup a connection based on the packet's connection ID. If there
// is no connection matching, create a new one.
- let (_, conn) = if !connections.contains_key(&hdr.dcid) {
+ let (_, client) = if !clients.contains_key(&hdr.dcid) {
if hdr.ty != quiche::Type::Initial {
error!("Packet is not Initial");
continue;
@@ -242,6 +263,11 @@
continue;
}
+ if scid.len() != hdr.dcid.len() {
+ error!("Invalid destination connection ID");
+ continue;
+ }
+
// Reuse the source connection ID we sent in the Retry
// packet, instead of changing it again.
scid.copy_from_slice(&hdr.dcid);
@@ -255,49 +281,64 @@
let conn = quiche::accept(&scid, odcid, &mut config).unwrap();
- connections.insert(scid.to_vec(), (src, conn));
+ let client = Client {
+ conn,
+ partial_responses: HashMap::new(),
+ };
- connections.get_mut(&scid[..]).unwrap()
+ clients.insert(scid.to_vec(), (src, client));
+
+ clients.get_mut(&scid[..]).unwrap()
} else {
- connections.get_mut(&hdr.dcid).unwrap()
+ clients.get_mut(&hdr.dcid).unwrap()
};
// Process potentially coalesced packets.
- let read = match conn.recv(pkt_buf) {
+ let read = match client.conn.recv(pkt_buf) {
Ok(v) => v,
Err(quiche::Error::Done) => {
- debug!("{} done reading", conn.trace_id());
+ debug!("{} done reading", client.conn.trace_id());
break;
},
Err(e) => {
- error!("{} recv failed: {:?}", conn.trace_id(), e);
+ error!("{} recv failed: {:?}", client.conn.trace_id(), e);
break 'read;
},
};
- debug!("{} processed {} bytes", conn.trace_id(), read);
+ debug!("{} processed {} bytes", client.conn.trace_id(), read);
- if conn.is_established() {
+ if client.conn.is_established() {
+ // Handle writable streams.
+ for stream_id in client.conn.writable() {
+ handle_writable(client, stream_id);
+ }
+
// Process all readable streams.
- let streams: Vec<u64> = conn.readable().collect();
- for s in streams {
- while let Ok((read, fin)) = conn.stream_recv(s, &mut buf) {
- debug!("{} received {} bytes", conn.trace_id(), read);
+ 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? {})",
- conn.trace_id(),
+ client.conn.trace_id(),
s,
stream_buf.len(),
fin
);
handle_stream(
- conn,
+ client,
s,
stream_buf,
args.get_str("--root"),
@@ -310,19 +351,20 @@
// Generate outgoing QUIC packets for all active connections and send
// them on the UDP socket, until quiche reports that there are no more
// packets to be sent.
- for (peer, conn) in connections.values_mut() {
+ for (peer, client) in clients.values_mut() {
loop {
- let write = match conn.send(&mut out) {
+ let write = match client.conn.send(&mut out) {
Ok(v) => v,
Err(quiche::Error::Done) => {
- debug!("{} done writing", conn.trace_id());
+ debug!("{} done writing", client.conn.trace_id());
break;
},
Err(e) => {
- error!("{} send failed: {:?}", conn.trace_id(), e);
- conn.close(false, 0x1, b"fail").ok();
+ error!("{} send failed: {:?}", client.conn.trace_id(), e);
+
+ client.conn.close(false, 0x1, b"fail").ok();
break;
},
};
@@ -337,19 +379,23 @@
panic!("send() failed: {:?}", e);
}
- debug!("{} written {} bytes", conn.trace_id(), write);
+ debug!("{} written {} bytes", client.conn.trace_id(), write);
}
}
// Garbage collect closed connections.
- connections.retain(|_, (_, ref mut c)| {
+ clients.retain(|_, (_, ref mut c)| {
debug!("Collecting garbage");
- if c.is_closed() {
- info!("{} connection collected {:?}", c.trace_id(), c.stats());
+ if c.conn.is_closed() {
+ info!(
+ "{} connection collected {:?}",
+ c.conn.trace_id(),
+ c.conn.stats()
+ );
}
- !c.is_closed()
+ !c.conn.is_closed()
});
}
}
@@ -413,9 +459,9 @@
}
/// Handles incoming HTTP/0.9 requests.
-fn handle_stream(
- conn: &mut quiche::Connection, stream: u64, buf: &[u8], root: &str,
-) {
+fn handle_stream(client: &mut Client, stream_id: u64, buf: &[u8], root: &str) {
+ let conn = &mut client.conn;
+
if buf.len() > 4 && &buf[..4] == b"GET " {
let uri = &buf[4..buf.len()];
let uri = String::from_utf8(uri.to_vec()).unwrap();
@@ -433,25 +479,68 @@
"{} got GET request for {:?} on stream {}",
conn.trace_id(),
path,
- stream
+ stream_id
);
- let data = std::fs::read(path.as_path())
+ let body = std::fs::read(path.as_path())
.unwrap_or_else(|_| b"Not Found!\r\n".to_vec());
info!(
"{} sending response of size {} on stream {}",
conn.trace_id(),
- data.len(),
- stream
+ body.len(),
+ stream_id
);
- if let Err(e) = conn.stream_send(stream, &data, true) {
- error!("{} stream send failed {:?}", conn.trace_id(), e);
+ let written = match conn.stream_send(stream_id, &body, true) {
+ Ok(v) => v,
+
+ Err(quiche::Error::Done) => 0,
+
+ Err(e) => {
+ error!("{} stream send failed {:?}", conn.trace_id(), e);
+ return;
+ },
+ };
+
+ if written < body.len() {
+ let response = PartialResponse { body, written };
+ client.partial_responses.insert(stream_id, response);
}
}
}
+/// Handles newly writable streams.
+fn handle_writable(client: &mut Client, stream_id: u64) {
+ let conn = &mut client.conn;
+
+ debug!("{} stream {} is writable", conn.trace_id(), stream_id);
+
+ if !client.partial_responses.contains_key(&stream_id) {
+ return;
+ }
+
+ let resp = client.partial_responses.get_mut(&stream_id).unwrap();
+ let body = &resp.body[resp.written..];
+
+ let written = match conn.stream_send(stream_id, &body, true) {
+ Ok(v) => v,
+
+ Err(quiche::Error::Done) => 0,
+
+ Err(e) => {
+ error!("{} stream send failed {:?}", conn.trace_id(), e);
+ return;
+ },
+ };
+
+ resp.written += written;
+
+ if resp.written == resp.body.len() {
+ client.partial_responses.remove(&stream_id);
+ }
+}
+
fn hex_dump(buf: &[u8]) -> String {
let vec: Vec<String> = buf.iter().map(|b| format!("{:02x}", b)).collect();
diff --git a/fuzz/.gitignore b/fuzz/.gitignore
new file mode 100644
index 0000000..35ae8a0
--- /dev/null
+++ b/fuzz/.gitignore
@@ -0,0 +1,2 @@
+target
+artifacts
diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
new file mode 100644
index 0000000..5a3b71e
--- /dev/null
+++ b/fuzz/Cargo.toml
@@ -0,0 +1,30 @@
+[package]
+name = "quiche-fuzz"
+version = "0.1.0"
+authors = ["Alessandro Ghedini <alessandro@ghedini.me>"]
+edition = "2018"
+publish = false
+
+[package.metadata]
+cargo-fuzz = true
+
+[dependencies]
+quiche = { path = ".." }
+lazy_static = "1"
+libfuzzer-sys = { git = "https://github.com/rust-fuzz/libfuzzer-sys.git" }
+
+# Prevent this from interfering with workspaces
+[workspace]
+members = ["."]
+
+[[bin]]
+name = "packet_recv_client"
+path = "src/packet_recv_client.rs"
+
+[[bin]]
+name = "packet_recv_server"
+path = "src/packet_recv_server.rs"
+
+[[bin]]
+name = "qpack_decode"
+path = "src/qpack_decode.rs"
diff --git a/fuzz/Dockerfile b/fuzz/Dockerfile
new file mode 100644
index 0000000..193fef1
--- /dev/null
+++ b/fuzz/Dockerfile
@@ -0,0 +1,11 @@
+FROM debian:bullseye
+LABEL maintainer="alessandro@cloudflare.com"
+
+WORKDIR /home/mayhem/
+
+COPY ./cert.crt ./
+COPY ./cert.key ./
+
+COPY ./target/x86_64-unknown-linux-gnu/debug/packet_recv_client ./
+COPY ./target/x86_64-unknown-linux-gnu/debug/packet_recv_server ./
+COPY ./target/x86_64-unknown-linux-gnu/debug/qpack_decode ./
diff --git a/fuzz/README.md b/fuzz/README.md
new file mode 100644
index 0000000..6852aaa
--- /dev/null
+++ b/fuzz/README.md
@@ -0,0 +1,11 @@
+This crate provides fuzzers based on [libfuzzer](https://llvm.org/docs/LibFuzzer.html).
+
+Available fuzzers:
+
+* packet\_recv\_client: Processes a single incoming packet (including frames) at
+ a time from the client side.
+
+* packet\_recv\_server: Processes a single incoming packet (including frames) at
+ a time from the server side.
+
+* qpack\_decode: Parses a single QPACK header block at a time.
diff --git a/fuzz/cert.crt b/fuzz/cert.crt
new file mode 100644
index 0000000..adfed31
--- /dev/null
+++ b/fuzz/cert.crt
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDkzCCAnugAwIBAgIUaj26Dyzr2W9R8juKm2pNyrtati0wDQYJKoZIhvcNAQEL
+BQAwWTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
+GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJcXVpYy50ZWNoMB4X
+DTE4MDkzMDIyMTE0OFoXDTE5MDkzMDIyMTE0OFowWTELMAkGA1UEBhMCQVUxEzAR
+BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5
+IEx0ZDESMBAGA1UEAwwJcXVpYy50ZWNoMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAqrS30fnkI6Q+5SKsBXkIwnhO61x/Wgt0zo5P+0yTAZDYVYtEhRlf
+mJ3esEleO1nq5MtM3d+6aVBJlwtTi8pBOzVfJklnxd07N3rKh3HZbGHybjhJFGT9
+U4sUrcKcCpSKJaEu7IQsQQs1Hh0B67MeqJG3F7OcYCF3OXC11WK3CtDDKcLcsa2x
++WImzsPfayzEjQ4ELTVDP73oQGR6D3HaWauKES4JjI9CMn8EJRCcxjwet+c4U3kQ
+g2z5KDbooBfCfrzmX3/EpMf/RaASaUtZF3kgfDT648dICWUoiparo1V73pg2vDe5
+RsAp4n1A7VCY48VvGEz9Qgcp8QFztpFJnwIDAQABo1MwUTAdBgNVHQ4EFgQUFOlS
+IeYH/41CN5BP/8w8F3e/fkYwHwYDVR0jBBgwFoAUFOlSIeYH/41CN5BP/8w8F3e/
+fkYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAZa7XK3My4Jpe
+SLz0BAj44QtghGdg98QFR3iZEnn0XC09HrkhbjaR8Ma3dn0QyMDRuPLLNl5j3VWu
+rDqngENbuJJBPGkCTzozFfMU6MZzGLK1ljIiGzkMXVEaamSj7GDJ2eR2i2cBugiM
+Yv7N/e8FbSMRBXoYVPjukoA8QwDJhS/oN47vt0+VsTi5wah9d3t0RCruAe/4TETo
+jPxjbEGTQ71dmU66xPZMrnqlGCNa4kN2alCDNfSg1yRp4j10zSmK0jHEHOuiHliW
+/Zc+aLEFcVB1QHmIyvcBIhKiuDbfbkWrqSiel6nLScIvhJaJOrGzQYBfjeZ4TO0m
+IHJUojcgZA==
+-----END CERTIFICATE-----
diff --git a/fuzz/cert.key b/fuzz/cert.key
new file mode 100644
index 0000000..0a2c39b
--- /dev/null
+++ b/fuzz/cert.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCqtLfR+eQjpD7l
+IqwFeQjCeE7rXH9aC3TOjk/7TJMBkNhVi0SFGV+Ynd6wSV47Werky0zd37ppUEmX
+C1OLykE7NV8mSWfF3Ts3esqHcdlsYfJuOEkUZP1TixStwpwKlIoloS7shCxBCzUe
+HQHrsx6okbcXs5xgIXc5cLXVYrcK0MMpwtyxrbH5YibOw99rLMSNDgQtNUM/vehA
+ZHoPcdpZq4oRLgmMj0IyfwQlEJzGPB635zhTeRCDbPkoNuigF8J+vOZff8Skx/9F
+oBJpS1kXeSB8NPrjx0gJZSiKlqujVXvemDa8N7lGwCnifUDtUJjjxW8YTP1CBynx
+AXO2kUmfAgMBAAECggEAdWR0KT1NS8luy0qtu9HBWWM8+pSQq87HFClADZRaYDBI
+5YMxqsqJOD4Q33CFEhHC/HZmtQpfen8RLINIgBCmDV6lwYGnkKWUTJHv53c+y08M
+Vgn1D8Zng+VYYio7/vapjjkrONGoUU6wx7WxFXMHuWsD25PUDTPWdrTxBv6s3A0X
+Le7UtuCdo/xNY4YS6S64SfiEPsBddj1NhoiwOHkXekpNRoAwnizjngubEkiznScu
+gwKCW4nPV8y4CoIYyncGayrKieg03llgRngFiGJKpKeyL2UkX07Fqb2tXuJ36+RA
+9DrluEkYWZCjOS+aaQu+NwxCkUV5pq+HcXQmF5VX+QKBgQDTrgF4sKwcIjm+k3Fp
+bqhMS5stuSQJVn85fCIeQLq3u5DRq9n+UOvq6GvdEXz0SiupLfkXx/pDwiOux2sn
+CcwMaPqWbFE4mSsCFCBkL/PvXSzH2zYesHOplztvcV+gexAjmoCikMBCcM00QpN1
+GScUmQGTk/7BKJYGnVchJOXbfQKBgQDOcoZryCDxUPsg2ZMwkrnpcM+fSTT1gcgf
+I3gbGohagiXVTDU4+S7I7WmsJv+lBUJCWRG0p8JJZb0NsgnrGyOfCKL59xAV5PyT
+xSXMIi2+OH+fQXblII76GqWCs7A7NxtEU2geSy4ePPzSS4G81FN2oeV1OxZ9a6fk
+6cFIzmqsSwKBgQDIBQlg6NiI8RJNcXdeH/EpvtuQNfzGUhR/1jtLCPEmgjcS2Odx
+Nzflzd92knrXP2rIPye7//wMoNsk4UzwI4LLSztWfl21NI5+NVRyNxmyWgHhi9M0
+5pk0bDH+WUv6Ea8rZWgdtNfnMD3HHw3FPZI/FWF2+QZlsRsqfuyA5iPI5QKBgQCu
+D7F2Po5H6FdUIx4O3icRw6PKURbtyDbKykUB1SUR6pmrdU2Kc84WatWl6Fuy7vQm
+rKJZBviwma8EVRA3wfIOrGF9D+noC+FJVffAXTDkKQ6xX6i3FvR1uvHBeW8k/hln
+SkuG/ywrIpCnXjJM21hjtayZYvBbXuF4B/6HPEKEcQKBgQC+DVoOVjsoyd9udTcp
+1v2xvwRVvU/OrPOLXwac1IbTgmb5FJYd8EZI0hdxJhialoTK3OONk04uxdn5tlAB
+QwKBmkXZEr9EIreMp18gbzmDGalx8UcS0j+nIZvmpZXWsIimAKDGEwFc8w+NAN5a
+X5UkSGjM6dnJocH0sLI7hXuVJw==
+-----END PRIVATE KEY-----
diff --git a/fuzz/corpus/packet_recv_client/080561a160bd0fa795238b128a11524a0a4c0816 b/fuzz/corpus/packet_recv_client/080561a160bd0fa795238b128a11524a0a4c0816
new file mode 100644
index 0000000..7efab29
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/080561a160bd0fa795238b128a11524a0a4c0816
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/0a86c5498ff3eb064758ea04d640ab1eabfa29ed b/fuzz/corpus/packet_recv_client/0a86c5498ff3eb064758ea04d640ab1eabfa29ed
new file mode 100644
index 0000000..df53bc9
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/0a86c5498ff3eb064758ea04d640ab1eabfa29ed
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/0ca4b4656f321e200226702873cb726d8d33f123 b/fuzz/corpus/packet_recv_client/0ca4b4656f321e200226702873cb726d8d33f123
new file mode 100644
index 0000000..63d8298
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/0ca4b4656f321e200226702873cb726d8d33f123
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/0e910ba9042c76b442ffbae3a74aff00aed83960 b/fuzz/corpus/packet_recv_client/0e910ba9042c76b442ffbae3a74aff00aed83960
new file mode 100644
index 0000000..b17c46a
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/0e910ba9042c76b442ffbae3a74aff00aed83960
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/1154e21f9b2c9ce472a65d1413d087df6139c9fa b/fuzz/corpus/packet_recv_client/1154e21f9b2c9ce472a65d1413d087df6139c9fa
new file mode 100644
index 0000000..f08381a
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/1154e21f9b2c9ce472a65d1413d087df6139c9fa
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/1252547c38988a6bea518b43fd2285a429cdd8e0 b/fuzz/corpus/packet_recv_client/1252547c38988a6bea518b43fd2285a429cdd8e0
new file mode 100644
index 0000000..f0f793b
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/1252547c38988a6bea518b43fd2285a429cdd8e0
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/13df9abe8be67f42cb1110788cc17f9dc1c5cf64 b/fuzz/corpus/packet_recv_client/13df9abe8be67f42cb1110788cc17f9dc1c5cf64
new file mode 100644
index 0000000..4ff9c04
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/13df9abe8be67f42cb1110788cc17f9dc1c5cf64
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/16eedfacb9f6d5288c06143f8e6c54c0066ac85f b/fuzz/corpus/packet_recv_client/16eedfacb9f6d5288c06143f8e6c54c0066ac85f
new file mode 100644
index 0000000..f8d4784
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/16eedfacb9f6d5288c06143f8e6c54c0066ac85f
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/1895dfbc061b55379cab2301de60b17f6eb83e56 b/fuzz/corpus/packet_recv_client/1895dfbc061b55379cab2301de60b17f6eb83e56
new file mode 100644
index 0000000..b987ad4
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/1895dfbc061b55379cab2301de60b17f6eb83e56
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/257af8d8a65356b09951c6bac6e9c1239d4fec94 b/fuzz/corpus/packet_recv_client/257af8d8a65356b09951c6bac6e9c1239d4fec94
new file mode 100644
index 0000000..8a42a89
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/257af8d8a65356b09951c6bac6e9c1239d4fec94
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/2b1c1ec224ffa1d8e2f56bc108de4194876a2c3d b/fuzz/corpus/packet_recv_client/2b1c1ec224ffa1d8e2f56bc108de4194876a2c3d
new file mode 100644
index 0000000..13cd179
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/2b1c1ec224ffa1d8e2f56bc108de4194876a2c3d
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/2d8a5845c09a670fd440f80c62301a120dee6dc3 b/fuzz/corpus/packet_recv_client/2d8a5845c09a670fd440f80c62301a120dee6dc3
new file mode 100644
index 0000000..80518a2
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/2d8a5845c09a670fd440f80c62301a120dee6dc3
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/2f4d2786e73c240bbca4625839730bfca71b0a5b b/fuzz/corpus/packet_recv_client/2f4d2786e73c240bbca4625839730bfca71b0a5b
new file mode 100644
index 0000000..b388161
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/2f4d2786e73c240bbca4625839730bfca71b0a5b
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/340ee3233240301922006810b756701864d93150 b/fuzz/corpus/packet_recv_client/340ee3233240301922006810b756701864d93150
new file mode 100644
index 0000000..574da90
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/340ee3233240301922006810b756701864d93150
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/407b0ccc1fc3972e19c3ea74279faa055aafa6cd b/fuzz/corpus/packet_recv_client/407b0ccc1fc3972e19c3ea74279faa055aafa6cd
new file mode 100644
index 0000000..d965c68
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/407b0ccc1fc3972e19c3ea74279faa055aafa6cd
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/41f87454dc4b348d1a7cd0b7c423418b971282e3 b/fuzz/corpus/packet_recv_client/41f87454dc4b348d1a7cd0b7c423418b971282e3
new file mode 100644
index 0000000..b530437
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/41f87454dc4b348d1a7cd0b7c423418b971282e3
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/428d56e4bdcd603e9a420d42cd9d87fd3698ef0d b/fuzz/corpus/packet_recv_client/428d56e4bdcd603e9a420d42cd9d87fd3698ef0d
new file mode 100644
index 0000000..5f28a75
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/428d56e4bdcd603e9a420d42cd9d87fd3698ef0d
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/4d6ad5cea9c02cceba576ac895ff184cdfe293e3 b/fuzz/corpus/packet_recv_client/4d6ad5cea9c02cceba576ac895ff184cdfe293e3
new file mode 100644
index 0000000..a972eb0
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/4d6ad5cea9c02cceba576ac895ff184cdfe293e3
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/52538a80094f7b62948fd31e68fd17a315d8dc91 b/fuzz/corpus/packet_recv_client/52538a80094f7b62948fd31e68fd17a315d8dc91
new file mode 100644
index 0000000..5cd813e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/52538a80094f7b62948fd31e68fd17a315d8dc91
@@ -0,0 +1 @@
+ª
\ No newline at end of file
diff --git a/fuzz/corpus/packet_recv_client/5cbb9fee5099b02333c132bdff4bec6cbe9ae585 b/fuzz/corpus/packet_recv_client/5cbb9fee5099b02333c132bdff4bec6cbe9ae585
new file mode 100644
index 0000000..2b7a7af
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/5cbb9fee5099b02333c132bdff4bec6cbe9ae585
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/63cb5dab8b69d5ea256fad0224852037a4d14e5a b/fuzz/corpus/packet_recv_client/63cb5dab8b69d5ea256fad0224852037a4d14e5a
new file mode 100644
index 0000000..bc31c12
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/63cb5dab8b69d5ea256fad0224852037a4d14e5a
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/6b76795c8b384510b63f7d729bf9ad3efeade2c0 b/fuzz/corpus/packet_recv_client/6b76795c8b384510b63f7d729bf9ad3efeade2c0
new file mode 100644
index 0000000..47fa168
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/6b76795c8b384510b63f7d729bf9ad3efeade2c0
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/6d09033d9cabf4be617ebcd83cd8170e7f91720a b/fuzz/corpus/packet_recv_client/6d09033d9cabf4be617ebcd83cd8170e7f91720a
new file mode 100644
index 0000000..4f1c9e8
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/6d09033d9cabf4be617ebcd83cd8170e7f91720a
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/787bef1f01133454c80c267bded9d23a84b7b8a2 b/fuzz/corpus/packet_recv_client/787bef1f01133454c80c267bded9d23a84b7b8a2
new file mode 100644
index 0000000..2213b67
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/787bef1f01133454c80c267bded9d23a84b7b8a2
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/7d083d65281b1c73f065036e5311b7a7d80d91c2 b/fuzz/corpus/packet_recv_client/7d083d65281b1c73f065036e5311b7a7d80d91c2
new file mode 100644
index 0000000..c828b09
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/7d083d65281b1c73f065036e5311b7a7d80d91c2
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/88530418a035908061f813f363920380285515ee b/fuzz/corpus/packet_recv_client/88530418a035908061f813f363920380285515ee
new file mode 100644
index 0000000..b976bcd
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/88530418a035908061f813f363920380285515ee
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/9105bbf68b549c00a0c72f9fef481ad785c92004 b/fuzz/corpus/packet_recv_client/9105bbf68b549c00a0c72f9fef481ad785c92004
new file mode 100644
index 0000000..20fd41c
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/9105bbf68b549c00a0c72f9fef481ad785c92004
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/9a01b915f4f6b4823d19b51320872b6a52564926 b/fuzz/corpus/packet_recv_client/9a01b915f4f6b4823d19b51320872b6a52564926
new file mode 100644
index 0000000..1e6d95e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/9a01b915f4f6b4823d19b51320872b6a52564926
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/9c68dee4925305f092c3a620310c1decd9489a48 b/fuzz/corpus/packet_recv_client/9c68dee4925305f092c3a620310c1decd9489a48
new file mode 100644
index 0000000..8bfd4a7
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/9c68dee4925305f092c3a620310c1decd9489a48
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/a0ec87d363149676561d4fb8eec4e90b899aed73 b/fuzz/corpus/packet_recv_client/a0ec87d363149676561d4fb8eec4e90b899aed73
new file mode 100644
index 0000000..7f72118
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/a0ec87d363149676561d4fb8eec4e90b899aed73
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/a17ec33ed1a3b81a980ae1233b0457bbd566be17 b/fuzz/corpus/packet_recv_client/a17ec33ed1a3b81a980ae1233b0457bbd566be17
new file mode 100644
index 0000000..037d2ad
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/a17ec33ed1a3b81a980ae1233b0457bbd566be17
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/aa29ba1720bcf4ecce12844858b7006b7b0cde93 b/fuzz/corpus/packet_recv_client/aa29ba1720bcf4ecce12844858b7006b7b0cde93
new file mode 100644
index 0000000..3b483de
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/aa29ba1720bcf4ecce12844858b7006b7b0cde93
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/ac9231da4082430afe8f4d40127814c613648d8e b/fuzz/corpus/packet_recv_client/ac9231da4082430afe8f4d40127814c613648d8e
new file mode 100644
index 0000000..501a6bb
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/ac9231da4082430afe8f4d40127814c613648d8e
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/fuzz/corpus/packet_recv_client/c2ad5674c5ceea9394b352524c84d29e1e50c1d4 b/fuzz/corpus/packet_recv_client/c2ad5674c5ceea9394b352524c84d29e1e50c1d4
new file mode 100644
index 0000000..94f094c
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/c2ad5674c5ceea9394b352524c84d29e1e50c1d4
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/c3ef27288834c6f5c4999f13312f0729a9fe93b6 b/fuzz/corpus/packet_recv_client/c3ef27288834c6f5c4999f13312f0729a9fe93b6
new file mode 100644
index 0000000..bc97480
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/c3ef27288834c6f5c4999f13312f0729a9fe93b6
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/cb63f7fc4b915aeff6776cf96b7f20140bc11675 b/fuzz/corpus/packet_recv_client/cb63f7fc4b915aeff6776cf96b7f20140bc11675
new file mode 100644
index 0000000..5c4788b
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/cb63f7fc4b915aeff6776cf96b7f20140bc11675
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/cc7a5873b3f2fd972c5c14714f02f52aab40bd8f b/fuzz/corpus/packet_recv_client/cc7a5873b3f2fd972c5c14714f02f52aab40bd8f
new file mode 100644
index 0000000..797e904
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/cc7a5873b3f2fd972c5c14714f02f52aab40bd8f
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/d0d5b0b2490054fdd6c1ea835c0161c071bb67f5 b/fuzz/corpus/packet_recv_client/d0d5b0b2490054fdd6c1ea835c0161c071bb67f5
new file mode 100644
index 0000000..9f40d04
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/d0d5b0b2490054fdd6c1ea835c0161c071bb67f5
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/d154c247dc32695b556d59310d2efef4aa84297c b/fuzz/corpus/packet_recv_client/d154c247dc32695b556d59310d2efef4aa84297c
new file mode 100644
index 0000000..6f062a0
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/d154c247dc32695b556d59310d2efef4aa84297c
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/dbf5a58cf0cfbf387674323820191e9837860174 b/fuzz/corpus/packet_recv_client/dbf5a58cf0cfbf387674323820191e9837860174
new file mode 100644
index 0000000..b689bcc
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/dbf5a58cf0cfbf387674323820191e9837860174
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/df5a6210c8f70017b1762fe703fca926c199383d b/fuzz/corpus/packet_recv_client/df5a6210c8f70017b1762fe703fca926c199383d
new file mode 100644
index 0000000..4d8fd4a
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/df5a6210c8f70017b1762fe703fca926c199383d
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/e7196d8bfbd208a23e835699b6f4209840c4a683 b/fuzz/corpus/packet_recv_client/e7196d8bfbd208a23e835699b6f4209840c4a683
new file mode 100644
index 0000000..d5d57fc
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/e7196d8bfbd208a23e835699b6f4209840c4a683
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/e9596e7b64799448e81531acf38e2078f318b044 b/fuzz/corpus/packet_recv_client/e9596e7b64799448e81531acf38e2078f318b044
new file mode 100644
index 0000000..c486819
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/e9596e7b64799448e81531acf38e2078f318b044
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/f07d5fc54ab668426f71ea031653863c66904f0a b/fuzz/corpus/packet_recv_client/f07d5fc54ab668426f71ea031653863c66904f0a
new file mode 100644
index 0000000..58c1555
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/f07d5fc54ab668426f71ea031653863c66904f0a
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/f0d747d897d9ad3b8921c2c98d42070be094036a b/fuzz/corpus/packet_recv_client/f0d747d897d9ad3b8921c2c98d42070be094036a
new file mode 100644
index 0000000..ed0e19a
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/f0d747d897d9ad3b8921c2c98d42070be094036a
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/f23a6e38bd149ea55853a8cd6b8fe1047eeed39f b/fuzz/corpus/packet_recv_client/f23a6e38bd149ea55853a8cd6b8fe1047eeed39f
new file mode 100644
index 0000000..70adb13
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/f23a6e38bd149ea55853a8cd6b8fe1047eeed39f
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/fe5e7b6996375f1f7a664705891db10054d8d397 b/fuzz/corpus/packet_recv_client/fe5e7b6996375f1f7a664705891db10054d8d397
new file mode 100644
index 0000000..bfe25c9
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/fe5e7b6996375f1f7a664705891db10054d8d397
Binary files differ
diff --git a/fuzz/corpus/packet_recv_client/ff38d421772c88784a9ca113e446bfc69287b6a1 b/fuzz/corpus/packet_recv_client/ff38d421772c88784a9ca113e446bfc69287b6a1
new file mode 100644
index 0000000..48b83c8
--- /dev/null
+++ b/fuzz/corpus/packet_recv_client/ff38d421772c88784a9ca113e446bfc69287b6a1
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/004b27fae0a9c997cb8ed8df9f01aeca2b7a7ddf b/fuzz/corpus/packet_recv_server/004b27fae0a9c997cb8ed8df9f01aeca2b7a7ddf
new file mode 100644
index 0000000..f946c2d
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/004b27fae0a9c997cb8ed8df9f01aeca2b7a7ddf
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/0090499a6044b4ee0b1399f74536070b9a131b57 b/fuzz/corpus/packet_recv_server/0090499a6044b4ee0b1399f74536070b9a131b57
new file mode 100644
index 0000000..3ecad4c
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/0090499a6044b4ee0b1399f74536070b9a131b57
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/037a150024f1f0b1b3d40ca0bad0a41cb0f3fc1c b/fuzz/corpus/packet_recv_server/037a150024f1f0b1b3d40ca0bad0a41cb0f3fc1c
new file mode 100644
index 0000000..1975cc0
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/037a150024f1f0b1b3d40ca0bad0a41cb0f3fc1c
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/04008eeb383eb14a3ab8e9e58a9f9f96139fbe70 b/fuzz/corpus/packet_recv_server/04008eeb383eb14a3ab8e9e58a9f9f96139fbe70
new file mode 100644
index 0000000..84358b6
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/04008eeb383eb14a3ab8e9e58a9f9f96139fbe70
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/043bc2606fd0197262e9442e5c6b28163cf80641 b/fuzz/corpus/packet_recv_server/043bc2606fd0197262e9442e5c6b28163cf80641
new file mode 100644
index 0000000..71e8ee8
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/043bc2606fd0197262e9442e5c6b28163cf80641
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/04bf553f2a69129a19fd83241fc82989818c655e b/fuzz/corpus/packet_recv_server/04bf553f2a69129a19fd83241fc82989818c655e
new file mode 100644
index 0000000..e220b9e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/04bf553f2a69129a19fd83241fc82989818c655e
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/073fa34f9550e99b442cff079df56ff03120d10f b/fuzz/corpus/packet_recv_server/073fa34f9550e99b442cff079df56ff03120d10f
new file mode 100644
index 0000000..93c2c43
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/073fa34f9550e99b442cff079df56ff03120d10f
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/074a556fe49e356f482237e7dada61ca88205d09 b/fuzz/corpus/packet_recv_server/074a556fe49e356f482237e7dada61ca88205d09
new file mode 100644
index 0000000..26517fb
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/074a556fe49e356f482237e7dada61ca88205d09
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/07a6233dfa2768455aac36b916069b0e99c939e5 b/fuzz/corpus/packet_recv_server/07a6233dfa2768455aac36b916069b0e99c939e5
new file mode 100644
index 0000000..b04dabe
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/07a6233dfa2768455aac36b916069b0e99c939e5
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/07e1c5b97cfbbc4fb310a9c096489d24761f38a4 b/fuzz/corpus/packet_recv_server/07e1c5b97cfbbc4fb310a9c096489d24761f38a4
new file mode 100644
index 0000000..5b048ad
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/07e1c5b97cfbbc4fb310a9c096489d24761f38a4
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/0832745635dff6418c76bc26f65f5732458e61fd b/fuzz/corpus/packet_recv_server/0832745635dff6418c76bc26f65f5732458e61fd
new file mode 100644
index 0000000..99ea6bb
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/0832745635dff6418c76bc26f65f5732458e61fd
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/0938d9ebdf2e7c92d7b697100d4c1cbc05c3d342 b/fuzz/corpus/packet_recv_server/0938d9ebdf2e7c92d7b697100d4c1cbc05c3d342
new file mode 100644
index 0000000..4b2bdd4
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/0938d9ebdf2e7c92d7b697100d4c1cbc05c3d342
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/09561cf158cbde994fa4910af669488a0bc03607 b/fuzz/corpus/packet_recv_server/09561cf158cbde994fa4910af669488a0bc03607
new file mode 100644
index 0000000..73d2c42
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/09561cf158cbde994fa4910af669488a0bc03607
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/09e7909f12f76e8ec157f5d2de9f26783641912b b/fuzz/corpus/packet_recv_server/09e7909f12f76e8ec157f5d2de9f26783641912b
new file mode 100644
index 0000000..c092ed9
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/09e7909f12f76e8ec157f5d2de9f26783641912b
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/09f888d69d5356406db343ee048f3b8dd496f0da b/fuzz/corpus/packet_recv_server/09f888d69d5356406db343ee048f3b8dd496f0da
new file mode 100644
index 0000000..5f7725b
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/09f888d69d5356406db343ee048f3b8dd496f0da
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/0a579f5a02223c84be316788199740cd11f8640e b/fuzz/corpus/packet_recv_server/0a579f5a02223c84be316788199740cd11f8640e
new file mode 100644
index 0000000..8bb7d65
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/0a579f5a02223c84be316788199740cd11f8640e
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/0b96ea0663bbbf4c321c3d9e1ad7f743c69df18d b/fuzz/corpus/packet_recv_server/0b96ea0663bbbf4c321c3d9e1ad7f743c69df18d
new file mode 100644
index 0000000..10fb1f4
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/0b96ea0663bbbf4c321c3d9e1ad7f743c69df18d
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/0be97fc8c29968ea82fc5797876831ca42b135c0 b/fuzz/corpus/packet_recv_server/0be97fc8c29968ea82fc5797876831ca42b135c0
new file mode 100644
index 0000000..de2c581
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/0be97fc8c29968ea82fc5797876831ca42b135c0
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/0c041ac88ac98d0e9b11fc689a4aed8db10d4a4a b/fuzz/corpus/packet_recv_server/0c041ac88ac98d0e9b11fc689a4aed8db10d4a4a
new file mode 100644
index 0000000..fa2fb4d
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/0c041ac88ac98d0e9b11fc689a4aed8db10d4a4a
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/0de159f7ef9736421682e7a8e5dbf475ebd0388b b/fuzz/corpus/packet_recv_server/0de159f7ef9736421682e7a8e5dbf475ebd0388b
new file mode 100644
index 0000000..eab453e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/0de159f7ef9736421682e7a8e5dbf475ebd0388b
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/10064ab28b1e42f31cb56035b4da8a8380d4eea2 b/fuzz/corpus/packet_recv_server/10064ab28b1e42f31cb56035b4da8a8380d4eea2
new file mode 100644
index 0000000..b80bc69
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/10064ab28b1e42f31cb56035b4da8a8380d4eea2
@@ -0,0 +1 @@
+ýýý_
\ No newline at end of file
diff --git a/fuzz/corpus/packet_recv_server/1154e21f9b2c9ce472a65d1413d087df6139c9fa b/fuzz/corpus/packet_recv_server/1154e21f9b2c9ce472a65d1413d087df6139c9fa
new file mode 100644
index 0000000..f08381a
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/1154e21f9b2c9ce472a65d1413d087df6139c9fa
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/121869b4bd03de3595ca44d682c783f0f83c6ead b/fuzz/corpus/packet_recv_server/121869b4bd03de3595ca44d682c783f0f83c6ead
new file mode 100644
index 0000000..ef15fd1
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/121869b4bd03de3595ca44d682c783f0f83c6ead
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/1226cbb4990c67d30d501e1492ad442405afeaae b/fuzz/corpus/packet_recv_server/1226cbb4990c67d30d501e1492ad442405afeaae
new file mode 100644
index 0000000..75e16af
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/1226cbb4990c67d30d501e1492ad442405afeaae
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/13be2836e15a2d1a45d8e3a31c02422db84956a7 b/fuzz/corpus/packet_recv_server/13be2836e15a2d1a45d8e3a31c02422db84956a7
new file mode 100644
index 0000000..d0e8bf1
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/13be2836e15a2d1a45d8e3a31c02422db84956a7
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/1563c2b62d55f4d19f7fec338070b6a1023bc9b4 b/fuzz/corpus/packet_recv_server/1563c2b62d55f4d19f7fec338070b6a1023bc9b4
new file mode 100644
index 0000000..db49338
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/1563c2b62d55f4d19f7fec338070b6a1023bc9b4
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/15c7a57add110f4a98be440024a16766ba34b5fe b/fuzz/corpus/packet_recv_server/15c7a57add110f4a98be440024a16766ba34b5fe
new file mode 100644
index 0000000..d6b0a8c
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/15c7a57add110f4a98be440024a16766ba34b5fe
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/15d8f271a8a3a2e599ed33a99fef034bfab635ce b/fuzz/corpus/packet_recv_server/15d8f271a8a3a2e599ed33a99fef034bfab635ce
new file mode 100644
index 0000000..9c31b32
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/15d8f271a8a3a2e599ed33a99fef034bfab635ce
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/16840d045cf254977c9bff6e70b963360788c1be b/fuzz/corpus/packet_recv_server/16840d045cf254977c9bff6e70b963360788c1be
new file mode 100644
index 0000000..ff22479
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/16840d045cf254977c9bff6e70b963360788c1be
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/16eedfacb9f6d5288c06143f8e6c54c0066ac85f b/fuzz/corpus/packet_recv_server/16eedfacb9f6d5288c06143f8e6c54c0066ac85f
new file mode 100644
index 0000000..f8d4784
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/16eedfacb9f6d5288c06143f8e6c54c0066ac85f
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/17dee5b19cc54271d38c9354b220b924a67fd2d2 b/fuzz/corpus/packet_recv_server/17dee5b19cc54271d38c9354b220b924a67fd2d2
new file mode 100644
index 0000000..41589cf
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/17dee5b19cc54271d38c9354b220b924a67fd2d2
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/17f7927c2c1e1740c22a705f5fd3c2c9abff976a b/fuzz/corpus/packet_recv_server/17f7927c2c1e1740c22a705f5fd3c2c9abff976a
new file mode 100644
index 0000000..4e1f0b4
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/17f7927c2c1e1740c22a705f5fd3c2c9abff976a
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/1ac225396950b62aaacf77f92494565244399bfe b/fuzz/corpus/packet_recv_server/1ac225396950b62aaacf77f92494565244399bfe
new file mode 100644
index 0000000..689537d
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/1ac225396950b62aaacf77f92494565244399bfe
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/1ae7d811f211b4a98ab7d95aaa680d141baf08ad b/fuzz/corpus/packet_recv_server/1ae7d811f211b4a98ab7d95aaa680d141baf08ad
new file mode 100644
index 0000000..f535ae3
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/1ae7d811f211b4a98ab7d95aaa680d141baf08ad
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/1b24bfa5c4520c307939c2cbaab9697933ce7a36 b/fuzz/corpus/packet_recv_server/1b24bfa5c4520c307939c2cbaab9697933ce7a36
new file mode 100644
index 0000000..f8d5c2d
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/1b24bfa5c4520c307939c2cbaab9697933ce7a36
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/1b48e05d3664e7349f7794bbdf2f7d29ff2758fe b/fuzz/corpus/packet_recv_server/1b48e05d3664e7349f7794bbdf2f7d29ff2758fe
new file mode 100644
index 0000000..8da402c
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/1b48e05d3664e7349f7794bbdf2f7d29ff2758fe
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/1be4a30fa166b9ba86fcf500fdba7a1a9f97d075 b/fuzz/corpus/packet_recv_server/1be4a30fa166b9ba86fcf500fdba7a1a9f97d075
new file mode 100644
index 0000000..cdfcf0e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/1be4a30fa166b9ba86fcf500fdba7a1a9f97d075
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/1c2f5d5038b8dd26ca7715aab504eb3f51ed9da9 b/fuzz/corpus/packet_recv_server/1c2f5d5038b8dd26ca7715aab504eb3f51ed9da9
new file mode 100644
index 0000000..bfd870b
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/1c2f5d5038b8dd26ca7715aab504eb3f51ed9da9
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/1c8502bf2e52109b83a8edcea373e7a4fcbc02a0 b/fuzz/corpus/packet_recv_server/1c8502bf2e52109b83a8edcea373e7a4fcbc02a0
new file mode 100644
index 0000000..211d4af
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/1c8502bf2e52109b83a8edcea373e7a4fcbc02a0
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/1ce2979fca6ec10c4e67f737603739a842ba9a41 b/fuzz/corpus/packet_recv_server/1ce2979fca6ec10c4e67f737603739a842ba9a41
new file mode 100644
index 0000000..02476ec
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/1ce2979fca6ec10c4e67f737603739a842ba9a41
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/1d4668d990232b91a28754de62156c7899e6856e b/fuzz/corpus/packet_recv_server/1d4668d990232b91a28754de62156c7899e6856e
new file mode 100644
index 0000000..527beb0
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/1d4668d990232b91a28754de62156c7899e6856e
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/1e0071c3cd56a0750ac04b83dd2392d59e02c5cf b/fuzz/corpus/packet_recv_server/1e0071c3cd56a0750ac04b83dd2392d59e02c5cf
new file mode 100644
index 0000000..1faa18c
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/1e0071c3cd56a0750ac04b83dd2392d59e02c5cf
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/200c2a0ba739b1c3c2925e6b2247644429401aac b/fuzz/corpus/packet_recv_server/200c2a0ba739b1c3c2925e6b2247644429401aac
new file mode 100644
index 0000000..dffa3ea
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/200c2a0ba739b1c3c2925e6b2247644429401aac
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/202951fc4aa1f3cc6429084e693966265f989df4 b/fuzz/corpus/packet_recv_server/202951fc4aa1f3cc6429084e693966265f989df4
new file mode 100644
index 0000000..bf37fad
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/202951fc4aa1f3cc6429084e693966265f989df4
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/209559d14467bbe10aa503d6adcc151384cf7eee b/fuzz/corpus/packet_recv_server/209559d14467bbe10aa503d6adcc151384cf7eee
new file mode 100644
index 0000000..933119d
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/209559d14467bbe10aa503d6adcc151384cf7eee
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/2180c55bdcef537ca41035b5d18b5de88398d77d b/fuzz/corpus/packet_recv_server/2180c55bdcef537ca41035b5d18b5de88398d77d
new file mode 100644
index 0000000..30f8231
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/2180c55bdcef537ca41035b5d18b5de88398d77d
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/21ae31cd632359de2337bcdba77d453bfb07a20b b/fuzz/corpus/packet_recv_server/21ae31cd632359de2337bcdba77d453bfb07a20b
new file mode 100644
index 0000000..4689d67
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/21ae31cd632359de2337bcdba77d453bfb07a20b
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/22a3f8827266e7f4acf795487fafdcd9dcf3e2a9 b/fuzz/corpus/packet_recv_server/22a3f8827266e7f4acf795487fafdcd9dcf3e2a9
new file mode 100644
index 0000000..16d06c9
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/22a3f8827266e7f4acf795487fafdcd9dcf3e2a9
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/23db19b83f38132449339273e72eac976aea6333 b/fuzz/corpus/packet_recv_server/23db19b83f38132449339273e72eac976aea6333
new file mode 100644
index 0000000..7b5739c
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/23db19b83f38132449339273e72eac976aea6333
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/260fc55abc18c7844145643a63f307702480a212 b/fuzz/corpus/packet_recv_server/260fc55abc18c7844145643a63f307702480a212
new file mode 100644
index 0000000..87ed40c
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/260fc55abc18c7844145643a63f307702480a212
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/261a546b1d4167a1671068fa1074d3f8020dbbae b/fuzz/corpus/packet_recv_server/261a546b1d4167a1671068fa1074d3f8020dbbae
new file mode 100644
index 0000000..3f265e4
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/261a546b1d4167a1671068fa1074d3f8020dbbae
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/2694224fcfeb0564f21e5e1559d83dcbd0287bea b/fuzz/corpus/packet_recv_server/2694224fcfeb0564f21e5e1559d83dcbd0287bea
new file mode 100644
index 0000000..6a1c6bf
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/2694224fcfeb0564f21e5e1559d83dcbd0287bea
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/280d0b015b96d4cd883d8ff5fb3b921309c990f2 b/fuzz/corpus/packet_recv_server/280d0b015b96d4cd883d8ff5fb3b921309c990f2
new file mode 100644
index 0000000..1fe9220
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/280d0b015b96d4cd883d8ff5fb3b921309c990f2
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/281ac5bdf3479592ffd156bd31a9f02662435f07 b/fuzz/corpus/packet_recv_server/281ac5bdf3479592ffd156bd31a9f02662435f07
new file mode 100644
index 0000000..05ab513
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/281ac5bdf3479592ffd156bd31a9f02662435f07
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/285e00988b2eda1ba6537e4782b69dc6f238ff7b b/fuzz/corpus/packet_recv_server/285e00988b2eda1ba6537e4782b69dc6f238ff7b
new file mode 100644
index 0000000..59abf67
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/285e00988b2eda1ba6537e4782b69dc6f238ff7b
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/2890be35ee55232f4b9b301be3c981f363fce03c b/fuzz/corpus/packet_recv_server/2890be35ee55232f4b9b301be3c981f363fce03c
new file mode 100644
index 0000000..acbcfb5
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/2890be35ee55232f4b9b301be3c981f363fce03c
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/2990fe3b259631bdba5d6a0faee30bebc2d844cc b/fuzz/corpus/packet_recv_server/2990fe3b259631bdba5d6a0faee30bebc2d844cc
new file mode 100644
index 0000000..15308fa
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/2990fe3b259631bdba5d6a0faee30bebc2d844cc
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/29c6ec9ed46d9d9d16660bc2da725c7ff6d910d0 b/fuzz/corpus/packet_recv_server/29c6ec9ed46d9d9d16660bc2da725c7ff6d910d0
new file mode 100644
index 0000000..4d08767
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/29c6ec9ed46d9d9d16660bc2da725c7ff6d910d0
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/2b78a580528915162f3a3bbfdd05921f79e13dd3 b/fuzz/corpus/packet_recv_server/2b78a580528915162f3a3bbfdd05921f79e13dd3
new file mode 100644
index 0000000..605cfed
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/2b78a580528915162f3a3bbfdd05921f79e13dd3
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/2cb18f2cfb01501cdcea8947ad02705360d0f3e5 b/fuzz/corpus/packet_recv_server/2cb18f2cfb01501cdcea8947ad02705360d0f3e5
new file mode 100644
index 0000000..ce1a9f2
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/2cb18f2cfb01501cdcea8947ad02705360d0f3e5
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/2cb4ef3f157f9533003498f1b45566d8047cd157 b/fuzz/corpus/packet_recv_server/2cb4ef3f157f9533003498f1b45566d8047cd157
new file mode 100644
index 0000000..281526a
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/2cb4ef3f157f9533003498f1b45566d8047cd157
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/2dbf885e1806d20ec31501adacb1623de98a0fda b/fuzz/corpus/packet_recv_server/2dbf885e1806d20ec31501adacb1623de98a0fda
new file mode 100644
index 0000000..e9bd9e8
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/2dbf885e1806d20ec31501adacb1623de98a0fda
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/2e446d375005a3de264879bacedbb2d2637a1b0b b/fuzz/corpus/packet_recv_server/2e446d375005a3de264879bacedbb2d2637a1b0b
new file mode 100644
index 0000000..3fb56f2
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/2e446d375005a3de264879bacedbb2d2637a1b0b
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/2e6255e05b21c418405a48a923aa1c7a4ab2ae01 b/fuzz/corpus/packet_recv_server/2e6255e05b21c418405a48a923aa1c7a4ab2ae01
new file mode 100644
index 0000000..31cd342
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/2e6255e05b21c418405a48a923aa1c7a4ab2ae01
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/2e8588f1feebd936b02f65283af2e57b177e7e09 b/fuzz/corpus/packet_recv_server/2e8588f1feebd936b02f65283af2e57b177e7e09
new file mode 100644
index 0000000..639350d
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/2e8588f1feebd936b02f65283af2e57b177e7e09
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/2e97e7ac926cac541712dadca0f4b1e713a926ed b/fuzz/corpus/packet_recv_server/2e97e7ac926cac541712dadca0f4b1e713a926ed
new file mode 100644
index 0000000..0cf9693
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/2e97e7ac926cac541712dadca0f4b1e713a926ed
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/2fc00732e098ef26cb5fd09bdd43abbbc7e01d05 b/fuzz/corpus/packet_recv_server/2fc00732e098ef26cb5fd09bdd43abbbc7e01d05
new file mode 100644
index 0000000..3f90acc
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/2fc00732e098ef26cb5fd09bdd43abbbc7e01d05
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/2fc05c24a32dc7c0917069b8d01e335c96588b33 b/fuzz/corpus/packet_recv_server/2fc05c24a32dc7c0917069b8d01e335c96588b33
new file mode 100644
index 0000000..6f22332
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/2fc05c24a32dc7c0917069b8d01e335c96588b33
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/313335448245f0966a3606d8c29c17fd8082d810 b/fuzz/corpus/packet_recv_server/313335448245f0966a3606d8c29c17fd8082d810
new file mode 100644
index 0000000..eaee25e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/313335448245f0966a3606d8c29c17fd8082d810
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/319185698c2b5669ed44cf0a624698cc58722c2c b/fuzz/corpus/packet_recv_server/319185698c2b5669ed44cf0a624698cc58722c2c
new file mode 100644
index 0000000..e038a49
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/319185698c2b5669ed44cf0a624698cc58722c2c
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/31e95fc2b1db5a4ee526eebcdd86c100adc52740 b/fuzz/corpus/packet_recv_server/31e95fc2b1db5a4ee526eebcdd86c100adc52740
new file mode 100644
index 0000000..f9e848b
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/31e95fc2b1db5a4ee526eebcdd86c100adc52740
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/32910d3477ffe0655ea833b56f9ce1147829cbbc b/fuzz/corpus/packet_recv_server/32910d3477ffe0655ea833b56f9ce1147829cbbc
new file mode 100644
index 0000000..cdd5c1a
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/32910d3477ffe0655ea833b56f9ce1147829cbbc
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/331b09f021f85d2101895076380db160f9df0415 b/fuzz/corpus/packet_recv_server/331b09f021f85d2101895076380db160f9df0415
new file mode 100644
index 0000000..12cf704
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/331b09f021f85d2101895076380db160f9df0415
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/344e9ab131feb524be2c83f774a5e844843289ab b/fuzz/corpus/packet_recv_server/344e9ab131feb524be2c83f774a5e844843289ab
new file mode 100644
index 0000000..8ee731c
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/344e9ab131feb524be2c83f774a5e844843289ab
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/35cc3a43f01ca79bbe7d23b4ce2123d9446fa315 b/fuzz/corpus/packet_recv_server/35cc3a43f01ca79bbe7d23b4ce2123d9446fa315
new file mode 100644
index 0000000..22f3a2d
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/35cc3a43f01ca79bbe7d23b4ce2123d9446fa315
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/3755e5285e76174ef9c9ec2a2583c6fb9a2e3dea b/fuzz/corpus/packet_recv_server/3755e5285e76174ef9c9ec2a2583c6fb9a2e3dea
new file mode 100644
index 0000000..18651cf
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/3755e5285e76174ef9c9ec2a2583c6fb9a2e3dea
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/377502f81653222fcfe37137e5768f34f5de40ff b/fuzz/corpus/packet_recv_server/377502f81653222fcfe37137e5768f34f5de40ff
new file mode 100644
index 0000000..a9244f5
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/377502f81653222fcfe37137e5768f34f5de40ff
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/39296e96d016048b1a5456fb0c7d1e75212ea0ab b/fuzz/corpus/packet_recv_server/39296e96d016048b1a5456fb0c7d1e75212ea0ab
new file mode 100644
index 0000000..76948b7
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/39296e96d016048b1a5456fb0c7d1e75212ea0ab
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/3966365577bef4abfa346c6fa6c0fa986f8dd60e b/fuzz/corpus/packet_recv_server/3966365577bef4abfa346c6fa6c0fa986f8dd60e
new file mode 100644
index 0000000..a1d9cd8
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/3966365577bef4abfa346c6fa6c0fa986f8dd60e
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/39b57c2e61bf184ce5e8be0956275cb2c8ca3789 b/fuzz/corpus/packet_recv_server/39b57c2e61bf184ce5e8be0956275cb2c8ca3789
new file mode 100644
index 0000000..862a40e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/39b57c2e61bf184ce5e8be0956275cb2c8ca3789
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/39e5494e6db4b21c5f76fa43d0ae4cf658d6c7ea b/fuzz/corpus/packet_recv_server/39e5494e6db4b21c5f76fa43d0ae4cf658d6c7ea
new file mode 100644
index 0000000..3f7a87e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/39e5494e6db4b21c5f76fa43d0ae4cf658d6c7ea
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/3a5ccbce2b4f3496f27fe93e657c6ac59391a4dc b/fuzz/corpus/packet_recv_server/3a5ccbce2b4f3496f27fe93e657c6ac59391a4dc
new file mode 100644
index 0000000..18e89b4
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/3a5ccbce2b4f3496f27fe93e657c6ac59391a4dc
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/3b0612192026e9c5e2f20ac0b014a865ef97a9f0 b/fuzz/corpus/packet_recv_server/3b0612192026e9c5e2f20ac0b014a865ef97a9f0
new file mode 100644
index 0000000..59300ac
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/3b0612192026e9c5e2f20ac0b014a865ef97a9f0
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/3b159074fba616ff48b49972b0306ed7a9061e95 b/fuzz/corpus/packet_recv_server/3b159074fba616ff48b49972b0306ed7a9061e95
new file mode 100644
index 0000000..b5bf3df
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/3b159074fba616ff48b49972b0306ed7a9061e95
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/3b7b6d5258296efc2b2a2451e55d0ccbdc8d17e4 b/fuzz/corpus/packet_recv_server/3b7b6d5258296efc2b2a2451e55d0ccbdc8d17e4
new file mode 100644
index 0000000..cddfb87
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/3b7b6d5258296efc2b2a2451e55d0ccbdc8d17e4
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/3c5d3c1624c5698055e71172f873ea31ad1f7634 b/fuzz/corpus/packet_recv_server/3c5d3c1624c5698055e71172f873ea31ad1f7634
new file mode 100644
index 0000000..3e9de89
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/3c5d3c1624c5698055e71172f873ea31ad1f7634
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/3cf63aab309f8006fbc677ce7b063bb032af0fea b/fuzz/corpus/packet_recv_server/3cf63aab309f8006fbc677ce7b063bb032af0fea
new file mode 100644
index 0000000..a3cfeda
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/3cf63aab309f8006fbc677ce7b063bb032af0fea
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/3d2df43b4711432f1f427e110336769b264c5758 b/fuzz/corpus/packet_recv_server/3d2df43b4711432f1f427e110336769b264c5758
new file mode 100644
index 0000000..969d60e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/3d2df43b4711432f1f427e110336769b264c5758
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/3d80b6d65c6f8cb73040b60e9773bec3267d4bff b/fuzz/corpus/packet_recv_server/3d80b6d65c6f8cb73040b60e9773bec3267d4bff
new file mode 100644
index 0000000..3b9e26a
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/3d80b6d65c6f8cb73040b60e9773bec3267d4bff
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/3dc980ad15c3d051057c40a6e39feb40cabda0b5 b/fuzz/corpus/packet_recv_server/3dc980ad15c3d051057c40a6e39feb40cabda0b5
new file mode 100644
index 0000000..3130285
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/3dc980ad15c3d051057c40a6e39feb40cabda0b5
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/3e87c97e6cba17ab4d59f1b941c1f7c9f4ba3a85 b/fuzz/corpus/packet_recv_server/3e87c97e6cba17ab4d59f1b941c1f7c9f4ba3a85
new file mode 100644
index 0000000..2c876b2
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/3e87c97e6cba17ab4d59f1b941c1f7c9f4ba3a85
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/3ee647fec9135922cf75239d539e5a8326966fa9 b/fuzz/corpus/packet_recv_server/3ee647fec9135922cf75239d539e5a8326966fa9
new file mode 100644
index 0000000..2393dee
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/3ee647fec9135922cf75239d539e5a8326966fa9
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/3f750b077479fdab1539c8f1c970a57e16159157 b/fuzz/corpus/packet_recv_server/3f750b077479fdab1539c8f1c970a57e16159157
new file mode 100644
index 0000000..4d0816e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/3f750b077479fdab1539c8f1c970a57e16159157
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/407a92369cbb1fb403df15a89af3bc0cec9bae0c b/fuzz/corpus/packet_recv_server/407a92369cbb1fb403df15a89af3bc0cec9bae0c
new file mode 100644
index 0000000..ac47f18
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/407a92369cbb1fb403df15a89af3bc0cec9bae0c
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/407b0ccc1fc3972e19c3ea74279faa055aafa6cd b/fuzz/corpus/packet_recv_server/407b0ccc1fc3972e19c3ea74279faa055aafa6cd
new file mode 100644
index 0000000..d965c68
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/407b0ccc1fc3972e19c3ea74279faa055aafa6cd
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/40b85fca6540bc88d254a70d32684fc141948912 b/fuzz/corpus/packet_recv_server/40b85fca6540bc88d254a70d32684fc141948912
new file mode 100644
index 0000000..7ee7574
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/40b85fca6540bc88d254a70d32684fc141948912
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/418de17fab3dffc191ec741fb04ca81b9288f9cd b/fuzz/corpus/packet_recv_server/418de17fab3dffc191ec741fb04ca81b9288f9cd
new file mode 100644
index 0000000..e698f8e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/418de17fab3dffc191ec741fb04ca81b9288f9cd
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/428d56e4bdcd603e9a420d42cd9d87fd3698ef0d b/fuzz/corpus/packet_recv_server/428d56e4bdcd603e9a420d42cd9d87fd3698ef0d
new file mode 100644
index 0000000..5f28a75
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/428d56e4bdcd603e9a420d42cd9d87fd3698ef0d
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/429c1b3273e105b577ec23fa54beb79ffa841e8b b/fuzz/corpus/packet_recv_server/429c1b3273e105b577ec23fa54beb79ffa841e8b
new file mode 100644
index 0000000..ed86ed1
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/429c1b3273e105b577ec23fa54beb79ffa841e8b
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/42d262b169ad6c90da08d3aeec2781934976f798 b/fuzz/corpus/packet_recv_server/42d262b169ad6c90da08d3aeec2781934976f798
new file mode 100644
index 0000000..a5b0c3e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/42d262b169ad6c90da08d3aeec2781934976f798
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/4599329e5f100773e54c0756defa5d336a460b62 b/fuzz/corpus/packet_recv_server/4599329e5f100773e54c0756defa5d336a460b62
new file mode 100644
index 0000000..eeddbbe
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/4599329e5f100773e54c0756defa5d336a460b62
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/46afde7278eb2d1bdc7a450869085f9be84c9dde b/fuzz/corpus/packet_recv_server/46afde7278eb2d1bdc7a450869085f9be84c9dde
new file mode 100644
index 0000000..c0255ba
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/46afde7278eb2d1bdc7a450869085f9be84c9dde
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/4778e73e2f1720a42d74465832d75d2797807f71 b/fuzz/corpus/packet_recv_server/4778e73e2f1720a42d74465832d75d2797807f71
new file mode 100644
index 0000000..7aa264b
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/4778e73e2f1720a42d74465832d75d2797807f71
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/47b8f34e66d3843ed631e5549e7c8aa363402619 b/fuzz/corpus/packet_recv_server/47b8f34e66d3843ed631e5549e7c8aa363402619
new file mode 100644
index 0000000..79a778e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/47b8f34e66d3843ed631e5549e7c8aa363402619
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/47be1b2c5e2bce8d1cea023c543983dd2adc5b94 b/fuzz/corpus/packet_recv_server/47be1b2c5e2bce8d1cea023c543983dd2adc5b94
new file mode 100644
index 0000000..7289dfd
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/47be1b2c5e2bce8d1cea023c543983dd2adc5b94
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/47c0eac8ea32842623789a060815156d886fc5e2 b/fuzz/corpus/packet_recv_server/47c0eac8ea32842623789a060815156d886fc5e2
new file mode 100644
index 0000000..fb8196a
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/47c0eac8ea32842623789a060815156d886fc5e2
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/47dad0b12279dab7501b71489b2578f9e085bc63 b/fuzz/corpus/packet_recv_server/47dad0b12279dab7501b71489b2578f9e085bc63
new file mode 100644
index 0000000..e4141e9
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/47dad0b12279dab7501b71489b2578f9e085bc63
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/49ebd535378e9909ee6ea40ec6e6bcfb83f2408c b/fuzz/corpus/packet_recv_server/49ebd535378e9909ee6ea40ec6e6bcfb83f2408c
new file mode 100644
index 0000000..4a14ab5
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/49ebd535378e9909ee6ea40ec6e6bcfb83f2408c
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/4ae614ac89cd7fa2bb9054095764404ed6414005 b/fuzz/corpus/packet_recv_server/4ae614ac89cd7fa2bb9054095764404ed6414005
new file mode 100644
index 0000000..700dcd6
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/4ae614ac89cd7fa2bb9054095764404ed6414005
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/4c7267da453125f25102f6427da8b45b10b71b92 b/fuzz/corpus/packet_recv_server/4c7267da453125f25102f6427da8b45b10b71b92
new file mode 100644
index 0000000..72b8d10
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/4c7267da453125f25102f6427da8b45b10b71b92
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/4c8f9520ae26a1ff496c865fd2d7a41256c0ba9d b/fuzz/corpus/packet_recv_server/4c8f9520ae26a1ff496c865fd2d7a41256c0ba9d
new file mode 100644
index 0000000..07ca0c4
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/4c8f9520ae26a1ff496c865fd2d7a41256c0ba9d
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/4d4d3cb9a9d368e6bdd01204f77f59a787d57013 b/fuzz/corpus/packet_recv_server/4d4d3cb9a9d368e6bdd01204f77f59a787d57013
new file mode 100644
index 0000000..19be60e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/4d4d3cb9a9d368e6bdd01204f77f59a787d57013
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/4d6ad5cea9c02cceba576ac895ff184cdfe293e3 b/fuzz/corpus/packet_recv_server/4d6ad5cea9c02cceba576ac895ff184cdfe293e3
new file mode 100644
index 0000000..a972eb0
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/4d6ad5cea9c02cceba576ac895ff184cdfe293e3
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/4d935541dec6b90afb114d7c8ebb191e7cbd9ef4 b/fuzz/corpus/packet_recv_server/4d935541dec6b90afb114d7c8ebb191e7cbd9ef4
new file mode 100644
index 0000000..71648ec
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/4d935541dec6b90afb114d7c8ebb191e7cbd9ef4
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/4e8913964b7d1200697c62738b9546c39454cf16 b/fuzz/corpus/packet_recv_server/4e8913964b7d1200697c62738b9546c39454cf16
new file mode 100644
index 0000000..c22b2a2
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/4e8913964b7d1200697c62738b9546c39454cf16
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/4f26b8ea7f67fecf92a24fd5c338ca16f5de8912 b/fuzz/corpus/packet_recv_server/4f26b8ea7f67fecf92a24fd5c338ca16f5de8912
new file mode 100644
index 0000000..273b1b1
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/4f26b8ea7f67fecf92a24fd5c338ca16f5de8912
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/4ffe6a7a3ece3fdfe1cc9f5151c23750618d3f63 b/fuzz/corpus/packet_recv_server/4ffe6a7a3ece3fdfe1cc9f5151c23750618d3f63
new file mode 100644
index 0000000..c43925e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/4ffe6a7a3ece3fdfe1cc9f5151c23750618d3f63
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/5033ecd4c1459fc02e9b421b9cac43bb8f5a22f1 b/fuzz/corpus/packet_recv_server/5033ecd4c1459fc02e9b421b9cac43bb8f5a22f1
new file mode 100644
index 0000000..2427878
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/5033ecd4c1459fc02e9b421b9cac43bb8f5a22f1
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/503ef6846e39a5c98658437121964bf526d81fce b/fuzz/corpus/packet_recv_server/503ef6846e39a5c98658437121964bf526d81fce
new file mode 100644
index 0000000..6257d86
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/503ef6846e39a5c98658437121964bf526d81fce
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/52538a80094f7b62948fd31e68fd17a315d8dc91 b/fuzz/corpus/packet_recv_server/52538a80094f7b62948fd31e68fd17a315d8dc91
new file mode 100644
index 0000000..5cd813e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/52538a80094f7b62948fd31e68fd17a315d8dc91
@@ -0,0 +1 @@
+ª
\ No newline at end of file
diff --git a/fuzz/corpus/packet_recv_server/5324a624b7b71aaea5c7bc4a45dfa2ba33b061fe b/fuzz/corpus/packet_recv_server/5324a624b7b71aaea5c7bc4a45dfa2ba33b061fe
new file mode 100644
index 0000000..2e726de
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/5324a624b7b71aaea5c7bc4a45dfa2ba33b061fe
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/534e1d81f463af5b18e7aaa45f1e74ae5e853593 b/fuzz/corpus/packet_recv_server/534e1d81f463af5b18e7aaa45f1e74ae5e853593
new file mode 100644
index 0000000..4110021
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/534e1d81f463af5b18e7aaa45f1e74ae5e853593
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/548faf0c830ddacd7fb4fc8b0aade0ba314ef205 b/fuzz/corpus/packet_recv_server/548faf0c830ddacd7fb4fc8b0aade0ba314ef205
new file mode 100644
index 0000000..e7269c8
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/548faf0c830ddacd7fb4fc8b0aade0ba314ef205
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/54bfd1193a3c2c2b75b1cd6ca915fdd12cc495ec b/fuzz/corpus/packet_recv_server/54bfd1193a3c2c2b75b1cd6ca915fdd12cc495ec
new file mode 100644
index 0000000..5726054
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/54bfd1193a3c2c2b75b1cd6ca915fdd12cc495ec
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/555316d562d32b878a404fcc1a3505887dd2a7c2 b/fuzz/corpus/packet_recv_server/555316d562d32b878a404fcc1a3505887dd2a7c2
new file mode 100644
index 0000000..5f2917b
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/555316d562d32b878a404fcc1a3505887dd2a7c2
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/55b4dffba631601255fd3900d9eb32ff58f160f6 b/fuzz/corpus/packet_recv_server/55b4dffba631601255fd3900d9eb32ff58f160f6
new file mode 100644
index 0000000..2c98359
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/55b4dffba631601255fd3900d9eb32ff58f160f6
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/573106df8cbf9742eca6616357c825bdbfeeb0b4 b/fuzz/corpus/packet_recv_server/573106df8cbf9742eca6616357c825bdbfeeb0b4
new file mode 100644
index 0000000..0726425
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/573106df8cbf9742eca6616357c825bdbfeeb0b4
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/57de28b7249a7ce060d126b25d3abbed27d4ed10 b/fuzz/corpus/packet_recv_server/57de28b7249a7ce060d126b25d3abbed27d4ed10
new file mode 100644
index 0000000..54f328f
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/57de28b7249a7ce060d126b25d3abbed27d4ed10
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/585dcb9e59443cc264bcca336b206b6e57472365 b/fuzz/corpus/packet_recv_server/585dcb9e59443cc264bcca336b206b6e57472365
new file mode 100644
index 0000000..bc5b96a
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/585dcb9e59443cc264bcca336b206b6e57472365
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/5990bce38251bb404a803f278ecae7fb56d0087f b/fuzz/corpus/packet_recv_server/5990bce38251bb404a803f278ecae7fb56d0087f
new file mode 100644
index 0000000..672ceb6
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/5990bce38251bb404a803f278ecae7fb56d0087f
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/59e3ec10058814c57e6631d662a77394de15b6d6 b/fuzz/corpus/packet_recv_server/59e3ec10058814c57e6631d662a77394de15b6d6
new file mode 100644
index 0000000..d922023
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/59e3ec10058814c57e6631d662a77394de15b6d6
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/5ae5ca0fe96581d0233f31658d71f255016dcfe8 b/fuzz/corpus/packet_recv_server/5ae5ca0fe96581d0233f31658d71f255016dcfe8
new file mode 100644
index 0000000..b0a2171
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/5ae5ca0fe96581d0233f31658d71f255016dcfe8
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/5b1413929319ab5a0c3824042f77559805b07109 b/fuzz/corpus/packet_recv_server/5b1413929319ab5a0c3824042f77559805b07109
new file mode 100644
index 0000000..1d29817
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/5b1413929319ab5a0c3824042f77559805b07109
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/5b5c82d2549188c08aab088bbd8ad50d9a8327d1 b/fuzz/corpus/packet_recv_server/5b5c82d2549188c08aab088bbd8ad50d9a8327d1
new file mode 100644
index 0000000..3f36493
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/5b5c82d2549188c08aab088bbd8ad50d9a8327d1
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/5b87c0d735b25e11e2821ed708ba8f8a476c6909 b/fuzz/corpus/packet_recv_server/5b87c0d735b25e11e2821ed708ba8f8a476c6909
new file mode 100644
index 0000000..895d8a8
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/5b87c0d735b25e11e2821ed708ba8f8a476c6909
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/5bef7b3d061c880c37f31959d841ad70d6f01004 b/fuzz/corpus/packet_recv_server/5bef7b3d061c880c37f31959d841ad70d6f01004
new file mode 100644
index 0000000..45cfcb0
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/5bef7b3d061c880c37f31959d841ad70d6f01004
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/5c10553ecb2f8673ffdf3bf0677e06c8f6bd4f73 b/fuzz/corpus/packet_recv_server/5c10553ecb2f8673ffdf3bf0677e06c8f6bd4f73
new file mode 100644
index 0000000..672aab6
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/5c10553ecb2f8673ffdf3bf0677e06c8f6bd4f73
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/5c7f27545a1eebb15e9a7c914131bdf4bdc41802 b/fuzz/corpus/packet_recv_server/5c7f27545a1eebb15e9a7c914131bdf4bdc41802
new file mode 100644
index 0000000..ef4bd8c
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/5c7f27545a1eebb15e9a7c914131bdf4bdc41802
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/5cbb9fee5099b02333c132bdff4bec6cbe9ae585 b/fuzz/corpus/packet_recv_server/5cbb9fee5099b02333c132bdff4bec6cbe9ae585
new file mode 100644
index 0000000..2b7a7af
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/5cbb9fee5099b02333c132bdff4bec6cbe9ae585
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/5cde70dc0f9a5947bff8c970b1d104b4882f9cfa b/fuzz/corpus/packet_recv_server/5cde70dc0f9a5947bff8c970b1d104b4882f9cfa
new file mode 100644
index 0000000..61e88d3
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/5cde70dc0f9a5947bff8c970b1d104b4882f9cfa
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/5d4c3d56866006388a535d0fd1823c3e72e2c1aa b/fuzz/corpus/packet_recv_server/5d4c3d56866006388a535d0fd1823c3e72e2c1aa
new file mode 100644
index 0000000..072029e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/5d4c3d56866006388a535d0fd1823c3e72e2c1aa
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/5daf4d1711e512c3d3d66fa4a3044f56c0d63a01 b/fuzz/corpus/packet_recv_server/5daf4d1711e512c3d3d66fa4a3044f56c0d63a01
new file mode 100644
index 0000000..f5b4d14
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/5daf4d1711e512c3d3d66fa4a3044f56c0d63a01
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/5dcb1218a497b273be557f3d85f2c220c8817e27 b/fuzz/corpus/packet_recv_server/5dcb1218a497b273be557f3d85f2c220c8817e27
new file mode 100644
index 0000000..d4600be
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/5dcb1218a497b273be557f3d85f2c220c8817e27
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/5e1da251e72e1d34a8c67880b95582886aaec63c b/fuzz/corpus/packet_recv_server/5e1da251e72e1d34a8c67880b95582886aaec63c
new file mode 100644
index 0000000..2ef2e00
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/5e1da251e72e1d34a8c67880b95582886aaec63c
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/5f5fbb9a9c602d64f82071f009e16b4bfd9e1334 b/fuzz/corpus/packet_recv_server/5f5fbb9a9c602d64f82071f009e16b4bfd9e1334
new file mode 100644
index 0000000..775c444
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/5f5fbb9a9c602d64f82071f009e16b4bfd9e1334
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/5f66a74a5a4728e60ba05046a7498ed64355be8a b/fuzz/corpus/packet_recv_server/5f66a74a5a4728e60ba05046a7498ed64355be8a
new file mode 100644
index 0000000..b8616c1
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/5f66a74a5a4728e60ba05046a7498ed64355be8a
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/5fd12cfbb23f704341a9ea1ea768e235bdc78e92 b/fuzz/corpus/packet_recv_server/5fd12cfbb23f704341a9ea1ea768e235bdc78e92
new file mode 100644
index 0000000..1cc203d
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/5fd12cfbb23f704341a9ea1ea768e235bdc78e92
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/61c6918e11ee7bc7387bf5d54ecefe4ccdb7063b b/fuzz/corpus/packet_recv_server/61c6918e11ee7bc7387bf5d54ecefe4ccdb7063b
new file mode 100644
index 0000000..d4517a4
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/61c6918e11ee7bc7387bf5d54ecefe4ccdb7063b
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/63cb5dab8b69d5ea256fad0224852037a4d14e5a b/fuzz/corpus/packet_recv_server/63cb5dab8b69d5ea256fad0224852037a4d14e5a
new file mode 100644
index 0000000..bc31c12
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/63cb5dab8b69d5ea256fad0224852037a4d14e5a
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/64390fc4270cd2ee95b57a5d80f1a49220f820a1 b/fuzz/corpus/packet_recv_server/64390fc4270cd2ee95b57a5d80f1a49220f820a1
new file mode 100644
index 0000000..8ddeeee
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/64390fc4270cd2ee95b57a5d80f1a49220f820a1
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/64cedd994a6d50b8390c215468ee53e996be9932 b/fuzz/corpus/packet_recv_server/64cedd994a6d50b8390c215468ee53e996be9932
new file mode 100644
index 0000000..49dcde5
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/64cedd994a6d50b8390c215468ee53e996be9932
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/65c4b02b9da4b41774b5cdb55d25a7a1872b65f6 b/fuzz/corpus/packet_recv_server/65c4b02b9da4b41774b5cdb55d25a7a1872b65f6
new file mode 100644
index 0000000..afccd8e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/65c4b02b9da4b41774b5cdb55d25a7a1872b65f6
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/662aab3330a95f0a6d8b850f845720d20bd5918e b/fuzz/corpus/packet_recv_server/662aab3330a95f0a6d8b850f845720d20bd5918e
new file mode 100644
index 0000000..3dd6758
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/662aab3330a95f0a6d8b850f845720d20bd5918e
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/686d465d163ce3279f3b56dfcc365379ca940d2c b/fuzz/corpus/packet_recv_server/686d465d163ce3279f3b56dfcc365379ca940d2c
new file mode 100644
index 0000000..acd49fa
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/686d465d163ce3279f3b56dfcc365379ca940d2c
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/68c9c8783e6d1aea2b87407b5bba0b3ff5185cb9 b/fuzz/corpus/packet_recv_server/68c9c8783e6d1aea2b87407b5bba0b3ff5185cb9
new file mode 100644
index 0000000..a6118c3
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/68c9c8783e6d1aea2b87407b5bba0b3ff5185cb9
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/695022107de1e32eff92620f0f660924703cac27 b/fuzz/corpus/packet_recv_server/695022107de1e32eff92620f0f660924703cac27
new file mode 100644
index 0000000..257100c
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/695022107de1e32eff92620f0f660924703cac27
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/6985fe8b88bba4d35dc9f590433aec77889cb9a8 b/fuzz/corpus/packet_recv_server/6985fe8b88bba4d35dc9f590433aec77889cb9a8
new file mode 100644
index 0000000..6561d95
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/6985fe8b88bba4d35dc9f590433aec77889cb9a8
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/6c005f0a68bf2c993cd48b240c5c73253e59be0d b/fuzz/corpus/packet_recv_server/6c005f0a68bf2c993cd48b240c5c73253e59be0d
new file mode 100644
index 0000000..31a3111
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/6c005f0a68bf2c993cd48b240c5c73253e59be0d
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/6cd3c9621358c0aae8eff3bdb6021d5c71546396 b/fuzz/corpus/packet_recv_server/6cd3c9621358c0aae8eff3bdb6021d5c71546396
new file mode 100644
index 0000000..65e0a74
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/6cd3c9621358c0aae8eff3bdb6021d5c71546396
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/6d09033d9cabf4be617ebcd83cd8170e7f91720a b/fuzz/corpus/packet_recv_server/6d09033d9cabf4be617ebcd83cd8170e7f91720a
new file mode 100644
index 0000000..4f1c9e8
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/6d09033d9cabf4be617ebcd83cd8170e7f91720a
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/6df463624931f8fce82043e6e75f85d5385d86c0 b/fuzz/corpus/packet_recv_server/6df463624931f8fce82043e6e75f85d5385d86c0
new file mode 100644
index 0000000..f8f5120
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/6df463624931f8fce82043e6e75f85d5385d86c0
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/6e39cfe31098e8af4d454f993486f696dd840326 b/fuzz/corpus/packet_recv_server/6e39cfe31098e8af4d454f993486f696dd840326
new file mode 100644
index 0000000..c6bc9f6
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/6e39cfe31098e8af4d454f993486f696dd840326
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/6f56c073676e1bbdbe402d375efc78f2f2352dca b/fuzz/corpus/packet_recv_server/6f56c073676e1bbdbe402d375efc78f2f2352dca
new file mode 100644
index 0000000..75f3183
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/6f56c073676e1bbdbe402d375efc78f2f2352dca
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/6f75adef2c6d06063e2322c56e1fb9e5587f8b5a b/fuzz/corpus/packet_recv_server/6f75adef2c6d06063e2322c56e1fb9e5587f8b5a
new file mode 100644
index 0000000..910127c
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/6f75adef2c6d06063e2322c56e1fb9e5587f8b5a
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/7159ee7c2e39c40713ecdd132ab33aa35666f476 b/fuzz/corpus/packet_recv_server/7159ee7c2e39c40713ecdd132ab33aa35666f476
new file mode 100644
index 0000000..84a8ba5
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/7159ee7c2e39c40713ecdd132ab33aa35666f476
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/7192f7208419bd726475a2d998f0350d0183b1c9 b/fuzz/corpus/packet_recv_server/7192f7208419bd726475a2d998f0350d0183b1c9
new file mode 100644
index 0000000..a3dd5a6
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/7192f7208419bd726475a2d998f0350d0183b1c9
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/72011084b1fc4d45569ac926051a986bcc9eed58 b/fuzz/corpus/packet_recv_server/72011084b1fc4d45569ac926051a986bcc9eed58
new file mode 100644
index 0000000..ded75ab
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/72011084b1fc4d45569ac926051a986bcc9eed58
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/7242449b742eb3beea347bd9f1efa92e8a511450 b/fuzz/corpus/packet_recv_server/7242449b742eb3beea347bd9f1efa92e8a511450
new file mode 100644
index 0000000..ed987c9
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/7242449b742eb3beea347bd9f1efa92e8a511450
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/72aa230a43702c106b5be51552c8ca033928b328 b/fuzz/corpus/packet_recv_server/72aa230a43702c106b5be51552c8ca033928b328
new file mode 100644
index 0000000..4d7bbaa
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/72aa230a43702c106b5be51552c8ca033928b328
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/7302a5bb17246f4c2f611d39a45f25e799b2dac1 b/fuzz/corpus/packet_recv_server/7302a5bb17246f4c2f611d39a45f25e799b2dac1
new file mode 100644
index 0000000..ef5d909
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/7302a5bb17246f4c2f611d39a45f25e799b2dac1
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/7414f8969e5237eb266b899197d512abc51396bb b/fuzz/corpus/packet_recv_server/7414f8969e5237eb266b899197d512abc51396bb
new file mode 100644
index 0000000..5670bc1
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/7414f8969e5237eb266b899197d512abc51396bb
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/749bc55f7525891f8087989567f791c28132df5b b/fuzz/corpus/packet_recv_server/749bc55f7525891f8087989567f791c28132df5b
new file mode 100644
index 0000000..2acd116
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/749bc55f7525891f8087989567f791c28132df5b
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/74eba5387f166bc5782ed8a7113d4d7ae039ecdc b/fuzz/corpus/packet_recv_server/74eba5387f166bc5782ed8a7113d4d7ae039ecdc
new file mode 100644
index 0000000..d350c03
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/74eba5387f166bc5782ed8a7113d4d7ae039ecdc
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/761799cd548dbfbc3d09156dd9db442cbdaa11fc b/fuzz/corpus/packet_recv_server/761799cd548dbfbc3d09156dd9db442cbdaa11fc
new file mode 100644
index 0000000..30df81c
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/761799cd548dbfbc3d09156dd9db442cbdaa11fc
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/780553773bff220555e65dc21e0f92555fe927b4 b/fuzz/corpus/packet_recv_server/780553773bff220555e65dc21e0f92555fe927b4
new file mode 100644
index 0000000..c813cdc
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/780553773bff220555e65dc21e0f92555fe927b4
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/787bef1f01133454c80c267bded9d23a84b7b8a2 b/fuzz/corpus/packet_recv_server/787bef1f01133454c80c267bded9d23a84b7b8a2
new file mode 100644
index 0000000..2213b67
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/787bef1f01133454c80c267bded9d23a84b7b8a2
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/79cbee276e027683c8a7d5e52dce0c1d145190b2 b/fuzz/corpus/packet_recv_server/79cbee276e027683c8a7d5e52dce0c1d145190b2
new file mode 100644
index 0000000..3ac62cf
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/79cbee276e027683c8a7d5e52dce0c1d145190b2
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/7a585168376510de22390fe53dc7442d58c9b5b1 b/fuzz/corpus/packet_recv_server/7a585168376510de22390fe53dc7442d58c9b5b1
new file mode 100644
index 0000000..dfbc1b5
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/7a585168376510de22390fe53dc7442d58c9b5b1
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/7ce83b5207edf57bee6f363324e1a50231a7a1af b/fuzz/corpus/packet_recv_server/7ce83b5207edf57bee6f363324e1a50231a7a1af
new file mode 100644
index 0000000..ca3dc19
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/7ce83b5207edf57bee6f363324e1a50231a7a1af
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/7d472e079c4a3b9fa84d23c1413279104f8c2505 b/fuzz/corpus/packet_recv_server/7d472e079c4a3b9fa84d23c1413279104f8c2505
new file mode 100644
index 0000000..dc020c5
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/7d472e079c4a3b9fa84d23c1413279104f8c2505
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/7d63f774e67685d514d2518d95b8e9e061c94013 b/fuzz/corpus/packet_recv_server/7d63f774e67685d514d2518d95b8e9e061c94013
new file mode 100644
index 0000000..448160b
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/7d63f774e67685d514d2518d95b8e9e061c94013
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/7dcbd340ccddc99b41a709eec0e3d05b6cc28c04 b/fuzz/corpus/packet_recv_server/7dcbd340ccddc99b41a709eec0e3d05b6cc28c04
new file mode 100644
index 0000000..c9124ce
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/7dcbd340ccddc99b41a709eec0e3d05b6cc28c04
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/7e3c38d02552017d5c67482889f30e58977b1750 b/fuzz/corpus/packet_recv_server/7e3c38d02552017d5c67482889f30e58977b1750
new file mode 100644
index 0000000..80c299d
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/7e3c38d02552017d5c67482889f30e58977b1750
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/7f7375dbfecd046deea52b3a1272ab0ac25fef7b b/fuzz/corpus/packet_recv_server/7f7375dbfecd046deea52b3a1272ab0ac25fef7b
new file mode 100644
index 0000000..d6e482d
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/7f7375dbfecd046deea52b3a1272ab0ac25fef7b
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/7fbeeff368d17a5dee11ddd3a818fdd5749f3aa8 b/fuzz/corpus/packet_recv_server/7fbeeff368d17a5dee11ddd3a818fdd5749f3aa8
new file mode 100644
index 0000000..26383af
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/7fbeeff368d17a5dee11ddd3a818fdd5749f3aa8
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/804a558727da1a082bd53078f6ab7d0d8768b7ee b/fuzz/corpus/packet_recv_server/804a558727da1a082bd53078f6ab7d0d8768b7ee
new file mode 100644
index 0000000..7f6cfba
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/804a558727da1a082bd53078f6ab7d0d8768b7ee
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/804d40a26a39c1b826330625e374e40d50620943 b/fuzz/corpus/packet_recv_server/804d40a26a39c1b826330625e374e40d50620943
new file mode 100644
index 0000000..2ab076c
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/804d40a26a39c1b826330625e374e40d50620943
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/80d7033d429db49a5413641ea7ea2bec24299a9b b/fuzz/corpus/packet_recv_server/80d7033d429db49a5413641ea7ea2bec24299a9b
new file mode 100644
index 0000000..8258d01
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/80d7033d429db49a5413641ea7ea2bec24299a9b
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/8150e6da52ba5791f91d9be39735d9950b94e1b1 b/fuzz/corpus/packet_recv_server/8150e6da52ba5791f91d9be39735d9950b94e1b1
new file mode 100644
index 0000000..72254fb
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/8150e6da52ba5791f91d9be39735d9950b94e1b1
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/83101d3d529af36d061cad6b3fe722cdc4083c76 b/fuzz/corpus/packet_recv_server/83101d3d529af36d061cad6b3fe722cdc4083c76
new file mode 100644
index 0000000..c10bcf2
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/83101d3d529af36d061cad6b3fe722cdc4083c76
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/831cc3e5de9a0a2b7fc2b97c80c1af7d20fca4bd b/fuzz/corpus/packet_recv_server/831cc3e5de9a0a2b7fc2b97c80c1af7d20fca4bd
new file mode 100644
index 0000000..5499853
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/831cc3e5de9a0a2b7fc2b97c80c1af7d20fca4bd
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/832e9a95acf57286b838e48cb49a548633764c26 b/fuzz/corpus/packet_recv_server/832e9a95acf57286b838e48cb49a548633764c26
new file mode 100644
index 0000000..926a3cb
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/832e9a95acf57286b838e48cb49a548633764c26
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/832f7ab909d6fbcf1ea838478763a55f072924da b/fuzz/corpus/packet_recv_server/832f7ab909d6fbcf1ea838478763a55f072924da
new file mode 100644
index 0000000..8cdf53e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/832f7ab909d6fbcf1ea838478763a55f072924da
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/84942c590583ad85e867bf80dc3c15d8a742625d b/fuzz/corpus/packet_recv_server/84942c590583ad85e867bf80dc3c15d8a742625d
new file mode 100644
index 0000000..07fd7f6
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/84942c590583ad85e867bf80dc3c15d8a742625d
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/8574d95bbbfbcde5d4a6dc60892da7c9a39ee26a b/fuzz/corpus/packet_recv_server/8574d95bbbfbcde5d4a6dc60892da7c9a39ee26a
new file mode 100644
index 0000000..64c25a8
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/8574d95bbbfbcde5d4a6dc60892da7c9a39ee26a
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/85a9aaa692d50df2b6d6e21806fac5693ef76dcd b/fuzz/corpus/packet_recv_server/85a9aaa692d50df2b6d6e21806fac5693ef76dcd
new file mode 100644
index 0000000..f222725
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/85a9aaa692d50df2b6d6e21806fac5693ef76dcd
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/86096ff2bc6cff213c691d62e2dc99c38028120a b/fuzz/corpus/packet_recv_server/86096ff2bc6cff213c691d62e2dc99c38028120a
new file mode 100644
index 0000000..b263a01
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/86096ff2bc6cff213c691d62e2dc99c38028120a
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/863610b481241fe33ed04e205319cd4800472071 b/fuzz/corpus/packet_recv_server/863610b481241fe33ed04e205319cd4800472071
new file mode 100644
index 0000000..0bd692f
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/863610b481241fe33ed04e205319cd4800472071
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/867ac8cfda943798ab8790cf08e40b1b686c330f b/fuzz/corpus/packet_recv_server/867ac8cfda943798ab8790cf08e40b1b686c330f
new file mode 100644
index 0000000..28a09ca
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/867ac8cfda943798ab8790cf08e40b1b686c330f
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/869d29db8aa47a14561f1b0004b311450b1f70a3 b/fuzz/corpus/packet_recv_server/869d29db8aa47a14561f1b0004b311450b1f70a3
new file mode 100644
index 0000000..a4a8dca
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/869d29db8aa47a14561f1b0004b311450b1f70a3
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/897df083689c12fcc31bb638dda0bfcbb5b116d8 b/fuzz/corpus/packet_recv_server/897df083689c12fcc31bb638dda0bfcbb5b116d8
new file mode 100644
index 0000000..e084250
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/897df083689c12fcc31bb638dda0bfcbb5b116d8
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/8b31bbb9500a3a27a62afd0bb491834d4874c0f3 b/fuzz/corpus/packet_recv_server/8b31bbb9500a3a27a62afd0bb491834d4874c0f3
new file mode 100644
index 0000000..56ffdee
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/8b31bbb9500a3a27a62afd0bb491834d4874c0f3
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/8b3322b22a978d3316c16dd9448964c4635f3b21 b/fuzz/corpus/packet_recv_server/8b3322b22a978d3316c16dd9448964c4635f3b21
new file mode 100644
index 0000000..22f0165
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/8b3322b22a978d3316c16dd9448964c4635f3b21
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/8bab95d756fdfe6e392c07bd9251599723f5d206 b/fuzz/corpus/packet_recv_server/8bab95d756fdfe6e392c07bd9251599723f5d206
new file mode 100644
index 0000000..1c8ef33
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/8bab95d756fdfe6e392c07bd9251599723f5d206
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/8d131405138fdf60fdc6d205a44fc0dedf9bf703 b/fuzz/corpus/packet_recv_server/8d131405138fdf60fdc6d205a44fc0dedf9bf703
new file mode 100644
index 0000000..8c43b81
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/8d131405138fdf60fdc6d205a44fc0dedf9bf703
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/8d1ec8d952b18d525c995252cf09f11fbfc479c4 b/fuzz/corpus/packet_recv_server/8d1ec8d952b18d525c995252cf09f11fbfc479c4
new file mode 100644
index 0000000..fd1f3c3
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/8d1ec8d952b18d525c995252cf09f11fbfc479c4
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/8e025c150df6fea3f41c33edc7c1b3fd6a512669 b/fuzz/corpus/packet_recv_server/8e025c150df6fea3f41c33edc7c1b3fd6a512669
new file mode 100644
index 0000000..5a77339
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/8e025c150df6fea3f41c33edc7c1b3fd6a512669
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/8edb45eea9d85576ae612574f8d1a097b2c8862e b/fuzz/corpus/packet_recv_server/8edb45eea9d85576ae612574f8d1a097b2c8862e
new file mode 100644
index 0000000..fa86402
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/8edb45eea9d85576ae612574f8d1a097b2c8862e
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/8f5a00be8a927fa040ae2811cd30fcb80e82b62b b/fuzz/corpus/packet_recv_server/8f5a00be8a927fa040ae2811cd30fcb80e82b62b
new file mode 100644
index 0000000..c8d2852
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/8f5a00be8a927fa040ae2811cd30fcb80e82b62b
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/8feac614720dac4afc5a156c0eaee8616be4919c b/fuzz/corpus/packet_recv_server/8feac614720dac4afc5a156c0eaee8616be4919c
new file mode 100644
index 0000000..29d0c2d
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/8feac614720dac4afc5a156c0eaee8616be4919c
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/9033992c183fd2cbd111dafe897c262309ce4b51 b/fuzz/corpus/packet_recv_server/9033992c183fd2cbd111dafe897c262309ce4b51
new file mode 100644
index 0000000..0a146b1
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/9033992c183fd2cbd111dafe897c262309ce4b51
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/90edec34d08bc15a2ba4e75e1f81e8e4d9148c71 b/fuzz/corpus/packet_recv_server/90edec34d08bc15a2ba4e75e1f81e8e4d9148c71
new file mode 100644
index 0000000..7903ecd
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/90edec34d08bc15a2ba4e75e1f81e8e4d9148c71
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/9105bbf68b549c00a0c72f9fef481ad785c92004 b/fuzz/corpus/packet_recv_server/9105bbf68b549c00a0c72f9fef481ad785c92004
new file mode 100644
index 0000000..20fd41c
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/9105bbf68b549c00a0c72f9fef481ad785c92004
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/91c7dab5baf2de5615bf449d0c5eeae81bfba584 b/fuzz/corpus/packet_recv_server/91c7dab5baf2de5615bf449d0c5eeae81bfba584
new file mode 100644
index 0000000..456ab79
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/91c7dab5baf2de5615bf449d0c5eeae81bfba584
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/929fc5673b96ad76696f56465b25e01ae6594114 b/fuzz/corpus/packet_recv_server/929fc5673b96ad76696f56465b25e01ae6594114
new file mode 100644
index 0000000..36c603e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/929fc5673b96ad76696f56465b25e01ae6594114
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/92f1c286df5a1373460ddbca96c2799e4877a447 b/fuzz/corpus/packet_recv_server/92f1c286df5a1373460ddbca96c2799e4877a447
new file mode 100644
index 0000000..357ed2d
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/92f1c286df5a1373460ddbca96c2799e4877a447
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/930e4a91e7e3a3d229ebd0a5d0ff88fe3d016b4f b/fuzz/corpus/packet_recv_server/930e4a91e7e3a3d229ebd0a5d0ff88fe3d016b4f
new file mode 100644
index 0000000..caf1592
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/930e4a91e7e3a3d229ebd0a5d0ff88fe3d016b4f
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/9575e6f216f3eeed4fb40329c3b51e12c1f0089e b/fuzz/corpus/packet_recv_server/9575e6f216f3eeed4fb40329c3b51e12c1f0089e
new file mode 100644
index 0000000..c7c370c
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/9575e6f216f3eeed4fb40329c3b51e12c1f0089e
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/95d3ca18d059e011b19a0ad120721cd69ac00db6 b/fuzz/corpus/packet_recv_server/95d3ca18d059e011b19a0ad120721cd69ac00db6
new file mode 100644
index 0000000..08f2080
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/95d3ca18d059e011b19a0ad120721cd69ac00db6
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/9771a862a292840167ac7b5b9d785c3e46d85d9c b/fuzz/corpus/packet_recv_server/9771a862a292840167ac7b5b9d785c3e46d85d9c
new file mode 100644
index 0000000..c861b2a
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/9771a862a292840167ac7b5b9d785c3e46d85d9c
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/98b63c9e1a1b6a3f3cb18392e152f3b5daaa6718 b/fuzz/corpus/packet_recv_server/98b63c9e1a1b6a3f3cb18392e152f3b5daaa6718
new file mode 100644
index 0000000..dd787c4
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/98b63c9e1a1b6a3f3cb18392e152f3b5daaa6718
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/9991c5adae53b07d22f18eb7697442003c330ddf b/fuzz/corpus/packet_recv_server/9991c5adae53b07d22f18eb7697442003c330ddf
new file mode 100644
index 0000000..976284f
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/9991c5adae53b07d22f18eb7697442003c330ddf
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/99d5b25158766824e300a2a9d2c3df14f5182ab4 b/fuzz/corpus/packet_recv_server/99d5b25158766824e300a2a9d2c3df14f5182ab4
new file mode 100644
index 0000000..c5c44be
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/99d5b25158766824e300a2a9d2c3df14f5182ab4
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/9b532cae1ba25658b7725e4a2cbb4125b4cf45e8 b/fuzz/corpus/packet_recv_server/9b532cae1ba25658b7725e4a2cbb4125b4cf45e8
new file mode 100644
index 0000000..c84018b
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/9b532cae1ba25658b7725e4a2cbb4125b4cf45e8
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/9b861b568e6a2df09f8bdac4b0554f0a52ded820 b/fuzz/corpus/packet_recv_server/9b861b568e6a2df09f8bdac4b0554f0a52ded820
new file mode 100644
index 0000000..7bb73db
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/9b861b568e6a2df09f8bdac4b0554f0a52ded820
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/9bb5779a4796d3c11581dc084907ebe4f9e9453e b/fuzz/corpus/packet_recv_server/9bb5779a4796d3c11581dc084907ebe4f9e9453e
new file mode 100644
index 0000000..1ec84f0
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/9bb5779a4796d3c11581dc084907ebe4f9e9453e
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/9bf8b9e4d4b331e0b39da8367e2fcfe9304cec9f b/fuzz/corpus/packet_recv_server/9bf8b9e4d4b331e0b39da8367e2fcfe9304cec9f
new file mode 100644
index 0000000..4289fb5
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/9bf8b9e4d4b331e0b39da8367e2fcfe9304cec9f
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/9c68dee4925305f092c3a620310c1decd9489a48 b/fuzz/corpus/packet_recv_server/9c68dee4925305f092c3a620310c1decd9489a48
new file mode 100644
index 0000000..8bfd4a7
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/9c68dee4925305f092c3a620310c1decd9489a48
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/9d1c988bc0b3988054f4029ed3b104d9963aa0f1 b/fuzz/corpus/packet_recv_server/9d1c988bc0b3988054f4029ed3b104d9963aa0f1
new file mode 100644
index 0000000..193681a
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/9d1c988bc0b3988054f4029ed3b104d9963aa0f1
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/9df5ce89be9eeb318e4ad6a44ec351422ddf88ab b/fuzz/corpus/packet_recv_server/9df5ce89be9eeb318e4ad6a44ec351422ddf88ab
new file mode 100644
index 0000000..957b28d
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/9df5ce89be9eeb318e4ad6a44ec351422ddf88ab
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/9fa947d891256dacdd01bf31898818a1d6b66cb8 b/fuzz/corpus/packet_recv_server/9fa947d891256dacdd01bf31898818a1d6b66cb8
new file mode 100644
index 0000000..1b026ac
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/9fa947d891256dacdd01bf31898818a1d6b66cb8
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/9feaecddced8936fa786ade9ef3dcd60bc7a44c8 b/fuzz/corpus/packet_recv_server/9feaecddced8936fa786ade9ef3dcd60bc7a44c8
new file mode 100644
index 0000000..07f092b
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/9feaecddced8936fa786ade9ef3dcd60bc7a44c8
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/a08e575f349c5669af7a2b616543dd7ae0ca4cc8 b/fuzz/corpus/packet_recv_server/a08e575f349c5669af7a2b616543dd7ae0ca4cc8
new file mode 100644
index 0000000..5b8a76f
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/a08e575f349c5669af7a2b616543dd7ae0ca4cc8
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/a176e2db9bab990b017a6d4fdd420c3a45a6e3b2 b/fuzz/corpus/packet_recv_server/a176e2db9bab990b017a6d4fdd420c3a45a6e3b2
new file mode 100644
index 0000000..2cfa236
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/a176e2db9bab990b017a6d4fdd420c3a45a6e3b2
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/a278ef7b32b6b622361343e9147adf849638ee5b b/fuzz/corpus/packet_recv_server/a278ef7b32b6b622361343e9147adf849638ee5b
new file mode 100644
index 0000000..1fb196e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/a278ef7b32b6b622361343e9147adf849638ee5b
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/a28fbf7656f2b702484581c0e4c3fe2f41897c13 b/fuzz/corpus/packet_recv_server/a28fbf7656f2b702484581c0e4c3fe2f41897c13
new file mode 100644
index 0000000..b4a31cc
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/a28fbf7656f2b702484581c0e4c3fe2f41897c13
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/a2d3497cd301f28e2e90ccacd1fc877ff47396ab b/fuzz/corpus/packet_recv_server/a2d3497cd301f28e2e90ccacd1fc877ff47396ab
new file mode 100644
index 0000000..99c33ba
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/a2d3497cd301f28e2e90ccacd1fc877ff47396ab
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/a3637e1c950dbb0f289a9e23950e670ef932d988 b/fuzz/corpus/packet_recv_server/a3637e1c950dbb0f289a9e23950e670ef932d988
new file mode 100644
index 0000000..c6d747d
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/a3637e1c950dbb0f289a9e23950e670ef932d988
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/a5e42b39022086b79a70dc3d360d6f4f2cb214ee b/fuzz/corpus/packet_recv_server/a5e42b39022086b79a70dc3d360d6f4f2cb214ee
new file mode 100644
index 0000000..54f6444
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/a5e42b39022086b79a70dc3d360d6f4f2cb214ee
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/a6bd5d11c85a2e2a183696b96f38ba14e20c57df b/fuzz/corpus/packet_recv_server/a6bd5d11c85a2e2a183696b96f38ba14e20c57df
new file mode 100644
index 0000000..012d279
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/a6bd5d11c85a2e2a183696b96f38ba14e20c57df
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/a6cdee244f7a11ef371bc3559184855966235000 b/fuzz/corpus/packet_recv_server/a6cdee244f7a11ef371bc3559184855966235000
new file mode 100644
index 0000000..8d4b657
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/a6cdee244f7a11ef371bc3559184855966235000
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/a6d1c873cb9a37cb670e1e167871dd5d6f710759 b/fuzz/corpus/packet_recv_server/a6d1c873cb9a37cb670e1e167871dd5d6f710759
new file mode 100644
index 0000000..773127f
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/a6d1c873cb9a37cb670e1e167871dd5d6f710759
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/a7300997c810cdb8e9eaa2e39e5fd47cc89577b0 b/fuzz/corpus/packet_recv_server/a7300997c810cdb8e9eaa2e39e5fd47cc89577b0
new file mode 100644
index 0000000..1387d7b
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/a7300997c810cdb8e9eaa2e39e5fd47cc89577b0
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/a7f3e7e56a6801f8b36c358ce38c8494f6b4553f b/fuzz/corpus/packet_recv_server/a7f3e7e56a6801f8b36c358ce38c8494f6b4553f
new file mode 100644
index 0000000..8b2fadb
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/a7f3e7e56a6801f8b36c358ce38c8494f6b4553f
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/aa04f99fbf88b71ced4c39f65661590607e1df7e b/fuzz/corpus/packet_recv_server/aa04f99fbf88b71ced4c39f65661590607e1df7e
new file mode 100644
index 0000000..82c6c64
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/aa04f99fbf88b71ced4c39f65661590607e1df7e
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/aa29ba1720bcf4ecce12844858b7006b7b0cde93 b/fuzz/corpus/packet_recv_server/aa29ba1720bcf4ecce12844858b7006b7b0cde93
new file mode 100644
index 0000000..3b483de
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/aa29ba1720bcf4ecce12844858b7006b7b0cde93
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/aade746913e9504bd7f11c1083a7dda100addb8f b/fuzz/corpus/packet_recv_server/aade746913e9504bd7f11c1083a7dda100addb8f
new file mode 100644
index 0000000..f31fe46
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/aade746913e9504bd7f11c1083a7dda100addb8f
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ac1715ad3199f513fb0440e11ea69cddbd67fe7c b/fuzz/corpus/packet_recv_server/ac1715ad3199f513fb0440e11ea69cddbd67fe7c
new file mode 100644
index 0000000..3878082
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ac1715ad3199f513fb0440e11ea69cddbd67fe7c
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ac177b954b2e984dbed4d86e0453926723279364 b/fuzz/corpus/packet_recv_server/ac177b954b2e984dbed4d86e0453926723279364
new file mode 100644
index 0000000..5ee30d6
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ac177b954b2e984dbed4d86e0453926723279364
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ac9231da4082430afe8f4d40127814c613648d8e b/fuzz/corpus/packet_recv_server/ac9231da4082430afe8f4d40127814c613648d8e
new file mode 100644
index 0000000..501a6bb
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ac9231da4082430afe8f4d40127814c613648d8e
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/fuzz/corpus/packet_recv_server/ad1df59fe9a1f4485582a42307709a941c9f371b b/fuzz/corpus/packet_recv_server/ad1df59fe9a1f4485582a42307709a941c9f371b
new file mode 100644
index 0000000..09363be
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ad1df59fe9a1f4485582a42307709a941c9f371b
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ad5dbd53448071d65ff237ab19af7fc87342d5a7 b/fuzz/corpus/packet_recv_server/ad5dbd53448071d65ff237ab19af7fc87342d5a7
new file mode 100644
index 0000000..00f488e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ad5dbd53448071d65ff237ab19af7fc87342d5a7
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ad781a92300b34cd7fdcc513c80f41cb00325f4c b/fuzz/corpus/packet_recv_server/ad781a92300b34cd7fdcc513c80f41cb00325f4c
new file mode 100644
index 0000000..654f5c4
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ad781a92300b34cd7fdcc513c80f41cb00325f4c
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/af391c579e972050e464e2e855f37dd3cd03d356 b/fuzz/corpus/packet_recv_server/af391c579e972050e464e2e855f37dd3cd03d356
new file mode 100644
index 0000000..2ee0ea8
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/af391c579e972050e464e2e855f37dd3cd03d356
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/b06848905a4adc77d2baaee13ffb459674dfda1e b/fuzz/corpus/packet_recv_server/b06848905a4adc77d2baaee13ffb459674dfda1e
new file mode 100644
index 0000000..3aa2c42
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/b06848905a4adc77d2baaee13ffb459674dfda1e
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/b094bfc273f56196f602551a1dc7b1a0461b417a b/fuzz/corpus/packet_recv_server/b094bfc273f56196f602551a1dc7b1a0461b417a
new file mode 100644
index 0000000..e767820
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/b094bfc273f56196f602551a1dc7b1a0461b417a
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/b0caf7e36ee986506b77316014f88e7ea599b889 b/fuzz/corpus/packet_recv_server/b0caf7e36ee986506b77316014f88e7ea599b889
new file mode 100644
index 0000000..946b10d
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/b0caf7e36ee986506b77316014f88e7ea599b889
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/b18edf440386451fc81c918acad1254435975bc8 b/fuzz/corpus/packet_recv_server/b18edf440386451fc81c918acad1254435975bc8
new file mode 100644
index 0000000..460442b
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/b18edf440386451fc81c918acad1254435975bc8
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/b256fc26a40c85e89defd85e45ea43b404981139 b/fuzz/corpus/packet_recv_server/b256fc26a40c85e89defd85e45ea43b404981139
new file mode 100644
index 0000000..4eef9a1
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/b256fc26a40c85e89defd85e45ea43b404981139
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/b2777c60586058f0f233bd1a08fec0e001f58e0c b/fuzz/corpus/packet_recv_server/b2777c60586058f0f233bd1a08fec0e001f58e0c
new file mode 100644
index 0000000..297630d
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/b2777c60586058f0f233bd1a08fec0e001f58e0c
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/b3ee80bc95574a4c653d0498ebdb76ef2b01442f b/fuzz/corpus/packet_recv_server/b3ee80bc95574a4c653d0498ebdb76ef2b01442f
new file mode 100644
index 0000000..f593a43
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/b3ee80bc95574a4c653d0498ebdb76ef2b01442f
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/b402e76b1527c966d8a32e9842009a568ab7ef15 b/fuzz/corpus/packet_recv_server/b402e76b1527c966d8a32e9842009a568ab7ef15
new file mode 100644
index 0000000..f894e19
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/b402e76b1527c966d8a32e9842009a568ab7ef15
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/b43497b4fae93508de7bf36e9d7a1d5fa02d4b6d b/fuzz/corpus/packet_recv_server/b43497b4fae93508de7bf36e9d7a1d5fa02d4b6d
new file mode 100644
index 0000000..7830fb6
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/b43497b4fae93508de7bf36e9d7a1d5fa02d4b6d
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/b505034ce9464f0d09fc9d049c075115fc275691 b/fuzz/corpus/packet_recv_server/b505034ce9464f0d09fc9d049c075115fc275691
new file mode 100644
index 0000000..2ab5b47
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/b505034ce9464f0d09fc9d049c075115fc275691
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/b518b07ab1ce06f73d80c9c89975bebd49843b62 b/fuzz/corpus/packet_recv_server/b518b07ab1ce06f73d80c9c89975bebd49843b62
new file mode 100644
index 0000000..11c8faa
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/b518b07ab1ce06f73d80c9c89975bebd49843b62
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/b67d72f9fd6fffc390c414315db788e9e918adc4 b/fuzz/corpus/packet_recv_server/b67d72f9fd6fffc390c414315db788e9e918adc4
new file mode 100644
index 0000000..f23eb35
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/b67d72f9fd6fffc390c414315db788e9e918adc4
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/b856f3f867e0d7d54a07450b510fe0220d05fdf6 b/fuzz/corpus/packet_recv_server/b856f3f867e0d7d54a07450b510fe0220d05fdf6
new file mode 100644
index 0000000..795a1cc
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/b856f3f867e0d7d54a07450b510fe0220d05fdf6
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/b95da898ccfb427f4c6887019bc92b4503a5d327 b/fuzz/corpus/packet_recv_server/b95da898ccfb427f4c6887019bc92b4503a5d327
new file mode 100644
index 0000000..cd7796c
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/b95da898ccfb427f4c6887019bc92b4503a5d327
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/b98fbda8aa5fd0590d5fb45237f3de5caa7fe3a8 b/fuzz/corpus/packet_recv_server/b98fbda8aa5fd0590d5fb45237f3de5caa7fe3a8
new file mode 100644
index 0000000..78ade8a
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/b98fbda8aa5fd0590d5fb45237f3de5caa7fe3a8
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ba79439d8fccd33f389ebbcdde21aa0760423957 b/fuzz/corpus/packet_recv_server/ba79439d8fccd33f389ebbcdde21aa0760423957
new file mode 100644
index 0000000..782d733
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ba79439d8fccd33f389ebbcdde21aa0760423957
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/bbe06ad001fe8339b1195ae12e3effcf03048f97 b/fuzz/corpus/packet_recv_server/bbe06ad001fe8339b1195ae12e3effcf03048f97
new file mode 100644
index 0000000..c2bf019
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/bbe06ad001fe8339b1195ae12e3effcf03048f97
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/bc31ed728ee5f134004f08f0379422ba3f7c69ed b/fuzz/corpus/packet_recv_server/bc31ed728ee5f134004f08f0379422ba3f7c69ed
new file mode 100644
index 0000000..ddddb39
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/bc31ed728ee5f134004f08f0379422ba3f7c69ed
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/bcef228a5c81ac722fb8162da6bd061241b80b7e b/fuzz/corpus/packet_recv_server/bcef228a5c81ac722fb8162da6bd061241b80b7e
new file mode 100644
index 0000000..8b9f0c8
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/bcef228a5c81ac722fb8162da6bd061241b80b7e
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/bcf2fb4c5c563d07580fa266963363e5caa2ff11 b/fuzz/corpus/packet_recv_server/bcf2fb4c5c563d07580fa266963363e5caa2ff11
new file mode 100644
index 0000000..3f8b164
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/bcf2fb4c5c563d07580fa266963363e5caa2ff11
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/bd67f7afe3d2eeb636ae70e0676b5bd9f3cd2cfa b/fuzz/corpus/packet_recv_server/bd67f7afe3d2eeb636ae70e0676b5bd9f3cd2cfa
new file mode 100644
index 0000000..685e340
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/bd67f7afe3d2eeb636ae70e0676b5bd9f3cd2cfa
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/c02e90f36b6f519af145228a67b3afa7cf7dc196 b/fuzz/corpus/packet_recv_server/c02e90f36b6f519af145228a67b3afa7cf7dc196
new file mode 100644
index 0000000..dd30de2
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/c02e90f36b6f519af145228a67b3afa7cf7dc196
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/c294a6480437b105c2d20f289169ce533eac50aa b/fuzz/corpus/packet_recv_server/c294a6480437b105c2d20f289169ce533eac50aa
new file mode 100644
index 0000000..af50240
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/c294a6480437b105c2d20f289169ce533eac50aa
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/c2ad5674c5ceea9394b352524c84d29e1e50c1d4 b/fuzz/corpus/packet_recv_server/c2ad5674c5ceea9394b352524c84d29e1e50c1d4
new file mode 100644
index 0000000..94f094c
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/c2ad5674c5ceea9394b352524c84d29e1e50c1d4
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/c3664857957ff3f446ee3d3ce91c58391744d3d2 b/fuzz/corpus/packet_recv_server/c3664857957ff3f446ee3d3ce91c58391744d3d2
new file mode 100644
index 0000000..f0e868e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/c3664857957ff3f446ee3d3ce91c58391744d3d2
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/c3a528a3faaa58ce92bb855c17b891d2cd93da2c b/fuzz/corpus/packet_recv_server/c3a528a3faaa58ce92bb855c17b891d2cd93da2c
new file mode 100644
index 0000000..3141d63
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/c3a528a3faaa58ce92bb855c17b891d2cd93da2c
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/c3c3d974ddbfda6ea5fc6b241bc8bf9d04b0b543 b/fuzz/corpus/packet_recv_server/c3c3d974ddbfda6ea5fc6b241bc8bf9d04b0b543
new file mode 100644
index 0000000..6a03376
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/c3c3d974ddbfda6ea5fc6b241bc8bf9d04b0b543
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/c51653e6d001f7a023623682e3cbde0a9e2b4e6c b/fuzz/corpus/packet_recv_server/c51653e6d001f7a023623682e3cbde0a9e2b4e6c
new file mode 100644
index 0000000..0c82c81
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/c51653e6d001f7a023623682e3cbde0a9e2b4e6c
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/c579cd6b62815e6fb6f4eacb62969923a5f85e84 b/fuzz/corpus/packet_recv_server/c579cd6b62815e6fb6f4eacb62969923a5f85e84
new file mode 100644
index 0000000..4f7002c
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/c579cd6b62815e6fb6f4eacb62969923a5f85e84
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/c58e25ec891d608123eb80d49cff0d74db985a81 b/fuzz/corpus/packet_recv_server/c58e25ec891d608123eb80d49cff0d74db985a81
new file mode 100644
index 0000000..c02e207
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/c58e25ec891d608123eb80d49cff0d74db985a81
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/c5aa9226f2d2075d5432d8e5884b403a60081b59 b/fuzz/corpus/packet_recv_server/c5aa9226f2d2075d5432d8e5884b403a60081b59
new file mode 100644
index 0000000..b066d4f
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/c5aa9226f2d2075d5432d8e5884b403a60081b59
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/c5cdc6cf337c1d52171e592335f017b1c51cfe81 b/fuzz/corpus/packet_recv_server/c5cdc6cf337c1d52171e592335f017b1c51cfe81
new file mode 100644
index 0000000..8211218
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/c5cdc6cf337c1d52171e592335f017b1c51cfe81
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/c5f1499e010b15dc172638d1cc5f0cb5897084b5 b/fuzz/corpus/packet_recv_server/c5f1499e010b15dc172638d1cc5f0cb5897084b5
new file mode 100644
index 0000000..8f9b8cf
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/c5f1499e010b15dc172638d1cc5f0cb5897084b5
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/c6d5e02da1e542ed018f5398b0f89c20dd18cb6b b/fuzz/corpus/packet_recv_server/c6d5e02da1e542ed018f5398b0f89c20dd18cb6b
new file mode 100644
index 0000000..0fae49b
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/c6d5e02da1e542ed018f5398b0f89c20dd18cb6b
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/c72307e4842f258daa92e1baf658686d0765a3ea b/fuzz/corpus/packet_recv_server/c72307e4842f258daa92e1baf658686d0765a3ea
new file mode 100644
index 0000000..9e74aba
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/c72307e4842f258daa92e1baf658686d0765a3ea
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/c8b3dfca9d94522cc847cc11a5144697869f4071 b/fuzz/corpus/packet_recv_server/c8b3dfca9d94522cc847cc11a5144697869f4071
new file mode 100644
index 0000000..3a860c4
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/c8b3dfca9d94522cc847cc11a5144697869f4071
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ca8bd7ec38f56f9d34dfd7a6fe06587066138ccc b/fuzz/corpus/packet_recv_server/ca8bd7ec38f56f9d34dfd7a6fe06587066138ccc
new file mode 100644
index 0000000..dcc2806
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ca8bd7ec38f56f9d34dfd7a6fe06587066138ccc
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ca96864e8a123d927857d797655fa005ecb52fa4 b/fuzz/corpus/packet_recv_server/ca96864e8a123d927857d797655fa005ecb52fa4
new file mode 100644
index 0000000..79dd93a
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ca96864e8a123d927857d797655fa005ecb52fa4
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/caab201f4e2fba707fac7f905d7864969f7c3cff b/fuzz/corpus/packet_recv_server/caab201f4e2fba707fac7f905d7864969f7c3cff
new file mode 100644
index 0000000..cb14bcb
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/caab201f4e2fba707fac7f905d7864969f7c3cff
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/cb27b29b81befd483195d504edd64a5d8acf16e4 b/fuzz/corpus/packet_recv_server/cb27b29b81befd483195d504edd64a5d8acf16e4
new file mode 100644
index 0000000..260bd82
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/cb27b29b81befd483195d504edd64a5d8acf16e4
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/cb776613448d84e62e0262aa5d53212c37cf5716 b/fuzz/corpus/packet_recv_server/cb776613448d84e62e0262aa5d53212c37cf5716
new file mode 100644
index 0000000..463e620
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/cb776613448d84e62e0262aa5d53212c37cf5716
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/cccbdbb130223b273fbc65cc706fd2a48da7c7af b/fuzz/corpus/packet_recv_server/cccbdbb130223b273fbc65cc706fd2a48da7c7af
new file mode 100644
index 0000000..a003960
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/cccbdbb130223b273fbc65cc706fd2a48da7c7af
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/cce52c3b3836ec8488539a4bc31de683e98c9a02 b/fuzz/corpus/packet_recv_server/cce52c3b3836ec8488539a4bc31de683e98c9a02
new file mode 100644
index 0000000..9d0b825
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/cce52c3b3836ec8488539a4bc31de683e98c9a02
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/cd25a4b55980e48c8da9801f57f5ff481615b559 b/fuzz/corpus/packet_recv_server/cd25a4b55980e48c8da9801f57f5ff481615b559
new file mode 100644
index 0000000..ea00f31
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/cd25a4b55980e48c8da9801f57f5ff481615b559
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ce04f8d935b42ceed2e62a494f114e07c94dc8f2 b/fuzz/corpus/packet_recv_server/ce04f8d935b42ceed2e62a494f114e07c94dc8f2
new file mode 100644
index 0000000..c293d43
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ce04f8d935b42ceed2e62a494f114e07c94dc8f2
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ce296aae96f18e68a27ed4add018661336af9248 b/fuzz/corpus/packet_recv_server/ce296aae96f18e68a27ed4add018661336af9248
new file mode 100644
index 0000000..67aefea
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ce296aae96f18e68a27ed4add018661336af9248
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ce57d64745407e5b3b89ff139cb4f159d80ab495 b/fuzz/corpus/packet_recv_server/ce57d64745407e5b3b89ff139cb4f159d80ab495
new file mode 100644
index 0000000..1e43fd1
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ce57d64745407e5b3b89ff139cb4f159d80ab495
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ce5fa0b6b551529d01f50b0055866987c4553b5d b/fuzz/corpus/packet_recv_server/ce5fa0b6b551529d01f50b0055866987c4553b5d
new file mode 100644
index 0000000..7a3a563
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ce5fa0b6b551529d01f50b0055866987c4553b5d
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ce72d9222251461783c1e92778f77a1c9f2f6451 b/fuzz/corpus/packet_recv_server/ce72d9222251461783c1e92778f77a1c9f2f6451
new file mode 100644
index 0000000..570fdf8
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ce72d9222251461783c1e92778f77a1c9f2f6451
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ce86d817ddb00bf9014a1239face675b7dca5131 b/fuzz/corpus/packet_recv_server/ce86d817ddb00bf9014a1239face675b7dca5131
new file mode 100644
index 0000000..cfa7766
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ce86d817ddb00bf9014a1239face675b7dca5131
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/cee7ac60f3040afe62a416a8348764d7f60dacf9 b/fuzz/corpus/packet_recv_server/cee7ac60f3040afe62a416a8348764d7f60dacf9
new file mode 100644
index 0000000..259a7fc
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/cee7ac60f3040afe62a416a8348764d7f60dacf9
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/cf16a73a43364286fae2b868612e45c36549ff5c b/fuzz/corpus/packet_recv_server/cf16a73a43364286fae2b868612e45c36549ff5c
new file mode 100644
index 0000000..2fa5c3e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/cf16a73a43364286fae2b868612e45c36549ff5c
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/cf6d923e9da930dc058f0ed867073a4165d35044 b/fuzz/corpus/packet_recv_server/cf6d923e9da930dc058f0ed867073a4165d35044
new file mode 100644
index 0000000..60366de
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/cf6d923e9da930dc058f0ed867073a4165d35044
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/cfb059835e9637a63bfcc478c9d9e4e85e21b08b b/fuzz/corpus/packet_recv_server/cfb059835e9637a63bfcc478c9d9e4e85e21b08b
new file mode 100644
index 0000000..aee0a6e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/cfb059835e9637a63bfcc478c9d9e4e85e21b08b
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/d0919fd7cc3dae243a442fdf26baf0381bf2b1a6 b/fuzz/corpus/packet_recv_server/d0919fd7cc3dae243a442fdf26baf0381bf2b1a6
new file mode 100644
index 0000000..5476c27
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/d0919fd7cc3dae243a442fdf26baf0381bf2b1a6
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/d0b6c1393b7ae600a59939d481b375f304b90c8d b/fuzz/corpus/packet_recv_server/d0b6c1393b7ae600a59939d481b375f304b90c8d
new file mode 100644
index 0000000..3acd9e7
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/d0b6c1393b7ae600a59939d481b375f304b90c8d
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/d0d5b0b2490054fdd6c1ea835c0161c071bb67f5 b/fuzz/corpus/packet_recv_server/d0d5b0b2490054fdd6c1ea835c0161c071bb67f5
new file mode 100644
index 0000000..9f40d04
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/d0d5b0b2490054fdd6c1ea835c0161c071bb67f5
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/d38424049f508b76e919d2bf5f37f406e2edb137 b/fuzz/corpus/packet_recv_server/d38424049f508b76e919d2bf5f37f406e2edb137
new file mode 100644
index 0000000..f8d10bf
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/d38424049f508b76e919d2bf5f37f406e2edb137
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/d39a828a33e58b82705e032667bb8a6d99fc17d1 b/fuzz/corpus/packet_recv_server/d39a828a33e58b82705e032667bb8a6d99fc17d1
new file mode 100644
index 0000000..3efc335
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/d39a828a33e58b82705e032667bb8a6d99fc17d1
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/d42424d06a739517e072aead8f0547b79e955f98 b/fuzz/corpus/packet_recv_server/d42424d06a739517e072aead8f0547b79e955f98
new file mode 100644
index 0000000..6b93688
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/d42424d06a739517e072aead8f0547b79e955f98
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/d576731d13137735394e6758890a48006f714715 b/fuzz/corpus/packet_recv_server/d576731d13137735394e6758890a48006f714715
new file mode 100644
index 0000000..1658e59
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/d576731d13137735394e6758890a48006f714715
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/d5bad307cce4db647209c57ca1d9337675bc68ab b/fuzz/corpus/packet_recv_server/d5bad307cce4db647209c57ca1d9337675bc68ab
new file mode 100644
index 0000000..b7bc948
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/d5bad307cce4db647209c57ca1d9337675bc68ab
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/d68f3cde62f07a817886fe7039db739fdc6c266d b/fuzz/corpus/packet_recv_server/d68f3cde62f07a817886fe7039db739fdc6c266d
new file mode 100644
index 0000000..57f4741
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/d68f3cde62f07a817886fe7039db739fdc6c266d
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/d6a745266dba86ce1eb3fc539ca6f7d1bbd4bc8f b/fuzz/corpus/packet_recv_server/d6a745266dba86ce1eb3fc539ca6f7d1bbd4bc8f
new file mode 100644
index 0000000..497deb4
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/d6a745266dba86ce1eb3fc539ca6f7d1bbd4bc8f
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/d7dcf33f17a0b7d6cdb1d7103fdb31113ce69384 b/fuzz/corpus/packet_recv_server/d7dcf33f17a0b7d6cdb1d7103fdb31113ce69384
new file mode 100644
index 0000000..6223e94
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/d7dcf33f17a0b7d6cdb1d7103fdb31113ce69384
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/d7f81106318ebdece2bc9975866a2ea0c4a1eff1 b/fuzz/corpus/packet_recv_server/d7f81106318ebdece2bc9975866a2ea0c4a1eff1
new file mode 100644
index 0000000..1293bcb
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/d7f81106318ebdece2bc9975866a2ea0c4a1eff1
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/d823b4c4e476530882490c9bcd86b07ca8eb87e2 b/fuzz/corpus/packet_recv_server/d823b4c4e476530882490c9bcd86b07ca8eb87e2
new file mode 100644
index 0000000..0c4bd50
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/d823b4c4e476530882490c9bcd86b07ca8eb87e2
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/d9412e3408d5fc77ccaffbb5a0e313e67bc48ecd b/fuzz/corpus/packet_recv_server/d9412e3408d5fc77ccaffbb5a0e313e67bc48ecd
new file mode 100644
index 0000000..96d4326
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/d9412e3408d5fc77ccaffbb5a0e313e67bc48ecd
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/da703af91d5df75e1690cbbf7840232157f62fe2 b/fuzz/corpus/packet_recv_server/da703af91d5df75e1690cbbf7840232157f62fe2
new file mode 100644
index 0000000..d181a3a
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/da703af91d5df75e1690cbbf7840232157f62fe2
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/dae45bf7af6f681040ec0ce57334bb79baeaddd3 b/fuzz/corpus/packet_recv_server/dae45bf7af6f681040ec0ce57334bb79baeaddd3
new file mode 100644
index 0000000..737e813
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/dae45bf7af6f681040ec0ce57334bb79baeaddd3
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/db03c307db5413339b7a421893a5c767924cea09 b/fuzz/corpus/packet_recv_server/db03c307db5413339b7a421893a5c767924cea09
new file mode 100644
index 0000000..9434c03
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/db03c307db5413339b7a421893a5c767924cea09
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/db1870a3ca82a231a738fda771d1e45cfad411aa b/fuzz/corpus/packet_recv_server/db1870a3ca82a231a738fda771d1e45cfad411aa
new file mode 100644
index 0000000..968af02
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/db1870a3ca82a231a738fda771d1e45cfad411aa
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/dbf5a58cf0cfbf387674323820191e9837860174 b/fuzz/corpus/packet_recv_server/dbf5a58cf0cfbf387674323820191e9837860174
new file mode 100644
index 0000000..b689bcc
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/dbf5a58cf0cfbf387674323820191e9837860174
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/dc916f419d7cd46856c90995cd2847fe190675af b/fuzz/corpus/packet_recv_server/dc916f419d7cd46856c90995cd2847fe190675af
new file mode 100644
index 0000000..0c7b16e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/dc916f419d7cd46856c90995cd2847fe190675af
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/df22060bbced6d861fb74b2e54c3a698dedd0bdd b/fuzz/corpus/packet_recv_server/df22060bbced6d861fb74b2e54c3a698dedd0bdd
new file mode 100644
index 0000000..c56b1a9
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/df22060bbced6d861fb74b2e54c3a698dedd0bdd
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/df5a6210c8f70017b1762fe703fca926c199383d b/fuzz/corpus/packet_recv_server/df5a6210c8f70017b1762fe703fca926c199383d
new file mode 100644
index 0000000..4d8fd4a
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/df5a6210c8f70017b1762fe703fca926c199383d
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/dfe0a8a5f7284aec092fe5f531c604a7decb1a70 b/fuzz/corpus/packet_recv_server/dfe0a8a5f7284aec092fe5f531c604a7decb1a70
new file mode 100644
index 0000000..5620edf
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/dfe0a8a5f7284aec092fe5f531c604a7decb1a70
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e01a400cd250cc0dda76cdb6861ec896a685e371 b/fuzz/corpus/packet_recv_server/e01a400cd250cc0dda76cdb6861ec896a685e371
new file mode 100644
index 0000000..4e3c568
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e01a400cd250cc0dda76cdb6861ec896a685e371
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e0670e8829865d09f9a392540cb9889082a3f8e1 b/fuzz/corpus/packet_recv_server/e0670e8829865d09f9a392540cb9889082a3f8e1
new file mode 100644
index 0000000..6d12410
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e0670e8829865d09f9a392540cb9889082a3f8e1
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e08ea37221282070a78ff1120fd8287eed0888b7 b/fuzz/corpus/packet_recv_server/e08ea37221282070a78ff1120fd8287eed0888b7
new file mode 100644
index 0000000..7d8f671
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e08ea37221282070a78ff1120fd8287eed0888b7
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e1960cfb1a500a88a12a3ea77e747a4fe853de95 b/fuzz/corpus/packet_recv_server/e1960cfb1a500a88a12a3ea77e747a4fe853de95
new file mode 100644
index 0000000..8c7f464
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e1960cfb1a500a88a12a3ea77e747a4fe853de95
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e1fe527c47f4f727531501983e39057fa831f1a2 b/fuzz/corpus/packet_recv_server/e1fe527c47f4f727531501983e39057fa831f1a2
new file mode 100644
index 0000000..a8be979
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e1fe527c47f4f727531501983e39057fa831f1a2
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e20b96a314999af261018e58e958ddc426f4f8ac b/fuzz/corpus/packet_recv_server/e20b96a314999af261018e58e958ddc426f4f8ac
new file mode 100644
index 0000000..9618b22
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e20b96a314999af261018e58e958ddc426f4f8ac
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e22e7964699d9cdc8f3c9689dda3945084720028 b/fuzz/corpus/packet_recv_server/e22e7964699d9cdc8f3c9689dda3945084720028
new file mode 100644
index 0000000..262f3af
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e22e7964699d9cdc8f3c9689dda3945084720028
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e29fcaa7a51460e3ebc85072db3ab405dec1a37d b/fuzz/corpus/packet_recv_server/e29fcaa7a51460e3ebc85072db3ab405dec1a37d
new file mode 100644
index 0000000..69159b1
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e29fcaa7a51460e3ebc85072db3ab405dec1a37d
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e3070c5c1e37b9a4be20dca2509eadab14fa1835 b/fuzz/corpus/packet_recv_server/e3070c5c1e37b9a4be20dca2509eadab14fa1835
new file mode 100644
index 0000000..916a8b1
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e3070c5c1e37b9a4be20dca2509eadab14fa1835
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e3135d5a9d4d3b6f09aaa5fdb8dad71293d0e491 b/fuzz/corpus/packet_recv_server/e3135d5a9d4d3b6f09aaa5fdb8dad71293d0e491
new file mode 100644
index 0000000..6c4d1cb
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e3135d5a9d4d3b6f09aaa5fdb8dad71293d0e491
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e333095405655fb10ad3d889409452f4b35144ea b/fuzz/corpus/packet_recv_server/e333095405655fb10ad3d889409452f4b35144ea
new file mode 100644
index 0000000..ec5f09d
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e333095405655fb10ad3d889409452f4b35144ea
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e3a887c9309f1da6d6be8212412f7740ff591eed b/fuzz/corpus/packet_recv_server/e3a887c9309f1da6d6be8212412f7740ff591eed
new file mode 100644
index 0000000..fe4d11b
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e3a887c9309f1da6d6be8212412f7740ff591eed
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e40542e3ad45c5bab6ba35a1be189d3fea4f8013 b/fuzz/corpus/packet_recv_server/e40542e3ad45c5bab6ba35a1be189d3fea4f8013
new file mode 100644
index 0000000..ed65cf2
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e40542e3ad45c5bab6ba35a1be189d3fea4f8013
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e5d007f1eb682ab2b83803e7d2a30467153a3ae7 b/fuzz/corpus/packet_recv_server/e5d007f1eb682ab2b83803e7d2a30467153a3ae7
new file mode 100644
index 0000000..7e0f6b6
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e5d007f1eb682ab2b83803e7d2a30467153a3ae7
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e6c2c0e1e649e2deead99e2fc1ab18d2ce2c484b b/fuzz/corpus/packet_recv_server/e6c2c0e1e649e2deead99e2fc1ab18d2ce2c484b
new file mode 100644
index 0000000..9bd6838
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e6c2c0e1e649e2deead99e2fc1ab18d2ce2c484b
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e7196d8bfbd208a23e835699b6f4209840c4a683 b/fuzz/corpus/packet_recv_server/e7196d8bfbd208a23e835699b6f4209840c4a683
new file mode 100644
index 0000000..d5d57fc
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e7196d8bfbd208a23e835699b6f4209840c4a683
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e782a1ccab4f6a4ad1baa2957b3f854d790c9847 b/fuzz/corpus/packet_recv_server/e782a1ccab4f6a4ad1baa2957b3f854d790c9847
new file mode 100644
index 0000000..3c769e8
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e782a1ccab4f6a4ad1baa2957b3f854d790c9847
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e7894bd2bcd3a032e0de4dc7426ad0f01bf4762c b/fuzz/corpus/packet_recv_server/e7894bd2bcd3a032e0de4dc7426ad0f01bf4762c
new file mode 100644
index 0000000..b581d7d
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e7894bd2bcd3a032e0de4dc7426ad0f01bf4762c
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e8c0ae5e6d8efdeef0e9fb52fa2343bf93d7e4ca b/fuzz/corpus/packet_recv_server/e8c0ae5e6d8efdeef0e9fb52fa2343bf93d7e4ca
new file mode 100644
index 0000000..bfd500a
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e8c0ae5e6d8efdeef0e9fb52fa2343bf93d7e4ca
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e8efbba5dab9ddb5fa40add356774a6efc9a51f0 b/fuzz/corpus/packet_recv_server/e8efbba5dab9ddb5fa40add356774a6efc9a51f0
new file mode 100644
index 0000000..1dab3c4
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e8efbba5dab9ddb5fa40add356774a6efc9a51f0
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e927e418f06d887cd7fd37b5ac4337aae8ed1117 b/fuzz/corpus/packet_recv_server/e927e418f06d887cd7fd37b5ac4337aae8ed1117
new file mode 100644
index 0000000..7907289
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e927e418f06d887cd7fd37b5ac4337aae8ed1117
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e9927692f3e69efcb0b2434e282c36b49a981ab3 b/fuzz/corpus/packet_recv_server/e9927692f3e69efcb0b2434e282c36b49a981ab3
new file mode 100644
index 0000000..cfeb65f
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e9927692f3e69efcb0b2434e282c36b49a981ab3
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/e9b66376beb08a37986d263277dc770babb048b7 b/fuzz/corpus/packet_recv_server/e9b66376beb08a37986d263277dc770babb048b7
new file mode 100644
index 0000000..c3fb7c8
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/e9b66376beb08a37986d263277dc770babb048b7
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ea27cd6bf811210113d0f0a624bad869b94b1c0e b/fuzz/corpus/packet_recv_server/ea27cd6bf811210113d0f0a624bad869b94b1c0e
new file mode 100644
index 0000000..93c9bcd
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ea27cd6bf811210113d0f0a624bad869b94b1c0e
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/eafc08ae8a0d8d0f164186bdba16ca55e3f7f514 b/fuzz/corpus/packet_recv_server/eafc08ae8a0d8d0f164186bdba16ca55e3f7f514
new file mode 100644
index 0000000..ea35fab
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/eafc08ae8a0d8d0f164186bdba16ca55e3f7f514
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/eba756583f4026932e9ec9f14a0ea54cc1783b62 b/fuzz/corpus/packet_recv_server/eba756583f4026932e9ec9f14a0ea54cc1783b62
new file mode 100644
index 0000000..e32f2ec
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/eba756583f4026932e9ec9f14a0ea54cc1783b62
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/eba825f77087e7400c4007aa14b3e783e121c6d9 b/fuzz/corpus/packet_recv_server/eba825f77087e7400c4007aa14b3e783e121c6d9
new file mode 100644
index 0000000..85004a7
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/eba825f77087e7400c4007aa14b3e783e121c6d9
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ebf49d73899160f9ce1b046c7c0cb5247f6128de b/fuzz/corpus/packet_recv_server/ebf49d73899160f9ce1b046c7c0cb5247f6128de
new file mode 100644
index 0000000..b9d0cca
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ebf49d73899160f9ce1b046c7c0cb5247f6128de
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ec7b1e22850c1c813397094df6f5e3d3791a926b b/fuzz/corpus/packet_recv_server/ec7b1e22850c1c813397094df6f5e3d3791a926b
new file mode 100644
index 0000000..c2b5745
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ec7b1e22850c1c813397094df6f5e3d3791a926b
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ec9971cb9b1f2cfaa5f614f1b33b01f0ad62f5ef b/fuzz/corpus/packet_recv_server/ec9971cb9b1f2cfaa5f614f1b33b01f0ad62f5ef
new file mode 100644
index 0000000..f2b31ca
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ec9971cb9b1f2cfaa5f614f1b33b01f0ad62f5ef
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ecf6d4413fa6446c4da4ce1d2400166a7d2684c3 b/fuzz/corpus/packet_recv_server/ecf6d4413fa6446c4da4ce1d2400166a7d2684c3
new file mode 100644
index 0000000..bf6ba72
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ecf6d4413fa6446c4da4ce1d2400166a7d2684c3
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ed939cfe2679cdb6cbce49551d741676ea0bfab0 b/fuzz/corpus/packet_recv_server/ed939cfe2679cdb6cbce49551d741676ea0bfab0
new file mode 100644
index 0000000..dfce07a
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ed939cfe2679cdb6cbce49551d741676ea0bfab0
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/edbe7790d88d0ea7732c7f83e373994526a9ae92 b/fuzz/corpus/packet_recv_server/edbe7790d88d0ea7732c7f83e373994526a9ae92
new file mode 100644
index 0000000..1af0876
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/edbe7790d88d0ea7732c7f83e373994526a9ae92
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/edc3c986d42ca7f6df19efc4f64814302f900b76 b/fuzz/corpus/packet_recv_server/edc3c986d42ca7f6df19efc4f64814302f900b76
new file mode 100644
index 0000000..f437b36
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/edc3c986d42ca7f6df19efc4f64814302f900b76
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ee34b5abfc6436f40a91457b85d952d7b46e505d b/fuzz/corpus/packet_recv_server/ee34b5abfc6436f40a91457b85d952d7b46e505d
new file mode 100644
index 0000000..820b592
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ee34b5abfc6436f40a91457b85d952d7b46e505d
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ee746652b30c1d768d93b744131267a5bb39065f b/fuzz/corpus/packet_recv_server/ee746652b30c1d768d93b744131267a5bb39065f
new file mode 100644
index 0000000..37ebd2d
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ee746652b30c1d768d93b744131267a5bb39065f
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/eeae5b965fad2de13b1aaf9aee7a0732fa4ca658 b/fuzz/corpus/packet_recv_server/eeae5b965fad2de13b1aaf9aee7a0732fa4ca658
new file mode 100644
index 0000000..e253fda
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/eeae5b965fad2de13b1aaf9aee7a0732fa4ca658
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/f008cf2fe33d730b758be35762dc0587d19dfdc4 b/fuzz/corpus/packet_recv_server/f008cf2fe33d730b758be35762dc0587d19dfdc4
new file mode 100644
index 0000000..fa47a3a
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/f008cf2fe33d730b758be35762dc0587d19dfdc4
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/f07d5fc54ab668426f71ea031653863c66904f0a b/fuzz/corpus/packet_recv_server/f07d5fc54ab668426f71ea031653863c66904f0a
new file mode 100644
index 0000000..58c1555
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/f07d5fc54ab668426f71ea031653863c66904f0a
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/f116defa2a292fcc500a3c83b5e81e85b5e675aa b/fuzz/corpus/packet_recv_server/f116defa2a292fcc500a3c83b5e81e85b5e675aa
new file mode 100644
index 0000000..2ba2d55
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/f116defa2a292fcc500a3c83b5e81e85b5e675aa
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/f1aa0cc7029a930bdb70a9d8977db850fa4d1cb5 b/fuzz/corpus/packet_recv_server/f1aa0cc7029a930bdb70a9d8977db850fa4d1cb5
new file mode 100644
index 0000000..eeccc12
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/f1aa0cc7029a930bdb70a9d8977db850fa4d1cb5
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/f2d1dbde2767cad2bb9697a7b663a98695802cf1 b/fuzz/corpus/packet_recv_server/f2d1dbde2767cad2bb9697a7b663a98695802cf1
new file mode 100644
index 0000000..644823b
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/f2d1dbde2767cad2bb9697a7b663a98695802cf1
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/f35a4ce3951a109f7ca41e7bbf8f146cdc17a32e b/fuzz/corpus/packet_recv_server/f35a4ce3951a109f7ca41e7bbf8f146cdc17a32e
new file mode 100644
index 0000000..4f99436
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/f35a4ce3951a109f7ca41e7bbf8f146cdc17a32e
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/f426a81a5bcdfe86927ac3dbb0b600bbc683a864 b/fuzz/corpus/packet_recv_server/f426a81a5bcdfe86927ac3dbb0b600bbc683a864
new file mode 100644
index 0000000..196ed54
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/f426a81a5bcdfe86927ac3dbb0b600bbc683a864
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/f4b6f6021573fc7c6929d8bfaecb1e1eb7dda439 b/fuzz/corpus/packet_recv_server/f4b6f6021573fc7c6929d8bfaecb1e1eb7dda439
new file mode 100644
index 0000000..f7701e4
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/f4b6f6021573fc7c6929d8bfaecb1e1eb7dda439
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/f5e41f37a7b537fb9f95b655935650f8be92d4e7 b/fuzz/corpus/packet_recv_server/f5e41f37a7b537fb9f95b655935650f8be92d4e7
new file mode 100644
index 0000000..2091d7e
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/f5e41f37a7b537fb9f95b655935650f8be92d4e7
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/f7632974174e7b343dd97a074b2db92b9de63204 b/fuzz/corpus/packet_recv_server/f7632974174e7b343dd97a074b2db92b9de63204
new file mode 100644
index 0000000..f6b7d98
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/f7632974174e7b343dd97a074b2db92b9de63204
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/f8d8b8463bbe17c60bf6e85ed4102d9a1b340329 b/fuzz/corpus/packet_recv_server/f8d8b8463bbe17c60bf6e85ed4102d9a1b340329
new file mode 100644
index 0000000..f6ab692
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/f8d8b8463bbe17c60bf6e85ed4102d9a1b340329
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/f91a99b78a5dc2823d7c35177243a3070082cbe3 b/fuzz/corpus/packet_recv_server/f91a99b78a5dc2823d7c35177243a3070082cbe3
new file mode 100644
index 0000000..73d8e85
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/f91a99b78a5dc2823d7c35177243a3070082cbe3
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/f97a6244c8ae1465193d0f741c252fe1ba045534 b/fuzz/corpus/packet_recv_server/f97a6244c8ae1465193d0f741c252fe1ba045534
new file mode 100644
index 0000000..70872ac
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/f97a6244c8ae1465193d0f741c252fe1ba045534
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/f9ad0ad4c5cf4a25d4807aacea6c6b794e2988c0 b/fuzz/corpus/packet_recv_server/f9ad0ad4c5cf4a25d4807aacea6c6b794e2988c0
new file mode 100644
index 0000000..a6c1137
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/f9ad0ad4c5cf4a25d4807aacea6c6b794e2988c0
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/fa8ccd95952731fb1e5e0051aec875dc05d8e2b5 b/fuzz/corpus/packet_recv_server/fa8ccd95952731fb1e5e0051aec875dc05d8e2b5
new file mode 100644
index 0000000..16c9996
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/fa8ccd95952731fb1e5e0051aec875dc05d8e2b5
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/fc0cad96551998b6e34d6ff6e2b1ee838e22407c b/fuzz/corpus/packet_recv_server/fc0cad96551998b6e34d6ff6e2b1ee838e22407c
new file mode 100644
index 0000000..b9613d5
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/fc0cad96551998b6e34d6ff6e2b1ee838e22407c
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/fc3b8c5484fd007e7019f6e1c26cf78d6c9cdc44 b/fuzz/corpus/packet_recv_server/fc3b8c5484fd007e7019f6e1c26cf78d6c9cdc44
new file mode 100644
index 0000000..3eca5ee
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/fc3b8c5484fd007e7019f6e1c26cf78d6c9cdc44
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/fcc9baf3b0fc3d14f84ddfbd6f83b2a98a4ea5a9 b/fuzz/corpus/packet_recv_server/fcc9baf3b0fc3d14f84ddfbd6f83b2a98a4ea5a9
new file mode 100644
index 0000000..4f364c6
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/fcc9baf3b0fc3d14f84ddfbd6f83b2a98a4ea5a9
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/fd3a94f83b7eeb068c30028edc9ac59a6822b95a b/fuzz/corpus/packet_recv_server/fd3a94f83b7eeb068c30028edc9ac59a6822b95a
new file mode 100644
index 0000000..2a2bdcd
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/fd3a94f83b7eeb068c30028edc9ac59a6822b95a
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/fd3d344d2990ed5e6cf8fb0b86c68c0cb4fa3c18 b/fuzz/corpus/packet_recv_server/fd3d344d2990ed5e6cf8fb0b86c68c0cb4fa3c18
new file mode 100644
index 0000000..c23857d
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/fd3d344d2990ed5e6cf8fb0b86c68c0cb4fa3c18
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/fecd280cf9b65b26d69a81b0f87c23b0e6759ee6 b/fuzz/corpus/packet_recv_server/fecd280cf9b65b26d69a81b0f87c23b0e6759ee6
new file mode 100644
index 0000000..5e6e6f1
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/fecd280cf9b65b26d69a81b0f87c23b0e6759ee6
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/fefbc5d76b91d845458d83d94f8f8354a732f314 b/fuzz/corpus/packet_recv_server/fefbc5d76b91d845458d83d94f8f8354a732f314
new file mode 100644
index 0000000..554c6eb
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/fefbc5d76b91d845458d83d94f8f8354a732f314
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ff38d421772c88784a9ca113e446bfc69287b6a1 b/fuzz/corpus/packet_recv_server/ff38d421772c88784a9ca113e446bfc69287b6a1
new file mode 100644
index 0000000..48b83c8
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ff38d421772c88784a9ca113e446bfc69287b6a1
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ffb2466045d355847f75cfb0d3ce7e6647eaff57 b/fuzz/corpus/packet_recv_server/ffb2466045d355847f75cfb0d3ce7e6647eaff57
new file mode 100644
index 0000000..989d699
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ffb2466045d355847f75cfb0d3ce7e6647eaff57
Binary files differ
diff --git a/fuzz/corpus/packet_recv_server/ffbfeda5913c90976bb01df7d4184345d5902900 b/fuzz/corpus/packet_recv_server/ffbfeda5913c90976bb01df7d4184345d5902900
new file mode 100644
index 0000000..1aa0431
--- /dev/null
+++ b/fuzz/corpus/packet_recv_server/ffbfeda5913c90976bb01df7d4184345d5902900
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/003a6c3aa00200ad3d9e9a51baa7483ef7edb210 b/fuzz/corpus/qpack_decode/003a6c3aa00200ad3d9e9a51baa7483ef7edb210
new file mode 100644
index 0000000..885600c
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/003a6c3aa00200ad3d9e9a51baa7483ef7edb210
@@ -0,0 +1 @@
+ïûÐÐ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/00509ff3fbd63d921ecbd5c230d4a292d6ad7e45 b/fuzz/corpus/qpack_decode/00509ff3fbd63d921ecbd5c230d4a292d6ad7e45
new file mode 100644
index 0000000..b3abb29
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/00509ff3fbd63d921ecbd5c230d4a292d6ad7e45
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/00f443118cff084c5ca55c3f714ee28095105361 b/fuzz/corpus/qpack_decode/00f443118cff084c5ca55c3f714ee28095105361
new file mode 100644
index 0000000..3dc1897
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/00f443118cff084c5ca55c3f714ee28095105361
@@ -0,0 +1 @@
+óÙÙ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/01bc7b79df2a7c073b31f811769e3349999cf725 b/fuzz/corpus/qpack_decode/01bc7b79df2a7c073b31f811769e3349999cf725
new file mode 100644
index 0000000..daf73cd
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/01bc7b79df2a7c073b31f811769e3349999cf725
@@ -0,0 +1 @@
+ÿÿÆÆöööö
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/02fd90197a20fcc63bdc60164295cc4b4cba9da2 b/fuzz/corpus/qpack_decode/02fd90197a20fcc63bdc60164295cc4b4cba9da2
new file mode 100644
index 0000000..fc3d269
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/02fd90197a20fcc63bdc60164295cc4b4cba9da2
@@ -0,0 +1 @@
+Æ8ö
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/0474b5f0bf8b3823ca64d6fe90e0eee5d4e41359 b/fuzz/corpus/qpack_decode/0474b5f0bf8b3823ca64d6fe90e0eee5d4e41359
new file mode 100644
index 0000000..95c2246
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/0474b5f0bf8b3823ca64d6fe90e0eee5d4e41359
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/056ac527c4f1a9e45330f70d2745072a3b6929c4 b/fuzz/corpus/qpack_decode/056ac527c4f1a9e45330f70d2745072a3b6929c4
new file mode 100644
index 0000000..c570709
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/056ac527c4f1a9e45330f70d2745072a3b6929c4
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/05e5a9f40a49ed6e519faf8c98665f6945a76e85 b/fuzz/corpus/qpack_decode/05e5a9f40a49ed6e519faf8c98665f6945a76e85
new file mode 100644
index 0000000..a004f10
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/05e5a9f40a49ed6e519faf8c98665f6945a76e85
@@ -0,0 +1 @@
+11ÊÊ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/06cd3faeb25e424e6255528ee42e62ad130ac59e b/fuzz/corpus/qpack_decode/06cd3faeb25e424e6255528ee42e62ad130ac59e
new file mode 100644
index 0000000..53b41e5
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/06cd3faeb25e424e6255528ee42e62ad130ac59e
@@ -0,0 +1 @@
+1ÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/06febe92c88ebe8766930a9baa048b8f9376d4e8 b/fuzz/corpus/qpack_decode/06febe92c88ebe8766930a9baa048b8f9376d4e8
new file mode 100644
index 0000000..e32525b
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/06febe92c88ebe8766930a9baa048b8f9376d4e8
@@ -0,0 +1 @@
+2>ÉÉÉ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/07b9f55ddb6d2962f98a9639b384fce88f009c25 b/fuzz/corpus/qpack_decode/07b9f55ddb6d2962f98a9639b384fce88f009c25
new file mode 100644
index 0000000..6faee08
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/07b9f55ddb6d2962f98a9639b384fce88f009c25
@@ -0,0 +1 @@
+!6Á
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/0954eb8f9310b690f07de1203b4b5ed3c5e892d3 b/fuzz/corpus/qpack_decode/0954eb8f9310b690f07de1203b4b5ed3c5e892d3
new file mode 100644
index 0000000..7ea40b6
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/0954eb8f9310b690f07de1203b4b5ed3c5e892d3
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/0973c21b60c82adbaec227cee85d098c7f5aa743 b/fuzz/corpus/qpack_decode/0973c21b60c82adbaec227cee85d098c7f5aa743
new file mode 100644
index 0000000..096d1e4
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/0973c21b60c82adbaec227cee85d098c7f5aa743
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/09d79fd328d4751f820dbef26c09d7afd73af173 b/fuzz/corpus/qpack_decode/09d79fd328d4751f820dbef26c09d7afd73af173
new file mode 100644
index 0000000..a382955
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/09d79fd328d4751f820dbef26c09d7afd73af173
@@ -0,0 +1 @@
+*üüüüü
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/0b8a48e394c9884a79ab56f596fa759917a0465c b/fuzz/corpus/qpack_decode/0b8a48e394c9884a79ab56f596fa759917a0465c
new file mode 100644
index 0000000..fe75585
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/0b8a48e394c9884a79ab56f596fa759917a0465c
@@ -0,0 +1 @@
+íÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/0bcd0768202e2e99e3e7e8ef5eba8734795cdb76 b/fuzz/corpus/qpack_decode/0bcd0768202e2e99e3e7e8ef5eba8734795cdb76
new file mode 100644
index 0000000..ab96e87
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/0bcd0768202e2e99e3e7e8ef5eba8734795cdb76
@@ -0,0 +1 @@
+ÅÅ<ÿÿÿÿË
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/0eb6ea4a4f86d82a634179655ed0919999267f3d b/fuzz/corpus/qpack_decode/0eb6ea4a4f86d82a634179655ed0919999267f3d
new file mode 100644
index 0000000..cc98bdc
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/0eb6ea4a4f86d82a634179655ed0919999267f3d
@@ -0,0 +1 @@
+1ëäää
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/0f3284951ca19768df55709e82ea20b955742996 b/fuzz/corpus/qpack_decode/0f3284951ca19768df55709e82ea20b955742996
new file mode 100644
index 0000000..9d00cec
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/0f3284951ca19768df55709e82ea20b955742996
@@ -0,0 +1 @@
+((þ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/0f66c0ddd46ee5ae5cbe2e6b016d07a7205af5c9 b/fuzz/corpus/qpack_decode/0f66c0ddd46ee5ae5cbe2e6b016d07a7205af5c9
new file mode 100644
index 0000000..2115560
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/0f66c0ddd46ee5ae5cbe2e6b016d07a7205af5c9
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/114dcb7e502f406a3b48f3230cc94a07aac40299 b/fuzz/corpus/qpack_decode/114dcb7e502f406a3b48f3230cc94a07aac40299
new file mode 100644
index 0000000..8219b95
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/114dcb7e502f406a3b48f3230cc94a07aac40299
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/11b21f01f641033d49eb46e1b304c68229c52ccf b/fuzz/corpus/qpack_decode/11b21f01f641033d49eb46e1b304c68229c52ccf
new file mode 100644
index 0000000..dc556a1
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/11b21f01f641033d49eb46e1b304c68229c52ccf
@@ -0,0 +1 @@
+/
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/11fb0cef1096a4ee1c20519d8fceaf9f48925973 b/fuzz/corpus/qpack_decode/11fb0cef1096a4ee1c20519d8fceaf9f48925973
new file mode 100644
index 0000000..5f19348
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/11fb0cef1096a4ee1c20519d8fceaf9f48925973
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/1217cf17554942ef9b1a48c9ec80006644ea6da7 b/fuzz/corpus/qpack_decode/1217cf17554942ef9b1a48c9ec80006644ea6da7
new file mode 100644
index 0000000..f10119f
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/1217cf17554942ef9b1a48c9ec80006644ea6da7
@@ -0,0 +1 @@
+ïÐÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/1256f042c18db040bb768fe235c460449da5a8b2 b/fuzz/corpus/qpack_decode/1256f042c18db040bb768fe235c460449da5a8b2
new file mode 100644
index 0000000..2cb5e3e
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/1256f042c18db040bb768fe235c460449da5a8b2
@@ -0,0 +1 @@
+'ÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/145fb971177b418075853fe53ef7c7c61e6125c7 b/fuzz/corpus/qpack_decode/145fb971177b418075853fe53ef7c7c61e6125c7
new file mode 100644
index 0000000..59af286
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/145fb971177b418075853fe53ef7c7c61e6125c7
@@ -0,0 +1 @@
+ÒÒâââ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/14b62eb8c71091066c2ec55fe2a43e9f6f8e601f b/fuzz/corpus/qpack_decode/14b62eb8c71091066c2ec55fe2a43e9f6f8e601f
new file mode 100644
index 0000000..d971896
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/14b62eb8c71091066c2ec55fe2a43e9f6f8e601f
@@ -0,0 +1 @@
+]+ÒÒ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/15b4360e3995d95fd63bcbe1a2abc9c32f787d01 b/fuzz/corpus/qpack_decode/15b4360e3995d95fd63bcbe1a2abc9c32f787d01
new file mode 100644
index 0000000..3014f5a
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/15b4360e3995d95fd63bcbe1a2abc9c32f787d01
@@ -0,0 +1 @@
+Ï+ï
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/164c58d62eec943923b5abcdfcec230ac4b63b93 b/fuzz/corpus/qpack_decode/164c58d62eec943923b5abcdfcec230ac4b63b93
new file mode 100644
index 0000000..dbac114
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/164c58d62eec943923b5abcdfcec230ac4b63b93
@@ -0,0 +1 @@
+1ëää
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/1655a85ea0a6740ff03b01702093c37f1169582d b/fuzz/corpus/qpack_decode/1655a85ea0a6740ff03b01702093c37f1169582d
new file mode 100644
index 0000000..55d14a3
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/1655a85ea0a6740ff03b01702093c37f1169582d
@@ -0,0 +1 @@
+××××××
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/16fae7c030376a640e7cd962a4244f0ce6c25a51 b/fuzz/corpus/qpack_decode/16fae7c030376a640e7cd962a4244f0ce6c25a51
new file mode 100644
index 0000000..c423586
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/16fae7c030376a640e7cd962a4244f0ce6c25a51
@@ -0,0 +1 @@
+îïïïïæ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/16fbecab0452a40d55897a66e8559c30065223b6 b/fuzz/corpus/qpack_decode/16fbecab0452a40d55897a66e8559c30065223b6
new file mode 100644
index 0000000..8bc7bf4
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/16fbecab0452a40d55897a66e8559c30065223b6
@@ -0,0 +1 @@
+Òâêêê
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/1708e3c33398a5ce728134c261f7d4b82727f415 b/fuzz/corpus/qpack_decode/1708e3c33398a5ce728134c261f7d4b82727f415
new file mode 100644
index 0000000..f2684bd
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/1708e3c33398a5ce728134c261f7d4b82727f415
@@ -0,0 +1 @@
+êÌÌ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/178cf681d94309a5e46ac81da11a0258088d1d9d b/fuzz/corpus/qpack_decode/178cf681d94309a5e46ac81da11a0258088d1d9d
new file mode 100644
index 0000000..7dd9376
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/178cf681d94309a5e46ac81da11a0258088d1d9d
@@ -0,0 +1 @@
+öôÀÀ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/18b4e2dfd4d6cb27b1fe9609c55097a3973dc9b3 b/fuzz/corpus/qpack_decode/18b4e2dfd4d6cb27b1fe9609c55097a3973dc9b3
new file mode 100644
index 0000000..bc619c8
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/18b4e2dfd4d6cb27b1fe9609c55097a3973dc9b3
@@ -0,0 +1 @@
++)+ÿÿÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/190cde9b492c3c73768207854baae175420918c2 b/fuzz/corpus/qpack_decode/190cde9b492c3c73768207854baae175420918c2
new file mode 100644
index 0000000..c72ef09
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/190cde9b492c3c73768207854baae175420918c2
@@ -0,0 +1 @@
+øÑÑÑÑþÀ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/1b0c4e94b945b3ec123fc95b5da3b0260487fcf8 b/fuzz/corpus/qpack_decode/1b0c4e94b945b3ec123fc95b5da3b0260487fcf8
new file mode 100644
index 0000000..33df956
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/1b0c4e94b945b3ec123fc95b5da3b0260487fcf8
@@ -0,0 +1 @@
+=þõ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/1d3b9a779257731270239110278e8615c9c04950 b/fuzz/corpus/qpack_decode/1d3b9a779257731270239110278e8615c9c04950
new file mode 100644
index 0000000..260aa4b
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/1d3b9a779257731270239110278e8615c9c04950
@@ -0,0 +1 @@
+*óÏÏ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/1d76cef839ee530ef9221cd33c439649de627947 b/fuzz/corpus/qpack_decode/1d76cef839ee530ef9221cd33c439649de627947
new file mode 100644
index 0000000..498e650
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/1d76cef839ee530ef9221cd33c439649de627947
@@ -0,0 +1 @@
+&ÏÚ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/1ee3f7b7ca7ec977ec3ab21ea814c91e1e708a07 b/fuzz/corpus/qpack_decode/1ee3f7b7ca7ec977ec3ab21ea814c91e1e708a07
new file mode 100644
index 0000000..72243d2
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/1ee3f7b7ca7ec977ec3ab21ea814c91e1e708a07
@@ -0,0 +1 @@
+2ëëëëë
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/1efbae5fe0830fdcf7839083c6e69f4fe4454384 b/fuzz/corpus/qpack_decode/1efbae5fe0830fdcf7839083c6e69f4fe4454384
new file mode 100644
index 0000000..0fb49e0
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/1efbae5fe0830fdcf7839083c6e69f4fe4454384
@@ -0,0 +1 @@
+öìÿøìÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/1f25297d6c312907136c32aac349f28444fdf3d0 b/fuzz/corpus/qpack_decode/1f25297d6c312907136c32aac349f28444fdf3d0
new file mode 100644
index 0000000..ef98733
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/1f25297d6c312907136c32aac349f28444fdf3d0
@@ -0,0 +1 @@
+óÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/1f5e18e20f4a8123a7ccc8df46e38199d60be0cf b/fuzz/corpus/qpack_decode/1f5e18e20f4a8123a7ccc8df46e38199d60be0cf
new file mode 100644
index 0000000..8e908f6
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/1f5e18e20f4a8123a7ccc8df46e38199d60be0cf
@@ -0,0 +1 @@
+1=ÿ!
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/1fa8d514b0bc8304acf67985de562af0d41c2f6e b/fuzz/corpus/qpack_decode/1fa8d514b0bc8304acf67985de562af0d41c2f6e
new file mode 100644
index 0000000..257e2c4
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/1fa8d514b0bc8304acf67985de562af0d41c2f6e
@@ -0,0 +1 @@
+..ÆÆ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/1fe315befdd1c076363783ce4ffce9de4a2e7a84 b/fuzz/corpus/qpack_decode/1fe315befdd1c076363783ce4ffce9de4a2e7a84
new file mode 100644
index 0000000..36ce749
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/1fe315befdd1c076363783ce4ffce9de4a2e7a84
@@ -0,0 +1 @@
+-ÎËË
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/205dc1a1c6ff18e91294d45c22acea77bd167737 b/fuzz/corpus/qpack_decode/205dc1a1c6ff18e91294d45c22acea77bd167737
new file mode 100644
index 0000000..743afae
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/205dc1a1c6ff18e91294d45c22acea77bd167737
@@ -0,0 +1 @@
++%ç
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/211d5a22b752342b74373de987a9898f8ee74fe3 b/fuzz/corpus/qpack_decode/211d5a22b752342b74373de987a9898f8ee74fe3
new file mode 100644
index 0000000..d957201
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/211d5a22b752342b74373de987a9898f8ee74fe3
@@ -0,0 +1 @@
+ÃÃÃÃ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/2163da8365714ba36b8047fe06a6a74502e358a2 b/fuzz/corpus/qpack_decode/2163da8365714ba36b8047fe06a6a74502e358a2
new file mode 100644
index 0000000..f522772
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/2163da8365714ba36b8047fe06a6a74502e358a2
@@ -0,0 +1 @@
+öÐÿÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/21e2abc5fbde4b4653d8643584fc3e5e84e72fee b/fuzz/corpus/qpack_decode/21e2abc5fbde4b4653d8643584fc3e5e84e72fee
new file mode 100644
index 0000000..be5822e
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/21e2abc5fbde4b4653d8643584fc3e5e84e72fee
@@ -0,0 +1 @@
+y1ÿöÿí
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/22a9f751660d9c6ed6334573cb64ec98f138cf4c b/fuzz/corpus/qpack_decode/22a9f751660d9c6ed6334573cb64ec98f138cf4c
new file mode 100644
index 0000000..8075dfc
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/22a9f751660d9c6ed6334573cb64ec98f138cf4c
@@ -0,0 +1 @@
+øþÀ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/23b5f31a247edf77fb3064ac694ce18e74ac0c5c b/fuzz/corpus/qpack_decode/23b5f31a247edf77fb3064ac694ce18e74ac0c5c
new file mode 100644
index 0000000..c12be96
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/23b5f31a247edf77fb3064ac694ce18e74ac0c5c
@@ -0,0 +1 @@
+}ÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/23c026e058f5fc205d45d0446a081a9a81162095 b/fuzz/corpus/qpack_decode/23c026e058f5fc205d45d0446a081a9a81162095
new file mode 100644
index 0000000..6ef78f5
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/23c026e058f5fc205d45d0446a081a9a81162095
@@ -0,0 +1 @@
+2ÞÔÔÔÔÔ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/2762737867b9a3421a39f8ff8dc112309b892dc1 b/fuzz/corpus/qpack_decode/2762737867b9a3421a39f8ff8dc112309b892dc1
new file mode 100644
index 0000000..191b1cb
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/2762737867b9a3421a39f8ff8dc112309b892dc1
@@ -0,0 +1 @@
++hè
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/27e9edabbd020c9a29cb58d6dd6a7c2e8f0c7740 b/fuzz/corpus/qpack_decode/27e9edabbd020c9a29cb58d6dd6a7c2e8f0c7740
new file mode 100644
index 0000000..9224836
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/27e9edabbd020c9a29cb58d6dd6a7c2e8f0c7740
@@ -0,0 +1 @@
+þ7Ð
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/287d91624c820325c515d0d507b432065c9b73c0 b/fuzz/corpus/qpack_decode/287d91624c820325c515d0d507b432065c9b73c0
new file mode 100644
index 0000000..98a5e6a
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/287d91624c820325c515d0d507b432065c9b73c0
@@ -0,0 +1,2 @@
+ø
+(*ÿ
diff --git a/fuzz/corpus/qpack_decode/29188f9afd4e867772618f298648322b119fcba3 b/fuzz/corpus/qpack_decode/29188f9afd4e867772618f298648322b119fcba3
new file mode 100644
index 0000000..a5b1dd9
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/29188f9afd4e867772618f298648322b119fcba3
@@ -0,0 +1 @@
+@ÎÎ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/2a7177b7d77d7c297a9d0b628924b5d8075f860f b/fuzz/corpus/qpack_decode/2a7177b7d77d7c297a9d0b628924b5d8075f860f
new file mode 100644
index 0000000..2fd64b3
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/2a7177b7d77d7c297a9d0b628924b5d8075f860f
@@ -0,0 +1 @@
+÷ÔÛ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/2b6fdb201d565b9c8a6f1619c6e8e7b2811bcfa7 b/fuzz/corpus/qpack_decode/2b6fdb201d565b9c8a6f1619c6e8e7b2811bcfa7
new file mode 100644
index 0000000..02cbeb2
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/2b6fdb201d565b9c8a6f1619c6e8e7b2811bcfa7
@@ -0,0 +1 @@
+}ÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/2bf14129f02304c761f997d496f718b0dd2b38ad b/fuzz/corpus/qpack_decode/2bf14129f02304c761f997d496f718b0dd2b38ad
new file mode 100644
index 0000000..75d22b0
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/2bf14129f02304c761f997d496f718b0dd2b38ad
@@ -0,0 +1 @@
++4ÿ"
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/2cc1ec648e54aa795f8f3bea116bd6a80a9de0ef b/fuzz/corpus/qpack_decode/2cc1ec648e54aa795f8f3bea116bd6a80a9de0ef
new file mode 100644
index 0000000..a668ad0
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/2cc1ec648e54aa795f8f3bea116bd6a80a9de0ef
@@ -0,0 +1 @@
+Ï_ò
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/2cd1c6a82dc227f1e5d70b1b002d65d3280c2f91 b/fuzz/corpus/qpack_decode/2cd1c6a82dc227f1e5d70b1b002d65d3280c2f91
new file mode 100644
index 0000000..1207845
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/2cd1c6a82dc227f1e5d70b1b002d65d3280c2f91
@@ -0,0 +1 @@
+Eððððð
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/2cdf64bbfd4cfba0c2b0979bfa3f517295c83de5 b/fuzz/corpus/qpack_decode/2cdf64bbfd4cfba0c2b0979bfa3f517295c83de5
new file mode 100644
index 0000000..4f01a0e
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/2cdf64bbfd4cfba0c2b0979bfa3f517295c83de5
@@ -0,0 +1 @@
+öÐÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/2d508c1042982b3abb09d32db0eb74d95fd383a9 b/fuzz/corpus/qpack_decode/2d508c1042982b3abb09d32db0eb74d95fd383a9
new file mode 100644
index 0000000..fb21926
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/2d508c1042982b3abb09d32db0eb74d95fd383a9
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/2db8cf644b31a81d1b33808acfa396d3af0b81a8 b/fuzz/corpus/qpack_decode/2db8cf644b31a81d1b33808acfa396d3af0b81a8
new file mode 100644
index 0000000..a6c9253
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/2db8cf644b31a81d1b33808acfa396d3af0b81a8
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/2e1cd2f1b648d419a3fc466ef72b9872f4437363 b/fuzz/corpus/qpack_decode/2e1cd2f1b648d419a3fc466ef72b9872f4437363
new file mode 100644
index 0000000..8f6dccf
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/2e1cd2f1b648d419a3fc466ef72b9872f4437363
@@ -0,0 +1 @@
+ìú÷÷÷÷
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/2e2d721f8ebe340a50bce862d4471db858e7b800 b/fuzz/corpus/qpack_decode/2e2d721f8ebe340a50bce862d4471db858e7b800
new file mode 100644
index 0000000..ce40039
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/2e2d721f8ebe340a50bce862d4471db858e7b800
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/2e3f9fb0925e81a5f13ccc9c11330e318ee49906 b/fuzz/corpus/qpack_decode/2e3f9fb0925e81a5f13ccc9c11330e318ee49906
new file mode 100644
index 0000000..10add34
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/2e3f9fb0925e81a5f13ccc9c11330e318ee49906
@@ -0,0 +1 @@
+ËÄÆÆÆÆ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/30cdedb1f8a43a9fa49ca3fff1a5a8c660e4414c b/fuzz/corpus/qpack_decode/30cdedb1f8a43a9fa49ca3fff1a5a8c660e4414c
new file mode 100644
index 0000000..f0ccf70
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/30cdedb1f8a43a9fa49ca3fff1a5a8c660e4414c
@@ -0,0 +1 @@
+ääääää
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/3130e6e549eb6bf75bfdf15f6f0e2a9a490821d0 b/fuzz/corpus/qpack_decode/3130e6e549eb6bf75bfdf15f6f0e2a9a490821d0
new file mode 100644
index 0000000..40c9a62
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/3130e6e549eb6bf75bfdf15f6f0e2a9a490821d0
@@ -0,0 +1 @@
+Ý1)ÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/318edab5378d4d506bea461b58afea23e7e27fbb b/fuzz/corpus/qpack_decode/318edab5378d4d506bea461b58afea23e7e27fbb
new file mode 100644
index 0000000..9a0414d
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/318edab5378d4d506bea461b58afea23e7e27fbb
@@ -0,0 +1 @@
++¢øø
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/31df74a6498b59a8fe8a32800609279ea43eaaad b/fuzz/corpus/qpack_decode/31df74a6498b59a8fe8a32800609279ea43eaaad
new file mode 100644
index 0000000..0d056aa
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/31df74a6498b59a8fe8a32800609279ea43eaaad
@@ -0,0 +1 @@
+9ëóó
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/31ea2d281fd0e7db70cc9c5f4b916708d7e9392c b/fuzz/corpus/qpack_decode/31ea2d281fd0e7db70cc9c5f4b916708d7e9392c
new file mode 100644
index 0000000..7aebcfa
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/31ea2d281fd0e7db70cc9c5f4b916708d7e9392c
@@ -0,0 +1 @@
+@@
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/3268849242d532afe91acbbef8f060515114cc8f b/fuzz/corpus/qpack_decode/3268849242d532afe91acbbef8f060515114cc8f
new file mode 100644
index 0000000..e1a4f67
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/3268849242d532afe91acbbef8f060515114cc8f
@@ -0,0 +1 @@
+öòòò
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/34a3fad3e20030995db5a3ed4a2901fa68ce16f9 b/fuzz/corpus/qpack_decode/34a3fad3e20030995db5a3ed4a2901fa68ce16f9
new file mode 100644
index 0000000..12d1018
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/34a3fad3e20030995db5a3ed4a2901fa68ce16f9
@@ -0,0 +1 @@
+öîÖÖÖÖ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/353155092c24627b6541e0d2ca10bc42c284016d b/fuzz/corpus/qpack_decode/353155092c24627b6541e0d2ca10bc42c284016d
new file mode 100644
index 0000000..b111892
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/353155092c24627b6541e0d2ca10bc42c284016d
@@ -0,0 +1 @@
+öîÚÚÚ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/362228006621773e913139fbe040869407edc67e b/fuzz/corpus/qpack_decode/362228006621773e913139fbe040869407edc67e
new file mode 100644
index 0000000..7e222bb
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/362228006621773e913139fbe040869407edc67e
@@ -0,0 +1 @@
+ééåå
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/363256bc5fc3bd629dbcd7baa700a4109ba92773 b/fuzz/corpus/qpack_decode/363256bc5fc3bd629dbcd7baa700a4109ba92773
new file mode 100644
index 0000000..4d08380
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/363256bc5fc3bd629dbcd7baa700a4109ba92773
@@ -0,0 +1 @@
+Æ7öö
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/36913588a61ded97099eb5ac93f666a5271548f8 b/fuzz/corpus/qpack_decode/36913588a61ded97099eb5ac93f666a5271548f8
new file mode 100644
index 0000000..9a83789
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/36913588a61ded97099eb5ac93f666a5271548f8
@@ -0,0 +1 @@
+Ý)Ý
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/38693f75473ff00949ad96ab8f9a40eb514a15a1 b/fuzz/corpus/qpack_decode/38693f75473ff00949ad96ab8f9a40eb514a15a1
new file mode 100644
index 0000000..e05e519
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/38693f75473ff00949ad96ab8f9a40eb514a15a1
@@ -0,0 +1 @@
+é1ùùùù
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/395469d07af4c7158e874ef209b29879711fd803 b/fuzz/corpus/qpack_decode/395469d07af4c7158e874ef209b29879711fd803
new file mode 100644
index 0000000..852ad03
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/395469d07af4c7158e874ef209b29879711fd803
@@ -0,0 +1 @@
+×××××
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/3b351c9b1b7ee7c6a3a88001c18557b91f977a31 b/fuzz/corpus/qpack_decode/3b351c9b1b7ee7c6a3a88001c18557b91f977a31
new file mode 100644
index 0000000..bccb091
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/3b351c9b1b7ee7c6a3a88001c18557b91f977a31
@@ -0,0 +1 @@
+ÒÒððððððððf
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/3bc0b93563e1fc20fe9cbfdedfa1d0ba014ecbca b/fuzz/corpus/qpack_decode/3bc0b93563e1fc20fe9cbfdedfa1d0ba014ecbca
new file mode 100644
index 0000000..f8ac0b3
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/3bc0b93563e1fc20fe9cbfdedfa1d0ba014ecbca
@@ -0,0 +1 @@
+1ùù
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/3c17f39da177c9c90cdeb98885a747af7998e163 b/fuzz/corpus/qpack_decode/3c17f39da177c9c90cdeb98885a747af7998e163
new file mode 100644
index 0000000..687c19d
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/3c17f39da177c9c90cdeb98885a747af7998e163
@@ -0,0 +1 @@
+12ÚÚ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/3c44e0084d42a1e0649bf2749f878ccf6685428d b/fuzz/corpus/qpack_decode/3c44e0084d42a1e0649bf2749f878ccf6685428d
new file mode 100644
index 0000000..7ae5597
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/3c44e0084d42a1e0649bf2749f878ccf6685428d
@@ -0,0 +1 @@
+--þþþþ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/3ce35db01488c8151ee15b60309c726be92bfaad b/fuzz/corpus/qpack_decode/3ce35db01488c8151ee15b60309c726be92bfaad
new file mode 100644
index 0000000..c1cba54
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/3ce35db01488c8151ee15b60309c726be92bfaad
@@ -0,0 +1 @@
++¢øøø
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/3f10cf0cb7b7315588e122ae99d7e443928e2c86 b/fuzz/corpus/qpack_decode/3f10cf0cb7b7315588e122ae99d7e443928e2c86
new file mode 100644
index 0000000..3333531
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/3f10cf0cb7b7315588e122ae99d7e443928e2c86
@@ -0,0 +1 @@
+[1ôô
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/3f1e39097a7b17426811114400dfb128ee434759 b/fuzz/corpus/qpack_decode/3f1e39097a7b17426811114400dfb128ee434759
new file mode 100644
index 0000000..33cf0da
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/3f1e39097a7b17426811114400dfb128ee434759
@@ -0,0 +1 @@
+1ùùùù
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/3f4bf38ee41bc3c86809c2884de76b8195418e2e b/fuzz/corpus/qpack_decode/3f4bf38ee41bc3c86809c2884de76b8195418e2e
new file mode 100644
index 0000000..287f9c1
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/3f4bf38ee41bc3c86809c2884de76b8195418e2e
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/3f84302a4734ba6c7f1402b5e0c7df3711904c23 b/fuzz/corpus/qpack_decode/3f84302a4734ba6c7f1402b5e0c7df3711904c23
new file mode 100644
index 0000000..b0dc886
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/3f84302a4734ba6c7f1402b5e0c7df3711904c23
@@ -0,0 +1 @@
+}ÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/3fa7cfad2169aa6e13e2efbf659df1028d493ed2 b/fuzz/corpus/qpack_decode/3fa7cfad2169aa6e13e2efbf659df1028d493ed2
new file mode 100644
index 0000000..3ce5054
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/3fa7cfad2169aa6e13e2efbf659df1028d493ed2
@@ -0,0 +1 @@
+[ÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/408d1466f2f31b38d83ba8558ccd3fb29db71c5d b/fuzz/corpus/qpack_decode/408d1466f2f31b38d83ba8558ccd3fb29db71c5d
new file mode 100644
index 0000000..1841d73
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/408d1466f2f31b38d83ba8558ccd3fb29db71c5d
@@ -0,0 +1 @@
+!6ÁÁ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/40ae6f1404b31147b2365f2eade16bcf6da5ba47 b/fuzz/corpus/qpack_decode/40ae6f1404b31147b2365f2eade16bcf6da5ba47
new file mode 100644
index 0000000..ce1985a
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/40ae6f1404b31147b2365f2eade16bcf6da5ba47
@@ -0,0 +1 @@
+1ÔÓ/
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/40dad5ef33a07865abc2eef6e90cac76649cd0d3 b/fuzz/corpus/qpack_decode/40dad5ef33a07865abc2eef6e90cac76649cd0d3
new file mode 100644
index 0000000..e774431
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/40dad5ef33a07865abc2eef6e90cac76649cd0d3
@@ -0,0 +1 @@
+)ÄôÄ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/4157abb3c3c77511cce8df0aae1c943fd46ef6c9 b/fuzz/corpus/qpack_decode/4157abb3c3c77511cce8df0aae1c943fd46ef6c9
new file mode 100644
index 0000000..5bae010
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/4157abb3c3c77511cce8df0aae1c943fd46ef6c9
@@ -0,0 +1 @@
+UUÍÍÍÍ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/417a31b64daf2a5b24cdfa2ccdbbfb729dafbb70 b/fuzz/corpus/qpack_decode/417a31b64daf2a5b24cdfa2ccdbbfb729dafbb70
new file mode 100644
index 0000000..d4ed9af
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/417a31b64daf2a5b24cdfa2ccdbbfb729dafbb70
@@ -0,0 +1 @@
+!6Ñ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/42d911f075e998fc624300590490aa74e872c94b b/fuzz/corpus/qpack_decode/42d911f075e998fc624300590490aa74e872c94b
new file mode 100644
index 0000000..d4101bf
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/42d911f075e998fc624300590490aa74e872c94b
@@ -0,0 +1 @@
+KÜÜÜÜ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/4398f5a8350826615fbb8797004d59733c9c3a2f b/fuzz/corpus/qpack_decode/4398f5a8350826615fbb8797004d59733c9c3a2f
new file mode 100644
index 0000000..97a0f04
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/4398f5a8350826615fbb8797004d59733c9c3a2f
@@ -0,0 +1 @@
+î*ÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/442298a684b08b33c1fa54ee1d56277e77f745c0 b/fuzz/corpus/qpack_decode/442298a684b08b33c1fa54ee1d56277e77f745c0
new file mode 100644
index 0000000..b0a9e8d
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/442298a684b08b33c1fa54ee1d56277e77f745c0
@@ -0,0 +1,2 @@
+ø
+(î*ÿ-
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/44b33774470d8f7fbc227e1c5ffa90add6c6a0f1 b/fuzz/corpus/qpack_decode/44b33774470d8f7fbc227e1c5ffa90add6c6a0f1
new file mode 100644
index 0000000..c938852
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/44b33774470d8f7fbc227e1c5ffa90add6c6a0f1
@@ -0,0 +1 @@
+--þþþ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/45b56ff37170d2cd4c456ac5ecf9810614a69058 b/fuzz/corpus/qpack_decode/45b56ff37170d2cd4c456ac5ecf9810614a69058
new file mode 100644
index 0000000..8a73f27
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/45b56ff37170d2cd4c456ac5ecf9810614a69058
@@ -0,0 +1 @@
+ì*ÿÿØÿÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/45e408ca1c35f5fad304b8d92d7de3bf33c10046 b/fuzz/corpus/qpack_decode/45e408ca1c35f5fad304b8d92d7de3bf33c10046
new file mode 100644
index 0000000..0714bab
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/45e408ca1c35f5fad304b8d92d7de3bf33c10046
@@ -0,0 +1 @@
+ïýìì
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/46a572653ee56a5591867cf26c515b40268f077b b/fuzz/corpus/qpack_decode/46a572653ee56a5591867cf26c515b40268f077b
new file mode 100644
index 0000000..d73f849
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/46a572653ee56a5591867cf26c515b40268f077b
@@ -0,0 +1 @@
+ óÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/4776eabfe1d9ec687982caa8f2f4e64d17481228 b/fuzz/corpus/qpack_decode/4776eabfe1d9ec687982caa8f2f4e64d17481228
new file mode 100644
index 0000000..e4a5b6a
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/4776eabfe1d9ec687982caa8f2f4e64d17481228
@@ -0,0 +1 @@
+11ÊÊÊ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/485371981e39d8efed14d2d1b49ca36b445eb079 b/fuzz/corpus/qpack_decode/485371981e39d8efed14d2d1b49ca36b445eb079
new file mode 100644
index 0000000..cc1a40a
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/485371981e39d8efed14d2d1b49ca36b445eb079
@@ -0,0 +1 @@
+ööÆ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/48a2a9f1aa6ada3435fc17029ca80498a69ed26d b/fuzz/corpus/qpack_decode/48a2a9f1aa6ada3435fc17029ca80498a69ed26d
new file mode 100644
index 0000000..f0f085c
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/48a2a9f1aa6ada3435fc17029ca80498a69ed26d
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/48d91022fc7056de0e9c16709d1e3a692b189bdb b/fuzz/corpus/qpack_decode/48d91022fc7056de0e9c16709d1e3a692b189bdb
new file mode 100644
index 0000000..4a53809
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/48d91022fc7056de0e9c16709d1e3a692b189bdb
@@ -0,0 +1 @@
+=óóóó
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/493b50f4f4ec34a60631f7268cb58d50ddcd52cc b/fuzz/corpus/qpack_decode/493b50f4f4ec34a60631f7268cb58d50ddcd52cc
new file mode 100644
index 0000000..004c292
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/493b50f4f4ec34a60631f7268cb58d50ddcd52cc
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/4942f68517eb3fd290d3e8eca384c833ef56c934 b/fuzz/corpus/qpack_decode/4942f68517eb3fd290d3e8eca384c833ef56c934
new file mode 100644
index 0000000..26c14bf
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/4942f68517eb3fd290d3e8eca384c833ef56c934
@@ -0,0 +1 @@
+Ðÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/4955bd092ffae3fc68a6047af5fd78e1bbce3a0d b/fuzz/corpus/qpack_decode/4955bd092ffae3fc68a6047af5fd78e1bbce3a0d
new file mode 100644
index 0000000..4dc1914
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/4955bd092ffae3fc68a6047af5fd78e1bbce3a0d
@@ -0,0 +1 @@
+1òä
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/4a5b401859b4f5fa5cfd8ff0715046f11d8b7ceb b/fuzz/corpus/qpack_decode/4a5b401859b4f5fa5cfd8ff0715046f11d8b7ceb
new file mode 100644
index 0000000..b130797
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/4a5b401859b4f5fa5cfd8ff0715046f11d8b7ceb
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/4b2f52fecfc1337859915af40bac1e4ffe03a385 b/fuzz/corpus/qpack_decode/4b2f52fecfc1337859915af40bac1e4ffe03a385
new file mode 100644
index 0000000..fd6dd26
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/4b2f52fecfc1337859915af40bac1e4ffe03a385
@@ -0,0 +1 @@
+ÊÊååÊåååååå
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/4c28e1f8ac88e41ceef99a1f4de5684897016c59 b/fuzz/corpus/qpack_decode/4c28e1f8ac88e41ceef99a1f4de5684897016c59
new file mode 100644
index 0000000..e90abe1
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/4c28e1f8ac88e41ceef99a1f4de5684897016c59
@@ -0,0 +1 @@
+ðE,ðgðð
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/4c29e2ec167bdec7cb0fcb09d1911a6b1e2c2d54 b/fuzz/corpus/qpack_decode/4c29e2ec167bdec7cb0fcb09d1911a6b1e2c2d54
new file mode 100644
index 0000000..17fe0c7
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/4c29e2ec167bdec7cb0fcb09d1911a6b1e2c2d54
@@ -0,0 +1 @@
+Ö
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/4c8e98ee49af013fc34af82fa209691a04a1c486 b/fuzz/corpus/qpack_decode/4c8e98ee49af013fc34af82fa209691a04a1c486
new file mode 100644
index 0000000..f047409
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/4c8e98ee49af013fc34af82fa209691a04a1c486
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/4d3b8a3c50cb37f29ee87dcd3116413107277b84 b/fuzz/corpus/qpack_decode/4d3b8a3c50cb37f29ee87dcd3116413107277b84
new file mode 100644
index 0000000..f9f794a
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/4d3b8a3c50cb37f29ee87dcd3116413107277b84
@@ -0,0 +1 @@
+ÒÂÂ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/4e20390dceca61cdc498adc3137cc0a53e493d97 b/fuzz/corpus/qpack_decode/4e20390dceca61cdc498adc3137cc0a53e493d97
new file mode 100644
index 0000000..c666af6
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/4e20390dceca61cdc498adc3137cc0a53e493d97
@@ -0,0 +1 @@
+=þõõõ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/4e56a46119df7f5e7ba5bec3a6757b3a8713bf5d b/fuzz/corpus/qpack_decode/4e56a46119df7f5e7ba5bec3a6757b3a8713bf5d
new file mode 100644
index 0000000..9a81bf8
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/4e56a46119df7f5e7ba5bec3a6757b3a8713bf5d
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/4f357c74e12231db795cee4daf58a26c6e0c0234 b/fuzz/corpus/qpack_decode/4f357c74e12231db795cee4daf58a26c6e0c0234
new file mode 100644
index 0000000..e654e96
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/4f357c74e12231db795cee4daf58a26c6e0c0234
@@ -0,0 +1 @@
+ÁÁÁÁ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/4f46f67b79b16e55ca510a1623b17c3a0c913bd6 b/fuzz/corpus/qpack_decode/4f46f67b79b16e55ca510a1623b17c3a0c913bd6
new file mode 100644
index 0000000..6d3602d
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/4f46f67b79b16e55ca510a1623b17c3a0c913bd6
@@ -0,0 +1 @@
+KÜÜÜ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/4f8490baa5a9e2d40d5c90834e03d1e1dc8b9a2f b/fuzz/corpus/qpack_decode/4f8490baa5a9e2d40d5c90834e03d1e1dc8b9a2f
new file mode 100644
index 0000000..fa67c8c
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/4f8490baa5a9e2d40d5c90834e03d1e1dc8b9a2f
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/509dd896b1b37ce5bb25ecf2cdb0e160cdd280ca b/fuzz/corpus/qpack_decode/509dd896b1b37ce5bb25ecf2cdb0e160cdd280ca
new file mode 100644
index 0000000..0538d8b
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/509dd896b1b37ce5bb25ecf2cdb0e160cdd280ca
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/51a1b400f2915ed00373991a8c4c9eab2c3269c8 b/fuzz/corpus/qpack_decode/51a1b400f2915ed00373991a8c4c9eab2c3269c8
new file mode 100644
index 0000000..f200442
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/51a1b400f2915ed00373991a8c4c9eab2c3269c8
@@ -0,0 +1 @@
++ß
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/51c31e5ae5fa159e4d791f823e32e75e8525681c b/fuzz/corpus/qpack_decode/51c31e5ae5fa159e4d791f823e32e75e8525681c
new file mode 100644
index 0000000..102c2c5
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/51c31e5ae5fa159e4d791f823e32e75e8525681c
@@ -0,0 +1 @@
+1ÞÔÔ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/551a7be4b7cb9ff84226e9b62cd67d551c6e3b0a b/fuzz/corpus/qpack_decode/551a7be4b7cb9ff84226e9b62cd67d551c6e3b0a
new file mode 100644
index 0000000..c74223d
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/551a7be4b7cb9ff84226e9b62cd67d551c6e3b0a
@@ -0,0 +1 @@
+1Ô08
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/5784552d65437e0d94c10121e8a528b010659c7a b/fuzz/corpus/qpack_decode/5784552d65437e0d94c10121e8a528b010659c7a
new file mode 100644
index 0000000..566360d
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/5784552d65437e0d94c10121e8a528b010659c7a
@@ -0,0 +1 @@
+/)Ù×
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/593252b2f284c7215e0cde91865848e51b9a7509 b/fuzz/corpus/qpack_decode/593252b2f284c7215e0cde91865848e51b9a7509
new file mode 100644
index 0000000..1950373
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/593252b2f284c7215e0cde91865848e51b9a7509
@@ -0,0 +1 @@
+ª1îî
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/59692629c8826b90542d70e6406c072b93f6024f b/fuzz/corpus/qpack_decode/59692629c8826b90542d70e6406c072b93f6024f
new file mode 100644
index 0000000..0683633
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/59692629c8826b90542d70e6406c072b93f6024f
@@ -0,0 +1 @@
+ÙûÒ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/5a8e93ead0e791f7689cf193442f4088fc504191 b/fuzz/corpus/qpack_decode/5a8e93ead0e791f7689cf193442f4088fc504191
new file mode 100644
index 0000000..0172f50
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/5a8e93ead0e791f7689cf193442f4088fc504191
@@ -0,0 +1 @@
+++ÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/5ad6d4dee7eb22b42e62835a327887abb4a6e70c b/fuzz/corpus/qpack_decode/5ad6d4dee7eb22b42e62835a327887abb4a6e70c
new file mode 100644
index 0000000..e9abd69
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/5ad6d4dee7eb22b42e62835a327887abb4a6e70c
@@ -0,0 +1 @@
+1)ìß
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/5caed74cc67e9f33af94aa56d7cb1badb08f1942 b/fuzz/corpus/qpack_decode/5caed74cc67e9f33af94aa56d7cb1badb08f1942
new file mode 100644
index 0000000..8b5b45f
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/5caed74cc67e9f33af94aa56d7cb1badb08f1942
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/5d55b356f7a8e09881dea724cce9848a5b514117 b/fuzz/corpus/qpack_decode/5d55b356f7a8e09881dea724cce9848a5b514117
new file mode 100644
index 0000000..bd9a293
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/5d55b356f7a8e09881dea724cce9848a5b514117
@@ -0,0 +1 @@
+10Ô{
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/5df91c5df959d8ec3ac4da0636526c9a572bb769 b/fuzz/corpus/qpack_decode/5df91c5df959d8ec3ac4da0636526c9a572bb769
new file mode 100644
index 0000000..4fa5083
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/5df91c5df959d8ec3ac4da0636526c9a572bb769
@@ -0,0 +1,2 @@
+ø
+A
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/5dff009a0630ac1127d65b9561b871b7b01cfeb5 b/fuzz/corpus/qpack_decode/5dff009a0630ac1127d65b9561b871b7b01cfeb5
new file mode 100644
index 0000000..8644a67
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/5dff009a0630ac1127d65b9561b871b7b01cfeb5
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/5e741fdf00eb0ce0f251bb41ff7374a1c5a71f33 b/fuzz/corpus/qpack_decode/5e741fdf00eb0ce0f251bb41ff7374a1c5a71f33
new file mode 100644
index 0000000..15f1a8e
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/5e741fdf00eb0ce0f251bb41ff7374a1c5a71f33
@@ -0,0 +1 @@
+íííííí
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/5e7bd00a6f0c996622aab0d05c4f5d2f8751dfb4 b/fuzz/corpus/qpack_decode/5e7bd00a6f0c996622aab0d05c4f5d2f8751dfb4
new file mode 100644
index 0000000..76e09fc
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/5e7bd00a6f0c996622aab0d05c4f5d2f8751dfb4
@@ -0,0 +1 @@
+ÎÎÕÕÕ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/5e8cefc8a703b7d3ebb940de640ae8c66d8980bf b/fuzz/corpus/qpack_decode/5e8cefc8a703b7d3ebb940de640ae8c66d8980bf
new file mode 100644
index 0000000..7adfac6
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/5e8cefc8a703b7d3ebb940de640ae8c66d8980bf
@@ -0,0 +1 @@
+ óÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/609049ea728bec5b16e9a4a4bdfd6335f269e656 b/fuzz/corpus/qpack_decode/609049ea728bec5b16e9a4a4bdfd6335f269e656
new file mode 100644
index 0000000..df9c34e
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/609049ea728bec5b16e9a4a4bdfd6335f269e656
@@ -0,0 +1 @@
+?ÂÂÂ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/6146e8e16f7e4182e92410337d3c06d2b929e68f b/fuzz/corpus/qpack_decode/6146e8e16f7e4182e92410337d3c06d2b929e68f
new file mode 100644
index 0000000..4e94054
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/6146e8e16f7e4182e92410337d3c06d2b929e68f
@@ -0,0 +1 @@
+ãããããããããã
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/6194641c7e568a9686eef5d8fbb1af93328bb03d b/fuzz/corpus/qpack_decode/6194641c7e568a9686eef5d8fbb1af93328bb03d
new file mode 100644
index 0000000..87a4d6f
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/6194641c7e568a9686eef5d8fbb1af93328bb03d
@@ -0,0 +1 @@
+?¿å
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/621713bcb2853ced1150bf12f7585d3ad66ef64e b/fuzz/corpus/qpack_decode/621713bcb2853ced1150bf12f7585d3ad66ef64e
new file mode 100644
index 0000000..b0ea26d
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/621713bcb2853ced1150bf12f7585d3ad66ef64e
@@ -0,0 +1 @@
+1ÔÞ-
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/62335104233db9c734ee96b964d2f904d7fc9b80 b/fuzz/corpus/qpack_decode/62335104233db9c734ee96b964d2f904d7fc9b80
new file mode 100644
index 0000000..8df7d94
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/62335104233db9c734ee96b964d2f904d7fc9b80
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/62974e9466d2b21407ee9352fe6522dfa3ff8f08 b/fuzz/corpus/qpack_decode/62974e9466d2b21407ee9352fe6522dfa3ff8f08
new file mode 100644
index 0000000..92a257c
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/62974e9466d2b21407ee9352fe6522dfa3ff8f08
@@ -0,0 +1 @@
+öÐÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/6297553457d7fb8271f3eeea3a7937d584c472ba b/fuzz/corpus/qpack_decode/6297553457d7fb8271f3eeea3a7937d584c472ba
new file mode 100644
index 0000000..7919bce
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/6297553457d7fb8271f3eeea3a7937d584c472ba
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/6519c68f4ec61a8e208c846c701565b77156d25a b/fuzz/corpus/qpack_decode/6519c68f4ec61a8e208c846c701565b77156d25a
new file mode 100644
index 0000000..59e3333
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/6519c68f4ec61a8e208c846c701565b77156d25a
@@ -0,0 +1,2 @@
+
+ÈÈÈ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/655606ec381b196f4f596e033a9356f41a23fc0e b/fuzz/corpus/qpack_decode/655606ec381b196f4f596e033a9356f41a23fc0e
new file mode 100644
index 0000000..0820dad
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/655606ec381b196f4f596e033a9356f41a23fc0e
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/657259eb8723fcdb43857865c56bfc48d6863034 b/fuzz/corpus/qpack_decode/657259eb8723fcdb43857865c56bfc48d6863034
new file mode 100644
index 0000000..5f3fe0c
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/657259eb8723fcdb43857865c56bfc48d6863034
@@ -0,0 +1 @@
+1ÄÊ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/668c5f1f5163b4c6239122f2d73a1527045a019d b/fuzz/corpus/qpack_decode/668c5f1f5163b4c6239122f2d73a1527045a019d
new file mode 100644
index 0000000..a94bc37
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/668c5f1f5163b4c6239122f2d73a1527045a019d
@@ -0,0 +1 @@
+$îÖÖÖÖÖÖÖÖ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/669436d423138023429e78aaabff715d271e8e03 b/fuzz/corpus/qpack_decode/669436d423138023429e78aaabff715d271e8e03
new file mode 100644
index 0000000..316ff2a
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/669436d423138023429e78aaabff715d271e8e03
@@ -0,0 +1 @@
+Ï}Mÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/66e37cd2395f350426ac9c5a6bc4b6b355d87361 b/fuzz/corpus/qpack_decode/66e37cd2395f350426ac9c5a6bc4b6b355d87361
new file mode 100644
index 0000000..5a82695
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/66e37cd2395f350426ac9c5a6bc4b6b355d87361
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/67dae0d993e891633cac6e4320aadd6db73f8bd0 b/fuzz/corpus/qpack_decode/67dae0d993e891633cac6e4320aadd6db73f8bd0
new file mode 100644
index 0000000..42e0df2
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/67dae0d993e891633cac6e4320aadd6db73f8bd0
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/67e48b433b08a48bf18a554d28488b9e22495ef7 b/fuzz/corpus/qpack_decode/67e48b433b08a48bf18a554d28488b9e22495ef7
new file mode 100644
index 0000000..660e1b4
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/67e48b433b08a48bf18a554d28488b9e22495ef7
@@ -0,0 +1 @@
+-2ËÉÉÉÉöò
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/6874d6337dfc5307922d404d5587ebcc756f7f4d b/fuzz/corpus/qpack_decode/6874d6337dfc5307922d404d5587ebcc756f7f4d
new file mode 100644
index 0000000..15b7e7b
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/6874d6337dfc5307922d404d5587ebcc756f7f4d
@@ -0,0 +1 @@
+1vÇ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/69d3fb33477d1de34b4490e844fb27bc4884ba66 b/fuzz/corpus/qpack_decode/69d3fb33477d1de34b4490e844fb27bc4884ba66
new file mode 100644
index 0000000..89d0d70
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/69d3fb33477d1de34b4490e844fb27bc4884ba66
@@ -0,0 +1 @@
+öGÌ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/69ec7906628dcd923b7fb59c276b6daff554acef b/fuzz/corpus/qpack_decode/69ec7906628dcd923b7fb59c276b6daff554acef
new file mode 100644
index 0000000..affa430
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/69ec7906628dcd923b7fb59c276b6daff554acef
@@ -0,0 +1 @@
+1ÊÊÊÊÊÊÊÊÊÊ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/6a4731796a3c7c70e938ee857a9eb68d9ee6d32f b/fuzz/corpus/qpack_decode/6a4731796a3c7c70e938ee857a9eb68d9ee6d32f
new file mode 100644
index 0000000..f4beefb
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/6a4731796a3c7c70e938ee857a9eb68d9ee6d32f
@@ -0,0 +1 @@
+íííí
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/6b0d76f43f3d54d84694974b61fbc02e2c7a386c b/fuzz/corpus/qpack_decode/6b0d76f43f3d54d84694974b61fbc02e2c7a386c
new file mode 100644
index 0000000..5a7c187
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/6b0d76f43f3d54d84694974b61fbc02e2c7a386c
@@ -0,0 +1 @@
+öáááá
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/6bdf00c4851bbe6d4447b7a878cc6471670525b4 b/fuzz/corpus/qpack_decode/6bdf00c4851bbe6d4447b7a878cc6471670525b4
new file mode 100644
index 0000000..bdaf58a
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/6bdf00c4851bbe6d4447b7a878cc6471670525b4
@@ -0,0 +1 @@
+óÏØØ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/6c8f26698182d8ad63f897e92cf8863459d728ca b/fuzz/corpus/qpack_decode/6c8f26698182d8ad63f897e92cf8863459d728ca
new file mode 100644
index 0000000..06dfa31
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/6c8f26698182d8ad63f897e92cf8863459d728ca
@@ -0,0 +1 @@
+*îÿÿÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/6cab9694bc72da0fe50785afc95785d4e220c272 b/fuzz/corpus/qpack_decode/6cab9694bc72da0fe50785afc95785d4e220c272
new file mode 100644
index 0000000..f27769d
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/6cab9694bc72da0fe50785afc95785d4e220c272
@@ -0,0 +1 @@
+î*ÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/6cb208ccdc982010795407a2e96651e468fad313 b/fuzz/corpus/qpack_decode/6cb208ccdc982010795407a2e96651e468fad313
new file mode 100644
index 0000000..fae7fd3
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/6cb208ccdc982010795407a2e96651e468fad313
@@ -0,0 +1 @@
+Òââ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/6cbd0076a469bd0931713ce16ee83d17ce29aa10 b/fuzz/corpus/qpack_decode/6cbd0076a469bd0931713ce16ee83d17ce29aa10
new file mode 100644
index 0000000..04cc6f4
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/6cbd0076a469bd0931713ce16ee83d17ce29aa10
@@ -0,0 +1 @@
+11)-
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/6d0210d244be3a811ce22d50ac5657cd1b6592f5 b/fuzz/corpus/qpack_decode/6d0210d244be3a811ce22d50ac5657cd1b6592f5
new file mode 100644
index 0000000..83fd032
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/6d0210d244be3a811ce22d50ac5657cd1b6592f5
@@ -0,0 +1 @@
+ÎÇÅÅÅ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/6e2023333d730d415a6a37163150aa156dcb790e b/fuzz/corpus/qpack_decode/6e2023333d730d415a6a37163150aa156dcb790e
new file mode 100644
index 0000000..f71ac90
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/6e2023333d730d415a6a37163150aa156dcb790e
@@ -0,0 +1 @@
++#çç
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/6e2732b0a42f79d0c7c6dd29c7cf9d8686168be6 b/fuzz/corpus/qpack_decode/6e2732b0a42f79d0c7c6dd29c7cf9d8686168be6
new file mode 100644
index 0000000..3f80f8c
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/6e2732b0a42f79d0c7c6dd29c7cf9d8686168be6
@@ -0,0 +1 @@
+-+ÎË
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/6e686fc7901327e814189179b95987cc27cbca5e b/fuzz/corpus/qpack_decode/6e686fc7901327e814189179b95987cc27cbca5e
new file mode 100644
index 0000000..c8fbbdb
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/6e686fc7901327e814189179b95987cc27cbca5e
@@ -0,0 +1 @@
+OÖÍ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/6e93f4aa42a4c77e842da26015d46d47ffaa3371 b/fuzz/corpus/qpack_decode/6e93f4aa42a4c77e842da26015d46d47ffaa3371
new file mode 100644
index 0000000..e869001
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/6e93f4aa42a4c77e842da26015d46d47ffaa3371
@@ -0,0 +1 @@
+*×ÝÝÝ×
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/6eef73ba3c3d74ca4124f8b5a024b093dc3c4205 b/fuzz/corpus/qpack_decode/6eef73ba3c3d74ca4124f8b5a024b093dc3c4205
new file mode 100644
index 0000000..72ee46a
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/6eef73ba3c3d74ca4124f8b5a024b093dc3c4205
@@ -0,0 +1 @@
+î/úú
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/701024cdd52b38fd398aba42201e4b5bee070a35 b/fuzz/corpus/qpack_decode/701024cdd52b38fd398aba42201e4b5bee070a35
new file mode 100644
index 0000000..f4fd6ea
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/701024cdd52b38fd398aba42201e4b5bee070a35
@@ -0,0 +1 @@
+ÏÖÅ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/70b11ceaf49697af8917c78cc07481a3053e585b b/fuzz/corpus/qpack_decode/70b11ceaf49697af8917c78cc07481a3053e585b
new file mode 100644
index 0000000..f99c6cc
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/70b11ceaf49697af8917c78cc07481a3053e585b
@@ -0,0 +1 @@
+ß2á
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/70c9156a6d37c9f56a8c44a47ec9ed456b822dc8 b/fuzz/corpus/qpack_decode/70c9156a6d37c9f56a8c44a47ec9ed456b822dc8
new file mode 100644
index 0000000..9474af4
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/70c9156a6d37c9f56a8c44a47ec9ed456b822dc8
@@ -0,0 +1 @@
+=þõõõõ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/7190700d24d8d33d1a5b6e56c4af965a8a944541 b/fuzz/corpus/qpack_decode/7190700d24d8d33d1a5b6e56c4af965a8a944541
new file mode 100644
index 0000000..aba613a
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/7190700d24d8d33d1a5b6e56c4af965a8a944541
@@ -0,0 +1 @@
+}(
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/729e6e4775d1891bbbec1c08b047c1e9348f32af b/fuzz/corpus/qpack_decode/729e6e4775d1891bbbec1c08b047c1e9348f32af
new file mode 100644
index 0000000..01ccca8
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/729e6e4775d1891bbbec1c08b047c1e9348f32af
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/74507cd75778583d448b3ac1572ee4773704dc12 b/fuzz/corpus/qpack_decode/74507cd75778583d448b3ac1572ee4773704dc12
new file mode 100644
index 0000000..bb65356
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/74507cd75778583d448b3ac1572ee4773704dc12
@@ -0,0 +1 @@
+ÿ×
diff --git a/fuzz/corpus/qpack_decode/760a0f8596894107bbf3cb152f2714eca9a5b229 b/fuzz/corpus/qpack_decode/760a0f8596894107bbf3cb152f2714eca9a5b229
new file mode 100644
index 0000000..66fcc78
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/760a0f8596894107bbf3cb152f2714eca9a5b229
@@ -0,0 +1 @@
+Ðÿÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/760e3549540e0dec05d73dee3a4539f774abbdbf b/fuzz/corpus/qpack_decode/760e3549540e0dec05d73dee3a4539f774abbdbf
new file mode 100644
index 0000000..44fd69a
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/760e3549540e0dec05d73dee3a4539f774abbdbf
@@ -0,0 +1 @@
+ööÀÀãÀ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/7682559146802ca6556b2f9d29d9cebfe2af2a62 b/fuzz/corpus/qpack_decode/7682559146802ca6556b2f9d29d9cebfe2af2a62
new file mode 100644
index 0000000..89fcb6a
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/7682559146802ca6556b2f9d29d9cebfe2af2a62
@@ -0,0 +1 @@
+?.æææ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/76ed5d5053b9d77f06c9349af1ad3cfe64a34b47 b/fuzz/corpus/qpack_decode/76ed5d5053b9d77f06c9349af1ad3cfe64a34b47
new file mode 100644
index 0000000..870e338
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/76ed5d5053b9d77f06c9349af1ad3cfe64a34b47
@@ -0,0 +1 @@
+ìúúúú
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/774bfcc5cb7dcf2e9421c565f00a8466099b009f b/fuzz/corpus/qpack_decode/774bfcc5cb7dcf2e9421c565f00a8466099b009f
new file mode 100644
index 0000000..5e450a5
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/774bfcc5cb7dcf2e9421c565f00a8466099b009f
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/7846dcd4852f005382a08c620b01cdd37d8c8105 b/fuzz/corpus/qpack_decode/7846dcd4852f005382a08c620b01cdd37d8c8105
new file mode 100644
index 0000000..a10d3d6
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/7846dcd4852f005382a08c620b01cdd37d8c8105
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/7a14213dd16b0ff54614db0f6fa5c92e7ddd003c b/fuzz/corpus/qpack_decode/7a14213dd16b0ff54614db0f6fa5c92e7ddd003c
new file mode 100644
index 0000000..cdb3e16
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/7a14213dd16b0ff54614db0f6fa5c92e7ddd003c
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/7adb4b2b01b02d776941eee489bb4d6dd1679c9b b/fuzz/corpus/qpack_decode/7adb4b2b01b02d776941eee489bb4d6dd1679c9b
new file mode 100644
index 0000000..f982a60
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/7adb4b2b01b02d776941eee489bb4d6dd1679c9b
@@ -0,0 +1 @@
+@í
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/7b97fcf1c756cb000b735bfe1caab8bb7de979d2 b/fuzz/corpus/qpack_decode/7b97fcf1c756cb000b735bfe1caab8bb7de979d2
new file mode 100644
index 0000000..e0d0872
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/7b97fcf1c756cb000b735bfe1caab8bb7de979d2
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/7bde08642b72f7ee94ca4411d004097185d0591f b/fuzz/corpus/qpack_decode/7bde08642b72f7ee94ca4411d004097185d0591f
new file mode 100644
index 0000000..934626e
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/7bde08642b72f7ee94ca4411d004097185d0591f
@@ -0,0 +1 @@
+1)ÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/7c39a4a29d006ba0cb8c63ba2bf141f059eee6aa b/fuzz/corpus/qpack_decode/7c39a4a29d006ba0cb8c63ba2bf141f059eee6aa
new file mode 100644
index 0000000..6533ec5
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/7c39a4a29d006ba0cb8c63ba2bf141f059eee6aa
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/7cecc99b16ea9add9bdf060e9ca988d1de27fe19 b/fuzz/corpus/qpack_decode/7cecc99b16ea9add9bdf060e9ca988d1de27fe19
new file mode 100644
index 0000000..954b1e0
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/7cecc99b16ea9add9bdf060e9ca988d1de27fe19
@@ -0,0 +1 @@
+!6ÑÑ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/7d6ba1e27eb2a88e8dc7c3ba192e1db8126be25b b/fuzz/corpus/qpack_decode/7d6ba1e27eb2a88e8dc7c3ba192e1db8126be25b
new file mode 100644
index 0000000..51300b3
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/7d6ba1e27eb2a88e8dc7c3ba192e1db8126be25b
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/7d9d5c3a6717115dacab918d72d3703e4d50ffc9 b/fuzz/corpus/qpack_decode/7d9d5c3a6717115dacab918d72d3703e4d50ffc9
new file mode 100644
index 0000000..95889fe
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/7d9d5c3a6717115dacab918d72d3703e4d50ffc9
@@ -0,0 +1 @@
+ÎÎÕÕÕÕ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/7dc0cac257f1d6addadff3d0ad79a0021016f1aa b/fuzz/corpus/qpack_decode/7dc0cac257f1d6addadff3d0ad79a0021016f1aa
new file mode 100644
index 0000000..e352caa
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/7dc0cac257f1d6addadff3d0ad79a0021016f1aa
@@ -0,0 +1,2 @@
+
+?ñññ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/7e851b9e588d08b165a5dd0d4fef0a93188c68a1 b/fuzz/corpus/qpack_decode/7e851b9e588d08b165a5dd0d4fef0a93188c68a1
new file mode 100644
index 0000000..ed0ba82
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/7e851b9e588d08b165a5dd0d4fef0a93188c68a1
@@ -0,0 +1 @@
+óØßß
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/7f86cdd00672fd7dc38f4f852232218f91137f16 b/fuzz/corpus/qpack_decode/7f86cdd00672fd7dc38f4f852232218f91137f16
new file mode 100644
index 0000000..89901e6
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/7f86cdd00672fd7dc38f4f852232218f91137f16
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/81e9c1db89bc488a985d1b49c7f8a4868a9e814c b/fuzz/corpus/qpack_decode/81e9c1db89bc488a985d1b49c7f8a4868a9e814c
new file mode 100644
index 0000000..0b4d6b2
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/81e9c1db89bc488a985d1b49c7f8a4868a9e814c
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/8293c275d07173b81c42c1700f05cba39887aeac b/fuzz/corpus/qpack_decode/8293c275d07173b81c42c1700f05cba39887aeac
new file mode 100644
index 0000000..0e72add
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/8293c275d07173b81c42c1700f05cba39887aeac
@@ -0,0 +1 @@
+ÒÒââââ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/82d9fea3e1cf306ebac72cdfcdf1bdfba0298d8e b/fuzz/corpus/qpack_decode/82d9fea3e1cf306ebac72cdfcdf1bdfba0298d8e
new file mode 100644
index 0000000..0e09e1c
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/82d9fea3e1cf306ebac72cdfcdf1bdfba0298d8e
@@ -0,0 +1 @@
+åéåéé
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/83aeeb5b621a6aed3ebac6195f864da183eeded6 b/fuzz/corpus/qpack_decode/83aeeb5b621a6aed3ebac6195f864da183eeded6
new file mode 100644
index 0000000..6855c8b
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/83aeeb5b621a6aed3ebac6195f864da183eeded6
@@ -0,0 +1 @@
+ù!ÿ!ÿ!
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/85a917f11d82d70af51ad1e6031f504d2c595306 b/fuzz/corpus/qpack_decode/85a917f11d82d70af51ad1e6031f504d2c595306
new file mode 100644
index 0000000..4f53fc4
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/85a917f11d82d70af51ad1e6031f504d2c595306
@@ -0,0 +1 @@
+ÒÒÒÒÒ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/85b73aeb57c1fb292d2b7a0970be4ada559196ae b/fuzz/corpus/qpack_decode/85b73aeb57c1fb292d2b7a0970be4ada559196ae
new file mode 100644
index 0000000..e719320
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/85b73aeb57c1fb292d2b7a0970be4ada559196ae
@@ -0,0 +1 @@
+qàqô
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/85e53271e14006f0265921d02d4d736cdc580b0b b/fuzz/corpus/qpack_decode/85e53271e14006f0265921d02d4d736cdc580b0b
new file mode 100644
index 0000000..ce542ef
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/85e53271e14006f0265921d02d4d736cdc580b0b
@@ -0,0 +1 @@
+ÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/8610bd4d02dfb5bcc68206c172948ceccd7b0f06 b/fuzz/corpus/qpack_decode/8610bd4d02dfb5bcc68206c172948ceccd7b0f06
new file mode 100644
index 0000000..c6d161f
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/8610bd4d02dfb5bcc68206c172948ceccd7b0f06
@@ -0,0 +1 @@
+)+ýýýýkÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/87b6aaf374ded0404c97c397cb19486fbbf75b9b b/fuzz/corpus/qpack_decode/87b6aaf374ded0404c97c397cb19486fbbf75b9b
new file mode 100644
index 0000000..24c6bd1
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/87b6aaf374ded0404c97c397cb19486fbbf75b9b
@@ -0,0 +1 @@
+ÅÅ<:ÅÇÅ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/87c56e1d3dcb2985e31b25031829595f01a98c9d b/fuzz/corpus/qpack_decode/87c56e1d3dcb2985e31b25031829595f01a98c9d
new file mode 100644
index 0000000..3b16a26
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/87c56e1d3dcb2985e31b25031829595f01a98c9d
@@ -0,0 +1 @@
++ûûûûû
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/8842648c397aed4db4b97078634a34912ffb1b40 b/fuzz/corpus/qpack_decode/8842648c397aed4db4b97078634a34912ffb1b40
new file mode 100644
index 0000000..c2681ad
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/8842648c397aed4db4b97078634a34912ffb1b40
@@ -0,0 +1 @@
+!$ê
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/887748fb5f1fd297a9f7fcd2e3fea48ca3a704ea b/fuzz/corpus/qpack_decode/887748fb5f1fd297a9f7fcd2e3fea48ca3a704ea
new file mode 100644
index 0000000..68a3bce
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/887748fb5f1fd297a9f7fcd2e3fea48ca3a704ea
@@ -0,0 +1 @@
+óÏØØØ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/88e0f0672ba32a06a0e0425880fd1742fab88b9b b/fuzz/corpus/qpack_decode/88e0f0672ba32a06a0e0425880fd1742fab88b9b
new file mode 100644
index 0000000..16acad7
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/88e0f0672ba32a06a0e0425880fd1742fab88b9b
@@ -0,0 +1 @@
+íÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/88ff73c4951dc5fb6818cca931fe5836d7533a0b b/fuzz/corpus/qpack_decode/88ff73c4951dc5fb6818cca931fe5836d7533a0b
new file mode 100644
index 0000000..73a3caa
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/88ff73c4951dc5fb6818cca931fe5836d7533a0b
@@ -0,0 +1 @@
+ÌÌÌÌÌ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/898801d667aff9b848f723b52e460b52a4f50d52 b/fuzz/corpus/qpack_decode/898801d667aff9b848f723b52e460b52a4f50d52
new file mode 100644
index 0000000..d6f7dae
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/898801d667aff9b848f723b52e460b52a4f50d52
@@ -0,0 +1 @@
+ï+ýý
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/8a139ea9c1f510eec672becc826ff8da11ff508d b/fuzz/corpus/qpack_decode/8a139ea9c1f510eec672becc826ff8da11ff508d
new file mode 100644
index 0000000..dee8296
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/8a139ea9c1f510eec672becc826ff8da11ff508d
@@ -0,0 +1 @@
+ÿÿþçÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/8a3757a54dce179c2fc392671beed180c41c2684 b/fuzz/corpus/qpack_decode/8a3757a54dce179c2fc392671beed180c41c2684
new file mode 100644
index 0000000..51b6797
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/8a3757a54dce179c2fc392671beed180c41c2684
@@ -0,0 +1 @@
++ÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/8b73196eadd69a47fcc1e5a733ff5ea28c1fc334 b/fuzz/corpus/qpack_decode/8b73196eadd69a47fcc1e5a733ff5ea28c1fc334
new file mode 100644
index 0000000..a30b706
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/8b73196eadd69a47fcc1e5a733ff5ea28c1fc334
@@ -0,0 +1 @@
+!/ïï
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/8c2718a089367eb9ffe18e34836769f4b92ddf09 b/fuzz/corpus/qpack_decode/8c2718a089367eb9ffe18e34836769f4b92ddf09
new file mode 100644
index 0000000..f0f5ebd
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/8c2718a089367eb9ffe18e34836769f4b92ddf09
@@ -0,0 +1 @@
+*îÿÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/8cdd1c93b9d0d0b389324e14c016bebbf3af319d b/fuzz/corpus/qpack_decode/8cdd1c93b9d0d0b389324e14c016bebbf3af319d
new file mode 100644
index 0000000..2c99b3d
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/8cdd1c93b9d0d0b389324e14c016bebbf3af319d
@@ -0,0 +1 @@
+¦¦èè
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/8d6d86ca876195fffe770f5e7ff15322aacbd6fd b/fuzz/corpus/qpack_decode/8d6d86ca876195fffe770f5e7ff15322aacbd6fd
new file mode 100644
index 0000000..9223920
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/8d6d86ca876195fffe770f5e7ff15322aacbd6fd
@@ -0,0 +1 @@
+y1ððð
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/8d7e7d273953beb87f64ddfea1356cd62336fd67 b/fuzz/corpus/qpack_decode/8d7e7d273953beb87f64ddfea1356cd62336fd67
new file mode 100644
index 0000000..b97f051
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/8d7e7d273953beb87f64ddfea1356cd62336fd67
@@ -0,0 +1 @@
+ýÄÄÄÄ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/8d8d84fbb5e7e62b41e23906694b10924e48f043 b/fuzz/corpus/qpack_decode/8d8d84fbb5e7e62b41e23906694b10924e48f043
new file mode 100644
index 0000000..9b1ce54
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/8d8d84fbb5e7e62b41e23906694b10924e48f043
@@ -0,0 +1 @@
+Òâêê
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/8efe635a6855115f384ec98e3d81a8a88e22d3f2 b/fuzz/corpus/qpack_decode/8efe635a6855115f384ec98e3d81a8a88e22d3f2
new file mode 100644
index 0000000..4448769
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/8efe635a6855115f384ec98e3d81a8a88e22d3f2
@@ -0,0 +1 @@
+ÏûÐÐÐ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/8f7d54945b6030c391ae3e5f2a25fd83f7112597 b/fuzz/corpus/qpack_decode/8f7d54945b6030c391ae3e5f2a25fd83f7112597
new file mode 100644
index 0000000..f01390b
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/8f7d54945b6030c391ae3e5f2a25fd83f7112597
@@ -0,0 +1 @@
+A÷îîÚî
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/8fca9331f1aa2bc20f83c732223ebbdc66013e3f b/fuzz/corpus/qpack_decode/8fca9331f1aa2bc20f83c732223ebbdc66013e3f
new file mode 100644
index 0000000..ab6b618
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/8fca9331f1aa2bc20f83c732223ebbdc66013e3f
@@ -0,0 +1 @@
+ö÷ÀÀÀÀ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/9022a1efce24a402d0e01ecfe8710bcf787b6d3e b/fuzz/corpus/qpack_decode/9022a1efce24a402d0e01ecfe8710bcf787b6d3e
new file mode 100644
index 0000000..3688463
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/9022a1efce24a402d0e01ecfe8710bcf787b6d3e
@@ -0,0 +1 @@
+åéééé
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/904961e377924e9ac4c7562560a8c51095f264c0 b/fuzz/corpus/qpack_decode/904961e377924e9ac4c7562560a8c51095f264c0
new file mode 100644
index 0000000..356cc39
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/904961e377924e9ac4c7562560a8c51095f264c0
@@ -0,0 +1 @@
+(=þþ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/90a7b6182d8f74b59bf4c555b3c47833cfaba962 b/fuzz/corpus/qpack_decode/90a7b6182d8f74b59bf4c555b3c47833cfaba962
new file mode 100644
index 0000000..0780094
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/90a7b6182d8f74b59bf4c555b3c47833cfaba962
@@ -0,0 +1 @@
+1ðÿÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/916f60bbd8912bd3c7df1a9a25081b8cdeafa172 b/fuzz/corpus/qpack_decode/916f60bbd8912bd3c7df1a9a25081b8cdeafa172
new file mode 100644
index 0000000..9f39e7d
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/916f60bbd8912bd3c7df1a9a25081b8cdeafa172
@@ -0,0 +1 @@
+2Ö÷÷
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/918de767f084f5459e70aa90da1b5645756894e6 b/fuzz/corpus/qpack_decode/918de767f084f5459e70aa90da1b5645756894e6
new file mode 100644
index 0000000..4074c5c
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/918de767f084f5459e70aa90da1b5645756894e6
@@ -0,0 +1 @@
+}ÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/9239676e1dd8ff443eb2a872272b262fd8f50480 b/fuzz/corpus/qpack_decode/9239676e1dd8ff443eb2a872272b262fd8f50480
new file mode 100644
index 0000000..ce6ecf6
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/9239676e1dd8ff443eb2a872272b262fd8f50480
@@ -0,0 +1 @@
+¦êèèèè
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/9279d328e42c04ffd42d2dd024f5f5c6b535d000 b/fuzz/corpus/qpack_decode/9279d328e42c04ffd42d2dd024f5f5c6b535d000
new file mode 100644
index 0000000..ba69c33
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/9279d328e42c04ffd42d2dd024f5f5c6b535d000
@@ -0,0 +1 @@
+=ÿÿ+ÿÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/92aea7114073ddfb8c169483e5cc221a45345c04 b/fuzz/corpus/qpack_decode/92aea7114073ddfb8c169483e5cc221a45345c04
new file mode 100644
index 0000000..c14cf47
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/92aea7114073ddfb8c169483e5cc221a45345c04
@@ -0,0 +1 @@
+óÙÙÙ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/92b413c1e0af9663039c21801dcf0b2821ac0211 b/fuzz/corpus/qpack_decode/92b413c1e0af9663039c21801dcf0b2821ac0211
new file mode 100644
index 0000000..7a30454
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/92b413c1e0af9663039c21801dcf0b2821ac0211
@@ -0,0 +1 @@
++È
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/93b31c0fabe097d63cb354ece52451c200a99441 b/fuzz/corpus/qpack_decode/93b31c0fabe097d63cb354ece52451c200a99441
new file mode 100644
index 0000000..29b8f34
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/93b31c0fabe097d63cb354ece52451c200a99441
@@ -0,0 +1 @@
+ô)ÃõÃõ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/944e2910d6f16e10c35af4cf462cb5671cca6e8b b/fuzz/corpus/qpack_decode/944e2910d6f16e10c35af4cf462cb5671cca6e8b
new file mode 100644
index 0000000..4caaa7d
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/944e2910d6f16e10c35af4cf462cb5671cca6e8b
@@ -0,0 +1 @@
+)ÄÄÄ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/94d4535b72de9b67b3cb4a1a7bf9e5ef762e5220 b/fuzz/corpus/qpack_decode/94d4535b72de9b67b3cb4a1a7bf9e5ef762e5220
new file mode 100644
index 0000000..7f9bba8
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/94d4535b72de9b67b3cb4a1a7bf9e5ef762e5220
@@ -0,0 +1 @@
+2ËÉÉÉÉ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/95043f606504b42dd3d4a1fdd04f02a3ca5ccd55 b/fuzz/corpus/qpack_decode/95043f606504b42dd3d4a1fdd04f02a3ca5ccd55
new file mode 100644
index 0000000..32bedb4
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/95043f606504b42dd3d4a1fdd04f02a3ca5ccd55
@@ -0,0 +1 @@
+ÿ+ÿ]ÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/955cf854888306bcfec262760d5275116bb89f5e b/fuzz/corpus/qpack_decode/955cf854888306bcfec262760d5275116bb89f5e
new file mode 100644
index 0000000..cc55700
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/955cf854888306bcfec262760d5275116bb89f5e
@@ -0,0 +1 @@
+öîÖÖÖ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/97be2fb0a60141992a8ed5fdbee5fbcd7f9de790 b/fuzz/corpus/qpack_decode/97be2fb0a60141992a8ed5fdbee5fbcd7f9de790
new file mode 100644
index 0000000..7b978c7
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/97be2fb0a60141992a8ed5fdbee5fbcd7f9de790
@@ -0,0 +1 @@
+ óÿÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/97ca30ed4e7eb680425aae49ac36e4ee5bc8fec1 b/fuzz/corpus/qpack_decode/97ca30ed4e7eb680425aae49ac36e4ee5bc8fec1
new file mode 100644
index 0000000..b895106
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/97ca30ed4e7eb680425aae49ac36e4ee5bc8fec1
@@ -0,0 +1 @@
+öÐÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/97ceaa82c165cfe6071af079be7255fc85bf1a3c b/fuzz/corpus/qpack_decode/97ceaa82c165cfe6071af079be7255fc85bf1a3c
new file mode 100644
index 0000000..29e181e
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/97ceaa82c165cfe6071af079be7255fc85bf1a3c
@@ -0,0 +1 @@
+ÿ
diff --git a/fuzz/corpus/qpack_decode/97f55eabd730e46c5939c359de17a59ad3a0d0b7 b/fuzz/corpus/qpack_decode/97f55eabd730e46c5939c359de17a59ad3a0d0b7
new file mode 100644
index 0000000..75e2ce8
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/97f55eabd730e46c5939c359de17a59ad3a0d0b7
@@ -0,0 +1 @@
+1-Ï
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/983121b88fea9e19e149f189b9b5b6f6c9fd297e b/fuzz/corpus/qpack_decode/983121b88fea9e19e149f189b9b5b6f6c9fd297e
new file mode 100644
index 0000000..0e391a6
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/983121b88fea9e19e149f189b9b5b6f6c9fd297e
@@ -0,0 +1 @@
+UUÍÍÍ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/9b7b94589cd77b35bda024935ed6f09e02173d54 b/fuzz/corpus/qpack_decode/9b7b94589cd77b35bda024935ed6f09e02173d54
new file mode 100644
index 0000000..0b3b645
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/9b7b94589cd77b35bda024935ed6f09e02173d54
@@ -0,0 +1 @@
+úú÷÷÷
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/9ca4f2bab966a837a21cf568200252ae5934642b b/fuzz/corpus/qpack_decode/9ca4f2bab966a837a21cf568200252ae5934642b
new file mode 100644
index 0000000..4d4007c
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/9ca4f2bab966a837a21cf568200252ae5934642b
@@ -0,0 +1 @@
+1 ÝÝÝÝ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/9ed33228a156ab3ee8aaa5c55d392ab1d04e49bb b/fuzz/corpus/qpack_decode/9ed33228a156ab3ee8aaa5c55d392ab1d04e49bb
new file mode 100644
index 0000000..5bb001f
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/9ed33228a156ab3ee8aaa5c55d392ab1d04e49bb
@@ -0,0 +1 @@
+*ïüüü
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/9fa727784ecae3d419f51dedc744ac7e9130d455 b/fuzz/corpus/qpack_decode/9fa727784ecae3d419f51dedc744ac7e9130d455
new file mode 100644
index 0000000..b091ea6
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/9fa727784ecae3d419f51dedc744ac7e9130d455
@@ -0,0 +1,2 @@
+ø
+(
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/9fe4b0269306af2d8cde56067dce4101db33619a b/fuzz/corpus/qpack_decode/9fe4b0269306af2d8cde56067dce4101db33619a
new file mode 100644
index 0000000..bcc0f23
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/9fe4b0269306af2d8cde56067dce4101db33619a
@@ -0,0 +1 @@
+ïýìììü
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/a08200bb6b6cee0937ad9d7294b2d8d6413dc12e b/fuzz/corpus/qpack_decode/a08200bb6b6cee0937ad9d7294b2d8d6413dc12e
new file mode 100644
index 0000000..886fafb
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/a08200bb6b6cee0937ad9d7294b2d8d6413dc12e
@@ -0,0 +1 @@
++çççç
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/a3c9fb74bd6e07a9dfdffd0c3d536d5f01424332 b/fuzz/corpus/qpack_decode/a3c9fb74bd6e07a9dfdffd0c3d536d5f01424332
new file mode 100644
index 0000000..dfb189f
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/a3c9fb74bd6e07a9dfdffd0c3d536d5f01424332
@@ -0,0 +1 @@
+/~*?
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/a3db4ff67a56780e66f0312a85c263ee2e7ebda1 b/fuzz/corpus/qpack_decode/a3db4ff67a56780e66f0312a85c263ee2e7ebda1
new file mode 100644
index 0000000..c8850b1
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/a3db4ff67a56780e66f0312a85c263ee2e7ebda1
@@ -0,0 +1 @@
+[ÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/a409472f9bde1212906b8327487defe1827bbfc7 b/fuzz/corpus/qpack_decode/a409472f9bde1212906b8327487defe1827bbfc7
new file mode 100644
index 0000000..434c683
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/a409472f9bde1212906b8327487defe1827bbfc7
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/a4394f612fcb34eba6060bef835285741dd58f21 b/fuzz/corpus/qpack_decode/a4394f612fcb34eba6060bef835285741dd58f21
new file mode 100644
index 0000000..a511a69
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/a4394f612fcb34eba6060bef835285741dd58f21
@@ -0,0 +1 @@
+*î÷
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/a48b4736860f91843b8957b932c42f91a149d55a b/fuzz/corpus/qpack_decode/a48b4736860f91843b8957b932c42f91a149d55a
new file mode 100644
index 0000000..c45857b
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/a48b4736860f91843b8957b932c42f91a149d55a
@@ -0,0 +1 @@
+öòòòò
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/a4ff01166f74f2cdd5077bd8575fb31ff9f7f205 b/fuzz/corpus/qpack_decode/a4ff01166f74f2cdd5077bd8575fb31ff9f7f205
new file mode 100644
index 0000000..4f9939e
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/a4ff01166f74f2cdd5077bd8575fb31ff9f7f205
@@ -0,0 +1 @@
+øÒÒÒ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/a50cb3702516af44293d4580c8007a65ac5aeb66 b/fuzz/corpus/qpack_decode/a50cb3702516af44293d4580c8007a65ac5aeb66
new file mode 100644
index 0000000..b43a53d
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/a50cb3702516af44293d4580c8007a65ac5aeb66
@@ -0,0 +1 @@
+Ø+ßßß
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/a54dc9571ee32a784dffc30865994cc8c2b6ff6b b/fuzz/corpus/qpack_decode/a54dc9571ee32a784dffc30865994cc8c2b6ff6b
new file mode 100644
index 0000000..05a1179
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/a54dc9571ee32a784dffc30865994cc8c2b6ff6b
@@ -0,0 +1 @@
+_1áá
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/a5c12cd7156d3c5fdd84a4e5c40f9c5d509afc44 b/fuzz/corpus/qpack_decode/a5c12cd7156d3c5fdd84a4e5c40f9c5d509afc44
new file mode 100644
index 0000000..fdd7170
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/a5c12cd7156d3c5fdd84a4e5c40f9c5d509afc44
@@ -0,0 +1 @@
+*îÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/a5d08c889eaf504580d50b259dd2266e29f11563 b/fuzz/corpus/qpack_decode/a5d08c889eaf504580d50b259dd2266e29f11563
new file mode 100644
index 0000000..6aec095
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/a5d08c889eaf504580d50b259dd2266e29f11563
@@ -0,0 +1 @@
+*óññÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/a7dd39fb46714cc10f5b008b6f52b82c9fb3b05c b/fuzz/corpus/qpack_decode/a7dd39fb46714cc10f5b008b6f52b82c9fb3b05c
new file mode 100644
index 0000000..baffcdb
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/a7dd39fb46714cc10f5b008b6f52b82c9fb3b05c
@@ -0,0 +1 @@
+þÓÓ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/a8892ef0f35b8c260ae84695c418ef55471e8e61 b/fuzz/corpus/qpack_decode/a8892ef0f35b8c260ae84695c418ef55471e8e61
new file mode 100644
index 0000000..55db621
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/a8892ef0f35b8c260ae84695c418ef55471e8e61
@@ -0,0 +1 @@
+úúÛÛÛ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/a8fbcb2cbb1bc3b3baeb9ed1a6d364e719326d7b b/fuzz/corpus/qpack_decode/a8fbcb2cbb1bc3b3baeb9ed1a6d364e719326d7b
new file mode 100644
index 0000000..1d34c34
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/a8fbcb2cbb1bc3b3baeb9ed1a6d364e719326d7b
@@ -0,0 +1 @@
+Ðÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/a9f8b4505da3e82a2c12fa4c1f9fefe2aeeb4f74 b/fuzz/corpus/qpack_decode/a9f8b4505da3e82a2c12fa4c1f9fefe2aeeb4f74
new file mode 100644
index 0000000..ca141d5
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/a9f8b4505da3e82a2c12fa4c1f9fefe2aeeb4f74
@@ -0,0 +1 @@
+ØØØØØØ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/aaad8fcce73984e4d0e4e9c298c6ac5d76008749 b/fuzz/corpus/qpack_decode/aaad8fcce73984e4d0e4e9c298c6ac5d76008749
new file mode 100644
index 0000000..28a00de
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/aaad8fcce73984e4d0e4e9c298c6ac5d76008749
@@ -0,0 +1 @@
+øÑÀÑÑÑÑÀ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/aaf76b4fd678d56c3b6c4d95a0635ff84d33f7c1 b/fuzz/corpus/qpack_decode/aaf76b4fd678d56c3b6c4d95a0635ff84d33f7c1
new file mode 100644
index 0000000..e90aa84
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/aaf76b4fd678d56c3b6c4d95a0635ff84d33f7c1
@@ -0,0 +1 @@
+óÏÁÏØ0
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/ab11ac135b8a2f281706b0cb4e35418cc946996e b/fuzz/corpus/qpack_decode/ab11ac135b8a2f281706b0cb4e35418cc946996e
new file mode 100644
index 0000000..2253db8
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ab11ac135b8a2f281706b0cb4e35418cc946996e
@@ -0,0 +1 @@
+åéé
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/ab4a4477d1040047d9f518bec1d7302443c8ce4e b/fuzz/corpus/qpack_decode/ab4a4477d1040047d9f518bec1d7302443c8ce4e
new file mode 100644
index 0000000..07a84ce
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ab4a4477d1040047d9f518bec1d7302443c8ce4e
@@ -0,0 +1 @@
+[ÿ#
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/ab818aab0de4c5888942169883964d4cf098bb62 b/fuzz/corpus/qpack_decode/ab818aab0de4c5888942169883964d4cf098bb62
new file mode 100644
index 0000000..d756df0
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ab818aab0de4c5888942169883964d4cf098bb62
@@ -0,0 +1 @@
+?ÿÿí
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/abe9a039192dcdc5d35ac1146b0d458db5fe2847 b/fuzz/corpus/qpack_decode/abe9a039192dcdc5d35ac1146b0d458db5fe2847
new file mode 100644
index 0000000..2df0c83
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/abe9a039192dcdc5d35ac1146b0d458db5fe2847
@@ -0,0 +1 @@
+H(ÞÞÞ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/ac098718fefcd65952b6955a67d1e3883477a623 b/fuzz/corpus/qpack_decode/ac098718fefcd65952b6955a67d1e3883477a623
new file mode 100644
index 0000000..9109f79
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ac098718fefcd65952b6955a67d1e3883477a623
@@ -0,0 +1 @@
+/
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/ac6e50c8805c43a35132a453c74abb21e15a7359 b/fuzz/corpus/qpack_decode/ac6e50c8805c43a35132a453c74abb21e15a7359
new file mode 100644
index 0000000..66cc67b
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ac6e50c8805c43a35132a453c74abb21e15a7359
@@ -0,0 +1 @@
+ÜÜÜ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/aca868cb502012189ba2cd942bbda17a89f199c0 b/fuzz/corpus/qpack_decode/aca868cb502012189ba2cd942bbda17a89f199c0
new file mode 100644
index 0000000..13c2c27
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/aca868cb502012189ba2cd942bbda17a89f199c0
@@ -0,0 +1 @@
+×-à
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/acde3d373ff3aef1cb306cefec67a6af8aaaee72 b/fuzz/corpus/qpack_decode/acde3d373ff3aef1cb306cefec67a6af8aaaee72
new file mode 100644
index 0000000..76d3110
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/acde3d373ff3aef1cb306cefec67a6af8aaaee72
@@ -0,0 +1 @@
+ÊÊåååå
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/ace37563a96f41eadfa932a654363fbd2c41db9d b/fuzz/corpus/qpack_decode/ace37563a96f41eadfa932a654363fbd2c41db9d
new file mode 100644
index 0000000..350c0ab
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ace37563a96f41eadfa932a654363fbd2c41db9d
@@ -0,0 +1 @@
+1-ÿ%
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/acf778e49f6732fdd0f7b2ad1325039afca4b6fb b/fuzz/corpus/qpack_decode/acf778e49f6732fdd0f7b2ad1325039afca4b6fb
new file mode 100644
index 0000000..36b15ef
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/acf778e49f6732fdd0f7b2ad1325039afca4b6fb
@@ -0,0 +1 @@
+íííí
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/ad7cf962013d95f5b570ab223b440769fe50e056 b/fuzz/corpus/qpack_decode/ad7cf962013d95f5b570ab223b440769fe50e056
new file mode 100644
index 0000000..6051927
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ad7cf962013d95f5b570ab223b440769fe50e056
@@ -0,0 +1 @@
+?.ææ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/ada3b5e9612ae460233a706486fdb90d17c5f709 b/fuzz/corpus/qpack_decode/ada3b5e9612ae460233a706486fdb90d17c5f709
new file mode 100644
index 0000000..588c121
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ada3b5e9612ae460233a706486fdb90d17c5f709
@@ -0,0 +1 @@
+ÿéÝîîëó1
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/ae80c54c939ef06fdf396beafe5e6ed05c1a1d04 b/fuzz/corpus/qpack_decode/ae80c54c939ef06fdf396beafe5e6ed05c1a1d04
new file mode 100644
index 0000000..3ec30df
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ae80c54c939ef06fdf396beafe5e6ed05c1a1d04
@@ -0,0 +1 @@
+%¯
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/aede77e3b44921c2eef61df172058959e4c89154 b/fuzz/corpus/qpack_decode/aede77e3b44921c2eef61df172058959e4c89154
new file mode 100644
index 0000000..71b0965
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/aede77e3b44921c2eef61df172058959e4c89154
@@ -0,0 +1 @@
+1[ùù
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/af013b4f32b27019d15a6f197598e7b7a8b9e46e b/fuzz/corpus/qpack_decode/af013b4f32b27019d15a6f197598e7b7a8b9e46e
new file mode 100644
index 0000000..da71b78
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/af013b4f32b27019d15a6f197598e7b7a8b9e46e
@@ -0,0 +1 @@
+ËÆÆÆÆ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/af8e29bc1479bfd3953e3e914dab24aeb6b2f3a9 b/fuzz/corpus/qpack_decode/af8e29bc1479bfd3953e3e914dab24aeb6b2f3a9
new file mode 100644
index 0000000..a15ee3e
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/af8e29bc1479bfd3953e3e914dab24aeb6b2f3a9
@@ -0,0 +1 @@
+11ð0
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/afb2e07f509ea1e6882583671dce20af3a75d314 b/fuzz/corpus/qpack_decode/afb2e07f509ea1e6882583671dce20af3a75d314
new file mode 100644
index 0000000..7caf4a9
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/afb2e07f509ea1e6882583671dce20af3a75d314
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/afb6103b720b66297a79f0c53886aa76248c59d2 b/fuzz/corpus/qpack_decode/afb6103b720b66297a79f0c53886aa76248c59d2
new file mode 100644
index 0000000..9b9c180
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/afb6103b720b66297a79f0c53886aa76248c59d2
@@ -0,0 +1 @@
+ïûÐÐÐÐ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/b01836131ee3e9976a3e3d019c721997614ffb67 b/fuzz/corpus/qpack_decode/b01836131ee3e9976a3e3d019c721997614ffb67
new file mode 100644
index 0000000..537aa9f
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/b01836131ee3e9976a3e3d019c721997614ffb67
@@ -0,0 +1 @@
+Òâêêêê
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/b01f2fbf82d93f658e46cb0f142e72df9877b02b b/fuzz/corpus/qpack_decode/b01f2fbf82d93f658e46cb0f142e72df9877b02b
new file mode 100644
index 0000000..1ff3b40
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/b01f2fbf82d93f658e46cb0f142e72df9877b02b
@@ -0,0 +1 @@
+ÓÓÓÓ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/b0578ad569b80a838f1f6e27a0f7024cea9ca180 b/fuzz/corpus/qpack_decode/b0578ad569b80a838f1f6e27a0f7024cea9ca180
new file mode 100644
index 0000000..81883b1
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/b0578ad569b80a838f1f6e27a0f7024cea9ca180
@@ -0,0 +1 @@
+ø)ý
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/b0de7fc0f0a12e637a923ec311d3ba65fee56ec1 b/fuzz/corpus/qpack_decode/b0de7fc0f0a12e637a923ec311d3ba65fee56ec1
new file mode 100644
index 0000000..d2304dd
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/b0de7fc0f0a12e637a923ec311d3ba65fee56ec1
@@ -0,0 +1 @@
+..Ã
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/b0ef0a9ad7da580f3eb171d50e81f746f7f28029 b/fuzz/corpus/qpack_decode/b0ef0a9ad7da580f3eb171d50e81f746f7f28029
new file mode 100644
index 0000000..5afd475
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/b0ef0a9ad7da580f3eb171d50e81f746f7f28029
@@ -0,0 +1 @@
+öÐÿÿÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/b148f8ed2d6c2ec6b34ecd08c8f242dbc49ff8e9 b/fuzz/corpus/qpack_decode/b148f8ed2d6c2ec6b34ecd08c8f242dbc49ff8e9
new file mode 100644
index 0000000..b44c91d
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/b148f8ed2d6c2ec6b34ecd08c8f242dbc49ff8e9
@@ -0,0 +1 @@
+ö®ÚÚÚÚ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/b33d5f762050649b644510cc598911c924fa4722 b/fuzz/corpus/qpack_decode/b33d5f762050649b644510cc598911c924fa4722
new file mode 100644
index 0000000..f37f3aa
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/b33d5f762050649b644510cc598911c924fa4722
@@ -0,0 +1 @@
+ÿÿÿÿÿÿÿÿë
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/b385f1dbf4263ab6ac6aea0141e8e20414c14954 b/fuzz/corpus/qpack_decode/b385f1dbf4263ab6ac6aea0141e8e20414c14954
new file mode 100644
index 0000000..e28cb0a
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/b385f1dbf4263ab6ac6aea0141e8e20414c14954
@@ -0,0 +1 @@
+þùùùùùùùùùÞ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/b3a152e4ef7a4a9b2c3a0f9fedd91ce7af575427 b/fuzz/corpus/qpack_decode/b3a152e4ef7a4a9b2c3a0f9fedd91ce7af575427
new file mode 100644
index 0000000..c88bcef
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/b3a152e4ef7a4a9b2c3a0f9fedd91ce7af575427
@@ -0,0 +1 @@
++¢øøøø
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/b4b9429587856456cdceaa62a4cde586e9a6c9e8 b/fuzz/corpus/qpack_decode/b4b9429587856456cdceaa62a4cde586e9a6c9e8
new file mode 100644
index 0000000..0099986
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/b4b9429587856456cdceaa62a4cde586e9a6c9e8
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/b4cb1c26942f125dc785ef1fb8b9cfd3ab34cfb1 b/fuzz/corpus/qpack_decode/b4cb1c26942f125dc785ef1fb8b9cfd3ab34cfb1
new file mode 100644
index 0000000..9dba05e
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/b4cb1c26942f125dc785ef1fb8b9cfd3ab34cfb1
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/b55f98a0d373da2ac08110c1a3f4a532e75e6889 b/fuzz/corpus/qpack_decode/b55f98a0d373da2ac08110c1a3f4a532e75e6889
new file mode 100644
index 0000000..eb1a51e
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/b55f98a0d373da2ac08110c1a3f4a532e75e6889
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/b633e8d7db20597b3a895fe83b76ea65fc139f20 b/fuzz/corpus/qpack_decode/b633e8d7db20597b3a895fe83b76ea65fc139f20
new file mode 100644
index 0000000..f55f763
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/b633e8d7db20597b3a895fe83b76ea65fc139f20
@@ -0,0 +1 @@
+/Ä-
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/b72b0ba50a14c80dc0d19e5240c2aa193940e84f b/fuzz/corpus/qpack_decode/b72b0ba50a14c80dc0d19e5240c2aa193940e84f
new file mode 100644
index 0000000..71675a4
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/b72b0ba50a14c80dc0d19e5240c2aa193940e84f
@@ -0,0 +1 @@
+ûÔû
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/b80b4300f9c9458e0565e13a7c0162b338cd4da9 b/fuzz/corpus/qpack_decode/b80b4300f9c9458e0565e13a7c0162b338cd4da9
new file mode 100644
index 0000000..995dddc
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/b80b4300f9c9458e0565e13a7c0162b338cd4da9
@@ -0,0 +1 @@
+=ÔÞÞ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/b8da48b7fb9c0fdb814688463c82834e7690cc89 b/fuzz/corpus/qpack_decode/b8da48b7fb9c0fdb814688463c82834e7690cc89
new file mode 100644
index 0000000..14ca024
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/b8da48b7fb9c0fdb814688463c82834e7690cc89
@@ -0,0 +1 @@
+ÌÌÌÌÌ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/bbd7aa5457268162b0c3b8ddd18949b49a7889aa b/fuzz/corpus/qpack_decode/bbd7aa5457268162b0c3b8ddd18949b49a7889aa
new file mode 100644
index 0000000..48bd99c
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/bbd7aa5457268162b0c3b8ddd18949b49a7889aa
@@ -0,0 +1 @@
+.æãã
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/bc1d5b4d00dd8d20c8e35f07683523f015d88d88 b/fuzz/corpus/qpack_decode/bc1d5b4d00dd8d20c8e35f07683523f015d88d88
new file mode 100644
index 0000000..39250ac
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/bc1d5b4d00dd8d20c8e35f07683523f015d88d88
@@ -0,0 +1 @@
+Ô:ÛÛ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/bc801df773f0084bd1b2069feb1420f35c6bbd7c b/fuzz/corpus/qpack_decode/bc801df773f0084bd1b2069feb1420f35c6bbd7c
new file mode 100644
index 0000000..b21a814
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/bc801df773f0084bd1b2069feb1420f35c6bbd7c
@@ -0,0 +1 @@
+Ø+ßßßß
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/bd325815b5404905ca0fdd7f47f28c44f0faa0bc b/fuzz/corpus/qpack_decode/bd325815b5404905ca0fdd7f47f28c44f0faa0bc
new file mode 100644
index 0000000..c7f7e4d
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/bd325815b5404905ca0fdd7f47f28c44f0faa0bc
@@ -0,0 +1 @@
+ÿÿï½
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/bf27ec9847edf3de2b3ae948c1b6c775b88e9b4c b/fuzz/corpus/qpack_decode/bf27ec9847edf3de2b3ae948c1b6c775b88e9b4c
new file mode 100644
index 0000000..a2c94c1
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/bf27ec9847edf3de2b3ae948c1b6c775b88e9b4c
@@ -0,0 +1 @@
+Ù*ûû
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/bfd140309b55388d4368abfb4493e3b926d8a107 b/fuzz/corpus/qpack_decode/bfd140309b55388d4368abfb4493e3b926d8a107
new file mode 100644
index 0000000..06cceb0
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/bfd140309b55388d4368abfb4493e3b926d8a107
@@ -0,0 +1 @@
+×-××
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/c077e58eecf841678475e04619f6bd11e9c3b68c b/fuzz/corpus/qpack_decode/c077e58eecf841678475e04619f6bd11e9c3b68c
new file mode 100644
index 0000000..a2d90dd
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/c077e58eecf841678475e04619f6bd11e9c3b68c
@@ -0,0 +1 @@
+ì*úúúú
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/c114dfe6a03d8c385683e409346cf943d727c630 b/fuzz/corpus/qpack_decode/c114dfe6a03d8c385683e409346cf943d727c630
new file mode 100644
index 0000000..44cc30f
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/c114dfe6a03d8c385683e409346cf943d727c630
@@ -0,0 +1 @@
+1 ÝÝ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/c1e97793349288fb2f568fff0df358552eb377b5 b/fuzz/corpus/qpack_decode/c1e97793349288fb2f568fff0df358552eb377b5
new file mode 100644
index 0000000..a43c130
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/c1e97793349288fb2f568fff0df358552eb377b5
@@ -0,0 +1 @@
+$ÎËËËË
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/c27493bb208cc0b30bff9c8c67260c7ddc6ba057 b/fuzz/corpus/qpack_decode/c27493bb208cc0b30bff9c8c67260c7ddc6ba057
new file mode 100644
index 0000000..b723b38
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/c27493bb208cc0b30bff9c8c67260c7ddc6ba057
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/c32bbc8ab30b946cedea8892e94bbc78ee0bbf98 b/fuzz/corpus/qpack_decode/c32bbc8ab30b946cedea8892e94bbc78ee0bbf98
new file mode 100644
index 0000000..c04ad32
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/c32bbc8ab30b946cedea8892e94bbc78ee0bbf98
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/c38d6017a99a150dc9c1e4e8152f01e4486c9842 b/fuzz/corpus/qpack_decode/c38d6017a99a150dc9c1e4e8152f01e4486c9842
new file mode 100644
index 0000000..8543877
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/c38d6017a99a150dc9c1e4e8152f01e4486c9842
@@ -0,0 +1 @@
+È?__?
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/c47497efd7175919cf755e3239683f59af8f014b b/fuzz/corpus/qpack_decode/c47497efd7175919cf755e3239683f59af8f014b
new file mode 100644
index 0000000..06047d8
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/c47497efd7175919cf755e3239683f59af8f014b
@@ -0,0 +1 @@
+?
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/c530ab4b2ea9e3721a4b87dc883453a4ed2bf956 b/fuzz/corpus/qpack_decode/c530ab4b2ea9e3721a4b87dc883453a4ed2bf956
new file mode 100644
index 0000000..168735b
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/c530ab4b2ea9e3721a4b87dc883453a4ed2bf956
@@ -0,0 +1 @@
+1vÇÇ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/c536ce3bfc347075cf823293168e1c37b8f0608b b/fuzz/corpus/qpack_decode/c536ce3bfc347075cf823293168e1c37b8f0608b
new file mode 100644
index 0000000..927531c
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/c536ce3bfc347075cf823293168e1c37b8f0608b
@@ -0,0 +1 @@
++1çççç
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/c5fc59005b93b187509db9aa3c7567c22f3d333a b/fuzz/corpus/qpack_decode/c5fc59005b93b187509db9aa3c7567c22f3d333a
new file mode 100644
index 0000000..aa449fc
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/c5fc59005b93b187509db9aa3c7567c22f3d333a
@@ -0,0 +1 @@
+1ÊÊÊÊÊ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/c66ae67583daf32c1cea1c29e4701f1933550ee3 b/fuzz/corpus/qpack_decode/c66ae67583daf32c1cea1c29e4701f1933550ee3
new file mode 100644
index 0000000..b891b10
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/c66ae67583daf32c1cea1c29e4701f1933550ee3
@@ -0,0 +1 @@
+/î
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/c710919e727b224fa4c8923a0e43274a27bcdd65 b/fuzz/corpus/qpack_decode/c710919e727b224fa4c8923a0e43274a27bcdd65
new file mode 100644
index 0000000..10a4cbc
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/c710919e727b224fa4c8923a0e43274a27bcdd65
@@ -0,0 +1 @@
+ÿÿÔ[
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/c8232da719422a3a91332975d029bba394c2668e b/fuzz/corpus/qpack_decode/c8232da719422a3a91332975d029bba394c2668e
new file mode 100644
index 0000000..0a3f3d7
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/c8232da719422a3a91332975d029bba394c2668e
@@ -0,0 +1 @@
+101°
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/c98f7b21ba594a47702b8ea96623a78c580cda18 b/fuzz/corpus/qpack_decode/c98f7b21ba594a47702b8ea96623a78c580cda18
new file mode 100644
index 0000000..bbe17e1
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/c98f7b21ba594a47702b8ea96623a78c580cda18
@@ -0,0 +1 @@
+?ÂÂÂÂ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/c99d56092377d6cbf02722b1856b0997f1fafa42 b/fuzz/corpus/qpack_decode/c99d56092377d6cbf02722b1856b0997f1fafa42
new file mode 100644
index 0000000..dabffef
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/c99d56092377d6cbf02722b1856b0997f1fafa42
@@ -0,0 +1 @@
+1ÞÔÔÔ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/c99eb953ed15a92b587ffed8044211e6cd804e2e b/fuzz/corpus/qpack_decode/c99eb953ed15a92b587ffed8044211e6cd804e2e
new file mode 100644
index 0000000..b0aba51
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/c99eb953ed15a92b587ffed8044211e6cd804e2e
@@ -0,0 +1 @@
+ÒÒÒÒÒÒÒÒÒ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/caf6fe4011b74d49e437d5932d86e4b7dabc301e b/fuzz/corpus/qpack_decode/caf6fe4011b74d49e437d5932d86e4b7dabc301e
new file mode 100644
index 0000000..0c26dab
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/caf6fe4011b74d49e437d5932d86e4b7dabc301e
@@ -0,0 +1 @@
+)ÈÈÈÈ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/cb2ac7afc0717cd7f3a576fb241307e7bfda47cb b/fuzz/corpus/qpack_decode/cb2ac7afc0717cd7f3a576fb241307e7bfda47cb
new file mode 100644
index 0000000..02ecce8
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/cb2ac7afc0717cd7f3a576fb241307e7bfda47cb
@@ -0,0 +1 @@
+11éÕ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/cba63b1f836324f5835c176bd0d4d0a0b3def09e b/fuzz/corpus/qpack_decode/cba63b1f836324f5835c176bd0d4d0a0b3def09e
new file mode 100644
index 0000000..f506fab
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/cba63b1f836324f5835c176bd0d4d0a0b3def09e
@@ -0,0 +1 @@
+ïýìììì
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/cc3f088b66e6f7689346adf09be7d12ed13bec85 b/fuzz/corpus/qpack_decode/cc3f088b66e6f7689346adf09be7d12ed13bec85
new file mode 100644
index 0000000..730cad9
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/cc3f088b66e6f7689346adf09be7d12ed13bec85
@@ -0,0 +1 @@
+öîÖÖ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/ccb9a2df52fa9196d64f93047a1fc105da59febb b/fuzz/corpus/qpack_decode/ccb9a2df52fa9196d64f93047a1fc105da59febb
new file mode 100644
index 0000000..e239ae3
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ccb9a2df52fa9196d64f93047a1fc105da59febb
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/ccc3751600a4dd9321e70642948b81f9264fe266 b/fuzz/corpus/qpack_decode/ccc3751600a4dd9321e70642948b81f9264fe266
new file mode 100644
index 0000000..20db151
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ccc3751600a4dd9321e70642948b81f9264fe266
@@ -0,0 +1 @@
+ÿ!ÿ!ÿ+
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/cd2abb5839df5f7459c93fb6206cfc8fb2ca59b2 b/fuzz/corpus/qpack_decode/cd2abb5839df5f7459c93fb6206cfc8fb2ca59b2
new file mode 100644
index 0000000..d769d96
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/cd2abb5839df5f7459c93fb6206cfc8fb2ca59b2
@@ -0,0 +1 @@
+*úññññ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/cd838d28596aef599fd12323d56ae236f6cffa1d b/fuzz/corpus/qpack_decode/cd838d28596aef599fd12323d56ae236f6cffa1d
new file mode 100644
index 0000000..4b78a61
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/cd838d28596aef599fd12323d56ae236f6cffa1d
@@ -0,0 +1 @@
+.ãââ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/ce2fd5e03c9528492e2df1b05cd219121049f68f b/fuzz/corpus/qpack_decode/ce2fd5e03c9528492e2df1b05cd219121049f68f
new file mode 100644
index 0000000..19b0883
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ce2fd5e03c9528492e2df1b05cd219121049f68f
@@ -0,0 +1 @@
+ÒÂ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/d076296403b26bc8da75936c1bc1cd2d8e090bbb b/fuzz/corpus/qpack_decode/d076296403b26bc8da75936c1bc1cd2d8e090bbb
new file mode 100644
index 0000000..2560912
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/d076296403b26bc8da75936c1bc1cd2d8e090bbb
@@ -0,0 +1 @@
+--àààà
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/d13b46d4cc88c3527cbe81067e342e72ded7bb2f b/fuzz/corpus/qpack_decode/d13b46d4cc88c3527cbe81067e342e72ded7bb2f
new file mode 100644
index 0000000..d247137
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/d13b46d4cc88c3527cbe81067e342e72ded7bb2f
@@ -0,0 +1 @@
+++ÿ"ÿ"
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/d1be237fa9dbd83b74871757d0da1f57f4315acd b/fuzz/corpus/qpack_decode/d1be237fa9dbd83b74871757d0da1f57f4315acd
new file mode 100644
index 0000000..6bbda5b
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/d1be237fa9dbd83b74871757d0da1f57f4315acd
@@ -0,0 +1 @@
+öÐÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/d1c629488469e8adfca11b1151abde9f30226b54 b/fuzz/corpus/qpack_decode/d1c629488469e8adfca11b1151abde9f30226b54
new file mode 100644
index 0000000..fc5f304
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/d1c629488469e8adfca11b1151abde9f30226b54
@@ -0,0 +1 @@
+ääääääääää
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/d347077d960f4146afb2d032ad4a592d9f65d2e5 b/fuzz/corpus/qpack_decode/d347077d960f4146afb2d032ad4a592d9f65d2e5
new file mode 100644
index 0000000..778a6b1
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/d347077d960f4146afb2d032ad4a592d9f65d2e5
@@ -0,0 +1 @@
+*îó
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/d41873c2b639232060eb1ecb4651f3013b87ada9 b/fuzz/corpus/qpack_decode/d41873c2b639232060eb1ecb4651f3013b87ada9
new file mode 100644
index 0000000..05a29c1
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/d41873c2b639232060eb1ecb4651f3013b87ada9
@@ -0,0 +1 @@
+ÆÆöööö
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/d42428711dc6c18ec63bfa1ba1f7b576895b37cd b/fuzz/corpus/qpack_decode/d42428711dc6c18ec63bfa1ba1f7b576895b37cd
new file mode 100644
index 0000000..bc241a7
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/d42428711dc6c18ec63bfa1ba1f7b576895b37cd
@@ -0,0 +1 @@
+#ç*2
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/d4446056a3bf8bbfcdf23e13fd688359554c967a b/fuzz/corpus/qpack_decode/d4446056a3bf8bbfcdf23e13fd688359554c967a
new file mode 100644
index 0000000..dd003c3
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/d4446056a3bf8bbfcdf23e13fd688359554c967a
@@ -0,0 +1 @@
+)ÈÈ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/d447b6bb8ef8297384aa8e342b04770bf2de9087 b/fuzz/corpus/qpack_decode/d447b6bb8ef8297384aa8e342b04770bf2de9087
new file mode 100644
index 0000000..425d022
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/d447b6bb8ef8297384aa8e342b04770bf2de9087
@@ -0,0 +1 @@
+#ïü
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/d4faa7f693fb609c526cde36e042a6c1779307aa b/fuzz/corpus/qpack_decode/d4faa7f693fb609c526cde36e042a6c1779307aa
new file mode 100644
index 0000000..6922af2
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/d4faa7f693fb609c526cde36e042a6c1779307aa
@@ -0,0 +1 @@
+񋋋
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/d5114b086b721f2c87ea7152025792958ab4c629 b/fuzz/corpus/qpack_decode/d5114b086b721f2c87ea7152025792958ab4c629
new file mode 100644
index 0000000..ae1354e
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/d5114b086b721f2c87ea7152025792958ab4c629
@@ -0,0 +1 @@
+@
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/d59b0a6d8d77f1aebfe2fc77989c2be9c5c2a88a b/fuzz/corpus/qpack_decode/d59b0a6d8d77f1aebfe2fc77989c2be9c5c2a88a
new file mode 100644
index 0000000..1d18c8a
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/d59b0a6d8d77f1aebfe2fc77989c2be9c5c2a88a
@@ -0,0 +1 @@
+à-àà
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/d5eb1d2078f1ffbc37a1841eaf544b32975343c5 b/fuzz/corpus/qpack_decode/d5eb1d2078f1ffbc37a1841eaf544b32975343c5
new file mode 100644
index 0000000..62f3594
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/d5eb1d2078f1ffbc37a1841eaf544b32975343c5
@@ -0,0 +1 @@
+++ÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/d808c7bd2e01e6d4efeada20219541f67330be04 b/fuzz/corpus/qpack_decode/d808c7bd2e01e6d4efeada20219541f67330be04
new file mode 100644
index 0000000..2d71a86
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/d808c7bd2e01e6d4efeada20219541f67330be04
@@ -0,0 +1 @@
++ûûûû
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/d877f331bee4a254a0276b8644fc79f0f365735c b/fuzz/corpus/qpack_decode/d877f331bee4a254a0276b8644fc79f0f365735c
new file mode 100644
index 0000000..06d8ea5
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/d877f331bee4a254a0276b8644fc79f0f365735c
@@ -0,0 +1 @@
+UUÍÍ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/d9ee24b43d84a7ae47f993fe347abb1b5af87244 b/fuzz/corpus/qpack_decode/d9ee24b43d84a7ae47f993fe347abb1b5af87244
new file mode 100644
index 0000000..491af26
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/d9ee24b43d84a7ae47f993fe347abb1b5af87244
@@ -0,0 +1 @@
+ààààà
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/dbdf5f20a84d27d4aab969544f6923dbb22b20f6 b/fuzz/corpus/qpack_decode/dbdf5f20a84d27d4aab969544f6923dbb22b20f6
new file mode 100644
index 0000000..ca43980
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/dbdf5f20a84d27d4aab969544f6923dbb22b20f6
@@ -0,0 +1 @@
+úúÛÛÛÛ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/dcf831459ba90de01bc3f01cd3ae73a660e65699 b/fuzz/corpus/qpack_decode/dcf831459ba90de01bc3f01cd3ae73a660e65699
new file mode 100644
index 0000000..a1dd04b
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/dcf831459ba90de01bc3f01cd3ae73a660e65699
@@ -0,0 +1 @@
+ö)ÃÃÃ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/dd376fcb9fd9dc3efaef8ed4654f4bc43271bbaf b/fuzz/corpus/qpack_decode/dd376fcb9fd9dc3efaef8ed4654f4bc43271bbaf
new file mode 100644
index 0000000..a0ccfcb
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/dd376fcb9fd9dc3efaef8ed4654f4bc43271bbaf
@@ -0,0 +1 @@
+=ÿÿ+ÿ]
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/dd384ff24d1d47fdcdf88b7b1d47dd2bd0e43c7d b/fuzz/corpus/qpack_decode/dd384ff24d1d47fdcdf88b7b1d47dd2bd0e43c7d
new file mode 100644
index 0000000..0b86f71
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/dd384ff24d1d47fdcdf88b7b1d47dd2bd0e43c7d
@@ -0,0 +1 @@
+æããããã
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/ddd77c0f36ced541f5c017064f8311eb57784c76 b/fuzz/corpus/qpack_decode/ddd77c0f36ced541f5c017064f8311eb57784c76
new file mode 100644
index 0000000..4820e77
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ddd77c0f36ced541f5c017064f8311eb57784c76
@@ -0,0 +1 @@
+æ:ããã
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/ddeec0588789faf5aed3fafc6168360cdbb9bf5b b/fuzz/corpus/qpack_decode/ddeec0588789faf5aed3fafc6168360cdbb9bf5b
new file mode 100644
index 0000000..6a730cc
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ddeec0588789faf5aed3fafc6168360cdbb9bf5b
@@ -0,0 +1 @@
+1ðÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/de5d9fc87976ecfc31355c7c6b60ecca537132ea b/fuzz/corpus/qpack_decode/de5d9fc87976ecfc31355c7c6b60ecca537132ea
new file mode 100644
index 0000000..78abf63
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/de5d9fc87976ecfc31355c7c6b60ecca537132ea
@@ -0,0 +1 @@
+rÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/de9f5b47e6fef0859b6880e50a4e517c348f2ac6 b/fuzz/corpus/qpack_decode/de9f5b47e6fef0859b6880e50a4e517c348f2ac6
new file mode 100644
index 0000000..bcf0094
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/de9f5b47e6fef0859b6880e50a4e517c348f2ac6
@@ -0,0 +1 @@
+11ðð
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/df203745a3a87e1caff6aa641db38704371ac0a4 b/fuzz/corpus/qpack_decode/df203745a3a87e1caff6aa641db38704371ac0a4
new file mode 100644
index 0000000..e5d70ae
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/df203745a3a87e1caff6aa641db38704371ac0a4
@@ -0,0 +1 @@
+*ïÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/dfc7c4433d71271ae50eef861ff3ff69f3e1b904 b/fuzz/corpus/qpack_decode/dfc7c4433d71271ae50eef861ff3ff69f3e1b904
new file mode 100644
index 0000000..a289094
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/dfc7c4433d71271ae50eef861ff3ff69f3e1b904
@@ -0,0 +1 @@
+óÙÙÙÙ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/e2920be6c2e662ddb1746434634850349e91ff13 b/fuzz/corpus/qpack_decode/e2920be6c2e662ddb1746434634850349e91ff13
new file mode 100644
index 0000000..9feddf1
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/e2920be6c2e662ddb1746434634850349e91ff13
@@ -0,0 +1 @@
+2¸ÄÄÄÄ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/e2f464dc8c5062fc5eb5d68ee6483f54728c06f2 b/fuzz/corpus/qpack_decode/e2f464dc8c5062fc5eb5d68ee6483f54728c06f2
new file mode 100644
index 0000000..b627b23
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/e2f464dc8c5062fc5eb5d68ee6483f54728c06f2
@@ -0,0 +1 @@
+11)/
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/e449c4f03c81524984675253869cc81d11ec825a b/fuzz/corpus/qpack_decode/e449c4f03c81524984675253869cc81d11ec825a
new file mode 100644
index 0000000..a44a1f3
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/e449c4f03c81524984675253869cc81d11ec825a
@@ -0,0 +1 @@
+1>É
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/e4606e40122ccf5f7bc773ac0f8a71b577ccd169 b/fuzz/corpus/qpack_decode/e4606e40122ccf5f7bc773ac0f8a71b577ccd169
new file mode 100644
index 0000000..4f20015
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/e4606e40122ccf5f7bc773ac0f8a71b577ccd169
@@ -0,0 +1 @@
+?òò
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/e78c26cd8a84d0d078d2b064b001721d529ac8d8 b/fuzz/corpus/qpack_decode/e78c26cd8a84d0d078d2b064b001721d529ac8d8
new file mode 100644
index 0000000..4360c38
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/e78c26cd8a84d0d078d2b064b001721d529ac8d8
@@ -0,0 +1 @@
+__ááá
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/e7b3d29d70f0fe088140cd840481c45e341f78ff b/fuzz/corpus/qpack_decode/e7b3d29d70f0fe088140cd840481c45e341f78ff
new file mode 100644
index 0000000..25627e4
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/e7b3d29d70f0fe088140cd840481c45e341f78ff
@@ -0,0 +1 @@
+*'ïüü[
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/e876f331c68bba111f69062c4ef13b360f13f3a3 b/fuzz/corpus/qpack_decode/e876f331c68bba111f69062c4ef13b360f13f3a3
new file mode 100644
index 0000000..4304603
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/e876f331c68bba111f69062c4ef13b360f13f3a3
@@ -0,0 +1 @@
+þþØ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/e92cead9c2e0461125338180ad72cb048d92adaa b/fuzz/corpus/qpack_decode/e92cead9c2e0461125338180ad72cb048d92adaa
new file mode 100644
index 0000000..6f5802f
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/e92cead9c2e0461125338180ad72cb048d92adaa
@@ -0,0 +1 @@
+1îë
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/ea842236c6f3c6aebe7d2df698bed3b0e749c50e b/fuzz/corpus/qpack_decode/ea842236c6f3c6aebe7d2df698bed3b0e749c50e
new file mode 100644
index 0000000..782509f
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ea842236c6f3c6aebe7d2df698bed3b0e749c50e
@@ -0,0 +1 @@
+ÿÿÿÿÿÿÿÿÿÿÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/ebffc79e43ea34881e615c06bb32fb7baa565a04 b/fuzz/corpus/qpack_decode/ebffc79e43ea34881e615c06bb32fb7baa565a04
new file mode 100644
index 0000000..b59eadc
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ebffc79e43ea34881e615c06bb32fb7baa565a04
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/ec03b5811eb2249aafa189511341a04f4e8a837a b/fuzz/corpus/qpack_decode/ec03b5811eb2249aafa189511341a04f4e8a837a
new file mode 100644
index 0000000..946d04e
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ec03b5811eb2249aafa189511341a04f4e8a837a
@@ -0,0 +1 @@
++¢ñ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/ed9718cda25871337a8a6b063d1f2b52a49466c6 b/fuzz/corpus/qpack_decode/ed9718cda25871337a8a6b063d1f2b52a49466c6
new file mode 100644
index 0000000..2f811bf
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ed9718cda25871337a8a6b063d1f2b52a49466c6
@@ -0,0 +1 @@
+*.æ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/ed991e047bcfc650a64d976010fcf1414ec22ba6 b/fuzz/corpus/qpack_decode/ed991e047bcfc650a64d976010fcf1414ec22ba6
new file mode 100644
index 0000000..3782a49
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ed991e047bcfc650a64d976010fcf1414ec22ba6
@@ -0,0 +1 @@
+++ÿÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/ee3025b9c75ccfcd02f0c093130f743e601f0d55 b/fuzz/corpus/qpack_decode/ee3025b9c75ccfcd02f0c093130f743e601f0d55
new file mode 100644
index 0000000..011d04d
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ee3025b9c75ccfcd02f0c093130f743e601f0d55
@@ -0,0 +1 @@
+þÓÓÓ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/ef5880817baa0645283b8d680b8b1265200e0d2f b/fuzz/corpus/qpack_decode/ef5880817baa0645283b8d680b8b1265200e0d2f
new file mode 100644
index 0000000..f9aacea
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ef5880817baa0645283b8d680b8b1265200e0d2f
@@ -0,0 +1 @@
+àqqÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/ef71daf3176a5ce69ca419407039aed15698cbcd b/fuzz/corpus/qpack_decode/ef71daf3176a5ce69ca419407039aed15698cbcd
new file mode 100644
index 0000000..5a5110b
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ef71daf3176a5ce69ca419407039aed15698cbcd
@@ -0,0 +1 @@
+#öÇÇÇ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/efa3e6fc959e5c2a02320c09001284bb36fc0b82 b/fuzz/corpus/qpack_decode/efa3e6fc959e5c2a02320c09001284bb36fc0b82
new file mode 100644
index 0000000..ef8202f
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/efa3e6fc959e5c2a02320c09001284bb36fc0b82
@@ -0,0 +1 @@
+/*_
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/f088eec22e671b1f10e9f48feb29c3c41e58dcf6 b/fuzz/corpus/qpack_decode/f088eec22e671b1f10e9f48feb29c3c41e58dcf6
new file mode 100644
index 0000000..f0ed804
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/f088eec22e671b1f10e9f48feb29c3c41e58dcf6
@@ -0,0 +1 @@
+'ïüü
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/f08fec5d5775ff22a1f1ff4549078178624d7fe6 b/fuzz/corpus/qpack_decode/f08fec5d5775ff22a1f1ff4549078178624d7fe6
new file mode 100644
index 0000000..b47e430
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/f08fec5d5775ff22a1f1ff4549078178624d7fe6
@@ -0,0 +1 @@
+àqqqq
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/f1de35e65f8c1a9914a58c34dbda3b0ae1a7eb2c b/fuzz/corpus/qpack_decode/f1de35e65f8c1a9914a58c34dbda3b0ae1a7eb2c
new file mode 100644
index 0000000..80a70e0
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/f1de35e65f8c1a9914a58c34dbda3b0ae1a7eb2c
@@ -0,0 +1 @@
+ååéå
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/f2a12ef8cd0d319281df5f6501763a558b57b580 b/fuzz/corpus/qpack_decode/f2a12ef8cd0d319281df5f6501763a558b57b580
new file mode 100644
index 0000000..a33cc99
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/f2a12ef8cd0d319281df5f6501763a558b57b580
@@ -0,0 +1 @@
+.æã
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/f33df30eca37893965546e24011c71525e435a0f b/fuzz/corpus/qpack_decode/f33df30eca37893965546e24011c71525e435a0f
new file mode 100644
index 0000000..2b89ca9
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/f33df30eca37893965546e24011c71525e435a0f
@@ -0,0 +1 @@
+$ÎËËË
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/f365523e00df550a666fc03179bd991c699f5931 b/fuzz/corpus/qpack_decode/f365523e00df550a666fc03179bd991c699f5931
new file mode 100644
index 0000000..eddbf65
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/f365523e00df550a666fc03179bd991c699f5931
@@ -0,0 +1 @@
+ØØØØØØØØØØØ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/f37c87ed1174080a3144f74ea3ba5f51c8a10235 b/fuzz/corpus/qpack_decode/f37c87ed1174080a3144f74ea3ba5f51c8a10235
new file mode 100644
index 0000000..79fc6e7
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/f37c87ed1174080a3144f74ea3ba5f51c8a10235
@@ -0,0 +1 @@
+=þõõ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/f3995cbb8cacc652e2c2df7047a93beb5d8a4d22 b/fuzz/corpus/qpack_decode/f3995cbb8cacc652e2c2df7047a93beb5d8a4d22
new file mode 100644
index 0000000..9f158e8
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/f3995cbb8cacc652e2c2df7047a93beb5d8a4d22
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/f3a557fcc5716ae116b98c50c55b5de5aebc6039 b/fuzz/corpus/qpack_decode/f3a557fcc5716ae116b98c50c55b5de5aebc6039
new file mode 100644
index 0000000..f134b02
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/f3a557fcc5716ae116b98c50c55b5de5aebc6039
@@ -0,0 +1 @@
++¢ø
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/f3f24aee46a0c212e456eff9d62503efbe7b8230 b/fuzz/corpus/qpack_decode/f3f24aee46a0c212e456eff9d62503efbe7b8230
new file mode 100644
index 0000000..1b08954
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/f3f24aee46a0c212e456eff9d62503efbe7b8230
@@ -0,0 +1 @@
++Ü
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/f575f73c58e30886d298480c36b0d53dc0b55253 b/fuzz/corpus/qpack_decode/f575f73c58e30886d298480c36b0d53dc0b55253
new file mode 100644
index 0000000..2953380
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/f575f73c58e30886d298480c36b0d53dc0b55253
@@ -0,0 +1 @@
+#öÇÇÇÇ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/f6c6d7df5dd163644f9d505dbae2d8d149af433f b/fuzz/corpus/qpack_decode/f6c6d7df5dd163644f9d505dbae2d8d149af433f
new file mode 100644
index 0000000..070e00d
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/f6c6d7df5dd163644f9d505dbae2d8d149af433f
@@ -0,0 +1 @@
+1>ÉÉ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/f6d131275f246f3dd626755da764c4c48205ac06 b/fuzz/corpus/qpack_decode/f6d131275f246f3dd626755da764c4c48205ac06
new file mode 100644
index 0000000..35871c7
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/f6d131275f246f3dd626755da764c4c48205ac06
@@ -0,0 +1 @@
+++ÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/f6d21f094d2570d2fd4a2d573835043aa689a359 b/fuzz/corpus/qpack_decode/f6d21f094d2570d2fd4a2d573835043aa689a359
new file mode 100644
index 0000000..0c75309
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/f6d21f094d2570d2fd4a2d573835043aa689a359
@@ -0,0 +1 @@
+1îëë
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/f836299301e3607d13422ba3113824efd4ca8a9a b/fuzz/corpus/qpack_decode/f836299301e3607d13422ba3113824efd4ca8a9a
new file mode 100644
index 0000000..28e3268
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/f836299301e3607d13422ba3113824efd4ca8a9a
@@ -0,0 +1 @@
+¦¦èèè
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/f86962aca14a0e7462055e8e62437fc999883dae b/fuzz/corpus/qpack_decode/f86962aca14a0e7462055e8e62437fc999883dae
new file mode 100644
index 0000000..6a74847
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/f86962aca14a0e7462055e8e62437fc999883dae
@@ -0,0 +1 @@
+öööö
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/f9a615ea7a544c93d57d36ed419959e8160f9d30 b/fuzz/corpus/qpack_decode/f9a615ea7a544c93d57d36ed419959e8160f9d30
new file mode 100644
index 0000000..4668874
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/f9a615ea7a544c93d57d36ed419959e8160f9d30
@@ -0,0 +1 @@
+î*ÿ
diff --git a/fuzz/corpus/qpack_decode/fb9383c6cc586995b596ff953606b482b72dc2b0 b/fuzz/corpus/qpack_decode/fb9383c6cc586995b596ff953606b482b72dc2b0
new file mode 100644
index 0000000..38e0e3d
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/fb9383c6cc586995b596ff953606b482b72dc2b0
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/fd2b656d2a64cccafa6614f3467a48896566dbf1 b/fuzz/corpus/qpack_decode/fd2b656d2a64cccafa6614f3467a48896566dbf1
new file mode 100644
index 0000000..0d5db70
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/fd2b656d2a64cccafa6614f3467a48896566dbf1
@@ -0,0 +1 @@
+?.ææææ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/fe9624059d279ff8c7d7df0d6d0b2e69daf3e123 b/fuzz/corpus/qpack_decode/fe9624059d279ff8c7d7df0d6d0b2e69daf3e123
new file mode 100644
index 0000000..bdaa7e1
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/fe9624059d279ff8c7d7df0d6d0b2e69daf3e123
Binary files differ
diff --git a/fuzz/corpus/qpack_decode/ffd78fdf7e03056b6bcd490d0e8e1ba20da0532f b/fuzz/corpus/qpack_decode/ffd78fdf7e03056b6bcd490d0e8e1ba20da0532f
new file mode 100644
index 0000000..f8a0beb
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ffd78fdf7e03056b6bcd490d0e8e1ba20da0532f
@@ -0,0 +1 @@
+)+ýýý½ýeÿÿÿ
\ No newline at end of file
diff --git a/fuzz/corpus/qpack_decode/ffd8764a05edef58e34aa23949f9c5ea170bce6e b/fuzz/corpus/qpack_decode/ffd8764a05edef58e34aa23949f9c5ea170bce6e
new file mode 100644
index 0000000..12d26a9
--- /dev/null
+++ b/fuzz/corpus/qpack_decode/ffd8764a05edef58e34aa23949f9c5ea170bce6e
@@ -0,0 +1 @@
+áááááááááá
\ No newline at end of file
diff --git a/fuzz/mayhem/packet_recv_client/Mayhemfile b/fuzz/mayhem/packet_recv_client/Mayhemfile
new file mode 100755
index 0000000..3efdf10
--- /dev/null
+++ b/fuzz/mayhem/packet_recv_client/Mayhemfile
@@ -0,0 +1,15 @@
+version: '1.0'
+
+project: quiche
+
+target: packet-recv-client-libfuzzer
+
+baseimage: kestrel.forallsecure.com:5000/ghedo/quiche-libfuzzer:1
+
+advanced_triage: false
+
+cmds:
+ - cmd: /home/mayhem/packet_recv_client
+ libfuzzer: true
+ asan: true
+ timeout: 5
diff --git a/fuzz/mayhem/packet_recv_client/corpus b/fuzz/mayhem/packet_recv_client/corpus
new file mode 120000
index 0000000..4acf030
--- /dev/null
+++ b/fuzz/mayhem/packet_recv_client/corpus
@@ -0,0 +1 @@
+../../corpus/packet_recv_server
\ No newline at end of file
diff --git a/fuzz/mayhem/packet_recv_server/Mayhemfile b/fuzz/mayhem/packet_recv_server/Mayhemfile
new file mode 100755
index 0000000..e2709b2
--- /dev/null
+++ b/fuzz/mayhem/packet_recv_server/Mayhemfile
@@ -0,0 +1,16 @@
+version: '1.0'
+
+project: quiche
+
+target: packet-recv-server-libfuzzer
+
+baseimage: kestrel.forallsecure.com:5000/ghedo/quiche-libfuzzer:1
+
+advanced_triage: false
+
+cmds:
+ - cmd: /home/mayhem/packet_recv_server
+ libfuzzer: true
+ asan: true
+ timeout: 5
+ env: { "QUICHE_FUZZ_CRT": "/home/mayhem/cert.crt", "QUICHE_FUZZ_KEY": "/home/mayhem/cert.key" }
diff --git a/fuzz/mayhem/packet_recv_server/corpus b/fuzz/mayhem/packet_recv_server/corpus
new file mode 120000
index 0000000..4acf030
--- /dev/null
+++ b/fuzz/mayhem/packet_recv_server/corpus
@@ -0,0 +1 @@
+../../corpus/packet_recv_server
\ No newline at end of file
diff --git a/fuzz/mayhem/qpack_decode/Mayhemfile b/fuzz/mayhem/qpack_decode/Mayhemfile
new file mode 100755
index 0000000..8ec6b78
--- /dev/null
+++ b/fuzz/mayhem/qpack_decode/Mayhemfile
@@ -0,0 +1,15 @@
+version: '1.0'
+
+project: quiche
+
+target: qpack-decode-libfuzzer
+
+baseimage: kestrel.forallsecure.com:5000/ghedo/quiche-libfuzzer:2
+
+advanced_triage: false
+
+cmds:
+ - cmd: /home/mayhem/qpack_decode
+ libfuzzer: true
+ asan: true
+ timeout: 5
diff --git a/fuzz/mayhem/qpack_decode/corpus b/fuzz/mayhem/qpack_decode/corpus
new file mode 120000
index 0000000..55f28bc
--- /dev/null
+++ b/fuzz/mayhem/qpack_decode/corpus
@@ -0,0 +1 @@
+../../corpus/qpack_decode
\ No newline at end of file
diff --git a/fuzz/src/packet_recv_client.rs b/fuzz/src/packet_recv_client.rs
new file mode 100644
index 0000000..6f41b42
--- /dev/null
+++ b/fuzz/src/packet_recv_client.rs
@@ -0,0 +1,38 @@
+#![no_main]
+
+#[macro_use]
+extern crate libfuzzer_sys;
+
+#[macro_use]
+extern crate lazy_static;
+
+use std::sync::Mutex;
+
+lazy_static! {
+ static ref CONFIG: Mutex<quiche::Config> = {
+ let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
+ config
+ .set_application_protos(b"\x06proto1\x06proto2")
+ .unwrap();
+ config.set_initial_max_data(30);
+ config.set_initial_max_stream_data_bidi_local(15);
+ config.set_initial_max_stream_data_bidi_remote(15);
+ config.set_initial_max_stream_data_uni(10);
+ config.set_initial_max_streams_bidi(3);
+ config.set_initial_max_streams_uni(3);
+ config.verify_peer(false);
+
+ Mutex::new(config)
+ };
+}
+
+static SCID: [u8; 16] = [0; 16];
+
+fuzz_target!(|data: &[u8]| {
+ let mut buf = data.to_vec();
+ let mut conn =
+ quiche::connect(Some("quic.tech"), &SCID, &mut CONFIG.lock().unwrap())
+ .unwrap();
+
+ conn.recv(&mut buf).ok();
+});
diff --git a/fuzz/src/packet_recv_server.rs b/fuzz/src/packet_recv_server.rs
new file mode 100644
index 0000000..c0f262d
--- /dev/null
+++ b/fuzz/src/packet_recv_server.rs
@@ -0,0 +1,43 @@
+#![no_main]
+
+#[macro_use]
+extern crate libfuzzer_sys;
+
+#[macro_use]
+extern crate lazy_static;
+
+use std::sync::Mutex;
+
+lazy_static! {
+ static ref CONFIG: Mutex<quiche::Config> = {
+ let crt_path = std::env::var("QUICHE_FUZZ_CRT")
+ .unwrap_or_else(|_| "examples/cert.crt".to_string());
+ let key_path = std::env::var("QUICHE_FUZZ_KEY")
+ .unwrap_or_else(|_| "examples/cert.key".to_string());
+
+ let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
+ config.load_cert_chain_from_pem_file(&crt_path).unwrap();
+ config.load_priv_key_from_pem_file(&key_path).unwrap();
+ config
+ .set_application_protos(b"\x06proto1\x06proto2")
+ .unwrap();
+ config.set_initial_max_data(30);
+ config.set_initial_max_stream_data_bidi_local(15);
+ config.set_initial_max_stream_data_bidi_remote(15);
+ config.set_initial_max_stream_data_uni(10);
+ config.set_initial_max_streams_bidi(3);
+ config.set_initial_max_streams_uni(3);
+
+ Mutex::new(config)
+ };
+}
+
+static SCID: [u8; 16] = [0; 16];
+
+fuzz_target!(|data: &[u8]| {
+ let mut buf = data.to_vec();
+ let mut conn =
+ quiche::accept(&SCID, None, &mut CONFIG.lock().unwrap()).unwrap();
+
+ conn.recv(&mut buf).ok();
+});
diff --git a/fuzz/src/qpack_decode.rs b/fuzz/src/qpack_decode.rs
new file mode 100644
index 0000000..50d650c
--- /dev/null
+++ b/fuzz/src/qpack_decode.rs
@@ -0,0 +1,11 @@
+#![no_main]
+
+#[macro_use]
+extern crate libfuzzer_sys;
+
+fuzz_target!(|data: &[u8]| {
+ let mut buf = data.to_vec();
+ let mut decoder = quiche::h3::qpack::Decoder::new();
+
+ decoder.decode(&mut buf, std::u64::MAX).ok();
+});
diff --git a/include/quiche.h b/include/quiche.h
index 6781bf1..07340f0 100644
--- a/include/quiche.h
+++ b/include/quiche.h
@@ -39,10 +39,10 @@
//
// The current QUIC wire version.
-#define QUICHE_PROTOCOL_VERSION 0xff000014
+#define QUICHE_PROTOCOL_VERSION 0xff000017
// The maximum length of a connection ID.
-#define QUICHE_MAX_CONN_ID_LEN 18
+#define QUICHE_MAX_CONN_ID_LEN 20
// The minimum length of Initial packets sent by a client.
#define QUICHE_MIN_CLIENT_INITIAL_LEN 1200
@@ -91,6 +91,9 @@
QUICHE_ERR_FINAL_SIZE = -13,
};
+// Returns a human readable string with the quiche version number.
+const char *quiche_version(void);
+
// Enables logging. |cb| will be called with log messages
void quiche_enable_debug_logging(void (*cb)(const char *line, void *argp),
void *argp);
@@ -120,7 +123,7 @@
// Configures the list of supported application protocols.
int quiche_config_set_application_protos(quiche_config *config,
- uint8_t *protos,
+ const uint8_t *protos,
size_t protos_len);
// Sets the `idle_timeout` transport parameter.
@@ -153,8 +156,8 @@
// Sets the `max_ack_delay` transport parameter.
void quiche_config_set_max_ack_delay(quiche_config *config, uint64_t v);
-// Sets the `disable_migration` transport parameter.
-void quiche_config_set_disable_migration(quiche_config *config, bool v);
+// Sets the `disable_active_migration` transport parameter.
+void quiche_config_set_disable_active_migration(quiche_config *config, bool v);
// Frees the config object.
void quiche_config_free(quiche_config *config);
@@ -222,26 +225,35 @@
int quiche_conn_stream_shutdown(quiche_conn *conn, uint64_t stream_id,
enum quiche_shutdown direction, uint64_t err);
+ssize_t quiche_conn_stream_capacity(quiche_conn *conn, uint64_t stream_id);
+
// Returns true if all the data has been read from the specified stream.
bool quiche_conn_stream_finished(quiche_conn *conn, uint64_t stream_id);
-// Fetches the next stream that has outstanding data to read. Returns false if
-// there are no readable streams.
-bool quiche_readable_next(quiche_conn *conn, uint64_t *stream_id);
+typedef struct StreamIter quiche_stream_iter;
-// Returns the amount of time until the next timeout event, as nanoseconds.
+// Returns an iterator over streams that have outstanding data to read.
+quiche_stream_iter *quiche_conn_readable(quiche_conn *conn);
+
+// Returns an iterator over streams that can be written to.
+quiche_stream_iter *quiche_conn_writable(quiche_conn *conn);
+
+// Returns the amount of time until the next timeout event, in nanoseconds.
uint64_t quiche_conn_timeout_as_nanos(quiche_conn *conn);
+// Returns the amount of time until the next timeout event, in milliseconds.
+uint64_t quiche_conn_timeout_as_millis(quiche_conn *conn);
+
// Processes a timeout event.
void quiche_conn_on_timeout(quiche_conn *conn);
// Closes the connection with the given error and reason.
-int quiche_conn_close(quiche_conn *conn, bool app, uint16_t err,
+int quiche_conn_close(quiche_conn *conn, bool app, uint64_t err,
const uint8_t *reason, size_t reason_len);
// Returns the negotiated ALPN protocol.
-uint8_t *quiche_conn_application_proto(quiche_conn *conn, uint8_t **out,
- size_t *out_len);
+void quiche_conn_application_proto(quiche_conn *conn, const uint8_t **out,
+ size_t *out_len);
// Returns true if the connection handshake is complete.
bool quiche_conn_is_established(quiche_conn *conn);
@@ -249,6 +261,13 @@
// Returns true if the connection is closed.
bool quiche_conn_is_closed(quiche_conn *conn);
+// Fetches the next stream from the given iterator. Returns false if there are
+// no more elements in the iterator.
+bool quiche_stream_iter_next(quiche_stream_iter *iter, uint64_t *stream_id);
+
+// Frees the given stream iterator object.
+void quiche_stream_iter_free(quiche_stream_iter *iter);
+
typedef struct {
// The number of QUIC packets received on this connection.
size_t recv;
@@ -277,16 +296,22 @@
//
/// The current HTTP/3 ALPN token.
-#define QUICHE_H3_APPLICATION_PROTOCOL "\x05h3-20"
+#define QUICHE_H3_APPLICATION_PROTOCOL "\x05h3-23"
// Stores configuration shared between multiple connections.
typedef struct Http3Config quiche_h3_config;
-// Creates a HTTP/3 config object with the given version.
-quiche_h3_config *quiche_h3_config_new(uint64_t num_placeholders,
- uint64_t max_header_list_size,
- uint64_t qpack_max_table_capacity,
- uint64_t qpack_blaocked_streams);
+// Creates an HTTP/3 config object with default settings values.
+quiche_h3_config *quiche_h3_config_new(void);
+
+// Sets the `SETTINGS_MAX_HEADER_LIST_SIZE` setting.
+void quiche_h3_config_set_max_header_list_size(quiche_h3_config *config, uint64_t v);
+
+// Sets the `SETTINGS_QPACK_MAX_TABLE_CAPACITY` setting.
+void quiche_h3_config_set_qpack_max_table_capacity(quiche_h3_config *config, uint64_t v);
+
+// Sets the `SETTINGS_QPACK_BLOCKED_STREAMS` setting.
+void quiche_h3_config_set_qpack_blocked_streams(quiche_h3_config *config, uint64_t v);
// Frees the HTTP/3 config object.
void quiche_h3_config_free(quiche_h3_config *config);
diff --git a/src/build.rs b/src/build.rs
index 8abb4c9..8ee97c5 100644
--- a/src/build.rs
+++ b/src/build.rs
@@ -1,5 +1,3 @@
-use cmake;
-
// Additional parameters for Android build of BoringSSL.
const CMAKE_PARAMS_ANDROID: &[(&str, &[(&str, &str)])] = &[
("aarch64", &[
@@ -55,12 +53,12 @@
]),
];
-/// Generate the platform-specific output path for lib
+/// Returns the platform-specific output path for lib.
///
/// MSVC generator on Windows place static libs in a target sub-folder,
/// so adjust library location based on platform and build target.
/// See issue: https://github.com/alexcrichton/cmake-rs/issues/18
-fn platform_output_path(lib: &str) -> String {
+fn get_boringssl_platform_output_path(lib: &str) -> String {
if cfg!(windows) {
if cfg!(debug_assertions) {
return format!("{}/Debug", lib);
@@ -72,9 +70,9 @@
};
}
-// Returns a new cmake::Config for building BoringSSL.
-//
-// It will add platform-specific parameters if needed.
+/// Returns a new cmake::Config for building BoringSSL.
+///
+/// It will add platform-specific parameters if needed.
fn get_boringssl_cmake_config() -> cmake::Config {
let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
let os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
@@ -122,25 +120,60 @@
};
}
+fn write_pkg_config() {
+ use std::io::prelude::*;
+
+ let profile = std::env::var("PROFILE").unwrap();
+ let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
+ let target_dir = format!("{}/target/{}", manifest_dir, profile);
+
+ let out_path = std::path::Path::new(&target_dir).join("quiche.pc");
+ let mut out_file = std::fs::File::create(&out_path).unwrap();
+
+ let include_dir = format!("{}/include", manifest_dir);
+ let version = std::env::var("CARGO_PKG_VERSION").unwrap();
+
+ let output = format!(
+ "# quiche
+
+includedir={}
+libdir={}
+
+Name: quiche
+Description: quiche library
+URL: https://github.com/cloudflare/quiche
+Version: {}
+Libs: -Wl,-rpath,${{libdir}} -L${{libdir}} -lquiche
+Cflags: -I${{includedir}}
+",
+ include_dir, target_dir, version
+ );
+
+ out_file.write_all(output.as_bytes()).unwrap();
+}
+
fn main() {
- #[cfg(feature = "no_bssl")]
- return;
+ if cfg!(feature = "boringssl-vendored") {
+ let bssl_dir = std::env::var("QUICHE_BSSL_PATH").unwrap_or_else(|_| {
+ get_boringssl_cmake_config()
+ .build_target("bssl")
+ .build()
+ .display()
+ .to_string()
+ });
- let bssl_dir = std::env::var("QUICHE_BSSL_PATH").unwrap_or_else(|_| {
- get_boringssl_cmake_config()
- .cflag("-fPIC")
- .build_target("bssl")
- .build()
- .display()
- .to_string()
- });
+ let crypto_path = get_boringssl_platform_output_path("crypto");
+ let crypto_dir = format!("{}/build/{}", bssl_dir, crypto_path);
+ println!("cargo:rustc-link-search=native={}", crypto_dir);
+ println!("cargo:rustc-link-lib=static=crypto");
- let crypto_dir =
- format!("{}/build/{}", bssl_dir, platform_output_path("crypto"));
- println!("cargo:rustc-link-search=native={}", crypto_dir);
- println!("cargo:rustc-link-lib=static=crypto");
+ let ssl_path = get_boringssl_platform_output_path("ssl");
+ let ssl_dir = format!("{}/build/{}", bssl_dir, ssl_path);
+ println!("cargo:rustc-link-search=native={}", ssl_dir);
+ println!("cargo:rustc-link-lib=static=ssl");
+ }
- let ssl_dir = format!("{}/build/{}", bssl_dir, platform_output_path("ssl"));
- println!("cargo:rustc-link-search=native={}", ssl_dir);
- println!("cargo:rustc-link-lib=static=ssl");
+ if cfg!(feature = "pkg-config-meta") {
+ write_pkg_config();
+ }
}
diff --git a/src/crypto.rs b/src/crypto.rs
index 5e34f95..c4deaff 100644
--- a/src/crypto.rs
+++ b/src/crypto.rs
@@ -26,26 +26,23 @@
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use ring::aead;
-use ring::digest;
use ring::hkdf;
-use ring::hmac;
use crate::Error;
use crate::Result;
-use crate::octets;
use crate::packet;
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Level {
- Initial = 0,
+ Initial = 0,
// Silence "variant is never constructed" warning because the value can
// be received from BoringSSL as part of the FFI callbacks.
#[allow(dead_code)]
- ZeroRTT = 1,
- Handshake = 2,
- Application = 3,
+ ZeroRTT = 1,
+ Handshake = 2,
+ OneRTT = 3,
}
impl Level {
@@ -55,7 +52,7 @@
packet::EPOCH_HANDSHAKE => Level::Handshake,
- packet::EPOCH_APPLICATION => Level::Application,
+ packet::EPOCH_APPLICATION => Level::OneRTT,
_ => unreachable!(),
}
@@ -91,11 +88,11 @@
}
}
- fn get_ring_digest(self) -> &'static digest::Algorithm {
+ fn get_ring_digest(self) -> hkdf::Algorithm {
match self {
- Algorithm::AES128_GCM => &digest::SHA256,
- Algorithm::AES256_GCM => &digest::SHA384,
- Algorithm::ChaCha20_Poly1305 => &digest::SHA256,
+ Algorithm::AES128_GCM => hkdf::HKDF_SHA256,
+ Algorithm::AES256_GCM => hkdf::HKDF_SHA384,
+ Algorithm::ChaCha20_Poly1305 => hkdf::HKDF_SHA256,
}
}
@@ -104,6 +101,10 @@
}
pub fn tag_len(self) -> usize {
+ if cfg!(fuzzing) {
+ return 0;
+ }
+
self.get_ring_aead().tag_len()
}
@@ -114,8 +115,11 @@
pub struct Open {
alg: Algorithm,
+
hp_key: aead::quic::HeaderProtectionKey,
- key: aead::OpeningKey,
+
+ key: aead::LessSafeKey,
+
nonce: Vec<u8>,
}
@@ -130,8 +134,10 @@
)
.map_err(|_| Error::CryptoFail)?,
- key: aead::OpeningKey::new(alg.get_ring_aead(), &key)
- .map_err(|_| Error::CryptoFail)?,
+ key: aead::LessSafeKey::new(
+ aead::UnboundKey::new(alg.get_ring_aead(), key)
+ .map_err(|_| Error::CryptoFail)?,
+ ),
nonce: Vec::from(iv),
@@ -142,11 +148,17 @@
pub fn open_with_u64_counter(
&self, counter: u64, ad: &[u8], buf: &mut [u8],
) -> Result<usize> {
+ if cfg!(fuzzing) {
+ return Ok(buf.len());
+ }
+
let nonce = make_nonce(&self.nonce, counter);
let ad = aead::Aad::from(ad);
- let plain = aead::open_in_place(&self.key, nonce, ad, 0, buf)
+ let plain = self
+ .key
+ .open_in_place(nonce, ad, buf)
.map_err(|_| Error::CryptoFail)?;
Ok(plain.len())
@@ -168,8 +180,11 @@
pub struct Seal {
alg: Algorithm,
+
hp_key: aead::quic::HeaderProtectionKey,
- key: aead::SealingKey,
+
+ key: aead::LessSafeKey,
+
nonce: Vec<u8>,
}
@@ -184,8 +199,10 @@
)
.map_err(|_| Error::CryptoFail)?,
- key: aead::SealingKey::new(alg.get_ring_aead(), key)
- .map_err(|_| Error::CryptoFail)?,
+ key: aead::LessSafeKey::new(
+ aead::UnboundKey::new(alg.get_ring_aead(), key)
+ .map_err(|_| Error::CryptoFail)?,
+ ),
nonce: Vec::from(iv),
@@ -195,13 +212,31 @@
pub fn seal_with_u64_counter(
&self, counter: u64, ad: &[u8], buf: &mut [u8],
- ) -> Result<usize> {
+ ) -> Result<()> {
+ if cfg!(fuzzing) {
+ return Ok(());
+ }
+
let nonce = make_nonce(&self.nonce, counter);
let ad = aead::Aad::from(ad);
- aead::seal_in_place(&self.key, nonce, ad, buf, self.alg().tag_len())
- .map_err(|_| Error::CryptoFail)
+ let tag_len = self.alg().tag_len();
+
+ let in_out_len =
+ buf.len().checked_sub(tag_len).ok_or(Error::CryptoFail)?;
+
+ let (in_out, tag_out) = buf.split_at_mut(in_out_len);
+
+ let tag = self
+ .key
+ .seal_in_place_separate_tag(nonce, ad, in_out)
+ .map_err(|_| Error::CryptoFail)?;
+
+ // Append the AEAD tag to the end of the sealed buffer.
+ tag_out.copy_from_slice(tag.as_ref());
+
+ Ok(())
}
pub fn new_mask(&self, sample: &[u8]) -> Result<[u8; 5]> {
@@ -265,26 +300,22 @@
Ok((open, seal))
}
-fn derive_initial_secret(secret: &[u8]) -> Result<hmac::SigningKey> {
+fn derive_initial_secret(secret: &[u8]) -> Result<hkdf::Prk> {
const INITIAL_SALT: [u8; 20] = [
- 0xef, 0x4f, 0xb0, 0xab, 0xb4, 0x74, 0x70, 0xc4, 0x1b, 0xef, 0xcf, 0x80,
- 0x31, 0x33, 0x4f, 0xae, 0x48, 0x5e, 0x09, 0xa0,
+ 0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb, 0x5a, 0x11, 0xa7, 0xd2, 0x43,
+ 0x2b, 0xb4, 0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02,
];
- let salt = hmac::SigningKey::new(&digest::SHA256, &INITIAL_SALT);
- Ok(hkdf::extract(&salt, secret))
+ let salt = hkdf::Salt::new(hkdf::HKDF_SHA256, &INITIAL_SALT);
+ Ok(salt.extract(secret))
}
-fn derive_client_initial_secret(
- prk: &hmac::SigningKey, out: &mut [u8],
-) -> Result<()> {
+fn derive_client_initial_secret(prk: &hkdf::Prk, out: &mut [u8]) -> Result<()> {
const LABEL: &[u8] = b"client in";
hkdf_expand_label(prk, LABEL, out)
}
-fn derive_server_initial_secret(
- prk: &hmac::SigningKey, out: &mut [u8],
-) -> Result<()> {
+fn derive_server_initial_secret(prk: &hkdf::Prk, out: &mut [u8]) -> Result<()> {
const LABEL: &[u8] = b"server in";
hkdf_expand_label(prk, LABEL, out)
}
@@ -300,7 +331,7 @@
return Err(Error::CryptoFail);
}
- let secret = hmac::SigningKey::new(aead.get_ring_digest(), secret);
+ let secret = hkdf::Prk::new_less_safe(aead.get_ring_digest(), secret);
hkdf_expand_label(&secret, LABEL, &mut out[..key_len])
}
@@ -315,7 +346,7 @@
return Err(Error::CryptoFail);
}
- let secret = hmac::SigningKey::new(aead.get_ring_digest(), secret);
+ let secret = hkdf::Prk::new_less_safe(aead.get_ring_digest(), secret);
hkdf_expand_label(&secret, LABEL, &mut out[..key_len])
}
@@ -330,33 +361,24 @@
return Err(Error::CryptoFail);
}
- let secret = hmac::SigningKey::new(aead.get_ring_digest(), secret);
+ let secret = hkdf::Prk::new_less_safe(aead.get_ring_digest(), secret);
hkdf_expand_label(&secret, LABEL, &mut out[..nonce_len])
}
fn hkdf_expand_label(
- prk: &hmac::SigningKey, label: &[u8], out: &mut [u8],
+ prk: &hkdf::Prk, label: &[u8], out: &mut [u8],
) -> Result<()> {
const LABEL_PREFIX: &[u8] = b"tls13 ";
- let mut info = [0; 24];
+ let out_len = (out.len() as u16).to_be_bytes();
+ let label_len = (LABEL_PREFIX.len() + label.len()) as u8;
- let info_len = {
- let mut b = octets::Octets::with_slice(&mut info);
+ let info = [&out_len, &[label_len][..], LABEL_PREFIX, label, &[0][..]];
- if b.put_u16(out.len() as u16).is_err() ||
- b.put_u8((LABEL_PREFIX.len() + label.len()) as u8).is_err() ||
- b.put_bytes(LABEL_PREFIX).is_err() ||
- b.put_bytes(label).is_err() ||
- b.put_u8(0).is_err()
- {
- return Err(Error::CryptoFail);
- }
-
- b.off()
- };
-
- hkdf::expand(prk, &info[..info_len], out);
+ prk.expand(&info, ArbitraryOutputLen(out.len()))
+ .map_err(|_| Error::CryptoFail)?
+ .fill(out)
+ .map_err(|_| Error::CryptoFail)?;
Ok(())
}
@@ -374,90 +396,23 @@
aead::Nonce::assume_unique_for_key(nonce)
}
+// The ring HKDF expand() API does not accept an arbitrary output length, so we
+// need to hide the `usize` length as part of a type that implements the trait
+// `ring::hkdf::KeyType` in order to trick ring into accepting it.
+struct ArbitraryOutputLen(usize);
+
+impl hkdf::KeyType for ArbitraryOutputLen {
+ fn len(&self) -> usize {
+ self.0
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn derive_initial_secrets() {
- let dcid = [0xc6, 0x54, 0xef, 0xd8, 0xa3, 0x1b, 0x47, 0x92];
-
- let mut secret = [0; 32];
- let mut pkt_key = [0; 16];
- let mut pkt_iv = [0; 12];
- let mut hdr_key = [0; 16];
-
- let aead = Algorithm::AES128_GCM;
-
- let initial_secret = derive_initial_secret(&dcid).unwrap();
-
- // Client.
- assert!(
- derive_client_initial_secret(&initial_secret, &mut secret).is_ok()
- );
- let expected_client_initial_secret = [
- 0x0c, 0x74, 0xbb, 0x95, 0xa1, 0x04, 0x8e, 0x52, 0xef, 0x3b, 0x72,
- 0xe1, 0x28, 0x89, 0x35, 0x1c, 0xd7, 0x3a, 0x55, 0x0f, 0xb6, 0x2c,
- 0x4b, 0xb0, 0x87, 0xe9, 0x15, 0xcc, 0xe9, 0x6c, 0xe3, 0xa0,
- ];
- assert_eq!(&secret, &expected_client_initial_secret);
-
- assert!(derive_pkt_key(aead, &secret, &mut pkt_key).is_ok());
- let expected_client_pkt_key = [
- 0x86, 0xd1, 0x83, 0x04, 0x80, 0xb4, 0x0f, 0x86, 0xcf, 0x9d, 0x68,
- 0xdc, 0xad, 0xf3, 0x5d, 0xfe,
- ];
- assert_eq!(&pkt_key, &expected_client_pkt_key);
-
- assert!(derive_pkt_iv(aead, &secret, &mut pkt_iv).is_ok());
- let expected_client_pkt_iv = [
- 0x12, 0xf3, 0x93, 0x8a, 0xca, 0x34, 0xaa, 0x02, 0x54, 0x31, 0x63,
- 0xd4,
- ];
- assert_eq!(&pkt_iv, &expected_client_pkt_iv);
-
- assert!(derive_hdr_key(aead, &secret, &mut hdr_key).is_ok());
- let expected_client_hdr_key = [
- 0xcd, 0x25, 0x3a, 0x36, 0xff, 0x93, 0x93, 0x7c, 0x46, 0x93, 0x84,
- 0xa8, 0x23, 0xaf, 0x6c, 0x56,
- ];
- assert_eq!(&hdr_key, &expected_client_hdr_key);
-
- // Server.
- assert!(
- derive_server_initial_secret(&initial_secret, &mut secret).is_ok()
- );
- let expected_server_initial_secret = [
- 0x4c, 0x9e, 0xdf, 0x24, 0xb0, 0xe5, 0xe5, 0x06, 0xdd, 0x3b, 0xfa,
- 0x4e, 0x0a, 0x03, 0x11, 0xe8, 0xc4, 0x1f, 0x35, 0x42, 0x73, 0xd8,
- 0xcb, 0x49, 0xdd, 0xd8, 0x46, 0x41, 0x38, 0xd4, 0x7e, 0xc6,
- ];
- assert_eq!(&secret, &expected_server_initial_secret);
-
- assert!(derive_pkt_key(aead, &secret, &mut pkt_key).is_ok());
- let expected_server_pkt_key = [
- 0x2c, 0x78, 0x63, 0x3e, 0x20, 0x6e, 0x99, 0xad, 0x25, 0x19, 0x64,
- 0xf1, 0x9f, 0x6d, 0xcd, 0x6d,
- ];
- assert_eq!(&pkt_key, &expected_server_pkt_key);
-
- assert!(derive_pkt_iv(aead, &secret, &mut pkt_iv).is_ok());
- let expected_server_pkt_iv = [
- 0x7b, 0x50, 0xbf, 0x36, 0x98, 0xa0, 0x6d, 0xfa, 0xbf, 0x75, 0xf2,
- 0x87,
- ];
- assert_eq!(&pkt_iv, &expected_server_pkt_iv);
-
- assert!(derive_hdr_key(aead, &secret, &mut hdr_key).is_ok());
- let expected_server_hdr_key = [
- 0x25, 0x79, 0xd8, 0x69, 0x6f, 0x85, 0xed, 0xa6, 0x8d, 0x35, 0x02,
- 0xb6, 0x55, 0x96, 0x58, 0x6b,
- ];
- assert_eq!(&hdr_key, &expected_server_hdr_key);
- }
-
- #[test]
- fn derive_initial_secrets2() {
let dcid = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08];
let mut secret = [0; 32];
@@ -474,30 +429,30 @@
derive_client_initial_secret(&initial_secret, &mut secret).is_ok()
);
let expected_client_initial_secret = [
- 0x8a, 0x35, 0x15, 0xa1, 0x4a, 0xe3, 0xc3, 0x1b, 0x9c, 0x2d, 0x6d,
- 0x5b, 0xc5, 0x85, 0x38, 0xca, 0x5c, 0xd2, 0xba, 0xa1, 0x19, 0x08,
- 0x71, 0x43, 0xe6, 0x08, 0x87, 0x42, 0x8d, 0xcb, 0x52, 0xf6,
+ 0xfd, 0xa3, 0x95, 0x3a, 0xec, 0xc0, 0x40, 0xe4, 0x8b, 0x34, 0xe2,
+ 0x7e, 0xf8, 0x7d, 0xe3, 0xa6, 0x09, 0x8e, 0xcf, 0x0e, 0x38, 0xb7,
+ 0xe0, 0x32, 0xc5, 0xc5, 0x7b, 0xcb, 0xd5, 0x97, 0x5b, 0x84,
];
assert_eq!(&secret, &expected_client_initial_secret);
assert!(derive_pkt_key(aead, &secret, &mut pkt_key).is_ok());
let expected_client_pkt_key = [
- 0x98, 0xb0, 0xd7, 0xe5, 0xe7, 0xa4, 0x02, 0xc6, 0x7c, 0x33, 0xf3,
- 0x50, 0xfa, 0x65, 0xea, 0x54,
+ 0xaf, 0x7f, 0xd7, 0xef, 0xeb, 0xd2, 0x18, 0x78, 0xff, 0x66, 0x81,
+ 0x12, 0x48, 0x98, 0x36, 0x94,
];
assert_eq!(&pkt_key, &expected_client_pkt_key);
assert!(derive_pkt_iv(aead, &secret, &mut pkt_iv).is_ok());
let expected_client_pkt_iv = [
- 0x19, 0xe9, 0x43, 0x87, 0x80, 0x5e, 0xb0, 0xb4, 0x6c, 0x03, 0xa7,
- 0x88,
+ 0x86, 0x81, 0x35, 0x94, 0x10, 0xa7, 0x0b, 0xb9, 0xc9, 0x2f, 0x04,
+ 0x20,
];
assert_eq!(&pkt_iv, &expected_client_pkt_iv);
assert!(derive_hdr_key(aead, &secret, &mut hdr_key).is_ok());
let expected_client_hdr_key = [
- 0x0e, 0xdd, 0x98, 0x2a, 0x6a, 0xc5, 0x27, 0xf2, 0xed, 0xdc, 0xbb,
- 0x73, 0x48, 0xde, 0xa5, 0xd7,
+ 0xa9, 0x80, 0xb8, 0xb4, 0xfb, 0x7d, 0x9f, 0xbc, 0x13, 0xe8, 0x14,
+ 0xc2, 0x31, 0x64, 0x25, 0x3d,
];
assert_eq!(&hdr_key, &expected_client_hdr_key);
@@ -506,30 +461,30 @@
derive_server_initial_secret(&initial_secret, &mut secret).is_ok()
);
let expected_server_initial_secret = [
- 0x47, 0xb2, 0xea, 0xea, 0x6c, 0x26, 0x6e, 0x32, 0xc0, 0x69, 0x7a,
- 0x9e, 0x2a, 0x89, 0x8b, 0xdf, 0x5c, 0x4f, 0xb3, 0xe5, 0xac, 0x34,
- 0xf0, 0xe5, 0x49, 0xbf, 0x2c, 0x58, 0x58, 0x1a, 0x38, 0x11,
+ 0x55, 0x43, 0x66, 0xb8, 0x19, 0x12, 0xff, 0x90, 0xbe, 0x41, 0xf1,
+ 0x7e, 0x80, 0x22, 0x21, 0x30, 0x90, 0xab, 0x17, 0xd8, 0x14, 0x91,
+ 0x79, 0xbc, 0xad, 0xf2, 0x22, 0xf2, 0x9f, 0xf2, 0xdd, 0xd5,
];
assert_eq!(&secret, &expected_server_initial_secret);
assert!(derive_pkt_key(aead, &secret, &mut pkt_key).is_ok());
let expected_server_pkt_key = [
- 0x9a, 0x8b, 0xe9, 0x02, 0xa9, 0xbd, 0xd9, 0x1d, 0x16, 0x06, 0x4c,
- 0xa1, 0x18, 0x04, 0x5f, 0xb4,
+ 0x5d, 0x51, 0xda, 0x9e, 0xe8, 0x97, 0xa2, 0x1b, 0x26, 0x59, 0xcc,
+ 0xc7, 0xe5, 0xbf, 0xa5, 0x77,
];
assert_eq!(&pkt_key, &expected_server_pkt_key);
assert!(derive_pkt_iv(aead, &secret, &mut pkt_iv).is_ok());
let expected_server_pkt_iv = [
- 0x0a, 0x82, 0x08, 0x6d, 0x32, 0x20, 0x5b, 0xa2, 0x22, 0x41, 0xd8,
- 0xdc,
+ 0x5e, 0x5a, 0xe6, 0x51, 0xfd, 0x1e, 0x84, 0x95, 0xaf, 0x13, 0x50,
+ 0x8b,
];
assert_eq!(&pkt_iv, &expected_server_pkt_iv);
assert!(derive_hdr_key(aead, &secret, &mut hdr_key).is_ok());
let expected_server_hdr_key = [
- 0x94, 0xb9, 0x45, 0x2d, 0x2b, 0x3c, 0x7c, 0x7f, 0x6d, 0xa7, 0xfd,
- 0xd8, 0x59, 0x35, 0x37, 0xfd,
+ 0xa8, 0xed, 0x82, 0xe6, 0x66, 0x4f, 0x86, 0x5a, 0xed, 0xf6, 0x10,
+ 0x69, 0x43, 0xf9, 0x5f, 0xb8,
];
assert_eq!(&hdr_key, &expected_server_hdr_key);
}
diff --git a/src/ffi.rs b/src/ffi.rs
index 0d89302..48d5946 100644
--- a/src/ffi.rs
+++ b/src/ffi.rs
@@ -38,6 +38,12 @@
use crate::*;
+#[no_mangle]
+pub extern fn quiche_version() -> *const u8 {
+ static VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), "\0");
+ VERSION.as_ptr()
+}
+
struct Logger {
cb: extern fn(line: *const u8, argp: *mut c_void),
argp: std::sync::atomic::AtomicPtr<c_void>,
@@ -191,8 +197,10 @@
}
#[no_mangle]
-pub extern fn quiche_config_set_disable_migration(config: &mut Config, v: bool) {
- config.set_disable_migration(v);
+pub extern fn quiche_config_set_disable_active_migration(
+ config: &mut Config, v: bool,
+) {
+ config.set_disable_active_migration(v);
}
#[no_mangle]
@@ -208,7 +216,7 @@
) -> c_int {
let buf = unsafe { slice::from_raw_parts_mut(buf, buf_len) };
let hdr = match Header::from_slice(buf, dcil) {
- Ok(h) => h,
+ Ok(v) => v,
Err(e) => return e.to_c() as c_int,
};
@@ -221,7 +229,7 @@
Type::Retry => 2,
Type::Handshake => 3,
Type::ZeroRTT => 4,
- Type::Application => 5,
+ Type::Short => 5,
Type::VersionNegotiation => 6,
};
@@ -448,6 +456,17 @@
}
#[no_mangle]
+pub extern fn quiche_conn_stream_capacity(
+ conn: &mut Connection, stream_id: u64,
+) -> ssize_t {
+ match conn.stream_capacity(stream_id) {
+ Ok(v) => v as ssize_t,
+
+ Err(e) => e.to_c(),
+ }
+}
+
+#[no_mangle]
pub extern fn quiche_conn_stream_finished(
conn: &mut Connection, stream_id: u64,
) -> bool {
@@ -455,20 +474,18 @@
}
#[no_mangle]
-pub extern fn quiche_readable_next(
- conn: &mut Connection, stream_id: *mut u64,
-) -> bool {
- if let Some(v) = conn.readable().next() {
- unsafe { *stream_id = v };
- return true;
- }
+pub extern fn quiche_conn_readable(conn: &Connection) -> *mut StreamIter {
+ Box::into_raw(Box::new(conn.readable()))
+}
- false
+#[no_mangle]
+pub extern fn quiche_conn_writable(conn: &Connection) -> *mut StreamIter {
+ Box::into_raw(Box::new(conn.writable()))
}
#[no_mangle]
pub extern fn quiche_conn_close(
- conn: &mut Connection, app: bool, err: u16, reason: *const u8,
+ conn: &mut Connection, app: bool, err: u64, reason: *const u8,
reason_len: size_t,
) -> c_int {
let reason = unsafe { slice::from_raw_parts(reason, reason_len) };
@@ -490,6 +507,15 @@
}
#[no_mangle]
+pub extern fn quiche_conn_timeout_as_millis(conn: &mut Connection) -> u64 {
+ match conn.timeout() {
+ Some(timeout) => timeout.as_millis() as u64,
+
+ None => std::u64::MAX,
+ }
+}
+
+#[no_mangle]
pub extern fn quiche_conn_on_timeout(conn: &mut Connection) {
conn.on_timeout()
}
@@ -514,6 +540,23 @@
conn.is_closed()
}
+#[no_mangle]
+pub extern fn quiche_stream_iter_next(
+ iter: &mut StreamIter, stream_id: *mut u64,
+) -> bool {
+ if let Some(v) = iter.next() {
+ unsafe { *stream_id = v };
+ return true;
+ }
+
+ false
+}
+
+#[no_mangle]
+pub extern fn quiche_stream_iter_free(iter: *mut StreamIter) {
+ unsafe { Box::from_raw(iter) };
+}
+
#[repr(C)]
pub struct Stats {
pub recv: usize,
diff --git a/src/frame.rs b/src/frame.rs
index 7e79c0f..75fa56e 100644
--- a/src/frame.rs
+++ b/src/frame.rs
@@ -35,6 +35,7 @@
pub const MAX_CRYPTO_OVERHEAD: usize = 8;
pub const MAX_STREAM_OVERHEAD: usize = 12;
+pub const MAX_STREAM_SIZE: u64 = 1 << 62;
#[derive(Clone, PartialEq)]
pub enum Frame {
@@ -57,7 +58,7 @@
StopSending {
stream_id: u64,
- error_code: u16,
+ error_code: u64,
},
Crypto {
@@ -109,6 +110,7 @@
NewConnectionId {
seq_num: u64,
+ retire_prior_to: u64,
conn_id: Vec<u8>,
reset_token: Vec<u8>,
},
@@ -126,13 +128,13 @@
},
ConnectionClose {
- error_code: u16,
+ error_code: u64,
frame_type: u64,
reason: Vec<u8>,
},
ApplicationClose {
- error_code: u16,
+ error_code: u64,
reason: Vec<u8>,
},
}
@@ -170,11 +172,11 @@
0x05 => Frame::StopSending {
stream_id: b.get_varint()?,
- error_code: b.get_u16()?,
+ error_code: b.get_varint()?,
},
0x06 => {
- let offset = b.get_varint()? as usize;
+ let offset = b.get_varint()?;
let data = b.get_bytes_with_varint_length()?;
let data = stream::RangeBuf::from(data.as_ref(), offset, false);
@@ -223,6 +225,7 @@
0x18 => Frame::NewConnectionId {
seq_num: b.get_varint()?,
+ retire_prior_to: b.get_varint()?,
conn_id: b.get_bytes_with_u8_length()?.to_vec(),
reset_token: b.get_bytes(16)?.to_vec(),
},
@@ -240,13 +243,13 @@
},
0x1c => Frame::ConnectionClose {
- error_code: b.get_u16()?,
+ error_code: b.get_varint()?,
frame_type: b.get_varint()?,
reason: b.get_bytes_with_varint_length()?.to_vec(),
},
0x1d => Frame::ApplicationClose {
- error_code: b.get_u16()?,
+ error_code: b.get_varint()?,
reason: b.get_bytes_with_varint_length()?.to_vec(),
},
@@ -268,7 +271,7 @@
(_, Frame::ConnectionClose { .. }) => true,
// All frames are allowed on Application packets.
- (packet::Type::Application, _) => true,
+ (packet::Type::Short, _) => true,
// All other cases are forbidden.
(..) => false,
@@ -344,7 +347,7 @@
b.put_varint(0x05)?;
b.put_varint(*stream_id)?;
- b.put_u16(*error_code)?;
+ b.put_varint(*error_code)?;
},
Frame::Crypto { data } => {
@@ -435,12 +438,14 @@
Frame::NewConnectionId {
seq_num,
+ retire_prior_to,
conn_id,
reset_token,
} => {
b.put_varint(0x18)?;
b.put_varint(*seq_num)?;
+ b.put_varint(*retire_prior_to)?;
b.put_u8(conn_id.len() as u8)?;
b.put_bytes(conn_id.as_ref())?;
b.put_bytes(reset_token.as_ref())?;
@@ -471,7 +476,7 @@
} => {
b.put_varint(0x1c)?;
- b.put_u16(*error_code)?;
+ b.put_varint(*error_code)?;
b.put_varint(*frame_type)?;
b.put_varint(reason.len() as u64)?;
b.put_bytes(reason.as_ref())?;
@@ -480,7 +485,7 @@
Frame::ApplicationClose { error_code, reason } => {
b.put_varint(0x1d)?;
- b.put_u16(*error_code)?;
+ b.put_varint(*error_code)?;
b.put_varint(reason.len() as u64)?;
b.put_bytes(reason.as_ref())?;
},
@@ -533,10 +538,13 @@
octets::varint_len(*final_size) // final_size
},
- Frame::StopSending { stream_id, .. } => {
+ Frame::StopSending {
+ stream_id,
+ error_code,
+ } => {
1 + // frame type
octets::varint_len(*stream_id) + // stream_id
- 2 // error_code
+ octets::varint_len(*error_code) // error_code
},
Frame::Crypto { data } => {
@@ -604,11 +612,13 @@
Frame::NewConnectionId {
seq_num,
+ retire_prior_to,
conn_id,
reset_token,
} => {
1 + // frame type
octets::varint_len(*seq_num) + // seq_num
+ octets::varint_len(*retire_prior_to) + // retire_prior_to
1 + // conn_id length
conn_id.len() + // conn_id
reset_token.len() // reset_token
@@ -630,18 +640,21 @@
},
Frame::ConnectionClose {
- frame_type, reason, ..
+ frame_type,
+ error_code,
+ reason,
+ ..
} => {
1 + // frame type
- 2 + // error_code
+ octets::varint_len(*error_code) + // error_code
octets::varint_len(*frame_type) + // frame_type
octets::varint_len(reason.len() as u64) + // reason_len
reason.len() // reason
},
- Frame::ApplicationClose { reason, .. } => {
+ Frame::ApplicationClose { reason, error_code } => {
1 + // frame type
- 2 + // error_code
+ octets::varint_len(*error_code) + // error_code
octets::varint_len(reason.len() as u64) + // reason_len
reason.len() // reason
},
@@ -811,7 +824,7 @@
for _i in 0..block_count {
let gap = b.get_varint()?;
- if smallest_ack - gap < 2 {
+ if smallest_ack < 2 + gap {
return Err(Error::InvalidFrame);
}
@@ -837,7 +850,7 @@
let stream_id = b.get_varint()?;
let offset = if first & 0x04 != 0 {
- b.get_varint()? as usize
+ b.get_varint()?
} else {
0
};
@@ -848,7 +861,7 @@
b.cap()
};
- if offset + len > 2usize.pow(62) {
+ if offset + len as u64 >= MAX_STREAM_SIZE {
return Err(Error::InvalidFrame);
}
@@ -878,10 +891,7 @@
assert_eq!(wire_len, 128);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_ok());
@@ -908,10 +918,7 @@
assert_eq!(&d[..wire_len], [0x01 as u8]);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
@@ -946,10 +953,7 @@
assert_eq!(wire_len, 17);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_ok());
@@ -979,10 +983,7 @@
assert_eq!(wire_len, 11);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
@@ -1011,10 +1012,7 @@
assert_eq!(wire_len, 7);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
@@ -1044,10 +1042,7 @@
assert_eq!(wire_len, 18);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_ok());
@@ -1075,10 +1070,7 @@
assert_eq!(wire_len, 17);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
@@ -1109,10 +1101,7 @@
assert_eq!(wire_len, 19);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
@@ -1132,7 +1121,7 @@
let frame = Frame::Stream {
stream_id: 32,
- data: stream::RangeBuf::from(&data, 2usize.pow(62) - 11, true),
+ data: stream::RangeBuf::from(&data, MAX_STREAM_SIZE - 11, true),
};
let wire_len = {
@@ -1144,7 +1133,7 @@
let mut b = octets::Octets::with_slice(&mut d);
assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
+ Frame::from_bytes(&mut b, packet::Type::Short),
Err(Error::InvalidFrame)
);
}
@@ -1163,10 +1152,7 @@
assert_eq!(wire_len, 5);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
@@ -1195,10 +1181,7 @@
assert_eq!(wire_len, 7);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
@@ -1224,10 +1207,7 @@
assert_eq!(wire_len, 5);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
@@ -1253,10 +1233,7 @@
assert_eq!(wire_len, 5);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
@@ -1282,10 +1259,7 @@
assert_eq!(wire_len, 5);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
@@ -1314,10 +1288,7 @@
assert_eq!(wire_len, 7);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
@@ -1343,10 +1314,7 @@
assert_eq!(wire_len, 5);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
@@ -1372,10 +1340,7 @@
assert_eq!(wire_len, 5);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
@@ -1393,6 +1358,7 @@
let frame = Frame::NewConnectionId {
seq_num: 123_213,
+ retire_prior_to: 122_211,
conn_id: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
reset_token: vec![0x42; 16],
};
@@ -1402,13 +1368,10 @@
frame.to_bytes(&mut b).unwrap()
};
- assert_eq!(wire_len, 37);
+ assert_eq!(wire_len, 41);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
@@ -1434,10 +1397,7 @@
assert_eq!(wire_len, 5);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
@@ -1465,10 +1425,7 @@
assert_eq!(wire_len, 9);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
@@ -1496,10 +1453,7 @@
assert_eq!(wire_len, 9);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
@@ -1526,13 +1480,10 @@
frame.to_bytes(&mut b).unwrap()
};
- assert_eq!(wire_len, 20);
+ assert_eq!(wire_len, 22);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_ok());
@@ -1558,13 +1509,10 @@
frame.to_bytes(&mut b).unwrap()
};
- assert_eq!(wire_len, 16);
+ assert_eq!(wire_len, 18);
let mut b = octets::Octets::with_slice(&mut d);
- assert_eq!(
- Frame::from_bytes(&mut b, packet::Type::Application),
- Ok(frame)
- );
+ assert_eq!(Frame::from_bytes(&mut b, packet::Type::Short), Ok(frame));
let mut b = octets::Octets::with_slice(&mut d);
assert!(Frame::from_bytes(&mut b, packet::Type::Initial).is_err());
diff --git a/src/h3/ffi.rs b/src/h3/ffi.rs
index 0afebec..95e2968 100644
--- a/src/h3/ffi.rs
+++ b/src/h3/ffi.rs
@@ -36,16 +36,8 @@
use crate::*;
#[no_mangle]
-pub extern fn quiche_h3_config_new(
- num_placeholders: u64, max_header_list_size: u64,
- qpack_max_table_capacity: u64, qpack_blocked_streams: u64,
-) -> *mut h3::Config {
- match h3::Config::new(
- num_placeholders,
- max_header_list_size,
- qpack_max_table_capacity,
- qpack_blocked_streams,
- ) {
+pub extern fn quiche_h3_config_new() -> *mut h3::Config {
+ match h3::Config::new() {
Ok(c) => Box::into_raw(Box::new(c)),
Err(_) => ptr::null_mut(),
@@ -53,6 +45,27 @@
}
#[no_mangle]
+pub extern fn quiche_h3_config_set_max_header_list_size(
+ config: &mut h3::Config, v: u64,
+) {
+ config.set_max_header_list_size(v);
+}
+
+#[no_mangle]
+pub extern fn quiche_h3_config_set_qpack_max_table_capacity(
+ config: &mut h3::Config, v: u64,
+) {
+ config.set_qpack_max_table_capacity(v);
+}
+
+#[no_mangle]
+pub extern fn quiche_h3_config_set_qpack_blocked_streams(
+ config: &mut h3::Config, v: u64,
+) {
+ config.set_qpack_blocked_streams(v);
+}
+
+#[no_mangle]
pub extern fn quiche_h3_config_free(config: *mut h3::Config) {
unsafe { Box::from_raw(config) };
}
diff --git a/src/h3/frame.rs b/src/h3/frame.rs
index 192490a..2d5f588 100644
--- a/src/h3/frame.rs
+++ b/src/h3/frame.rs
@@ -24,14 +24,12 @@
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-use super::Error;
use super::Result;
use crate::octets;
pub const DATA_FRAME_TYPE_ID: u64 = 0x0;
pub const HEADERS_FRAME_TYPE_ID: u64 = 0x1;
-pub const PRIORITY_FRAME_TYPE_ID: u64 = 0x2;
pub const CANCEL_PUSH_FRAME_TYPE_ID: u64 = 0x3;
pub const SETTINGS_FRAME_TYPE_ID: u64 = 0x4;
pub const PUSH_PROMISE_FRAME_TYPE_ID: u64 = 0x5;
@@ -42,7 +40,6 @@
const SETTINGS_QPACK_MAX_TABLE_CAPACITY: u64 = 0x1;
const SETTINGS_MAX_HEADER_LIST_SIZE: u64 = 0x6;
const SETTINGS_QPACK_BLOCKED_STREAMS: u64 = 0x7;
-const SETTINGS_NUM_PLACEHOLDERS: u64 = 0x9;
#[derive(Clone, PartialEq)]
pub enum Frame {
@@ -59,7 +56,6 @@
},
Settings {
- num_placeholders: Option<u64>,
max_header_list_size: Option<u64>,
qpack_max_table_capacity: Option<u64>,
qpack_blocked_streams: Option<u64>,
@@ -82,6 +78,8 @@
DuplicatePush {
push_id: u64,
},
+
+ Unknown,
}
impl Frame {
@@ -122,7 +120,7 @@
push_id: b.get_varint()?,
},
- _ => return Err(Error::Done),
+ _ => Frame::Unknown,
};
Ok(frame)
@@ -154,7 +152,6 @@
},
Frame::Settings {
- num_placeholders,
max_header_list_size,
qpack_max_table_capacity,
qpack_blocked_streams,
@@ -162,11 +159,6 @@
} => {
let mut len = 0;
- if let Some(val) = num_placeholders {
- len += octets::varint_len(SETTINGS_NUM_PLACEHOLDERS);
- len += octets::varint_len(*val);
- }
-
if let Some(val) = max_header_list_size {
len += octets::varint_len(SETTINGS_MAX_HEADER_LIST_SIZE);
len += octets::varint_len(*val);
@@ -190,11 +182,6 @@
b.put_varint(SETTINGS_FRAME_TYPE_ID)?;
b.put_varint(len as u64)?;
- if let Some(val) = num_placeholders {
- b.put_varint(SETTINGS_NUM_PLACEHOLDERS)?;
- b.put_varint(*val as u64)?;
- }
-
if let Some(val) = max_header_list_size {
b.put_varint(SETTINGS_MAX_HEADER_LIST_SIZE)?;
b.put_varint(*val as u64)?;
@@ -248,6 +235,8 @@
b.put_varint(*push_id)?;
},
+
+ Frame::Unknown => unreachable!(),
}
Ok(before - b.cap())
@@ -270,13 +259,12 @@
},
Frame::Settings {
- num_placeholders,
max_header_list_size,
qpack_max_table_capacity,
qpack_blocked_streams,
..
} => {
- write!(f, "SETTINGS placeholders={:?}, max_headers={:?}, qpack_max_table={:?}, qpack_blocked={:?} ", num_placeholders, max_header_list_size, qpack_max_table_capacity, qpack_blocked_streams)?;
+ write!(f, "SETTINGS max_headers={:?}, qpack_max_table={:?}, qpack_blocked={:?} ", max_header_list_size, qpack_max_table_capacity, qpack_blocked_streams)?;
},
Frame::PushPromise {
@@ -302,6 +290,10 @@
Frame::DuplicatePush { push_id } => {
write!(f, "DUPLICATE_PUSH push_id={}", push_id)?;
},
+
+ Frame::Unknown => {
+ write!(f, "UNKNOWN")?;
+ },
}
Ok(())
@@ -311,7 +303,6 @@
fn parse_settings_frame(
b: &mut octets::Octets, settings_length: usize,
) -> Result<Frame> {
- let mut num_placeholders = None;
let mut max_header_list_size = None;
let mut qpack_max_table_capacity = None;
let mut qpack_blocked_streams = None;
@@ -333,17 +324,12 @@
qpack_blocked_streams = Some(settings_val);
},
- SETTINGS_NUM_PLACEHOLDERS => {
- num_placeholders = Some(settings_val);
- },
-
// Unknown Settings parameters must be ignored.
_ => (),
}
}
Ok(Frame::Settings {
- num_placeholders,
max_header_list_size,
qpack_max_table_capacity,
qpack_blocked_streams,
@@ -456,14 +442,13 @@
let mut d = [42; 128];
let frame = Frame::Settings {
- num_placeholders: Some(0),
max_header_list_size: Some(0),
qpack_max_table_capacity: Some(0),
qpack_blocked_streams: Some(0),
grease: None,
};
- let frame_payload_len = 8;
+ let frame_payload_len = 6;
let frame_header_len = 2;
let wire_len = {
@@ -489,7 +474,6 @@
let mut d = [42; 128];
let frame = Frame::Settings {
- num_placeholders: Some(0),
max_header_list_size: Some(0),
qpack_max_table_capacity: Some(0),
qpack_blocked_streams: Some(0),
@@ -498,14 +482,13 @@
// Frame parsing will always ignore GREASE values.
let frame_parsed = Frame::Settings {
- num_placeholders: Some(0),
max_header_list_size: Some(0),
qpack_max_table_capacity: Some(0),
qpack_blocked_streams: Some(0),
grease: None,
};
- let frame_payload_len = 10;
+ let frame_payload_len = 8;
let frame_header_len = 2;
let wire_len = {
@@ -531,14 +514,13 @@
let mut d = [42; 128];
let frame = Frame::Settings {
- num_placeholders: Some(16),
max_header_list_size: Some(1024),
qpack_max_table_capacity: None,
qpack_blocked_streams: None,
grease: None,
};
- let frame_payload_len = 5;
+ let frame_payload_len = 3;
let frame_header_len = 2;
let wire_len = {
@@ -564,7 +546,6 @@
let mut d = [42; 128];
let frame = Frame::Settings {
- num_placeholders: None,
max_header_list_size: None,
qpack_max_table_capacity: Some(0),
qpack_blocked_streams: Some(0),
@@ -708,6 +689,9 @@
fn unknown_type() {
let mut d = [42; 12];
- assert_eq!(Frame::from_bytes(255, 12345, &mut d[..]), Err(Error::Done));
+ assert_eq!(
+ Frame::from_bytes(255, 12345, &mut d[..]),
+ Ok(Frame::Unknown)
+ );
}
}
diff --git a/src/h3/mod.rs b/src/h3/mod.rs
index eeda005..8c7a190 100644
--- a/src/h3/mod.rs
+++ b/src/h3/mod.rs
@@ -49,7 +49,7 @@
//! connection is creating its configuration object:
//!
//! ```
-//! let h3_config = quiche::h3::Config::new(0, 1024, 0, 0)?;
+//! let h3_config = quiche::h3::Config::new()?;
//! # Ok::<(), quiche::h3::Error>(())
//! ```
//!
@@ -61,7 +61,7 @@
//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
//! # let scid = [0xba; 16];
//! # let mut conn = quiche::connect(None, &scid, &mut config).unwrap();
-//! # let h3_config = quiche::h3::Config::new(0, 1024, 0, 0)?;
+//! # let h3_config = quiche::h3::Config::new()?;
//! let h3_conn = quiche::h3::Connection::with_transport(&mut conn, &h3_config)?;
//! # Ok::<(), quiche::h3::Error>(())
//! ```
@@ -76,7 +76,7 @@
//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
//! # let scid = [0xba; 16];
//! # let mut conn = quiche::connect(None, &scid, &mut config).unwrap();
-//! # let h3_config = quiche::h3::Config::new(0, 1024, 0, 0)?;
+//! # let h3_config = quiche::h3::Config::new()?;
//! # let mut h3_conn = quiche::h3::Connection::with_transport(&mut conn, &h3_config)?;
//! let req = vec![
//! quiche::h3::Header::new(":method", "GET"),
@@ -97,7 +97,7 @@
//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
//! # let scid = [0xba; 16];
//! # let mut conn = quiche::connect(None, &scid, &mut config).unwrap();
-//! # let h3_config = quiche::h3::Config::new(0, 1024, 0, 0)?;
+//! # let h3_config = quiche::h3::Config::new()?;
//! # let mut h3_conn = quiche::h3::Connection::with_transport(&mut conn, &h3_config)?;
//! let req = vec![
//! quiche::h3::Header::new(":method", "GET"),
@@ -125,7 +125,7 @@
//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
//! # let scid = [0xba; 16];
//! # let mut conn = quiche::accept(&scid, None, &mut config).unwrap();
-//! # let h3_config = quiche::h3::Config::new(0, 1024, 0, 0)?;
+//! # let h3_config = quiche::h3::Config::new()?;
//! # let mut h3_conn = quiche::h3::Connection::with_transport(&mut conn, &h3_config)?;
//! loop {
//! match h3_conn.poll(&mut conn) {
@@ -178,7 +178,7 @@
//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
//! # let scid = [0xba; 16];
//! # let mut conn = quiche::connect(None, &scid, &mut config).unwrap();
-//! # let h3_config = quiche::h3::Config::new(0, 1024, 0, 0)?;
+//! # let h3_config = quiche::h3::Config::new()?;
//! # let mut h3_conn = quiche::h3::Connection::with_transport(&mut conn, &h3_config)?;
//! loop {
//! match h3_conn.poll(&mut conn) {
@@ -246,12 +246,13 @@
//! [`send_response()`]: struct.Connection.html#method.send_response
//! [`send_body()`]: struct.Connection.html#method.send_body
-use std::collections::BTreeMap;
+use std::collections::HashMap;
+use std::collections::VecDeque;
use crate::octets;
/// The current HTTP/3 ALPN token.
-pub const APPLICATION_PROTOCOL: &[u8] = b"\x05h3-20";
+pub const APPLICATION_PROTOCOL: &[u8] = b"\x05h3-23";
/// A specialized [`Result`] type for quiche HTTP/3 operations.
///
@@ -263,135 +264,138 @@
/// An HTTP/3 error.
#[derive(Clone, Copy, Debug, PartialEq)]
-#[repr(C)]
pub enum Error {
/// There is no error or no work to do
- Done = -1,
+ Done,
/// The provided buffer is too short.
- BufferTooShort = -2,
+ BufferTooShort,
- /// Setting sent in wrong direction.
- WrongSettingDirection = -3,
-
- /// The server attempted to push content that the client will not accept.
- PushRefused = -4,
+ /// Peer violated protocol requirements in a way which doesn’t match a
+ /// more specific error code, or endpoint declines to use the more
+ /// specific error code.
+ GeneralProtocolError,
/// Internal error in the HTTP/3 stack.
- InternalError = -5,
-
- /// The server attempted to push something the client already has.
- PushAlreadyInCache = -6,
+ InternalError,
/// The client no longer needs the requested data.
- RequestCancelled = -7,
+ RequestCancelled,
/// The request stream terminated before completing the request.
- IncompleteRequest = -8,
+ RequestIncomplete,
/// Forward connection failure for CONNECT target.
- ConnectError = -9,
+ ConnectError,
/// Endpoint detected that the peer is exhibiting behavior that causes.
/// excessive load.
- ExcessiveLoad = -10,
+ ExcessiveLoad,
/// Operation cannot be served over HTTP/3. Retry over HTTP/1.1.
- VersionFallback = -11,
+ VersionFallback,
- /// Frame received on stream where it is not permitted.
- WrongStream = -12,
+ /// Stream ID or Push ID greater that current maximum was
+ /// used incorrectly, such as exceeding a limit, reducing a limit,
+ /// or being reused.
+ IdError,
- /// Stream ID, Push ID or Placeholder Id greater that current maximum was.
- /// used
- LimitExceeded = -13,
-
- /// Push ID used in two different stream headers.
- DuplicatePush = -14,
-
- /// Unknown unidirection stream type.
- UnknownStreamType = -15,
-
- /// Too many unidirectional streams of a type were created.
- WrongStreamCount = -16,
+ /// The endpoint detected that its peer created a stream that it will not
+ /// accept.
+ StreamCreationError,
/// A required critical stream was closed.
- ClosedCriticalStream = -17,
-
- /// Unidirectional stream type opened at peer that is prohibited.
- WrongStreamDirection = -18,
+ ClosedCriticalStream,
/// Inform client that remainder of request is not needed. Used in
/// STOP_SENDING only.
- EarlyResponse = -19,
+ EarlyResponse,
/// No SETTINGS frame at beginning of control stream.
- MissingSettings = -20,
+ MissingSettings,
/// A frame was received which is not permitted in the current state.
- UnexpectedFrame = -21,
+ FrameUnexpected,
/// Server rejected request without performing any application processing.
- RequestRejected = -22,
+ RequestRejected,
- /// Peer violated protocol requirements in a way that doesn't match a more
- /// specific code.
- GeneralProtocolError = -23,
+ /// An endpoint detected an error in the payload of a SETTINGS frame:
+ /// a duplicate setting was detected, a client-only setting was sent by a
+ /// server, or a server-only setting by a client.
+ SettingsError,
- /// TODO: malformed frame where last on-wire byte is the frame type.
- MalformedFrame = -24,
+ /// Frame violated layout or size rules.
+ FrameError,
/// QPACK Header block decompression failure.
- QpackDecompressionFailed = -25,
+ QpackDecompressionFailed,
/// QPACK encoder stream error.
- QpackEncoderStreamError = -26,
+ QpackEncoderStreamError,
/// QPACK decoder stream error.
- QpackDecoderStreamError = -27,
+ QpackDecoderStreamError,
/// Error originated from the transport layer.
- TransportError = -28,
+ TransportError(crate::Error),
}
impl Error {
- fn to_wire(self) -> u16 {
+ fn to_wire(self) -> u64 {
match self {
- Error::Done => 0x0,
- Error::WrongSettingDirection => 0x1,
- Error::PushRefused => 0x2,
- Error::InternalError => 0x3,
- Error::PushAlreadyInCache => 0x4,
- Error::RequestCancelled => 0x5,
- Error::IncompleteRequest => 0x6,
- Error::ConnectError => 0x07,
- Error::ExcessiveLoad => 0x08,
- Error::VersionFallback => 0x09,
- Error::WrongStream => 0xA,
- Error::LimitExceeded => 0xB,
- Error::DuplicatePush => 0xC,
- Error::UnknownStreamType => 0xD,
- Error::WrongStreamCount => 0xE,
- Error::ClosedCriticalStream => 0xF,
- Error::WrongStreamDirection => 0x10,
- Error::EarlyResponse => 0x11,
- Error::MissingSettings => 0x12,
- Error::UnexpectedFrame => 0x13,
- Error::RequestRejected => 0x14,
- Error::GeneralProtocolError => 0xFF,
- Error::MalformedFrame => 0x10,
+ Error::Done => 0x100,
+ Error::GeneralProtocolError => 0x101,
+ Error::InternalError => 0x102,
+ Error::StreamCreationError => 0x103,
+ Error::ClosedCriticalStream => 0x104,
+ Error::FrameUnexpected => 0x105,
+ Error::FrameError => 0x106,
+ Error::ExcessiveLoad => 0x107,
+ Error::IdError => 0x108,
+ Error::SettingsError => 0x109,
+ Error::MissingSettings => 0x10A,
+ Error::RequestRejected => 0x10B,
+ Error::RequestCancelled => 0x10C,
+ Error::RequestIncomplete => 0x10D,
+ Error::EarlyResponse => 0x10E,
+ Error::ConnectError => 0x10F,
+ Error::VersionFallback => 0x110,
Error::QpackDecompressionFailed => 0x200,
Error::QpackEncoderStreamError => 0x201,
Error::QpackDecoderStreamError => 0x202,
Error::BufferTooShort => 0x999,
- Error::TransportError => 0xFF,
+ Error::TransportError { .. } => 0xFF,
}
}
fn to_c(self) -> libc::ssize_t {
- self as _
+ match self {
+ Error::Done => -1,
+ Error::BufferTooShort => -2,
+ Error::GeneralProtocolError => -3,
+ Error::InternalError => -5,
+ Error::RequestCancelled => -7,
+ Error::RequestIncomplete => -8,
+ Error::ConnectError => -9,
+ Error::ExcessiveLoad => -10,
+ Error::VersionFallback => -11,
+ Error::IdError => -13,
+ Error::StreamCreationError => -15,
+ Error::ClosedCriticalStream => -17,
+ Error::EarlyResponse => -19,
+ Error::MissingSettings => -20,
+ Error::FrameUnexpected => -21,
+ Error::RequestRejected => -22,
+ Error::SettingsError => -23,
+ Error::FrameError => -24,
+ Error::QpackDecompressionFailed => -25,
+ Error::QpackEncoderStreamError => -26,
+ Error::QpackDecoderStreamError => -27,
+ Error::TransportError { .. } => -28,
+ }
}
}
@@ -402,11 +406,6 @@
}
impl std::error::Error for Error {
- fn description(&self) -> &str {
- // TODO: fill this
- ""
- }
-
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
@@ -417,7 +416,7 @@
match err {
super::Error::Done => Error::Done,
- _ => Error::TransportError,
+ _ => Error::TransportError(err),
}
}
}
@@ -430,25 +429,41 @@
/// An HTTP/3 configuration.
pub struct Config {
- num_placeholders: u64,
- max_header_list_size: u64,
- qpack_max_table_capacity: u64,
- qpack_blocked_streams: u64,
+ max_header_list_size: Option<u64>,
+ qpack_max_table_capacity: Option<u64>,
+ qpack_blocked_streams: Option<u64>,
}
impl Config {
- /// Creates a new configuration object with the specified parameters.
- pub fn new(
- num_placeholders: u64, max_header_list_size: u64,
- qpack_max_table_capacity: u64, qpack_blocked_streams: u64,
- ) -> Result<Config> {
+ /// Creates a new configuration object with default settings.
+ pub fn new() -> Result<Config> {
Ok(Config {
- num_placeholders,
- max_header_list_size,
- qpack_max_table_capacity,
- qpack_blocked_streams,
+ max_header_list_size: None,
+ qpack_max_table_capacity: None,
+ qpack_blocked_streams: None,
})
}
+
+ /// Sets the `SETTINGS_MAX_HEADER_LIST_SIZE` setting.
+ ///
+ /// By default no limit is enforced.
+ pub fn set_max_header_list_size(&mut self, v: u64) {
+ self.max_header_list_size = Some(v);
+ }
+
+ /// Sets the `SETTINGS_QPACK_MAX_TABLE_CAPACITY` setting.
+ ///
+ /// The default value is `0`.
+ pub fn set_qpack_max_table_capacity(&mut self, v: u64) {
+ self.qpack_max_table_capacity = Some(v);
+ }
+
+ /// Sets the `SETTINGS_QPACK_BLOCKED_STREAMS` setting.
+ ///
+ /// The default value is `0`.
+ pub fn set_qpack_blocked_streams(&mut self, v: u64) {
+ self.qpack_blocked_streams = Some(v);
+ }
}
/// A name-value pair representing a raw HTTP header.
@@ -497,7 +512,6 @@
}
struct ConnectionSettings {
- pub num_placeholders: Option<u64>,
pub max_header_list_size: Option<u64>,
pub qpack_max_table_capacity: Option<u64>,
pub qpack_blocked_streams: Option<u64>,
@@ -515,7 +529,7 @@
highest_request_stream_id: u64,
highest_uni_stream_id: u64,
- streams: BTreeMap<u64, stream::Stream>,
+ streams: HashMap<u64, stream::Stream>,
local_settings: ConnectionSettings,
peer_settings: ConnectionSettings,
@@ -530,6 +544,10 @@
peer_qpack_streams: QpackStreams,
max_push_id: u64,
+
+ finished_streams: VecDeque<u64>,
+
+ frames_greased: bool,
}
impl Connection {
@@ -542,17 +560,15 @@
highest_request_stream_id: 0,
highest_uni_stream_id: initial_uni_stream_id,
- streams: BTreeMap::new(),
+ streams: HashMap::new(),
local_settings: ConnectionSettings {
- num_placeholders: Some(config.num_placeholders),
- max_header_list_size: Some(config.max_header_list_size),
- qpack_max_table_capacity: Some(config.qpack_max_table_capacity),
- qpack_blocked_streams: Some(config.qpack_blocked_streams),
+ max_header_list_size: config.max_header_list_size,
+ qpack_max_table_capacity: config.qpack_max_table_capacity,
+ qpack_blocked_streams: config.qpack_blocked_streams,
},
peer_settings: ConnectionSettings {
- num_placeholders: None,
max_header_list_size: None,
qpack_max_table_capacity: None,
qpack_blocked_streams: None,
@@ -575,6 +591,10 @@
},
max_push_id: 0,
+
+ finished_streams: VecDeque::new(),
+
+ frames_greased: false,
})
}
@@ -656,15 +676,17 @@
let header_block = self.encode_header_block(headers)?;
- if conn.grease {
+ if !self.frames_greased && conn.grease {
self.send_grease_frames(conn, stream_id)?;
+ self.frames_greased = true;
}
trace!(
- "{} sending HEADERS of size {} on stream {}",
+ "{} tx frm HEADERS stream={} len={} fin={}",
conn.trace_id(),
+ stream_id,
header_block.len(),
- stream_id
+ fin
);
conn.stream_send(
@@ -695,14 +717,34 @@
// Validate that it is sane to send data on the stream.
if !self.streams.contains_key(&stream_id) || stream_id % 4 != 0 {
- return Err(Error::WrongStream);
+ return Err(Error::FrameUnexpected);
}
+ let overhead = octets::varint_len(frame::DATA_FRAME_TYPE_ID) +
+ octets::varint_len(body.len() as u64);
+
+ let stream_cap = conn.stream_capacity(stream_id)?;
+
+ // Make sure there is enough capacity to send the frame header and at
+ // least one byte of frame payload (this to avoid sending 0-length DATA
+ // frames).
+ if stream_cap <= overhead {
+ return Err(Error::Done);
+ }
+
+ // Cap the frame payload length to the stream's capacity.
+ let body_len = std::cmp::min(body.len(), stream_cap - overhead);
+
+ // If we can't send the entire body, set the fin flag to false so the
+ // application can try again later.
+ let fin = if body_len != body.len() { false } else { fin };
+
trace!(
- "{} sending DATA frame of size {} on stream {}",
+ "{} tx frm DATA stream={} len={} fin={}",
conn.trace_id(),
- body.len(),
- stream_id
+ stream_id,
+ body_len,
+ fin
);
conn.stream_send(
@@ -711,20 +753,10 @@
false,
)?;
- conn.stream_send(stream_id, b.put_varint(body.len() as u64)?, false)?;
+ conn.stream_send(stream_id, b.put_varint(body_len as u64)?, false)?;
// Return how many bytes were written, excluding the frame header.
- let written = conn.stream_send(stream_id, body, fin)?;
-
- // Tidy up streams.
- if fin &&
- self.streams
- .get(&stream_id)
- .filter(|s| s.peer_fin())
- .is_some()
- {
- self.streams.remove(&stream_id);
- };
+ let written = conn.stream_send(stream_id, &body[..body_len], fin)?;
Ok(written)
}
@@ -749,7 +781,15 @@
return Err(Error::Done);
}
- Ok(stream.try_consume_data(conn, out)?)
+ let read = stream.try_consume_data(conn, out)?;
+
+ // While body is being received, the stream is marked as finished only
+ // when all data is read by the application.
+ if conn.stream_finished(stream_id) {
+ self.finished_streams.push_back(stream_id);
+ }
+
+ Ok(read)
}
/// Processes HTTP/3 data received from the peer.
@@ -765,258 +805,42 @@
/// [`send_body()`]: struct.Connection.html#method.send_body
/// [`close()`]: ../struct.Connection.html#method.close
pub fn poll(&mut self, conn: &mut super::Connection) -> Result<(u64, Event)> {
- let streams: Vec<u64> = conn.readable().collect();
+ // Process control streams first.
+ if let Some(stream_id) = self.peer_control_stream_id {
+ self.process_control_stream(conn, stream_id)?;
+ }
+
+ if let Some(stream_id) = self.peer_qpack_streams.encoder_stream_id {
+ self.process_control_stream(conn, stream_id)?;
+ }
+
+ if let Some(stream_id) = self.peer_qpack_streams.decoder_stream_id {
+ self.process_control_stream(conn, stream_id)?;
+ }
+
+ // Process finished streams list.
+ if let Some(finished) = self.finished_streams.pop_front() {
+ return Ok((finished, Event::Finished));
+ }
// Process HTTP/3 data from readable streams.
- for s in streams {
+ for s in conn.readable() {
trace!("{} stream id {} is readable", conn.trace_id(), s);
- match self.handle_stream(conn, s) {
- Ok(_) | Err(Error::Done) => continue,
+ let ev = match self.process_readable_stream(conn, s) {
+ Ok(v) => Some(v),
+
+ Err(Error::Done) => None,
Err(e) => return Err(e),
};
- }
- for (stream_id, stream) in
- self.streams.iter_mut().filter(|s| !s.1.peer_fin())
- {
- if let Some(frame) = stream.get_frame() {
- trace!(
- "{} rx frm {:?} on stream {}",
- conn.trace_id(),
- frame,
- stream_id
- );
-
- match frame {
- frame::Frame::Settings {
- num_placeholders,
- max_header_list_size,
- qpack_max_table_capacity,
- qpack_blocked_streams,
- ..
- } => {
- if self.is_server && num_placeholders.is_some() {
- conn.close(
- true,
- Error::WrongSettingDirection.to_wire(),
- b"Num placeholder setting received by server.",
- )?;
-
- return Err(Error::WrongSettingDirection);
- }
-
- self.peer_settings = ConnectionSettings {
- num_placeholders,
- max_header_list_size,
- qpack_max_table_capacity,
- qpack_blocked_streams,
- };
- },
-
- frame::Frame::Headers { mut header_block } => {
- if Some(*stream_id) == self.peer_control_stream_id {
- conn.close(
- true,
- Error::UnexpectedFrame.to_wire(),
- b"HEADERS received on control stream",
- )?;
-
- return Err(Error::UnexpectedFrame);
- }
-
- let headers = self
- .qpack_decoder
- .decode(&mut header_block[..])
- .map_err(|_| Error::QpackDecompressionFailed)?;
- return Ok((*stream_id, Event::Headers(headers)));
- },
-
- frame::Frame::Data { .. } => {
- if Some(*stream_id) == self.peer_control_stream_id {
- conn.close(
- true,
- Error::UnexpectedFrame.to_wire(),
- b"DATA received on control stream",
- )?;
-
- return Err(Error::UnexpectedFrame);
- }
-
- // Do nothing. The Data event is returned separately.
- },
-
- frame::Frame::GoAway {
- stream_id: goaway_stream_id,
- } => {
- if self.is_server {
- conn.close(
- true,
- Error::UnexpectedFrame.to_wire(),
- b"GOWAY received on server",
- )?;
-
- return Err(Error::UnexpectedFrame);
- }
-
- if Some(*stream_id) != self.peer_control_stream_id {
- conn.close(
- true,
- Error::UnexpectedFrame.to_wire(),
- b"GOAWAY received on non-control stream",
- )?;
-
- return Err(Error::UnexpectedFrame);
- }
-
- if goaway_stream_id % 4 != 0 {
- conn.close(
- true,
- Error::WrongStream.to_wire(),
- b"GOAWAY received with ID of non-request stream",
- )?;
-
- return Err(Error::WrongStream);
- }
-
- // TODO: implement GOAWAY
- },
-
- frame::Frame::MaxPushId { push_id } => {
- if Some(*stream_id) != self.peer_control_stream_id {
- conn.close(
- true,
- Error::WrongStream.to_wire(),
- b"MAX_PUSH_ID received on non-control stream",
- )?;
-
- return Err(Error::WrongStream);
- }
-
- if !self.is_server {
- conn.close(
- true,
- Error::UnexpectedFrame.to_wire(),
- b"MAX_PUSH_ID received by client",
- )?;
-
- return Err(Error::UnexpectedFrame);
- }
-
- // The spec says this lower limit elicits an
- // HTTP_MALFORMED_FRAME error. It's a non-sensical
- // error because at this point we already parsed the
- // frame just fine. Therefore, just send a
- // HTTP_GENERAL_PROTOCOL_ERROR.
- if push_id < self.max_push_id {
- conn.close(
- true,
- Error::GeneralProtocolError.to_wire(),
- b"MAX_PUSH_ID reduced limit",
- )?;
-
- return Err(Error::GeneralProtocolError);
- }
-
- self.max_push_id = push_id;
- },
-
- frame::Frame::PushPromise { .. } => {
- if self.is_server {
- conn.close(
- true,
- Error::UnexpectedFrame.to_wire(),
- b"PUSH_PROMISE received by server",
- )?;
-
- return Err(Error::UnexpectedFrame);
- }
-
- if stream_id % 4 != 0 {
- conn.close(
- true,
- Error::UnexpectedFrame.to_wire(),
- b"PUSH_PROMISE received on non-request stream",
- )?;
-
- return Err(Error::UnexpectedFrame);
- }
-
- // TODO: implement more checks and PUSH_PROMISE event
- },
-
- frame::Frame::DuplicatePush { .. } => {
- if self.is_server {
- conn.close(
- true,
- Error::UnexpectedFrame.to_wire(),
- b"DUPLICATE_PUSH received by server",
- )?;
-
- return Err(Error::UnexpectedFrame);
- }
-
- if stream_id % 4 != 0 {
- conn.close(
- true,
- Error::UnexpectedFrame.to_wire(),
- b"DUPLICATE_PUSH received on non-request stream",
- )?;
-
- return Err(Error::UnexpectedFrame);
- }
-
- // TODO: implement DUPLICATE_PUSH
- },
-
- frame::Frame::CancelPush { .. } => {
- if Some(*stream_id) != self.peer_control_stream_id {
- conn.close(
- true,
- Error::WrongStream.to_wire(),
- b"CANCEL_PUSH received on non-control stream",
- )?;
-
- return Err(Error::WrongStream);
- }
-
- // TODO: implement CANCEL_PUSH frame
- },
- }
+ if conn.stream_finished(s) {
+ self.finished_streams.push_back(s);
}
- // Report a Data event if we have a pending incoming DATA
- // notification active.
- if stream.has_incoming_data() {
- stream.notify_incoming_data(false);
-
- return Ok((*stream_id, Event::Data));
- }
-
- if conn.stream_finished(*stream_id) {
- // Only fin the stream and generate events once.
- if !stream.peer_fin() {
- stream.set_peer_fin(true);
-
- match stream.ty() {
- Some(stream::Type::Control) |
- Some(stream::Type::QpackEncoder) |
- Some(stream::Type::QpackDecoder) => {
- conn.close(
- true,
- Error::ClosedCriticalStream.to_wire(),
- b"Critical stream closed.",
- )?;
-
- return Err(Error::ClosedCriticalStream);
- },
-
- _ => (),
- }
-
- return Ok((*stream_id, Event::Finished));
- }
+ if let Some(ev) = ev {
+ return Ok(ev);
}
}
@@ -1031,7 +855,7 @@
return Ok(ret);
}
- Err(Error::LimitExceeded)
+ Err(Error::IdError)
}
/// Allocates a new unidirectional stream ID for the local endpoint to use.
@@ -1042,7 +866,7 @@
return Ok(ret);
}
- Err(Error::LimitExceeded)
+ Err(Error::IdError)
}
fn open_uni_stream(
@@ -1085,11 +909,7 @@
let mut d = [42; 128];
let mut b = octets::Octets::with_slice(&mut d);
- trace!(
- "{} sending GREASE frames on stream id {}",
- conn.trace_id(),
- stream_id
- );
+ trace!("{} tx frm GREASE stream={}", conn.trace_id(), stream_id);
// Empty GREASE frame.
conn.stream_send(stream_id, b.put_varint(grease_value())?, false)?;
@@ -1109,17 +929,13 @@
fn open_grease_stream(&mut self, conn: &mut super::Connection) -> Result<()> {
match self.open_uni_stream(conn, grease_value()) {
Ok(stream_id) => {
- trace!(
- "{} sending GREASE stream on stream id {}",
- conn.trace_id(),
- stream_id
- );
+ trace!("{} open GREASE stream {}", conn.trace_id(), stream_id);
conn.stream_send(stream_id, b"GREASE is the word", false)?;
},
- Err(Error::LimitExceeded) => {
- trace!("{} sending GREASE stream was blocked", conn.trace_id(),);
+ Err(Error::IdError) => {
+ trace!("{} GREASE stream blocked", conn.trace_id(),);
return Ok(());
},
@@ -1136,13 +952,6 @@
self.open_uni_stream(conn, stream::HTTP3_CONTROL_STREAM_TYPE_ID)?,
);
- // Client cannot send placeholders, so validate here
- let num_placeholders = if self.is_server {
- self.local_settings.num_placeholders
- } else {
- None
- };
-
let grease = if conn.grease {
Some((grease_value(), grease_value()))
} else {
@@ -1150,7 +959,6 @@
};
let frame = frame::Frame::Settings {
- num_placeholders,
max_header_list_size: self.local_settings.max_header_list_size,
qpack_max_table_capacity: self
.local_settings
@@ -1173,15 +981,42 @@
Ok(())
}
- fn handle_stream(
+ fn process_control_stream(
&mut self, conn: &mut super::Connection, stream_id: u64,
) -> Result<()> {
- let stream = self
- .streams
+ match self.process_readable_stream(conn, stream_id) {
+ Ok(_) => (),
+
+ Err(Error::Done) => (),
+
+ Err(e) => return Err(e),
+ };
+
+ if conn.stream_finished(stream_id) {
+ conn.close(
+ true,
+ Error::ClosedCriticalStream.to_wire(),
+ b"Critical stream closed.",
+ )?;
+
+ return Err(Error::ClosedCriticalStream);
+ }
+
+ Ok(())
+ }
+
+ fn process_readable_stream(
+ &mut self, conn: &mut super::Connection, stream_id: u64,
+ ) -> Result<(u64, Event)> {
+ self.streams
.entry(stream_id)
.or_insert_with(|| stream::Stream::new(stream_id, false));
- loop {
+ // We need to get a fresh reference to the stream for each
+ // iteration, to avoid borrowing `self` for the entire duration
+ // of the loop, because we'll need to borrow it again in the
+ // `State::FramePayload` case below.
+ while let Some(stream) = self.streams.get_mut(&stream_id) {
match stream.state() {
stream::State::StreamType => {
stream.try_fill_buffer(conn)?;
@@ -1193,7 +1028,11 @@
};
let ty = stream::Type::deserialize(varint)?;
- stream.set_ty(ty)?;
+
+ if let Err(e) = stream.set_ty(ty) {
+ conn.close(true, e.to_wire(), b"")?;
+ return Err(e);
+ }
match &ty {
stream::Type::Control => {
@@ -1201,15 +1040,15 @@
if self.peer_control_stream_id.is_some() {
conn.close(
true,
- Error::WrongStreamCount.to_wire(),
+ Error::StreamCreationError.to_wire(),
b"Received multiple control streams",
)?;
- return Err(Error::WrongStreamCount);
+ return Err(Error::StreamCreationError);
}
trace!(
- "{} peer's control stream: {}",
+ "{} open peer's control stream {}",
conn.trace_id(),
stream_id
);
@@ -1222,11 +1061,11 @@
if self.is_server {
conn.close(
true,
- Error::WrongStreamDirection.to_wire(),
+ Error::StreamCreationError.to_wire(),
b"Server received push stream.",
)?;
- return Err(Error::WrongStreamDirection);
+ return Err(Error::StreamCreationError);
}
},
@@ -1236,11 +1075,11 @@
{
conn.close(
true,
- Error::WrongStreamCount.to_wire(),
+ Error::StreamCreationError.to_wire(),
b"Received multiple QPACK encoder streams",
)?;
- return Err(Error::WrongStreamCount);
+ return Err(Error::StreamCreationError);
}
self.peer_qpack_streams.encoder_stream_id =
@@ -1253,11 +1092,11 @@
{
conn.close(
true,
- Error::WrongStreamCount.to_wire(),
+ Error::StreamCreationError.to_wire(),
b"Received multiple QPACK decoder streams",
)?;
- return Err(Error::WrongStreamCount);
+ return Err(Error::StreamCreationError);
}
self.peer_qpack_streams.decoder_stream_id =
@@ -1282,7 +1121,10 @@
Err(_) => continue,
};
- stream.set_push_id(varint)?;
+ if let Err(e) = stream.set_push_id(varint) {
+ conn.close(true, e.to_wire(), b"")?;
+ return Err(e);
+ }
},
stream::State::FrameType => {
@@ -1295,14 +1137,16 @@
};
match stream.set_frame_type(varint) {
- Err(Error::UnexpectedFrame) => {
+ Err(Error::FrameUnexpected) => {
let msg = format!("Unexpected frame type {}", varint);
+
conn.close(
true,
- Error::UnexpectedFrame.to_wire(),
+ Error::FrameUnexpected.to_wire(),
msg.as_bytes(),
)?;
- return Err(Error::UnexpectedFrame);
+
+ return Err(Error::FrameUnexpected);
},
Err(e) => {
@@ -1311,6 +1155,7 @@
e.to_wire(),
b"Error handling frame.",
)?;
+
return Err(e);
},
@@ -1327,56 +1172,51 @@
Err(_) => continue,
};
- stream.set_frame_payload_len(varint)?;
+ if let Err(e) = stream.set_frame_payload_len(varint) {
+ conn.close(true, e.to_wire(), b"")?;
+ return Err(e);
+ }
},
stream::State::FramePayload => {
stream.try_fill_buffer(conn)?;
- if let Err(e) = stream.try_consume_frame() {
- match e {
- Error::Done => (),
+ let frame = match stream.try_consume_frame() {
+ Ok(frame) => frame,
- _ => conn.close(
+ Err(Error::Done) => return Err(Error::Done),
+
+ Err(e) => {
+ conn.close(
true,
e.to_wire(),
b"Error handling frame.",
- )?,
- };
+ )?;
- return Err(e);
- }
+ return Err(e);
+ },
+ };
+
+ match self.process_frame(conn, stream_id, frame) {
+ Ok(ev) => return Ok(ev),
+
+ Err(Error::Done) => (),
+
+ Err(e) => return Err(e),
+ };
},
stream::State::Data => {
- // If the stream is readable and we are in the Data state
- // it means that there is some DATA payload (even if only
- // partial) in the transport stream.
- //
- // This can either be newly received data, or data that
- // was previously received but not yet read by the
- // application. We don't really have a way to tell either
- // way, so we set the incoming data flag in both cases in
- // a "level-triggered" fashion.
- stream.notify_incoming_data(true);
- break;
+ return Ok((stream_id, Event::Data));
},
stream::State::QpackInstruction => {
- stream.try_fill_buffer(conn)?;
+ let mut d = [0; 4096];
- let e = match stream.ty() {
- Some(stream::Type::QpackEncoder) =>
- Error::QpackEncoderStreamError,
- Some(stream::Type::QpackDecoder) =>
- Error::QpackDecoderStreamError,
-
- _ => unreachable!(),
- };
-
- conn.close(true, e.to_wire(), b"")?;
-
- return Err(e);
+ // Read data from the stream and discard immediately.
+ loop {
+ conn.stream_recv(stream_id, &mut d)?;
+ }
},
stream::State::Drain => {
@@ -1390,6 +1230,213 @@
Err(Error::Done)
}
+
+ fn process_frame(
+ &mut self, conn: &mut super::Connection, stream_id: u64,
+ frame: frame::Frame,
+ ) -> Result<(u64, Event)> {
+ trace!(
+ "{} rx frm {:?} stream={}",
+ conn.trace_id(),
+ frame,
+ stream_id
+ );
+
+ match frame {
+ frame::Frame::Settings {
+ max_header_list_size,
+ qpack_max_table_capacity,
+ qpack_blocked_streams,
+ ..
+ } => {
+ self.peer_settings = ConnectionSettings {
+ max_header_list_size,
+ qpack_max_table_capacity,
+ qpack_blocked_streams,
+ };
+ },
+
+ frame::Frame::Headers { mut header_block } => {
+ if Some(stream_id) == self.peer_control_stream_id {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"HEADERS received on control stream",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ // Use "infinite" as default value for max_header_list_size if
+ // it is not configured by the application.
+ let max_size = self
+ .local_settings
+ .max_header_list_size
+ .unwrap_or(std::u64::MAX);
+
+ let headers = self
+ .qpack_decoder
+ .decode(&mut header_block[..], max_size)
+ .map_err(|e| match e {
+ qpack::Error::HeaderListTooLarge => Error::ExcessiveLoad,
+
+ _ => Error::QpackDecompressionFailed,
+ })?;
+
+ return Ok((stream_id, Event::Headers(headers)));
+ },
+
+ frame::Frame::Data { .. } => {
+ if Some(stream_id) == self.peer_control_stream_id {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"DATA received on control stream",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ // Do nothing. The Data event is returned separately.
+ },
+
+ frame::Frame::GoAway {
+ stream_id: goaway_stream_id,
+ } => {
+ if self.is_server {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"GOWAY received on server",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ if Some(stream_id) != self.peer_control_stream_id {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"GOAWAY received on non-control stream",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ if goaway_stream_id % 4 != 0 {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"GOAWAY received with ID of non-request stream",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ // TODO: implement GOAWAY
+ },
+
+ frame::Frame::MaxPushId { push_id } => {
+ if Some(stream_id) != self.peer_control_stream_id {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"MAX_PUSH_ID received on non-control stream",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ if !self.is_server {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"MAX_PUSH_ID received by client",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ if push_id < self.max_push_id {
+ conn.close(
+ true,
+ Error::IdError.to_wire(),
+ b"MAX_PUSH_ID reduced limit",
+ )?;
+
+ return Err(Error::IdError);
+ }
+
+ self.max_push_id = push_id;
+ },
+
+ frame::Frame::PushPromise { .. } => {
+ if self.is_server {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"PUSH_PROMISE received by server",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ if stream_id % 4 != 0 {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"PUSH_PROMISE received on non-request stream",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ // TODO: implement more checks and PUSH_PROMISE event
+ },
+
+ frame::Frame::DuplicatePush { .. } => {
+ if self.is_server {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"DUPLICATE_PUSH received by server",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ if stream_id % 4 != 0 {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"DUPLICATE_PUSH received on non-request stream",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ // TODO: implement DUPLICATE_PUSH
+ },
+
+ frame::Frame::CancelPush { .. } => {
+ if Some(stream_id) != self.peer_control_stream_id {
+ conn.close(
+ true,
+ Error::FrameUnexpected.to_wire(),
+ b"CANCEL_PUSH received on non-control stream",
+ )?;
+
+ return Err(Error::FrameUnexpected);
+ }
+
+ // TODO: implement CANCEL_PUSH frame
+ },
+
+ frame::Frame::Unknown => (),
+ }
+
+ Err(Error::Done)
+ }
}
/// Generates an HTTP/3 GREASE variable length integer.
@@ -1416,7 +1463,7 @@
///
/// Some utility functions are provided that make it less verbose to send
/// request, responses and individual headers. The full quiche API remains
- /// avaialable for any test that need to do unconventional things (such as
+ /// available for any test that need to do unconventional things (such as
/// bad behaviour that triggers errors).
pub struct Session {
pub pipe: testing::Pipe,
@@ -1440,12 +1487,12 @@
config.set_initial_max_streams_uni(5);
config.verify_peer(false);
- let mut h3_config = Config::new(0, 1024, 0, 0)?;
- Session::with_configs(&mut config, &mut h3_config)
+ let h3_config = Config::new()?;
+ Session::with_configs(&mut config, &h3_config)
}
pub fn with_configs(
- config: &mut crate::Config, h3_config: &mut Config,
+ config: &mut crate::Config, h3_config: &Config,
) -> Result<Session> {
Ok(Session {
pipe: testing::Pipe::with_config(config)?,
@@ -1533,10 +1580,8 @@
Header::new("user-agent", "quiche-test"),
];
- let stream = self
- .client
- .send_request(&mut self.pipe.client, &req, fin)
- .unwrap();
+ let stream =
+ self.client.send_request(&mut self.pipe.client, &req, fin)?;
self.advance().ok();
@@ -1553,6 +1598,7 @@
Header::new(":status", "200"),
Header::new("server", "quiche-test"),
];
+
self.server.send_response(
&mut self.pipe.server,
stream,
@@ -1728,7 +1774,7 @@
let resp = s.send_response(stream, false).unwrap();
for _ in 0..total_data_frames - 1 {
- s.send_body_server(stream, false).unwrap();;
+ s.send_body_server(stream, false).unwrap();
}
let body = s.send_body_server(stream, true).unwrap();
@@ -1754,7 +1800,7 @@
let (stream, req) = s.send_request(false).unwrap();
- let body = s.send_body_client(stream, true).unwrap();;
+ let body = s.send_body_client(stream, true).unwrap();
let mut recv_buf = vec![0; body.len()];
@@ -1811,14 +1857,19 @@
let mut s = Session::default().unwrap();
s.handshake().unwrap();
+ let mut reqs = Vec::new();
+
let (stream1, req1) = s.send_request(false).unwrap();
assert_eq!(stream1, 0);
+ reqs.push(req1);
let (stream2, req2) = s.send_request(false).unwrap();
assert_eq!(stream2, 4);
+ reqs.push(req2);
let (stream3, req3) = s.send_request(false).unwrap();
assert_eq!(stream3, 8);
+ reqs.push(req3);
let body = s.send_body_client(stream1, false).unwrap();
s.send_body_client(stream2, false).unwrap();
@@ -1832,40 +1883,35 @@
s.send_body_client(stream2, true).unwrap();
s.send_body_client(stream1, true).unwrap();
- assert_eq!(s.poll_server(), Ok((stream1, Event::Headers(req1))));
- assert_eq!(s.poll_server(), Ok((stream1, Event::Data)));
- assert_eq!(s.recv_body_server(stream1, &mut recv_buf), Ok(body.len()));
- assert_eq!(s.poll_server(), Ok((stream1, Event::Data)));
- assert_eq!(s.recv_body_server(stream1, &mut recv_buf), Ok(body.len()));
- assert_eq!(s.poll_server(), Ok((stream1, Event::Finished)));
+ for _ in 0..reqs.len() {
+ let (stream, ev) = s.poll_server().unwrap();
+ assert_eq!(ev, Event::Headers(reqs[(stream / 4) as usize].clone()));
+ assert_eq!(s.poll_server(), Ok((stream, Event::Data)));
+ assert_eq!(s.recv_body_server(stream, &mut recv_buf), Ok(body.len()));
+ assert_eq!(s.poll_server(), Ok((stream, Event::Data)));
+ 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(), Ok((stream2, Event::Headers(req2))));
- assert_eq!(s.poll_server(), Ok((stream2, Event::Data)));
- assert_eq!(s.recv_body_server(stream2, &mut recv_buf), Ok(body.len()));
- assert_eq!(s.poll_server(), Ok((stream2, Event::Data)));
- assert_eq!(s.recv_body_server(stream2, &mut recv_buf), Ok(body.len()));
- assert_eq!(s.poll_server(), Ok((stream2, Event::Finished)));
-
- assert_eq!(s.poll_server(), Ok((stream3, Event::Headers(req3))));
- assert_eq!(s.poll_server(), Ok((stream3, Event::Data)));
- assert_eq!(s.recv_body_server(stream3, &mut recv_buf), Ok(body.len()));
- assert_eq!(s.poll_server(), Ok((stream3, Event::Data)));
- assert_eq!(s.recv_body_server(stream3, &mut recv_buf), Ok(body.len()));
- assert_eq!(s.poll_server(), Ok((stream3, Event::Finished)));
assert_eq!(s.poll_server(), Err(Error::Done));
+ let mut resps = Vec::new();
+
let resp1 = s.send_response(stream1, true).unwrap();
+ resps.push(resp1);
+
let resp2 = s.send_response(stream2, true).unwrap();
+ resps.push(resp2);
+
let resp3 = s.send_response(stream3, true).unwrap();
+ resps.push(resp3);
- assert_eq!(s.poll_client(), Ok((stream1, Event::Headers(resp1))),);
- assert_eq!(s.poll_client(), Ok((stream1, Event::Finished)));
+ for _ in 0..resps.len() {
+ let (stream, ev) = s.poll_client().unwrap();
+ assert_eq!(ev, Event::Headers(resps[(stream / 4) as usize].clone()));
+ assert_eq!(s.poll_client(), Ok((stream, Event::Finished)));
+ }
- assert_eq!(s.poll_client(), Ok((stream2, Event::Headers(resp2))),);
- assert_eq!(s.poll_client(), Ok((stream2, Event::Finished)));
-
- assert_eq!(s.poll_client(), Ok((stream3, Event::Headers(resp3))),);
- assert_eq!(s.poll_client(), Ok((stream3, Event::Finished)));
assert_eq!(s.poll_client(), Err(Error::Done));
}
@@ -1876,11 +1922,11 @@
let mut s = Session::default().unwrap();
s.handshake().unwrap();
- assert_eq!(s.send_body_server(0, true), Err(Error::WrongStream));
+ assert_eq!(s.send_body_server(0, true), Err(Error::FrameUnexpected));
assert_eq!(
s.send_body_server(s.server.control_stream_id.unwrap(), true),
- Err(Error::WrongStream)
+ Err(Error::FrameUnexpected)
);
assert_eq!(
@@ -1888,7 +1934,7 @@
s.server.local_qpack_streams.encoder_stream_id.unwrap(),
true
),
- Err(Error::WrongStream)
+ Err(Error::FrameUnexpected)
);
assert_eq!(
@@ -1896,12 +1942,12 @@
s.server.local_qpack_streams.decoder_stream_id.unwrap(),
true
),
- Err(Error::WrongStream)
+ Err(Error::FrameUnexpected)
);
assert_eq!(
s.send_body_server(s.server.peer_control_stream_id.unwrap(), true),
- Err(Error::WrongStream)
+ Err(Error::FrameUnexpected)
);
assert_eq!(
@@ -1909,7 +1955,7 @@
s.server.peer_qpack_streams.encoder_stream_id.unwrap(),
true
),
- Err(Error::WrongStream)
+ Err(Error::FrameUnexpected)
);
assert_eq!(
@@ -1917,7 +1963,7 @@
s.server.peer_qpack_streams.decoder_stream_id.unwrap(),
true
),
- Err(Error::WrongStream)
+ Err(Error::FrameUnexpected)
);
}
@@ -1943,7 +1989,7 @@
let mut s = Session::default().unwrap();
s.handshake().unwrap();
- let (stream, _req) = s.send_request(false).unwrap();
+ let (stream, req) = s.send_request(false).unwrap();
s.send_frame_client(
frame::Frame::MaxPushId { push_id: 2 },
@@ -1952,7 +1998,8 @@
)
.unwrap();
- assert_eq!(s.poll_server(), Err(Error::WrongStream));
+ assert_eq!(s.poll_server(), Ok((stream, Event::Headers(req))));
+ assert_eq!(s.poll_server(), Err(Error::FrameUnexpected));
}
#[test]
@@ -1976,8 +2023,7 @@
)
.unwrap();
- assert_eq!(s.poll_server(), Err(Error::Done));
- assert_eq!(s.poll_server(), Err(Error::GeneralProtocolError));
+ assert_eq!(s.poll_server(), Err(Error::IdError));
}
#[test]
@@ -1993,7 +2039,7 @@
)
.unwrap();
- assert_eq!(s.poll_client(), Err(Error::UnexpectedFrame));
+ assert_eq!(s.poll_client(), Err(Error::FrameUnexpected));
}
#[test]
@@ -2017,7 +2063,7 @@
.unwrap();
assert_eq!(s.poll_server(), Ok((stream, Event::Headers(req))));
- assert_eq!(s.poll_server(), Err(Error::UnexpectedFrame));
+ assert_eq!(s.poll_server(), Err(Error::FrameUnexpected));
}
#[test]
@@ -2042,7 +2088,7 @@
let mut s = Session::default().unwrap();
s.handshake().unwrap();
- let (stream, _req) = s.send_request(false).unwrap();
+ let (stream, req) = s.send_request(false).unwrap();
s.send_frame_client(
frame::Frame::CancelPush { push_id: 2 },
@@ -2051,7 +2097,8 @@
)
.unwrap();
- assert_eq!(s.poll_server(), Err(Error::WrongStream));
+ assert_eq!(s.poll_server(), Ok((stream, Event::Headers(req))));
+ assert_eq!(s.poll_server(), Err(Error::FrameUnexpected));
}
#[test]
@@ -2086,7 +2133,7 @@
.unwrap();
assert_eq!(s.poll_server(), Ok((stream, Event::Headers(req))));
- assert_eq!(s.poll_server(), Err(Error::UnexpectedFrame));
+ assert_eq!(s.poll_server(), Err(Error::FrameUnexpected));
}
#[test]
@@ -2104,7 +2151,7 @@
s.advance().ok();
- assert_eq!(s.poll_server(), Err(Error::UnexpectedFrame));
+ assert_eq!(s.poll_server(), Err(Error::FrameUnexpected));
}
#[test]
@@ -2137,78 +2184,13 @@
)
.unwrap();
- assert_eq!(s.poll_client(), Err(Error::WrongStream));
- }
-
- #[test]
- /// Send a prioritized request from the client, ensure server accepts it.
- fn priority_request() {
- let mut s = Session::default().unwrap();
- s.handshake().unwrap();
-
- let mut d = [42; 128];
- let mut b = octets::Octets::with_slice(&mut d);
-
- // Create an approximate PRIORITY frame in the buffer.
- b.put_varint(frame::PRIORITY_FRAME_TYPE_ID).unwrap();
- b.put_varint(2).unwrap(); // 2 u8s = Bitfield + Weight
- b.put_u8(0).unwrap(); // bitfield
- b.put_u8(16).unwrap(); // weight
- let off = b.off();
-
- let stream = 0;
- s.pipe.client.stream_send(stream, &d[..off], false).unwrap();
- s.advance().ok();
-
- let req = vec![
- Header::new(":method", "GET"),
- Header::new(":scheme", "https"),
- Header::new(":authority", "quic.tech"),
- Header::new(":path", "/test"),
- Header::new("user-agent", "quiche-test"),
- ];
-
- s.client
- .send_headers(&mut s.pipe.client, stream, &req, true)
- .unwrap();
- s.advance().ok();
-
- assert_eq!(s.poll_server(), Ok((stream, Event::Headers(req))));
- assert_eq!(s.poll_server(), Ok((stream, Event::Finished)));
- }
-
- #[test]
- /// Send a PRIORITY frame from the client, ensure server accepts it.
- fn priority_control_stream() {
- let mut s = Session::default().unwrap();
- s.handshake().unwrap();
-
- let mut d = [42; 128];
- let mut b = octets::Octets::with_slice(&mut d);
-
- // Create an approximate PRIORITY frame in the buffer.
- b.put_varint(frame::PRIORITY_FRAME_TYPE_ID).unwrap();
- b.put_varint(1 + octets::varint_parse_len(1) as u64 + 1)
- .unwrap(); // 2 u8s = Bitfield + varint + Weight
- b.put_u8(176).unwrap(); // bitfield
- b.put_varint(1).unwrap();
- b.put_u8(16).unwrap(); // weight
- let off = b.off();
-
- s.pipe
- .client
- .stream_send(s.client.control_stream_id.unwrap(), &d[..off], false)
- .unwrap();
-
- s.advance().ok();
-
- assert_eq!(s.poll_server(), Err(Error::Done));
+ assert_eq!(s.poll_client(), Err(Error::FrameUnexpected));
}
#[test]
/// Ensure quiche allocates streams for client and server roles as expected.
fn uni_stream_local_counting() {
- let config = Config::new(0, 1024, 0, 0).unwrap();
+ let config = Config::new().unwrap();
let mut h3_cln = Connection::new(&config, false).unwrap();
@@ -2249,7 +2231,7 @@
s.advance().ok();
- assert_eq!(s.poll_server(), Err(Error::WrongStreamCount));
+ assert_eq!(s.poll_server(), Err(Error::StreamCreationError));
}
#[test]
@@ -2288,21 +2270,20 @@
}
#[test]
- /// Client sends data on a QPACK stream, which we don't allow.
+ /// Client closes QPACK stream, which is forbidden.
fn close_qpack_stream() {
- // TODO: once we add support for QPACK dynamic table, this test should
- // be changed to testing for critical stream being closed.
let mut s = Session::default().unwrap();
s.handshake().unwrap();
let mut qpack_stream_closed = false;
- s.send_frame_client(
- frame::Frame::MaxPushId { push_id: 1 },
- s.client.local_qpack_streams.encoder_stream_id.unwrap(),
- true,
- )
- .unwrap();
+ let stream_id = s.client.local_qpack_streams.encoder_stream_id.unwrap();
+ let d = [0; 1];
+
+ s.pipe.client.stream_send(stream_id, &d, false).unwrap();
+ s.pipe.client.stream_send(stream_id, &d, true).unwrap();
+
+ s.advance().ok();
loop {
match s.server.poll(&mut s.pipe.server) {
@@ -2312,7 +2293,7 @@
break;
},
- Err(Error::QpackEncoderStreamError) => {
+ Err(Error::ClosedCriticalStream) => {
qpack_stream_closed = true;
break;
},
@@ -2323,6 +2304,197 @@
assert!(qpack_stream_closed);
}
+
+ #[test]
+ /// Client sends QPACK data.
+ fn qpack_data() {
+ // TODO: QPACK instructions are ignored until dynamic table support is
+ // added so we just test that the data is safely ignored.
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let e_stream_id = s.client.local_qpack_streams.encoder_stream_id.unwrap();
+ let d_stream_id = s.client.local_qpack_streams.decoder_stream_id.unwrap();
+ let d = [0; 20];
+
+ s.pipe.client.stream_send(e_stream_id, &d, false).unwrap();
+ s.pipe.client.stream_send(d_stream_id, &d, false).unwrap();
+
+ s.advance().ok();
+
+ loop {
+ match s.server.poll(&mut s.pipe.server) {
+ Ok(_) => (),
+
+ Err(Error::Done) => {
+ break;
+ },
+
+ Err(_) => {
+ panic!();
+ },
+ }
+ }
+ }
+
+ #[test]
+ /// Tests limits for the stream state buffer maximum size.
+ fn max_state_buf_size() {
+ // DATA frames don't consume the state buffer, so can be of any size.
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let mut d = [42; 128];
+ let mut b = octets::Octets::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();
+
+ 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, &d, false).unwrap();
+
+ s.advance().ok();
+
+ assert_eq!(s.server.poll(&mut s.pipe.server), Ok((0, Event::Data)));
+
+ // GREASE frames consume the state buffer, so need to be limited.
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let mut d = [42; 128];
+ let mut b = octets::Octets::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();
+
+ 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, &d, false).unwrap();
+
+ s.advance().ok();
+
+ assert_eq!(s.server.poll(&mut s.pipe.server), Err(Error::InternalError));
+ }
+
+ #[test]
+ /// Tests that DATA frames are properly truncated depending on the request
+ /// stream's outgoing flow control capacity.
+ fn stream_backpressure() {
+ let bytes = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ let (stream, req) = s.send_request(false).unwrap();
+
+ let total_data_frames = 6;
+
+ for _ in 0..total_data_frames {
+ assert_eq!(
+ s.client
+ .send_body(&mut s.pipe.client, stream, &bytes, false),
+ Ok(bytes.len())
+ );
+
+ s.advance().ok();
+ }
+
+ assert_eq!(
+ s.client.send_body(&mut s.pipe.client, stream, &bytes, true),
+ Ok(bytes.len() - 2)
+ );
+
+ s.advance().ok();
+
+ let mut recv_buf = vec![0; bytes.len()];
+
+ assert_eq!(s.poll_server(), Ok((stream, Event::Headers(req))));
+
+ for _ in 0..total_data_frames {
+ assert_eq!(s.poll_server(), Ok((stream, Event::Data)));
+ assert_eq!(
+ s.recv_body_server(stream, &mut recv_buf),
+ Ok(bytes.len())
+ );
+ }
+
+ assert_eq!(s.poll_server(), Ok((stream, Event::Data)));
+ 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));
+ }
+
+ #[test]
+ /// Tests that the max header list size setting is enforced.
+ fn request_max_header_size_limit() {
+ let mut config = crate::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"\x02h3").unwrap();
+ config.set_initial_max_data(1500);
+ config.set_initial_max_stream_data_bidi_local(150);
+ config.set_initial_max_stream_data_bidi_remote(150);
+ config.set_initial_max_stream_data_uni(150);
+ config.set_initial_max_streams_bidi(5);
+ config.set_initial_max_streams_uni(5);
+ config.verify_peer(false);
+
+ let mut h3_config = Config::new().unwrap();
+ h3_config.set_max_header_list_size(65);
+
+ let mut s = Session::with_configs(&mut config, &mut h3_config).unwrap();
+
+ s.handshake().unwrap();
+
+ let req = vec![
+ Header::new(":method", "GET"),
+ Header::new(":scheme", "https"),
+ Header::new(":authority", "quic.tech"),
+ Header::new(":path", "/test"),
+ Header::new("aaaaaaa", "aaaaaaaa"),
+ ];
+
+ let stream = s
+ .client
+ .send_request(&mut s.pipe.client, &req, true)
+ .unwrap();
+
+ s.advance().ok();
+
+ assert_eq!(stream, 0);
+
+ assert_eq!(s.poll_server(), Err(Error::ExcessiveLoad));
+ }
+
+ #[test]
+ /// Tests that Error::TransportError contains a transport error.
+ fn transport_error() {
+ let mut s = Session::default().unwrap();
+ s.handshake().unwrap();
+
+ assert!(s.send_request(true).is_ok());
+ assert!(s.send_request(true).is_ok());
+ assert!(s.send_request(true).is_ok());
+ assert!(s.send_request(true).is_ok());
+ assert!(s.send_request(true).is_ok());
+
+ assert_eq!(
+ s.send_request(true),
+ Err(Error::TransportError(crate::Error::StreamLimit))
+ );
+ }
}
mod ffi;
diff --git a/src/h3/qpack/decoder.rs b/src/h3/qpack/decoder.rs
index b99993c..d52c760 100644
--- a/src/h3/qpack/decoder.rs
+++ b/src/h3/qpack/decoder.rs
@@ -89,11 +89,15 @@
}
/// Decodes a QPACK header block into a list of headers.
- pub fn decode(&mut self, buf: &mut [u8]) -> Result<Vec<Header>> {
+ pub fn decode(
+ &mut self, buf: &mut [u8], max_size: u64,
+ ) -> Result<Vec<Header>> {
let mut b = octets::Octets::with_slice(buf);
let mut out = Vec::new();
+ let mut left = max_size;
+
let req_insert_count = decode_int(&mut b, 8)?;
let base = decode_int(&mut b, 7)?;
@@ -112,10 +116,16 @@
trace!("Indexed index={} static={}", index, s);
if !s {
- unimplemented!("dynamic table");
+ // TODO: implement dynamic table
+ return Err(Error::InvalidHeaderValue);
}
let (name, value) = lookup_static(index)?;
+
+ left = left
+ .checked_sub((name.len() + value.len()) as u64)
+ .ok_or(Error::HeaderListTooLarge)?;
+
out.push(Header::new(&name, &value));
},
@@ -124,7 +134,8 @@
trace!("Indexed With Post Base index={}", index);
- unimplemented!("dynamic table");
+ // TODO: implement dynamic table
+ return Err(Error::InvalidHeaderValue);
},
Representation::Literal => {
@@ -148,6 +159,10 @@
value
);
+ left = left
+ .checked_sub((name.len() + value.len()) as u64)
+ .ok_or(Error::HeaderListTooLarge)?;
+
out.push(Header::new(&name, &value));
},
@@ -166,17 +181,24 @@
);
if !s {
- unimplemented!("dynamic table");
+ // TODO: implement dynamic table
+ return Err(Error::InvalidHeaderValue);
}
let (name, _) = lookup_static(name_idx)?;
+
+ left = left
+ .checked_sub((name.len() + value.len()) as u64)
+ .ok_or(Error::HeaderListTooLarge)?;
+
out.push(Header::new(name, &value));
},
Representation::LiteralWithPostBase => {
trace!("Literal With Post Base");
- unimplemented!("dynamic table");
+ // TODO: implement dynamic table
+ return Err(Error::InvalidHeaderValue);
},
}
}
@@ -317,7 +339,11 @@
while b.cap() > 0 {
let byte = b.get_u8()?;
- val += u64::from(byte & 0x7f) << shift;
+ let inc = u64::from(byte & 0x7f)
+ .checked_shl(shift)
+ .ok_or(Error::BufferTooShort)?;
+
+ val = val.checked_add(inc).ok_or(Error::BufferTooShort)?;
shift += 7;
diff --git a/src/h3/qpack/mod.rs b/src/h3/qpack/mod.rs
index 42680e1..e284d6c 100644
--- a/src/h3/qpack/mod.rs
+++ b/src/h3/qpack/mod.rs
@@ -53,6 +53,9 @@
/// The decoded QPACK header name or value is not valid.
InvalidHeaderValue,
+
+ /// The decoded header list exceeded the size limit.
+ HeaderListTooLarge,
}
impl std::fmt::Display for Error {
@@ -62,15 +65,6 @@
}
impl std::error::Error for Error {
- fn description(&self) -> &str {
- match self {
- Error::BufferTooShort => "buffer is too short",
- Error::InvalidHuffmanEncoding => "invalid huffman encoding",
- Error::InvalidStaticTableIndex => "invalid QPACK static table index",
- Error::InvalidHeaderValue => "invalid QPACK header name or value",
- }
- }
-
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
@@ -108,7 +102,7 @@
assert!(enc.encode(&headers, &mut encoded).is_ok());
let mut dec = Decoder::new();
- assert_eq!(dec.decode(&mut encoded), Ok(headers));
+ assert_eq!(dec.decode(&mut encoded, std::u64::MAX), Ok(headers));
}
}
diff --git a/src/h3/stream.rs b/src/h3/stream.rs
index e08d33c..aa350d2 100644
--- a/src/h3/stream.rs
+++ b/src/h3/stream.rs
@@ -24,8 +24,6 @@
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-use std::collections::VecDeque;
-
use super::Error;
use super::Result;
@@ -38,6 +36,8 @@
pub const QPACK_ENCODER_STREAM_TYPE_ID: u64 = 0x2;
pub const QPACK_DECODER_STREAM_TYPE_ID: u64 = 0x3;
+const MAX_STATE_BUF_SIZE: usize = (1 << 24) - 1;
+
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Type {
Control,
@@ -127,20 +127,11 @@
/// The type of the frame currently being parsed.
frame_type: Option<u64>,
- /// List of frames that have already been parsed, but not yet processed.
- frames: VecDeque<frame::Frame>,
-
/// Whether the stream was created locally, or by the peer.
is_local: bool,
/// Whether the stream has been initialized.
initialized: bool,
-
- /// Whether the peer has finished sending data on this stream.
- is_peer_fin: bool,
-
- /// Whether we have DATA frame data buffered and ready to be read.
- has_incoming_data: bool,
}
impl Stream {
@@ -173,12 +164,9 @@
state_off: 0,
frame_type: None,
- frames: VecDeque::new(),
is_local,
initialized: false,
- is_peer_fin: false,
- has_incoming_data: false,
}
}
@@ -186,22 +174,6 @@
self.state
}
- pub fn ty(&self) -> Option<Type> {
- self.ty
- }
-
- pub fn peer_fin(&self) -> bool {
- self.is_peer_fin
- }
-
- pub fn set_peer_fin(&mut self, fin: bool) {
- self.is_peer_fin = fin;
- }
-
- pub fn get_frame(&mut self) -> Option<frame::Frame> {
- self.frames.pop_front()
- }
-
/// Sets the stream's type and transitions to the next state.
pub fn set_ty(&mut self, ty: Type) -> Result<()> {
assert_eq!(self.state, State::StreamType);
@@ -222,7 +194,7 @@
Type::Unknown => State::Drain,
};
- self.state_transition(state, 1, true);
+ self.state_transition(state, 1, true)?;
Ok(())
}
@@ -233,7 +205,7 @@
// TODO: implement push ID.
- self.state_transition(State::FrameType, 1, true);
+ self.state_transition(State::FrameType, 1, true)?;
Ok(())
}
@@ -253,58 +225,52 @@
(frame::SETTINGS_FRAME_TYPE_ID, false) =>
self.initialized = true,
- // Additional SETTINGS frame.
- (frame::SETTINGS_FRAME_TYPE_ID, true) =>
- return Err(Error::UnexpectedFrame),
-
- // Frames that can never be received on control streams.
- (frame::DATA_FRAME_TYPE_ID, _) =>
- return Err(Error::WrongStream),
-
- (frame::HEADERS_FRAME_TYPE_ID, _) =>
- return Err(Error::WrongStream),
-
- (frame::PUSH_PROMISE_FRAME_TYPE_ID, _) =>
- return Err(Error::WrongStream),
-
- (frame::DUPLICATE_PUSH_FRAME_TYPE_ID, _) =>
- return Err(Error::WrongStream),
-
+ // Non-SETTINGS frames not allowed on control stream
+ // before initialization.
(_, false) => return Err(Error::MissingSettings),
+ // Additional SETTINGS frame.
+ (frame::SETTINGS_FRAME_TYPE_ID, true) =>
+ return Err(Error::FrameUnexpected),
+
+ // Frames that can't be received on control stream
+ // after initialization.
+ (frame::DATA_FRAME_TYPE_ID, true) =>
+ return Err(Error::FrameUnexpected),
+
+ (frame::HEADERS_FRAME_TYPE_ID, true) =>
+ return Err(Error::FrameUnexpected),
+
+ (frame::PUSH_PROMISE_FRAME_TYPE_ID, true) =>
+ return Err(Error::FrameUnexpected),
+
+ (frame::DUPLICATE_PUSH_FRAME_TYPE_ID, true) =>
+ return Err(Error::FrameUnexpected),
+
+ // All other frames are ignored after initialization.
(_, true) => (),
}
},
Some(Type::Request) => {
- // Request stream starts uninitialized and only HEADERS or
- // PRIORITY is accepted in that state. Other
- // frames cause an error. Once initialized, no
- // more PRIORITY frames are permitted.
+ // Request stream starts uninitialized and only HEADERS
+ // is accepted. Other frames cause an error.
if !self.is_local {
match (ty, self.initialized) {
(frame::HEADERS_FRAME_TYPE_ID, false) =>
self.initialized = true,
- (frame::PRIORITY_FRAME_TYPE_ID, false) =>
- self.initialized = true,
-
- // Additional PRIORITY frame is error.
- (frame::PRIORITY_FRAME_TYPE_ID, true) =>
- return Err(Error::UnexpectedFrame),
-
- // Frames that can never be received on request streams.
(frame::CANCEL_PUSH_FRAME_TYPE_ID, _) =>
- return Err(Error::WrongStream),
+ return Err(Error::FrameUnexpected),
(frame::SETTINGS_FRAME_TYPE_ID, _) =>
- return Err(Error::WrongStream),
+ return Err(Error::FrameUnexpected),
(frame::GOAWAY_FRAME_TYPE_ID, _) =>
- return Err(Error::WrongStream),
+ return Err(Error::FrameUnexpected),
(frame::MAX_PUSH_FRAME_TYPE_ID, _) =>
- return Err(Error::WrongStream),
+ return Err(Error::FrameUnexpected),
// All other frames can be ignored regardless of stream
// state.
@@ -318,37 +284,34 @@
Some(Type::Push) => {
match ty {
// Frames that can never be received on request streams.
- frame::PRIORITY_FRAME_TYPE_ID =>
- return Err(Error::WrongStream),
-
frame::CANCEL_PUSH_FRAME_TYPE_ID =>
- return Err(Error::WrongStream),
+ return Err(Error::FrameUnexpected),
frame::SETTINGS_FRAME_TYPE_ID =>
- return Err(Error::WrongStream),
+ return Err(Error::FrameUnexpected),
frame::PUSH_PROMISE_FRAME_TYPE_ID =>
- return Err(Error::WrongStream),
+ return Err(Error::FrameUnexpected),
frame::GOAWAY_FRAME_TYPE_ID =>
- return Err(Error::WrongStream),
+ return Err(Error::FrameUnexpected),
frame::MAX_PUSH_FRAME_TYPE_ID =>
- return Err(Error::WrongStream),
+ return Err(Error::FrameUnexpected),
frame::DUPLICATE_PUSH_FRAME_TYPE_ID =>
- return Err(Error::WrongStream),
+ return Err(Error::FrameUnexpected),
_ => (),
}
},
- _ => return Err(Error::UnexpectedFrame),
+ _ => return Err(Error::FrameUnexpected),
}
self.frame_type = Some(ty);
- self.state_transition(State::FramePayloadLen, 1, true);
+ self.state_transition(State::FramePayloadLen, 1, true)?;
Ok(())
}
@@ -368,7 +331,7 @@
_ => (State::FramePayload, true),
};
- self.state_transition(state, len as usize, resize);
+ self.state_transition(state, len as usize, resize)?;
return Ok(());
}
@@ -445,19 +408,17 @@
}
/// Tries to parse a frame from the state buffer.
- pub fn try_consume_frame(&mut self) -> Result<()> {
+ pub fn try_consume_frame(&mut self) -> Result<frame::Frame> {
// TODO: properly propagate frame parsing errors.
- if let Ok(frame) = frame::Frame::from_bytes(
+ let frame = frame::Frame::from_bytes(
self.frame_type.unwrap(),
self.state_len as u64,
&mut self.state_buf,
- ) {
- self.frames.push_back(frame);
- }
+ )?;
- self.state_transition(State::FrameType, 1, true);
+ self.state_transition(State::FrameType, 1, true)?;
- Ok(())
+ Ok(frame)
}
/// Tries to read DATA payload from the transport stream.
@@ -471,7 +432,7 @@
self.state_off += len;
if self.state_buffer_complete() {
- self.state_transition(State::FrameType, 1, true);
+ self.state_transition(State::FrameType, 1, true)?;
}
Ok(len)
@@ -492,20 +453,12 @@
self.state_off += len;
if self.state_buffer_complete() {
- self.state_transition(State::FrameType, 1, true);
+ self.state_transition(State::FrameType, 1, true)?;
}
Ok(len)
}
- pub fn notify_incoming_data(&mut self, has_data: bool) {
- self.has_incoming_data = has_data;
- }
-
- pub fn has_incoming_data(&self) -> bool {
- self.has_incoming_data
- }
-
/// 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
@@ -515,7 +468,7 @@
/// buffer.
fn state_transition(
&mut self, new_state: State, expected_len: usize, resize: bool,
- ) {
+ ) -> Result<()> {
self.state = new_state;
self.state_off = 0;
self.state_len = expected_len;
@@ -523,8 +476,17 @@
// Some states don't need the state buffer, so don't resize it if not
// necessary.
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
+ // size to avoid DoS.
+ if self.state_len > MAX_STATE_BUF_SIZE {
+ return Err(Error::InternalError);
+ }
+
self.state_buf.resize(self.state_len, 0);
}
+
+ Ok(())
}
}
@@ -542,7 +504,6 @@
let mut b = octets::Octets::with_slice(&mut d);
let frame = frame::Frame::Settings {
- num_placeholders: Some(0),
max_header_list_size: Some(0),
qpack_max_table_capacity: Some(0),
qpack_blocked_streams: Some(0),
@@ -577,17 +538,15 @@
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_payload_len = stream.try_consume_varint().unwrap();
- assert_eq!(frame_payload_len, 8);
+ 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();
- assert_eq!(stream.try_consume_frame(), Ok(()));
+ assert_eq!(stream.try_consume_frame(), Ok(frame));
assert_eq!(stream.state, State::FrameType);
-
- assert_eq!(stream.get_frame(), Some(frame));
}
#[test]
@@ -600,7 +559,6 @@
let mut b = octets::Octets::with_slice(&mut d);
let frame = frame::Frame::Settings {
- num_placeholders: Some(0),
max_header_list_size: Some(0),
qpack_max_table_capacity: Some(0),
qpack_blocked_streams: Some(0),
@@ -636,23 +594,21 @@
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_payload_len = stream.try_consume_varint().unwrap();
- assert_eq!(frame_payload_len, 8);
+ 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();
- assert_eq!(stream.try_consume_frame(), Ok(()));
+ assert_eq!(stream.try_consume_frame(), Ok(frame));
assert_eq!(stream.state, State::FrameType);
- assert_eq!(stream.get_frame(), Some(frame));
-
// Parse the second SETTINGS frame type.
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
- assert_eq!(stream.set_frame_type(frame_ty), Err(Error::UnexpectedFrame));
+ assert_eq!(stream.set_frame_type(frame_ty), Err(Error::FrameUnexpected));
}
#[test]
@@ -667,7 +623,6 @@
let goaway = frame::Frame::GoAway { stream_id: 0 };
let settings = frame::Frame::Settings {
- num_placeholders: Some(0),
max_header_list_size: Some(0),
qpack_max_table_capacity: Some(0),
qpack_blocked_streams: Some(0),
@@ -710,7 +665,6 @@
let hdrs = frame::Frame::Headers { header_block };
let settings = frame::Frame::Settings {
- num_placeholders: Some(0),
max_header_list_size: Some(0),
qpack_max_table_capacity: Some(0),
qpack_blocked_streams: Some(0),
@@ -744,14 +698,13 @@
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
- assert_eq!(stream.try_consume_frame(), Ok(()));
- stream.get_frame();
+ assert!(stream.try_consume_frame().is_ok());
// Parse HEADERS.
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
let frame_ty = stream.try_consume_varint().unwrap();
- assert_eq!(stream.set_frame_type(frame_ty), Err(Error::WrongStream));
+ assert_eq!(stream.set_frame_type(frame_ty), Err(Error::FrameUnexpected));
}
#[test]
@@ -762,7 +715,6 @@
assert_eq!(stream.state, State::FrameType);
assert_eq!(stream.try_consume_varint(), Err(Error::Done));
- assert_eq!(stream.get_frame(), None);
}
#[test]
@@ -805,11 +757,9 @@
// Parse the HEADERS frame.
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
- assert_eq!(stream.try_consume_frame(), Ok(()));
+ assert_eq!(stream.try_consume_frame(), Ok(hdrs));
assert_eq!(stream.state, State::FrameType);
- assert_eq!(stream.get_frame(), Some(hdrs));
-
// Parse the DATA frame type.
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
@@ -840,202 +790,6 @@
}
#[test]
- fn priority_request_good() {
- let mut stream = Stream::new(0, false);
-
- let mut d = vec![42; 1280];
- let mut b = octets::Octets::with_slice(&mut d);
-
- let header_block = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
- let payload = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
- let hdrs = frame::Frame::Headers { header_block };
- let data = frame::Frame::Data {
- payload: payload.clone(),
- };
-
- // Create an approximate PRIORITY frame in the buffer.
- b.put_varint(frame::PRIORITY_FRAME_TYPE_ID).unwrap();
- b.put_varint(2).unwrap(); // 2 u8s = Bitfield + Weight
- b.put_u8(0).unwrap(); // bitfield
- b.put_u8(16).unwrap(); // weight
-
- hdrs.to_bytes(&mut b).unwrap();
- data.to_bytes(&mut b).unwrap();
-
- let mut cursor = std::io::Cursor::new(d);
-
- // Parse the PRIORITY frame type.
- stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
-
- let frame_ty = stream.try_consume_varint().unwrap();
- assert_eq!(frame_ty, frame::PRIORITY_FRAME_TYPE_ID);
-
- stream.set_frame_type(frame_ty).unwrap();
- assert_eq!(stream.state, State::FramePayloadLen);
-
- // Parse the PRIORITY frame payload length.
- stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
-
- let frame_payload_len = stream.try_consume_varint().unwrap();
- assert_eq!(frame_payload_len, 2);
-
- stream.set_frame_payload_len(frame_payload_len).unwrap();
- assert_eq!(stream.state, State::FramePayload);
-
- // Parse the PRIORITY frame.
- stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
-
- assert_eq!(stream.try_consume_frame(), Ok(()));
- assert_eq!(stream.state, State::FrameType);
-
- // TODO: if/when PRIRORITY frame is fully implemented, test it
- // e.g. `assert_eq!(stream.get_frame(), Some(priority));`
-
- // Parse the HEADERS frame type.
- stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
-
- let frame_ty = 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();
- 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();
-
- assert_eq!(stream.try_consume_frame(), Ok(()));
- assert_eq!(stream.state, State::FrameType);
-
- assert_eq!(stream.get_frame(), Some(hdrs));
-
- // Parse the DATA frame type.
- stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
-
- let frame_ty = 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();
- 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);
-
- assert_eq!(stream.state, State::FrameType);
- }
-
- #[test]
- fn priority_control_good() {
- let mut stream = Stream::new(2, false);
-
- let mut d = vec![42; 1280];
- let mut b = octets::Octets::with_slice(&mut d);
-
- let settings = frame::Frame::Settings {
- num_placeholders: Some(0),
- max_header_list_size: Some(0),
- qpack_max_table_capacity: Some(0),
- qpack_blocked_streams: Some(0),
- grease: None,
- };
-
- b.put_varint(HTTP3_CONTROL_STREAM_TYPE_ID).unwrap();
- settings.to_bytes(&mut b).unwrap();
-
- // Create an approximate PRIORITY frame in the buffer.
- b.put_varint(frame::PRIORITY_FRAME_TYPE_ID).unwrap();
- b.put_varint(1 + octets::varint_parse_len(1) as u64 + 1)
- .unwrap(); // 2 u8s = Bitfield + varint + Weight
- b.put_u8(128).unwrap(); // bitfield
- b.put_varint(1).unwrap();
- b.put_u8(16).unwrap(); // weight
-
- let mut cursor = std::io::Cursor::new(d);
-
- // Parse stream type.
- stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
-
- let stream_ty = stream.try_consume_varint().unwrap();
- assert_eq!(stream_ty, HTTP3_CONTROL_STREAM_TYPE_ID);
- stream
- .set_ty(Type::deserialize(stream_ty).unwrap())
- .unwrap();
- assert_eq!(stream.state, State::FrameType);
-
- // Parse the SETTINGS frame type.
- stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
-
- let frame_ty = 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();
- assert_eq!(frame_payload_len, 8);
- 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();
-
- assert_eq!(stream.try_consume_frame(), Ok(()));
- assert_eq!(stream.state, State::FrameType);
-
- // Parse the PRIORITY frame type.
- stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
-
- let frame_ty = stream.try_consume_varint().unwrap();
- assert_eq!(frame_ty, frame::PRIORITY_FRAME_TYPE_ID);
-
- stream.set_frame_type(frame_ty).unwrap();
- assert_eq!(stream.state, State::FramePayloadLen);
-
- // Parse the PRIORITY frame payload length.
- stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
-
- let frame_payload_len = stream.try_consume_varint().unwrap();
- assert_eq!(frame_payload_len, 3);
-
- stream.set_frame_payload_len(frame_payload_len).unwrap();
- assert_eq!(stream.state, State::FramePayload);
-
- // Parse the PRIORITY frame.
- stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
-
- assert_eq!(stream.try_consume_frame(), Ok(()));
- assert_eq!(stream.state, State::FrameType);
-
- // TODO: if/when PRIRORITY frame is fully implemented, test it
- // e.g. `assert_eq!(stream.get_frame(), Some(priority));`
- }
-
- #[test]
fn push_good() {
let mut stream = Stream::new(2, false);
@@ -1096,11 +850,9 @@
// Parse the HEADERS frame.
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
- assert_eq!(stream.try_consume_frame(), Ok(()));
+ assert_eq!(stream.try_consume_frame(), Ok(hdrs));
assert_eq!(stream.state, State::FrameType);
- assert_eq!(stream.get_frame(), Some(hdrs));
-
// Parse the DATA frame type.
stream.try_fill_buffer_for_tests(&mut cursor).unwrap();
diff --git a/src/lib.rs b/src/lib.rs
index b4ee2dc..f78dd50 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -205,9 +205,7 @@
//! # let mut conn = quiche::accept(&scid, None, &mut config)?;
//! if conn.is_established() {
//! // Iterate over readable streams.
-//! let streams: Vec<u64> = conn.readable().collect();
-//!
-//! for stream_id in streams {
+//! for stream_id in conn.readable() {
//! // Stream is readable, read until there's no more data.
//! while let Ok((read, fin)) = conn.stream_recv(stream_id, &mut buf) {
//! println!("Got {} bytes on stream {}", read, stream_id);
@@ -242,7 +240,7 @@
use std::time;
/// The current QUIC wire version.
-pub const PROTOCOL_VERSION: u32 = 0xff00_0014;
+pub const PROTOCOL_VERSION: u32 = 0xff00_0017;
/// The maximum length of a connection ID.
pub const MAX_CONN_ID_LEN: usize = crate::packet::MAX_CID_LEN as usize;
@@ -310,7 +308,7 @@
}
impl Error {
- fn to_wire(self) -> u16 {
+ fn to_wire(self) -> u64 {
match self {
Error::Done => 0x0,
Error::InvalidFrame => 0x7,
@@ -337,24 +335,6 @@
}
impl std::error::Error for Error {
- fn description(&self) -> &str {
- match self {
- Error::Done => "nothing else to do",
- Error::BufferTooShort => "buffer is too short",
- Error::UnknownVersion => "version is unknown",
- Error::InvalidFrame => "frame is invalid",
- Error::InvalidPacket => "packet is invalid",
- Error::InvalidState => "connection state is invalid",
- Error::InvalidStreamState => "stream state is invalid",
- Error::InvalidTransportParam => "transport parameter is invalid",
- Error::CryptoFail => "crypto operation failed",
- Error::TlsFail => "TLS failed",
- Error::FlowControl => "flow control limit was violated",
- Error::StreamLimit => "stream limit was violated",
- Error::FinalSize => "data exceeded stream's final size",
- }
- }
-
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
@@ -403,7 +383,7 @@
/// # Ok::<(), quiche::Error>(())
/// ```
pub fn new(version: u32) -> Result<Config> {
- let tls_ctx = tls::Context::new().map_err(|_| Error::TlsFail)?;
+ let tls_ctx = tls::Context::new()?;
Ok(Config {
local_transport_params: TransportParams::default(),
@@ -427,9 +407,7 @@
/// # Ok::<(), quiche::Error>(())
/// ```
pub fn load_cert_chain_from_pem_file(&mut self, file: &str) -> Result<()> {
- self.tls_ctx
- .use_certificate_chain_file(file)
- .map_err(|_| Error::TlsFail)
+ self.tls_ctx.use_certificate_chain_file(file)
}
/// Configures the given private key.
@@ -444,17 +422,20 @@
/// # Ok::<(), quiche::Error>(())
/// ```
pub fn load_priv_key_from_pem_file(&mut self, file: &str) -> Result<()> {
- self.tls_ctx
- .use_privkey_file(file)
- .map_err(|_| Error::TlsFail)
+ self.tls_ctx.use_privkey_file(file)
}
/// Configures whether to verify the peer's certificate.
+ ///
+ /// The default value is `true` for client connections, and `false` for
+ /// server ones.
pub fn verify_peer(&mut self, verify: bool) {
self.tls_ctx.set_verify(verify);
}
/// Configures whether to send GREASE values.
+ ///
+ /// The default value is `true`.
pub fn grease(&mut self, grease: bool) {
self.grease = grease;
}
@@ -481,6 +462,8 @@
/// On the server this configures the list of supported protocols to match
/// against the client-supplied list.
///
+ /// Applications must set a value, but no default is provided.
+ ///
/// ## Examples:
///
/// ```
@@ -501,71 +484,86 @@
self.application_protos = protos_list;
- self.tls_ctx
- .set_alpn(&self.application_protos)
- .map_err(|_| Error::TlsFail)
+ self.tls_ctx.set_alpn(&self.application_protos)
}
/// Sets the `idle_timeout` transport parameter.
+ ///
+ /// By default no timeout is used.
pub fn set_idle_timeout(&mut self, v: u64) {
self.local_transport_params.idle_timeout = v;
}
- /// Sets the `stateless_reset_token` transport parameter.
- pub fn set_stateless_reset_token(&mut self, v: &[u8; 16]) {
- self.local_transport_params.stateless_reset_token = Some(v.to_vec());
- }
-
/// Sets the `max_packet_size transport` parameter.
+ ///
+ /// The default value is `65527`.
pub fn set_max_packet_size(&mut self, v: u64) {
self.local_transport_params.max_packet_size = v;
}
/// Sets the `initial_max_data` transport parameter.
+ ///
+ /// The default value is `0`.
pub fn set_initial_max_data(&mut self, v: u64) {
self.local_transport_params.initial_max_data = v;
}
/// Sets the `initial_max_stream_data_bidi_local` transport parameter.
+ ///
+ /// The default value is `0`.
pub fn set_initial_max_stream_data_bidi_local(&mut self, v: u64) {
self.local_transport_params
.initial_max_stream_data_bidi_local = v;
}
/// Sets the `initial_max_stream_data_bidi_remote` transport parameter.
+ ///
+ /// The default value is `0`.
pub fn set_initial_max_stream_data_bidi_remote(&mut self, v: u64) {
self.local_transport_params
.initial_max_stream_data_bidi_remote = v;
}
/// Sets the `initial_max_stream_data_uni` transport parameter.
+ ///
+ /// The default value is `0`.
pub fn set_initial_max_stream_data_uni(&mut self, v: u64) {
self.local_transport_params.initial_max_stream_data_uni = v;
}
/// Sets the `initial_max_streams_bidi` transport parameter.
+ ///
+ /// The default value is `0`.
pub fn set_initial_max_streams_bidi(&mut self, v: u64) {
self.local_transport_params.initial_max_streams_bidi = v;
}
/// Sets the `initial_max_streams_uni` transport parameter.
+ ///
+ /// The default value is `0`.
pub fn set_initial_max_streams_uni(&mut self, v: u64) {
self.local_transport_params.initial_max_streams_uni = v;
}
/// Sets the `ack_delay_exponent` transport parameter.
+ ///
+ /// The default value is `3`.
pub fn set_ack_delay_exponent(&mut self, v: u64) {
self.local_transport_params.ack_delay_exponent = v;
}
/// Sets the `max_ack_delay` transport parameter.
+ ///
+ /// The default value is `25`.
pub fn set_max_ack_delay(&mut self, v: u64) {
self.local_transport_params.max_ack_delay = v;
}
- /// Sets the `disable_migration` transport parameter.
- pub fn set_disable_migration(&mut self, v: bool) {
- self.local_transport_params.disable_migration = v;
+ /// Sets the `disable_active_migration` transport parameter.
+ ///
+ /// The default value is `false`.
+ pub fn set_disable_active_migration(&mut self, v: bool) {
+ self.local_transport_params.disable_active_migration = v;
}
}
@@ -608,20 +606,20 @@
sent_count: usize,
/// Total number of bytes received from the peer.
- rx_data: usize,
+ rx_data: u64,
/// Local flow control limit for the connection.
- max_rx_data: usize,
+ max_rx_data: u64,
/// Updated local flow control limit for the connection. This is used to
/// trigger sending MAX_DATA frames after a certain threshold.
- max_rx_data_next: usize,
+ max_rx_data_next: u64,
/// Total number of bytes sent to the peer.
- tx_data: usize,
+ tx_data: u64,
/// Peer's flow control limit for the connection.
- max_tx_data: usize,
+ max_tx_data: u64,
/// Total number of bytes the server can send before the peer's address
/// is verified.
@@ -646,10 +644,10 @@
early_app_pkts: usize,
/// Error code to be sent to the peer in CONNECTION_CLOSE.
- error: Option<u16>,
+ error: Option<u64>,
/// Error code to be sent to the peer in APPLICATION_CLOSE.
- app_error: Option<u16>,
+ app_error: Option<u64>,
/// Error reason to be sent to the peer in APPLICATION_CLOSE.
app_reason: Vec<u8>,
@@ -686,6 +684,13 @@
/// Whether the connection handshake has completed.
handshake_completed: bool,
+ /// Whether the connection handshake has been confirmed.
+ handshake_confirmed: bool,
+
+ /// Whether an ACK-eliciting packet has been sent since last receiving a
+ /// packet.
+ ack_eliciting_sent: bool,
+
/// Whether the connection is closed.
closed: bool,
@@ -738,10 +743,8 @@
) -> Result<Box<Connection>> {
let conn = Connection::new(scid, None, config, false)?;
- if server_name.is_some() {
- conn.handshake
- .set_host_name(server_name.unwrap())
- .map_err(|_| Error::TlsFail)?;
+ if let Some(server_name) = server_name {
+ conn.handshake.set_host_name(server_name)?;
}
Ok(conn)
@@ -844,7 +847,7 @@
fn new(
scid: &[u8], odcid: Option<&[u8]>, config: &mut Config, is_server: bool,
) -> Result<Box<Connection>> {
- let tls = config.tls_ctx.new_handshake().map_err(|_| Error::TlsFail)?;
+ let tls = config.tls_ctx.new_handshake()?;
Connection::with_tls(scid, odcid, config, tls, is_server)
}
@@ -885,8 +888,8 @@
sent_count: 0,
rx_data: 0,
- max_rx_data: max_rx_data as usize,
- max_rx_data_next: max_rx_data as usize,
+ max_rx_data,
+ max_rx_data_next: max_rx_data,
tx_data: 0,
max_tx_data: 0,
@@ -929,6 +932,10 @@
handshake_completed: false,
+ handshake_confirmed: false,
+
+ ack_eliciting_sent: false,
+
closed: false,
grease: config.grease,
@@ -939,14 +946,14 @@
Some(odcid.to_vec());
}
- conn.handshake.init(&conn).map_err(|_| Error::TlsFail)?;
+ conn.handshake.init(&conn)?;
conn.streams.update_local_max_streams_bidi(
- config.local_transport_params.initial_max_streams_bidi as usize,
+ config.local_transport_params.initial_max_streams_bidi,
);
conn.streams.update_local_max_streams_uni(
- config.local_transport_params.initial_max_streams_uni as usize,
+ config.local_transport_params.initial_max_streams_uni,
);
// Derive initial secrets for the client. We can do this here because
@@ -1107,7 +1114,7 @@
self.got_peer_conn_id = false;
self.recovery.drop_unacked_data(packet::EPOCH_INITIAL);
self.pkt_num_spaces[packet::EPOCH_INITIAL].clear();
- self.handshake.clear().map_err(|_| Error::TlsFail)?;
+ self.handshake.clear()?;
return Err(Error::Done);
}
@@ -1151,18 +1158,18 @@
self.got_peer_conn_id = false;
self.recovery.drop_unacked_data(packet::EPOCH_INITIAL);
self.pkt_num_spaces[packet::EPOCH_INITIAL].clear();
- self.handshake.clear().map_err(|_| Error::TlsFail)?;
+ self.handshake.clear()?;
return Err(Error::Done);
}
- if hdr.ty != packet::Type::Application && hdr.version != self.version {
+ if hdr.ty != packet::Type::Short && hdr.version != self.version {
return Err(Error::UnknownVersion);
}
// 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::Application {
+ let payload_len = if hdr.ty == packet::Type::Short {
b.cap()
} else {
b.get_varint()? as usize
@@ -1205,6 +1212,10 @@
let aead = match self.pkt_num_spaces[epoch].crypto_open {
Some(ref v) => v,
+ // Ignore packets that can't be decrypted because we don't yet have
+ // the necessary decryption keys, to avoid packet reordering (e.g.
+ // between Initial and Handshake) to causet he connection to be
+ // closed.
None => {
trace!(
"{} dropped undecryptable packet type={:?} len={}",
@@ -1235,28 +1246,8 @@
pn
);
- let mut payload = match packet::decrypt_pkt(
- &mut b,
- pn,
- hdr.pkt_num_len,
- payload_len,
- &aead,
- ) {
- Ok(v) => v,
-
- Err(Error::CryptoFail) => {
- trace!(
- "{} dropped undecryptable packet type={:?} len={}",
- self.trace_id,
- hdr.ty,
- payload_len,
- );
-
- return Ok(header_len + payload_len);
- },
-
- Err(e) => return Err(e),
- };
+ let mut payload =
+ packet::decrypt_pkt(&mut b, pn, hdr.pkt_num_len, payload_len, &aead)?;
if self.pkt_num_spaces[epoch].recv_pkt_num.contains(pn) {
trace!("{} ignored duplicate packet {}", self.trace_id, pn);
@@ -1266,7 +1257,7 @@
// Keep track of the number of Application packets received before the
// handshake is completed, and drop any that exceed the initial
// congestion window packet count.
- if hdr.ty == packet::Type::Application && !self.is_established() {
+ if hdr.ty == packet::Type::Short && !self.is_established() {
self.early_app_pkts += 1;
if self.early_app_pkts > recovery::INITIAL_WINDOW_PACKETS {
@@ -1303,7 +1294,7 @@
// If the packet this frame belongs to is an early Application one,
// buffer the frame for later processing.
- if hdr.ty == packet::Type::Application && !self.is_established() {
+ if hdr.ty == packet::Type::Short && !self.is_established() {
self.early_app_frames.push(frame);
continue;
}
@@ -1314,14 +1305,15 @@
// Process ACK'd frames.
for acked in self.recovery.acked[epoch].drain(..) {
match acked {
- // Stop acknowledging packets less than or equal to the
- // largest acknowledged in the sent ACK frame that, in
- // turn, got ACK'd.
frame::Frame::ACK { ranges, .. } => {
- let largest_acked = ranges.largest().unwrap();
- self.pkt_num_spaces[epoch]
- .recv_pkt_need_ack
- .remove_until(largest_acked);
+ // Stop acknowledging packets less than or equal to the
+ // largest acknowledged in the sent ACK frame that, in
+ // turn, got ACK'd.
+ if let Some(largest_acked) = ranges.largest() {
+ self.pkt_num_spaces[epoch]
+ .recv_pkt_need_ack
+ .remove_until(largest_acked);
+ }
},
frame::Frame::Crypto { data } => {
@@ -1334,6 +1326,7 @@
frame::Frame::Stream { stream_id, data } => {
let stream = match self.streams.get_mut(stream_id) {
Some(v) => v,
+
None => continue,
};
@@ -1375,20 +1368,39 @@
// successfully processed, so we can drop the initial state and consider
// the client's address to be verified.
if self.is_server && hdr.ty == packet::Type::Handshake {
- self.drop_initial_state();
+ self.drop_epoch_state(packet::EPOCH_INITIAL);
self.verified_peer_address = true;
}
+ self.ack_eliciting_sent = false;
+
Ok(read)
}
/// Writes a single QUIC packet to be sent to the peer.
///
- /// On success the number of bytes processed from the input buffer is
- /// returned, or [`Done`].
+ /// On success the number of bytes written to the output buffer is
+ /// returned, or [`Done`] if there was nothing to write.
+ ///
+ /// The application should call `send()` multiple times until [`Done`] is
+ /// returned, indicating that there are no more packets to send. It is
+ /// recommended that `send()` be called in the following cases:
+ ///
+ /// * When the application receives QUIC packets from the peer (that is,
+ /// any time [`recv()`] is also called).
+ ///
+ /// * When the connection timer expires (that is, any time [`on_timeout()`]
+ /// is also called).
+ ///
+ /// * When the application sends data to the peer (for examples, any time
+ /// [`stream_send()`] or [`stream_shutdown()`] are called).
///
/// [`Done`]: enum.Error.html#variant.Done
+ /// [`recv()`]: struct.Connection.html#method.recv
+ /// [`on_timeout()`]: struct.Connection.html#method.on_timeout
+ /// [`stream_send()`]: struct.Connection.html#method.stream_send
+ /// [`stream_shutdown()`]: struct.Connection.html#method.stream_shutdown
///
/// ## Examples:
///
@@ -1466,12 +1478,24 @@
frame::Frame::Stream { stream_id, data } => {
let stream = match self.streams.get_mut(stream_id) {
Some(v) => v,
+
None => continue,
};
- self.tx_data -= data.len();
+ // TODO: due to a packet loss edge case the following could
+ // go negative, though it's not clear why, so will need to
+ // figure it out.
+ self.tx_data = self.tx_data.saturating_sub(data.len() as u64);
+
+ let was_flushable = stream.is_flushable();
stream.send.push(data)?;
+
+ // If the stream is now flushable push it to the flushable
+ // queue, but only if it wasn't already queued.
+ if stream.is_flushable() && !was_flushable {
+ self.streams.push_flushable(stream_id);
+ }
},
frame::Frame::ACK { .. } => {
@@ -1553,13 +1577,13 @@
// Create MAX_DATA frame, when the new limit is at least double the
// amount of data that can be received before blocking.
- if pkt_type == packet::Type::Application &&
- !is_closing &&
+ if pkt_type == packet::Type::Short &&
(self.max_rx_data_next != self.max_rx_data &&
- self.max_rx_data_next / 2 > self.max_rx_data - self.rx_data)
+ self.max_rx_data_next / 2 > self.max_rx_data - self.rx_data) &&
+ !is_closing
{
let frame = frame::Frame::MaxData {
- max: self.max_rx_data_next as u64,
+ max: self.max_rx_data_next,
};
if frame.wire_len() <= left {
@@ -1576,17 +1600,26 @@
}
// Create MAX_STREAM_DATA frames as needed.
- if pkt_type == packet::Type::Application && !is_closing {
- for (id, stream) in self
- .streams
- .iter_mut()
- .filter(|(_, s)| s.recv.more_credit())
- {
+ if pkt_type == packet::Type::Short && !is_closing {
+ for stream_id in self.streams.almost_full() {
+ let stream = match self.streams.get_mut(stream_id) {
+ Some(v) => v,
+
+ None => {
+ // The stream doesn't exist anymore, so remove it from
+ // the almost full set.
+ self.streams.mark_almost_full(stream_id, false);
+ continue;
+ },
+ };
+
let frame = frame::Frame::MaxStreamData {
- stream_id: *id,
+ stream_id,
max: stream.recv.update_max_data() as u64,
};
+ self.streams.mark_almost_full(stream_id, false);
+
if frame.wire_len() > left {
break;
}
@@ -1601,7 +1634,7 @@
}
}
- // Create PING and PADDING for TLP.
+ // Create PING for PTO probe.
if self.recovery.probes > 0 && left >= 1 {
let frame = frame::Frame::Ping;
@@ -1637,7 +1670,7 @@
// Create APPLICATION_CLOSE frame.
if let Some(err) = self.app_error {
- if pkt_type == packet::Type::Application {
+ if pkt_type == packet::Type::Short {
let frame = frame::Frame::ApplicationClose {
error_code: err,
reason: self.app_reason.clone(),
@@ -1673,7 +1706,10 @@
}
// Create CRYPTO frame.
- if self.pkt_num_spaces[epoch].crypto_stream.writable() && !is_closing {
+ if self.pkt_num_spaces[epoch].crypto_stream.is_flushable() &&
+ left > frame::MAX_CRYPTO_OVERHEAD &&
+ !is_closing
+ {
let crypto_len = left - frame::MAX_CRYPTO_OVERHEAD;
let crypto_buf = self.pkt_num_spaces[epoch]
.crypto_stream
@@ -1692,20 +1728,23 @@
is_crypto = true;
}
- // Create a single STREAM frame for the first stream that is writable.
- if pkt_type == packet::Type::Application &&
- !is_closing &&
+ // Create a single STREAM frame for the first stream that is flushable.
+ if pkt_type == packet::Type::Short &&
self.max_tx_data > self.tx_data &&
- left > frame::MAX_STREAM_OVERHEAD
+ left > frame::MAX_STREAM_OVERHEAD &&
+ !is_closing
{
- // TODO: round-robin selected stream instead of picking the first
- for (id, stream) in
- self.streams.iter_mut().filter(|(_, s)| s.writable())
- {
+ while let Some(stream_id) = self.streams.pop_flushable() {
+ let stream = match self.streams.get_mut(stream_id) {
+ Some(v) => v,
+
+ None => continue,
+ };
+
// Make sure we can fit the data in the packet.
let stream_len = cmp::min(
left - frame::MAX_STREAM_OVERHEAD,
- self.max_tx_data - self.tx_data,
+ (self.max_tx_data - self.tx_data) as usize,
);
let stream_buf = stream.send.pop(stream_len)?;
@@ -1714,10 +1753,10 @@
continue;
}
- self.tx_data += stream_buf.len();
+ self.tx_data += stream_buf.len() as u64;
let frame = frame::Frame::Stream {
- stream_id: *id,
+ stream_id,
data: stream_buf,
};
@@ -1728,6 +1767,13 @@
ack_eliciting = true;
in_flight = true;
+
+ // If the stream is still flushable, push it to the back of the
+ // queue again.
+ if stream.is_flushable() {
+ self.streams.push_flushable(stream_id);
+ }
+
break;
}
}
@@ -1767,7 +1813,7 @@
payload_len += overhead;
// Only long header packets have an explicit length field.
- if pkt_type != packet::Type::Application {
+ if pkt_type != packet::Type::Short {
let len = pn_len + payload_len;
b.put_varint(len as u64)?;
}
@@ -1824,11 +1870,28 @@
// On the client, drop initial state after sending an Handshake packet.
if !self.is_server && hdr.ty == packet::Type::Handshake {
- self.drop_initial_state();
+ self.drop_epoch_state(packet::EPOCH_INITIAL);
}
self.max_send_bytes = self.max_send_bytes.saturating_sub(written);
+ // (Re)start the idle timer if we are sending the first ACK-eliciting
+ // packet since last receiving a packet.
+ if ack_eliciting &&
+ !self.ack_eliciting_sent &&
+ self.local_transport_params.idle_timeout > 0
+ {
+ self.idle_timer = Some(
+ now + time::Duration::from_millis(
+ self.local_transport_params.idle_timeout,
+ ),
+ );
+ }
+
+ if ack_eliciting {
+ self.ack_eliciting_sent = true;
+ }
+
Ok(written)
}
@@ -1866,25 +1929,43 @@
return Err(Error::InvalidStreamState);
}
- let stream = match self.streams.get_mut(stream_id) {
- Some(v) => v,
- None => return Err(Error::InvalidStreamState),
- };
+ let stream = self
+ .streams
+ .get_mut(stream_id)
+ .ok_or(Error::InvalidStreamState)?;
- if !stream.readable() {
+ if !stream.is_readable() {
return Err(Error::Done);
}
let (read, fin) = stream.recv.pop(out)?;
- self.max_rx_data_next = self.max_rx_data_next.saturating_add(read);
+ self.max_rx_data_next = self.max_rx_data_next.saturating_add(read as u64);
+
+ let readable = stream.is_readable();
+
+ if stream.recv.almost_full() {
+ self.streams.mark_almost_full(stream_id, true);
+ }
+
+ if !readable {
+ self.streams.mark_readable(stream_id, false);
+ }
Ok((read, fin))
}
/// Writes data to a stream.
///
- /// On success the number of bytes written is returned.
+ /// On success the number of bytes written is returned, or [`Done`] if no
+ /// data was written (e.g. because the stream has no capacity).
+ ///
+ /// Note that in order to avoid buffering an infinite amount of data in the
+ /// stream's send buffer, streams are only allowed to buffer outgoing data
+ /// up to the amount that the peer allows it to send (that is, up to the
+ /// stream's outgoing flow control capacity).
+ ///
+ /// [`Done`]: enum.Error.html#variant.Done
///
/// ## Examples:
///
@@ -1908,27 +1989,26 @@
return Err(Error::InvalidStreamState);
}
- let max_rx_data =
- self.local_transport_params
- .initial_max_stream_data_bidi_local as usize;
- let max_tx_data =
- self.peer_transport_params
- .initial_max_stream_data_bidi_remote as usize;
-
// Get existing stream or create a new one.
- let stream = self.streams.get_or_create(
- stream_id,
- max_rx_data,
- max_tx_data,
- true,
- self.is_server,
- )?;
+ let stream = self.get_or_create_stream(stream_id, true)?;
- // TODO: implement backpressure based on peer's flow control
+ let was_flushable = stream.is_flushable();
- stream.send.push_slice(buf, fin)?;
+ let sent = stream.send.push_slice(buf, fin)?;
- Ok(buf.len())
+ let writable = stream.is_writable();
+
+ // If the stream is now flushable push it to the flushable queue, but
+ // only if it wasn't already queued.
+ if stream.is_flushable() && !was_flushable {
+ self.streams.push_flushable(stream_id);
+ }
+
+ if !writable {
+ self.streams.mark_writable(stream_id, false);
+ }
+
+ Ok(sent)
}
/// Shuts down reading or writing from/to the specified stream.
@@ -1956,15 +2036,34 @@
match direction {
// TODO: send STOP_SENDING
- Shutdown::Read => stream.recv.shutdown(),
+ Shutdown::Read => {
+ stream.recv.shutdown()?;
+
+ // Once shutdown, the stream is guaranteed to be non-readable.
+ self.streams.mark_readable(stream_id, false);
+ },
// TODO: send RESET_STREAM
- Shutdown::Write => stream.send.shutdown(),
+ Shutdown::Write => {
+ stream.send.shutdown()?;
+
+ // Once shutdown, the stream is guaranteed to be non-writable.
+ self.streams.mark_writable(stream_id, false);
+ },
}
Ok(())
}
+ /// Returns the stream's outgoing flow control capacity in bytes.
+ pub fn stream_capacity(&self, stream_id: u64) -> Result<usize> {
+ if let Some(stream) = self.streams.get(stream_id) {
+ return Ok(stream.send.cap());
+ };
+
+ Err(Error::InvalidStreamState)
+ }
+
/// Returns true if all the data has been read from the specified stream.
///
/// This instructs the application that all the data received from the
@@ -1976,13 +2075,19 @@
pub fn stream_finished(&self, stream_id: u64) -> bool {
let stream = match self.streams.get(stream_id) {
Some(v) => v,
+
None => return true,
};
stream.recv.is_fin()
}
- /// Creates an iterator over streams that have outstanding data to read.
+ /// Returns an iterator over streams that have outstanding data to read.
+ ///
+ /// Note that the iterator will only include streams that were readable at
+ /// the time the iterator itself was created (i.e. when `readable()` was
+ /// called). To account for newly readable streams, the iterator needs to
+ /// be created again.
///
/// ## Examples:
///
@@ -1993,9 +2098,7 @@
/// # let scid = [0xba; 16];
/// # let mut conn = quiche::accept(&scid, None, &mut config)?;
/// // Iterate over readable streams.
- /// let streams: Vec<u64> = conn.readable().collect();
- ///
- /// for stream_id in streams {
+ /// for stream_id in conn.readable() {
/// // Stream is readable, read until there's no more data.
/// while let Ok((read, fin)) = conn.stream_recv(stream_id, &mut buf) {
/// println!("Got {} bytes on stream {}", read, stream_id);
@@ -2003,10 +2106,49 @@
/// }
/// # Ok::<(), quiche::Error>(())
/// ```
- pub fn readable(&mut self) -> Readable {
+ pub fn readable(&self) -> StreamIter {
self.streams.readable()
}
+ /// Returns an iterator over streams that can be written to.
+ ///
+ /// A "writable" stream is a stream that has enough flow control capacity to
+ /// send data to the peer. To avoid buffering an infinite amount of data,
+ /// streams are only allowed to buffer outgoing data up to the amount that
+ /// the peer allows to send.
+ ///
+ /// Note that the iterator will only include streams that were writable at
+ /// the time the iterator itself was created (i.e. when `writable()` was
+ /// called). To account for newly writable streams, the iterator needs to
+ /// be created again.
+ ///
+ /// ## Examples:
+ ///
+ /// ```no_run
+ /// # let mut buf = [0; 512];
+ /// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
+ /// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
+ /// # let scid = [0xba; 16];
+ /// # let mut conn = quiche::accept(&scid, None, &mut config)?;
+ /// // Iterate over writable streams.
+ /// for stream_id in conn.writable() {
+ /// // Stream is writable, write some data.
+ /// if let Ok(written) = conn.stream_send(stream_id, &buf, false) {
+ /// println!("Written {} bytes on stream {}", written, stream_id);
+ /// }
+ /// }
+ /// # Ok::<(), quiche::Error>(())
+ /// ```
+ pub fn writable(&self) -> StreamIter {
+ // If there is not enough connection-level flow control capacity, none
+ // of the streams are writable, so return an empty iterator.
+ if self.max_tx_data <= self.tx_data {
+ return StreamIter::default();
+ }
+
+ self.streams.writable()
+ }
+
/// Returns the amount of time until the next timeout event.
///
/// Once the given duration has elapsed, the [`on_timeout()`] method should
@@ -2057,21 +2199,22 @@
return;
}
- if self.idle_timer.is_some() && self.idle_timer.unwrap() <= now {
- trace!("{} idle timeout expired", self.trace_id);
+ if let Some(timer) = self.idle_timer {
+ if timer <= now {
+ trace!("{} idle timeout expired", self.trace_id);
- self.closed = true;
- return;
+ self.closed = true;
+ return;
+ }
}
- if self.recovery.loss_detection_timer().is_some() &&
- self.recovery.loss_detection_timer().unwrap() <= now
- {
- trace!("{} loss detection timeout expired", self.trace_id);
+ if let Some(timer) = self.recovery.loss_detection_timer() {
+ if timer <= now {
+ trace!("{} loss detection timeout expired", self.trace_id);
- self.recovery.on_loss_detection_timeout(now, &self.trace_id);
-
- return;
+ self.recovery.on_loss_detection_timeout(now, &self.trace_id);
+ return;
+ }
}
}
@@ -2091,7 +2234,7 @@
/// [`send()`]: struct.Connection.html#method.send
/// [`timeout()`]: struct.Connection.html#method.timeout
/// [`is_closed()`]: struct.Connection.html#method.is_closed
- pub fn close(&mut self, app: bool, err: u16, reason: &[u8]) -> Result<()> {
+ pub fn close(&mut self, app: bool, err: u64, reason: &[u8]) -> Result<()> {
if self.draining_timer.is_some() {
return Err(Error::Done);
}
@@ -2180,13 +2323,13 @@
return Err(Error::InvalidTransportParam);
}
- self.max_tx_data = peer_params.initial_max_data as usize;
+ self.max_tx_data = peer_params.initial_max_data;
self.streams.update_peer_max_streams_bidi(
- peer_params.initial_max_streams_bidi as usize,
+ peer_params.initial_max_streams_bidi,
);
self.streams.update_peer_max_streams_uni(
- peer_params.initial_max_streams_uni as usize,
+ peer_params.initial_max_streams_uni,
);
self.recovery.max_ack_delay =
@@ -2211,11 +2354,9 @@
}
},
- Err(tls::Error::TlsFail) => return Err(Error::TlsFail),
+ Err(Error::Done) => (),
- Err(tls::Error::SyscallFail) => return Err(Error::TlsFail),
-
- Err(_) => (),
+ Err(e) => return Err(e),
}
}
@@ -2230,7 +2371,7 @@
crypto::Level::Initial => packet::EPOCH_INITIAL,
crypto::Level::ZeroRTT => unreachable!(),
crypto::Level::Handshake => packet::EPOCH_HANDSHAKE,
- crypto::Level::Application => packet::EPOCH_APPLICATION,
+ crypto::Level::OneRTT => packet::EPOCH_APPLICATION,
};
return Ok(epoch);
@@ -2254,9 +2395,9 @@
}
}
- // If there are writable streams, use Application.
+ // If there are flushable streams, use Application.
if self.handshake_completed &&
- (self.streams.has_writable() || self.streams.has_out_of_credit())
+ (self.streams.has_flushable() || self.streams.has_almost_full())
{
return Ok(packet::EPOCH_APPLICATION);
}
@@ -2264,6 +2405,20 @@
Err(Error::Done)
}
+ /// Returns the mutable stream with the given ID if it exists, or creates
+ /// a new one otherwise.
+ fn get_or_create_stream(
+ &mut self, id: u64, local: bool,
+ ) -> Result<&mut stream::Stream> {
+ self.streams.get_or_create(
+ id,
+ &self.local_transport_params,
+ &self.peer_transport_params,
+ local,
+ self.is_server,
+ )
+ }
+
/// Processes an incoming frame.
fn process_frame(
&mut self, frame: frame::Frame, epoch: packet::Epoch,
@@ -2277,10 +2432,11 @@
frame::Frame::Ping => (),
frame::Frame::ACK { ranges, ack_delay } => {
- let ack_delay = ack_delay *
- 2_u64.pow(
+ let ack_delay = ack_delay
+ .checked_mul(2_u64.pow(
self.peer_transport_params.ack_delay_exponent as u32,
- );
+ ))
+ .ok_or(Error::InvalidFrame)?;
self.recovery.on_ack_received(
&ranges,
@@ -2288,7 +2444,18 @@
epoch,
now,
&self.trace_id,
- );
+ )?;
+
+ // When we receive an ACK for a 1-RTT packet after handshake
+ // completion, it means the handshake has been confirmed.
+ if epoch == packet::EPOCH_APPLICATION && self.handshake_completed
+ {
+ self.handshake_confirmed = true;
+
+ // Once the handshake is confirmed, we can drop Handshake
+ // keys.
+ self.drop_epoch_state(packet::EPOCH_HANDSHAKE);
+ }
},
frame::Frame::ResetStream {
@@ -2303,25 +2470,10 @@
return Err(Error::InvalidStreamState);
}
- let max_rx_data = self
- .local_transport_params
- .initial_max_stream_data_bidi_remote
- as usize;
- let max_tx_data = self
- .peer_transport_params
- .initial_max_stream_data_bidi_local
- as usize;
-
// Get existing stream or create a new one.
- let stream = self.streams.get_or_create(
- stream_id,
- max_rx_data,
- max_tx_data,
- false,
- self.is_server,
- )?;
+ let stream = self.get_or_create_stream(stream_id, false)?;
- self.rx_data += stream.recv.reset(final_size as usize)?;
+ self.rx_data += stream.recv.reset(final_size)? as u64;
if self.rx_data > self.max_rx_data {
return Err(Error::FlowControl);
@@ -2351,9 +2503,7 @@
while let Ok((read, _)) = stream.recv.pop(&mut crypto_buf) {
let recv_buf = &crypto_buf[..read];
- self.handshake
- .provide_data(level, &recv_buf)
- .map_err(|_| Error::TlsFail)?;
+ self.handshake.provide_data(level, &recv_buf)?;
}
self.do_handshake(now)?;
@@ -2370,57 +2520,48 @@
return Err(Error::InvalidStreamState);
}
- let max_rx_data = self
- .local_transport_params
- .initial_max_stream_data_bidi_remote
- as usize;
- let max_tx_data = self
- .peer_transport_params
- .initial_max_stream_data_bidi_local
- as usize;
+ // Check for flow control limits.
+ let data_len = data.len() as u64;
- // Get existing stream or create a new one.
- let stream = self.streams.get_or_create(
- stream_id,
- max_rx_data,
- max_tx_data,
- false,
- self.is_server,
- )?;
-
- self.rx_data += data.len();
-
- if self.rx_data > self.max_rx_data {
+ if self.rx_data + data_len > self.max_rx_data {
return Err(Error::FlowControl);
}
+ // Get existing stream or create a new one.
+ let stream = self.get_or_create_stream(stream_id, false)?;
+
stream.recv.push(data)?;
+
+ if stream.is_readable() {
+ self.streams.mark_readable(stream_id, true);
+ }
+
+ self.rx_data += data_len;
},
frame::Frame::MaxData { max } => {
- self.max_tx_data = cmp::max(self.max_tx_data, max as usize);
+ self.max_tx_data = cmp::max(self.max_tx_data, max);
},
frame::Frame::MaxStreamData { stream_id, max } => {
- let max_rx_data = self
- .local_transport_params
- .initial_max_stream_data_bidi_remote
- as usize;
- let max_tx_data = self
- .peer_transport_params
- .initial_max_stream_data_bidi_local
- as usize;
-
// Get existing stream or create a new one.
- let stream = self.streams.get_or_create(
- stream_id,
- max_rx_data,
- max_tx_data,
- false,
- self.is_server,
- )?;
+ let stream = self.get_or_create_stream(stream_id, false)?;
- stream.send.update_max_data(max as usize);
+ let was_flushable = stream.is_flushable();
+
+ stream.send.update_max_data(max);
+
+ let writable = stream.is_writable();
+
+ // If the stream is now flushable push it to the flushable queue,
+ // but only if it wasn't already queued.
+ if stream.is_flushable() && !was_flushable {
+ self.streams.push_flushable(stream_id);
+ }
+
+ if writable {
+ self.streams.mark_writable(stream_id, true);
+ }
},
frame::Frame::MaxStreamsBidi { max } => {
@@ -2428,7 +2569,7 @@
return Err(Error::StreamLimit);
}
- self.streams.update_peer_max_streams_bidi(max as usize);
+ self.streams.update_peer_max_streams_bidi(max);
},
frame::Frame::MaxStreamsUni { max } => {
@@ -2436,7 +2577,7 @@
return Err(Error::StreamLimit);
}
- self.streams.update_peer_max_streams_uni(max as usize);
+ self.streams.update_peer_max_streams_uni(max);
},
frame::Frame::DataBlocked { .. } => (),
@@ -2471,21 +2612,18 @@
Ok(())
}
- /// Drops the initial keys and recovery state.
- fn drop_initial_state(&mut self) {
- if self.pkt_num_spaces[packet::EPOCH_INITIAL]
- .crypto_open
- .is_none()
- {
+ /// Drops the keys and recovery state for the given epoch.
+ fn drop_epoch_state(&mut self, epoch: packet::Epoch) {
+ if self.pkt_num_spaces[epoch].crypto_open.is_none() {
return;
}
- self.pkt_num_spaces[packet::EPOCH_INITIAL].crypto_open = None;
- self.pkt_num_spaces[packet::EPOCH_INITIAL].crypto_seal = None;
- self.pkt_num_spaces[packet::EPOCH_INITIAL].clear();
- self.recovery.drop_unacked_data(packet::EPOCH_INITIAL);
+ self.pkt_num_spaces[epoch].crypto_open = None;
+ self.pkt_num_spaces[epoch].crypto_seal = None;
+ self.pkt_num_spaces[epoch].clear();
+ self.recovery.drop_unacked_data(epoch);
- trace!("{} dropped initial state", self.trace_id);
+ trace!("{} dropped epoch {} state", self.trace_id, epoch);
}
}
@@ -2536,8 +2674,9 @@
pub initial_max_streams_uni: u64,
pub ack_delay_exponent: u64,
pub max_ack_delay: u64,
- pub disable_migration: bool,
- // pub preferred_address: ...
+ pub disable_active_migration: bool,
+ // pub preferred_address: ...,
+ pub active_conn_id_limit: u64,
}
impl Default for TransportParams {
@@ -2555,7 +2694,8 @@
initial_max_streams_uni: 0,
ack_delay_exponent: 3,
max_ack_delay: 25,
- disable_migration: false,
+ disable_active_migration: false,
+ active_conn_id_limit: 0,
}
}
}
@@ -2657,7 +2797,7 @@
},
0x000c => {
- tp.disable_migration = true;
+ tp.disable_active_migration = true;
},
0x000d => {
@@ -2668,6 +2808,10 @@
// TODO: decode preferred_address
},
+ 0x000e => {
+ tp.active_conn_id_limit = val.get_varint()?;
+ },
+
// Ignore unknown parameters.
_ => (),
}
@@ -2766,13 +2910,19 @@
b.put_varint(tp.max_ack_delay)?;
}
- if tp.disable_migration {
+ if tp.disable_active_migration {
b.put_u16(0x000c)?;
b.put_u16(0)?;
}
// TODO: encode preferred_address
+ if tp.active_conn_id_limit != 0 {
+ b.put_u16(0x000e)?;
+ b.put_u16(octets::varint_len(tp.active_conn_id_limit) as u16)?;
+ b.put_varint(tp.active_conn_id_limit)?;
+ }
+
b.off()
};
@@ -2821,7 +2971,11 @@
)?;
write!(f, "ack_delay_exponent={} ", self.ack_delay_exponent)?;
write!(f, "max_ack_delay={} ", self.max_ack_delay)?;
- write!(f, "disable_migration={}", self.disable_migration)?;
+ write!(
+ f,
+ "disable_active_migration={}",
+ self.disable_active_migration
+ )?;
Ok(())
}
@@ -2845,6 +2999,7 @@
config.set_initial_max_data(30);
config.set_initial_max_stream_data_bidi_local(15);
config.set_initial_max_stream_data_bidi_remote(15);
+ config.set_initial_max_stream_data_uni(10);
config.set_initial_max_streams_bidi(3);
config.set_initial_max_streams_uni(3);
config.verify_peer(false);
@@ -2925,7 +3080,7 @@
pub fn flush_client(&mut self, buf: &mut [u8]) -> Result<()> {
loop {
let len = match self.client.send(buf) {
- Ok(write) => write,
+ Ok(v) => v,
Err(Error::Done) => break,
@@ -2947,7 +3102,7 @@
pub fn flush_server(&mut self, buf: &mut [u8]) -> Result<()> {
loop {
let len = match self.server.send(buf) {
- Ok(write) => write,
+ Ok(v) => v,
Err(Error::Done) => break,
@@ -3055,7 +3210,7 @@
let payload_len =
frames.iter().fold(0, |acc, x| acc + x.wire_len()) + space.overhead();
- if pkt_type != packet::Type::Application {
+ if pkt_type != packet::Type::Short {
let len = pn_len + payload_len;
b.put_varint(len as u64)?;
}
@@ -3142,13 +3297,14 @@
initial_max_streams_uni: 18_473,
ack_delay_exponent: 20,
max_ack_delay: 2_u64.pow(14) - 1,
- disable_migration: true,
+ disable_active_migration: true,
+ active_conn_id_limit: 8,
};
let mut raw_params = [42; 256];
let mut raw_params =
TransportParams::encode(&tp, true, &mut raw_params).unwrap();
- assert_eq!(raw_params.len(), 96);
+ assert_eq!(raw_params.len(), 101);
let new_tp = TransportParams::decode(&mut raw_params, false).unwrap();
@@ -3204,6 +3360,61 @@
}
#[test]
+ fn handshake_confirmation() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ // Client sends initial flight
+ let mut len = pipe.client.send(&mut buf).unwrap();
+
+ // Server sends initial flight..
+ len = testing::recv_send(&mut pipe.server, &mut buf, len).unwrap();
+
+ assert!(!pipe.client.handshake_completed);
+ assert!(!pipe.client.handshake_confirmed);
+
+ assert!(!pipe.server.handshake_completed);
+ assert!(!pipe.server.handshake_confirmed);
+
+ // Client sends Handshake packet.
+ len = testing::recv_send(&mut pipe.client, &mut buf, len).unwrap();
+
+ assert!(pipe.client.handshake_completed);
+ assert!(!pipe.client.handshake_confirmed);
+
+ assert!(!pipe.server.handshake_completed);
+ assert!(!pipe.server.handshake_confirmed);
+
+ // Server completes handshake, and sends first 1-RTT packet.
+ len = testing::recv_send(&mut pipe.server, &mut buf, len).unwrap();
+
+ assert!(pipe.client.handshake_completed);
+ assert!(!pipe.client.handshake_confirmed);
+
+ assert!(pipe.server.handshake_completed);
+ assert!(!pipe.server.handshake_confirmed);
+
+ // Client ACKs 1-RTT packet.
+ len = testing::recv_send(&mut pipe.client, &mut buf, len).unwrap();
+
+ assert!(pipe.client.handshake_completed);
+ assert!(!pipe.client.handshake_confirmed);
+
+ assert!(pipe.server.handshake_completed);
+ assert!(!pipe.server.handshake_confirmed);
+
+ // Server handshake is confirmed.
+ testing::recv_send(&mut pipe.server, &mut buf, len).unwrap();
+
+ assert!(pipe.client.handshake_completed);
+ assert!(!pipe.client.handshake_confirmed);
+
+ assert!(pipe.server.handshake_completed);
+ assert!(pipe.server.handshake_confirmed);
+ }
+
+ #[test]
fn handshake_alpn_mismatch() {
let mut buf = [0; 65535];
@@ -3271,6 +3482,52 @@
}
#[test]
+ fn empty_stream_frame() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ let frames = [frame::Frame::Stream {
+ stream_id: 4,
+ data: stream::RangeBuf::from(b"aaaaa", 0, false),
+ }];
+
+ let pkt_type = packet::Type::Short;
+ assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), 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)));
+
+ let frames = [frame::Frame::Stream {
+ stream_id: 4,
+ data: stream::RangeBuf::from(b"", 5, true),
+ }];
+
+ let pkt_type = packet::Type::Short;
+ assert_eq!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf), 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)));
+
+ let frames = [frame::Frame::Stream {
+ stream_id: 4,
+ data: stream::RangeBuf::from(b"", 15, true),
+ }];
+
+ let pkt_type = packet::Type::Short;
+ assert_eq!(
+ pipe.send_pkt_to_server(pkt_type, &frames, &mut buf),
+ Err(Error::FinalSize)
+ );
+ }
+
+ #[test]
fn flow_control_limit() {
let mut buf = [0; 65535];
@@ -3293,7 +3550,7 @@
},
];
- let pkt_type = packet::Type::Application;
+ let pkt_type = packet::Type::Short;
assert_eq!(
pipe.send_pkt_to_server(pkt_type, &frames, &mut buf),
Err(Error::FlowControl),
@@ -3319,7 +3576,7 @@
},
];
- let pkt_type = packet::Type::Application;
+ let pkt_type = packet::Type::Short;
assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok());
@@ -3348,7 +3605,7 @@
}
#[test]
- fn stream_flow_control_limit() {
+ fn stream_flow_control_limit_bidi() {
let mut buf = [0; 65535];
let mut pipe = testing::Pipe::default().unwrap();
@@ -3360,7 +3617,27 @@
data: stream::RangeBuf::from(b"aaaaaaaaaaaaaaaa", 0, true),
}];
- let pkt_type = packet::Type::Application;
+ let pkt_type = packet::Type::Short;
+ assert_eq!(
+ pipe.send_pkt_to_server(pkt_type, &frames, &mut buf),
+ Err(Error::FlowControl),
+ );
+ }
+
+ #[test]
+ fn stream_flow_control_limit_uni() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ let frames = [frame::Frame::Stream {
+ stream_id: 2,
+ data: stream::RangeBuf::from(b"aaaaaaaaaaa", 0, true),
+ }];
+
+ let pkt_type = packet::Type::Short;
assert_eq!(
pipe.send_pkt_to_server(pkt_type, &frames, &mut buf),
Err(Error::FlowControl),
@@ -3380,7 +3657,7 @@
data: stream::RangeBuf::from(b"aaaaaaa", 0, false),
}];
- let pkt_type = packet::Type::Application;
+ let pkt_type = packet::Type::Short;
assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok());
@@ -3452,7 +3729,7 @@
},
];
- let pkt_type = packet::Type::Application;
+ let pkt_type = packet::Type::Short;
assert_eq!(
pipe.send_pkt_to_server(pkt_type, &frames, &mut buf),
Err(Error::StreamLimit),
@@ -3469,14 +3746,14 @@
let frames = [frame::Frame::MaxStreamsBidi { max: 2u64.pow(60) }];
- let pkt_type = packet::Type::Application;
+ let pkt_type = packet::Type::Short;
assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok());
let frames = [frame::Frame::MaxStreamsBidi {
max: 2u64.pow(60) + 1,
}];
- let pkt_type = packet::Type::Application;
+ let pkt_type = packet::Type::Short;
assert_eq!(
pipe.send_pkt_to_server(pkt_type, &frames, &mut buf),
Err(Error::StreamLimit),
@@ -3522,7 +3799,7 @@
},
];
- let pkt_type = packet::Type::Application;
+ let pkt_type = packet::Type::Short;
assert_eq!(
pipe.send_pkt_to_server(pkt_type, &frames, &mut buf),
Err(Error::StreamLimit),
@@ -3539,14 +3816,14 @@
let frames = [frame::Frame::MaxStreamsUni { max: 2u64.pow(60) }];
- let pkt_type = packet::Type::Application;
+ let pkt_type = packet::Type::Short;
assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok());
let frames = [frame::Frame::MaxStreamsUni {
max: 2u64.pow(60) + 1,
}];
- let pkt_type = packet::Type::Application;
+ let pkt_type = packet::Type::Short;
assert_eq!(
pipe.send_pkt_to_server(pkt_type, &frames, &mut buf),
Err(Error::StreamLimit),
@@ -3576,7 +3853,7 @@
},
];
- let pkt_type = packet::Type::Application;
+ let pkt_type = packet::Type::Short;
assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok());
let mut b = [0; 15];
@@ -3607,7 +3884,7 @@
},
];
- let pkt_type = packet::Type::Application;
+ let pkt_type = packet::Type::Short;
assert!(pipe.send_pkt_to_server(pkt_type, &frames, &mut buf).is_ok());
let mut b = [0; 15];
@@ -3643,7 +3920,7 @@
},
];
- let pkt_type = packet::Type::Application;
+ let pkt_type = packet::Type::Short;
assert_eq!(
pipe.send_pkt_to_server(pkt_type, &frames, &mut buf),
Err(Error::FlowControl),
@@ -3662,7 +3939,7 @@
data: vec![0xba; 8],
}];
- let pkt_type = packet::Type::Application;
+ let pkt_type = packet::Type::Short;
let len = pipe
.send_pkt_to_server(pkt_type, &frames, &mut buf)
@@ -3814,11 +4091,16 @@
let mut r = pipe.server.readable();
assert_eq!(r.next(), None);
- assert_eq!(pipe.client.stream_send(4, b"hello, world", false), Ok(12));
+ assert_eq!(pipe.client.stream_send(4, b"bye", false), Ok(3));
assert_eq!(pipe.advance(&mut buf), Ok(()));
let mut r = pipe.server.readable();
assert_eq!(r.next(), None);
+
+ assert_eq!(
+ pipe.server.stream_shutdown(4, Shutdown::Read, 0),
+ Err(Error::Done)
+ );
}
#[test]
@@ -3839,24 +4121,290 @@
let mut b = [0; 15];
pipe.server.stream_recv(4, &mut b).unwrap();
- assert_eq!(pipe.client.stream_send(4, b"hello, world", false), Ok(12));
+ assert_eq!(pipe.client.stream_send(4, b"a", false), Ok(1));
assert_eq!(pipe.client.stream_shutdown(4, Shutdown::Write, 0), Ok(()));
assert_eq!(pipe.advance(&mut buf), Ok(()));
let mut r = pipe.server.readable();
assert_eq!(r.next(), None);
- assert_eq!(pipe.client.stream_send(4, b"hello, world", false), Ok(12));
+ assert_eq!(pipe.client.stream_send(4, b"bye", false), Ok(3));
assert_eq!(pipe.advance(&mut buf), Ok(()));
let mut r = pipe.server.readable();
assert_eq!(r.next(), None);
+
+ assert_eq!(
+ pipe.client.stream_shutdown(4, Shutdown::Write, 0),
+ Err(Error::Done)
+ );
+ }
+
+ #[test]
+ /// Tests that the order of flushable streams scheduled on the wire is the
+ /// same as the order of `stream_send()` calls done by the application.
+ fn stream_round_robin() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(8, b"aaaaa", false), Ok(5));
+ assert_eq!(pipe.client.stream_send(0, b"aaaaa", false), Ok(5));
+ assert_eq!(pipe.client.stream_send(4, b"aaaaa", false), Ok(5));
+
+ let len = pipe.client.send(&mut buf).unwrap();
+
+ let frames =
+ testing::decode_pkt(&mut pipe.server, &mut buf, len).unwrap();
+
+ assert_eq!(
+ frames.iter().next(),
+ Some(&frame::Frame::Stream {
+ stream_id: 8,
+ data: stream::RangeBuf::from(b"aaaaa", 0, false),
+ })
+ );
+
+ let len = pipe.client.send(&mut buf).unwrap();
+
+ let frames =
+ testing::decode_pkt(&mut pipe.server, &mut buf, len).unwrap();
+
+ assert_eq!(
+ frames.iter().next(),
+ Some(&frame::Frame::Stream {
+ stream_id: 0,
+ data: stream::RangeBuf::from(b"aaaaa", 0, false),
+ })
+ );
+
+ let len = pipe.client.send(&mut buf).unwrap();
+
+ let frames =
+ testing::decode_pkt(&mut pipe.server, &mut buf, len).unwrap();
+
+ assert_eq!(
+ frames.iter().next(),
+ Some(&frame::Frame::Stream {
+ stream_id: 4,
+ data: stream::RangeBuf::from(b"aaaaa", 0, false),
+ })
+ );
+ }
+
+ #[test]
+ /// Tests the readable iterator.
+ fn stream_readable() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ // No readable streams.
+ let mut r = pipe.client.readable();
+ assert_eq!(r.next(), None);
+
+ assert_eq!(pipe.client.stream_send(4, b"aaaaa", false), Ok(5));
+
+ let mut r = pipe.client.readable();
+ assert_eq!(r.next(), None);
+
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ // Server received stream.
+ let mut r = pipe.server.readable();
+ assert_eq!(r.next(), Some(4));
+ assert_eq!(r.next(), None);
+
+ assert_eq!(
+ pipe.server.stream_send(4, b"aaaaaaaaaaaaaaa", false),
+ Ok(15)
+ );
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ let mut r = pipe.client.readable();
+ assert_eq!(r.next(), Some(4));
+ assert_eq!(r.next(), None);
+
+ // Client drains stream.
+ let mut b = [0; 15];
+ pipe.client.stream_recv(4, &mut b).unwrap();
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ let mut r = pipe.client.readable();
+ assert_eq!(r.next(), None);
+
+ // Server suts down stream.
+ let mut r = pipe.server.readable();
+ assert_eq!(r.next(), Some(4));
+ assert_eq!(r.next(), None);
+
+ assert_eq!(pipe.server.stream_shutdown(4, 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(8, b"aaaaa", false), Ok(5));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(12, b"aaaaa", false), Ok(5));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ let mut r = pipe.server.readable();
+ assert_eq!(r.len(), 2);
+
+ assert!(r.next().is_some());
+ assert!(r.next().is_some());
+ assert!(r.next().is_none());
+
+ assert_eq!(r.len(), 0);
+ }
+
+ #[test]
+ /// Tests the writable iterator.
+ fn stream_writable() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ // No writable streams.
+ let mut w = pipe.client.writable();
+ assert_eq!(w.next(), None);
+
+ assert_eq!(pipe.client.stream_send(4, b"aaaaa", false), Ok(5));
+
+ // Client created stream.
+ let mut w = pipe.client.writable();
+ assert_eq!(w.next(), Some(4));
+ assert_eq!(w.next(), None);
+
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ // Server created stream.
+ let mut w = pipe.server.writable();
+ assert_eq!(w.next(), Some(4));
+ assert_eq!(w.next(), None);
+
+ assert_eq!(
+ pipe.server.stream_send(4, b"aaaaaaaaaaaaaaa", false),
+ Ok(15)
+ );
+
+ // Server stream is full.
+ let mut w = pipe.server.writable();
+ assert_eq!(w.next(), None);
+
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ // Client drains stream.
+ let mut b = [0; 15];
+ pipe.client.stream_recv(4, &mut b).unwrap();
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ // Server stream is writable again.
+ let mut w = pipe.server.writable();
+ assert_eq!(w.next(), Some(4));
+ assert_eq!(w.next(), None);
+
+ // Server suts down stream.
+ assert_eq!(pipe.server.stream_shutdown(4, 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(8, b"aaaaa", false), Ok(5));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ assert_eq!(pipe.client.stream_send(12, b"aaaaa", false), Ok(5));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ let mut w = pipe.server.writable();
+ assert_eq!(w.len(), 2);
+
+ assert!(w.next().is_some());
+ assert!(w.next().is_some());
+ assert!(w.next().is_none());
+
+ assert_eq!(w.len(), 0);
+
+ // Server finishes stream.
+ assert_eq!(pipe.server.stream_send(12, b"aaaaa", true), Ok(5));
+
+ let mut w = pipe.server.writable();
+ assert_eq!(w.next(), Some(8));
+ assert_eq!(w.next(), None);
+ }
+
+ #[test]
+ /// Tests that we don't exceed the per-connection flow control limit set by
+ /// the peer.
+ fn flow_control_limit_send() {
+ let mut buf = [0; 65535];
+
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ assert_eq!(pipe.handshake(&mut buf), Ok(()));
+
+ assert_eq!(
+ pipe.client.stream_send(0, b"aaaaaaaaaaaaaaa", false),
+ Ok(15)
+ );
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+ assert_eq!(
+ pipe.client.stream_send(4, b"aaaaaaaaaaaaaaa", false),
+ Ok(15)
+ );
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+ assert_eq!(pipe.client.stream_send(8, b"a", false), Ok(1));
+ assert_eq!(pipe.advance(&mut buf), Ok(()));
+
+ let mut r = pipe.server.readable();
+ assert!(r.next().is_some());
+ assert!(r.next().is_some());
+ assert!(r.next().is_none());
+ }
+
+ #[test]
+ /// Tests that invalid packets received before any other valid ones cause
+ /// the server to close the connection immediately.
+ fn invalid_initial() {
+ let mut buf = [0; 65535];
+ let mut pipe = testing::Pipe::default().unwrap();
+
+ let frames = [frame::Frame::Padding { len: 10 }];
+
+ let written = testing::encode_pkt(
+ &mut pipe.client,
+ packet::Type::Initial,
+ &frames,
+ &mut buf,
+ )
+ .unwrap();
+
+ // Corrupt the packets's last byte to make decryption fail (the last
+ // byte is part of the AEAD tag, so changing it means that the packet
+ // cannot be authenticated during decryption).
+ buf[written - 1] = 0;
+
+ assert_eq!(pipe.server.timeout(), None);
+
+ assert_eq!(
+ pipe.server.recv(&mut buf[..written]),
+ Err(Error::CryptoFail)
+ );
}
}
pub use crate::packet::Header;
pub use crate::packet::Type;
-pub use crate::stream::Readable;
+pub use crate::stream::StreamIter;
mod crypto;
mod ffi;
diff --git a/src/octets.rs b/src/octets.rs
index ab37b9d..98b3c4b 100644
--- a/src/octets.rs
+++ b/src/octets.rs
@@ -48,10 +48,6 @@
}
impl std::error::Error for BufferTooShortError {
- fn description(&self) -> &str {
- "buffer is too short"
- }
-
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
@@ -59,18 +55,19 @@
macro_rules! peek_u {
($b:expr, $ty:ty, $len:expr) => {{
+ let len = $len;
let src = &$b.buf[$b.off..];
- if src.len() < $len {
+ if src.len() < len {
return Err(BufferTooShortError);
}
let mut out: $ty = 0;
unsafe {
let dst = &mut out as *mut $ty as *mut u8;
- let off = (mem::size_of::<$ty>() - $len) as isize;
+ let off = (mem::size_of::<$ty>() - len) as isize;
- ptr::copy_nonoverlapping(src.as_ptr(), dst.offset(off), $len);
+ ptr::copy_nonoverlapping(src.as_ptr(), dst.offset(off), len);
};
Ok(<$ty>::from_be(out))
@@ -89,18 +86,22 @@
macro_rules! put_u {
($b:expr, $ty:ty, $v:expr, $len:expr) => {{
- if $b.buf.len() < $b.off + $len {
+ let len = $len;
+
+ if $b.buf.len() < $b.off + len {
return Err(BufferTooShortError);
}
+ let v = $v;
+
#[allow(clippy::range_plus_one)]
- let dst = &mut $b.buf[$b.off..($b.off + $len)];
+ let dst = &mut $b.buf[$b.off..($b.off + len)];
unsafe {
- let src = &<$ty>::to_be($v) as *const $ty as *const u8;
- let off = (mem::size_of::<$ty>() - $len) as isize;
+ let src = &<$ty>::to_be(v) as *const $ty as *const u8;
+ let off = (mem::size_of::<$ty>() - len) as isize;
- ptr::copy_nonoverlapping(src.offset(off), dst.as_mut_ptr(), $len);
+ ptr::copy_nonoverlapping(src.offset(off), dst.as_mut_ptr(), len);
}
$b.off += $len;
@@ -701,7 +702,7 @@
#[test]
fn split() {
- let mut d = *b"helloworld";
+ let mut d = b"helloworld".to_vec();
let mut b = Octets::with_slice(&mut d);
assert_eq!(b.cap(), 10);
@@ -727,16 +728,16 @@
#[test]
fn split_at() {
- let mut d = *b"helloworld";
+ let mut d = b"helloworld".to_vec();
{
let mut b = Octets::with_slice(&mut d);
let (first, second) = b.split_at(5).unwrap();
- let mut exp1 = *b"hello";
+ let mut exp1 = b"hello".to_vec();
assert_eq!(first.as_ref(), &mut exp1[..]);
- let mut exp2 = *b"world";
+ let mut exp2 = b"world".to_vec();
assert_eq!(second.as_ref(), &mut exp2[..]);
}
@@ -744,10 +745,10 @@
let mut b = Octets::with_slice(&mut d);
let (first, second) = b.split_at(10).unwrap();
- let mut exp1 = *b"helloworld";
+ let mut exp1 = b"helloworld".to_vec();
assert_eq!(first.as_ref(), &mut exp1[..]);
- let mut exp2 = *b"";
+ let mut exp2 = b"".to_vec();
assert_eq!(second.as_ref(), &mut exp2[..]);
}
@@ -755,10 +756,10 @@
let mut b = Octets::with_slice(&mut d);
let (first, second) = b.split_at(9).unwrap();
- let mut exp1 = *b"helloworl";
+ let mut exp1 = b"helloworl".to_vec();
assert_eq!(first.as_ref(), &mut exp1[..]);
- let mut exp2 = *b"d";
+ let mut exp2 = b"d".to_vec();
assert_eq!(second.as_ref(), &mut exp2[..]);
}
@@ -770,17 +771,17 @@
#[test]
fn slice() {
- let mut d = *b"helloworld";
+ let mut d = b"helloworld".to_vec();
{
let mut b = Octets::with_slice(&mut d);
- let mut exp = *b"hello";
+ let mut exp = b"hello".to_vec();
assert_eq!(b.slice(5), Ok(&mut exp[..]));
}
{
let mut b = Octets::with_slice(&mut d);
- let mut exp = *b"";
+ let mut exp = b"".to_vec();
assert_eq!(b.slice(0), Ok(&mut exp[..]));
}
@@ -788,7 +789,7 @@
let mut b = Octets::with_slice(&mut d);
b.get_bytes(5).unwrap();
- let mut exp = *b"world";
+ let mut exp = b"world".to_vec();
assert_eq!(b.slice(5), Ok(&mut exp[..]));
}
@@ -800,29 +801,29 @@
#[test]
fn slice_last() {
- let mut d = *b"helloworld";
+ let mut d = b"helloworld".to_vec();
{
let mut b = Octets::with_slice(&mut d);
- let mut exp = *b"orld";
+ let mut exp = b"orld".to_vec();
assert_eq!(b.slice_last(4), Ok(&mut exp[..]));
}
{
let mut b = Octets::with_slice(&mut d);
- let mut exp = *b"d";
+ let mut exp = b"d".to_vec();
assert_eq!(b.slice_last(1), Ok(&mut exp[..]));
}
{
let mut b = Octets::with_slice(&mut d);
- let mut exp = *b"";
+ let mut exp = b"".to_vec();
assert_eq!(b.slice_last(0), Ok(&mut exp[..]));
}
{
let mut b = Octets::with_slice(&mut d);
- let mut exp = *b"helloworld";
+ let mut exp = b"helloworld".to_vec();
assert_eq!(b.slice_last(10), Ok(&mut exp[..]));
}
diff --git a/src/packet.rs b/src/packet.rs
index 058dc76..5166a4e 100644
--- a/src/packet.rs
+++ b/src/packet.rs
@@ -43,7 +43,7 @@
const TYPE_MASK: u8 = 0x30;
const PKT_NUM_MASK: u8 = 0x03;
-pub const MAX_CID_LEN: u8 = 18;
+pub const MAX_CID_LEN: u8 = 20;
const MAX_PKT_NUM_LEN: usize = 4;
const SAMPLE_LEN: usize = 16;
@@ -78,8 +78,8 @@
/// Version negotiation packet.
VersionNegotiation,
- /// Short header packet.
- Application,
+ /// 1-RTT short header packet.
+ Short,
}
impl Type {
@@ -89,7 +89,7 @@
EPOCH_HANDSHAKE => Type::Handshake,
- EPOCH_APPLICATION => Type::Application,
+ EPOCH_APPLICATION => Type::Short,
_ => unreachable!(),
}
@@ -103,7 +103,7 @@
Type::Handshake => Ok(EPOCH_HANDSHAKE),
- Type::Application => Ok(EPOCH_APPLICATION),
+ Type::Short => Ok(EPOCH_APPLICATION),
_ => Err(Error::InvalidPacket),
}
@@ -153,7 +153,7 @@
impl Header {
/// Parses a QUIC packet header from the given buffer.
///
- /// The `dcil` parameter is the length of the destination connection ID,
+ /// The `dcid_len` parameter is the length of the destination connection ID,
/// required to parse short header packets.
///
/// ## Examples:
@@ -168,22 +168,22 @@
/// let hdr = quiche::Header::from_slice(&mut buf[..len], LOCAL_CONN_ID_LEN)?;
/// # Ok::<(), quiche::Error>(())
/// ```
- pub fn from_slice(buf: &mut [u8], dcil: usize) -> Result<Header> {
+ pub fn from_slice(buf: &mut [u8], dcid_len: usize) -> Result<Header> {
let mut b = octets::Octets::with_slice(buf);
- Header::from_bytes(&mut b, dcil)
+ Header::from_bytes(&mut b, dcid_len)
}
pub(crate) fn from_bytes(
- b: &mut octets::Octets, dcil: usize,
+ b: &mut octets::Octets, dcid_len: usize,
) -> Result<Header> {
let first = b.get_u8()?;
if !Header::is_long(first) {
// Decode short header.
- let dcid = b.get_bytes(dcil)?;
+ let dcid = b.get_bytes(dcid_len)?;
return Ok(Header {
- ty: Type::Application,
+ ty: Type::Short,
version: 0,
dcid: dcid.to_vec(),
scid: Vec::new(),
@@ -211,31 +211,17 @@
}
};
- let (dcil, scil) = match b.get_u8() {
- Ok(v) => {
- let mut dcil = v >> 4;
- let mut scil = v & 0xf;
+ let dcid_len = b.get_u8()?;
+ if version == crate::PROTOCOL_VERSION && dcid_len > MAX_CID_LEN {
+ return Err(Error::InvalidPacket);
+ }
+ let dcid = b.get_bytes(dcid_len as usize)?.to_vec();
- if dcil > 0 {
- dcil += 3;
- }
-
- if scil > 0 {
- scil += 3;
- }
-
- if dcil > MAX_CID_LEN || scil > MAX_CID_LEN {
- return Err(Error::InvalidPacket);
- }
-
- (dcil, scil)
- },
-
- Err(_) => return Err(Error::BufferTooShort),
- };
-
- let dcid = b.get_bytes(dcil as usize)?.to_vec();
- let scid = b.get_bytes(scil as usize)?.to_vec();
+ let scid_len = b.get_u8()?;
+ if version == crate::PROTOCOL_VERSION && scid_len > MAX_CID_LEN {
+ return Err(Error::InvalidPacket);
+ }
+ let scid = b.get_bytes(scid_len as usize)?.to_vec();
// End of invariants.
@@ -249,17 +235,13 @@
},
Type::Retry => {
- let mut odcil = first & 0x0f;
+ let odcid_len = b.get_u8()?;
- if odcil > 0 {
- odcil += 3;
- }
-
- if odcil > MAX_CID_LEN {
+ if odcid_len > MAX_CID_LEN {
return Err(Error::InvalidPacket);
}
- odcid = Some(b.get_bytes(odcil as usize)?.to_vec());
+ odcid = Some(b.get_bytes(odcid_len as usize)?.to_vec());
token = Some(b.to_vec());
},
@@ -298,7 +280,7 @@
first |= self.pkt_num_len.saturating_sub(1) as u8;
// Encode short header.
- if self.ty == Type::Application {
+ if self.ty == Type::Short {
// Unset form bit for short header.
first &= !FORM_BIT;
@@ -329,32 +311,19 @@
first |= FORM_BIT | FIXED_BIT | (ty << 4);
- if self.ty == Type::Retry {
- let odcid = self.odcid.as_ref().unwrap();
- first |= (odcid.len() - 3) as u8;
- }
-
out.put_u8(first)?;
out.put_u32(self.version)?;
- let mut cil: u8 = 0;
-
- if !self.dcid.is_empty() {
- cil |= ((self.dcid.len() - 3) as u8) << 4;
- }
-
- if !self.scid.is_empty() {
- cil |= ((self.scid.len() - 3) as u8) & 0xf;
- }
-
- out.put_u8(cil)?;
-
+ out.put_u8(self.dcid.len() as u8)?;
out.put_bytes(&self.dcid)?;
+
+ out.put_u8(self.scid.len() as u8)?;
out.put_bytes(&self.scid)?;
if self.ty == Type::Retry {
let odcid = self.odcid.as_ref().unwrap();
+ out.put_u8(odcid.len() as u8)?;
out.put_bytes(odcid)?;
}
@@ -393,7 +362,7 @@
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:?}", self.ty)?;
- if self.ty != Type::Application {
+ if self.ty != Type::Short {
write!(f, " version={:x}", self.version)?;
}
@@ -402,7 +371,7 @@
write!(f, "{:02x}", b)?;
}
- if self.ty != Type::Application {
+ if self.ty != Type::Short {
write!(f, " scid=")?;
for b in &self.scid {
write!(f, "{:02x}", b)?;
@@ -427,7 +396,7 @@
write!(f, " versions={:x?}", versions)?;
}
- if self.ty == Type::Application {
+ if self.ty == Type::Short {
write!(f, " key_phase={}", self.key_phase)?;
}
@@ -500,7 +469,7 @@
hdr.pkt_num = pn;
hdr.pkt_num_len = pn_len;
- if hdr.ty == Type::Application {
+ if hdr.ty == Type::Short {
hdr.key_phase = (first & KEY_PHASE_BIT) != 0;
}
@@ -534,7 +503,11 @@
let (header, mut payload) = b.split_at(payload_offset)?;
- let mut ciphertext = payload.peek_bytes(payload_len - pn_len)?;
+ let payload_len = payload_len
+ .checked_sub(pn_len)
+ .ok_or(Error::InvalidPacket)?;
+
+ let mut ciphertext = payload.peek_bytes(payload_len)?;
let payload_len =
aead.open_with_u64_counter(pn, header.as_ref(), ciphertext.as_mut())?;
@@ -610,18 +583,9 @@
b.put_u8(first)?;
b.put_u32(0)?;
- // Invert client's scid and dcid.
- let mut cil: u8 = 0;
- if !scid.is_empty() {
- cil |= ((scid.len() - 3) as u8) << 4;
- }
-
- if !dcid.is_empty() {
- cil |= ((dcid.len() - 3) as u8) & 0xf;
- }
-
- b.put_u8(cil)?;
+ b.put_u8(scid.len() as u8)?;
b.put_bytes(&scid)?;
+ b.put_u8(dcid.len() as u8)?;
b.put_bytes(&dcid)?;
b.put_u32(crate::PROTOCOL_VERSION)?;
@@ -688,13 +652,12 @@
crypto_open: None,
crypto_seal: None,
- crypto_stream: stream::Stream::new(std::usize::MAX, std::usize::MAX),
+ crypto_stream: stream::Stream::new(std::u64::MAX, std::u64::MAX),
}
}
pub fn clear(&mut self) {
- self.crypto_stream =
- stream::Stream::new(std::usize::MAX, std::usize::MAX);
+ self.crypto_stream = stream::Stream::new(std::u64::MAX, std::u64::MAX);
self.ack_elicited = false;
}
@@ -704,7 +667,7 @@
}
pub fn ready(&self) -> bool {
- self.crypto_stream.writable() || self.ack_elicited
+ self.crypto_stream.is_flushable() || self.ack_elicited
}
}
@@ -777,7 +740,7 @@
key_phase: false,
};
- let mut d = [0; 50];
+ let mut d = [0; 52];
let mut b = octets::Octets::with_slice(&mut d);
assert!(hdr.to_bytes(&mut b).is_ok());
@@ -811,6 +774,87 @@
}
#[test]
+ fn initial_v1_dcid_too_long() {
+ let hdr = Header {
+ ty: Type::Initial,
+ version: crate::PROTOCOL_VERSION,
+ dcid: vec![
+ 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba,
+ 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba,
+ ],
+ scid: vec![0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb],
+ pkt_num: 0,
+ pkt_num_len: 0,
+ odcid: None,
+ token: Some(vec![0x05, 0x06, 0x07, 0x08]),
+ versions: None,
+ key_phase: false,
+ };
+
+ let mut d = [0; 50];
+
+ let mut b = octets::Octets::with_slice(&mut d);
+ assert!(hdr.to_bytes(&mut b).is_ok());
+
+ let mut b = octets::Octets::with_slice(&mut d);
+ assert_eq!(Header::from_bytes(&mut b, 21), Err(Error::InvalidPacket));
+ }
+
+ #[test]
+ fn initial_v1_scid_too_long() {
+ let hdr = Header {
+ ty: Type::Initial,
+ version: crate::PROTOCOL_VERSION,
+ dcid: vec![0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba],
+ scid: vec![
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
+ ],
+ pkt_num: 0,
+ pkt_num_len: 0,
+ odcid: None,
+ token: Some(vec![0x05, 0x06, 0x07, 0x08]),
+ versions: None,
+ key_phase: false,
+ };
+
+ let mut d = [0; 50];
+
+ let mut b = octets::Octets::with_slice(&mut d);
+ assert!(hdr.to_bytes(&mut b).is_ok());
+
+ let mut b = octets::Octets::with_slice(&mut d);
+ assert_eq!(Header::from_bytes(&mut b, 9), Err(Error::InvalidPacket));
+ }
+
+ #[test]
+ fn initial_non_v1_scid_long() {
+ let hdr = Header {
+ ty: Type::Initial,
+ version: 0xafafafaf,
+ dcid: vec![0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba],
+ scid: vec![
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
+ 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb,
+ ],
+ pkt_num: 0,
+ pkt_num_len: 0,
+ odcid: None,
+ token: Some(vec![0x05, 0x06, 0x07, 0x08]),
+ versions: None,
+ key_phase: false,
+ };
+
+ let mut d = [0; 50];
+
+ let mut b = octets::Octets::with_slice(&mut d);
+ assert!(hdr.to_bytes(&mut b).is_ok());
+
+ let mut b = octets::Octets::with_slice(&mut d);
+ assert_eq!(Header::from_bytes(&mut b, 9).unwrap(), hdr);
+ }
+
+ #[test]
fn handshake() {
let hdr = Header {
ty: Type::Handshake,
@@ -837,7 +881,7 @@
#[test]
fn application() {
let hdr = Header {
- ty: Type::Application,
+ ty: Type::Short,
version: 0,
dcid: vec![0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba],
scid: vec![],
@@ -1000,116 +1044,116 @@
#[test]
fn decrypt_client_initial() {
let mut pkt = [
- 0xc1, 0xff, 0x00, 0x00, 0x12, 0x50, 0x83, 0x94, 0xc8, 0xf0, 0x3e,
- 0x51, 0x57, 0x08, 0x00, 0x44, 0x9f, 0x0d, 0xbc, 0x19, 0x5a, 0x00,
- 0x00, 0xf3, 0xa6, 0x94, 0xc7, 0x57, 0x75, 0xb4, 0xe5, 0x46, 0x17,
- 0x2c, 0xe9, 0xe0, 0x47, 0xcd, 0x0b, 0x5b, 0xee, 0x51, 0x81, 0x64,
- 0x8c, 0x72, 0x7a, 0xdc, 0x87, 0xf7, 0xea, 0xe5, 0x44, 0x73, 0xec,
- 0x6c, 0xba, 0x6b, 0xda, 0xd4, 0xf5, 0x98, 0x23, 0x17, 0x4b, 0x76,
- 0x9f, 0x12, 0x35, 0x8a, 0xbd, 0x29, 0x2d, 0x4f, 0x32, 0x86, 0x93,
- 0x44, 0x84, 0xfb, 0x8b, 0x23, 0x9c, 0x38, 0x73, 0x2e, 0x1f, 0x3b,
- 0xbb, 0xc6, 0xa0, 0x03, 0x05, 0x64, 0x87, 0xeb, 0x8b, 0x5c, 0x88,
- 0xb9, 0xfd, 0x92, 0x79, 0xff, 0xff, 0x3b, 0x0f, 0x4e, 0xcf, 0x95,
- 0xc4, 0x62, 0x4d, 0xb6, 0xd6, 0x5d, 0x41, 0x13, 0x32, 0x9e, 0xe9,
- 0xb0, 0xbf, 0x8c, 0xdd, 0x7c, 0x8a, 0x8d, 0x72, 0x80, 0x6d, 0x55,
- 0xdf, 0x25, 0xec, 0xb6, 0x64, 0x88, 0xbc, 0x11, 0x9d, 0x7c, 0x9a,
- 0x29, 0xab, 0xaf, 0x99, 0xbb, 0x33, 0xc5, 0x6b, 0x08, 0xad, 0x8c,
- 0x26, 0x99, 0x5f, 0x83, 0x8b, 0xb3, 0xb7, 0xa3, 0xd5, 0xc1, 0x85,
- 0x8b, 0x8e, 0xc0, 0x6b, 0x83, 0x9d, 0xb2, 0xdc, 0xf9, 0x18, 0xd5,
- 0xea, 0x93, 0x17, 0xf1, 0xac, 0xd6, 0xb6, 0x63, 0xcc, 0x89, 0x25,
- 0x86, 0x8e, 0x2f, 0x6a, 0x1b, 0xda, 0x54, 0x66, 0x95, 0xf3, 0xc3,
- 0xf3, 0x31, 0x75, 0x94, 0x4d, 0xb4, 0xa1, 0x1a, 0x34, 0x6a, 0xfb,
- 0x07, 0xe7, 0x84, 0x89, 0xe5, 0x09, 0xb0, 0x2a, 0xdd, 0x51, 0xb7,
- 0xb2, 0x03, 0xed, 0xa5, 0xc3, 0x30, 0xb0, 0x36, 0x41, 0x17, 0x9a,
- 0x31, 0xfb, 0xba, 0x9b, 0x56, 0xce, 0x00, 0xf3, 0xd5, 0xb5, 0xe3,
- 0xd7, 0xd9, 0xc5, 0x42, 0x9a, 0xeb, 0xb9, 0x57, 0x6f, 0x2f, 0x7e,
- 0xac, 0xbe, 0x27, 0xbc, 0x1b, 0x80, 0x82, 0xaa, 0xf6, 0x8f, 0xb6,
- 0x9c, 0x92, 0x1a, 0xa5, 0xd3, 0x3e, 0xc0, 0xc8, 0x51, 0x04, 0x10,
- 0x86, 0x5a, 0x17, 0x8d, 0x86, 0xd7, 0xe5, 0x41, 0x22, 0xd5, 0x5e,
- 0xf2, 0xc2, 0xbb, 0xc0, 0x40, 0xbe, 0x46, 0xd7, 0xfe, 0xce, 0x73,
- 0xfe, 0x8a, 0x1b, 0x24, 0x49, 0x5e, 0xc1, 0x60, 0xdf, 0x2d, 0xa9,
- 0xb2, 0x0a, 0x7b, 0xa2, 0xf2, 0x6d, 0xfa, 0x2a, 0x44, 0x36, 0x6d,
- 0xbc, 0x63, 0xde, 0x5c, 0xd7, 0xd7, 0xc9, 0x4c, 0x57, 0x17, 0x2f,
- 0xe6, 0xd7, 0x9c, 0x90, 0x1f, 0x02, 0x5c, 0x00, 0x10, 0xb0, 0x2c,
- 0x89, 0xb3, 0x95, 0x40, 0x2c, 0x00, 0x9f, 0x62, 0xdc, 0x05, 0x3b,
- 0x80, 0x67, 0xa1, 0xe0, 0xed, 0x0a, 0x1e, 0x0c, 0xf5, 0x08, 0x7d,
- 0x7f, 0x78, 0xcb, 0xd9, 0x4a, 0xfe, 0x0c, 0x3d, 0xd5, 0x5d, 0x2d,
- 0x4b, 0x1a, 0x5c, 0xfe, 0x2b, 0x68, 0xb8, 0x62, 0x64, 0xe3, 0x51,
- 0xd1, 0xdc, 0xd8, 0x58, 0x78, 0x3a, 0x24, 0x0f, 0x89, 0x3f, 0x00,
- 0x8c, 0xee, 0xd7, 0x43, 0xd9, 0x69, 0xb8, 0xf7, 0x35, 0xa1, 0x67,
- 0x7e, 0xad, 0x96, 0x0b, 0x1f, 0xb1, 0xec, 0xc5, 0xac, 0x83, 0xc2,
- 0x73, 0xb4, 0x92, 0x88, 0xd0, 0x2d, 0x72, 0x86, 0x20, 0x7e, 0x66,
- 0x3c, 0x45, 0xe1, 0xa7, 0xba, 0xf5, 0x06, 0x40, 0xc9, 0x1e, 0x76,
- 0x29, 0x41, 0xcf, 0x38, 0x0c, 0xe8, 0xd7, 0x9f, 0x3e, 0x86, 0x76,
- 0x7f, 0xbb, 0xcd, 0x25, 0xb4, 0x2e, 0xf7, 0x0e, 0xc3, 0x34, 0x83,
- 0x5a, 0x3a, 0x6d, 0x79, 0x2e, 0x17, 0x0a, 0x43, 0x2c, 0xe0, 0xcb,
- 0x7b, 0xde, 0x9a, 0xaa, 0x1e, 0x75, 0x63, 0x7c, 0x1c, 0x34, 0xae,
- 0x5f, 0xef, 0x43, 0x38, 0xf5, 0x3d, 0xb8, 0xb1, 0x3a, 0x4d, 0x2d,
- 0xf5, 0x94, 0xef, 0xbf, 0xa0, 0x87, 0x84, 0x54, 0x38, 0x15, 0xc9,
- 0xc0, 0xd4, 0x87, 0xbd, 0xdf, 0xa1, 0x53, 0x9b, 0xc2, 0x52, 0xcf,
- 0x43, 0xec, 0x36, 0x86, 0xe9, 0x80, 0x2d, 0x65, 0x1c, 0xfd, 0x2a,
- 0x82, 0x9a, 0x06, 0xa9, 0xf3, 0x32, 0xa7, 0x33, 0xa4, 0xa8, 0xae,
- 0xd8, 0x0e, 0xfe, 0x34, 0x78, 0x09, 0x3f, 0xbc, 0x69, 0xc8, 0x60,
- 0x81, 0x46, 0xb3, 0xf1, 0x6f, 0x1a, 0x5c, 0x4e, 0xac, 0x93, 0x20,
- 0xda, 0x49, 0xf1, 0xaf, 0xa5, 0xf5, 0x38, 0xdd, 0xec, 0xbb, 0xe7,
- 0x88, 0x8f, 0x43, 0x55, 0x12, 0xd0, 0xdd, 0x74, 0xfd, 0x9b, 0x8c,
- 0x99, 0xe3, 0x14, 0x5b, 0xa8, 0x44, 0x10, 0xd8, 0xca, 0x9a, 0x36,
- 0xdd, 0x88, 0x41, 0x09, 0xe7, 0x6e, 0x5f, 0xb8, 0x22, 0x2a, 0x52,
- 0xe1, 0x47, 0x3d, 0xa1, 0x68, 0x51, 0x9c, 0xe7, 0xa8, 0xa3, 0xc3,
- 0x2e, 0x91, 0x49, 0x67, 0x1b, 0x16, 0x72, 0x4c, 0x6c, 0x5c, 0x51,
- 0xbb, 0x5c, 0xd6, 0x4f, 0xb5, 0x91, 0xe5, 0x67, 0xfb, 0x78, 0xb1,
- 0x0f, 0x9f, 0x6f, 0xee, 0x62, 0xc2, 0x76, 0xf2, 0x82, 0xa7, 0xdf,
- 0x6b, 0xcf, 0x7c, 0x17, 0x74, 0x7b, 0xc9, 0xa8, 0x1e, 0x6c, 0x9c,
- 0x3b, 0x03, 0x2f, 0xdd, 0x0e, 0x1c, 0x3a, 0xc9, 0xea, 0xa5, 0x07,
- 0x7d, 0xe3, 0xde, 0xd1, 0x8b, 0x2e, 0xd4, 0xfa, 0xf3, 0x28, 0xf4,
- 0x98, 0x75, 0xaf, 0x2e, 0x36, 0xad, 0x5c, 0xe5, 0xf6, 0xcc, 0x99,
- 0xef, 0x4b, 0x60, 0xe5, 0x7b, 0x3b, 0x5b, 0x9c, 0x9f, 0xcb, 0xcd,
- 0x4c, 0xfb, 0x39, 0x75, 0xe7, 0x0c, 0xe4, 0xc2, 0x50, 0x6b, 0xcd,
- 0x71, 0xfe, 0xf0, 0xe5, 0x35, 0x92, 0x46, 0x15, 0x04, 0xe3, 0xd4,
- 0x2c, 0x88, 0x5c, 0xaa, 0xb2, 0x1b, 0x78, 0x2e, 0x26, 0x29, 0x4c,
- 0x6a, 0x9d, 0x61, 0x11, 0x8c, 0xc4, 0x0a, 0x26, 0xf3, 0x78, 0x44,
- 0x1c, 0xeb, 0x48, 0xf3, 0x1a, 0x36, 0x2b, 0xf8, 0x50, 0x2a, 0x72,
- 0x3a, 0x36, 0xc6, 0x35, 0x02, 0x22, 0x9a, 0x46, 0x2c, 0xc2, 0xa3,
- 0x79, 0x62, 0x79, 0xa5, 0xe3, 0xa7, 0xf8, 0x1a, 0x68, 0xc7, 0xf8,
- 0x13, 0x12, 0xc3, 0x81, 0xcc, 0x16, 0xa4, 0xab, 0x03, 0x51, 0x3a,
- 0x51, 0xad, 0x5b, 0x54, 0x30, 0x6e, 0xc1, 0xd7, 0x8a, 0x5e, 0x47,
- 0xe2, 0xb1, 0x5e, 0x5b, 0x7a, 0x14, 0x38, 0xe5, 0xb8, 0xb2, 0x88,
- 0x2d, 0xbd, 0xad, 0x13, 0xd6, 0xa4, 0xa8, 0xc3, 0x55, 0x8c, 0xae,
- 0x04, 0x35, 0x01, 0xb6, 0x8e, 0xb3, 0xb0, 0x40, 0x06, 0x71, 0x52,
- 0x33, 0x7c, 0x05, 0x1c, 0x40, 0xb5, 0xaf, 0x80, 0x9a, 0xca, 0x28,
- 0x56, 0x98, 0x6f, 0xd1, 0xc8, 0x6a, 0x4a, 0xde, 0x17, 0xd2, 0x54,
- 0xb6, 0x26, 0x2a, 0xc1, 0xbc, 0x07, 0x73, 0x43, 0xb5, 0x2b, 0xf8,
- 0x9f, 0xa2, 0x7d, 0x73, 0xe3, 0xc6, 0xf3, 0x11, 0x8c, 0x99, 0x61,
- 0xf0, 0xbe, 0xbe, 0x68, 0xa5, 0xc3, 0x23, 0xc2, 0xd8, 0x4b, 0x8c,
- 0x29, 0xa2, 0x80, 0x7d, 0xf6, 0x63, 0x63, 0x52, 0x23, 0x24, 0x2a,
- 0x2c, 0xe9, 0x82, 0x8d, 0x44, 0x29, 0xac, 0x27, 0x0a, 0xab, 0x5f,
- 0x18, 0x41, 0xe8, 0xe4, 0x9c, 0xf4, 0x33, 0xb1, 0x54, 0x79, 0x89,
- 0xf4, 0x19, 0xca, 0xa3, 0xc7, 0x58, 0xff, 0xf9, 0x6d, 0xed, 0x40,
- 0xcf, 0x34, 0x27, 0xf0, 0x76, 0x1b, 0x67, 0x8d, 0xaa, 0x1a, 0x9e,
- 0x55, 0x54, 0x46, 0x5d, 0x46, 0xb7, 0xa9, 0x17, 0x49, 0x3f, 0xc7,
- 0x0f, 0x9e, 0xc5, 0xe4, 0xe5, 0xd7, 0x86, 0xca, 0x50, 0x17, 0x30,
- 0x89, 0x8a, 0xaa, 0x11, 0x51, 0xdc, 0xd3, 0x18, 0x29, 0x64, 0x1e,
- 0x29, 0x42, 0x8d, 0x90, 0xe6, 0x06, 0x55, 0x11, 0xc2, 0x4d, 0x31,
- 0x09, 0xf7, 0xcb, 0xa3, 0x22, 0x25, 0xd4, 0xac, 0xcf, 0xc5, 0x4f,
- 0xec, 0x42, 0xb7, 0x33, 0xf9, 0x58, 0x52, 0x52, 0xee, 0x36, 0xfa,
- 0x5e, 0xa0, 0xc6, 0x56, 0x93, 0x43, 0x85, 0xb4, 0x68, 0xee, 0xe2,
- 0x45, 0x31, 0x51, 0x46, 0xb8, 0xc0, 0x47, 0xed, 0x27, 0xc5, 0x19,
- 0xb2, 0xc0, 0xa5, 0x2d, 0x33, 0xef, 0xe7, 0x2c, 0x18, 0x6f, 0xfe,
- 0x0a, 0x23, 0x0f, 0x50, 0x56, 0x76, 0xc5, 0x32, 0x4b, 0xaa, 0x6a,
- 0xe0, 0x06, 0xa7, 0x3e, 0x13, 0xaa, 0x8c, 0x39, 0xab, 0x17, 0x3a,
- 0xd2, 0xb2, 0x77, 0x8e, 0xea, 0x0b, 0x34, 0xc4, 0x6f, 0x2b, 0x3b,
- 0xea, 0xe2, 0xc6, 0x2a, 0x2c, 0x8d, 0xb2, 0x38, 0xbf, 0x58, 0xfc,
- 0x7c, 0x27, 0xbd, 0xce, 0xb9, 0x6c, 0x56, 0xd2, 0x9d, 0xee, 0xc8,
- 0x7c, 0x12, 0x35, 0x1b, 0xfd, 0x59, 0x62, 0x49, 0x74, 0x18, 0x71,
- 0x6a, 0x4b, 0x91, 0x5d, 0x33, 0x4f, 0xfb, 0x5b, 0x92, 0xca, 0x94,
- 0xff, 0xe1, 0xe4, 0xf7, 0x89, 0x67, 0x04, 0x26, 0x38, 0x63, 0x9a,
- 0x9d, 0xe3, 0x25, 0x35, 0x7f, 0x5f, 0x08, 0xf6, 0x43, 0x50, 0x61,
- 0xe5, 0xa2, 0x74, 0x70, 0x39, 0x36, 0xc0, 0x6f, 0xc5, 0x6a, 0xf9,
- 0x2c, 0x42, 0x07, 0x97, 0x49, 0x9c, 0xa4, 0x31, 0xa7, 0xab, 0xaa,
- 0x46, 0x18, 0x63, 0xbc, 0xa6, 0x56, 0xfa, 0xcf, 0xad, 0x56, 0x4e,
- 0x62, 0x74, 0xd4, 0xa7, 0x41, 0x03, 0x3a, 0xca, 0x1e, 0x31, 0xbf,
- 0x63, 0x20, 0x0d, 0xf4, 0x1c, 0xdf, 0x41, 0xc1, 0x0b, 0x91, 0x2b,
- 0xec,
+ 0xc0, 0xff, 0x00, 0x00, 0x17, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e,
+ 0x51, 0x57, 0x08, 0x00, 0x00, 0x44, 0x9e, 0x3b, 0x34, 0x3a, 0xa8,
+ 0x53, 0x50, 0x64, 0xa4, 0x26, 0x8a, 0x0d, 0x9d, 0x7b, 0x1c, 0x9d,
+ 0x25, 0x0a, 0xe3, 0x55, 0x16, 0x22, 0x76, 0xe9, 0xb1, 0xe3, 0x01,
+ 0x1e, 0xf6, 0xbb, 0xc0, 0xab, 0x48, 0xad, 0x5b, 0xcc, 0x26, 0x81,
+ 0xe9, 0x53, 0x85, 0x7c, 0xa6, 0x2b, 0xec, 0xd7, 0x52, 0x4d, 0xaa,
+ 0xc4, 0x73, 0xe6, 0x8d, 0x74, 0x05, 0xfb, 0xba, 0x4e, 0x9e, 0xe6,
+ 0x16, 0xc8, 0x70, 0x38, 0xbd, 0xbe, 0x90, 0x8c, 0x06, 0xd9, 0x60,
+ 0x5d, 0x9a, 0xc4, 0x90, 0x30, 0x35, 0x9e, 0xec, 0xb1, 0xd0, 0x5a,
+ 0x14, 0xe1, 0x17, 0xdb, 0x8c, 0xed, 0xe2, 0xbb, 0x09, 0xd0, 0xdb,
+ 0xbf, 0xee, 0x27, 0x1c, 0xb3, 0x74, 0xd8, 0xf1, 0x0a, 0xbe, 0xc8,
+ 0x2d, 0x0f, 0x59, 0xa1, 0xde, 0xe2, 0x9f, 0xe9, 0x56, 0x38, 0xed,
+ 0x8d, 0xd4, 0x1d, 0xa0, 0x74, 0x87, 0x46, 0x87, 0x91, 0xb7, 0x19,
+ 0xc5, 0x5c, 0x46, 0x96, 0x8e, 0xb3, 0xb5, 0x46, 0x80, 0x03, 0x71,
+ 0x02, 0xa2, 0x8e, 0x53, 0xdc, 0x1d, 0x12, 0x90, 0x3d, 0xb0, 0xaf,
+ 0x58, 0x21, 0x79, 0x4b, 0x41, 0xc4, 0xa9, 0x33, 0x57, 0xfa, 0x59,
+ 0xce, 0x69, 0xcf, 0xe7, 0xf6, 0xbd, 0xfa, 0x62, 0x9e, 0xef, 0x78,
+ 0x61, 0x64, 0x47, 0xe1, 0xd6, 0x11, 0xc4, 0xba, 0xf7, 0x1b, 0xf3,
+ 0x3f, 0xeb, 0xcb, 0x03, 0x13, 0x7c, 0x2c, 0x75, 0xd2, 0x53, 0x17,
+ 0xd3, 0xe1, 0x3b, 0x68, 0x43, 0x70, 0xf6, 0x68, 0x41, 0x1c, 0x0f,
+ 0x00, 0x30, 0x4b, 0x50, 0x1c, 0x8f, 0xd4, 0x22, 0xbd, 0x9b, 0x9a,
+ 0xd8, 0x1d, 0x64, 0x3b, 0x20, 0xda, 0x89, 0xca, 0x05, 0x25, 0xd2,
+ 0x4d, 0x2b, 0x14, 0x20, 0x41, 0xca, 0xe0, 0xaf, 0x20, 0x50, 0x92,
+ 0xe4, 0x30, 0x08, 0x0c, 0xd8, 0x55, 0x9e, 0xa4, 0xc5, 0xc6, 0xe4,
+ 0xfa, 0x3f, 0x66, 0x08, 0x2b, 0x7d, 0x30, 0x3e, 0x52, 0xce, 0x01,
+ 0x62, 0xba, 0xa9, 0x58, 0x53, 0x2b, 0x0b, 0xbc, 0x2b, 0xc7, 0x85,
+ 0x68, 0x1f, 0xcf, 0x37, 0x48, 0x5d, 0xff, 0x65, 0x95, 0xe0, 0x1e,
+ 0x73, 0x9c, 0x8a, 0xc9, 0xef, 0xba, 0x31, 0xb9, 0x85, 0xd5, 0xf6,
+ 0x56, 0xcc, 0x09, 0x24, 0x32, 0xd7, 0x81, 0xdb, 0x95, 0x22, 0x17,
+ 0x24, 0x87, 0x64, 0x1c, 0x4d, 0x3a, 0xb8, 0xec, 0xe0, 0x1e, 0x39,
+ 0xbc, 0x85, 0xb1, 0x54, 0x36, 0x61, 0x47, 0x75, 0xa9, 0x8b, 0xa8,
+ 0xfa, 0x12, 0xd4, 0x6f, 0x9b, 0x35, 0xe2, 0xa5, 0x5e, 0xb7, 0x2d,
+ 0x7f, 0x85, 0x18, 0x1a, 0x36, 0x66, 0x63, 0x38, 0x7d, 0xdc, 0x20,
+ 0x55, 0x18, 0x07, 0xe0, 0x07, 0x67, 0x3b, 0xd7, 0xe2, 0x6b, 0xf9,
+ 0xb2, 0x9b, 0x5a, 0xb1, 0x0a, 0x1c, 0xa8, 0x7c, 0xbb, 0x7a, 0xd9,
+ 0x7e, 0x99, 0xeb, 0x66, 0x95, 0x9c, 0x2a, 0x9b, 0xc3, 0xcb, 0xde,
+ 0x47, 0x07, 0xff, 0x77, 0x20, 0xb1, 0x10, 0xfa, 0x95, 0x35, 0x46,
+ 0x74, 0xe3, 0x95, 0x81, 0x2e, 0x47, 0xa0, 0xae, 0x53, 0xb4, 0x64,
+ 0xdc, 0xb2, 0xd1, 0xf3, 0x45, 0xdf, 0x36, 0x0d, 0xc2, 0x27, 0x27,
+ 0x0c, 0x75, 0x06, 0x76, 0xf6, 0x72, 0x4e, 0xb4, 0x79, 0xf0, 0xd2,
+ 0xfb, 0xb6, 0x12, 0x44, 0x29, 0x99, 0x04, 0x57, 0xac, 0x6c, 0x91,
+ 0x67, 0xf4, 0x0a, 0xab, 0x73, 0x99, 0x98, 0xf3, 0x8b, 0x9e, 0xcc,
+ 0xb2, 0x4f, 0xd4, 0x7c, 0x84, 0x10, 0x13, 0x1b, 0xf6, 0x5a, 0x52,
+ 0xaf, 0x84, 0x12, 0x75, 0xd5, 0xb3, 0xd1, 0x88, 0x0b, 0x19, 0x7d,
+ 0xf2, 0xb5, 0xde, 0xa3, 0xe6, 0xde, 0x56, 0xeb, 0xce, 0x3f, 0xfb,
+ 0x6e, 0x92, 0x77, 0xa8, 0x20, 0x82, 0xf8, 0xd9, 0x67, 0x7a, 0x67,
+ 0x67, 0x08, 0x9b, 0x67, 0x1e, 0xbd, 0x24, 0x4c, 0x21, 0x4f, 0x0b,
+ 0xde, 0x95, 0xc2, 0xbe, 0xb0, 0x2c, 0xd1, 0x17, 0x2d, 0x58, 0xbd,
+ 0xf3, 0x9d, 0xce, 0x56, 0xff, 0x68, 0xeb, 0x35, 0xab, 0x39, 0xb4,
+ 0x9b, 0x4e, 0xac, 0x7c, 0x81, 0x5e, 0xa6, 0x04, 0x51, 0xd6, 0xe6,
+ 0xab, 0x82, 0x11, 0x91, 0x18, 0xdf, 0x02, 0xa5, 0x86, 0x84, 0x4a,
+ 0x9f, 0xfe, 0x16, 0x2b, 0xa0, 0x06, 0xd0, 0x66, 0x9e, 0xf5, 0x76,
+ 0x68, 0xca, 0xb3, 0x8b, 0x62, 0xf7, 0x1a, 0x25, 0x23, 0xa0, 0x84,
+ 0x85, 0x2c, 0xd1, 0xd0, 0x79, 0xb3, 0x65, 0x8d, 0xc2, 0xf3, 0xe8,
+ 0x79, 0x49, 0xb5, 0x50, 0xba, 0xb3, 0xe1, 0x77, 0xcf, 0xc4, 0x9e,
+ 0xd1, 0x90, 0xdf, 0xf0, 0x63, 0x0e, 0x43, 0x07, 0x7c, 0x30, 0xde,
+ 0x8f, 0x6a, 0xe0, 0x81, 0x53, 0x7f, 0x1e, 0x83, 0xda, 0x53, 0x7d,
+ 0xa9, 0x80, 0xaf, 0xa6, 0x68, 0xe7, 0xb7, 0xfb, 0x25, 0x30, 0x1c,
+ 0xf7, 0x41, 0x52, 0x4b, 0xe3, 0xc4, 0x98, 0x84, 0xb4, 0x28, 0x21,
+ 0xf1, 0x75, 0x52, 0xfb, 0xd1, 0x93, 0x1a, 0x81, 0x30, 0x17, 0xb6,
+ 0xb6, 0x59, 0x0a, 0x41, 0xea, 0x18, 0xb6, 0xba, 0x49, 0xcd, 0x48,
+ 0xa4, 0x40, 0xbd, 0x9a, 0x33, 0x46, 0xa7, 0x62, 0x3f, 0xb4, 0xba,
+ 0x34, 0xa3, 0xee, 0x57, 0x1e, 0x3c, 0x73, 0x1f, 0x35, 0xa7, 0xa3,
+ 0xcf, 0x25, 0xb5, 0x51, 0xa6, 0x80, 0xfa, 0x68, 0x76, 0x35, 0x07,
+ 0xb7, 0xfd, 0xe3, 0xaa, 0xf0, 0x23, 0xc5, 0x0b, 0x9d, 0x22, 0xda,
+ 0x68, 0x76, 0xba, 0x33, 0x7e, 0xb5, 0xe9, 0xdd, 0x9e, 0xc3, 0xda,
+ 0xf9, 0x70, 0x24, 0x2b, 0x6c, 0x5a, 0xab, 0x3a, 0xa4, 0xb2, 0x96,
+ 0xad, 0x8b, 0x9f, 0x68, 0x32, 0xf6, 0x86, 0xef, 0x70, 0xfa, 0x93,
+ 0x8b, 0x31, 0xb4, 0xe5, 0xdd, 0xd7, 0x36, 0x44, 0x42, 0xd3, 0xea,
+ 0x72, 0xe7, 0x3d, 0x66, 0x8f, 0xb0, 0x93, 0x77, 0x96, 0xf4, 0x62,
+ 0x92, 0x3a, 0x81, 0xa4, 0x7e, 0x1c, 0xee, 0x74, 0x26, 0xff, 0x6d,
+ 0x92, 0x21, 0x26, 0x9b, 0x5a, 0x62, 0xec, 0x03, 0xd6, 0xec, 0x94,
+ 0xd1, 0x26, 0x06, 0xcb, 0x48, 0x55, 0x60, 0xba, 0xb5, 0x74, 0x81,
+ 0x60, 0x09, 0xe9, 0x65, 0x04, 0x24, 0x93, 0x85, 0xbb, 0x61, 0xa8,
+ 0x19, 0xbe, 0x04, 0xf6, 0x2c, 0x20, 0x66, 0x21, 0x4d, 0x83, 0x60,
+ 0xa2, 0x02, 0x2b, 0xeb, 0x31, 0x62, 0x40, 0xb6, 0xc7, 0xd7, 0x8b,
+ 0xbe, 0x56, 0xc1, 0x30, 0x82, 0xe0, 0xca, 0x27, 0x26, 0x61, 0x21,
+ 0x0a, 0xbf, 0x02, 0x0b, 0xf3, 0xb5, 0x78, 0x3f, 0x14, 0x26, 0x43,
+ 0x6c, 0xf9, 0xff, 0x41, 0x84, 0x05, 0x93, 0xa5, 0xd0, 0x63, 0x8d,
+ 0x32, 0xfc, 0x51, 0xc5, 0xc6, 0x5f, 0xf2, 0x91, 0xa3, 0xa7, 0xa5,
+ 0x2f, 0xd6, 0x77, 0x5e, 0x62, 0x3a, 0x44, 0x39, 0xcc, 0x08, 0xdd,
+ 0x25, 0x58, 0x2f, 0xeb, 0xc9, 0x44, 0xef, 0x92, 0xd8, 0xdb, 0xd3,
+ 0x29, 0xc9, 0x1d, 0xe3, 0xe9, 0xc9, 0x58, 0x2e, 0x41, 0xf1, 0x7f,
+ 0x3d, 0x18, 0x6f, 0x10, 0x4a, 0xd3, 0xf9, 0x09, 0x95, 0x11, 0x6c,
+ 0x68, 0x2a, 0x2a, 0x14, 0xa3, 0xb4, 0xb1, 0xf5, 0x47, 0xc3, 0x35,
+ 0xf0, 0xbe, 0x71, 0x0f, 0xc9, 0xfc, 0x03, 0xe0, 0xe5, 0x87, 0xb8,
+ 0xcd, 0xa3, 0x1c, 0xe6, 0x5b, 0x96, 0x98, 0x78, 0xa4, 0xad, 0x42,
+ 0x83, 0xe6, 0xd5, 0xb0, 0x37, 0x3f, 0x43, 0xda, 0x86, 0xe9, 0xe0,
+ 0xff, 0xe1, 0xae, 0x0f, 0xdd, 0xd3, 0x51, 0x62, 0x55, 0xbd, 0x74,
+ 0x56, 0x6f, 0x36, 0xa3, 0x87, 0x03, 0xd5, 0xf3, 0x42, 0x49, 0xde,
+ 0xd1, 0xf6, 0x6b, 0x3d, 0x9b, 0x45, 0xb9, 0xaf, 0x2c, 0xcf, 0xef,
+ 0xe9, 0x84, 0xe1, 0x33, 0x76, 0xb1, 0xb2, 0xc6, 0x40, 0x4a, 0xa4,
+ 0x8c, 0x80, 0x26, 0x13, 0x23, 0x43, 0xda, 0x3f, 0x3a, 0x33, 0x65,
+ 0x9e, 0xc1, 0xb3, 0xe9, 0x50, 0x80, 0x54, 0x0b, 0x28, 0xb7, 0xf3,
+ 0xfc, 0xd3, 0x5f, 0xa5, 0xd8, 0x43, 0xb5, 0x79, 0xa8, 0x4c, 0x08,
+ 0x91, 0x21, 0xa6, 0x0d, 0x8c, 0x17, 0x54, 0x91, 0x5c, 0x34, 0x4e,
+ 0xea, 0xf4, 0x5a, 0x9b, 0xf2, 0x7d, 0xc0, 0xc1, 0xe7, 0x84, 0x16,
+ 0x16, 0x91, 0x22, 0x09, 0x13, 0x13, 0xeb, 0x0e, 0x87, 0x55, 0x5a,
+ 0xbd, 0x70, 0x66, 0x26, 0xe5, 0x57, 0xfc, 0x36, 0xa0, 0x4f, 0xcd,
+ 0x19, 0x1a, 0x58, 0x82, 0x91, 0x04, 0xd6, 0x07, 0x5c, 0x55, 0x94,
+ 0xf6, 0x27, 0xca, 0x50, 0x6b, 0xf1, 0x81, 0xda, 0xec, 0x94, 0x0f,
+ 0x4a, 0x4f, 0x3a, 0xf0, 0x07, 0x4e, 0xee, 0x89, 0xda, 0xac, 0xde,
+ 0x67, 0x58, 0x31, 0x26, 0x22, 0xd4, 0xfa, 0x67, 0x5b, 0x39, 0xf7,
+ 0x28, 0xe0, 0x62, 0xd2, 0xbe, 0xe6, 0x80, 0xd8, 0xf4, 0x1a, 0x59,
+ 0x7c, 0x26, 0x26, 0x48, 0xbb, 0x18, 0xbc, 0xfc, 0x13, 0xc8, 0xb3,
+ 0xd9, 0x7b, 0x1a, 0x77, 0xb2, 0xac, 0x3a, 0xf7, 0x45, 0xd6, 0x1a,
+ 0x34, 0xcc, 0x47, 0x09, 0x86, 0x5b, 0xac, 0x82, 0x4a, 0x94, 0xbb,
+ 0x19, 0x05, 0x80, 0x15, 0xe4, 0xe4, 0x2d, 0xc9, 0xbe, 0x6c, 0x78,
+ 0x03, 0x56, 0x73, 0x21, 0x82, 0x9d, 0xd8, 0x58, 0x53, 0x39, 0x62,
+ 0x69,
];
let dcid = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08];
@@ -1142,19 +1186,19 @@
#[test]
fn decrypt_server_initial() {
let mut pkt = [
- 0xc4, 0xff, 0x00, 0x00, 0x12, 0x05, 0xf0, 0x67, 0xa5, 0x50, 0x2a,
- 0x42, 0x62, 0xb5, 0x00, 0x40, 0x74, 0xf7, 0xed, 0x5f, 0x01, 0xc4,
- 0xc2, 0xa2, 0x30, 0x3d, 0x29, 0x7e, 0x3c, 0x51, 0x9b, 0xf6, 0xb2,
- 0x23, 0x86, 0xe3, 0xd0, 0xbd, 0x6d, 0xfc, 0x66, 0x12, 0x16, 0x77,
- 0x29, 0x80, 0x31, 0x04, 0x1b, 0xb9, 0xa7, 0x9c, 0x9f, 0x0f, 0x9d,
- 0x4c, 0x58, 0x77, 0x27, 0x0a, 0x66, 0x0f, 0x5d, 0xa3, 0x62, 0x07,
- 0xd9, 0x8b, 0x73, 0x83, 0x9b, 0x2f, 0xdf, 0x2e, 0xf8, 0xe7, 0xdf,
- 0x5a, 0x51, 0xb1, 0x7b, 0x8c, 0x68, 0xd8, 0x64, 0xfd, 0x3e, 0x70,
- 0x8c, 0x6c, 0x1b, 0x71, 0xa9, 0x8a, 0x33, 0x18, 0x15, 0x59, 0x9e,
- 0xf5, 0x01, 0x4e, 0xa3, 0x8c, 0x44, 0xbd, 0xfd, 0x38, 0x7c, 0x03,
- 0xb5, 0x27, 0x5c, 0x35, 0xe0, 0x09, 0xb6, 0x23, 0x8f, 0x83, 0x14,
- 0x20, 0x04, 0x7c, 0x72, 0x71, 0x28, 0x1c, 0xcb, 0x54, 0xdf, 0x78,
- 0x84,
+ 0xc9, 0xff, 0x00, 0x00, 0x17, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50,
+ 0x2a, 0x42, 0x62, 0xb5, 0x00, 0x40, 0x74, 0x16, 0x8b, 0xf2, 0x2b,
+ 0x70, 0x02, 0x59, 0x6f, 0x99, 0xae, 0x67, 0xab, 0xf6, 0x5a, 0x58,
+ 0x52, 0xf5, 0x4f, 0x58, 0xc3, 0x7c, 0x80, 0x86, 0x82, 0xe2, 0xe4,
+ 0x04, 0x92, 0xd8, 0xa3, 0x89, 0x9f, 0xb0, 0x4f, 0xc0, 0xaf, 0xe9,
+ 0xaa, 0xbc, 0x87, 0x67, 0xb1, 0x8a, 0x0a, 0xa4, 0x93, 0x53, 0x74,
+ 0x26, 0x37, 0x3b, 0x48, 0xd5, 0x02, 0x21, 0x4d, 0xd8, 0x56, 0xd6,
+ 0x3b, 0x78, 0xce, 0xe3, 0x7b, 0xc6, 0x64, 0xb3, 0xfe, 0x86, 0xd4,
+ 0x87, 0xac, 0x7a, 0x77, 0xc5, 0x30, 0x38, 0xa3, 0xcd, 0x32, 0xf0,
+ 0xb5, 0x00, 0x4d, 0x9f, 0x57, 0x54, 0xc4, 0xf7, 0xf2, 0xd1, 0xf3,
+ 0x5c, 0xf3, 0xf7, 0x11, 0x63, 0x51, 0xc9, 0x2b, 0x9c, 0xf9, 0xbb,
+ 0x6d, 0x09, 0x1d, 0xdf, 0xc8, 0xb3, 0x2d, 0x43, 0x23, 0x48, 0xa2,
+ 0xc4, 0x13,
];
let dcid = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08];
@@ -1173,4 +1217,343 @@
test_decrypt_pkt(&mut pkt, &dcid, false, &frames, 1, 2);
}
+
+ fn test_encrypt_pkt(
+ header: &mut [u8], dcid: &[u8], frames: &[u8], pn: u64, pn_len: usize,
+ is_server: bool, expected_pkt: &[u8],
+ ) {
+ let mut b = octets::Octets::with_slice(header);
+
+ let hdr = Header::from_bytes(&mut b, 0).unwrap();
+ assert_eq!(hdr.ty, Type::Initial);
+
+ let mut out = vec![0; expected_pkt.len()];
+ let mut b = octets::Octets::with_slice(&mut out);
+
+ b.put_bytes(header).unwrap();
+
+ let (_, aead) =
+ crypto::derive_initial_key_material(dcid, is_server).unwrap();
+
+ let overhead = aead.alg().tag_len();
+
+ let payload_len = frames.len() + overhead;
+
+ let payload_offset = b.off();
+
+ b.put_bytes(frames).unwrap();
+
+ let written =
+ encrypt_pkt(&mut b, pn, pn_len, payload_len, payload_offset, &aead)
+ .unwrap();
+
+ assert_eq!(written, expected_pkt.len());
+ assert_eq!(&out[..written], &expected_pkt[..]);
+ }
+
+ #[test]
+ fn encrypt_client_initial() {
+ let mut header = [
+ 0xc3, 0xff, 0x00, 0x00, 0x17, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e,
+ 0x51, 0x57, 0x08, 0x00, 0x00, 0x44, 0x9e, 0x00, 0x00, 0x00, 0x02,
+ ];
+
+ let dcid = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08];
+
+ let frames = [
+ 0x06, 0x00, 0x40, 0xc4, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x03, 0x66,
+ 0x60, 0x26, 0x1f, 0xf9, 0x47, 0xce, 0xa4, 0x9c, 0xce, 0x6c, 0xfa,
+ 0xd6, 0x87, 0xf4, 0x57, 0xcf, 0x1b, 0x14, 0x53, 0x1b, 0xa1, 0x41,
+ 0x31, 0xa0, 0xe8, 0xf3, 0x09, 0xa1, 0xd0, 0xb9, 0xc4, 0x00, 0x00,
+ 0x06, 0x13, 0x01, 0x13, 0x03, 0x13, 0x02, 0x01, 0x00, 0x00, 0x91,
+ 0x00, 0x00, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x00, 0x06, 0x73, 0x65,
+ 0x72, 0x76, 0x65, 0x72, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0a,
+ 0x00, 0x14, 0x00, 0x12, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00,
+ 0x19, 0x01, 0x00, 0x01, 0x01, 0x01, 0x02, 0x01, 0x03, 0x01, 0x04,
+ 0x00, 0x23, 0x00, 0x00, 0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00,
+ 0x1d, 0x00, 0x20, 0x4c, 0xfd, 0xfc, 0xd1, 0x78, 0xb7, 0x84, 0xbf,
+ 0x32, 0x8c, 0xae, 0x79, 0x3b, 0x13, 0x6f, 0x2a, 0xed, 0xce, 0x00,
+ 0x5f, 0xf1, 0x83, 0xd7, 0xbb, 0x14, 0x95, 0x20, 0x72, 0x36, 0x64,
+ 0x70, 0x37, 0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04, 0x00, 0x0d,
+ 0x00, 0x20, 0x00, 0x1e, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02,
+ 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01,
+ 0x06, 0x01, 0x02, 0x01, 0x04, 0x02, 0x05, 0x02, 0x06, 0x02, 0x02,
+ 0x02, 0x00, 0x2d, 0x00, 0x02, 0x01, 0x01, 0x00, 0x1c, 0x00, 0x02,
+ 0x40, 0x01, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,
+ 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, 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, 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, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ];
+
+ let pkt = [
+ 0xc0, 0xff, 0x00, 0x00, 0x17, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e,
+ 0x51, 0x57, 0x08, 0x00, 0x00, 0x44, 0x9e, 0x3b, 0x34, 0x3a, 0xa8,
+ 0x53, 0x50, 0x64, 0xa4, 0x26, 0x8a, 0x0d, 0x9d, 0x7b, 0x1c, 0x9d,
+ 0x25, 0x0a, 0xe3, 0x55, 0x16, 0x22, 0x76, 0xe9, 0xb1, 0xe3, 0x01,
+ 0x1e, 0xf6, 0xbb, 0xc0, 0xab, 0x48, 0xad, 0x5b, 0xcc, 0x26, 0x81,
+ 0xe9, 0x53, 0x85, 0x7c, 0xa6, 0x2b, 0xec, 0xd7, 0x52, 0x4d, 0xaa,
+ 0xc4, 0x73, 0xe6, 0x8d, 0x74, 0x05, 0xfb, 0xba, 0x4e, 0x9e, 0xe6,
+ 0x16, 0xc8, 0x70, 0x38, 0xbd, 0xbe, 0x90, 0x8c, 0x06, 0xd9, 0x60,
+ 0x5d, 0x9a, 0xc4, 0x90, 0x30, 0x35, 0x9e, 0xec, 0xb1, 0xd0, 0x5a,
+ 0x14, 0xe1, 0x17, 0xdb, 0x8c, 0xed, 0xe2, 0xbb, 0x09, 0xd0, 0xdb,
+ 0xbf, 0xee, 0x27, 0x1c, 0xb3, 0x74, 0xd8, 0xf1, 0x0a, 0xbe, 0xc8,
+ 0x2d, 0x0f, 0x59, 0xa1, 0xde, 0xe2, 0x9f, 0xe9, 0x56, 0x38, 0xed,
+ 0x8d, 0xd4, 0x1d, 0xa0, 0x74, 0x87, 0x46, 0x87, 0x91, 0xb7, 0x19,
+ 0xc5, 0x5c, 0x46, 0x96, 0x8e, 0xb3, 0xb5, 0x46, 0x80, 0x03, 0x71,
+ 0x02, 0xa2, 0x8e, 0x53, 0xdc, 0x1d, 0x12, 0x90, 0x3d, 0xb0, 0xaf,
+ 0x58, 0x21, 0x79, 0x4b, 0x41, 0xc4, 0xa9, 0x33, 0x57, 0xfa, 0x59,
+ 0xce, 0x69, 0xcf, 0xe7, 0xf6, 0xbd, 0xfa, 0x62, 0x9e, 0xef, 0x78,
+ 0x61, 0x64, 0x47, 0xe1, 0xd6, 0x11, 0xc4, 0xba, 0xf7, 0x1b, 0xf3,
+ 0x3f, 0xeb, 0xcb, 0x03, 0x13, 0x7c, 0x2c, 0x75, 0xd2, 0x53, 0x17,
+ 0xd3, 0xe1, 0x3b, 0x68, 0x43, 0x70, 0xf6, 0x68, 0x41, 0x1c, 0x0f,
+ 0x00, 0x30, 0x4b, 0x50, 0x1c, 0x8f, 0xd4, 0x22, 0xbd, 0x9b, 0x9a,
+ 0xd8, 0x1d, 0x64, 0x3b, 0x20, 0xda, 0x89, 0xca, 0x05, 0x25, 0xd2,
+ 0x4d, 0x2b, 0x14, 0x20, 0x41, 0xca, 0xe0, 0xaf, 0x20, 0x50, 0x92,
+ 0xe4, 0x30, 0x08, 0x0c, 0xd8, 0x55, 0x9e, 0xa4, 0xc5, 0xc6, 0xe4,
+ 0xfa, 0x3f, 0x66, 0x08, 0x2b, 0x7d, 0x30, 0x3e, 0x52, 0xce, 0x01,
+ 0x62, 0xba, 0xa9, 0x58, 0x53, 0x2b, 0x0b, 0xbc, 0x2b, 0xc7, 0x85,
+ 0x68, 0x1f, 0xcf, 0x37, 0x48, 0x5d, 0xff, 0x65, 0x95, 0xe0, 0x1e,
+ 0x73, 0x9c, 0x8a, 0xc9, 0xef, 0xba, 0x31, 0xb9, 0x85, 0xd5, 0xf6,
+ 0x56, 0xcc, 0x09, 0x24, 0x32, 0xd7, 0x81, 0xdb, 0x95, 0x22, 0x17,
+ 0x24, 0x87, 0x64, 0x1c, 0x4d, 0x3a, 0xb8, 0xec, 0xe0, 0x1e, 0x39,
+ 0xbc, 0x85, 0xb1, 0x54, 0x36, 0x61, 0x47, 0x75, 0xa9, 0x8b, 0xa8,
+ 0xfa, 0x12, 0xd4, 0x6f, 0x9b, 0x35, 0xe2, 0xa5, 0x5e, 0xb7, 0x2d,
+ 0x7f, 0x85, 0x18, 0x1a, 0x36, 0x66, 0x63, 0x38, 0x7d, 0xdc, 0x20,
+ 0x55, 0x18, 0x07, 0xe0, 0x07, 0x67, 0x3b, 0xd7, 0xe2, 0x6b, 0xf9,
+ 0xb2, 0x9b, 0x5a, 0xb1, 0x0a, 0x1c, 0xa8, 0x7c, 0xbb, 0x7a, 0xd9,
+ 0x7e, 0x99, 0xeb, 0x66, 0x95, 0x9c, 0x2a, 0x9b, 0xc3, 0xcb, 0xde,
+ 0x47, 0x07, 0xff, 0x77, 0x20, 0xb1, 0x10, 0xfa, 0x95, 0x35, 0x46,
+ 0x74, 0xe3, 0x95, 0x81, 0x2e, 0x47, 0xa0, 0xae, 0x53, 0xb4, 0x64,
+ 0xdc, 0xb2, 0xd1, 0xf3, 0x45, 0xdf, 0x36, 0x0d, 0xc2, 0x27, 0x27,
+ 0x0c, 0x75, 0x06, 0x76, 0xf6, 0x72, 0x4e, 0xb4, 0x79, 0xf0, 0xd2,
+ 0xfb, 0xb6, 0x12, 0x44, 0x29, 0x99, 0x04, 0x57, 0xac, 0x6c, 0x91,
+ 0x67, 0xf4, 0x0a, 0xab, 0x73, 0x99, 0x98, 0xf3, 0x8b, 0x9e, 0xcc,
+ 0xb2, 0x4f, 0xd4, 0x7c, 0x84, 0x10, 0x13, 0x1b, 0xf6, 0x5a, 0x52,
+ 0xaf, 0x84, 0x12, 0x75, 0xd5, 0xb3, 0xd1, 0x88, 0x0b, 0x19, 0x7d,
+ 0xf2, 0xb5, 0xde, 0xa3, 0xe6, 0xde, 0x56, 0xeb, 0xce, 0x3f, 0xfb,
+ 0x6e, 0x92, 0x77, 0xa8, 0x20, 0x82, 0xf8, 0xd9, 0x67, 0x7a, 0x67,
+ 0x67, 0x08, 0x9b, 0x67, 0x1e, 0xbd, 0x24, 0x4c, 0x21, 0x4f, 0x0b,
+ 0xde, 0x95, 0xc2, 0xbe, 0xb0, 0x2c, 0xd1, 0x17, 0x2d, 0x58, 0xbd,
+ 0xf3, 0x9d, 0xce, 0x56, 0xff, 0x68, 0xeb, 0x35, 0xab, 0x39, 0xb4,
+ 0x9b, 0x4e, 0xac, 0x7c, 0x81, 0x5e, 0xa6, 0x04, 0x51, 0xd6, 0xe6,
+ 0xab, 0x82, 0x11, 0x91, 0x18, 0xdf, 0x02, 0xa5, 0x86, 0x84, 0x4a,
+ 0x9f, 0xfe, 0x16, 0x2b, 0xa0, 0x06, 0xd0, 0x66, 0x9e, 0xf5, 0x76,
+ 0x68, 0xca, 0xb3, 0x8b, 0x62, 0xf7, 0x1a, 0x25, 0x23, 0xa0, 0x84,
+ 0x85, 0x2c, 0xd1, 0xd0, 0x79, 0xb3, 0x65, 0x8d, 0xc2, 0xf3, 0xe8,
+ 0x79, 0x49, 0xb5, 0x50, 0xba, 0xb3, 0xe1, 0x77, 0xcf, 0xc4, 0x9e,
+ 0xd1, 0x90, 0xdf, 0xf0, 0x63, 0x0e, 0x43, 0x07, 0x7c, 0x30, 0xde,
+ 0x8f, 0x6a, 0xe0, 0x81, 0x53, 0x7f, 0x1e, 0x83, 0xda, 0x53, 0x7d,
+ 0xa9, 0x80, 0xaf, 0xa6, 0x68, 0xe7, 0xb7, 0xfb, 0x25, 0x30, 0x1c,
+ 0xf7, 0x41, 0x52, 0x4b, 0xe3, 0xc4, 0x98, 0x84, 0xb4, 0x28, 0x21,
+ 0xf1, 0x75, 0x52, 0xfb, 0xd1, 0x93, 0x1a, 0x81, 0x30, 0x17, 0xb6,
+ 0xb6, 0x59, 0x0a, 0x41, 0xea, 0x18, 0xb6, 0xba, 0x49, 0xcd, 0x48,
+ 0xa4, 0x40, 0xbd, 0x9a, 0x33, 0x46, 0xa7, 0x62, 0x3f, 0xb4, 0xba,
+ 0x34, 0xa3, 0xee, 0x57, 0x1e, 0x3c, 0x73, 0x1f, 0x35, 0xa7, 0xa3,
+ 0xcf, 0x25, 0xb5, 0x51, 0xa6, 0x80, 0xfa, 0x68, 0x76, 0x35, 0x07,
+ 0xb7, 0xfd, 0xe3, 0xaa, 0xf0, 0x23, 0xc5, 0x0b, 0x9d, 0x22, 0xda,
+ 0x68, 0x76, 0xba, 0x33, 0x7e, 0xb5, 0xe9, 0xdd, 0x9e, 0xc3, 0xda,
+ 0xf9, 0x70, 0x24, 0x2b, 0x6c, 0x5a, 0xab, 0x3a, 0xa4, 0xb2, 0x96,
+ 0xad, 0x8b, 0x9f, 0x68, 0x32, 0xf6, 0x86, 0xef, 0x70, 0xfa, 0x93,
+ 0x8b, 0x31, 0xb4, 0xe5, 0xdd, 0xd7, 0x36, 0x44, 0x42, 0xd3, 0xea,
+ 0x72, 0xe7, 0x3d, 0x66, 0x8f, 0xb0, 0x93, 0x77, 0x96, 0xf4, 0x62,
+ 0x92, 0x3a, 0x81, 0xa4, 0x7e, 0x1c, 0xee, 0x74, 0x26, 0xff, 0x6d,
+ 0x92, 0x21, 0x26, 0x9b, 0x5a, 0x62, 0xec, 0x03, 0xd6, 0xec, 0x94,
+ 0xd1, 0x26, 0x06, 0xcb, 0x48, 0x55, 0x60, 0xba, 0xb5, 0x74, 0x81,
+ 0x60, 0x09, 0xe9, 0x65, 0x04, 0x24, 0x93, 0x85, 0xbb, 0x61, 0xa8,
+ 0x19, 0xbe, 0x04, 0xf6, 0x2c, 0x20, 0x66, 0x21, 0x4d, 0x83, 0x60,
+ 0xa2, 0x02, 0x2b, 0xeb, 0x31, 0x62, 0x40, 0xb6, 0xc7, 0xd7, 0x8b,
+ 0xbe, 0x56, 0xc1, 0x30, 0x82, 0xe0, 0xca, 0x27, 0x26, 0x61, 0x21,
+ 0x0a, 0xbf, 0x02, 0x0b, 0xf3, 0xb5, 0x78, 0x3f, 0x14, 0x26, 0x43,
+ 0x6c, 0xf9, 0xff, 0x41, 0x84, 0x05, 0x93, 0xa5, 0xd0, 0x63, 0x8d,
+ 0x32, 0xfc, 0x51, 0xc5, 0xc6, 0x5f, 0xf2, 0x91, 0xa3, 0xa7, 0xa5,
+ 0x2f, 0xd6, 0x77, 0x5e, 0x62, 0x3a, 0x44, 0x39, 0xcc, 0x08, 0xdd,
+ 0x25, 0x58, 0x2f, 0xeb, 0xc9, 0x44, 0xef, 0x92, 0xd8, 0xdb, 0xd3,
+ 0x29, 0xc9, 0x1d, 0xe3, 0xe9, 0xc9, 0x58, 0x2e, 0x41, 0xf1, 0x7f,
+ 0x3d, 0x18, 0x6f, 0x10, 0x4a, 0xd3, 0xf9, 0x09, 0x95, 0x11, 0x6c,
+ 0x68, 0x2a, 0x2a, 0x14, 0xa3, 0xb4, 0xb1, 0xf5, 0x47, 0xc3, 0x35,
+ 0xf0, 0xbe, 0x71, 0x0f, 0xc9, 0xfc, 0x03, 0xe0, 0xe5, 0x87, 0xb8,
+ 0xcd, 0xa3, 0x1c, 0xe6, 0x5b, 0x96, 0x98, 0x78, 0xa4, 0xad, 0x42,
+ 0x83, 0xe6, 0xd5, 0xb0, 0x37, 0x3f, 0x43, 0xda, 0x86, 0xe9, 0xe0,
+ 0xff, 0xe1, 0xae, 0x0f, 0xdd, 0xd3, 0x51, 0x62, 0x55, 0xbd, 0x74,
+ 0x56, 0x6f, 0x36, 0xa3, 0x87, 0x03, 0xd5, 0xf3, 0x42, 0x49, 0xde,
+ 0xd1, 0xf6, 0x6b, 0x3d, 0x9b, 0x45, 0xb9, 0xaf, 0x2c, 0xcf, 0xef,
+ 0xe9, 0x84, 0xe1, 0x33, 0x76, 0xb1, 0xb2, 0xc6, 0x40, 0x4a, 0xa4,
+ 0x8c, 0x80, 0x26, 0x13, 0x23, 0x43, 0xda, 0x3f, 0x3a, 0x33, 0x65,
+ 0x9e, 0xc1, 0xb3, 0xe9, 0x50, 0x80, 0x54, 0x0b, 0x28, 0xb7, 0xf3,
+ 0xfc, 0xd3, 0x5f, 0xa5, 0xd8, 0x43, 0xb5, 0x79, 0xa8, 0x4c, 0x08,
+ 0x91, 0x21, 0xa6, 0x0d, 0x8c, 0x17, 0x54, 0x91, 0x5c, 0x34, 0x4e,
+ 0xea, 0xf4, 0x5a, 0x9b, 0xf2, 0x7d, 0xc0, 0xc1, 0xe7, 0x84, 0x16,
+ 0x16, 0x91, 0x22, 0x09, 0x13, 0x13, 0xeb, 0x0e, 0x87, 0x55, 0x5a,
+ 0xbd, 0x70, 0x66, 0x26, 0xe5, 0x57, 0xfc, 0x36, 0xa0, 0x4f, 0xcd,
+ 0x19, 0x1a, 0x58, 0x82, 0x91, 0x04, 0xd6, 0x07, 0x5c, 0x55, 0x94,
+ 0xf6, 0x27, 0xca, 0x50, 0x6b, 0xf1, 0x81, 0xda, 0xec, 0x94, 0x0f,
+ 0x4a, 0x4f, 0x3a, 0xf0, 0x07, 0x4e, 0xee, 0x89, 0xda, 0xac, 0xde,
+ 0x67, 0x58, 0x31, 0x26, 0x22, 0xd4, 0xfa, 0x67, 0x5b, 0x39, 0xf7,
+ 0x28, 0xe0, 0x62, 0xd2, 0xbe, 0xe6, 0x80, 0xd8, 0xf4, 0x1a, 0x59,
+ 0x7c, 0x26, 0x26, 0x48, 0xbb, 0x18, 0xbc, 0xfc, 0x13, 0xc8, 0xb3,
+ 0xd9, 0x7b, 0x1a, 0x77, 0xb2, 0xac, 0x3a, 0xf7, 0x45, 0xd6, 0x1a,
+ 0x34, 0xcc, 0x47, 0x09, 0x86, 0x5b, 0xac, 0x82, 0x4a, 0x94, 0xbb,
+ 0x19, 0x05, 0x80, 0x15, 0xe4, 0xe4, 0x2d, 0xc9, 0xbe, 0x6c, 0x78,
+ 0x03, 0x56, 0x73, 0x21, 0x82, 0x9d, 0xd8, 0x58, 0x53, 0x39, 0x62,
+ 0x69,
+ ];
+
+ test_encrypt_pkt(&mut header, &dcid, &frames, 2, 4, false, &pkt);
+ }
+
+ #[test]
+ fn encrypt_server_initial() {
+ let mut header = [
+ 0xc1, 0xff, 0x00, 0x00, 0x17, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50,
+ 0x2a, 0x42, 0x62, 0xb5, 0x00, 0x40, 0x74, 0x00, 0x01,
+ ];
+
+ let dcid = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08];
+
+ let frames = [
+ 0x0d, 0x00, 0x00, 0x00, 0x00, 0x18, 0x41, 0x0a, 0x02, 0x00, 0x00,
+ 0x56, 0x03, 0x03, 0xee, 0xfc, 0xe7, 0xf7, 0xb3, 0x7b, 0xa1, 0xd1,
+ 0x63, 0x2e, 0x96, 0x67, 0x78, 0x25, 0xdd, 0xf7, 0x39, 0x88, 0xcf,
+ 0xc7, 0x98, 0x25, 0xdf, 0x56, 0x6d, 0xc5, 0x43, 0x0b, 0x9a, 0x04,
+ 0x5a, 0x12, 0x00, 0x13, 0x01, 0x00, 0x00, 0x2e, 0x00, 0x33, 0x00,
+ 0x24, 0x00, 0x1d, 0x00, 0x20, 0x9d, 0x3c, 0x94, 0x0d, 0x89, 0x69,
+ 0x0b, 0x84, 0xd0, 0x8a, 0x60, 0x99, 0x3c, 0x14, 0x4e, 0xca, 0x68,
+ 0x4d, 0x10, 0x81, 0x28, 0x7c, 0x83, 0x4d, 0x53, 0x11, 0xbc, 0xf3,
+ 0x2b, 0xb9, 0xda, 0x1a, 0x00, 0x2b, 0x00, 0x02, 0x03, 0x04,
+ ];
+
+ let pkt = [
+ 0xc9, 0xff, 0x00, 0x00, 0x17, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50,
+ 0x2a, 0x42, 0x62, 0xb5, 0x00, 0x40, 0x74, 0x16, 0x8b, 0xf2, 0x2b,
+ 0x70, 0x02, 0x59, 0x6f, 0x99, 0xae, 0x67, 0xab, 0xf6, 0x5a, 0x58,
+ 0x52, 0xf5, 0x4f, 0x58, 0xc3, 0x7c, 0x80, 0x86, 0x82, 0xe2, 0xe4,
+ 0x04, 0x92, 0xd8, 0xa3, 0x89, 0x9f, 0xb0, 0x4f, 0xc0, 0xaf, 0xe9,
+ 0xaa, 0xbc, 0x87, 0x67, 0xb1, 0x8a, 0x0a, 0xa4, 0x93, 0x53, 0x74,
+ 0x26, 0x37, 0x3b, 0x48, 0xd5, 0x02, 0x21, 0x4d, 0xd8, 0x56, 0xd6,
+ 0x3b, 0x78, 0xce, 0xe3, 0x7b, 0xc6, 0x64, 0xb3, 0xfe, 0x86, 0xd4,
+ 0x87, 0xac, 0x7a, 0x77, 0xc5, 0x30, 0x38, 0xa3, 0xcd, 0x32, 0xf0,
+ 0xb5, 0x00, 0x4d, 0x9f, 0x57, 0x54, 0xc4, 0xf7, 0xf2, 0xd1, 0xf3,
+ 0x5c, 0xf3, 0xf7, 0x11, 0x63, 0x51, 0xc9, 0x2b, 0x9c, 0xf9, 0xbb,
+ 0x6d, 0x09, 0x1d, 0xdf, 0xc8, 0xb3, 0x2d, 0x43, 0x23, 0x48, 0xa2,
+ 0xc4, 0x13,
+ ];
+
+ test_encrypt_pkt(&mut header, &dcid, &frames, 1, 2, true, &pkt);
+ }
+
+ #[test]
+ fn decrypto_pkt_underflow() {
+ let mut buf = [0; 65535];
+ let mut b = octets::Octets::with_slice(&mut buf);
+
+ let hdr = Header {
+ ty: Type::Initial,
+ version: crate::PROTOCOL_VERSION,
+ dcid: Vec::new(),
+ scid: Vec::new(),
+ odcid: None,
+ pkt_num: 0,
+ pkt_num_len: 0,
+ token: None,
+ versions: None,
+ key_phase: false,
+ };
+
+ hdr.to_bytes(&mut b).unwrap();
+
+ b.put_bytes(&[0; 50]).unwrap();
+
+ let payload_len = b.get_varint().unwrap() as usize;
+
+ let (aead, _) = crypto::derive_initial_key_material(b"", true).unwrap();
+
+ assert_eq!(
+ decrypt_pkt(&mut b, 0, 1, payload_len, &aead),
+ Err(Error::InvalidPacket)
+ );
+ }
}
diff --git a/src/ranges.rs b/src/ranges.rs
index f2f6a92..94ebccd 100644
--- a/src/ranges.rs
+++ b/src/ranges.rs
@@ -56,7 +56,7 @@
// Check if following existing ranges overlap with the new one.
while let Some(r) = self.next_to(start) {
// Existing range is fully contained in the new range, remove it.
- if range_contains(&item, r.start) && range_contains(&item, r.end) {
+ if item.contains(&r.start) && item.contains(&r.end) {
self.inner.remove(&r.start);
continue;
}
@@ -133,16 +133,15 @@
impl std::fmt::Debug for RangeSet {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- write!(
- f,
- "{:?}",
- self.iter()
- .map(|mut r| {
- r.end -= 1;
- r
- })
- .collect::<Vec<Range<u64>>>()
- )
+ let ranges: Vec<Range<u64>> = self
+ .iter()
+ .map(|mut r| {
+ r.end -= 1;
+ r
+ })
+ .collect();
+
+ write!(f, "{:?}", ranges)
}
}
@@ -211,10 +210,6 @@
}
}
-fn range_contains(r: &Range<u64>, item: u64) -> bool {
- r.start <= item && item <= r.end
-}
-
fn range_overlaps(r: &Range<u64>, other: &Range<u64>) -> bool {
other.start >= r.start && other.start <= r.end ||
other.end >= r.start && other.end <= r.end
diff --git a/src/recovery.rs b/src/recovery.rs
index 096d0da..f58d550 100644
--- a/src/recovery.rs
+++ b/src/recovery.rs
@@ -32,6 +32,9 @@
use std::collections::BTreeMap;
+use crate::Error;
+use crate::Result;
+
use crate::frame;
use crate::packet;
use crate::ranges;
@@ -39,6 +42,8 @@
// Loss Recovery
const PACKET_THRESHOLD: u64 = 3;
+const TIME_THRESHOLD: f64 = 9.0 / 8.0;
+
const GRANULARITY: Duration = Duration::from_millis(1);
const INITIAL_RTT: Duration = Duration::from_millis(500);
@@ -83,6 +88,8 @@
largest_acked_pkt: [u64; packet::EPOCH_COUNT],
+ largest_sent_pkt: [u64; packet::EPOCH_COUNT],
+
latest_rtt: Duration,
smoothed_rtt: Option<Duration>,
@@ -133,6 +140,8 @@
largest_acked_pkt: [std::u64::MAX; packet::EPOCH_COUNT],
+ largest_sent_pkt: [0; packet::EPOCH_COUNT],
+
latest_rtt: Duration::new(0, 0),
smoothed_rtt: None,
@@ -178,6 +187,9 @@
let is_crypto = pkt.is_crypto;
let sent_bytes = pkt.size;
+ self.largest_sent_pkt[epoch] =
+ cmp::max(self.largest_sent_pkt[epoch], pkt.pkt_num);
+
self.sent[epoch].insert(pkt_num, pkt);
if in_flight {
@@ -203,9 +215,16 @@
pub fn on_ack_received(
&mut self, ranges: &ranges::RangeSet, ack_delay: u64,
epoch: packet::Epoch, now: Instant, trace_id: &str,
- ) {
+ ) -> Result<()> {
let largest_acked = ranges.largest().unwrap();
+ // If the largest packet number ACKed exceeds any packet number we have
+ // sent, then the ACK is obviously invalid, so there's no need to
+ // continue further.
+ if largest_acked > self.largest_sent_pkt[epoch] {
+ return Err(Error::InvalidPacket);
+ }
+
if self.largest_acked_pkt[epoch] == std::u64::MAX {
self.largest_acked_pkt[epoch] = largest_acked;
} else {
@@ -241,7 +260,7 @@
}
if !has_newly_acked {
- return;
+ return Ok(());
}
self.detect_lost_packets(epoch, now, trace_id);
@@ -252,6 +271,8 @@
self.set_loss_detection_timer();
trace!("{} {:?}", trace_id, self);
+
+ Ok(())
}
pub fn on_loss_detection_timeout(&mut self, now: Instant, trace_id: &str) {
@@ -350,9 +371,12 @@
latest_rtt
};
- self.rttvar = (self.rttvar * 3 + sub_abs(srtt, adjusted_rtt)) / 4;
+ self.rttvar = self.rttvar.mul_f64(3.0 / 4.0) +
+ sub_abs(srtt, adjusted_rtt).mul_f64(1.0 / 4.0);
- self.smoothed_rtt = Some((srtt * 7 + adjusted_rtt) / 8);
+ self.smoothed_rtt = Some(
+ srtt.mul_f64(7.0 / 8.0) + adjusted_rtt.mul_f64(1.0 / 8.0),
+ );
},
}
}
@@ -413,7 +437,8 @@
let largest_acked = self.largest_acked_pkt[epoch];
- let loss_delay = (cmp::max(self.latest_rtt, self.rtt()) * 9) / 8;
+ let loss_delay =
+ cmp::max(self.latest_rtt, self.rtt()).mul_f64(TIME_THRESHOLD);
let loss_delay = cmp::max(loss_delay, GRANULARITY);
let lost_send_time = now - loss_delay;
diff --git a/src/stream.rs b/src/stream.rs
index b877bb4..4c34273 100644
--- a/src/stream.rs
+++ b/src/stream.rs
@@ -30,6 +30,8 @@
use std::collections::hash_map;
use std::collections::BinaryHeap;
use std::collections::HashMap;
+use std::collections::HashSet;
+use std::collections::VecDeque;
use crate::Error;
use crate::Result;
@@ -43,16 +45,40 @@
streams: HashMap<u64, Stream>,
/// Peer's maximum bidirectional stream count limit.
- peer_max_streams_bidi: usize,
+ peer_max_streams_bidi: u64,
/// Peer's maximum unidirectional stream count limit.
- peer_max_streams_uni: usize,
+ peer_max_streams_uni: u64,
/// Local maximum bidirectional stream count limit.
- local_max_streams_bidi: usize,
+ local_max_streams_bidi: u64,
/// Local maximum unidirectional stream count limit.
- local_max_streams_uni: usize,
+ local_max_streams_uni: u64,
+
+ /// Queue of stream IDs corresponding to streams that have buffered data
+ /// ready to be sent to the peer. This also implies that the stream has
+ /// enough flow control credits to send at least some of that data.
+ ///
+ /// Streams are added to the back of the list, and removed from the front.
+ flushable: VecDeque<u64>,
+
+ /// Set of stream IDs corresponding to streams that have outstanding data
+ /// to read. This is used to generate a `StreamIter` of streams without
+ /// having to iterate over the full list of streams.
+ readable: HashSet<u64>,
+
+ /// Set of stream IDs corresponding to streams that have enough flow control
+ /// capacity to be written to, and is not finished. This is used to generate
+ /// a `StreamIter` of streams without having to iterate over the full list
+ /// of streams.
+ writable: HashSet<u64>,
+
+ /// Set of stream IDs corresponding to streams that are almost out of flow
+ /// control credit and need to send MAX_STREAM_DATA. This is used to
+ /// generate a `StreamIter` of streams without having to iterate over the
+ /// full list of streams.
+ almost_full: HashSet<u64>,
}
impl StreamMap {
@@ -69,12 +95,18 @@
/// Returns the mutable stream with the given ID if it exists, or creates
/// a new one otherwise.
///
+ /// The `local` parameter indicates whether the stream's creation was
+ /// requested by the local application rather than the peer, and is
+ /// used to validate the requested stream ID, and to select the initial
+ /// flow control values from the local and remote transport parameters
+ /// (also passed as arguments).
+ ///
/// This also takes care of enforcing both local and the peer's stream
/// count limits. If one of these limits is violated, the `StreamLimit`
/// error is returned.
- pub fn get_or_create(
- &mut self, id: u64, max_rx_data: usize, max_tx_data: usize, local: bool,
- is_server: bool,
+ pub(crate) fn get_or_create(
+ &mut self, id: u64, local_params: &crate::TransportParams,
+ peer_params: &crate::TransportParams, local: bool, is_server: bool,
) -> Result<&mut Stream> {
let stream = match self.streams.entry(id) {
hash_map::Entry::Vacant(v) => {
@@ -82,6 +114,27 @@
return Err(Error::InvalidStreamState);
}
+ let (max_rx_data, max_tx_data) = match (local, is_bidi(id)) {
+ // Locally-initiated bidirectional stream.
+ (true, true) => (
+ local_params.initial_max_stream_data_bidi_local,
+ peer_params.initial_max_stream_data_bidi_remote,
+ ),
+
+ // Locally-initiated unidirectional stream.
+ (true, false) => (0, peer_params.initial_max_stream_data_uni),
+
+ // Remotely-initiated bidirectional stream.
+ (false, true) => (
+ local_params.initial_max_stream_data_bidi_remote,
+ peer_params.initial_max_stream_data_bidi_local,
+ ),
+
+ // Remotely-initiated unidirectional stream.
+ (false, false) =>
+ (local_params.initial_max_stream_data_uni, 0),
+ };
+
// Enforce stream count limits.
match (is_local(id, is_server), is_bidi(id)) {
(true, true) =>
@@ -116,48 +169,121 @@
hash_map::Entry::Occupied(v) => v.into_mut(),
};
+ // Stream might already be writable due to initial flow control limits.
+ if stream.is_writable() {
+ self.writable.insert(id);
+ }
+
Ok(stream)
}
+ /// Pushes the stream ID to the back of the flushable streams queue.
+ ///
+ /// Note that the caller is responsible for checking that the specified
+ /// stream ID was not in the queue already before calling this.
+ ///
+ /// Queueing a stream multiple times simultaneously means that it might be
+ /// unfairly scheduled more often than other streams, and might also cause
+ /// spurious cycles through the queue, so it should be avoided.
+ pub fn push_flushable(&mut self, stream_id: u64) {
+ self.flushable.push_back(stream_id);
+ }
+
+ /// Removes and returns the first stream ID from the flushable streams
+ /// queue.
+ ///
+ /// Note that if the stream is still flushable after sending some of its
+ /// outstanding data, it needs to be added back to the queu.
+ pub fn pop_flushable(&mut self) -> Option<u64> {
+ self.flushable.pop_front()
+ }
+
+ /// Adds or removes the stream ID to/from the readable streams set.
+ ///
+ /// If the stream was already in the list, this does nothing.
+ pub fn mark_readable(&mut self, stream_id: u64, readable: bool) {
+ if readable {
+ self.readable.insert(stream_id);
+ } else {
+ self.readable.remove(&stream_id);
+ }
+ }
+
+ /// Adds or removes the stream ID to/from the writable streams set.
+ ///
+ /// This should also be called anytime a new stream is created, in addition
+ /// to when an existing stream becomes writable (or stops being writable).
+ ///
+ /// If the stream was already in the list, this does nothing.
+ pub fn mark_writable(&mut self, stream_id: u64, writable: bool) {
+ if writable {
+ self.writable.insert(stream_id);
+ } else {
+ self.writable.remove(&stream_id);
+ }
+ }
+
+ /// Adds or removes the stream ID to/from the almost full streams set.
+ ///
+ /// If the stream was already in the list, this does nothing.
+ pub fn mark_almost_full(&mut self, stream_id: u64, almost_full: bool) {
+ if almost_full {
+ self.almost_full.insert(stream_id);
+ } else {
+ self.almost_full.remove(&stream_id);
+ }
+ }
+
/// Updates the local maximum bidirectional stream count limit.
- pub fn update_local_max_streams_bidi(&mut self, v: usize) {
+ pub fn update_local_max_streams_bidi(&mut self, v: u64) {
self.local_max_streams_bidi = cmp::max(self.local_max_streams_bidi, v);
}
/// Updates the local maximum unidirectional stream count limit.
- pub fn update_local_max_streams_uni(&mut self, v: usize) {
+ pub fn update_local_max_streams_uni(&mut self, v: u64) {
self.local_max_streams_uni = cmp::max(self.local_max_streams_uni, v);
}
/// Updates the peer's maximum bidirectional stream count limit.
- pub fn update_peer_max_streams_bidi(&mut self, v: usize) {
+ pub fn update_peer_max_streams_bidi(&mut self, v: u64) {
self.peer_max_streams_bidi = cmp::max(self.peer_max_streams_bidi, v);
}
/// Updates the peer's maximum unidirectional stream count limit.
- pub fn update_peer_max_streams_uni(&mut self, v: usize) {
+ pub fn update_peer_max_streams_uni(&mut self, v: u64) {
self.peer_max_streams_uni = cmp::max(self.peer_max_streams_uni, v);
}
/// Creates an iterator over streams that have outstanding data to read.
- pub fn readable(&mut self) -> Readable {
- Readable::new(&self.streams)
+ pub fn readable(&self) -> StreamIter {
+ StreamIter::from(&self.readable)
}
- /// Creates an iterator over all streams.
- pub fn iter_mut(&mut self) -> hash_map::IterMut<u64, Stream> {
- self.streams.iter_mut()
+ /// Creates an iterator over streams that can be written to.
+ pub fn writable(&self) -> StreamIter {
+ StreamIter::from(&self.writable)
+ }
+
+ /// Creates an iterator over streams that need to send MAX_STREAM_DATA.
+ pub fn almost_full(&self) -> StreamIter {
+ StreamIter::from(&self.almost_full)
}
/// Returns true if there are any streams that have data to write.
- pub fn has_writable(&self) -> bool {
- self.streams.values().any(Stream::writable)
+ pub fn has_flushable(&self) -> bool {
+ !self.flushable.is_empty()
}
/// Returns true if there are any streams that need to update the local
/// flow control limit.
- pub fn has_out_of_credit(&self) -> bool {
- self.streams.values().any(|s| s.recv.more_credit())
+ pub fn has_almost_full(&self) -> bool {
+ !self.almost_full.is_empty()
+ }
+
+ /// Creates an iterator over all streams.
+ #[cfg(test)]
+ pub fn iter_mut(&mut self) -> hash_map::IterMut<u64, Stream> {
+ self.streams.iter_mut()
}
}
@@ -173,7 +299,7 @@
impl Stream {
/// Creates a new stream with the given flow control limits.
- pub fn new(max_rx_data: usize, max_tx_data: usize) -> Stream {
+ pub fn new(max_rx_data: u64, max_tx_data: u64) -> Stream {
Stream {
recv: RecvBuf::new(max_rx_data),
send: SendBuf::new(max_tx_data),
@@ -181,13 +307,22 @@
}
/// Returns true if the stream has data to read.
- pub fn readable(&self) -> bool {
+ pub fn is_readable(&self) -> bool {
self.recv.ready()
}
- /// Returns true if the stream has data to write.
- pub fn writable(&self) -> bool {
- self.send.ready() && self.send.off() <= self.send.max_data
+ /// Returns true if the stream has enough flow control capacity to be
+ /// written to, and is not finished.
+ pub fn is_writable(&self) -> bool {
+ !self.send.shutdown &&
+ !self.send.is_fin() &&
+ self.send.off < self.send.max_data
+ }
+
+ /// Returns true if the stream has data to send and is allowed to send at
+ /// least some of it.
+ pub fn is_flushable(&self) -> bool {
+ self.send.ready() && self.send.off() < self.send.max_data
}
}
@@ -201,34 +336,31 @@
(stream_id & 0x2) == 0
}
-/// An iterator over the streams that have outstanding data to read.
-///
-/// This can be obtained by calling a connection's [`readable()`] method.
-///
-/// [`readable()`]: struct.Connection.html#method.readable
-pub struct Readable<'a> {
- streams: hash_map::Iter<'a, u64, Stream>,
+/// An iterator over QUIC streams.
+#[derive(Default)]
+pub struct StreamIter {
+ streams: Vec<u64>,
}
-impl<'a> Readable<'a> {
- fn new(streams: &HashMap<u64, Stream>) -> Readable {
- Readable {
- streams: streams.iter(),
+impl StreamIter {
+ fn from(streams: &HashSet<u64>) -> Self {
+ StreamIter {
+ streams: streams.iter().copied().collect(),
}
}
}
-impl<'a> Iterator for Readable<'a> {
+impl Iterator for StreamIter {
type Item = u64;
fn next(&mut self) -> Option<Self::Item> {
- for (id, s) in &mut self.streams {
- if s.readable() {
- return Some(*id);
- }
- }
+ self.streams.pop()
+ }
+}
- None
+impl ExactSizeIterator for StreamIter {
+ fn len(&self) -> usize {
+ self.streams.len()
}
}
@@ -244,19 +376,19 @@
data: BinaryHeap<RangeBuf>,
/// The lowest data offset that has yet to be read by the application.
- off: usize,
+ off: u64,
/// The total length of data received on this stream.
- len: usize,
+ len: u64,
/// The maximum offset the peer is allowed to send us.
- max_data: usize,
+ max_data: u64,
/// The updated maximum offset the peer is allowed to send us.
- max_data_next: usize,
+ max_data_next: u64,
/// The final stream offset received from the peer, if any.
- fin_off: Option<usize>,
+ fin_off: Option<u64>,
/// Whether incoming data is validated but not buffered.
drain: bool,
@@ -264,7 +396,7 @@
impl RecvBuf {
/// Creates a new receive buffer.
- fn new(max_data: usize) -> RecvBuf {
+ fn new(max_data: u64) -> RecvBuf {
RecvBuf {
max_data,
max_data_next: max_data,
@@ -278,11 +410,6 @@
/// as handling incoming data that overlaps data that is already in the
/// buffer.
pub fn push(&mut self, buf: RangeBuf) -> Result<()> {
- if self.off >= buf.max_off() {
- // Data is fully duplicate.
- return Ok(());
- }
-
if buf.max_off() > self.max_data {
return Err(Error::FlowControl);
}
@@ -304,16 +431,34 @@
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());
}
- // We already saved the final offset, so there's nothing else we
- // need to keep from the RangeBuf if it's empty.
- if buf.is_empty() {
+ // 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 self.drain {
return Ok(());
}
@@ -323,6 +468,15 @@
while let Some(mut buf) = tmp_buf {
tmp_buf = None;
+ // Discard incoming data below current stream offset. Bytes up to
+ // `self.off` have already been received so we should not buffer
+ // them again. This is also important to make sure `ready()` doesn't
+ // get stuck when a buffer with lower offset than the stream's is
+ // buffered.
+ if self.off > buf.off() {
+ buf = buf.split_off((self.off - buf.off()) as usize);
+ }
+
for b in &self.data {
// New buffer is fully contained in existing buffer.
if buf.off() >= b.off() && buf.max_off() <= b.max_off() {
@@ -331,12 +485,12 @@
// New buffer's start overlaps existing buffer.
if buf.off() >= b.off() && buf.off() < b.max_off() {
- buf = buf.split_off(b.max_off() - buf.off());
+ buf = buf.split_off((b.max_off() - buf.off()) as usize);
}
// New buffer's end overlaps existing buffer.
if buf.off() < b.off() && buf.max_off() > b.off() {
- tmp_buf = Some(buf.split_off(b.off() - buf.off()));
+ tmp_buf = Some(buf.split_off((b.off() - buf.off()) as usize));
}
}
@@ -368,13 +522,14 @@
while cap > 0 && self.ready() {
let mut buf = match self.data.pop() {
Some(v) => v,
+
None => break,
};
if buf.len() > cap {
let new_buf = RangeBuf {
data: buf.data.split_off(cap),
- off: buf.off + cap,
+ off: buf.off + cap as u64,
fin: buf.fin,
};
@@ -385,19 +540,19 @@
out[len..len + buf.len()].copy_from_slice(&buf.data);
- self.off += buf.len();
+ self.off += buf.len() as u64;
len += buf.len();
cap -= buf.len();
}
- self.max_data_next = self.max_data_next.saturating_add(len);
+ self.max_data_next = self.max_data_next.saturating_add(len as u64);
Ok((len, self.is_fin()))
}
/// Resets the stream at the given offset.
- pub fn reset(&mut self, final_size: usize) -> Result<usize> {
+ pub fn reset(&mut self, final_size: u64) -> Result<usize> {
// Stream's size is already known, forbid changing it.
if let Some(fin_off) = self.fin_off {
if fin_off != final_size {
@@ -414,25 +569,31 @@
// Return how many bytes need to be removed from the connection flow
// control.
- Ok(final_size - self.len)
+ Ok((final_size - self.len) as usize)
}
/// Commits the new max_data limit and returns it.
- pub fn update_max_data(&mut self) -> usize {
+ pub fn update_max_data(&mut self) -> u64 {
self.max_data = self.max_data_next;
self.max_data
}
/// Shuts down receiving data.
- pub fn shutdown(&mut self) {
+ pub fn shutdown(&mut self) -> Result<()> {
+ if self.drain {
+ return Err(Error::Done);
+ }
+
self.drain = true;
self.data.clear();
+
+ Ok(())
}
/// Returns true if we need to update the local flow control limit.
- pub fn more_credit(&self) -> bool {
+ pub fn almost_full(&self) -> bool {
// Send MAX_STREAM_DATA when the new limit is at least double the
// amount of data that can be received before blocking.
self.fin_off.is_none() &&
@@ -441,6 +602,9 @@
}
/// Returns true if the receive-side of the stream is complete.
+ ///
+ /// This happens when the stream's receive final size is known, and the
+ /// application has read all data from the stream.
pub fn is_fin(&self) -> bool {
if self.fin_off == Some(self.off) {
return true;
@@ -453,6 +617,7 @@
fn ready(&self) -> bool {
let buf = match self.data.peek() {
Some(v) => v,
+
None => return false,
};
@@ -475,16 +640,19 @@
data: BinaryHeap<RangeBuf>,
/// The maximum offset of data buffered in the stream.
- off: usize,
+ off: u64,
/// The amount of data that was ever written to this stream.
- len: usize,
+ len: u64,
/// The maximum offset we are allowed to send to the peer.
- max_data: usize,
+ max_data: u64,
/// The highest contiguous ACK'd offset.
- off_ack: usize,
+ ack_off: u64,
+
+ /// The final stream offset written to the stream, if any.
+ fin_off: Option<u64>,
/// Whether the stream's send-side has been shut down.
shutdown: bool,
@@ -492,7 +660,7 @@
impl SendBuf {
/// Creates a new send buffer.
- fn new(max_data: usize) -> SendBuf {
+ fn new(max_data: u64) -> SendBuf {
SendBuf {
max_data,
..SendBuf::default()
@@ -500,16 +668,36 @@
}
/// Inserts the given slice of data at the end of the buffer.
- pub fn push_slice(&mut self, data: &[u8], fin: bool) -> Result<()> {
+ ///
+ /// The number of bytes that were actually stored in the buffer is returned
+ /// (this may be lower than the size of the input buffer, in case of partial
+ /// writes).
+ pub fn push_slice(
+ &mut self, mut data: &[u8], mut fin: bool,
+ ) -> Result<usize> {
let mut len = 0;
if self.shutdown {
- return Ok(());
+ // Since we won't write any more data anyway, pretend that we sent
+ // all data that was passed in.
+ return Ok(data.len());
}
if data.is_empty() {
+ // Create a dummy range buffer, in order to propagate the `fin` flag
+ // into `RangeBuf::push()`. This will be discarded later on.
let buf = RangeBuf::from(&[], self.off, fin);
- return self.push(buf);
+
+ return self.push(buf).map(|_| 0);
+ }
+
+ if data.len() > self.cap() {
+ // Truncate the input buffer according to the stream's capacity.
+ let len = self.cap();
+ data = &data[..len];
+
+ // We are not buffering the full input, so clear the fin flag.
+ fin = false;
}
// Split the input buffer into multiple RangeBufs. Otherwise a big
@@ -523,24 +711,46 @@
let buf = RangeBuf::from(chunk, self.off, fin);
self.push(buf)?;
- self.off += chunk.len();
+ self.off += chunk.len() as u64;
}
- Ok(())
+ Ok(data.len())
}
/// Inserts the given chunk of data in the buffer.
pub fn push(&mut self, buf: RangeBuf) -> Result<()> {
+ if let Some(fin_off) = self.fin_off {
+ // Can't write past final offset.
+ if buf.max_off() > fin_off {
+ return Err(Error::FinalSize);
+ }
+
+ // Can't "undo" final offset.
+ if buf.max_off() == fin_off && !buf.fin() {
+ return Err(Error::FinalSize);
+ }
+ }
+
if self.shutdown {
return Ok(());
}
// Don't queue data that was already fully ACK'd.
- if self.off_ack >= buf.max_off() {
+ if self.ack_off >= buf.max_off() {
return Ok(());
}
- self.len += buf.len();
+ self.len += buf.len() as u64;
+
+ if buf.fin() {
+ self.fin_off = Some(buf.max_off());
+ }
+
+ // We already recorded the final offset, so we can just discard the
+ // empty buffer now.
+ if buf.is_empty() {
+ return Ok(());
+ }
self.data.push(buf);
@@ -550,7 +760,8 @@
/// Returns contiguous data from the send buffer as a single `RangeBuf`.
pub fn pop(&mut self, max_data: usize) -> Result<RangeBuf> {
let mut out = RangeBuf::default();
- out.data = Vec::with_capacity(cmp::min(max_data, self.len));
+ out.data =
+ Vec::with_capacity(cmp::min(max_data as u64, self.len) as usize);
let mut out_len = max_data;
let mut out_off = self.data.peek().map_or_else(|| 0, RangeBuf::off);
@@ -562,11 +773,13 @@
{
let mut buf = match self.data.pop() {
Some(v) => v,
+
None => break,
};
- if buf.len() > out_len || buf.max_off() >= self.max_data {
- let new_len = cmp::min(out_len, self.max_data - buf.off());
+ if buf.len() > out_len || buf.max_off() > self.max_data {
+ let new_len =
+ cmp::min(out_len, (self.max_data - buf.off()) as usize);
let new_buf = buf.split_off(new_len);
self.data.push(new_buf);
@@ -576,39 +789,63 @@
out.off = buf.off;
}
- self.len -= buf.len();
+ self.len -= buf.len() as u64;
out_len -= buf.len();
out_off = buf.max_off();
- out.fin = out.fin || buf.fin();
-
out.data.extend_from_slice(&buf.data);
}
+ // Override the `fin` flag set for the output buffer by matching the
+ // buffer's maximum offset against the stream's final offset (if known).
+ //
+ // This is more efficient than tracking `fin` using the range buffers
+ // themselves, and lets us avoid queueing empty buffers just so we can
+ // propagate the final size.
+ out.fin = self.fin_off == Some(out.max_off());
+
Ok(out)
}
/// Updates the max_data limit to the given value.
- pub fn update_max_data(&mut self, max_data: usize) {
+ pub fn update_max_data(&mut self, max_data: u64) {
self.max_data = cmp::max(self.max_data, max_data);
}
/// Increments the ACK'd data offset.
- pub fn ack(&mut self, off: usize, len: usize) {
+ pub fn ack(&mut self, off: u64, len: usize) {
// Keep track of the highest contiguously ACK'd offset. This can be
// used to avoid spurious retransmissions of data that has already
// been ACK'd.
- if self.off_ack == off {
- self.off_ack += len;
+ if self.ack_off == off {
+ self.ack_off += len as u64;
}
}
/// Shuts down sending data.
- pub fn shutdown(&mut self) {
+ pub fn shutdown(&mut self) -> Result<()> {
+ if self.shutdown {
+ return Err(Error::Done);
+ }
+
self.shutdown = true;
self.data.clear();
+
+ Ok(())
+ }
+
+ /// Returns true if the send-side of the stream is complete.
+ ///
+ /// This happens when the stream's send final size is knwon, and the
+ /// application has already written data up to that point.
+ pub fn is_fin(&self) -> bool {
+ if self.fin_off == Some(self.off) {
+ return true;
+ }
+
+ false
}
/// Returns true if there is data to be written.
@@ -617,26 +854,31 @@
}
/// Returns the lowest offset of data buffered.
- fn off(&self) -> usize {
+ fn off(&self) -> u64 {
match self.data.peek() {
Some(v) => v.off(),
None => self.off,
}
}
+
+ /// Returns the outgoing flow control capacity.
+ pub fn cap(&self) -> usize {
+ (self.max_data - self.off) as usize
+ }
}
/// Buffer holding data at a specific offset.
#[derive(Clone, Debug, Default, Eq)]
pub struct RangeBuf {
data: Vec<u8>,
- off: usize,
+ off: u64,
fin: bool,
}
impl RangeBuf {
/// Creates a new `RangeBuf` from the given slice.
- pub(crate) fn from(buf: &[u8], off: usize, fin: bool) -> RangeBuf {
+ pub(crate) fn from(buf: &[u8], off: u64, fin: bool) -> RangeBuf {
RangeBuf {
data: Vec::from(buf),
off,
@@ -650,13 +892,13 @@
}
/// Returns the starting offset of `self`.
- pub fn off(&self) -> usize {
+ pub fn off(&self) -> u64 {
self.off
}
/// Returns the final offset of `self`.
- pub fn max_off(&self) -> usize {
- self.off() + self.len()
+ pub fn max_off(&self) -> u64 {
+ self.off() + self.len() as u64
}
/// Returns the length of `self`.
@@ -673,7 +915,7 @@
pub fn split_off(&mut self, at: usize) -> RangeBuf {
let buf = RangeBuf {
data: self.data.split_off(at),
- off: self.off + at,
+ off: self.off + at as u64,
fin: self.fin,
};
@@ -722,7 +964,7 @@
#[test]
fn empty_read() {
- let mut recv = RecvBuf::new(std::usize::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -731,8 +973,64 @@
}
#[test]
+ fn empty_stream_frame() {
+ let mut recv = RecvBuf::new(15);
+ assert_eq!(recv.len, 0);
+
+ let buf = RangeBuf::from(b"hello", 0, false);
+ assert!(recv.push(buf).is_ok());
+ assert_eq!(recv.len, 5);
+ assert_eq!(recv.off, 0);
+ assert_eq!(recv.data.len(), 1);
+
+ let mut buf = [0; 32];
+ assert_eq!(recv.pop(&mut buf), Ok((5, false)));
+
+ // Don't store non-fin empty buffer.
+ let buf = RangeBuf::from(b"", 10, false);
+ assert!(recv.push(buf).is_ok());
+ 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.push(buf), Err(Error::FlowControl));
+
+ // Store fin empty buffer.
+ let buf = RangeBuf::from(b"", 5, true);
+ assert!(recv.push(buf).is_ok());
+ 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.push(buf).is_ok());
+ 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.push(buf).is_ok());
+ 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.push(buf), Err(Error::FinalSize));
+ let buf = RangeBuf::from(b"", 4, true);
+ assert_eq!(recv.push(buf), Err(Error::FinalSize));
+
+ let mut buf = [0; 32];
+ assert_eq!(recv.pop(&mut buf), Ok((0, true)));
+ }
+
+ #[test]
fn ordered_read() {
- let mut recv = RecvBuf::new(std::usize::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -769,7 +1067,7 @@
#[test]
fn split_read() {
- let mut recv = RecvBuf::new(std::usize::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -809,7 +1107,7 @@
#[test]
fn incomplete_read() {
- let mut recv = RecvBuf::new(std::usize::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -837,7 +1135,7 @@
#[test]
fn zero_len_read() {
- let mut recv = RecvBuf::new(std::usize::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -865,13 +1163,15 @@
#[test]
fn past_read() {
- let mut recv = RecvBuf::new(std::usize::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
let first = RangeBuf::from(b"something", 0, false);
- let second = RangeBuf::from(b"hello", 3, true);
+ let second = RangeBuf::from(b"hello", 3, false);
+ let third = RangeBuf::from(b"ello", 4, true);
+ let fourth = RangeBuf::from(b"ello", 5, true);
assert!(recv.push(first).is_ok());
assert_eq!(recv.len, 9);
@@ -890,12 +1190,19 @@
assert_eq!(recv.off, 9);
assert_eq!(recv.data.len(), 0);
+ assert_eq!(recv.push(third), Err(Error::FinalSize));
+
+ assert!(recv.push(fourth).is_ok());
+ assert_eq!(recv.len, 9);
+ assert_eq!(recv.off, 9);
+ assert_eq!(recv.data.len(), 0);
+
assert_eq!(recv.pop(&mut buf), Err(Error::Done));
}
#[test]
fn fully_overlapping_read() {
- let mut recv = RecvBuf::new(std::usize::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -926,7 +1233,7 @@
#[test]
fn fully_overlapping_read2() {
- let mut recv = RecvBuf::new(std::usize::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -947,7 +1254,6 @@
let (len, fin) = recv.pop(&mut buf).unwrap();
assert_eq!(len, 9);
assert_eq!(fin, false);
- println!("{}", std::str::from_utf8(&buf[..len]).unwrap());
assert_eq!(&buf[..len], b"somehello");
assert_eq!(recv.len, 9);
assert_eq!(recv.off, 9);
@@ -958,7 +1264,7 @@
#[test]
fn fully_overlapping_read3() {
- let mut recv = RecvBuf::new(std::usize::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -979,7 +1285,6 @@
let (len, fin) = recv.pop(&mut buf).unwrap();
assert_eq!(len, 9);
assert_eq!(fin, false);
- println!("{}", std::str::from_utf8(&buf[..len]).unwrap());
assert_eq!(&buf[..len], b"somhellog");
assert_eq!(recv.len, 9);
assert_eq!(recv.off, 9);
@@ -990,7 +1295,7 @@
#[test]
fn fully_overlapping_read_multi() {
- let mut recv = RecvBuf::new(std::usize::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -1017,7 +1322,6 @@
let (len, fin) = recv.pop(&mut buf).unwrap();
assert_eq!(len, 18);
assert_eq!(fin, false);
- println!("{}", std::str::from_utf8(&buf[..len]).unwrap());
assert_eq!(&buf[..len], b"somhellogsomhellog");
assert_eq!(recv.len, 18);
assert_eq!(recv.off, 18);
@@ -1028,7 +1332,7 @@
#[test]
fn overlapping_start_read() {
- let mut recv = RecvBuf::new(std::usize::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -1058,7 +1362,7 @@
#[test]
fn overlapping_end_read() {
- let mut recv = RecvBuf::new(std::usize::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -1088,7 +1392,7 @@
#[test]
fn partially_multi_overlapping_reordered_read() {
- let mut recv = RecvBuf::new(std::usize::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -1125,7 +1429,7 @@
#[test]
fn partially_multi_overlapping_reordered_read2() {
- let mut recv = RecvBuf::new(std::usize::MAX);
+ let mut recv = RecvBuf::new(std::u64::MAX);
assert_eq!(recv.len, 0);
let mut buf = [0; 32];
@@ -1170,7 +1474,6 @@
let (len, fin) = recv.pop(&mut buf).unwrap();
assert_eq!(len, 14);
assert_eq!(fin, false);
- println!("{}", std::str::from_utf8(&buf[..len]).unwrap());
assert_eq!(&buf[..len], b"aabbbcdddeefff");
assert_eq!(recv.len, 14);
assert_eq!(recv.off, 14);
@@ -1181,7 +1484,7 @@
#[test]
fn empty_write() {
- let mut send = SendBuf::new(std::usize::MAX);
+ let mut send = SendBuf::new(std::u64::MAX);
assert_eq!(send.len, 0);
let write = send.pop(std::usize::MAX).unwrap();
@@ -1191,16 +1494,16 @@
#[test]
fn multi_write() {
- let mut send = SendBuf::new(std::usize::MAX);
+ let mut send = SendBuf::new(std::u64::MAX);
assert_eq!(send.len, 0);
- let first = *b"something";
- let second = *b"helloworld";
+ let first = b"something";
+ let second = b"helloworld";
- assert!(send.push_slice(&first, false).is_ok());
+ assert!(send.push_slice(first, false).is_ok());
assert_eq!(send.len, 9);
- assert!(send.push_slice(&second, true).is_ok());
+ assert!(send.push_slice(second, true).is_ok());
assert_eq!(send.len, 19);
let write = send.pop(128).unwrap();
@@ -1212,16 +1515,16 @@
#[test]
fn split_write() {
- let mut send = SendBuf::new(std::usize::MAX);
+ let mut send = SendBuf::new(std::u64::MAX);
assert_eq!(send.len, 0);
- let first = *b"something";
- let second = *b"helloworld";
+ let first = b"something";
+ let second = b"helloworld";
- assert!(send.push_slice(&first, false).is_ok());
+ assert!(send.push_slice(first, false).is_ok());
assert_eq!(send.len, 9);
- assert!(send.push_slice(&second, true).is_ok());
+ assert!(send.push_slice(second, true).is_ok());
assert_eq!(send.len, 19);
let write = send.pop(10).unwrap();
@@ -1248,17 +1551,17 @@
#[test]
fn resend() {
- let mut send = SendBuf::new(std::usize::MAX);
+ let mut send = SendBuf::new(std::u64::MAX);
assert_eq!(send.len, 0);
assert_eq!(send.off(), 0);
- let first = *b"something";
- let second = *b"helloworld";
+ let first = b"something";
+ let second = b"helloworld";
- assert!(send.push_slice(&first, false).is_ok());
+ assert!(send.push_slice(first, false).is_ok());
assert_eq!(send.off(), 0);
- assert!(send.push_slice(&second, true).is_ok());
+ assert!(send.push_slice(second, true).is_ok());
assert_eq!(send.off(), 0);
let write1 = send.pop(4).unwrap();
@@ -1315,42 +1618,57 @@
let mut send = SendBuf::default();
assert_eq!(send.len, 0);
- let first = *b"something";
- let second = *b"helloworld";
+ let first = b"something";
+ let second = b"helloworld";
- assert!(send.push_slice(&first, false).is_ok());
- assert_eq!(send.len, 9);
+ assert_eq!(send.push_slice(first, false), Ok(0));
+ assert_eq!(send.len, 0);
- assert!(send.push_slice(&second, true).is_ok());
- assert_eq!(send.len, 19);
+ assert_eq!(send.push_slice(second, true), Ok(0));
+ assert_eq!(send.len, 0);
send.update_max_data(5);
+ assert_eq!(send.push_slice(first, false), Ok(5));
+ assert_eq!(send.len, 5);
+
+ assert_eq!(send.push_slice(second, true), Ok(0));
+ assert_eq!(send.len, 5);
+
let write = send.pop(10).unwrap();
assert_eq!(write.off(), 0);
assert_eq!(write.len(), 5);
assert_eq!(write.fin(), false);
assert_eq!(&write[..], b"somet");
- assert_eq!(send.len, 14);
+ assert_eq!(send.len, 0);
let write = send.pop(10).unwrap();
assert_eq!(write.off(), 0);
assert_eq!(write.len(), 0);
assert_eq!(write.fin(), false);
assert_eq!(&write[..], b"");
- assert_eq!(send.len, 14);
+ assert_eq!(send.len, 0);
send.update_max_data(15);
+ assert_eq!(send.push_slice(&first[5..], false), Ok(4));
+ assert_eq!(send.len, 4);
+
+ assert_eq!(send.push_slice(second, true), Ok(6));
+ assert_eq!(send.len, 10);
+
let write = send.pop(10).unwrap();
assert_eq!(write.off(), 5);
assert_eq!(write.len(), 10);
assert_eq!(write.fin(), false);
assert_eq!(&write[..], b"hinghellow");
- assert_eq!(send.len, 4);
+ assert_eq!(send.len, 0);
send.update_max_data(25);
+ assert_eq!(send.push_slice(&second[6..], true), Ok(4));
+ assert_eq!(send.len, 4);
+
let write = send.pop(10).unwrap();
assert_eq!(write.off(), 15);
assert_eq!(write.len(), 4);
@@ -1361,12 +1679,12 @@
#[test]
fn zero_len_write() {
- let mut send = SendBuf::new(std::usize::MAX);
+ let mut send = SendBuf::new(std::u64::MAX);
assert_eq!(send.len, 0);
- let first = *b"something";
+ let first = b"something";
- assert!(send.push_slice(&first, false).is_ok());
+ assert!(send.push_slice(first, false).is_ok());
assert_eq!(send.len, 9);
assert!(send.push_slice(&[], true).is_ok());
@@ -1383,7 +1701,7 @@
#[test]
fn recv_flow_control() {
let mut stream = Stream::new(15, 0);
- assert!(!stream.recv.more_credit());
+ assert!(!stream.recv.almost_full());
let mut buf = [0; 32];
@@ -1393,7 +1711,7 @@
assert_eq!(stream.recv.push(second), Ok(()));
assert_eq!(stream.recv.push(first), Ok(()));
- assert!(!stream.recv.more_credit());
+ assert!(!stream.recv.almost_full());
assert_eq!(stream.recv.push(third), Err(Error::FlowControl));
@@ -1401,10 +1719,10 @@
assert_eq!(&buf[..len], b"helloworld");
assert_eq!(fin, false);
- assert!(stream.recv.more_credit());
+ assert!(stream.recv.almost_full());
assert_eq!(stream.recv.update_max_data(), 25);
- assert!(!stream.recv.more_credit());
+ assert!(!stream.recv.almost_full());
let third = RangeBuf::from(b"something", 10, false);
assert_eq!(stream.recv.push(third), Ok(()));
@@ -1413,7 +1731,7 @@
#[test]
fn recv_past_fin() {
let mut stream = Stream::new(15, 0);
- assert!(!stream.recv.more_credit());
+ assert!(!stream.recv.almost_full());
let first = RangeBuf::from(b"hello", 0, true);
let second = RangeBuf::from(b"world", 5, false);
@@ -1425,7 +1743,7 @@
#[test]
fn recv_fin_dup() {
let mut stream = Stream::new(15, 0);
- assert!(!stream.recv.more_credit());
+ assert!(!stream.recv.almost_full());
let first = RangeBuf::from(b"hello", 0, true);
let second = RangeBuf::from(b"hello", 0, true);
@@ -1443,7 +1761,7 @@
#[test]
fn recv_fin_change() {
let mut stream = Stream::new(15, 0);
- assert!(!stream.recv.more_credit());
+ assert!(!stream.recv.almost_full());
let first = RangeBuf::from(b"hello", 0, true);
let second = RangeBuf::from(b"world", 5, true);
@@ -1455,7 +1773,7 @@
#[test]
fn recv_fin_lower_than_received() {
let mut stream = Stream::new(15, 0);
- assert!(!stream.recv.more_credit());
+ assert!(!stream.recv.almost_full());
let first = RangeBuf::from(b"hello", 0, true);
let second = RangeBuf::from(b"world", 5, false);
@@ -1467,7 +1785,7 @@
#[test]
fn recv_fin_flow_control() {
let mut stream = Stream::new(15, 0);
- assert!(!stream.recv.more_credit());
+ assert!(!stream.recv.almost_full());
let mut buf = [0; 32];
@@ -1481,13 +1799,13 @@
assert_eq!(&buf[..len], b"helloworld");
assert_eq!(fin, true);
- assert!(!stream.recv.more_credit());
+ assert!(!stream.recv.almost_full());
}
#[test]
fn recv_fin_reset_mismatch() {
let mut stream = Stream::new(15, 0);
- assert!(!stream.recv.more_credit());
+ assert!(!stream.recv.almost_full());
let first = RangeBuf::from(b"hello", 0, true);
@@ -1498,7 +1816,7 @@
#[test]
fn recv_reset_dup() {
let mut stream = Stream::new(15, 0);
- assert!(!stream.recv.more_credit());
+ assert!(!stream.recv.almost_full());
let first = RangeBuf::from(b"hello", 0, false);
@@ -1510,7 +1828,7 @@
#[test]
fn recv_reset_change() {
let mut stream = Stream::new(15, 0);
- assert!(!stream.recv.more_credit());
+ assert!(!stream.recv.almost_full());
let first = RangeBuf::from(b"hello", 0, false);
@@ -1522,7 +1840,7 @@
#[test]
fn recv_reset_lower_than_received() {
let mut stream = Stream::new(15, 0);
- assert!(!stream.recv.more_credit());
+ assert!(!stream.recv.almost_full());
let first = RangeBuf::from(b"hello", 0, false);
@@ -1538,9 +1856,9 @@
let second = b"world";
let third = b"something";
- assert_eq!(stream.send.push_slice(first, false), Ok(()));
- assert_eq!(stream.send.push_slice(second, false), Ok(()));
- assert_eq!(stream.send.push_slice(third, false), Ok(()));
+ assert!(stream.send.push_slice(first, false).is_ok());
+ assert!(stream.send.push_slice(second, false).is_ok());
+ assert!(stream.send.push_slice(third, false).is_ok());
let write = stream.send.pop(25).unwrap();
assert_eq!(write.off(), 0);
@@ -1569,4 +1887,96 @@
assert_eq!(write.fin(), false);
assert_eq!(write.data, b"somet");
}
+
+ #[test]
+ fn send_past_fin() {
+ let mut stream = Stream::new(0, 15);
+
+ let first = b"hello";
+ let second = b"world";
+ let third = b"third";
+
+ assert_eq!(stream.send.push_slice(first, false), Ok(5));
+
+ assert_eq!(stream.send.push_slice(second, true), Ok(5));
+ assert!(stream.send.is_fin());
+
+ assert_eq!(stream.send.push_slice(third, false), Err(Error::FinalSize));
+ }
+
+ #[test]
+ fn send_fin_dup() {
+ let mut stream = Stream::new(0, 15);
+
+ let first = RangeBuf::from(b"hello", 0, true);
+ let second = RangeBuf::from(b"hello", 0, true);
+
+ assert_eq!(stream.send.push(first), Ok(()));
+ assert_eq!(stream.send.push(second), Ok(()));
+ }
+
+ #[test]
+ fn send_undo_fin() {
+ let mut stream = Stream::new(0, 15);
+
+ let first = b"hello";
+ let second = RangeBuf::from(b"hello", 0, false);
+
+ assert_eq!(stream.send.push_slice(first, true), Ok(5));
+ assert!(stream.send.is_fin());
+
+ assert_eq!(stream.send.push(second), Err(Error::FinalSize));
+ }
+
+ #[test]
+ fn send_fin_max_data_match() {
+ let mut stream = Stream::new(0, 15);
+
+ let slice = b"hellohellohello";
+
+ assert!(stream.send.push_slice(slice, true).is_ok());
+
+ let write = stream.send.pop(15).unwrap();
+ assert_eq!(write.off(), 0);
+ assert_eq!(write.len(), 15);
+ assert_eq!(write.fin(), true);
+ assert_eq!(write.data, slice);
+ }
+
+ #[test]
+ fn send_fin_zero_length() {
+ let mut stream = Stream::new(0, 15);
+
+ assert_eq!(stream.send.push_slice(b"hello", false), Ok(5));
+ assert_eq!(stream.send.push_slice(b"", true), Ok(0));
+ assert!(stream.send.is_fin());
+
+ let write = stream.send.pop(5).unwrap();
+ assert_eq!(write.off(), 0);
+ assert_eq!(write.len(), 5);
+ assert_eq!(write.fin(), true);
+ assert_eq!(write.data, b"hello");
+ }
+
+ #[test]
+ fn recv_data_below_off() {
+ let mut stream = Stream::new(15, 0);
+
+ let first = RangeBuf::from(b"hello", 0, false);
+
+ assert_eq!(stream.recv.push(first), Ok(()));
+
+ let mut buf = [0; 10];
+
+ let (len, fin) = stream.recv.pop(&mut buf).unwrap();
+ assert_eq!(&buf[..len], b"hello");
+ assert_eq!(fin, false);
+
+ let first = RangeBuf::from(b"elloworld", 1, true);
+ assert_eq!(stream.recv.push(first), Ok(()));
+
+ let (len, fin) = stream.recv.pop(&mut buf).unwrap();
+ assert_eq!(&buf[..len], b"world");
+ assert_eq!(fin, true);
+ }
}
diff --git a/src/tls.rs b/src/tls.rs
index 16314a7..7819b6d 100644
--- a/src/tls.rs
+++ b/src/tls.rs
@@ -40,6 +40,9 @@
use lazy_static;
+use crate::Error;
+use crate::Result;
+
use crate::Connection;
use crate::TransportParams;
@@ -47,19 +50,8 @@
use crate::octets;
use crate::packet;
-pub type Result<T> = std::result::Result<T, Error>;
-
-#[derive(Clone, Debug, PartialEq)]
-pub enum Error {
- TlsFail,
- WantRead,
- WantWrite,
- SyscallFail,
- PendingOperation,
-}
-
const TLS1_3_VERSION: u16 = 0x0304;
-const TLS_ALERT_ERROR: u16 = 0x100;
+const TLS_ALERT_ERROR: u64 = 0x100;
#[allow(non_camel_case_types)]
#[repr(transparent)]
@@ -264,6 +256,8 @@
}
}
+unsafe impl std::marker::Send for Context {}
+
impl Drop for Context {
fn drop(&mut self) {
unsafe { SSL_CTX_free(self.as_ptr()) }
@@ -300,8 +294,7 @@
&conn.local_transport_params,
conn.is_server,
&mut raw_params,
- )
- .map_err(|_| Error::TlsFail)?;
+ )?;
self.set_quic_transport_params(raw_params)?;
@@ -458,6 +451,7 @@
let conn =
match get_ex_data_from_ptr::<Connection>(ssl, *QUICHE_EX_DATA_INDEX) {
Some(v) => v,
+
None => return 0,
};
@@ -473,12 +467,13 @@
crypto::Level::ZeroRTT => unimplemented!("0-RTT"),
crypto::Level::Handshake =>
&mut conn.pkt_num_spaces[packet::EPOCH_HANDSHAKE],
- crypto::Level::Application =>
+ crypto::Level::OneRTT =>
&mut conn.pkt_num_spaces[packet::EPOCH_APPLICATION],
};
let aead = match get_cipher_from_ptr(ssl) {
Ok(v) => v,
+
Err(_) => return 0,
};
@@ -505,6 +500,7 @@
let open = match crypto::Open::new(aead, &key, &iv, &pn_key) {
Ok(v) => v,
+
Err(_) => return 0,
};
@@ -526,6 +522,7 @@
let seal = match crypto::Seal::new(aead, &key, &iv, &pn_key) {
Ok(v) => v,
+
Err(_) => return 0,
};
@@ -540,6 +537,7 @@
let conn =
match get_ex_data_from_ptr::<Connection>(ssl, *QUICHE_EX_DATA_INDEX) {
Some(v) => v,
+
None => return 0,
};
@@ -557,7 +555,7 @@
crypto::Level::ZeroRTT => unreachable!(),
crypto::Level::Handshake =>
&mut conn.pkt_num_spaces[packet::EPOCH_HANDSHAKE],
- crypto::Level::Application =>
+ crypto::Level::OneRTT =>
&mut conn.pkt_num_spaces[packet::EPOCH_APPLICATION],
};
@@ -579,6 +577,7 @@
let conn =
match get_ex_data_from_ptr::<Connection>(ssl, *QUICHE_EX_DATA_INDEX) {
Some(v) => v,
+
None => return 0,
};
@@ -589,7 +588,7 @@
alert
);
- let error: u16 = TLS_ALERT_ERROR + u16::from(alert);
+ let error: u64 = TLS_ALERT_ERROR + u64::from(alert);
conn.error = Some(error);
1
@@ -619,6 +618,7 @@
let conn =
match get_ex_data_from_ptr::<Connection>(ssl, *QUICHE_EX_DATA_INDEX) {
Some(v) => v,
+
None => return 3, // SSL_TLSEXT_ERR_NOACK
};
@@ -690,25 +690,25 @@
},
// SSL_ERROR_WANT_READ
- 2 => Err(Error::WantRead),
+ 2 => Err(Error::Done),
// SSL_ERROR_WANT_WRITE
- 3 => Err(Error::WantWrite),
+ 3 => Err(Error::Done),
// SSL_ERROR_WANT_X509_LOOKUP
- 4 => Err(Error::PendingOperation),
+ 4 => Err(Error::Done),
// SSL_ERROR_SYSCALL
- 5 => Err(Error::SyscallFail),
+ 5 => Err(Error::TlsFail),
// SSL_ERROR_PENDING_CERTIFICATE
- 12 => Err(Error::PendingOperation),
+ 12 => Err(Error::Done),
// SSL_ERROR_WANT_PRIVATE_KEY_OPERATION
- 13 => Err(Error::PendingOperation),
+ 13 => Err(Error::Done),
// SSL_ERROR_PENDING_TICKET
- 14 => Err(Error::PendingOperation),
+ 14 => Err(Error::Done),
_ => Err(Error::TlsFail),
}
diff --git a/tools/http3_test/.gitignore b/tools/http3_test/.gitignore
new file mode 100644
index 0000000..6936990
--- /dev/null
+++ b/tools/http3_test/.gitignore
@@ -0,0 +1,3 @@
+/target
+**/*.rs.bk
+Cargo.lock
diff --git a/tools/http3_test/Cargo.toml b/tools/http3_test/Cargo.toml
new file mode 100644
index 0000000..fa3be83
--- /dev/null
+++ b/tools/http3_test/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "http3_test"
+version = "0.1.0"
+authors = ["Lucas Pardue <lucaspardue.24.7@gmail.com>"]
+edition = "2018"
+publish = false
+
+[dependencies]
+docopt = "1"
+env_logger = "0.6"
+mio = "0.6"
+url = "1"
+log = "0.4"
+ring = "0.16"
+serde = "1.0"
+serde_json = "1.0"
+serde_derive = "1.0"
+quiche = { path = "../../"}
diff --git a/tools/http3_test/README.md b/tools/http3_test/README.md
new file mode 100644
index 0000000..666396d
--- /dev/null
+++ b/tools/http3_test/README.md
@@ -0,0 +1,24 @@
+This crate provides an API to build httpbin test requests and expected
+outcomes. These can be used with the quiche HTTP/3 module to
+communicate with an httpbin test server.
+
+Building
+--------
+
+```bash
+ $ cargo build
+```
+
+Running
+--------
+We use cargo test to execute different httpbin tests. By default this points to https://cloudflare-quic.com/b
+
+```bash
+ $ cargo test
+```
+
+To test a different server, use the HTTPBIN_ENDPOINT environment variable
+
+```bash
+ $ HTTPBIN_ENDPOINT=https://<some_other_endpoint> cargo test
+```
diff --git a/tools/http3_test/src/lib.rs b/tools/http3_test/src/lib.rs
new file mode 100644
index 0000000..cd6d0be
--- /dev/null
+++ b/tools/http3_test/src/lib.rs
@@ -0,0 +1,442 @@
+// Copyright (C) 2019, Cloudflare, Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+//! 🔧 HTTP/3 integration test utilities.
+//!
+//! This crate provides utilities to help integration tests against HTTP/3
+//! endpoints. Structures and methods can be combined with a [`quiche`]
+//! HTTP/3 client to run tests against a server. This client could be a
+//! binary or run as part of cargo test.
+//!
+//! ## Creating a test
+//!
+//! A test is an instance of [`Http3Test`], which consists of a set of
+//! [`Http3Req`] and a single [`Http3Assert`].
+//!
+//!
+//! Creating a single request:
+//!
+//! ```no_run
+//! let mut url = url::Url::parse("https://cloudflare-quic.com/b/get").unwrap();
+//! let mut reqs = Vec::new();
+//!
+//! reqs.push(http3_test::Http3Req::new("GET", &url, None, None));
+//! ```
+//!
+//! Assertions are used to check the received response headers and body
+//! against expectations. Each test has a [`Http3Assert`] which
+//! can access the received data. For example, to check the response
+//! status code is a 200 we could write the function:
+//!
+//! ```no_run
+//! fn assert_status(reqs: &[http3_test::Http3Req]) {
+//! let status = reqs[0]
+//! .resp_hdrs
+//! .iter()
+//! .find(|&x| x.name() == ":status")
+//! .unwrap();
+//! assert_eq!(status.value(), "200");
+//! }
+//! ```
+//!
+//! However, because checking response headers is so common, for convenience
+//! the expected headers can be provided during [`Http3Assert`] construction:
+//!
+//! ```no_run
+//! let mut url = url::Url::parse("https://cloudflare-quic.com/b/get").unwrap();
+//! let mut reqs = Vec::new();
+//!
+//! let expect_hdrs = Some(vec![quiche::h3::Header::new(":status", "200")]);
+//! reqs.push(http3_test::Http3Req::new("GET", &url, None, expect_hdrs));
+//! ```
+//!
+//! The [`assert_headers!`] macro can be used to validate the received headers,
+//! this means we can write a much simpler assertion:
+//!
+//! ```no_run
+//! fn assert_status(reqs: &[http3_test::Http3Req]) {
+//! http3_test::assert_headers!(reqs[0]);
+//! }
+//! ```
+//!
+//! Whatever methods you choose to use, once the requests and assertions are
+//! made we can create the test:
+//!
+//! ```no_run
+//! let mut url = url::Url::parse("https://cloudflare-quic.com/b/get").unwrap();
+//! let mut reqs = Vec::new();
+//!
+//! let expect_hdrs = Some(vec![quiche::h3::Header::new(":status", "200")]);
+//! reqs.push(http3_test::Http3Req::new("GET", &url, None, expect_hdrs));
+//!
+//! // Using a closure...
+//! let assert =
+//! |reqs: &[http3_test::Http3Req]| http3_test::assert_headers!(reqs[0]);
+//!
+//! let mut test = http3_test::Http3Test::new(url, reqs, assert, true);
+//! ```
+//!
+//! ## Sending test requests
+//!
+//! Testing a server requires a quiche connection and an HTTP/3 connection.
+//!
+//! Request are issued with the [`send_requests()`] method. The concurrency
+//! of requests within a single Http3Test is set in [`new()`]. If concurrency is
+//! disabled [`send_requests()`] will to send a single request and return.
+//! So call the method multiple times to issue more requests. Once all
+//! requests have been sent, further calls will return `quiche::h3:Error::Done`.
+//!
+//! Example:
+//! ```no_run
+//! # let mut url = url::Url::parse("https://cloudflare-quic.com/b/get").unwrap();
+//! # let mut reqs = Vec::new();
+//! # let expect_hdrs = Some(vec![quiche::h3::Header::new(":status", "200")]);
+//! # reqs.push(http3_test::Http3Req::new("GET", &url, None, expect_hdrs));
+//! # // Using a closure...
+//! # let assert = |reqs: &[http3_test::Http3Req]| {
+//! # http3_test::assert_headers!(reqs[0]);
+//! # };
+//! let mut test = http3_test::Http3Test::new(url, reqs, assert, true);
+//!
+//! let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
+//! let scid = [0xba; 16];
+//! let mut conn = quiche::connect(None, &scid, &mut config).unwrap();
+//! let h3_config = quiche::h3::Config::new()?;
+//! let mut http3_conn = quiche::h3::Connection::with_transport(&mut conn, &h3_config)?;
+//!
+//! test.send_requests(&mut conn, &mut http3_conn).unwrap();
+//! # Ok::<(), quiche::h3::Error>(())
+//! ```
+//!
+//! ## Handling responses
+//!
+//! Response data is used to validate test cases so it is important to
+//! store received data in the test object. This can be done with the
+//! [`add_response_headers()`] and [`add_response_body()`] methods. Note
+//! that the stream ID is used to correlate the response with the correct
+//! request.
+//!
+//! For example, when handling HTTP/3 connection events using `poll()`:
+//!
+//! ```no_run
+//! # let mut url = url::Url::parse("https://cloudflare-quic.com/b/get").unwrap();
+//! # let mut reqs = Vec::new();
+//! # let expect_hdrs = Some(vec![quiche::h3::Header::new(":status", "200")]);
+//! # reqs.push(http3_test::Http3Req::new("GET", &url, None, expect_hdrs));
+//! # // Using a closure...
+//! # let assert = |reqs: &[http3_test::Http3Req]| {
+//! # http3_test::assert_headers!(reqs[0]);
+//! # };
+//! # let mut test = http3_test::Http3Test::new(url, reqs, assert, true);
+//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
+//! # let scid = [0xba; 16];
+//! # let mut conn = quiche::connect(None, &scid, &mut config).unwrap();
+//! # let h3_config = quiche::h3::Config::new()?;
+//! # let mut http3_conn = quiche::h3::Connection::with_transport(&mut conn, &h3_config)?;
+//! match http3_conn.poll(&mut conn) {
+//! Ok((stream_id, quiche::h3::Event::Headers(headers))) => {
+//! test.add_response_headers(stream_id, &headers);
+//! },
+//!
+//! Ok((stream_id, quiche::h3::Event::Data)) => {
+//! let mut buf = [0; 65535];
+//! if let Ok(read) = http3_conn.recv_body(&mut conn, stream_id, &mut buf)
+//! {
+//! test.add_response_body(stream_id, &buf, read);
+//! }
+//! },
+//!
+//! _ => ()
+//! }
+//! # Ok::<(), quiche::h3::Error>(())
+//! ```
+//!
+//! ## Tests assertion
+//!
+//! The [`assert()`] method executes the provided test assertion using the
+//! entire set of [`Http3Req`]s. Calling this prematurely is likely to result
+//! in failure, so it is important to store response data and track the number
+//! of completed requests matches the total for a test.
+//!
+//! ```no_run
+//! # let mut url = url::Url::parse("https://cloudflare-quic.com/b/get").unwrap();
+//! # let mut reqs = Vec::new();
+//! # let expect_hdrs = Some(vec![quiche::h3::Header::new(":status", "200")]);
+//! # reqs.push(http3_test::Http3Req::new("GET", &url, None, expect_hdrs));
+//! # // Using a closure...
+//! # let assert = |reqs: &[http3_test::Http3Req]| {
+//! # http3_test::assert_headers!(reqs[0]);
+//! # };
+//! # let mut test = http3_test::Http3Test::new(url, reqs, assert, true);
+//! # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
+//! # let scid = [0xba; 16];
+//! # let mut conn = quiche::connect(None, &scid, &mut config).unwrap();
+//! # let h3_config = quiche::h3::Config::new()?;
+//! # let mut http3_conn = quiche::h3::Connection::with_transport(&mut conn, &h3_config)?;
+//! let mut requests_complete = 0;
+//! let request_count = test.requests_count();
+//! match http3_conn.poll(&mut conn) {
+//! Ok((_stream_id, quiche::h3::Event::Finished)) => {
+//! requests_complete += 1;
+//! if requests_complete == request_count {
+//! test.assert()
+//! }
+//! },
+//! _ => ()
+//! }
+//! # Ok::<(), quiche::h3::Error>(())
+//! ```
+//!
+//! [`quiche`]: https://github.com/cloudflare/quiche/
+//! [test]: struct.Http3Test.html
+//! [`Http3Test`]: struct.Http3Test.html
+//! [`Http3Assert`]: struct.Http3Assert.html
+//! [`Http3req`]: struct.Http3Req.html
+//! [`assert_headers!`]: macro.assert_headers.html
+//! [`new()`]: struct.Http3Test.html#method.new
+//! [`send_requests()`]: struct.Http3Test.html#method.send_requests
+//! [`requests_count()`]: struct.Http3Test.html#method.requests_count
+//! [`assert()`]: struct.Http3Test.html#method.assert
+//! [`add_response_headers()`]:
+//! struct.Http3Test.html#method.add_response_headers [`add_response_body()`]:
+//! struct.Http3Test.html#method.add_response_body
+
+#[macro_use]
+extern crate log;
+
+use std::collections::HashMap;
+
+use quiche::h3::Header;
+
+pub const USER_AGENT: &str = "quiche-http3-integration-client";
+
+/// Stores the request, the expected response headers, and the actual response.
+///
+/// The assert_headers! macro is provided for convenience to validate the
+/// received headers match the expected headers.
+#[derive(Clone)]
+pub struct Http3Req {
+ pub url: url::Url,
+ pub hdrs: Vec<Header>,
+ body: Option<Vec<u8>>,
+ pub expect_resp_hdrs: Option<Vec<Header>>,
+ pub resp_hdrs: Vec<Header>,
+ pub resp_body: Vec<u8>,
+}
+
+impl Http3Req {
+ pub fn new(
+ method: &str, url: &url::Url, body: Option<Vec<u8>>,
+ expect_resp_hdrs: Option<Vec<Header>>,
+ ) -> Http3Req {
+ let mut path = String::from(url.path());
+ if let Some(query) = url.query() {
+ path.push('?');
+ path.push_str(query);
+ }
+
+ let mut hdrs = vec![
+ Header::new(":method", method),
+ Header::new(":scheme", url.scheme()),
+ Header::new(":authority", url.host_str().unwrap()),
+ Header::new(":path", &path),
+ Header::new("user-agent", USER_AGENT),
+ ];
+
+ if let Some(body) = &body {
+ hdrs.push(Header::new("content-length", &body.len().to_string()));
+ }
+
+ Http3Req {
+ url: url.clone(),
+ hdrs,
+ body,
+ expect_resp_hdrs: expect_resp_hdrs.clone(),
+ resp_hdrs: Vec::new(),
+ resp_body: Vec::new(),
+ }
+ }
+}
+
+/// Asserts that the Http3Req received response headers match the expected
+/// response headers.
+///
+/// Header values are compared with [`assert_eq!`] and this macro will panic
+/// similarly.
+///
+/// If an expected header is not present this macro will panic and print the
+/// missing header name.AsMut
+///
+/// [`assert_eq!`]: std/macro.assert.html
+#[macro_export]
+macro_rules! assert_headers {
+ ($req:expr) => ({
+ if let Some(expect_hdrs) = &$req.expect_resp_hdrs {
+ for hdr in expect_hdrs {
+ match $req.resp_hdrs.iter().find(|&x| x.name() == hdr.name()) {
+ Some(h) => { assert_eq!(hdr.value(), h.value());},
+
+ None => {
+ panic!(format!("assertion failed: expected response header field {} not present!", hdr.name()));
+ }
+ }
+ }
+ }
+ });
+ ($req:expr,) => ({ $crate::assert_headers!($req)});
+ ($req:expr, $($arg:tt)+) => ({
+ if let Some(expect_hdrs) = &$req.expect_resp_hdrs {
+ for hdr in expect_hdrs {
+ match $req.resp_hdrs.iter().find(|&x| x.name() == hdr.name()) {
+ Some(h) => { assert_eq!(hdr.value(), h.value(), $($arg)+);},
+
+ None => {
+ panic!(format!("assertion failed: expected response header field {} not present! {}", hdr.name(), $($arg)+));
+ }
+ }
+ }
+ }
+ });
+}
+
+/// A helper function pointer type for assertions.
+///
+/// Each test assertion can check the set of Http3Req
+/// however they like.
+pub type Http3Assert = fn(&[Http3Req]);
+
+/// The main object for getting things done.
+///
+/// The factory method new() is used to set up a vector of Http3Req objects and
+/// map them to a test assertion function. The public functions are used to send
+/// requests and store response data. Internally we track some other state to
+/// make sure everything goes smoothly.
+///
+/// Many tests have similar inputs or assertions, so utility functions help
+/// cover many of the common cases like testing different status codes or
+/// checking that a response body is echoed back.
+pub struct Http3Test {
+ endpoint: url::Url,
+ reqs: Vec<Http3Req>,
+ assert: Http3Assert,
+ issued_reqs: HashMap<u64, usize>,
+ concurrent: bool,
+ current_idx: usize,
+}
+
+impl Http3Test {
+ pub fn new(
+ endpoint: url::Url, reqs: Vec<Http3Req>, assert: Http3Assert,
+ concurrent: bool,
+ ) -> Http3Test {
+ Http3Test {
+ endpoint,
+ reqs,
+ assert,
+ issued_reqs: HashMap::new(),
+ concurrent,
+ current_idx: 0,
+ }
+ }
+
+ /// Returns the total number of requests in a test.
+ pub fn requests_count(&mut self) -> usize {
+ self.reqs.len()
+ }
+
+ pub fn endpoint(&self) -> url::Url {
+ self.endpoint.clone()
+ }
+
+ /// Send one or more requests based on test type and the concurrency
+ /// property. If any send fails, a quiche::h3::Error is returned.
+ pub fn send_requests(
+ &mut self, conn: &mut quiche::Connection,
+ h3_conn: &mut quiche::h3::Connection,
+ ) -> quiche::h3::Result<()> {
+ if self.reqs.len() - self.current_idx == 0 {
+ return Err(quiche::h3::Error::Done);
+ }
+
+ let reqs_to_make = if self.concurrent {
+ self.reqs.len() - self.current_idx
+ } else {
+ 1
+ };
+
+ for _ in 0..reqs_to_make {
+ let req = &self.reqs[self.current_idx];
+
+ info!("sending HTTP request {:?}", req.hdrs);
+
+ let s =
+ match h3_conn.send_request(conn, &req.hdrs, req.body.is_none()) {
+ Ok(stream_id) => stream_id,
+
+ Err(e) => {
+ error!("failed to send request {:?}", e);
+ return Err(e);
+ },
+ };
+
+ self.issued_reqs.insert(s, self.current_idx);
+
+ if let Some(body) = &req.body {
+ info!("sending body {:?}", body);
+
+ if let Err(e) = h3_conn.send_body(conn, s, body, true) {
+ error!("failed to send request body {:?}", e);
+ return Err(e);
+ }
+ }
+
+ self.current_idx += 1;
+ }
+
+ Ok(())
+ }
+
+ /// Append response headers for an issued request.
+ pub fn add_response_headers(&mut self, stream_id: u64, headers: &[Header]) {
+ let i = self.issued_reqs.get(&stream_id).unwrap();
+ self.reqs[*i].resp_hdrs.extend_from_slice(headers);
+ }
+
+ /// Append data to the response body for an issued request.
+ pub fn add_response_body(
+ &mut self, stream_id: u64, data: &[u8], data_len: usize,
+ ) {
+ let i = self.issued_reqs.get(&stream_id).unwrap();
+ self.reqs[*i].resp_body.extend_from_slice(&data[..data_len]);
+ }
+
+ /// Execute the test assertion(s).
+ pub fn assert(&mut self) {
+ (self.assert)(&self.reqs);
+ }
+}
+
+pub mod runner;
diff --git a/tools/http3_test/src/runner.rs b/tools/http3_test/src/runner.rs
new file mode 100644
index 0000000..e919f96
--- /dev/null
+++ b/tools/http3_test/src/runner.rs
@@ -0,0 +1,323 @@
+// Copyright (C) 2019, Cloudflare, Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+use ring::rand::*;
+
+pub fn run(
+ test: &mut crate::Http3Test, peer_addr: std::net::SocketAddr,
+ verify_peer: bool, idle_timeout: u64,
+) {
+ const MAX_DATAGRAM_SIZE: usize = 1350;
+
+ let mut buf = [0; 65535];
+ let mut out = [0; MAX_DATAGRAM_SIZE];
+
+ let max_data = 1_000_000;
+
+ let max_stream_data = 1_000_000;
+
+ let version = "babababa";
+ let version = u32::from_str_radix(version, 16).unwrap();
+
+ let mut reqs_count = 0;
+
+ let mut reqs_complete = 0;
+
+ // Setup the event loop.
+ let poll = mio::Poll::new().unwrap();
+ let mut events = mio::Events::with_capacity(1024);
+
+ info!("connecting to {:}", peer_addr);
+
+ // Bind to INADDR_ANY or IN6ADDR_ANY depending on the IP family of the
+ // server address. This is needed on macOS and BSD variants that don't
+ // support binding to IN6ADDR_ANY for both v4 and v6.
+ let bind_addr = match peer_addr {
+ std::net::SocketAddr::V4(_) => "0.0.0.0:0",
+ std::net::SocketAddr::V6(_) => "[::]:0",
+ };
+
+ // Create the UDP socket backing the QUIC connection, and register it with
+ // the event loop.
+ let socket = std::net::UdpSocket::bind(bind_addr).unwrap();
+ socket.connect(peer_addr).unwrap();
+
+ let socket = mio::net::UdpSocket::from_socket(socket).unwrap();
+ poll.register(
+ &socket,
+ mio::Token(0),
+ mio::Ready::readable(),
+ mio::PollOpt::edge(),
+ )
+ .unwrap();
+
+ // Create the configuration for the QUIC connection.
+ let mut config = quiche::Config::new(version).unwrap();
+
+ config.verify_peer(verify_peer);
+
+ config
+ .set_application_protos(quiche::h3::APPLICATION_PROTOCOL)
+ .unwrap();
+
+ config.set_idle_timeout(idle_timeout);
+ config.set_max_packet_size(MAX_DATAGRAM_SIZE as u64);
+ config.set_initial_max_data(max_data);
+ config.set_initial_max_stream_data_bidi_local(max_stream_data);
+ config.set_initial_max_stream_data_bidi_remote(max_stream_data);
+ config.set_initial_max_stream_data_uni(max_stream_data);
+ config.set_initial_max_streams_bidi(100);
+ config.set_initial_max_streams_uni(100);
+ config.set_disable_active_migration(true);
+
+ let mut http3_conn = None;
+
+ if std::env::var_os("SSLKEYLOGFILE").is_some() {
+ config.log_keys();
+ }
+
+ // Generate a random source connection ID for the connection.
+ let mut scid = [0; quiche::MAX_CONN_ID_LEN];
+ SystemRandom::new().fill(&mut scid[..]).unwrap();
+
+ // Create a QUIC connection and initiate handshake.
+ let url = &test.endpoint();
+ let mut conn = quiche::connect(url.domain(), &scid, &mut config).unwrap();
+
+ let write = match conn.send(&mut out) {
+ Ok(v) => v,
+
+ Err(e) => panic!("initial send failed: {:?}", e),
+ };
+
+ while let Err(e) = socket.send(&out[..write]) {
+ if e.kind() == std::io::ErrorKind::WouldBlock {
+ debug!("send() would block");
+ continue;
+ }
+
+ panic!("send() failed: {:?}", e);
+ }
+
+ debug!("written {}", write);
+
+ let req_start = std::time::Instant::now();
+
+ loop {
+ poll.poll(&mut events, conn.timeout()).unwrap();
+
+ // Read incoming UDP packets from the socket and feed them to quiche,
+ // until there are no more packets to read.
+ 'read: loop {
+ // If the event loop reported no events, it means that the timeout
+ // has expired, so handle it without attempting to read packets. We
+ // will then proceed with the send loop.
+ if events.is_empty() {
+ debug!("timed out");
+
+ conn.on_timeout();
+
+ break 'read;
+ }
+
+ let len = match socket.recv(&mut buf) {
+ Ok(v) => v,
+
+ Err(e) => {
+ // There are no more UDP packets to read, so end the read
+ // loop.
+ if e.kind() == std::io::ErrorKind::WouldBlock {
+ debug!("recv() would block");
+ break 'read;
+ }
+
+ panic!("recv() failed: {:?}", e);
+ },
+ };
+
+ debug!("got {} bytes", len);
+
+ // Process potentially coalesced packets.
+ let read = match conn.recv(&mut buf[..len]) {
+ Ok(v) => v,
+
+ Err(quiche::Error::Done) => {
+ debug!("done reading");
+ break;
+ },
+
+ Err(e) => {
+ error!("recv failed: {:?}", e);
+ break 'read;
+ },
+ };
+
+ debug!("processed {} bytes", read);
+ }
+
+ if conn.is_closed() {
+ info!("connection closed, {:?}", conn.stats());
+
+ if reqs_complete != reqs_count {
+ panic!("Client timed out after {:?} and only completed {}/{} requests",
+ req_start.elapsed(), reqs_complete, reqs_count);
+ }
+
+ break;
+ }
+
+ // Create a new HTTP/3 connection and end an HTTP request as soon as
+ // the QUIC connection is established.
+ if conn.is_established() && http3_conn.is_none() {
+ let h3_config = quiche::h3::Config::new().unwrap();
+
+ let mut h3_conn =
+ quiche::h3::Connection::with_transport(&mut conn, &h3_config)
+ .unwrap();
+
+ reqs_count = test.requests_count();
+
+ test.send_requests(&mut conn, &mut h3_conn).unwrap();
+
+ http3_conn = Some(h3_conn);
+ }
+
+ if let Some(http3_conn) = &mut http3_conn {
+ // Process HTTP/3 events.
+ loop {
+ match http3_conn.poll(&mut conn) {
+ Ok((stream_id, quiche::h3::Event::Headers(headers))) => {
+ info!(
+ "got response headers {:?} on stream id {}",
+ headers, stream_id
+ );
+
+ test.add_response_headers(stream_id, &headers);
+ },
+
+ Ok((stream_id, quiche::h3::Event::Data)) => {
+ if let Ok(read) =
+ http3_conn.recv_body(&mut conn, stream_id, &mut buf)
+ {
+ info!(
+ "got {} bytes of response data on stream {}",
+ read, stream_id
+ );
+
+ test.add_response_body(stream_id, &buf, read);
+ }
+ },
+
+ Ok((_stream_id, quiche::h3::Event::Finished)) => {
+ reqs_complete += 1;
+
+ info!(
+ "{}/{} responses received",
+ reqs_complete, reqs_count
+ );
+
+ if reqs_complete == reqs_count {
+ info!(
+ "Completed test run. {}/{} response(s) received in {:?}, closing...",
+ reqs_complete,
+ reqs_count,
+ req_start.elapsed()
+ );
+
+ match conn.close(true, 0x00, b"kthxbye") {
+ // Already closed.
+ Ok(_) | Err(quiche::Error::Done) => (),
+
+ Err(e) => panic!("error closing conn: {:?}", e),
+ }
+
+ test.assert();
+
+ break;
+ }
+
+ match test.send_requests(&mut conn, http3_conn) {
+ Ok(_) => (),
+ Err(quiche::h3::Error::Done) => (),
+ Err(e) => panic!("error sending request {:?}", e),
+ }
+ },
+
+ Err(quiche::h3::Error::Done) => {
+ break;
+ },
+
+ Err(e) => {
+ error!("HTTP/3 processing failed: {:?}", e);
+
+ break;
+ },
+ }
+ }
+ }
+
+ // Generate outgoing QUIC packets and send them on the UDP socket, until
+ // quiche reports that there are no more packets to be sent.
+ loop {
+ let write = match conn.send(&mut out) {
+ Ok(v) => v,
+
+ Err(quiche::Error::Done) => {
+ debug!("done writing");
+ break;
+ },
+
+ Err(e) => {
+ error!("send failed: {:?}", e);
+ conn.close(false, 0x1, b"fail").ok();
+ break;
+ },
+ };
+
+ if let Err(e) = socket.send(&out[..write]) {
+ if e.kind() == std::io::ErrorKind::WouldBlock {
+ debug!("send() would block");
+ break;
+ }
+
+ panic!("send() failed: {:?}", e);
+ }
+
+ debug!("written {}", write);
+ }
+
+ if conn.is_closed() {
+ info!("connection closed, {:?}", conn.stats());
+
+ if reqs_complete != reqs_count {
+ panic!("Client timed out after {:?} and only completed {}/{} requests",
+ req_start.elapsed(), reqs_complete, reqs_count);
+ }
+
+ break;
+ }
+ }
+}
diff --git a/tools/http3_test/tests/httpbin_tests.rs b/tools/http3_test/tests/httpbin_tests.rs
new file mode 100644
index 0000000..6ce997d
--- /dev/null
+++ b/tools/http3_test/tests/httpbin_tests.rs
@@ -0,0 +1,718 @@
+mod httpbin_tests {
+ use std::collections::HashMap;
+ use std::net::ToSocketAddrs;
+
+ use http3_test::*;
+ use quiche::h3::*;
+
+ use std::sync::Once;
+
+ static INIT: Once = Once::new();
+
+ fn endpoint(testpoint: Option<&str>) -> url::Url {
+ let endpoint = match std::env::var_os("HTTPBIN_ENDPOINT") {
+ Some(val) => val.into_string().unwrap(),
+
+ None => String::from("https://cloudflare-quic.com/b"),
+ };
+
+ let mut url = url::Url::parse(&endpoint).unwrap();
+
+ if let Some(testpoint) = testpoint {
+ let path = format!("{}/{}", url.path(), &testpoint);
+ url.set_path(&path);
+ }
+
+ url
+ }
+
+ fn host() -> std::net::SocketAddr {
+ let url = match std::env::var_os("HTTPBIN_HOST") {
+ Some(val) => {
+ let host = val.into_string().unwrap();
+ let url = format!("{}{}", "https://", host);
+
+ url::Url::parse(&url).unwrap()
+ },
+
+ None => endpoint(None),
+ };
+
+ url.to_socket_addrs().unwrap().next().unwrap()
+ }
+
+ fn verify_peer() -> bool {
+ match std::env::var_os("VERIFY_PEER") {
+ Some(val) => match val.to_str().unwrap() {
+ "false" => {
+ return false;
+ },
+
+ _ => {
+ return true;
+ },
+ },
+
+ None => {
+ return true;
+ },
+ };
+ }
+
+ fn idle_timeout() -> u64 {
+ match std::env::var_os("IDLE_TIMEOUT") {
+ Some(val) =>
+ u64::from_str_radix(&val.into_string().unwrap(), 10).unwrap(),
+
+ None => 60000,
+ }
+ }
+
+ // A rudimentary structure to hold httpbin response data
+ #[derive(Debug, serde::Deserialize)]
+ struct HttpBinResponseBody {
+ args: Option<HashMap<String, String>>,
+ data: Option<String>,
+ files: Option<HashMap<String, String>>,
+ form: Option<HashMap<String, String>>,
+ headers: Option<HashMap<String, String>>,
+ json: Option<HashMap<String, String>>,
+ #[serde(rename = "user-agent")]
+ user_agent: Option<String>,
+ server: Option<String>,
+ #[serde(rename = "content-type")]
+ content_type: Option<Vec<String>>,
+ origin: Option<String>,
+ url: Option<String>,
+ }
+
+ fn jsonify(data: &[u8]) -> HttpBinResponseBody {
+ serde_json::from_slice(&data).unwrap()
+ }
+
+ fn do_test(reqs: Vec<Http3Req>, assert: Http3Assert, concurrent: bool) {
+ INIT.call_once(|| {
+ env_logger::builder()
+ .default_format_timestamp_nanos(true)
+ .init()
+ });
+
+ let mut test = Http3Test::new(endpoint(None), reqs, assert, concurrent);
+ runner::run(&mut test, host(), verify_peer(), idle_timeout());
+ }
+
+ // Build a single request and expected response with status code
+ fn request_check_status(testpoint: &str, status: usize) -> Vec<Http3Req> {
+ let expect_hdrs = Some(vec![Header::new(":status", &status.to_string())]);
+
+ let url = endpoint(Some(testpoint));
+
+ vec![Http3Req::new("GET", &url, None, expect_hdrs)]
+ }
+
+ // Build a single request with a simple JSON body using the provided method
+ fn request_with_body(method: &str) -> Vec<Http3Req> {
+ let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+
+ let url = endpoint(Some(&method.to_ascii_lowercase()));
+
+ let req_body = serde_json::json!({"key1": "value1", "key2": "value2"});
+
+ let mut req = Http3Req::new(
+ &method.to_ascii_uppercase(),
+ &url,
+ Some(req_body.to_string().into_bytes()),
+ expect_hdrs,
+ );
+
+ req.hdrs
+ .push(Header::new("content-type", "application/json"));
+
+ vec![req]
+ }
+
+ fn assert_request_body(reqs: &[Http3Req]) {
+ assert_headers!(reqs[0]);
+
+ let json = jsonify(&reqs[0].resp_body).json.unwrap();
+
+ assert_eq!(json["key1"], "value1");
+ assert_eq!(json["key2"], "value2");
+ }
+
+ fn assert_headers_only(reqs: &[Http3Req]) {
+ for req in reqs {
+ assert_headers!(req);
+ }
+ }
+
+ #[test]
+ fn get() {
+ let mut reqs = Vec::new();
+ let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+
+ let mut url = endpoint(Some("get"));
+
+ // Request 1
+ reqs.push(Http3Req::new("GET", &url, None, expect_hdrs.clone()));
+
+ // Request 2
+ url.set_query(Some("key1=value1&key2=value2"));
+ reqs.push(Http3Req::new("GET", &url, None, expect_hdrs.clone()));
+
+ let assert = |reqs: &[Http3Req]| {
+ assert_headers!(reqs[0]);
+ assert_headers!(reqs[1]);
+
+ let json = jsonify(&reqs[1].resp_body);
+ if let Some(args) = json.args {
+ assert_eq!(args["key1"], "value1");
+ assert_eq!(args["key2"], "value2")
+ }
+ };
+
+ do_test(reqs, assert, true);
+ }
+
+ #[test]
+ fn ip() {
+ let reqs = request_check_status("ip", 200);
+
+ let assert = |reqs: &[Http3Req]| {
+ assert_headers!(reqs[0]);
+
+ let json = jsonify(&reqs[0].resp_body);
+ assert!(json.origin.is_some())
+ };
+
+ do_test(reqs, assert, true);
+ }
+
+ #[test]
+ fn useragent() {
+ let reqs = request_check_status("user-agent", 200);
+
+ let assert = |reqs: &[Http3Req]| {
+ assert_headers!(reqs[0]);
+
+ let json = jsonify(&reqs[0].resp_body);
+ assert_eq!(json.user_agent, Some(USER_AGENT.to_string()));
+ };
+
+ do_test(reqs, assert, true);
+ }
+
+ #[test]
+ fn headers() {
+ let reqs = request_check_status("headers", 200);
+
+ let assert = |reqs: &[Http3Req]| {
+ assert_headers!(reqs[0]);
+
+ let json = jsonify(&reqs[0].resp_body);
+ if let Some(args) = json.args {
+ assert_eq!(args["Host"], reqs[0].url.host_str().unwrap());
+ }
+ };
+
+ do_test(reqs, assert, true);
+ }
+
+ #[test]
+ fn post() {
+ let reqs = request_with_body("post");
+ do_test(reqs, assert_request_body, true);
+ }
+
+ #[test]
+ fn put() {
+ let reqs = request_with_body("put");
+ do_test(reqs, assert_request_body, true);
+ }
+
+ #[test]
+ fn patch() {
+ let reqs = request_with_body("patch");
+ do_test(reqs, assert_request_body, true);
+ }
+
+ #[test]
+ fn delete() {
+ let reqs = request_with_body("delete");
+ do_test(reqs, assert_request_body, true);
+ }
+
+ #[test]
+ fn encode_utf8() {
+ let mut reqs = Vec::new();
+
+ let expect_hdrs = Some(vec![
+ Header::new(":status", "200"),
+ Header::new("content-type", "text/html; charset=utf-8"),
+ ]);
+
+ let url = endpoint(Some("encoding/utf8"));
+
+ reqs.push(Http3Req::new("GET", &url, None, expect_hdrs));
+
+ do_test(reqs, assert_headers_only, true);
+ }
+
+ #[test]
+ fn gzip() {
+ let mut reqs = Vec::new();
+
+ let expect_hdrs = Some(vec![
+ Header::new(":status", "200"),
+ Header::new("content-encoding", "gzip"),
+ ]);
+
+ let url = endpoint(Some("gzip"));
+
+ let mut req = Http3Req::new("GET", &url, None, expect_hdrs);
+ req.hdrs.push(Header::new("accept-encoding", "gzip"));
+
+ reqs.push(req);
+
+ do_test(reqs, assert_headers_only, true);
+ }
+
+ #[test]
+ fn deflate() {
+ let mut reqs = Vec::new();
+
+ // Not all servers actually take up the deflate option,
+ // so don't check content-type response header.
+ let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+
+ let url = endpoint(Some("deflate"));
+
+ let mut req = Http3Req::new("GET", &url, None, expect_hdrs);
+ req.hdrs.push(Header::new("accept-encoding", "deflate"));
+ reqs.push(req);
+
+ do_test(reqs, assert_headers_only, true);
+ }
+
+ #[test]
+ fn status() {
+ let mut reqs = Vec::new();
+
+ for i in (200..600).step_by(100) {
+ for j in 0..5 {
+ let expect_hdrs =
+ Some(vec![Header::new(":status", &(i + j).to_string())]);
+
+ let testpoint = format!("{}/{}", "status", i + j);
+ let url = endpoint(Some(&testpoint));
+
+ reqs.push(Http3Req::new("GET", &url, None, expect_hdrs));
+ }
+ }
+
+ do_test(reqs, assert_headers_only, false);
+ }
+
+ #[test]
+ fn response_headers() {
+ let mut reqs = Vec::new();
+ let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+
+ let mut url = endpoint(Some("response-headers"));
+ url.set_query(Some(
+ "content-type=text/plain;+charset=UTF-8&server=httpbin",
+ ));
+ reqs.push(Http3Req::new("GET", &url, None, expect_hdrs));
+
+ let assert = |reqs: &[Http3Req]| {
+ assert_headers!(reqs[0]);
+ let json = jsonify(&reqs[0].resp_body);
+
+ let server = json.server.unwrap();
+ assert_eq!(server, "httpbin");
+
+ let content_type = json.content_type.unwrap();
+ assert_eq!(content_type[0], "application/json");
+ assert_eq!(content_type[1], "text/plain; charset=UTF-8");
+ };
+
+ do_test(reqs, assert, true);
+ }
+
+ #[test]
+ fn redirect() {
+ let mut reqs = Vec::new();
+ let mut url = endpoint(Some("redirect-to"));
+
+ // Request 1
+ let expect_hdrs = Some(vec![
+ Header::new(":status", "302"),
+ Header::new("location", "https://example.com"),
+ ]);
+
+ url.set_query(Some("url=https://example.com"));
+
+ reqs.push(Http3Req::new("GET", &url, None, expect_hdrs));
+
+ // Request 2
+ let expect_hdrs = Some(vec![
+ Header::new(":status", "307"),
+ Header::new("location", "https://example.com"),
+ ]);
+ url.set_query(Some("url=https://example.com&status_code=307"));
+
+ reqs.push(Http3Req::new("GET", &url, None, expect_hdrs));
+
+ // Request 3
+ let expect_hdrs = Some(vec![Header::new(":status", "302")]);
+ let url = endpoint(Some("relative-redirect/3"));
+ reqs.push(Http3Req::new("GET", &url, None, expect_hdrs));
+
+ do_test(reqs, assert_headers_only, true);
+ }
+
+ #[test]
+ fn cookies() {
+ // Tests cookie redirect cases since the client ignores cookies
+ let mut reqs = Vec::new();
+
+ // Request 1
+ let expect_hdrs = Some(vec![Header::new(":status", "302")]);
+ let mut url = endpoint(Some("cookies/set"));
+ url.set_query(Some("k1=v1"));
+
+ reqs.push(Http3Req::new("GET", &url, None, expect_hdrs));
+
+ // Request 2
+ let expect_hdrs = Some(vec![Header::new(":status", "302")]);
+
+ let mut url = endpoint(Some("cookies/set"));
+ url.set_query(Some("k1=v1"));
+
+ reqs.push(Http3Req::new("GET", &url, None, expect_hdrs));
+
+ do_test(reqs, assert_headers_only, true);
+ }
+
+ #[test]
+ fn basic_auth() {
+ let mut reqs = Vec::new();
+ let url = endpoint(Some("basic-auth/user/passwd"));
+
+ let expect_hdrs = Some(vec![
+ Header::new(":status", "401"),
+ Header::new("www-authenticate", "Basic realm=\"Fake Realm\""),
+ ]);
+
+ reqs.push(Http3Req::new("GET", &url, None, expect_hdrs));
+
+ do_test(reqs, assert_headers_only, true);
+ }
+
+ #[test]
+ fn stream() {
+ let mut reqs = Vec::new();
+
+ let sizes = [1, 50, 100];
+
+ for size in &sizes {
+ let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+
+ let testpoint = format!("{}/{}", "stream", size.to_string());
+
+ let url = endpoint(Some(&testpoint));
+
+ reqs.push(Http3Req::new("GET", &url, None, expect_hdrs));
+ }
+
+ let assert = |reqs: &[Http3Req]| {
+ assert_headers!(reqs[0]);
+ assert_headers!(reqs[1]);
+ assert_headers!(reqs[2]);
+
+ let line_count = std::str::from_utf8(&reqs[0].resp_body)
+ .unwrap()
+ .matches('\n')
+ .count();
+ assert_eq!(line_count, 1);
+
+ let line_count = std::str::from_utf8(&reqs[1].resp_body)
+ .unwrap()
+ .matches('\n')
+ .count();
+ assert_eq!(line_count, 50);
+
+ let line_count = std::str::from_utf8(&reqs[2].resp_body)
+ .unwrap()
+ .matches('\n')
+ .count();
+ assert_eq!(line_count, 100);
+ };
+
+ do_test(reqs, assert, true);
+ }
+
+ #[test]
+ fn delay() {
+ let mut reqs = Vec::new();
+
+ let delays = [1, 10, 30];
+
+ for delay in &delays {
+ let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+
+ let testpoint = format!("{}/{}", "delay", delay);
+ let url = endpoint(Some(&testpoint));
+
+ reqs.push(Http3Req::new("GET", &url, None, expect_hdrs));
+ }
+
+ do_test(reqs, assert_headers_only, false);
+ }
+
+ #[test]
+ fn drip() {
+ let mut reqs = Vec::new();
+
+ let durations = [1, 10, 30];
+
+ for duration in &durations {
+ let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+
+ let mut url = endpoint(Some("drip"));
+ url.set_query(Some(&format!(
+ "duration={}&numbytes=5&code=200",
+ duration
+ )));
+
+ reqs.push(Http3Req::new("GET", &url, None, expect_hdrs));
+ }
+
+ do_test(reqs, assert_headers_only, false);
+ }
+
+ #[test]
+ fn range() {
+ let mut reqs = Vec::new();
+
+ // Request 1
+ let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+
+ let url = endpoint(Some("range/102400"));
+
+ let req = Http3Req::new("GET", &url, None, expect_hdrs);
+ reqs.push(req);
+
+ // Request 2
+ let expect_hdrs = Some(vec![
+ Header::new(":status", "206"),
+ Header::new("content-range", "bytes 0-49/102400"),
+ ]);
+
+ let mut req = Http3Req::new("GET", &url, None, expect_hdrs);
+ req.hdrs.push(Header::new("range", "bytes=0-49"));
+ reqs.push(req);
+
+ // Request 3
+ let expect_hdrs = Some(vec![
+ Header::new(":status", "206"),
+ Header::new("content-range", "bytes 100-10000/102400"),
+ ]);
+ let mut req = Http3Req::new("GET", &url, None, expect_hdrs);
+ req.hdrs.push(Header::new("range", "bytes=100-10000"));
+ reqs.push(req);
+
+ do_test(reqs, assert_headers_only, true);
+ }
+
+ #[test]
+ fn cache() {
+ let mut reqs = Vec::new();
+
+ // Request 1
+ let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+
+ let url = endpoint(Some("cache"));
+
+ let req = Http3Req::new("GET", &url, None, expect_hdrs);
+ reqs.push(req);
+
+ // Request 2
+ let expect_hdrs = Some(vec![Header::new(":status", "304")]);
+
+ let mut req = Http3Req::new("GET", &url, None, expect_hdrs);
+ req.hdrs.push(Header::new(
+ "if-modified-since",
+ "Wed, 21 Oct 2015 07:28:00 GMT",
+ ));
+ reqs.push(req);
+
+ // Request 3
+ let expect_hdrs = Some(vec![Header::new(":status", "304")]);
+ let mut req = Http3Req::new("GET", &url, None, expect_hdrs);
+ req.hdrs.push(Header::new("if-none-match", "*"));
+ reqs.push(req);
+
+ do_test(reqs, assert_headers_only, true);
+ }
+
+ #[test]
+ fn bytes() {
+ let mut reqs = Vec::new();
+
+ let sizes = [10, 100, 1000, 10000, 100_000];
+
+ for size in &sizes {
+ let expect_hdrs = Some(vec![
+ Header::new(":status", "200"),
+ Header::new("content-length", &size.to_string()),
+ ]);
+
+ let testpoint = format!("{}/{}", "bytes", size.to_string());
+ let url = endpoint(Some(&testpoint));
+
+ reqs.push(Http3Req::new("GET", &url, None, expect_hdrs));
+ }
+
+ do_test(reqs, assert_headers_only, true);
+ }
+
+ #[test]
+ fn stream_bytes() {
+ let mut reqs = Vec::new();
+
+ let sizes = [10, 100, 1000, 10000, 100_000];
+
+ for size in &sizes {
+ let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+
+ let testpoint = format!("{}/{}", "stream-bytes", size.to_string());
+ let url = endpoint(Some(&testpoint));
+
+ reqs.push(Http3Req::new("GET", &url, None, expect_hdrs));
+ }
+
+ do_test(reqs, assert_headers_only, true);
+ }
+
+ #[test]
+ fn image() {
+ let mut reqs = Vec::new();
+
+ // Request 1
+ let expect_hdrs = Some(vec![Header::new(":status", "406")]);
+
+ let url = endpoint(Some("image"));
+
+ let mut req = Http3Req::new("GET", &url, None, expect_hdrs);
+ req.hdrs.push(Header::new("accept", "*/*"));
+ reqs.push(req);
+
+ // Request 2
+ let expect_hdrs = Some(vec![
+ Header::new(":status", "200"),
+ Header::new("content-type", "image/png"),
+ ]);
+ let mut req = Http3Req::new("GET", &url, None, expect_hdrs);
+ req.hdrs.push(Header::new("accept", "image/*"));
+ reqs.push(req);
+
+ // Multiple requests based on accept
+ let formats = ["image/webp", "image/svg+xml", "image/jpeg", "image/png"];
+ for format in &formats {
+ let expect_hdrs = Some(vec![
+ Header::new(":status", "200"),
+ Header::new("content-type", &format),
+ ]);
+
+ let mut req = Http3Req::new("GET", &url, None, expect_hdrs);
+ req.hdrs.push(Header::new("accept", &format));
+ reqs.push(req);
+ }
+
+ // Multiple requests based on path
+ for format in &formats {
+ let expect_hdrs = Some(vec![
+ Header::new(":status", "200"),
+ Header::new("content-type", &format),
+ ]);
+
+ let testpoint = if format == &"image/svg+xml" {
+ "image/svg"
+ } else {
+ format
+ };
+
+ let url = endpoint(Some(&testpoint));
+ let mut req = Http3Req::new("GET", &url, None, expect_hdrs);
+ req.hdrs.push(Header::new("accept", &format));
+ reqs.push(req);
+ }
+
+ do_test(reqs, assert_headers_only, true);
+ }
+
+ #[test]
+ fn form() {
+ let mut reqs = Vec::new();
+ let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+
+ let url = endpoint(Some("post"));
+
+ let req_body = "custname=dave&custtel=1234&custemail=dave@example.com&size=large&topping=bacon&delivery=&comments=pronto";
+
+ let mut req = Http3Req::new(
+ "POST",
+ &url,
+ Some(req_body.to_string().into_bytes()),
+ expect_hdrs,
+ );
+
+ req.hdrs.push(Header::new(
+ "content-type",
+ "application/x-www-form-urlencoded",
+ ));
+ reqs.push(req);
+
+ let assert = |reqs: &[Http3Req]| {
+ assert_headers!(reqs[0]);
+
+ let json = jsonify(&reqs[0].resp_body);
+ if let Some(form) = json.form {
+ assert_eq!(form["custname"], "dave");
+ assert_eq!(form["custtel"], "1234");
+ assert_eq!(form["custemail"], "dave@example.com");
+ assert_eq!(form["size"], "large");
+ assert_eq!(form["topping"], "bacon");
+ assert_eq!(form["delivery"], "");
+ assert_eq!(form["comments"], "pronto");
+ }
+ };
+
+ do_test(reqs, assert, true);
+ }
+
+ #[test]
+ fn html() {
+ let reqs = request_check_status("html", 200);
+ do_test(reqs, assert_headers_only, true);
+ }
+
+ #[test]
+ fn xml() {
+ let reqs = request_check_status("xml", 200);
+ do_test(reqs, assert_headers_only, true);
+ }
+
+ #[test]
+ fn robots() {
+ let reqs = request_check_status("robots.txt", 200);
+ do_test(reqs, assert_headers_only, true);
+ }
+
+ #[test]
+ fn links() {
+ let reqs = request_check_status("links/10", 302);
+ do_test(reqs, assert_headers_only, true);
+ }
+}
diff --git a/tools/quic-trace-log/Cargo.toml b/tools/quic-trace-log/Cargo.toml
index ad31080..cf7f1b0 100644
--- a/tools/quic-trace-log/Cargo.toml
+++ b/tools/quic-trace-log/Cargo.toml
@@ -4,6 +4,7 @@
authors = ["Alessandro Ghedini <alessandro@ghedini.me>"]
edition = "2018"
build = "src/build.rs"
+publish = false
[build-dependencies]
protoc-rust = "2"
diff --git a/tools/quic-trace-log/src/main.rs b/tools/quic-trace-log/src/main.rs
index bcf3690..e659027 100644
--- a/tools/quic-trace-log/src/main.rs
+++ b/tools/quic-trace-log/src/main.rs
@@ -24,8 +24,6 @@
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#![feature(duration_float)]
-
use std::io::BufRead;
use regex::Regex;
@@ -96,8 +94,8 @@
if let Some(caps) = pkt_re.captures(&l) {
// Flush previous event.
- if event.is_some() {
- events.push(event.unwrap());
+ if let Some(event) = event {
+ events.push(event);
}
let mut ev = quic_trace::Event::new();