1use super::types::{ConnectionId, ConstrainedError, PacketFlags, SequenceNumber};
22
23pub const HEADER_SIZE: usize = 5;
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub struct ConstrainedHeader {
31 pub connection_id: ConnectionId,
33 pub seq: SequenceNumber,
35 pub ack: SequenceNumber,
37 pub flags: PacketFlags,
39}
40
41impl ConstrainedHeader {
42 pub const fn new(
44 connection_id: ConnectionId,
45 seq: SequenceNumber,
46 ack: SequenceNumber,
47 flags: PacketFlags,
48 ) -> Self {
49 Self {
50 connection_id,
51 seq,
52 ack,
53 flags,
54 }
55 }
56
57 pub fn syn(connection_id: ConnectionId) -> Self {
59 Self {
60 connection_id,
61 seq: SequenceNumber::new(0),
62 ack: SequenceNumber::new(0),
63 flags: PacketFlags::SYN,
64 }
65 }
66
67 pub fn syn_ack(connection_id: ConnectionId, ack: SequenceNumber) -> Self {
69 Self {
70 connection_id,
71 seq: SequenceNumber::new(0),
72 ack,
73 flags: PacketFlags::SYN_ACK,
74 }
75 }
76
77 pub fn ack(connection_id: ConnectionId, seq: SequenceNumber, ack: SequenceNumber) -> Self {
79 Self {
80 connection_id,
81 seq,
82 ack,
83 flags: PacketFlags::ACK,
84 }
85 }
86
87 pub fn data(connection_id: ConnectionId, seq: SequenceNumber, ack: SequenceNumber) -> Self {
89 Self {
90 connection_id,
91 seq,
92 ack,
93 flags: PacketFlags::DATA.union(PacketFlags::ACK),
94 }
95 }
96
97 pub fn fin(connection_id: ConnectionId, seq: SequenceNumber, ack: SequenceNumber) -> Self {
99 Self {
100 connection_id,
101 seq,
102 ack,
103 flags: PacketFlags::FIN.union(PacketFlags::ACK),
104 }
105 }
106
107 pub fn reset(connection_id: ConnectionId) -> Self {
109 Self {
110 connection_id,
111 seq: SequenceNumber::new(0),
112 ack: SequenceNumber::new(0),
113 flags: PacketFlags::RST,
114 }
115 }
116
117 pub fn ping(connection_id: ConnectionId, seq: SequenceNumber) -> Self {
119 Self {
120 connection_id,
121 seq,
122 ack: SequenceNumber::new(0),
123 flags: PacketFlags::PING,
124 }
125 }
126
127 pub fn pong(connection_id: ConnectionId, ack: SequenceNumber) -> Self {
129 Self {
130 connection_id,
131 seq: SequenceNumber::new(0),
132 ack,
133 flags: PacketFlags::PONG,
134 }
135 }
136
137 pub fn to_bytes(&self) -> [u8; HEADER_SIZE] {
141 let cid_bytes = self.connection_id.to_bytes();
142 [
143 cid_bytes[0],
144 cid_bytes[1],
145 self.seq.value(),
146 self.ack.value(),
147 self.flags.value(),
148 ]
149 }
150
151 pub fn from_bytes(bytes: &[u8]) -> Result<Self, ConstrainedError> {
155 if bytes.len() < HEADER_SIZE {
156 return Err(ConstrainedError::PacketTooSmall {
157 expected: HEADER_SIZE,
158 actual: bytes.len(),
159 });
160 }
161
162 Ok(Self {
163 connection_id: ConnectionId::from_bytes([bytes[0], bytes[1]]),
164 seq: SequenceNumber::new(bytes[2]),
165 ack: SequenceNumber::new(bytes[3]),
166 flags: PacketFlags::new(bytes[4]),
167 })
168 }
169
170 pub const fn is_syn(&self) -> bool {
172 self.flags.is_syn()
173 }
174
175 pub const fn is_syn_ack(&self) -> bool {
177 self.flags.is_syn() && self.flags.is_ack()
178 }
179
180 pub const fn is_ack(&self) -> bool {
182 self.flags.is_ack()
183 }
184
185 pub const fn is_fin(&self) -> bool {
187 self.flags.is_fin()
188 }
189
190 pub const fn is_rst(&self) -> bool {
192 self.flags.is_rst()
193 }
194
195 pub const fn is_data(&self) -> bool {
197 self.flags.is_data()
198 }
199
200 pub const fn is_ping(&self) -> bool {
202 self.flags.is_ping()
203 }
204
205 pub const fn is_pong(&self) -> bool {
207 self.flags.is_pong()
208 }
209}
210
211impl std::fmt::Display for ConstrainedHeader {
212 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
213 write!(
214 f,
215 "[{} {} {} {}]",
216 self.connection_id, self.seq, self.ack, self.flags
217 )
218 }
219}
220
221#[derive(Debug, Clone)]
223pub struct ConstrainedPacket {
224 pub header: ConstrainedHeader,
226 pub payload: Vec<u8>,
228}
229
230impl ConstrainedPacket {
231 pub fn new(header: ConstrainedHeader, payload: Vec<u8>) -> Self {
233 Self { header, payload }
234 }
235
236 pub fn control(header: ConstrainedHeader) -> Self {
238 Self {
239 header,
240 payload: Vec::new(),
241 }
242 }
243
244 pub fn data(
246 connection_id: ConnectionId,
247 seq: SequenceNumber,
248 ack: SequenceNumber,
249 payload: Vec<u8>,
250 ) -> Self {
251 Self {
252 header: ConstrainedHeader::data(connection_id, seq, ack),
253 payload,
254 }
255 }
256
257 pub fn total_size(&self) -> usize {
259 HEADER_SIZE + self.payload.len()
260 }
261
262 pub fn to_bytes(&self) -> Vec<u8> {
264 let mut bytes = Vec::with_capacity(self.total_size());
265 bytes.extend_from_slice(&self.header.to_bytes());
266 bytes.extend_from_slice(&self.payload);
267 bytes
268 }
269
270 pub fn from_bytes(bytes: &[u8]) -> Result<Self, ConstrainedError> {
272 let header = ConstrainedHeader::from_bytes(bytes)?;
273 let payload = if bytes.len() > HEADER_SIZE {
274 bytes[HEADER_SIZE..].to_vec()
275 } else {
276 Vec::new()
277 };
278 Ok(Self { header, payload })
279 }
280
281 pub fn has_payload(&self) -> bool {
283 !self.payload.is_empty()
284 }
285}
286
287#[cfg(test)]
288mod tests {
289 use super::*;
290
291 #[test]
292 fn test_header_serialization() {
293 let header = ConstrainedHeader::new(
294 ConnectionId::new(0x1234),
295 SequenceNumber::new(10),
296 SequenceNumber::new(5),
297 PacketFlags::DATA.union(PacketFlags::ACK),
298 );
299
300 let bytes = header.to_bytes();
301 assert_eq!(bytes.len(), HEADER_SIZE);
302 assert_eq!(bytes[0], 0x12); assert_eq!(bytes[1], 0x34); assert_eq!(bytes[2], 10); assert_eq!(bytes[3], 5); assert_eq!(bytes[4], 0x12); let restored = ConstrainedHeader::from_bytes(&bytes).unwrap();
309 assert_eq!(restored, header);
310 }
311
312 #[test]
313 fn test_header_from_bytes_too_short() {
314 let result = ConstrainedHeader::from_bytes(&[1, 2, 3]);
315 assert!(result.is_err());
316 match result {
317 Err(ConstrainedError::PacketTooSmall { expected, actual }) => {
318 assert_eq!(expected, HEADER_SIZE);
319 assert_eq!(actual, 3);
320 }
321 _ => panic!("Expected PacketTooSmall error"),
322 }
323 }
324
325 #[test]
326 fn test_syn_header() {
327 let header = ConstrainedHeader::syn(ConnectionId::new(0xABCD));
328 assert!(header.is_syn());
329 assert!(!header.is_ack());
330 assert_eq!(header.seq, SequenceNumber::new(0));
331 }
332
333 #[test]
334 fn test_syn_ack_header() {
335 let header = ConstrainedHeader::syn_ack(ConnectionId::new(0xABCD), SequenceNumber::new(1));
336 assert!(header.is_syn());
337 assert!(header.is_ack());
338 assert!(header.is_syn_ack());
339 assert_eq!(header.ack, SequenceNumber::new(1));
340 }
341
342 #[test]
343 fn test_data_header() {
344 let header = ConstrainedHeader::data(
345 ConnectionId::new(0x1234),
346 SequenceNumber::new(5),
347 SequenceNumber::new(3),
348 );
349 assert!(header.is_data());
350 assert!(header.is_ack());
351 assert!(!header.is_syn());
352 }
353
354 #[test]
355 fn test_fin_header() {
356 let header = ConstrainedHeader::fin(
357 ConnectionId::new(0x1234),
358 SequenceNumber::new(10),
359 SequenceNumber::new(8),
360 );
361 assert!(header.is_fin());
362 assert!(header.is_ack());
363 }
364
365 #[test]
366 fn test_reset_header() {
367 let header = ConstrainedHeader::reset(ConnectionId::new(0x1234));
368 assert!(header.is_rst());
369 assert!(!header.is_ack());
370 }
371
372 #[test]
373 fn test_ping_pong_headers() {
374 let ping = ConstrainedHeader::ping(ConnectionId::new(0x1234), SequenceNumber::new(5));
375 assert!(ping.is_ping());
376 assert!(!ping.is_pong());
377
378 let pong = ConstrainedHeader::pong(ConnectionId::new(0x1234), SequenceNumber::new(5));
379 assert!(pong.is_pong());
380 assert!(!pong.is_ping());
381 }
382
383 #[test]
384 fn test_header_display() {
385 let header = ConstrainedHeader::data(
386 ConnectionId::new(0xABCD),
387 SequenceNumber::new(10),
388 SequenceNumber::new(5),
389 );
390 let display = format!("{}", header);
391 assert!(display.contains("ABCD"));
392 assert!(display.contains("SEQ:10"));
393 assert!(display.contains("ACK|DATA"));
394 }
395
396 #[test]
397 fn test_packet_serialization() {
398 let packet = ConstrainedPacket::data(
399 ConnectionId::new(0x1234),
400 SequenceNumber::new(5),
401 SequenceNumber::new(3),
402 b"Hello".to_vec(),
403 );
404
405 assert_eq!(packet.total_size(), HEADER_SIZE + 5);
406 assert!(packet.has_payload());
407
408 let bytes = packet.to_bytes();
409 assert_eq!(bytes.len(), HEADER_SIZE + 5);
410 assert_eq!(&bytes[HEADER_SIZE..], b"Hello");
411
412 let restored = ConstrainedPacket::from_bytes(&bytes).unwrap();
413 assert_eq!(restored.header, packet.header);
414 assert_eq!(restored.payload, packet.payload);
415 }
416
417 #[test]
418 fn test_control_packet() {
419 let packet = ConstrainedPacket::control(ConstrainedHeader::syn(ConnectionId::new(0x1234)));
420 assert!(!packet.has_payload());
421 assert_eq!(packet.total_size(), HEADER_SIZE);
422 }
423
424 #[test]
425 fn test_packet_from_bytes_header_only() {
426 let header = ConstrainedHeader::ack(
427 ConnectionId::new(0x1234),
428 SequenceNumber::new(1),
429 SequenceNumber::new(0),
430 );
431 let bytes = header.to_bytes();
432
433 let packet = ConstrainedPacket::from_bytes(&bytes).unwrap();
434 assert_eq!(packet.header, header);
435 assert!(packet.payload.is_empty());
436 }
437}