13 constexpr const char* source =
"quic::frame";
17 auto make_error(
int code,
const std::string&
message,
18 const std::string& details =
"") -> Result<T>
30 return std::visit([](
const auto& fr) ->
frame_type {
31 using T = std::decay_t<
decltype(fr)>;
32 if constexpr (std::is_same_v<T, padding_frame>)
34 else if constexpr (std::is_same_v<T, ping_frame>)
36 else if constexpr (std::is_same_v<T, ack_frame>)
38 else if constexpr (std::is_same_v<T, reset_stream_frame>)
40 else if constexpr (std::is_same_v<T, stop_sending_frame>)
42 else if constexpr (std::is_same_v<T, crypto_frame>)
44 else if constexpr (std::is_same_v<T, new_token_frame>)
46 else if constexpr (std::is_same_v<T, stream_frame>)
48 else if constexpr (std::is_same_v<T, max_data_frame>)
50 else if constexpr (std::is_same_v<T, max_stream_data_frame>)
52 else if constexpr (std::is_same_v<T, max_streams_frame>)
55 else if constexpr (std::is_same_v<T, data_blocked_frame>)
57 else if constexpr (std::is_same_v<T, stream_data_blocked_frame>)
59 else if constexpr (std::is_same_v<T, streams_blocked_frame>)
62 else if constexpr (std::is_same_v<T, new_connection_id_frame>)
64 else if constexpr (std::is_same_v<T, retire_connection_id_frame>)
66 else if constexpr (std::is_same_v<T, path_challenge_frame>)
68 else if constexpr (std::is_same_v<T, path_response_frame>)
70 else if constexpr (std::is_same_v<T, connection_close_frame>)
73 else if constexpr (std::is_same_v<T, handshake_done_frame>)
108 default:
return "UNKNOWN";
127 return make_error<std::pair<frame, size_t>>(
134 if (type_result.is_err())
136 return make_error<std::pair<frame, size_t>>(
138 "Failed to decode frame type");
141 auto [type_value, type_len] = type_result.value();
142 auto remaining = data.subspan(type_len);
148 if (result.is_err())
return result;
149 auto& [f, consumed] = result.value();
150 return ok(std::make_pair(std::move(f), type_len + consumed));
157 return parse_padding(data);
161 auto result = parse_ping(remaining);
162 if (result.is_err())
return result;
163 auto& [f, consumed] = result.value();
164 return ok(std::make_pair(std::move(f), type_len + consumed));
169 auto result = parse_ack(remaining,
false);
170 if (result.is_err())
return result;
171 auto& [f, consumed] = result.value();
172 return ok(std::make_pair(std::move(f), type_len + consumed));
177 auto result = parse_ack(remaining,
true);
178 if (result.is_err())
return result;
179 auto& [f, consumed] = result.value();
180 return ok(std::make_pair(std::move(f), type_len + consumed));
185 auto result = parse_reset_stream(remaining);
186 if (result.is_err())
return result;
187 auto& [f, consumed] = result.value();
188 return ok(std::make_pair(std::move(f), type_len + consumed));
193 auto result = parse_stop_sending(remaining);
194 if (result.is_err())
return result;
195 auto& [f, consumed] = result.value();
196 return ok(std::make_pair(std::move(f), type_len + consumed));
201 auto result = parse_crypto(remaining);
202 if (result.is_err())
return result;
203 auto& [f, consumed] = result.value();
204 return ok(std::make_pair(std::move(f), type_len + consumed));
209 auto result = parse_new_token(remaining);
210 if (result.is_err())
return result;
211 auto& [f, consumed] = result.value();
212 return ok(std::make_pair(std::move(f), type_len + consumed));
217 auto result = parse_max_data(remaining);
218 if (result.is_err())
return result;
219 auto& [f, consumed] = result.value();
220 return ok(std::make_pair(std::move(f), type_len + consumed));
225 auto result = parse_max_stream_data(remaining);
226 if (result.is_err())
return result;
227 auto& [f, consumed] = result.value();
228 return ok(std::make_pair(std::move(f), type_len + consumed));
233 auto result = parse_max_streams(remaining,
true);
234 if (result.is_err())
return result;
235 auto& [f, consumed] = result.value();
236 return ok(std::make_pair(std::move(f), type_len + consumed));
241 auto result = parse_max_streams(remaining,
false);
242 if (result.is_err())
return result;
243 auto& [f, consumed] = result.value();
244 return ok(std::make_pair(std::move(f), type_len + consumed));
249 auto result = parse_data_blocked(remaining);
250 if (result.is_err())
return result;
251 auto& [f, consumed] = result.value();
252 return ok(std::make_pair(std::move(f), type_len + consumed));
257 auto result = parse_stream_data_blocked(remaining);
258 if (result.is_err())
return result;
259 auto& [f, consumed] = result.value();
260 return ok(std::make_pair(std::move(f), type_len + consumed));
265 auto result = parse_streams_blocked(remaining,
true);
266 if (result.is_err())
return result;
267 auto& [f, consumed] = result.value();
268 return ok(std::make_pair(std::move(f), type_len + consumed));
273 auto result = parse_streams_blocked(remaining,
false);
274 if (result.is_err())
return result;
275 auto& [f, consumed] = result.value();
276 return ok(std::make_pair(std::move(f), type_len + consumed));
281 auto result = parse_new_connection_id(remaining);
282 if (result.is_err())
return result;
283 auto& [f, consumed] = result.value();
284 return ok(std::make_pair(std::move(f), type_len + consumed));
289 auto result = parse_retire_connection_id(remaining);
290 if (result.is_err())
return result;
291 auto& [f, consumed] = result.value();
292 return ok(std::make_pair(std::move(f), type_len + consumed));
297 auto result = parse_path_challenge(remaining);
298 if (result.is_err())
return result;
299 auto& [f, consumed] = result.value();
300 return ok(std::make_pair(std::move(f), type_len + consumed));
305 auto result = parse_path_response(remaining);
306 if (result.is_err())
return result;
307 auto& [f, consumed] = result.value();
308 return ok(std::make_pair(std::move(f), type_len + consumed));
313 auto result = parse_connection_close(remaining,
false);
314 if (result.is_err())
return result;
315 auto& [f, consumed] = result.value();
316 return ok(std::make_pair(std::move(f), type_len + consumed));
321 auto result = parse_connection_close(remaining,
true);
322 if (result.is_err())
return result;
323 auto& [f, consumed] = result.value();
324 return ok(std::make_pair(std::move(f), type_len + consumed));
329 auto result = parse_handshake_done(remaining);
330 if (result.is_err())
return result;
331 auto& [f, consumed] = result.value();
332 return ok(std::make_pair(std::move(f), type_len + consumed));
336 return make_error<std::pair<frame, size_t>>(
338 "Unknown frame type",
339 "type=" + std::to_string(type_value));
346 std::vector<frame> frames;
349 while (offset < data.size())
351 auto result = parse(data.subspan(offset));
354 return make_error<std::vector<frame>>(
356 "Failed to parse frame at offset " + std::to_string(offset));
359 auto& [f, consumed] = result.value();
360 frames.push_back(std::move(f));
364 return ok(std::move(frames));
372 while (count < data.size() && data[count] == 0x00)
384 return ok(std::make_pair(
frame{f}, count));
402 if (largest.is_err())
return make_error<std::pair<frame, size_t>>(
405 offset += largest.value().second;
409 if (delay.is_err())
return make_error<std::pair<frame, size_t>>(
412 offset += delay.value().second;
416 if (range_count.is_err())
return make_error<std::pair<frame, size_t>>(
418 offset += range_count.value().second;
422 if (first_range.is_err())
return make_error<std::pair<frame, size_t>>(
424 offset += first_range.value().second;
428 for (uint64_t i = 0; i < range_count.value().first; ++i)
433 if (gap.is_err())
return make_error<std::pair<frame, size_t>>(
435 range.
gap = gap.value().first;
436 offset += gap.value().second;
439 if (length.is_err())
return make_error<std::pair<frame, size_t>>(
441 range.
length = length.value().first;
442 offset += length.value().second;
444 f.
ranges.push_back(range);
453 if (
ect0.is_err())
return make_error<std::pair<frame, size_t>>(
456 offset +=
ect0.value().second;
459 if (
ect1.is_err())
return make_error<std::pair<frame, size_t>>(
462 offset +=
ect1.value().second;
465 if (
ecn_ce.is_err())
return make_error<std::pair<frame, size_t>>(
468 offset +=
ecn_ce.value().second;
473 return ok(std::make_pair(
frame{f}, offset));
483 if (stream_id.is_err())
return make_error<std::pair<frame, size_t>>(
486 offset += stream_id.value().second;
489 if (error_code.is_err())
return make_error<std::pair<frame, size_t>>(
492 offset += error_code.value().second;
495 if (final_size.is_err())
return make_error<std::pair<frame, size_t>>(
498 offset += final_size.value().second;
500 return ok(std::make_pair(
frame{f}, offset));
510 if (stream_id.is_err())
return make_error<std::pair<frame, size_t>>(
513 offset += stream_id.value().second;
516 if (error_code.is_err())
return make_error<std::pair<frame, size_t>>(
519 offset += error_code.value().second;
521 return ok(std::make_pair(
frame{f}, offset));
531 if (crypto_offset.is_err())
return make_error<std::pair<frame, size_t>>(
533 f.
offset = crypto_offset.value().first;
534 offset += crypto_offset.value().second;
537 if (length.is_err())
return make_error<std::pair<frame, size_t>>(
539 offset += length.value().second;
541 if (data.size() - offset < length.value().first)
543 return make_error<std::pair<frame, size_t>>(
547 f.
data.assign(data.begin() + offset, data.begin() + offset + length.value().first);
548 offset += length.value().first;
550 return ok(std::make_pair(
frame{f}, offset));
560 if (length.is_err())
return make_error<std::pair<frame, size_t>>(
562 offset += length.value().second;
564 if (data.size() - offset < length.value().first)
566 return make_error<std::pair<frame, size_t>>(
570 f.
token.assign(data.begin() + offset, data.begin() + offset + length.value().first);
571 offset += length.value().first;
573 return ok(std::make_pair(
frame{f}, offset));
584 if (stream_id.is_err())
return make_error<std::pair<frame, size_t>>(
587 offset += stream_id.value().second;
593 if (stream_offset.is_err())
return make_error<std::pair<frame, size_t>>(
595 f.
offset = stream_offset.value().first;
596 offset += stream_offset.value().second;
604 if (len_result.is_err())
return make_error<std::pair<frame, size_t>>(
606 length = len_result.value().first;
607 offset += len_result.value().second;
612 length = data.size() - offset;
619 if (data.size() - offset < length)
621 return make_error<std::pair<frame, size_t>>(
625 f.
data.assign(data.begin() + offset, data.begin() + offset + length);
628 return ok(std::make_pair(
frame{f}, offset));
637 if (
max_data.is_err())
return make_error<std::pair<frame, size_t>>(
651 if (stream_id.is_err())
return make_error<std::pair<frame, size_t>>(
654 offset += stream_id.value().second;
657 if (
max_data.is_err())
return make_error<std::pair<frame, size_t>>(
662 return ok(std::make_pair(
frame{f}, offset));
672 if (max_streams.is_err())
return make_error<std::pair<frame, size_t>>(
676 return ok(std::make_pair(
frame{f}, max_streams.value().second));
685 if (
max_data.is_err())
return make_error<std::pair<frame, size_t>>(
699 if (stream_id.is_err())
return make_error<std::pair<frame, size_t>>(
702 offset += stream_id.value().second;
705 if (
max_data.is_err())
return make_error<std::pair<frame, size_t>>(
710 return ok(std::make_pair(
frame{f}, offset));
720 if (max_streams.is_err())
return make_error<std::pair<frame, size_t>>(
724 return ok(std::make_pair(
frame{f}, max_streams.value().second));
735 if (seq.is_err())
return make_error<std::pair<frame, size_t>>(
738 offset += seq.value().second;
742 if (retire.is_err())
return make_error<std::pair<frame, size_t>>(
745 offset += retire.value().second;
748 if (data.size() <= offset)
750 return make_error<std::pair<frame, size_t>>(
753 uint8_t cid_len = data[offset++];
756 return make_error<std::pair<frame, size_t>>(
761 if (data.size() - offset < cid_len)
763 return make_error<std::pair<frame, size_t>>(
766 f.
connection_id.assign(data.begin() + offset, data.begin() + offset + cid_len);
770 if (data.size() - offset < 16)
772 return make_error<std::pair<frame, size_t>>(
775 std::copy(data.begin() + offset, data.begin() + offset + 16,
779 return ok(std::make_pair(
frame{f}, offset));
788 if (seq.is_err())
return make_error<std::pair<frame, size_t>>(
792 return ok(std::make_pair(
frame{f}, seq.value().second));
800 return make_error<std::pair<frame, size_t>>(
805 std::copy(data.begin(), data.begin() + 8, f.
data.begin());
807 return ok(std::make_pair(
frame{f},
size_t{8}));
815 return make_error<std::pair<frame, size_t>>(
820 std::copy(data.begin(), data.begin() + 8, f.
data.begin());
822 return ok(std::make_pair(
frame{f},
size_t{8}));
834 if (error_code.is_err())
return make_error<std::pair<frame, size_t>>(
837 offset += error_code.value().second;
843 if (frame_type_val.is_err())
return make_error<std::pair<frame, size_t>>(
846 offset += frame_type_val.value().second;
851 if (reason_len.is_err())
return make_error<std::pair<frame, size_t>>(
853 offset += reason_len.value().second;
856 if (data.size() - offset < reason_len.value().first)
858 return make_error<std::pair<frame, size_t>>(
862 f.
reason_phrase.assign(
reinterpret_cast<const char*
>(data.data() + offset),
863 reason_len.value().first);
864 offset += reason_len.value().first;
866 return ok(std::make_pair(
frame{f}, offset));
882 buffer.insert(buffer.end(), encoded.begin(), encoded.end());
886 std::span<const uint8_t> data)
888 buffer.insert(buffer.end(), data.begin(), data.end());
893 return std::visit([](
const auto& fr) -> std::vector<uint8_t> {
894 using T = std::decay_t<
decltype(fr)>;
895 if constexpr (std::is_same_v<T, padding_frame>)
896 return build_padding(fr.count);
897 else if constexpr (std::is_same_v<T, ping_frame>)
899 else if constexpr (std::is_same_v<T, ack_frame>)
900 return build_ack(fr);
901 else if constexpr (std::is_same_v<T, reset_stream_frame>)
902 return build_reset_stream(fr);
903 else if constexpr (std::is_same_v<T, stop_sending_frame>)
904 return build_stop_sending(fr);
905 else if constexpr (std::is_same_v<T, crypto_frame>)
906 return build_crypto(fr);
907 else if constexpr (std::is_same_v<T, new_token_frame>)
908 return build_new_token(fr);
909 else if constexpr (std::is_same_v<T, stream_frame>)
910 return build_stream(fr);
911 else if constexpr (std::is_same_v<T, max_data_frame>)
912 return build_max_data(fr);
913 else if constexpr (std::is_same_v<T, max_stream_data_frame>)
914 return build_max_stream_data(fr);
915 else if constexpr (std::is_same_v<T, max_streams_frame>)
916 return build_max_streams(fr);
917 else if constexpr (std::is_same_v<T, data_blocked_frame>)
918 return build_data_blocked(fr);
919 else if constexpr (std::is_same_v<T, stream_data_blocked_frame>)
920 return build_stream_data_blocked(fr);
921 else if constexpr (std::is_same_v<T, streams_blocked_frame>)
922 return build_streams_blocked(fr);
923 else if constexpr (std::is_same_v<T, new_connection_id_frame>)
924 return build_new_connection_id(fr);
925 else if constexpr (std::is_same_v<T, retire_connection_id_frame>)
926 return build_retire_connection_id(fr);
927 else if constexpr (std::is_same_v<T, path_challenge_frame>)
928 return build_path_challenge(fr);
929 else if constexpr (std::is_same_v<T, path_response_frame>)
930 return build_path_response(fr);
931 else if constexpr (std::is_same_v<T, connection_close_frame>)
932 return build_connection_close(fr);
933 else if constexpr (std::is_same_v<T, handshake_done_frame>)
934 return build_handshake_done();
942 return std::vector<uint8_t>(count, 0x00);
952 std::vector<uint8_t> buffer;
959 append_varint(buffer, f.largest_acknowledged);
962 append_varint(buffer, f.ack_delay);
965 append_varint(buffer, f.ranges.size());
969 uint64_t first_range = 0;
970 if (!f.ranges.empty())
972 first_range = f.ranges[0].length;
974 append_varint(buffer, first_range);
977 for (
size_t i = 1; i < f.ranges.size(); ++i)
979 append_varint(buffer, f.ranges[i].gap);
980 append_varint(buffer, f.ranges[i].length);
986 append_varint(buffer, f.ecn->ect0);
987 append_varint(buffer, f.ecn->ect1);
988 append_varint(buffer, f.ecn->ecn_ce);
995 -> std::vector<uint8_t>
997 std::vector<uint8_t> buffer;
999 append_varint(buffer, f.stream_id);
1000 append_varint(buffer, f.application_error_code);
1001 append_varint(buffer, f.final_size);
1006 -> std::vector<uint8_t>
1008 std::vector<uint8_t> buffer;
1010 append_varint(buffer, f.stream_id);
1011 append_varint(buffer, f.application_error_code);
1017 std::vector<uint8_t> buffer;
1019 append_varint(buffer, f.offset);
1020 append_varint(buffer, f.data.size());
1021 append_bytes(buffer, f.data);
1026 -> std::vector<uint8_t>
1028 std::vector<uint8_t> buffer;
1030 append_varint(buffer, f.token.size());
1031 append_bytes(buffer, f.token);
1036 -> std::vector<uint8_t>
1038 std::vector<uint8_t> buffer;
1042 buffer.push_back(type);
1045 append_varint(buffer, f.stream_id);
1050 append_varint(buffer, f.offset);
1056 append_varint(buffer, f.data.size());
1060 append_bytes(buffer, f.data);
1066 -> std::vector<uint8_t>
1068 std::vector<uint8_t> buffer;
1070 append_varint(buffer, f.maximum_data);
1075 -> std::vector<uint8_t>
1077 std::vector<uint8_t> buffer;
1079 append_varint(buffer, f.stream_id);
1080 append_varint(buffer, f.maximum_stream_data);
1085 -> std::vector<uint8_t>
1087 std::vector<uint8_t> buffer;
1088 append_varint(buffer, f.bidirectional
1091 append_varint(buffer, f.maximum_streams);
1096 -> std::vector<uint8_t>
1098 std::vector<uint8_t> buffer;
1100 append_varint(buffer, f.maximum_data);
1105 -> std::vector<uint8_t>
1107 std::vector<uint8_t> buffer;
1109 append_varint(buffer, f.stream_id);
1110 append_varint(buffer, f.maximum_stream_data);
1115 -> std::vector<uint8_t>
1117 std::vector<uint8_t> buffer;
1118 append_varint(buffer, f.bidirectional
1121 append_varint(buffer, f.maximum_streams);
1126 -> std::vector<uint8_t>
1128 std::vector<uint8_t> buffer;
1130 append_varint(buffer, f.sequence_number);
1131 append_varint(buffer, f.retire_prior_to);
1134 buffer.push_back(
static_cast<uint8_t
>(f.connection_id.size()));
1137 append_bytes(buffer, f.connection_id);
1140 buffer.insert(buffer.end(), f.stateless_reset_token.begin(),
1141 f.stateless_reset_token.end());
1147 -> std::vector<uint8_t>
1149 std::vector<uint8_t> buffer;
1151 append_varint(buffer, f.sequence_number);
1156 -> std::vector<uint8_t>
1158 std::vector<uint8_t> buffer;
1160 buffer.insert(buffer.end(), f.data.begin(), f.data.end());
1165 -> std::vector<uint8_t>
1167 std::vector<uint8_t> buffer;
1169 buffer.insert(buffer.end(), f.data.begin(), f.data.end());
1174 -> std::vector<uint8_t>
1176 std::vector<uint8_t> buffer;
1177 append_varint(buffer, f.is_application_error
1181 append_varint(buffer, f.error_code);
1184 if (!f.is_application_error)
1186 append_varint(buffer, f.frame_type);
1190 append_varint(buffer, f.reason_phrase.size());
1193 buffer.insert(buffer.end(), f.reason_phrase.begin(), f.reason_phrase.end());
static auto build_path_response(const path_response_frame &f) -> std::vector< uint8_t >
Build PATH_RESPONSE frame.
static auto build_streams_blocked(const streams_blocked_frame &f) -> std::vector< uint8_t >
Build STREAMS_BLOCKED frame.
static auto build_reset_stream(const reset_stream_frame &f) -> std::vector< uint8_t >
Build RESET_STREAM frame.
static auto build_stream(const stream_frame &f, bool include_length=true) -> std::vector< uint8_t >
Build STREAM frame.
static auto build_stop_sending(const stop_sending_frame &f) -> std::vector< uint8_t >
Build STOP_SENDING frame.
static auto build_ack(const ack_frame &f) -> std::vector< uint8_t >
Build ACK frame.
static auto build_padding(size_t count=1) -> std::vector< uint8_t >
Build PADDING frame.
static auto build_max_stream_data(const max_stream_data_frame &f) -> std::vector< uint8_t >
Build MAX_STREAM_DATA frame.
static auto build_data_blocked(const data_blocked_frame &f) -> std::vector< uint8_t >
Build DATA_BLOCKED frame.
static auto build_new_token(const new_token_frame &f) -> std::vector< uint8_t >
Build NEW_TOKEN frame.
static auto build_max_data(const max_data_frame &f) -> std::vector< uint8_t >
Build MAX_DATA frame.
static auto build_ping() -> std::vector< uint8_t >
Build PING frame.
static auto build_new_connection_id(const new_connection_id_frame &f) -> std::vector< uint8_t >
Build NEW_CONNECTION_ID frame.
static auto build_crypto(const crypto_frame &f) -> std::vector< uint8_t >
Build CRYPTO frame.
static auto build(const frame &f) -> std::vector< uint8_t >
Build any frame from variant.
static void append_bytes(std::vector< uint8_t > &buffer, std::span< const uint8_t > data)
static auto build_path_challenge(const path_challenge_frame &f) -> std::vector< uint8_t >
Build PATH_CHALLENGE frame.
static auto build_connection_close(const connection_close_frame &f) -> std::vector< uint8_t >
Build CONNECTION_CLOSE frame.
static auto build_handshake_done() -> std::vector< uint8_t >
Build HANDSHAKE_DONE frame.
static void append_varint(std::vector< uint8_t > &buffer, uint64_t value)
static auto build_stream_data_blocked(const stream_data_blocked_frame &f) -> std::vector< uint8_t >
Build STREAM_DATA_BLOCKED frame.
static auto build_retire_connection_id(const retire_connection_id_frame &f) -> std::vector< uint8_t >
Build RETIRE_CONNECTION_ID frame.
static auto build_max_streams(const max_streams_frame &f) -> std::vector< uint8_t >
Build MAX_STREAMS frame.
static auto parse_connection_close(std::span< const uint8_t > data, bool is_app) -> Result< std::pair< frame, size_t > >
static auto parse_path_response(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
static auto parse_max_stream_data(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
static auto parse_ack(std::span< const uint8_t > data, bool has_ecn) -> Result< std::pair< frame, size_t > >
static auto peek_type(std::span< const uint8_t > data) -> Result< std::pair< uint64_t, size_t > >
Get the frame type from raw data without full parsing.
static auto parse_ping(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
static auto parse_all(std::span< const uint8_t > data) -> Result< std::vector< frame > >
Parse all frames from buffer.
static auto parse_reset_stream(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
static auto parse_data_blocked(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
static auto parse_retire_connection_id(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
static auto parse_max_streams(std::span< const uint8_t > data, bool bidi) -> Result< std::pair< frame, size_t > >
static auto parse_stream_data_blocked(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
static auto parse_stream(std::span< const uint8_t > data, uint8_t flags) -> Result< std::pair< frame, size_t > >
static auto parse_path_challenge(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
static auto parse_padding(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
static auto parse_new_connection_id(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
static auto parse_crypto(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
static auto parse_stop_sending(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
static auto parse_new_token(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
static auto parse(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
Parse a single frame from buffer.
static auto parse_max_data(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
static auto parse_handshake_done(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
static auto parse_streams_blocked(std::span< const uint8_t > data, bool bidi) -> Result< std::pair< frame, size_t > >
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
constexpr uint8_t fin
Stream is finished.
constexpr uint8_t len
Length field present.
constexpr uint8_t off
Offset field present.
constexpr auto is_stream_frame(uint64_t type) noexcept -> bool
Check if a frame type value represents a STREAM frame.
@ error
Black hole detected, reset to base.
auto frame_type_to_string(frame_type type) -> std::string
Get string name for a frame type.
constexpr auto make_stream_type(bool has_fin, bool has_length, bool has_offset) noexcept -> uint8_t
Build STREAM frame type from flags.
frame_type
QUIC frame types as defined in RFC 9000 Section 12.4.
std::variant< padding_frame, ping_frame, ack_frame, reset_stream_frame, stop_sending_frame, crypto_frame, new_token_frame, stream_frame, max_data_frame, max_stream_data_frame, max_streams_frame, data_blocked_frame, stream_data_blocked_frame, streams_blocked_frame, new_connection_id_frame, retire_connection_id_frame, path_challenge_frame, path_response_frame, connection_close_frame, handshake_done_frame > frame
Variant type holding any QUIC frame.
auto get_frame_type(const frame &f) -> frame_type
Get the frame type for a frame variant.
@ ect0
ECN Capable Transport (0)
@ ecn_ce
Congestion Experienced.
@ ect1
ECN Capable Transport (1)
constexpr auto get_stream_flags(uint64_t type) noexcept -> uint8_t
Extract STREAM flags from frame type.
ACK frame (RFC 9000 Section 19.3)
uint64_t ack_delay
Time since receiving largest_acknowledged (encoded)
std::optional< ecn_counts > ecn
ECN counts (for ACK_ECN frames)
uint64_t largest_acknowledged
Largest packet number acknowledged.
std::vector< ack_range > ranges
Additional ACK ranges.
ACK Range for ACK frames.
uint64_t gap
Number of contiguous unacknowledged packets.
uint64_t length
Number of contiguous acknowledged packets.
CONNECTION_CLOSE frame (RFC 9000 Section 19.19)
uint64_t error_code
Error code indicating reason.
std::string reason_phrase
Human-readable reason.
bool is_application_error
True if application-level error.
uint64_t frame_type
Type of frame that triggered (transport close only)
CRYPTO frame (RFC 9000 Section 19.6)
uint64_t offset
Byte offset in crypto stream.
std::vector< uint8_t > data
Cryptographic handshake data.
DATA_BLOCKED frame (RFC 9000 Section 19.12)
uint64_t maximum_data
Connection-level limit at which blocking occurred.
ECN counts for ACK_ECN frames.
uint64_t ect1
ECT(1) count.
uint64_t ect0
ECT(0) count.
uint64_t ecn_ce
ECN-CE count.
HANDSHAKE_DONE frame (RFC 9000 Section 19.20)
MAX_DATA frame (RFC 9000 Section 19.9)
uint64_t maximum_data
Maximum data that can be sent.
MAX_STREAM_DATA frame (RFC 9000 Section 19.10)
uint64_t maximum_stream_data
Maximum stream data.
uint64_t stream_id
Stream identifier.
MAX_STREAMS frame (RFC 9000 Section 19.11)
uint64_t maximum_streams
Maximum number of streams.
bool bidirectional
True for bidi, false for uni.
NEW_CONNECTION_ID frame (RFC 9000 Section 19.15)
std::vector< uint8_t > connection_id
Connection ID (1-20 bytes)
uint64_t sequence_number
Sequence number for this CID.
std::array< uint8_t, 16 > stateless_reset_token
Stateless reset token.
uint64_t retire_prior_to
CIDs below this should be retired.
NEW_TOKEN frame (RFC 9000 Section 19.7)
std::vector< uint8_t > token
Opaque token.
PADDING frame (RFC 9000 Section 19.1)
size_t count
Number of padding bytes.
PATH_CHALLENGE frame (RFC 9000 Section 19.17)
std::array< uint8_t, 8 > data
Arbitrary 8-byte data.
PATH_RESPONSE frame (RFC 9000 Section 19.18)
std::array< uint8_t, 8 > data
Data from PATH_CHALLENGE.
PING frame (RFC 9000 Section 19.2)
RESET_STREAM frame (RFC 9000 Section 19.4)
uint64_t application_error_code
Application error code.
uint64_t final_size
Final size of stream.
uint64_t stream_id
Stream identifier.
RETIRE_CONNECTION_ID frame (RFC 9000 Section 19.16)
uint64_t sequence_number
Sequence number of CID to retire.
STOP_SENDING frame (RFC 9000 Section 19.5)
uint64_t application_error_code
Application error code.
uint64_t stream_id
Stream identifier.
STREAM_DATA_BLOCKED frame (RFC 9000 Section 19.13)
uint64_t maximum_stream_data
Stream-level limit at which blocking occurred.
uint64_t stream_id
Stream identifier.
STREAM frame (RFC 9000 Section 19.8)
std::vector< uint8_t > data
Stream data.
uint64_t stream_id
Stream identifier.
uint64_t offset
Byte offset in stream (0 if not present)
bool fin
True if this is the final data.
STREAMS_BLOCKED frame (RFC 9000 Section 19.14)
uint64_t maximum_streams
Stream limit at which blocking occurred.
bool bidirectional
True for bidi, false for uni.