From: Marcin Siodelski Date: Thu, 18 Jul 2013 15:01:11 +0000 (+0200) Subject: [3036] Return instance of Option6ClientFqdn for option 39. X-Git-Tag: bind10-1.2.0beta1-release~257^2~20 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d803eeaf3f71b0f68d26fde29802adf2a55fa31d;p=thirdparty%2Fkea.git [3036] Return instance of Option6ClientFqdn for option 39. Also folded long lines in OptionDefinition implementation. --- diff --git a/src/lib/dhcp/option_definition.cc b/src/lib/dhcp/option_definition.cc index bf2c5fb4a8..ac1369ca17 100644 --- a/src/lib/dhcp/option_definition.cc +++ b/src/lib/dhcp/option_definition.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -101,7 +102,8 @@ OptionDefinition::addRecordField(const OptionDataType data_type) { if (data_type >= OPT_RECORD_TYPE || data_type == OPT_ANY_ADDRESS_TYPE || data_type == OPT_EMPTY_TYPE) { - isc_throw(isc::BadValue, "attempted to add invalid data type to the record."); + isc_throw(isc::BadValue, + "attempted to add invalid data type to the record."); } record_fields_.push_back(data_type); } @@ -127,19 +129,23 @@ OptionDefinition::optionFactory(Option::Universe u, uint16_t type, factoryInteger(u, type, begin, end)); case OPT_UINT16_TYPE: - return (array_type_ ? factoryIntegerArray(u, type, begin, end) : + return (array_type_ ? + factoryIntegerArray(u, type, begin, end) : factoryInteger(u, type, begin, end)); case OPT_INT16_TYPE: - return (array_type_ ? factoryIntegerArray(u, type, begin, end) : + return (array_type_ ? + factoryIntegerArray(u, type, begin, end) : factoryInteger(u, type, begin, end)); case OPT_UINT32_TYPE: - return (array_type_ ? factoryIntegerArray(u, type, begin, end) : + return (array_type_ ? + factoryIntegerArray(u, type, begin, end) : factoryInteger(u, type, begin, end)); case OPT_INT32_TYPE: - return (array_type_ ? factoryIntegerArray(u, type, begin, end) : + return (array_type_ ? + factoryIntegerArray(u, type, begin, end) : factoryInteger(u, type, begin, end)); case OPT_IPV4_ADDRESS_TYPE: @@ -183,6 +189,10 @@ OptionDefinition::optionFactory(Option::Universe u, uint16_t type, // option only for the same reasons as described in // for IA_NA and IA_PD above. return (factoryIAAddr6(type, begin, end)); + } else if (code_ == D6O_CLIENT_FQDN && haveClientFqdnFormat()) { + // FQDN option requires special processing. Thus, there is + // a specialized class to handle it. + return (OptionPtr(new Option6ClientFqdn(begin, end))); } } } @@ -264,10 +274,12 @@ OptionDefinition::validate() const { // it no way to tell when other data fields begin. err_str << "array of strings is not a valid option definition."; } else if (type_ == OPT_BINARY_TYPE) { - err_str << "array of binary values is not a valid option definition."; + err_str << "array of binary values is not" + << " a valid option definition."; } else if (type_ == OPT_EMPTY_TYPE) { - err_str << "array of empty value is not a valid option definition."; + err_str << "array of empty value is not" + << " a valid option definition."; } @@ -275,33 +287,34 @@ OptionDefinition::validate() const { // At least two data fields should be added to the record. Otherwise // non-record option definition could be used. if (getRecordFields().size() < 2) { - err_str << "invalid number of data fields: " << getRecordFields().size() + err_str << "invalid number of data fields: " + << getRecordFields().size() << " specified for the option of type 'record'. Expected at" << " least 2 fields."; } else { // If the number of fields is valid we have to check if their order // is valid too. We check that string or binary data fields are not - // laid before other fields. But we allow that they are laid at the end of - // an option. + // laid before other fields. But we allow that they are laid at the + // end of an option. const RecordFieldsCollection& fields = getRecordFields(); for (RecordFieldsConstIter it = fields.begin(); it != fields.end(); ++it) { if (*it == OPT_STRING_TYPE && it < fields.end() - 1) { - err_str << "string data field can't be laid before data fields" - << " of other types."; + err_str << "string data field can't be laid before data" + << " fields of other types."; break; } if (*it == OPT_BINARY_TYPE && it < fields.end() - 1) { - err_str << "binary data field can't be laid before data fields" - << " of other types."; + err_str << "binary data field can't be laid before data" + << " fields of other types."; } /// Empty type is not allowed within a record. if (*it == OPT_EMPTY_TYPE) { - err_str << "empty data type can't be stored as a field in an" - << " option record."; + err_str << "empty data type can't be stored as a field in" + << " an option record."; break; } } @@ -341,13 +354,24 @@ OptionDefinition::haveIAAddr6Format() const { return (haveIAx6Format(OPT_IPV6_ADDRESS_TYPE)); } +bool +OptionDefinition::haveClientFqdnFormat() const { + return (haveType(OPT_RECORD_TYPE) && + (record_fields_.size() == 2) && + (record_fields_[0] == OPT_UINT8_TYPE) && + (record_fields_[1] == OPT_FQDN_TYPE)); +} + template -T OptionDefinition::lexicalCastWithRangeCheck(const std::string& value_str) const { +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::integer_type && OptionDataTypeTraits::type != OPT_BOOLEAN_TYPE) { - isc_throw(BadDataTypeCast, "unable to do lexical cast to non-integer and" + 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 @@ -364,16 +388,18 @@ T OptionDefinition::lexicalCastWithRangeCheck(const std::string& value_str) cons if (OptionDataTypeTraits::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()); + 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::integer_type) { if (result > numeric_limits::max() || result < numeric_limits::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::min() << ".." << numeric_limits::max()); + << value_str << ". This value is expected to be" + << " in the range of " << numeric_limits::min() + << ".." << numeric_limits::max()); } } return (static_cast(result)); @@ -395,30 +421,37 @@ OptionDefinition::writeToBuffer(const std::string& value, // 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(value), buf); + OptionDataTypeUtil::writeBool(lexicalCastWithRangeCheck(value), + buf); return; case OPT_INT8_TYPE: - OptionDataTypeUtil::writeInt(lexicalCastWithRangeCheck(value), + OptionDataTypeUtil::writeInt + (lexicalCastWithRangeCheck(value), buf); return; case OPT_INT16_TYPE: - OptionDataTypeUtil::writeInt(lexicalCastWithRangeCheck(value), + OptionDataTypeUtil::writeInt + (lexicalCastWithRangeCheck(value), buf); return; case OPT_INT32_TYPE: - OptionDataTypeUtil::writeInt(lexicalCastWithRangeCheck(value), + OptionDataTypeUtil::writeInt + (lexicalCastWithRangeCheck(value), buf); return; case OPT_UINT8_TYPE: - OptionDataTypeUtil::writeInt(lexicalCastWithRangeCheck(value), + OptionDataTypeUtil::writeInt + (lexicalCastWithRangeCheck(value), buf); return; case OPT_UINT16_TYPE: - OptionDataTypeUtil::writeInt(lexicalCastWithRangeCheck(value), + OptionDataTypeUtil::writeInt + (lexicalCastWithRangeCheck(value), buf); return; case OPT_UINT32_TYPE: - OptionDataTypeUtil::writeInt(lexicalCastWithRangeCheck(value), + OptionDataTypeUtil::writeInt + (lexicalCastWithRangeCheck(value), buf); return; case OPT_IPV4_ADDRESS_TYPE: @@ -426,7 +459,8 @@ OptionDefinition::writeToBuffer(const std::string& value, { asiolink::IOAddress address(value); if (!address.isV4() && !address.isV6()) { - isc_throw(BadDataTypeCast, "provided address " << address.toText() + isc_throw(BadDataTypeCast, "provided address " + << address.toText() << " is not a valid IPv4 or IPv6 address."); } OptionDataTypeUtil::writeAddress(address, buf); @@ -454,7 +488,8 @@ OptionPtr OptionDefinition::factoryAddrList4(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end) { - boost::shared_ptr option(new Option4AddrLst(type, begin, end)); + boost::shared_ptr option(new Option4AddrLst(type, begin, + end)); return (option); } @@ -462,7 +497,8 @@ OptionPtr OptionDefinition::factoryAddrList6(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end) { - boost::shared_ptr option(new Option6AddrLst(type, begin, end)); + boost::shared_ptr option(new Option6AddrLst(type, begin, + end)); return (option); } @@ -486,8 +522,9 @@ OptionDefinition::factoryIA6(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end) { if (std::distance(begin, end) < Option6IA::OPTION6_IA_LEN) { - isc_throw(isc::OutOfRange, "input option buffer has invalid size, expected " - "at least " << Option6IA::OPTION6_IA_LEN << " bytes"); + isc_throw(isc::OutOfRange, "input option buffer has invalid size," + << " expected at least " << Option6IA::OPTION6_IA_LEN + << " bytes"); } boost::shared_ptr option(new Option6IA(type, begin, end)); return (option); @@ -498,10 +535,12 @@ OptionDefinition::factoryIAAddr6(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end) { if (std::distance(begin, end) < Option6IAAddr::OPTION6_IAADDR_LEN) { - isc_throw(isc::OutOfRange, "input option buffer has invalid size, expected " - " at least " << Option6IAAddr::OPTION6_IAADDR_LEN << " bytes"); + isc_throw(isc::OutOfRange, + "input option buffer has invalid size, expected at least " + << Option6IAAddr::OPTION6_IAADDR_LEN << " bytes"); } - boost::shared_ptr option(new Option6IAAddr(type, begin, end)); + boost::shared_ptr option(new Option6IAAddr(type, begin, + end)); return (option); } diff --git a/src/lib/dhcp/option_definition.h b/src/lib/dhcp/option_definition.h index dcfc3c7a9a..99a57f504c 100644 --- a/src/lib/dhcp/option_definition.h +++ b/src/lib/dhcp/option_definition.h @@ -275,6 +275,12 @@ public: /// @return true if specified format is IAADDR option format. bool haveIAAddr6Format() const; + /// @brief Check if specified format is OPTION_CLIENT_FQDN option format. + /// + /// @return true of specified format is OPTION_CLIENT_FQDN option format, + /// false otherwise. + bool haveClientFqdnFormat() const; + /// @brief Option factory. /// /// This function creates an instance of DHCP option using diff --git a/src/lib/dhcp/tests/libdhcp++_unittest.cc b/src/lib/dhcp/tests/libdhcp++_unittest.cc index d523158dd6..dad4ad5522 100644 --- a/src/lib/dhcp/tests/libdhcp++_unittest.cc +++ b/src/lib/dhcp/tests/libdhcp++_unittest.cc @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -905,7 +906,8 @@ TEST_F(LibDhcpTest, stdOptionDefs6) { typeid(Option)); LibDhcpTest::testStdOptionDefs6(D6O_CLIENT_FQDN, client_fqdn_buf.begin(), - client_fqdn_buf.end(), typeid(OptionCustom)); + client_fqdn_buf.end(), + typeid(Option6ClientFqdn)); LibDhcpTest::testStdOptionDefs6(D6O_PANA_AGENT, begin, end, typeid(Option6AddrLst)); diff --git a/src/lib/dhcp/tests/option_definition_unittest.cc b/src/lib/dhcp/tests/option_definition_unittest.cc index f7602a6467..d3b766d36c 100644 --- a/src/lib/dhcp/tests/option_definition_unittest.cc +++ b/src/lib/dhcp/tests/option_definition_unittest.cc @@ -928,7 +928,7 @@ TEST_F(OptionDefinitionTest, utf8StringTokenized) { // Let's create some dummy option. const uint16_t opt_code = 80; OptionDefinition opt_def("OPTION_WITH_STRING", opt_code, "string"); - + std::vector values; values.push_back("Hello World"); values.push_back("this string should not be included in the option"); @@ -960,7 +960,7 @@ TEST_F(OptionDefinitionTest, integerInvalidType) { // The purpose of this test is to verify that helper methods // haveIA6Format and haveIAAddr6Format can be used to determine // IA_NA and IAADDR option formats. -TEST_F(OptionDefinitionTest, recognizeFormat) { +TEST_F(OptionDefinitionTest, haveIAFormat) { // IA_NA option format. OptionDefinition opt_def1("OPTION_IA_NA", D6O_IA_NA, "record"); for (int i = 0; i < 3; ++i) { @@ -984,4 +984,19 @@ TEST_F(OptionDefinitionTest, recognizeFormat) { EXPECT_FALSE(opt_def4.haveIAAddr6Format()); } +// This test verifies that haveClientFqdnFormat function recognizes that option +// definition describes the format of DHCPv6 Client Fqdn Option Format. +TEST_F(OptionDefinitionTest, haveClientFqdnFormat) { + OptionDefinition opt_def("OPTION_CLIENT_FQDN", D6O_CLIENT_FQDN, "record"); + opt_def.addRecordField("uint8"); + opt_def.addRecordField("fqdn"); + EXPECT_TRUE(opt_def.haveClientFqdnFormat()); + + // Create option format which is not matching the Client FQDN option format + // to verify that tested function does dont always return true. + OptionDefinition opt_def_invalid("OPTION_CLIENT_FQDN", D6O_CLIENT_FQDN, + "uint8"); + EXPECT_FALSE(opt_def_invalid.haveClientFqdnFormat()); +} + } // anonymous namespace