BIND 10 trac2304, updated. 31c8d5e0b4cdec573baf77f09fca75a362f641b6 [2304] Added Option6IntArray option type and unit tests.

BIND 10 source code commits bind10-changes at lists.isc.org
Fri Oct 5 18:42:34 UTC 2012


The branch, trac2304 has been updated
       via  31c8d5e0b4cdec573baf77f09fca75a362f641b6 (commit)
      from  273e195ef434e87ebf9838381d4b49e8a3081acb (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 31c8d5e0b4cdec573baf77f09fca75a362f641b6
Author: Marcin Siodelski <marcin at isc.org>
Date:   Fri Oct 5 20:42:20 2012 +0200

    [2304] Added Option6IntArray option type and unit tests.

-----------------------------------------------------------------------

Summary of changes:
 src/lib/dhcp/Makefile.am                           |    1 +
 src/lib/dhcp/option6_int.h                         |    8 +-
 .../dhcp/{option6_int.h => option6_int_array.h}    |   91 +++++++++++---------
 src/lib/dhcp/option_data_types.h                   |    1 +
 src/lib/dhcp/option_definition.cc                  |    1 +
 src/lib/dhcp/option_definition.h                   |   24 +++++-
 src/lib/dhcp/tests/option_definition_unittest.cc   |   83 +++++++++++++++++-
 7 files changed, 162 insertions(+), 47 deletions(-)
 copy src/lib/dhcp/{option6_int.h => option6_int_array.h} (64%)

-----------------------------------------------------------------------
diff --git a/src/lib/dhcp/Makefile.am b/src/lib/dhcp/Makefile.am
index ef887d5..47d482c 100644
--- a/src/lib/dhcp/Makefile.am
+++ b/src/lib/dhcp/Makefile.am
@@ -28,6 +28,7 @@ libb10_dhcp___la_SOURCES += option6_iaaddr.cc option6_iaaddr.h
 libb10_dhcp___la_SOURCES += option6_addrlst.cc option6_addrlst.h
 libb10_dhcp___la_SOURCES += option4_addrlst.cc option4_addrlst.h
 libb10_dhcp___la_SOURCES += option6_int.h
+libb10_dhcp___la_SOURCES += option6_int_array.h
 libb10_dhcp___la_SOURCES += dhcp6.h dhcp4.h
 libb10_dhcp___la_SOURCES += pkt6.cc pkt6.h
 libb10_dhcp___la_SOURCES += pkt4.cc pkt4.h
diff --git a/src/lib/dhcp/option6_int.h b/src/lib/dhcp/option6_int.h
index 6531499..1ecf3dc 100644
--- a/src/lib/dhcp/option6_int.h
+++ b/src/lib/dhcp/option6_int.h
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef OPTION_INT6_H_
-#define OPTION_INT6_H_
+#ifndef OPTION6_INT_H_
+#define OPTION6_INT_H_
 
 #include <stdint.h>
 #include <limits>
@@ -144,10 +144,10 @@ public:
 
 private:
 
-    T value_;
+    T value_; ///< Value cabveyed by the option.
 };
 
 } // isc::dhcp namespace
 } // isc namespace
 
