Loading debian/changelog +12 −0 Original line number Diff line number Diff line libnetplus (20260504+7) unstable; urgency=medium * QUIC: cap max_udp_payload_size to 1472 (Ethernet-safe) instead of 16384. The old value caused 16KB UDP datagrams that get fragmented into ~11 IP fragments each, amplifying packet loss ~11x on standard 1500 MTU networks. This was the primary cause of store_stripe hanging — the server received only ~30% of packets despite the client believing they were delivered. * QUIC: add post-HEAD range verification diagnostic — logs recv_contiguous and first range immediately after inserting offset-0 data to trace the contig=0 mystery libnetplus (20260504+6) unstable; urgency=medium * QUIC: add per-stream recv_frame_count diagnostic — tracks how many Loading src/quic.cpp +15 −5 Original line number Diff line number Diff line Loading @@ -2525,10 +2525,10 @@ std::vector<uint8_t> quic::buildTransportParameters() { params.insert(params.end(), timeout_len_buf, timeout_len_buf + timeout_len_size); params.insert(params.end(), timeout_buf, timeout_buf + timeout_len); // max_udp_payload_size (0x03) — advertise 16384 (large datagrams) // max_udp_payload_size (0x03) — advertise 1472 (Ethernet-safe, no IP fragmentation) params.push_back(0x03); uint8_t mups_buf[8]; size_t mups_len = encodeVarInt(16384, mups_buf); size_t mups_len = encodeVarInt(1472, mups_buf); uint8_t mups_len_buf[8]; size_t mups_len_size = encodeVarInt(mups_len, mups_len_buf); params.insert(params.end(), mups_len_buf, mups_len_buf + mups_len_size); Loading Loading @@ -3449,6 +3449,16 @@ void quic::processStreamFrame(const uint8_t* data, size_t len, size_t& offset) { if (!stream.recv_ranges.empty() && stream.recv_ranges.begin()->first == 0) { stream.recv_contiguous = stream.recv_ranges.begin()->second; } // Diagnostic: verify HEAD range persists after insertion if (_is_server && stream_offset == 0 && stream.recv_fin_offset != UINT64_MAX) { std::cerr << "[QUIC-DIAG] stream " << stream_id << " post-HEAD: contig=" << stream.recv_contiguous << " ranges=" << stream.recv_ranges.size() << " first_range=[" << stream.recv_ranges.begin()->first << "," << stream.recv_ranges.begin()->second << "]" << "\n"; } } offset += stream_len; Loading Loading @@ -4202,9 +4212,9 @@ void quic::parseTransportParameters(const uint8_t* data, size_t len) { case 0x03: { // max_udp_payload_size size_t vb; uint64_t peer_max_payload = decodeVarInt(&data[offset], vb); // Clamp to 16384 (safe max for QUIC datagrams) if (peer_max_payload > 16384) peer_max_payload = 16384; // Clamp to 1472 (Ethernet-safe, avoids IP fragmentation) if (peer_max_payload > 1472) peer_max_payload = 1472; if (peer_max_payload > _max_udp_payload) _max_udp_payload = peer_max_payload; break; Loading Loading
debian/changelog +12 −0 Original line number Diff line number Diff line libnetplus (20260504+7) unstable; urgency=medium * QUIC: cap max_udp_payload_size to 1472 (Ethernet-safe) instead of 16384. The old value caused 16KB UDP datagrams that get fragmented into ~11 IP fragments each, amplifying packet loss ~11x on standard 1500 MTU networks. This was the primary cause of store_stripe hanging — the server received only ~30% of packets despite the client believing they were delivered. * QUIC: add post-HEAD range verification diagnostic — logs recv_contiguous and first range immediately after inserting offset-0 data to trace the contig=0 mystery libnetplus (20260504+6) unstable; urgency=medium * QUIC: add per-stream recv_frame_count diagnostic — tracks how many Loading
src/quic.cpp +15 −5 Original line number Diff line number Diff line Loading @@ -2525,10 +2525,10 @@ std::vector<uint8_t> quic::buildTransportParameters() { params.insert(params.end(), timeout_len_buf, timeout_len_buf + timeout_len_size); params.insert(params.end(), timeout_buf, timeout_buf + timeout_len); // max_udp_payload_size (0x03) — advertise 16384 (large datagrams) // max_udp_payload_size (0x03) — advertise 1472 (Ethernet-safe, no IP fragmentation) params.push_back(0x03); uint8_t mups_buf[8]; size_t mups_len = encodeVarInt(16384, mups_buf); size_t mups_len = encodeVarInt(1472, mups_buf); uint8_t mups_len_buf[8]; size_t mups_len_size = encodeVarInt(mups_len, mups_len_buf); params.insert(params.end(), mups_len_buf, mups_len_buf + mups_len_size); Loading Loading @@ -3449,6 +3449,16 @@ void quic::processStreamFrame(const uint8_t* data, size_t len, size_t& offset) { if (!stream.recv_ranges.empty() && stream.recv_ranges.begin()->first == 0) { stream.recv_contiguous = stream.recv_ranges.begin()->second; } // Diagnostic: verify HEAD range persists after insertion if (_is_server && stream_offset == 0 && stream.recv_fin_offset != UINT64_MAX) { std::cerr << "[QUIC-DIAG] stream " << stream_id << " post-HEAD: contig=" << stream.recv_contiguous << " ranges=" << stream.recv_ranges.size() << " first_range=[" << stream.recv_ranges.begin()->first << "," << stream.recv_ranges.begin()->second << "]" << "\n"; } } offset += stream_len; Loading Loading @@ -4202,9 +4212,9 @@ void quic::parseTransportParameters(const uint8_t* data, size_t len) { case 0x03: { // max_udp_payload_size size_t vb; uint64_t peer_max_payload = decodeVarInt(&data[offset], vb); // Clamp to 16384 (safe max for QUIC datagrams) if (peer_max_payload > 16384) peer_max_payload = 16384; // Clamp to 1472 (Ethernet-safe, avoids IP fragmentation) if (peer_max_payload > 1472) peer_max_payload = 1472; if (peer_max_payload > _max_udp_payload) _max_udp_payload = peer_max_payload; break; Loading