1use crate::{
33 DummyPduProvider, FaultInfo, GenericSendError, IndicationConfig, PduProvider,
34 PositiveAckParams,
35 lost_segments::{LostSegmentError, LostSegmentStore},
36 user::TransactionFinishedParams,
37};
38use core::{
39 cell::{Cell, RefCell},
40 str::{Utf8Error, from_utf8, from_utf8_unchecked},
41};
42
43use super::{
44 Countdown, EntityType, LocalEntityConfig, PacketTarget, PduSender, RemoteConfigStore,
45 RemoteEntityConfig, State, TimerContext, TimerCreator, TransactionId, UserFaultHook,
46 filestore::{FilestoreError, VirtualFilestore},
47 user::{CfdpUser, FileSegmentRecvdParams, MetadataReceivedParams},
48};
49use smallvec::SmallVec;
50use spacepackets::{
51 cfdp::{
52 ChecksumType, ConditionCode, FaultHandlerCode, LargeFileFlag, PduType, TransactionStatus,
53 TransmissionMode,
54 pdu::{
55 CfdpPdu, CommonPduConfig, FileDirectiveType, PduError, PduHeader,
56 ack::AckPdu,
57 eof::EofPdu,
58 file_data::FileDataPdu,
59 finished::{DeliveryCode, FileStatus, FinishedPduCreator},
60 metadata::{MetadataGenericParams, MetadataPduReader},
61 nak::{NakPduCreator, NakPduCreatorWithReservedSeqReqsBuf},
62 },
63 tlv::{EntityIdTlv, GenericTlv, ReadableTlv, TlvType, msg_to_user::MsgToUserTlv},
64 },
65 util::{UnsignedByteField, UnsignedEnum},
66};
67
68#[derive(Debug)]
69struct FileNames {
70 src_file_name: [u8; u8::MAX as usize],
71 src_file_name_len: usize,
72 dest_file_name: [u8; u8::MAX as usize],
73 dest_file_name_len: usize,
74 dest_path_buf: [u8; u8::MAX as usize * 2],
75 dest_file_path_len: usize,
76}
77
78#[derive(Debug, Default, Clone, Copy)]
79pub struct AnomalyTracker {
80 invalid_ack_directive_code: u8,
81 lost_segment_errors: u8,
82}
83
84impl AnomalyTracker {
85 #[inline]
86 pub fn invalid_ack_directive_code(&mut self) -> u8 {
87 self.invalid_ack_directive_code
88 }
89
90 #[inline]
91 pub fn lost_segment_errors(&mut self) -> u8 {
92 self.lost_segment_errors
93 }
94
95 #[inline]
96 pub fn increment_lost_segment_errors(&mut self) {
97 self.lost_segment_errors = self.lost_segment_errors.wrapping_add(1);
98 }
99
100 #[inline]
101 pub fn increment_invalid_ack_directive_code(&mut self) {
102 self.invalid_ack_directive_code = self.invalid_ack_directive_code.wrapping_add(1);
103 }
104
105 #[inline]
106 pub fn reset(&mut self) {
107 *self = Default::default();
108 }
109}
110
111#[derive(Debug, PartialEq, Eq, Copy, Clone)]
112enum CompletionDisposition {
113 Completed = 0,
114 Cancelled = 1,
115}
116
117#[derive(Debug, Copy, Clone, PartialEq, Eq)]
119#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
120#[cfg_attr(feature = "defmt", derive(defmt::Format))]
121pub enum TransactionStep {
122 Idle,
123 TransactionStart,
124 WaitingForMetadata,
129 ReceivingFileDataPdus,
130 ReceivingFileDataPdusWithCheckLimitHandling,
134 WaitingForMissingData,
135 TransferCompletion,
137 WaitingForFinishedAck,
138}
139
140#[derive(Debug)]
141struct FinishedParams {
142 condition_code: Cell<ConditionCode>,
143 delivery_code: Cell<DeliveryCode>,
144 fault_location_finished: Cell<Option<EntityIdTlv>>,
145 file_status: FileStatus,
146}
147
148impl Default for FinishedParams {
149 fn default() -> Self {
150 Self {
151 condition_code: Cell::new(ConditionCode::NoError),
152 delivery_code: Cell::new(DeliveryCode::Incomplete),
153 fault_location_finished: Cell::new(None),
154 file_status: FileStatus::Unreported,
155 }
156 }
157}
158
159impl FinishedParams {
160 pub fn reset(&mut self) {
161 self.condition_code.set(ConditionCode::NoError);
162 self.delivery_code.set(DeliveryCode::Incomplete);
163 self.file_status = FileStatus::Unreported;
164 }
165}
166
167#[derive(Debug, Copy, Clone)]
168pub struct AcknowledgedModeParams {
169 last_start_offset: u64,
170 last_end_offset: u64,
171 metadata_missing: bool,
172 nak_activity_counter: u32,
173 deferred_procedure_active: bool,
174}
175
176#[derive(Debug)]
178struct TransactionParams<CountdownInstance: Countdown> {
179 pdu_conf: CommonPduConfig,
180 file_names: FileNames,
181 msgs_to_user_size: usize,
182 msgs_to_user_buf: [u8; 1024],
184 remote_cfg: Option<RemoteEntityConfig>,
185 transaction_id: Option<TransactionId>,
186 metadata_params: MetadataGenericParams,
187 file_size: u64,
188 progress: u64,
189 acked_params: Option<AcknowledgedModeParams>,
190 deferred_procedure_timer: Option<CountdownInstance>,
191 finished_params: FinishedParams,
192 positive_ack_params: Option<PositiveAckParams>,
193 ack_timer: Option<CountdownInstance>,
194 metadata_only: bool,
195 completion_disposition: Cell<CompletionDisposition>,
196 checksum: u32,
197 anomaly_tracker: AnomalyTracker,
198 current_check_count: u32,
199 current_check_timer: Option<CountdownInstance>,
200}
201
202impl<CheckTimer: Countdown> TransactionParams<CheckTimer> {
203 fn transmission_mode(&self) -> TransmissionMode {
204 self.pdu_conf.trans_mode
205 }
206}
207
208impl Default for FileNames {
209 fn default() -> Self {
210 Self {
211 src_file_name: [0; u8::MAX as usize],
212 src_file_name_len: Default::default(),
213 dest_file_name: [0; u8::MAX as usize],
214 dest_file_name_len: Default::default(),
215 dest_path_buf: [0; u8::MAX as usize * 2],
216 dest_file_path_len: Default::default(),
217 }
218 }
219}
220
221impl<CheckTimer: Countdown> TransactionParams<CheckTimer> {
222 fn file_size(&self) -> u64 {
223 self.metadata_params.file_size
224 }
225
226 fn metadata_params(&self) -> &MetadataGenericParams {
227 &self.metadata_params
228 }
229}
230
231impl<CheckTimer: Countdown> Default for TransactionParams<CheckTimer> {
232 fn default() -> Self {
233 Self {
234 pdu_conf: Default::default(),
235 msgs_to_user_size: 0,
236 file_size: 0,
237 msgs_to_user_buf: [0; 1024],
238 file_names: Default::default(),
239 remote_cfg: None,
240 transaction_id: None,
241 metadata_params: Default::default(),
242 progress: Default::default(),
243 deferred_procedure_timer: None,
244 acked_params: None,
245 metadata_only: false,
246 positive_ack_params: None,
247 ack_timer: None,
248 finished_params: FinishedParams::default(),
249 completion_disposition: Cell::new(CompletionDisposition::Completed),
250 checksum: 0,
251 current_check_count: 0,
252 anomaly_tracker: AnomalyTracker::default(),
253 current_check_timer: None,
254 }
255 }
256}
257
258impl<CheckTimer: Countdown> TransactionParams<CheckTimer> {
259 fn reset(&mut self) {
260 self.finished_params.reset();
261 self.anomaly_tracker.reset();
262 }
263}
264
265#[derive(Debug, thiserror::Error)]
266#[non_exhaustive]
267pub enum DestError {
268 #[error("expected file directive")]
270 DirectiveFieldEmpty,
271 #[error("can not process packet type {pdu_type:?} with directive type {directive_type:?}")]
272 CantProcessPacketType {
273 pdu_type: PduType,
274 directive_type: Option<FileDirectiveType>,
275 },
276 #[error("first packet must be metadata PDU for unacknowledged transfers")]
277 FirstPacketNotMetadata,
278 #[error(
279 "can not process PDU with type {pdu_type:?} and directive field {file_directive_type:?} in \
280 current transaction step {step:?}"
281 )]
282 WrongStepForPdu {
283 step: TransactionStep,
284 pdu_type: PduType,
285 file_directive_type: Option<FileDirectiveType>,
286 },
287 #[error("busy with transfer")]
289 RecvdMetadataButIsBusy,
290 #[error("empty source file field")]
291 EmptySrcFileField,
292 #[error("empty dest file field")]
293 EmptyDestFileField,
294 #[error("pdu error {0}")]
295 Pdu(#[from] PduError),
296 #[error("io error {0}")]
297 #[cfg(feature = "std")]
298 Io(#[from] std::io::Error),
299 #[error("file store error: {0}")]
300 Filestore(#[from] FilestoreError),
301 #[error("unexpected large file size which is not supported for current transfer")]
302 UnexpectedLargeFileSize,
303 #[error("lost segment error: {0}")]
304 LostSegmentError(#[from] LostSegmentError),
305 #[error("path conversion error {0}")]
306 PathConversion(#[from] Utf8Error),
307 #[error("error building dest path from source file name and dest folder")]
308 PathConcat,
309 #[error("no remote entity configuration found for {0:?}")]
310 NoRemoteConfigFound(UnsignedByteField),
311 #[error("issue sending PDU: {0}")]
312 SendError(#[from] GenericSendError),
313 #[error("invalid remote entity configuration: {0:?}")]
314 InvalidRemoteConfig(RemoteEntityConfig),
315 #[error("cfdp feature not implemented")]
316 NotImplemented,
317}
318
319pub struct DestinationHandler<
346 PduSenderInstance: PduSender,
347 UserFaultHookInstance: UserFaultHook,
348 VirtualFileStoreInstance: VirtualFilestore,
349 RemoteConfigStoreInstance: RemoteConfigStore,
350 TimerCreatorInstance: TimerCreator<Countdown = CountdownInstance>,
351 CountdownInstance: Countdown,
352 LostSegmentTracker: LostSegmentStore,
353> {
354 local_cfg: LocalEntityConfig<UserFaultHookInstance>,
355 step: core::cell::Cell<TransactionStep>,
356 state: State,
357 transaction_params: TransactionParams<CountdownInstance>,
358 pdu_and_cksum_buffer: RefCell<[u8; crate::buf_len::PACKET_BUF_LEN]>,
359 pub pdu_sender: PduSenderInstance,
360 pub vfs: VirtualFileStoreInstance,
361 pub remote_cfg_table: RemoteConfigStoreInstance,
362 pub check_timer_creator: TimerCreatorInstance,
363 lost_segment_tracker: LostSegmentTracker,
364}
365
366#[cfg(feature = "std")]
367pub type StdDestinationHandler<PduSender, UserFaultHook> = DestinationHandler<
368 PduSender,
369 UserFaultHook,
370 crate::filestore::NativeFilestore,
371 crate::RemoteConfigStoreStd,
372 crate::StdTimerCreator,
373 crate::StdCountdown,
374 crate::lost_segments::LostSegmentsList,
375>;
376
377#[cfg(feature = "std")]
378impl<PduSenderInstance: PduSender, UserFaultHookInstance: UserFaultHook>
379 StdDestinationHandler<PduSenderInstance, UserFaultHookInstance>
380{
381 #[cfg(feature = "std")]
382 pub fn new_std(
383 local_cfg: LocalEntityConfig<UserFaultHookInstance>,
384 pdu_sender: PduSenderInstance,
385 ) -> Self {
386 Self::new(
387 local_cfg,
388 pdu_sender,
389 crate::filestore::NativeFilestore::default(),
390 crate::RemoteConfigStoreStd::default(),
391 crate::StdTimerCreator::default(),
392 crate::lost_segments::LostSegmentsList::default(),
393 )
394 }
395}
396
397impl<
398 PduSenderInstance: PduSender,
399 UserFaultHookInstance: UserFaultHook,
400 VirtualFilestoreInstance: VirtualFilestore,
401 RemoteConfigStoreInstance: RemoteConfigStore,
402 TimerCreatorInstance: TimerCreator<Countdown = CountdownInstance>,
403 CountdownInstance: Countdown,
404 LostSegmentTracker: LostSegmentStore,
405>
406 DestinationHandler<
407 PduSenderInstance,
408 UserFaultHookInstance,
409 VirtualFilestoreInstance,
410 RemoteConfigStoreInstance,
411 TimerCreatorInstance,
412 CountdownInstance,
413 LostSegmentTracker,
414 >
415{
416 pub fn new(
437 local_cfg: LocalEntityConfig<UserFaultHookInstance>,
438 pdu_sender: PduSenderInstance,
439 vfs: VirtualFilestoreInstance,
440 remote_cfg_table: RemoteConfigStoreInstance,
441 timer_creator: TimerCreatorInstance,
442 lost_segment_tracker: LostSegmentTracker,
443 ) -> Self {
444 Self {
445 local_cfg,
446 step: Cell::new(TransactionStep::Idle),
447 state: State::Idle,
448 transaction_params: Default::default(),
449 pdu_and_cksum_buffer: core::cell::RefCell::new([0; crate::buf_len::PACKET_BUF_LEN]),
450 pdu_sender,
451 vfs,
452 remote_cfg_table,
453 check_timer_creator: timer_creator,
454 lost_segment_tracker,
455 }
456 }
457
458 pub fn state_machine_no_packet(
459 &mut self,
460 cfdp_user: &mut impl CfdpUser,
461 ) -> Result<u32, DestError> {
462 self.state_machine(cfdp_user, None::<&DummyPduProvider>)
463 }
464
465 pub fn state_machine(
474 &mut self,
475 cfdp_user: &mut impl CfdpUser,
476 packet_to_insert: Option<&impl PduProvider>,
477 ) -> Result<u32, DestError> {
478 let mut sent_packets = 0;
479 if let Some(packet) = packet_to_insert {
480 sent_packets += self.insert_packet(cfdp_user, packet)?;
481 }
482 match self.state {
483 State::Idle => {
484 }
486 State::Busy => {
487 sent_packets += self.fsm_busy(cfdp_user)?;
488 }
489 State::Suspended => {
490 }
492 }
493 Ok(sent_packets)
494 }
495
496 pub fn cancel_request(&mut self, transaction_id: &TransactionId) -> bool {
505 if self.state() == super::State::Idle {
506 return false;
507 }
508 if let Some(active_id) = self.transaction_id() {
509 if active_id == *transaction_id {
510 self.trigger_notice_of_completion_cancelled(
511 ConditionCode::CancelRequestReceived,
512 EntityIdTlv::new(self.local_cfg.id),
513 );
514
515 self.set_step(TransactionStep::TransferCompletion);
516 return true;
517 }
518 }
519 false
520 }
521
522 #[inline]
525 pub fn transmission_mode(&self) -> Option<TransmissionMode> {
526 if self.state == State::Idle {
527 return None;
528 }
529 Some(self.transaction_params.transmission_mode())
530 }
531
532 #[inline]
533 pub fn transaction_id(&self) -> Option<TransactionId> {
534 self.transaction_params.transaction_id
535 }
536
537 #[inline]
539 pub fn step(&self) -> TransactionStep {
540 self.step.get()
541 }
542
543 #[inline]
546 pub fn state(&self) -> State {
547 self.state
548 }
549
550 #[inline]
551 pub fn local_cfg(&self) -> &LocalEntityConfig<UserFaultHookInstance> {
552 &self.local_cfg
553 }
554
555 #[inline]
556 pub fn local_cfg_mut(&mut self) -> &mut LocalEntityConfig<UserFaultHookInstance> {
557 &mut self.local_cfg
558 }
559
560 pub fn reset(&mut self) {
565 self.set_step(TransactionStep::Idle);
566 self.state = State::Idle;
567 self.transaction_params.reset();
568 }
569
570 fn insert_packet(
571 &mut self,
572 cfdp_user: &mut impl CfdpUser,
573 packet_to_insert: &impl PduProvider,
574 ) -> Result<u32, DestError> {
575 let mut sent_packets = 0;
576 if packet_to_insert.packet_target()? != PacketTarget::DestEntity {
577 return Err(DestError::CantProcessPacketType {
580 pdu_type: packet_to_insert.pdu_type(),
581 directive_type: packet_to_insert.file_directive_type(),
582 });
583 }
584 match packet_to_insert.pdu_type() {
585 PduType::FileDirective => {
586 if packet_to_insert.file_directive_type().is_none() {
587 return Err(DestError::DirectiveFieldEmpty);
588 }
589 sent_packets += self.handle_file_directive(
590 cfdp_user,
591 packet_to_insert.file_directive_type().unwrap(),
592 packet_to_insert.raw_pdu(),
593 )?;
594 }
595 PduType::FileData => {
596 let fd_pdu = FileDataPdu::from_bytes(packet_to_insert.raw_pdu())?;
597 sent_packets += self.handle_file_data(cfdp_user, fd_pdu)?;
598 }
599 }
600 Ok(sent_packets)
601 }
602
603 fn handle_file_directive(
604 &mut self,
605 cfdp_user: &mut impl CfdpUser,
606 pdu_directive: FileDirectiveType,
607 raw_packet: &[u8],
608 ) -> Result<u32, DestError> {
609 let mut sent_packets = 0;
610 match pdu_directive {
611 FileDirectiveType::EofPdu => {
612 let eof_pdu = EofPdu::from_bytes(raw_packet)?;
613 sent_packets += self.handle_eof_pdu(cfdp_user, eof_pdu)?
614 }
615 FileDirectiveType::FinishedPdu
616 | FileDirectiveType::NakPdu
617 | FileDirectiveType::KeepAlivePdu => {
618 return Err(DestError::CantProcessPacketType {
619 pdu_type: PduType::FileDirective,
620 directive_type: Some(pdu_directive),
621 });
622 }
623 FileDirectiveType::AckPdu => {
624 let ack_pdu = AckPdu::from_bytes(raw_packet)?;
625 self.handle_ack_pdu(ack_pdu)?;
626 }
627 FileDirectiveType::MetadataPdu => {
628 let metadata_pdu = MetadataPduReader::from_bytes(raw_packet)?;
629 self.handle_metadata_pdu(metadata_pdu)?
630 }
631 FileDirectiveType::PromptPdu => self.handle_prompt_pdu(raw_packet)?,
632 };
633 Ok(sent_packets)
634 }
635
636 fn handle_ack_pdu(&mut self, ack_pdu: AckPdu) -> Result<(), DestError> {
637 if ack_pdu.directive_code_of_acked_pdu() != FileDirectiveType::FinishedPdu {
638 self.transaction_params
639 .anomaly_tracker
640 .increment_invalid_ack_directive_code();
641 }
642 self.reset();
644 Ok(())
645 }
646
647 fn first_packet_handling(&mut self, pdu_config: &CommonPduConfig) -> Result<(), DestError> {
648 self.transaction_params.reset();
649 let remote_cfg = self.remote_cfg_table.get(pdu_config.source_id().value());
650 if remote_cfg.is_none() {
651 return Err(DestError::NoRemoteConfigFound(pdu_config.source_id()));
652 }
653 self.transaction_params.remote_cfg = Some(*remote_cfg.unwrap());
654 self.transaction_params.transaction_id = Some(TransactionId::new(
655 pdu_config.source_id(),
656 pdu_config.transaction_seq_num,
657 ));
658 self.transaction_params.pdu_conf = *pdu_config;
659 self.transaction_params.pdu_conf.direction = spacepackets::cfdp::Direction::TowardsSender;
660 self.state = State::Busy;
661 Ok(())
662 }
663
664 fn handle_metadata_pdu(&mut self, metadata_pdu: MetadataPduReader) -> Result<(), DestError> {
665 let first_packet = self.step() == TransactionStep::Idle;
666 if first_packet {
667 self.first_packet_handling(metadata_pdu.pdu_header().common_pdu_conf())?;
668 }
669 match self.transmission_mode() {
670 Some(transmission_mode) => {
671 if !first_packet && transmission_mode == TransmissionMode::Unacknowledged {
672 return Err(DestError::RecvdMetadataButIsBusy);
673 }
674 match self.transaction_params.acked_params.as_mut() {
675 Some(acked_params) => {
676 if acked_params.metadata_missing {
677 if let Some(timer) =
678 self.transaction_params.deferred_procedure_timer.as_mut()
679 {
680 acked_params.nak_activity_counter = 0;
681 timer.reset();
682 }
683 acked_params.metadata_missing = false;
684 } else {
685 return Ok(());
687 }
688 }
689 None => {
690 self.transaction_params.acked_params = Some(AcknowledgedModeParams {
691 last_start_offset: 0,
692 last_end_offset: 0,
693 metadata_missing: false,
694 nak_activity_counter: 0,
695 deferred_procedure_active: false,
696 });
697 }
698 }
699 }
700 None => {
701 return Err(DestError::RecvdMetadataButIsBusy);
702 }
703 }
704
705 self.transaction_params.metadata_params = *metadata_pdu.metadata_params();
706 let remote_cfg = self.remote_cfg_table.get(metadata_pdu.source_id().value());
707 if remote_cfg.is_none() {
708 return Err(DestError::NoRemoteConfigFound(metadata_pdu.dest_id()));
709 }
710
711 let src_name = metadata_pdu.src_file_name();
712 let dest_name = metadata_pdu.dest_file_name();
713 if src_name.is_empty() && dest_name.is_empty() {
714 self.transaction_params.metadata_only = true;
715 }
716 if !self.transaction_params.metadata_only && src_name.is_empty() {
717 return Err(DestError::EmptySrcFileField);
718 }
719 if !self.transaction_params.metadata_only && dest_name.is_empty() {
720 return Err(DestError::EmptyDestFileField);
721 }
722 if !self.transaction_params.metadata_only {
723 self.transaction_params.file_names.src_file_name[..src_name.len_value()]
724 .copy_from_slice(src_name.value());
725 self.transaction_params.file_names.src_file_name_len = src_name.len_value();
726 if dest_name.is_empty() {
727 return Err(DestError::EmptyDestFileField);
728 }
729 self.transaction_params.file_names.dest_file_name[..dest_name.len_value()]
730 .copy_from_slice(dest_name.value());
731 self.transaction_params.file_names.dest_file_name_len = dest_name.len_value();
732 self.transaction_params.msgs_to_user_size = 0;
733 }
734 if !metadata_pdu.options().is_empty() {
735 for option_tlv in metadata_pdu.options_iter().unwrap() {
736 if option_tlv.is_standard_tlv()
737 && option_tlv.tlv_type().unwrap() == TlvType::MsgToUser
738 {
739 self.transaction_params
740 .msgs_to_user_buf
741 .copy_from_slice(option_tlv.raw_data().unwrap());
742 self.transaction_params.msgs_to_user_size += option_tlv.len_full();
743 }
744 }
745 }
746 self.set_step(TransactionStep::TransactionStart);
747 Ok(())
748 }
749
750 fn reset_nak_activity_parameters_if_active(&mut self) {
751 if let Some(acked_params) = self.transaction_params.acked_params.as_mut() {
752 if acked_params.metadata_missing {
753 if let Some(timer) = self.transaction_params.deferred_procedure_timer.as_mut() {
754 acked_params.nak_activity_counter = 0;
755 timer.reset();
756 }
757 }
758 }
759 }
760
761 fn handle_file_data_without_previous_metadata(
762 &mut self,
763 fd_pdu: &FileDataPdu,
764 ) -> Result<u32, DestError> {
765 let mut packets_sent = 0;
766 if fd_pdu.transmission_mode() == TransmissionMode::Unacknowledged {
767 return Err(DestError::FirstPacketNotMetadata);
769 }
770 self.first_packet_handling(fd_pdu.pdu_header().common_pdu_conf())?;
771 self.transaction_params.progress = fd_pdu.offset() + fd_pdu.file_data().len() as u64;
772 self.transaction_params.acked_params = Some(AcknowledgedModeParams {
773 last_start_offset: 0,
774 last_end_offset: 0,
775 nak_activity_counter: 0,
776 metadata_missing: true,
777 deferred_procedure_active: false,
778 });
779 if fd_pdu.file_data().len() as u64 > 0 {
780 self.lost_segment_tracker
781 .add_lost_segment((0, self.transaction_params.progress))?;
782 let ack_params = self.transaction_params.acked_params.as_mut().unwrap();
783 ack_params.last_start_offset = self.transaction_params.progress;
784 ack_params.last_end_offset = self.transaction_params.progress;
785 }
786 if self
787 .transaction_params
788 .remote_cfg
789 .as_ref()
790 .unwrap()
791 .immediate_nak_mode
792 {
793 let mut num_seg_reqs = 1;
794 if fd_pdu.file_data().len() as u64 > 0 {
795 num_seg_reqs += 1;
796 }
797 let pdu_header = PduHeader::new_for_file_directive(self.transaction_params.pdu_conf, 0);
798 let mut nak_pdu = NakPduCreatorWithReservedSeqReqsBuf::new(
799 self.pdu_and_cksum_buffer.get_mut(),
800 pdu_header,
801 num_seg_reqs,
802 )
803 .map_err(PduError::from)?;
804 let buf_mut = nak_pdu.segment_request_buffer_mut();
805 let mut current_offset = 0;
806 let increment = if pdu_header.common_pdu_conf().file_flag == LargeFileFlag::Large {
807 8
808 } else {
809 4
810 };
811 buf_mut[0..current_offset].fill(0);
812 current_offset += increment;
813 buf_mut[current_offset..current_offset + increment].fill(0);
814 current_offset += increment;
815 if fd_pdu.file_data().len() as u64 > 0 {
816 buf_mut[0..current_offset].fill(0);
817 current_offset += increment;
818 if pdu_header.common_pdu_conf().file_flag == LargeFileFlag::Large {
819 buf_mut[current_offset..current_offset + increment]
820 .copy_from_slice(&self.transaction_params.progress.to_be_bytes());
821 } else {
822 buf_mut[current_offset..current_offset + increment]
823 .copy_from_slice(&(self.transaction_params.progress as u32).to_be_bytes());
824 }
825 }
826 let written_size = nak_pdu
827 .finish(0, self.transaction_params.progress)
828 .map_err(PduError::from)?;
829 self.pdu_sender.send_file_directive_pdu(
830 FileDirectiveType::NakPdu,
831 &self.pdu_and_cksum_buffer.borrow()[0..written_size],
832 )?;
833 packets_sent += 1;
834 }
835 Ok(packets_sent)
836 }
837
838 fn handle_file_data(
839 &mut self,
840 user: &mut impl CfdpUser,
841 fd_pdu: FileDataPdu,
842 ) -> Result<u32, DestError> {
843 let mut sent_packets = 0;
844 let mut handle_indication = |id: TransactionId, indication_config: &IndicationConfig| {
845 if indication_config.file_segment_recv {
846 user.file_segment_recvd_indication(&FileSegmentRecvdParams {
847 id,
848 offset: fd_pdu.offset(),
849 length: fd_pdu.file_data().len(),
850 segment_metadata: fd_pdu.segment_metadata(),
851 });
852 }
853 };
854 let step = self.step.get();
855 if self.state == State::Idle {
856 if step == TransactionStep::Idle {
857 sent_packets += self.handle_file_data_without_previous_metadata(&fd_pdu)?;
858 self.set_step(TransactionStep::WaitingForMetadata);
859 handle_indication(
860 self.transaction_id().unwrap(),
861 &self.local_cfg.indication_cfg,
862 );
863 return Ok(sent_packets);
864 }
865 if step != TransactionStep::ReceivingFileDataPdus
866 && step != TransactionStep::ReceivingFileDataPdusWithCheckLimitHandling
867 {
868 return Err(DestError::WrongStepForPdu {
869 pdu_type: PduType::FileData,
870 file_directive_type: None,
871 step,
872 });
873 }
874 }
875 handle_indication(
876 self.transaction_id().unwrap(),
877 &self.local_cfg.indication_cfg,
878 );
879 if let Err(e) = self.vfs.write_data(
880 unsafe {
882 from_utf8_unchecked(
883 &self.transaction_params.file_names.dest_path_buf
885 [0..self.transaction_params.file_names.dest_file_path_len],
886 )
887 },
888 fd_pdu.offset(),
889 fd_pdu.file_data(),
890 ) {
891 if self.declare_fault(ConditionCode::FilestoreRejection)
892 == FaultHandlerCode::AbandonTransaction
893 {
894 self.abandon_transaction();
895 }
896 return Err(e.into());
897 }
898 self.transaction_params.progress = core::cmp::max(
899 self.transaction_params.progress,
900 fd_pdu.offset() + fd_pdu.file_data().len() as u64,
901 );
902 if self.transmission_mode().unwrap() == TransmissionMode::Acknowledged {
903 sent_packets += self.lost_segment_handling(&fd_pdu)?;
904 }
905 Ok(sent_packets)
906 }
907
908 fn lost_segment_handling(&mut self, fd_pdu: &FileDataPdu) -> Result<u32, DestError> {
909 if self.transaction_params.acked_params.is_none() {
912 return Ok(0);
913 }
914
915 let mut sent_packets = 0;
916 let acked_params = self.transaction_params.acked_params.as_mut().unwrap();
917 if fd_pdu.offset() > acked_params.last_end_offset {
918 let lost_segment = (acked_params.last_end_offset, fd_pdu.offset());
919 self.lost_segment_tracker.add_lost_segment(lost_segment)?;
920 if self
921 .transaction_params
922 .remote_cfg
923 .as_ref()
924 .unwrap()
925 .immediate_nak_mode
926 {
927 let pdu_header =
928 PduHeader::new_for_file_directive(self.transaction_params.pdu_conf, 0);
929 if self.transaction_params.pdu_conf.file_flag == LargeFileFlag::Normal
930 && lost_segment.0 > u32::MAX as u64
931 || lost_segment.1 > u32::MAX as u64
932 {
933 return Err(DestError::UnexpectedLargeFileSize);
934 }
935 let seg32 = [(lost_segment.0 as u32, lost_segment.1 as u32)];
936 let seg64 = [lost_segment];
937 let nak_pdu = if self.transaction_params.pdu_conf.file_flag == LargeFileFlag::Normal
938 {
939 NakPduCreator::new_normal_file_size(
940 pdu_header,
941 0,
942 self.transaction_params.progress as u32,
943 &seg32,
944 )
945 .unwrap()
946 } else {
947 NakPduCreator::new_large_file_size(
948 pdu_header,
949 0,
950 self.transaction_params.progress,
951 &seg64,
952 )
953 .unwrap()
954 };
955 let written_len = nak_pdu.write_to_bytes(self.pdu_and_cksum_buffer.get_mut())?;
956 self.pdu_sender.send_file_directive_pdu(
957 FileDirectiveType::NakPdu,
958 &self.pdu_and_cksum_buffer.borrow()[0..written_len],
959 )?;
960 sent_packets += 1;
961 }
962 }
963 if fd_pdu.offset() >= acked_params.last_end_offset {
964 acked_params.last_start_offset = fd_pdu.offset();
965 acked_params.last_end_offset = fd_pdu.offset() + fd_pdu.file_data().len() as u64;
966 }
967 if fd_pdu.offset() + fd_pdu.file_data().len() as u64 <= acked_params.last_start_offset {
968 let removed = self.lost_segment_tracker.remove_lost_segment((
970 fd_pdu.offset(),
971 fd_pdu.offset() + fd_pdu.file_data().len() as u64,
972 ))?;
973 if removed && acked_params.deferred_procedure_active {
976 self.reset_nak_activity_parameters_if_active();
977 }
978 }
979 Ok(sent_packets)
980 }
981
982 fn handle_eof_pdu(
983 &mut self,
984 cfdp_user: &mut impl CfdpUser,
985 eof_pdu: EofPdu,
986 ) -> Result<u32, DestError> {
987 let sent_packets = 0;
988 let first_packet = self.step() == TransactionStep::Idle;
989 if first_packet {
990 self.first_packet_handling(eof_pdu.pdu_header().common_pdu_conf())?;
991 }
992 if self.local_cfg.indication_cfg.eof_recv {
993 cfdp_user
995 .eof_recvd_indication(self.transaction_params.transaction_id.as_ref().unwrap());
996 }
997 if first_packet {
998 if self.transmission_mode().unwrap() == TransmissionMode::Unacknowledged {
999 return Err(DestError::WrongStepForPdu {
1000 pdu_type: PduType::FileDirective,
1001 file_directive_type: Some(FileDirectiveType::EofPdu),
1002 step: self.step(),
1003 });
1004 }
1005 return self.handle_eof_without_previous_metadata_in_acked_mode(&eof_pdu);
1006 }
1007 if eof_pdu.condition_code() == ConditionCode::NoError {
1008 if !self.handle_eof_no_error(&eof_pdu)? {
1009 return Ok(sent_packets);
1010 }
1011 } else {
1012 self.handle_eof_cancel(&eof_pdu);
1013 };
1014 let mut sent_packets = 0;
1015 match self.transaction_params.transmission_mode() {
1016 TransmissionMode::Acknowledged => {
1017 self.acknowledge_eof_pdu(&eof_pdu)?;
1018 sent_packets += 1;
1019 match self.transaction_params.acked_params.as_ref() {
1020 Some(acked_params) => {
1021 if acked_params.metadata_missing || !self.lost_segment_tracker.is_empty() {
1022 self.start_deferred_lost_segment_handling();
1023 } else {
1024 self.set_step(TransactionStep::TransferCompletion);
1025 }
1026 }
1027 None => {
1029 self.start_deferred_lost_segment_handling();
1030 }
1031 }
1032 }
1033 TransmissionMode::Unacknowledged => {
1034 self.set_step(TransactionStep::TransferCompletion);
1035 }
1036 }
1037 Ok(sent_packets)
1038 }
1039
1040 fn handle_eof_without_previous_metadata_in_acked_mode(
1041 &mut self,
1042 eof_pdu: &EofPdu,
1043 ) -> Result<u32, DestError> {
1044 let mut sent_packets = 0;
1045 self.transaction_params.file_size = eof_pdu.file_size();
1046 self.transaction_params.checksum = eof_pdu.file_checksum();
1047 self.transaction_params.acked_params = Some(AcknowledgedModeParams {
1048 last_start_offset: 0,
1049 last_end_offset: 0,
1050 nak_activity_counter: 0,
1051 metadata_missing: true,
1052 deferred_procedure_active: false,
1053 });
1054 if self.transaction_params.file_size > 0 {
1055 self.lost_segment_tracker.reset();
1056 self.lost_segment_tracker
1058 .add_lost_segment((0, eof_pdu.file_size()))?;
1059 }
1060 if eof_pdu.condition_code() != ConditionCode::NoError {
1061 self.handle_eof_cancel(eof_pdu);
1062 }
1063 self.acknowledge_eof_pdu(eof_pdu)?;
1064 sent_packets += 1;
1065 if self.transaction_params.completion_disposition.get() == CompletionDisposition::Cancelled
1066 {
1067 self.set_step(TransactionStep::TransferCompletion);
1068 return Ok(sent_packets);
1069 }
1070 self.set_step(TransactionStep::WaitingForMetadata);
1071 self.start_deferred_lost_segment_handling();
1072 Ok(sent_packets)
1073 }
1074
1075 fn handle_eof_cancel(&mut self, eof_pdu: &EofPdu) {
1076 self.trigger_notice_of_completion_cancelled(
1079 eof_pdu.condition_code(),
1080 EntityIdTlv::new(self.transaction_params.remote_cfg.unwrap().entity_id),
1081 );
1082 self.transaction_params.progress = eof_pdu.file_size();
1084 if let Some(ack_params) = &self.transaction_params.acked_params {
1085 if ack_params.metadata_missing {
1086 return;
1087 }
1088 }
1089 if self.transaction_params.progress == 0 {
1090 self.transaction_params
1092 .finished_params
1093 .delivery_code
1094 .set(DeliveryCode::Complete);
1095 return;
1096 }
1097 if self.checksum_verify(self.transaction_params.progress, eof_pdu.file_checksum()) {
1098 self.transaction_params
1099 .finished_params
1100 .delivery_code
1101 .set(DeliveryCode::Complete);
1102 return;
1103 }
1104 self.transaction_params
1105 .finished_params
1106 .delivery_code
1107 .set(DeliveryCode::Incomplete);
1108 }
1109
1110 fn acknowledge_eof_pdu(&mut self, eof_pdu: &EofPdu) -> Result<(), DestError> {
1111 let pdu_header = PduHeader::new_for_file_directive(self.transaction_params.pdu_conf, 0);
1112 let ack_pdu = AckPdu::new_for_eof_pdu(
1113 pdu_header,
1114 eof_pdu.condition_code(),
1115 TransactionStatus::Active,
1116 );
1117 let written_len = ack_pdu.write_to_bytes(self.pdu_and_cksum_buffer.get_mut())?;
1118 self.pdu_sender.send_file_directive_pdu(
1119 FileDirectiveType::AckPdu,
1120 &self.pdu_and_cksum_buffer.borrow()[0..written_len],
1121 )?;
1122 Ok(())
1123 }
1124
1125 fn start_deferred_lost_segment_handling(&mut self) {
1126 match &mut self.transaction_params.acked_params {
1127 Some(params) => {
1128 params.last_start_offset = self.transaction_params.file_size;
1129 params.last_end_offset = self.transaction_params.file_size;
1130 params.deferred_procedure_active = true;
1131 params.nak_activity_counter = 0;
1132 }
1133 None => {
1134 self.transaction_params.acked_params = Some(AcknowledgedModeParams {
1135 last_start_offset: self.transaction_params.file_size,
1136 last_end_offset: self.transaction_params.file_size,
1137 metadata_missing: false,
1138 nak_activity_counter: 0,
1139 deferred_procedure_active: true,
1140 })
1141 }
1142 }
1143 }
1144
1145 fn check_for_deferred_lost_segment_completion(&mut self, metadata_missing: bool) -> bool {
1146 if self.lost_segment_tracker.is_empty() && !metadata_missing {
1147 match self.checksum_verify(
1149 self.transaction_params.progress,
1150 self.transaction_params.checksum,
1151 ) {
1152 true => {
1153 self.transaction_params
1154 .finished_params
1155 .condition_code
1156 .set(ConditionCode::NoError);
1157 self.transaction_params
1158 .finished_params
1159 .delivery_code
1160 .set(DeliveryCode::Complete);
1161 }
1162 false => {
1163 self.transaction_params
1164 .finished_params
1165 .condition_code
1166 .set(ConditionCode::FileChecksumFailure);
1167 self.transaction_params
1168 .finished_params
1169 .delivery_code
1170 .set(DeliveryCode::Incomplete);
1171 }
1172 }
1173 self.transaction_params
1174 .acked_params
1175 .as_mut()
1176 .unwrap()
1177 .deferred_procedure_active = false;
1178 self.set_step(TransactionStep::TransferCompletion);
1179 return true;
1180 }
1181 false
1182 }
1183
1184 fn deferred_lost_segment_handling(&mut self) -> Result<u32, DestError> {
1185 assert!(
1186 self.transaction_params.acked_params.is_some(),
1187 "acknowledged parameters unexpectedly None"
1188 );
1189 let acked_params = self.transaction_params.acked_params.unwrap();
1190 if self.check_for_deferred_lost_segment_completion(acked_params.metadata_missing) {
1191 return Ok(0);
1192 }
1193 let mut sent_packets = 0;
1194 let first_nak_issuance = self.transaction_params.deferred_procedure_timer.is_none();
1195 if first_nak_issuance {
1196 self.transaction_params.deferred_procedure_timer = Some(
1197 self.check_timer_creator
1198 .create_countdown(TimerContext::NakActivity {
1199 expiry_time: self
1200 .transaction_params
1201 .remote_cfg
1202 .as_ref()
1203 .unwrap()
1204 .nak_timer_interval,
1205 }),
1206 );
1207 } else if !self
1208 .transaction_params
1209 .deferred_procedure_timer
1210 .as_ref()
1211 .unwrap()
1212 .has_expired()
1213 {
1214 return Ok(sent_packets);
1215 }
1216 if !first_nak_issuance
1217 && acked_params.nak_activity_counter + 1
1218 == self
1219 .transaction_params
1220 .remote_cfg
1221 .as_ref()
1222 .unwrap()
1223 .nak_timer_expiration_limit
1224 {
1225 self.transaction_params
1226 .finished_params
1227 .delivery_code
1228 .set(DeliveryCode::Incomplete);
1229 if self.declare_fault(ConditionCode::NakLimitReached)
1230 == FaultHandlerCode::AbandonTransaction
1231 {
1232 self.abandon_transaction();
1233 }
1234 return Ok(sent_packets);
1235 }
1236 if !first_nak_issuance {
1237 self.transaction_params
1238 .acked_params
1239 .as_mut()
1240 .unwrap()
1241 .nak_activity_counter += 1;
1242 self.transaction_params
1243 .deferred_procedure_timer
1244 .as_mut()
1245 .unwrap()
1246 .reset();
1247 }
1248 let pdu_header = PduHeader::new_for_file_directive(self.transaction_params.pdu_conf, 0);
1249 let max_segment_reqs = NakPduCreatorWithReservedSeqReqsBuf::calculate_max_segment_requests(
1250 self.transaction_params
1251 .remote_cfg
1252 .as_ref()
1253 .unwrap()
1254 .max_packet_len,
1255 &pdu_header,
1256 )
1257 .map_err(|_| DestError::InvalidRemoteConfig(self.transaction_params.remote_cfg.unwrap()))?;
1258 let mut segments_to_send = self.lost_segment_tracker.number_of_segments();
1259 if acked_params.metadata_missing {
1260 segments_to_send += 1;
1261 }
1262 if segments_to_send <= max_segment_reqs {
1263 let mut nak_pdu_creator = NakPduCreatorWithReservedSeqReqsBuf::new(
1266 self.pdu_and_cksum_buffer.get_mut(),
1267 pdu_header,
1268 segments_to_send,
1269 )
1270 .unwrap();
1271 self.lost_segment_tracker
1277 .write_to_nak_segment_list(&mut nak_pdu_creator, acked_params.metadata_missing)
1278 .expect("unexpected lost segment write error");
1279 let written_len = nak_pdu_creator
1280 .finish(0, self.transaction_params.file_size)
1281 .map_err(PduError::from)?;
1282 self.pdu_sender.send_file_directive_pdu(
1283 FileDirectiveType::NakPdu,
1284 &self.pdu_and_cksum_buffer.borrow()[0..written_len],
1285 )?;
1286 sent_packets += 1;
1287 } else {
1288 sent_packets += self.write_multi_packet_nak_sequence(
1289 segments_to_send,
1290 max_segment_reqs,
1291 acked_params.metadata_missing,
1292 )?;
1293 }
1294
1295 Ok(sent_packets)
1296 }
1297
1298 #[cold]
1299 fn write_multi_packet_nak_sequence(
1300 &mut self,
1301 mut segments_to_send: usize,
1302 max_segments: usize,
1303 first_segment_metadata: bool,
1304 ) -> Result<u32, DestError> {
1305 let mut sent_packets = 0;
1306 let pdu_header = PduHeader::new_for_file_directive(self.transaction_params.pdu_conf, 0);
1307 let mut nak_pdu_creator = NakPduCreatorWithReservedSeqReqsBuf::new(
1308 self.pdu_and_cksum_buffer.get_mut(),
1309 pdu_header,
1310 max_segments,
1311 )
1312 .unwrap();
1313
1314 let mut segment_index = 0;
1315 let mut buf_index = 0;
1316 let mut current_start_of_scope = 0;
1317 let mut current_end_of_scope = 0;
1318 let mut seg_buf = nak_pdu_creator.segment_request_buffer_mut();
1319
1320 if first_segment_metadata {
1322 if pdu_header.common_pdu_conf().file_flag == LargeFileFlag::Large {
1323 seg_buf[0..16].fill(0);
1324 buf_index = 16;
1325 } else {
1326 seg_buf[0..8].fill(0);
1327 buf_index = 8;
1328 }
1329 segment_index = 1; }
1331
1332 for (idx, (start, end)) in self.lost_segment_tracker.iter().enumerate() {
1333 if segment_index == max_segments {
1335 let written_len = nak_pdu_creator
1336 .finish(current_start_of_scope, current_end_of_scope)
1337 .map_err(PduError::from)?;
1338 self.pdu_sender.send_file_directive_pdu(
1339 FileDirectiveType::NakPdu,
1340 &self.pdu_and_cksum_buffer.borrow()[..written_len],
1341 )?;
1342 sent_packets += 1;
1343 segments_to_send = segments_to_send.saturating_sub(max_segments);
1344
1345 nak_pdu_creator = NakPduCreatorWithReservedSeqReqsBuf::new(
1347 self.pdu_and_cksum_buffer.get_mut(),
1348 pdu_header,
1349 core::cmp::min(segments_to_send, max_segments),
1350 )
1351 .unwrap();
1352 seg_buf = nak_pdu_creator.segment_request_buffer_mut();
1353 segment_index = 0;
1354 current_start_of_scope = current_end_of_scope;
1355 buf_index = 0;
1356 }
1357
1358 if pdu_header.common_pdu_conf().file_flag == LargeFileFlag::Large {
1360 seg_buf[buf_index..buf_index + 8].copy_from_slice(&start.to_be_bytes());
1361 buf_index += 8;
1362 seg_buf[buf_index..buf_index + 8].copy_from_slice(&end.to_be_bytes());
1363 buf_index += 8;
1364 } else {
1365 seg_buf[buf_index..buf_index + 4].copy_from_slice(&(start as u32).to_be_bytes());
1366 buf_index += 4;
1367 seg_buf[buf_index..buf_index + 4].copy_from_slice(&(end as u32).to_be_bytes());
1368 buf_index += 4;
1369 }
1370 if idx == max_segments {
1371 current_end_of_scope = self.transaction_params.progress;
1373 } else {
1374 current_end_of_scope = end;
1375 }
1376 segment_index += 1;
1377 }
1378
1379 if segment_index > 0 {
1381 let written_len = nak_pdu_creator
1382 .finish(current_start_of_scope, current_end_of_scope)
1383 .map_err(PduError::from)?;
1384 self.pdu_sender.send_file_directive_pdu(
1385 FileDirectiveType::NakPdu,
1386 &self.pdu_and_cksum_buffer.borrow()[..written_len],
1387 )?;
1388 sent_packets += 1;
1389 }
1390 Ok(sent_packets)
1391 }
1392
1393 fn trigger_notice_of_completion_cancelled(
1394 &self,
1395 cond_code: ConditionCode,
1396 fault_location: EntityIdTlv,
1397 ) {
1398 self.transaction_params
1399 .completion_disposition
1400 .set(CompletionDisposition::Cancelled);
1401 self.transaction_params
1402 .finished_params
1403 .condition_code
1404 .set(cond_code);
1405 self.transaction_params
1406 .finished_params
1407 .fault_location_finished
1408 .set(Some(fault_location));
1409 if self.transaction_params.progress == 0 {
1412 self.transaction_params
1413 .finished_params
1414 .delivery_code
1415 .set(DeliveryCode::Complete);
1416 }
1417 }
1418
1419 fn handle_eof_no_error(&mut self, eof_pdu: &EofPdu) -> Result<bool, DestError> {
1421 if self.transaction_params.progress > eof_pdu.file_size() {
1423 match self.declare_fault(ConditionCode::FileSizeError) {
1424 FaultHandlerCode::IgnoreError => (),
1425 FaultHandlerCode::AbandonTransaction => {
1426 self.abandon_transaction();
1427 return Ok(false);
1428 }
1429 FaultHandlerCode::NoticeOfCancellation | FaultHandlerCode::NoticeOfSuspension => {
1430 return Ok(false);
1431 }
1432 }
1433 } else if (self.transaction_params.progress < eof_pdu.file_size())
1434 && self.transaction_params.transmission_mode() == TransmissionMode::Acknowledged
1435 {
1436 self.lost_segment_tracker
1440 .add_lost_segment((self.transaction_params.progress, eof_pdu.file_size()))?;
1441 }
1442
1443 self.transaction_params.file_size = eof_pdu.file_size();
1444 self.transaction_params.checksum = eof_pdu.file_checksum();
1445 if self.transaction_params.transmission_mode() == TransmissionMode::Unacknowledged
1446 && !self.checksum_verify(
1447 self.transaction_params.progress,
1448 self.transaction_params.checksum,
1449 )
1450 {
1451 self.start_check_limit_handling();
1452 return Ok(false);
1453 }
1454 self.transaction_params
1455 .finished_params
1456 .delivery_code
1457 .set(DeliveryCode::Complete);
1458 self.transaction_params
1459 .finished_params
1460 .condition_code
1461 .set(ConditionCode::NoError);
1462 Ok(true)
1463 }
1464
1465 fn checksum_verify(&mut self, verify_len: u64, checksum: u32) -> bool {
1466 if self.transaction_params.metadata_params().checksum_type == ChecksumType::NullChecksum
1467 || self.transaction_params.metadata_only
1468 {
1469 return true;
1470 }
1471 match self.vfs.checksum_verify(
1472 checksum,
1473 unsafe {
1475 from_utf8_unchecked(
1476 &self.transaction_params.file_names.dest_path_buf
1477 [0..self.transaction_params.file_names.dest_file_path_len],
1478 )
1479 },
1480 self.transaction_params.metadata_params().checksum_type,
1481 verify_len,
1482 self.pdu_and_cksum_buffer.get_mut(),
1483 ) {
1484 Ok(false) => {
1485 if self.declare_fault(ConditionCode::FileChecksumFailure)
1486 == FaultHandlerCode::AbandonTransaction
1487 {
1488 self.abandon_transaction();
1489 }
1490 false
1491 }
1492 Ok(true) => true,
1493 Err(e) => match e {
1494 FilestoreError::ChecksumTypeNotImplemented(_) => {
1495 if self.declare_fault(ConditionCode::UnsupportedChecksumType)
1496 == FaultHandlerCode::AbandonTransaction
1497 {
1498 self.abandon_transaction();
1499 }
1500 true
1503 }
1504 _ => {
1505 if self.declare_fault(ConditionCode::FilestoreRejection)
1506 == FaultHandlerCode::AbandonTransaction
1507 {
1508 self.abandon_transaction();
1509 }
1510 false
1512 }
1513 },
1514 }
1515 }
1516
1517 fn start_check_limit_handling(&mut self) {
1518 self.set_step(TransactionStep::ReceivingFileDataPdusWithCheckLimitHandling);
1519 self.transaction_params.current_check_timer = Some(
1520 self.check_timer_creator
1521 .create_countdown(TimerContext::CheckLimit {
1522 local_id: self.local_cfg.id,
1523 remote_id: self.transaction_params.remote_cfg.unwrap().entity_id,
1524 entity_type: EntityType::Receiving,
1525 }),
1526 );
1527 self.transaction_params.current_check_count = 0;
1528 }
1529
1530 fn check_limit_handling(&mut self) -> Result<(), DestError> {
1531 if self.transaction_params.current_check_timer.is_none() {
1532 return Ok(());
1533 }
1534 let check_timer = self
1535 .transaction_params
1536 .current_check_timer
1537 .as_ref()
1538 .unwrap();
1539 if check_timer.has_expired() {
1540 if self.checksum_verify(
1541 self.transaction_params.progress,
1542 self.transaction_params.checksum,
1543 ) {
1544 self.transaction_params
1545 .finished_params
1546 .condition_code
1547 .set(ConditionCode::NoError);
1548 self.transaction_params
1549 .finished_params
1550 .delivery_code
1551 .set(DeliveryCode::Complete);
1552 self.set_step(TransactionStep::TransferCompletion);
1553 return Ok(());
1554 }
1555 if self.transaction_params.current_check_count + 1
1556 >= self.transaction_params.remote_cfg.unwrap().check_limit
1557 {
1558 if self.declare_fault(ConditionCode::CheckLimitReached)
1559 == FaultHandlerCode::AbandonTransaction
1560 {
1561 self.abandon_transaction();
1562 }
1563 } else {
1564 self.transaction_params.current_check_count += 1;
1565 self.transaction_params
1566 .current_check_timer
1567 .as_mut()
1568 .unwrap()
1569 .reset();
1570 }
1571 }
1572 Ok(())
1573 }
1574
1575 fn handle_prompt_pdu(&mut self, _raw_packet: &[u8]) -> Result<(), DestError> {
1576 Err(DestError::NotImplemented)
1577 }
1578
1579 fn fsm_busy(&mut self, cfdp_user: &mut impl CfdpUser) -> Result<u32, DestError> {
1580 let mut sent_packets = 0;
1581 if self.step() == TransactionStep::TransactionStart {
1582 let result = self.transaction_start(cfdp_user);
1583 if let Err(e) = result {
1584 self.reset();
1588 return Err(e);
1589 }
1590 }
1591 if self.step() == TransactionStep::WaitingForMetadata
1592 || self.step() == TransactionStep::ReceivingFileDataPdus
1593 {
1594 if let Some(ack_params) = &mut self.transaction_params.acked_params {
1595 if ack_params.deferred_procedure_active {
1596 sent_packets += self.deferred_lost_segment_handling()?;
1597 }
1598 }
1599 }
1600 if self.step() == TransactionStep::ReceivingFileDataPdusWithCheckLimitHandling {
1601 self.check_limit_handling()?;
1602 }
1603 if self.step() == TransactionStep::TransferCompletion {
1604 sent_packets += self.transfer_completion(cfdp_user)?;
1605 }
1606 if self.step() == TransactionStep::WaitingForFinishedAck {
1607 sent_packets += self.handle_positive_ack_procedures()?;
1608 if self.step() == TransactionStep::TransferCompletion {
1611 sent_packets += self.transfer_completion(cfdp_user)?;
1612 }
1613 }
1614 Ok(sent_packets)
1615 }
1616
1617 fn transaction_start(&mut self, cfdp_user: &mut impl CfdpUser) -> Result<(), DestError> {
1618 let id = self.transaction_id().unwrap();
1619 let dest_name = from_utf8(
1620 &self.transaction_params.file_names.dest_file_name
1621 [..self.transaction_params.file_names.dest_file_name_len],
1622 )?;
1623 self.transaction_params.file_names.dest_path_buf[0..dest_name.len()]
1624 .copy_from_slice(dest_name.as_bytes());
1625 self.transaction_params.file_names.dest_file_path_len = dest_name.len();
1626 let source_id = self.transaction_params.pdu_conf.source_id();
1627 let src_name = from_utf8(
1628 &self.transaction_params.file_names.src_file_name
1629 [0..self.transaction_params.file_names.src_file_name_len],
1630 )?;
1631 let mut msgs_to_user = SmallVec::<[MsgToUserTlv<'_>; 16]>::new();
1632 let mut num_msgs_to_user = 0;
1633 if self.transaction_params.msgs_to_user_size > 0 {
1634 let mut index = 0;
1635 while index < self.transaction_params.msgs_to_user_size {
1636 let msgs_to_user_tlv =
1638 MsgToUserTlv::from_bytes(&self.transaction_params.msgs_to_user_buf[index..])
1639 .expect("message to user creation failed unexpectedly");
1640 msgs_to_user.push(msgs_to_user_tlv);
1641 index += msgs_to_user_tlv.len_full();
1642 num_msgs_to_user += 1;
1643 }
1644 }
1645 let metadata_recvd_params = MetadataReceivedParams {
1646 id,
1647 source_id,
1648 file_size: self.transaction_params.file_size(),
1649 src_file_name: src_name,
1650 dest_file_name: dest_name,
1651 msgs_to_user: &msgs_to_user[..num_msgs_to_user],
1652 };
1653 cfdp_user.metadata_recvd_indication(&metadata_recvd_params);
1654
1655 if self.vfs.exists(dest_name)? && self.vfs.is_dir(dest_name)? {
1656 let source_file_name = self.vfs.file_name(src_name)?;
1662 if source_file_name.is_none() {
1663 return Err(DestError::PathConcat);
1664 }
1665 let source_name = source_file_name.unwrap();
1666 self.transaction_params.file_names.dest_path_buf[dest_name.len()] = b'/';
1667 self.transaction_params.file_names.dest_path_buf
1668 [dest_name.len() + 1..dest_name.len() + 1 + source_name.len()]
1669 .copy_from_slice(source_name.as_bytes());
1670 self.transaction_params.file_names.dest_file_path_len += 1 + source_name.len();
1671 }
1672 let dest_path_str = from_utf8(
1673 &self.transaction_params.file_names.dest_path_buf
1674 [0..self.transaction_params.file_names.dest_file_path_len],
1675 )?;
1676 if self.vfs.exists(dest_path_str)? {
1677 self.vfs.truncate_file(dest_path_str)?;
1678 } else {
1679 self.vfs.create_file(dest_path_str)?;
1680 }
1681 self.transaction_params.finished_params.file_status = FileStatus::Retained;
1682 drop(msgs_to_user);
1683 self.set_step(TransactionStep::ReceivingFileDataPdus);
1684 Ok(())
1685 }
1686
1687 fn transfer_completion(&mut self, cfdp_user: &mut impl CfdpUser) -> Result<u32, DestError> {
1688 let mut sent_packets = 0;
1689 self.notice_of_completion(cfdp_user)?;
1690 if self.transaction_params.transmission_mode() == TransmissionMode::Acknowledged
1691 || self.transaction_params.metadata_params().closure_requested
1692 {
1693 sent_packets += self.send_finished_pdu()?;
1694 self.start_positive_ack_procedure();
1695 if self.transaction_params.transmission_mode() == TransmissionMode::Acknowledged {
1696 self.set_step(TransactionStep::WaitingForFinishedAck);
1697 return Ok(sent_packets);
1698 }
1699 }
1700 self.reset();
1701 Ok(sent_packets)
1702 }
1703
1704 fn start_positive_ack_procedure(&mut self) {
1705 match &mut self.transaction_params.positive_ack_params {
1706 Some(current) => {
1707 current.ack_counter = 0;
1708 }
1709 None => {
1710 self.transaction_params.positive_ack_params = Some(PositiveAckParams {
1711 ack_counter: 0,
1712 positive_ack_of_cancellation: false,
1713 })
1714 }
1715 }
1716 self.transaction_params.ack_timer = Some(
1717 self.check_timer_creator
1718 .create_countdown(TimerContext::PositiveAck {
1719 expiry_time: self
1720 .transaction_params
1721 .remote_cfg
1722 .as_ref()
1723 .unwrap()
1724 .positive_ack_timer_interval,
1725 }),
1726 );
1727 }
1728
1729 fn handle_positive_ack_procedures(&mut self) -> Result<u32, DestError> {
1730 if self.transaction_params.positive_ack_params.is_none() {
1732 return Ok(0);
1733 }
1734 let params = self.transaction_params.positive_ack_params.unwrap();
1735
1736 if !self
1738 .transaction_params
1739 .ack_timer
1740 .as_mut()
1741 .unwrap()
1742 .has_expired()
1743 {
1744 return Ok(0);
1745 }
1746
1747 let expiration_limit = self
1748 .transaction_params
1749 .remote_cfg
1750 .as_ref()
1751 .unwrap()
1752 .positive_ack_timer_expiration_limit;
1753 if params.ack_counter + 1 >= expiration_limit {
1755 if self.declare_fault(ConditionCode::PositiveAckLimitReached)
1756 == FaultHandlerCode::AbandonTransaction
1757 {
1758 self.abandon_transaction();
1759 return Ok(0);
1760 }
1761 self.transaction_params
1762 .positive_ack_params
1763 .as_mut()
1764 .unwrap()
1765 .positive_ack_of_cancellation = true;
1766 return Ok(0);
1767 }
1768
1769 let params_mut = self
1770 .transaction_params
1771 .positive_ack_params
1772 .as_mut()
1773 .unwrap();
1774 params_mut.ack_counter += 1;
1775 self.transaction_params.ack_timer.as_mut().unwrap().reset();
1776 self.send_finished_pdu()
1777 }
1778
1779 fn notice_of_completion(&mut self, cfdp_user: &mut impl CfdpUser) -> Result<(), DestError> {
1780 if self.transaction_params.completion_disposition.get() == CompletionDisposition::Completed
1781 {
1782 } else if self
1784 .transaction_params
1785 .remote_cfg
1786 .as_ref()
1787 .unwrap()
1788 .disposition_on_cancellation
1789 && self.transaction_params.finished_params.delivery_code.get()
1790 == DeliveryCode::Incomplete
1791 {
1792 let dest_path = unsafe {
1794 from_utf8_unchecked(
1795 &self.transaction_params.file_names.dest_path_buf
1796 [0..self.transaction_params.file_names.dest_file_path_len],
1797 )
1798 };
1799 if self.vfs.exists(dest_path)? && self.vfs.is_file(dest_path)? {
1800 self.vfs.remove_file(dest_path)?;
1801 }
1802 self.transaction_params.finished_params.file_status = FileStatus::DiscardDeliberately;
1803 }
1804 let tstate = &self.transaction_params;
1805 let transaction_finished_params = TransactionFinishedParams {
1806 id: tstate.transaction_id.unwrap(),
1807 condition_code: tstate.finished_params.condition_code.get(),
1808 delivery_code: tstate.finished_params.delivery_code.get(),
1809 file_status: tstate.finished_params.file_status,
1810 };
1811 cfdp_user.transaction_finished_indication(&transaction_finished_params);
1812 Ok(())
1813 }
1814
1815 fn declare_fault(&self, condition_code: ConditionCode) -> FaultHandlerCode {
1818 let transaction_id = self.transaction_id().unwrap();
1820 let progress = self.transaction_params.progress;
1821 let mut fh_code = self
1822 .local_cfg
1823 .fault_handler
1824 .get_fault_handler(condition_code);
1825 if let Some(positive_ack) = &self.transaction_params.positive_ack_params {
1828 if positive_ack.positive_ack_of_cancellation {
1829 fh_code = FaultHandlerCode::AbandonTransaction;
1830 }
1831 }
1832 match fh_code {
1833 FaultHandlerCode::NoticeOfCancellation => {
1834 self.notice_of_cancellation(condition_code, EntityIdTlv::new(self.local_cfg().id));
1835 }
1836 FaultHandlerCode::NoticeOfSuspension => self.notice_of_suspension(),
1837 FaultHandlerCode::IgnoreError => (),
1838 FaultHandlerCode::AbandonTransaction => (),
1839 }
1840 self.local_cfg.fault_handler.report_fault(
1841 fh_code,
1842 FaultInfo::new(transaction_id, condition_code, progress),
1843 )
1844 }
1845
1846 fn notice_of_cancellation(&self, condition_code: ConditionCode, fault_location: EntityIdTlv) {
1847 self.set_step_internal(TransactionStep::TransferCompletion);
1848 let tstate = &self.transaction_params;
1849 tstate.finished_params.condition_code.set(condition_code);
1850 tstate
1851 .completion_disposition
1852 .set(CompletionDisposition::Cancelled);
1853 tstate
1854 .finished_params
1855 .fault_location_finished
1856 .set(Some(fault_location));
1857 }
1858
1859 fn notice_of_suspension(&self) {
1860 }
1862
1863 fn abandon_transaction(&mut self) {
1864 self.reset();
1865 }
1866
1867 #[inline]
1868 fn set_step_internal(&self, step: TransactionStep) {
1869 self.step.set(step);
1870 }
1871
1872 #[inline]
1873 fn set_step(&mut self, step: TransactionStep) {
1874 self.set_step_internal(step);
1875 }
1876
1877 fn send_finished_pdu(&mut self) -> Result<u32, DestError> {
1878 let tstate = &self.transaction_params;
1879
1880 let pdu_header = PduHeader::new_for_file_directive(self.transaction_params.pdu_conf, 0);
1881 let finished_pdu = if tstate.finished_params.condition_code.get() == ConditionCode::NoError
1882 || tstate.finished_params.condition_code.get() == ConditionCode::UnsupportedChecksumType
1883 {
1884 FinishedPduCreator::new_no_error(
1885 pdu_header,
1886 tstate.finished_params.delivery_code.get(),
1887 tstate.finished_params.file_status,
1888 )
1889 } else {
1890 FinishedPduCreator::new(
1891 pdu_header,
1892 tstate.finished_params.condition_code.get(),
1893 tstate.finished_params.delivery_code.get(),
1894 tstate.finished_params.file_status,
1895 &[],
1896 tstate.finished_params.fault_location_finished.get(),
1897 )
1898 };
1899 finished_pdu.write_to_bytes(self.pdu_and_cksum_buffer.get_mut())?;
1900 self.pdu_sender.send_file_directive_pdu(
1901 FileDirectiveType::FinishedPdu,
1902 &self.pdu_and_cksum_buffer.borrow()[0..finished_pdu.len_written()],
1903 )?;
1904 Ok(1)
1905 }
1906}
1907
1908#[cfg(test)]
1909mod tests {
1910 #[allow(unused_imports)]
1911 use std::println;
1912 use std::{
1913 fs,
1914 path::{Path, PathBuf},
1915 string::String,
1916 };
1917
1918 use alloc::vec::Vec;
1919 use rand::Rng;
1920 use spacepackets::{
1921 cfdp::{
1922 ChecksumType, TransmissionMode,
1923 lv::Lv,
1924 pdu::{
1925 WritablePduPacket, finished::FinishedPduReader, metadata::MetadataPduCreator,
1926 nak::NakPduReader,
1927 },
1928 },
1929 util::UnsignedByteFieldU8,
1930 };
1931
1932 use crate::{
1933 CRC_32, FaultHandler, IndicationConfig, PduRawWithInfo, RemoteConfigStoreStd,
1934 filestore::NativeFilestore,
1935 lost_segments::LostSegmentsList,
1936 tests::{
1937 LOCAL_ID, REMOTE_ID, SentPdu, TestCfdpSender, TestCfdpUser, TestCheckTimer,
1938 TestCheckTimerCreator, TestFaultHandler, TimerExpiryControl, basic_remote_cfg_table,
1939 },
1940 };
1941
1942 use super::*;
1943
1944 #[derive(Debug, Clone, Copy)]
1945 pub struct TransferInfo {
1946 id: TransactionId,
1947 header: PduHeader,
1948 }
1949
1950 type TestDestHandler = DestinationHandler<
1951 TestCfdpSender,
1952 TestFaultHandler,
1953 NativeFilestore,
1954 RemoteConfigStoreStd,
1955 TestCheckTimerCreator,
1956 TestCheckTimer,
1957 LostSegmentsList,
1958 >;
1959
1960 struct DestHandlerTestbench {
1961 expiry_control: TimerExpiryControl,
1962 handler: TestDestHandler,
1963 src_path: PathBuf,
1964 dest_path: PathBuf,
1965 check_dest_file: bool,
1966 check_handler_idle_at_drop: bool,
1967 closure_requested: bool,
1968 pdu_conf: CommonPduConfig,
1969 expected_full_data: Vec<u8>,
1970 expected_file_size: u64,
1971 buf: [u8; 512],
1972 }
1973
1974 impl DestHandlerTestbench {
1975 fn new_with_fixed_paths(
1976 fault_handler: TestFaultHandler,
1977
1978 transmission_mode: TransmissionMode,
1979 closure_requested: bool,
1980 ) -> Self {
1981 let (src_path, dest_path) = init_full_filepaths_textfile();
1982 assert!(!Path::exists(&dest_path));
1983 Self::new(
1984 fault_handler,
1985 transmission_mode,
1986 closure_requested,
1987 true,
1988 src_path,
1989 dest_path,
1990 )
1991 }
1992
1993 fn new(
1994 fault_handler: TestFaultHandler,
1995 transmission_mode: TransmissionMode,
1996 closure_requested: bool,
1997 check_dest_file: bool,
1998 src_path: PathBuf,
1999 dest_path: PathBuf,
2000 ) -> Self {
2001 let expiry_control = TimerExpiryControl::default();
2002 let test_sender = TestCfdpSender::default();
2003 let dest_handler = default_dest_handler(fault_handler, test_sender, &expiry_control);
2004 let mut handler = Self {
2005 expiry_control,
2006 handler: dest_handler,
2007 src_path,
2008 closure_requested,
2009 dest_path,
2010 check_dest_file,
2011 check_handler_idle_at_drop: true,
2012 expected_file_size: 0,
2013 pdu_conf: CommonPduConfig::new_with_byte_fields(
2014 LOCAL_ID,
2015 REMOTE_ID,
2016 UnsignedByteFieldU8::new(0),
2017 )
2018 .unwrap(),
2019 expected_full_data: Vec::new(),
2020 buf: [0; 512],
2021 };
2022 handler.pdu_conf.trans_mode = transmission_mode;
2023 handler.state_check(State::Idle, TransactionStep::Idle);
2024 handler
2025 }
2026
2027 pub fn fault_handler(&self) -> &FaultHandler<TestFaultHandler> {
2028 &self.handler.local_cfg.fault_handler
2029 }
2030
2031 #[inline]
2032 fn set_large_file_flag(&mut self, large_file: LargeFileFlag) {
2033 self.pdu_conf.file_flag = large_file;
2034 }
2035
2036 fn dest_path(&self) -> &PathBuf {
2037 &self.dest_path
2038 }
2039
2040 fn all_fault_queues_empty(&self) -> bool {
2041 self.handler
2042 .local_cfg
2043 .user_fault_hook()
2044 .borrow()
2045 .all_queues_empty()
2046 }
2047
2048 #[allow(dead_code)]
2049 fn indication_cfg_mut(&mut self) -> &mut IndicationConfig {
2050 &mut self.handler.local_cfg.indication_cfg
2051 }
2052
2053 fn remote_cfg_mut(&mut self) -> &mut RemoteEntityConfig {
2054 self.handler
2055 .remote_cfg_table
2056 .get_mut(LOCAL_ID.value())
2057 .unwrap()
2058 }
2059
2060 fn pdu_queue_empty(&mut self) -> bool {
2061 self.handler.pdu_sender.queue_empty()
2062 }
2063
2064 fn pdu_queue_len(&mut self) -> usize {
2065 self.handler.pdu_sender.queue_len()
2066 }
2067
2068 fn get_next_pdu(&mut self) -> Option<SentPdu> {
2069 self.handler.pdu_sender.retrieve_next_pdu()
2070 }
2071
2072 fn indication_cfg(&mut self) -> &IndicationConfig {
2073 &self.handler.local_cfg.indication_cfg
2074 }
2075
2076 fn set_check_timer_expired(&mut self) {
2077 self.expiry_control.set_check_limit_expired();
2078 }
2079
2080 fn set_nak_activity_timer_expired(&mut self) {
2081 self.expiry_control.set_nak_activity_expired();
2082 }
2083
2084 fn set_positive_ack_expired(&mut self) {
2085 self.expiry_control.set_positive_ack_expired();
2086 }
2087
2088 fn test_user_from_cached_paths(&self, expected_file_size: u64) -> TestCfdpUser {
2089 TestCfdpUser::new(
2090 0,
2091 self.src_path.to_string_lossy().into(),
2092 self.dest_path.to_string_lossy().into(),
2093 expected_file_size,
2094 )
2095 }
2096
2097 fn generic_transfer_init(
2098 &mut self,
2099 user: &mut TestCfdpUser,
2100 file_size: u64,
2101 ) -> Result<TransferInfo, DestError> {
2102 self.expected_file_size = file_size;
2103 assert_eq!(user.transaction_indication_call_count, 0);
2104 assert_eq!(user.metadata_recv_queue.len(), 0);
2105 let pdu_header = PduHeader::new_for_file_directive(self.pdu_conf, 0);
2106 let metadata_pdu = create_metadata_pdu(
2107 &pdu_header,
2108 self.src_path.as_path(),
2109 self.dest_path.as_path(),
2110 file_size,
2111 self.closure_requested,
2112 );
2113 let packet_info = create_packet_info(&metadata_pdu, &mut self.buf);
2114 self.handler.state_machine(user, Some(&packet_info))?;
2115 assert_eq!(user.metadata_recv_queue.len(), 1);
2116 assert_eq!(
2117 self.handler.transmission_mode().unwrap(),
2118 self.pdu_conf.trans_mode
2119 );
2120 assert_eq!(user.transaction_indication_call_count, 0);
2121 assert_eq!(user.metadata_recv_queue.len(), 1);
2122 let metadata_recvd = user.metadata_recv_queue.pop_front().unwrap();
2123 assert_eq!(metadata_recvd.source_id, LOCAL_ID.into());
2124 assert_eq!(
2125 metadata_recvd.src_file_name,
2126 String::from(self.src_path.to_str().unwrap())
2127 );
2128 assert_eq!(
2129 metadata_recvd.dest_file_name,
2130 String::from(self.dest_path().to_str().unwrap())
2131 );
2132 assert_eq!(metadata_recvd.id, self.handler.transaction_id().unwrap());
2133 assert_eq!(metadata_recvd.file_size, file_size);
2134 assert!(metadata_recvd.msgs_to_user.is_empty());
2135 Ok(TransferInfo {
2136 id: self.handler.transaction_id().unwrap(),
2137 header: pdu_header,
2138 })
2139 }
2140
2141 fn generic_file_data_insert(
2142 &mut self,
2143 user: &mut TestCfdpUser,
2144 offset: u64,
2145 file_data_chunk: &[u8],
2146 ) -> Result<u32, DestError> {
2147 let pdu_header = PduHeader::new_for_file_data_default(self.pdu_conf, 0);
2148 let filedata_pdu =
2149 FileDataPdu::new_no_seg_metadata(pdu_header, offset, file_data_chunk);
2150 filedata_pdu
2151 .write_to_bytes(&mut self.buf)
2152 .expect("writing file data PDU failed");
2153 let packet_info = PduRawWithInfo::new(&self.buf).expect("creating packet info failed");
2154 let result = self.handler.state_machine(user, Some(&packet_info));
2155 if self.indication_cfg().file_segment_recv {
2156 assert!(!user.file_seg_recvd_queue.is_empty());
2157 let file_seg = user.file_seg_recvd_queue.pop_front().unwrap();
2158 assert_eq!(file_seg.offset, offset);
2159 assert_eq!(file_seg.length, file_data_chunk.len());
2160 }
2161 result
2162 }
2163
2164 fn generic_eof_no_error(
2165 &mut self,
2166 user: &mut TestCfdpUser,
2167 expected_full_data: Vec<u8>,
2168 ) -> Result<u32, DestError> {
2169 self.expected_full_data = expected_full_data;
2170 assert_eq!(user.finished_indic_queue.len(), 0);
2171 let pdu_header = PduHeader::new_for_file_directive(self.pdu_conf, 0);
2172 let eof_pdu = create_no_error_eof(&self.expected_full_data, &pdu_header);
2173 let packet_info = create_packet_info(&eof_pdu, &mut self.buf);
2174 self.check_handler_idle_at_drop = true;
2175 self.check_dest_file = true;
2176 let result = self.handler.state_machine(user, Some(&packet_info));
2177 if self.indication_cfg().eof_recv {
2178 assert_eq!(user.eof_recvd_call_count, 1);
2179 }
2180 result
2181 }
2182
2183 fn check_completion_indication_success(&mut self, user: &mut TestCfdpUser) {
2184 assert_eq!(user.finished_indic_queue.len(), 1);
2185 let finished_indication = user.finished_indic_queue.pop_front().unwrap();
2186 assert_eq!(
2187 finished_indication.id,
2188 self.handler.transaction_id().unwrap()
2189 );
2190 assert_eq!(finished_indication.file_status, FileStatus::Retained);
2191 assert_eq!(finished_indication.delivery_code, DeliveryCode::Complete);
2192 assert_eq!(finished_indication.condition_code, ConditionCode::NoError);
2193 }
2194
2195 fn check_completion_indication_failure(
2196 &mut self,
2197 user: &mut TestCfdpUser,
2198 cond_code: ConditionCode,
2199 file_status: FileStatus,
2200 delivery_code: DeliveryCode,
2201 ) {
2202 assert_eq!(user.finished_indic_queue.len(), 1);
2203 let finished_indication = user.finished_indic_queue.pop_front().unwrap();
2204 assert_eq!(
2205 finished_indication.id,
2206 self.handler.transaction_id().unwrap()
2207 );
2208 assert_eq!(finished_indication.file_status, file_status);
2209 assert_eq!(finished_indication.delivery_code, delivery_code);
2210 assert_eq!(finished_indication.condition_code, cond_code);
2211 }
2212
2213 fn check_eof_ack_pdu(&mut self, cond_code: ConditionCode) {
2214 assert!(!self.pdu_queue_empty());
2215 let pdu = self.get_next_pdu().unwrap();
2216 assert_eq!(pdu.pdu_type, PduType::FileDirective);
2217 assert_eq!(pdu.file_directive_type.unwrap(), FileDirectiveType::AckPdu);
2218 let ack_pdu = AckPdu::from_bytes(&pdu.raw_pdu).unwrap();
2219 assert_eq!(ack_pdu.condition_code(), cond_code);
2220 assert_eq!(ack_pdu.transaction_status(), TransactionStatus::Active);
2221 assert_eq!(
2222 ack_pdu.directive_code_of_acked_pdu(),
2223 FileDirectiveType::EofPdu
2224 );
2225 }
2226
2227 fn check_finished_pdu_success(&mut self) {
2228 let pdu = self.get_next_pdu().unwrap();
2229 assert_eq!(pdu.pdu_type, PduType::FileDirective);
2230 assert_eq!(
2231 pdu.file_directive_type.unwrap(),
2232 FileDirectiveType::FinishedPdu
2233 );
2234 let finished_pdu = FinishedPduReader::from_bytes(&pdu.raw_pdu).unwrap();
2235 assert_eq!(finished_pdu.delivery_code(), DeliveryCode::Complete);
2236 assert_eq!(finished_pdu.file_status(), FileStatus::Retained);
2237 assert_eq!(finished_pdu.condition_code(), ConditionCode::NoError);
2238 assert!(finished_pdu.fault_location().is_none());
2239 }
2240
2241 fn check_finished_pdu_failure(
2242 &mut self,
2243 cond_code: ConditionCode,
2244 file_status: FileStatus,
2245 delivery_code: DeliveryCode,
2246 ) {
2247 let pdu = self.get_next_pdu().unwrap();
2248 assert_eq!(pdu.pdu_type, PduType::FileDirective);
2249 assert_eq!(
2250 pdu.file_directive_type.unwrap(),
2251 FileDirectiveType::FinishedPdu
2252 );
2253 let finished_pdu = FinishedPduReader::from_bytes(&pdu.raw_pdu).unwrap();
2254 assert_eq!(finished_pdu.delivery_code(), delivery_code);
2255 assert_eq!(finished_pdu.file_status(), file_status);
2256 assert_eq!(finished_pdu.condition_code(), cond_code);
2257 }
2258
2259 fn acknowledge_finished_pdu(
2260 &mut self,
2261 user: &mut impl CfdpUser,
2262 transfer_info: &TransferInfo,
2263 ) {
2264 let ack_pdu = AckPdu::new_for_finished_pdu(
2265 transfer_info.header,
2266 ConditionCode::NoError,
2267 TransactionStatus::Active,
2268 );
2269 self.handler
2270 .state_machine(user, Some(&create_packet_info(&ack_pdu, &mut self.buf)))
2271 .expect("handling ack PDU failed");
2272 }
2273
2274 fn state_check(&self, state: State, step: TransactionStep) {
2275 assert_eq!(self.handler.state(), state);
2276 assert_eq!(self.handler.step(), step);
2277 }
2278 }
2279
2280 impl Drop for DestHandlerTestbench {
2282 fn drop(&mut self) {
2283 if !self.all_fault_queues_empty() {
2284 let fh_queues = self.handler.local_cfg.user_fault_hook().borrow();
2285 println!(
2286 "fault queues not empty. cancellation {}, suspension {}, ignored {}, abandon {}",
2287 fh_queues.notice_of_cancellation_queue.len(),
2288 fh_queues.notice_of_suspension_queue.len(),
2289 fh_queues.ignored_queue.len(),
2290 fh_queues.abandoned_queue.len()
2291 );
2292 }
2293 assert!(self.all_fault_queues_empty(), "fault queues not empty, ");
2294 assert!(self.pdu_queue_empty());
2295 if self.check_handler_idle_at_drop {
2296 self.state_check(State::Idle, TransactionStep::Idle);
2297 }
2298 if self.check_dest_file {
2299 assert!(Path::exists(&self.dest_path));
2300 let read_content = fs::read(&self.dest_path).expect("reading back string failed");
2301 assert_eq!(read_content.len() as u64, self.expected_file_size);
2302 assert_eq!(read_content, self.expected_full_data);
2303 assert!(fs::remove_file(self.dest_path.as_path()).is_ok());
2304 }
2305 }
2306 }
2307
2308 fn init_full_filepaths_textfile() -> (PathBuf, PathBuf) {
2309 (
2310 tempfile::TempPath::from_path("/tmp/test.txt").to_path_buf(),
2311 tempfile::NamedTempFile::new()
2312 .unwrap()
2313 .into_temp_path()
2314 .to_path_buf(),
2315 )
2316 }
2317
2318 fn default_dest_handler(
2319 test_fault_handler: TestFaultHandler,
2320 test_packet_sender: TestCfdpSender,
2321 expiry_control: &TimerExpiryControl,
2322 ) -> TestDestHandler {
2323 let local_entity_cfg = LocalEntityConfig {
2324 id: REMOTE_ID.into(),
2325 indication_cfg: IndicationConfig::default(),
2326 fault_handler: FaultHandler::new(test_fault_handler),
2327 };
2328 DestinationHandler::new(
2329 local_entity_cfg,
2330 test_packet_sender,
2331 NativeFilestore::default(),
2332 basic_remote_cfg_table(LOCAL_ID, 1024, true),
2333 TestCheckTimerCreator::new(expiry_control),
2334 LostSegmentsList::default(),
2335 )
2336 }
2337
2338 fn create_metadata_pdu<'filename>(
2339 pdu_header: &PduHeader,
2340 src_name: &'filename Path,
2341 dest_name: &'filename Path,
2342 file_size: u64,
2343 closure_requested: bool,
2344 ) -> MetadataPduCreator<'filename, 'filename, 'static> {
2345 let checksum_type = if file_size == 0 {
2346 ChecksumType::NullChecksum
2347 } else {
2348 ChecksumType::Crc32
2349 };
2350 let metadata_params =
2351 MetadataGenericParams::new(closure_requested, checksum_type, file_size);
2352 MetadataPduCreator::new_no_opts(
2353 *pdu_header,
2354 metadata_params,
2355 Lv::new_from_str(src_name.as_os_str().to_str().unwrap()).unwrap(),
2356 Lv::new_from_str(dest_name.as_os_str().to_str().unwrap()).unwrap(),
2357 )
2358 }
2359
2360 fn create_packet_info<'a>(
2361 pdu: &'a impl WritablePduPacket,
2362 buf: &'a mut [u8],
2363 ) -> PduRawWithInfo<'a> {
2364 let written_len = pdu
2365 .write_to_bytes(buf)
2366 .expect("writing metadata PDU failed");
2367 PduRawWithInfo::new(&buf[..written_len]).expect("generating packet info failed")
2368 }
2369
2370 fn create_no_error_eof(file_data: &[u8], pdu_header: &PduHeader) -> EofPdu {
2371 let crc32 = if !file_data.is_empty() {
2372 let mut digest = CRC_32.digest();
2373 digest.update(file_data);
2374 digest.finalize()
2375 } else {
2376 0
2377 };
2378 EofPdu::new_no_error(*pdu_header, crc32, file_data.len() as u64)
2379 }
2380
2381 #[test]
2382 fn test_basic() {
2383 let fault_handler = TestFaultHandler::default();
2384 let test_sender = TestCfdpSender::default();
2385 let dest_handler =
2386 default_dest_handler(fault_handler, test_sender, &TimerExpiryControl::default());
2387 assert!(dest_handler.transmission_mode().is_none());
2388 assert!(
2389 dest_handler
2390 .local_cfg
2391 .fault_handler
2392 .user_hook
2393 .borrow()
2394 .all_queues_empty()
2395 );
2396 assert!(dest_handler.pdu_sender.queue_empty());
2397 assert_eq!(dest_handler.state(), State::Idle);
2398 assert_eq!(dest_handler.step(), TransactionStep::Idle);
2399 }
2400
2401 #[test]
2402 fn test_cancelling_idle_fsm() {
2403 let fault_handler = TestFaultHandler::default();
2404 let test_sender = TestCfdpSender::default();
2405 let mut dest_handler =
2406 default_dest_handler(fault_handler, test_sender, &TimerExpiryControl::default());
2407 assert!(!dest_handler.cancel_request(&TransactionId::new(
2408 UnsignedByteFieldU8::new(0).into(),
2409 UnsignedByteFieldU8::new(0).into()
2410 )));
2411 }
2412
2413 #[test]
2414 fn test_empty_file_transfer_not_acked_no_closure() {
2415 let fault_handler = TestFaultHandler::default();
2416 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
2417 fault_handler,
2418 TransmissionMode::Unacknowledged,
2419 false,
2420 );
2421 let mut test_user = tb.test_user_from_cached_paths(0);
2422 tb.generic_transfer_init(&mut test_user, 0)
2423 .expect("transfer init failed");
2424 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
2425 tb.generic_eof_no_error(&mut test_user, Vec::new())
2426 .expect("EOF no error insertion failed");
2427 tb.check_completion_indication_success(&mut test_user);
2428 }
2429
2430 #[test]
2431 fn test_empty_file_transfer_invalid_remote_id() {
2432 let fault_handler = TestFaultHandler::default();
2433 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
2434 fault_handler,
2435 TransmissionMode::Unacknowledged,
2436 false,
2437 );
2438 let mut test_user = tb.test_user_from_cached_paths(0);
2439 let mut conf = tb.pdu_conf;
2440 conf.set_source_and_dest_id(REMOTE_ID, LOCAL_ID).unwrap();
2442 let pdu_header = PduHeader::new_for_file_directive(conf, 0);
2443 let metadata_pdu = create_metadata_pdu(
2444 &pdu_header,
2445 tb.src_path.as_path(),
2446 tb.dest_path.as_path(),
2447 0,
2448 false,
2449 );
2450 let packet_info = create_packet_info(&metadata_pdu, &mut tb.buf);
2451 if let Err(DestError::NoRemoteConfigFound(id)) =
2452 tb.handler.state_machine(&mut test_user, Some(&packet_info))
2453 {
2454 assert_eq!(id, REMOTE_ID.into());
2455 } else {
2456 panic!("expected no remote config found error");
2457 }
2458 tb.check_dest_file = false;
2459 }
2460
2461 #[test]
2462 fn test_empty_file_transfer_acked() {
2463 let fault_handler = TestFaultHandler::default();
2464 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
2465 fault_handler,
2466 TransmissionMode::Acknowledged,
2467 false,
2468 );
2469 let mut user = tb.test_user_from_cached_paths(0);
2470 let transfer_info = tb
2471 .generic_transfer_init(&mut user, 0)
2472 .expect("transfer init failed");
2473 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
2474 tb.generic_eof_no_error(&mut user, Vec::new())
2475 .expect("EOF no error insertion failed");
2476 tb.check_completion_indication_success(&mut user);
2477 assert_eq!(tb.pdu_queue_len(), 2);
2478 tb.check_eof_ack_pdu(ConditionCode::NoError);
2479 tb.check_finished_pdu_success();
2480 tb.acknowledge_finished_pdu(&mut user, &transfer_info);
2481 }
2482
2483 #[test]
2484 fn test_small_file_transfer_not_acked() {
2485 let file_data_str = "Hello World!";
2486 let file_data = file_data_str.as_bytes();
2487 let file_size = file_data.len() as u64;
2488 let fault_handler = TestFaultHandler::default();
2489
2490 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
2491 fault_handler,
2492 TransmissionMode::Unacknowledged,
2493 false,
2494 );
2495 let mut user = tb.test_user_from_cached_paths(file_size);
2496 let _transfer_info = tb
2497 .generic_transfer_init(&mut user, file_size)
2498 .expect("transfer init failed");
2499 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
2500 assert_eq!(
2501 tb.generic_file_data_insert(&mut user, 0, file_data)
2502 .expect("file data insertion failed"),
2503 0
2504 );
2505 assert_eq!(
2506 tb.generic_eof_no_error(&mut user, file_data.to_vec())
2507 .expect("EOF no error insertion failed"),
2508 0
2509 );
2510 tb.check_completion_indication_success(&mut user);
2511 }
2512
2513 #[test]
2514 fn test_small_file_transfer_acked() {
2515 let file_data_str = "Hello World!";
2516 let file_data = file_data_str.as_bytes();
2517 let file_size = file_data.len() as u64;
2518 let fault_handler = TestFaultHandler::default();
2519
2520 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
2521 fault_handler,
2522 TransmissionMode::Acknowledged,
2523 false,
2524 );
2525 let mut user = tb.test_user_from_cached_paths(file_size);
2526 let transfer_info = tb
2527 .generic_transfer_init(&mut user, file_size)
2528 .expect("transfer init failed");
2529 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
2530 assert_eq!(
2531 tb.generic_file_data_insert(&mut user, 0, file_data)
2532 .expect("file data insertion failed"),
2533 0
2534 );
2535 assert_eq!(
2536 tb.generic_eof_no_error(&mut user, file_data.to_vec())
2537 .expect("EOF no error insertion failed"),
2538 2
2539 );
2540 tb.check_completion_indication_success(&mut user);
2541 assert_eq!(tb.pdu_queue_len(), 2);
2542 tb.check_eof_ack_pdu(ConditionCode::NoError);
2543 tb.check_finished_pdu_success();
2544 tb.acknowledge_finished_pdu(&mut user, &transfer_info);
2545 }
2546
2547 #[test]
2548 fn test_segmented_file_transfer_not_acked() {
2549 let mut rng = rand::rng();
2550 let mut random_data = [0u8; 512];
2551 rng.fill(&mut random_data);
2552 let file_size = random_data.len() as u64;
2553 let segment_len = 256;
2554 let fault_handler = TestFaultHandler::default();
2555
2556 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
2557 fault_handler,
2558 TransmissionMode::Unacknowledged,
2559 false,
2560 );
2561 let mut test_user = tb.test_user_from_cached_paths(file_size);
2562 tb.generic_transfer_init(&mut test_user, file_size)
2563 .expect("transfer init failed");
2564 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
2565 tb.generic_file_data_insert(&mut test_user, 0, &random_data[0..segment_len])
2566 .expect("file data insertion failed");
2567 tb.generic_file_data_insert(
2568 &mut test_user,
2569 segment_len as u64,
2570 &random_data[segment_len..],
2571 )
2572 .expect("file data insertion failed");
2573 tb.generic_eof_no_error(&mut test_user, random_data.to_vec())
2574 .expect("EOF no error insertion failed");
2575 tb.check_completion_indication_success(&mut test_user);
2576 }
2577
2578 #[test]
2579 fn test_segmented_file_transfer_acked() {
2580 let mut rng = rand::rng();
2581 let mut random_data = [0u8; 512];
2582 rng.fill(&mut random_data);
2583 let file_size = random_data.len() as u64;
2584 let segment_len = 256;
2585 let fault_handler = TestFaultHandler::default();
2586
2587 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
2588 fault_handler,
2589 TransmissionMode::Acknowledged,
2590 false,
2591 );
2592 let mut user = tb.test_user_from_cached_paths(file_size);
2593 let transfer_info = tb
2594 .generic_transfer_init(&mut user, file_size)
2595 .expect("transfer init failed");
2596 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
2597 tb.generic_file_data_insert(&mut user, 0, &random_data[0..segment_len])
2598 .expect("file data insertion failed");
2599 tb.generic_file_data_insert(&mut user, segment_len as u64, &random_data[segment_len..])
2600 .expect("file data insertion failed");
2601 tb.generic_eof_no_error(&mut user, random_data.to_vec())
2602 .expect("EOF no error insertion failed");
2603 tb.check_completion_indication_success(&mut user);
2604 assert_eq!(tb.pdu_queue_len(), 2);
2605 tb.check_eof_ack_pdu(ConditionCode::NoError);
2606 tb.check_finished_pdu_success();
2607 tb.acknowledge_finished_pdu(&mut user, &transfer_info);
2608 }
2609
2610 #[test]
2611 fn test_check_limit_handling_transfer_success() {
2612 let mut rng = rand::rng();
2613 let mut random_data = [0u8; 512];
2614 rng.fill(&mut random_data);
2615 let file_size = random_data.len() as u64;
2616 let segment_len = 256;
2617 let fault_handler = TestFaultHandler::default();
2618
2619 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
2620 fault_handler,
2621 TransmissionMode::Unacknowledged,
2622 false,
2623 );
2624 let mut test_user = tb.test_user_from_cached_paths(file_size);
2625 let transfer_info = tb
2626 .generic_transfer_init(&mut test_user, file_size)
2627 .expect("transfer init failed");
2628
2629 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
2630 tb.generic_file_data_insert(&mut test_user, 0, &random_data[0..segment_len])
2631 .expect("file data insertion 0 failed");
2632 tb.generic_eof_no_error(&mut test_user, random_data.to_vec())
2633 .expect("EOF no error insertion failed");
2634
2635 let mut fault_handler = tb.handler.local_cfg.fault_handler.user_hook.borrow_mut();
2637 assert_eq!(fault_handler.ignored_queue.len(), 1);
2638 let cancelled = fault_handler.ignored_queue.pop_front().unwrap();
2639 assert_eq!(cancelled.transaction_id(), transfer_info.id);
2640 assert_eq!(
2641 cancelled.condition_code(),
2642 ConditionCode::FileChecksumFailure
2643 );
2644 assert_eq!(cancelled.progress(), segment_len as u64);
2645
2646 drop(fault_handler);
2647 tb.state_check(
2648 State::Busy,
2649 TransactionStep::ReceivingFileDataPdusWithCheckLimitHandling,
2650 );
2651 tb.set_check_timer_expired();
2652
2653 tb.generic_file_data_insert(
2654 &mut test_user,
2655 segment_len as u64,
2656 &random_data[segment_len..],
2657 )
2658 .expect("file data insertion 1 failed");
2659 tb.handler
2660 .state_machine_no_packet(&mut test_user)
2661 .expect("fsm failure");
2662
2663 tb.check_completion_indication_success(&mut test_user);
2664 assert!(test_user.indication_queues_empty());
2665 }
2666
2667 #[test]
2668 fn test_check_limit_handling_limit_reached() {
2669 let mut rng = rand::rng();
2670 let mut random_data = [0u8; 512];
2671 rng.fill(&mut random_data);
2672 let file_size = random_data.len() as u64;
2673 let segment_len: usize = 256;
2674 let check_checksum_failure =
2675 |testbench: &mut DestHandlerTestbench, transaction_id: TransactionId| {
2676 let mut fault_hook = testbench.fault_handler().user_hook.borrow_mut();
2677 assert!(fault_hook.notice_of_suspension_queue.is_empty());
2678 let ignored_queue = &mut fault_hook.ignored_queue;
2679 assert_eq!(ignored_queue.len(), 1);
2680 let ignored = ignored_queue.pop_front().unwrap();
2681 assert_eq!(ignored.transaction_id(), transaction_id);
2682 assert_eq!(ignored.condition_code(), ConditionCode::FileChecksumFailure);
2683 assert_eq!(ignored.progress(), segment_len as u64);
2684 };
2685
2686 let fault_handler = TestFaultHandler::default();
2687 let mut testbench = DestHandlerTestbench::new_with_fixed_paths(
2688 fault_handler,
2689 TransmissionMode::Unacknowledged,
2690 false,
2691 );
2692 let mut test_user = testbench.test_user_from_cached_paths(file_size);
2693 let transfer_info = testbench
2694 .generic_transfer_init(&mut test_user, file_size)
2695 .expect("transfer init failed");
2696
2697 testbench.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
2698 testbench
2699 .generic_file_data_insert(&mut test_user, 0, &random_data[0..segment_len])
2700 .expect("file data insertion 0 failed");
2701 testbench
2702 .generic_eof_no_error(&mut test_user, random_data.to_vec())
2703 .expect("EOF no error insertion failed");
2704 check_checksum_failure(&mut testbench, transfer_info.id);
2705
2706 testbench.state_check(
2707 State::Busy,
2708 TransactionStep::ReceivingFileDataPdusWithCheckLimitHandling,
2709 );
2710
2711 testbench.set_check_timer_expired();
2712 testbench
2713 .handler
2714 .state_machine_no_packet(&mut test_user)
2715 .expect("fsm error");
2716 testbench.state_check(
2717 State::Busy,
2718 TransactionStep::ReceivingFileDataPdusWithCheckLimitHandling,
2719 );
2720 check_checksum_failure(&mut testbench, transfer_info.id);
2721
2722 testbench.set_check_timer_expired();
2723 testbench
2724 .handler
2725 .state_machine_no_packet(&mut test_user)
2726 .expect("fsm error");
2727 check_checksum_failure(&mut testbench, transfer_info.id);
2728
2729 testbench.state_check(State::Idle, TransactionStep::Idle);
2730
2731 {
2732 let mut fault_hook = testbench.fault_handler().user_hook.borrow_mut();
2733 let cancelled_queue = &mut fault_hook.notice_of_cancellation_queue;
2734 assert_eq!(cancelled_queue.len(), 1);
2735 let cancelled = cancelled_queue.pop_front().unwrap();
2736 assert_eq!(cancelled.transaction_id(), transfer_info.id);
2737 assert_eq!(cancelled.condition_code(), ConditionCode::CheckLimitReached);
2738 assert_eq!(cancelled.progress(), segment_len as u64);
2739 }
2740
2741 assert_eq!(test_user.finished_indic_queue.len(), 1);
2742 let finished_indication = test_user.finished_indic_queue.pop_front().unwrap();
2743 assert_eq!(finished_indication.id, transfer_info.id);
2744 assert_eq!(
2745 finished_indication.condition_code,
2746 ConditionCode::CheckLimitReached
2747 );
2748 assert_eq!(finished_indication.delivery_code, DeliveryCode::Incomplete);
2749 assert_eq!(finished_indication.file_status, FileStatus::Retained);
2750
2751 assert!(testbench.handler.pdu_sender.queue_empty());
2752
2753 testbench.check_dest_file = false;
2755 assert!(Path::exists(testbench.dest_path()));
2756 let read_content = fs::read(testbench.dest_path()).expect("reading back string failed");
2757 assert_eq!(read_content.len(), segment_len);
2758 assert_eq!(read_content, &random_data[0..segment_len]);
2759 assert!(fs::remove_file(testbench.dest_path().as_path()).is_ok());
2760 assert!(test_user.indication_queues_empty());
2761 }
2762
2763 fn check_finished_pdu_success(sent_pdu: &SentPdu) {
2764 assert_eq!(sent_pdu.pdu_type, PduType::FileDirective);
2765 assert_eq!(
2766 sent_pdu.file_directive_type,
2767 Some(FileDirectiveType::FinishedPdu)
2768 );
2769 let finished_pdu = FinishedPduReader::from_bytes(&sent_pdu.raw_pdu).unwrap();
2770 assert_eq!(finished_pdu.file_status(), FileStatus::Retained);
2771 assert_eq!(finished_pdu.condition_code(), ConditionCode::NoError);
2772 assert_eq!(finished_pdu.delivery_code(), DeliveryCode::Complete);
2773 assert!(finished_pdu.fault_location().is_none());
2774 assert_eq!(finished_pdu.fs_responses_raw(), &[]);
2775 }
2776
2777 #[test]
2778 fn test_file_transfer_with_closure() {
2779 let fault_handler = TestFaultHandler::default();
2780 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
2781 fault_handler,
2782 TransmissionMode::Unacknowledged,
2783 true,
2784 );
2785 let mut test_user = tb.test_user_from_cached_paths(0);
2786 tb.generic_transfer_init(&mut test_user, 0)
2787 .expect("transfer init failed");
2788 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
2789 let sent_packets = tb
2790 .generic_eof_no_error(&mut test_user, Vec::new())
2791 .expect("EOF no error insertion failed");
2792 assert_eq!(sent_packets, 1);
2793 assert!(tb.all_fault_queues_empty());
2794 tb.state_check(State::Idle, TransactionStep::Idle);
2796 assert!(!tb.handler.pdu_sender.queue_empty());
2797 let sent_pdu = tb.handler.pdu_sender.retrieve_next_pdu().unwrap();
2798 check_finished_pdu_success(&sent_pdu);
2799 tb.check_completion_indication_success(&mut test_user);
2800 assert!(test_user.indication_queues_empty());
2801 }
2802
2803 #[test]
2804 fn test_finished_pdu_insertion_rejected() {
2805 let fault_handler = TestFaultHandler::default();
2806 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
2807 fault_handler,
2808 TransmissionMode::Unacknowledged,
2809 false,
2810 );
2811 tb.check_dest_file = false;
2812 let mut user = tb.test_user_from_cached_paths(0);
2813 let finished_pdu = FinishedPduCreator::new_no_error(
2814 PduHeader::new_for_file_directive(CommonPduConfig::default(), 0),
2815 DeliveryCode::Complete,
2816 FileStatus::Retained,
2817 );
2818 let finished_pdu_raw = finished_pdu.to_vec().unwrap();
2819 let packet_info = PduRawWithInfo::new(&finished_pdu_raw).unwrap();
2820 let error = tb.handler.state_machine(&mut user, Some(&packet_info));
2821 assert!(error.is_err());
2822 let error = error.unwrap_err();
2823 if let DestError::CantProcessPacketType {
2824 pdu_type,
2825 directive_type,
2826 } = error
2827 {
2828 assert_eq!(pdu_type, PduType::FileDirective);
2829 assert_eq!(directive_type, Some(FileDirectiveType::FinishedPdu));
2830 }
2831 }
2832
2833 #[test]
2834 fn test_metadata_insertion_twice_fails() {
2835 let fault_handler = TestFaultHandler::default();
2836 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
2837 fault_handler,
2838 TransmissionMode::Unacknowledged,
2839 true,
2840 );
2841 let mut user = tb.test_user_from_cached_paths(0);
2842 tb.generic_transfer_init(&mut user, 0)
2843 .expect("transfer init failed");
2844 tb.check_handler_idle_at_drop = false;
2845 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
2846 let pdu_header = PduHeader::new_for_file_directive(tb.pdu_conf, 0);
2847 let metadata_pdu = create_metadata_pdu(
2848 &pdu_header,
2849 tb.src_path.as_path(),
2850 tb.dest_path.as_path(),
2851 0,
2852 tb.closure_requested,
2853 );
2854 let packet_info = create_packet_info(&metadata_pdu, &mut tb.buf);
2855 let error = tb.handler.state_machine(&mut user, Some(&packet_info));
2856 assert!(error.is_err());
2857 let error = error.unwrap_err();
2858 if let DestError::RecvdMetadataButIsBusy = error {
2859 } else {
2860 panic!("unexpected error: {:?}", error);
2861 }
2862 }
2863
2864 #[test]
2865 fn test_checksum_failure_not_acked() {
2866 let file_data_str = "Hello World!";
2867 let file_data = file_data_str.as_bytes();
2868 let file_size = file_data.len() as u64;
2869 let fault_handler = TestFaultHandler::default();
2870 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
2871 fault_handler,
2872 TransmissionMode::Unacknowledged,
2873 true,
2874 );
2875 let mut user = tb.test_user_from_cached_paths(file_size);
2876 tb.generic_transfer_init(&mut user, file_size)
2877 .expect("transfer init failed");
2878 let faulty_file_data = b"Hemlo World!";
2879 assert_eq!(
2880 tb.generic_file_data_insert(&mut user, 0, faulty_file_data)
2881 .expect("file data insertion failed"),
2882 0
2883 );
2884 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
2885 let sent_packets = tb
2886 .generic_eof_no_error(&mut user, file_data.into())
2887 .expect("EOF no error insertion failed");
2888 assert_eq!(sent_packets, 0);
2890
2891 let transaction_id = tb.handler.transaction_id().unwrap();
2892 let mut fault_hook = tb.handler.local_cfg.user_fault_hook().borrow_mut();
2893 assert!(fault_hook.notice_of_suspension_queue.is_empty());
2894
2895 let ignored_queue = &mut fault_hook.ignored_queue;
2898 assert_eq!(ignored_queue.len(), 1);
2899 let cancelled = ignored_queue.pop_front().unwrap();
2900 assert_eq!(cancelled.transaction_id(), transaction_id);
2901 assert_eq!(
2902 cancelled.condition_code(),
2903 ConditionCode::FileChecksumFailure
2904 );
2905 assert_eq!(cancelled.progress(), file_size);
2906 drop(fault_hook);
2907
2908 tb.state_check(
2909 State::Busy,
2910 TransactionStep::ReceivingFileDataPdusWithCheckLimitHandling,
2911 );
2912 tb.set_check_timer_expired();
2913 tb.handler
2914 .state_machine_no_packet(&mut user)
2915 .expect("fsm error");
2916 tb.state_check(
2917 State::Busy,
2918 TransactionStep::ReceivingFileDataPdusWithCheckLimitHandling,
2919 );
2920 tb.set_check_timer_expired();
2921 tb.handler
2922 .state_machine_no_packet(&mut user)
2923 .expect("fsm error");
2924 tb.state_check(State::Idle, TransactionStep::Idle);
2925
2926 let mut fault_hook = tb.handler.local_cfg.user_fault_hook().borrow_mut();
2928 let cancelled_queue = &mut fault_hook.notice_of_cancellation_queue;
2929 assert_eq!(cancelled_queue.len(), 1);
2930 let cancelled = cancelled_queue.pop_front().unwrap();
2931 assert_eq!(cancelled.transaction_id(), transaction_id);
2932 assert_eq!(cancelled.condition_code(), ConditionCode::CheckLimitReached);
2933 assert_eq!(cancelled.progress(), file_size);
2934
2935 drop(fault_hook);
2936
2937 let sent_pdu = tb.handler.pdu_sender.retrieve_next_pdu().unwrap();
2938 assert_eq!(sent_pdu.pdu_type, PduType::FileDirective);
2939 assert_eq!(
2940 sent_pdu.file_directive_type,
2941 Some(FileDirectiveType::FinishedPdu)
2942 );
2943 let finished_pdu = FinishedPduReader::from_bytes(&sent_pdu.raw_pdu).unwrap();
2944 assert_eq!(finished_pdu.file_status(), FileStatus::Retained);
2945 assert_eq!(
2946 finished_pdu.condition_code(),
2947 ConditionCode::CheckLimitReached
2948 );
2949
2950 let mut fault_hook = tb.handler.local_cfg.user_fault_hook().borrow_mut();
2951 let ignored_queue = &mut fault_hook.ignored_queue;
2952 assert_eq!(ignored_queue.len(), 2);
2953 let mut ignored = ignored_queue.pop_front().unwrap();
2954 assert_eq!(ignored.transaction_id(), transaction_id);
2955 assert_eq!(ignored.condition_code(), ConditionCode::FileChecksumFailure);
2956 assert_eq!(ignored.progress(), file_size);
2957 ignored = ignored_queue.pop_front().unwrap();
2958 assert_eq!(ignored.transaction_id(), transaction_id);
2959 assert_eq!(ignored.condition_code(), ConditionCode::FileChecksumFailure);
2960 assert_eq!(ignored.progress(), file_size);
2961
2962 assert_eq!(finished_pdu.delivery_code(), DeliveryCode::Incomplete);
2963 assert!(finished_pdu.fault_location().is_some());
2964 assert_eq!(
2965 *finished_pdu.fault_location().unwrap().entity_id(),
2966 REMOTE_ID.into()
2967 );
2968 assert_eq!(finished_pdu.fs_responses_raw(), &[]);
2969 assert!(tb.handler.pdu_sender.queue_empty());
2970 user.verify_finished_indication_retained(
2971 DeliveryCode::Incomplete,
2972 ConditionCode::CheckLimitReached,
2973 transaction_id,
2974 );
2975 tb.expected_full_data = faulty_file_data.to_vec();
2976 }
2977
2978 #[test]
2979 fn test_file_copy_to_directory() {
2980 let fault_handler = TestFaultHandler::default();
2981 let src_path = tempfile::TempPath::from_path("/tmp/test.txt").to_path_buf();
2982 let dest_path = tempfile::TempDir::new().unwrap();
2983 let mut dest_path_buf = dest_path.keep();
2984 let mut tb = DestHandlerTestbench::new(
2985 fault_handler,
2986 TransmissionMode::Unacknowledged,
2987 false,
2988 false,
2989 src_path.clone(),
2990 dest_path_buf.clone(),
2991 );
2992 dest_path_buf.push(src_path.file_name().unwrap());
2993 tb.dest_path = dest_path_buf;
2994 let mut user = tb.test_user_from_cached_paths(0);
2995 tb.generic_transfer_init(&mut user, 0)
2996 .expect("transfer init failed");
2997 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
2998 tb.generic_eof_no_error(&mut user, Vec::new())
2999 .expect("EOF no error insertion failed");
3000 tb.check_completion_indication_success(&mut user);
3001 }
3002
3003 #[test]
3004 fn test_tranfer_cancellation_empty_file_with_eof_pdu() {
3005 let fault_handler = TestFaultHandler::default();
3006 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
3007 fault_handler,
3008 TransmissionMode::Unacknowledged,
3009 false,
3010 );
3011 let mut user = tb.test_user_from_cached_paths(0);
3012 let transfer_info = tb
3013 .generic_transfer_init(&mut user, 0)
3014 .expect("transfer init failed");
3015 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
3016 let pdu_header = PduHeader::new_for_file_directive(tb.pdu_conf, 0);
3017 let cancel_eof = EofPdu::new(
3018 pdu_header,
3019 ConditionCode::CancelRequestReceived,
3020 0,
3021 0,
3022 Some(EntityIdTlv::new(LOCAL_ID.into())),
3023 );
3024 let packets = tb
3025 .handler
3026 .state_machine(
3027 &mut user,
3028 Some(&PduRawWithInfo::new(&cancel_eof.to_vec().unwrap()).unwrap()),
3029 )
3030 .expect("state machine call with EOF insertion failed");
3031 assert_eq!(packets, 0);
3032 user.verify_finished_indication_retained(
3033 DeliveryCode::Complete,
3034 ConditionCode::CancelRequestReceived,
3035 transfer_info.id,
3036 );
3037 }
3038
3039 fn generic_tranfer_cancellation_partial_file_with_eof_pdu(
3040 with_closure: bool,
3041 insert_packet: bool,
3042 ) {
3043 let file_data_str = "Hello World!";
3044 let file_data = file_data_str.as_bytes();
3045 let file_size = 5;
3046
3047 let fault_handler = TestFaultHandler::default();
3048 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
3049 fault_handler,
3050 TransmissionMode::Unacknowledged,
3051 with_closure,
3052 );
3053 let mut user = tb.test_user_from_cached_paths(file_size);
3054 let transfer_info = tb
3055 .generic_transfer_init(&mut user, file_size)
3056 .expect("transfer init failed");
3057 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
3058 if insert_packet {
3059 tb.generic_file_data_insert(&mut user, 0, &file_data[0..5])
3060 .expect("file data insertion failed");
3061 }
3062 let mut digest = CRC_32.digest();
3063 digest.update(&file_data[0..5]);
3064 let checksum = digest.finalize();
3065 let pdu_header = PduHeader::new_for_file_directive(tb.pdu_conf, 0);
3066 let cancel_eof = EofPdu::new(
3067 pdu_header,
3068 ConditionCode::CancelRequestReceived,
3069 checksum,
3070 5,
3071 Some(EntityIdTlv::new(LOCAL_ID.into())),
3072 );
3073 let packets = tb
3074 .handler
3075 .state_machine(
3076 &mut user,
3077 Some(&PduRawWithInfo::new(&cancel_eof.to_vec().unwrap()).unwrap()),
3078 )
3079 .expect("state machine call with EOF insertion failed");
3080 if with_closure {
3081 assert_eq!(packets, 1);
3082 let finished_pdu = tb.handler.pdu_sender.retrieve_next_pdu().unwrap();
3083 assert_eq!(finished_pdu.pdu_type, PduType::FileDirective);
3084 assert_eq!(
3085 finished_pdu.file_directive_type.unwrap(),
3086 FileDirectiveType::FinishedPdu
3087 );
3088 let finished_pdu = FinishedPduReader::from_bytes(&finished_pdu.raw_pdu).unwrap();
3089 assert_eq!(
3090 finished_pdu.condition_code(),
3091 ConditionCode::CancelRequestReceived
3092 );
3093 if insert_packet {
3094 assert_eq!(finished_pdu.delivery_code(), DeliveryCode::Complete);
3096 user.verify_finished_indication_retained(
3097 DeliveryCode::Complete,
3098 ConditionCode::CancelRequestReceived,
3099 transfer_info.id,
3100 );
3101 } else {
3102 assert_eq!(finished_pdu.delivery_code(), DeliveryCode::Incomplete);
3104 tb.check_dest_file = false;
3105 let mut fault_hook = tb.handler.local_cfg.user_fault_hook().borrow_mut();
3106 let ignored_queue = &mut fault_hook.ignored_queue;
3107 let ignored = ignored_queue.pop_front().unwrap();
3108 assert_eq!(ignored.transaction_id(), transfer_info.id);
3109 assert_eq!(ignored.condition_code(), ConditionCode::FileChecksumFailure);
3110 assert_eq!(ignored.progress(), 5);
3111 user.verify_finished_indication_retained(
3112 DeliveryCode::Incomplete,
3113 ConditionCode::CancelRequestReceived,
3114 transfer_info.id,
3115 );
3116 }
3117 assert_eq!(finished_pdu.file_status(), FileStatus::Retained);
3118 assert_eq!(
3119 finished_pdu
3120 .fault_location()
3121 .expect("no fault location set"),
3122 EntityIdTlv::new(LOCAL_ID.into())
3123 );
3124 } else {
3125 user.verify_finished_indication_retained(
3126 DeliveryCode::Complete,
3127 ConditionCode::CancelRequestReceived,
3128 transfer_info.id,
3129 );
3130 assert_eq!(packets, 0);
3131 }
3132 tb.expected_file_size = file_size;
3133 tb.expected_full_data = file_data[0..file_size as usize].to_vec();
3134 }
3135
3136 #[test]
3137 fn test_tranfer_cancellation_partial_file_with_eof_pdu_no_closure_complete() {
3138 generic_tranfer_cancellation_partial_file_with_eof_pdu(false, true);
3139 }
3140
3141 #[test]
3142 fn test_tranfer_cancellation_partial_file_with_eof_pdu_with_closure_complete() {
3143 generic_tranfer_cancellation_partial_file_with_eof_pdu(true, true);
3144 }
3145
3146 #[test]
3147 fn test_tranfer_cancellation_partial_file_with_eof_pdu_with_closure_incomplete() {
3148 generic_tranfer_cancellation_partial_file_with_eof_pdu(true, false);
3149 }
3150
3151 #[test]
3152 fn test_tranfer_cancellation_empty_file_with_cancel_api() {
3153 let fault_handler = TestFaultHandler::default();
3154 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
3155 fault_handler,
3156 TransmissionMode::Unacknowledged,
3157 false,
3158 );
3159 let mut user = tb.test_user_from_cached_paths(0);
3160 let transfer_info = tb
3161 .generic_transfer_init(&mut user, 0)
3162 .expect("transfer init failed");
3163 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
3164 tb.handler.cancel_request(&transfer_info.id);
3165 let packets = tb
3166 .handler
3167 .state_machine_no_packet(&mut user)
3168 .expect("state machine call with EOF insertion failed");
3169 user.verify_finished_indication_retained(
3170 DeliveryCode::Complete,
3171 ConditionCode::CancelRequestReceived,
3172 transfer_info.id,
3173 );
3174 assert_eq!(packets, 0);
3175 }
3176
3177 #[test]
3178 fn test_tranfer_cancellation_empty_file_with_cancel_api_and_closure() {
3179 let fault_handler = TestFaultHandler::default();
3180 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
3181 fault_handler,
3182 TransmissionMode::Unacknowledged,
3183 true,
3184 );
3185 let mut user = tb.test_user_from_cached_paths(0);
3186 let transfer_info = tb
3187 .generic_transfer_init(&mut user, 0)
3188 .expect("transfer init failed");
3189 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
3190 tb.handler.cancel_request(&transfer_info.id);
3191 let packets = tb
3192 .handler
3193 .state_machine_no_packet(&mut user)
3194 .expect("state machine call with EOF insertion failed");
3195 assert_eq!(packets, 1);
3196 let next_pdu = tb.get_next_pdu().unwrap();
3197 assert_eq!(next_pdu.pdu_type, PduType::FileDirective);
3198 assert_eq!(
3199 next_pdu.file_directive_type.unwrap(),
3200 FileDirectiveType::FinishedPdu
3201 );
3202 let finished_pdu =
3203 FinishedPduReader::new(&next_pdu.raw_pdu).expect("finished pdu read failed");
3204 assert_eq!(
3205 finished_pdu.condition_code(),
3206 ConditionCode::CancelRequestReceived
3207 );
3208 assert_eq!(finished_pdu.file_status(), FileStatus::Retained);
3209 assert_eq!(finished_pdu.delivery_code(), DeliveryCode::Complete);
3211 assert_eq!(
3212 finished_pdu.fault_location(),
3213 Some(EntityIdTlv::new(REMOTE_ID.into()))
3214 );
3215 user.verify_finished_indication_retained(
3216 DeliveryCode::Complete,
3217 ConditionCode::CancelRequestReceived,
3218 transfer_info.id,
3219 );
3220 }
3221
3222 #[test]
3223 fn test_tranfer_cancellation_partial_file_with_cancel_api_and_closure() {
3224 let file_data_str = "Hello World!";
3225 let file_data = file_data_str.as_bytes();
3226 let file_size = 5;
3227
3228 let fault_handler = TestFaultHandler::default();
3229 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
3230 fault_handler,
3231 TransmissionMode::Unacknowledged,
3232 true,
3233 );
3234 let mut user = tb.test_user_from_cached_paths(file_size);
3235 let transfer_info = tb
3236 .generic_transfer_init(&mut user, file_size)
3237 .expect("transfer init failed");
3238 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
3239 tb.generic_file_data_insert(&mut user, 0, &file_data[0..5])
3240 .expect("file data insertion failed");
3241
3242 tb.handler.cancel_request(&transfer_info.id);
3243 let packets = tb
3244 .handler
3245 .state_machine_no_packet(&mut user)
3246 .expect("state machine call with EOF insertion failed");
3247 assert_eq!(packets, 1);
3248 let next_pdu = tb.get_next_pdu().unwrap();
3249 assert_eq!(next_pdu.pdu_type, PduType::FileDirective);
3250 assert_eq!(
3251 next_pdu.file_directive_type.unwrap(),
3252 FileDirectiveType::FinishedPdu
3253 );
3254 let finished_pdu =
3255 FinishedPduReader::new(&next_pdu.raw_pdu).expect("finished pdu read failed");
3256 assert_eq!(
3257 finished_pdu.condition_code(),
3258 ConditionCode::CancelRequestReceived
3259 );
3260 assert_eq!(finished_pdu.file_status(), FileStatus::Retained);
3261 assert_eq!(finished_pdu.delivery_code(), DeliveryCode::Incomplete);
3262 assert_eq!(
3263 finished_pdu.fault_location(),
3264 Some(EntityIdTlv::new(REMOTE_ID.into()))
3265 );
3266 tb.expected_file_size = file_size;
3267 tb.expected_full_data = file_data[0..file_size as usize].to_vec();
3268 user.verify_finished_indication_retained(
3269 DeliveryCode::Incomplete,
3270 ConditionCode::CancelRequestReceived,
3271 transfer_info.id,
3272 );
3273 }
3274
3275 #[test]
3277 fn test_tranfer_cancellation_file_disposition_not_done_for_empty_file() {
3278 let fault_handler = TestFaultHandler::default();
3279 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
3280 fault_handler,
3281 TransmissionMode::Unacknowledged,
3282 false,
3283 );
3284 let remote_cfg_mut = tb
3285 .handler
3286 .remote_cfg_table
3287 .get_mut(LOCAL_ID.value())
3288 .unwrap();
3289 remote_cfg_mut.disposition_on_cancellation = true;
3290 let mut user = tb.test_user_from_cached_paths(0);
3291 let transfer_info = tb
3292 .generic_transfer_init(&mut user, 0)
3293 .expect("transfer init failed");
3294 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
3295
3296 tb.handler.cancel_request(&transfer_info.id);
3297 let packets = tb
3298 .handler
3299 .state_machine_no_packet(&mut user)
3300 .expect("state machine call with EOF insertion failed");
3301 assert_eq!(packets, 0);
3302 user.verify_finished_indication_retained(
3303 DeliveryCode::Complete,
3304 ConditionCode::CancelRequestReceived,
3305 transfer_info.id,
3306 );
3307 }
3308
3309 #[test]
3310 fn test_tranfer_cancellation_file_disposition_not_done_for_incomplete_file() {
3311 let file_data_str = "Hello World!";
3312 let file_data = file_data_str.as_bytes();
3313 let file_size = file_data.len() as u64;
3314
3315 let fault_handler = TestFaultHandler::default();
3316 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
3317 fault_handler,
3318 TransmissionMode::Unacknowledged,
3319 false,
3320 );
3321 tb.check_dest_file = false;
3322 let remote_cfg_mut = tb
3323 .handler
3324 .remote_cfg_table
3325 .get_mut(LOCAL_ID.value())
3326 .unwrap();
3327 remote_cfg_mut.disposition_on_cancellation = true;
3328 let mut user = tb.test_user_from_cached_paths(file_size);
3329 let transfer_info = tb
3330 .generic_transfer_init(&mut user, file_size)
3331 .expect("transfer init failed");
3332 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
3333 tb.generic_file_data_insert(&mut user, 0, &file_data[0..5])
3334 .expect("file data insertion failed");
3335
3336 tb.handler.cancel_request(&transfer_info.id);
3337 let packets = tb
3338 .handler
3339 .state_machine_no_packet(&mut user)
3340 .expect("state machine call with EOF insertion failed");
3341 assert_eq!(packets, 0);
3342 assert!(!Path::exists(tb.dest_path()));
3344 assert_eq!(user.finished_indic_queue.len(), 1);
3345 user.verify_finished_indication(
3346 DeliveryCode::Incomplete,
3347 ConditionCode::CancelRequestReceived,
3348 transfer_info.id,
3349 FileStatus::DiscardDeliberately,
3350 );
3351 }
3352
3353 fn generic_test_immediate_nak_request(file_flag: LargeFileFlag) {
3354 let file_data_str = "Hello World!";
3355 let file_data = file_data_str.as_bytes();
3356 let file_size = file_data.len() as u64;
3357 let fault_handler = TestFaultHandler::default();
3358
3359 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
3360 fault_handler,
3361 TransmissionMode::Acknowledged,
3362 false,
3363 );
3364 tb.set_large_file_flag(file_flag);
3365 tb.remote_cfg_mut().immediate_nak_mode = true;
3366 let mut user = tb.test_user_from_cached_paths(file_size);
3367 let transfer_info = tb
3368 .generic_transfer_init(&mut user, file_size)
3369 .expect("transfer init failed");
3370 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
3371
3372 assert_eq!(
3374 tb.generic_file_data_insert(&mut user, 4, &file_data[4..])
3375 .expect("file data insertion failed"),
3376 1
3377 );
3378 assert_eq!(tb.pdu_queue_len(), 1);
3379 let pdu = tb.get_next_pdu().unwrap();
3380 assert_eq!(pdu.pdu_type, PduType::FileDirective);
3381 assert_eq!(pdu.file_directive_type.unwrap(), FileDirectiveType::NakPdu);
3382 let nak_pdu = NakPduReader::new(&pdu.raw_pdu).unwrap();
3383 assert_eq!(nak_pdu.pdu_header().common_pdu_conf().file_flag, file_flag);
3384 assert_eq!(nak_pdu.start_of_scope(), 0);
3385 assert_eq!(nak_pdu.end_of_scope(), file_size);
3386 let seg_reqs: Vec<(u64, u64)> = nak_pdu.get_segment_requests_iterator().unwrap().collect();
3387 assert_eq!(seg_reqs.len(), 1);
3388 assert_eq!(seg_reqs[0], (0, 4));
3389 tb.generic_file_data_insert(&mut user, 0, &file_data[0..4])
3391 .expect("file data insertion failed");
3392
3393 tb.generic_eof_no_error(&mut user, file_data.to_vec())
3394 .expect("EOF no error insertion failed");
3395 tb.check_completion_indication_success(&mut user);
3396 assert_eq!(tb.pdu_queue_len(), 2);
3397 tb.check_eof_ack_pdu(ConditionCode::NoError);
3398 tb.check_finished_pdu_success();
3399 tb.acknowledge_finished_pdu(&mut user, &transfer_info);
3400 }
3401
3402 #[test]
3403 fn test_immediate_nak_request() {
3404 generic_test_immediate_nak_request(LargeFileFlag::Normal);
3405 }
3406
3407 #[test]
3408 fn test_immediate_nak_request_large_file() {
3409 generic_test_immediate_nak_request(LargeFileFlag::Large);
3410 }
3411
3412 fn generic_test_deferred_nak_request(file_flag: LargeFileFlag) {
3413 let file_data_str = "Hello World!";
3414 let file_data = file_data_str.as_bytes();
3415 let file_size = file_data.len() as u64;
3416 let fault_handler = TestFaultHandler::default();
3417
3418 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
3419 fault_handler,
3420 TransmissionMode::Acknowledged,
3421 false,
3422 );
3423 tb.set_large_file_flag(file_flag);
3424 tb.remote_cfg_mut().immediate_nak_mode = false;
3426 let mut user = tb.test_user_from_cached_paths(file_size);
3427 let transfer_info = tb
3428 .generic_transfer_init(&mut user, file_size)
3429 .expect("transfer init failed");
3430 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
3431
3432 assert_eq!(
3433 tb.generic_file_data_insert(&mut user, 4, &file_data[4..])
3434 .expect("file data insertion failed"),
3435 0
3436 );
3437 assert_eq!(
3438 tb.generic_eof_no_error(&mut user, file_data.to_vec())
3439 .expect("EOF no error insertion failed"),
3440 2
3441 );
3442 assert_eq!(tb.pdu_queue_len(), 2);
3443 tb.check_eof_ack_pdu(ConditionCode::NoError);
3444 assert_eq!(tb.pdu_queue_len(), 1);
3445 let pdu = tb.get_next_pdu().unwrap();
3446 assert_eq!(pdu.pdu_type, PduType::FileDirective);
3447 assert_eq!(pdu.file_directive_type.unwrap(), FileDirectiveType::NakPdu);
3448 let nak_pdu = NakPduReader::new(&pdu.raw_pdu).unwrap();
3449 assert_eq!(nak_pdu.start_of_scope(), 0);
3450 assert_eq!(nak_pdu.end_of_scope(), file_size);
3451 let seg_reqs: Vec<(u64, u64)> = nak_pdu.get_segment_requests_iterator().unwrap().collect();
3452 assert_eq!(seg_reqs.len(), 1);
3453 assert_eq!(seg_reqs[0], (0, 4));
3454
3455 tb.generic_file_data_insert(&mut user, 0, &file_data[0..4])
3457 .expect("file data insertion failed");
3458 tb.check_completion_indication_success(&mut user);
3459 assert_eq!(tb.pdu_queue_len(), 1);
3460 tb.check_finished_pdu_success();
3461 tb.acknowledge_finished_pdu(&mut user, &transfer_info);
3462 }
3463
3464 #[test]
3465 fn test_deferred_nak_request() {
3466 generic_test_deferred_nak_request(LargeFileFlag::Normal);
3467 }
3468
3469 #[test]
3470 fn test_deferred_nak_request_large() {
3471 generic_test_deferred_nak_request(LargeFileFlag::Large);
3472 }
3473
3474 #[test]
3475 fn test_file_data_before_metadata() {
3476 let file_data_str = "Hello World!";
3477 let file_data = file_data_str.as_bytes();
3478 let file_size = file_data.len() as u64;
3479 let fault_handler = TestFaultHandler::default();
3480
3481 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
3482 fault_handler,
3483 TransmissionMode::Acknowledged,
3484 false,
3485 );
3486 tb.remote_cfg_mut().immediate_nak_mode = true;
3487 let mut user = tb.test_user_from_cached_paths(file_size);
3488 assert_eq!(
3489 tb.generic_file_data_insert(&mut user, 0, file_data)
3490 .expect("file data insertion failed"),
3491 1
3492 );
3493 tb.state_check(State::Busy, TransactionStep::WaitingForMetadata);
3494 assert_eq!(tb.pdu_queue_len(), 1);
3495 let pdu = tb.get_next_pdu().unwrap();
3496 assert_eq!(pdu.pdu_type, PduType::FileDirective);
3497 assert_eq!(pdu.file_directive_type.unwrap(), FileDirectiveType::NakPdu);
3498 let nak_pdu = NakPduReader::new(&pdu.raw_pdu).unwrap();
3499 assert_eq!(nak_pdu.start_of_scope(), 0);
3500 assert_eq!(nak_pdu.end_of_scope(), file_size);
3501 let seg_reqs: Vec<(u64, u64)> = nak_pdu.get_segment_requests_iterator().unwrap().collect();
3502 assert_eq!(seg_reqs.len(), 2);
3503 assert_eq!(seg_reqs[0], (0, 0));
3505 assert_eq!(seg_reqs[1], (0, 12));
3508
3509 let transfer_info = tb
3510 .generic_transfer_init(&mut user, file_size)
3511 .expect("transfer init failed");
3512 assert_eq!(
3514 tb.generic_file_data_insert(&mut user, 0, file_data)
3515 .expect("file data insertion failed"),
3516 0
3517 );
3518 assert_eq!(
3519 tb.generic_eof_no_error(&mut user, file_data.to_vec())
3520 .expect("EOF no error insertion failed"),
3521 2
3522 );
3523 tb.check_completion_indication_success(&mut user);
3524 assert_eq!(tb.pdu_queue_len(), 2);
3525 tb.check_eof_ack_pdu(ConditionCode::NoError);
3526 tb.check_finished_pdu_success();
3527 tb.acknowledge_finished_pdu(&mut user, &transfer_info);
3528 }
3529
3530 #[test]
3531 fn test_eof_before_metadata() {
3532 let file_data_str = "Hello World!";
3533 let file_data = file_data_str.as_bytes();
3534 let file_size = file_data.len() as u64;
3535 let fault_handler = TestFaultHandler::default();
3536
3537 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
3538 fault_handler,
3539 TransmissionMode::Acknowledged,
3540 false,
3541 );
3542 tb.remote_cfg_mut().immediate_nak_mode = true;
3543 let mut user = tb.test_user_from_cached_paths(file_size);
3544 assert_eq!(
3546 tb.generic_eof_no_error(&mut user, file_data.to_vec())
3547 .expect("file data insertion failed"),
3548 2
3549 );
3550 tb.state_check(State::Busy, TransactionStep::WaitingForMetadata);
3551 assert_eq!(tb.pdu_queue_len(), 2);
3552 tb.check_eof_ack_pdu(ConditionCode::NoError);
3553 let pdu = tb.get_next_pdu().unwrap();
3554 assert_eq!(pdu.pdu_type, PduType::FileDirective);
3555 assert_eq!(pdu.file_directive_type.unwrap(), FileDirectiveType::NakPdu);
3556 let nak_pdu = NakPduReader::new(&pdu.raw_pdu).unwrap();
3557 assert_eq!(nak_pdu.start_of_scope(), 0);
3558 assert_eq!(nak_pdu.end_of_scope(), file_size);
3559 let seg_reqs: Vec<(u64, u64)> = nak_pdu.get_segment_requests_iterator().unwrap().collect();
3560 assert_eq!(seg_reqs.len(), 2);
3561 assert_eq!(seg_reqs[0], (0, 0));
3563 assert_eq!(seg_reqs[1], (0, 12));
3566
3567 let transfer_info = tb
3568 .generic_transfer_init(&mut user, file_size)
3569 .expect("transfer init failed");
3570 assert_eq!(
3572 tb.generic_file_data_insert(&mut user, 0, file_data)
3573 .expect("file data insertion failed"),
3574 1
3575 );
3576 tb.check_completion_indication_success(&mut user);
3577 assert_eq!(tb.pdu_queue_len(), 1);
3578 tb.check_finished_pdu_success();
3579 tb.acknowledge_finished_pdu(&mut user, &transfer_info);
3580 }
3581
3582 #[test]
3583 fn test_nak_limit_reached() {
3584 let file_data_str = "Hello World!";
3585 let file_data = file_data_str.as_bytes();
3586 let file_size = file_data.len() as u64;
3587 let fault_handler = TestFaultHandler::default();
3588
3589 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
3590 fault_handler,
3591 TransmissionMode::Acknowledged,
3592 false,
3593 );
3594 tb.remote_cfg_mut().immediate_nak_mode = false;
3596 let mut user = tb.test_user_from_cached_paths(file_size);
3597 let transfer_info = tb
3598 .generic_transfer_init(&mut user, file_size)
3599 .expect("transfer init failed");
3600 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
3601
3602 assert_eq!(
3603 tb.generic_file_data_insert(&mut user, 4, &file_data[4..])
3604 .expect("file data insertion failed"),
3605 0
3606 );
3607 assert_eq!(
3608 tb.generic_eof_no_error(&mut user, file_data.to_vec())
3609 .expect("EOF no error insertion failed"),
3610 2
3611 );
3612 assert_eq!(tb.pdu_queue_len(), 2);
3613 tb.check_eof_ack_pdu(ConditionCode::NoError);
3614 assert_eq!(tb.pdu_queue_len(), 1);
3615 let pdu = tb.get_next_pdu().unwrap();
3616 assert_eq!(pdu.pdu_type, PduType::FileDirective);
3617 assert_eq!(pdu.file_directive_type.unwrap(), FileDirectiveType::NakPdu);
3618 let nak_pdu = NakPduReader::new(&pdu.raw_pdu).unwrap();
3619 assert_eq!(nak_pdu.start_of_scope(), 0);
3620 assert_eq!(nak_pdu.end_of_scope(), file_size);
3621 let seg_reqs: Vec<(u64, u64)> = nak_pdu.get_segment_requests_iterator().unwrap().collect();
3622 assert_eq!(seg_reqs.len(), 1);
3623 assert_eq!(seg_reqs[0], (0, 4));
3624
3625 tb.set_nak_activity_timer_expired();
3627 assert_eq!(tb.handler.state_machine_no_packet(&mut user).unwrap(), 1);
3628 assert_eq!(tb.pdu_queue_len(), 1);
3629 let pdu = tb.get_next_pdu().unwrap();
3630 assert_eq!(pdu.pdu_type, PduType::FileDirective);
3631 assert_eq!(pdu.file_directive_type.unwrap(), FileDirectiveType::NakPdu);
3632 let nak_pdu = NakPduReader::new(&pdu.raw_pdu).unwrap();
3633 assert_eq!(nak_pdu.start_of_scope(), 0);
3634 assert_eq!(nak_pdu.end_of_scope(), file_size);
3635 let seg_reqs: Vec<(u64, u64)> = nak_pdu.get_segment_requests_iterator().unwrap().collect();
3636 assert_eq!(seg_reqs.len(), 1);
3637 assert_eq!(seg_reqs[0], (0, 4));
3638
3639 tb.set_nak_activity_timer_expired();
3641 assert_eq!(tb.handler.state_machine_no_packet(&mut user).unwrap(), 1);
3642 assert_eq!(tb.pdu_queue_len(), 1);
3643 tb.check_completion_indication_failure(
3644 &mut user,
3645 ConditionCode::NakLimitReached,
3646 FileStatus::Retained,
3647 DeliveryCode::Incomplete,
3648 );
3649 tb.check_finished_pdu_failure(
3650 ConditionCode::NakLimitReached,
3651 FileStatus::Retained,
3652 DeliveryCode::Incomplete,
3653 );
3654
3655 {
3656 let mut fault_hook = tb.fault_handler().user_hook.borrow_mut();
3657 assert_eq!(fault_hook.notice_of_cancellation_queue.len(), 1);
3658 let cancellation = fault_hook.notice_of_cancellation_queue.pop_front().unwrap();
3659 assert_eq!(cancellation.transaction_id(), transfer_info.id);
3660 assert_eq!(
3661 cancellation.condition_code(),
3662 ConditionCode::NakLimitReached
3663 );
3664 assert_eq!(cancellation.progress(), file_size);
3665 }
3666 tb.acknowledge_finished_pdu(&mut user, &transfer_info);
3667 tb.check_dest_file = false;
3668 }
3669
3670 #[test]
3671 fn test_positive_ack_procedure() {
3672 let fault_handler = TestFaultHandler::default();
3673 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
3674 fault_handler,
3675 TransmissionMode::Acknowledged,
3676 false,
3677 );
3678 let mut user = tb.test_user_from_cached_paths(0);
3679 let transfer_info = tb
3680 .generic_transfer_init(&mut user, 0)
3681 .expect("transfer init failed");
3682 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
3683 tb.generic_eof_no_error(&mut user, Vec::new())
3684 .expect("EOF no error insertion failed");
3685 tb.check_completion_indication_success(&mut user);
3686 assert_eq!(tb.pdu_queue_len(), 2);
3687 tb.check_eof_ack_pdu(ConditionCode::NoError);
3688 tb.check_finished_pdu_success();
3689
3690 tb.set_positive_ack_expired();
3691 assert_eq!(tb.handler.state_machine_no_packet(&mut user).unwrap(), 1);
3693 tb.check_finished_pdu_success();
3694 tb.acknowledge_finished_pdu(&mut user, &transfer_info);
3695 }
3696
3697 fn generic_positive_ack_test(
3698 tb: &mut DestHandlerTestbench,
3699 user: &mut TestCfdpUser,
3700 ) -> TransferInfo {
3701 let transfer_info = tb
3702 .generic_transfer_init(user, 0)
3703 .expect("transfer init failed");
3704 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
3705 tb.generic_eof_no_error(user, Vec::new())
3706 .expect("EOF no error insertion failed");
3707 tb.check_completion_indication_success(user);
3708 assert_eq!(tb.pdu_queue_len(), 2);
3709 tb.check_eof_ack_pdu(ConditionCode::NoError);
3710 tb.check_finished_pdu_success();
3711
3712 tb.set_positive_ack_expired();
3714 assert_eq!(tb.handler.state_machine_no_packet(user).unwrap(), 1);
3715 tb.check_finished_pdu_success();
3716
3717 tb.set_positive_ack_expired();
3719 assert_eq!(tb.handler.state_machine_no_packet(user).unwrap(), 1);
3720
3721 tb.check_finished_pdu_failure(
3722 ConditionCode::PositiveAckLimitReached,
3723 FileStatus::Retained,
3724 DeliveryCode::Complete,
3725 );
3726 tb.check_completion_indication_failure(
3727 user,
3728 ConditionCode::PositiveAckLimitReached,
3729 FileStatus::Retained,
3730 DeliveryCode::Complete,
3731 );
3732 {
3733 let mut fault_handler = tb.fault_handler().user_hook.borrow_mut();
3734 assert!(!fault_handler.cancellation_queue_empty());
3735 let cancellation = fault_handler
3736 .notice_of_cancellation_queue
3737 .pop_front()
3738 .unwrap();
3739 assert_eq!(cancellation.transaction_id(), transfer_info.id);
3740 assert_eq!(
3741 cancellation.condition_code(),
3742 ConditionCode::PositiveAckLimitReached
3743 );
3744 assert_eq!(cancellation.progress(), 0);
3745 }
3746 transfer_info
3747 }
3748
3749 #[test]
3750 fn test_positive_ack_limit_reached() {
3751 let fault_handler = TestFaultHandler::default();
3752 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
3753 fault_handler,
3754 TransmissionMode::Acknowledged,
3755 false,
3756 );
3757 let mut user = tb.test_user_from_cached_paths(0);
3758 let transfer_info = generic_positive_ack_test(&mut tb, &mut user);
3759 tb.acknowledge_finished_pdu(&mut user, &transfer_info);
3762 }
3763
3764 #[test]
3765 fn test_positive_ack_limit_reached_with_subsequent_abandonment() {
3766 let fault_handler = TestFaultHandler::default();
3767 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
3768 fault_handler,
3769 TransmissionMode::Acknowledged,
3770 false,
3771 );
3772 let mut user = tb.test_user_from_cached_paths(0);
3773 let transfer_info = generic_positive_ack_test(&mut tb, &mut user);
3774
3775 tb.set_positive_ack_expired();
3777 assert_eq!(tb.handler.state_machine_no_packet(&mut user).unwrap(), 1);
3778 tb.check_finished_pdu_failure(
3779 ConditionCode::PositiveAckLimitReached,
3780 FileStatus::Retained,
3781 DeliveryCode::Complete,
3782 );
3783
3784 tb.set_positive_ack_expired();
3786 assert_eq!(tb.handler.state_machine_no_packet(&mut user).unwrap(), 0);
3787 {
3788 let mut fault_handler = tb.fault_handler().user_hook.borrow_mut();
3789 assert!(!fault_handler.abandoned_queue_empty());
3790 let cancellation = fault_handler.abandoned_queue.pop_front().unwrap();
3791 assert_eq!(cancellation.transaction_id(), transfer_info.id);
3792 assert_eq!(
3793 cancellation.condition_code(),
3794 ConditionCode::PositiveAckLimitReached
3795 );
3796 assert_eq!(cancellation.progress(), 0);
3797 }
3798 }
3799
3800 #[test]
3801 fn test_multi_segment_nak() {
3802 let file_data_str = "Hello Wooorld!";
3803 let file_data = file_data_str.as_bytes();
3804 let file_size = file_data.len() as u64;
3805 let fault_handler = TestFaultHandler::default();
3806
3807 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
3808 fault_handler,
3809 TransmissionMode::Acknowledged,
3810 false,
3811 );
3812 tb.remote_cfg_mut().immediate_nak_mode = false;
3814 let mut user = tb.test_user_from_cached_paths(file_size);
3815 let transfer_info = tb
3816 .generic_transfer_init(&mut user, file_size)
3817 .expect("transfer init failed");
3818 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
3819
3820 assert_eq!(
3821 tb.generic_file_data_insert(&mut user, 2, &file_data[2..4])
3822 .expect("file data insertion failed"),
3823 0
3824 );
3825 assert_eq!(
3826 tb.generic_file_data_insert(&mut user, 6, &file_data[6..8])
3827 .expect("file data insertion failed"),
3828 0
3829 );
3830 assert_eq!(
3831 tb.generic_file_data_insert(&mut user, 10, &file_data[10..])
3832 .expect("file data insertion failed"),
3833 0
3834 );
3835 assert_eq!(
3836 tb.generic_eof_no_error(&mut user, file_data.to_vec())
3837 .expect("EOF no error insertion failed"),
3838 2
3839 );
3840 assert_eq!(tb.pdu_queue_len(), 2);
3841 tb.check_eof_ack_pdu(ConditionCode::NoError);
3842 assert_eq!(tb.pdu_queue_len(), 1);
3843 let pdu = tb.get_next_pdu().unwrap();
3844 assert_eq!(pdu.pdu_type, PduType::FileDirective);
3845 assert_eq!(pdu.file_directive_type.unwrap(), FileDirectiveType::NakPdu);
3846 let nak_pdu = NakPduReader::new(&pdu.raw_pdu).unwrap();
3847 assert_eq!(nak_pdu.start_of_scope(), 0);
3848 assert_eq!(nak_pdu.end_of_scope(), file_size);
3849 let seg_reqs: Vec<(u64, u64)> = nak_pdu.get_segment_requests_iterator().unwrap().collect();
3850 assert_eq!(seg_reqs.len(), 3);
3851 assert_eq!(seg_reqs[0], (0, 2));
3852 assert_eq!(seg_reqs[1], (4, 6));
3853 assert_eq!(seg_reqs[2], (8, 10));
3854
3855 tb.generic_file_data_insert(&mut user, 0, &file_data[0..2])
3857 .expect("file data insertion failed");
3858 tb.generic_file_data_insert(&mut user, 4, &file_data[4..6])
3859 .expect("file data insertion failed");
3860 tb.generic_file_data_insert(&mut user, 8, &file_data[8..10])
3861 .expect("file data insertion failed");
3862 tb.check_completion_indication_success(&mut user);
3863 assert_eq!(tb.pdu_queue_len(), 1);
3864 tb.check_finished_pdu_success();
3865 tb.acknowledge_finished_pdu(&mut user, &transfer_info);
3866 }
3867
3868 #[test]
3869 fn test_multi_packet_nak_sequence_large_file_flag() {
3870 let file_data = [0_u8; 64];
3871 let file_size = file_data.len() as u64;
3872 let fault_handler = TestFaultHandler::default();
3873
3874 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
3875 fault_handler,
3876 TransmissionMode::Acknowledged,
3877 false,
3878 );
3879 tb.remote_cfg_mut().immediate_nak_mode = false;
3881 let max_packet_len = 80;
3882 tb.remote_cfg_mut().max_packet_len = max_packet_len;
3883 tb.set_large_file_flag(LargeFileFlag::Large);
3884 let mut user = tb.test_user_from_cached_paths(file_size);
3885 let transfer_info = tb
3886 .generic_transfer_init(&mut user, file_size)
3887 .expect("transfer init failed");
3888 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
3889
3890 assert_eq!(
3891 NakPduCreatorWithReservedSeqReqsBuf::calculate_max_segment_requests(
3892 max_packet_len,
3893 &PduHeader::new_for_file_directive(tb.pdu_conf, 0),
3894 )
3895 .unwrap(),
3896 3
3897 );
3898 let missing_segs_0: &[(u64, u64)] = &[(0, 2), (4, 6), (8, 10)];
3899 let missing_segs_1: &[(u64, u64)] = &[(12, 14)];
3900 assert_eq!(
3901 tb.generic_file_data_insert(&mut user, 2, &file_data[2..4])
3902 .expect("file data insertion failed"),
3903 0
3904 );
3905 assert_eq!(
3906 tb.generic_file_data_insert(&mut user, 6, &file_data[6..8])
3907 .expect("file data insertion failed"),
3908 0
3909 );
3910 assert_eq!(
3911 tb.generic_file_data_insert(&mut user, 10, &file_data[10..12])
3912 .expect("file data insertion failed"),
3913 0
3914 );
3915 assert_eq!(
3916 tb.generic_file_data_insert(&mut user, 14, &file_data[14..file_size as usize])
3917 .expect("file data insertion failed"),
3918 0
3919 );
3920 assert_eq!(
3921 tb.generic_eof_no_error(&mut user, file_data.to_vec())
3922 .expect("EOF no error insertion failed"),
3923 3
3924 );
3925 assert_eq!(tb.pdu_queue_len(), 3);
3926 tb.check_eof_ack_pdu(ConditionCode::NoError);
3927 let pdu = tb.get_next_pdu().unwrap();
3928 assert_eq!(pdu.pdu_type, PduType::FileDirective);
3929 assert_eq!(pdu.file_directive_type.unwrap(), FileDirectiveType::NakPdu);
3930 let nak_pdu = NakPduReader::new(&pdu.raw_pdu).unwrap();
3931 assert_eq!(nak_pdu.start_of_scope(), 0);
3932 assert_eq!(nak_pdu.end_of_scope(), 10);
3933 let seg_reqs: Vec<(u64, u64)> = nak_pdu.get_segment_requests_iterator().unwrap().collect();
3934 assert_eq!(seg_reqs, missing_segs_0);
3935
3936 let pdu = tb.get_next_pdu().unwrap();
3937 assert_eq!(pdu.pdu_type, PduType::FileDirective);
3938 assert_eq!(pdu.file_directive_type.unwrap(), FileDirectiveType::NakPdu);
3939 let nak_pdu = NakPduReader::new(&pdu.raw_pdu).unwrap();
3940 assert_eq!(nak_pdu.start_of_scope(), 10);
3941 assert_eq!(nak_pdu.end_of_scope(), file_size);
3942 let seg_reqs: Vec<(u64, u64)> = nak_pdu.get_segment_requests_iterator().unwrap().collect();
3943 assert_eq!(seg_reqs, missing_segs_1);
3944
3945 for missing_seg in missing_segs_0 {
3946 assert_eq!(
3947 tb.generic_file_data_insert(
3948 &mut user,
3949 missing_seg.0,
3950 &file_data[missing_seg.0 as usize..missing_seg.1 as usize]
3951 )
3952 .expect("file data insertion failed"),
3953 0
3954 );
3955 }
3956 for missing_seg in missing_segs_1 {
3957 assert_eq!(
3958 tb.generic_file_data_insert(
3959 &mut user,
3960 missing_seg.0,
3961 &file_data[missing_seg.0 as usize..missing_seg.1 as usize]
3962 )
3963 .expect("file data insertion failed"),
3964 1
3965 );
3966 }
3967
3968 tb.check_completion_indication_success(&mut user);
3969 assert_eq!(tb.pdu_queue_len(), 1);
3970 tb.check_finished_pdu_success();
3971 tb.acknowledge_finished_pdu(&mut user, &transfer_info);
3972 }
3973
3974 #[test]
3975 fn test_multi_packet_nak_sequence_normal_file_flag() {
3976 let file_data = [0_u8; 64];
3977 let file_size = file_data.len() as u64;
3978 let fault_handler = TestFaultHandler::default();
3979
3980 let mut tb = DestHandlerTestbench::new_with_fixed_paths(
3981 fault_handler,
3982 TransmissionMode::Acknowledged,
3983 false,
3984 );
3985 tb.remote_cfg_mut().immediate_nak_mode = false;
3987 let max_packet_len = 50;
3988 tb.remote_cfg_mut().max_packet_len = max_packet_len;
3989 let mut user = tb.test_user_from_cached_paths(file_size);
3990 let transfer_info = tb
3991 .generic_transfer_init(&mut user, file_size)
3992 .expect("transfer init failed");
3993 tb.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
3994
3995 assert_eq!(
3996 NakPduCreatorWithReservedSeqReqsBuf::calculate_max_segment_requests(
3997 max_packet_len,
3998 &PduHeader::new_for_file_directive(tb.pdu_conf, 0),
3999 )
4000 .unwrap(),
4001 4
4002 );
4003 let missing_segs_0: &[(u64, u64)] = &[(0, 2), (4, 6), (8, 10), (12, 14)];
4004 let missing_segs_1: &[(u64, u64)] = &[(16, 18)];
4005 assert_eq!(
4006 tb.generic_file_data_insert(&mut user, 2, &file_data[2..4])
4007 .expect("file data insertion failed"),
4008 0
4009 );
4010 assert_eq!(
4011 tb.generic_file_data_insert(&mut user, 6, &file_data[6..8])
4012 .expect("file data insertion failed"),
4013 0
4014 );
4015 assert_eq!(
4016 tb.generic_file_data_insert(&mut user, 10, &file_data[10..12])
4017 .expect("file data insertion failed"),
4018 0
4019 );
4020 assert_eq!(
4021 tb.generic_file_data_insert(&mut user, 14, &file_data[14..16])
4022 .expect("file data insertion failed"),
4023 0
4024 );
4025 assert_eq!(
4026 tb.generic_file_data_insert(&mut user, 18, &file_data[18..file_size as usize])
4027 .expect("file data insertion failed"),
4028 0
4029 );
4030 assert_eq!(
4031 tb.generic_eof_no_error(&mut user, file_data.to_vec())
4032 .expect("EOF no error insertion failed"),
4033 3
4034 );
4035 assert_eq!(tb.pdu_queue_len(), 3);
4036 tb.check_eof_ack_pdu(ConditionCode::NoError);
4037 let pdu = tb.get_next_pdu().unwrap();
4038 assert_eq!(pdu.pdu_type, PduType::FileDirective);
4039 assert_eq!(pdu.file_directive_type.unwrap(), FileDirectiveType::NakPdu);
4040 let nak_pdu = NakPduReader::new(&pdu.raw_pdu).unwrap();
4041 assert_eq!(nak_pdu.start_of_scope(), 0);
4042 assert_eq!(nak_pdu.end_of_scope(), 14);
4043 let seg_reqs: Vec<(u64, u64)> = nak_pdu.get_segment_requests_iterator().unwrap().collect();
4044 assert_eq!(seg_reqs, missing_segs_0);
4045
4046 let pdu = tb.get_next_pdu().unwrap();
4047 assert_eq!(pdu.pdu_type, PduType::FileDirective);
4048 assert_eq!(pdu.file_directive_type.unwrap(), FileDirectiveType::NakPdu);
4049 let nak_pdu = NakPduReader::new(&pdu.raw_pdu).unwrap();
4050 assert_eq!(nak_pdu.start_of_scope(), 14);
4051 assert_eq!(nak_pdu.end_of_scope(), file_size);
4052 let seg_reqs: Vec<(u64, u64)> = nak_pdu.get_segment_requests_iterator().unwrap().collect();
4053 assert_eq!(seg_reqs, missing_segs_1);
4054
4055 for missing_seg in missing_segs_0 {
4056 assert_eq!(
4057 tb.generic_file_data_insert(
4058 &mut user,
4059 missing_seg.0,
4060 &file_data[missing_seg.0 as usize..missing_seg.1 as usize]
4061 )
4062 .expect("file data insertion failed"),
4063 0
4064 );
4065 }
4066 for missing_seg in missing_segs_1 {
4067 assert_eq!(
4068 tb.generic_file_data_insert(
4069 &mut user,
4070 missing_seg.0,
4071 &file_data[missing_seg.0 as usize..missing_seg.1 as usize]
4072 )
4073 .expect("file data insertion failed"),
4074 1
4075 );
4076 }
4077
4078 tb.check_completion_indication_success(&mut user);
4079 assert_eq!(tb.pdu_queue_len(), 1);
4080 tb.check_finished_pdu_success();
4081 tb.acknowledge_finished_pdu(&mut user, &transfer_info);
4082 }
4083}