From: Marcin Siodelski Date: Fri, 24 Jun 2016 11:32:39 +0000 (+0200) Subject: [4497] Implemented deep copy of DHCP options. X-Git-Tag: trac4551_base~23^2~18 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=90615322d44e2015ff1dffa0b7c5fbc0723d7bad;p=thirdparty%2Fkea.git [4497] Implemented deep copy of DHCP options. --- diff --git a/src/lib/dhcp/option.cc b/src/lib/dhcp/option.cc index d91c4a411c..d3bf8ad408 100644 --- a/src/lib/dhcp/option.cc +++ b/src/lib/dhcp/option.cc @@ -53,6 +53,31 @@ Option::Option(Universe u, uint16_t type, OptionBufferConstIter first, check(); } +Option::Option(const Option& option) + : universe_(option.universe_), type_(option.type_), + data_(option.data_), options_(), + encapsulated_space_(option.encapsulated_space_) { + option.getOptionsCopy(options_); +} + +Option& +Option::operator=(const Option& rhs) { + if (&rhs != this) { + universe_ = rhs.universe_; + type_ = rhs.type_; + data_ = rhs.data_; + rhs.getOptionsCopy(options_); + encapsulated_space_ = rhs.encapsulated_space_; + } + return (*this); +} + +OptionPtr +Option::clone() const { + OptionPtr option(new Option(*this)); + return (option); +} + void Option::check() const { if ( (universe_ != V4) && (universe_ != V6) ) { @@ -180,6 +205,18 @@ OptionPtr Option::getOption(uint16_t opt_type) const { return OptionPtr(); // NULL } +void +Option::getOptionsCopy(OptionCollection& options_copy) const { + OptionCollection local_options; + for (OptionCollection::const_iterator it = options_.begin(); + it != options_.end(); ++it) { + OptionPtr copy = it->second->clone(); + local_options.insert(std::make_pair(it->second->getType(), + copy)); + } + options_copy.swap(local_options); +} + bool Option::delOption(uint16_t opt_type) { isc::dhcp::OptionCollection::iterator x = options_.find(opt_type); if ( x != options_.end() ) { diff --git a/src/lib/dhcp/option.h b/src/lib/dhcp/option.h index 181f28924a..b5e385c5c6 100644 --- a/src/lib/dhcp/option.h +++ b/src/lib/dhcp/option.h @@ -144,6 +144,12 @@ public: Option(Universe u, uint16_t type, OptionBufferConstIter first, OptionBufferConstIter last); + Option(const Option& option); + + Option& operator=(const Option& rhs); + + virtual OptionPtr clone() const; + /// @brief returns option universe (V4 or V6) /// /// @return universe type @@ -257,6 +263,8 @@ public: return (options_); } + void getOptionsCopy(OptionCollection& options_copy) const; + /// Attempts to delete first suboption of requested type /// /// @param type Type of option to be deleted. @@ -364,6 +372,13 @@ public: protected: + template + OptionPtr cloneInternal() const { + boost::shared_ptr + option(new OptionType(*dynamic_cast(this))); + return (option); + } + /// @brief Store option's header in a buffer. /// /// This method writes option's header into a buffer in the diff --git a/src/lib/dhcp/option4_addrlst.cc b/src/lib/dhcp/option4_addrlst.cc index 981fe8dc75..61bdc4f2f6 100644 --- a/src/lib/dhcp/option4_addrlst.cc +++ b/src/lib/dhcp/option4_addrlst.cc @@ -55,6 +55,11 @@ Option4AddrLst::Option4AddrLst(uint8_t type, const IOAddress& addr) setAddress(addr); } +OptionPtr +Option4AddrLst::clone() const { + return (cloneInternal()); +} + void Option4AddrLst::pack(isc::util::OutputBuffer& buf) const { diff --git a/src/lib/dhcp/option4_addrlst.h b/src/lib/dhcp/option4_addrlst.h index 02777569f2..e1448ce29d 100644 --- a/src/lib/dhcp/option4_addrlst.h +++ b/src/lib/dhcp/option4_addrlst.h @@ -80,6 +80,8 @@ public: Option4AddrLst(uint8_t type, OptionBufferConstIter first, OptionBufferConstIter last); + virtual OptionPtr clone() const; + /// @brief Writes option in a wire-format to a buffer. /// /// Method will throw if option storing fails for some reason. diff --git a/src/lib/dhcp/option4_client_fqdn.cc b/src/lib/dhcp/option4_client_fqdn.cc index 5dd571bceb..e5057076a7 100644 --- a/src/lib/dhcp/option4_client_fqdn.cc +++ b/src/lib/dhcp/option4_client_fqdn.cc @@ -346,11 +346,17 @@ Option4ClientFqdn::Option4ClientFqdn(const Option4ClientFqdn& source) impl_(new Option4ClientFqdnImpl(*source.impl_)) { } +OptionPtr +Option4ClientFqdn::clone() const { + return (cloneInternal()); +} + Option4ClientFqdn& // This assignment operator handles assignment to self, it uses copy // constructor of Option4ClientFqdnImpl to copy all required values. // cppcheck-suppress operatorEqToSelf Option4ClientFqdn::operator=(const Option4ClientFqdn& source) { + Option::operator=(source); Option4ClientFqdnImpl* old_impl = impl_; impl_ = new Option4ClientFqdnImpl(*source.impl_); delete(old_impl); @@ -396,6 +402,11 @@ Option4ClientFqdn::setFlag(const uint8_t flag, const bool set_flag) { impl_->flags_ = new_flag; } +std::pair +Option4ClientFqdn::getRcode() const { + return (std::make_pair(impl_->rcode1_, impl_->rcode2_)); +} + void Option4ClientFqdn::setRcode(const Rcode& rcode) { impl_->rcode1_ = rcode; diff --git a/src/lib/dhcp/option4_client_fqdn.h b/src/lib/dhcp/option4_client_fqdn.h index c23bb8ecc7..5656112e69 100644 --- a/src/lib/dhcp/option4_client_fqdn.h +++ b/src/lib/dhcp/option4_client_fqdn.h @@ -1,4 +1,4 @@ -// Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2013-2016 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -11,6 +11,7 @@ #include #include +#include namespace isc { namespace dhcp { @@ -215,9 +216,11 @@ public: explicit Option4ClientFqdn(OptionBufferConstIter first, OptionBufferConstIter last); - /// @brief Copy constructor + /// @brief Copy constructor Option4ClientFqdn(const Option4ClientFqdn& source); + virtual OptionPtr clone() const; + /// @brief Destructor virtual ~Option4ClientFqdn(); @@ -251,6 +254,12 @@ public: /// @brief Sets the flag field value to 0. void resetFlags(); + /// @brief Returns @c Rcode objects representing value of RCODE1 and RCODE2. + /// + /// @return Pair of Rcode objects of which first is the RCODE1 and the + /// second is RCODE2. + std::pair getRcode() const; + /// @brief Set Rcode value. /// /// @param rcode An @c Rcode object representing value of RCODE1 and RCODE2. diff --git a/src/lib/dhcp/option6_addrlst.cc b/src/lib/dhcp/option6_addrlst.cc index f71537c254..ab505c4da7 100644 --- a/src/lib/dhcp/option6_addrlst.cc +++ b/src/lib/dhcp/option6_addrlst.cc @@ -41,6 +41,11 @@ Option6AddrLst::Option6AddrLst(uint16_t type, OptionBufferConstIter begin, unpack(begin, end); } +OptionPtr +Option6AddrLst::clone() const { + return (cloneInternal()); +} + void Option6AddrLst::setAddress(const isc::asiolink::IOAddress& addr) { if (!addr.isV6()) { diff --git a/src/lib/dhcp/option6_addrlst.h b/src/lib/dhcp/option6_addrlst.h index 0b22a1b4f8..217b76ffa0 100644 --- a/src/lib/dhcp/option6_addrlst.h +++ b/src/lib/dhcp/option6_addrlst.h @@ -45,6 +45,8 @@ public: Option6AddrLst(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end); + virtual OptionPtr clone() const; + /// @brief Assembles on-wire form of this option /// /// @param buf pointer to packet buffer diff --git a/src/lib/dhcp/option6_client_fqdn.cc b/src/lib/dhcp/option6_client_fqdn.cc index 020f8efe24..700146a98c 100644 --- a/src/lib/dhcp/option6_client_fqdn.cc +++ b/src/lib/dhcp/option6_client_fqdn.cc @@ -293,11 +293,17 @@ Option6ClientFqdn::Option6ClientFqdn(const Option6ClientFqdn& source) impl_(new Option6ClientFqdnImpl(*source.impl_)) { } +OptionPtr +Option6ClientFqdn::clone() const { + return (cloneInternal()); +} + Option6ClientFqdn& // This assignment operator handles assignment to self, it uses copy // constructor of Option6ClientFqdnImpl to copy all required values. // cppcheck-suppress operatorEqToSelf Option6ClientFqdn::operator=(const Option6ClientFqdn& source) { + Option::operator=(source); Option6ClientFqdnImpl* old_impl = impl_; impl_ = new Option6ClientFqdnImpl(*source.impl_); delete(old_impl); diff --git a/src/lib/dhcp/option6_client_fqdn.h b/src/lib/dhcp/option6_client_fqdn.h index 3f7d5f6c9c..35c55d1520 100644 --- a/src/lib/dhcp/option6_client_fqdn.h +++ b/src/lib/dhcp/option6_client_fqdn.h @@ -137,9 +137,11 @@ public: explicit Option6ClientFqdn(OptionBufferConstIter first, OptionBufferConstIter last); - /// @brief Copy constructor + /// @brief Copy constructor Option6ClientFqdn(const Option6ClientFqdn& source); + virtual OptionPtr clone() const; + /// @brief Destructor virtual ~Option6ClientFqdn(); diff --git a/src/lib/dhcp/option6_ia.cc b/src/lib/dhcp/option6_ia.cc index bfcce7e244..887ec1e645 100644 --- a/src/lib/dhcp/option6_ia.cc +++ b/src/lib/dhcp/option6_ia.cc @@ -48,6 +48,11 @@ Option6IA::Option6IA(uint16_t type, OptionBufferConstIter begin, unpack(begin, end); } +OptionPtr +Option6IA::clone() const { + return (cloneInternal()); +} + void Option6IA::pack(isc::util::OutputBuffer& buf) const { buf.writeUint16(type_); buf.writeUint16(len() - OPTION6_HDR_LEN); diff --git a/src/lib/dhcp/option6_ia.h b/src/lib/dhcp/option6_ia.h index 315b6ff3ef..b29c77727f 100644 --- a/src/lib/dhcp/option6_ia.h +++ b/src/lib/dhcp/option6_ia.h @@ -39,6 +39,8 @@ public: Option6IA(uint16_t type, OptionBuffer::const_iterator begin, OptionBuffer::const_iterator end); + virtual OptionPtr clone() const; + /// Writes option in wire-format to buf, returns pointer to first unused /// byte after stored option. /// diff --git a/src/lib/dhcp/option6_iaaddr.cc b/src/lib/dhcp/option6_iaaddr.cc index 4f6812130d..477be9e603 100644 --- a/src/lib/dhcp/option6_iaaddr.cc +++ b/src/lib/dhcp/option6_iaaddr.cc @@ -42,6 +42,11 @@ Option6IAAddr::Option6IAAddr(uint32_t type, OptionBuffer::const_iterator begin, unpack(begin, end); } +OptionPtr +Option6IAAddr::clone() const { + return (cloneInternal()); +} + void Option6IAAddr::pack(isc::util::OutputBuffer& buf) const { buf.writeUint16(type_); diff --git a/src/lib/dhcp/option6_iaaddr.h b/src/lib/dhcp/option6_iaaddr.h index 1425a4ce1f..4709269965 100644 --- a/src/lib/dhcp/option6_iaaddr.h +++ b/src/lib/dhcp/option6_iaaddr.h @@ -46,6 +46,8 @@ public: Option6IAAddr(uint32_t type, OptionBuffer::const_iterator begin, OptionBuffer::const_iterator end); + virtual OptionPtr clone() const; + /// @brief Writes option in wire-format. /// /// Writes option in wire-format to buf, returns pointer to first unused diff --git a/src/lib/dhcp/option6_iaprefix.cc b/src/lib/dhcp/option6_iaprefix.cc index 5b96247169..95dacd6127 100644 --- a/src/lib/dhcp/option6_iaprefix.cc +++ b/src/lib/dhcp/option6_iaprefix.cc @@ -44,6 +44,11 @@ Option6IAPrefix::Option6IAPrefix(uint32_t type, OptionBuffer::const_iterator beg unpack(begin, end); } +OptionPtr +Option6IAPrefix::clone() const { + return (cloneInternal()); +} + void Option6IAPrefix::pack(isc::util::OutputBuffer& buf) const { if (!addr_.isV6()) { isc_throw(isc::BadValue, addr_ << " is not an IPv6 address"); diff --git a/src/lib/dhcp/option6_iaprefix.h b/src/lib/dhcp/option6_iaprefix.h index e6c588d5e9..c9be8ee681 100644 --- a/src/lib/dhcp/option6_iaprefix.h +++ b/src/lib/dhcp/option6_iaprefix.h @@ -74,6 +74,8 @@ public: Option6IAPrefix(uint32_t type, OptionBuffer::const_iterator begin, OptionBuffer::const_iterator end); + virtual OptionPtr clone() const; + /// @brief Writes option in wire-format. /// /// Writes option in wire-format to buf, returns pointer to first unused diff --git a/src/lib/dhcp/option6_status_code.cc b/src/lib/dhcp/option6_status_code.cc index e46315839f..f0de03bab4 100644 --- a/src/lib/dhcp/option6_status_code.cc +++ b/src/lib/dhcp/option6_status_code.cc @@ -40,6 +40,11 @@ Option6StatusCode::Option6StatusCode(OptionBufferConstIter begin, unpack(begin, end); } +OptionPtr +Option6StatusCode::clone() const { + return (cloneInternal()); +} + void Option6StatusCode::pack(isc::util::OutputBuffer& buf) const { // Pack option header. diff --git a/src/lib/dhcp/option6_status_code.h b/src/lib/dhcp/option6_status_code.h index c022c59e43..3b012186f0 100644 --- a/src/lib/dhcp/option6_status_code.h +++ b/src/lib/dhcp/option6_status_code.h @@ -37,6 +37,8 @@ public: /// @param end Iterator to end of option data (first byte after option end). Option6StatusCode(OptionBufferConstIter begin, OptionBufferConstIter end); + virtual OptionPtr clone() const; + /// @brief Writes option in wire-format. /// /// Writes option in wire-format to buf, returns pointer to first unused diff --git a/src/lib/dhcp/option_custom.cc b/src/lib/dhcp/option_custom.cc index 1d99da7449..e868083429 100644 --- a/src/lib/dhcp/option_custom.cc +++ b/src/lib/dhcp/option_custom.cc @@ -40,6 +40,11 @@ OptionCustom::OptionCustom(const OptionDefinition& def, createBuffers(getData()); } +OptionPtr +OptionCustom::clone() const { + return (cloneInternal()); +} + void OptionCustom::addArrayDataField(const asiolink::IOAddress& address) { checkArrayType(); diff --git a/src/lib/dhcp/option_custom.h b/src/lib/dhcp/option_custom.h index e766ebef18..28eb35dc48 100644 --- a/src/lib/dhcp/option_custom.h +++ b/src/lib/dhcp/option_custom.h @@ -79,6 +79,8 @@ public: OptionCustom(const OptionDefinition& def, Universe u, OptionBufferConstIter first, OptionBufferConstIter last); + virtual OptionPtr clone() const; + /// @brief Create new buffer and set its value as an IP address. /// /// @param address IPv4 or IPv6 address to be written to diff --git a/src/lib/dhcp/option_int.h b/src/lib/dhcp/option_int.h index 2aa81ecbc8..fd5d233320 100644 --- a/src/lib/dhcp/option_int.h +++ b/src/lib/dhcp/option_int.h @@ -46,6 +46,9 @@ typedef boost::shared_ptr OptionUint32Ptr; /// @param T data field type (see above). template class OptionInt: public Option { +private: + + typedef boost::shared_ptr > OptionIntTypePtr; public: /// @brief Constructor. @@ -90,6 +93,10 @@ public: unpack(begin, end); } + virtual OptionPtr clone() const { + return (cloneInternal >()); + } + /// Writes option in wire-format to buf, returns pointer to first unused /// byte after stored option. /// diff --git a/src/lib/dhcp/option_int_array.h b/src/lib/dhcp/option_int_array.h index d8a533ab7f..d29bc89bf3 100644 --- a/src/lib/dhcp/option_int_array.h +++ b/src/lib/dhcp/option_int_array.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,9 @@ typedef boost::shared_ptr OptionUint32ArrayPtr; /// @param T data field type (see above). template class OptionIntArray: public Option { +private: + + typedef boost::shared_ptr > OptionIntArrayTypePtr; public: @@ -116,6 +120,10 @@ public: unpack(begin, end); } + virtual OptionPtr clone() const { + return (cloneInternal >()); + } + /// @brief Adds a new value to the array. /// /// @param value a value being added. diff --git a/src/lib/dhcp/option_opaque_data_tuples.cc b/src/lib/dhcp/option_opaque_data_tuples.cc index 28a4a5982a..1fc5c614ea 100644 --- a/src/lib/dhcp/option_opaque_data_tuples.cc +++ b/src/lib/dhcp/option_opaque_data_tuples.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -25,6 +25,11 @@ OptionOpaqueDataTuples::OptionOpaqueDataTuples(Option::Universe u, unpack(begin, end); } +OptionPtr +OptionOpaqueDataTuples::clone() const { + return (cloneInternal()); +} + void OptionOpaqueDataTuples::pack(isc::util::OutputBuffer& buf) const { packHeader(buf); diff --git a/src/lib/dhcp/option_opaque_data_tuples.h b/src/lib/dhcp/option_opaque_data_tuples.h index 18b977c5e5..64823ee8bf 100644 --- a/src/lib/dhcp/option_opaque_data_tuples.h +++ b/src/lib/dhcp/option_opaque_data_tuples.h @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -62,6 +62,8 @@ public: OptionBufferConstIter begin, OptionBufferConstIter end); + OptionPtr clone() const; + /// @brief Renders option into the buffer in the wire format. /// /// @param [out] buf Buffer to which the option is rendered. @@ -137,12 +139,11 @@ private: /// /// This function returns the length field type which should be used /// for the opaque data tuples being added to this option. - /// Currently this class is only used for a DHCPv6 option it may be expanded - /// for DHCPv4 in the future. /// /// @return Tuple length field type for the universe this option belongs to. OpaqueDataTuple::LengthFieldType getLengthFieldType() const { - return (OpaqueDataTuple::LENGTH_2_BYTES); + return (universe_ == Option::V6 ? OpaqueDataTuple::LENGTH_2_BYTES : + OpaqueDataTuple::LENGTH_1_BYTE); } /// @brief Returns minimal length of the option for the given universe. diff --git a/src/lib/dhcp/option_string.cc b/src/lib/dhcp/option_string.cc index 4e8e6b3a3d..553f84fee5 100644 --- a/src/lib/dhcp/option_string.cc +++ b/src/lib/dhcp/option_string.cc @@ -27,6 +27,11 @@ OptionString::OptionString(const Option::Universe u, const uint16_t type, unpack(begin, end); } +OptionPtr +OptionString::clone() const { + return (cloneInternal()); +} + std::string OptionString::getValue() const { const OptionBuffer& data = getData(); diff --git a/src/lib/dhcp/option_string.h b/src/lib/dhcp/option_string.h index d3a8f83b0d..701c370507 100644 --- a/src/lib/dhcp/option_string.h +++ b/src/lib/dhcp/option_string.h @@ -56,6 +56,8 @@ public: OptionString(const Option::Universe u, const uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end); + OptionPtr clone() const; + /// @brief Returns length of the whole option, including header. /// /// @return length of the whole option. diff --git a/src/lib/dhcp/option_vendor.cc b/src/lib/dhcp/option_vendor.cc index dd85a2793c..25fed0047e 100644 --- a/src/lib/dhcp/option_vendor.cc +++ b/src/lib/dhcp/option_vendor.cc @@ -23,6 +23,10 @@ OptionVendor::OptionVendor(Option::Universe u, OptionBufferConstIter begin, unpack(begin, end); } +OptionPtr +OptionVendor::clone() const { + return (cloneInternal()); +} void OptionVendor::pack(isc::util::OutputBuffer& buf) const { packHeader(buf); diff --git a/src/lib/dhcp/option_vendor.h b/src/lib/dhcp/option_vendor.h index a0b5b1734e..7dddf42e00 100644 --- a/src/lib/dhcp/option_vendor.h +++ b/src/lib/dhcp/option_vendor.h @@ -50,6 +50,8 @@ public: OptionVendor(Option::Universe u, OptionBufferConstIter begin, OptionBufferConstIter end); + OptionPtr clone() const; + /// @brief Writes option in wire-format to buf, returns pointer to first /// unused byte after stored option. /// diff --git a/src/lib/dhcp/option_vendor_class.cc b/src/lib/dhcp/option_vendor_class.cc index 7ecf5d1e4f..3e1ec161d1 100644 --- a/src/lib/dhcp/option_vendor_class.cc +++ b/src/lib/dhcp/option_vendor_class.cc @@ -20,13 +20,18 @@ OptionVendorClass::OptionVendorClass(Option::Universe u, } } - OptionVendorClass::OptionVendorClass(Option::Universe u, - OptionBufferConstIter begin, - OptionBufferConstIter end) +OptionVendorClass::OptionVendorClass(Option::Universe u, + OptionBufferConstIter begin, + OptionBufferConstIter end) : Option(u, getOptionCode(u)) { unpack(begin, end); } +OptionPtr +OptionVendorClass::clone() const { + return (cloneInternal()); +} + void OptionVendorClass::pack(isc::util::OutputBuffer& buf) const { packHeader(buf); diff --git a/src/lib/dhcp/option_vendor_class.h b/src/lib/dhcp/option_vendor_class.h index 2018c838fd..b00f9f189c 100644 --- a/src/lib/dhcp/option_vendor_class.h +++ b/src/lib/dhcp/option_vendor_class.h @@ -69,6 +69,8 @@ public: OptionVendorClass(Option::Universe u, OptionBufferConstIter begin, OptionBufferConstIter end); + OptionPtr clone() const; + /// @brief Renders option into the buffer in the wire format. /// /// @param [out] buf Buffer to which the option is rendered. diff --git a/src/lib/dhcp/tests/Makefile.am b/src/lib/dhcp/tests/Makefile.am index c0c584e712..caf369ac81 100644 --- a/src/lib/dhcp/tests/Makefile.am +++ b/src/lib/dhcp/tests/Makefile.am @@ -59,6 +59,7 @@ libdhcp___unittests_SOURCES += option_int_unittest.cc libdhcp___unittests_SOURCES += option_int_array_unittest.cc libdhcp___unittests_SOURCES += option_data_types_unittest.cc libdhcp___unittests_SOURCES += option_definition_unittest.cc +libdhcp___unittests_SOURCES += option_copy_unittest.cc libdhcp___unittests_SOURCES += option_custom_unittest.cc libdhcp___unittests_SOURCES += option_opaque_data_tuples_unittest.cc libdhcp___unittests_SOURCES += option_unittest.cc diff --git a/src/lib/dhcp/tests/libdhcp++_unittest.cc b/src/lib/dhcp/tests/libdhcp++_unittest.cc index 8c50d79a2f..6b3f98e8e6 100644 --- a/src/lib/dhcp/tests/libdhcp++_unittest.cc +++ b/src/lib/dhcp/tests/libdhcp++_unittest.cc @@ -36,6 +36,7 @@ #include #include +#include #include diff --git a/src/lib/dhcp/tests/option_copy_unittest.cc b/src/lib/dhcp/tests/option_copy_unittest.cc new file mode 100644 index 0000000000..10429c98b2 --- /dev/null +++ b/src/lib/dhcp/tests/option_copy_unittest.cc @@ -0,0 +1,585 @@ +// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace std; +using namespace isc; +using namespace isc::asiolink; +using namespace isc::dhcp; +using namespace isc::util; + +namespace { + +enum OpType { + COPY, + CLONE, + ASSIGN +}; + +template +void testCopyAssign(const OpType& op_type, + boost::shared_ptr& option, + boost::shared_ptr& option_copy) { + option->setEncapsulatedSpace("foo"); + + OptionUint16Ptr sub1 = OptionUint16Ptr(new OptionUint16(Option::V4, 10, 234)); + Option4AddrLstPtr sub2 = + Option4AddrLstPtr(new Option4AddrLst(11, IOAddress("192.0.2.3"))); + option->addOption(sub1); + option->addOption(sub2); + + switch (op_type) { + case COPY: + option_copy.reset(new OptionType(*option)); + break; + case CLONE: + option_copy = boost::dynamic_pointer_cast(option->clone()); + ASSERT_TRUE(option_copy); + break; + case ASSIGN: + option_copy->setEncapsulatedSpace("bar"); + *option_copy = *option; + break; + default: + ADD_FAILURE() << "unsupported operation"; + return; + } + + EXPECT_EQ(option->getUniverse(), option_copy->getUniverse()); + EXPECT_EQ(option->getType(), option_copy->getType()); + EXPECT_EQ(option->len(), option_copy->len()); + EXPECT_EQ(option->getEncapsulatedSpace(), option_copy->getEncapsulatedSpace()); + EXPECT_TRUE(std::equal(option->getData().begin(), option->getData().end(), + option_copy->getData().begin())); + + const OptionCollection& option_subs = option->getOptions(); + const OptionCollection& option_copy_subs = option_copy->getOptions(); + + ASSERT_EQ(option_subs.size(), option_copy_subs.size()); + OptionCollection::const_iterator it_copy = option_copy_subs.begin(); + for (OptionCollection::const_iterator it = option_subs.begin(); + it != option_subs.end(); ++it, ++it_copy) { + EXPECT_EQ(it->first, it_copy->first); + EXPECT_NE(it->second, it_copy->second); + Option* opt_ptr = it->second.get(); + Option* opt_copy_ptr = it_copy->second.get(); + EXPECT_TRUE(typeid(*opt_ptr) == typeid(*opt_copy_ptr)); + } + + std::vector buf = option->toBinary(true); + std::vector buf_copy = option_copy->toBinary(true); + + ASSERT_EQ(buf.size(), buf_copy.size()); + EXPECT_TRUE(std::equal(buf_copy.begin(), buf_copy.end(), buf.begin())); +} + +void testOption(const OpType& op_type) { + OptionBuffer buf(10, 1); + OptionPtr option(new Option(Option::V4, 1, buf)); + OptionPtr option_copy(new Option(Option::V6, 1000)); + + ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + + std::vector binary_copy = option_copy->toBinary(true); + + OptionBuffer buf_modified(10, 2); + option->setData(buf_modified.begin(), buf_modified.end()); + + std::vector binary_modified = option->toBinary(true); + + ASSERT_EQ(binary_modified.size(), binary_copy.size()); + EXPECT_FALSE(std::equal(binary_copy.begin(), binary_copy.end(), + binary_modified.begin())); +} + +TEST(OptionCopyTest, optionConstructor) { + testOption(COPY); +} + +TEST(OptionCopyTest, optionClone) { + testOption(CLONE); +} + +TEST(OptionCopyTest, optionAssignment) { + testOption(ASSIGN); +} + + +void testOptionInt(const OpType& op_type) { + OptionUint16Ptr option(new OptionUint16(Option::V4, 1, 12345)); + OptionUint16Ptr option_copy(new OptionUint16(Option::V6, 10, 11111)); + + ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + + ASSERT_EQ(12345, option->getValue()); + ASSERT_EQ(12345, option_copy->getValue()); + + option->setValue(9); + ASSERT_EQ(9, option->getValue()); + EXPECT_EQ(12345, option_copy->getValue()); +} + +TEST(OptionCopyTest, optionIntConstructor) { + testOptionInt(COPY); +} + +TEST(OptionCopyTest, optionIntClone) { + testOptionInt(CLONE); +} + +TEST(OptionCopyTest, optionIntAssignment) { + testOptionInt(ASSIGN); +} + +void testOptionIntArray(const OpType& op_type) { + OptionUint32ArrayPtr option(new OptionUint32Array(Option::V4, 1));; + option->addValue(2345); + option->addValue(3456); + OptionUint32ArrayPtr option_copy(new OptionUint32Array(Option::V6, 10)); + option_copy->addValue(5678); + option_copy->addValue(6789); + + ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + + option->setValues(std::vector(2, 7)); + + std::vector values_copy = option_copy->getValues(); + ASSERT_EQ(2, values_copy.size()); + EXPECT_EQ(2345, values_copy[0]); + EXPECT_EQ(3456, values_copy[1]); +} + +TEST(OptionCopyTest, optionIntArrayConstructor) { + testOptionIntArray(COPY); +} + +TEST(OptionCopyTest, optionIntArrayClone) { + testOptionIntArray(CLONE); +} + +TEST(OptionCopyTest, optionIntArrayAssignment) { + testOptionIntArray(ASSIGN); +} + +template +void testOptionAddrLst(const OpType& op_type, + const IOAddress& option_address, + const IOAddress& option_copy_address, + const IOAddress& option_modified_address) { + typedef boost::shared_ptr OptionTypePtr; + OptionTypePtr option(new OptionType(1, option_address)); + OptionTypePtr option_copy(new OptionType(10, option_copy_address)); + + ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + + option->setAddress(option_modified_address); + typename OptionType::AddressContainer addrs_copy = option_copy->getAddresses(); + ASSERT_EQ(1, addrs_copy.size()); + EXPECT_EQ(option_address.toText(), addrs_copy[0].toText()); +} + +void testOption4AddrLst(const OpType& op_type) { + testOptionAddrLst(op_type, + IOAddress("127.0.0.1"), + IOAddress("192.0.2.111"), + IOAddress("127.0.0.1")); +} + +void testOption6AddrLst(const OpType& op_type) { + testOptionAddrLst(op_type, + IOAddress("2001:db8:1::2"), + IOAddress("3001::cafe"), + IOAddress("3000:1::1")); +} + +TEST(OptionCopyTest, option4AddrLstConstructor) { + testOption4AddrLst(COPY); +} + +TEST(OptionCopyTest, option4AddrLstClone) { + testOption4AddrLst(CLONE); +} + +TEST(OptionCopyTest, option4AddrLstAssignment) { + testOption4AddrLst(ASSIGN); +} + +TEST(OptionCopyTest, option6AddrLstConstructor) { + testOption6AddrLst(COPY); +} + +TEST(OptionCopyTest, option6AddrLstClone) { + testOption6AddrLst(CLONE); +} + +TEST(OptionCopyTest, option6AddrLstAssignment) { + testOption6AddrLst(ASSIGN); +} + +void testOption6IA(const OpType& op_type) { + Option6IAPtr option(new Option6IA(D6O_IA_NA, 1234)); + option->setT1(1000); + option->setT2(2000); + Option6IAPtr option_copy(new Option6IA(D6O_IA_PD, 5678)); + + ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + + option->setT1(3000); + option->setT2(4000); + option->setIAID(5678); + + EXPECT_EQ(1000, option_copy->getT1()); + EXPECT_EQ(2000, option_copy->getT2()); + EXPECT_EQ(1234, option_copy->getIAID()); +} + +TEST(OptionCopyTest, option6IAConstructor) { + testOption6IA(COPY); +} + +TEST(OptionCopyTest, option6IAClone) { + testOption6IA(CLONE); +} + +TEST(OptionCopyTest, option6IAAssignment) { + testOption6IA(ASSIGN); +} + +void testOption6IAAddr(const OpType& op_type) { + Option6IAAddrPtr option(new Option6IAAddr(D6O_IAADDR, + IOAddress("2001:db8:1::1"), + 60, 90)); + Option6IAAddrPtr option_copy(new Option6IAAddr(D6O_IAADDR, + IOAddress("2001:db8:1::2"), + 50, 80)); + + ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + + option->setAddress(IOAddress("2001:db8:1::3")); + option->setPreferred(1000); + option->setValid(2000); + + EXPECT_EQ("2001:db8:1::1", option_copy->getAddress().toText()); + EXPECT_EQ(60, option_copy->getPreferred()); + EXPECT_EQ(90, option_copy->getValid()); +} + +TEST(OptionCopyTest, option6IAAddrConstructor) { + testOption6IAAddr(COPY); +} + +TEST(OptionCopyTest, option6IAAddrClone) { + testOption6IAAddr(CLONE); +} + +TEST(OptionCopyTest, option6IAAddrAssignment) { + testOption6IAAddr(ASSIGN); +} + +void testOption6IAPrefix(const OpType& op_type) { + Option6IAPrefixPtr option(new Option6IAPrefix(D6O_IAPREFIX, + IOAddress("3000::"), + 64, 60, 90)); + Option6IAPrefixPtr option_copy(new Option6IAPrefix(D6O_IAPREFIX, + IOAddress("3001::"), + 48, 50, 80)); + + ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + + option->setPrefix(IOAddress("3002::"), 32); + option->setPreferred(1000); + option->setValid(2000); + + EXPECT_EQ("3000::", option_copy->getAddress().toText()); + EXPECT_EQ(64, option_copy->getLength()); + EXPECT_EQ(60, option_copy->getPreferred()); + EXPECT_EQ(90, option_copy->getValid()); +} + +TEST(OptionCopyTest, option6IAPrefixConstructor) { + testOption6IAPrefix(COPY); +} + +TEST(OptionCopyTest, option6IAPrefixClone) { + testOption6IAPrefix(CLONE); +} + +TEST(OptionCopyTest, option6IAPrefixAssignment) { + testOption6IAPrefix(ASSIGN); +} + +void testOption6StatusCode(const OpType& op_type) { + Option6StatusCodePtr option(new Option6StatusCode(STATUS_NoBinding, + "no binding")); + Option6StatusCodePtr option_copy(new Option6StatusCode(STATUS_Success, + "success")); + + ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + + option->setStatusCode(STATUS_NoAddrsAvail); + option->setStatusMessage("foo"); + + EXPECT_EQ(STATUS_NoBinding, option_copy->getStatusCode()); + EXPECT_EQ("no binding", option_copy->getStatusMessage()); +} + +TEST(OptionCopyTest, option6StatusCodeConstructor) { + testOption6StatusCode(COPY); +} + +TEST(OptionCopyTest, option6StatusCodeClone) { + testOption6StatusCode(CLONE); +} + +TEST(OptionCopyTest, option6StatusCodeAssignment) { + testOption6StatusCode(ASSIGN); +} + +void testOptionString(const OpType& op_type) { + OptionStringPtr option(new OptionString(Option::V4, 1, "option value")); + OptionStringPtr option_copy(new OptionString(Option::V6, 10, + "another value")); + + ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + + option->setValue("foo"); + EXPECT_EQ("option value", option_copy->getValue()); +} + +TEST(OptionCopyTest, optionStringConstructor) { + testOptionString(COPY); +} + +TEST(OptionCopyTest, optionStringClone) { + testOptionString(CLONE); +} + +TEST(OptionCopyTest, optionStringAssignment) { + testOptionString(ASSIGN); +} + +void testOptionVendor(const OpType& op_type) { + OptionVendorPtr option(new OptionVendor(Option::V4, 2986)); + OptionVendorPtr option_copy(new OptionVendor(Option::V6, 1111)); + + ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + + option->setVendorId(2222); + EXPECT_EQ(2986, option_copy->getVendorId()); +} + +TEST(OptionCopyTest, optionVendorConstructor) { + testOptionVendor(COPY); +} + +TEST(OptionCopyTest, optionVendorClone) { + testOptionVendor(CLONE); +} + +TEST(OptionCopyTest, optionVendorAssignment) { + testOptionVendor(ASSIGN); +} + +void testOptionVendorClass(const OpType& op_type) { + OptionVendorClassPtr option(new OptionVendorClass(Option::V4, 2986)); + OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_1_BYTE); + tuple = "vendor-class-value"; + option->setTuple(0, tuple); + OptionVendorClassPtr option_copy(new OptionVendorClass(Option::V6, + 1111)); + OpaqueDataTuple tuple_copy(OpaqueDataTuple::LENGTH_2_BYTES); + tuple = "vendor-class-assigned"; + option_copy->addTuple(tuple_copy); + + ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + + tuple = "modified-vendor-class-value"; + option->setTuple(0, tuple); + tuple = "another-modified-vendor-class-value"; + option->addTuple(tuple); + + ASSERT_EQ(1, option_copy->getTuplesNum()); + tuple = option_copy->getTuple(0); + EXPECT_TRUE(tuple.equals("vendor-class-value")); +} + +TEST(OptionCopyTest, optionVendorClassConstructor) { + testOptionVendorClass(COPY); +} + +TEST(OptionCopyTest, optionVendorClassClone) { + testOptionVendorClass(CLONE); +} + +TEST(OptionCopyTest, optionVendorClassAssignment) { + testOptionVendorClass(ASSIGN); +} + +template +void testOptionClientFqdn(const OpType& op_type, + boost::shared_ptr& option, + boost::shared_ptr& option_copy) { + ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + + option->setDomainName("newname", OptionType::PARTIAL); + option->setFlag(OptionType::FLAG_S, false); + option->setFlag(OptionType::FLAG_N, true); + + Option4ClientFqdnPtr option4 = + boost::dynamic_pointer_cast(option); + if (option4) { + option4->setRcode(64); + } + + EXPECT_EQ("myname.example.org.", option_copy->getDomainName()); + EXPECT_EQ(OptionType::FULL, option_copy->getDomainNameType()); + EXPECT_TRUE(option_copy->getFlag(OptionType::FLAG_S)); + EXPECT_FALSE(option_copy->getFlag(OptionType::FLAG_N)); + + Option4ClientFqdnPtr option_copy4 = + boost::dynamic_pointer_cast(option_copy); + if (option_copy4) { + EXPECT_EQ(255, option_copy4->getRcode().first.getCode()); + EXPECT_EQ(255, option_copy4->getRcode().second.getCode()); + } +} + +void testOption4ClientFqdn(const OpType& op_type) { + Option4ClientFqdnPtr + option(new Option4ClientFqdn(Option4ClientFqdn::FLAG_S, + Option4ClientFqdn::Rcode(255), + "myname.example.org")); + Option4ClientFqdnPtr + option_copy(new Option4ClientFqdn(Option4ClientFqdn::FLAG_O, + Option4ClientFqdn::Rcode(0), + "other.example.org")); + + ASSERT_NO_FATAL_FAILURE(testOptionClientFqdn(op_type, option, + option_copy)); +} + +TEST(OptionCopyTest, option4ClientFqdnConstructor) { + testOption4ClientFqdn(COPY); +} + +TEST(OptionCopyTest, option4ClientFqdnClone) { + testOption4ClientFqdn(CLONE); +} + +TEST(OptionCopyTest, option4ClientFqdnAssignment) { + testOption4ClientFqdn(ASSIGN); +} + +void testOption6ClientFqdn(const OpType& op_type) { + Option6ClientFqdnPtr + option(new Option6ClientFqdn(Option6ClientFqdn::FLAG_S, + "myname.example.org")); + Option6ClientFqdnPtr + option_copy(new Option6ClientFqdn(Option6ClientFqdn::FLAG_O, + "other.example.org")); + + ASSERT_NO_FATAL_FAILURE(testOptionClientFqdn(op_type, option, + option_copy)); +} + +TEST(OptionCopyTest, option6ClientFqdnConstructor) { + testOption6ClientFqdn(COPY); +} + +TEST(OptionCopyTest, option6ClientFqdnClone) { + testOption6ClientFqdn(CLONE); +} + +TEST(OptionCopyTest, option6ClientFqdnAssignment) { + testOption6ClientFqdn(ASSIGN); +} + +void testOptionCustom(const OpType& op_type) { + OptionDefinition def("foo", 1, "uint16", true); + OptionCustomPtr option(new OptionCustom(def, Option::V4)); + OptionDefinition def_assigned("bar", 10, "record"); + def_assigned.addRecordField("ipv4-address"); + def_assigned.addRecordField("uint32"); + OptionCustomPtr option_copy(new OptionCustom(def_assigned, Option::V6)); + + ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); +} + +TEST(OptionCopyTest, optionCustomConstructor) { + testOptionCustom(COPY); +} + +TEST(OptionCopyTest, optionCustomClone) { + testOptionCustom(CLONE); +} + +TEST(OptionCopyTest, optionCustomAssignment) { + testOptionCustom(ASSIGN); +} + +void testOptionOpaqueDataTuples(const OpType& op_type) { + OptionOpaqueDataTuplesPtr option(new OptionOpaqueDataTuples(Option::V4, 1)); + OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_1_BYTE); + tuple = "a string"; + option->addTuple(tuple); + tuple = "another string"; + option->addTuple(tuple); + OptionOpaqueDataTuplesPtr option_copy(new OptionOpaqueDataTuples(Option::V6, 10)); + OpaqueDataTuple tuple_copy(OpaqueDataTuple::LENGTH_2_BYTES); + tuple_copy = "copy string"; + option_copy->addTuple(tuple_copy); + + ASSERT_NO_FATAL_FAILURE(testCopyAssign(op_type, option, option_copy)); + + tuple = "modified-first-tuple"; + option->setTuple(0, tuple); + tuple = "modified-second-tuple"; + option->addTuple(tuple); + + ASSERT_EQ(2, option_copy->getTuplesNum()); + EXPECT_TRUE(option_copy->getTuple(0).equals("a string")); + EXPECT_TRUE(option_copy->getTuple(1).equals("another string")); +} + +TEST(OptionCopyTest, optionOpaqueDataTuplesConstructor) { + testOptionOpaqueDataTuples(COPY); +} + +TEST(OptionCopyTest, optionOpaqueDataTuplesClone) { + testOptionOpaqueDataTuples(CLONE); +} + +TEST(OptionCopyTest, optionOpaqueDataTuplesAssign) { + testOptionOpaqueDataTuples(ASSIGN); +} + +} diff --git a/src/lib/dhcp/tests/option_opaque_data_tuples_unittest.cc b/src/lib/dhcp/tests/option_opaque_data_tuples_unittest.cc index 34922bf13e..6bbd76660f 100644 --- a/src/lib/dhcp/tests/option_opaque_data_tuples_unittest.cc +++ b/src/lib/dhcp/tests/option_opaque_data_tuples_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -58,6 +58,12 @@ TEST(OptionOpaqueDataTuples, addTuple) { // for DHCPv6 option. OpaqueDataTuple tuple2(OpaqueDataTuple::LENGTH_1_BYTE); EXPECT_THROW(data_tuple.addTuple(tuple2), isc::BadValue); + + // Similarly, adding a tuple with 2 bytes long length field should + // fail for DHCPv4 option. + OptionOpaqueDataTuples data_tuple2(Option::V4, 65); + OpaqueDataTuple tuple3(OpaqueDataTuple::LENGTH_2_BYTES); + EXPECT_THROW(data_tuple2.addTuple(tuple3), isc::BadValue); } // This test checks that it is possible to replace existing tuple. diff --git a/src/lib/dhcp/tests/option_unittest.cc b/src/lib/dhcp/tests/option_unittest.cc index 3d8289d47f..38eab46178 100644 --- a/src/lib/dhcp/tests/option_unittest.cc +++ b/src/lib/dhcp/tests/option_unittest.cc @@ -6,9 +6,12 @@ #include +#include #include #include #include +#include +#include #include #include @@ -24,6 +27,7 @@ using namespace std; using namespace isc; +using namespace isc::asiolink; using namespace isc::dhcp; using namespace isc::util; using boost::scoped_ptr;