1use super::varint;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum FrameType {
12 Padding,
13 Ping,
14 Ack,
15 AckEcn,
16 ResetStream,
17 StopSending,
18 Crypto,
19 NewToken,
20 Stream,
22 MaxData,
23 MaxStreamData,
24 MaxStreams,
25 MaxStreamsBidi,
26 DataBlocked,
27 StreamDataBlocked,
28 StreamsBlocked,
29 StreamsBlockedBidi,
30 NewConnectionId,
31 RetireConnectionId,
32 PathChallenge,
33 PathResponse,
34 ConnectionClose,
35 ConnectionCloseApp,
36 HandshakeDone,
37 Unknown(u8),
38}
39
40impl FrameType {
41 #[must_use]
44 pub fn as_u8(&self) -> u8 {
45 match self {
46 Self::Padding => 0x00,
47 Self::Ping => 0x01,
48 Self::Ack => 0x02,
49 Self::AckEcn => 0x03,
50 Self::ResetStream => 0x04,
51 Self::StopSending => 0x05,
52 Self::Crypto => 0x06,
53 Self::NewToken => 0x07,
54 Self::Stream => 0x08,
55 Self::MaxData => 0x10,
56 Self::MaxStreamData => 0x11,
57 Self::MaxStreams => 0x12,
58 Self::MaxStreamsBidi => 0x13,
59 Self::DataBlocked => 0x14,
60 Self::StreamDataBlocked => 0x15,
61 Self::StreamsBlocked => 0x16,
62 Self::StreamsBlockedBidi => 0x17,
63 Self::NewConnectionId => 0x18,
64 Self::RetireConnectionId => 0x19,
65 Self::PathChallenge => 0x1A,
66 Self::PathResponse => 0x1B,
67 Self::ConnectionClose => 0x1C,
68 Self::ConnectionCloseApp => 0x1D,
69 Self::HandshakeDone => 0x1E,
70 Self::Unknown(t) => *t,
71 }
72 }
73}
74
75impl FrameType {
76 #[must_use]
82 pub fn from_u8(t: u8) -> Self {
83 match t {
84 0x00 => Self::Padding,
85 0x01 => Self::Ping,
86 0x02 => Self::Ack,
87 0x03 => Self::AckEcn,
88 0x04 => Self::ResetStream,
89 0x05 => Self::StopSending,
90 0x06 => Self::Crypto,
91 0x07 => Self::NewToken,
92 0x08..=0x0F => Self::Stream,
93 0x10 => Self::MaxData,
94 0x11 => Self::MaxStreamData,
95 0x12 => Self::MaxStreams,
96 0x13 => Self::MaxStreamsBidi,
97 0x14 => Self::DataBlocked,
98 0x15 => Self::StreamDataBlocked,
99 0x16 => Self::StreamsBlocked,
100 0x17 => Self::StreamsBlockedBidi,
101 0x18 => Self::NewConnectionId,
102 0x19 => Self::RetireConnectionId,
103 0x1A => Self::PathChallenge,
104 0x1B => Self::PathResponse,
105 0x1C => Self::ConnectionClose,
106 0x1D => Self::ConnectionCloseApp,
107 0x1E => Self::HandshakeDone,
108 _ => Self::Unknown(t),
109 }
110 }
111
112 #[must_use]
114 pub fn name(&self) -> &'static str {
115 match self {
116 Self::Padding => "PADDING",
117 Self::Ping => "PING",
118 Self::Ack => "ACK",
119 Self::AckEcn => "ACK_ECN",
120 Self::ResetStream => "RESET_STREAM",
121 Self::StopSending => "STOP_SENDING",
122 Self::Crypto => "CRYPTO",
123 Self::NewToken => "NEW_TOKEN",
124 Self::Stream => "STREAM",
125 Self::MaxData => "MAX_DATA",
126 Self::MaxStreamData => "MAX_STREAM_DATA",
127 Self::MaxStreams => "MAX_STREAMS",
128 Self::MaxStreamsBidi => "MAX_STREAMS_BIDI",
129 Self::DataBlocked => "DATA_BLOCKED",
130 Self::StreamDataBlocked => "STREAM_DATA_BLOCKED",
131 Self::StreamsBlocked => "STREAMS_BLOCKED",
132 Self::StreamsBlockedBidi => "STREAMS_BLOCKED_BIDI",
133 Self::NewConnectionId => "NEW_CONNECTION_ID",
134 Self::RetireConnectionId => "RETIRE_CONNECTION_ID",
135 Self::PathChallenge => "PATH_CHALLENGE",
136 Self::PathResponse => "PATH_RESPONSE",
137 Self::ConnectionClose => "CONNECTION_CLOSE",
138 Self::ConnectionCloseApp => "CONNECTION_CLOSE_APP",
139 Self::HandshakeDone => "HANDSHAKE_DONE",
140 Self::Unknown(_) => "UNKNOWN",
141 }
142 }
143}
144
145#[derive(Debug, Clone)]
150pub struct QuicFrame {
151 pub frame_type: FrameType,
153 pub offset: usize,
155 pub length: usize,
157}
158
159#[must_use]
165pub fn parse_frames(buf: &[u8]) -> Vec<QuicFrame> {
166 let mut frames = Vec::new();
167 let mut pos = 0;
168
169 while pos < buf.len() {
170 let frame_start = pos;
171 let raw_type = buf[pos];
172 let frame_type = FrameType::from_u8(raw_type);
173 pos += 1; match frame_type {
176 FrameType::Padding => {
177 frames.push(QuicFrame {
179 frame_type,
180 offset: frame_start,
181 length: 1,
182 });
183 },
184
185 FrameType::Ping => {
186 frames.push(QuicFrame {
187 frame_type,
188 offset: frame_start,
189 length: 1,
190 });
191 },
192
193 FrameType::Ack | FrameType::AckEcn => {
194 let remaining = &buf[pos..];
199 let (largest_ack, n1) = match varint::decode(remaining) {
200 Some(v) => v,
201 None => break,
202 };
203 let _ = largest_ack;
204 pos += n1;
205
206 let remaining = &buf[pos..];
207 let (_ack_delay, n2) = match varint::decode(remaining) {
208 Some(v) => v,
209 None => break,
210 };
211 pos += n2;
212
213 let remaining = &buf[pos..];
214 let (ack_range_count, n3) = match varint::decode(remaining) {
215 Some(v) => v,
216 None => break,
217 };
218 pos += n3;
219
220 let remaining = &buf[pos..];
222 let (_first_range, n4) = match varint::decode(remaining) {
223 Some(v) => v,
224 None => break,
225 };
226 pos += n4;
227
228 let mut ok = true;
230 for _ in 0..ack_range_count {
231 if let Some((_, ng)) = varint::decode(&buf[pos..]) {
232 pos += ng;
233 } else {
234 ok = false;
235 break;
236 }
237 if let Some((_, nr)) = varint::decode(&buf[pos..]) {
238 pos += nr;
239 } else {
240 ok = false;
241 break;
242 }
243 }
244 if !ok {
245 break;
246 }
247
248 if frame_type == FrameType::AckEcn {
250 for _ in 0..3 {
251 if let Some((_, n)) = varint::decode(&buf[pos..]) {
252 pos += n;
253 } else {
254 break;
255 }
256 }
257 }
258
259 frames.push(QuicFrame {
260 frame_type,
261 offset: frame_start,
262 length: pos - frame_start,
263 });
264 },
265
266 FrameType::Crypto => {
267 let (_crypto_offset, n1) = match varint::decode(&buf[pos..]) {
269 Some(v) => v,
270 None => break,
271 };
272 pos += n1;
273
274 let (data_len, n2) = match varint::decode(&buf[pos..]) {
275 Some(v) => v,
276 None => break,
277 };
278 pos += n2;
279
280 let data_len = data_len as usize;
281 if pos + data_len > buf.len() {
282 break;
283 }
284 pos += data_len;
285
286 frames.push(QuicFrame {
287 frame_type,
288 offset: frame_start,
289 length: pos - frame_start,
290 });
291 },
292
293 FrameType::NewToken => {
294 let (token_len, n1) = match varint::decode(&buf[pos..]) {
296 Some(v) => v,
297 None => break,
298 };
299 pos += n1;
300
301 let token_len = token_len as usize;
302 if pos + token_len > buf.len() {
303 break;
304 }
305 pos += token_len;
306
307 frames.push(QuicFrame {
308 frame_type,
309 offset: frame_start,
310 length: pos - frame_start,
311 });
312 },
313
314 FrameType::Stream => {
315 let off_bit = raw_type & 0x01 != 0;
320 let len_bit = raw_type & 0x02 != 0;
321
322 let (_stream_id, n1) = match varint::decode(&buf[pos..]) {
324 Some(v) => v,
325 None => break,
326 };
327 pos += n1;
328
329 if off_bit {
331 let (_stream_offset, n2) = match varint::decode(&buf[pos..]) {
332 Some(v) => v,
333 None => break,
334 };
335 pos += n2;
336 }
337
338 if len_bit {
340 let (data_len, n3) = match varint::decode(&buf[pos..]) {
341 Some(v) => v,
342 None => break,
343 };
344 pos += n3;
345
346 let data_len = data_len as usize;
347 if pos + data_len > buf.len() {
348 break;
349 }
350 pos += data_len;
351 } else {
352 pos = buf.len();
354 }
355
356 frames.push(QuicFrame {
357 frame_type,
358 offset: frame_start,
359 length: pos - frame_start,
360 });
361 },
362
363 FrameType::MaxData
364 | FrameType::MaxStreams
365 | FrameType::MaxStreamsBidi
366 | FrameType::DataBlocked
367 | FrameType::StreamsBlocked
368 | FrameType::StreamsBlockedBidi
369 | FrameType::RetireConnectionId => {
370 let (_, n1) = match varint::decode(&buf[pos..]) {
372 Some(v) => v,
373 None => break,
374 };
375 pos += n1;
376
377 frames.push(QuicFrame {
378 frame_type,
379 offset: frame_start,
380 length: pos - frame_start,
381 });
382 },
383
384 FrameType::MaxStreamData | FrameType::StreamDataBlocked => {
385 let (_, n1) = match varint::decode(&buf[pos..]) {
387 Some(v) => v,
388 None => break,
389 };
390 pos += n1;
391
392 let (_, n2) = match varint::decode(&buf[pos..]) {
393 Some(v) => v,
394 None => break,
395 };
396 pos += n2;
397
398 frames.push(QuicFrame {
399 frame_type,
400 offset: frame_start,
401 length: pos - frame_start,
402 });
403 },
404
405 FrameType::ResetStream => {
406 for _ in 0..3 {
408 let (_, n) = if let Some(v) = varint::decode(&buf[pos..]) {
409 v
410 } else {
411 frames.push(QuicFrame {
412 frame_type,
413 offset: frame_start,
414 length: pos - frame_start,
415 });
416 return frames;
417 };
418 pos += n;
419 }
420 frames.push(QuicFrame {
421 frame_type,
422 offset: frame_start,
423 length: pos - frame_start,
424 });
425 },
426
427 FrameType::StopSending => {
428 for _ in 0..2 {
430 let (_, n) = if let Some(v) = varint::decode(&buf[pos..]) {
431 v
432 } else {
433 frames.push(QuicFrame {
434 frame_type,
435 offset: frame_start,
436 length: pos - frame_start,
437 });
438 return frames;
439 };
440 pos += n;
441 }
442 frames.push(QuicFrame {
443 frame_type,
444 offset: frame_start,
445 length: pos - frame_start,
446 });
447 },
448
449 FrameType::NewConnectionId => {
450 let (_, n1) = match varint::decode(&buf[pos..]) {
453 Some(v) => v,
454 None => break,
455 };
456 pos += n1;
457
458 let (_, n2) = match varint::decode(&buf[pos..]) {
459 Some(v) => v,
460 None => break,
461 };
462 pos += n2;
463
464 if pos >= buf.len() {
465 break;
466 }
467 let conn_id_len = buf[pos] as usize;
468 pos += 1;
469
470 if pos + conn_id_len + 16 > buf.len() {
471 break;
472 }
473 pos += conn_id_len + 16;
474
475 frames.push(QuicFrame {
476 frame_type,
477 offset: frame_start,
478 length: pos - frame_start,
479 });
480 },
481
482 FrameType::PathChallenge | FrameType::PathResponse => {
483 if pos + 8 > buf.len() {
485 break;
486 }
487 pos += 8;
488
489 frames.push(QuicFrame {
490 frame_type,
491 offset: frame_start,
492 length: pos - frame_start,
493 });
494 },
495
496 FrameType::ConnectionClose => {
497 let (_, n1) = match varint::decode(&buf[pos..]) {
500 Some(v) => v,
501 None => break,
502 };
503 pos += n1;
504
505 let (_, n2) = match varint::decode(&buf[pos..]) {
506 Some(v) => v,
507 None => break,
508 };
509 pos += n2;
510
511 let (phrase_len, n3) = match varint::decode(&buf[pos..]) {
512 Some(v) => v,
513 None => break,
514 };
515 pos += n3;
516
517 let phrase_len = phrase_len as usize;
518 if pos + phrase_len > buf.len() {
519 break;
520 }
521 pos += phrase_len;
522
523 frames.push(QuicFrame {
524 frame_type,
525 offset: frame_start,
526 length: pos - frame_start,
527 });
528 },
529
530 FrameType::ConnectionCloseApp => {
531 let (_, n1) = match varint::decode(&buf[pos..]) {
534 Some(v) => v,
535 None => break,
536 };
537 pos += n1;
538
539 let (phrase_len, n2) = match varint::decode(&buf[pos..]) {
540 Some(v) => v,
541 None => break,
542 };
543 pos += n2;
544
545 let phrase_len = phrase_len as usize;
546 if pos + phrase_len > buf.len() {
547 break;
548 }
549 pos += phrase_len;
550
551 frames.push(QuicFrame {
552 frame_type,
553 offset: frame_start,
554 length: pos - frame_start,
555 });
556 },
557
558 FrameType::HandshakeDone => {
559 frames.push(QuicFrame {
561 frame_type,
562 offset: frame_start,
563 length: 1,
564 });
565 },
566
567 FrameType::Unknown(_) => {
568 break;
570 },
571 }
572 }
573
574 frames
575}
576
577#[cfg(test)]
578mod tests {
579 use super::*;
580
581 #[test]
582 fn test_frame_type_from_u8() {
583 assert_eq!(FrameType::from_u8(0x00), FrameType::Padding);
584 assert_eq!(FrameType::from_u8(0x01), FrameType::Ping);
585 assert_eq!(FrameType::from_u8(0x02), FrameType::Ack);
586 assert_eq!(FrameType::from_u8(0x06), FrameType::Crypto);
587 assert_eq!(FrameType::from_u8(0x08), FrameType::Stream);
588 assert_eq!(FrameType::from_u8(0x0F), FrameType::Stream);
589 assert_eq!(FrameType::from_u8(0x1E), FrameType::HandshakeDone);
590 assert_eq!(FrameType::from_u8(0xFF), FrameType::Unknown(0xFF));
591 }
592
593 #[test]
594 fn test_frame_type_names() {
595 assert_eq!(FrameType::Padding.name(), "PADDING");
596 assert_eq!(FrameType::Crypto.name(), "CRYPTO");
597 assert_eq!(FrameType::Stream.name(), "STREAM");
598 assert_eq!(FrameType::Unknown(0xAB).name(), "UNKNOWN");
599 }
600
601 #[test]
602 fn test_parse_padding_and_ping() {
603 let buf = [0x00u8, 0x00, 0x01]; let frames = parse_frames(&buf);
605 assert_eq!(frames.len(), 3);
606 assert_eq!(frames[0].frame_type, FrameType::Padding);
607 assert_eq!(frames[1].frame_type, FrameType::Padding);
608 assert_eq!(frames[2].frame_type, FrameType::Ping);
609 assert_eq!(frames[2].offset, 2);
610 assert_eq!(frames[2].length, 1);
611 }
612
613 #[test]
614 fn test_parse_handshake_done() {
615 let buf = [0x1Eu8];
616 let frames = parse_frames(&buf);
617 assert_eq!(frames.len(), 1);
618 assert_eq!(frames[0].frame_type, FrameType::HandshakeDone);
619 assert_eq!(frames[0].length, 1);
620 }
621
622 #[test]
623 fn test_parse_crypto_frame() {
624 let buf = [0x06u8, 0x00, 0x04, 0xDE, 0xAD, 0xBE, 0xEF];
626 let frames = parse_frames(&buf);
627 assert_eq!(frames.len(), 1);
628 assert_eq!(frames[0].frame_type, FrameType::Crypto);
629 assert_eq!(frames[0].offset, 0);
630 assert_eq!(frames[0].length, 7); }
632
633 #[test]
634 fn test_parse_stream_frame_with_len() {
635 let buf = [0x0Au8, 0x01, 0x02, 0xAA, 0xBB];
638 let frames = parse_frames(&buf);
639 assert_eq!(frames.len(), 1);
640 assert_eq!(frames[0].frame_type, FrameType::Stream);
641 assert_eq!(frames[0].length, 5);
642 }
643
644 #[test]
645 fn test_parse_stops_on_unknown() {
646 let buf = [0x01u8, 0xFF, 0x01]; let frames = parse_frames(&buf);
648 assert_eq!(frames.len(), 1);
649 assert_eq!(frames[0].frame_type, FrameType::Ping);
650 }
651}