openc3-cosmos-cfdp 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +18 -0
  3. data/README.md +181 -0
  4. data/Rakefile +40 -0
  5. data/lib/cfdp.rb +283 -0
  6. data/lib/cfdp_api.rb +204 -0
  7. data/microservices/CFDP/Gemfile +37 -0
  8. data/microservices/CFDP/Rakefile +6 -0
  9. data/microservices/CFDP/app/controllers/application_controller.rb +46 -0
  10. data/microservices/CFDP/app/controllers/cfdp_controller.rb +222 -0
  11. data/microservices/CFDP/app/models/cfdp_checksum.rb +52 -0
  12. data/microservices/CFDP/app/models/cfdp_crc_checksum.rb +41 -0
  13. data/microservices/CFDP/app/models/cfdp_mib.rb +613 -0
  14. data/microservices/CFDP/app/models/cfdp_model.rb +25 -0
  15. data/microservices/CFDP/app/models/cfdp_null_checksum.rb +29 -0
  16. data/microservices/CFDP/app/models/cfdp_pdu.rb +202 -0
  17. data/microservices/CFDP/app/models/cfdp_receive_transaction.rb +590 -0
  18. data/microservices/CFDP/app/models/cfdp_source_transaction.rb +449 -0
  19. data/microservices/CFDP/app/models/cfdp_topic.rb +58 -0
  20. data/microservices/CFDP/app/models/cfdp_transaction.rb +188 -0
  21. data/microservices/CFDP/app/models/cfdp_user.rb +601 -0
  22. data/microservices/CFDP/bin/rails +4 -0
  23. data/microservices/CFDP/bin/rake +4 -0
  24. data/microservices/CFDP/bin/setup +25 -0
  25. data/microservices/CFDP/config/application.rb +55 -0
  26. data/microservices/CFDP/config/boot.rb +4 -0
  27. data/microservices/CFDP/config/credentials.yml.enc +1 -0
  28. data/microservices/CFDP/config/environment.rb +5 -0
  29. data/microservices/CFDP/config/environments/development.rb +53 -0
  30. data/microservices/CFDP/config/environments/production.rb +75 -0
  31. data/microservices/CFDP/config/environments/test.rb +50 -0
  32. data/microservices/CFDP/config/initializers/application_controller_renderer.rb +8 -0
  33. data/microservices/CFDP/config/initializers/backtrace_silencers.rb +7 -0
  34. data/microservices/CFDP/config/initializers/cfdp_initializer.rb +26 -0
  35. data/microservices/CFDP/config/initializers/cors.rb +16 -0
  36. data/microservices/CFDP/config/initializers/filter_parameter_logging.rb +8 -0
  37. data/microservices/CFDP/config/initializers/inflections.rb +16 -0
  38. data/microservices/CFDP/config/initializers/mime_types.rb +4 -0
  39. data/microservices/CFDP/config/initializers/wrap_parameters.rb +9 -0
  40. data/microservices/CFDP/config/locales/en.yml +29 -0
  41. data/microservices/CFDP/config/puma.rb +38 -0
  42. data/microservices/CFDP/config/routes.rb +16 -0
  43. data/microservices/CFDP/config.ru +5 -0
  44. data/microservices/CFDP/init.sh +9 -0
  45. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_ack.rb +82 -0
  46. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_enum.rb +237 -0
  47. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_eof.rb +87 -0
  48. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_file_data.rb +98 -0
  49. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_finished.rb +114 -0
  50. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_keep_alive.rb +65 -0
  51. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_metadata.rb +116 -0
  52. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_nak.rb +91 -0
  53. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_prompt.rb +60 -0
  54. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_tlv.rb +291 -0
  55. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_user_ops.rb +749 -0
  56. data/microservices/CFDP/public/robots.txt +1 -0
  57. data/microservices/CFDP/spec/models/cfdp_pdu_ack_spec.rb +114 -0
  58. data/microservices/CFDP/spec/models/cfdp_pdu_eof_spec.rb +159 -0
  59. data/microservices/CFDP/spec/models/cfdp_pdu_file_data_spec.rb +76 -0
  60. data/microservices/CFDP/spec/models/cfdp_pdu_finished_spec.rb +192 -0
  61. data/microservices/CFDP/spec/models/cfdp_pdu_keep_alive_spec.rb +69 -0
  62. data/microservices/CFDP/spec/models/cfdp_pdu_metadata_spec.rb +346 -0
  63. data/microservices/CFDP/spec/models/cfdp_pdu_nak_spec.rb +126 -0
  64. data/microservices/CFDP/spec/models/cfdp_pdu_prompt_spec.rb +94 -0
  65. data/microservices/CFDP/spec/models/cfdp_pdu_spec.rb +111 -0
  66. data/microservices/CFDP/spec/rails_helper.rb +71 -0
  67. data/microservices/CFDP/spec/requests/cfdp_spec.rb +1965 -0
  68. data/microservices/CFDP/spec/spec_helper.rb +200 -0
  69. data/plugin.txt +67 -0
  70. data/targets/CFDPTEST/cmd_tlm/cmd.txt +5 -0
  71. data/targets/CFDPTEST/cmd_tlm/tlm.txt +4 -0
  72. data/targets/CFDPTEST/procedures/cfdp_test_suite.rb +130 -0
  73. data/targets/CFDPTEST/target.txt +4 -0
  74. metadata +118 -0
