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 f.
ranges.push_back({0, first_range.value().first});
430 for (uint64_t i = 0; i < range_count.value().first; ++i)
435 if (gap.is_err())
return make_error<std::pair<frame, size_t>>(
437 range.
gap = gap.value().first;
438 offset += gap.value().second;
441 if (length.is_err())
return make_error<std::pair<frame, size_t>>(
443 range.
length = length.value().first;
444 offset += length.value().second;
446 f.
ranges.push_back(range);
455 if (
ect0.is_err())
return make_error<std::pair<frame, size_t>>(
458 offset +=
ect0.value().second;
461 if (
ect1.is_err())
return make_error<std::pair<frame, size_t>>(
464 offset +=
ect1.value().second;
467 if (
ecn_ce.is_err())
return make_error<std::pair<frame, size_t>>(
470 offset +=
ecn_ce.value().second;
475 return ok(std::make_pair(
frame{f}, offset));
485 if (stream_id.is_err())
return make_error<std::pair<frame, size_t>>(
488 offset += stream_id.value().second;
491 if (error_code.is_err())
return make_error<std::pair<frame, size_t>>(
494 offset += error_code.value().second;
497 if (final_size.is_err())
return make_error<std::pair<frame, size_t>>(
500 offset += final_size.value().second;
502 return ok(std::make_pair(
frame{f}, offset));
512 if (stream_id.is_err())
return make_error<std::pair<frame, size_t>>(
515 offset += stream_id.value().second;
518 if (error_code.is_err())
return make_error<std::pair<frame, size_t>>(
521 offset += error_code.value().second;
523 return ok(std::make_pair(
frame{f}, offset));
533 if (crypto_offset.is_err())
return make_error<std::pair<frame, size_t>>(
535 f.
offset = crypto_offset.value().first;
536 offset += crypto_offset.value().second;
539 if (length.is_err())
return make_error<std::pair<frame, size_t>>(
541 offset += length.value().second;
543 if (data.size() - offset < length.value().first)
545 return make_error<std::pair<frame, size_t>>(
549 f.
data.assign(data.begin() + offset, data.begin() + offset + length.value().first);
550 offset += length.value().first;
552 return ok(std::make_pair(
frame{f}, offset));
562 if (length.is_err())
return make_error<std::pair<frame, size_t>>(
564 offset += length.value().second;
566 if (data.size() - offset < length.value().first)
568 return make_error<std::pair<frame, size_t>>(
572 f.
token.assign(data.begin() + offset, data.begin() + offset + length.value().first);
573 offset += length.value().first;
575 return ok(std::make_pair(
frame{f}, offset));
586 if (stream_id.is_err())
return make_error<std::pair<frame, size_t>>(
589 offset += stream_id.value().second;
595 if (stream_offset.is_err())
return make_error<std::pair<frame, size_t>>(
597 f.
offset = stream_offset.value().first;
598 offset += stream_offset.value().second;
606 if (len_result.is_err())
return make_error<std::pair<frame, size_t>>(
608 length = len_result.value().first;
609 offset += len_result.value().second;
614 length = data.size() - offset;
621 if (data.size() - offset < length)
623 return make_error<std::pair<frame, size_t>>(
627 f.
data.assign(data.begin() + offset, data.begin() + offset + length);
630 return ok(std::make_pair(
frame{f}, offset));
639 if (
max_data.is_err())
return make_error<std::pair<frame, size_t>>(
653 if (stream_id.is_err())
return make_error<std::pair<frame, size_t>>(
656 offset += stream_id.value().second;
659 if (
max_data.is_err())
return make_error<std::pair<frame, size_t>>(
664 return ok(std::make_pair(
frame{f}, offset));
674 if (max_streams.is_err())
return make_error<std::pair<frame, size_t>>(
678 return ok(std::make_pair(
frame{f}, max_streams.value().second));
687 if (
max_data.is_err())
return make_error<std::pair<frame, size_t>>(
701 if (stream_id.is_err())
return make_error<std::pair<frame, size_t>>(
704 offset += stream_id.value().second;
707 if (
max_data.is_err())
return make_error<std::pair<frame, size_t>>(
712 return ok(std::make_pair(
frame{f}, offset));
722 if (max_streams.is_err())
return make_error<std::pair<frame, size_t>>(
726 return ok(std::make_pair(
frame{f}, max_streams.value().second));
737 if (seq.is_err())
return make_error<std::pair<frame, size_t>>(
740 offset += seq.value().second;
744 if (retire.is_err())
return make_error<std::pair<frame, size_t>>(
747 offset += retire.value().second;
750 if (data.size() <= offset)
752 return make_error<std::pair<frame, size_t>>(
755 uint8_t cid_len = data[offset++];
758 return make_error<std::pair<frame, size_t>>(
763 if (data.size() - offset < cid_len)
765 return make_error<std::pair<frame, size_t>>(
768 f.
connection_id.assign(data.begin() + offset, data.begin() + offset + cid_len);
772 if (data.size() - offset < 16)
774 return make_error<std::pair<frame, size_t>>(
777 std::copy(data.begin() + offset, data.begin() + offset + 16,
781 return ok(std::make_pair(
frame{f}, offset));
790 if (seq.is_err())
return make_error<std::pair<frame, size_t>>(
794 return ok(std::make_pair(
frame{f}, seq.value().second));
802 return make_error<std::pair<frame, size_t>>(
807 std::copy(data.begin(), data.begin() + 8, f.
data.begin());
809 return ok(std::make_pair(
frame{f},
size_t{8}));
817 return make_error<std::pair<frame, size_t>>(
822 std::copy(data.begin(), data.begin() + 8, f.
data.begin());
824 return ok(std::make_pair(
frame{f},
size_t{8}));
836 if (error_code.is_err())
return make_error<std::pair<frame, size_t>>(
839 offset += error_code.value().second;
845 if (frame_type_val.is_err())
return make_error<std::pair<frame, size_t>>(
848 offset += frame_type_val.value().second;
853 if (reason_len.is_err())
return make_error<std::pair<frame, size_t>>(
855 offset += reason_len.value().second;
858 if (data.size() - offset < reason_len.value().first)
860 return make_error<std::pair<frame, size_t>>(
864 f.
reason_phrase.assign(
reinterpret_cast<const char*
>(data.data() + offset),
865 reason_len.value().first);
866 offset += reason_len.value().first;
868 return ok(std::make_pair(
frame{f}, offset));
884 buffer.insert(buffer.end(), encoded.begin(), encoded.end());
888 std::span<const uint8_t> data)
890 buffer.insert(buffer.end(), data.begin(), data.end());
895 return std::visit([](
const auto& fr) -> std::vector<uint8_t> {
896 using T = std::decay_t<
decltype(fr)>;
897 if constexpr (std::is_same_v<T, padding_frame>)
898 return build_padding(fr.count);
899 else if constexpr (std::is_same_v<T, ping_frame>)
901 else if constexpr (std::is_same_v<T, ack_frame>)
902 return build_ack(fr);
903 else if constexpr (std::is_same_v<T, reset_stream_frame>)
904 return build_reset_stream(fr);
905 else if constexpr (std::is_same_v<T, stop_sending_frame>)
906 return build_stop_sending(fr);
907 else if constexpr (std::is_same_v<T, crypto_frame>)
908 return build_crypto(fr);
909 else if constexpr (std::is_same_v<T, new_token_frame>)
910 return build_new_token(fr);
911 else if constexpr (std::is_same_v<T, stream_frame>)
912 return build_stream(fr);
913 else if constexpr (std::is_same_v<T, max_data_frame>)
914 return build_max_data(fr);
915 else if constexpr (std::is_same_v<T, max_stream_data_frame>)
916 return build_max_stream_data(fr);
917 else if constexpr (std::is_same_v<T, max_streams_frame>)
918 return build_max_streams(fr);
919 else if constexpr (std::is_same_v<T, data_blocked_frame>)
920 return build_data_blocked(fr);
921 else if constexpr (std::is_same_v<T, stream_data_blocked_frame>)
922 return build_stream_data_blocked(fr);
923 else if constexpr (std::is_same_v<T, streams_blocked_frame>)
924 return build_streams_blocked(fr);
925 else if constexpr (std::is_same_v<T, new_connection_id_frame>)
926 return build_new_connection_id(fr);
927 else if constexpr (std::is_same_v<T, retire_connection_id_frame>)
928 return build_retire_connection_id(fr);
929 else if constexpr (std::is_same_v<T, path_challenge_frame>)
930 return build_path_challenge(fr);
931 else if constexpr (std::is_same_v<T, path_response_frame>)
932 return build_path_response(fr);
933 else if constexpr (std::is_same_v<T, connection_close_frame>)
934 return build_connection_close(fr);
935 else if constexpr (std::is_same_v<T, handshake_done_frame>)
936 return build_handshake_done();
944 return std::vector<uint8_t>(count, 0x00);
954 std::vector<uint8_t> buffer;
961 append_varint(buffer, f.largest_acknowledged);
964 append_varint(buffer, f.ack_delay);
967 append_varint(buffer, f.ranges.empty() ? 0 : f.ranges.size() - 1);
971 uint64_t first_range = 0;
972 if (!f.ranges.empty())
974 first_range = f.ranges[0].length;
976 append_varint(buffer, first_range);
979 for (
size_t i = 1; i < f.ranges.size(); ++i)
981 append_varint(buffer, f.ranges[i].gap);
982 append_varint(buffer, f.ranges[i].length);
988 append_varint(buffer, f.ecn->ect0);
989 append_varint(buffer, f.ecn->ect1);
990 append_varint(buffer, f.ecn->ecn_ce);
997 -> std::vector<uint8_t>
999 std::vector<uint8_t> buffer;
1001 append_varint(buffer, f.stream_id);
1002 append_varint(buffer, f.application_error_code);
1003 append_varint(buffer, f.final_size);
1008 -> std::vector<uint8_t>
1010 std::vector<uint8_t> buffer;
1012 append_varint(buffer, f.stream_id);
1013 append_varint(buffer, f.application_error_code);
1019 std::vector<uint8_t> buffer;
1021 append_varint(buffer, f.offset);
1022 append_varint(buffer, f.data.size());
1023 append_bytes(buffer, f.data);
1028 -> std::vector<uint8_t>
1030 std::vector<uint8_t> buffer;
1032 append_varint(buffer, f.token.size());
1033 append_bytes(buffer, f.token);
1038 -> std::vector<uint8_t>
1040 std::vector<uint8_t> buffer;
1044 buffer.push_back(type);
1047 append_varint(buffer, f.stream_id);
1052 append_varint(buffer, f.offset);
1058 append_varint(buffer, f.data.size());
1062 append_bytes(buffer, f.data);
1068 -> std::vector<uint8_t>
1070 std::vector<uint8_t> buffer;
1072 append_varint(buffer, f.maximum_data);
1077 -> std::vector<uint8_t>
1079 std::vector<uint8_t> buffer;
1081 append_varint(buffer, f.stream_id);
1082 append_varint(buffer, f.maximum_stream_data);
1087 -> std::vector<uint8_t>
1089 std::vector<uint8_t> buffer;
1090 append_varint(buffer, f.bidirectional
1093 append_varint(buffer, f.maximum_streams);
1098 -> std::vector<uint8_t>
1100 std::vector<uint8_t> buffer;
1102 append_varint(buffer, f.maximum_data);
1107 -> std::vector<uint8_t>
1109 std::vector<uint8_t> buffer;
1111 append_varint(buffer, f.stream_id);
1112 append_varint(buffer, f.maximum_stream_data);
1117 -> std::vector<uint8_t>
1119 std::vector<uint8_t> buffer;
1120 append_varint(buffer, f.bidirectional
1123 append_varint(buffer, f.maximum_streams);
1128 -> std::vector<uint8_t>
1130 std::vector<uint8_t> buffer;
1132 append_varint(buffer, f.sequence_number);
1133 append_varint(buffer, f.retire_prior_to);
1136 buffer.push_back(
static_cast<uint8_t
>(f.connection_id.size()));
1139 append_bytes(buffer, f.connection_id);
1142 buffer.insert(buffer.end(), f.stateless_reset_token.begin(),
1143 f.stateless_reset_token.end());
1149 -> std::vector<uint8_t>
1151 std::vector<uint8_t> buffer;
1153 append_varint(buffer, f.sequence_number);
1158 -> std::vector<uint8_t>
1160 std::vector<uint8_t> buffer;
1162 buffer.insert(buffer.end(), f.data.begin(), f.data.end());
1167 -> std::vector<uint8_t>
1169 std::vector<uint8_t> buffer;
1171 buffer.insert(buffer.end(), f.data.begin(), f.data.end());
1176 -> std::vector<uint8_t>
1178 std::vector<uint8_t> buffer;
1179 append_varint(buffer, f.is_application_error
1183 append_varint(buffer, f.error_code);
1186 if (!f.is_application_error)
1188 append_varint(buffer, f.frame_type);
1192 append_varint(buffer, f.reason_phrase.size());
1195 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.