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