Skip to content

Commit 88205ce

Browse files
committed
improve destination handler logic
1 parent 88975f7 commit 88205ce

File tree

4 files changed

+42
-39
lines changed

4 files changed

+42
-39
lines changed

src/cfdppy/exceptions.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from spacepackets.util import UnsignedByteField
88

99

10-
class NoRemoteEntityCfgFound(Exception):
10+
class NoRemoteEntityConfigFound(Exception):
1111
def __init__(self, entity_id: UnsignedByteField):
1212
super().__init__()
1313
self.remote_entity_id = entity_id
@@ -122,8 +122,10 @@ def __init__(self, packet: GenericPduPacket):
122122
class PduIgnoredForDestReason(enum.IntEnum):
123123
FIRST_PACKET_NOT_METADATA_PDU = 0
124124
"""First packet received was not a metadata PDU for the unacknowledged mode."""
125+
125126
INVALID_MODE_FOR_ACKED_MODE_PACKET = 1
126127
"""The received PDU can only be handled in acknowledged mode."""
128+
127129
FIRST_PACKET_IN_ACKED_MODE_NOT_METADATA_NOT_EOF_NOT_FD = 2
128130
"""For the acknowledged mode, the first packet that was received with
129131
no metadata received previously was not a File Data PDU or EOF PDU."""

src/cfdppy/handler/dest.py

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
InvalidDestinationId,
4141
InvalidPduDirection,
4242
InvalidPduForDestHandler,
43-
NoRemoteEntityCfgFound,
43+
NoRemoteEntityConfigFound,
4444
PduIgnoredForDest,
4545
PduIgnoredForDestReason,
4646
UnretrievedPdusToBeSent,
@@ -411,7 +411,7 @@ def state_machine(self, packet: GenericPduPacket | None = None) -> FsmResult:
411411
Raises
412412
--------
413413
414-
NoRemoteEntityCfgFound
414+
NoRemoteEntityConfigFound
415415
No remote configuration found for source entity ID extracted from the PDU packet.
416416
InvalidPduDirection
417417
PDU direction bit is invalid.
@@ -441,7 +441,7 @@ def _check_inserted_packet(self, packet: GenericPduPacket) -> None:
441441
if packet.dest_entity_id.value != self.cfg.local_entity_id.value:
442442
raise InvalidDestinationId(self.cfg.local_entity_id, packet.dest_entity_id)
443443
if self.remote_cfg_table.get_cfg(packet.source_entity_id) is None:
444-
raise NoRemoteEntityCfgFound(entity_id=packet.dest_entity_id)
444+
raise NoRemoteEntityConfigFound(entity_id=packet.dest_entity_id)
445445
if get_packet_destination(packet) == PacketDestination.SOURCE_HANDLER:
446446
raise InvalidPduForDestHandler(packet)
447447
if (self.states.state == CfdpState.IDLE) and (
@@ -514,12 +514,12 @@ def __idle_fsm(self, packet: GenericPduPacket | None) -> None:
514514
pdu_holder = PduHolder(packet)
515515
if pdu_holder.pdu_type == PduType.FILE_DATA:
516516
file_data_pdu = pdu_holder.to_file_data_pdu()
517-
self._start_transaction_missing_metadata_recv_fd(file_data_pdu)
517+
self._start_transaction_first_packet_file_data(file_data_pdu)
518518
else:
519519
assert pdu_holder.pdu_directive_type is not None
520520
if pdu_holder.pdu_directive_type == DirectiveType.EOF_PDU:
521521
eof_pdu = pdu_holder.to_eof_pdu()
522-
self._start_transaction_missing_metadata_recv_eof(eof_pdu)
522+
self._start_transaction_first_packet_eof(eof_pdu)
523523
elif pdu_holder.pdu_directive_type == DirectiveType.METADATA_PDU:
524524
metadata_pdu = pdu_holder.to_metadata_pdu()
525525
self._start_transaction(metadata_pdu)
@@ -584,43 +584,44 @@ def _handle_first_packet_not_metadata_pdu(self, packet: GenericPduPacket) -> Non
584584
packet,
585585
)
586586

587-
def _start_transaction_missing_metadata_recv_eof(self, eof_pdu: EofPdu) -> None:
587+
def _start_transaction_first_packet_eof(self, eof_pdu: EofPdu) -> None:
588588
self._common_first_packet_not_metadata_pdu_handler(eof_pdu)
589589
self._handle_eof_without_previous_metadata(eof_pdu)
590590