-#endif /* OPTION_IA_H_ */
+#endif /* OPTION6_INT_H_ */
diff --git a/src/lib/dhcp/option6_int_array.h b/src/lib/dhcp/option6_int_array.h
new file mode 100644
index 0000000..6783bf3
--- /dev/null
+++ b/src/lib/dhcp/option6_int_array.h
@@ -0,0 +1,164 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef OPTION6_INT_ARRAY_H_
+#define OPTION6_INT_ARRAY_H_
+
+#include <stdint.h>
+#include <limits>
+#include <util/io_utilities.h>
+#include "dhcp/libdhcp++.h"
+#include "dhcp/option.h"
+#include "dhcp/option_data_types.h"
+
+namespace isc {
+namespace dhcp {
+
+/// This template class represents DHCPv6 option with array of
+/// integer values. The type of the elements in the array can be
+/// any of the following:
+/// - uint8_t,
+/// - uint16_t,
+/// - uint32_t,
+/// - int8_t,
+/// - int16_t,
+/// - int32_t.
+///
+/// @param T data field type (see above).
+template<typename T>
+class Option6IntArray: public Option {
+
+public:
+
+    typedef std::vector<T> ValuesCollection;
+
+    /// @brief Constructor.
+    ///
+    /// @param type option type.
+    /// @param value option value.
+    Option6IntArray(uint16_t type, const ValuesCollection& values)
+        : Option(Option::V6, type), values_(values) {
+        if (!OptionDataTypes<T>::valid) {
+            isc_throw(dhcp::InvalidDataType, "non-numeric type");
+        }
+    }
+
+    /// @brief Constructor.
+    ///
+    /// This constructor creates option from a buffer. This construtor
+    /// may throw exception if \ref unpack function throws during buffer
+    /// parsing.
+    ///
+    /// @param type option type.
+    /// @param begin iterator to first byte of option data.
+    /// @param end iterator to end of option data (first byte after option end).
+    ///
+    /// @todo mention here what it throws.
+    Option6IntArray(uint16_t type, OptionBufferConstIter begin,
+                    OptionBufferConstIter end)
+        : Option(Option::V6, type) {
+        if (!OptionDataTypes<T>::valid) {
+            isc_throw(dhcp::InvalidDataType, "non-numeric type");
+        }
+        unpack(begin, end);
+    }
+
+    /// Writes option in wire-format to buf, returns pointer to first unused
+    /// byte after stored option.
+    ///
+    /// @param [out] buf buffer (option will be stored here)
+    ///
+    /// @throw isc::BadValue if invalid option type has been provided.
+    void pack(isc::util::OutputBuffer& buf) {
+        buf.writeUint16(type_);
+        buf.writeUint16(len() - OPTION6_HDR_LEN);
+        for (int i = 0; i < values_.size(); ++i) {
+            switch (OptionDataTypes<T>::len) {
+            case 1:
+                buf.writeUint8(values_[i]);
+                break;
+            case 2:
+                buf.writeUint16(values_[i]);
+                break;
+            case 4:
+                buf.writeUint32(values_[i]);
+                break;
+            default:
+                isc_throw(dhcp::InvalidDataType, "non-numeric type");
+            }
+        }
+    }
+
+    /// @brief Parses received buffer
+    ///
+    /// Parses received buffer and returns offset to the first unused byte after
+    /// parsed option.
+    ///
+    /// @param begin iterator to first byte of option data
+    /// @param end iterator to end of option data (first byte after option end)
+    virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end) {
+        if (distance(begin, end) % sizeof(T) != 0) {
+            isc_throw(OutOfRange, "Option " << type_ << " truncated");
+        }
+        values_.clear();
+        while (begin != end) {
+            switch (OptionDataTypes<T>::len) {
+            case 1:
+                values_.push_back(*begin);
+                break;
+            case 2:
+                values_.push_back(isc::util::readUint16(&(*begin)));
+                break;
+            case 4:
+                values_.push_back(isc::util::readUint32(&(*begin)));
+                break;
+            default:
+                isc_throw(dhcp::InvalidDataType, "non-numeric type");
+            }
+            begin += sizeof(T);
+        }
+
+        LibDHCP::unpackOptions6(OptionBuffer(begin, end), options_);
+    }
+
+    /// @brief Returns collection of values.
+    ///
+    /// @return collection of values.
+    const ValuesCollection& getValues() const { return values_; }
+
+    /// @brief returns complete length of option
+    ///
+    /// Returns length of this option, including option header and suboptions
+    ///
+    /// @return length of this option
+    virtual uint16_t len() {
+        uint16_t length = OPTION6_HDR_LEN + values_.size() * sizeof(T);
+        // length of all suboptions
+        for (Option::OptionCollection::iterator it = options_.begin();
+             it != options_.end();
+             ++it) {
+            length += (*it).second->len();
+        }
+        return (length);
+    }
+
+private:
+
+    ValuesCollection values_;
+};
+
+} // isc::dhcp namespace
+} // isc namespace
+
+#endif /* OPTION6_INT_ARRAY_H_ */
diff --git a/src/lib/dhcp/option_data_types.h b/src/lib/dhcp/option_data_types.h
index d23ae9b..52be59f 100644
--- a/src/lib/dhcp/option_data_types.h
+++ b/src/lib/dhcp/option_data_types.h
@@ -15,6 +15,7 @@
 #ifndef OPTION_DATA_TYPES_H_
 #define OPTION_DATA_TYPES_H_
 
