phantom_protocol/transport/phantom_udp/
envelope.rs1pub const CID_LEN: usize = 8;
8pub type ConnId = [u8; CID_LEN];
11
12pub const HDR_LEN: usize = 1 + CID_LEN;
14pub const PATH_MTU: usize = 1200;
16pub const FRAG_SUBHDR_LEN: usize = 8;
18pub const MAX_INNER_UNFRAGMENTED: usize = PATH_MTU - HDR_LEN;
20pub const MAX_INNER_FRAG_CHUNK: usize = PATH_MTU - HDR_LEN - FRAG_SUBHDR_LEN;
22
23const TYPE_SHIFT: u8 = 6;
24const FRAG_BIT: u8 = 0b0010_0000;
25const RESERVED_MASK: u8 = 0b0001_1111; #[derive(Clone, Copy, PartialEq, Eq, Debug)]
28pub enum PacketType {
29 Initial,
31 OneRtt,
33 Retry,
35}
36
37#[derive(Clone, Copy, PartialEq, Eq, Debug)]
38pub struct OuterHeader {
39 pub ty: PacketType,
40 pub fragmented: bool,
41 pub cid: ConnId,
42}
43
44#[derive(Clone, Copy, PartialEq, Eq, Debug)]
45pub enum EnvelopeError {
46 Truncated,
47 ReservedType,
48 ReservedBitsSet,
49 FrameTooLarge,
50}
51
52impl core::fmt::Display for EnvelopeError {
53 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
54 match self {
55 Self::Truncated => write!(f, "datagram too short for the PhantomUDP envelope header"),
56 Self::ReservedType => write!(f, "reserved PhantomUDP packet type"),
57 Self::ReservedBitsSet => write!(f, "reserved PhantomUDP flag bits set"),
58 Self::FrameTooLarge => write!(f, "frame exceeds the maximum fragmentable size"),
59 }
60 }
61}
62
63impl std::error::Error for EnvelopeError {}
64
65pub fn encode_header(buf: &mut Vec<u8>, ty: PacketType, fragmented: bool, cid: &ConnId) {
67 let type_bits = match ty {
68 PacketType::Initial => 0b00,
69 PacketType::OneRtt => 0b01,
70 PacketType::Retry => 0b10,
71 };
72 let mut flags = type_bits << TYPE_SHIFT;
73 if fragmented {
74 flags |= FRAG_BIT;
75 }
76 buf.push(flags);
77 buf.extend_from_slice(cid);
78}
79
80pub fn decode_header(buf: &[u8]) -> Result<(OuterHeader, &[u8]), EnvelopeError> {
82 if buf.len() < HDR_LEN {
83 return Err(EnvelopeError::Truncated);
84 }
85 let flags = buf[0];
86 if flags & RESERVED_MASK != 0 {
87 return Err(EnvelopeError::ReservedBitsSet);
88 }
89 let ty = match flags >> TYPE_SHIFT {
90 0b00 => PacketType::Initial,
91 0b01 => PacketType::OneRtt,
92 0b10 => PacketType::Retry,
93 _ => return Err(EnvelopeError::ReservedType),
94 };
95 let fragmented = flags & FRAG_BIT != 0;
96 let mut cid = [0u8; CID_LEN];
97 cid.copy_from_slice(&buf[1..1 + CID_LEN]);
98 Ok((
99 OuterHeader {
100 ty,
101 fragmented,
102 cid,
103 },
104 &buf[HDR_LEN..],
105 ))
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 #[test]
113 fn roundtrip_initial_unfragmented() {
114 let cid: ConnId = [1, 2, 3, 4, 5, 6, 7, 8];
115 let mut buf = Vec::new();
116 encode_header(&mut buf, PacketType::Initial, false, &cid);
117 assert_eq!(buf.len(), HDR_LEN);
118 let (hdr, rest) = decode_header(&buf).expect("decode");
119 assert_eq!(hdr.ty, PacketType::Initial);
120 assert!(!hdr.fragmented);
121 assert_eq!(hdr.cid, cid);
122 assert!(rest.is_empty());
123 }
124
125 #[test]
126 fn roundtrip_onertt_fragmented_with_payload() {
127 let cid: ConnId = [9; 8];
128 let mut buf = Vec::new();
129 encode_header(&mut buf, PacketType::OneRtt, true, &cid);
130 buf.extend_from_slice(b"abc");
131 let (hdr, rest) = decode_header(&buf).expect("decode");
132 assert_eq!(hdr.ty, PacketType::OneRtt);
133 assert!(hdr.fragmented);
134 assert_eq!(rest, b"abc");
135 }
136
137 #[test]
138 fn rejects_truncated() {
139 assert!(matches!(
140 decode_header(&[0u8; 4]),
141 Err(EnvelopeError::Truncated)
142 ));
143 }
144
145 #[test]
146 fn rejects_reserved_type() {
147 let mut buf = vec![0b1100_0000]; buf.extend_from_slice(&[0u8; CID_LEN]);
149 assert!(matches!(
150 decode_header(&buf),
151 Err(EnvelopeError::ReservedType)
152 ));
153 }
154
155 #[test]
156 fn rejects_reserved_bits_set() {
157 let mut buf = vec![0b0000_0001]; buf.extend_from_slice(&[0u8; CID_LEN]);
159 assert!(matches!(
160 decode_header(&buf),
161 Err(EnvelopeError::ReservedBitsSet)
162 ));
163 }
164}