From 48b8c6891aa2f2ca231b75fc38222c7f9437f0d1 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 23 Jan 2024 19:43:52 +0100 Subject: [PATCH] verified first finished PDU success --- satrs-core/Cargo.toml | 2 +- satrs-core/src/cfdp/dest.rs | 130 ++++++++++++++++++++++++------------ 2 files changed, 90 insertions(+), 42 deletions(-) diff --git a/satrs-core/Cargo.toml b/satrs-core/Cargo.toml index c46fc3b..d16f0a0 100644 --- a/satrs-core/Cargo.toml +++ b/satrs-core/Cargo.toml @@ -73,7 +73,7 @@ features = ["all"] optional = true [dependencies.spacepackets] -version = "0.7.0-beta.3" +version = "0.7.0-beta.4" default-features = false # git = "https://egit.irs.uni-stuttgart.de/rust/spacepackets.git" # rev = "297cfad22637d3b07a1b27abe56d9a607b5b82a7" diff --git a/satrs-core/src/cfdp/dest.rs b/satrs-core/src/cfdp/dest.rs index be4eb88..495e5fa 100644 --- a/satrs-core/src/cfdp/dest.rs +++ b/satrs-core/src/cfdp/dest.rs @@ -21,7 +21,7 @@ use spacepackets::{ CfdpPdu, CommonPduConfig, FileDirectiveType, PduError, PduHeader, WritablePduPacket, }, tlv::{msg_to_user::MsgToUserTlv, EntityIdTlv, GenericTlv, TlvType}, - ConditionCode, FaultHandlerCode, PduType, TransmissionMode, + ChecksumType, ConditionCode, FaultHandlerCode, PduType, TransmissionMode, }, util::UnsignedByteField, }; @@ -47,6 +47,7 @@ struct TransferState { transaction_id: Option, metadata_params: MetadataGenericParams, progress: u64, + metadata_only: bool, condition_code: ConditionCode, delivery_code: DeliveryCode, file_status: FileStatus, @@ -62,6 +63,7 @@ impl Default for TransferState { transaction_id: None, metadata_params: Default::default(), progress: Default::default(), + metadata_only: false, condition_code: ConditionCode::NoError, delivery_code: DeliveryCode::Incomplete, file_status: FileStatus::Unreported, @@ -344,21 +346,29 @@ impl DestinationHandler { // TODO: Support for metadata only PDUs. let src_name = metadata_pdu.src_file_name(); - if src_name.is_empty() { + let dest_name = metadata_pdu.dest_file_name(); + if src_name.is_empty() && dest_name.is_empty() { + self.tparams.tstate.metadata_only = true; + } + if !self.tparams.tstate.metadata_only && src_name.is_empty() { return Err(DestError::EmptySrcFileField); } - self.tparams.file_properties.src_file_name[..src_name.len_value()] - .copy_from_slice(src_name.value()); - self.tparams.file_properties.src_file_name_len = src_name.len_value(); - let dest_name = metadata_pdu.dest_file_name(); - if dest_name.is_empty() { + if !self.tparams.tstate.metadata_only && dest_name.is_empty() { return Err(DestError::EmptyDestFileField); } - self.tparams.file_properties.dest_file_name[..dest_name.len_value()] - .copy_from_slice(dest_name.value()); - self.tparams.file_properties.dest_file_name_len = dest_name.len_value(); - self.tparams.pdu_conf = *metadata_pdu.pdu_header().common_pdu_conf(); - self.tparams.msgs_to_user_size = 0; + if !self.tparams.tstate.metadata_only { + self.tparams.file_properties.src_file_name[..src_name.len_value()] + .copy_from_slice(src_name.value()); + self.tparams.file_properties.src_file_name_len = src_name.len_value(); + if dest_name.is_empty() { + return Err(DestError::EmptyDestFileField); + } + self.tparams.file_properties.dest_file_name[..dest_name.len_value()] + .copy_from_slice(dest_name.value()); + self.tparams.file_properties.dest_file_name_len = dest_name.len_value(); + self.tparams.pdu_conf = *metadata_pdu.pdu_header().common_pdu_conf(); + self.tparams.msgs_to_user_size = 0; + } if !metadata_pdu.options().is_empty() { for option_tlv in metadata_pdu.options_iter().unwrap() { if option_tlv.is_standard_tlv() @@ -476,27 +486,38 @@ impl DestinationHandler { } fn checksum_verify(&mut self, checksum: u32) -> bool { - match self.vfs.checksum_verify( - self.tparams.file_properties.dest_path_buf.to_str().unwrap(), - self.tparams.metadata_params().checksum_type, - checksum, - &mut self.tparams.cksum_buf, - ) { - Ok(checksum_success) => checksum_success, - Err(e) => match e { - FilestoreError::ChecksumTypeNotImplemented(_) => { - self.declare_fault(ConditionCode::UnsupportedChecksumType); - // For this case, the applicable algorithm shall the the null checksum, which - // is always succesful. - true + let mut file_delivery_complete = false; + if self.tparams.metadata_params().checksum_type == ChecksumType::NullChecksum + || self.tparams.tstate.metadata_only + { + file_delivery_complete = true; + self.tparams.tstate.delivery_code = DeliveryCode::Complete; + self.tparams.tstate.condition_code = ConditionCode::NoError; + } else { + match self.vfs.checksum_verify( + self.tparams.file_properties.dest_path_buf.to_str().unwrap(), + self.tparams.metadata_params().checksum_type, + checksum, + &mut self.tparams.cksum_buf, + ) { + Ok(checksum_success) => { + file_delivery_complete = checksum_success; } - _ => { - self.declare_fault(ConditionCode::FilestoreRejection); - // Treat this equivalent to a failed checksum procedure. - false - } - }, + Err(e) => match e { + FilestoreError::ChecksumTypeNotImplemented(_) => { + self.declare_fault(ConditionCode::UnsupportedChecksumType); + // For this case, the applicable algorithm shall be the the null checksum, + // which is always succesful. + file_delivery_complete = true; + } + _ => { + self.declare_fault(ConditionCode::FilestoreRejection); + // Treat this equivalent to a failed checksum procedure. + } + }, + }; } + file_delivery_complete } fn start_check_limit_handling(&mut self) { @@ -771,7 +792,7 @@ mod tests { use spacepackets::{ cfdp::{ lv::Lv, - pdu::{metadata::MetadataPduCreator, WritablePduPacket}, + pdu::{finished::FinishedPduReader, metadata::MetadataPduCreator, WritablePduPacket}, ChecksumType, TransmissionMode, }, util::{UbfU16, UnsignedByteFieldU16}, @@ -794,7 +815,12 @@ mod tests { pub length: usize, } - type SharedPduPacketQueue = Arc, Vec)>>>; + struct SentPdu { + pdu_type: PduType, + file_directive_type: Option, + raw_pdu: Vec, + } + type SharedPduPacketQueue = Arc>>; #[derive(Default, Clone)] struct TestCfdpSender { packet_queue: SharedPduPacketQueue, @@ -807,16 +833,19 @@ mod tests { file_directive_type: Option, raw_pdu: &[u8], ) -> Result<(), PduError> { - self.packet_queue.lock().unwrap().push_back(( + self.packet_queue.lock().unwrap().push_back(SentPdu { pdu_type, file_directive_type, - raw_pdu.to_vec(), - )); + raw_pdu: raw_pdu.to_vec(), + }); Ok(()) } } impl TestCfdpSender { + pub fn retrieve_next_pdu(&self) -> Option { + self.packet_queue.lock().unwrap().pop_front() + } pub fn queue_empty(&self) -> bool { self.packet_queue.lock().unwrap().is_empty() } @@ -1153,7 +1182,7 @@ mod tests { self.src_path.as_path(), self.dest_path.as_path(), file_size, - self.closure_requested + self.closure_requested, ); let packet_info = create_packet_info(&metadata_pdu, &mut self.buf); self.handler.state_machine(user, Some(&packet_info))?; @@ -1284,14 +1313,15 @@ mod tests { src_name: &'filename Path, dest_name: &'filename Path, file_size: u64, - closure_requested: bool + closure_requested: bool, ) -> MetadataPduCreator<'filename, 'filename, 'static> { let checksum_type = if file_size == 0 { ChecksumType::NullChecksum } else { ChecksumType::Crc32 }; - let metadata_params = MetadataGenericParams::new(closure_requested, checksum_type, file_size); + let metadata_params = + MetadataGenericParams::new(closure_requested, checksum_type, file_size); MetadataPduCreator::new_no_opts( *pdu_header, metadata_params, @@ -1528,6 +1558,20 @@ mod tests { assert!(fs::remove_file(test_obj.dest_path().as_path()).is_ok()); } + fn check_finished_pdu_success(sent_pdu: &SentPdu) { + assert_eq!(sent_pdu.pdu_type, PduType::FileDirective); + assert_eq!( + sent_pdu.file_directive_type, + Some(FileDirectiveType::FinishedPdu) + ); + let finished_pdu = FinishedPduReader::from_bytes(&sent_pdu.raw_pdu).unwrap(); + assert_eq!(finished_pdu.file_status(), FileStatus::Retained); + assert_eq!(finished_pdu.condition_code(), ConditionCode::NoError); + assert_eq!(finished_pdu.delivery_code(), DeliveryCode::Complete); + assert!(finished_pdu.fault_location().is_none()); + assert_eq!(finished_pdu.fs_responses_raw(), &[]); + } + #[test] fn test_file_transfer_with_closure() { let fault_handler = TestFaultHandler::default(); @@ -1537,11 +1581,15 @@ mod tests { .generic_transfer_init(&mut test_user, 0) .expect("transfer init failed"); test_obj.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus); - test_obj + let sent_packets = test_obj .generic_eof_no_error(&mut test_user, Vec::new()) .expect("EOF no error insertion failed"); + assert_eq!(sent_packets, 1); assert!(fault_handler.all_queues_empty()); + // The Finished PDU was sent, so the state machine is done. test_obj.state_check(State::Idle, TransactionStep::Idle); - // assert!(!test_obj.pdu_sender.queue_empty()); + assert!(!test_obj.pdu_sender.queue_empty()); + let sent_pdu = test_obj.pdu_sender.retrieve_next_pdu().unwrap(); + check_finished_pdu_success(&sent_pdu); } }