Parcourir la source

[2491] Create Status Code option using an option definition.

Marcin Siodelski il y a 12 ans
Parent
commit
372f3a19f5

+ 13 - 7
src/bin/dhcp6/dhcp6_srv.cc

@@ -24,6 +24,7 @@
 #include <dhcp/option6_iaaddr.h>
 #include <dhcp/option6_iaaddr.h>
 #include <dhcp/option6_iaaddr.h>
 #include <dhcp/option6_iaaddr.h>
 #include <dhcp/option6_int_array.h>
 #include <dhcp/option6_int_array.h>
+#include <dhcp/option_custom.h>
 #include <dhcp/pkt6.h>
 #include <dhcp/pkt6.h>
 #include <dhcp6/dhcp6_log.h>
 #include <dhcp6/dhcp6_log.h>
 #include <dhcp6/dhcp6_srv.h>
 #include <dhcp6/dhcp6_srv.h>
@@ -348,13 +349,18 @@ void Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer)
 }
 }
 
 
 OptionPtr Dhcpv6Srv::createStatusCode(uint16_t code, const std::string& text) {
 OptionPtr Dhcpv6Srv::createStatusCode(uint16_t code, const std::string& text) {
-
-    // @todo: Implement Option6_StatusCode and rewrite this code here
-    vector<uint8_t> data(text.c_str(), text.c_str() + text.length());
-    data.insert(data.begin(), static_cast<uint8_t>(code % 256));
-    data.insert(data.begin(), static_cast<uint8_t>(code >> 8));
-    OptionPtr status(new Option(Option::V6, D6O_STATUS_CODE, data));
-    return (status);
+    OptionDefinitionPtr status_code_def =
+        LibDHCP::getOptionDef(Option::V6, D6O_STATUS_CODE);
+    assert(status_code_def);
+
+    boost::shared_ptr<OptionCustom> option_status =
+        boost::dynamic_pointer_cast<
+            OptionCustom>(status_code_def->optionFactory(Option::V6, D6O_STATUS_CODE));
+    assert(option_status);
+
+    option_status->writeInteger<uint16_t>(code, 0);
+    option_status->writeString(text, 1);
+    return (option_status);
 }
 }
 
 
 Subnet6Ptr Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
 Subnet6Ptr Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {

+ 16 - 5
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc

@@ -801,12 +801,23 @@ TEST_F(Dhcpv6SrvTest, StatusCode) {
     ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
     ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
 
 
     // a dummy content for client-id
     // a dummy content for client-id
-    uint8_t expected[] = {0x0, 0x3, 0x41, 0x42, 0x43, 0x44, 0x45};
-    OptionBuffer exp(expected, expected + sizeof(expected));
-
+    uint8_t expected[] = {
+        0x0, 0xD, // option code = 14
+        0x0, 0x7, // option length = 7
+        0x0, 0x3, // status code = 3
+        0x41, 0x42, 0x43, 0x44, 0x45 // string value ABCDE
+    };
+    // Create the option.
     OptionPtr status = srv->createStatusCode(3, "ABCDE");
     OptionPtr status = srv->createStatusCode(3, "ABCDE");
-
-    EXPECT_TRUE(status->getData() == exp);
+    // Allocate an output buffer. We will store the option
+    // in wire format here.
+    OutputBuffer buf(sizeof(expected));
+    // Prepare the wire format.
+    ASSERT_NO_THROW(status->pack(buf));
+    // Check that the option buffer has valid length (option header + data).
+    ASSERT_EQ(sizeof(expected), buf.getLength());
+    // Verify the contents of the option.
+    EXPECT_EQ(0, memcmp(expected, buf.getData(), sizeof(expected)));
 }
 }
 
 
 // This test verifies if the selectSubnet() method works as expected.
 // This test verifies if the selectSubnet() method works as expected.

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

@@ -32,7 +32,17 @@ OptionCustom::OptionCustom(const OptionDefinition& def,
                              const OptionBuffer& data)
                              const OptionBuffer& data)
     : Option(u, def.getCode(), data.begin(), data.end()),
     : Option(u, def.getCode(), data.begin(), data.end()),
       definition_(def) {
       definition_(def) {
-    createBuffers(data_);
+    // It is possible that no data is provided if an option
+    // is being created on a server side. In such case a bunch
+    // of buffers with default values is first created and then
+    // the values are replaced using writeXXX functions. Thus
+    // we need to detect that no data has been specified and
+    // take a different code path.
+    if (!data_.empty()) {
+        createBuffers(data_);
+    } else {
+        createBuffers();
+    }
 }
 }
 
 
 OptionCustom::OptionCustom(const OptionDefinition& def,
 OptionCustom::OptionCustom(const OptionDefinition& def,

+ 1 - 1
src/lib/dhcp/option_definition.cc

@@ -136,7 +136,7 @@ OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
                 return (factoryIAAddr6(type, begin, end));
                 return (factoryIAAddr6(type, begin, end));
             }
             }
         }
         }
-        return (OptionPtr(new OptionCustom(*this, u, begin, end)));
+        return (OptionPtr(new OptionCustom(*this, u, OptionBuffer(begin, end))));
 
 
     } catch (const Exception& ex) {
     } catch (const Exception& ex) {
         isc_throw(InvalidOptionValue, ex.what());
         isc_throw(InvalidOptionValue, ex.what());

+ 1 - 1
src/lib/dhcp/option_definition.h

@@ -246,7 +246,7 @@ public:
     /// @throw MalformedOptionDefinition if option definition is invalid.
     /// @throw MalformedOptionDefinition if option definition is invalid.
     /// @throw InvalidOptionValue if data for the option is invalid.
     /// @throw InvalidOptionValue if data for the option is invalid.
     OptionPtr optionFactory(Option::Universe u, uint16_t type,
     OptionPtr optionFactory(Option::Universe u, uint16_t type,
-                            const OptionBuffer& buf) const;
+                            const OptionBuffer& buf = OptionBuffer()) const;
 
 
     /// @brief Option factory.
     /// @brief Option factory.
     ///
     ///