@@ -0,0 +1,601 @@
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 'thread'
18
+ require 'openc3/config/config_parser'
19
+ require 'openc3/packets/json_packet'
20
+ require 'openc3/utilities/logger'
21
+ require 'openc3/topics/topic'
22
+ require_relative 'cfdp_mib'
23
+ require_relative 'cfdp_receive_transaction'
24
+
25
+ class CfdpUser
26
+ def initialize
27
+ @thread = nil
28
+ @cancel_thread = false
29
+ @item_name_lookup = {}
30
+ @source_transactions = []
31
+ @source_threads = []
32
+
33
+ at_exit do
34
+ stop()
35
+ end
36
+ end
37
+
38
+ def start
39
+ @thread = Thread.new do
40
+ begin
41
+ source_entity = CfdpMib.source_entity
42
+ topics = []
43
+
44
+ tlm_packets = source_entity['tlm_info']
45
+ tlm_packets.each do |target_name, packet_name, item_name|
46
+ topic = "#{ENV['OPENC3_SCOPE']}__DECOM__{#{target_name.upcase}}__#{packet_name.upcase}"
47
+ topics << topic
48
+ @item_name_lookup[topic] = item_name.upcase
49
+ end
50
+ OpenC3::Topic.update_topic_offsets(topics)
51
+ while !@cancel_thread
52
+ # TODO: Handle freezing transactions if interface disconnects (or target goes unhealthy), and unfreezing if comes back to functional
53
+
54
+ OpenC3::Topic.read_topics(topics) do |topic, msg_id, msg_hash, redis|
55
+ break if @cancel_thread
56
+ begin
57
+ pdu_hash = receive_packet(topic, msg_id, msg_hash, redis)
58
+
59
+ if pdu_hash['DIRECTION'] == "TOWARD_FILE_RECEIVER"
60
+ if pdu_hash['DESTINATION_ENTITY_ID'] != CfdpMib.source_entity_id
61
+ OpenC3::Logger.error("Receiver PDU received for wrong entity: Mine: #{CfdpMib.source_entity_id}, Destination: #{pdu_hash['DESTINATION_ENTITY_ID']}", scope: ENV['OPENC3_SCOPE'])
62
+ next
63
+ end
64
+ else
65
+ if pdu_hash['SOURCE_ENTITY_ID'] != CfdpMib.source_entity_id
66
+ OpenC3::Logger.error("Sender PDU received for wrong entity: Mine: #{CfdpMib.source_entity_id}, Source: #{pdu_hash['SOURCE_ENTITY_ID']}", scope: ENV['OPENC3_SCOPE'])
67
+ next
68
+ end
69
+ end
70
+
71
+ transaction_id = CfdpTransaction.build_transaction_id(pdu_hash["SOURCE_ENTITY_ID"], pdu_hash["SEQUENCE_NUMBER"])
72
+ transaction = CfdpMib.transactions[transaction_id]
73
+ if transaction
74
+ transaction.handle_pdu(pdu_hash)
75
+ elsif pdu_hash["DIRECTIVE_CODE"] == "METADATA" or pdu_hash["DIRECTIVE_CODE"].nil?
76
+ transaction = CfdpReceiveTransaction.new(pdu_hash) # Also calls handle_pdu inside
77
+ else
78
+ raise "Unknown transaction: #{transaction_id}, #{pdu_hash}"
79
+ end
80
+ if pdu_hash["DIRECTIVE_CODE"] == "METADATA" and not transaction.metadata_pdu_count > 1
81
+ # Handle messages_to_user
82
+ messages_to_user = []
83
+ if pdu_hash["TLVS"]
84
+ pdu_hash["TLVS"].each do |tlv|
85
+ if tlv["TYPE"] == "MESSAGE_TO_USER"
86
+ messages_to_user << tlv
87
+ end
88
+ end
89
+ end
90
+ handle_messages_to_user(pdu_hash, messages_to_user) if messages_to_user.length > 0
91
+ end
92
+ rescue => err
93
+ OpenC3::Logger.error(err.formatted, scope: ENV['OPENC3_SCOPE'])
94
+ end
95
+ end
96
+ proxy_responses = []
97
+ CfdpMib.transactions.dup.each do |transaction_id, transaction|
98
+ transaction.update
99
+ if transaction.proxy_response_needed
100
+ # Send the proxy response
101
+ params = {}
102
+ params[:destination_entity_id] = transaction.proxy_response_info["SOURCE_ENTITY_ID"]
103
+ params[:messages_to_user] = []
104
+ destination_entity = CfdpMib.entity(Integer(params[:destination_entity_id]))
105
+ pdu = CfdpPdu.build_initial_pdu(type: "FILE_DIRECTIVE", destination_entity: destination_entity, file_size: 0, segmentation_control: "NOT_PRESERVED", transmission_mode: nil)
106
+ params[:messages_to_user] << pdu.build_proxy_put_response_message(condition_code: transaction.condition_code, delivery_code: transaction.delivery_code, file_status: transaction.file_status)
107
+ params[:messages_to_user] << pdu.build_originating_transaction_id_message(source_entity_id: transaction.proxy_response_info["SOURCE_ENTITY_ID"], sequence_number: transaction.proxy_response_info["SEQUENCE_NUMBER"])
108
+ transaction.filestore_responses.each do |filestore_response|
109
+ params[:messages_to_user] << pdu.build_proxy_filestore_response_message(action_code: filestore_response["ACTION_CODE"], status_code: filestore_response["STATUS_CODE"], first_file_name: filestore_response["FIRST_FILE_NAME"], second_file_name: filestore_response["SECOND_FILE_NAME"], filestore_message: filestore_response["FILESTORE_MESSAGE"])
110
+ end
111
+ proxy_responses << params
112
+ transaction.proxy_response_needed = false
113
+ transaction.proxy_response_info = nil
114
+ end
115
+ end
116
+ proxy_responses.each do |params|
117
+ start_source_transaction(params)
118
+ end
119
+ end
120
+ rescue => err
121
+ OpenC3::Logger.error(err.formatted, scope: ENV['OPENC3_SCOPE'])
122
+ end
123
+ end
124
+ end
125
+
126
+ def receive_packet(topic, msg_id, msg_hash, redis)
127
+ topic_split = topic.gsub(/{|}/, '').split("__") # Remove the redis hashtag curly braces
128
+ target_name = topic_split[2]
129
+ packet_name = topic_split[3]
130
+ stored = OpenC3::ConfigParser.handle_true_false(msg_hash["stored"])
131
+ packet = OpenC3::JsonPacket.new(:TLM, target_name, packet_name, msg_hash["time"].to_i, stored, msg_hash['json_data'])
132
+ pdu_data = packet.read(@item_name_lookup[topic])
133
+ return CfdpPdu.decom(pdu_data)
134
+ end
135
+
136
+ def stop
137
+ @cancel_thread = true
138
+ @source_transactions.each do |t|
139
+ t.abandon
140
+ end
141
+ @thread.join if @thread
142
+ @thread = nil
143
+ sleep(0.6) # Give threads time to die
144
+ @source_threads.each do |st|
145
+ st.kill if st.alive?
146
+ end
147
+ end
148
+
149
+ def start_source_transaction(params, proxy_response_info: nil)
150
+ transaction = CfdpSourceTransaction.new
151
+ transaction.proxy_response_info = proxy_response_info
152
+ @source_transactions << transaction
153
+ @source_threads << Thread.new do
154
+ begin
155
+ if params[:remote_entity_id] and Integer(params[:remote_entity_id]) != CfdpMib.source_entity_id
156
+ # Proxy Put
157
+ destination_entity = CfdpMib.entity(Integer(params[:destination_entity_id]))
158
+ pdu = CfdpPdu.build_initial_pdu(type: "FILE_DIRECTIVE", destination_entity: destination_entity, file_size: 0, segmentation_control: "NOT_PRESERVED", transmission_mode: nil)
159
+ messages_to_user = []
160
+ # messages_to_user << pdu.build_originating_transaction_id_message(source_entity_id: CfdpMib.source_entity.id, sequence_number: transaction.transaction_seq_num)
161
+ messages_to_user << pdu.build_proxy_put_request_message(destination_entity_id: Integer(params[:destination_entity_id]), source_file_name: params[:source_file_name], destination_file_name: params[:destination_file_name])
162
+ if params[:messages_to_user]
163
+ params[:messages_to_user].each do |message_to_user|
164
+ messages_to_user << pdu.build_proxy_message_to_user_message(message_to_user: message_to_user)
165
+ end
166
+ end
167
+ if params[:filestore_requests]
168
+ params[:filestore_requests].each do |filestore_request|
169
+ messages_to_user << pdu.build_proxy_filestore_request_message(action_code: filestore_request[0], first_file_name: filestore_request[1], second_file_name: filestore_request[2])
170
+ end
171
+ end
172
+ if params[:fault_handler_overrides]
173
+ params[:fault_handler_overrides].each do |fault_handler_override|
174
+ messages_to_user << pdu.build_proxy_fault_handler_override_message(condition_code: fault_handler_override[0], handler_code: fault_handler_override[1])
175
+ end
176
+ end
177
+ if params[:transmission_mode]
178
+ messages_to_user << pdu.build_proxy_transmission_mode_message(transmission_mode: params[:transmission_mode])
179
+ end
180
+ if params[:flow_label]
181
+ messages_to_user << pdu.build_proxy_flow_label_message(flow_label: params[:flow_label])
182
+ end
183
+ if params[:segmentation_control]
184
+ messages_to_user << pdu.build_proxy_segmentation_control_message(segmentation_control: params[:segmentation_control])
185
+ end
186
+ if params[:closure_requested]
187
+ messages_to_user << pdu.build_proxy_closure_request_message(closure_requested: params[:closure_requested])
188
+ end
189
+ OpenC3::Logger.info("CFDP Transaction #{transaction.id} Proxy Put to Remote Entity #{params[:remote_entity_id]}, Destination Entity #{params[:destination_entity_id]}\nSource File Name: #{params[:source_file_name]}\nDestination File Name: #{params[:destination_file_name]}", scope: ENV['OPENC3_SCOPE'])
190
+ transaction.put(
191
+ destination_entity_id: Integer(params[:remote_entity_id]),
192
+ closure_requested: params[:closure_requested],
193
+ transmission_mode: params[:transmission_mode],
194
+ fault_handler_overrides: params[:fault_handler_overrides],
195
+ messages_to_user: messages_to_user
196
+ )
197
+ else
198
+ # Regular Put
199
+ OpenC3::Logger.info("CFDP Transaction #{transaction.id} Put to Entity #{params[:destination_entity_id]}\nSource File Name: #{params[:source_file_name]}\nDestination File Name: #{params[:destination_file_name]}", scope: ENV['OPENC3_SCOPE'])
200
+ transaction.put(
201
+ destination_entity_id: Integer(params[:destination_entity_id]),
202
+ source_file_name: params[:source_file_name],
203
+ destination_file_name: params[:destination_file_name],
204
+ transmission_mode: params[:transmission_mode],
205
+ closure_requested: params[:closure_requested],
206
+ filestore_requests: params[:filestore_requests],
207
+ fault_handler_overrides: params[:fault_handler_overrides],
208
+ messages_to_user: params[:messages_to_user],
209
+ flow_label: params[:flow_label],
210
+ segmentation_control: params[:segmentation_control]
211
+ )
212
+ end
213
+ rescue => err
214
+ OpenC3::Logger.error(err.formatted, scope: ENV['OPENC3_SCOPE'])
215
+ end
216
+ end
217
+ return transaction
218
+ end
219
+
220
+ def proxy_request_setup(params)
221
+ messages_to_user = []
222
+ entity_id = Integer(params[:remote_entity_id])
223
+ destination_entity = CfdpMib.entity(entity_id)
224
+ pdu = CfdpPdu.build_initial_pdu(type: "FILE_DIRECTIVE", destination_entity: destination_entity, file_size: 0, segmentation_control: "NOT_PRESERVED", transmission_mode: nil)
225
+ return pdu, entity_id, messages_to_user
226
+ end
227
+
228
+ def proxy_request_start(entity_id:, messages_to_user:)
229
+ params = {}
230
+ params[:destination_entity_id] = entity_id
231
+ params[:messages_to_user] = messages_to_user
232
+ return start_source_transaction(params)
233
+ end
234
+
235
+ def start_directory_listing(params)
236
+ raise "directory_name required" unless params[:directory_name] and params[:directory_name].length > 0
237
+ raise "directory_file_name required" unless params[:directory_file_name] and params[:directory_file_name].length > 0
238
+ pdu, entity_id, messages_to_user = proxy_request_setup(params)
239
+ messages_to_user << pdu.build_directory_listing_request_message(directory_name: params[:directory_name], directory_file_name: params[:directory_file_name])
240
+ return proxy_request_start(entity_id: entity_id, messages_to_user: messages_to_user)
241
+ end
242
+
243
+ def cancel(params)
244
+ if params[:remote_entity_id] and Integer(params[:remote_entity_id]) != CfdpMib.source_entity_id
245
+ # Proxy Cancel
246
+ pdu, entity_id, messages_to_user = proxy_request_setup(params)
247
+ source_entity_id, sequence_number = params[:transaction_id].split('__')
248
+ messages_to_user << pdu.build_proxy_put_cancel_message()
249
+ messages_to_user << pdu.build_originating_transaction_id_message(source_entity_id: Integer(source_entity_id), sequence_number: Integer(sequence_number))
250
+ return proxy_request_start(entity_id: entity_id, messages_to_user: messages_to_user)
251
+ else
252
+ transaction = CfdpMib.transactions[params[:transaction_id]]
253
+ if transaction
254
+ transaction.cancel
255
+ return transaction
256
+ else
257
+ return nil
258
+ end
259
+ end
260
+ end
261
+
262
+ def suspend(params)
263
+ if params[:remote_entity_id] and Integer(params[:remote_entity_id]) != CfdpMib.source_entity_id
264
+ # Proxy Suspend
265
+ pdu, entity_id, messages_to_user = proxy_request_setup(params)
266
+ source_entity_id, sequence_number = params[:transaction_id].split('__')
267
+ messages_to_user << pdu.build_remote_suspend_request_message(source_entity_id: Integer(source_entity_id), sequence_number: Integer(sequence_number))
268
+ return proxy_request_start(entity_id: entity_id, messages_to_user: messages_to_user)
269
+ else
270
+ transaction = CfdpMib.transactions[params[:transaction_id]]
271
+ if transaction
272
+ transaction.suspend
273
+ return transaction
274
+ else
275
+ return nil
276
+ end
277
+ end
278
+ end
279
+
280
+ def resume(params)
281
+ if params[:remote_entity_id] and Integer(params[:remote_entity_id]) != CfdpMib.source_entity_id
282
+ # Proxy Resume
283
+ pdu, entity_id, messages_to_user = proxy_request_setup(params)
284
+ source_entity_id, sequence_number = params[:transaction_id].split('__')
285
+ messages_to_user << pdu.build_remote_resume_request_message(source_entity_id: Integer(source_entity_id), sequence_number: Integer(sequence_number))
286
+ return proxy_request_start(entity_id: entity_id, messages_to_user: messages_to_user)
287
+ else
288
+ transaction = CfdpMib.transactions[params[:transaction_id]]
289
+ if transaction
290
+ transaction.resume
291
+ return transaction
292
+ else
293
+ return nil
294
+ end
295
+ end
296
+ end
297
+
298
+ def report(params)
299
+ if params[:remote_entity_id] and Integer(params[:remote_entity_id]) != CfdpMib.source_entity_id
300
+ raise "report_file_name required" unless params[:report_file_name] and params[:report_file_name].length > 0
301
+ # Proxy Report
302
+ pdu, entity_id, messages_to_user = proxy_request_setup(params)
303
+ source_entity_id, sequence_number = params[:transaction_id].split('__')
304
+ messages_to_user << pdu.build_remote_status_report_request_message(source_entity_id: Integer(source_entity_id), sequence_number: Integer(sequence_number), report_file_name: params[:report_file_name])
305
+ return proxy_request_start(entity_id: entity_id, messages_to_user: messages_to_user)
306
+ else
307
+ transaction = CfdpMib.transactions[params[:transaction_id]]
308
+ if transaction
309
+ transaction.report
310
+ return transaction
311
+ else
312
+ return nil
313
+ end
314
+ end
315
+ end
316
+
317
+ def handle_messages_to_user(metadata_pdu_hash, messages_to_user)
318
+ proxy_action = nil
319
+ source_entity_id = nil
320
+ sequence_number = nil
321
+ request_source_entity_id = nil
322
+ request_sequence_number = nil
323
+ condition_code = nil
324
+ delivery_code = nil
325
+ file_status = nil
326
+ filestore_responses = []
327
+ directory_name = nil
328
+ directory_file_name = nil
329
+ response_code = nil
330
+ transaction_status = nil
331
+ suspension_indicator = nil
332
+ report_file_name = nil
333
+
334
+ params = {}
335
+ params[:fault_handler_overrides] = []
336
+ params[:messages_to_user] = []
337
+ params[:filestore_requests] = []
338
+
339
+ messages_to_user.each do |message_to_user|
340
+ case message_to_user['MSG_TYPE']
341
+ when "PROXY_PUT_REQUEST"
342
+ params[:destination_entity_id] = message_to_user["DESTINATION_ENTITY_ID"]
343
+ params[:source_file_name] = message_to_user["SOURCE_FILE_NAME"]
344
+ params[:destination_file_name] = message_to_user["DESTINATION_FILE_NAME"]
345
+ destination_entity = CfdpMib.entity(Integer(params[:destination_entity_id]))
346
+ pdu = CfdpPdu.build_initial_pdu(type: "FILE_DIRECTIVE", destination_entity: destination_entity, file_size: 0, segmentation_control: "NOT_PRESERVED", transmission_mode: nil)
347
+ params[:messages_to_user] << pdu.build_originating_transaction_id_message(source_entity_id: metadata_pdu_hash["SOURCE_ENTITY_ID"], sequence_number: metadata_pdu_hash["SEQUENCE_NUMBER"])
348
+ proxy_action = :PUT
349
+
350
+ when "PROXY_MESSAGE_TO_USER"
351
+ params[:messages_to_user] << message_to_user["MESSAGE_TO_USER"]
352
+
353
+ when "PROXY_FILESTORE_REQUEST"
354
+ params[:filestore_requests] << message_to_user["ACTION_CODE", message_to_user["FIRST_FILE_NAME"]]
355
+ params[:filestore_requests][-1] << message_to_user["SECOND_FILE_NAME"] if message_to_user["SECOND_FILE_NAME"]
356
+
357
+ when "PROXY_FAULT_HANDLER_OVERRIDE"
358
+ params[:fault_handler_overrides] << [message_to_user["CONDITION_CODE"], message_to_user["HANDLER_CODE"]]
359
+
360
+ when "PROXY_TRANSMISSION_MODE"
361
+ params[:transmission_mode] = message_to_user["TRANSMISSION_MODE"]
362
+
363
+ when "PROXY_FLOW_LABEL"
364
+ params[:flow_label] = message_to_user["FLOW_LABEL"]
365
+
366
+ when "PROXY_SEGMENTATION_CONTROL"
367
+ params[:segmentation_control] = message_to_user["SEGMENTATION_CONTROL"]
368
+
369
+ when "PROXY_PUT_RESPONSE"
370
+ # This is back at the originator
371
+ condition_code = message_to_user["CONDITION_CODE"]
372
+ delivery_code = message_to_user["DELIVERY_CODE"]
373
+ file_status = message_to_user["FILE_STATUS"]
374
+ proxy_action = :PUT_RESPONSE
375
+
376
+ when "PROXY_FILESTORE_RESPONSE"
377
+ # This is back at the originator
378
+ filestore_responses << message_to_user.except("MSG_TYPE", "MSG_ID")
379
+
380
+ when "PROXY_PUT_CANCEL"
381
+ proxy_action = :CANCEL
382
+
383
+ when "ORIGINATING_TRANSACTION_ID"
384
+ source_entity_id = message_to_user["SOURCE_ENTITY_ID"]
385
+ sequence_number = message_to_user["SEQUENCE_NUMBER"]
386
+
387
+ when "PROXY_CLOSURE_REQUEST"
388
+ params[:closure_requested] = message_to_user["CLOSURE_REQUESTED"]
389
+
390
+ when "DIRECTORY_LISTING_REQUEST"
391
+ proxy_action = :DIRECTORY_LISTING
392
+ directory_name = message_to_user["DIRECTORY_NAME"]
393
+ directory_file_name = message_to_user["DIRECTORY_FILE_NAME"]
394
+
395
+ when "DIRECTORY_LISTING_RESPONSE"
396
+ # This is back at the originator
397
+ proxy_action = :DIRECTORY_LISTING_RESPONSE
398
+ directory_name = message_to_user["DIRECTORY_NAME"]
399
+ directory_file_name = message_to_user["DIRECTORY_FILE_NAME"]
400
+ response_code = message_to_user["RESPONSE_CODE"]
401
+
402
+ when "REMOTE_STATUS_REPORT_REQUEST"
403
+ proxy_action = :REPORT
404
+ request_source_entity_id = message_to_user["SOURCE_ENTITY_ID"]
405
+ request_sequence_number = message_to_user["SEQUENCE_NUMBER"]
406
+ report_file_name = message_to_user["REPORT_FILE_NAME"]
407
+
408
+ when "REMOTE_STATUS_REPORT_RESPONSE"
409
+ # This is back at the originator
410
+ proxy_action = :REPORT_RESPONSE
411
+ request_source_entity_id = message_to_user["SOURCE_ENTITY_ID"]
412
+ request_sequence_number = message_to_user["SEQUENCE_NUMBER"]
413
+ transaction_status = message_to_user["TRANSACTION_STATUS"]
414
+ response_code = message_to_user["RESPONSE_CODE"]
415
+
416
+ when "REMOTE_SUSPEND_REQUEST"
417
+ proxy_action = :SUSPEND
418
+ request_source_entity_id = message_to_user["SOURCE_ENTITY_ID"]
419
+ request_sequence_number = message_to_user["SEQUENCE_NUMBER"]
420
+
421
+ when "REMOTE_SUSPEND_RESPONSE"
422
+ # This is back at the originator
423
+ proxy_action = :SUSPEND_RESPONSE
424
+ request_source_entity_id = message_to_user["SOURCE_ENTITY_ID"]
425
+ request_sequence_number = message_to_user["SEQUENCE_NUMBER"]
426
+ suspension_indicator = message_to_user["SUSPENSION_INDICATOR"]
427
+ transaction_status = message_to_user["TRANSACTION_STATUS"]
428
+
429
+ when "REMOTE_RESUME_REQUEST"
430
+ proxy_action = :RESUME
431
+ request_source_entity_id = message_to_user["SOURCE_ENTITY_ID"]
432
+ request_sequence_number = message_to_user["SEQUENCE_NUMBER"]
433
+
434
+ when "REMOTE_RESUME_RESPONSE"
435
+ # This is back at the originator
436
+ proxy_action = :RESUME_RESPONSE
437
+ request_source_entity_id = message_to_user["SOURCE_ENTITY_ID"]
438
+ request_sequence_number = message_to_user["SEQUENCE_NUMBER"]
439
+ suspension_indicator = message_to_user["SUSPENSION_INDICATOR"]
440
+ transaction_status = message_to_user["TRANSACTION_STATUS"]
441
+
442
+ when "UNKNOWN"
443
+ # Unknown Message - Ignore
444
+ if message_to_user["DATA"].to_s.is_printable?
445
+ OpenC3::Logger.warn("Received Unknown #{message_to_user["DATA"].length} Byte Message to User (#{message_to_user["MSG_TYPE_VALUE"]}): '#{message_to_user["DATA"].to_s}'", scope: ENV['OPENC3_SCOPE'])
446
+ else
447
+ OpenC3::Logger.warn("Received Unknown #{message_to_user["DATA"].length} Byte Message to User (#{message_to_user["MSG_TYPE_VALUE"]}): #{message_to_user["DATA"].to_s.simple_formatted}", scope: ENV['OPENC3_SCOPE'])
448
+ end
449
+ end
450
+ end
451
+
452
+ if proxy_action
453
+ case proxy_action
454
+ when :CANCEL
455
+ CfdpMib.transactions.dup.each do |transaction_id, transaction|
456
+ if transaction.proxy_response_info
457
+ if transaction.proxy_response_info["SOURCE_ENTITY_ID"] == source_entity_id and transaction.proxy_response_info["SEQUENCE_NUMBER"] == sequence_number
458
+ transaction.cancel(metadata_pdu_hash["SOURCE_ENTITY_ID"])
459
+ break
460
+ end
461
+ end
462
+ end
463
+
464
+ when :PUT
465
+ proxy_response_info = {
466
+ "SOURCE_ENTITY_ID" => metadata_pdu_hash["SOURCE_ENTITY_ID"],
467
+ "SEQUENCE_NUMBER" => metadata_pdu_hash["SEQUENCE_NUMBER"]
468
+ }
469
+ transaction = start_source_transaction(params, proxy_response_info: proxy_response_info)
470
+
471
+ when :PUT_RESPONSE
472
+ transaction_id = CfdpTransaction.build_transaction_id(source_entity_id, sequence_number)
473
+ if filestore_responses.length > 0
474
+ CfdpTopic.write_indication('Proxy-Put-Response',
475
+ transaction_id: transaction_id, condition_code: condition_code,
476
+ file_status: file_status, delivery_code: delivery_code,
477
+ filestore_responses: filestore_responses)
478
+ else
479
+ CfdpTopic.write_indication('Proxy-Put-Response',
480
+ transaction_id: transaction_id, condition_code: condition_code,
481
+ file_status: file_status, delivery_code: delivery_code)
482
+ end
483
+
484
+ when :DIRECTORY_LISTING
485
+ result = CfdpMib.directory_listing(directory_name, directory_file_name)
486
+ if result
487
+ params = {}
488
+ params[:destination_entity_id] = metadata_pdu_hash["SOURCE_ENTITY_ID"]
489
+ params[:source_file_name] = StringIO.new(result)
490
+ if directory_file_name and directory_file_name.length > 0
491
+ params[:destination_file_name] = directory_file_name
492
+ else
493
+ params[:destination_file_name] = "default_directory_file_name.txt"
494
+ end
495
+ params[:messages_to_user] = []
496
+ destination_entity = CfdpMib.entity(metadata_pdu_hash["SOURCE_ENTITY_ID"])
497
+ pdu = CfdpPdu.build_initial_pdu(type: "FILE_DIRECTIVE", destination_entity: destination_entity, file_size: 0, segmentation_control: "NOT_PRESERVED", transmission_mode: nil)
498
+ params[:messages_to_user] << pdu.build_directory_listing_response_message(response_code: "SUCCESSFUL", directory_name: directory_name, directory_file_name: directory_file_name)
499
+ params[:messages_to_user] << pdu.build_originating_transaction_id_message(source_entity_id: metadata_pdu_hash["SOURCE_ENTITY_ID"], sequence_number: metadata_pdu_hash["SEQUENCE_NUMBER"])
500
+ start_source_transaction(params)
501
+ else
502
+ params = {}
503
+ params[:destination_entity_id] = metadata_pdu_hash["SOURCE_ENTITY_ID"]
504
+ params[:source_file_name] = nil
505
+ params[:destination_file_name] = nil
506
+ params[:messages_to_user] = []
507
+ destination_entity = CfdpMib.entity(metadata_pdu_hash["SOURCE_ENTITY_ID"])
508
+ pdu = CfdpPdu.build_initial_pdu(type: "FILE_DIRECTIVE", destination_entity: destination_entity, file_size: 0, segmentation_control: "NOT_PRESERVED", transmission_mode: nil)
509
+ params[:messages_to_user] << pdu.build_directory_listing_response_message(response_code: "UNSUCCESSFUL", directory_name: directory_name, directory_file_name: directory_file_name)
510
+ params[:messages_to_user] << pdu.build_originating_transaction_id_message(source_entity_id: metadata_pdu_hash["SOURCE_ENTITY_ID"], sequence_number: metadata_pdu_hash["SEQUENCE_NUMBER"])
511
+ start_source_transaction(params)
512
+ end
513
+
514
+ when :DIRECTORY_LISTING_RESPONSE
515
+ transaction_id = CfdpTransaction.build_transaction_id(source_entity_id, sequence_number)
516
+ CfdpTopic.write_indication('Directory-Listing-Response',
517
+ transaction_id: transaction_id, response_code: response_code,
518
+ directory_name: directory_name, directory_file_name: directory_file_name)
519
+
520
+ when :REPORT
521
+ transaction_id = CfdpTransaction.build_transaction_id(request_source_entity_id, request_sequence_number)
522
+ transaction = CfdpMib.transactions[transaction_id]
523
+ if transaction
524
+ params = {}
525
+ params[:destination_entity_id] = metadata_pdu_hash["SOURCE_ENTITY_ID"]
526
+ params[:source_file_name] = StringIO.new(transaction.build_report)
527
+ if report_file_name and report_file_name.length > 0
528
+ params[:destination_file_name] = report_file_name
529
+ else
530
+ params[:destination_file_name] = "default_report_file_name.txt"
531
+ end
532
+ params[:messages_to_user] = []
533
+ destination_entity = CfdpMib.entity(metadata_pdu_hash["SOURCE_ENTITY_ID"])
534
+ pdu = CfdpPdu.build_initial_pdu(type: "FILE_DIRECTIVE", destination_entity: destination_entity, file_size: 0, segmentation_control: "NOT_PRESERVED", transmission_mode: nil)
535
+ params[:messages_to_user] << pdu.build_remote_status_report_response_message(source_entity_id: request_source_entity_id, sequence_number: request_sequence_number, transaction_status: transaction.transaction_status, response_code: "SUCCESSFUL")
536
+ params[:messages_to_user] << pdu.build_originating_transaction_id_message(source_entity_id: metadata_pdu_hash["SOURCE_ENTITY_ID"], sequence_number: metadata_pdu_hash["SEQUENCE_NUMBER"])
537
+ start_source_transaction(params)
538
+ else
539
+ params = {}
540
+ params[:destination_entity_id] = metadata_pdu_hash["SOURCE_ENTITY_ID"]
541
+ params[:source_file_name] = nil
542
+ params[:destination_file_name] = nil
543
+ params[:messages_to_user] = []
544
+ destination_entity = CfdpMib.entity(metadata_pdu_hash["SOURCE_ENTITY_ID"])
545
+ pdu = CfdpPdu.build_initial_pdu(type: "FILE_DIRECTIVE", destination_entity: destination_entity, file_size: 0, segmentation_control: "NOT_PRESERVED", transmission_mode: nil)
546
+ params[:messages_to_user] << pdu.build_remote_status_report_response_message(source_entity_id: request_source_entity_id, sequence_number: request_sequence_number, transaction_status: "UNDEFINED", response_code: "UNSUCCESSFUL")
547
+ params[:messages_to_user] << pdu.build_originating_transaction_id_message(source_entity_id: metadata_pdu_hash["SOURCE_ENTITY_ID"], sequence_number: metadata_pdu_hash["SEQUENCE_NUMBER"])
548
+ start_source_transaction(params)
549
+ end
550
+
551
+ when :REPORT_RESPONSE
552
+ transaction_id = CfdpTransaction.build_transaction_id(source_entity_id, sequence_number)
553
+ CfdpTopic.write_indication('Remote-Report-Response',
554
+ transaction_id: transaction_id, source_entity_id: request_source_entity_id, sequence_number: request_sequence_number,
555
+ transaction_status: transaction_status, response_code: response_code)
556
+
557
+ when :SUSPEND, :RESUME
558
+ transaction_id = CfdpTransaction.build_transaction_id(request_source_entity_id, request_sequence_number)
559
+ transaction = CfdpMib.transactions[transaction_id]
560
+ suspension_indicator = "NOT_SUSPENDED"
561
+ transaction_status = "UNDEFINED"
562
+ if transaction
563
+ if proxy_action == :SUSPEND
564
+ transaction.suspend
565
+ else
566
+ transaction.resume
567
+ end
568
+ transaction_status = transaction.transaction_status
569
+ suspension_indicator = "SUSPENDED" if transaction.state == "SUSPENDED"
570
+ end
571
+ params = {}
572
+ params[:destination_entity_id] = metadata_pdu_hash["SOURCE_ENTITY_ID"]
573
+ params[:source_file_name] = nil
574
+ params[:destination_file_name] = nil
575
+ params[:messages_to_user] = []
576
+ destination_entity = CfdpMib.entity(metadata_pdu_hash["SOURCE_ENTITY_ID"])
577
+ pdu = CfdpPdu.build_initial_pdu(type: "FILE_DIRECTIVE", destination_entity: destination_entity, file_size: 0, segmentation_control: "NOT_PRESERVED", transmission_mode: nil)
578
+ if proxy_action == :SUSPEND
579
+ params[:messages_to_user] << pdu.build_remote_suspend_response_message(source_entity_id: request_source_entity_id, sequence_number: request_sequence_number, transaction_status: transaction_status, suspension_indicator: suspension_indicator)
580
+ else
581
+ params[:messages_to_user] << pdu.build_remote_resume_response_message(source_entity_id: request_source_entity_id, sequence_number: request_sequence_number, transaction_status: transaction_status, suspension_indicator: suspension_indicator)
582
+ end
583
+ params[:messages_to_user] << pdu.build_originating_transaction_id_message(source_entity_id: metadata_pdu_hash["SOURCE_ENTITY_ID"], sequence_number: metadata_pdu_hash["SEQUENCE_NUMBER"])
584
+ start_source_transaction(params)
585
+
586
+ when :SUSPEND_RESPONSE
587
+ transaction_id = CfdpTransaction.build_transaction_id(source_entity_id, sequence_number)
588
+ CfdpTopic.write_indication('Remote-Suspend-Response',
589
+ transaction_id: transaction_id, source_entity_id: request_source_entity_id, sequence_number: request_sequence_number,
590
+ transaction_status: transaction_status, suspension_indicator: suspension_indicator)
591
+
592
+ when :RESUME_RESPONSE
593
+ transaction_id = CfdpTransaction.build_transaction_id(source_entity_id, sequence_number)
594
+ CfdpTopic.write_indication('Remote-Resume-Response',
595
+ transaction_id: transaction_id, source_entity_id: request_source_entity_id, sequence_number: request_sequence_number,
596
+ transaction_status: transaction_status, suspension_indicator: suspension_indicator)
597
+
598
+ end
599
+ end
600
+ end
601
+ end
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path("../config/application", __dir__)
3
+ require_relative "../config/boot"
4
+ require "rails/commands"
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative "../config/boot"
3
+ require "rake"
4
+ Rake.application.run
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+ require "fileutils"
3
+
4
+ # path to your application root.
5
+ APP_ROOT = File.expand_path("..", __dir__)
6
+
7
+ def system!(*args)
8
+ system(*args) || abort("\n== Command #{args} failed ==")
9
+ end
10
+
11
+ FileUtils.chdir APP_ROOT do
12
+ # This script is a way to set up or update your development environment automatically.
13
+ # This script is idempotent, so that you can run it at any time and get an expectable outcome.
14
+ # Add necessary setup steps to this file.
15
+
16
+ puts "== Installing dependencies =="
17
+ system! "gem install bundler --conservative"
18
+ system("bundle check") || system!("bundle install")
19
+
20
+ puts "\n== Removing old logs and tempfiles =="
21
+ system! "bin/rails log:clear tmp:clear"
22
+
23
+ puts "\n== Restarting application server =="
24
+ system! "bin/rails restart"
25
+ end