1use num_derive::FromPrimitive;
2use num_traits::FromPrimitive;
3use serde::Serialize;
4
5use std::fmt;
6use std::io::Read;
7
8use super::{
9 error::{PDUError, PDUResult},
10 ops::{EntityID, TransactionSeqNum},
11};
12
13#[repr(u8)]
14#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, FromPrimitive, Serialize)]
15pub enum Condition {
17 NoError = 0b0000,
19 PositiveLimitReached = 0b0001,
21 InvalidTransmissionMode = 0b0011,
23 FileStoreRejection = 0b0100,
25 FileChecksumFailure = 0b0101,
27 FilesizeError = 0b0110,
29 NakLimitReached = 0b0111,
31 InactivityDetected = 0b1000,
33 InvalidFileStructure = 0b1001,
35 UnsupportedChecksumType = 0b1011,
37 CancelReceived = 0b1111,
39}
40
41#[repr(u8)]
42#[derive(Clone, Debug, PartialEq, Eq, FromPrimitive)]
43pub enum U3 {
45 Zero = 0b000,
46}
47
48#[repr(u8)]
49#[derive(Clone, Debug, PartialEq, Eq, FromPrimitive)]
50pub enum PDUType {
52 FileDirective = 0,
54 FileData = 1,
56}
57
58#[repr(u8)]
59#[derive(Clone, Copy, Debug, PartialEq, Eq, FromPrimitive)]
60pub enum Direction {
62 ToReceiver = 0,
63 ToSender = 1,
64}
65
66#[repr(u8)]
67#[derive(Clone, Copy, Debug, PartialEq, Eq, FromPrimitive)]
68pub enum TransmissionMode {
70 Acknowledged = 0,
71 Unacknowledged = 1,
72}
73impl PDUEncode for TransmissionMode {
74 type PDUType = Self;
75
76 fn encoded_len(&self) -> u16 {
77 1
78 }
79
80 fn decode<T: Read>(buffer: &mut T) -> PDUResult<Self::PDUType> {
81 let mut u8_buff = [0u8; 1];
82 buffer.read_exact(&mut u8_buff)?;
83 let possible_mode = u8_buff[0];
84 Self::from_u8(possible_mode).ok_or(PDUError::InvalidTransmissionMode(possible_mode))
85 }
86
87 fn encode(self) -> Vec<u8> {
88 vec![self as u8]
89 }
90}
91
92#[repr(u8)]
93#[derive(Clone, Copy, Debug, PartialEq, Eq, FromPrimitive)]
94pub enum CRCFlag {
96 NotPresent = 0,
97 Present = 1,
98}
99
100#[repr(u8)]
101#[derive(Clone, Copy, Debug, PartialEq, Eq, FromPrimitive)]
102pub enum FileSizeFlag {
104 Small = 0,
105 Large = 1,
106}
107
108impl FileSizeFlag {
109 pub fn encoded_len(&self) -> u16 {
111 match self {
112 FileSizeFlag::Small => 4,
113 FileSizeFlag::Large => 8,
114 }
115 }
116}
117#[repr(u8)]
118#[derive(Clone, Copy, Debug, PartialEq, Eq, FromPrimitive)]
119pub enum SegmentationControl {
121 NotPreserved = 0,
122 }
124
125#[repr(u8)]
126#[derive(Clone, Copy, Debug, PartialEq, Eq, FromPrimitive)]
127pub enum SegmentedData {
129 NotPresent = 0,
130 Present = 1,
131}
132
133#[repr(u8)]
134#[derive(Clone, Copy, Debug, PartialEq, Eq, FromPrimitive)]
135pub enum DeliveryCode {
137 Complete = 0,
138 Incomplete = 1,
139}
140
141#[repr(u8)]
142#[derive(Clone, Copy, Debug, PartialEq, Eq, FromPrimitive)]
143pub enum FileStatusCode {
145 Discarded = 0b00,
146 FileStoreRejection = 0b01,
147 Retained = 0b10,
148 Unreported = 0b11,
149}
150
151#[repr(u8)]
152#[derive(Clone, Copy, Debug, PartialEq, Eq, FromPrimitive, Serialize)]
153pub enum TransactionStatus {
155 Undefined = 0b00,
156 Active = 0b01,
157 Terminated = 0b10,
158 Unrecognized = 0b11,
159}
160
161pub trait PDUEncode {
163 type PDUType;
164 fn encoded_len(&self) -> u16;
166
167 fn encode(self) -> Vec<u8>;
169
170 fn decode<T: Read>(buffer: &mut T) -> PDUResult<Self::PDUType>;
172}
173
174pub trait FSSEncode {
177 type PDUType;
178
179 fn encoded_len(&self, file_size_flag: FileSizeFlag) -> u16;
181
182 fn encode(self, file_size_flag: FileSizeFlag) -> Vec<u8>;
184
185 fn decode<T: Read>(buffer: &mut T, file_size_flag: FileSizeFlag) -> PDUResult<Self::PDUType>;
187}
188
189pub trait SegmentEncode {
192 type PDUType;
193
194 fn encoded_len(&self, file_size_flag: FileSizeFlag) -> u16;
196
197 fn encode(self, file_size_flag: FileSizeFlag) -> Vec<u8>;
199
200 fn decode<T: Read>(
202 buffer: &mut T,
203 segmentation_flag: SegmentedData,
204 file_size_flag: FileSizeFlag,
205 ) -> PDUResult<Self::PDUType>;
206}
207
208#[derive(Clone, Debug, PartialEq, Eq)]
209pub struct PDUHeader {
211 pub version: U3,
213
214 pub pdu_type: PDUType,
216
217 pub direction: Direction,
219
220 pub transmission_mode: TransmissionMode,
222
223 pub crc_flag: CRCFlag,
225
226 pub large_file_flag: FileSizeFlag,
228
229 pub pdu_data_field_length: u16,
234
235 pub segmentation_control: SegmentationControl,
237
238 pub segment_metadata_flag: SegmentedData,
240
241 pub source_entity_id: EntityID,
243
244 pub transaction_sequence_number: TransactionSeqNum,
246
247 pub destination_entity_id: EntityID,
249}
250impl PDUEncode for PDUHeader {
251 type PDUType = Self;
252
253 fn encoded_len(&self) -> u16 {
254 1 +
256 2
258 + 1
260 + self.source_entity_id.encoded_len()
261 + self.transaction_sequence_number.encoded_len()
262 + self.destination_entity_id.encoded_len()
263 }
264
265 fn encode(self) -> Vec<u8> {
266 let first_byte = ((self.version as u8) << 5)
267 | ((self.pdu_type as u8) << 4)
268 | ((self.direction as u8) << 3)
269 | ((self.transmission_mode as u8) << 2)
270 | ((self.crc_flag as u8) << 1)
271 | self.large_file_flag as u8;
272 let mut buffer = vec![first_byte];
273 buffer.extend(match &self.crc_flag {
275 CRCFlag::NotPresent => self.pdu_data_field_length.to_be_bytes(),
276 CRCFlag::Present => (self.pdu_data_field_length + 2).to_be_bytes(),
277 });
278 buffer.push(
279 ((self.segmentation_control as u8) << 7)
280 | ((self.source_entity_id.encoded_len() as u8 - 1) << 4)
281 | ((self.segment_metadata_flag as u8) << 3)
282 | (self.transaction_sequence_number.encoded_len() as u8 - 1),
283 );
284 buffer.extend(self.source_entity_id.to_be_bytes());
285 buffer.extend(self.transaction_sequence_number.to_be_bytes());
286 buffer.extend(self.destination_entity_id.to_be_bytes());
287 buffer
288 }
289
290 fn decode<T: Read>(buffer: &mut T) -> PDUResult<Self::PDUType> {
291 let mut u8_buff = [0_u8; 1];
292 buffer.read_exact(&mut u8_buff)?;
293
294 let version = {
295 let possible = (u8_buff[0] & 0xE0) >> 5;
296 U3::from_u8(possible).ok_or(PDUError::InvalidVersion(possible))?
297 };
298
299 let pdu_type = {
300 let possible = (u8_buff[0] & 0x10) >> 4;
301 PDUType::from_u8(possible).ok_or(PDUError::InvalidPDUType(possible))?
302 };
303
304 let direction = {
305 let possible = (u8_buff[0] & 0x8) >> 3;
306 Direction::from_u8(possible).ok_or(PDUError::InvalidDirection(possible))?
307 };
308
309 let transmission_mode = {
310 let possible = (u8_buff[0] & 0x4) >> 2;
311 TransmissionMode::from_u8(possible)
312 .ok_or(PDUError::InvalidTransmissionMode(possible))?
313 };
314
315 let crc_flag = {
316 let possible = (u8_buff[0] & 0x2) >> 1;
317 CRCFlag::from_u8(possible).ok_or(PDUError::InvalidCRCFlag(possible))?
318 };
319
320 let large_file_flag = {
321 let possible = u8_buff[0] & 0x1;
322 FileSizeFlag::from_u8(possible).ok_or(PDUError::InvalidFileSizeFlag(possible))?
323 };
324
325 let pdu_data_field_length = {
326 let mut u16_buff = [0_u8; 2];
327 buffer.read_exact(&mut u16_buff)?;
328 match &crc_flag {
332 CRCFlag::NotPresent => u16::from_be_bytes(u16_buff),
333 CRCFlag::Present => u16::from_be_bytes(u16_buff) - 2,
334 }
335 };
336
337 buffer.read_exact(&mut u8_buff)?;
338
339 let segmentation_control = {
340 let possible = (u8_buff[0] & 0x80) >> 7;
341 SegmentationControl::from_u8(possible)
342 .ok_or(PDUError::InvalidSegmentControl(possible))?
343 };
344
345 let segment_metadata_flag = {
346 let possible = (u8_buff[0] & 8) >> 3;
347 SegmentedData::from_u8(possible)
348 .ok_or(PDUError::InvalidSegmentMetadataFlag(possible))?
349 };
350
351 let entity_id_length = ((u8_buff[0] & 0x70) >> 4) + 1;
354 let transaction_sequence_length = (u8_buff[0] & 0x7) + 1;
355
356 let source_entity_id: EntityID = {
357 let mut buff = vec![0_u8; entity_id_length as usize];
358 buffer.read_exact(buff.as_mut_slice())?;
359 EntityID::try_from(buff.to_vec())?
360 };
361
362 let transaction_sequence_number = {
363 let mut buff = vec![0_u8; transaction_sequence_length as usize];
364 buffer.read_exact(buff.as_mut_slice())?;
365 TransactionSeqNum::try_from(buff.to_vec())?
366 };
367
368 let destination_entity_id = {
369 let mut buff = vec![0_u8; entity_id_length as usize];
370 buffer.read_exact(buff.as_mut_slice())?;
371 EntityID(u16::from_be_bytes(
372 buff.try_into()
373 .expect("Unable to coerce vec into same sized array."),
374 ))
375 };
376
377 Ok(Self {
378 version,
379 pdu_type,
380 direction,
381 transmission_mode,
382 crc_flag,
383 large_file_flag,
384 pdu_data_field_length,
385 segmentation_control,
386 segment_metadata_flag,
387 source_entity_id,
388 transaction_sequence_number,
389 destination_entity_id,
390 })
391 }
392}
393
394impl fmt::Display for Condition {
395 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
396 write!(
397 f,
398 "{}",
399 match self {
400 Condition::NoError => "No Error",
401 Condition::InvalidTransmissionMode => "Invalid Transmission",
402 Condition::FileStoreRejection => "Filestore Rejection",
403 Condition::FileChecksumFailure => "Checksum Failure",
404 Condition::FilesizeError => "Unexpected File Size",
405 Condition::InactivityDetected => "Inactivity Detected",
406 Condition::InvalidFileStructure => "Invalid File Structure",
407 Condition::PositiveLimitReached => "Transaction Timeout",
408 Condition::UnsupportedChecksumType => "Unsupported Checksum",
409 _ => "Unknown",
410 }
411 )
412 }
413}
414
415impl fmt::Display for Direction {
416 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
417 write!(
418 f,
419 "{}",
420 match self {
421 Direction::ToReceiver => "Outgoing",
422 Direction::ToSender => "Incoming",
423 }
424 )
425 }
426}
427
428pub fn read_length_value_pair<T: Read>(buffer: &mut T) -> PDUResult<Vec<u8>> {
430 let mut u8_buff = [0u8; 1];
431 buffer.read_exact(&mut u8_buff)?;
432 let length = u8_buff[0];
433 let mut vector = vec![0u8; length as usize];
434 buffer.read_exact(vector.as_mut_slice())?;
435 Ok(vector)
436}
437
438#[cfg(test)]
439mod test {
440 #![allow(clippy::too_many_arguments)]
441
442 use std::{u16, u32};
443
444 use super::*;
445 use rstest::rstest;
446
447 #[rstest]
448 #[case(
449 12_u16,
450 EntityID::from(u16::MAX),
451 TransactionSeqNum::from(u32::MAX),
452 EntityID::from(u16::MAX)
453 )]
454 #[case(
455 8745_u16,
456 EntityID::from(u16::MAX),
457 TransactionSeqNum::from(u32::MAX),
458 EntityID::from(u16::MAX)
459 )]
460 #[case(
461 65531_u16,
462 EntityID::from(u16::MAX),
463 TransactionSeqNum::from(u32::MAX),
464 EntityID::from(u16::MAX)
465 )]
466 fn pdu_header(
467 #[values(U3::Zero)] version: U3,
468 #[values(PDUType::FileDirective, PDUType::FileData)] pdu_type: PDUType,
469 #[values(Direction::ToReceiver, Direction::ToSender)] direction: Direction,
470 #[values(TransmissionMode::Acknowledged, TransmissionMode::Unacknowledged)]
471 transmission_mode: TransmissionMode,
472 #[values(CRCFlag::NotPresent, CRCFlag::Present)] crc_flag: CRCFlag,
473 #[values(FileSizeFlag::Small, FileSizeFlag::Large)] large_file_flag: FileSizeFlag,
474 #[case] pdu_data_field_length: u16,
475 #[case] source_entity_id: EntityID,
476 #[case] transaction_sequence_number: TransactionSeqNum,
477 #[case] destination_entity_id: EntityID,
478 ) -> PDUResult<()> {
479 let (segmentation_control, segment_metadata_flag) = match &pdu_type {
480 PDUType::FileData => (SegmentationControl::NotPreserved, SegmentedData::Present),
481 PDUType::FileDirective => (SegmentationControl::NotPreserved, SegmentedData::Present),
482 };
483
484 let expected = PDUHeader {
485 version,
486 pdu_type,
487 direction,
488 transmission_mode,
489 crc_flag,
490 large_file_flag,
491 pdu_data_field_length,
492 segmentation_control,
493 segment_metadata_flag,
494 source_entity_id,
495 transaction_sequence_number,
496 destination_entity_id,
497 };
498 let buffer = expected.clone().encode();
499 let recovered = PDUHeader::decode(&mut buffer.as_slice())?;
500 assert_eq!(expected, recovered);
501
502 Ok(())
503 }
504}