Continue CFDP handlers #90

Merged
muellerr merged 34 commits from continue_cfdp_handlers into main 2024-01-29 23:42:04 +01:00
2 changed files with 90 additions and 42 deletions
Showing only changes of commit 48b8c6891a - Show all commits

View File

@ -73,7 +73,7 @@ features = ["all"]
optional = true optional = true
[dependencies.spacepackets] [dependencies.spacepackets]
version = "0.7.0-beta.3" version = "0.7.0-beta.4"
default-features = false default-features = false
# git = "https://egit.irs.uni-stuttgart.de/rust/spacepackets.git" # git = "https://egit.irs.uni-stuttgart.de/rust/spacepackets.git"
# rev = "297cfad22637d3b07a1b27abe56d9a607b5b82a7" # rev = "297cfad22637d3b07a1b27abe56d9a607b5b82a7"

View File

@ -21,7 +21,7 @@ use spacepackets::{
CfdpPdu, CommonPduConfig, FileDirectiveType, PduError, PduHeader, WritablePduPacket, CfdpPdu, CommonPduConfig, FileDirectiveType, PduError, PduHeader, WritablePduPacket,
}, },
tlv::{msg_to_user::MsgToUserTlv, EntityIdTlv, GenericTlv, TlvType}, tlv::{msg_to_user::MsgToUserTlv, EntityIdTlv, GenericTlv, TlvType},
ConditionCode, FaultHandlerCode, PduType, TransmissionMode, ChecksumType, ConditionCode, FaultHandlerCode, PduType, TransmissionMode,
}, },
util::UnsignedByteField, util::UnsignedByteField,
}; };
@ -47,6 +47,7 @@ struct TransferState {
transaction_id: Option<TransactionId>, transaction_id: Option<TransactionId>,
metadata_params: MetadataGenericParams, metadata_params: MetadataGenericParams,
progress: u64, progress: u64,
metadata_only: bool,
condition_code: ConditionCode, condition_code: ConditionCode,
delivery_code: DeliveryCode, delivery_code: DeliveryCode,
file_status: FileStatus, file_status: FileStatus,
@ -62,6 +63,7 @@ impl Default for TransferState {
transaction_id: None, transaction_id: None,
metadata_params: Default::default(), metadata_params: Default::default(),
progress: Default::default(), progress: Default::default(),
metadata_only: false,
condition_code: ConditionCode::NoError, condition_code: ConditionCode::NoError,
delivery_code: DeliveryCode::Incomplete, delivery_code: DeliveryCode::Incomplete,
file_status: FileStatus::Unreported, file_status: FileStatus::Unreported,
@ -344,21 +346,29 @@ impl DestinationHandler {
// TODO: Support for metadata only PDUs. // TODO: Support for metadata only PDUs.
let src_name = metadata_pdu.src_file_name(); 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); return Err(DestError::EmptySrcFileField);
} }
self.tparams.file_properties.src_file_name[..src_name.len_value()] if !self.tparams.tstate.metadata_only && dest_name.is_empty() {
.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() {
return Err(DestError::EmptyDestFileField); return Err(DestError::EmptyDestFileField);
} }
self.tparams.file_properties.dest_file_name[..dest_name.len_value()] if !self.tparams.tstate.metadata_only {
.copy_from_slice(dest_name.value()); self.tparams.file_properties.src_file_name[..src_name.len_value()]
self.tparams.file_properties.dest_file_name_len = dest_name.len_value(); .copy_from_slice(src_name.value());
self.tparams.pdu_conf = *metadata_pdu.pdu_header().common_pdu_conf(); self.tparams.file_properties.src_file_name_len = src_name.len_value();
self.tparams.msgs_to_user_size = 0; 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() { if !metadata_pdu.options().is_empty() {
for option_tlv in metadata_pdu.options_iter().unwrap() { for option_tlv in metadata_pdu.options_iter().unwrap() {
if option_tlv.is_standard_tlv() if option_tlv.is_standard_tlv()
@ -476,27 +486,38 @@ impl DestinationHandler {
} }
fn checksum_verify(&mut self, checksum: u32) -> bool { fn checksum_verify(&mut self, checksum: u32) -> bool {
match self.vfs.checksum_verify( let mut file_delivery_complete = false;
self.tparams.file_properties.dest_path_buf.to_str().unwrap(), if self.tparams.metadata_params().checksum_type == ChecksumType::NullChecksum
self.tparams.metadata_params().checksum_type, || self.tparams.tstate.metadata_only
checksum, {
&mut self.tparams.cksum_buf, file_delivery_complete = true;
) { self.tparams.tstate.delivery_code = DeliveryCode::Complete;
Ok(checksum_success) => checksum_success, self.tparams.tstate.condition_code = ConditionCode::NoError;
Err(e) => match e { } else {
FilestoreError::ChecksumTypeNotImplemented(_) => { match self.vfs.checksum_verify(
self.declare_fault(ConditionCode::UnsupportedChecksumType); self.tparams.file_properties.dest_path_buf.to_str().unwrap(),
// For this case, the applicable algorithm shall the the null checksum, which self.tparams.metadata_params().checksum_type,
// is always succesful. checksum,
true &mut self.tparams.cksum_buf,
) {
Ok(checksum_success) => {
file_delivery_complete = checksum_success;
} }
_ => { Err(e) => match e {
self.declare_fault(ConditionCode::FilestoreRejection); FilestoreError::ChecksumTypeNotImplemented(_) => {
// Treat this equivalent to a failed checksum procedure. self.declare_fault(ConditionCode::UnsupportedChecksumType);
false // 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) { fn start_check_limit_handling(&mut self) {
@ -771,7 +792,7 @@ mod tests {
use spacepackets::{ use spacepackets::{
cfdp::{ cfdp::{
lv::Lv, lv::Lv,
pdu::{metadata::MetadataPduCreator, WritablePduPacket}, pdu::{finished::FinishedPduReader, metadata::MetadataPduCreator, WritablePduPacket},
ChecksumType, TransmissionMode, ChecksumType, TransmissionMode,
}, },
util::{UbfU16, UnsignedByteFieldU16}, util::{UbfU16, UnsignedByteFieldU16},
@ -794,7 +815,12 @@ mod tests {
pub length: usize, pub length: usize,
} }
type SharedPduPacketQueue = Arc<Mutex<VecDeque<(PduType, Option<FileDirectiveType>, Vec<u8>)>>>; struct SentPdu {
pdu_type: PduType,
file_directive_type: Option<FileDirectiveType>,
raw_pdu: Vec<u8>,
}
type SharedPduPacketQueue = Arc<Mutex<VecDeque<SentPdu>>>;
#[derive(Default, Clone)] #[derive(Default, Clone)]
struct TestCfdpSender { struct TestCfdpSender {
packet_queue: SharedPduPacketQueue, packet_queue: SharedPduPacketQueue,
@ -807,16 +833,19 @@ mod tests {
file_directive_type: Option<FileDirectiveType>, file_directive_type: Option<FileDirectiveType>,
raw_pdu: &[u8], raw_pdu: &[u8],
) -> Result<(), PduError> { ) -> Result<(), PduError> {
self.packet_queue.lock().unwrap().push_back(( self.packet_queue.lock().unwrap().push_back(SentPdu {
pdu_type, pdu_type,
file_directive_type, file_directive_type,
raw_pdu.to_vec(), raw_pdu: raw_pdu.to_vec(),
)); });
Ok(()) Ok(())
} }
} }
impl TestCfdpSender { impl TestCfdpSender {
pub fn retrieve_next_pdu(&self) -> Option<SentPdu> {
self.packet_queue.lock().unwrap().pop_front()
}
pub fn queue_empty(&self) -> bool { pub fn queue_empty(&self) -> bool {
self.packet_queue.lock().unwrap().is_empty() self.packet_queue.lock().unwrap().is_empty()
} }
@ -1153,7 +1182,7 @@ mod tests {
self.src_path.as_path(), self.src_path.as_path(),
self.dest_path.as_path(), self.dest_path.as_path(),
file_size, file_size,
self.closure_requested self.closure_requested,
); );
let packet_info = create_packet_info(&metadata_pdu, &mut self.buf); let packet_info = create_packet_info(&metadata_pdu, &mut self.buf);
self.handler.state_machine(user, Some(&packet_info))?; self.handler.state_machine(user, Some(&packet_info))?;
@ -1284,14 +1313,15 @@ mod tests {
src_name: &'filename Path, src_name: &'filename Path,
dest_name: &'filename Path, dest_name: &'filename Path,
file_size: u64, file_size: u64,
closure_requested: bool closure_requested: bool,
) -> MetadataPduCreator<'filename, 'filename, 'static> { ) -> MetadataPduCreator<'filename, 'filename, 'static> {
let checksum_type = if file_size == 0 { let checksum_type = if file_size == 0 {
ChecksumType::NullChecksum ChecksumType::NullChecksum
} else { } else {
ChecksumType::Crc32 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( MetadataPduCreator::new_no_opts(
*pdu_header, *pdu_header,
metadata_params, metadata_params,
@ -1528,6 +1558,20 @@ mod tests {
assert!(fs::remove_file(test_obj.dest_path().as_path()).is_ok()); 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] #[test]
fn test_file_transfer_with_closure() { fn test_file_transfer_with_closure() {
let fault_handler = TestFaultHandler::default(); let fault_handler = TestFaultHandler::default();
@ -1537,11 +1581,15 @@ mod tests {
.generic_transfer_init(&mut test_user, 0) .generic_transfer_init(&mut test_user, 0)
.expect("transfer init failed"); .expect("transfer init failed");
test_obj.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus); test_obj.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
test_obj let sent_packets = test_obj
.generic_eof_no_error(&mut test_user, Vec::new()) .generic_eof_no_error(&mut test_user, Vec::new())
.expect("EOF no error insertion failed"); .expect("EOF no error insertion failed");
assert_eq!(sent_packets, 1);
assert!(fault_handler.all_queues_empty()); 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); 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);
} }
} }