Browse Source

[2270] Changes after review

- added boundary checks for Uint32Parser
- fixed #include order
- Class renamed to Dhcp4ConfigParser
- added extra test for Uint32Parser
- Many Doxygen fixes and clean-ups
Tomek Mrugalski 12 years ago
parent
commit
c84efb2586

+ 86 - 76
src/bin/dhcp4/config_parser.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -12,26 +12,22 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 // PERFORMANCE OF THIS SOFTWARE.
 
 
-#include <stdint.h>
-#include <iostream>
-#include <vector>
-#include <map>
+// We want UINT32_MAX macro to be defined in stdint.h
+#define __STDC_LIMIT_MACROS
+
 #include <boost/foreach.hpp>
 #include <boost/foreach.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/scoped_ptr.hpp>
 #include <boost/lexical_cast.hpp>
 #include <boost/lexical_cast.hpp>
 #include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string.hpp>
-#include <asiolink/io_address.h>
-#include <cc/data.h>
 #include <config/ccsession.h>
 #include <config/ccsession.h>
-#include <log/logger_support.h>
-#include <dhcp/triplet.h>
-#include <dhcp/pool.h>
-#include <dhcp/subnet.h>
 #include <dhcp/cfgmgr.h>
 #include <dhcp/cfgmgr.h>
 #include <dhcp4/config_parser.h>
 #include <dhcp4/config_parser.h>
 #include <dhcp4/dhcp4_log.h>
 #include <dhcp4/dhcp4_log.h>
 
 
+#include <stdint.h>
+#include <iostream>
+#include <vector>
+#include <map>
+
 using namespace std;
 using namespace std;
 using namespace isc::data;
 using namespace isc::data;
 using namespace isc::asiolink;
 using namespace isc::asiolink;
