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;
118 if (candidate_pn + pn_hwin <= expected_pn && candidate_pn < (1ULL << 62) - pn_win)
120 return candidate_pn + pn_win;
122 if (candidate_pn > expected_pn + pn_hwin && candidate_pn >= pn_win)
124 return candidate_pn - pn_win;
131 uint64_t num_unacked = (full_pn > largest_acked) ? (full_pn - largest_acked) : 1;
133 if (num_unacked < (1ULL << 7))
137 if (num_unacked < (1ULL << 15))
141 if (num_unacked < (1ULL << 23))
159 if ((data[0] & header_form_long) == 0)
163 uint32_t
version = (
static_cast<uint32_t
>(data[1]) << 24) |
164 (
static_cast<uint32_t
>(data[2]) << 16) |
165 (
static_cast<uint32_t
>(data[3]) << 8) |
166 static_cast<uint32_t
>(data[4]);
175 return make_error<std::pair<packet_header, size_t>>(
177 "Empty packet data");
180 if (is_long_header(data[0]))
182 auto result = parse_long_header(data);
185 return make_error<std::pair<packet_header, size_t>>(
186 result.error().
code, result.error().message);
188 auto& [header, len] = result.value();
195 return make_error<std::pair<packet_header, size_t>>(
197 "Short header requires known connection ID length. Use parse_short_header().");
207 return make_error<std::pair<long_header, size_t>>(
209 "Insufficient data for long header");
221 return make_error<std::pair<long_header, size_t>>(
223 "Not a long header packet");
229 return make_error<std::pair<long_header, size_t>>(
231 "Invalid fixed bit in long header");
235 if (data.size() < offset + 4)
237 return make_error<std::pair<long_header, size_t>>(
239 "Insufficient data for version");
241 header.
version = (
static_cast<uint32_t
>(data[offset]) << 24) |
242 (
static_cast<uint32_t
>(data[offset + 1]) << 16) |
243 (
static_cast<uint32_t
>(data[offset + 2]) << 8) |
244 static_cast<uint32_t
>(data[offset + 3]);
248 if (data.size() < offset + 1)
250 return make_error<std::pair<long_header, size_t>>(
252 "Insufficient data for DCID length");
254 uint8_t dcid_len = data[offset++];
257 return make_error<std::pair<long_header, size_t>>(
259 "DCID length exceeds maximum");
263 if (data.size() < offset + dcid_len)
265 return make_error<std::pair<long_header, size_t>>(
267 "Insufficient data for DCID");
273 if (data.size() < offset + 1)
275 return make_error<std::pair<long_header, size_t>>(
277 "Insufficient data for SCID length");
279 uint8_t scid_len = data[offset++];
282 return make_error<std::pair<long_header, size_t>>(
284 "SCID length exceeds maximum");
288 if (data.size() < offset + scid_len)
290 return make_error<std::pair<long_header, size_t>>(
292 "Insufficient data for SCID");
298 auto ptype = header.
type();
304 if (token_len_result.is_err())
306 return make_error<std::pair<long_header, size_t>>(
308 "Failed to decode token length");
310 auto [token_len, token_len_bytes] = token_len_result.value();
311 offset += token_len_bytes;
314 if (data.size() < offset + token_len)
316 return make_error<std::pair<long_header, size_t>>(
318 "Insufficient data for token");
320 header.
token.assign(data.begin() +
static_cast<ptrdiff_t
>(offset),
321 data.begin() +
static_cast<ptrdiff_t
>(offset + token_len));
326 if (pkt_len_result.is_err())
328 return make_error<std::pair<long_header, size_t>>(
330 "Failed to decode packet length");
332 offset += pkt_len_result.value().second;
341 if (pkt_len_result.is_err())
343 return make_error<std::pair<long_header, size_t>>(
345 "Failed to decode packet length");
347 offset += pkt_len_result.value().second;
359 return ok(std::make_pair(std::move(header), offset));
363 size_t conn_id_length)
367 if (data.size() < 1 + conn_id_length + 1)
369 return make_error<std::pair<short_header, size_t>>(
371 "Insufficient data for short header");
383 return make_error<std::pair<short_header, size_t>>(
385 "Not a short header packet");
391 return make_error<std::pair<short_header, size_t>>(
393 "Invalid fixed bit in short header");
397 if (conn_id_length > 0)
399 if (data.size() < offset + conn_id_length)
401 return make_error<std::pair<short_header, size_t>>(
403 "Insufficient data for DCID");
406 offset += conn_id_length;
412 return ok(std::make_pair(std::move(header), offset));
420 std::span<const uint8_t> data)
422 buffer.insert(buffer.end(), data.begin(), data.end());
428 const std::vector<uint8_t>& token,
430 uint32_t
version) -> std::vector<uint8_t>
432 std::vector<uint8_t> buffer;
438 uint8_t first_byte = header_form_long | fixed_bit |
440 static_cast<uint8_t
>(pn_len - 1);
441 buffer.push_back(first_byte);
444 buffer.push_back(
static_cast<uint8_t
>(
version >> 24));
445 buffer.push_back(
static_cast<uint8_t
>(
version >> 16));
446 buffer.push_back(
static_cast<uint8_t
>(
version >> 8));
447 buffer.push_back(
static_cast<uint8_t
>(
version));
450 buffer.push_back(
static_cast<uint8_t
>(dest_cid.length()));
451 append_bytes(buffer, dest_cid.data());
454 buffer.push_back(
static_cast<uint8_t
>(src_cid.length()));
455 append_bytes(buffer, src_cid.data());
459 append_bytes(buffer, token_len_encoded);
460 append_bytes(buffer, token);
464 append_bytes(buffer, pn_bytes);
473 uint32_t
version) -> std::vector<uint8_t>
475 std::vector<uint8_t> buffer;
480 uint8_t first_byte = header_form_long | fixed_bit |
482 static_cast<uint8_t
>(pn_len - 1);
483 buffer.push_back(first_byte);
486 buffer.push_back(
static_cast<uint8_t
>(
version >> 24));
487 buffer.push_back(
static_cast<uint8_t
>(
version >> 16));
488 buffer.push_back(
static_cast<uint8_t
>(
version >> 8));
489 buffer.push_back(
static_cast<uint8_t
>(
version));
492 buffer.push_back(
static_cast<uint8_t
>(dest_cid.length()));
493 append_bytes(buffer, dest_cid.data());
496 buffer.push_back(
static_cast<uint8_t
>(src_cid.length()));
497 append_bytes(buffer, src_cid.data());
501 append_bytes(buffer, pn_bytes);
510 uint32_t
version) -> std::vector<uint8_t>
512 std::vector<uint8_t> buffer;
517 uint8_t first_byte = header_form_long | fixed_bit |
519 static_cast<uint8_t
>(pn_len - 1);
520 buffer.push_back(first_byte);
523 buffer.push_back(
static_cast<uint8_t
>(
version >> 24));
524 buffer.push_back(
static_cast<uint8_t
>(
version >> 16));
525 buffer.push_back(
static_cast<uint8_t
>(
version >> 8));
526 buffer.push_back(
static_cast<uint8_t
>(
version));
529 buffer.push_back(
static_cast<uint8_t
>(dest_cid.length()));
530 append_bytes(buffer, dest_cid.data());
533 buffer.push_back(
static_cast<uint8_t
>(src_cid.length()));
534 append_bytes(buffer, src_cid.data());
538 append_bytes(buffer, pn_bytes);
546 const std::vector<uint8_t>& token,
547 const std::array<uint8_t, 16>& integrity_tag,
548 uint32_t
version) -> std::vector<uint8_t>
550 std::vector<uint8_t> buffer;
553 uint8_t first_byte = header_form_long | fixed_bit |
555 buffer.push_back(first_byte);
558 buffer.push_back(
static_cast<uint8_t
>(
version >> 24));
559 buffer.push_back(
static_cast<uint8_t
>(
version >> 16));
560 buffer.push_back(
static_cast<uint8_t
>(
version >> 8));
561 buffer.push_back(
static_cast<uint8_t
>(
version));
564 buffer.push_back(
static_cast<uint8_t
>(dest_cid.length()));
565 append_bytes(buffer, dest_cid.data());
568 buffer.push_back(
static_cast<uint8_t
>(src_cid.length()));
569 append_bytes(buffer, src_cid.data());
572 append_bytes(buffer, token);
575 buffer.insert(buffer.end(), integrity_tag.begin(), integrity_tag.end());
584 bool spin_bit) -> std::vector<uint8_t>
586 std::vector<uint8_t> buffer;
591 uint8_t first_byte = fixed_bit;
594 first_byte |= spin_bit_mask;
598 first_byte |= key_phase_mask;
600 first_byte |=
static_cast<uint8_t
>(pn_len - 1);
601 buffer.push_back(first_byte);
604 append_bytes(buffer, dest_cid.data());
608 append_bytes(buffer, pn_bytes);
615 auto ptype = header.type();
619 return build_initial(header.dest_conn_id, header.src_conn_id,
620 header.token, header.packet_number, header.version);
622 return build_handshake(header.dest_conn_id, header.src_conn_id,
623 header.packet_number, header.version);
625 return build_zero_rtt(header.dest_conn_id, header.src_conn_id,
626 header.packet_number, header.version);
628 return build_retry(header.dest_conn_id, header.src_conn_id,
629 header.token, header.retry_integrity_tag, header.version);
637 return build_short(header.dest_conn_id, header.packet_number,
638 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.