1use byteorder::{BigEndian, ByteOrder};
2use thiserror::Error;
3
4#[derive(Error, Debug)]
5pub enum AdspError {
6 #[error("invalid size - expected at least {expected} bytes but found {found}")]
7 InvalidSize { expected: usize, found: usize },
8 #[error("unknown descriptor code {code}")]
9 UnknownDescriptor { code: u8 },
10}
11
12#[derive(Debug, Copy, Clone, PartialEq, Eq)]
14#[repr(u8)]
15pub enum AdspDescriptor {
16 ControlPacket = 0x80,
18 OpenConnRequest = 0x81,
20 OpenConnAck = 0x82,
22 OpenConnReqAck = 0x83,
24 OpenConnDeny = 0x84,
26 CloseAdvice = 0x85,
28 ForwardReset = 0x86,
30 RetransmitAdvice = 0x87,
32 Acknowledgment = 0x88,
34}
35
36impl TryFrom<u8> for AdspDescriptor {
37 type Error = AdspError;
38
39 fn try_from(value: u8) -> Result<Self, Self::Error> {
40 match value {
41 0x80 => Ok(AdspDescriptor::ControlPacket),
42 0x81 => Ok(AdspDescriptor::OpenConnRequest),
43 0x82 => Ok(AdspDescriptor::OpenConnAck),
44 0x83 => Ok(AdspDescriptor::OpenConnReqAck),
45 0x84 => Ok(AdspDescriptor::OpenConnDeny),
46 0x85 => Ok(AdspDescriptor::CloseAdvice),
47 0x86 => Ok(AdspDescriptor::ForwardReset),
48 0x87 => Ok(AdspDescriptor::RetransmitAdvice),
49 0x88 => Ok(AdspDescriptor::Acknowledgment),
50 _ => Err(AdspError::UnknownDescriptor { code: value }),
51 }
52 }
53}
54
55#[derive(Debug, Clone, PartialEq, Eq)]
68pub struct AdspPacket {
69 pub descriptor: AdspDescriptor,
71 pub connection_id: u16,
73 pub first_byte_seq: u32,
75 pub next_recv_seq: u32,
77 pub recv_window: u16,
79 pub flags: u8,
81}
82
83impl AdspPacket {
84 pub const HEADER_LEN: usize = 13;
86
87 pub const FLAG_CONTROL: u8 = 0x80;
88 pub const FLAG_ACK: u8 = 0x40;
89 pub const FLAG_EOM: u8 = 0x20;
90 pub const FLAG_ATTENTION: u8 = 0x10;
91
92 pub fn parse(buf: &[u8]) -> Result<Self, AdspError> {
97 if buf.len() < Self::HEADER_LEN {
98 return Err(AdspError::InvalidSize {
99 expected: Self::HEADER_LEN,
100 found: buf.len(),
101 });
102 }
103
104 let descriptor = AdspDescriptor::try_from(buf[0])?;
105 let connection_id = BigEndian::read_u16(&buf[1..3]);
106 let first_byte_seq = BigEndian::read_u32(&buf[3..7]);
107 let next_recv_seq = BigEndian::read_u32(&buf[7..11]);
108 let recv_window = BigEndian::read_u16(&buf[11..13]);
109 let flags = buf[0] & 0xF0; Ok(Self {
112 descriptor,
113 connection_id,
114 first_byte_seq,
115 next_recv_seq,
116 recv_window,
117 flags,
118 })
119 }
120
121 pub fn to_bytes(&self, buf: &mut [u8]) -> Result<usize, AdspError> {
126 if buf.len() < Self::HEADER_LEN {
127 return Err(AdspError::InvalidSize {
128 expected: Self::HEADER_LEN,
129 found: buf.len(),
130 });
131 }
132
133 buf[0] = (self.descriptor as u8) | self.flags;
135 BigEndian::write_u16(&mut buf[1..3], self.connection_id);
136 BigEndian::write_u32(&mut buf[3..7], self.first_byte_seq);
137 BigEndian::write_u32(&mut buf[7..11], self.next_recv_seq);
138 BigEndian::write_u16(&mut buf[11..13], self.recv_window);
139
140 Ok(Self::HEADER_LEN)
141 }
142}
143
144#[derive(Debug, Clone, PartialEq, Eq)]
146pub struct AdspAttentionPacket<'a> {
147 pub header: AdspPacket,
148 pub attention_code: u16,
149 pub data: &'a [u8],
150}
151
152impl<'a> AdspAttentionPacket<'a> {
153 pub fn parse(buf: &'a [u8]) -> Result<Self, AdspError> {
155 let header = AdspPacket::parse(buf)?;
156
157 if header.flags & AdspPacket::FLAG_ATTENTION == 0 {
158 return Err(AdspError::UnknownDescriptor { code: buf[0] }); }
160
161 let payload = &buf[AdspPacket::HEADER_LEN..];
162 if payload.len() < 2 {
163 return Err(AdspError::InvalidSize {
164 expected: AdspPacket::HEADER_LEN + 2,
165 found: buf.len(),
166 });
167 }
168
169 let attention_code = BigEndian::read_u16(&payload[0..2]);
170 let data = &payload[2..];
171
172 Ok(Self {
173 header,
174 attention_code,
175 data,
176 })
177 }
178
179 pub fn write_payload_to(&self, buf: &mut [u8]) -> Result<usize, AdspError> {
181 if buf.len() < 2 + self.data.len() {
182 return Err(AdspError::InvalidSize {
183 expected: 2 + self.data.len(),
184 found: buf.len(),
185 });
186 }
187
188 BigEndian::write_u16(&mut buf[0..2], self.attention_code);
189 buf[2..2 + self.data.len()].copy_from_slice(self.data);
190
191 Ok(2 + self.data.len())
192 }
193}
194
195#[cfg(test)]
196mod tests {
197 use super::*;
198
199 #[test]
200 fn test_parse_open_conn_request() {
201 let data: &[u8] = &[
204 0x81, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
205 ];
206
207 let packet = AdspPacket::parse(data).expect("failed to parse");
208
209 assert_eq!(packet.descriptor, AdspDescriptor::OpenConnRequest);
210 assert_eq!(packet.connection_id, 0x1234);
211 assert_eq!(packet.first_byte_seq, 0);
212 assert_eq!(packet.next_recv_seq, 0);
213 assert_eq!(packet.recv_window, 4096);
214 }
215
216 #[test]
217 fn test_parse_control_packet() {
218 let data: &[u8] = &[
220 0x80, 0xAB, 0xCD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x20, 0x00,
221 ];
222
223 let packet = AdspPacket::parse(data).expect("failed to parse");
224
225 assert_eq!(packet.descriptor, AdspDescriptor::ControlPacket);
226 assert_eq!(packet.connection_id, 0xABCD);
227 assert_eq!(packet.first_byte_seq, 0x00010000);
228 assert_eq!(packet.next_recv_seq, 0x00020000);
229 assert_eq!(packet.recv_window, 8192);
230 }
231
232 #[test]
233 fn test_parse_acknowledgment() {
234 let data: &[u8] = &[
236 0x88, 0x00, 0x42, 0x00, 0x00, 0x03, 0xE8, 0x00, 0x00, 0x07, 0xD0, 0x08, 0x00,
237 ];
238
239 let packet = AdspPacket::parse(data).expect("failed to parse");
240
241 assert_eq!(packet.descriptor, AdspDescriptor::Acknowledgment);
242 assert_eq!(packet.connection_id, 0x0042);
243 assert_eq!(packet.first_byte_seq, 1000);
244 assert_eq!(packet.next_recv_seq, 2000);
245 assert_eq!(packet.recv_window, 2048);
246 }
247
248 #[test]
249 fn test_encode_open_conn_ack() {
250 let packet = AdspPacket {
251 descriptor: AdspDescriptor::OpenConnAck,
252 connection_id: 0x5678,
253 first_byte_seq: 0,
254 next_recv_seq: 0,
255 recv_window: 8192,
256 flags: 0,
257 };
258
259 let expected: &[u8] = &[
260 0x82, 0x56, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
261 ];
262
263 let mut buf = [0u8; 13];
264 let len = packet.to_bytes(&mut buf).expect("failed to encode");
265
266 assert_eq!(len, AdspPacket::HEADER_LEN);
267 assert_eq!(&buf, expected);
268 }
269
270 #[test]
271 fn test_encode_close_advice() {
272 let packet = AdspPacket {
273 descriptor: AdspDescriptor::CloseAdvice,
274 connection_id: 0x9999,
275 first_byte_seq: 1234567,
276 next_recv_seq: 7654321,
277 recv_window: 0,
278 flags: 0,
279 };
280
281 let mut buf = [0u8; 13];
282 let len = packet.to_bytes(&mut buf).expect("failed to encode");
283
284 assert_eq!(len, AdspPacket::HEADER_LEN);
285 assert_eq!(buf[0], 0x85); assert_eq!(BigEndian::read_u16(&buf[1..3]), 0x9999);
287 assert_eq!(BigEndian::read_u32(&buf[3..7]), 1234567);
288 assert_eq!(BigEndian::read_u32(&buf[7..11]), 7654321);
289 assert_eq!(BigEndian::read_u16(&buf[11..13]), 0);
290 }
291
292 #[test]
293 fn test_round_trip() {
294 let original = AdspPacket {
295 descriptor: AdspDescriptor::ForwardReset,
296 connection_id: 0xBEEF,
297 first_byte_seq: 0xDEADBEEF,
298 next_recv_seq: 0xCAFEBABE,
299 recv_window: 0xFFFF,
300 flags: 0x80, };
302
303 let mut buf = [0u8; 13];
304 let len = original.to_bytes(&mut buf).expect("failed to encode");
305 assert_eq!(len, AdspPacket::HEADER_LEN);
306
307 let parsed = AdspPacket::parse(&buf).expect("failed to parse");
308 assert_eq!(original, parsed);
309 }
310
311 #[test]
312 fn test_invalid_descriptor() {
313 let data: &[u8] = &[
315 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316 ];
317
318 let result = AdspPacket::parse(data);
319 assert!(result.is_err());
320 match result {
321 Err(AdspError::UnknownDescriptor { code: 0x99 }) => {}
322 _ => panic!("Expected UnknownDescriptor error"),
323 }
324 }
325
326 #[test]
327 fn test_buffer_too_small_parse() {
328 let data: &[u8] = &[0x80, 0x00, 0x00]; let result = AdspPacket::parse(data);
331 assert!(result.is_err());
332 match result {
333 Err(AdspError::InvalidSize {
334 expected: 13,
335 found: 3,
336 }) => {}
337 _ => panic!("Expected InvalidSize error"),
338 }
339 }
340
341 #[test]
342 fn test_buffer_too_small_encode() {
343 let packet = AdspPacket {
344 descriptor: AdspDescriptor::ControlPacket,
345 connection_id: 1,
346 first_byte_seq: 0,
347 next_recv_seq: 0,
348 recv_window: 1024,
349 flags: 0,
350 };
351
352 let mut buf = [0u8; 5]; let result = packet.to_bytes(&mut buf);
354 assert!(result.is_err());
355 match result {
356 Err(AdspError::InvalidSize {
357 expected: 13,
358 found: 5,
359 }) => {}
360 _ => panic!("Expected InvalidSize error"),
361 }
362 }
363
364 #[test]
365 fn test_parse_with_data_payload() {
366 let data: &[u8] = &[
368 0x80, 0x11, 0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00,
369 b'H', b'e', b'l', b'l', b'o',
371 ];
372
373 let packet = AdspPacket::parse(data).expect("failed to parse");
374
375 assert_eq!(packet.descriptor, AdspDescriptor::ControlPacket);
376 assert_eq!(packet.connection_id, 0x1122);
377 assert_eq!(packet.first_byte_seq, 1);
378 assert_eq!(packet.next_recv_seq, 2);
379 assert_eq!(packet.recv_window, 4096);
380
381 let payload = &data[AdspPacket::HEADER_LEN..];
383 assert_eq!(payload, b"Hello");
384 }
385}