@@ -43,17 +39,11 @@ namespace dhcp {
 typedef pair<string, ConstElementPtr> ConfigPair;
 typedef pair<string, ConstElementPtr> ConfigPair;
 
 
 /// @brief a factory method that will create a parser for a given element name
 /// @brief a factory method that will create a parser for a given element name
-typedef DhcpConfigParser* ParserFactory(const std::string& config_id);
+typedef Dhcp4ConfigParser* ParserFactory(const std::string& config_id);
 
 
 /// @brief a collection of factories that creates parsers for specified element names
 /// @brief a collection of factories that creates parsers for specified element names
 typedef std::map<std::string, ParserFactory*> FactoryMap;
 typedef std::map<std::string, ParserFactory*> FactoryMap;
 
 
-/// @brief a collection of elements that store uint32 values (e.g. renew-timer = 900)
-typedef std::map<string, uint32_t> Uint32Storage;
-
-/// @brief a collection of elements that store string values
-typedef std::map<string, string> StringStorage;
-
 /// @brief a collection of pools
 /// @brief a collection of pools
 ///
 ///
 /// That type is used as intermediate storage, when pools are parsed, but there is
 /// That type is used as intermediate storage, when pools are parsed, but there is
@@ -72,12 +62,12 @@ StringStorage string_defaults;
 /// will accept any configuration and will just print it out
 /// will accept any configuration and will just print it out
 /// on commit. Useful for debugging existing configurations and
 /// on commit. Useful for debugging existing configurations and
 /// adding new ones.
 /// adding new ones.
-class DebugParser : public DhcpConfigParser {
+class DebugParser : public Dhcp4ConfigParser {
 public:
 public:
 
 
     /// @brief Constructor
     /// @brief Constructor
     ///
     ///
-    /// See \ref DhcpConfigParser class for details.
+    /// See \ref Dhcp4ConfigParser class for details.
     ///
     ///
     /// @param param_name name of the parsed parameter
     /// @param param_name name of the parsed parameter
     DebugParser(const std::string& param_name)
     DebugParser(const std::string& param_name)
@@ -86,7 +76,7 @@ public:
 
 
     /// @brief builds parameter value
     /// @brief builds parameter value
     ///
     ///
-    /// See \ref DhcpConfigParser class for details.
+    /// See \ref Dhcp4ConfigParser class for details.
     ///
     ///
     /// @param new_config pointer to the new configuration
     /// @param new_config pointer to the new configuration
     virtual void build(ConstElementPtr new_config) {
     virtual void build(ConstElementPtr new_config) {
@@ -100,7 +90,7 @@ public:
     /// This is a method required by base class. It pretends to apply the
     /// This is a method required by base class. It pretends to apply the
     /// configuration, but in fact it only prints the parameter out.
     /// configuration, but in fact it only prints the parameter out.
     ///
     ///
-    /// See \ref DhcpConfigParser class for details.
+    /// See \ref Dhcp4ConfigParser class for details.
     virtual void commit() {
     virtual void commit() {
         // Debug message. The whole DebugParser class is used only for parser
         // Debug message. The whole DebugParser class is used only for parser
         // debugging, and is not used in production code. It is very convenient
         // debugging, and is not used in production code. It is very convenient
@@ -112,11 +102,11 @@ public:
     /// @brief factory that constructs DebugParser objects
     /// @brief factory that constructs DebugParser objects
     ///
     ///
     /// @param param_name name of the parameter to be parsed
     /// @param param_name name of the parameter to be parsed
-    static DhcpConfigParser* Factory(const std::string& param_name) {
+    static Dhcp4ConfigParser* Factory(const std::string& param_name) {
         return (new DebugParser(param_name));
         return (new DebugParser(param_name));
     }
     }
 
 
-protected:
+private:
     /// name of the parsed parameter
     /// name of the parsed parameter
     std::string param_name_;
     std::string param_name_;
 
 
@@ -131,11 +121,11 @@ protected:
 /// (uint32_defaults). If used in smaller scopes (e.g. to parse parameters
 /// (uint32_defaults). If used in smaller scopes (e.g. to parse parameters
 /// in subnet config), it can be pointed to a different storage, using
 /// in subnet config), it can be pointed to a different storage, using
 /// setStorage() method. This class follows the parser interface, laid out
 /// setStorage() method. This class follows the parser interface, laid out
-/// in its base class, \ref DhcpConfigParser.
+/// in its base class, \ref Dhcp4ConfigParser.
 ///
 ///
 /// For overview of usability of this generic purpose parser, see
 /// For overview of usability of this generic purpose parser, see
-/// \ref dhcpv4-config-inherit page.
-class Uint32Parser : public DhcpConfigParser {
+/// \ref dhcp4-config-inherit page.
+class Uint32Parser : public Dhcp4ConfigParser {
 public:
 public:
 
 
     /// @brief constructor for Uint32Parser
     /// @brief constructor for Uint32Parser
@@ -150,13 +140,30 @@ public:
     /// \ref setStorage() for details.
     /// \ref setStorage() for details.
     ///
     ///
     /// @param value pointer to the content of parsed values
     /// @param value pointer to the content of parsed values
+    /// @throw BadValue if supplied value could not be base to uint32_t
     virtual void build(ConstElementPtr value) {
     virtual void build(ConstElementPtr value) {
+        int64_t check;
+        string x = value->str();
         try {
         try {
-            value_ = boost::lexical_cast<uint32_t>(value->str());
+            check = boost::lexical_cast<int64_t>(x);
         } catch (const boost::bad_lexical_cast &) {
         } catch (const boost::bad_lexical_cast &) {
             isc_throw(BadValue, "Failed to parse value " << value->str()
             isc_throw(BadValue, "Failed to parse value " << value->str()
                       << " as unsigned 32-bit integer.");
                       << " as unsigned 32-bit integer.");
         }
         }
+        if (check > UINT32_MAX) {
+            isc_throw(BadValue, "Value " << value->str() << "is too large"
+                      << " for unsigned 32-bit integer.");
+        }
+        if (check < 0) {
+            isc_throw(BadValue, "Value " << value->str() << "is negative."
+                      << " Only 0 or larger are allowed for unsigned 32-bit integer.");
+        }
+
+        // value is small enough to fit
+        value_ = static_cast<uint32_t>(check);
+
+        /// @todo: check if there is no such name in the map. Otherwise
+        /// the insert will fail silently
         storage_->insert(pair<string, uint32_t>(param_name_, value_));
         storage_->insert(pair<string, uint32_t>(param_name_, value_));
     }
     }
 
 
@@ -166,7 +173,7 @@ public:
     /// is not commited anywhere. Higher level parsers are expected to
     /// is not commited anywhere. Higher level parsers are expected to
     /// use values stored in the storage, e.g. renew-timer for a given
     /// use values stored in the storage, e.g. renew-timer for a given
     /// subnet is stored in subnet-specific storage. It is not commited
     /// subnet is stored in subnet-specific storage. It is not commited
-    /// here, but is rather used by \ref Subnet4Parser when constructing
+    /// here, but is rather used by \ref Subnet4ConfigParser when constructing
     /// the subnet.
     /// the subnet.
     virtual void commit() {
     virtual void commit() {
     }
     }
@@ -174,13 +181,13 @@ public:
     /// @brief factory that constructs Uint32Parser objects
     /// @brief factory that constructs Uint32Parser objects
     ///
     ///
     /// @param param_name name of the parameter to be parsed
     /// @param param_name name of the parameter to be parsed
-    static DhcpConfigParser* Factory(const std::string& param_name) {
+    static Dhcp4ConfigParser* Factory(const std::string& param_name) {
         return (new Uint32Parser(param_name));
         return (new Uint32Parser(param_name));
     }
     }
 
 
     /// @brief sets storage for value of this parameter
     /// @brief sets storage for value of this parameter
     ///
     ///
-    /// See \ref dhcpv4-config-inherit for details.
+    /// See \ref dhcp4-config-inherit for details.
     ///
     ///
     /// @param storage pointer to the storage container
     /// @param storage pointer to the storage container
     void setStorage(Uint32Storage* storage) {
     void setStorage(Uint32Storage* storage) {
@@ -205,11 +212,11 @@ protected:
 /// (string_defaults). If used in smaller scopes (e.g. to parse parameters
 /// (string_defaults). If used in smaller scopes (e.g. to parse parameters
 /// in subnet config), it can be pointed to a different storage, using
 /// in subnet config), it can be pointed to a different storage, using
 /// setStorage() method. This class follows the parser interface, laid out
 /// setStorage() method. This class follows the parser interface, laid out
-/// in its base class, \ref DhcpConfigParser.
+/// in its base class, \ref Dhcp4ConfigParser.
 ///
 ///
 /// For overview of usability of this generic purpose parser, see
 /// For overview of usability of this generic purpose parser, see
-/// \ref dhcpv4-config-inherit page.
-class StringParser : public DhcpConfigParser {
+/// \ref dhcp4-config-inherit page.
+class StringParser : public Dhcp4ConfigParser {
 public:
 public:
 
 
     /// @brief constructor for StringParser
     /// @brief constructor for StringParser
@@ -227,6 +234,8 @@ public:
     virtual void build(ConstElementPtr value) {
     virtual void build(ConstElementPtr value) {
         value_ = value->str();
         value_ = value->str();
         boost::erase_all(value_, "\"");
         boost::erase_all(value_, "\"");
+        /// @todo: check if there is no such name in the map. Otherwise
+        /// the insert will fail silently
         storage_->insert(pair<string, string>(param_name_, value_));
         storage_->insert(pair<string, string>(param_name_, value_));
     }
     }
 
 
@@ -244,13 +253,13 @@ public:
     /// @brief factory that constructs StringParser objects
     /// @brief factory that constructs StringParser objects
     ///
     ///
     /// @param param_name name of the parameter to be parsed
     /// @param param_name name of the parameter to be parsed
-    static DhcpConfigParser* Factory(const std::string& param_name) {
+    static Dhcp4ConfigParser* Factory(const std::string& param_name) {
         return (new StringParser(param_name));
         return (new StringParser(param_name));
     }
     }
 
 
     /// @brief sets storage for value of this parameter
     /// @brief sets storage for value of this parameter
     ///
     ///
-    /// See \ref dhcpv4-config-inherit for details.
+    /// See \ref dhcp4-config-inherit for details.
     ///
     ///
     /// @param storage pointer to the storage container
     /// @param storage pointer to the storage container
     void setStorage(StringStorage* storage) {
     void setStorage(StringStorage* storage) {
@@ -277,7 +286,7 @@ protected:
 /// designates all interfaces.
 /// designates all interfaces.
 ///
 ///
 /// It is useful for parsing Dhcp4/interface parameter.
 /// It is useful for parsing Dhcp4/interface parameter.
-class InterfaceListConfigParser : public DhcpConfigParser {
+class InterfaceListConfigParser : public Dhcp4ConfigParser {
 public:
 public:
 
 
     /// @brief constructor
     /// @brief constructor
@@ -286,17 +295,18 @@ public:
     /// "interface" parameter only. All other types will throw exception.
     /// "interface" parameter only. All other types will throw exception.
     ///
     ///
     /// @param param_name name of the configuration parameter being parsed
     /// @param param_name name of the configuration parameter being parsed
+    /// @throw BadValue if supplied parameter name is not "interface"
     InterfaceListConfigParser(const std::string& param_name) {
     InterfaceListConfigParser(const std::string& param_name) {
         if (param_name != "interface") {
         if (param_name != "interface") {
-            isc_throw(NotImplemented, "Internal error. Interface configuration "
+            isc_throw(BadValue, "Internal error. Interface configuration "
                       "parser called for the wrong parameter: " << param_name);
                       "parser called for the wrong parameter: " << param_name);
         }
         }
     }
     }
 
 
     /// @brief parses parameters value
     /// @brief parses parameters value
     ///
     ///
-    /// Parses configuration entry (list of parameters) and stores it in
-    /// storage. See \ref setStorage() for details.
+    /// Parses configuration entry (list of parameters) and adds each element
+    /// to the interfaces list.
     ///
     ///
     /// @param value pointer to the content of parsed values
     /// @param value pointer to the content of parsed values
     virtual void build(ConstElementPtr value) {
     virtual void build(ConstElementPtr value) {
@@ -314,7 +324,7 @@ public:
     /// @brief factory that constructs InterfaceListConfigParser objects
     /// @brief factory that constructs InterfaceListConfigParser objects
     ///
     ///
     /// @param param_name name of the parameter to be parsed
     /// @param param_name name of the parameter to be parsed
-    static DhcpConfigParser* Factory(const std::string& param_name) {
+    static Dhcp4ConfigParser* Factory(const std::string& param_name) {
         return (new InterfaceListConfigParser(param_name));
         return (new InterfaceListConfigParser(param_name));
     }
     }
 
 
@@ -333,7 +343,7 @@ protected:
 /// before build(). Otherwise exception will be thrown.
 /// before build(). Otherwise exception will be thrown.
 ///
 ///
 /// It is useful for parsing Dhcp4/subnet4[X]/pool parameters.
 /// It is useful for parsing Dhcp4/subnet4[X]/pool parameters.
-class PoolParser : public DhcpConfigParser {
+class PoolParser : public Dhcp4ConfigParser {
 public:
 public:
 
 
     /// @brief constructor.
     /// @brief constructor.
@@ -347,10 +357,13 @@ public:
     /// This method parses the actual list of interfaces.
     /// This method parses the actual list of interfaces.
     /// No validation is done at this stage, everything is interpreted as
     /// No validation is done at this stage, everything is interpreted as
     /// interface name.
     /// interface name.
+    /// @param pools_list list of pools defined for a subnet
+    /// @throw InvalidOperation if storage was not specified (setStorage() not called)
+    /// @throw Dhcp4ConfigError when pool parsing fails
     void build(ConstElementPtr pools_list) {
     void build(ConstElementPtr pools_list) {
         // setStorage() should have been called before build
         // setStorage() should have been called before build
         if (!pools_) {
         if (!pools_) {
-            isc_throw(NotImplemented, "Parser logic error. No pool storage set,"
+            isc_throw(InvalidOperation, "Parser logic error. No pool storage set,"
                       " but pool parser asked to parse pools");
                       " but pool parser asked to parse pools");
         }
         }
 
 
@@ -416,7 +429,7 @@ public:
 
 
     /// @brief sets storage for value of this parameter
     /// @brief sets storage for value of this parameter
     ///
     ///
-    /// See \ref dhcpv4-config-inherit for details.
+    /// See \ref dhcp4-config-inherit for details.
     ///
     ///
     /// @param storage pointer to the storage container
     /// @param storage pointer to the storage container
     void setStorage(PoolStorage* storage) {
     void setStorage(PoolStorage* storage) {
@@ -433,7 +446,7 @@ public:
     /// @brief factory that constructs PoolParser objects
     /// @brief factory that constructs PoolParser objects
     ///
     ///
     /// @param param_name name of the parameter to be parsed
     /// @param param_name name of the parameter to be parsed
-    static DhcpConfigParser* Factory(const std::string& param_name) {
+    static Dhcp4ConfigParser* Factory(const std::string& param_name) {
         return (new PoolParser(param_name));
         return (new PoolParser(param_name));
     }
     }
 
 
@@ -449,7 +462,7 @@ protected:
 ///
 ///
 /// This class parses the whole subnet definition. It creates parsers
 /// This class parses the whole subnet definition. It creates parsers
 /// for received configuration parameters as needed.
 /// for received configuration parameters as needed.
-class Subnet4ConfigParser : public DhcpConfigParser {
+class Subnet4ConfigParser : public Dhcp4ConfigParser {
 public:
 public:
 
 
     /// @brief constructor
     /// @brief constructor
@@ -469,22 +482,22 @@ public:
 
 
             // if this is an Uint32 parser, tell it to store the values
             // if this is an Uint32 parser, tell it to store the values
             // in values_, rather than in global storage
             // in values_, rather than in global storage
-            boost::shared_ptr<Uint32Parser> uintParser =
+            boost::shared_ptr<Uint32Parser> uint_parser =
                 boost::dynamic_pointer_cast<Uint32Parser>(parser);
                 boost::dynamic_pointer_cast<Uint32Parser>(parser);
-            if (uintParser) {
-                uintParser->setStorage(&uint32_values_);
+            if (uint_parser) {
+                uint_parser->setStorage(&uint32_values_);
             } else {
             } else {
 
 
-                boost::shared_ptr<StringParser> stringParser =
+                boost::shared_ptr<StringParser> string_parser =
                     boost::dynamic_pointer_cast<StringParser>(parser);
                     boost::dynamic_pointer_cast<StringParser>(parser);
-                if (stringParser) {
-                    stringParser->setStorage(&string_values_);
+                if (string_parser) {
+                    string_parser->setStorage(&string_values_);
                 } else {
                 } else {
 
 
-                    boost::shared_ptr<PoolParser> poolParser =
+                    boost::shared_ptr<PoolParser> pool_parser =
                         boost::dynamic_pointer_cast<PoolParser>(parser);
                         boost::dynamic_pointer_cast<PoolParser>(parser);
-                    if (poolParser) {
-                        poolParser->setStorage(&pools_);
+                    if (pool_parser) {
+                        pool_parser->setStorage(&pools_);
                     }
                     }
                 }
                 }
             }
             }
@@ -502,6 +515,7 @@ public:
     /// storing the values that are actually consumed here. Pool definitions
     /// storing the values that are actually consumed here. Pool definitions
     /// created in other parsers are used here and added to newly created Subnet4
     /// created in other parsers are used here and added to newly created Subnet4
     /// objects. Subnet4 are then added to DHCP CfgMgr.
     /// objects. Subnet4 are then added to DHCP CfgMgr.
+    /// @throw Dhcp4ConfigError if there are any issues encountered during commit
     void commit() {
     void commit() {
 
 
         StringStorage::const_iterator it = string_values_.find("subnet");
         StringStorage::const_iterator it = string_values_.find("subnet");
@@ -549,7 +563,8 @@ protected:
     ///
     ///
     /// @param config_id name od the entry
     /// @param config_id name od the entry
     /// @return parser object for specified entry name
     /// @return parser object for specified entry name
-    DhcpConfigParser* createSubnet4ConfigParser(const std::string& config_id) {
+    /// @throw NotImplemented if trying to create a parser for unknown config element
+    Dhcp4ConfigParser* createSubnet4ConfigParser(const std::string& config_id) {
         FactoryMap factories;
         FactoryMap factories;
 
 
         factories.insert(pair<string, ParserFactory*>(
         factories.insert(pair<string, ParserFactory*>(
@@ -585,6 +600,7 @@ protected:
     ///
     ///
     /// @param name name of the parameter
     /// @param name name of the parameter
     /// @return triplet with the parameter name
     /// @return triplet with the parameter name
+    /// @throw Dhcp4ConfigError when requested parameter is not present
     Triplet<uint32_t> getParam(const std::string& name) {
     Triplet<uint32_t> getParam(const std::string& name) {
         uint32_t value = 0;
         uint32_t value = 0;
         bool found = false;
         bool found = false;
@@ -627,7 +643,7 @@ protected:
 /// This is a wrapper parser that handles the whole list of Subnet4
 /// This is a wrapper parser that handles the whole list of Subnet4
 /// definitions. It iterates over all entries and creates Subnet4ConfigParser
 /// definitions. It iterates over all entries and creates Subnet4ConfigParser
 /// for each entry.
 /// for each entry.
-class Subnets4ListConfigParser : public DhcpConfigParser {
+class Subnets4ListConfigParser : public Dhcp4ConfigParser {
 public:
 public:
 
 
     /// @brief constructor
     /// @brief constructor
@@ -676,7 +692,7 @@ public:
     /// @brief Returns Subnet4ListConfigParser object
     /// @brief Returns Subnet4ListConfigParser object
     /// @param param_name name of the parameter
     /// @param param_name name of the parameter
     /// @return Subnets4ListConfigParser object
     /// @return Subnets4ListConfigParser object
-    static DhcpConfigParser* Factory(const std::string& param_name) {
+    static Dhcp4ConfigParser* Factory(const std::string& param_name) {
         return (new Subnets4ListConfigParser(param_name));
         return (new Subnets4ListConfigParser(param_name));
     }
     }
 
 
@@ -691,7 +707,8 @@ public:
 ///
 ///
 /// @param config_id pointer to received global configuration entry
 /// @param config_id pointer to received global configuration entry
 /// @return parser for specified global DHCPv4 parameter
 /// @return parser for specified global DHCPv4 parameter
-DhcpConfigParser* createGlobalDhcpConfigParser(const std::string& config_id) {
+/// @throw NotImplemented if trying to create a parser for unknown config element
+Dhcp4ConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id) {
     FactoryMap factories;
     FactoryMap factories;
 
 
     factories.insert(pair<string, ParserFactory*>(
     factories.insert(pair<string, ParserFactory*>(
@@ -723,25 +740,18 @@ DhcpConfigParser* createGlobalDhcpConfigParser(const std::string& config_id) {
 
 
 /// @brief configures DHCPv4 server
 /// @brief configures DHCPv4 server
 ///
 ///
-/// This function is called every time a new configuration is received. The extra
-/// parameter is a reference to DHCPv4 server component. It is currently not used
-/// and CfgMgr::instance() is accessed instead.
-///
-/// This method does not throw. It catches all exceptions and returns them as
-/// reconfiguration statuses. It may return the following response codes:
-/// 0 - configuration successful
-/// 1 - malformed configuration (parsing failed)
-/// 2 - logical error (parsing was successful, but the values are invalid)
-///
-/// @param config_set a new configuration for DHCPv4 server
-/// @return answer that contains result of reconfiguration
 isc::data::ConstElementPtr
 isc::data::ConstElementPtr
 configureDhcp4Server(Dhcpv4Srv& , ConstElementPtr config_set) {
 configureDhcp4Server(Dhcpv4Srv& , ConstElementPtr config_set) {
     if (!config_set) {
     if (!config_set) {
-        isc_throw(Dhcp4ConfigError,
-                  "Null pointer is passed to configuration parser");
+        ConstElementPtr answer = isc::config::createAnswer(1,
+                                 string("Can't parse NULL config"));
+        return (answer);
     }
     }
 
 
+    /// Let's wipe previous configuration defaults
+    uint32_defaults.clear();
+    string_defaults.clear();
+
     /// @todo: append most essential info here (like "2 new subnets configured")
     /// @todo: append most essential info here (like "2 new subnets configured")
     string config_details;
     string config_details;
 
 
@@ -751,7 +761,7 @@ configureDhcp4Server(Dhcpv4Srv& , ConstElementPtr config_set) {
     try {
     try {
         BOOST_FOREACH(ConfigPair config_pair, config_set->mapValue()) {
         BOOST_FOREACH(ConfigPair config_pair, config_set->mapValue()) {
 
 
-            ParserPtr parser(createGlobalDhcpConfigParser(config_pair.first));
+            ParserPtr parser(createGlobalDhcp4ConfigParser(config_pair.first));
             parser->build(config_pair.second);
             parser->build(config_pair.second);
             parsers.push_back(parser);
             parsers.push_back(parser);
         }
         }

+ 46 - 29
src/bin/dhcp4/config_parser.h

@@ -12,9 +12,9 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 // PERFORMANCE OF THIS SOFTWARE.
 
 
-#include <string>
 #include <exceptions/exceptions.h>
 #include <exceptions/exceptions.h>
 #include <cc/data.h>
 #include <cc/data.h>
+#include <string>
 
 
 #ifndef DHCP4_CONFIG_PARSER_H
 #ifndef DHCP4_CONFIG_PARSER_H
 #define DHCP4_CONFIG_PARSER_H
 #define DHCP4_CONFIG_PARSER_H
@@ -27,21 +27,34 @@ namespace dhcp {
 
 
 class Dhcpv4Srv;
 class Dhcpv4Srv;
 
 
+/// @brief a collection of elements that store uint32 values (e.g. renew-timer = 900)
+typedef std::map<std::string, uint32_t> Uint32Storage;
+
+/// @brief a collection of elements that store string values
+typedef std::map<std::string, std::string> StringStorage;
+
 /// An exception that is thrown if an error occurs while configuring an
 /// An exception that is thrown if an error occurs while configuring an
 /// \c Dhcpv4Srv object.
 /// \c Dhcpv4Srv object.
 class Dhcp4ConfigError : public isc::Exception {
 class Dhcp4ConfigError : public isc::Exception {
 public:
 public:
 
 
-/// @brief constructor
-///
-/// @param file name of the file, where exception occurred
-/// @param line line of the file, where exception occurred
-/// @param what text description of the issue that caused exception
-Dhcp4ConfigError(const char* file, size_t line, const char* what) :
-    isc::Exception(file, line, what) {}
+    /// @brief constructor
+    ///
+    /// @param file name of the file, where exception occurred
+    /// @param line line of the file, where exception occurred
+    /// @param what text description of the issue that caused exception
+    Dhcp4ConfigError(const char* file, size_t line, const char* what)
+        : isc::Exception(file, line, what) {}
 };
 };
 
 
-class DhcpConfigParser {
+/// @brief Base abstract class for all DHCPv4 parsers
+///
+/// Each instance of a class derived from this class parses one specific config
+/// element. Sometimes elements are simple (e.g. a string) and sometimes quite
+/// complex (e.g. a subnet). In such case, it is likely that a parser will
+/// spawn child parsers to parse child elements in the configuration.
+/// @todo: Merge this class with DhcpConfigParser in src/bin/dhcp6
+class Dhcp4ConfigParser {
     ///
     ///
     /// \name Constructors and Destructor
     /// \name Constructors and Destructor
     ///
     ///
@@ -50,17 +63,21 @@ class DhcpConfigParser {
     /// pure base class.
     /// pure base class.
     //@{
     //@{
 private:
 private:
-    DhcpConfigParser(const DhcpConfigParser& source);
-    DhcpConfigParser& operator=(const DhcpConfigParser& source);
+
+    // Private construtor and assignment operator assures that nobody
+    // will be able to copy or assign a parser. There are no defined
+    // bodies for them.
+    Dhcp4ConfigParser(const Dhcp4ConfigParser& source);
+    Dhcp4ConfigParser& operator=(const Dhcp4ConfigParser& source);
 protected:
 protected:
     /// \brief The default constructor.
     /// \brief The default constructor.
     ///
     ///
     /// This is intentionally defined as \c protected as this base class should
     /// This is intentionally defined as \c protected as this base class should
     /// never be instantiated (except as part of a derived class).
     /// never be instantiated (except as part of a derived class).
-    DhcpConfigParser() {}
+    Dhcp4ConfigParser() {}
 public:
 public:
     /// The destructor.
     /// The destructor.
-    virtual ~DhcpConfigParser() {}
+    virtual ~Dhcp4ConfigParser() {}
     //@}
     //@}
 
 
     /// \brief Prepare configuration value.
     /// \brief Prepare configuration value.
@@ -107,7 +124,7 @@ public:
 };
 };
 
 
 /// @brief a pointer to configuration parser
 /// @brief a pointer to configuration parser
-typedef boost::shared_ptr<DhcpConfigParser> ParserPtr;
+typedef boost::shared_ptr<Dhcp4ConfigParser> ParserPtr;
 
 
 /// @brief a collection of parsers
 /// @brief a collection of parsers
 ///
 ///
@@ -115,7 +132,7 @@ typedef boost::shared_ptr<DhcpConfigParser> ParserPtr;
 typedef std::vector<ParserPtr> ParserCollection;
 typedef std::vector<ParserPtr> ParserCollection;
 
 
 
 
-/// \brief Configure an \c Dhcpv4Srv object with a set of configuration values.
+/// \brief Configure DHCPv4 server (\c Dhcpv4Srv) with a set of configuration values.
 ///
 ///
 /// This function parses configuration information stored in \c config_set
 /// This function parses configuration information stored in \c config_set
 /// and configures the \c server by applying the configuration to it.
 /// and configures the \c server by applying the configuration to it.
@@ -126,22 +143,22 @@ typedef std::vector<ParserPtr> ParserCollection;
 ///
 ///
 /// If a syntax or semantics level error happens during the configuration
 /// If a syntax or semantics level error happens during the configuration
 /// (such as malformed configuration or invalid configuration parameter),
 /// (such as malformed configuration or invalid configuration parameter),
-/// this function throws an exception of class \c Dhcp4ConfigError.
-/// If the given configuration requires resource allocation and it fails,
-/// a corresponding standard exception will be thrown.
-/// Other exceptions may also be thrown, depending on the implementation of
-/// the underlying derived class of \c Dhcp4ConfigError.
-/// In any case the strong guarantee is provided as described above except
-/// in the very rare cases where the \c commit() method of a parser throws
-/// an exception.  If that happens this function converts the exception
-/// into a \c FatalError exception and rethrows it.  This exception is
-/// expected to be caught at the highest level of the application to terminate
-/// the program gracefully.
+/// this function returns appropriate error code.
+///
+/// This function is called every time a new configuration is received. The extra
+/// parameter is a reference to DHCPv4 server component. It is currently not used
+/// and CfgMgr::instance() is accessed instead.
+///
+/// This method does not throw. It catches all exceptions and returns them as
+/// reconfiguration statuses. It may return the following response codes:
+/// 0 - configuration successful
+/// 1 - malformed configuration (parsing failed)
+/// 2 - logical error (parsing was successful, but the values are invalid)
 ///
 ///
-/// \param server The \c Dhcpv4Srv object to be configured.
-/// \param config_set A JSON style configuration to apply to \c server.
+/// @param config_set a new configuration (JSON) for DHCPv4 server
+/// @return answer that contains result of reconfiguration
 isc::data::ConstElementPtr
 isc::data::ConstElementPtr
-configureDhcp4Server(Dhcpv4Srv& server,
+configureDhcp4Server(Dhcpv4Srv&,
                      isc::data::ConstElementPtr config_set);
                      isc::data::ConstElementPtr config_set);
 
 
 }; // end of isc::dhcp namespace
 }; // end of isc::dhcp namespace

+ 3 - 4
src/bin/dhcp4/ctrl_dhcp4_srv.cc

@@ -14,9 +14,6 @@
 
 
 #include <config.h>
 #include <config.h>
 
 
-#include <cassert>
-#include <iostream>
-
 #include <asiolink/asiolink.h>
 #include <asiolink/asiolink.h>
 #include <cc/data.h>
 #include <cc/data.h>
 #include <cc/session.h>
 #include <cc/session.h>
@@ -29,6 +26,8 @@
 #include <dhcp/iface_mgr.h>
 #include <dhcp/iface_mgr.h>
 #include <exceptions/exceptions.h>
 #include <exceptions/exceptions.h>
 #include <util/buffer.h>
 #include <util/buffer.h>
+#include <cassert>
+#include <iostream>
 
 
 using namespace isc::asiolink;
 using namespace isc::asiolink;
 using namespace isc::cc;
 using namespace isc::cc;
@@ -126,7 +125,7 @@ void ControlledDhcpv4Srv::establishSession() {
 
 
     /// Integrate the asynchronous I/O model of BIND 10 configuration
     /// Integrate the asynchronous I/O model of BIND 10 configuration
     /// control with the "select" model of the DHCP server.  This is
     /// control with the "select" model of the DHCP server.  This is
-    /// fully explained in \ref dhcpv4Session.
+    /// fully explained in \ref dhcp4-session.
     int ctrl_socket = cc_session_->getSocketDesc();
     int ctrl_socket = cc_session_->getSocketDesc();
     LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_CCSESSION_STARTED)
     LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_CCSESSION_STARTED)
               .arg(ctrl_socket);
               .arg(ctrl_socket);

+ 2 - 2
src/bin/dhcp4/ctrl_dhcp4_srv.h

@@ -34,7 +34,7 @@ namespace dhcp {
 /// embedded environments.
 /// embedded environments.
 ///
 ///
 /// For detailed explanation or relations between main(), ControlledDhcpv4Srv,
 /// For detailed explanation or relations between main(), ControlledDhcpv4Srv,
-/// Dhcpv4Srv and other classes, see \ref dhcpv4Session.
+/// Dhcpv4Srv and other classes, see \ref dhcp4-session.
 class ControlledDhcpv4Srv : public isc::dhcp::Dhcpv4Srv {
 class ControlledDhcpv4Srv : public isc::dhcp::Dhcpv4Srv {
 public:
 public:
 
 
@@ -66,7 +66,7 @@ public:
 
 
     /// @brief Session callback, processes received commands.
     /// @brief Session callback, processes received commands.
     ///
     ///
-    /// @param command_id text represenation of the command (e.g. "shutdown")
+    /// @param command text represenation of the command (e.g. "shutdown")
     /// @param args optional parameters
     /// @param args optional parameters
     ///
     ///
     /// @return status of the command
     /// @return status of the command

+ 0 - 2
src/bin/dhcp4/dhcp4.dox

@@ -15,8 +15,6 @@ DHCPv4 server component does not support direct traffic (relayed
 only), as support for transmission to hosts without IPv4 address
 only), as support for transmission to hosts without IPv4 address
 assigned is not implemented in IfaceMgr yet.
 assigned is not implemented in IfaceMgr yet.
 
 
-DHCPv4 server component does not use BIND10 logging yet.
-
 @section dhcp4-session BIND10 message queue integration
 @section dhcp4-session BIND10 message queue integration
 
 
 DHCPv4 server component is now integrated with BIND10 message queue.
 DHCPv4 server component is now integrated with BIND10 message queue.

+ 1 - 1
src/bin/dhcp4/dhcp4_srv.cc

@@ -17,8 +17,8 @@
 #include <dhcp/iface_mgr.h>
 #include <dhcp/iface_mgr.h>
 #include <dhcp4/dhcp4_srv.h>
 #include <dhcp4/dhcp4_srv.h>
 #include <dhcp4/dhcp4_log.h>
 #include <dhcp4/dhcp4_log.h>
-#include <asiolink/io_address.h>
 #include <dhcp/option4_addrlst.h>
 #include <dhcp/option4_addrlst.h>
+#include <asiolink/io_address.h>
 
 
 using namespace isc;
 using namespace isc;
 using namespace isc::asiolink;
 using namespace isc::asiolink;

+ 3 - 3
src/bin/dhcp4/dhcp4_srv.h

@@ -15,10 +15,10 @@
 #ifndef DHCPV4_SRV_H
 #ifndef DHCPV4_SRV_H
 #define DHCPV4_SRV_H
 #define DHCPV4_SRV_H
 
 
-#include <boost/noncopyable.hpp>
 #include <dhcp/dhcp4.h>
 #include <dhcp/dhcp4.h>
 #include <dhcp/pkt4.h>
 #include <dhcp/pkt4.h>
 #include <dhcp/option.h>
 #include <dhcp/option.h>
+#include <boost/noncopyable.hpp>
 #include <iostream>
 #include <iostream>
 
 
 namespace isc {
 namespace isc {
@@ -34,11 +34,11 @@ namespace dhcp {
 /// appropriate responses.
 /// appropriate responses.
 ///
 ///
 /// This class does not support any controlling mechanisms directly.
 /// This class does not support any controlling mechanisms directly.
-/// See derived \ref ControlledDhcv4Srv class for support for
+/// See derived \ref ControlledDhcpv4Srv class for support for
 /// command and configuration updates over msgq.
 /// command and configuration updates over msgq.
 ///
 ///
 /// For detailed explanation or relations between main(), ControlledDhcpv4Srv,
 /// For detailed explanation or relations between main(), ControlledDhcpv4Srv,
-/// Dhcpv4Srv and other classes, see \ref dhcpv4Session.
+/// Dhcpv4Srv and other classes, see \ref dhcp4-session.
 class Dhcpv4Srv : public boost::noncopyable {
 class Dhcpv4Srv : public boost::noncopyable {
 
 
     public:
     public:

+ 91 - 31
src/bin/dhcp4/tests/config_parser_unittest.cc

@@ -13,9 +13,6 @@
 // PERFORMANCE OF THIS SOFTWARE.
 // PERFORMANCE OF THIS SOFTWARE.
 
 
 #include <config.h>
 #include <config.h>
-#include <iostream>
-#include <fstream>
-#include <sstream>
 
 
 #include <arpa/inet.h>
 #include <arpa/inet.h>
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
@@ -25,6 +22,10 @@
 #include <config/ccsession.h>
 #include <config/ccsession.h>
 #include <dhcp/subnet.h>
 #include <dhcp/subnet.h>
 #include <dhcp/cfgmgr.h>
 #include <dhcp/cfgmgr.h>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <limits.h>
 
 
 using namespace std;
 using namespace std;
 using namespace isc;
 using namespace isc;
@@ -33,6 +34,12 @@ using namespace isc::asiolink;
 using namespace isc::data;
 using namespace isc::data;
 using namespace isc::config;
 using namespace isc::config;
 
 
+namespace isc {
+namespace dhcp {
+extern Uint32Storage uint32_defaults;
+}
+}
+
 namespace {
 namespace {
 
 
 class Dhcp4ParserTest : public ::testing::Test {
 class Dhcp4ParserTest : public ::testing::Test {
@@ -45,6 +52,26 @@ public:
         srv_ = new Dhcpv4Srv(0);
         srv_ = new Dhcpv4Srv(0);
     }
     }
 
 
+    // Checks if global parameter of name have expected_value
+    void checkGlobalUint32(string name, uint32_t expected_value) {
+        Uint32Storage::const_iterator it = uint32_defaults.find(name);
+        if (it == uint32_defaults.end()) {
+            ADD_FAILURE() << "Expected uint32 with name " << name
+                          << " not found";
+            return;
+        }
+        EXPECT_EQ(expected_value, it->second);
+    }
+
+    // Checks if config_result (result of DHCP server configuration) has
+    // expected code (0 for success, other for failures).
+    // Also stores result in rcode_ and comment_.
+    void checkResult(ConstElementPtr status, int expected_code) {
+        ASSERT_TRUE(status);
+        comment_ = parseAnswer(rcode_, status);
+        EXPECT_EQ(expected_code, rcode_);
+    }
+
     ~Dhcp4ParserTest() {
     ~Dhcp4ParserTest() {
         delete srv_;
         delete srv_;
     };
     };
@@ -66,9 +93,7 @@ TEST_F(Dhcp4ParserTest, version) {
                     Element::fromJSON("{\"version\": 0}")));
                     Element::fromJSON("{\"version\": 0}")));
 
 
     // returned value must be 0 (configuration accepted)
     // returned value must be 0 (configuration accepted)
-    ASSERT_TRUE(x);
-    comment_ = parseAnswer(rcode_, x);
-    EXPECT_EQ(0, rcode_);
+    checkResult(x, 0);
 }
 }
 
 
 /// The goal of this test is to verify that the code accepts only
 /// The goal of this test is to verify that the code accepts only
@@ -81,15 +106,13 @@ TEST_F(Dhcp4ParserTest, bogus_command) {
                     Element::fromJSON("{\"bogus\": 5}")));
                     Element::fromJSON("{\"bogus\": 5}")));
 
 
     // returned value must be 1 (configuration parse error)
     // returned value must be 1 (configuration parse error)
-    ASSERT_TRUE(x);
-    comment_ = parseAnswer(rcode_, x);
-    EXPECT_EQ(1, rcode_);
+    checkResult(x, 1);
 }
 }
 
 
 /// The goal of this test is to verify if wrongly defined subnet will
 /// The goal of this test is to verify if wrongly defined subnet will
 /// be rejected. Properly defined subnet must include at least one
 /// be rejected. Properly defined subnet must include at least one
 /// pool definition.
 /// pool definition.
-TEST_F(Dhcp4ParserTest, empty_subnet) {
+TEST_F(Dhcp4ParserTest, emptySubnet) {
 
 
     ConstElementPtr status;
     ConstElementPtr status;
 
 
@@ -101,9 +124,11 @@ TEST_F(Dhcp4ParserTest, empty_subnet) {
                                       "\"valid-lifetime\": 4000 }")));
                                       "\"valid-lifetime\": 4000 }")));
 
 
     // returned value should be 0 (success)
     // returned value should be 0 (success)
-    ASSERT_TRUE(status);
-    comment_ = parseAnswer(rcode_, status);
-    EXPECT_EQ(0, rcode_);
+    checkResult(status, 0);
+
+    checkGlobalUint32("rebind-timer", 2000);
+    checkGlobalUint32("renew-timer", 1000);
+    checkGlobalUint32("valid-lifetime", 4000);
 }
 }
 
 
 /// The goal of this test is to verify if defined subnet uses global
 /// The goal of this test is to verify if defined subnet uses global
@@ -126,9 +151,7 @@ TEST_F(Dhcp4ParserTest, subnet_global_defaults) {
     EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
     EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
 
 
     // check if returned status is OK
     // check if returned status is OK
-    ASSERT_TRUE(status);
-    comment_ = parseAnswer(rcode_, status);
-    EXPECT_EQ(0, rcode_);
+    checkResult(status, 0);
 
 
     // Now check if the configuration was indeed handled and we have
     // Now check if the configuration was indeed handled and we have
     // expected pool configured.
     // expected pool configured.
@@ -141,7 +164,7 @@ TEST_F(Dhcp4ParserTest, subnet_global_defaults) {
 
 
 // This test checks if it is possible to override global values
 // This test checks if it is possible to override global values
 // on a per subnet basis.
 // on a per subnet basis.
-TEST_F(Dhcp4ParserTest, subnet_local) {
+TEST_F(Dhcp4ParserTest, subnetLocal) {
 
 
     ConstElementPtr status;
     ConstElementPtr status;
 
 
@@ -162,9 +185,7 @@ TEST_F(Dhcp4ParserTest, subnet_local) {
     EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
     EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
 
 
     // returned value should be 0 (configuration success)
     // returned value should be 0 (configuration success)
-    ASSERT_TRUE(status);
-    comment_ = parseAnswer(rcode_, status);
-    EXPECT_EQ(0, rcode_);
+    checkResult(status, 0);
 
 
     Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"));
     Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"));
     ASSERT_TRUE(subnet);
     ASSERT_TRUE(subnet);
@@ -175,7 +196,7 @@ TEST_F(Dhcp4ParserTest, subnet_local) {
 
 
 // Test verifies that a subnet with pool values that do not belong to that
 // Test verifies that a subnet with pool values that do not belong to that
 // pool are rejected.
 // pool are rejected.
-TEST_F(Dhcp4ParserTest, pool_out_of_subnet) {
+TEST_F(Dhcp4ParserTest, poolOutOfSubnet) {
 
 
     ConstElementPtr status;
     ConstElementPtr status;
 
 
@@ -194,17 +215,15 @@ TEST_F(Dhcp4ParserTest, pool_out_of_subnet) {
 
 
     // returned value must be 2 (values error)
     // returned value must be 2 (values error)
     // as the pool does not belong to that subnet
     // as the pool does not belong to that subnet
-    ASSERT_TRUE(status);
-    comment_ = parseAnswer(rcode_, status);
-    EXPECT_EQ(2, rcode_);
+    checkResult(status, 2);
 }
 }
 
 
 // Goal of this test is to verify if pools can be defined
 // Goal of this test is to verify if pools can be defined
 // using prefix/length notation. There is no separate test for min-max
 // using prefix/length notation. There is no separate test for min-max
 // notation as it was tested in several previous tests.
 // notation as it was tested in several previous tests.
-TEST_F(Dhcp4ParserTest, pool_prefix_len) {
+TEST_F(Dhcp4ParserTest, poolPrefixLen) {
 
 
-    ConstElementPtr x;
+    ConstElementPtr status;
 
 
     string config = "{ \"interface\": [ \"all\" ],"
     string config = "{ \"interface\": [ \"all\" ],"
         "\"rebind-timer\": 2000, "
         "\"rebind-timer\": 2000, "
@@ -217,12 +236,10 @@ TEST_F(Dhcp4ParserTest, pool_prefix_len) {
 
 
     ElementPtr json = Element::fromJSON(config);
     ElementPtr json = Element::fromJSON(config);
 
 
-    EXPECT_NO_THROW(x = configureDhcp4Server(*srv_, json));
+    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
 
 
-    // returned value must be 1 (configuration parse error)
-    ASSERT_TRUE(x);
-    comment_ = parseAnswer(rcode_, x);
-    EXPECT_EQ(0, rcode_);
+    // returned value must be 0 (configuration accepted)
+    checkResult(status, 0);
 
 
     Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"));
     Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"));
     ASSERT_TRUE(subnet);
     ASSERT_TRUE(subnet);
@@ -231,4 +248,47 @@ TEST_F(Dhcp4ParserTest, pool_prefix_len) {
     EXPECT_EQ(4000, subnet->getValid());
     EXPECT_EQ(4000, subnet->getValid());
 }
 }
 
 
+/// This test checks if Uint32Parser can really parse the whole range
+/// and properly err of out of range values. As we can't call Uint32Parser
+/// directly, we are exploiting the fact that it is used to parse global
+/// parameter renew-timer and the results are stored in uint32_defaults.
+TEST_F(Dhcp4ParserTest, Uint32Parser) {
+
+    ConstElementPtr status;
+
+    // CASE 1: 0 - minimum value, should work
+    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_,
+                    Element::fromJSON("{\"version\": 0,"
+                                      "\"renew-timer\": 0}")));
+
+    // returned value must be ok (0 is a proper value)
+    checkResult(status, 0);
+    checkGlobalUint32("renew-timer", 0);
+
+    // CASE 2: 4294967295U (UINT_MAX) should work as well
+    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_,
+                    Element::fromJSON("{\"version\": 0,"
+                                      "\"renew-timer\": 4294967295}")));
+
+    // returned value must be ok (0 is a proper value)
+    checkResult(status, 0);
+    checkGlobalUint32("renew-timer", 4294967295U);
+
+    // CASE 3: 4294967296U (UINT_MAX + 1) should not work
+    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_,
+                    Element::fromJSON("{\"version\": 0,"
+                                      "\"renew-timer\": 4294967296}")));
+
+    // returned value must be rejected (1 configuration error)
+    checkResult(status, 1);
+
+    // CASE 4: -1 (UINT_MIN -1 ) should not work
+    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_,
+                    Element::fromJSON("{\"version\": 0,"
+                                      "\"renew-timer\": -1}")));
+
+    // returned value must be rejected (1 configuration error)
+    checkResult(status, 1);
+}
+
 };
 };