From fd9d38795b9380c24661ec93c5c58a8a7938befd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Rubinos=20Rodr=C3=ADguez?= Date: Mon, 8 Jun 2026 20:55:43 +0200 Subject: [PATCH 1/2] fix(handshake): budget CRYPTO fragmentation off peer max_udp_payload_size, not local 1200 floor (#5) --- src/nquic_protocol_send.erl | 5 ++--- test/nquic_protocol_tests.erl | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/nquic_protocol_send.erl b/src/nquic_protocol_send.erl index 4e8ba74..dee723e 100644 --- a/src/nquic_protocol_send.erl +++ b/src/nquic_protocol_send.erl @@ -274,16 +274,15 @@ batch_frames([F | Rest], Budget, Used, Cur, Batches) -> -spec handshake_payload_budget(nquic_protocol:state()) -> pos_integer(). handshake_payload_budget(#conn_state{ - dcid = DCID, scid = SCID, max_payload_size = MaxPayload, remote_params = RP + dcid = DCID, scid = SCID, remote_params = RP }) -> PeerMax = case RP of #transport_params{max_udp_payload_size = M} when is_integer(M), M >= 1200 -> M; _ -> 1200 end, - Limit = min(MaxPayload, PeerMax), Overhead = 1 + 4 + 1 + byte_size(DCID) + 1 + byte_size(SCID) + 2 + 4 + ?AEAD_TAG_SIZE, - max(1, Limit - Overhead). + PeerMax - Overhead. -spec presplit_crypto_frames([nquic_frame:t()], pos_integer()) -> [nquic_frame:t()]. presplit_crypto_frames(Frames, Budget) -> diff --git a/test/nquic_protocol_tests.erl b/test/nquic_protocol_tests.erl index fb5cc26..f3a946a 100644 --- a/test/nquic_protocol_tests.erl +++ b/test/nquic_protocol_tests.erl @@ -1675,14 +1675,24 @@ build_handshake_packets_small_flight_single_packet_test() -> ?assertEqual(1, length(Packets)). build_handshake_packets_splits_large_flight_test() -> - State = queue_handshake_flight(make_handshake_send_state(1472), crypto:strong_rand_bytes(4000)), + PeerMax = 1472, + State = queue_handshake_flight( + make_handshake_send_state(PeerMax), crypto:strong_rand_bytes(4000) + ), {Packets, _State1} = nquic_protocol_send_queues:flush_handshake(State), - ?assert(length(Packets) >= 4), + ?assert(length(Packets) >= 2), lists:foreach( - fun(P) -> ?assert(byte_size(iolist_to_binary(P)) =< 1200) end, + fun(P) -> ?assert(byte_size(iolist_to_binary(P)) =< PeerMax) end, Packets ). +build_handshake_packets_large_peer_keeps_flight_single_test() -> + State = queue_handshake_flight( + make_handshake_send_state(65527), crypto:strong_rand_bytes(1500) + ), + {Packets, _State1} = nquic_protocol_send_queues:flush_handshake(State), + ?assertEqual(1, length(Packets)). + build_handshake_packets_respects_peer_max_udp_payload_test() -> PeerMax = 1300, State0 = (make_handshake_send_state(PeerMax))#conn_state{max_payload_size = 9000}, From cccdb99d87f5190dc0ae01a01c2162b410e9cab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Rubinos=20Rodr=C3=ADguez?= Date: Mon, 8 Jun 2026 21:25:01 +0200 Subject: [PATCH 2/2] chore: version bump --- CHANGELOG.md | 6 ++++++ README.md | 2 +- src/nquic.app.src | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25b3852..cb60c18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.0.2] - 2026-06-08 + +### Fixed + +- Budget CRYPTO handshake fragmentation off the peer's advertised `max_udp_payload_size` rather than the local 1200-byte floor, so the handshake flight fits the peer's datagram limit (#5) + ## [1.0.1] - 2026-06-03 ### Fixed diff --git a/README.md b/README.md index 891ff6f..40d4854 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Pure Erlang QUIC transport for Erlang/OTP 27+. ## Getting started ```erlang -{deps, [{nquic, "1.0.1"}]}. +{deps, [{nquic, "1.0.2"}]}. ``` ### Client diff --git a/src/nquic.app.src b/src/nquic.app.src index 2bfa0ec..830b9d6 100644 --- a/src/nquic.app.src +++ b/src/nquic.app.src @@ -1,6 +1,6 @@ {application, nquic, [ {description, "QUIC transport protocol (RFC 9000/9001/9002) for Erlang/OTP 27+"}, - {vsn, "1.0.1"}, + {vsn, "1.0.2"}, {registered, []}, {applications, [ kernel,