Browse Source

[1959] Added factory function to create instance of options.

Marcin Siodelski 12 years ago
parent
commit
8935b6716b

+ 26 - 0
src/lib/dhcp/libdhcp++.cc

@@ -15,6 +15,7 @@
 #include <boost/shared_array.hpp>
 #include <boost/shared_ptr.hpp>
 #include <util/buffer.h>
+#include <exceptions/exceptions.h>
 #include <dhcp/libdhcp++.h>
 #include "config.h"
 #include <dhcp/dhcp4.h>
@@ -34,6 +35,31 @@ std::map<unsigned short, Option::Factory*> LibDHCP::v4factories_;
 std::map<unsigned short, Option::Factory*> LibDHCP::v6factories_;
 
 
+OptionPtr
+LibDHCP::optionFactory(Option::Universe u,
+                       uint16_t type,
+                       const OptionBuffer& buf) {
+    FactoryMap::iterator it;
+    if (u == Option::V4) {
+        it = v4factories_.find(type);
+        if (it == v4factories_.end()) {
+            isc_throw(BadValue, "factory function not registered "
+            "for DHCP v4 option type " << type);
+        }
+    } else if (u == Option::V6) {
+        it = v6factories_.find(type);
+        if (it == v6factories_.end()) {
+            isc_throw(BadValue, "factory function not registered "
+                      "for DHCPv6 option type " << type);
+        }
+    } else {
+        isc_throw(BadValue, "invalid universe specified (expected "
+                  "Option::V4 or Option::V6");
+    }
+    return(it->second(u, type, buf));
+}
+
+
 size_t LibDHCP::unpackOptions6(const OptionBuffer& buf,
                                isc::dhcp::Option::OptionCollection& options) {
     size_t offset = 0;

+ 23 - 2
src/lib/dhcp/libdhcp++.h

@@ -25,6 +25,27 @@ namespace dhcp {
 class LibDHCP {
 
 public:
+
+    /// Map of factory functions.
+    typedef std::map<unsigned short, Option::Factory*>  FactoryMap;
+
+    /// @brief Factory function to create instance of option.
+    ///
+    /// Factory method creates instance of specified option. The option
+    /// to be created has to have corresponding factory function
+    /// registered with \ref LibDHCP::OptionFactoryRegister.
+    ///
+    /// @param u universe of the option (V4 or V6)
+    /// @param type option-type
+    /// @param buf option-buffer
+    /// @throw isc::InvalidOperation if there is no factory function
+    /// registered for specified option type.
+    /// @return instance of option.
+    static isc::dhcp::OptionPtr optionFactory(isc::dhcp::Option::Universe u,
+                                              uint16_t type,
+                                              const OptionBuffer& buf);
+
+
     /// Builds collection of options.
     ///
     /// Builds raw (on-wire) data for provided collection of options.
@@ -84,10 +105,10 @@ public:
                                       Option::Factory * factory);
 protected:
     /// pointers to factories that produce DHCPv6 options
-    static std::map<unsigned short, Option::Factory*> v4factories_;
+    static FactoryMap v4factories_;
 
     /// pointers to factories that produce DHCPv6 options
-    static std::map<unsigned short, Option::Factory*> v6factories_;
+    static FactoryMap v6factories_;
 };
 
 }

+ 8 - 0
src/lib/dhcp/option.cc

