openc3-cosmos-cfdp 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +18 -0
- data/README.md +181 -0
- data/Rakefile +40 -0
- data/lib/cfdp.rb +283 -0
- data/lib/cfdp_api.rb +204 -0
- data/microservices/CFDP/Gemfile +37 -0
- data/microservices/CFDP/Rakefile +6 -0
- data/microservices/CFDP/app/controllers/application_controller.rb +46 -0
- data/microservices/CFDP/app/controllers/cfdp_controller.rb +222 -0
- data/microservices/CFDP/app/models/cfdp_checksum.rb +52 -0
- data/microservices/CFDP/app/models/cfdp_crc_checksum.rb +41 -0
- data/microservices/CFDP/app/models/cfdp_mib.rb +613 -0
- data/microservices/CFDP/app/models/cfdp_model.rb +25 -0
- data/microservices/CFDP/app/models/cfdp_null_checksum.rb +29 -0
- data/microservices/CFDP/app/models/cfdp_pdu.rb +202 -0
- data/microservices/CFDP/app/models/cfdp_receive_transaction.rb +590 -0
- data/microservices/CFDP/app/models/cfdp_source_transaction.rb +449 -0
- data/microservices/CFDP/app/models/cfdp_topic.rb +58 -0
- data/microservices/CFDP/app/models/cfdp_transaction.rb +188 -0
- data/microservices/CFDP/app/models/cfdp_user.rb +601 -0
- data/microservices/CFDP/bin/rails +4 -0
- data/microservices/CFDP/bin/rake +4 -0
- data/microservices/CFDP/bin/setup +25 -0
- data/microservices/CFDP/config/application.rb +55 -0
- data/microservices/CFDP/config/boot.rb +4 -0
- data/microservices/CFDP/config/credentials.yml.enc +1 -0
- data/microservices/CFDP/config/environment.rb +5 -0
- data/microservices/CFDP/config/environments/development.rb +53 -0
- data/microservices/CFDP/config/environments/production.rb +75 -0
- data/microservices/CFDP/config/environments/test.rb +50 -0
- data/microservices/CFDP/config/initializers/application_controller_renderer.rb +8 -0
- data/microservices/CFDP/config/initializers/backtrace_silencers.rb +7 -0
- data/microservices/CFDP/config/initializers/cfdp_initializer.rb +26 -0
- data/microservices/CFDP/config/initializers/cors.rb +16 -0
- data/microservices/CFDP/config/initializers/filter_parameter_logging.rb +8 -0
- data/microservices/CFDP/config/initializers/inflections.rb +16 -0
- data/microservices/CFDP/config/initializers/mime_types.rb +4 -0
- data/microservices/CFDP/config/initializers/wrap_parameters.rb +9 -0
- data/microservices/CFDP/config/locales/en.yml +29 -0
- data/microservices/CFDP/config/puma.rb +38 -0
- data/microservices/CFDP/config/routes.rb +16 -0
- data/microservices/CFDP/config.ru +5 -0
- data/microservices/CFDP/init.sh +9 -0
- data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_ack.rb +82 -0
- data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_enum.rb +237 -0
- data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_eof.rb +87 -0
- data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_file_data.rb +98 -0
- data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_finished.rb +114 -0
- data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_keep_alive.rb +65 -0
- data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_metadata.rb +116 -0
- data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_nak.rb +91 -0
- data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_prompt.rb +60 -0
- data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_tlv.rb +291 -0
- data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_user_ops.rb +749 -0
- data/microservices/CFDP/public/robots.txt +1 -0
- data/microservices/CFDP/spec/models/cfdp_pdu_ack_spec.rb +114 -0
- data/microservices/CFDP/spec/models/cfdp_pdu_eof_spec.rb +159 -0
- data/microservices/CFDP/spec/models/cfdp_pdu_file_data_spec.rb +76 -0
- data/microservices/CFDP/spec/models/cfdp_pdu_finished_spec.rb +192 -0
- data/microservices/CFDP/spec/models/cfdp_pdu_keep_alive_spec.rb +69 -0
- data/microservices/CFDP/spec/models/cfdp_pdu_metadata_spec.rb +346 -0
- data/microservices/CFDP/spec/models/cfdp_pdu_nak_spec.rb +126 -0
- data/microservices/CFDP/spec/models/cfdp_pdu_prompt_spec.rb +94 -0
- data/microservices/CFDP/spec/models/cfdp_pdu_spec.rb +111 -0
- data/microservices/CFDP/spec/rails_helper.rb +71 -0
- data/microservices/CFDP/spec/requests/cfdp_spec.rb +1965 -0
- data/microservices/CFDP/spec/spec_helper.rb +200 -0
- data/plugin.txt +67 -0
- data/targets/CFDPTEST/cmd_tlm/cmd.txt +5 -0
- data/targets/CFDPTEST/cmd_tlm/tlm.txt +4 -0
- data/targets/CFDPTEST/procedures/cfdp_test_suite.rb +130 -0
- data/targets/CFDPTEST/target.txt +4 -0
- metadata +118 -0
data/lib/cfdp_api.rb
ADDED
@@ -0,0 +1,204 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# Copyright 2023 OpenC3, Inc.
|
4
|
+
# All Rights Reserved.
|
5
|
+
#
|
6
|
+
# Licensed for Evaluation and Educational Use
|
7
|
+
#
|
8
|
+
# This file may only be used commercially under the terms of a commercial license
|
9
|
+
# purchased from OpenC3, Inc.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
14
|
+
#
|
15
|
+
# The development of this software was funded in-whole or in-part by MethaneSAT LLC.
|
16
|
+
|
17
|
+
require 'openc3/utilities/authentication'
|
18
|
+
require 'openc3/io/json_api'
|
19
|
+
|
20
|
+
# Usage:
|
21
|
+
#
|
22
|
+
# Note: Recommend using the methods in cfdp.rb rather than this file directly
|
23
|
+
#
|
24
|
+
# In ScriptRunner:
|
25
|
+
# require 'cfdp_api'
|
26
|
+
# api = CfdpApi.new
|
27
|
+
# api.put(...)
|
28
|
+
#
|
29
|
+
# Outside cluster - Open Source:
|
30
|
+
# require 'cfdp_api'
|
31
|
+
# $openc3_scope = 'DEFAULT'
|
32
|
+
# ENV['OPENC3_API_PASSWORD'] = 'password'
|
33
|
+
# api = CfdpApi.new(hostname: '127.0.0.1', port: 2900)
|
34
|
+
# api.put(...)
|
35
|
+
#
|
36
|
+
# Outside cluster - Enterprise
|
37
|
+
# require 'cfdp_api'
|
38
|
+
# $openc3_scope = 'DEFAULT'
|
39
|
+
# ENV['OPENC3_KEYCLOAK_URL'] = '127.0.0.1:2900'
|
40
|
+
# ENV['OPENC3_API_USER'] = 'operator'
|
41
|
+
# ENV['OPENC3_API_PASSWORD'] = 'operator'
|
42
|
+
# api = CfdpApi.new(hostname: '127.0.0.1', port: 2900)
|
43
|
+
# api.put(...)
|
44
|
+
#
|
45
|
+
class CfdpApi < OpenC3::JsonApi
|
46
|
+
def put(
|
47
|
+
destination_entity_id:,
|
48
|
+
source_file_name:,
|
49
|
+
destination_file_name:,
|
50
|
+
transmission_mode: nil,
|
51
|
+
closure_requested: nil,
|
52
|
+
filestore_requests: [],
|
53
|
+
fault_handler_overrides: [],
|
54
|
+
flow_label: nil,
|
55
|
+
segmentation_control: "NOT_PRESERVED",
|
56
|
+
messages_to_user: [],
|
57
|
+
remote_entity_id: nil, # Used to indicate proxy put
|
58
|
+
scope: $openc3_scope)
|
59
|
+
|
60
|
+
begin
|
61
|
+
endpoint = "/put"
|
62
|
+
data = {
|
63
|
+
"destination_entity_id" => destination_entity_id.to_i,
|
64
|
+
"source_file_name" => source_file_name,
|
65
|
+
"destination_file_name" => destination_file_name,
|
66
|
+
"transmission_mode" => transmission_mode,
|
67
|
+
"closure_requested" => closure_requested,
|
68
|
+
"filestore_requests" => filestore_requests,
|
69
|
+
"fault_handler_overrides" => fault_handler_overrides,
|
70
|
+
"messages_to_user" => messages_to_user,
|
71
|
+
"flow_label" => flow_label,
|
72
|
+
"segmentation_control" => segmentation_control
|
73
|
+
}
|
74
|
+
data["remote_entity_id"] = remote_entity_id.to_i if remote_entity_id
|
75
|
+
response = _request('post', endpoint, data: data, scope: scope)
|
76
|
+
if response.nil? || response.code != 200
|
77
|
+
if response
|
78
|
+
raise "CFDP put error: #{response.code}: #{response.body}"
|
79
|
+
else
|
80
|
+
raise "CFDP put failed"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
return response.body
|
84
|
+
rescue => error
|
85
|
+
raise "CFDP put failed due to #{error.formatted}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def cancel(transaction_id:, remote_entity_id: nil, scope: $openc3_scope)
|
90
|
+
transaction_id_post(method_name: "cancel", transaction_id: transaction_id, remote_entity_id: remote_entity_id, scope: $openc3_scope)
|
91
|
+
end
|
92
|
+
|
93
|
+
def suspend(transaction_id:, remote_entity_id: nil, scope: $openc3_scope)
|
94
|
+
transaction_id_post(method_name: "suspend", transaction_id: transaction_id, remote_entity_id: remote_entity_id, scope: $openc3_scope)
|
95
|
+
end
|
96
|
+
|
97
|
+
def resume(transaction_id:, remote_entity_id: nil, scope: $openc3_scope)
|
98
|
+
transaction_id_post(method_name: "resume", transaction_id: transaction_id, remote_entity_id: remote_entity_id, scope: $openc3_scope)
|
99
|
+
end
|
100
|
+
|
101
|
+
def report(transaction_id:, remote_entity_id: nil, report_file_name: nil, scope: $openc3_scope)
|
102
|
+
transaction_id_post(method_name: "report", transaction_id: transaction_id, remote_entity_id: remote_entity_id, report_file_name: report_file_name, scope: $openc3_scope)
|
103
|
+
end
|
104
|
+
|
105
|
+
def subscribe(scope: $openc3_scope)
|
106
|
+
begin
|
107
|
+
endpoint = "/subscribe"
|
108
|
+
response = _request('get', endpoint, scope: scope)
|
109
|
+
if response.nil? || response.code != 200
|
110
|
+
if response
|
111
|
+
raise "CFDP subscribe error: #{response.code}: #{response.body}"
|
112
|
+
else
|
113
|
+
raise "CFDP subscribe failed"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
# Most recent topic id
|
117
|
+
return response.body
|
118
|
+
rescue => error
|
119
|
+
raise "CFDP subscribe failed due to #{error.formatted}"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def indications(transaction_id: nil, continuation: nil, limit: 100, scope: $openc3_scope)
|
124
|
+
begin
|
125
|
+
endpoint = "/indications"
|
126
|
+
endpoint << ('/' + transaction_id.to_s) if transaction_id
|
127
|
+
query = {}
|
128
|
+
query[:continuation] = continuation if continuation
|
129
|
+
query[:limit] = limit if limit
|
130
|
+
response = _request('get', endpoint, query: query, scope: scope)
|
131
|
+
if response.nil? || response.code != 200
|
132
|
+
if response
|
133
|
+
raise "CFDP indications error: #{response.code}: #{response.body}"
|
134
|
+
else
|
135
|
+
raise "CFDP indications failed"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
# Hash of continuation, and indications array
|
139
|
+
return JSON.parse(response.body)
|
140
|
+
rescue => error
|
141
|
+
raise "CFDP indications failed due to #{error.formatted}"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def directory_listing(remote_entity_id:, directory_name:, directory_file_name:, scope: $openc3_scope)
|
146
|
+
begin
|
147
|
+
endpoint = "/directorylisting"
|
148
|
+
data = { "remote_entity_id" => remote_entity_id, "directory_name" => directory_name, "directory_file_name" => directory_file_name }
|
149
|
+
response = _request('post', endpoint, data: data, scope: scope)
|
150
|
+
if response.nil? || response.code != 200
|
151
|
+
if response
|
152
|
+
raise "CFDP directory listing error: #{response.code}: #{response.body}"
|
153
|
+
else
|
154
|
+
raise "CFDP directory listing failed"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
return response.body
|
158
|
+
rescue => error
|
159
|
+
raise "CFDP directory listing failed due to #{error.formatted}"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def transactions(active: true, scope: $openc3_scope)
|
164
|
+
begin
|
165
|
+
endpoint = "/transactions"
|
166
|
+
query = {}
|
167
|
+
query[:active] = active if active
|
168
|
+
response = _request('get', endpoint, query: query, scope: scope)
|
169
|
+
if response.nil? || response.code != 200
|
170
|
+
if response
|
171
|
+
raise "CFDP transactions error: #{response.code}: #{response.body}"
|
172
|
+
else
|
173
|
+
raise "CFDP transactions failed"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
# Array of Transaction Hashes
|
177
|
+
return JSON.parse(response.body)
|
178
|
+
rescue => error
|
179
|
+
raise "CFDP transactions failed due to #{error.formatted}"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# private
|
184
|
+
|
185
|
+
def transaction_id_post(method_name:, transaction_id:, remote_entity_id: nil, report_file_name: nil, scope: $openc3_scope)
|
186
|
+
begin
|
187
|
+
endpoint = "/#{method_name}"
|
188
|
+
data = { "transaction_id" => transaction_id.to_s }
|
189
|
+
data['remote_entity_id'] = remote_entity_id if remote_entity_id
|
190
|
+
data['report_file_name'] = report_file_name if report_file_name
|
191
|
+
response = _request('post', endpoint, data: data, scope: scope)
|
192
|
+
if response.nil? || response.code != 200
|
193
|
+
if response
|
194
|
+
raise "CFDP #{method_name} error: #{response.code}: #{response.body}"
|
195
|
+
else
|
196
|
+
raise "CFDP #{method_name} failed"
|
197
|
+
end
|
198
|
+
end
|
199
|
+
return response.body
|
200
|
+
rescue => error
|
201
|
+
raise "CFDP #{method_name} failed due to #{error.formatted}"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
source ENV['RUBYGEMS_URL'] || "https://rubygems.org"
|
2
|
+
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
3
|
+
|
4
|
+
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
|
5
|
+
gem 'rails', '>= 7.0.0'
|
6
|
+
|
7
|
+
# Reduces boot times through caching; required in config/boot.rb
|
8
|
+
gem 'bootsnap', '>= 1.9.3', require: false
|
9
|
+
|
10
|
+
# Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible
|
11
|
+
gem 'rack-cors', '>= 1.1'
|
12
|
+
|
13
|
+
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
|
14
|
+
gem 'tzinfo-data'
|
15
|
+
|
16
|
+
# Run against this stable release
|
17
|
+
group :development, :test do
|
18
|
+
gem 'rspec-rails', '~> 6.0'
|
19
|
+
gem 'simplecov', '~> 0.20'
|
20
|
+
gem 'simplecov-cobertura', '~> 2.1'
|
21
|
+
end
|
22
|
+
|
23
|
+
group :test do
|
24
|
+
gem 'mock_redis'
|
25
|
+
end
|
26
|
+
|
27
|
+
if ENV['OPENC3_DEVEL']
|
28
|
+
gem 'openc3', :path => ENV['OPENC3_DEVEL']
|
29
|
+
elsif ENV['OPENC3_PATH']
|
30
|
+
gem 'openc3', :path => ENV['OPENC3_PATH']
|
31
|
+
else
|
32
|
+
gem 'openc3', '>= 5.4.2.pre'
|
33
|
+
end
|
34
|
+
|
35
|
+
if ENV['OPENC3_ENTERPRISE_TAG']
|
36
|
+
gem 'openc3-enterprise', '>= 5.4.2.pre'
|
37
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# Copyright 2023 OpenC3, Inc.
|
4
|
+
# All Rights Reserved.
|
5
|
+
#
|
6
|
+
# Licensed for Evaluation and Educational Use
|
7
|
+
#
|
8
|
+
# This file may only be used commercially under the terms of a commercial license
|
9
|
+
# purchased from OpenC3, Inc.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
14
|
+
#
|
15
|
+
# The development of this software was funded in-whole or in-part by MethaneSAT LLC.
|
16
|
+
|
17
|
+
require 'openc3/utilities/authorization'
|
18
|
+
|
19
|
+
class ApplicationController < ActionController::API
|
20
|
+
include OpenC3::Authorization
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# Authorize and rescue the possible execeptions
|
25
|
+
# @return [Boolean] true if authorize successful
|
26
|
+
def authorization(permission, target_name: nil, packet_name: nil, interface_name: nil, router_name: nil)
|
27
|
+
begin
|
28
|
+
authorize(
|
29
|
+
permission: permission,
|
30
|
+
target_name: target_name,
|
31
|
+
packet_name: packet_name,
|
32
|
+
interface_name: interface_name,
|
33
|
+
router_name: router_name,
|
34
|
+
scope: params[:scope],
|
35
|
+
token: request.headers['HTTP_AUTHORIZATION'],
|
36
|
+
)
|
37
|
+
rescue OpenC3::AuthError => e
|
38
|
+
render(json: { status: 'error', message: e.message }, status: 401) and
|
39
|
+
return false
|
40
|
+
rescue OpenC3::ForbiddenError => e
|
41
|
+
render(json: { status: 'error', message: e.message }, status: 403) and
|
42
|
+
return false
|
43
|
+
end
|
44
|
+
true
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,222 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# Copyright 2023 OpenC3, Inc.
|
4
|
+
# All Rights Reserved.
|
5
|
+
#
|
6
|
+
# Licensed for Evaluation and Educational Use
|
7
|
+
#
|
8
|
+
# This file may only be used commercially under the terms of a commercial license
|
9
|
+
# purchased from OpenC3, Inc.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
14
|
+
#
|
15
|
+
# The development of this software was funded in-whole or in-part by MethaneSAT LLC.
|
16
|
+
|
17
|
+
require 'openc3/config/config_parser'
|
18
|
+
|
19
|
+
class CfdpController < ApplicationController
|
20
|
+
# Put.request (destination CFDP entity ID,
|
21
|
+
# [source file name],
|
22
|
+
# [destination file name],
|
23
|
+
# [segmentation control], # Not supported
|
24
|
+
# [fault handler overrides],
|
25
|
+
# [flow label], # Not supported
|
26
|
+
# [transmission mode],
|
27
|
+
# [closure requested],
|
28
|
+
# [messages to user],
|
29
|
+
# [filestore requests])
|
30
|
+
def put
|
31
|
+
params.require([:destination_entity_id])
|
32
|
+
return unless check_authorization()
|
33
|
+
transaction = $cfdp_user.start_source_transaction(params)
|
34
|
+
render json: transaction.id
|
35
|
+
rescue ActionController::ParameterMissing => error
|
36
|
+
render :json => { :status => 'error', :message => error.message }, :status => 400
|
37
|
+
rescue => error
|
38
|
+
render :json => { :status => 'error', :message => error.message }, :status => 500
|
39
|
+
end
|
40
|
+
|
41
|
+
# Cancel.request (transaction ID)
|
42
|
+
def cancel
|
43
|
+
params.require([:transaction_id])
|
44
|
+
return unless check_authorization()
|
45
|
+
transaction = $cfdp_user.cancel(params)
|
46
|
+
if transaction
|
47
|
+
render json: transaction.id
|
48
|
+
else
|
49
|
+
render :json => { :status => 'error', :message => "Transaction #{params[:transaction_id]} not found" }, :status => 404
|
50
|
+
end
|
51
|
+
rescue => error
|
52
|
+
render :json => { :status => 'error', :message => error.message }, :status => 500
|
53
|
+
end
|
54
|
+
|
55
|
+
# Suspend.request (transaction ID)
|
56
|
+
def suspend
|
57
|
+
params.require([:transaction_id])
|
58
|
+
return unless check_authorization()
|
59
|
+
transaction = $cfdp_user.suspend(params)
|
60
|
+
if transaction
|
61
|
+
render json: transaction.id
|
62
|
+
else
|
63
|
+
render :json => { :status => 'error', :message => "Transaction #{params[:transaction_id]} not found" }, :status => 404
|
64
|
+
end
|
65
|
+
rescue => error
|
66
|
+
render :json => { :status => 'error', :message => error.message }, :status => 500
|
67
|
+
end
|
68
|
+
|
69
|
+
# Resume.request (transaction ID)
|
70
|
+
def resume
|
71
|
+
params.require([:transaction_id])
|
72
|
+
return unless check_authorization()
|
73
|
+
transaction = $cfdp_user.resume(params)
|
74
|
+
if transaction
|
75
|
+
render json: transaction.id
|
76
|
+
else
|
77
|
+
render :json => { :status => 'error', :message => "Transaction #{params[:transaction_id]} not found" }, :status => 404
|
78
|
+
end
|
79
|
+
rescue => error
|
80
|
+
render :json => { :status => 'error', :message => error.message }, :status => 500
|
81
|
+
end
|
82
|
+
|
83
|
+
# Report.request (transaction ID)
|
84
|
+
def report
|
85
|
+
params.require([:transaction_id])
|
86
|
+
return unless check_authorization()
|
87
|
+
transaction = $cfdp_user.report(params)
|
88
|
+
if transaction
|
89
|
+
render json: transaction.id
|
90
|
+
else
|
91
|
+
render :json => { :status => 'error', :message => "Transaction #{params[:transaction_id]} not found" }, :status => 404
|
92
|
+
end
|
93
|
+
rescue => error
|
94
|
+
render :json => { :status => 'error', :message => error.message }, :status => 500
|
95
|
+
end
|
96
|
+
|
97
|
+
def directory_listing
|
98
|
+
params.require([:remote_entity_id, :directory_name, :directory_file_name])
|
99
|
+
return unless check_authorization()
|
100
|
+
transaction = $cfdp_user.start_directory_listing(params)
|
101
|
+
render json: transaction.id
|
102
|
+
rescue ActionController::ParameterMissing => error
|
103
|
+
render :json => { :status => 'error', :message => error.message }, :status => 400
|
104
|
+
rescue => error
|
105
|
+
render :json => { :status => 'error', :message => error.message }, :status => 500
|
106
|
+
end
|
107
|
+
|
108
|
+
def subscribe
|
109
|
+
return unless check_authorization()
|
110
|
+
result = CfdpTopic.subscribe_indications
|
111
|
+
render json: result
|
112
|
+
rescue => error
|
113
|
+
render :json => { :status => 'error', :message => error.message }, :status => 500
|
114
|
+
end
|
115
|
+
|
116
|
+
# Transaction.indication (transaction ID)
|
117
|
+
# EOF-Sent.indication (transaction ID)
|
118
|
+
# Transaction-Finished.indication (transaction ID,
|
119
|
+
# [filestore responses],
|
120
|
+
# [status report],
|
121
|
+
# condition code,
|
122
|
+
# file status,
|
123
|
+
# delivery code)
|
124
|
+
# Metadata-Recv.indication (transaction ID,
|
125
|
+
# source CFDP entity ID,
|
126
|
+
# [file size],
|
127
|
+
# [source file name],
|
128
|
+
# [destination file name],
|
129
|
+
# [messages to user])
|
130
|
+
# File-Segment-Recv.indication (transaction ID,
|
131
|
+
# offset,
|
132
|
+
# length,
|
133
|
+
# [record continuation state,
|
134
|
+
# length of segment metadata,
|
135
|
+
# segment metadata])
|
136
|
+
# Suspended.indication (transaction ID,
|
137
|
+
# condition code)
|
138
|
+
# Resumed.indication (transaction ID,
|
139
|
+
# progress)
|
140
|
+
# Report.indication (transaction ID,
|
141
|
+
# status report)
|
142
|
+
# Fault.indication (transaction ID,
|
143
|
+
# condition code,
|
144
|
+
# progress)
|
145
|
+
# Abandoned.indication (transaction ID,
|
146
|
+
# condition code,
|
147
|
+
# progress)
|
148
|
+
# EOF-Recv.indication (transaction ID)
|
149
|
+
def indications
|
150
|
+
return unless check_authorization()
|
151
|
+
result = CfdpTopic.read_indications(transaction_id: params[:transaction_id], continuation: params[:continuation], limit: params[:limit])
|
152
|
+
render json: result
|
153
|
+
rescue => error
|
154
|
+
render :json => { :status => 'error', :message => error.message }, :status => 500
|
155
|
+
end
|
156
|
+
|
157
|
+
def transactions
|
158
|
+
return unless check_authorization()
|
159
|
+
active = false
|
160
|
+
active = true if OpenC3::ConfigParser.handle_true_false_nil(params[:active])
|
161
|
+
result = []
|
162
|
+
transactions = CfdpMib.transactions.dup
|
163
|
+
transactions.each do |t_id, t|
|
164
|
+
if not active or t.transaction_status == "ACTIVE"
|
165
|
+
result << t
|
166
|
+
end
|
167
|
+
end
|
168
|
+
result = result.sort {|a, b| a.id <=> b.id}
|
169
|
+
render json: result
|
170
|
+
rescue => error
|
171
|
+
render :json => { :status => 'error', :message => error.message }, :status => 500
|
172
|
+
end
|
173
|
+
|
174
|
+
# private
|
175
|
+
|
176
|
+
def check_authorization
|
177
|
+
cmd_entity_id = nil
|
178
|
+
cmd_entity = nil
|
179
|
+
|
180
|
+
if params[:remote_entity_id]
|
181
|
+
if params[:remote_entity_id].to_i.to_s != params[:remote_entity_id].to_s
|
182
|
+
render :json => { :status => 'error', :message => "remote_entity_id must be numeric" }, :status => 400
|
183
|
+
return false
|
184
|
+
end
|
185
|
+
cmd_entity_id = Integer(params[:remote_entity_id])
|
186
|
+
cmd_entity = CfdpMib.entity(cmd_entity_id)
|
187
|
+
elsif params[:destination_entity_id]
|
188
|
+
if params[:destination_entity_id].to_i.to_s != params[:destination_entity_id].to_s
|
189
|
+
render :json => { :status => 'error', :message => "destination_entity_id must be numeric" }, :status => 400
|
190
|
+
return
|
191
|
+
end
|
192
|
+
cmd_entity_id = Integer(params[:destination_entity_id])
|
193
|
+
cmd_entity = CfdpMib.entity(cmd_entity_id)
|
194
|
+
else
|
195
|
+
cmd_entity_id = CfdpMib.source_entity_id
|
196
|
+
cmd_entity = CfdpMib.entity(cmd_entity_id)
|
197
|
+
end
|
198
|
+
|
199
|
+
if cmd_entity
|
200
|
+
target_name, packet_name, item_name = cmd_entity["cmd_info"]
|
201
|
+
unless target_name and packet_name and item_name
|
202
|
+
tlm_packets = cmd_entity["tlm_info"]
|
203
|
+
tlm_packets ||= []
|
204
|
+
target_name, packet_name, item_name = tlm_packets[0]
|
205
|
+
end
|
206
|
+
if target_name and packet_name and item_name
|
207
|
+
# Caller must be able to send this command
|
208
|
+
return false unless authorization('cmd', target_name: target_name, packet_name: packet_name)
|
209
|
+
else
|
210
|
+
render :json => { :status => 'error', :message => "info not configured for entity: #{cmd_entity_id}" }, :status => 400
|
211
|
+
return false
|
212
|
+
end
|
213
|
+
else
|
214
|
+
render :json => { :status => 'error', :message => "Unknown entity: #{cmd_entity_id}" }, :status => 400
|
215
|
+
return false
|
216
|
+
end
|
217
|
+
|
218
|
+
# Authorized
|
219
|
+
return true
|
220
|
+
end
|
221
|
+
|
222
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# Copyright 2023 OpenC3, Inc.
|
4
|
+
# All Rights Reserved.
|
5
|
+
#
|
6
|
+
# Licensed for Evaluation and Educational Use
|
7
|
+
#
|
8
|
+
# This file may only be used commercially under the terms of a commercial license
|
9
|
+
# purchased from OpenC3, Inc.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
14
|
+
#
|
15
|
+
# The development of this software was funded in-whole or in-part by MethaneSAT LLC.
|
16
|
+
|
17
|
+
class CfdpChecksum
|
18
|
+
def initialize
|
19
|
+
@checksum = 0
|
20
|
+
end
|
21
|
+
|
22
|
+
def add(offset, data)
|
23
|
+
front_pad_bytes = offset % 4
|
24
|
+
if front_pad_bytes != 0
|
25
|
+
data = ("\x00" * front_pad_bytes) << data
|
26
|
+
end
|
27
|
+
end_pad_bytes = 4 - data.length % 4
|
28
|
+
if end_pad_bytes != 4
|
29
|
+
data = data + ("\x00" * end_pad_bytes)
|
30
|
+
end
|
31
|
+
values = data.unpack('N*')
|
32
|
+
values.each do |value|
|
33
|
+
@checksum += value
|
34
|
+
end
|
35
|
+
return @checksum
|
36
|
+
end
|
37
|
+
|
38
|
+
# Expected to be calculated as we go using add, so file unused
|
39
|
+
def checksum(file, full_checksum_needed)
|
40
|
+
if full_checksum_needed
|
41
|
+
file.rewind
|
42
|
+
data = file.read
|
43
|
+
@checksum = 0
|
44
|
+
add(0, data)
|
45
|
+
end
|
46
|
+
return @checksum & 0xFFFFFFFF
|
47
|
+
end
|
48
|
+
|
49
|
+
def check(file, other_checksum, full_checksum_needed)
|
50
|
+
checksum(file, full_checksum_needed) == other_checksum
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# Copyright 2023 OpenC3, Inc.
|
4
|
+
# All Rights Reserved.
|
5
|
+
#
|
6
|
+
# Licensed for Evaluation and Educational Use
|
7
|
+
#
|
8
|
+
# This file may only be used commercially under the terms of a commercial license
|
9
|
+
# purchased from OpenC3, Inc.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
14
|
+
#
|
15
|
+
# The development of this software was funded in-whole or in-part by MethaneSAT LLC.
|
16
|
+
|
17
|
+
require 'openc3/utilities/crc'
|
18
|
+
|
19
|
+
class CfdpCrcChecksum
|
20
|
+
def initialize(poly, seed, xor, reflect)
|
21
|
+
@crc = OpenC3::Crc32.new(poly, seed, xor, reflect)
|
22
|
+
@checksum = 0
|
23
|
+
end
|
24
|
+
|
25
|
+
# Incremental not supported so add ignored
|
26
|
+
def add(offset, data)
|
27
|
+
return 0
|
28
|
+
end
|
29
|
+
|
30
|
+
# Uses file because incremental add is not supported
|
31
|
+
def checksum(file, full_checksum_needed)
|
32
|
+
file.rewind
|
33
|
+
data = file.read
|
34
|
+
@checksum = @crc.calc(data)
|
35
|
+
return @checksum & 0xFFFFFFFF
|
36
|
+
end
|
37
|
+
|
38
|
+
def check(file, other_checksum, full_checksum_needed)
|
39
|
+
checksum(file, full_checksum_needed) == other_checksum
|
40
|
+
end
|
41
|
+
end
|