namespace isc {
namespace dhcp {
+OptionDataTypeUtil::OptionDataTypeUtil() {
+ 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;
+
+ data_type_names_[OPT_EMPTY_TYPE] = "empty";
+ data_type_names_[OPT_BINARY_TYPE] = "binary";
+ data_type_names_[OPT_BOOLEAN_TYPE] = "boolean";
+ data_type_names_[OPT_INT8_TYPE] = "int8";
+ data_type_names_[OPT_INT16_TYPE] = "int16";
+ data_type_names_[OPT_INT32_TYPE] = "int32";
+ data_type_names_[OPT_UINT8_TYPE] = "uint8";
+ data_type_names_[OPT_UINT16_TYPE] = "uint16";
+ data_type_names_[OPT_UINT32_TYPE] = "uint32";
+ data_type_names_[OPT_IPV4_ADDRESS_TYPE] = "ipv4-address";
+ data_type_names_[OPT_IPV6_ADDRESS_TYPE] = "ipv4-address";
+ data_type_names_[OPT_STRING_TYPE] = "string";
+ data_type_names_[OPT_FQDN_TYPE] = "fqdn";
+ data_type_names_[OPT_RECORD_TYPE] = "record";
+ data_type_names_[OPT_UNKNOWN_TYPE] = "unknown";
+}
+
+OptionDataType
+OptionDataTypeUtil::getDataType(const std::string& data_type) {
+ return (OptionDataTypeUtil::instance().getDataTypeImpl(data_type));
+}
+
+OptionDataType
+OptionDataTypeUtil::getDataTypeImpl(const std::string& data_type) const {
+ 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 (OPT_UNKNOWN_TYPE);
+}
+
int
OptionDataTypeUtil::getDataTypeLen(const OptionDataType data_type) {
switch (data_type) {
return (0);
}
+const std::string&
+OptionDataTypeUtil::getDataTypeName(const OptionDataType data_type) {
+ return (OptionDataTypeUtil::instance().getDataTypeNameImpl(data_type));
+}
+
+const std::string&
+OptionDataTypeUtil::getDataTypeNameImpl(const OptionDataType data_type) const {
+ std::map<OptionDataType, std::string>::const_iterator data_type_it =
+ data_type_names_.find(data_type);
+ if (data_type_it != data_type_names_.end()) {
+ return (data_type_it->second);
+ }
+ return (data_type_names_.find(OPT_UNKNOWN_TYPE)->second);
+}
+
+OptionDataTypeUtil&
+OptionDataTypeUtil::instance() {
+ static OptionDataTypeUtil instance;
+ return (instance);
+}
+
void
OptionDataTypeUtil::readAddress(const std::vector<uint8_t>& buf,
const short family,
static const OptionDataType type = OPT_STRING_TYPE;
};
-/// @brief Utility class to write/read data to/from a buffer.
+/// @brief Utility class for option data types.
class OptionDataTypeUtil {
public:
+ /// @brief Return option data type from its name.
+ ///
+ /// @param data_type data type name.
+ /// @return option data type.
+ static OptionDataType getDataType(const std::string& data_type);
+
+ /// @brief Return option data type name from the data type enumerator.
+ ///
+ /// @param data_type option data type.
+ /// @return option data type name.
+ static const std::string& getDataTypeName(const OptionDataType data_type);
+
/// @brief Get data type buffer length.
///
/// This functionm returs the size of a particular data type.
/// @param [out] buf output buffer.
static void writeString(const std::string& value,
std::vector<uint8_t>& buf);
+private:
+
+ /// The container holding mapping of data type names to
+ /// data types enumerator.
+ std::map<std::string, OptionDataType> data_types_;
+
+ /// The container holding mapping of data types to data
+ /// type names.
+ std::map<OptionDataType, std::string> data_type_names_;
+
+ /// @brief Private constructor.
+ ///
+ /// This constructor is private because this class should
+ /// be used as singleton (through static public functions).
+ OptionDataTypeUtil();
+
+ /// @brief Return instance of OptionDataTypeUtil
+ ///
+ /// This function is used by some of the public static functions
+ /// to create an instance of OptionDataTypeUtil class.
+ /// When instance is called it calls the class'es constructor
+ /// and initializes some of the private data members.
+ ///
+ /// @return instance of OptionDataTypeUtil singleton.
+ static OptionDataTypeUtil& instance();
+ /// @brief Return option data type from its name.
+ ///
+ /// @param data_type data type name.
+ /// @return option data type.
+ OptionDataType getDataTypeImpl(const std::string& data_type) const;
+
+ /// @brief Return option data type name from the data type enumerator.
+ ///
+ /// @param data_type option data type.
+ /// @return option data type name.
+ const std::string& getDataTypeNameImpl(const OptionDataType data_type) const;
};
namespace isc {
namespace dhcp {
-OptionDefinition::DataTypeUtil::DataTypeUtil() {
- 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;
-}
-
-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 (OPT_UNKNOWN_TYPE);
-}
-
-template<typename T>
-T OptionDefinition::DataTypeUtil::lexicalCastWithRangeCheck(const std::string& value_str) const {
- // Lexical cast in case of our data types make sense only
- // for uintX_t, intX_t and bool type.
- if (!OptionDataTypeTraits<T>::integer_type &&
- OptionDataTypeTraits<T>::type != OPT_BOOLEAN_TYPE) {
- isc_throw(BadDataTypeCast, "unable to do lexical cast to non-integer and"
- << " non-boolean data type");
- }
- // We use the 64-bit value here because it has wider range than
- // any other type we use here and it allows to detect out of
- // bounds conditions e.g. negative value specified for uintX_t
- // data type. Obviously if the value exceeds the limits of int64
- // this function will not handle that properly.
- int64_t result = 0;
- try {
- result = boost::lexical_cast<int64_t>(value_str);
- } catch (const boost::bad_lexical_cast& ex) {
- // Prepare error message here.
- std::string data_type_str = "boolean";
- if (OptionDataTypeTraits<T>::integer_type) {
- data_type_str = "integer";
- }
- isc_throw(BadDataTypeCast, "unable to do lexical cast to " << data_type_str
- << " data type for value " << value_str << ": " << ex.what());
- }
- // Perform range checks for integer values only (exclude bool values).
- if (OptionDataTypeTraits<T>::integer_type) {
- if (result > numeric_limits<T>::max() ||
- result < numeric_limits<T>::min()) {
- isc_throw(BadDataTypeCast, "unable to do lexical cast for value "
- << value_str << ". This value is expected to be in the range of "
- << numeric_limits<T>::min() << ".." << numeric_limits<T>::max());
- }
- }
- return (static_cast<T>(result));
-}
-
-void
-OptionDefinition::DataTypeUtil::writeToBuffer(const std::string& value,
- const OptionDataType type,
- OptionBuffer& buf) {
- // We are going to write value given by value argument to the buffer.
- // The actual type of the value is given by second argument. Check
- // this argument to determine how to write this value to the buffer.
- switch (type) {
- case OPT_BINARY_TYPE:
- OptionDataTypeUtil::writeBinary(value, buf);
- return;
- case OPT_BOOLEAN_TYPE:
- // We encode the true value as 1 and false as 0 on 8 bits.
- // That way we actually waste 7 bits but it seems to be the
- // simpler way to encode boolean.
- // @todo Consider if any other encode methods can be used.
- OptionDataTypeUtil::writeBool(lexicalCastWithRangeCheck<bool>(value), buf);
- return;
- case OPT_INT8_TYPE:
- OptionDataTypeUtil::writeInt<uint8_t>(lexicalCastWithRangeCheck<int8_t>(value),
- buf);
- return;
- case OPT_INT16_TYPE:
- OptionDataTypeUtil::writeInt<uint16_t>(lexicalCastWithRangeCheck<int16_t>(value),
- buf);
- return;
- case OPT_INT32_TYPE:
- OptionDataTypeUtil::writeInt<uint32_t>(lexicalCastWithRangeCheck<int32_t>(value),
- buf);
- return;
- case OPT_UINT8_TYPE:
- OptionDataTypeUtil::writeInt<uint8_t>(lexicalCastWithRangeCheck<uint8_t>(value),
- buf);
- return;
- case OPT_UINT16_TYPE:
- OptionDataTypeUtil::writeInt<uint16_t>(lexicalCastWithRangeCheck<uint16_t>(value),
- buf);
- return;
- case OPT_UINT32_TYPE:
- OptionDataTypeUtil::writeInt<uint32_t>(lexicalCastWithRangeCheck<uint32_t>(value),
- buf);
- return;
- case OPT_IPV4_ADDRESS_TYPE:
- case OPT_IPV6_ADDRESS_TYPE:
- {
- asiolink::IOAddress address(value);
- if (!address.getAddress().is_v4() &&
- !address.getAddress().is_v6()) {
- isc_throw(BadDataTypeCast, "provided address " << address.toText()
- << " is not a valid "
- << (address.getAddress().is_v4() ? "IPv4" : "IPv6")
- << " address");
- }
- OptionDataTypeUtil::writeAddress(address, buf);
- return;
- }
- case OPT_STRING_TYPE:
- OptionDataTypeUtil::writeString(value, buf);
- return;
- case OPT_FQDN_TYPE:
- {
- // FQDN implementation is not terribly complicated but will require
- // creation of some additional logic (maybe object) that will parse
- // the fqdn into labels.
- isc_throw(isc::NotImplemented, "write of FQDN record into option buffer"
- " is not supported yet");
- return;
- }
- default:
- // We hit this point because invalid option data type has been specified
- // This may be the case because 'empty' or 'record' data type has been
- // specified. We don't throw exception here because it will be thrown
- // at the exit point from this function.
- ;
- }
- isc_throw(isc::BadValue, "attempt to write invalid option data field type"
- " into the option buffer: " << type);
-
-}
OptionDefinition::OptionDefinition(const std::string& name,
const uint16_t code,
// 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().getOptionDataType(type);
+ type_ = OptionDataTypeUtil::getDataType(type);
}
OptionDefinition::OptionDefinition(const std::string& name,
void
OptionDefinition::addRecordField(const std::string& data_type_name) {
- OptionDataType data_type = DataTypeUtil::instance().getOptionDataType(data_type_name);
+ OptionDataType data_type = OptionDataTypeUtil::getDataType(data_type_name);
addRecordField(data_type);
}
if (values.size() == 0) {
isc_throw(InvalidOptionValue, "no option value specified");
}
- DataTypeUtil::instance().writeToBuffer(values[0], type_, buf);
+ writeToBuffer(values[0], type_, buf);
} else if (array_type_ && type_ != OPT_RECORD_TYPE) {
for (size_t i = 0; i < values.size(); ++i) {
- DataTypeUtil::instance().writeToBuffer(values[i], type_, buf);
+ writeToBuffer(values[i], type_, buf);
}
} else if (type_ == OPT_RECORD_TYPE) {
const RecordFieldsCollection& records = getRecordFields();
<< " provided.");
}
for (size_t i = 0; i < records.size(); ++i) {
- DataTypeUtil::instance().writeToBuffer(values[i], records[i], buf);
+ writeToBuffer(values[i], records[i], buf);
}
}
return (optionFactory(u, type, buf.begin(), buf.end()));
return (haveIAx6Format(OPT_IPV6_ADDRESS_TYPE));
}
+template<typename T>
+T OptionDefinition::lexicalCastWithRangeCheck(const std::string& value_str) const {
+ // Lexical cast in case of our data types make sense only
+ // for uintX_t, intX_t and bool type.
+ if (!OptionDataTypeTraits<T>::integer_type &&
+ OptionDataTypeTraits<T>::type != OPT_BOOLEAN_TYPE) {
+ isc_throw(BadDataTypeCast, "unable to do lexical cast to non-integer and"
+ << " non-boolean data type");
+ }
+ // We use the 64-bit value here because it has wider range than
+ // any other type we use here and it allows to detect out of
+ // bounds conditions e.g. negative value specified for uintX_t
+ // data type. Obviously if the value exceeds the limits of int64
+ // this function will not handle that properly.
+ int64_t result = 0;
+ try {
+ result = boost::lexical_cast<int64_t>(value_str);
+ } catch (const boost::bad_lexical_cast& ex) {
+ // Prepare error message here.
+ std::string data_type_str = "boolean";
+ if (OptionDataTypeTraits<T>::integer_type) {
+ data_type_str = "integer";
+ }
+ isc_throw(BadDataTypeCast, "unable to do lexical cast to " << data_type_str
+ << " data type for value " << value_str << ": " << ex.what());
+ }
+ // Perform range checks for integer values only (exclude bool values).
+ if (OptionDataTypeTraits<T>::integer_type) {
+ if (result > numeric_limits<T>::max() ||
+ result < numeric_limits<T>::min()) {
+ isc_throw(BadDataTypeCast, "unable to do lexical cast for value "
+ << value_str << ". This value is expected to be in the range of "
+ << numeric_limits<T>::min() << ".." << numeric_limits<T>::max());
+ }
+ }
+ return (static_cast<T>(result));
+}
+
+void
+OptionDefinition::writeToBuffer(const std::string& value,
+ const OptionDataType type,
+ OptionBuffer& buf) const {
+ // We are going to write value given by value argument to the buffer.
+ // The actual type of the value is given by second argument. Check
+ // this argument to determine how to write this value to the buffer.
+ switch (type) {
+ case OPT_BINARY_TYPE:
+ OptionDataTypeUtil::writeBinary(value, buf);
+ return;
+ case OPT_BOOLEAN_TYPE:
+ // We encode the true value as 1 and false as 0 on 8 bits.
+ // That way we actually waste 7 bits but it seems to be the
+ // simpler way to encode boolean.
+ // @todo Consider if any other encode methods can be used.
+ OptionDataTypeUtil::writeBool(lexicalCastWithRangeCheck<bool>(value), buf);
+ return;
+ case OPT_INT8_TYPE:
+ OptionDataTypeUtil::writeInt<uint8_t>(lexicalCastWithRangeCheck<int8_t>(value),
+ buf);
+ return;
+ case OPT_INT16_TYPE:
+ OptionDataTypeUtil::writeInt<uint16_t>(lexicalCastWithRangeCheck<int16_t>(value),
+ buf);
+ return;
+ case OPT_INT32_TYPE:
+ OptionDataTypeUtil::writeInt<uint32_t>(lexicalCastWithRangeCheck<int32_t>(value),
+ buf);
+ return;
+ case OPT_UINT8_TYPE:
+ OptionDataTypeUtil::writeInt<uint8_t>(lexicalCastWithRangeCheck<uint8_t>(value),
+ buf);
+ return;
+ case OPT_UINT16_TYPE:
+ OptionDataTypeUtil::writeInt<uint16_t>(lexicalCastWithRangeCheck<uint16_t>(value),
+ buf);
+ return;
+ case OPT_UINT32_TYPE:
+ OptionDataTypeUtil::writeInt<uint32_t>(lexicalCastWithRangeCheck<uint32_t>(value),
+ buf);
+ return;
+ case OPT_IPV4_ADDRESS_TYPE:
+ case OPT_IPV6_ADDRESS_TYPE:
+ {
+ asiolink::IOAddress address(value);
+ if (!address.getAddress().is_v4() &&
+ !address.getAddress().is_v6()) {
+ isc_throw(BadDataTypeCast, "provided address " << address.toText()
+ << " is not a valid "
+ << (address.getAddress().is_v4() ? "IPv4" : "IPv6")
+ << " address");
+ }
+ OptionDataTypeUtil::writeAddress(address, buf);
+ return;
+ }
+ case OPT_STRING_TYPE:
+ OptionDataTypeUtil::writeString(value, buf);
+ return;
+ case OPT_FQDN_TYPE:
+ {
+ // FQDN implementation is not terribly complicated but will require
+ // creation of some additional logic (maybe object) that will parse
+ // the fqdn into labels.
+ isc_throw(isc::NotImplemented, "write of FQDN record into option buffer"
+ " is not supported yet");
+ return;
+ }
+ default:
+ // We hit this point because invalid option data type has been specified
+ // This may be the case because 'empty' or 'record' data type has been
+ // specified. We don't throw exception here because it will be thrown
+ // at the exit point from this function.
+ ;
+ }
+ isc_throw(isc::BadValue, "attempt to write invalid option data field type"
+ " into the option buffer: " << type);
+
+}
+
OptionPtr
OptionDefinition::factoryAddrList4(uint16_t type,
OptionBufferConstIter begin,
/// Const iterator for record data fields.
typedef std::vector<OptionDataType>::const_iterator RecordFieldsConstIter;
-private:
-
- /// @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
- /// can persist for all option definitions.
- ///
- /// @todo This class can be extended to return the string value
- /// representing the data type from the enum value.
- class DataTypeUtil {
- public:
-
- /// @brief Return the sole instance of this class.
- ///
- /// @return instance of this class.
- static DataTypeUtil& instance() {
- static DataTypeUtil instance;
- return (instance);
- }
-
- /// @brief Convert type given as string value to option data type.
- ///
- /// @param data_type_name data type string.
- ///
- /// @return option data type.
- OptionDataType getOptionDataType(const std::string& data_type_name);
-
- /// @brief Perform lexical cast of the value and validate its range.
- ///
- /// This function performs lexical cast of a string value to integer
- /// or boolean value and checks if the resulting value is within a
- /// range of a target type. Note that range checks are not performed
- /// on boolean values. The target type should be one of the supported
- /// integer types or bool.
- ///
- /// @param value_str input value given as string.
- /// @tparam T target type for lexical cast.
- ///
- /// @return cast value.
- /// @throw BadDataTypeCast if cast was not successful.
- template<typename T>
- T lexicalCastWithRangeCheck(const std::string& value_str) const;
-
- /// @brief Write the string value into the provided buffer.
- ///
- /// This method writes the given value to the specified buffer.
- /// The provided string value may represent data of different types.
- /// The actual data type is specified with the second argument.
- /// Based on a value of this argument, this function will first
- /// try to cast the string value to the particular data type and
- /// if it is successful it will store the data in the buffer
- /// in a binary format.
- ///
- /// @param value string representation of the value to be written.
- /// @param type the actual data type to be stored.
- /// @param [in, out] buf buffer where the value is to be stored.
- ///
- /// @throw BadDataTypeCast if data write was unsuccessful.
- void writeToBuffer(const std::string& value, const OptionDataType type,
- OptionBuffer& buf);
-
- private:
- /// @brief Private constructor.
- ///
- /// Constructor initializes the internal data structures, e.g.
- /// mapping between data type name and the corresponding enum.
- /// This constructor is private to ensure that exactly one
- /// instance of this class can be created using \ref instance
- /// function.
- DataTypeUtil();
-
- /// Map of data types, maps name of the type to enum value.
- std::map<std::string, OptionDataType> data_types_;
- };
-
-public:
/// @brief Constructor.
///
/// @param name option name.
return (type == type_);
}
+ /// @brief Perform lexical cast of the value and validate its range.
+ ///
+ /// This function performs lexical cast of a string value to integer
+ /// or boolean value and checks if the resulting value is within a
+ /// range of a target type. Note that range checks are not performed
+ /// on boolean values. The target type should be one of the supported
+ /// integer types or bool.
+ ///
+ /// @param value_str input value given as string.
+ /// @tparam T target type for lexical cast.
+ ///
+ /// @return cast value.
+ /// @throw BadDataTypeCast if cast was not successful.
+ template<typename T>
+ T lexicalCastWithRangeCheck(const std::string& value_str) const;
+
+ /// @brief Write the string value into the provided buffer.
+ ///
+ /// This method writes the given value to the specified buffer.
+ /// The provided string value may represent data of different types.
+ /// The actual data type is specified with the second argument.
+ /// Based on a value of this argument, this function will first
+ /// try to cast the string value to the particular data type and
+ /// if it is successful it will store the data in the buffer
+ /// in a binary format.
+ ///
+ /// @param value string representation of the value to be written.
+ /// @param type the actual data type to be stored.
+ /// @param [in, out] buf buffer where the value is to be stored.
+ ///
+ /// @throw BadDataTypeCast if data write was unsuccessful.
+ void writeToBuffer(const std::string& value, const OptionDataType type,
+ OptionBuffer& buf) const;
+
/// @brief Sanity check universe value.
///
/// @param expected_universe expected universe value.