Skip to content

CfdpManager: fail a downlink whose source file shrinks while it is sent - #6364

Open
bitWarrior wants to merge 1 commit into
nasa:develfrom
bitWarrior:fix/cfdp-tx-short-read
Open

bitWarrior wants to merge 1 commit into
nasa:develfrom
bitWarrior:fix/cfdp-tx-short-read

Conversation

@bitWarrior

Copy link
Copy Markdown
Collaborator

Summary

If a file's size goes down while CfdpManager is downlinking it, the downlink never finishes. sSubstateSendFileData asks sSendFileData for the bytes between m_foffs and the file size captured when the transfer started. Once the source has been truncated below m_foffs, the read returns OP_OK with 0 bytes. The empty File Data PDU was still sent and reported as success with bytes_processed == 0, which falls into the empty else branch. m_foffs never advances and the transaction never reaches EOF. Every cycle sends max_outgoing_pdus_per_cycle empty File Data PDUs and blocks later downlinks on that channel. A Class 2 NAK retransmission over a truncated range stalls the same way, because the chunk is never removed from the list.

This can happen whenever anything onboard rewrites or truncates a file that is queued or being sent.

Changes

  • TransactionTx.cpp: sSendFileData treats a successful 0-byte read while bytes are still expected as a file error. It emits the new TxFileShortRead event and returns ERROR without sending a PDU. The existing error handling then ends the transfer:
    • File data path: TXN_STATUS_FILESTORE_REJECTION, then EOF.
    • NAK response path: TXN_STATUS_NAK_RESPONSE_ERROR.
  • Events.fppi / docs/sdd.md: new TxFileShortRead event (warning low) with the file, the offset, and the starting size.
  • Unit tests: Class1TxSourceTruncated and Class2TxSourceTruncated start a 200 KB downlink, truncate the source after the first cycle, and run 10 more cycles. Each expects exactly one TxFileShortRead, no completion event, and at most 4 PDUs sent after the truncation.
    • Class 1: TxFileTransferFailed.
    • Class 2: EOF sent with the failure status.

Testing

CfdpManager UTs: 219/219 pass. With the new check disabled, both new tests fail.

Notes

  • After EOF, a NAK retransmission in sTickNak that hits a truncated range now sends nothing. The transaction then ends through its ACK-limit or inactivity timer instead of sending empty PDUs. Failing it immediately there would mean finishing a transaction while its queue is being traversed, so that part is left as is.
  • If the source grows or is rewritten at the same length mid-transfer, the downlink still completes with mixed content. Receiving into a temporary file and staging the source are separate, larger changes.

🤖 Generated with Claude Code

sSubstateSendFileData asks sSendFileData for the bytes between m_foffs
and the file size captured when the transfer started. If the source has
been truncated below m_foffs, the read returns OP_OK with 0 bytes. The
empty File Data PDU was still sent and reported as success with
bytes_processed == 0, which fell into the empty else branch: m_foffs
never advanced, the downlink never reached EOF, and every cycle sent
max_outgoing_pdus_per_cycle empty File Data PDUs and blocked later
downlinks on that channel. A Class 2 NAK retransmission over a
truncated range stalled the same way, since the chunk was never
removed.

sSendFileData now treats a successful 0-byte read with bytes still
expected as a file error: it emits the new TxFileShortRead event and
returns ERROR without sending a PDU. The file data path then fails the
transfer with TXN_STATUS_FILESTORE_REJECTION and sends EOF, and the NAK
response path fails it with TXN_STATUS_NAK_RESPONSE_ERROR, as for other
read errors.

Add Class 1 and Class 2 unit tests that truncate the source mid-downlink.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

Coverage report — base devel

Overall (line): 85.93% → 85.94% (+0.01)
Regression threshold: 0.50% (line).

Regressions

(none over threshold)

Modules changed

Module Line Δ Function Δ Branch Δ
Os/Generic/Types 91.79 -0.35 92.86 +0.00 73.83 +0.00
Os/Posix 71.03 -0.25 87.50 +0.00 50.89 -0.45
Os/Generic 90.18 -0.10 89.13 +0.00 75.48 -0.19
Svc/Ccsds/CfdpManager 90.87 +0.07 96.89 +0.00 78.28 +0.18
Fw/DataStructures 97.96 +0.27 97.14 +0.00 82.66 +0.36

New modules

Module Line Function Branch
Fw/Prm 0.00 0.00 0.00

Modules without UTs

CFDP/Checksum/GTest, Drv/LinuxGpioDriver, Drv/LinuxI2cDriver, Drv/LinuxSpiDriver, Drv/Ports/DataTypes, Drv/PosixUartDriver, FppTestProject/FppTest/topology/async, FppTestProject/FppTest/topology/components/Comp, FppTestProject/FppTest/topology/components/Framework, FppTestProject/FppTest/topology/components/Receiver, FppTestProject/FppTest/topology/components/Sender, FppTestProject/FppTest/topology/guarded, FppTestProject/FppTest/topology/sync, FppTestProject/FppTest/topology/top_ports, FppTestProject/FppTest/topology/types, Fw/Com, Fw/Comp, Fw/FilePacket/GTest, Fw/Fpy, Fw/Obj, Fw/Port, Fw/Sm, Fw/Test, Fw/Types/GTest, Os/Models, Svc/Ccsds/Types, Svc/Ccsds/Utils, Svc/FatalHandler, Svc/Subtopologies/CdhCore, Svc/Subtopologies/ComCcsds, Svc/Subtopologies/ComCcsdsSdls, Svc/Subtopologies/ComFprime, Svc/Subtopologies/ComLoggerTee, Svc/Subtopologies/DataProducts, Svc/Subtopologies/DpCompression, Svc/Subtopologies/FileHandling, Svc/Subtopologies/FileHandlingCfdp, Svc/Subtopologies/FileHandlingCfdp/FileHandlingCfdpConfig, TestDeploymentsProject/Ref/DpDemo, TestDeploymentsProject/Ref/PingReceiver, TestDeploymentsProject/Ref/RecvBuffApp, TestDeploymentsProject/Ref/SendBuffApp, TestDeploymentsProject/Ref/Top, TestDeploymentsProject/Ref/TypeDemo, cmake/test/data/TestConfigDeployment, cmake/test/data/TestDeployment/TestBuildAutocoder, cmake/test/data/TestDeployment/TestDuplicateDirective, cmake/test/data/TestDeployment/TestHeaderAutocoder, cmake/test/data/TestDeployment/TestLinkDepends, cmake/test/data/TestDeployment/TestRelative, cmake/test/data/test-fprime-library/TestLibrary/TestComponent, cmake/test/data/test-fprime-library2/TestLibrary2/TestComponent

@bitWarrior

Copy link
Copy Markdown
Collaborator Author

The one failing check here, Integration Tests (teensy41), is not caused by this change. The same job also fails on devel's scheduled run today (run 42523390404), and #6363 fails it too.

  • Same failure: every failing run breaks the same way. The board flashes, then wait_for_boot raises TimeoutError: Timed out waiting for i/o to finish and the process exits with -9.
  • Last pass: the scheduled devel run on Nov 7 passed.
  • pico2: passes in all of these runs.

It looks like a problem with the teensy41 board or runner (details in #6363 (comment)).

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant