]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[2270] Merge branch 'master' into trac2270
authorTomek Mrugalski <tomasz@isc.org>
Wed, 12 Dec 2012 13:50:38 +0000 (14:50 +0100)
committerTomek Mrugalski <tomasz@isc.org>
Wed, 12 Dec 2012 13:50:38 +0000 (14:50 +0100)
Conflicts:
ChangeLog
doc/devel/02-dhcp.dox
src/bin/dhcp4/ctrl_dhcp4_srv.cc
src/bin/dhcp4/dhcp4_srv.cc
src/bin/dhcp4/dhcp4_srv.h
src/bin/dhcp6/config_parser.cc
src/bin/dhcp6/config_parser.h

16 files changed:
1  2 
ChangeLog
doc/devel/mainpage.dox
doc/guide/bind10-guide.xml
src/bin/dhcp4/Makefile.am
src/bin/dhcp4/config_parser.cc
src/bin/dhcp4/ctrl_dhcp4_srv.cc
src/bin/dhcp4/ctrl_dhcp4_srv.h
src/bin/dhcp4/dhcp4_messages.mes
src/bin/dhcp4/dhcp4_srv.h
src/bin/dhcp4/tests/Makefile.am
src/bin/dhcp4/tests/config_parser_unittest.cc
src/bin/dhcp6/config_parser.cc
src/bin/dhcp6/config_parser.h
src/bin/dhcp6/dhcp6.dox
src/lib/dhcpsrv/cfgmgr.cc
src/lib/dhcpsrv/cfgmgr.h

diff --cc ChangeLog
index f7f5ab14a58aaee7cc4e27b97438d1706f862970,06207ec8090b761b1f20f77d9c13941581ab5b29..91645876f1db681f4e837b13ad7212836ea8e3b2
+++ b/ChangeLog
- 4XX.  [func]          tomek
++525.  [func]          tomek
 +      b10-dhcp4: DHCPv4 server is now able to parse configuration. It
 +      is possible to specify IPv4 subnets with dynamic pools within
 +      them. Although configuration is accepted, it is not used yet. This
 +      will be implemented shortly.
