15 constexpr const char* source =
"quic::packet";
18 auto make_error(
int code,
const std::string&
message,
19 const std::string& details =
"") -> Result<T>
25 constexpr uint8_t header_form_long = 0x80;
26 constexpr uint8_t fixed_bit = 0x40;
29 constexpr uint8_t long_packet_type_mask = 0x30;
30 constexpr uint8_t long_packet_type_shift = 4;
33 constexpr uint8_t spin_bit_mask = 0x20;
34 constexpr uint8_t key_phase_mask = 0x04;
35 constexpr uint8_t pn_length_mask = 0x03;
52 default:
return "Unknown";
89 -> std::pair<std::vector<uint8_t>,
size_t>
91 size_t len = encoded_length(full_pn, largest_acked);
92 std::vector<uint8_t> result(len);
95 for (
size_t i = 0; i < len; ++i)
97 result[len - 1 - i] =
static_cast<uint8_t
>(full_pn >> (i * 8));
100 return {result, len};
104 uint64_t largest_pn)
noexcept -> uint64_t
107 uint64_t expected_pn = largest_pn + 1;
108 uint64_t pn_win = 1ULL << (pn_length * 8);
109 uint64_t pn_hwin = pn_win / 2;
110 uint64_t pn_mask = pn_win - 1;
113 uint64_t candidate_pn = (expected_pn & ~pn_mask) | truncated_pn;
116 if (candidate_pn <= expected_pn - pn_hwin && candidate_pn < (1ULL << 62) - pn_win)
118 return candidate_pn + pn_win;
120 if (candidate_pn > expected_pn + pn_hwin && candidate_pn >= pn_win)
122 return candidate_pn - pn_win;
129 uint64_t num_unacked = (full_pn > largest_acked) ? (full_pn - largest_acked) : 1;
131 if (num_unacked < (1ULL << 7))
135 if (num_unacked < (1ULL << 15))
139 if (num_unacked < (1ULL << 23))
157 if ((data[0] & header_form_long) == 0)
161 uint32_t
version = (
static_cast<uint32_t
>(data[1]) << 24) |
162 (
static_cast<uint32_t
>(data[2]) << 16) |
163 (
static_cast<uint32_t
>(data[3]) << 8) |
164 static_cast<uint32_t
>(data[4]);
173 return make_error<std::pair<packet_header, size_t>>(
175 "Empty packet data");
178 if (is_long_header(data[0]))
180 auto result = parse_long_header(data);
183 return make_error<std::pair<packet_header, size_t>>(
184 result.error().code, result.error().message);
186 auto& [header, len] = result.value();
193 return make_error<std::pair<packet_header, size_t>>(
195 "Short header requires known connection ID length. Use parse_short_header().");
205 return make_error<std::pair<long_header, size_t>>(
207 "Insufficient data for long header");
219 return make_error<std::pair<long_header, size_t>>(
221 "Not a long header packet");
227 return make_error<std::pair<long_header, size_t>>(
229 "Invalid fixed bit in long header");
233 if (data.size() < offset + 4)
235 return make_error<std::pair<long_header, size_t>>(
237 "Insufficient data for version");
239 header.
version = (
static_cast<uint32_t
>(data[offset]) << 24) |
240 (
static_cast<uint32_t
>(data[offset + 1]) << 16) |
241 (
static_cast<uint32_t
>(data[offset + 2]) << 8) |
242 static_cast<uint32_t
>(data[offset + 3]);
246 if (data.size() < offset + 1)
248 return make_error<std::pair<long_header, size_t>>(
250 "Insufficient data for DCID length");
252 uint8_t dcid_len = data[offset++];
255 return make_error<std::pair<long_header, size_t>>(
257 "DCID length exceeds maximum");
261 if (data.size() < offset + dcid_len)
263 return make_error<std::pair<long_header, size_t>>(
265 "Insufficient data for DCID");
271 if (data.size() < offset + 1)
273 return make_error<std::pair<long_header, size_t>>(
275 "Insufficient data for SCID length");
277 uint8_t scid_len = data[offset++];
280 return make_error<std::pair<long_header, size_t>>(
282 "SCID length exceeds maximum");
286 if (data.size() < offset + scid_len)
288 return make_error<std::pair<long_header, size_t>>(
290 "Insufficient data for SCID");
296 auto ptype = header.
type();
302 if (token_len_result.is_err())
304 return make_error<std::pair<long_header, size_t>>(
306 "Failed to decode token length");
308 auto [token_len, token_len_bytes] = token_len_result.value();
309 offset += token_len_bytes;
312 if (data.size() < offset + token_len)
314 return make_error<std::pair<long_header, size_t>>(
316 "Insufficient data for token");
318 header.
token.assign(data.begin() +
static_cast<ptrdiff_t
>(offset),
319 data.begin() +
static_cast<ptrdiff_t
>(offset + token_len));
324 if (pkt_len_result.is_err())
326 return make_error<std::pair<long_header, size_t>>(
328 "Failed to decode packet length");
330 offset += pkt_len_result.value().second;
339 if (pkt_len_result.is_err())
341 return make_error<std::pair<long_header, size_t>>(
343 "Failed to decode packet length");
345 offset += pkt_len_result.value().second;
357 return ok(std::make_pair(std::move(header), offset));
361 size_t conn_id_length)
365 if (data.size() < 1 + conn_id_length + 1)
367 return make_error<std::pair<short_header, size_t>>(
369 "Insufficient data for short header");
381 return make_error<std::pair<short_header, size_t>>(
383 "Not a short header packet");
389 return make_error<std::pair<short_header, size_t>>(
391 "Invalid fixed bit in short header");
395 if (conn_id_length > 0)
397 if (data.size() < offset + conn_id_length)
399 return make_error<std::pair<short_header, size_t>>(
401 "Insufficient data for DCID");
404 offset += conn_id_length;
410 return ok(std::make_pair(std::move(header), offset));
418 std::span<const uint8_t> data)
420 buffer.insert(buffer.end(), data.begin(), data.end());
426 const std::vector<uint8_t>& token,
428 uint32_t
version) -> std::vector<uint8_t>
430 std::vector<uint8_t> buffer;
436 uint8_t first_byte = header_form_long | fixed_bit |
438 static_cast<uint8_t
>(pn_len - 1);
439 buffer.push_back(first_byte);
442 buffer.push_back(
static_cast<uint8_t
>(
version >> 24));
443 buffer.push_back(
static_cast<uint8_t
>(
version >> 16));
444 buffer.push_back(
static_cast<uint8_t
>(
version >> 8));
445 buffer.push_back(
static_cast<uint8_t
>(
version));
448 buffer.push_back(
static_cast<uint8_t
>(dest_cid.length()));
449 append_bytes(buffer, dest_cid.data());
452 buffer.push_back(
static_cast<uint8_t
>(src_cid.length()));
453 append_bytes(buffer, src_cid.data());
457 append_bytes(buffer, token_len_encoded);
458 append_bytes(buffer, token);
462 append_bytes(buffer, pn_bytes);
471 uint32_t
version) -> std::vector<uint8_t>
473 std::vector<uint8_t> buffer;
478 uint8_t first_byte = header_form_long | fixed_bit |
480 static_cast<uint8_t
>(pn_len - 1);
481 buffer.push_back(first_byte);
484 buffer.push_back(
static_cast<uint8_t
>(
version >> 24));
485 buffer.push_back(
static_cast<uint8_t
>(
version >> 16));
486 buffer.push_back(
static_cast<uint8_t
>(
version >> 8));
487 buffer.push_back(
static_cast<uint8_t
>(
version));
490 buffer.push_back(
static_cast<uint8_t
>(dest_cid.length()));
491 append_bytes(buffer, dest_cid.data());
494 buffer.push_back(
static_cast<uint8_t
>(src_cid.length()));
495 append_bytes(buffer, src_cid.data());
499 append_bytes(buffer, pn_bytes);
508 uint32_t
version) -> std::vector<uint8_t>
510 std::vector<uint8_t> buffer;
515 uint8_t first_byte = header_form_long | fixed_bit |
517 static_cast<uint8_t
>(pn_len - 1);
518 buffer.push_back(first_byte);
521 buffer.push_back(
static_cast<uint8_t
>(
version >> 24));
522 buffer.push_back(
static_cast<uint8_t
>(
version >> 16));
523 buffer.push_back(
static_cast<uint8_t
>(
version >> 8));
524 buffer.push_back(
static_cast<uint8_t
>(
version));
527 buffer.push_back(
static_cast<uint8_t
>(dest_cid.length()));
528 append_bytes(buffer, dest_cid.data());
531 buffer.push_back(
static_cast<uint8_t
>(src_cid.length()));
532 append_bytes(buffer, src_cid.data());
536 append_bytes(buffer, pn_bytes);
544 const std::vector<uint8_t>& token,
545 const std::array<uint8_t, 16>& integrity_tag,
546 uint32_t
version) -> std::vector<uint8_t>
548 std::vector<uint8_t> buffer;
551 uint8_t first_byte = header_form_long | fixed_bit |
553 buffer.push_back(first_byte);
556 buffer.push_back(
static_cast<uint8_t
>(
version >> 24));
557 buffer.push_back(
static_cast<uint8_t
>(
version >> 16));
558 buffer.push_back(
static_cast<uint8_t
>(
version >> 8));
559 buffer.push_back(
static_cast<uint8_t
>(
version));
562 buffer.push_back(
static_cast<uint8_t
>(dest_cid.length()));
563 append_bytes(buffer, dest_cid.data());
566 buffer.push_back(
static_cast<uint8_t
>(src_cid.length()));
567 append_bytes(buffer, src_cid.data());
570 append_bytes(buffer, token);
573 buffer.insert(buffer.end(), integrity_tag.begin(), integrity_tag.end());
582 bool spin_bit) -> std::vector<uint8_t>
584 std::vector<uint8_t> buffer;
589 uint8_t first_byte = fixed_bit;
592 first_byte |= spin_bit_mask;
596 first_byte |= key_phase_mask;
598 first_byte |=
static_cast<uint8_t
>(pn_len - 1);
599 buffer.push_back(first_byte);
602 append_bytes(buffer, dest_cid.data());
606 append_bytes(buffer, pn_bytes);
613 auto ptype = header.type();
617 return build_initial(header.dest_conn_id, header.src_conn_id,
618 header.token, header.packet_number, header.version);
620 return build_handshake(header.dest_conn_id, header.src_conn_id,
621 header.packet_number, header.version);
623 return build_zero_rtt(header.dest_conn_id, header.src_conn_id,
624 header.packet_number, header.version);
626 return build_retry(header.dest_conn_id, header.src_conn_id,
627 header.token, header.retry_integrity_tag, header.version);
635 return build_short(header.dest_conn_id, header.packet_number,
636 header.key_phase(), header.spin_bit());
QUIC Connection ID (RFC 9000 Section 5.1)
static constexpr size_t max_length
Maximum length of a connection ID (RFC 9000)
static auto build_retry(const connection_id &dest_cid, const connection_id &src_cid, const std::vector< uint8_t > &token, const std::array< uint8_t, 16 > &integrity_tag, uint32_t version=quic_version::version_1) -> std::vector< uint8_t >
Build a Retry packet header.
static auto build_handshake(const connection_id &dest_cid, const connection_id &src_cid, uint64_t packet_number, uint32_t version=quic_version::version_1) -> std::vector< uint8_t >
Build a Handshake packet header.
static auto build_short(const connection_id &dest_cid, uint64_t packet_number, bool key_phase=false, bool spin_bit=false) -> std::vector< uint8_t >
Build a Short Header (1-RTT) packet.
static auto build_zero_rtt(const connection_id &dest_cid, const connection_id &src_cid, uint64_t packet_number, uint32_t version=quic_version::version_1) -> std::vector< uint8_t >
Build a 0-RTT packet header.
static auto build_initial(const connection_id &dest_cid, const connection_id &src_cid, const std::vector< uint8_t > &token, uint64_t packet_number, uint32_t version=quic_version::version_1) -> std::vector< uint8_t >
Build an Initial packet header.
static void append_bytes(std::vector< uint8_t > &buffer, std::span< const uint8_t > data)
Helper to append bytes to buffer.
static auto build(const long_header &header) -> std::vector< uint8_t >
Build a long header from a header structure.
static auto encoded_length(uint64_t full_pn, uint64_t largest_acked) noexcept -> size_t
Get the minimum number of bytes needed to encode a packet number.
static auto decode(uint64_t truncated_pn, size_t pn_length, uint64_t largest_pn) noexcept -> uint64_t
Decode a packet number from received data.
static auto encode(uint64_t full_pn, uint64_t largest_acked) -> std::pair< std::vector< uint8_t >, size_t >
Encode a packet number for transmission.
static auto parse_header(std::span< const uint8_t > data) -> Result< std::pair< packet_header, size_t > >
Parse a packet header (without header protection removal)
static auto parse_long_header(std::span< const uint8_t > data) -> Result< std::pair< long_header, size_t > >
Parse a long header packet.
static auto parse_short_header(std::span< const uint8_t > data, size_t conn_id_length) -> Result< std::pair< short_header, size_t > >
Parse a short header packet.
static auto is_version_negotiation(std::span< const uint8_t > data) noexcept -> bool
Check if this is a version negotiation packet.
static auto encode(uint64_t value) -> std::vector< uint8_t >
Encode a value to variable-length format.
static auto decode(std::span< const uint8_t > data) -> Result< std::pair< uint64_t, size_t > >
Decode variable-length integer from buffer.
constexpr int invalid_argument
@ error
Black hole detected, reset to base.
auto packet_type_to_string(packet_type type) -> std::string
Convert packet type to string for debugging.
packet_type
QUIC packet types (RFC 9000 Section 17)
std::variant< long_header, short_header > packet_header
Variant type for packet headers.
constexpr const char * version() noexcept
Get the network system version string.