Skip to content
This repository has been archived by the owner on May 19, 2022. It is now read-only.

Commit

Permalink
Handle SDR validation via exceptions. #18
Browse files Browse the repository at this point in the history
  • Loading branch information
jtikalsky committed Nov 15, 2018
1 parent 6853100 commit f3a5c26
Show file tree
Hide file tree
Showing 18 changed files with 134 additions and 131 deletions.
10 changes: 5 additions & 5 deletions Vivado/ipmc_zynq_vivado.sdk/common/uw-ipmc/libs/except.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
#include <stdexcept>
#include <string>

// Global custom exceptions
#define DEFINE_GENERIC_EXCEPTION(name, base) \
namespace except { \
#define DEFINE_LOCAL_GENERIC_EXCEPTION(name, base) \
class name : public base { \
public: \
explicit name(const std::string& what_arg) : base(what_arg) { }; \
explicit name(const char* what_arg) : base(what_arg) { }; \
}; \
}
};

#define DEFINE_GENERIC_EXCEPTION(name, base) \
namespace except { DEFINE_LOCAL_GENERIC_EXCEPTION(name, base) }

DEFINE_GENERIC_EXCEPTION(hardware_error, std::runtime_error)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,12 @@
* the record. It only tests if the data is well-formed for the
* SensorDataRecord subclass it is being interpreted by. It may not be valid
* with any other parser.
*
* \warning Do not call any accessors on a record that is not valid.
*
* @return true if the record is well-formed, else false
*/
bool SensorDataRecord::validate() const {
void SensorDataRecord::validate() const {
if (this->sdr_data.size() < 5)
return false;
throw invalid_sdr_error("This SDR is shorter than the required headers.");
if (this->sdr_data.size() < (5U + this->sdr_data[4]))
return false;
return true;
throw invalid_sdr_error("This SDR is shorter than specified in the header");
}

/**
Expand Down Expand Up @@ -58,28 +53,38 @@ std::shared_ptr<SensorDataRecord> SensorDataRecord::interpret(const std::vector<
*/
rec = NULL;
}
if (rec && !rec->validate())
return NULL;
if (rec) {
try {
rec->validate();
}
catch (invalid_sdr_error &e) {
return NULL;
}
}
return std::shared_ptr<SensorDataRecord>(rec);
}

uint16_t SensorDataRecord::record_id() const {
configASSERT(this->sdr_data.size() >= 2);
if (this->sdr_data.size() < 2)
throw invalid_sdr_error("Truncated SDR");
return (this->sdr_data[0] << 8) | this->sdr_data[1];
}

void SensorDataRecord::record_id(uint16_t record_id) {
configASSERT(this->sdr_data.size() >= 2);
if (this->sdr_data.size() < 2)
throw invalid_sdr_error("Truncated SDR");
this->sdr_data[0] = record_id >> 8;
this->sdr_data[1] = record_id & 0xff;
}

uint8_t SensorDataRecord::record_version() const {
configASSERT(this->sdr_data.size() >= 3);
if (this->sdr_data.size() < 3)
throw invalid_sdr_error("Truncated SDR");
return this->sdr_data[2];
}

