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