@@ -29,6 +29,14 @@ using namespace isc::util;
 namespace isc {
 namespace dhcp {
 
+OptionPtr
+Option::factory(Option::Universe u,
+        uint16_t type,
+        const OptionBuffer& buf) {
+    return(LibDHCP::optionFactory(u, type, buf));
+}
+
+
 Option::Option(Universe u, uint16_t type)
     :universe_(u), type_(type) {
 

+ 17 - 0
src/lib/dhcp/option.h

@@ -66,6 +66,23 @@ public:
     /// @return a pointer to a created option object
     typedef OptionPtr Factory(Option::Universe u, uint16_t type, const OptionBuffer& buf);
 
+    /// @brief Factory function to create instance of option.
+    ///
+    /// Factory method creates instance of specified option. The option
+    /// to be created has to have corresponding factory function
+    /// registered with \ref LibDHCP::OptionFactoryRegister.
+    ///
+    /// @param u universe of the option (V4 or V6)
+    /// @param type option-type
+    /// @param buf option-buffer
+    /// @throw isc::InvalidOperation if there is no factory function
+    /// registered for specified option type.
+    /// @return instance of option.
+    static OptionPtr factory(Option::Universe u,
+                             uint16_t type,
+                             const OptionBuffer& buf);
+
+
     /// @brief ctor, used for options constructed, usually during transmission
     ///
     /// @param u option universe (DHCPv4 or DHCPv6)

+ 63 - 0
src/lib/dhcp/tests/libdhcp++_unittest.cc

@@ -18,6 +18,8 @@
 #include <arpa/inet.h>
 #include <gtest/gtest.h>
 #include <util/buffer.h>
+#include <dhcp/dhcp4.h>
+#include <dhcp/dhcp6.h>
 #include <dhcp/libdhcp++.h>
 #include "config.h"
 
@@ -31,6 +33,19 @@ class LibDhcpTest : public ::testing::Test {
 public:
     LibDhcpTest() {
     }
+
+    /// @brief Generic factory function to create any option.
+    ///
+    /// Generic factory function to create any option.
+    ///
+    /// @param u universe (V4 or V6)
+    /// @param type option-type
+    /// @param buf option-buffer
+    static OptionPtr genericOptionFactory(Option::Universe u, uint16_t type,
+                                          const OptionBuffer& buf) {
+        Option* option = new Option(u, type, buf);
+        return OptionPtr(option);
+    }
 };
 
 static const uint8_t packed[] = {
@@ -41,6 +56,54 @@ static const uint8_t packed[] = {
     1,  1, 0, 1, 114 // opt5 (5 bytes)
 };
 
+TEST(LibDhcpTest, optionFactory) {
+    OptionBuffer buf;
+    // Factory functions for specific options must be registered before
+    // they can be used to create options instances. Otherwise exception
+    // is rised.
+    EXPECT_THROW(LibDHCP::optionFactory(Option::V4, DHO_SUBNET_MASK, buf),
+                 isc::BadValue);
+
+    // Let's register some factory functions (two v4 and one v6 function).
+    // Registration may trigger exception if function for the specified
+    // option has been registered already.
+    ASSERT_NO_THROW(
+        LibDHCP::OptionFactoryRegister(Option::V4, DHO_SUBNET_MASK,
+                                       &LibDhcpTest::genericOptionFactory);
+    );
+    ASSERT_NO_THROW(
+        LibDHCP::OptionFactoryRegister(Option::V4, DHO_TIME_OFFSET,
+                                       &LibDhcpTest::genericOptionFactory);
+    );
+    ASSERT_NO_THROW(
+        LibDHCP::OptionFactoryRegister(Option::V6, D6O_CLIENTID,
+                                       &LibDhcpTest::genericOptionFactory);
+    );
+
+    // Invoke factory functions for all options (check if registration
+    // was successful).
+    OptionPtr opt_subnet_mask;
+    opt_subnet_mask = LibDHCP::optionFactory(Option::V4,
+                                             DHO_SUBNET_MASK,
+                                             buf);
+    // Check if non-NULL DHO_SUBNET_MASK option pointer has been returned.
+    EXPECT_TRUE(opt_subnet_mask);
+
+    OptionPtr opt_time_offset;
+    opt_time_offset = LibDHCP::optionFactory(Option::V4,
+                                             DHO_TIME_OFFSET,
+                                             buf);
+    // Check if non-NULL DHO_TIME_OFFSET option pointer has been returned.
+    EXPECT_TRUE(opt_time_offset);
+
+    OptionPtr opt_clientid;
+    opt_clientid = LibDHCP::optionFactory(Option::V6,
+                                          D6O_CLIENTID,
+                                          buf);
+    // Check if non-NULL D6O_CLIENTID option pointer has been returned.
+    EXPECT_TRUE(opt_clientid);
+}
+
 TEST(LibDhcpTest, packOptions6) {
     OptionBuffer buf(512);
     isc::dhcp::Option::OptionCollection opts; // list of options