uint8_t SensorDataRecord::record_type() const {
configASSERT(this->sdr_data.size() >= 4);
if (this->sdr_data.size() < 4)
throw invalid_sdr_error("Truncated SDR");
return this->sdr_data[3];
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <vector>
#include <stdint.h>
#include <memory>
#include <libs/except.h>

/**
* A minimal class implementing the most basic level of SDR(ecord) support,
Expand All @@ -29,7 +30,9 @@ class SensorDataRecord {
SensorDataRecord(const std::vector<uint8_t> &sdr_data = std::vector<uint8_t>()) : sdr_data(sdr_data) { };
virtual ~SensorDataRecord() { };

virtual bool validate() const;
DEFINE_LOCAL_GENERIC_EXCEPTION(invalid_sdr_error, std::runtime_error)

virtual void validate() const;
/**
* @return the Record Type supported by the current handler subclass.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@
#include <IPMC.h>
#include <math.h>

bool SensorDataRecord01::validate() const {
if (!SensorDataRecordReadableSensor::validate())
return false;
void SensorDataRecord01::validate() const {
SensorDataRecordReadableSensor::validate();
if (this->record_type() != 0x01)
return false;
return true;
throw invalid_sdr_error("SensorDataRecord01 supports only type 01h SDRs.");
}

/// Create a bitmask with the lower `nbits` bits set.
Expand All @@ -23,12 +21,13 @@ bool SensorDataRecord01::validate() const {
/// Define a `type` type SDR_FIELD from byte `byte`[a:b].
#define SDR_FIELD(name, type, byte, a, b, attributes) \
type SensorDataRecord01::name() const attributes { \
configASSERT(this->validate()); \
this->validate(); \
return static_cast<type>((this->sdr_data[byte] >> (b)) & LOWBITS((a)-(b)+1)); \
} \
void SensorDataRecord01::name(type val) attributes { \
configASSERT((static_cast<uint8_t>(val) & LOWBITS((a)-(b)+1)) == static_cast<uint8_t>(val)); \
configASSERT(this->validate()); \
if ((static_cast<uint8_t>(val) & LOWBITS((a)-(b)+1)) != static_cast<uint8_t>(val)) \
throw std::domain_error("The supplied value does not fit correctly in the field."); \
this->validate(); \
this->sdr_data[byte] &= ~(LOWBITS((a)-(b)+1)<<(b)); /* Erase old value */ \
this->sdr_data[byte] |= static_cast<uint8_t>(val)<<(b); /* Set new value */ \
}
Expand All @@ -38,12 +37,13 @@ SDR_FIELD(units_numeric_format, enum SensorDataRecord01::UnitsNumericFormat, 20,
SDR_FIELD(linearization, enum SensorDataRecord01::Linearization, 23, 7, 0, )

uint16_t SensorDataRecord01::conversion_m() const {
configASSERT(this->validate());
this->validate();
return this->sdr_data[24] | ((this->sdr_data[25]&0xc0)<<2);
}
void SensorDataRecord01::conversion_m(uint16_t val) {
configASSERT((val & 0x3ff) == val);
configASSERT(this->validate());
if ((val & 0x3ff) != val)
throw std::domain_error("The supplied value does not fit correctly in the field.");
this->validate();
this->sdr_data[24] = val & 0xff;
this->sdr_data[25] &= ~0xc0;
this->sdr_data[25] |= val >> 8;
Expand All @@ -52,24 +52,26 @@ void SensorDataRecord01::conversion_m(uint16_t val) {
SDR_FIELD(conversion_m_tolerance, uint8_t, 25, 5, 0, ) // Unit: +/- half raw counts

uint16_t SensorDataRecord01::conversion_b() const {
configASSERT(this->validate());
this->validate();
return this->sdr_data[26] | ((this->sdr_data[27]&0xc0)<<2);
}
void SensorDataRecord01::conversion_b(uint16_t val) {
configASSERT((val & 0x3ff) == val);
configASSERT(this->validate());
if ((val & 0x3ff) != val)
throw std::domain_error("The supplied value does not fit correctly in the field.");
this->validate();
this->sdr_data[26] = val & 0xff;
this->sdr_data[27] &= ~0xc0;
this->sdr_data[27] |= val >> 8;
}

uint16_t SensorDataRecord01::conversion_b_accuracy() const {
configASSERT(this->validate());
this->validate();
return (this->sdr_data[27] & 0x3f) | ((this->sdr_data[28]&0xf0)<<2);
}
void SensorDataRecord01::conversion_b_accuracy(uint16_t val) {
configASSERT((val & 0x3ff) == val);
configASSERT(this->validate());
if ((val & 0x3ff) != val)
throw std::domain_error("The supplied value does not fit correctly in the field.");
this->validate();
this->sdr_data[27] &= ~0x3f;
this->sdr_data[27] |= val & 0x3f;
this->sdr_data[28] &= ~0xf0;
Expand All @@ -81,30 +83,32 @@ SDR_FIELD(conversion_b_accuracy_exp, uint8_t, 28, 3, 2, )
SDR_FIELD(sensor_direction, enum SensorDataRecordReadableSensor::Direction, 28, 1, 0, )

int8_t SensorDataRecord01::conversion_r_exp() const {
configASSERT(this->validate());
this->validate();
uint8_t val = this->sdr_data[29] >> 4;
if (val & 0x08)
val |= 0xf0; // Extend the 1 sign to 8 bits. (2s complement)
return *reinterpret_cast<int8_t*>(&val);
}
void SensorDataRecord01::conversion_r_exp(int8_t val) {
uint8_t uval = *reinterpret_cast<uint8_t*>(&val);
configASSERT((uval&0xf0) == 0 || (uval&0xf0) == 0xf0);
configASSERT(this->validate());
if (!((uval&0xf0) == 0 || (uval&0xf0) == 0xf0))
throw std::domain_error("The supplied value does not fit correctly in the field.");
this->validate();
this->sdr_data[29] = (uval<<4) | (this->sdr_data[29] & 0x0f);
}

int8_t SensorDataRecord01::conversion_b_exp() const {
configASSERT(this->validate());
this->validate();
uint8_t val = this->sdr_data[29] & 0x0f;
if (val & 0x08)
val |= 0xf0; // Extend the 1 sign to 8 bits. (2s complement)
return *reinterpret_cast<int8_t*>(&val);
}
void SensorDataRecord01::conversion_b_exp(int8_t val) {
uint8_t uval = *reinterpret_cast<uint8_t*>(&val);
configASSERT((uval&0xf0) == 0 || (uval&0xf0) == 0xf0);
configASSERT(this->validate());
if (!((uval&0xf0) == 0 || (uval&0xf0) == 0xf0))
throw std::domain_error("The supplied value does not fit correctly in the field.");
this->validate();
this->sdr_data[29] = (this->sdr_data[29] & 0xf0) | uval;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class SensorDataRecord01 : public SensorDataRecordReadableSensor {
/// Instantiate a Type 01 SensorDataRecord
SensorDataRecord01(const std::vector<uint8_t> &sdr_data = std::vector<uint8_t>()) : SensorDataRecordSensor(sdr_data), SensorDataRecordReadableSensor(sdr_data) { };
virtual ~SensorDataRecord01() { };
virtual bool validate() const;
virtual void validate() const;
virtual uint8_t parsed_record_type() const { return 0x01; };

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,11 @@
#include <services/ipmi/sdr/SensorDataRecord02.h>
#include <IPMC.h>

bool SensorDataRecord02::validate() const {
if (!SensorDataRecordReadableSensor::validate())
return false;
if (!SensorDataRecordSharedSensor::validate())
return false;
void SensorDataRecord02::validate() const {
SensorDataRecordReadableSensor::validate();
SensorDataRecordSharedSensor::validate();
if (this->record_type() != 0x02)
return false;
return true;
throw invalid_sdr_error("SensorDataRecord02 supports only type 02h SDRs.");
}

void SensorDataRecord02::initialize_blank(std::string name) {
Expand All @@ -30,12 +27,13 @@ void SensorDataRecord02::initialize_blank(std::string name) {
/// Define a `type` type SDR_FIELD from byte `byte`[a:b].
#define SDR_FIELD(name, type, byte, a, b, attributes) \
type SensorDataRecord02::name() const attributes { \
configASSERT(this->validate()); \
this->validate(); \
return static_cast<type>((this->sdr_data[byte] >> (b)) & LOWBITS((a)-(b)+1)); \
} \
void SensorDataRecord02::name(type val) attributes { \
configASSERT((static_cast<uint8_t>(val) & LOWBITS((a)-(b)+1)) == static_cast<uint8_t>(val)); \
configASSERT(this->validate()); \
if ((static_cast<uint8_t>(val) & LOWBITS((a)-(b)+1)) != static_cast<uint8_t>(val)) \
throw std::domain_error("The supplied value does not fit correctly in the field."); \
this->validate(); \
this->sdr_data[byte] &= ~(LOWBITS((a)-(b)+1)<<(b)); /* Erase old value */ \
this->sdr_data[byte] |= static_cast<uint8_t>(val)<<(b); /* Set new value */ \
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class SensorDataRecord02 : public SensorDataRecordReadableSensor, SensorDataReco
/// Instantiate a Type 02 SensorDataRecord
SensorDataRecord02(const std::vector<uint8_t> &sdr_data = std::vector<uint8_t>()) : SensorDataRecordSensor(sdr_data), SensorDataRecordReadableSensor(sdr_data), SensorDataRecordSharedSensor(sdr_data) { };
virtual ~SensorDataRecord02() { };
virtual bool validate() const;
virtual void validate() const;
virtual uint8_t parsed_record_type() const { return 0x02; };
virtual void initialize_blank(std::string name);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@
#include <services/ipmi/sdr/SensorDataRecord03.h>
#include <IPMC.h>

bool SensorDataRecord03::validate() const {
if (!SensorDataRecordSharedSensor::validate())
return false;
void SensorDataRecord03::validate() const {
SensorDataRecordSharedSensor::validate();
if (this->record_type() != 0x03)
return false;
return true;
throw invalid_sdr_error("SensorDataRecord03 supports only type 03h SDRs.");
}

/// Create a bitmask with the lower `nbits` bits set.
Expand All @@ -22,12 +20,13 @@ bool SensorDataRecord03::validate() const {
/// Define a `type` type SDR_FIELD from byte `byte`[a:b].
#define SDR_FIELD(name, type, byte, a, b, attributes) \
type SensorDataRecord03::name() const attributes { \
configASSERT(this->validate()); \
this->validate(); \
return static_cast<type>((this->sdr_data[byte] >> (b)) & LOWBITS((a)-(b)+1)); \
} \
void SensorDataRecord03::name(type val) attributes { \
configASSERT((static_cast<uint8_t>(val) & LOWBITS((a)-(b)+1)) == static_cast<uint8_t>(val)); \
configASSERT(this->validate()); \
if ((static_cast<uint8_t>(val) & LOWBITS((a)-(b)+1)) != static_cast<uint8_t>(val)) \
throw std::domain_error("The supplied value does not fit correctly in the field."); \
this->validate(); \
this->sdr_data[byte] &= ~(LOWBITS((a)-(b)+1)<<(b)); /* Erase old value */ \
this->sdr_data[byte] |= static_cast<uint8_t>(val)<<(b); /* Set new value */ \
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class SensorDataRecord03 : public SensorDataRecordSharedSensor {
/// Instantiate a Type 02 SensorDataRecord
SensorDataRecord03(const std::vector<uint8_t> &sdr_data = std::vector<uint8_t>()) : SensorDataRecordSensor(sdr_data), SensorDataRecordSharedSensor(sdr_data) { };
virtual ~SensorDataRecord03() { };
virtual bool validate() const;
virtual void validate() const;
virtual uint8_t parsed_record_type() const { return 0x03; };

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,27 @@
#include <iterator>

std::vector<uint8_t> SensorDataRecord12::record_key() const {
configASSERT(this->validate());
this->validate();
return std::vector<uint8_t>(std::next(this->sdr_data.begin(), 5), std::next(this->sdr_data.begin(), 8));
}

bool SensorDataRecord12::validate() const {
if (!SensorDataRecord::validate())
return false;
void SensorDataRecord12::validate() const {
SensorDataRecord::validate();
if (this->record_type() != 0x12)
return false;
throw invalid_sdr_error("SensorDataRecord12 supports only type 12h SDRs.");
// Check that the ID field's Type/Length specification is valid.
if (this->sdr_data.size() < 16 +1U /* One byte of ID content */ +1U /* Change offset of last, to size of container */)
return false;
throw invalid_sdr_error("Truncated SDR");
unsigned idlen = ipmi_type_length_field_get_length(std::vector<uint8_t>(std::next(this->sdr_data.begin(), 16), this->sdr_data.end()));
if (idlen > 17) // IDString TypeLengthCode (= 1) + IDString Bytes (<= 16)
return false;
throw invalid_sdr_error("Invalid ID string");
if (16+idlen < this->sdr_data.size())
return false;
return true;
throw invalid_sdr_error("Truncated ID string");
}

void SensorDataRecord12::initialize_blank(std::string name) {
configASSERT(name.size() <= 16); // Specification limit
if (name.size() > 16) // Specification limit
throw std::domain_error("Sensor names must be <= 16 characters.");
this->sdr_data.resize(0); // Clear
this->sdr_data.resize(16, 0); // Initialize Blank Fields
this->sdr_data.push_back(0xC0 | name.size()); // Type/Length code: Raw ASCII/Unicode, with length.
Expand All @@ -42,12 +41,13 @@ void SensorDataRecord12::initialize_blank(std::string name) {
/// Define a `type` type SDR_FIELD from byte `byte`[a:b].
#define SDR_FIELD(name, type, byte, a, b, attributes) \
type SensorDataRecord12::name() const attributes { \
configASSERT(this->validate()); \
this->validate(); \
return static_cast<type>((this->sdr_data[byte] >> (b)) & LOWBITS((a)-(b)+1)); \
} \
void SensorDataRecord12::name(type val) attributes { \
configASSERT((static_cast<uint8_t>(val) & LOWBITS((a)-(b)+1)) == static_cast<uint8_t>(val)); \
configASSERT(this->validate()); \
if ((static_cast<uint8_t>(val) & LOWBITS((a)-(b)+1)) != static_cast<uint8_t>(val)) \
throw std::domain_error("The supplied value does not fit correctly in the field."); \
this->validate(); \
this->sdr_data[byte] &= ~(LOWBITS((a)-(b)+1)<<(b)); /* Erase old value */ \
this->sdr_data[byte] |= static_cast<uint8_t>(val)<<(b); /* Set new value */ \
}
Expand Down Expand Up @@ -77,12 +77,13 @@ SDR_FIELD(entity_instance, uint8_t, 13, 7, 0, )
SDR_FIELD(oem, uint8_t, 14, 7, 0, )

std::string SensorDataRecord12::id_string() const {
configASSERT(this->validate());
this->validate();
return render_ipmi_type_length_field(std::vector<uint8_t>(std::next(this->sdr_data.begin(), 16), this->sdr_data.end()));
}
void SensorDataRecord12::id_string(std::string val) {
configASSERT(this->validate());
configASSERT(val.size() <= 16); // Specified.
this->validate();
if (val.size() > 16) // Specified.
throw std::domain_error("Sensor names must be <= 16 characters.");
this->sdr_data.resize(16); // Downsize.
this->sdr_data.push_back(0xC0 | val.size()); // Type/Length code: Raw ASCII/Unicode, with length.
for (auto it = val.begin(), eit = val.end(); it != eit; ++it)
Expand Down
Loading

0 comments on commit f3a5c26

Please sign in to comment.