]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[4497] Implemented deep copy of DHCP options.
authorMarcin Siodelski <marcin@isc.org>
Fri, 24 Jun 2016 11:32:39 +0000 (13:32 +0200)
committerMarcin Siodelski <marcin@isc.org>
Fri, 8 Jul 2016 05:50:19 +0000 (07:50 +0200)
35 files changed:
src/lib/dhcp/option.cc
src/lib/dhcp/option.h
src/lib/dhcp/option4_addrlst.cc
src/lib/dhcp/option4_addrlst.h
src/lib/dhcp/option4_client_fqdn.cc
src/lib/dhcp/option4_client_fqdn.h
src/lib/dhcp/option6_addrlst.cc
src/lib/dhcp/option6_addrlst.h
src/lib/dhcp/option6_client_fqdn.cc
src/lib/dhcp/option6_client_fqdn.h
src/lib/dhcp/option6_ia.cc
src/lib/dhcp/option6_ia.h
src/lib/dhcp/option6_iaaddr.cc
src/lib/dhcp/option6_iaaddr.h
src/lib/dhcp/option6_iaprefix.cc
src/lib/dhcp/option6_iaprefix.h
src/lib/dhcp/option6_status_code.cc
src/lib/dhcp/option6_status_code.h
src/lib/dhcp/option_custom.cc
src/lib/dhcp/option_custom.h
src/lib/dhcp/option_int.h
src/lib/dhcp/option_int_array.h
src/lib/dhcp/option_opaque_data_tuples.cc
src/lib/dhcp/option_opaque_data_tuples.h
src/lib/dhcp/option_string.cc
src/lib/dhcp/option_string.h
src/lib/dhcp/option_vendor.cc
src/lib/dhcp/option_vendor.h
src/lib/dhcp/option_vendor_class.cc
src/lib/dhcp/option_vendor_class.h
src/lib/dhcp/tests/Makefile.am
src/lib/dhcp/tests/libdhcp++_unittest.cc
src/lib/dhcp/tests/option_copy_unittest.cc [new file with mode: 0644]
src/lib/dhcp/tests/option_opaque_data_tuples_unittest.cc
src/lib/dhcp/tests/option_unittest.cc

index d91c4a411c9f741ac28dc26ed199d5673997d52a..d3bf8ad408d19e1fda66e26ae97bae88796fb2f5 100644 (file)
@@ -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() ) {
index 181f28924a830dc53ded0cca588fa3d5235f433c..b5e385c5c66352b6b5045a14035427cdf16b96cd 100644 (file)
@@ -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<typename OptionType>
+    OptionPtr cloneInternal() const {
+        boost::shared_ptr<OptionType>
+            option(new OptionType(*dynamic_cast<const OptionType*>(this)));
+        return (option);
+    }
+
     /// @brief Store option's header in a buffer.
     ///
     /// This method writes option's header into a buffer in the
index 981fe8dc753e5e5beffde903b23cdd73c5fa4b8d..61bdc4f2f69d8ec9b16a2afe549d0a5dd7d2e742 100644 (file)
@@ -55,6 +55,11 @@ Option4AddrLst::Option4AddrLst(uint8_t type, const IOAddress& addr)
     setAddress(addr);
 }
 
