Browse Source

[2312] Initialize structure holding buffer for data fields.

Marcin Siodelski 12 years ago
parent
commit
bfc050ed6c

+ 30 - 1
src/lib/dhcp/option_custom.cc

@@ -60,7 +60,36 @@ OptionCustom::createBuffers() {
     // to use it to split the data_ buffer into set of sub buffers.
     definition_.validate();
 
-    // @todo create buffers here
+    std::vector<OptionBuffer> buffers;
+    if (definition_.getType() == OPT_RECORD_TYPE) {
+        const OptionDefinition::RecordFieldsCollection& fields =
+            definition_.getRecordFields();
+        OptionBuffer::iterator data = data_.begin();
+        for (OptionDefinition::RecordFieldsConstIter field = fields.begin();
+             field != fields.end(); ++field) {
+            int data_size = OptionDataTypeUtil::getDataTypeLen(*field);
+            if (data_size == 0) {
+                if (*field == OPT_IPV4_ADDRESS_TYPE) {
+                    data_size = asiolink::V4ADDRESS_LEN;
+                } else if (*field == OPT_IPV6_ADDRESS_TYPE) {
+                    data_size = asiolink::V6ADDRESS_LEN;
+                } else if (*field == OPT_STRING_TYPE ||
+                           *field == OPT_FQDN_TYPE ||
+                           *field == OPT_BINARY_TYPE) {
+                    data_size = std::distance(data, data_.end());
+                } else {
+                    isc_throw(InvalidDataType, "invalid option data type"
+                              << " used in the option record");
+                }
+            }
+            if (std::distance(data, data_.end()) < data_size ||
+                data_size == 0) {
+                isc_throw(OutOfRange, "option buffer truncated");
+            }
+            buffers_.push_back(OptionBuffer(data, data + data_size));
+            data += data_size;
+        }
+    }
 }
 
 void

+ 19 - 0
src/lib/dhcp/option_data_types.cc

@@ -18,6 +18,25 @@
 namespace isc {
 namespace dhcp {
 
+int
+OptionDataTypeUtil::getDataTypeLen(const OptionDataType data_type) {
+    switch (data_type) {
+    case OPT_BOOLEAN_TYPE:
+    case OPT_INT8_TYPE:
+    case OPT_UINT8_TYPE:
+        return (1);
+    case OPT_INT16_TYPE:
+    case OPT_UINT16_TYPE:
+        return (2);
+    case OPT_INT32_TYPE:
+    case OPT_UINT32_TYPE:
+        return (4);
+    default:
+        ;
+    }
+    return (0);
+}
+
 void
 OptionDataTypeUtil::readAddress(const std::vector<uint8_t>& buf,
                             const short family,

+ 14 - 0
src/lib/dhcp/option_data_types.h

@@ -178,6 +178,20 @@ struct OptionDataTypeTraits<std::string> {
 class OptionDataTypeUtil {
 public:
 
+    /// @brief Get data type size.
+    ///
+    /// This functionm returs the size of a particular data type.
+    /// Values retured by this function correspond to the data type
+    /// sizes defined in OptionDataTypeTraits so they rather indicate
+    /// the fixed length of the data being written into the buffer,
+    /// not the sizeof the particular data type. Thus for data types
+    /// such as string, binary etc. for which the buffer length can't
+    /// be determined this function returns 0.
+    ///
+    /// @param data_type data type which size is to be returned.
+    /// @return data type size or zero for variable length types.
+    static int getDataTypeLen(const OptionDataType data_type);
+
     /// @brief Read IPv4 or IPv6 addres from a buffer.
     ///
     /// @param buf input buffer.

+ 5 - 5
src/lib/dhcp/tests/option_custom_unittest.cc

@@ -51,7 +51,7 @@ public:
     template<typename T>
     void writeInt(T value, std::vector<uint8_t>& buf) {
         for (int i = 0; i < sizeof(T); ++i) {
-            buf.push_back(value >> ((3 - i) * 8) & 0xFF);
+            buf.push_back(value >> ((sizeof(T) - i - 1) * 8) & 0xFF);
         }
     }
 
@@ -70,7 +70,7 @@ TEST_F(OptionCustomTest, constructor) {
           ASSERT_THROW(opt_def1.validate(), isc::Exception); */
 }
 
-TEST_F(OptionCustomTest, setData) {
+TEST_F(OptionCustomTest, setRecordData) {
     OptionDefinition opt_def("OPTION_FOO", 1000, "record");
     ASSERT_NO_THROW(opt_def.addRecordField("uint16"));
     ASSERT_NO_THROW(opt_def.addRecordField("boolean"));
@@ -80,17 +80,17 @@ TEST_F(OptionCustomTest, setData) {
 
     OptionBuffer buf;
     writeInt<uint16_t>(8712, buf);
-    buf.push_back(1);
+    buf.push_back(static_cast<unsigned short>(1));
     writeAddress(IOAddress("192.168.0.1"), buf);
     writeAddress(IOAddress("2001:db8:1::1"), buf);
     writeString("ABCD", buf);
 
-    OptionCustom option(opt_def, Option::V6, buf_.begin(), buf_.begin() + 30);
+    OptionCustom option(opt_def, Option::V6, buf.begin(), buf.begin() + 27);
     ASSERT_TRUE(option.valid());
 
     uint16_t value0 = 0;
     ASSERT_NO_THROW(value0 = option.readInteger<uint16_t>(0));
-    EXPECT_EQ(0x0001, value0);
+    EXPECT_EQ(8712, value0);
     bool value1 = false;
     ASSERT_NO_THROW(value1 = option.readBoolean(1));
     EXPECT_TRUE(value1);

+ 0 - 5
src/lib/dhcp/tests/option_definition_unittest.cc

@@ -652,11 +652,6 @@ TEST_F(OptionDefinitionTest, uint8Tokenized) {
     std::vector<std::string> values;
     values.push_back("123");
     values.push_back("456");
-    try {
-        option_v6 = opt_def.optionFactory(Option::V6, D6O_PREFERENCE, values);
-    } catch (std::exception& ex) {
-        std::cout << ex.what() << std::endl;
-    }
     ASSERT_NO_THROW(
         option_v6 = opt_def.optionFactory(Option::V6, D6O_PREFERENCE, values);
     );