This plugin provides a microservice and corresponding API for handling the CCSDS File Delivery Protocol (CFDP).
This CFDP implementation is intended to be compliant with:
- CCSDS 727.0-B-5 - Blue Book July 2020
- CCSDS 727.0-B-4 - Blue Book January 2007
- CCSDS 727.0-B-3 - Blue Book June 2005
It is also potentially compliant with earlier versions but that has not been evaluated.
- Install this plugin in the Admin Tool
- During installation, edit plugin.txt to configure all of your MIB settings (See MIB Configuration Below)
In particular be sure to set the desired protocol_version_number for each remote entity. protocol_version_number 0 is used for all versions of the standard before the 2020 release. protocol_version_number 1 is used for the current release and potential future releases. This plugin defaults to using protocol_version_number 1.
See: cfdp.rb
require 'cfdp'
# Send a file and wait up to 10 minutes for complete (Default mode)
transaction_id, indication = cfdp_put(destination_entity_id: 1, source_file_name: "file_to_send.bin", destination_file_name: "received_file.bin")
# Force UNACKNOWLEDGED mode
transaction_id, indication = cfdp_put(destination_entity_id: 1, source_file_name: "file_to_send.bin", destination_file_name: "received_file.bin", transmission_mode: "UNACKNOWLEDGED")
# Force UNACKNOWLEDGED mode and request closure
transaction_id, indication = cfdp_put(destination_entity_id: 1, source_file_name: "file_to_send.bin", destination_file_name: "received_file.bin", transmission_mode: "UNACKNOWLEDGED", closure_requested: "CLOSURE_REQUESTED")
# Force ACKNOWLEDGED mode
transaction_id, indication = cfdp_put(destination_entity_id: 1, source_file_name: "file_to_send.bin", destination_file_name: "received_file.bin", transmission_mode: "ACKNOWLEDGED")
# Send a file and don't wait
continuation = cfdp_subscribe()
transaction_id = cfdp_put(destination_entity_id: 1, source_file_name: "file_to_send.bin", destination_file_name: "received_file.bin", timeout: nil)
...
DO_OTHER_THINGS
...
indication = cfdp_indications(transaction_id: transaction_id, indication_type: 'Transaction-Finished', continuation: continuation)
# Cancel a transaction
indication = cfdp_cancel(transaction_id: transaction_id)
# Suspend a transaction
indication = cfdp_suspend(transaction_id: transaction_id)
# Resume a suspended transaction
indication = cfdp_resume(transaction_id: transaction_id)
# Get a report on a transaction
indication = cfdp_report(transaction_id: transaction_id)
puts indication["status_report"]
# Get a list of transactions
transactions = cfdp_transactions(active: true)
# Filestore requests
requests = []
requests << ["CREATE_FILE", file_name]
requests << ["DELETE_FILE", file_name]
requests << ["RENAME_FILE", old_file_name, new_file_name]
requests << ["APPEND_FILE", file_name, appended_file_name]
requests << ["REPLACE_FILE", replaced_file_name, contents_file_name]
requests << ["CREATE_DIRECTORY", directory_name]
requests << ["REMOVE_DIRECTORY", directory_name]
requests << ["DENY_FILE", file_name]
requests << ["DENY_DIRECTORY", directory_name]
transaction_id, indication = cfdp_put(destination_entity_id: 1, filestore_requests: requests)
indication["filestore_responses"].each do |response|
puts "Filestore failed: #{response}" if response["STATUS_CODE"] != "SUCCESSFUL"
end
# Proxy operations
# These add remote_entity_id to specify a remote entity
# Get a file (using proxy put) and wait for it to be received
remote_entity_id = 1
my_entity_id = 2
transaction_id, indication = cfdp_put(remote_entity_id: remote_entity_id, destination_entity_id: my_entity_id, source_file_name: "file_to_send.bin", destination_file_name: "received_file.bin")
# Cancel a proxy put transaction
indication = cfdp_cancel(transaction_id: transaction_id, remote_entity_id: 1)
# Suspend a remote transaction
indication = cfdp_suspend(transaction_id: transaction_id, remote_entity_id: 1)
# Resume a remote transaction
indication = cfdp_resume(transaction_id: transaction_id, remote_entity_id: 1)
# Get a status report on a remote transaction
indication = cfdp_report(transaction_id: transaction_id, remote_entity_id: 1, report_file_name: "my_report.txt")
# Get a remote directory listing
indications = cfdp_directory_listing(remote_entity_id: 1, directory_name: "/files", directory_file_name: "my_listing.txt")
This is a conveninence method that allows you to easily send multiple files. This operation is not part of the CFDP specification, so it is implemented by initiating a separate PUT request for each file in the given directory. It is used the same way as cfdp_put(), but you must pass the path to a directory instead of a file (e.g. "/tmp" instead of "/tmp/foo.txt").
The CFDP Management Information Base (MIB) is configured by passing options to the CFDP microservice in plugin.txt. See the local plugin.txt, for example:
MICROSERVICE CFDP CFDP
...
# MIB Options Follow - Modify for your CFDP implementation!
OPTION root_path /DEFAULT/targets_modified/CFDP/tmp
OPTION bucket config
The MIB Options will always need to be configured for your CFDP implementation and mission. The plugin.txt is an example which includes a test implementation. This can be edited on installation in COSMOS (click the plugin.txt tab) but can also be edited and built locally.
Settings fall into three groups:
- Global Configuration - Engine-wide settings that have a single value for the whole CFDP microservice. They are not associated with any entity.
- Local (Source) Entity Configuration - Settings for this COSMOS engine's own entity, declared with
source_entity_id. They govern indications, fault handling, telemetry reception, and transaction retention. - Remote (Destination) Entity Configuration - Per-peer settings declared with
destination_entity_id. They govern the CFDP protocol behavior used to communicate with each remote entity, both when sending files to it and when receiving files from it.
Every per-entity setting is applied to the most recently declared source_entity_id or destination_entity_id. Internally, the same set of fields exists on every entity (the parser does not prevent a "remote" setting from being placed on the source entity or vice versa), so the groupings below reflect which entity the engine actually reads each setting from at runtime.
Minimum required settings:
- A source_entity_id and corresponding tlm_info must be given.
- At least one destination_entity_id must be defined with a corresponding cmd_info.
- root_path must be defined
- bucket should be set if the root_path is in a bucket. Otherwise the root path is assumed to be a mounted volume.
The default bucket config works with the bucket store bundled with COSMOS. When COSMOS is configured to use S3 directly, bucket must be set to the actual S3 bucket name (e.g. mycompany-cosmos-config). root_path is still given as an absolute path; the leading / is stripped when building S3 object keys, so /DEFAULT/targets_modified/CFDP/tmp is stored under DEFAULT/targets_modified/CFDP/tmp in the bucket.
OPTION root_path /DEFAULT/targets_modified/CFDP/tmp
OPTION bucket mycompany-cosmos-config
These settings are applied to the CFDP microservice via OPTION <name> <value> in the plugin.txt and apply to the entire engine, independent of any entity. They can be specified anywhere in the options list.
| Setting Name | Description | Allowed Values | Default Value |
|---|---|---|---|
| root_path | The path to send/receive files from (absolute path) | Valid directory | N/A - Must be given |
| bucket | The bucket to send/receive files from. Must be the actual S3 bucket name when using AWS S3 directly (see Using AWS S3) | Valid bucket Name | nil - Serve from mounted volume |
| prevent_received_file_overwrite | Appends a timestamp to the file name for received files if the file already exists | true or false | true |
| allow_duplicate_transaction_ids | Allows receiving transactions with an ID that was previously used by a completed transaction by deleting the old transaction. Does not affect metadata received for a transaction that is still running, which is never treated as a conflict. | true or false | false |
| transaction_cleanup_frequency_hours | How often to purge old (completed) transactions from RAM and Redis | Any integer | 24 |
Note:
plugin_test_modeis a plugin.txt buildVARIABLE(not a MIBOPTION). When set true it installs two dummy entities/targets that can send/receive transactions to each other for testing. It is consumed when the plugin is built, not by the CFDP microservice.
These settings are applied via OPTION <name> <value> after declaring the source_entity_id. They configure this COSMOS engine's own (local) entity. At runtime they are read from the local entity regardless of whether a transaction is being sent or received.
| Setting Name | Description | Allowed Values | Default Value |
|---|---|---|---|
| source_entity_id | The entity id for this CFDP microservice | Any integer | N/A - Must be given |
| tlm_info | A target_name, packet_name, and item_name to receive PDUs. Multiple tlm_info options can be given | COSMOS packet information | N/A - Must be given |
| eof_sent_indication | Issue EOF-Sent.indication | true or false | true |
| eof_recv_indication | Issue EOF-Recv.indication | true or false | true |
| file_segment_recv_indication | Issue File-Segment-Recv.indication | true or false | true |
| transaction_finished_indication | Issue Transaction-Finished.indication | true or false | true |
| suspended_indication | Issue Suspended.indication | true or false | true |
| resume_indication | Issue Resume.indication | true or false | true |
| crcs_required | When true, reject received PDUs without a CRC. A CRC that is present is always checked. | true or false | true |
| enable_eof_nak | Send a NAK in response to a received EOF. Only the local (receiving) entity's value is used. | true or false | false |
| transaction_closure_requested | Default closure requested setting used when this engine sends a file. Read from the local entity. | CLOSURE_REQUESTED or CLOSURE_NOT_REQUESTED | CLOSURE_REQUESTED |
| fault_handler | Fault handler setting. Only the local (source) entity's fault handlers are consulted. | (ACK_LIMIT_REACHED, KEEP_ALIVE_LIMIT_REACHED, INVALID_TRANSMISSION_MODE, FILESTORE_REJECTION, FILE_CHECKSUM_FAILURE, FILE_SIZE_ERROR, NAK_LIMIT_REACHED, INACTIVITY_DETECTED, INVALID_FILE_STRUCTURE, CHECK_LIMIT_REACHED, or UNSUPPORTED_CHECKSUM_TYPE) followed by (ISSUE_NOTICE_OF_CANCELLATION, ISSUE_NOTICE_OF_SUSPENSION, IGNORE_ERROR, or ABANDON_TRANSACTION) | See Code |
| transaction_retain_seconds | Time to keep completed transactions in seconds. Only the source entity's value is used. | Floating point value greater than 0 | 86400 |
These settings are applied via OPTION <name> <value> after declaring a destination_entity_id. They configure a remote peer (Bus or Payload Flight Software) and are read whenever this engine communicates with that peer - both when sending files to it and when receiving files from it.
| Setting Name | Description | Allowed Values | Default Value |
|---|---|---|---|
| destination_entity_id | Id of a remote entity to configure | Any integer | N/A - Must be given |
| cmd_info | The target_name, packet_name, and item_name to send PDUs for the destination entity | COSMOS packet information | N/A - Must be given |
| protocol_version_number | CFDP Version Number used for all PDUs sent to this entity | 0 or 1 | 1 - CFDP Blue Book Rev 5+ |
| crcs_required | Include a CRC on all PDUs sent to this entity | true or false | true |
| ack_timer_interval | Ack timeout in seconds | Any integer | 600 seconds |
| nak_timer_interval | Nak timeout in seconds | Any integer | 600 seconds |
| maximum_file_segment_length | Maximum amount of file data in a segment in bytes | Any integer | 1024 bytes |
| ack_timer_expiration_limit | Number of times to wait for the ack timeout before declaring a fault | Any integer | 1 |
| nak_timer_expiration_limit | Number of times to wait for the nak timeout before declaring a fault | Any integer | 1 |
| transaction_inactivity_limit | Number of times to wait for the keep alive timeout before declaring the transaction inactive fault | Any integer | 1 |
| check_limit | Number of times to check for transaction complete before declaring a fault | Any integer | 1 |
| keep_alive_discrepancy_limit | Maximum difference between keep alive progress and source progress allowed before declaring a fault. | Any integer | 1024000 bytes |
| enable_acks | Send Acks in Acknowledged mode | true or false | true |
| enable_keep_alive | Send Keep Alives in Acknowledged mode | true or false | true |
| enable_finished | Send Finished PDU if closure requested or acknowledged mode | true or false | true |
| default_transmission_mode | Default put mode | ACKNOWLEDGED or UNACKNOWLEDGED | UNACKNOWLEDGED |
| entity_id_length | Size of entity ids in bytes minus one, used for all PDUs sent to this entity | 0 to 7 | 0 = 1 byte |
| sequence_number_length | Size of sequence numbers in bytes minus one, used for all PDUs sent to this entity | 0 to 7 | 0 = 1 byte |
| default_checksum_type | Checksum type number | 0 to 15 | 0 = Default CFDP checksum |
| incomplete_file_disposition | What to do with an incomplete file | DISCARD or RETAIN | DISCARD |
| cmd_delay | Delay after sending each PDU in seconds. Defaults to no delay. | Floating point value greater than 0 | nil |
All PDUs sent to an entity, including the ACK, NAK, Keep Alive, and Finished PDUs sent back while receiving a file from it, use that entity's protocol_version_number, crcs_required, entity_id_length, and sequence_number_length. Received PDUs are decoded using the version, CRC flag, and lengths carried in each PDU header, so these settings do not need to match on the source entity. The one exception is crcs_required on the source entity, which rejects received PDUs that have no CRC (see Local (Source) Entity Configuration).
The following settings are read from the local (source) entity in one role and from a remote (destination) entity in the other, so for predictable behavior they should be configured consistently on both your source_entity_id and each destination_entity_id:
| Setting Name | Description | Allowed Values | Default Value | Read from local entity | Read from remote entity |
|---|---|---|---|---|---|
| check_interval | Interval to check for transaction complete in seconds | Any integer | 600 seconds | When sending (waiting for closure after EOF) | When receiving (check timer for completion) |
| keep_alive_interval | Keep Alive Period in seconds | Any integer | 600 seconds | When resuming a transaction (inactivity timeout) | When receiving (keep alive / inactivity timers) |
| immediate_nak_mode | Send NAKs as soon as something is noticed missing | true or false | true | When receiving, on EOF-triggered NAK decisions | When receiving, on file-data-triggered NAK decisions |
- Segmentation Control and Flow Label have no effect
- Suspension requests are not queued as specified in 6.5.4.1.2
- Annex B - Store and Forward Overlay Operations are not implemented
- Extended operations and classes 3 and 4 from the earlier CFDP standards are not implemented
We encourage you to contribute to OpenC3 COSMOS and this project!
Contributing is easy.
- Fork the project
- Create a feature branch
- Make your changes
- Submit a pull request
By contributing to this project, you agree to the following terms in our OpenC3 Builder License: LICENSE.md
OpenC3 Evaluation and Educational License
See LICENSE.md