591+
# This function is only called in acknowledged mode.
591592
def _handle_eof_without_previous_metadata(self, eof_pdu: EofPdu) -> None:
592593
self._params.fp.progress = eof_pdu.file_size
593594
self._params.fp.file_size = eof_pdu.file_size
594595
self._params.acked_params.metadata_missing = True
595596
if self._params.fp.progress > 0:
596597
# Clear old list, deferred procedure for the whole file is now active.
597598
self._params.acked_params.lost_seg_tracker.reset()
598-
# I will just wait until the metadata has been received with re-requesting the file
599-
# data PDU. How does the standard expect me to process file data PDUs where I do not
600-
# even know the filenames? How would I even generically do this? I will add the whole
601-
# file to the lost segments map for now.
599+
# Add the whole file to the lost segments map for now.
602600
self._params.acked_params.lost_seg_tracker.add_lost_segment((0, eof_pdu.file_size))
603601
if self.cfg.indication_cfg.eof_recv_indication_required:
604602
assert self._params.transaction_id is not None
605603
self.user.eof_recv_indication(self._params.transaction_id)
604+
if eof_pdu.condition_code != ConditionCode.NO_ERROR:
605+
self._handle_cancel_eof(eof_pdu)
606606
self._prepare_eof_ack_packet()
607607
self._eof_ack_pdu_done()
608608

609609
def _eof_ack_pdu_done(self) -> None:
610+
if self._params.completion_disposition == CompletionDisposition.CANCELED:
611+
self.states.step = TransactionStep.TRANSFER_COMPLETION
612+
return
610613
if (
611614
self._params.acked_params.lost_seg_tracker.num_lost_segments > 0
612615
or self._params.acked_params.metadata_missing
613616
):
614617
self._start_deferred_lost_segment_handling()
618+
return
619+
self._checksum_verify()
620+
self.states.step = TransactionStep.TRANSFER_COMPLETION
615621

616-
else:
617-
if self._params.completion_disposition != CompletionDisposition.CANCELED:
618-
self._checksum_verify()
619-
self.states.step = TransactionStep.TRANSFER_COMPLETION
620-
621-
def _start_transaction_missing_metadata_recv_fd(self, fd_pdu: FileDataPdu) -> None:
622+
def _start_transaction_first_packet_file_data(self, fd_pdu: FileDataPdu) -> None:
622623
self._common_first_packet_not_metadata_pdu_handler(fd_pdu)
623-
self._handle_fd_without_previous_metadata(fd_pdu)
624+
self._handle_file_data_without_previous_metadata(fd_pdu)
624625

625626
def _handle_finished_pdu_sent(self) -> None:
626627
if (
@@ -632,13 +633,10 @@ def _handle_finished_pdu_sent(self) -> None:
632633
return
633634
self._reset_internal(False)
634635

635-
def _handle_fd_without_previous_metadata(self, fd_pdu: FileDataPdu) -> None:
636+
def _handle_file_data_without_previous_metadata(self, fd_pdu: FileDataPdu) -> None:
636637
self._params.fp.progress = fd_pdu.offset + len(fd_pdu.file_data)
637638
if len(fd_pdu.file_data) > 0:
638-
# I will just wait until the metadata has been received with re-requesting the file
639-
# data PDU. How does the standard expect me to process file data PDUs where I do not
640-
# even know the filenames? How would I even generically do this?
641-
# I will add this file segment (and all others which came before and might be missing
639+
# Add this file segment (and all others which came before and might be missing
642640
# as well) to the lost segment list.
643641
self._params.acked_params.lost_seg_tracker.add_lost_segment(
644642
(0, self._params.fp.progress)
@@ -703,7 +701,7 @@ def _handle_metadata_packet(self, metadata_pdu: MetadataPdu) -> None:
703701
_LOGGER.warning(
704702
f"No remote configuration found for remote ID {metadata_pdu.dest_entity_id}"
705703
)
706-
raise NoRemoteEntityCfgFound(metadata_pdu.dest_entity_id)
704+
raise NoRemoteEntityConfigFound(metadata_pdu.dest_entity_id)
707705
if not self._params.fp.metadata_only:
708706
self.states.step = TransactionStep.RECEIVING_FILE_DATA
709707
self._init_vfs_handling(Path(metadata_pdu.source_file_name).name) # type: ignore
@@ -756,7 +754,7 @@ def _handle_waiting_for_missing_metadata(self, packet_holder: PduHolder) -> None
756754
if packet_holder.pdu is None:
757755
return
758756
if packet_holder.pdu_type == PduType.FILE_DATA:
759-
self._handle_fd_without_previous_metadata(packet_holder.to_file_data_pdu())
757+
self._handle_file_data_without_previous_metadata(packet_holder.to_file_data_pdu())
760758
elif packet_holder.pdu_directive_type == DirectiveType.METADATA_PDU:
761759
self._handle_metadata_packet(packet_holder.to_metadata_pdu())
762760
if self._params.acked_params.deferred_lost_segment_detection_active:
@@ -974,18 +972,21 @@ def _handle_eof_pdu(self, eof_pdu: EofPdu) -> bool | None:
974972
if not regular_completion:
975973
return None
976974
else:
977-
# This is an EOF (Cancel), perform Cancel Response Procedures according to chapter
978-
# 4.6.6 of the standard. Set remote ID as fault location.
979-
self._trigger_notice_of_completion_canceled(
980-
eof_pdu.condition_code,
981-
EntityIdTlv(self._params.remote_cfg.entity_id.as_bytes),
982-
)
983-
# Store this as progress for the checksum calculation.
984-
self._params.fp.progress = self._params.fp.file_size
985-
self._params.finished_params.delivery_code = DeliveryCode.DATA_INCOMPLETE
975+
self._handle_cancel_eof(eof_pdu)
986976
self._file_transfer_complete_transition()
987977
return False
988978

979+
def _handle_cancel_eof(self, eof_pdu: EofPdu) -> None:
980+
# This is an EOF (Cancel), perform Cancel Response Procedures according to chapter
981+
# 4.6.6 of the standard. Set remote ID as fault location.
982+
self._trigger_notice_of_completion_canceled(
983+
eof_pdu.condition_code,
984+
EntityIdTlv(self._params.remote_cfg.entity_id.as_bytes),
985+
)
986+
# Store this as progress for the checksum calculation.
987+
self._params.fp.progress = self._params.fp.file_size
988+
self._params.finished_params.delivery_code = DeliveryCode.DATA_INCOMPLETE
989+
989990
def _handle_no_error_eof(self) -> bool:
990991
"""Returns whether the transfer can be completed regularly."""
991992
# CFDP 4.6.1.2.9: Declare file size error if progress exceeds file size

src/cfdppy/handler/source.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
InvalidPduForSourceHandler,
5151
InvalidSourceId,
5252
InvalidTransactionSeqNum,
53-
NoRemoteEntityCfgFound,
53+
NoRemoteEntityConfigFound,
5454
PduIgnoredForSource,
5555
PduIgnoredForSourceReason,
5656
SourceFileDoesNotExist,
@@ -345,7 +345,7 @@ def put_request(self, request: PutRequest) -> bool:
345345
assert isinstance(self._put_req.dest_file, Path)
346346
self._params.remote_cfg = self.remote_cfg_table.get_cfg(request.destination_id)
347347
if self._params.remote_cfg is None:
348-
raise NoRemoteEntityCfgFound(entity_id=request.destination_id)
348+
raise NoRemoteEntityConfigFound(entity_id=request.destination_id)
349349
self._params.dest_id = request.destination_id
350350
self.states._num_packets_ready = 0
351351
self.states.state = CfdpState.BUSY
@@ -391,7 +391,7 @@ def _check_inserted_packet(self, packet: AbstractFileDirectiveBase) -> None:
391391
# TODO: This can happen if a packet is received for which no transaction was started..
392392
# A better exception might be worth a thought..
393393
if self._params.remote_cfg is None:
394-
raise NoRemoteEntityCfgFound(entity_id=packet.dest_entity_id)
394+
raise NoRemoteEntityConfigFound(entity_id=packet.dest_entity_id)
395395
if packet.dest_entity_id.value != self._params.remote_cfg.entity_id.value:
396396
raise InvalidDestinationId(self._params.remote_cfg.entity_id, packet.dest_entity_id)
397397

tests/test_dest_handler_naked.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
RemoteEntityCfgTable,
2727
)
2828
from cfdppy.defs import CfdpState
29-
from cfdppy.exceptions import NoRemoteEntityCfgFound
29+
from cfdppy.exceptions import NoRemoteEntityConfigFound
3030
from cfdppy.handler.dest import (
3131
DestHandler,
3232
PduIgnoredForDest,
@@ -122,7 +122,7 @@ def test_remote_cfg_does_not_exist(self):
122122
)
123123
file_transfer_init = MetadataPdu(params=metadata_params, pdu_conf=self.src_pdu_conf)
124124
self._state_checker(None, False, CfdpState.IDLE, TransactionStep.IDLE)
125-
with self.assertRaises(NoRemoteEntityCfgFound):
125+
with self.assertRaises(NoRemoteEntityConfigFound):
126126
self.dest_handler.state_machine(file_transfer_init)
127127

128128
def test_check_timer_mechanism(self):

0 commit comments

Comments
 (0)