Commit ce7728b0 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[2490] Moved OptionDefinition::DataType enum to common header.

parent 648f693c
......@@ -257,20 +257,20 @@ LibDHCP::initStdOptionDefs6() {
struct OptionParams {
std::string name;
uint16_t code;
OptionDefinition::DataType type;
OptionDataType type;
bool array;
};
OptionParams params[] = {
{ "CLIENTID", D6O_CLIENTID, OptionDefinition::BINARY_TYPE, false },
{ "SERVERID", D6O_SERVERID, OptionDefinition::BINARY_TYPE, false },
{ "IA_NA", D6O_IA_NA, OptionDefinition::RECORD_TYPE, false },
{ "IAADDR", D6O_IAADDR, OptionDefinition::RECORD_TYPE, false },
{ "ORO", D6O_ORO, OptionDefinition::UINT16_TYPE, true },
{ "ELAPSED_TIME", D6O_ELAPSED_TIME, OptionDefinition::UINT16_TYPE, false },
{ "STATUS_CODE", D6O_STATUS_CODE, OptionDefinition::RECORD_TYPE, false },
{ "RAPID_COMMIT", D6O_RAPID_COMMIT, OptionDefinition::EMPTY_TYPE, false },
{ "DNS_SERVERS", D6O_NAME_SERVERS, OptionDefinition::IPV6_ADDRESS_TYPE, true },
{ "IA_PD", D6O_IA_PD, OptionDefinition::RECORD_TYPE, false }
{ "CLIENTID", D6O_CLIENTID, OPT_BINARY_TYPE, false },
{ "SERVERID", D6O_SERVERID, OPT_BINARY_TYPE, false },
{ "IA_NA", D6O_IA_NA, OPT_RECORD_TYPE, false },
{ "IAADDR", D6O_IAADDR, OPT_RECORD_TYPE, false },
{ "ORO", D6O_ORO, OPT_UINT16_TYPE, true },
{ "ELAPSED_TIME", D6O_ELAPSED_TIME, OPT_UINT16_TYPE, false },
{ "STATUS_CODE", D6O_STATUS_CODE, OPT_RECORD_TYPE, false },
{ "RAPID_COMMIT", D6O_RAPID_COMMIT, OPT_EMPTY_TYPE, false },
{ "DNS_SERVERS", D6O_NAME_SERVERS, OPT_IPV6_ADDRESS_TYPE, true },
{ "IA_PD", D6O_IA_PD, OPT_RECORD_TYPE, false }
};
const int params_size = sizeof(params) / sizeof(params[0]);
......@@ -283,17 +283,17 @@ LibDHCP::initStdOptionDefs6() {
case D6O_IA_NA:
case D6O_IA_PD:
for (int j = 0; j < 3; ++j) {
definition->addRecordField(OptionDefinition::UINT32_TYPE);
definition->addRecordField(OPT_UINT32_TYPE);
}
break;
case D6O_IAADDR:
definition->addRecordField(OptionDefinition::IPV6_ADDRESS_TYPE);
definition->addRecordField(OptionDefinition::UINT32_TYPE);
definition->addRecordField(OptionDefinition::UINT32_TYPE);
definition->addRecordField(OPT_IPV6_ADDRESS_TYPE);
definition->addRecordField(OPT_UINT32_TYPE);
definition->addRecordField(OPT_UINT32_TYPE);
break;
case D6O_STATUS_CODE:
definition->addRecordField(OptionDefinition::UINT16_TYPE);
definition->addRecordField(OptionDefinition::STRING_TYPE);
definition->addRecordField(OPT_UINT16_TYPE);
definition->addRecordField(OPT_STRING_TYPE);
break;
default:
// The default case is intentionally left empty
......
......@@ -48,7 +48,7 @@ public:
/// as template parameter is not a supported integer type.
Option6Int(uint16_t type, T value)
: Option(Option::V6, type), value_(value) {
if (!OptionDataTypes<T>::valid) {
if (!OptionDataTypeTraits<T>::integer_type) {
isc_throw(dhcp::InvalidDataType, "non-integer type");
}
}
......@@ -69,7 +69,7 @@ public:
Option6Int(uint16_t type, OptionBufferConstIter begin,
OptionBufferConstIter end)
: Option(Option::V6, type) {
if (!OptionDataTypes<T>::valid) {
if (!OptionDataTypeTraits<T>::integer_type) {
isc_throw(dhcp::InvalidDataType, "non-integer type");
}
unpack(begin, end);
......@@ -91,7 +91,7 @@ public:
// order to the provided buffer. The same functions can be safely used
// for either unsiged or signed integers so there is not need to create
// special cases for intX_t types.
switch (OptionDataTypes<T>::len) {
switch (OptionDataTypeTraits<T>::len) {
case 1:
buf.writeUint8(value_);
break;
......@@ -130,7 +130,7 @@ public:
// order from the provided buffer. The same functions can be safely used
// for either unsiged or signed integers so there is not need to create
// special cases for intX_t types.
int data_size_len = OptionDataTypes<T>::len;
int data_size_len = OptionDataTypeTraits<T>::len;
switch (data_size_len) {
case 1:
value_ = *begin;
......@@ -145,9 +145,9 @@ public:
isc_throw(dhcp::InvalidDataType, "non-integer type");
}
// Use local variable to set a new value for this iterator.
// When using OptionDataTypes<T>::len directly some versions
// When using OptionDataTypeTraits<T>::len directly some versions
// of clang complain about unresolved reference to
// OptionDataTypes structure during linking.
// OptionDataTypeTraits structure during linking.
begin += data_size_len;
LibDHCP::unpackOptions6(OptionBuffer(begin, end), options_);
}
......
......@@ -58,7 +58,7 @@ public:
Option6IntArray(uint16_t type)
: Option(Option::V6, type),
values_(0) {
if (!OptionDataTypes<T>::valid) {
if (!OptionDataTypeTraits<T>::integer_type) {
isc_throw(dhcp::InvalidDataType, "non-integer type");
}
}
......@@ -74,7 +74,7 @@ public:
/// as template parameter is not a supported integer type.
Option6IntArray(uint16_t type, const OptionBuffer& buf)
: Option(Option::V6, type) {
if (!OptionDataTypes<T>::valid) {
if (!OptionDataTypeTraits<T>::integer_type) {
isc_throw(dhcp::InvalidDataType, "non-integer type");
}
unpack(buf.begin(), buf.end());
......@@ -97,7 +97,7 @@ public:
Option6IntArray(uint16_t type, OptionBufferConstIter begin,
OptionBufferConstIter end)
: Option(Option::V6, type) {
if (!OptionDataTypes<T>::valid) {
if (!OptionDataTypeTraits<T>::integer_type) {
isc_throw(dhcp::InvalidDataType, "non-integer type");
}
unpack(begin, end);
......@@ -120,7 +120,7 @@ public:
// order to the provided buffer. The same functions can be safely used
// for either unsiged or signed integers so there is not need to create
// special cases for intX_t types.
switch (OptionDataTypes<T>::len) {
switch (OptionDataTypeTraits<T>::len) {
case 1:
buf.writeUint8(values_[i]);
break;
......@@ -166,7 +166,7 @@ public:
// order from the provided buffer. The same functions can be safely used
// for either unsiged or signed integers so there is not need to create
// special cases for intX_t types.
int data_size_len = OptionDataTypes<T>::len;
int data_size_len = OptionDataTypeTraits<T>::len;
switch (data_size_len) {
case 1:
values_.push_back(*begin);
......@@ -181,9 +181,9 @@ public:
isc_throw(dhcp::InvalidDataType, "non-integer type");
}
// Use local variable to set a new value for this iterator.
// When using OptionDataTypes<T>::len directly some versions
// When using OptionDataTypeTraits<T>::len directly some versions
// of clang complain about unresolved reference to
// OptionDataTypes structure during linking.
// OptionDataTypeTraits structure during linking.
begin += data_size_len;
}
// We do not unpack sub-options here because we have array-type option.
......
......@@ -15,6 +15,7 @@
#ifndef OPTION_DATA_TYPES_H
#define OPTION_DATA_TYPES_H
#include <asiolink/io_address.h>
#include <exceptions/exceptions.h>
#include <stdint.h>
......@@ -29,59 +30,129 @@ public:
isc::Exception(file, line, what) { };
};
/// @brief Trait class for integer data types supported in DHCP option definitions.
/// @brief Data types of DHCP option fields.
enum OptionDataType {
OPT_EMPTY_TYPE,
OPT_BINARY_TYPE,
OPT_BOOLEAN_TYPE,
OPT_INT8_TYPE,
OPT_INT16_TYPE,
OPT_INT32_TYPE,
OPT_UINT8_TYPE,
OPT_UINT16_TYPE,
OPT_UINT32_TYPE,
OPT_ANY_ADDRESS_TYPE,
OPT_IPV4_ADDRESS_TYPE,
OPT_IPV6_ADDRESS_TYPE,
OPT_STRING_TYPE,
OPT_FQDN_TYPE,
OPT_RECORD_TYPE,
OPT_UNKNOWN_TYPE
};
/// @brief Trait class for data types supported in DHCP option definitions.
///
/// This is useful to check whether the type specified as template parameter
/// is supported by classes like Option6Int, Option6IntArray and some template
/// factory functions in OptionDefinition class.
template<typename T>
struct OptionDataTypes {
struct OptionDataTypeTraits {
static const bool valid = false;
static const int len = 0;
static const bool integer_type = false;
static const OptionDataType type = OPT_UNKNOWN_TYPE;
};
/// binary type is supported
template<>
struct OptionDataTypeTraits<OptionBuffer> {
static const bool valid = true;
static const int len = sizeof(OptionBuffer);
static const bool integer_type = false;
static const OptionDataType type = OPT_BINARY_TYPE;
};
/// bool type is supported
template<>
struct OptionDataTypeTraits<bool> {
static const bool valid = true;
static const int len = sizeof(bool);
static const bool integer_type = false;
static const OptionDataType type = OPT_BOOLEAN_TYPE;
};
/// int8_t type is supported.
template<>
struct OptionDataTypes<int8_t> {
struct OptionDataTypeTraits<int8_t> {
static const bool valid = true;
static const int len = 1;
static const bool integer_type = true;
static const OptionDataType type = OPT_INT8_TYPE;
};
/// int16_t type is supported.
template<>
struct OptionDataTypes<int16_t> {
struct OptionDataTypeTraits<int16_t> {
static const bool valid = true;
static const int len = 2;
static const bool integer_type = true;
static const OptionDataType type = OPT_INT16_TYPE;
};
/// int32_t type is supported.
template<>
struct OptionDataTypes<int32_t> {
struct OptionDataTypeTraits<int32_t> {
static const bool valid = true;
static const int len = 4;
static const bool integer_type = true;
static const OptionDataType type = OPT_INT32_TYPE;
};
/// uint8_t type is supported.
template<>
struct OptionDataTypes<uint8_t> {
struct OptionDataTypeTraits<uint8_t> {
static const bool valid = true;
static const int len = 1;
static const bool integer_type = true;
static const OptionDataType type = OPT_UINT8_TYPE;
};
/// uint16_t type is supported.
template<>
struct OptionDataTypes<uint16_t> {
struct OptionDataTypeTraits<uint16_t> {
static const bool valid = true;
static const int len = 2;
static const bool integer_type = true;
static const OptionDataType type = OPT_UINT16_TYPE;
};
/// uint32_t type is supported.
template<>
struct OptionDataTypes<uint32_t> {
struct OptionDataTypeTraits<uint32_t> {
static const bool valid = true;
static const int len = 4;
static const bool integer_type = true;
static const OptionDataType type = OPT_UINT32_TYPE;
};
/// IPv4 and IPv6 address type is supported
template<>
struct OptionDataTypeTraits<asiolink::IOAddress> {
static const bool valid = true;
static const int len = sizeof(asiolink::IOAddress);
static const bool integer_type = false;
static const OptionDataType type = OPT_ANY_ADDRESS_TYPE;
};
/// string type is supported
template<>
struct OptionDataTypeTraits<std::string> {
static const bool valid = true;
static const int len = sizeof(std::string);
static const bool integer_type = false;
static const OptionDataType type = OPT_STRING_TYPE;
};
} // isc::dhcp namespace
} // isc namespace
......
......@@ -28,30 +28,35 @@ namespace isc {
namespace dhcp {
OptionDefinition::DataTypeUtil::DataTypeUtil() {
data_types_["empty"] = EMPTY_TYPE;
data_types_["binary"] = BINARY_TYPE;
data_types_["boolean"] = BOOLEAN_TYPE;
data_types_["int8"] = INT8_TYPE;
data_types_["int16"] = INT16_TYPE;
data_types_["int32"] = INT32_TYPE;
data_types_["uint8"] = UINT8_TYPE;
data_types_["uint16"] = UINT16_TYPE;
data_types_["uint32"] = UINT32_TYPE;
data_types_["ipv4-address"] = IPV4_ADDRESS_TYPE;
data_types_["ipv6-address"] = IPV6_ADDRESS_TYPE;
data_types_["string"] = STRING_TYPE;
data_types_["fqdn"] = FQDN_TYPE;
data_types_["record"] = RECORD_TYPE;
data_types_["empty"] = OPT_EMPTY_TYPE;
data_types_["binary"] = OPT_BINARY_TYPE;
data_types_["boolean"] = OPT_BOOLEAN_TYPE;
data_types_["int8"] = OPT_INT8_TYPE;
data_types_["int16"] = OPT_INT16_TYPE;
data_types_["int32"] = OPT_INT32_TYPE;
data_types_["uint8"] = OPT_UINT8_TYPE;
data_types_["uint16"] = OPT_UINT16_TYPE;
data_types_["uint32"] = OPT_UINT32_TYPE;
data_types_["ipv4-address"] = OPT_IPV4_ADDRESS_TYPE;
data_types_["ipv6-address"] = OPT_IPV6_ADDRESS_TYPE;
data_types_["string"] = OPT_STRING_TYPE;
data_types_["fqdn"] = OPT_FQDN_TYPE;
data_types_["record"] = OPT_RECORD_TYPE;
}
OptionDefinition::DataType
OptionDefinition::DataTypeUtil::getDataType(const std::string& data_type) {
std::map<std::string, DataType>::const_iterator data_type_it =
template<typename T>
T OptionDefinition::DataTypeUtil::dataTypeCast(const std::string& value_str) const {
return (T());
}
OptionDataType
OptionDefinition::DataTypeUtil::getOptionDataType(const std::string& data_type) {
std::map<std::string, OptionDataType>::const_iterator data_type_it =
data_types_.find(data_type);
if (data_type_it != data_types_.end()) {
return (data_type_it->second);
}
return UNKNOWN_TYPE;
return (OPT_UNKNOWN_TYPE);
}
OptionDefinition::OptionDefinition(const std::string& name,
......@@ -60,17 +65,17 @@ OptionDefinition::OptionDefinition(const std::string& name,
const bool array_type /* = false */)
: name_(name),
code_(code),
type_(UNKNOWN_TYPE),
type_(OPT_UNKNOWN_TYPE),
array_type_(array_type) {
// Data type is held as enum value by this class.
// Use the provided option type string to get the
// corresponding enum value.
type_ = DataTypeUtil::instance().getDataType(type);
type_ = DataTypeUtil::instance().getOptionDataType(type);
}
OptionDefinition::OptionDefinition(const std::string& name,
const uint16_t code,
const DataType type,
const OptionDataType type,
const bool array_type /* = false */)
: name_(name),
code_(code),
......@@ -80,17 +85,17 @@ OptionDefinition::OptionDefinition(const std::string& name,
void
OptionDefinition::addRecordField(const std::string& data_type_name) {
DataType data_type = DataTypeUtil::instance().getDataType(data_type_name);
OptionDataType data_type = DataTypeUtil::instance().getOptionDataType(data_type_name);
addRecordField(data_type);
}
void
OptionDefinition::addRecordField(const DataType data_type) {
if (type_ != RECORD_TYPE) {
OptionDefinition::addRecordField(const OptionDataType data_type) {
if (type_ != OPT_RECORD_TYPE) {
isc_throw(isc::InvalidOperation, "'record' option type must be used"
" to add data fields to the record");
}
if (data_type >= UNKNOWN_TYPE) {
if (data_type >= OPT_UNKNOWN_TYPE) {
isc_throw(isc::BadValue, "attempted to add invalid data type to the record");
}
record_fields_.push_back(data_type);
......@@ -101,32 +106,32 @@ OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
OptionBufferConstIter begin,
OptionBufferConstIter end) const {
validate();
if (type_ == BINARY_TYPE) {
if (type_ == OPT_BINARY_TYPE) {
return (factoryGeneric(u, type, begin, end));
} else if (type_ == IPV6_ADDRESS_TYPE && array_type_) {
} else if (type_ == OPT_IPV6_ADDRESS_TYPE && array_type_) {
return (factoryAddrList6(u, type, begin, end));
} else if (type_ == IPV4_ADDRESS_TYPE && array_type_) {
} else if (type_ == OPT_IPV4_ADDRESS_TYPE && array_type_) {
return (factoryAddrList4(u, type, begin, end));
} else if (type_ == EMPTY_TYPE) {
} else if (type_ == OPT_EMPTY_TYPE) {
return (factoryEmpty(u, type, begin, end));
} else if (code_ == D6O_IA_NA && haveIA6Format()) {
return (factoryIA6(u, type, begin, end));
} else if (code_ == D6O_IAADDR && haveIAAddr6Format()) {
return (factoryIAAddr6(u, type, begin, end));
} else if (type_ == UINT8_TYPE) {
} else if (type_ == OPT_UINT8_TYPE) {
if (array_type_) {
return (factoryGeneric(u, type, begin, end));
} else {
return (factoryInteger<uint8_t>(u, type, begin, end));
}
} else if (type_ == UINT16_TYPE) {
} else if (type_ == OPT_UINT16_TYPE) {
if (array_type_) {
return (factoryIntegerArray<uint16_t>(u, type, begin, end));
} else {
return (factoryInteger<uint16_t>(u, type, begin, end));
}
} else if (type_ == UINT32_TYPE) {
} else if (type_ == OPT_UINT32_TYPE) {
if (array_type_) {
return (factoryIntegerArray<uint32_t>(u, type, begin, end));
} else {
......@@ -167,19 +172,19 @@ OptionDefinition::validate() const {
isc_throw(isc::BadValue, "option name must not contain spaces");
}
// Unsupported option types are not allowed.
if (type_ >= UNKNOWN_TYPE) {
if (type_ >= OPT_UNKNOWN_TYPE) {
isc_throw(isc::OutOfRange, "option type value " << type_
<< " is out of range");
}
}
bool
OptionDefinition::haveIAx6Format(OptionDefinition::DataType first_type) const {
return (haveType(RECORD_TYPE) &&
OptionDefinition::haveIAx6Format(OptionDataType first_type) const {
return (haveType(OPT_RECORD_TYPE) &&
record_fields_.size() == 3 &&
record_fields_[0] == first_type &&
record_fields_[1] == UINT32_TYPE &&
record_fields_[2] == UINT32_TYPE);
record_fields_[1] == OPT_UINT32_TYPE &&
record_fields_[2] == OPT_UINT32_TYPE);
}
bool
......@@ -190,12 +195,12 @@ OptionDefinition::haveIA6Format() const {
// arrays do not impose limitations on number of elements in
// the array while this limitation is needed for IA_NA - need
// exactly 3 elements.
return (haveIAx6Format(UINT32_TYPE));
return (haveIAx6Format(OPT_UINT32_TYPE));
}
bool
OptionDefinition::haveIAAddr6Format() const {
return (haveIAx6Format(IPV6_ADDRESS_TYPE));
return (haveIAx6Format(OPT_IPV6_ADDRESS_TYPE));
}
OptionPtr
......
......@@ -111,33 +111,14 @@ class Option6IntArray;
class OptionDefinition {
public:
/// Data types of DHCP option fields.
enum DataType {
EMPTY_TYPE,
BINARY_TYPE,
BOOLEAN_TYPE,
INT8_TYPE,
INT16_TYPE,
INT32_TYPE,
UINT8_TYPE,
UINT16_TYPE,
UINT32_TYPE,
IPV4_ADDRESS_TYPE,
IPV6_ADDRESS_TYPE,
STRING_TYPE,
FQDN_TYPE,
RECORD_TYPE,
UNKNOWN_TYPE
};
/// List of fields within the record.
typedef std::vector<DataType> RecordFieldsCollection;
typedef std::vector<OptionDataType> RecordFieldsCollection;
/// Const iterator for record data fields.
typedef std::vector<DataType>::const_iterator RecordFieldsConstIter;
typedef std::vector<OptionDataType>::const_iterator RecordFieldsConstIter;
private:
/// @brief Utility class for operations on DataTypes.
/// @brief Utility class for operations on OptionDataTypes.
///
/// This class is implemented as the singleton because the list of
/// supported data types need only be loaded only once into memory as it
......@@ -156,12 +137,15 @@ private:
return (instance);
}
template<typename T>
T dataTypeCast(const std::string& value_str) const;
/// @brief Convert type given as string value to option data type.
///
/// @param data_type_name data type string.
///
/// @return option data type.
DataType getDataType(const std::string& data_type_name);
OptionDataType getOptionDataType(const std::string& data_type_name);
private:
/// @brief Private constructor.
......@@ -174,7 +158,7 @@ private:
DataTypeUtil();
/// Map of data types, maps name of the type to enum value.
std::map<std::string, DataType> data_types_;
std::map<std::string, OptionDataType> data_types_;
};
public:
......@@ -199,7 +183,7 @@ public:
/// option fields are the array.
OptionDefinition(const std::string& name,
const uint16_t code,
const DataType type,
const OptionDataType type,
const bool array_type = false);
/// @brief Adds data field to the record.
......@@ -216,7 +200,7 @@ public:
///
/// @throw isc::InvalidOperation if option type is not set to RECORD_TYPE.
/// @throw isc::BadValue if specified invalid data type.
void addRecordField(const DataType data_type);
void addRecordField(const OptionDataType data_type);
/// @brief Return array type indicator.
///
......@@ -244,7 +228,7 @@ public:
/// @brief Return option data type.
///
/// @return option data type.
DataType getType() const { return (type_); };
OptionDataType getType() const { return (type_); };
/// @brief Check if the option definition is valid.
///
......@@ -427,12 +411,12 @@ private:
/// @param first_type type of the first data field.
///
/// @return true if actual option format matches expected format.
bool haveIAx6Format(const OptionDefinition::DataType first_type) const;
bool haveIAx6Format(const OptionDataType first_type) const;
/// @brief Check if specified type matches option definition type.
///
/// @return true if specified type matches option definition type.
inline bool haveType(const DataType type) const {
inline bool haveType(const OptionDataType type) const {
return (type == type_);
}
......@@ -450,7 +434,7 @@ private:
/// Option code.
uint16_t code_;
/// Option data type.
DataType type_;
OptionDataType type_;
/// Indicates wheter option is a single value or array.
bool array_type_;
/// Collection of data fields within the record.
......
......@@ -52,27 +52,28 @@ TEST_F(OptionDefinitionTest, constructor) {
// to enum value returned by getType().
OptionDefinition opt_def1("OPTION_CLIENTID", 1, "string");
EXPECT_EQ("OPTION_CLIENTID", opt_def1.getName());
EXPECT_EQ(1, opt_def1.getCode());
EXPECT_EQ(OptionDefinition::STRING_TYPE, opt_def1.getType());
EXPECT_EQ(OPT_STRING_TYPE, opt_def1.getType());
EXPECT_FALSE(opt_def1.getArrayType());
EXPECT_NO_THROW(opt_def1.validate());
// Specify the option data type as an enum value.
OptionDefinition opt_def2("OPTION_RAPID_COMMIT", 14,
OptionDefinition::EMPTY_TYPE);
OPT_EMPTY_TYPE);
EXPECT_EQ("OPTION_RAPID_COMMIT", opt_def2.getName());
EXPECT_EQ(14, opt_def2.getCode());
EXPECT_EQ(OptionDefinition::EMPTY_TYPE, opt_def2.getType());
EXPECT_EQ(OPT_EMPTY_TYPE, opt_def2.getType());
EXPECT_FALSE(opt_def2.getArrayType());
EXPECT_NO_THROW(opt_def1.validate());