++      (Trac #2270, git de29c07129d41c96ee0d5eebdd30a1ea7fb9ac8a)
++
+ 524.  [func]          tomek
+       b10-dhcp6 is now able to handle RENEW messages. Leases are
+       renewed and REPLY responses are sent back to clients.
+       (Trac #2325, git 7f6c9d057cc0a7a10f41ce7da9c8565b9ee85246)
+ 523.  [bug]           muks
+       Fixed a problem in inmem NSEC3 lookup (for, instance when using a
+       zone with no non-apex names) which caused exceptions when the zone
+       origin was not added as an explicit NSEC3 record.
+       (Trac #2503, git 6fe86386be0e7598633fe35999112c1a6e3b0370)
+ 522.  [func]*         jelte
+       Configuration of TSIG keys for b10-xfrin has changed; instead of
+       specifying the full TSIG key (<name>:<base64>:<algo>) it now expects
+       just the name, and uses the global TSIG Key Ring like all the other
+       components (configuration list /tsig_keys/keys).
+       Note: this is not automatically updated, so if you use TSIG in
+       xfrin, you need to update your configuration.
+       (Trac #1351, git e65b7b36f60f14b7abe083da411e6934cdfbae7a)
+ 521.  [func]          marcin
+       Implemented definitions for DHCPv6 standard options identified
+       by codes up to 48. These definitions are now used by the DHCPv6
+       server to create instances of options being sent to a client.
+       (Trac #2491, git 0a4faa07777189ed9c25211987a1a9b574015a95)
+ 520.  [func]          jelte
+       The system no longer prints initial log messages to stdout
+       regardless of what logging configuration is present, but it
+       temporarily stores any log messages until the configuration is
+       processed. If there is no specific configuration, or if the
+       configuration cannot be accessed, it will still fall back to stdout.
+       Note that there are still a few instances where output is printed,
+       these shall be addressed separately.
+       Note also that, currently, in case it falls back to stdout (such as
+       when it cannot connect to b10-cfgmgr), all log messages are always
+       printed (including debug messages), regardless of whether -v was
+       used. This shall also be addressed in a future change.
+       (Trac #2445, git 74a0abe5a6d10b28e4a3e360e87b129c232dea68)
+ 519.  [bug]           muks
+       Fixed a problem in inmem NSEC lookup which caused returning an
+       incorrect NSEC record or (in rare cases) assert failures
+       when a non-existent domain was queried, which was a sub-domain of
+       a domain that existed.
+       (Trac #2504, git 835553eb309d100b062051f7ef18422d2e8e3ae4)
+ 518.  [func]          stephen
+       Extend DHCP MySQL backend to handle IPv4 addresses.
+       (Trac #2404, git ce7db48d3ff5d5aad12b1da5e67ae60073cb2607)
+ 517.  [func]          stephen
+       Added IOAddress::toBytes() to get byte representation of address.
+       Also added convenience methods for V4/V6 address determination.
+       (Trac #2396, git c23f87e8ac3ea781b38d688f8f7b58539f85e35a)
+ 516.  [bug]           marcin
+       Fixed 'make distcheck' failure when running perfdhcp unit tests.
+       The unit tests used to read files from the folder specified
+       with the path relative to current folder, thus when the test was
+       run from a different folder the files could not be found.
+       (Trac #2479, git 4e8325e1b309f1d388a3055ec1e1df98c377f383)
+ 515.  [bug]           jinmei
+       The in-memory data source now accepts an RRSIG provided without
+       a covered RRset in loading.  A subsequent query for its owner name
+       of the covered type would generally result in NXRRSET; if the
+       covered RRset is of type NSEC3, the corresponding NSEC3 processing
+       would result in SERVFAIL.
+       (Trac #2420, git 6744c100953f6def5500bcb4bfc330b9ffba0f5f)
+ 514.  [bug]           jelte
+       b10-msgq now handles socket errors more gracefully when sending data
+       to clients. It no longer exits with 'broken pipe' errors, and is
+       also better at resending data on temporary error codes from send().
+       (Trac #2398, git 9f6b45ee210a253dca608848a58c824ff5e0d234)
+ 513.  [func]          marcin
+       Implemented the OptionCustom class for DHCPv4 and DHCPv6.
+       This class represents an option which has a defined
+       structure: a set of data fields of specific types and order.
+       It is used to represent those options that can't be
+       represented by any other specialized class.
+       (Trac #2312, git 28d885b457dda970d9aecc5de018ec1120143a10)
+ 512.  [func]          jelte
+       Added a new tool b10-certgen, to check and update the self-signed
+       SSL certificate used by b10-cmdctl. The original certificate
+       provided has been removed, and a fresh one is generated upon first
+       build. See the b10-certgen manpage for information on how to update
+       existing installed certificates.
+       (Trac #1044, git 510773dd9057ccf6caa8241e74a7a0b34ca971ab)
+ 511.  [bug]           stephen
+       Fixed a race condition in the DHCP tests whereby the test program
+       spawned a subprocess and attempted to read (without waiting) from
+       the interconnecting pipe before the subprocess had written
+       anything.  The lack of output was being interpreted as a test
+       failure.
+       (Trac #2410, git f53e65cdceeb8e6da4723730e4ed0a17e4646579)
+ 510.  [func]          marcin
+       DHCP option instances can be created using a collection of strings.
+       Each string represents a value of a particular data field within
+       an option. The data field values, given as strings, are validated
+       against the actual types of option fields specified in the options
+       definitions.
+       (Trac #2490, git 56cfd6612fcaeae9acec4a94e1e5f1a88142c44d)
+ 509.  [func]          muks
+       Log messages now include the pid of the process that logged the
+       message.
+       (Trac #1745, git fc8bbf3d438e8154e7c2bdd322145a7f7854dc6a)
+ 508.  [bug]           stephen
+       Split the DHCP library into two directories, each with its own
+       Makefile.  This properly solves the problem whereby a "make"
+       operation with multiple threads could fail because of the
+       dependencies between two libraries in the same directory.
+       (Trac #2475, git 834fa9e8f5097c6fd06845620f68547a97da8ff8)
+ bind10-devel-20121115 released on November 15, 2012
+ 507.  [doc]           jelte
+       Added a chapter about the use of the bindctl command tool to
+       to the BIND 10 guide.
+       (Trac #2305, git c4b0294b5bf4a9d32fb18ab62ca572f492788d72)
+ 506.  [security]              jinmei
+       Fixed a use-after-free case in handling DNAME record with the
+       in-memory data source.  This could lead to a crash of b10-auth
+       if it serves a zone containing a DNAME RR from the in-memory
+       data source.  This bug was introduced at bind10-devel-20120927.
+       (Trac #2471, git 2b1793ac78f972ddb1ae2fd092a7f539902223ff)
+ 505.  [bug]           jelte
+       Fixed a bug in b10-xfrin where a wrong call was made during the
+       final check of a TSIG-signed transfer, incorrectly rejecting the
+       transfer.
+       (Trac #2464, git eac81c0cbebee72f6478bdb5cda915f5470d08e1)
+ 504.  [bug]*          naokikambe
+       Fixed an XML format viewed from b10-stats-httpd. Regarding
+       per-zone counters as zones of Xfrout, a part of the item
+       values wasn't an exact XML format. A zone name can be
+       specified in URI as
+       /bind10/statistics/xml/Xfrout/zones/example.org/xfrreqdone.
+       XSD and XSL formats are also changed to constant ones due
+       to these changes.
+       (Trac #2298, git 512d2d46f3cb431bcdbf8d90af27bff8874ba075)
+ 503.  [func]          Stephen
+       Add initial version of a MySQL backend for the DHCP code.  This
+       implements the basic IPv6 lease access functions - add lease, delete
+       lease and update lease.  The backend is enabled by specifying
+       --with-dhcp-mysql on the "configure" command line: without this
+       switch, the MySQL code is not compiled, so leaving BIND 10 able to
+       be built on systems without MySQL installed.
+       (Trac #2342, git c7defffb89bd0f3fdd7ad2437c78950bcb86ad37)
+ 502.  [func]          vorner
+       TTLs can be specified with units as well as number of seconds now.
+       This allows specifications like "1D3H".
+       (Trac #2384, git 44c321c37e17347f33ced9d0868af0c891ff422b)
+ 501.  [func]          tomek
+       Added DHCPv6 allocation engine, now used in the processing of DHCPv6
+       messages.
+       (Trac #2414, git b3526430f02aa3dc3273612524d23137b8f1fe87)
+ 500.  [bug]           jinmei
+       Corrected the autoconf example in the examples directory so it can
+       use the configured path to Boost to check availability of the BIND 10
+       library.  Previously the sample configure script could fail if
+       Boost is installed in an uncommon place.  Also, it now provides a
+       helper m4 function and example usage for embedding the library
+       path to executable (using linker options like -Wl,-R) to help
+       minimize post-build hassles.
+       (Trac #2356, git 36514ddc884c02a063e166d44319467ce6fb1d8f)
+ 499.  [func]          team
+       The b10-auth 'loadzone' command now uses the internal thread
+       introduced in 495 to (re)load a zone in the background, so that
+       query processing isn't blocked while loading a zone.
+       (Trac #2213, git 686594e391c645279cc4a95e0e0020d1c01fba7e)
+ 498.  [func]          marcin
+       Implemented DHCPv6 option values configuration using configuration
+       manager. In order to set values for data fields carried by the
+       particular option, user specifies the string of hexadecimal digits
+       that is in turn converted to binary data and stored into option
+       buffer. More user friendly way of option content specification is
+       planned.
+       (Trac #2318, git e75c686cd9c14f4d6c2a242a0a0853314704fee9)
+ 497.  [bug]           jinmei
+       Fixed several issues in isc-sysinfo:
+       - make sure it doesn't report a negative value for free memory
+         size (this happened on FreeBSD, but can possibly occur on other
+         BSD variants)
+       - correctly identifies the SMP support in kernel on FreeBSD
+       - print more human readable uptime as well as the time in seconds
+       (Trac #2297, git 59a449f506948e2371ffa87dcd19059388bd1657)
+ 496.  [func]          tomek
+       DHCPv6 Allocation Engine implemented. It allows address allocation
+       from the configured subnets/pools. It currently features a single
+       allocator: IterativeAllocator, which assigns addresses iteratively.
+       Other allocators (hashed, random) are planned.
+       (Trac #2324, git 8aa188a10298e3a55b725db36502a99d2a8d638a)
+ 495.  [func]          team
+       b10-auth now handles reconfiguration of data sources in
+       background using a separate thread.  This means even if the new
+       configuration includes a large amount of data to be loaded into
+       memory (very large zones and/or a very large number of zones),
+       the reconfiguration doesn't block query handling.
+       (Multiple Trac tickets up to #2211)
+ 494.  [bug]           jinmei
+       Fixed a problem that shutting down BIND 10 kept some of the
+       processes alive.  It was two-fold: when the main bind10 process
+       started as a root, started b10-sockcreator with the privilege, and
+       then dropped the privilege, the bind10 process cannot kill the
+       sockcreator via signal any more (when it has to), but it kept
+       sending the signal and didn't stop.  Also, when running on Python
+       3.1 (or older), the sockcreator had some additional file
+       descriptor open, which prevented it from exiting even after the
+       bind10 process terminated.  Now the bind10 process simply gives up
+       killing a subprocess if it fails due to lack of permission, and it
+       makes sure the socket creator is spawned without any unnecessary
+       FDs open.
+       (Trac #1858, git 405d85c8a0042ba807a3a123611ff383c4081ee1)
+ 493.  [build]         jinmei
+       Fixed build failure with newer versions of clang++.  These
+       versions are stricter regarding "unused variable" and "unused
+       (driver) arguments" warnings, and cause fatal build error
+       with -Werror.  The affected versions of clang++ include Apple's
+       customized version 4.1 included in Xcode 4.5.1.  So this fix
+       will solve build errors for Mac OS X that uses newer versions of
+       Xcode.
+       (Trac #2340, git 55be177fc4f7537143ab6ef5a728bd44bdf9d783,
+       3e2a372012e633d017a97029d13894e743199741 and commits before it
+       with [2340] in the commit log)
  
  492.  [func]          tomek
        libdhcpsrv: The DHCP Configuration Manager is now able to store
Simple merge
Simple merge
index 3939915115f470a0478f2a9a49d7cfb9589ce445,e0c97d17b89a432978a766a9d35e613579f96f8c..c8965911d739c349f0c165c45050ad55edd6b2b7
@@@ -58,7 -57,6 +58,7 @@@ b10_dhcp4_CXXFLAGS = -Wno-unused-parame
  endif
  
  b10_dhcp4_LDADD  = $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
- b10_dhcp4_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcpsrv.la
++b10_dhcp4_LDADD += $(top_builddir)/src/lib/dhcpsrv/libb10-dhcpsrv.la
  b10_dhcp4_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
  b10_dhcp4_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
  b10_dhcp4_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
index 08ea89433694be8717f613e96ad30fe531ac6d6b,0000000000000000000000000000000000000000..aa2fa4f3d81fc3ffe925e7092869273e045b4f86
mode 100644,000000..100644
--- /dev/null
@@@ -1,772 -1,0 +1,772 @@@
- #include <dhcp/cfgmgr.h>
 +// 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.
 +
 +#include <config/ccsession.h>
++#include <dhcpsrv/cfgmgr.h>
 +#include <dhcp4/config_parser.h>
 +#include <dhcp4/dhcp4_log.h>
 +#include <boost/foreach.hpp>
 +#include <boost/lexical_cast.hpp>
 +#include <boost/algorithm/string.hpp>
 +#include <limits>
 +#include <iostream>
 +#include <vector>
 +#include <map>
 +
 +using namespace std;
 +using namespace isc::data;
 +using namespace isc::asiolink;
 +
 +namespace isc {
 +namespace dhcp {
 +
 +/// @brief auxiliary type used for storing element name and its parser
 +typedef pair<string, ConstElementPtr> ConfigPair;
 +
 +/// @brief a factory method that will create a parser for a given element name
 +typedef Dhcp4ConfigParser* ParserFactory(const std::string& config_id);
 +
 +/// @brief a collection of factories that creates parsers for specified element names
 +typedef std::map<std::string, ParserFactory*> FactoryMap;
 +
 +/// @brief a collection of pools
 +///
 +/// That type is used as intermediate storage, when pools are parsed, but there is
 +/// no subnet object created yet to store them.
 +typedef std::vector<Pool4Ptr> PoolStorage;
 +
 +/// @brief Global uint32 parameters that will be used as defaults.
 +Uint32Storage uint32_defaults;
 +
 +/// @brief global string parameters that will be used as defaults.
 +StringStorage string_defaults;
 +
 +/// @brief a dummy configuration parser
 +///
 +/// It is a debugging parser. It does not configure anything,
 +/// will accept any configuration and will just print it out
 +/// on commit. Useful for debugging existing configurations and
 +/// adding new ones.
 +class DebugParser : public Dhcp4ConfigParser {
 +public:
 +
 +    /// @brief Constructor
 +    ///
 +    /// See \ref Dhcp4ConfigParser class for details.
 +    ///
 +    /// @param param_name name of the parsed parameter
 +    DebugParser(const std::string& param_name)
 +        :param_name_(param_name) {
 +    }
 +
 +    /// @brief builds parameter value
 +    ///
 +    /// See \ref Dhcp4ConfigParser class for details.
 +    ///
 +    /// @param new_config pointer to the new configuration
 +    virtual void build(ConstElementPtr new_config) {
 +        std::cout << "Build for token: [" << param_name_ << "] = ["
 +                  << value_->str() << "]" << std::endl;
 +        value_ = new_config;
 +    }
 +
 +    /// @brief pretends to apply the configuration
 +    ///
 +    /// This is a method required by base class. It pretends to apply the
 +    /// configuration, but in fact it only prints the parameter out.
 +    ///
 +    /// See \ref Dhcp4ConfigParser class for details.
 +    virtual void commit() {
 +        // Debug message. The whole DebugParser class is used only for parser
 +        // debugging, and is not used in production code. It is very convenient
 +        // to keep it around. Please do not turn this cout into logger calls.
 +        std::cout << "Commit for token: [" << param_name_ << "] = ["
 +                  << value_->str() << "]" << std::endl;
 +    }
 +
 +    /// @brief factory that constructs DebugParser objects
 +    ///
 +    /// @param param_name name of the parameter to be parsed
 +    static Dhcp4ConfigParser* Factory(const std::string& param_name) {
 +        return (new DebugParser(param_name));
 +    }
 +
 +private:
 +    /// name of the parsed parameter
 +    std::string param_name_;
 +
 +    /// pointer to the actual value of the parameter
 +    ConstElementPtr value_;
 +};
 +
 +/// @brief Configuration parser for uint32 parameters
 +///
 +/// This class is a generic parser that is able to handle any uint32 integer
 +/// type. By default it stores the value in external global container
 +/// (uint32_defaults). If used in smaller scopes (e.g. to parse parameters
 +/// in subnet config), it can be pointed to a different storage, using
 +/// setStorage() method. This class follows the parser interface, laid out
 +/// in its base class, \ref Dhcp4ConfigParser.
 +///
 +/// For overview of usability of this generic purpose parser, see
 +/// \ref dhcp4-config-inherit page.
 +class Uint32Parser : public Dhcp4ConfigParser {
 +public:
 +
 +    /// @brief constructor for Uint32Parser
 +    /// @param param_name name of the configuration parameter being parsed
 +    Uint32Parser(const std::string& param_name)
 +        :storage_(&uint32_defaults), param_name_(param_name) {
 +    }
 +
 +    /// @brief builds parameter value
 +    ///
 +    /// Parses configuration entry and stores it in a storage. See
 +    /// \ref setStorage() for details.
 +    ///
 +    /// @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) {
 +        int64_t check;
 +        string x = value->str();
 +        try {
 +            check = boost::lexical_cast<int64_t>(x);
 +        } catch (const boost::bad_lexical_cast &) {
 +            isc_throw(BadValue, "Failed to parse value " << value->str()
 +                      << " as unsigned 32-bit integer.");
 +        }
 +        if (check > std::numeric_limits<uint32_t>::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);
 +
 +        (*storage_)[param_name_] = value_;
 +    }
 +
 +    /// @brief does nothing
 +    ///
 +    /// This method is required for all parsers. The value itself
 +    /// is not commited anywhere. Higher level parsers are expected to
 +    /// use values stored in the storage, e.g. renew-timer for a given
 +    /// subnet is stored in subnet-specific storage. It is not commited
 +    /// here, but is rather used by \ref Subnet4ConfigParser when constructing
 +    /// the subnet.
 +    virtual void commit() {
 +    }
 +
 +    /// @brief factory that constructs Uint32Parser objects
 +    ///
 +    /// @param param_name name of the parameter to be parsed
 +    static Dhcp4ConfigParser* Factory(const std::string& param_name) {
 +        return (new Uint32Parser(param_name));
 +    }
 +
 +    /// @brief sets storage for value of this parameter
 +    ///
 +    /// See \ref dhcp4-config-inherit for details.
 +    ///
 +    /// @param storage pointer to the storage container
 +    void setStorage(Uint32Storage* storage) {
 +        storage_ = storage;
 +    }
 +
 +private:
 +    /// pointer to the storage, where parsed value will be stored
 +    Uint32Storage* storage_;
 +
 +    /// name of the parameter to be parsed
 +    std::string param_name_;
 +
 +    /// the actual parsed value
 +    uint32_t value_;
 +};
 +
 +/// @brief Configuration parser for string parameters
 +///
 +/// This class is a generic parser that is able to handle any string
 +/// parameter. By default it stores the value in external global container
 +/// (string_defaults). If used in smaller scopes (e.g. to parse parameters
 +/// in subnet config), it can be pointed to a different storage, using
 +/// setStorage() method. This class follows the parser interface, laid out
 +/// in its base class, \ref Dhcp4ConfigParser.
 +///
 +/// For overview of usability of this generic purpose parser, see
 +/// \ref dhcp4-config-inherit page.
 +class StringParser : public Dhcp4ConfigParser {
 +public:
 +
 +    /// @brief constructor for StringParser
 +    /// @param param_name name of the configuration parameter being parsed
 +    StringParser(const std::string& param_name)
 +        :storage_(&string_defaults), param_name_(param_name) {
 +    }
 +
 +    /// @brief parses parameter value
 +    ///
 +    /// Parses configuration entry and stores it in storage. See
 +    /// \ref setStorage() for details.
 +    ///
 +    /// @param value pointer to the content of parsed values
 +    virtual void build(ConstElementPtr value) {
 +        value_ = value->str();
 +        boost::erase_all(value_, "\"");
 +
 +        (*storage_)[param_name_] = value_;
 +    }
 +
 +    /// @brief does nothing
 +    ///
 +    /// This method is required for all parser. The value itself
 +    /// is not commited anywhere. Higher level parsers are expected to
 +    /// use values stored in the storage, e.g. renew-timer for a given
 +    /// subnet is stored in subnet-specific storage. It is not commited
 +    /// here, but is rather used by its parent parser when constructing
 +    /// an object, e.g. the subnet.
 +    virtual void commit() {
 +    }
 +
 +    /// @brief factory that constructs StringParser objects
 +    ///
 +    /// @param param_name name of the parameter to be parsed
 +    static Dhcp4ConfigParser* Factory(const std::string& param_name) {
 +        return (new StringParser(param_name));
 +    }
 +
 +    /// @brief sets storage for value of this parameter
 +    ///
 +    /// See \ref dhcp4-config-inherit for details.
 +    ///
 +    /// @param storage pointer to the storage container
 +    void setStorage(StringStorage* storage) {
 +        storage_ = storage;
 +    }
 +
 +private:
 +    /// pointer to the storage, where parsed value will be stored
 +    StringStorage* storage_;
 +
 +    /// name of the parameter to be parsed
 +    std::string param_name_;
 +
 +    /// the actual parsed value
 +    std::string value_;
 +};
 +
 +
 +/// @brief parser for interface list definition
 +///
 +/// This parser handles Dhcp4/interface entry.
 +/// It contains a list of network interfaces that the server listens on.
 +/// In particular, it can contain an entry called "all" or "any" that
 +/// designates all interfaces.
 +///
 +/// It is useful for parsing Dhcp4/interface parameter.
 +class InterfaceListConfigParser : public Dhcp4ConfigParser {
 +public:
 +
 +    /// @brief constructor
 +    ///
 +    /// As this is a dedicated parser, it must be used to parse
 +    /// "interface" parameter only. All other types will throw exception.
 +    ///
 +    /// @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) {
 +        if (param_name != "interface") {
 +            isc_throw(BadValue, "Internal error. Interface configuration "
 +                      "parser called for the wrong parameter: " << param_name);
 +        }
 +    }
 +
 +    /// @brief parses parameters value
 +    ///
 +    /// Parses configuration entry (list of parameters) and adds each element
 +    /// to the interfaces list.
 +    ///
 +    /// @param value pointer to the content of parsed values
 +    virtual void build(ConstElementPtr value) {
 +        BOOST_FOREACH(ConstElementPtr iface, value->listValue()) {
 +            interfaces_.push_back(iface->str());
 +        }
 +    }
 +
 +    /// @brief commits interfaces list configuration
 +    virtual void commit() {
 +        /// @todo: Implement per interface listening. Currently always listening
 +        /// on all interfaces.
 +    }
 +
 +    /// @brief factory that constructs InterfaceListConfigParser objects
 +    ///
 +    /// @param param_name name of the parameter to be parsed
 +    static Dhcp4ConfigParser* Factory(const std::string& param_name) {
 +        return (new InterfaceListConfigParser(param_name));
 +    }
 +
 +private:
 +    /// contains list of network interfaces
 +    vector<string> interfaces_;
 +};
 +
 +/// @brief parser for pool definition
 +///
 +/// This parser handles pool definitions, i.e. a list of entries of one
 +/// of two syntaxes: min-max and prefix/len. Pool4 objects are created
 +/// and stored in chosen PoolStorage container.
 +///
 +/// As there are no default values for pool, setStorage() must be called
 +/// before build(). Otherwise exception will be thrown.
 +///
 +/// It is useful for parsing Dhcp4/subnet4[X]/pool parameters.
 +class PoolParser : public Dhcp4ConfigParser {
 +public:
 +
 +    /// @brief constructor.
 +    PoolParser(const std::string& /*param_name*/)
 +        :pools_(NULL) {
 +        // ignore parameter name, it is always Dhcp4/subnet4[X]/pool
 +    }
 +
 +    /// @brief parses the actual list
 +    ///
 +    /// This method parses the actual list of interfaces.
 +    /// No validation is done at this stage, everything is interpreted as
 +    /// 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) {
 +        // setStorage() should have been called before build
 +        if (!pools_) {
 +            isc_throw(InvalidOperation, "Parser logic error. No pool storage set,"
 +                      " but pool parser asked to parse pools");
 +        }
 +
 +        BOOST_FOREACH(ConstElementPtr text_pool, pools_list->listValue()) {
 +
 +            // That should be a single pool representation. It should contain
 +            // text is form prefix/len or first - last. Note that spaces
 +            // are allowed
 +            string txt = text_pool->stringValue();
 +
 +            // first let's remove any whitespaces
 +            boost::erase_all(txt, " "); // space
 +            boost::erase_all(txt, "\t"); // tabulation
 +
 +            // Is this prefix/len notation?
 +            size_t pos = txt.find("/");
 +            if (pos != string::npos) {
 +                IOAddress addr("::");
 +                uint8_t len = 0;
 +                try {
 +                    addr = IOAddress(txt.substr(0, pos));
 +
 +                    // start with the first character after /
 +                    string prefix_len = txt.substr(pos + 1);
 +
 +                    // It is lexical cast to int and then downcast to uint8_t.
 +                    // Direct cast to uint8_t (which is really an unsigned char)
 +                    // will result in interpreting the first digit as output
 +                    // value and throwing exception if length is written on two
 +                    // digits (because there are extra characters left over).
 +
 +                    // No checks for values over 128. Range correctness will
 +                    // be checked in Pool4 constructor.
 +                    len = boost::lexical_cast<int>(prefix_len);
 +                } catch (...)  {
 +                    isc_throw(Dhcp4ConfigError, "Failed to parse pool "
 +                              "definition: " << text_pool->stringValue());
 +                }
 +
 +                Pool4Ptr pool(new Pool4(addr, len));
 +                pools_->push_back(pool);
 +                continue;
 +            }
 +
 +            // Is this min-max notation?
 +            pos = txt.find("-");
 +            if (pos != string::npos) {
 +                // using min-max notation
 +                IOAddress min(txt.substr(0,pos));
 +                IOAddress max(txt.substr(pos + 1));
 +
 +                Pool4Ptr pool(new Pool4(min, max));
 +
 +                pools_->push_back(pool);
 +                continue;
 +            }
 +
 +            isc_throw(Dhcp4ConfigError, "Failed to parse pool definition:"
 +                      << text_pool->stringValue() <<
 +                      ". Does not contain - (for min-max) nor / (prefix/len)");
 +        }
 +    }
 +
 +    /// @brief sets storage for value of this parameter
 +    ///
 +    /// See \ref dhcp4-config-inherit for details.
 +    ///
 +    /// @param storage pointer to the storage container
 +    void setStorage(PoolStorage* storage) {
 +        pools_ = storage;
 +    }
 +
 +    /// @brief does nothing.
 +    ///
 +    /// This method is required for all parsers. The value itself
 +    /// is not commited anywhere. Higher level parsers (for subnet) are expected
 +    /// to use values stored in the storage.
 +    virtual void commit() {}
 +
 +    /// @brief factory that constructs PoolParser objects
 +    ///
 +    /// @param param_name name of the parameter to be parsed
 +    static Dhcp4ConfigParser* Factory(const std::string& param_name) {
 +        return (new PoolParser(param_name));
 +    }
 +
 +private:
 +    /// @brief pointer to the actual Pools storage
 +    ///
 +    /// That is typically a storage somewhere in Subnet parser
 +    /// (an upper level parser).
 +    PoolStorage* pools_;
 +};
 +
 +/// @brief this class parses a single subnet
 +///
 +/// This class parses the whole subnet definition. It creates parsers
 +/// for received configuration parameters as needed.
 +class Subnet4ConfigParser : public Dhcp4ConfigParser {
 +public:
 +
 +    /// @brief constructor
 +    Subnet4ConfigParser(const std::string& ) {
 +        // The parameter should always be "subnet", but we don't check here
 +        // against it in case someone wants to reuse this parser somewhere.
 +    }
 +
 +    /// @brief parses parameter value
 +    ///
 +    /// @param subnet pointer to the content of subnet definition
 +    void build(ConstElementPtr subnet) {
 +
 +        BOOST_FOREACH(ConfigPair param, subnet->mapValue()) {
 +
 +            ParserPtr parser(createSubnet4ConfigParser(param.first));
 +
 +            // if this is an Uint32 parser, tell it to store the values
 +            // in values_, rather than in global storage
 +            boost::shared_ptr<Uint32Parser> uint_parser =
 +                boost::dynamic_pointer_cast<Uint32Parser>(parser);
 +            if (uint_parser) {
 +                uint_parser->setStorage(&uint32_values_);
 +            } else {
 +
 +                boost::shared_ptr<StringParser> string_parser =
 +                    boost::dynamic_pointer_cast<StringParser>(parser);
 +                if (string_parser) {
 +                    string_parser->setStorage(&string_values_);
 +                } else {
 +
 +                    boost::shared_ptr<PoolParser> pool_parser =
 +                        boost::dynamic_pointer_cast<PoolParser>(parser);
 +                    if (pool_parser) {
 +                        pool_parser->setStorage(&pools_);
 +                    }
 +                }
 +            }
 +
 +            parser->build(param.second);
 +            parsers_.push_back(parser);
 +        }
 +
 +        // Ok, we now have subnet parsed
 +    }
 +
 +    /// @brief commits received configuration.
 +    ///
 +    /// This method does most of the configuration. Many other parsers are just
 +    /// storing the values that are actually consumed here. Pool definitions
 +    /// created in other parsers are used here and added to newly created Subnet4
 +    /// objects. Subnet4 are then added to DHCP CfgMgr.
 +    /// @throw Dhcp4ConfigError if there are any issues encountered during commit
 +    void commit() {
 +
 +        StringStorage::const_iterator it = string_values_.find("subnet");
 +        if (it == string_values_.end()) {
 +            isc_throw(Dhcp4ConfigError,
 +                      "Mandatory subnet definition in subnet missing");
 +        }
 +        string subnet_txt = it->second;
 +        boost::erase_all(subnet_txt, " ");
 +        boost::erase_all(subnet_txt, "\t");
 +
 +        size_t pos = subnet_txt.find("/");
 +        if (pos == string::npos) {
 +            isc_throw(Dhcp4ConfigError,
 +                      "Invalid subnet syntax (prefix/len expected):" << it->second);
 +        }
 +        IOAddress addr(subnet_txt.substr(0, pos));
 +        uint8_t len = boost::lexical_cast<unsigned int>(subnet_txt.substr(pos + 1));
 +
 +        Triplet<uint32_t> t1 = getParam("renew-timer");
 +        Triplet<uint32_t> t2 = getParam("rebind-timer");
 +        Triplet<uint32_t> valid = getParam("valid-lifetime");
 +
 +        /// @todo: Convert this to logger once the parser is working reliably
 +        stringstream tmp;
 +        tmp << addr.toText() << "/" << (int)len
 +            << " with params t1=" << t1 << ", t2=" << t2 << ", valid=" << valid;
 +
 +        LOG_INFO(dhcp4_logger, DHCP4_CONFIG_NEW_SUBNET).arg(tmp.str());
 +
 +        Subnet4Ptr subnet(new Subnet4(addr, len, t1, t2, valid));
 +
 +        for (PoolStorage::iterator it = pools_.begin(); it != pools_.end(); ++it) {
 +            subnet->addPool4(*it);
 +        }
 +
 +        CfgMgr::instance().addSubnet4(subnet);
 +    }
 +
 +private:
 +
 +    /// @brief creates parsers for entries in subnet definition
 +    ///
 +    /// @todo Add subnet-specific things here (e.g. subnet-specific options)
 +    ///
 +    /// @param config_id name od the entry
 +    /// @return parser object for specified entry name
 +    /// @throw NotImplemented if trying to create a parser for unknown config element
 +    Dhcp4ConfigParser* createSubnet4ConfigParser(const std::string& config_id) {
 +        FactoryMap factories;
 +
 +        factories["valid-lifetime"] = Uint32Parser::Factory;
 +        factories["renew-timer"] = Uint32Parser::Factory;
 +        factories["rebind-timer"] = Uint32Parser::Factory;
 +        factories["subnet"] = StringParser::Factory;
 +        factories["pool"] = PoolParser::Factory;
 +
 +        FactoryMap::iterator f = factories.find(config_id);
 +        if (f == factories.end()) {
 +            // Used for debugging only.
 +            // return new DebugParser(config_id);
 +
 +            isc_throw(NotImplemented,
 +                      "Parser error: Subnet4 parameter not supported: "
 +                      << config_id);
 +        }
 +        return (f->second(config_id));
 +    }
 +
 +    /// @brief returns value for a given parameter (after using inheritance)
 +    ///
 +    /// This method implements inheritance. For a given parameter name, it first
 +    /// checks if there is a global value for it and overwrites it with specific
 +    /// value if such value was defined in subnet.
 +    ///
 +    /// @param name name of the parameter
 +    /// @return triplet with the parameter name
 +    /// @throw Dhcp4ConfigError when requested parameter is not present
 +    Triplet<uint32_t> getParam(const std::string& name) {
 +        uint32_t value = 0;
 +        bool found = false;
 +        Uint32Storage::iterator global = uint32_defaults.find(name);
 +        if (global != uint32_defaults.end()) {
 +            value = global->second;
 +            found = true;
 +        }
 +
 +        Uint32Storage::iterator local = uint32_values_.find(name);
 +        if (local != uint32_values_.end()) {
 +            value = local->second;
 +            found = true;
 +        }
 +
 +        if (found) {
 +            return (Triplet<uint32_t>(value));
 +        } else {
 +            isc_throw(Dhcp4ConfigError, "Mandatory parameter " << name
 +                      << " missing (no global default and no subnet-"
 +                      << "specific value)");
 +        }
 +    }
 +
 +    /// storage for subnet-specific uint32 values
 +    Uint32Storage uint32_values_;
 +
 +    /// storage for subnet-specific integer values
 +    StringStorage string_values_;
 +
 +    /// storage for pools belonging to this subnet
 +    PoolStorage pools_;
 +
 +    /// parsers are stored here
 +    ParserCollection parsers_;
 +};
 +
 +/// @brief this class parses list of subnets
 +///
 +/// This is a wrapper parser that handles the whole list of Subnet4
 +/// definitions. It iterates over all entries and creates Subnet4ConfigParser
 +/// for each entry.
 +class Subnets4ListConfigParser : public Dhcp4ConfigParser {
 +public:
 +
 +    /// @brief constructor
 +    ///
 +    Subnets4ListConfigParser(const std::string&) {
 +        /// parameter name is ignored
 +    }
 +
 +    /// @brief parses contents of the list
 +    ///
 +    /// Iterates over all entries on the list and creates Subnet4ConfigParser
 +    /// for each entry.
 +    ///
 +    /// @param subnets_list pointer to a list of IPv4 subnets
 +    void build(ConstElementPtr subnets_list) {
 +
 +        // No need to define FactoryMap here. There's only one type
 +        // used: Subnet4ConfigParser
 +
 +        BOOST_FOREACH(ConstElementPtr subnet, subnets_list->listValue()) {
 +
 +            ParserPtr parser(new Subnet4ConfigParser("subnet"));
 +            parser->build(subnet);
 +            subnets_.push_back(parser);
 +        }
 +
 +    }
 +
 +    /// @brief commits subnets definitions.
 +    ///
 +    /// Iterates over all Subnet4 parsers. Each parser contains definitions
 +    /// of a single subnet and its parameters and commits each subnet separately.
 +    void commit() {
 +        // @todo: Implement more subtle reconfiguration than toss
 +        // the old one and replace with the new one.
 +
 +        // remove old subnets
 +        CfgMgr::instance().deleteSubnets4();
 +
 +        BOOST_FOREACH(ParserPtr subnet, subnets_) {
 +            subnet->commit();
 +        }
 +
 +    }
 +
 +    /// @brief Returns Subnet4ListConfigParser object
 +    /// @param param_name name of the parameter
 +    /// @return Subnets4ListConfigParser object
 +    static Dhcp4ConfigParser* Factory(const std::string& param_name) {
 +        return (new Subnets4ListConfigParser(param_name));
 +    }
 +
 +    /// @brief collection of subnet parsers.
 +    ParserCollection subnets_;
 +};
 +
 +/// @brief creates global parsers
 +///
 +/// This method creates global parsers that parse global parameters, i.e.
 +/// those that take format of Dhcp4/param1, Dhcp4/param2 and so forth.
 +///
 +/// @param config_id pointer to received global configuration entry
 +/// @return parser for specified global DHCPv4 parameter
 +/// @throw NotImplemented if trying to create a parser for unknown config element
 +Dhcp4ConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id) {
 +    FactoryMap factories;
 +
 +    factories["valid-lifetime"] = Uint32Parser::Factory;
 +    factories["renew-timer"] = Uint32Parser::Factory;
 +    factories["rebind-timer"] = Uint32Parser::Factory;
 +    factories["interface"] = InterfaceListConfigParser::Factory;
 +    factories["subnet4"] = Subnets4ListConfigParser::Factory;
 +    factories["version"] = StringParser::Factory;
 +
 +    FactoryMap::iterator f = factories.find(config_id);
 +    if (f == factories.end()) {
 +        // Used for debugging only.
 +        // return new DebugParser(config_id);
 +
 +        isc_throw(NotImplemented,
 +                  "Parser error: Global configuration parameter not supported: "
 +                  << config_id);
 +    }
 +    return (f->second(config_id));
 +}
 +
 +isc::data::ConstElementPtr
 +configureDhcp4Server(Dhcpv4Srv& , ConstElementPtr config_set) {
 +    if (!config_set) {
 +        ConstElementPtr answer = isc::config::createAnswer(1,
 +                                 string("Can't parse NULL config"));
 +        return (answer);
 +    }
 +
 +    /// @todo: append most essential info here (like "2 new subnets configured")
 +    string config_details;
 +
 +    LOG_DEBUG(dhcp4_logger, DBG_DHCP4_COMMAND, DHCP4_CONFIG_START).arg(config_set->str());
 +
 +    ParserCollection parsers;
 +    try {
 +        BOOST_FOREACH(ConfigPair config_pair, config_set->mapValue()) {
 +
 +            ParserPtr parser(createGlobalDhcp4ConfigParser(config_pair.first));
 +            parser->build(config_pair.second);
 +            parsers.push_back(parser);
 +        }
 +    } catch (const isc::Exception& ex) {
 +        ConstElementPtr answer = isc::config::createAnswer(1,
 +                                 string("Configuration parsing failed:") + ex.what());
 +        return (answer);
 +    } catch (...) {
 +        // for things like bad_cast in boost::lexical_cast
 +        ConstElementPtr answer = isc::config::createAnswer(1,
 +                                 string("Configuration parsing failed"));
 +    }
 +
 +    try {
 +        BOOST_FOREACH(ParserPtr parser, parsers) {
 +            parser->commit();
 +        }
 +    }
 +    catch (const isc::Exception& ex) {
 +        ConstElementPtr answer = isc::config::createAnswer(2,
 +                                 string("Configuration commit failed:") + ex.what());
 +        return (answer);
 +    } catch (...) {
 +        // for things like bad_cast in boost::lexical_cast
 +        ConstElementPtr answer = isc::config::createAnswer(2,
 +                                 string("Configuration commit failed"));
 +    }
 +
 +    LOG_INFO(dhcp4_logger, DHCP4_CONFIG_COMPLETE).arg(config_details);
 +
 +    ConstElementPtr answer = isc::config::createAnswer(0, "Configuration commited.");
 +    return (answer);
 +}
 +
 +}; // end of isc::dhcp namespace
 +}; // end of isc namespace
index c9366af83325f71a6a086cbd9dd61aa286d0a76b,b02bf72d1e107ccb0f7df25e31aba7ccd40209b4..20eedebc05fd9634e0334265bc9ae9a808731986
  #include <dhcp4/ctrl_dhcp4_srv.h>
  #include <dhcp4/dhcp4_log.h>
  #include <dhcp4/spec_config.h>
- #include <dhcp/iface_mgr.h>
 +#include <dhcp4/config_parser.h>
  #include <exceptions/exceptions.h>
  #include <util/buffer.h>
 +#include <cassert>
 +#include <iostream>
  
+ #include <cassert>
+ #include <iostream>
  using namespace isc::asiolink;
  using namespace isc::cc;
  using namespace isc::config;
Simple merge
Simple merge
Simple merge
index 5dd55b35d07eb97b231a9ef930fea7c5dfa218ac,ddc3000f67ff6c92e8a98281b51bb144fbb4d276..e60191993d8a8911d0f09145773fa7fd6cbbb921
@@@ -67,7 -65,6 +67,7 @@@ dhcp4_unittests_LDFLAGS = $(AM_LDFLAGS
  dhcp4_unittests_LDADD = $(GTEST_LDADD)
  dhcp4_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
  dhcp4_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
- dhcp4_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcpsrv.la
++dhcp4_unittests_LDADD += $(top_builddir)/src/lib/dhcpsrv/libb10-dhcpsrv.la
  dhcp4_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
  dhcp4_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
  dhcp4_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
index c27999686b7ba6bf2c5236e4db2b8715e7e85f35,0000000000000000000000000000000000000000..22307df6647cb576b30adf28984be4f3dfe6db33
mode 100644,000000..100644
--- /dev/null
@@@ -1,294 -1,0 +1,294 @@@
- #include <dhcp/subnet.h>
- #include <dhcp/cfgmgr.h>
 +// 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.
 +
 +#include <config.h>
 +
 +#include <arpa/inet.h>
 +#include <gtest/gtest.h>
 +
 +#include <dhcp4/dhcp4_srv.h>
 +#include <dhcp4/config_parser.h>
 +#include <config/ccsession.h>
++#include <dhcpsrv/subnet.h>
++#include <dhcpsrv/cfgmgr.h>
 +#include <iostream>
 +#include <fstream>
 +#include <sstream>
 +#include <limits.h>
 +
 +using namespace std;
 +using namespace isc;
 +using namespace isc::dhcp;
 +using namespace isc::asiolink;
 +using namespace isc::data;
 +using namespace isc::config;
 +
 +namespace isc {
 +namespace dhcp {
 +extern Uint32Storage uint32_defaults;
 +}
 +}
 +
 +namespace {
 +
 +class Dhcp4ParserTest : public ::testing::Test {
 +public:
 +    Dhcp4ParserTest()
 +    :rcode_(-1) {
 +        // Open port 0 means to not do anything at all. We don't want to
 +        // deal with sockets here, just check if configuration handling
 +        // is sane.
 +        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() {
 +        delete srv_;
 +    };
 +
 +    Dhcpv4Srv* srv_;
 +
 +    int rcode_;
 +    ConstElementPtr comment_;
 +};
 +
 +// Goal of this test is a verification if a very simple config update
 +// with just a bumped version number. That's the simplest possible
 +// config update.
 +TEST_F(Dhcp4ParserTest, version) {
 +
 +    ConstElementPtr x;
 +
 +    EXPECT_NO_THROW(x = configureDhcp4Server(*srv_,
 +                    Element::fromJSON("{\"version\": 0}")));
 +
 +    // returned value must be 0 (configuration accepted)
 +    checkResult(x, 0);
 +}
 +
 +/// The goal of this test is to verify that the code accepts only
 +/// valid commands and malformed or unsupported parameters are rejected.
 +TEST_F(Dhcp4ParserTest, bogusCommand) {
 +
 +    ConstElementPtr x;
 +
 +    EXPECT_NO_THROW(x = configureDhcp4Server(*srv_,
 +                    Element::fromJSON("{\"bogus\": 5}")));
 +
 +    // returned value must be 1 (configuration parse error)
 +    checkResult(x, 1);
 +}
 +
 +/// The goal of this test is to verify if wrongly defined subnet will
 +/// be rejected. Properly defined subnet must include at least one
 +/// pool definition.
 +TEST_F(Dhcp4ParserTest, emptySubnet) {
 +
 +    ConstElementPtr status;
 +
 +    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_,
 +                    Element::fromJSON("{ \"interface\": [ \"all\" ],"
 +                                      "\"rebind-timer\": 2000, "
 +                                      "\"renew-timer\": 1000, "
 +                                      "\"subnet4\": [  ], "
 +                                      "\"valid-lifetime\": 4000 }")));
 +
 +    // returned value should be 0 (success)
 +    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
 +/// parameter timer definitions.
 +TEST_F(Dhcp4ParserTest, subnetGlobalDefaults) {
 +
 +    ConstElementPtr status;
 +
 +    string config = "{ \"interface\": [ \"all\" ],"
 +        "\"rebind-timer\": 2000, "
 +        "\"renew-timer\": 1000, "
 +        "\"subnet4\": [ { "
 +        "    \"pool\": [ \"192.0.2.1 - 192.0.2.100\" ],"
 +        "    \"subnet\": \"192.0.2.0/24\" } ],"
 +        "\"valid-lifetime\": 4000 }";
 +    cout << config << endl;
 +
 +    ElementPtr json = Element::fromJSON(config);
 +
 +    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
 +
 +    // check if returned status is OK
 +    checkResult(status, 0);
 +
 +    // Now check if the configuration was indeed handled and we have
 +    // expected pool configured.
 +    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"));
 +    ASSERT_TRUE(subnet);
 +    EXPECT_EQ(1000, subnet->getT1());
 +    EXPECT_EQ(2000, subnet->getT2());
 +    EXPECT_EQ(4000, subnet->getValid());
 +}
 +
 +// This test checks if it is possible to override global values
 +// on a per subnet basis.
 +TEST_F(Dhcp4ParserTest, subnetLocal) {
 +
 +    ConstElementPtr status;
 +
 +    string config = "{ \"interface\": [ \"all\" ],"
 +        "\"rebind-timer\": 2000, "
 +        "\"renew-timer\": 1000, "
 +        "\"subnet4\": [ { "
 +        "    \"pool\": [ \"192.0.2.1 - 192.0.2.100\" ],"
 +        "    \"renew-timer\": 1, "
 +        "    \"rebind-timer\": 2, "
 +        "    \"valid-lifetime\": 4,"
 +        "    \"subnet\": \"192.0.2.0/24\" } ],"
 +        "\"valid-lifetime\": 4000 }";
 +    cout << config << endl;
 +
 +    ElementPtr json = Element::fromJSON(config);
 +
 +    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
 +
 +    // returned value should be 0 (configuration success)
 +    checkResult(status, 0);
 +
 +    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"));
 +    ASSERT_TRUE(subnet);
 +    EXPECT_EQ(1, subnet->getT1());
 +    EXPECT_EQ(2, subnet->getT2());
 +    EXPECT_EQ(4, subnet->getValid());
 +}
 +
 +// Test verifies that a subnet with pool values that do not belong to that
 +// pool are rejected.
 +TEST_F(Dhcp4ParserTest, poolOutOfSubnet) {
 +
 +    ConstElementPtr status;
 +
 +    string config = "{ \"interface\": [ \"all\" ],"
 +        "\"rebind-timer\": 2000, "
 +        "\"renew-timer\": 1000, "
 +        "\"subnet4\": [ { "
 +        "    \"pool\": [ \"192.0.4.0/28\" ],"
 +        "    \"subnet\": \"192.0.2.0/24\" } ],"
 +        "\"valid-lifetime\": 4000 }";
 +    cout << config << endl;
 +
 +    ElementPtr json = Element::fromJSON(config);
 +
 +    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
 +
 +    // returned value must be 2 (values error)
 +    // as the pool does not belong to that subnet
 +    checkResult(status, 2);
 +}
 +
 +// Goal of this test is to verify if pools can be defined
 +// using prefix/length notation. There is no separate test for min-max
 +// notation as it was tested in several previous tests.
 +TEST_F(Dhcp4ParserTest, poolPrefixLen) {
 +
 +    ConstElementPtr status;
 +
 +    string config = "{ \"interface\": [ \"all\" ],"
 +        "\"rebind-timer\": 2000, "
 +        "\"renew-timer\": 1000, "
 +        "\"subnet4\": [ { "
 +        "    \"pool\": [ \"192.0.2.128/28\" ],"
 +        "    \"subnet\": \"192.0.2.0/24\" } ],"
 +        "\"valid-lifetime\": 4000 }";
 +    cout << config << endl;
 +
 +    ElementPtr json = Element::fromJSON(config);
 +
 +    EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json));
 +
 +    // returned value must be 0 (configuration accepted)
 +    checkResult(status, 0);
 +
 +    Subnet4Ptr subnet = CfgMgr::instance().getSubnet4(IOAddress("192.0.2.200"));
 +    ASSERT_TRUE(subnet);
 +    EXPECT_EQ(1000, subnet->getT1());
 +    EXPECT_EQ(2000, subnet->getT2());
 +    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);
 +}
 +
 +};
index 486cfd4655d23d8eba2f10e9598eae3bc19fdbcf,1c55649f3954055415f1e1fcc1bae8c0e79cb700..3db6aeceeaea6bc513c304c7207735c178d65b32
@@@ -134,7 -147,10 +147,10 @@@ private
  /// in its base class, \ref DhcpConfigParser.
  ///
  /// For overview of usability of this generic purpose parser, see
 -/// \ref dhcpv6-config-inherit page.
 +/// \ref dhcp6-config-inherit page.
+ ///
+ /// @todo this class should be turned into the template class which
+ /// will handle all uintX_types of data (see ticket #2415).
  class Uint32Parser : public DhcpConfigParser {
  public:
  
@@@ -227,6 -269,8 +269,9 @@@ public
      virtual void build(ConstElementPtr value) {
          value_ = value->str();
          boost::erase_all(value_, "\"");
++
+         // If a given parameter already exists in the storage we override
+         // its value. If it doesn't we insert a new element.
          (*storage_)[param_name_] = value_;
      }
  
@@@ -440,10 -480,10 +484,10 @@@ public
          return (new PoolParser(param_name));
      }
  
 -protected:
 +private:
      /// @brief pointer to the actual Pools storage
      ///
-     /// That is typically a storage somewhere in Subnet parser
+     /// This is typically a storage somewhere in Subnet parser
      /// (an upper level parser).
      PoolStorage* pools_;
  };
index f8fe76c82f396261151259d774bc29a784808232,9f7c3ae7bce264221a7cd34fe2d09fb2afa9fd44..ed44bb9e3b6cbe57cbc1f6138c5fbb28d82e0209
  #ifndef DHCP6_CONFIG_PARSER_H
  #define DHCP6_CONFIG_PARSER_H
  
- /// DHCPv4 and DHCPv6. They should be merged. A ticket #2355.
 +/// @todo: This header file and its .cc counterpart are very similar between
 -
++/// DHCPv4 and DHCPv6. They should be merged. See ticket #2355.
++
+ #include <cc/data.h>
+ #include <exceptions/exceptions.h>
+ #include <string>
  
  namespace isc {
  namespace dhcp {
index e34f9a507271d6c9d44766fe7fc4361360564002,c234f40ed319aec073093b6c08236f368565cbb5..7e9204a9e5c3633447c3efa48b332ee9d1622404
@@@ -49,9 -49,9 +49,9 @@@
   elements and creates parsers for a given scope. This process may be repeated
   (sort of) recursively.
  
 - @section dhcpv6-config-inherit DHCPv6 Configuration Inheritance
 + @section dhcp6-config-inherit DHCPv6 Configuration Inheritance
  
-  One notable useful features of DHCP configuration is its parameter inheritance.
+  One notable useful feature of DHCP configuration is its parameter inheritance.
   For example, renew-timer value may be specified at a global scope and it then
   applies to all subnets. However, some subnets may have it overwritten with more
   specific values that takes precedence over global values that are considered
Simple merge
Simple merge