diff --git a/src/dest.rs b/src/dest.rs index 3d3415e..fb8c6f2 100644 --- a/src/dest.rs +++ b/src/dest.rs @@ -561,6 +561,10 @@ impl< ) { Ok(checksum_success) => { file_delivery_complete = checksum_success; + if !checksum_success { + self.tparams.tstate.delivery_code = DeliveryCode::Incomplete; + self.tparams.tstate.condition_code = ConditionCode::FileChecksumFailure; + } } Err(e) => match e { FilestoreError::ChecksumTypeNotImplemented(_) => { @@ -850,7 +854,7 @@ impl< #[cfg(test)] mod tests { - use core::{borrow::BorrowMut, cell::Cell, sync::atomic::AtomicBool}; + use core::{cell::Cell, sync::atomic::AtomicBool}; #[allow(unused_imports)] use std::println; use std::{fs, string::String}; @@ -860,11 +864,7 @@ mod tests { use spacepackets::{ cfdp::{ lv::Lv, - pdu::{ - finished::{self, FinishedPduReader}, - metadata::MetadataPduCreator, - WritablePduPacket, - }, + pdu::{finished::FinishedPduReader, metadata::MetadataPduCreator, WritablePduPacket}, ChecksumType, TransmissionMode, }, util::{UbfU16, UnsignedByteFieldU16}, @@ -1526,6 +1526,9 @@ mod tests { let transaction_id = tb.handler.transaction_id().unwrap(); let mut fault_hook = tb.handler.local_cfg.user_fault_hook().borrow_mut(); assert!(fault_hook.notice_of_suspension_queue.is_empty()); + + // The file checksum failure is ignored by default and check limit handling is now + // performed. let ignored_queue = &mut fault_hook.ignored_queue; assert_eq!(ignored_queue.len(), 1); let cancelled = ignored_queue.pop_front().unwrap(); @@ -1552,6 +1555,7 @@ mod tests { .expect("fsm error"); tb.state_check(State::Idle, TransactionStep::Idle); + // Transaction is cancelled because the check limit is reached. let mut fault_hook = tb.handler.local_cfg.user_fault_hook().borrow_mut(); let cancelled_queue = &mut fault_hook.notice_of_cancellation_queue; assert_eq!(cancelled_queue.len(), 1); @@ -1575,6 +1579,12 @@ mod tests { ConditionCode::CheckLimitReached ); assert_eq!(finished_pdu.delivery_code(), DeliveryCode::Incomplete); + assert!(finished_pdu.fault_location().is_some()); + assert_eq!( + *finished_pdu.fault_location().unwrap().entity_id(), + REMOTE_ID.into() + ); + assert_eq!(finished_pdu.fs_responses_raw(), &[]); assert!(tb.handler.pdu_sender.queue_empty()); tb.expected_full_data = faulty_file_data.to_vec(); } diff --git a/src/lib.rs b/src/lib.rs index 3a56dce..2f85b89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -724,6 +724,7 @@ impl PduProvider for DummyPduProvider { pub struct PacketInfo<'raw_packet> { pdu_type: PduType, file_directive_type: Option, + packet_len: usize, raw_packet: &'raw_packet [u8], } @@ -782,6 +783,7 @@ impl<'raw> PacketInfo<'raw> { return Ok(Self { pdu_type: pdu_header.pdu_type(), file_directive_type: None, + packet_len: pdu_header.pdu_len(), raw_packet, }); } @@ -801,12 +803,13 @@ impl<'raw> PacketInfo<'raw> { Ok(Self { pdu_type: pdu_header.pdu_type(), file_directive_type: Some(directive), + packet_len: pdu_header.pdu_len(), raw_packet, }) } pub fn raw_packet(&self) -> &[u8] { - self.raw_packet + &self.raw_packet[0..self.packet_len] } } @@ -1195,6 +1198,10 @@ pub(crate) mod tests { packet_info.file_directive_type().unwrap(), FileDirectiveType::MetadataPdu ); + assert_eq!( + packet_info.raw_packet(), + &buf[0..metadata_pdu.len_written()] + ); assert_eq!( packet_info.packet_target().unwrap(), PacketTarget::DestEntity @@ -1210,6 +1217,10 @@ pub(crate) mod tests { .write_to_bytes(&mut buf) .expect("writing file data PDU failed"); let packet_info = PacketInfo::new(&buf).expect("creating packet info failed"); + assert_eq!( + packet_info.raw_packet(), + &buf[0..file_data_pdu.len_written()] + ); assert_eq!(packet_info.pdu_type(), PduType::FileData); assert!(packet_info.file_directive_type().is_none()); assert_eq!( @@ -1229,6 +1240,7 @@ pub(crate) mod tests { let packet_info = PacketInfo::new(&buf).expect("creating packet info failed"); assert_eq!(packet_info.pdu_type(), PduType::FileDirective); assert!(packet_info.file_directive_type().is_some()); + assert_eq!(packet_info.raw_packet(), &buf[0..eof_pdu.len_written()]); assert_eq!( packet_info.file_directive_type().unwrap(), FileDirectiveType::EofPdu @@ -1292,10 +1304,13 @@ pub(crate) mod tests { assert!(!remote_entity_cfg.remove_config(REMOTE_ID.value())); let remote_entity_retrieved = remote_entity_cfg.get(REMOTE_ID.value()).unwrap(); assert_eq!(remote_entity_retrieved.entity_id, REMOTE_ID.into()); + // Does not exist. + assert!(remote_entity_cfg.get(LOCAL_ID.value()).is_none()); + assert!(remote_entity_cfg.get_mut(LOCAL_ID.value()).is_none()); } #[test] - fn test_remote_cfg_provider_vector() { + fn test_remote_cfg_provider_std() { let remote_entity_cfg = RemoteEntityConfig::new_with_default_values( REMOTE_ID.into(), 1024, @@ -1304,7 +1319,7 @@ pub(crate) mod tests { TransmissionMode::Unacknowledged, ChecksumType::Crc32, ); - let mut remote_cfg_provider = VecRemoteEntityConfigProvider::default(); + let mut remote_cfg_provider = StdRemoteEntityConfigProvider::default(); assert!(remote_cfg_provider.0.is_empty()); remote_cfg_provider.add_config(&remote_entity_cfg); assert_eq!(remote_cfg_provider.0.len(), 1); @@ -1326,6 +1341,44 @@ pub(crate) mod tests { assert_eq!(remote_cfg_provider.0.len(), 1); let cfg_1_mut = remote_cfg_provider.get_mut(LOCAL_ID.value()).unwrap(); cfg_1_mut.default_crc_type = ChecksumType::Crc32C; + assert!(!remote_cfg_provider.remove_config(REMOTE_ID.value())); + assert!(remote_cfg_provider.get_mut(REMOTE_ID.value()).is_none()); + } + + #[test] + fn test_remote_cfg_provider_vector() { + let mut remote_cfg_provider = VecRemoteEntityConfigProvider::default(); + let remote_entity_cfg = RemoteEntityConfig::new_with_default_values( + REMOTE_ID.into(), + 1024, + true, + false, + TransmissionMode::Unacknowledged, + ChecksumType::Crc32, + ); + assert!(remote_cfg_provider.0.is_empty()); + remote_cfg_provider.add_config(&remote_entity_cfg); + assert_eq!(remote_cfg_provider.0.len(), 1); + let remote_entity_cfg_2 = RemoteEntityConfig::new_with_default_values( + LOCAL_ID.into(), + 1024, + true, + false, + TransmissionMode::Unacknowledged, + ChecksumType::Crc32, + ); + let cfg_0 = remote_cfg_provider.get(REMOTE_ID.value()).unwrap(); + assert_eq!(cfg_0.entity_id, REMOTE_ID.into()); + remote_cfg_provider.add_config(&remote_entity_cfg_2); + assert_eq!(remote_cfg_provider.0.len(), 2); + let cfg_1 = remote_cfg_provider.get(LOCAL_ID.value()).unwrap(); + assert_eq!(cfg_1.entity_id, LOCAL_ID.into()); + assert!(remote_cfg_provider.remove_config(REMOTE_ID.value())); + assert_eq!(remote_cfg_provider.0.len(), 1); + let cfg_1_mut = remote_cfg_provider.get_mut(LOCAL_ID.value()).unwrap(); + cfg_1_mut.default_crc_type = ChecksumType::Crc32C; + assert!(!remote_cfg_provider.remove_config(REMOTE_ID.value())); + assert!(remote_cfg_provider.get_mut(REMOTE_ID.value()).is_none()); } #[test] @@ -1352,4 +1405,49 @@ pub(crate) mod tests { Ok(PacketTarget::SourceEntity) ); } + + #[test] + fn test_fault_handler_checksum_error_ignored_by_default() { + let fault_handler = FaultHandler::new(TestFaultHandler::default()); + assert_eq!( + fault_handler.get_fault_handler(ConditionCode::FileChecksumFailure), + FaultHandlerCode::IgnoreError + ); + } + + #[test] + fn test_fault_handler_unsupported_checksum_ignored_by_default() { + let fault_handler = FaultHandler::new(TestFaultHandler::default()); + assert_eq!( + fault_handler.get_fault_handler(ConditionCode::UnsupportedChecksumType), + FaultHandlerCode::IgnoreError + ); + } + + #[test] + fn test_fault_handler_basic() { + let mut fault_handler = FaultHandler::new(TestFaultHandler::default()); + assert_eq!( + fault_handler.get_fault_handler(ConditionCode::FileChecksumFailure), + FaultHandlerCode::IgnoreError + ); + fault_handler.set_fault_handler( + ConditionCode::FileChecksumFailure, + FaultHandlerCode::NoticeOfCancellation, + ); + assert_eq!( + fault_handler.get_fault_handler(ConditionCode::FileChecksumFailure), + FaultHandlerCode::NoticeOfCancellation + ); + } + + #[test] + fn transaction_id_hashable_usable_as_map_key() { + let mut map = HashMap::new(); + let transaction_id_0 = TransactionId::new( + UnsignedByteFieldU8::new(1).into(), + UnsignedByteFieldU8::new(2).into(), + ); + map.insert(transaction_id_0, 5_u32); + } }