+#include <stdint.h>
 #include <exceptions/exceptions.h>
 
 namespace isc {
diff --git a/src/lib/dhcp/option_definition.cc b/src/lib/dhcp/option_definition.cc
index fef7176..63f3758 100644
--- a/src/lib/dhcp/option_definition.cc
+++ b/src/lib/dhcp/option_definition.cc
@@ -18,6 +18,7 @@
 #include "dhcp/option6_ia.h"
 #include "dhcp/option6_iaaddr.h"
 #include "dhcp/option6_int.h"
+#include "dhcp/option6_int_array.h"
 
 using namespace std;
 using namespace isc::util;
diff --git a/src/lib/dhcp/option_definition.h b/src/lib/dhcp/option_definition.h
index 73df860..ade275a 100644
--- a/src/lib/dhcp/option_definition.h
+++ b/src/lib/dhcp/option_definition.h
@@ -15,7 +15,9 @@
 #ifndef OPTION_DEFINITION_H_
 #define OPTION_DEFINITION_H_
 
+#include "dhcp/option_data_types.h"
 #include "dhcp/option6_int.h"
+#include "dhcp/option6_int_array.h"
 #include "dhcp/option.h"
 
 namespace isc {
@@ -258,7 +260,7 @@ public:
     ///
     /// @param u universe (V6 or V4).
     /// @param type option type.
-    /// @param buf option buffer (must be empty).
+    /// @param buf option buffer.
     /// @param T type of the data field (must be one of the uintX_t or intX_t).
     template<typename T>
     static OptionPtr factoryInteger(Option::Universe, uint16_t type, const OptionBuffer& buf) {
@@ -266,7 +268,25 @@ public:
             isc_throw(isc::OutOfRange, "provided option buffer is too large, expected: "
                       << sizeof(T) << " bytes");
         }
-        OptionPtr option(new Option6Int<T>(type, buf.begin(), buf.begin() + buf.size()));
+        OptionPtr option(new Option6Int<T>(type, buf.begin(), buf.end()));
+        return (option);
+    }
+
+    /// @brief Factory function to create option with array of integer values.
+    ///
+    /// @param u universe (V6 or V4).
+    /// @param type option type.
+    /// @param buf option buffer.
+    /// @param T type of the data field (must be one of the uintX_t or intX_t).
+    template<typename T>
+    static OptionPtr factoryIntegerArray(Option::Universe, uint16_t type, const OptionBuffer& buf) {
+        if (buf.size() == 0) {
+            isc_throw(isc::OutOfRange, "option buffer length must be greater than zero");
+        } else if (buf.size() % OptionDataTypes<T>::len != 0) {
+            isc_throw(isc::OutOfRange, "option buffer length must be multiple of "
+                      << OptionDataTypes<T>::len << " bytes");
+        }
+        OptionPtr option(new Option6IntArray<T>(type, buf.begin(), buf.end()));
         return (option);
     }
 
diff --git a/src/lib/dhcp/tests/option_definition_unittest.cc b/src/lib/dhcp/tests/option_definition_unittest.cc
index 05536b0..d1a7a96 100644
--- a/src/lib/dhcp/tests/option_definition_unittest.cc
+++ b/src/lib/dhcp/tests/option_definition_unittest.cc
@@ -29,6 +29,7 @@
 #include "dhcp/option6_ia.h"
 #include "dhcp/option6_iaaddr.h"
 #include "dhcp/option6_int.h"
+#include "dhcp/option6_int_array.h"
 #include "dhcp/option_definition.h"
 
 using namespace std;
@@ -319,7 +320,7 @@ TEST_F(OptionDefinitionTest, factoryIAAddr6) {
     EXPECT_EQ(0x04050607, option_cast_v6->getValid());
 }
 
-TEST_F(OptionDefinitionTest, factoryIntegerNegative) {
+TEST_F(OptionDefinitionTest, factoryIntegerInvalidType) {
     EXPECT_THROW(
         OptionDefinition::factoryInteger<bool>(Option::V6, D6O_PREFERENCE, OptionBuffer(1)),
         isc::dhcp::InvalidDataType
@@ -408,4 +409,84 @@ TEST_F(OptionDefinitionTest, factoryInteger32) {
     // @todo Add more cases for DHCPv4
 }
 
+TEST_F(OptionDefinitionTest, factoryInteger16Array) {
+    Option::Factory* f = OptionDefinition::factoryIntegerArray<uint16_t>;
+    OptionPtr option_v6;
+    // Provided buffer size must be greater than zero. Check if we
+    // get exception if we provide zero-length buffer.
+    EXPECT_THROW(
+        option_v6 = f(Option::V6, 79, OptionBuffer()),
+        isc::OutOfRange
+    );
+    // Buffer length must be multiple of data type size.
+    EXPECT_THROW(
+        option_v6 = f(Option::V6, 79, OptionBuffer(5)),
+        isc::OutOfRange
+    );
+    // Positive scenario, initiate the buffer with length being
+    // multiple of uint16_t size.
+    // buffer elements will be: 0x112233.
+    OptionBuffer buf(6);
+    for (int i = 0; i < 6; ++i) {
+        buf[i] = i / 2;
+    }
+    // Constructor should succeed because buffer has correct size.
+    EXPECT_NO_THROW(
+        option_v6 = f(Option::V6, 79, buf);
+    );
+    boost::shared_ptr<Option6IntArray<uint16_t> > option_cast_v6 =
+        boost::static_pointer_cast<Option6IntArray<uint16_t> >(option_v6);
+    // Get the values from the initiated options and validate.
+    Option6IntArray<uint16_t>::ValuesCollection values = 
+        option_cast_v6->getValues();
+    for (int i = 0; i < values.size(); ++i) {
+        // Expected value is calculated using on the same pattern
+        // as the one we used to initiate buffer:
+        // for i=0, expected = 0x00, for i = 1, expected == 0x11 etc.
+        uint16_t expected = (i << 8) | i;
+        EXPECT_EQ(expected, values[i]);
+    }
+}
+
+TEST_F(OptionDefinitionTest, factoryInteger32Array) {
+    Option::Factory* f = OptionDefinition::factoryIntegerArray<uint32_t>;
+    const uint16_t opt_code = 80;
+    OptionPtr option_v6;
+    // Provided buffer size must be greater than zero. Check if we
+    // get exception if we provide zero-length buffer.
+    EXPECT_THROW(
+        option_v6 = f(Option::V6, opt_code, OptionBuffer()),
+        isc::OutOfRange
+    );
+    // Buffer length must be multiple of data type size.
+    EXPECT_THROW(
+        option_v6 = f(Option::V6, opt_code, OptionBuffer(5)),
+        isc::OutOfRange
+    );
+    // Positive scenario, initiate the buffer with length being
+    // multiple of uint16_t size.
+    // buffer elements will be: 0x111122223333.
+    OptionBuffer buf(12);
+    for (int i = 0; i < buf.size(); ++i) {
+        buf[i] = i / 4;
+    }
+    // Constructor should succeed because buffer has correct size.
+    EXPECT_NO_THROW(
+        option_v6 = f(Option::V6, opt_code, buf);
+    );
+    boost::shared_ptr<Option6IntArray<uint32_t> > option_cast_v6 =
+        boost::static_pointer_cast<Option6IntArray<uint32_t> >(option_v6);
+    // Get the values from the initiated options and validate.
+    Option6IntArray<uint32_t>::ValuesCollection values = 
+        option_cast_v6->getValues();
+    for (int i = 0; i < values.size(); ++i) {
+        // Expected value is calculated using on the same pattern
+        // as the one we used to initiate buffer:
+        // for i=0, expected = 0x0000, for i = 1, expected == 0x1111 etc.
+        uint32_t expected = 0x01010101 * i;
+        EXPECT_EQ(expected, values[i]);
+    }
+}
+
+
 } // anonymous namespace



More information about the bind10-changes mailing list