F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
FpySequencerValidationState.cpp
Go to the documentation of this file.
1 #include <Utils/Hash/Hash.hpp>
4 
5 namespace Svc {
6 
8  // if this assertion fails, you aren't allocating enough bytes for the
9  // FpySequencer. this is because you must have a buffer big enough to fit the
10  // header of a sequence
11  FW_ASSERT(bytes >= Fpy::Header::SERIALIZED_SIZE, static_cast<FwAssertArgType>(bytes));
12  FwSizeType originalBytes = bytes;
13  bool recoverable = false;
14  this->m_allocatorId = identifier;
15  U8* allocatedMemory = static_cast<U8*>(allocator.allocate(identifier, bytes, recoverable));
16  // if this fails, unable to allocate the requested amount of money
17  FW_ASSERT(bytes >= originalBytes, static_cast<FwAssertArgType>(bytes));
18  this->m_sequenceBuffer.setExtBuffer(allocatedMemory, bytes);
19 }
20 
22  allocator.deallocate(this->m_allocatorId, this->m_sequenceBuffer.getBuffAddr());
23  this->m_sequenceBuffer.clear();
24 }
25 
26 // loads the sequence in memory, and does header/crc/integrity checks.
27 // return SUCCESS if sequence is valid, FAILURE otherwise
28 Fw::Success FpySequencer::validate() {
29  if (this->m_sequenceFilePath.length() == 0) {
30  this->log_WARNING_HI_FileOpenError(this->m_sequenceFilePath, static_cast<I32>(Os::File::INVALID_ARGUMENT));
31  return Fw::Success::FAILURE;
32  }
33 
34  if (!this->checkSandbox(this->m_sequenceFilePath)) {
35  return Fw::Success::FAILURE;
36  }
37 
38  // crc needs to be initialized with a particular value
39  // for the calculation to work
40  this->m_computedCRC.init();
41 
42  Os::File sequenceFile;
43  Os::File::Status openStatus = sequenceFile.open(this->m_sequenceFilePath.toChar(), Os::File::OPEN_READ);
44 
45  if (openStatus != Os::File::Status::OP_OK) {
46  this->log_WARNING_HI_FileOpenError(this->m_sequenceFilePath, static_cast<I32>(openStatus));
47  return Fw::Success::FAILURE;
48  }
49 
50  Fw::Success readStatus =
52 
53  if (readStatus != Fw::Success::SUCCESS) {
54  return Fw::Success::FAILURE;
55  }
56 
57  readStatus = this->readHeader();
58 
59  if (readStatus != Fw::Success::SUCCESS) {
60  return Fw::Success::FAILURE;
61  }
62 
63  readStatus =
64  readBytes(sequenceFile, this->m_sequenceObj.get_header().get_bodySize(), FpySequencer_FileReadStage::BODY);
65 
66  if (readStatus != Fw::Success::SUCCESS) {
67  return Fw::Success::FAILURE;
68  }
69 
70  readStatus = this->readBody();
71 
72  if (readStatus != Fw::Success::SUCCESS) {
73  return Fw::Success::FAILURE;
74  }
75 
76  // read footer bytes but don't include in CRC
77  readStatus = this->readBytes(sequenceFile, Fpy::Footer::SERIALIZED_SIZE, FpySequencer_FileReadStage::FOOTER, false);
78 
79  if (readStatus != Fw::Success::SUCCESS) {
80  return Fw::Success::FAILURE;
81  }
82 
83  readStatus = this->readFooter();
84 
85  if (readStatus != Fw::Success::SUCCESS) {
86  return Fw::Success::FAILURE;
87  }
88 
89  // make sure we're at EOF. The size() and position() OS calls can fail
90  // on filesystem errors or if the file was concurrently modified by
91  // another FileManager command (e.g. RemoveFile or AppendFile) between
92  // the file open and this point. Treat the failure as a validation
93  // failure rather than aborting the FSW process.
94  FwSizeType sequenceFileSize;
95  Os::File::Status sizeStatus = sequenceFile.size(sequenceFileSize);
96  if (sizeStatus != Os::File::Status::OP_OK) {
97  this->log_WARNING_HI_FileApiError(this->m_sequenceFilePath, static_cast<I32>(sizeStatus));
98  return Fw::Success::FAILURE;
99  }
100 
101  FwSizeType sequenceFilePosition;
102  Os::File::Status positionStatus = sequenceFile.position(sequenceFilePosition);
103  if (positionStatus != Os::File::Status::OP_OK) {
104  this->log_WARNING_HI_FileApiError(this->m_sequenceFilePath, static_cast<I32>(positionStatus));
105  return Fw::Success::FAILURE;
106  }
107 
108  if (sequenceFileSize != sequenceFilePosition) {
109  this->log_WARNING_HI_ExtraBytesInSequence(static_cast<FwSizeType>(sequenceFileSize - sequenceFilePosition));
110  return Fw::Success::FAILURE;
111  }
112 
113  if (this->m_sequenceArgs.get_size() > Fpy::MAX_STACK_SIZE) {
115  static_cast<Fpy::StackSizeType>(this->m_sequenceArgs.get_size()));
116  return Fw::Success::FAILURE;
117  }
118 
119  // The argument size arrives separately from the argument buffer, so it can describe more bytes
120  // than that buffer holds. Reject before anything reads the buffer by that size.
121  const FwSizeType argCapacity = static_cast<FwSizeType>(sizeof(this->m_sequenceArgs.get_buffer()));
122  if (this->m_sequenceArgs.get_size() > argCapacity) {
123  this->log_WARNING_HI_ArgSizeExceedsCapacity(this->m_sequenceArgs.get_size(), argCapacity);
124  return Fw::Success::FAILURE;
125  }
126 
127  return Fw::Success::SUCCESS;
128 }
129 
130 // reads and validates the header from the m_sequenceBuffer
131 // return SUCCESS if sequence is valid, FAILURE otherwise
132 Fw::Success FpySequencer::readHeader() {
133  // deser header
134  Fw::SerializeStatus deserStatus = this->m_sequenceBuffer.deserializeTo(this->m_sequenceObj.get_header());
135  if (deserStatus != Fw::SerializeStatus::FW_SERIALIZE_OK) {
137  FpySequencer_FileReadStage::HEADER, this->m_sequenceFilePath, static_cast<I32>(deserStatus),
138  this->m_sequenceBuffer.getDeserializeSizeLeft(), this->m_sequenceBuffer.getSize());
139  return Fw::Success::FAILURE;
140  }
141 
142  // check matching schema version
143  if (this->m_sequenceObj.get_header().get_schemaVersion() != Fpy::SCHEMA_VERSION) {
145  this->m_sequenceObj.get_header().get_schemaVersion());
146  return Fw::Success::FAILURE;
147  }
148 
149  if (this->m_sequenceObj.get_header().get_argumentCount() > Fpy::MAX_SEQUENCE_ARG_COUNT) {
152  return Fw::Success::FAILURE;
153  }
154 
155  if (this->m_sequenceObj.get_header().get_statementCount() > Fpy::MAX_SEQUENCE_STATEMENT_COUNT) {
158  return Fw::Success::FAILURE;
159  }
160  return Fw::Success::SUCCESS;
161 }
162 
163 // reads and validates the body from the m_sequenceBuffer
164 // return SUCCESS if sequence is valid, FAILURE otherwise
165 Fw::Success FpySequencer::readBody() {
166  Fw::SerializeStatus deserStatus;
167 
168  const U8 argumentCount = this->m_sequenceObj.get_header().get_argumentCount();
169  this->m_totalExpectedArgSize = 0;
170 
171  // deser arguments
172  // Read and deserialize each arg_spec incrementally since they're variable-length
173  for (U8 i = 0; i < argumentCount; i++) {
174  Fpy::ArgSpec& argSpec = this->m_sequenceObj.get_args()[i];
175  deserStatus = this->m_sequenceBuffer.deserializeTo(argSpec);
176  if (deserStatus != Fw::SerializeStatus::FW_SERIALIZE_OK) {
178  FpySequencer_FileReadStage::BODY, this->m_sequenceFilePath, static_cast<I32>(deserStatus),
179  this->m_sequenceBuffer.getDeserializeSizeLeft(), this->m_sequenceBuffer.getSize());
180  return Fw::Success::FAILURE;
181  }
182 
183  m_totalExpectedArgSize += argSpec.get_argSize();
184  }
185 
186  // Check for overflow
187  if (m_totalExpectedArgSize > Fpy::MAX_STACK_SIZE) {
188  this->log_WARNING_HI_ArgTotalSizeExceedsStackLimit(m_totalExpectedArgSize);
189  return Fw::Success::FAILURE;
190  }
191 
192  // Validate total argument size
193  if (this->m_totalExpectedArgSize != this->m_sequenceArgs.get_size()) {
194  this->log_WARNING_HI_ArgSizeMismatch(this->m_totalExpectedArgSize, this->m_sequenceArgs.get_size(),
195  this->m_sequenceFilePath);
196  return Fw::Success::FAILURE;
197  }
198 
199  // deser statements
200  const U16 statementCount = this->m_sequenceObj.get_header().get_statementCount();
201  for (U16 statementIdx = 0; statementIdx < statementCount; statementIdx++) {
202  // deser statement
203  deserStatus = this->m_sequenceBuffer.deserializeTo(this->m_sequenceObj.get_statements()[statementIdx]);
204  if (deserStatus != Fw::FW_SERIALIZE_OK) {
206  FpySequencer_FileReadStage::BODY, this->m_sequenceFilePath, static_cast<I32>(deserStatus),
207  this->m_sequenceBuffer.getDeserializeSizeLeft(), this->m_sequenceBuffer.getSize());
208  return Fw::Success::FAILURE;
209  }
210  }
211  return Fw::Success::SUCCESS;
212 }
213 
214 // reads and validates the footer from the m_sequenceBuffer
215 // return SUCCESS if sequence is valid, FAILURE otherwise
216 Fw::Success FpySequencer::readFooter() {
217  Fw::SerializeStatus deserStatus = this->m_sequenceBuffer.deserializeTo(this->m_sequenceObj.get_footer());
218  if (deserStatus != Fw::FW_SERIALIZE_OK) {
220  FpySequencer_FileReadStage::FOOTER, this->m_sequenceFilePath, static_cast<I32>(deserStatus),
221  this->m_sequenceBuffer.getDeserializeSizeLeft(), this->m_sequenceBuffer.getSize());
222  return Fw::Success::FAILURE;
223  }
224 
225  // need this for some reason to "finalize" the crc TODO get an explanation on this
226  U32 computedCRC = 0;
227  this->m_computedCRC.finalize(computedCRC);
228 
229  if (computedCRC != this->m_sequenceObj.get_footer().get_crc()) {
230  this->log_WARNING_HI_WrongCRC(this->m_sequenceObj.get_footer().get_crc(), computedCRC);
231  return Fw::Success::FAILURE;
232  }
233 
234  return Fw::Success::SUCCESS;
235 }
236 
237 // reads some bytes from the open file into the m_sequenceBuffer.
238 // return success if successful
239 Fw::Success FpySequencer::readBytes(Os::File& file,
240  FwSizeType expectedReadLen,
241  const FpySequencer_FileReadStage& readStage,
242  bool updateCrc) {
243  FW_ASSERT(file.isOpen());
244  // this has to be declared a var because file.read must take a ref
245  FwSizeType actualReadLen = expectedReadLen;
246 
247  const FwSizeType capacity = this->m_sequenceBuffer.getCapacity();
248 
249  // if this fails, then you need to give the sequencer more buffer memory. pass in a bigger number
250  // to fpySeq.allocateBuffer(). This is usually done in topology setup CPP
251  if (expectedReadLen > capacity) {
252  this->log_WARNING_HI_InsufficientBufferSpace(static_cast<U64>(capacity), this->m_sequenceFilePath);
253  return Fw::Success::FAILURE;
254  }
255 
256  Os::File::Status fileStatus = file.read(this->m_sequenceBuffer.getBuffAddr(), actualReadLen);
257 
258  if (fileStatus != Os::File::OP_OK) {
259  this->log_WARNING_HI_FileReadError(readStage, this->m_sequenceFilePath, static_cast<I32>(fileStatus));
260  return Fw::Success::FAILURE;
261  }
262 
263  if (actualReadLen < expectedReadLen) {
264  this->log_WARNING_HI_EndOfFileError(readStage, this->m_sequenceFilePath);
265  return Fw::Success::FAILURE;
266  }
267 
268  // should probably fail if we read in MORE bytes than we ask for
269  FW_ASSERT(expectedReadLen == actualReadLen, static_cast<FwAssertArgType>(expectedReadLen),
270  static_cast<FwAssertArgType>(actualReadLen));
271 
272  Fw::SerializeStatus serializeStatus =
273  this->m_sequenceBuffer.setBuffLen(static_cast<Fw::Serializable::SizeType>(expectedReadLen));
274  FW_ASSERT(serializeStatus == Fw::FW_SERIALIZE_OK, serializeStatus);
275 
276  if (updateCrc) {
277  this->m_computedCRC.update(this->m_sequenceBuffer.getBuffAddr(), expectedReadLen);
278  }
279 
280  return Fw::Success::SUCCESS;
281 }
282 
283 } // namespace Svc
void update(const void *const data, const FwSizeType len)
Definition: HashImpl.cpp:34
Serialization/Deserialization operation was successful.
void clear()
Clear external buffer.
virtual void * allocate(const FwEnumStoreType identifier, FwSizeType &size, bool &recoverable, FwSizeType alignment=alignof(std::max_align_t))=0
Operation succeeded.
Definition: Os.hpp:27
U16 get_statementCount() const
Get member statementCount.
Type_of_args & get_args()
Get member args.
Representing success.
void log_WARNING_HI_InsufficientBufferSpace(U64 bufferSize, const Fw::StringBase &filePath) const
Log event InsufficientBufferSpace.
PlatformSizeType FwSizeType
I32 FwEnumStoreType
void log_WARNING_HI_WrongCRC(U32 expected, U32 actual) const
Log event WrongCRC.
void log_WARNING_HI_ArgSizeExceedsCapacity(FwSizeType actual, FwSizeType capacity) const
Log event ArgSizeExceedsCapacity.
Serializable::SizeType getSize() const override
Get current buffer size.
Status position(FwSizeType &position_result) override
get file pointer position of the currently open file
Definition: File.cpp:120
SerializeStatus deserializeTo(U8 &val, Endianness mode=Endianness::BIG) override
Deserialize an 8-bit unsigned integer value.
Status size(FwSizeType &size_result) override
get size of currently open file
Definition: File.cpp:111
void log_WARNING_HI_FileApiError(const Fw::StringBase &filePath, I32 errorCode) const
Log event FileApiError.
void log_WARNING_HI_ExtraBytesInSequence(FwSizeType remaining) const
Log event ExtraBytesInSequence.
Serializable::SizeType getCapacity() const override
Get buffer capacity.
void log_WARNING_HI_TooManySequenceDirectives(U16 count, U16 max) const
Log event TooManySequenceDirectives.
void init()
Definition: HashImpl.cpp:30
SerializeStatus
forward declaration for string
Os::FileInterface::Status open(const char *path, Mode mode)
open file with supplied path and mode
Definition: File.cpp:50
void log_WARNING_HI_EndOfFileError(const Svc::FpySequencer_FileReadStage &readStage, const Fw::StringBase &filePath) const
Log event EndOfFileError.
U8 get_schemaVersion() const
Get member schemaVersion.
U8 * getBuffAddr()
Get buffer address for data filling (non-const version)
Svc::Fpy::Header & get_header()
Get member header.
Invalid argument passed in.
Definition: File.hpp:51
Type_of_buffer & get_buffer()
Get member buffer.
Serializable::SizeType getDeserializeSizeLeft() const override
Get remaining deserialization buffer size.
void log_WARNING_HI_FileReadError(const Svc::FpySequencer_FileReadStage &readStage, const Fw::StringBase &filePath, I32 errorCode) const
Log event FileReadError.
U32 get_bodySize() const
Get member bodySize.
Type_of_statements & get_statements()
Get member statements.
void allocateBuffer(FwEnumStoreType identifier, Fw::MemAllocator &allocator, FwSizeType bytes)
const char * toChar() const
Convert to a C-style char*.
FwSizeType get_size() const
Get member size.
Representing failure.
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:54
SerializeStatus setBuffLen(Serializable::SizeType length) override
Set buffer length manually.
Status read(U8 *buffer, FwSizeType &size)
read data from this file into supplied buffer bounded by size
Definition: File.cpp:194
void log_WARNING_HI_FileOpenError(const Fw::StringBase &filePath, I32 errorCode) const
Log event FileOpenError.
void setExtBuffer(U8 *buffPtr, Serializable::SizeType size)
Set the external buffer.
Memory Allocation base class.
Svc::Fpy::Footer & get_footer()
Get member footer.
Operation was successful.
Definition: File.hpp:42
void log_WARNING_HI_ArgTotalSizeExceedsStackLimit(Svc::Fpy::StackSizeType argSize) const
Log event ArgTotalSizeExceedsStackLimit.
Open file for reading.
Definition: File.hpp:33
U8 get_argumentCount() const
Get member argumentCount.
void log_WARNING_HI_WrongSchemaVersion(U8 expected, U8 actual) const
Log event WrongSchemaVersion.
RateGroupDivider component implementation.
virtual SizeType length() const
Get the length of the string.
void log_WARNING_HI_TooManySequenceArgs(U8 count, U8 max) const
Log event TooManySequenceArgs.
void log_WARNING_HI_ArgSizeMismatch(Svc::Fpy::StackSizeType expected, FwSizeType actual, const Fw::StringBase &filePath) const
Log event ArgSizeMismatch.
virtual void deallocate(const FwEnumStoreType identifier, void *ptr)=0
void deallocateBuffer(Fw::MemAllocator &allocator)
void log_WARNING_HI_FileReadDeserializeError(const Svc::FpySequencer_FileReadStage &readStage, const Fw::StringBase &filePath, I32 errorCode, U64 buffLeft, U64 buffLength) const
Log event FileReadDeserializeError.
void finalize(HashBuffer &buffer) const
Definition: HashImpl.cpp:40
#define FW_ASSERT(...)
Definition: Assert.hpp:14
Success/Failure.
bool isOpen() const
determine if the file is open
Definition: File.cpp:105
The size of the serial representation.