+OptionPtr
+Option4AddrLst::clone() const {
+    return (cloneInternal<Option4AddrLst>());
+}
+
 void
 Option4AddrLst::pack(isc::util::OutputBuffer& buf) const {
 
index 02777569f268630f69735d6e23780a0c8c2f04d9..e1448ce29d49a3dd751dab6f4b9ab5b1369948a9 100644 (file)
@@ -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.
index 5dd571bceb6e621a618984ea2d3ac6eb3073b580..e5057076a723e0e34fbb6f2fb48ec149fda02c0f 100644 (file)
@@ -346,11 +346,17 @@ Option4ClientFqdn::Option4ClientFqdn(const Option4ClientFqdn& source)
       impl_(new Option4ClientFqdnImpl(*source.impl_)) {
 }
 
+OptionPtr
+Option4ClientFqdn::clone() const {
+    return (cloneInternal<Option4ClientFqdn>());
+}
+
 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::Rcode, Option4ClientFqdn::Rcode>
+Option4ClientFqdn::getRcode() const {
+    return (std::make_pair(impl_->rcode1_, impl_->rcode2_));
+}
+
 void
 Option4ClientFqdn::setRcode(const Rcode& rcode) {
     impl_->rcode1_ = rcode;
index c23bb8ecc769a5013fbe0ec0a072745eca16c357..5656112e693b8f16057eb3781849af7c60cfadf1 100644 (file)
@@ -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 <dns/name.h>
 
 #include <string>
+#include <utility>
 
 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<Rcode, Rcode> getRcode() const;
+
     /// @brief Set Rcode value.
     ///
     /// @param rcode An @c Rcode object representing value of RCODE1 and RCODE2.
index f71537c254b31dedc59ae7c39d001483d111bd26..ab505c4da745f0fd8bab255ca52b5b52fbc1f944 100644 (file)
@@ -41,6 +41,11 @@ Option6AddrLst::Option6AddrLst(uint16_t type, OptionBufferConstIter begin,
     unpack(begin, end);
 }
 
+OptionPtr
+Option6AddrLst::clone() const {
+    return (cloneInternal<Option6AddrLst>());
+}
+
 void
 Option6AddrLst::setAddress(const isc::asiolink::IOAddress& addr) {
     if (!addr.isV6()) {
index 0b22a1b4f8845fd4d62c69bb2f95b798d010a83d..217b76ffa045d5deb68a0980763ea026cbecf2e7 100644 (file)
@@ -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
index 020f8efe24d8a295524b206823f2a36169fec0a0..700146a98c57104231b1d5f61003c9e6c927b843 100644 (file)
@@ -293,11 +293,17 @@ Option6ClientFqdn::Option6ClientFqdn(const Option6ClientFqdn& source)
       impl_(new Option6ClientFqdnImpl(*source.impl_)) {
 }
 
+OptionPtr
+Option6ClientFqdn::clone() const {
+    return (cloneInternal<Option6ClientFqdn>());
+}
+
 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);
index 3f7d5f6c9c56e2e8783984b331d4e94e62d47b2a..35c55d15201c8af238c7acdeb895da7cbd78c3d4 100644 (file)
@@ -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();
 
index bfcce7e244a76d57d58bc8ea46f79fd1f89056b5..887ec1e64545bccc90afed37a8c83c92498a1760 100644 (file)
@@ -48,6 +48,11 @@ Option6IA::Option6IA(uint16_t type, OptionBufferConstIter begin,
     unpack(begin, end);
 }
 
+OptionPtr
+Option6IA::clone() const {
+    return (cloneInternal<Option6IA>());
+}
+
 void Option6IA::pack(isc::util::OutputBuffer& buf) const {
     buf.writeUint16(type_);
     buf.writeUint16(len() - OPTION6_HDR_LEN);
index 315b6ff3ef5e0ce48084752075702f31331da6e3..b29c77727fdf96585c7cf48d16a84d1412fdbb44 100644 (file)
@@ -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.
     ///
index 4f6812130dbab7b03c83a9cea719d159411ef67b..477be9e60357ea56e22a35385cf288bfca36eeb8 100644 (file)
@@ -42,6 +42,11 @@ Option6IAAddr::Option6IAAddr(uint32_t type, OptionBuffer::const_iterator begin,
     unpack(begin, end);
 }
 
+OptionPtr
+Option6IAAddr::clone() const {
+    return (cloneInternal<Option6IAAddr>());
+}
+
 void Option6IAAddr::pack(isc::util::OutputBuffer& buf) const {
 
     buf.writeUint16(type_);
index 1425a4ce1f34af029b0494b8d2b649b277c0ac1c..47092699655082661dff8842ddf73a36879ef814 100644 (file)
@@ -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
index 5b96247169a990adc7ae673e3388f3bfd8ff2b63..95dacd6127df16036984438ed71a7809bc4c4cec 100644 (file)
@@ -44,6 +44,11 @@ Option6IAPrefix::Option6IAPrefix(uint32_t type, OptionBuffer::const_iterator beg
     unpack(begin, end);
 }
 
+OptionPtr
+Option6IAPrefix::clone() const {
+    return (cloneInternal<Option6IAPrefix>());
+}
+
 void Option6IAPrefix::pack(isc::util::OutputBuffer& buf) const {
     if (!addr_.isV6()) {
         isc_throw(isc::BadValue, addr_ << " is not an IPv6 address");
index e6c588d5e90a0641cfe522ffcfb716ff8d3944ac..c9be8ee68150438113013396b99ab7b823ecc3e1 100644 (file)
@@ -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
index e46315839f29cc742f8c76d9a96a43ba11ed7ab1..f0de03bab43d2611f0a8234b77979e45298e45f0 100644 (file)
@@ -40,6 +40,11 @@ Option6StatusCode::Option6StatusCode(OptionBufferConstIter begin,
     unpack(begin, end);
 }
 
+OptionPtr
+Option6StatusCode::clone() const {
+    return (cloneInternal<Option6StatusCode>());
+}
+
 void
 Option6StatusCode::pack(isc::util::OutputBuffer& buf) const {
     // Pack option header.
index c022c59e43844e3b9423a737c78462e90c45c620..3b012186f0e7247c7c6f0dc0f3fa97015c7e1693 100644 (file)
@@ -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
index 1d99da744963dac6cebcb438d8f2b61108d5a6ee..e8680834295b403a5aa26b7a450ccb555405e85e 100644 (file)
@@ -40,6 +40,11 @@ OptionCustom::OptionCustom(const OptionDefinition& def,
     createBuffers(getData());
 }
 
+OptionPtr
+OptionCustom::clone() const {
+    return (cloneInternal<OptionCustom>());
+}
+
 void
 OptionCustom::addArrayDataField(const asiolink::IOAddress& address) {
     checkArrayType();
index e766ebef18eab2f69787696f589b524d2d681e0a..28eb35dc48d7ad53158f2e56d4d62942b7391a13 100644 (file)
@@ -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
index 2aa81ecbc894edabc18f7df5458524244bfed30d..fd5d233320a3667dfd420d39533360785ea28968 100644 (file)
@@ -46,6 +46,9 @@ typedef boost::shared_ptr<OptionUint32> OptionUint32Ptr;
 /// @param T data field type (see above).
 template<typename T>
 class OptionInt: public Option {
+private:
+
+    typedef boost::shared_ptr<OptionInt<T> > OptionIntTypePtr;
 
 public:
     /// @brief Constructor.
@@ -90,6 +93,10 @@ public:
         unpack(begin, end);
     }
 
+    virtual OptionPtr clone() const {
+        return (cloneInternal<OptionInt<T> >());
+    }
+
     /// Writes option in wire-format to buf, returns pointer to first unused
     /// byte after stored option.
     ///
index d8a533ab7f9ca0a9466c82c864010719da5756c3..d29bc89bf3ad70268871e7354745b0047ff25627 100644 (file)
@@ -11,6 +11,7 @@
 #include <dhcp/option.h>
 #include <dhcp/option_data_types.h>
 #include <util/io_utilities.h>
+#include <boost/shared_ptr.hpp>
 #include <sstream>
 #include <stdint.h>
 
@@ -53,6 +54,9 @@ typedef boost::shared_ptr<OptionUint32Array> OptionUint32ArrayPtr;
 /// @param T data field type (see above).
 template<typename T>
 class OptionIntArray: public Option {
+private:
+
+    typedef boost::shared_ptr<OptionIntArray<T> > OptionIntArrayTypePtr;
 
 public:
 
@@ -116,6 +120,10 @@ public:
         unpack(begin, end);
     }
 
+    virtual OptionPtr clone() const {
+        return (cloneInternal<OptionIntArray<T> >());
+    }
+
     /// @brief Adds a new value to the array.
     ///
     /// @param value a value being added.
index 28a4a5982ad02e8157bbbbafaeaa858f7717d034..1fc5c614ea04a05e592b8a9a72a1834a68c6f4c1 100644 (file)
@@ -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<OptionOpaqueDataTuples>());
+}
+
 void
 OptionOpaqueDataTuples::pack(isc::util::OutputBuffer& buf) const {
     packHeader(buf);
index 18b977c5e551c31ab0a781207d272c68c164bbf9..64823ee8bf0853879b779e41bddb6bfd7ebc135f 100644 (file)
@@ -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.
index 4e8e6b3a3d04187788c28f0e9ef2205c6be652b3..553f84fee53335dbe27fb67b570e9cd9fd2476ab 100644 (file)
@@ -27,6 +27,11 @@ OptionString::OptionString(const Option::Universe u, const uint16_t type,
     unpack(begin, end);
 }
 
+OptionPtr
+OptionString::clone() const {
+    return (cloneInternal<OptionString>());
+}
+
 std::string
 OptionString::getValue() const {
     const OptionBuffer& data = getData();
index d3a8f83b0d83dc18fe487584e1a46bdf2e52f468..701c3705074b7e13845c19d353a4d90fafaefa81 100644 (file)
@@ -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.
index dd85a2793cff861f4b81e28de683a22be4c1d978..25fed0047e1ef817592323c1255b267fc2522668 100644 (file)
@@ -23,6 +23,10 @@ OptionVendor::OptionVendor(Option::Universe u, OptionBufferConstIter begin,
     unpack(begin, end);
 }
 
+OptionPtr
+OptionVendor::clone() const {
+    return (cloneInternal<OptionVendor>());
+}
 
 void OptionVendor::pack(isc::util::OutputBuffer& buf) const {
     packHeader(buf);
index a0b5b1734e2f451bbd25df634a84aa43dadc2fad..7dddf42e0054b7072bcfa2f203376bcaaceea92f 100644 (file)
@@ -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.
     ///
index 7ecf5d1e4f007bac57fb25cbf8e0890d6f680348..3e1ec161d1015574011fbb6e249ed99e3325404b 100644 (file)
@@ -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<OptionVendorClass>());
+}
+
 void
 OptionVendorClass::pack(isc::util::OutputBuffer& buf) const {
     packHeader(buf);
index 2018c838fdd7abc3710e659b52b482b5e73cddbe..b00f9f189cc19a63af1414db3112a0fe0460176d 100644 (file)
@@ -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.
index c0c584e712aecc4a609a19605314db7e1a3aabe5..caf369ac815dcab9da1053ceb789a0ede0f634cf 100644 (file)
@@ -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
index 8c50d79a2f78c5354718f479d5b9e44200c16188..6b3f98e8e65ad3bf83950f2ba5502dfa2d339e6b 100644 (file)
@@ -36,6 +36,7 @@
 
 #include <iostream>
 #include <sstream>
+#include <typeinfo>
 
 #include <arpa/inet.h>
 
diff --git a/src/lib/dhcp/tests/option_copy_unittest.cc b/src/lib/dhcp/tests/option_copy_unittest.cc
new file mode 100644 (file)
index 0000000..10429c9
--- /dev/null
@@ -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 <config.h>
+
+#include <asiolink/io_address.h>
+#include <dhcp/dhcp6.h>
+#include <dhcp/opaque_data_tuple.h>
+#include <dhcp/option.h>
+#include <dhcp/option_custom.h>
+#include <dhcp/option_definition.h>
+#include <dhcp/option_int.h>
+#include <dhcp/option_int_array.h>
+#include <dhcp/option_opaque_data_tuples.h>
+#include <dhcp/option_string.h>
+#include <dhcp/option_vendor.h>
+#include <dhcp/option_vendor_class.h>
+#include <dhcp/option4_addrlst.h>
+#include <dhcp/option4_client_fqdn.h>
+#include <dhcp/option6_addrlst.h>
+#include <dhcp/option6_client_fqdn.h>
+#include <dhcp/option6_ia.h>
+#include <dhcp/option6_iaaddr.h>
+#include <dhcp/option6_iaprefix.h>
+#include <dhcp/option6_status_code.h>
+#include <util/buffer.h>
+
+#include <boost/pointer_cast.hpp>
+#include <gtest/gtest.h>
+
+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<typename OptionType>
+void testCopyAssign(const OpType& op_type,
+                    boost::shared_ptr<OptionType>& option,
+                    boost::shared_ptr<OptionType>& 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<OptionType>(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<uint8_t> buf = option->toBinary(true);
+    std::vector<uint8_t> 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<uint8_t> binary_copy = option_copy->toBinary(true);
+
+    OptionBuffer buf_modified(10, 2);
+    option->setData(buf_modified.begin(), buf_modified.end());
+
+    std::vector<uint8_t> 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<uint32_t>(2, 7));
+
+    std::vector<uint32_t> 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<typename OptionType>
+void testOptionAddrLst(const OpType& op_type,
+                       const IOAddress& option_address,
+                       const IOAddress& option_copy_address,
+                       const IOAddress& option_modified_address) {
+    typedef boost::shared_ptr<OptionType> 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<Option4AddrLst>(op_type,
+                                      IOAddress("127.0.0.1"),
+                                      IOAddress("192.0.2.111"),
+                                      IOAddress("127.0.0.1"));
+}
+
+void testOption6AddrLst(const OpType& op_type) {
+    testOptionAddrLst<Option6AddrLst>(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<typename OptionType>
+void testOptionClientFqdn(const OpType& op_type,
+                          boost::shared_ptr<OptionType>& option,
+                          boost::shared_ptr<OptionType>& 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<Option4ClientFqdn>(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<Option4ClientFqdn>(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<Option4ClientFqdn>(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<Option6ClientFqdn>(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);
+}
+
+}
index 34922bf13eb32623849b0fdda34d0182172040be..6bbd76660f62c95fdb627074de15872259fa122a 100644 (file)
@@ -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.
index 3d8289d47fcfb3eea809da175e3db3220f128e9b..38eab46178237e6ab5c7a5b0de3ca057acdbafd2 100644 (file)
@@ -6,9 +6,12 @@
 
 #include <config.h>
 
+#include <asiolink/io_address.h>
 #include <dhcp/dhcp6.h>
 #include <dhcp/libdhcp++.h>
 #include <dhcp/option.h>
+#include <dhcp/option_int.h>
+#include <dhcp/option4_addrlst.h>
 #include <exceptions/exceptions.h>
 #include <util/buffer.h>
 
@@ -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;