Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
frame.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2024, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
7
9{
10
11namespace
12{
13 constexpr const char* source = "quic::frame";
14
15 // Error helper
16 template<typename T>
17 auto make_error(int code, const std::string& message,
18 const std::string& details = "") -> Result<T>
19 {
20 return error<T>(code, message, source, details);
21 }
22} // namespace
23
24// ============================================================================
25// frame_types.h implementations
26// ============================================================================
27
29{
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>)
35 return frame_type::ping;
36 else if constexpr (std::is_same_v<T, ack_frame>)
37 return fr.ecn ? frame_type::ack_ecn : frame_type::ack;
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>)
43 return frame_type::crypto;
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>)
53 return fr.bidirectional ? frame_type::max_streams_bidi
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>)
60 return fr.bidirectional ? frame_type::streams_blocked_bidi
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>)
71 return fr.is_application_error ? frame_type::connection_close_app
73 else if constexpr (std::is_same_v<T, handshake_done_frame>)
75 else
77 }, f);
78}
79
80auto frame_type_to_string(frame_type type) -> std::string
81{
82 switch (type)
83 {
84 case frame_type::padding: return "PADDING";
85 case frame_type::ping: return "PING";
86 case frame_type::ack: return "ACK";
87 case frame_type::ack_ecn: return "ACK_ECN";
88 case frame_type::reset_stream: return "RESET_STREAM";
89 case frame_type::stop_sending: return "STOP_SENDING";
90 case frame_type::crypto: return "CRYPTO";
91 case frame_type::new_token: return "NEW_TOKEN";
92 case frame_type::stream_base: return "STREAM";
93 case frame_type::max_data: return "MAX_DATA";
94 case frame_type::max_stream_data: return "MAX_STREAM_DATA";
95 case frame_type::max_streams_bidi: return "MAX_STREAMS_BIDI";
96 case frame_type::max_streams_uni: return "MAX_STREAMS_UNI";
97 case frame_type::data_blocked: return "DATA_BLOCKED";
98 case frame_type::stream_data_blocked: return "STREAM_DATA_BLOCKED";
99 case frame_type::streams_blocked_bidi: return "STREAMS_BLOCKED_BIDI";
100 case frame_type::streams_blocked_uni: return "STREAMS_BLOCKED_UNI";
101 case frame_type::new_connection_id: return "NEW_CONNECTION_ID";
102 case frame_type::retire_connection_id: return "RETIRE_CONNECTION_ID";
103 case frame_type::path_challenge: return "PATH_CHALLENGE";
104 case frame_type::path_response: return "PATH_RESPONSE";
105 case frame_type::connection_close: return "CONNECTION_CLOSE";
106 case frame_type::connection_close_app: return "CONNECTION_CLOSE_APP";
107 case frame_type::handshake_done: return "HANDSHAKE_DONE";
108 default: return "UNKNOWN";
109 }
110}
111
112// ============================================================================
113// frame_parser implementations
114// ============================================================================
115
116auto frame_parser::peek_type(std::span<const uint8_t> data)
118{
119 return varint::decode(data);
120}
121
122auto frame_parser::parse(std::span<const uint8_t> data)
124{
125 if (data.empty())
126 {
127 return make_error<std::pair<frame, size_t>>(
129 "Empty frame data");
130 }
131
132 // Parse frame type
133 auto type_result = varint::decode(data);
134 if (type_result.is_err())
135 {
136 return make_error<std::pair<frame, size_t>>(
138 "Failed to decode frame type");
139 }
140
141 auto [type_value, type_len] = type_result.value();
142 auto remaining = data.subspan(type_len);
143
144 // Check for STREAM frames (0x08-0x0f)
145 if (is_stream_frame(type_value))
146 {
147 auto result = parse_stream(remaining, get_stream_flags(type_value));
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));
151 }
152
153 // Dispatch based on frame type
154 switch (static_cast<frame_type>(type_value))
155 {
157 return parse_padding(data);
158
159 case frame_type::ping:
160 {
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));
165 }
166
167 case frame_type::ack:
168 {
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));
173 }
174
176 {
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));
181 }
182
184 {
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));
189 }
190
192 {
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));
197 }
198
200 {
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));
205 }
206
208 {
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));
213 }
214
216 {
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));
221 }
222
224 {
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));
229 }
230
232 {
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));
237 }
238
240 {
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));
245 }
246
248 {
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));
253 }
254
256 {
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));
261 }
262
264 {
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));
269 }
270
272 {
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));
277 }
278
280 {
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));
285 }
286
288 {
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));
293 }
294
296 {
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));
301 }
302
304 {
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));
309 }
310
312 {
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));
317 }
318
320 {
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));
325 }
326
328 {
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));
333 }
334
335 default:
336 return make_error<std::pair<frame, size_t>>(
338 "Unknown frame type",
339 "type=" + std::to_string(type_value));
340 }
341}
342
343auto frame_parser::parse_all(std::span<const uint8_t> data)
345{
346 std::vector<frame> frames;
347 size_t offset = 0;
348
349 while (offset < data.size())
350 {
351 auto result = parse(data.subspan(offset));
352 if (result.is_err())
353 {
354 return make_error<std::vector<frame>>(
356 "Failed to parse frame at offset " + std::to_string(offset));
357 }
358
359 auto& [f, consumed] = result.value();
360 frames.push_back(std::move(f));
361 offset += consumed;
362 }
363
364 return ok(std::move(frames));
365}
366
367auto frame_parser::parse_padding(std::span<const uint8_t> data)
369{
370 // Count consecutive padding bytes
371 size_t count = 0;
372 while (count < data.size() && data[count] == 0x00)
373 {
374 ++count;
375 }
376
377 if (count == 0)
378 {
379 count = 1; // At least one padding byte was consumed (the type)
380 }
381
383 f.count = count;
384 return ok(std::make_pair(frame{f}, count));
385}
386
387auto frame_parser::parse_ping(std::span<const uint8_t> /*data*/)
389{
390 // PING frame has no payload after type
391 return ok(std::make_pair(frame{ping_frame{}}, size_t{0}));
392}
393
394auto frame_parser::parse_ack(std::span<const uint8_t> data, bool has_ecn)
396{
397 size_t offset = 0;
398 ack_frame f;
399
400 // Largest Acknowledged
401 auto largest = varint::decode(data.subspan(offset));
402 if (largest.is_err()) return make_error<std::pair<frame, size_t>>(
403 error_codes::common_errors::invalid_argument, "Failed to parse largest acknowledged");
404 f.largest_acknowledged = largest.value().first;
405 offset += largest.value().second;
406
407 // ACK Delay
408 auto delay = varint::decode(data.subspan(offset));
409 if (delay.is_err()) return make_error<std::pair<frame, size_t>>(
410 error_codes::common_errors::invalid_argument, "Failed to parse ack delay");
411 f.ack_delay = delay.value().first;
412 offset += delay.value().second;
413
414 // ACK Range Count
415 auto range_count = varint::decode(data.subspan(offset));
416 if (range_count.is_err()) return make_error<std::pair<frame, size_t>>(
417 error_codes::common_errors::invalid_argument, "Failed to parse ack range count");
418 offset += range_count.value().second;
419
420 // First ACK Range
421 auto first_range = varint::decode(data.subspan(offset));
422 if (first_range.is_err()) return make_error<std::pair<frame, size_t>>(
423 error_codes::common_errors::invalid_argument, "Failed to parse first ack range");
424 offset += first_range.value().second;
425
426 // The first range implicitly starts at largest_acknowledged
427 // Additional ranges
428 for (uint64_t i = 0; i < range_count.value().first; ++i)
429 {
430 ack_range range;
431
432 auto gap = varint::decode(data.subspan(offset));
433 if (gap.is_err()) return make_error<std::pair<frame, size_t>>(
434 error_codes::common_errors::invalid_argument, "Failed to parse ack gap");
435 range.gap = gap.value().first;
436 offset += gap.value().second;
437
438 auto length = varint::decode(data.subspan(offset));
439 if (length.is_err()) return make_error<std::pair<frame, size_t>>(
440 error_codes::common_errors::invalid_argument, "Failed to parse ack range length");
441 range.length = length.value().first;
442 offset += length.value().second;
443
444 f.ranges.push_back(range);
445 }
446
447 // ECN Counts (if present)
448 if (has_ecn)
449 {
450 ecn_counts ecn;
451
452 auto ect0 = varint::decode(data.subspan(offset));
453 if (ect0.is_err()) return make_error<std::pair<frame, size_t>>(
454 error_codes::common_errors::invalid_argument, "Failed to parse ECT(0) count");
455 ecn.ect0 = ect0.value().first;
456 offset += ect0.value().second;
457
458 auto ect1 = varint::decode(data.subspan(offset));
459 if (ect1.is_err()) return make_error<std::pair<frame, size_t>>(
460 error_codes::common_errors::invalid_argument, "Failed to parse ECT(1) count");
461 ecn.ect1 = ect1.value().first;
462 offset += ect1.value().second;
463
464 auto ecn_ce = varint::decode(data.subspan(offset));
465 if (ecn_ce.is_err()) return make_error<std::pair<frame, size_t>>(
466 error_codes::common_errors::invalid_argument, "Failed to parse ECN-CE count");
467 ecn.ecn_ce = ecn_ce.value().first;
468 offset += ecn_ce.value().second;
469
470 f.ecn = ecn;
471 }
472
473 return ok(std::make_pair(frame{f}, offset));
474}
475
476auto frame_parser::parse_reset_stream(std::span<const uint8_t> data)
478{
479 size_t offset = 0;
481
482 auto stream_id = varint::decode(data.subspan(offset));
483 if (stream_id.is_err()) return make_error<std::pair<frame, size_t>>(
484 error_codes::common_errors::invalid_argument, "Failed to parse stream id");
485 f.stream_id = stream_id.value().first;
486 offset += stream_id.value().second;
487
488 auto error_code = varint::decode(data.subspan(offset));
489 if (error_code.is_err()) return make_error<std::pair<frame, size_t>>(
490 error_codes::common_errors::invalid_argument, "Failed to parse error code");
491 f.application_error_code = error_code.value().first;
492 offset += error_code.value().second;
493
494 auto final_size = varint::decode(data.subspan(offset));
495 if (final_size.is_err()) return make_error<std::pair<frame, size_t>>(
496 error_codes::common_errors::invalid_argument, "Failed to parse final size");
497 f.final_size = final_size.value().first;
498 offset += final_size.value().second;
499
500 return ok(std::make_pair(frame{f}, offset));
501}
502
503auto frame_parser::parse_stop_sending(std::span<const uint8_t> data)
505{
506 size_t offset = 0;
508
509 auto stream_id = varint::decode(data.subspan(offset));
510 if (stream_id.is_err()) return make_error<std::pair<frame, size_t>>(
511 error_codes::common_errors::invalid_argument, "Failed to parse stream id");
512 f.stream_id = stream_id.value().first;
513 offset += stream_id.value().second;
514
515 auto error_code = varint::decode(data.subspan(offset));
516 if (error_code.is_err()) return make_error<std::pair<frame, size_t>>(
517 error_codes::common_errors::invalid_argument, "Failed to parse error code");
518 f.application_error_code = error_code.value().first;
519 offset += error_code.value().second;
520
521 return ok(std::make_pair(frame{f}, offset));
522}
523
524auto frame_parser::parse_crypto(std::span<const uint8_t> data)
526{
527 size_t offset = 0;
528 crypto_frame f;
529
530 auto crypto_offset = varint::decode(data.subspan(offset));
531 if (crypto_offset.is_err()) return make_error<std::pair<frame, size_t>>(
532 error_codes::common_errors::invalid_argument, "Failed to parse crypto offset");
533 f.offset = crypto_offset.value().first;
534 offset += crypto_offset.value().second;
535
536 auto length = varint::decode(data.subspan(offset));
537 if (length.is_err()) return make_error<std::pair<frame, size_t>>(
538 error_codes::common_errors::invalid_argument, "Failed to parse crypto length");
539 offset += length.value().second;
540
541 if (data.size() - offset < length.value().first)
542 {
543 return make_error<std::pair<frame, size_t>>(
544 error_codes::common_errors::invalid_argument, "Insufficient crypto data");
545 }
546
547 f.data.assign(data.begin() + offset, data.begin() + offset + length.value().first);
548 offset += length.value().first;
549
550 return ok(std::make_pair(frame{f}, offset));
551}
552
553auto frame_parser::parse_new_token(std::span<const uint8_t> data)
555{
556 size_t offset = 0;
558
559 auto length = varint::decode(data.subspan(offset));
560 if (length.is_err()) return make_error<std::pair<frame, size_t>>(
561 error_codes::common_errors::invalid_argument, "Failed to parse token length");
562 offset += length.value().second;
563
564 if (data.size() - offset < length.value().first)
565 {
566 return make_error<std::pair<frame, size_t>>(
567 error_codes::common_errors::invalid_argument, "Insufficient token data");
568 }
569
570 f.token.assign(data.begin() + offset, data.begin() + offset + length.value().first);
571 offset += length.value().first;
572
573 return ok(std::make_pair(frame{f}, offset));
574}
575
576auto frame_parser::parse_stream(std::span<const uint8_t> data, uint8_t flags)
578{
579 size_t offset = 0;
580 stream_frame f;
581
582 // Stream ID
583 auto stream_id = varint::decode(data.subspan(offset));
584 if (stream_id.is_err()) return make_error<std::pair<frame, size_t>>(
585 error_codes::common_errors::invalid_argument, "Failed to parse stream id");
586 f.stream_id = stream_id.value().first;
587 offset += stream_id.value().second;
588
589 // Offset (if OFF bit set)
590 if (flags & stream_flags::off)
591 {
592 auto stream_offset = varint::decode(data.subspan(offset));
593 if (stream_offset.is_err()) return make_error<std::pair<frame, size_t>>(
594 error_codes::common_errors::invalid_argument, "Failed to parse stream offset");
595 f.offset = stream_offset.value().first;
596 offset += stream_offset.value().second;
597 }
598
599 // Length (if LEN bit set)
600 uint64_t length = 0;
601 if (flags & stream_flags::len)
602 {
603 auto len_result = varint::decode(data.subspan(offset));
604 if (len_result.is_err()) return make_error<std::pair<frame, size_t>>(
605 error_codes::common_errors::invalid_argument, "Failed to parse stream length");
606 length = len_result.value().first;
607 offset += len_result.value().second;
608 }
609 else
610 {
611 // Without LEN, data extends to end of packet
612 length = data.size() - offset;
613 }
614
615 // FIN bit
616 f.fin = (flags & stream_flags::fin) != 0;
617
618 // Data
619 if (data.size() - offset < length)
620 {
621 return make_error<std::pair<frame, size_t>>(
622 error_codes::common_errors::invalid_argument, "Insufficient stream data");
623 }
624
625 f.data.assign(data.begin() + offset, data.begin() + offset + length);
626 offset += length;
627
628 return ok(std::make_pair(frame{f}, offset));
629}
630
631auto frame_parser::parse_max_data(std::span<const uint8_t> data)
633{
635
636 auto max_data = varint::decode(data);
637 if (max_data.is_err()) return make_error<std::pair<frame, size_t>>(
638 error_codes::common_errors::invalid_argument, "Failed to parse max data");
639 f.maximum_data = max_data.value().first;
640
641 return ok(std::make_pair(frame{f}, max_data.value().second));
642}
643
644auto frame_parser::parse_max_stream_data(std::span<const uint8_t> data)
646{
647 size_t offset = 0;
649
650 auto stream_id = varint::decode(data.subspan(offset));
651 if (stream_id.is_err()) return make_error<std::pair<frame, size_t>>(
652 error_codes::common_errors::invalid_argument, "Failed to parse stream id");
653 f.stream_id = stream_id.value().first;
654 offset += stream_id.value().second;
655
656 auto max_data = varint::decode(data.subspan(offset));
657 if (max_data.is_err()) return make_error<std::pair<frame, size_t>>(
658 error_codes::common_errors::invalid_argument, "Failed to parse max stream data");
659 f.maximum_stream_data = max_data.value().first;
660 offset += max_data.value().second;
661
662 return ok(std::make_pair(frame{f}, offset));
663}
664
665auto frame_parser::parse_max_streams(std::span<const uint8_t> data, bool bidi)
667{
669 f.bidirectional = bidi;
670
671 auto max_streams = varint::decode(data);
672 if (max_streams.is_err()) return make_error<std::pair<frame, size_t>>(
673 error_codes::common_errors::invalid_argument, "Failed to parse max streams");
674 f.maximum_streams = max_streams.value().first;
675
676 return ok(std::make_pair(frame{f}, max_streams.value().second));
677}
678
679auto frame_parser::parse_data_blocked(std::span<const uint8_t> data)
681{
683
684 auto max_data = varint::decode(data);
685 if (max_data.is_err()) return make_error<std::pair<frame, size_t>>(
686 error_codes::common_errors::invalid_argument, "Failed to parse max data");
687 f.maximum_data = max_data.value().first;
688
689 return ok(std::make_pair(frame{f}, max_data.value().second));
690}
691
692auto frame_parser::parse_stream_data_blocked(std::span<const uint8_t> data)
694{
695 size_t offset = 0;
697
698 auto stream_id = varint::decode(data.subspan(offset));
699 if (stream_id.is_err()) return make_error<std::pair<frame, size_t>>(
700 error_codes::common_errors::invalid_argument, "Failed to parse stream id");
701 f.stream_id = stream_id.value().first;
702 offset += stream_id.value().second;
703
704 auto max_data = varint::decode(data.subspan(offset));
705 if (max_data.is_err()) return make_error<std::pair<frame, size_t>>(
706 error_codes::common_errors::invalid_argument, "Failed to parse max stream data");
707 f.maximum_stream_data = max_data.value().first;
708 offset += max_data.value().second;
709
710 return ok(std::make_pair(frame{f}, offset));
711}
712
713auto frame_parser::parse_streams_blocked(std::span<const uint8_t> data, bool bidi)
715{
717 f.bidirectional = bidi;
718
719 auto max_streams = varint::decode(data);
720 if (max_streams.is_err()) return make_error<std::pair<frame, size_t>>(
721 error_codes::common_errors::invalid_argument, "Failed to parse max streams");
722 f.maximum_streams = max_streams.value().first;
723
724 return ok(std::make_pair(frame{f}, max_streams.value().second));
725}
726
727auto frame_parser::parse_new_connection_id(std::span<const uint8_t> data)
729{
730 size_t offset = 0;
732
733 // Sequence Number
734 auto seq = varint::decode(data.subspan(offset));
735 if (seq.is_err()) return make_error<std::pair<frame, size_t>>(
736 error_codes::common_errors::invalid_argument, "Failed to parse sequence number");
737 f.sequence_number = seq.value().first;
738 offset += seq.value().second;
739
740 // Retire Prior To
741 auto retire = varint::decode(data.subspan(offset));
742 if (retire.is_err()) return make_error<std::pair<frame, size_t>>(
743 error_codes::common_errors::invalid_argument, "Failed to parse retire prior to");
744 f.retire_prior_to = retire.value().first;
745 offset += retire.value().second;
746
747 // Connection ID Length (1 byte, not varint)
748 if (data.size() <= offset)
749 {
750 return make_error<std::pair<frame, size_t>>(
751 error_codes::common_errors::invalid_argument, "Missing connection id length");
752 }
753 uint8_t cid_len = data[offset++];
754 if (cid_len > 20)
755 {
756 return make_error<std::pair<frame, size_t>>(
757 error_codes::common_errors::invalid_argument, "Connection ID too long");
758 }
759
760 // Connection ID
761 if (data.size() - offset < cid_len)
762 {
763 return make_error<std::pair<frame, size_t>>(
764 error_codes::common_errors::invalid_argument, "Insufficient connection id data");
765 }
766 f.connection_id.assign(data.begin() + offset, data.begin() + offset + cid_len);
767 offset += cid_len;
768
769 // Stateless Reset Token (16 bytes)
770 if (data.size() - offset < 16)
771 {
772 return make_error<std::pair<frame, size_t>>(
773 error_codes::common_errors::invalid_argument, "Insufficient reset token data");
774 }
775 std::copy(data.begin() + offset, data.begin() + offset + 16,
776 f.stateless_reset_token.begin());
777 offset += 16;
778
779 return ok(std::make_pair(frame{f}, offset));
780}
781
782auto frame_parser::parse_retire_connection_id(std::span<const uint8_t> data)
784{
786
787 auto seq = varint::decode(data);
788 if (seq.is_err()) return make_error<std::pair<frame, size_t>>(
789 error_codes::common_errors::invalid_argument, "Failed to parse sequence number");
790 f.sequence_number = seq.value().first;
791
792 return ok(std::make_pair(frame{f}, seq.value().second));
793}
794
795auto frame_parser::parse_path_challenge(std::span<const uint8_t> data)
797{
798 if (data.size() < 8)
799 {
800 return make_error<std::pair<frame, size_t>>(
801 error_codes::common_errors::invalid_argument, "Insufficient path challenge data");
802 }
803
805 std::copy(data.begin(), data.begin() + 8, f.data.begin());
806
807 return ok(std::make_pair(frame{f}, size_t{8}));
808}
809
810auto frame_parser::parse_path_response(std::span<const uint8_t> data)
812{
813 if (data.size() < 8)
814 {
815 return make_error<std::pair<frame, size_t>>(
816 error_codes::common_errors::invalid_argument, "Insufficient path response data");
817 }
818
820 std::copy(data.begin(), data.begin() + 8, f.data.begin());
821
822 return ok(std::make_pair(frame{f}, size_t{8}));
823}
824
825auto frame_parser::parse_connection_close(std::span<const uint8_t> data, bool is_app)
827{
828 size_t offset = 0;
830 f.is_application_error = is_app;
831
832 // Error Code
833 auto error_code = varint::decode(data.subspan(offset));
834 if (error_code.is_err()) return make_error<std::pair<frame, size_t>>(
835 error_codes::common_errors::invalid_argument, "Failed to parse error code");
836 f.error_code = error_code.value().first;
837 offset += error_code.value().second;
838
839 // Frame Type (transport close only)
840 if (!is_app)
841 {
842 auto frame_type_val = varint::decode(data.subspan(offset));
843 if (frame_type_val.is_err()) return make_error<std::pair<frame, size_t>>(
844 error_codes::common_errors::invalid_argument, "Failed to parse frame type");
845 f.frame_type = frame_type_val.value().first;
846 offset += frame_type_val.value().second;
847 }
848
849 // Reason Phrase Length
850 auto reason_len = varint::decode(data.subspan(offset));
851 if (reason_len.is_err()) return make_error<std::pair<frame, size_t>>(
852 error_codes::common_errors::invalid_argument, "Failed to parse reason phrase length");
853 offset += reason_len.value().second;
854
855 // Reason Phrase
856 if (data.size() - offset < reason_len.value().first)
857 {
858 return make_error<std::pair<frame, size_t>>(
859 error_codes::common_errors::invalid_argument, "Insufficient reason phrase data");
860 }
861
862 f.reason_phrase.assign(reinterpret_cast<const char*>(data.data() + offset),
863 reason_len.value().first);
864 offset += reason_len.value().first;
865
866 return ok(std::make_pair(frame{f}, offset));
867}
868
869auto frame_parser::parse_handshake_done(std::span<const uint8_t> /*data*/)
871{
872 return ok(std::make_pair(frame{handshake_done_frame{}}, size_t{0}));
873}
874
875// ============================================================================
876// frame_builder implementations
877// ============================================================================
878
879void frame_builder::append_varint(std::vector<uint8_t>& buffer, uint64_t value)
880{
881 auto encoded = varint::encode(value);
882 buffer.insert(buffer.end(), encoded.begin(), encoded.end());
883}
884
885void frame_builder::append_bytes(std::vector<uint8_t>& buffer,
886 std::span<const uint8_t> data)
887{
888 buffer.insert(buffer.end(), data.begin(), data.end());
889}
890
891auto frame_builder::build(const frame& f) -> std::vector<uint8_t>
892{
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>)
898 return build_ping();
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();
935 else
936 return {};
937 }, f);
938}
939
940auto frame_builder::build_padding(size_t count) -> std::vector<uint8_t>
941{
942 return std::vector<uint8_t>(count, 0x00);
943}
944
945auto frame_builder::build_ping() -> std::vector<uint8_t>
946{
947 return {0x01};
948}
949
950auto frame_builder::build_ack(const ack_frame& f) -> std::vector<uint8_t>
951{
952 std::vector<uint8_t> buffer;
953
954 // Frame type
955 append_varint(buffer, f.ecn ? static_cast<uint64_t>(frame_type::ack_ecn)
956 : static_cast<uint64_t>(frame_type::ack));
957
958 // Largest Acknowledged
959 append_varint(buffer, f.largest_acknowledged);
960
961 // ACK Delay
962 append_varint(buffer, f.ack_delay);
963
964 // ACK Range Count
965 append_varint(buffer, f.ranges.size());
966
967 // First ACK Range (largest_ack - smallest_ack in first range)
968 // For simplicity, we'll use 0 if no ranges are specified
969 uint64_t first_range = 0;
970 if (!f.ranges.empty())
971 {
972 first_range = f.ranges[0].length;
973 }
974 append_varint(buffer, first_range);
975
976 // Additional ranges (skip first)
977 for (size_t i = 1; i < f.ranges.size(); ++i)
978 {
979 append_varint(buffer, f.ranges[i].gap);
980 append_varint(buffer, f.ranges[i].length);
981 }
982
983 // ECN Counts
984 if (f.ecn)
985 {
986 append_varint(buffer, f.ecn->ect0);
987 append_varint(buffer, f.ecn->ect1);
988 append_varint(buffer, f.ecn->ecn_ce);
989 }
990
991 return buffer;
992}
993
995 -> std::vector<uint8_t>
996{
997 std::vector<uint8_t> buffer;
998 append_varint(buffer, static_cast<uint64_t>(frame_type::reset_stream));
999 append_varint(buffer, f.stream_id);
1000 append_varint(buffer, f.application_error_code);
1001 append_varint(buffer, f.final_size);
1002 return buffer;
1003}
1004
1006 -> std::vector<uint8_t>
1007{
1008 std::vector<uint8_t> buffer;
1009 append_varint(buffer, static_cast<uint64_t>(frame_type::stop_sending));
1010 append_varint(buffer, f.stream_id);
1011 append_varint(buffer, f.application_error_code);
1012 return buffer;
1013}
1014
1015auto frame_builder::build_crypto(const crypto_frame& f) -> std::vector<uint8_t>
1016{
1017 std::vector<uint8_t> buffer;
1018 append_varint(buffer, static_cast<uint64_t>(frame_type::crypto));
1019 append_varint(buffer, f.offset);
1020 append_varint(buffer, f.data.size());
1021 append_bytes(buffer, f.data);
1022 return buffer;
1023}
1024
1026 -> std::vector<uint8_t>
1027{
1028 std::vector<uint8_t> buffer;
1029 append_varint(buffer, static_cast<uint64_t>(frame_type::new_token));
1030 append_varint(buffer, f.token.size());
1031 append_bytes(buffer, f.token);
1032 return buffer;
1033}
1034
1035auto frame_builder::build_stream(const stream_frame& f, bool include_length)
1036 -> std::vector<uint8_t>
1037{
1038 std::vector<uint8_t> buffer;
1039
1040 // Build frame type with flags
1041 uint8_t type = make_stream_type(f.fin, include_length, f.offset > 0);
1042 buffer.push_back(type);
1043
1044 // Stream ID
1045 append_varint(buffer, f.stream_id);
1046
1047 // Offset (if non-zero)
1048 if (f.offset > 0)
1049 {
1050 append_varint(buffer, f.offset);
1051 }
1052
1053 // Length (if requested)
1054 if (include_length)
1055 {
1056 append_varint(buffer, f.data.size());
1057 }
1058
1059 // Data
1060 append_bytes(buffer, f.data);
1061
1062 return buffer;
1063}
1064
1066 -> std::vector<uint8_t>
1067{
1068 std::vector<uint8_t> buffer;
1069 append_varint(buffer, static_cast<uint64_t>(frame_type::max_data));
1070 append_varint(buffer, f.maximum_data);
1071 return buffer;
1072}
1073
1075 -> std::vector<uint8_t>
1076{
1077 std::vector<uint8_t> buffer;
1078 append_varint(buffer, static_cast<uint64_t>(frame_type::max_stream_data));
1079 append_varint(buffer, f.stream_id);
1080 append_varint(buffer, f.maximum_stream_data);
1081 return buffer;
1082}
1083
1085 -> std::vector<uint8_t>
1086{
1087 std::vector<uint8_t> buffer;
1088 append_varint(buffer, f.bidirectional
1089 ? static_cast<uint64_t>(frame_type::max_streams_bidi)
1090 : static_cast<uint64_t>(frame_type::max_streams_uni));
1091 append_varint(buffer, f.maximum_streams);
1092 return buffer;
1093}
1094
1096 -> std::vector<uint8_t>
1097{
1098 std::vector<uint8_t> buffer;
1099 append_varint(buffer, static_cast<uint64_t>(frame_type::data_blocked));
1100 append_varint(buffer, f.maximum_data);
1101 return buffer;
1102}
1103
1105 -> std::vector<uint8_t>
1106{
1107 std::vector<uint8_t> buffer;
1108 append_varint(buffer, static_cast<uint64_t>(frame_type::stream_data_blocked));
1109 append_varint(buffer, f.stream_id);
1110 append_varint(buffer, f.maximum_stream_data);
1111 return buffer;
1112}
1113
1115 -> std::vector<uint8_t>
1116{
1117 std::vector<uint8_t> buffer;
1118 append_varint(buffer, f.bidirectional
1119 ? static_cast<uint64_t>(frame_type::streams_blocked_bidi)
1120 : static_cast<uint64_t>(frame_type::streams_blocked_uni));
1121 append_varint(buffer, f.maximum_streams);
1122 return buffer;
1123}
1124
1126 -> std::vector<uint8_t>
1127{
1128 std::vector<uint8_t> buffer;
1129 append_varint(buffer, static_cast<uint64_t>(frame_type::new_connection_id));
1130 append_varint(buffer, f.sequence_number);
1131 append_varint(buffer, f.retire_prior_to);
1132
1133 // Connection ID length (1 byte, not varint)
1134 buffer.push_back(static_cast<uint8_t>(f.connection_id.size()));
1135
1136 // Connection ID
1137 append_bytes(buffer, f.connection_id);
1138
1139 // Stateless Reset Token
1140 buffer.insert(buffer.end(), f.stateless_reset_token.begin(),
1141 f.stateless_reset_token.end());
1142
1143 return buffer;
1144}
1145
1147 -> std::vector<uint8_t>
1148{
1149 std::vector<uint8_t> buffer;
1150 append_varint(buffer, static_cast<uint64_t>(frame_type::retire_connection_id));
1151 append_varint(buffer, f.sequence_number);
1152 return buffer;
1153}
1154
1156 -> std::vector<uint8_t>
1157{
1158 std::vector<uint8_t> buffer;
1159 append_varint(buffer, static_cast<uint64_t>(frame_type::path_challenge));
1160 buffer.insert(buffer.end(), f.data.begin(), f.data.end());
1161 return buffer;
1162}
1163
1165 -> std::vector<uint8_t>
1166{
1167 std::vector<uint8_t> buffer;
1168 append_varint(buffer, static_cast<uint64_t>(frame_type::path_response));
1169 buffer.insert(buffer.end(), f.data.begin(), f.data.end());
1170 return buffer;
1171}
1172
1174 -> std::vector<uint8_t>
1175{
1176 std::vector<uint8_t> buffer;
1177 append_varint(buffer, f.is_application_error
1178 ? static_cast<uint64_t>(frame_type::connection_close_app)
1179 : static_cast<uint64_t>(frame_type::connection_close));
1180
1181 append_varint(buffer, f.error_code);
1182
1183 // Frame Type (transport close only)
1184 if (!f.is_application_error)
1185 {
1186 append_varint(buffer, f.frame_type);
1187 }
1188
1189 // Reason Phrase Length
1190 append_varint(buffer, f.reason_phrase.size());
1191
1192 // Reason Phrase
1193 buffer.insert(buffer.end(), f.reason_phrase.begin(), f.reason_phrase.end());
1194
1195 return buffer;
1196}
1197
1198auto frame_builder::build_handshake_done() -> std::vector<uint8_t>
1199{
1200 return {static_cast<uint8_t>(frame_type::handshake_done)};
1201}
1202
1203} // namespace kcenon::network::protocols::quic
static auto build_path_response(const path_response_frame &f) -> std::vector< uint8_t >
Build PATH_RESPONSE frame.
Definition frame.cpp:1164
static auto build_streams_blocked(const streams_blocked_frame &f) -> std::vector< uint8_t >
Build STREAMS_BLOCKED frame.
Definition frame.cpp:1114
static auto build_reset_stream(const reset_stream_frame &f) -> std::vector< uint8_t >
Build RESET_STREAM frame.
Definition frame.cpp:994
static auto build_stream(const stream_frame &f, bool include_length=true) -> std::vector< uint8_t >
Build STREAM frame.
Definition frame.cpp:1035
static auto build_stop_sending(const stop_sending_frame &f) -> std::vector< uint8_t >
Build STOP_SENDING frame.
Definition frame.cpp:1005
static auto build_ack(const ack_frame &f) -> std::vector< uint8_t >
Build ACK frame.
Definition frame.cpp:950
static auto build_padding(size_t count=1) -> std::vector< uint8_t >
Build PADDING frame.
Definition frame.cpp:940
static auto build_max_stream_data(const max_stream_data_frame &f) -> std::vector< uint8_t >
Build MAX_STREAM_DATA frame.
Definition frame.cpp:1074
static auto build_data_blocked(const data_blocked_frame &f) -> std::vector< uint8_t >
Build DATA_BLOCKED frame.
Definition frame.cpp:1095
static auto build_new_token(const new_token_frame &f) -> std::vector< uint8_t >
Build NEW_TOKEN frame.
Definition frame.cpp:1025
static auto build_max_data(const max_data_frame &f) -> std::vector< uint8_t >
Build MAX_DATA frame.
Definition frame.cpp:1065
static auto build_ping() -> std::vector< uint8_t >
Build PING frame.
Definition frame.cpp:945
static auto build_new_connection_id(const new_connection_id_frame &f) -> std::vector< uint8_t >
Build NEW_CONNECTION_ID frame.
Definition frame.cpp:1125
static auto build_crypto(const crypto_frame &f) -> std::vector< uint8_t >
Build CRYPTO frame.
Definition frame.cpp:1015
static auto build(const frame &f) -> std::vector< uint8_t >
Build any frame from variant.
Definition frame.cpp:891
static void append_bytes(std::vector< uint8_t > &buffer, std::span< const uint8_t > data)
Definition frame.cpp:885
static auto build_path_challenge(const path_challenge_frame &f) -> std::vector< uint8_t >
Build PATH_CHALLENGE frame.
Definition frame.cpp:1155
static auto build_connection_close(const connection_close_frame &f) -> std::vector< uint8_t >
Build CONNECTION_CLOSE frame.
Definition frame.cpp:1173
static auto build_handshake_done() -> std::vector< uint8_t >
Build HANDSHAKE_DONE frame.
Definition frame.cpp:1198
static void append_varint(std::vector< uint8_t > &buffer, uint64_t value)
Definition frame.cpp:879
static auto build_stream_data_blocked(const stream_data_blocked_frame &f) -> std::vector< uint8_t >
Build STREAM_DATA_BLOCKED frame.
Definition frame.cpp:1104
static auto build_retire_connection_id(const retire_connection_id_frame &f) -> std::vector< uint8_t >
Build RETIRE_CONNECTION_ID frame.
Definition frame.cpp:1146
static auto build_max_streams(const max_streams_frame &f) -> std::vector< uint8_t >
Build MAX_STREAMS frame.
Definition frame.cpp:1084
static auto parse_connection_close(std::span< const uint8_t > data, bool is_app) -> Result< std::pair< frame, size_t > >
Definition frame.cpp:825
static auto parse_path_response(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
Definition frame.cpp:810
static auto parse_max_stream_data(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
Definition frame.cpp:644
static auto parse_ack(std::span< const uint8_t > data, bool has_ecn) -> Result< std::pair< frame, size_t > >
Definition frame.cpp:394
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.
Definition frame.cpp:116
static auto parse_ping(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
Definition frame.cpp:387
static auto parse_all(std::span< const uint8_t > data) -> Result< std::vector< frame > >
Parse all frames from buffer.
Definition frame.cpp:343
static auto parse_reset_stream(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
Definition frame.cpp:476
static auto parse_data_blocked(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
Definition frame.cpp:679
static auto parse_retire_connection_id(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
Definition frame.cpp:782
static auto parse_max_streams(std::span< const uint8_t > data, bool bidi) -> Result< std::pair< frame, size_t > >
Definition frame.cpp:665
static auto parse_stream_data_blocked(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
Definition frame.cpp:692
static auto parse_stream(std::span< const uint8_t > data, uint8_t flags) -> Result< std::pair< frame, size_t > >
Definition frame.cpp:576
static auto parse_path_challenge(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
Definition frame.cpp:795
static auto parse_padding(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
Definition frame.cpp:367
static auto parse_new_connection_id(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
Definition frame.cpp:727
static auto parse_crypto(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
Definition frame.cpp:524
static auto parse_stop_sending(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
Definition frame.cpp:503
static auto parse_new_token(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
Definition frame.cpp:553
static auto parse(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
Parse a single frame from buffer.
Definition frame.cpp:122
static auto parse_max_data(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
Definition frame.cpp:631
static auto parse_handshake_done(std::span< const uint8_t > data) -> Result< std::pair< frame, size_t > >
Definition frame.cpp:869
static auto parse_streams_blocked(std::span< const uint8_t > data, bool bidi) -> Result< std::pair< frame, size_t > >
Definition frame.cpp:713
static auto encode(uint64_t value) -> std::vector< uint8_t >
Encode a value to variable-length format.
Definition varint.cpp:10
static auto decode(std::span< const uint8_t > data) -> Result< std::pair< uint64_t, size_t > >
Decode variable-length integer from buffer.
Definition varint.cpp:146
constexpr uint8_t fin
Stream is finished.
Definition frame_types.h:63
constexpr uint8_t len
Length field present.
Definition frame_types.h:64
constexpr uint8_t off
Offset field present.
Definition frame_types.h:65
constexpr auto is_stream_frame(uint64_t type) noexcept -> bool
Check if a frame type value represents a STREAM frame.
Definition frame_types.h:73
@ error
Black hole detected, reset to base.
auto frame_type_to_string(frame_type type) -> std::string
Get string name for a frame type.
Definition frame.cpp:80
constexpr auto make_stream_type(bool has_fin, bool has_length, bool has_offset) noexcept -> uint8_t
Build STREAM frame type from flags.
Definition frame_types.h:89
frame_type
QUIC frame types as defined in RFC 9000 Section 12.4.
Definition frame_types.h:25
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.
Definition frame.cpp:28
constexpr auto get_stream_flags(uint64_t type) noexcept -> uint8_t
Extract STREAM flags from frame type.
Definition frame_types.h:81
VoidResult ok()
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.
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.
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.
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)
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)
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.
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.
STREAM_DATA_BLOCKED frame (RFC 9000 Section 19.13)
uint64_t maximum_stream_data
Stream-level limit at which blocking occurred.
STREAM frame (RFC 9000 Section 19.8)
std::vector< uint8_t > data
Stream data.
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.