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();