]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[2546] Merge branch 'master' into trac2546
authorStephen Morris <stephen@isc.org>
Thu, 13 Dec 2012 11:38:21 +0000 (11:38 +0000)
committerStephen Morris <stephen@isc.org>
Thu, 13 Dec 2012 11:38:21 +0000 (11:38 +0000)
Conflicts:
doc/devel/mainpage.dox
src/bin/dhcp4/ctrl_dhcp4_srv.h
src/bin/dhcp4/dhcp4_srv.h
src/bin/dhcp6/dhcp6.dox

Also modified the following files during the
resolution of the merge issues:
    src/bin/dhcp4/config_parser.cc
    src/bin/dhcp4/ctrl_dhcp4_srv.cc
    src/bin/dhcp4/dhcp4.dox
    src/bin/dhcp6/config_parser.cc
    src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
    src/lib/dhcp/option_custom.h
    src/lib/dhcp/pkt4.h
    src/lib/dhcpsrv/database_backends.dox

14 files changed:
1  2 
doc/devel/mainpage.dox
src/bin/dhcp4/config_parser.cc
src/bin/dhcp4/ctrl_dhcp4_srv.cc
src/bin/dhcp4/ctrl_dhcp4_srv.h
src/bin/dhcp4/dhcp4.dox
src/bin/dhcp6/config_parser.cc
src/bin/dhcp6/dhcp6.dox
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
src/lib/dhcp/option.h
src/lib/dhcp/option_custom.h
src/lib/dhcp/pkt4.h
src/lib/dhcp/pkt6.h
src/lib/dhcpsrv/cfgmgr.h
src/lib/dhcpsrv/database_backends.dox

index c2c69ca738acd8423b081d323a0a2181a6bd1f40,407723e3d9ef7aac17cd2c2b277059c5d8460746..295fd03986afd57fcda5f41d29ed9ae9da0a50ed
   * - @subpage DataScrubbing
   *
   * @section DHCP
-  * - @subpage dhcpv4
+  * - @subpage dhcp4
 - *   - @subpage dhcp4-session
 - *   - @subpage dhcp4-config-parser
 - *   - @subpage dhcp4-config-inherit
 + *   - @subpage dhcpv4Session
-  * - @subpage dhcpv6
++ *   - @subpage dhcpv4ConfigParser
++ *   - @subpage dhcpv4ConfigInherit
+  * - @subpage dhcp6
 - *   - @subpage dhcp6-session
 - *   - @subpage dhcp6-config-parser
 - *   - @subpage dhcp6-config-inherit
 + *   - @subpage dhcpv6Session
 + *   - @subpage dhcpv6ConfigParser
 + *   - @subpage dhcpv6ConfigInherit
   * - @subpage libdhcp
   *   - @subpage libdhcpIntro
   *   - @subpage libdhcpIfaceMgr
@@@ -33,7 -35,7 +35,7 @@@
   *   - @subpage leasemgr
   *   - @subpage cfgmgr
   *   - @subpage allocengine
-- * - @subpage dhcp-database-backends
++ * - @subpage dhcpDatabaseBackends
   * - @subpage perfdhcpInternals
   *
   * @section misc Miscellaneous topics
index 0000000000000000000000000000000000000000,aa2fa4f3d81fc3ffe925e7092869273e045b4f86..08d16f8bcb5709c4d43ce6fd329d8c81196781ef
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,772 +1,772 @@@
 -/// \ref dhcp4-config-inherit page.
+ // 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
 -    /// See \ref dhcp4-config-inherit for details.
++/// \ref dhcpv4ConfigInherit 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
+     ///
 -/// \ref dhcp4-config-inherit page.
++    /// See \ref dhcpv4ConfigInherit 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
 -    /// See \ref dhcp4-config-inherit for details.
++/// \ref dhcpv4ConfigInherit 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.
++    /// See \ref dhcpv4ConfigInherit 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 dhcpv4ConfigInherit 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 b02bf72d1e107ccb0f7df25e31aba7ccd40209b4,20eedebc05fd9634e0334265bc9ae9a808731986..eb5d4821537dec33948d751faa9c844ac2733d78
@@@ -104,9 -113,21 +113,21 @@@ void ControlledDhcpv4Srv::establishSess
                                            dhcp4CommandHandler, false);
      config_session_->start();
  
+     // We initially create ModuleCCSession() without configHandler, as
+     // the session module is too eager to send partial configuration.
+     // We want to get the full configuration, so we explicitly call
+     // getFullConfig() and then pass it to our configHandler.
+     config_session_->setConfigHandler(dhcp4ConfigHandler);
+     try {
+         configureDhcp4Server(*this, config_session_->getFullConfig());
+     } catch (const Dhcp4ConfigError& ex) {
+         LOG_ERROR(dhcp4_logger, DHCP4_CONFIG_LOAD_FAIL).arg(ex.what());
+     }
      /// Integrate the asynchronous I/O model of BIND 10 configuration
      /// control with the "select" model of the DHCP server.  This is
 -    /// fully explained in \ref dhcp4-session.
 +    /// fully explained in \ref dhcpv4Session.
      int ctrl_socket = cc_session_->getSocketDesc();
      LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_CCSESSION_STARTED)
                .arg(ctrl_socket);
index 5f450772dd72caf351bc616318d9aea479ee9d09,c1a26cc557a99f31a3a1caccd37d47d637814a5c..9bd261ca8e95d9eb3e74d437fc369f5c10349664
@@@ -66,8 -66,8 +66,10 @@@ public
  
      /// @brief Session callback, processes received commands.
      ///
 +    /// @param command Text represenation of the command (e.g. "shutdown")
 +    /// @param args Optional parameters
+     /// @param command text represenation of the command (e.g. "shutdown")
+     /// @param args optional parameters
      ///
      /// @return status of the command
      static isc::data::ConstElementPtr
index 0000000000000000000000000000000000000000,54f2bd36e8b1cdc782ac93ece04a8a463170ec6d..05f167045ffbc8cd6c88ddcbe8910f6cef0fe513
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,68 +1,68 @@@
 -@section dhcp4-session BIND10 message queue integration
+ /**
+  @page dhcp4 DHCPv4 Server Component
+ BIND10 offers DHCPv4 server implementation. It is implemented as
+ b10-dhcp4 component.  Its primary code is located in
+ isc::dhcp::Dhcpv4Srv class. It uses \ref libdhcp extensively,
+ especially isc::dhcp::Pkt4, isc::dhcp::Option and
+ isc::dhcp::IfaceMgr classes. Currently this code offers skeleton
+ functionality, i.e. it is able to receive and process incoming
+ requests and trasmit responses. However, it does not have database
+ management, so it returns only one, hardcoded lease to whoever asks
+ for it.
+ DHCPv4 server component does not support direct traffic (relayed
+ only), as support for transmission to hosts without IPv4 address
+ assigned is not implemented in IfaceMgr yet.
 -@section dhcp4-config-parser Configuration Parser in DHCPv4
++@section dhcpv4Session BIND10 message queue integration
+ DHCPv4 server component is now integrated with BIND10 message queue.
+ The integration is performed by establishSession() and disconnectSession()
+ functions in isc::dhcp::ControlledDhcpv4Srv class. main() method deifined
+ in the src/bin/dhcp4/main.cc file instantiates isc::dhcp::ControlledDhcpv4Srv
+ class that establishes connection with msgq and install necessary handlers
+ for receiving commands and configuration updates. It is derived from
+ a base isc::dhcp::Dhcpv4Srv class that implements DHCPv4 server functionality,
+ without any controlling mechanisms.
+ ControlledDhcpv4Srv instantiates several components to make management
+ session possible. In particular, isc::cc::Session cc_session
+ object uses ASIO for establishing connection. It registers its socket
+ in isc::asiolink::IOService io_service object. Typically, other components
+ (e.g. auth or resolver) that use ASIO for their communication, register their
+ other sockets in the
+ same io_service and then just call io_service.run() method that does
+ not return, until one of the callback decides that it is time to shut down
+ the whole component cal calls io_service.stop(). DHCPv4 works in a
+ different way. It does receive messages using select()
+ (see isc::dhcp::IfaceMgr::receive4()), which is incompatible with ASIO.
+ To solve this problem, socket descriptor is extracted from cc_session
+ object and is passed to IfaceMgr by using isc::dhcp::IfaceMgr::set_session_socket().
+ IfaceMgr then uses this socket in its select() call. If there is some
+ data to be read, it calls registered callback that is supposed to
+ read and process incoming data.
+ This somewhat complicated approach is needed for a simple reason. In
+ embedded deployments there will be no message queue. Not referring directly
+ to anything related to message queue in isc::dhcp::Dhcpv4Srv and
+ isc::dhcp::IfaceMgr classes brings in two benefits. First, the can
+ be used with and without message queue. Second benefit is related to the
+ first one: \ref libdhcp is supposed to be simple and robust and not require
+ many dependencies. One notable example of a use case that benefits from
+ this approach is a perfdhcp tool. Finally, the idea is that it should be
+ possible to instantiate Dhcpv4Srv object directly, thus getting a server
+ that does not support msgq. That is useful for embedded environments.
+ It may also be useful in validation.
 -See \ref dhcp6-config-parser.
++@section dhcpv4ConfigParser Configuration Parser in DHCPv4
+ This parser follows exactly the same logic as its DHCPv6 counterpart.
 -@section dhcp4-config-inherit DHCPv4 configuration inheritance
++See \ref dhcpv6ConfigParser.
 -counterpart. See \ref dhcp6-config-inherit.
++@section dhcpv4ConfigInherit DHCPv4 configuration inheritance
+ Configuration inheritance in DHCPv4 follows exactly the same logic as its DHCPv6
++counterpart. See \ref dhcpv6ConfigInherit.
+ */
index 2038d12f9aad9e9fbdbad003503294dd64df6571,3db6aeceeaea6bc513c304c7207735c178d65b32..4c6fab15f2f1584dbe31bf568fd682b6c09ac0be
@@@ -147,7 -147,7 +147,7 @@@ 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.
++/// \ref dhcpv6ConfigInherit page.
  ///
  /// @todo this class should be turned into the template class which
  /// will handle all uintX_types of data (see ticket #2415).
@@@ -222,7 -222,7 +222,7 @@@ public
  
      /// @brief sets storage for value of this parameter
      ///
-     /// See \ref dhcpv6-config-inherit for details.
 -    /// See \ref dhcp6-config-inherit for details.
++    /// See \ref dhcpv6ConfigInherit for details.
      ///
      /// @param storage pointer to the storage container
      void setStorage(Uint32Storage* storage) {
@@@ -250,7 -250,7 +250,7 @@@ 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.
++/// \ref dhcpv6ConfigInherit page.
  class StringParser : public DhcpConfigParser {
  public:
  
  
      /// @brief sets storage for value of this parameter
      ///
-     /// See \ref dhcpv6-config-inherit for details.
 -    /// See \ref dhcp6-config-inherit for details.
++    /// See \ref dhcpv6ConfigInherit for details.
      ///
      /// @param storage pointer to the storage container
      void setStorage(StringStorage* storage) {
@@@ -442,7 -446,7 +446,7 @@@ public
              pos = txt.find("-");
              if (pos != string::npos) {
                  // using min-max notation
-                 IOAddress min(txt.substr(0,pos - 1));
 -                IOAddress min(txt.substr(0,pos));
++                IOAddress min(txt.substr(0, pos));
                  IOAddress max(txt.substr(pos + 1));
  
                  Pool6Ptr pool(new Pool6(Pool6::TYPE_IA, min, max));
  
      /// @brief sets storage for value of this parameter
      ///
-     /// See \ref dhcpv6-config-inherit for details.
 -    /// See \ref dhcp6-config-inherit for details.
++    /// See \ref dhcpv6ConfigInherit for details.
      ///
      /// @param storage pointer to the storage container
      void setStorage(PoolStorage* storage) {
Simple merge
index 9679700df415ece4112af80470328ec1725948a8,03bf3093a1b2bc83829195aa05f07328bfdd4517..de0dc28d2ac6bc9a3661482b0e1cab4abe59ffa1
@@@ -749,50 -786,207 +786,207 @@@ TEST_F(Dhcpv6SrvTest, ManyRequests) 
      cout << "Assigned address to client3=" << addr3->getAddress().toText() << endl;
  }
  
+ // This test verifies that incoming (positive) RENEW can be handled properly, that a
+ // REPLY is generated, that the response has an address and that address
+ // really belongs to the configured pool and that lease is actually renewed.
+ //
+ // expected:
+ // - returned REPLY message has copy of client-id
+ // - returned REPLY message has server-id
+ // - returned REPLY message has IA that includes IAADDR
+ // - lease is actually renewed in LeaseMgr
+ TEST_F(Dhcpv6SrvTest, RenewBasic) {
+     boost::scoped_ptr<NakedDhcpv6Srv> srv;
+     ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
  
- TEST_F(Dhcpv6SrvTest, serverReceivedPacketName) {
-     // Check all possible packet types
-     for (int itype = 0; itype < 256; ++itype) {
-         uint8_t type = itype;
+     const IOAddress addr("2001:db8:1:1::cafe:babe");
+     const uint32_t iaid = 234;
  
-         switch (type) {
-         case DHCPV6_CONFIRM:
-             EXPECT_STREQ("CONFIRM", Dhcpv6Srv::serverReceivedPacketName(type));
-             break;
+     // Generate client-id also duid_
+     OptionPtr clientid = generateClientId();
  
-         case DHCPV6_DECLINE:
-             EXPECT_STREQ("DECLINE", Dhcpv6Srv::serverReceivedPacketName(type));
-             break;
+     // Check that the address we are about to use is indeed in pool
+     ASSERT_TRUE(subnet_->inPool(addr));
+     // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
+     // value on purpose. They should be updated during RENEW.
+     Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid_, iaid,
+                                501, 502, 503, 504, subnet_->getID(), 0));
+     lease->cltt_ = 1234;
+     ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+     // Check that the lease is really in the database
+     Lease6Ptr l = LeaseMgrFactory::instance().getLease6(addr);
+     ASSERT_TRUE(l);
+     // Check that T1, T2, preferred, valid and cltt really set and not using
+     // previous (500, 501, etc.) values
+     EXPECT_NE(l->t1_, subnet_->getT1());
+     EXPECT_NE(l->t2_, subnet_->getT2());
+     EXPECT_NE(l->preferred_lft_, subnet_->getPreferred());
+     EXPECT_NE(l->valid_lft_, subnet_->getValid());
+     EXPECT_NE(l->cltt_, time(NULL));
+     // Let's create a RENEW
+     Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, 1234));
+     req->setRemoteAddr(IOAddress("fe80::abcd"));
+     boost::shared_ptr<Option6IA> ia = generateIA(iaid, 1500, 3000);
  
-         case DHCPV6_INFORMATION_REQUEST:
-             EXPECT_STREQ("INFORMATION_REQUEST",
-                          Dhcpv6Srv::serverReceivedPacketName(type));
-             break;
+     OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
+     ia->addOption(renewed_addr_opt);
+     req->addOption(ia);
+     req->addOption(clientid);
  
-         case DHCPV6_REBIND:
-             EXPECT_STREQ("REBIND", Dhcpv6Srv::serverReceivedPacketName(type));
-             break;
+     // Server-id is mandatory in RENEW
+     req->addOption(srv->getServerID());
  
-         case DHCPV6_RELEASE:
-             EXPECT_STREQ("RELEASE", Dhcpv6Srv::serverReceivedPacketName(type));
-             break;
+     // Pass it to the server and hope for a REPLY
+     Pkt6Ptr reply = srv->processRenew(req);
  
-         case DHCPV6_RENEW:
-             EXPECT_STREQ("RENEW", Dhcpv6Srv::serverReceivedPacketName(type));
-             break;
+     // Check if we get response at all
+     checkResponse(reply, DHCPV6_REPLY, 1234);
  
-         case DHCPV6_REQUEST:
-             EXPECT_STREQ("REQUEST", Dhcpv6Srv::serverReceivedPacketName(type));
-             break;
+     OptionPtr tmp = reply->getOption(D6O_IA_NA);
+     ASSERT_TRUE(tmp);
  
-         case DHCPV6_SOLICIT:
-             EXPECT_STREQ("SOLICIT", Dhcpv6Srv::serverReceivedPacketName(type));
-             break;
+     // Check that IA_NA was returned and that there's an address included
+     boost::shared_ptr<Option6IAAddr> addr_opt = checkIA_NA(reply, 234, subnet_->getT1(),
+                                                            subnet_->getT2());
  
-         default:
-             EXPECT_STREQ("UNKNOWN", Dhcpv6Srv::serverReceivedPacketName(type));
-         }
-     }
+     // Check that we've got the address we requested
+     checkIAAddr(addr_opt, addr, subnet_->getPreferred(), subnet_->getValid());
+     // Check DUIDs
+     checkServerId(reply, srv->getServerID());
+     checkClientId(reply, clientid);
+     // Check that the lease is really in the database
+     l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr_opt);
+     ASSERT_TRUE(l);
+     // Check that T1, T2, preferred, valid and cltt were really updated
+     EXPECT_EQ(l->t1_, subnet_->getT1());
+     EXPECT_EQ(l->t2_, subnet_->getT2());
+     EXPECT_EQ(l->preferred_lft_, subnet_->getPreferred());
+     EXPECT_EQ(l->valid_lft_, subnet_->getValid());
+     // Checking for CLTT is a bit tricky if we want to avoid off by 1 errors
+     int32_t cltt = static_cast<int32_t>(l->cltt_);
+     int32_t expected = static_cast<int32_t>(time(NULL));
+     // equality or difference by 1 between cltt and expected is ok.
+     EXPECT_GE(1, abs(cltt - expected));
 -    EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease6(addr_opt->getAddress()));
++    EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr_opt->getAddress()));
+ }
+ // This test verifies that incoming (invalid) RENEW can be handled properly.
+ //
+ // This test checks 3 scenarios:
+ // 1. there is no such lease at all
+ // 2. there is such a lease, but it is assigned to a different IAID
+ // 3. there is such a lease, but it belongs to a different client
+ //
+ // expected:
+ // - returned REPLY message has copy of client-id
+ // - returned REPLY message has server-id
+ // - returned REPLY message has IA that includes STATUS-CODE
+ // - No lease in LeaseMgr
+ TEST_F(Dhcpv6SrvTest, RenewReject) {
+     boost::scoped_ptr<NakedDhcpv6Srv> srv;
+     ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
+     const IOAddress addr("2001:db8:1:1::dead");
+     const uint32_t transid = 1234;
+     const uint32_t valid_iaid = 234;
+     const uint32_t bogus_iaid = 456;
+     // Quick sanity check that the address we're about to use is ok
+     ASSERT_TRUE(subnet_->inPool(addr));
+     // GenerateClientId() also sets duid_
+     OptionPtr clientid = generateClientId();
+     // Check that the lease is NOT in the database
+     Lease6Ptr l = LeaseMgrFactory::instance().getLease6(addr);
+     ASSERT_FALSE(l);
+     // Let's create a RENEW
+     Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_RENEW, transid));
+     req->setRemoteAddr(IOAddress("fe80::abcd"));
+     boost::shared_ptr<Option6IA> ia = generateIA(bogus_iaid, 1500, 3000);
+     OptionPtr renewed_addr_opt(new Option6IAAddr(D6O_IAADDR, addr, 300, 500));
+     ia->addOption(renewed_addr_opt);
+     req->addOption(ia);
+     req->addOption(clientid);
+     // Server-id is mandatory in RENEW
+     req->addOption(srv->getServerID());
+     // Case 1: No lease known to server
+     // Pass it to the server and hope for a REPLY
+     Pkt6Ptr reply = srv->processRenew(req);
+     // Check if we get response at all
+     checkResponse(reply, DHCPV6_REPLY, transid);
+     OptionPtr tmp = reply->getOption(D6O_IA_NA);
+     ASSERT_TRUE(tmp);
+     // Check that IA_NA was returned and that there's an address included
+     ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
+     ASSERT_TRUE(ia);
+     checkRejectedIA_NA(ia, STATUS_NoAddrsAvail);
+     // Check that there is no lease added
+     l = LeaseMgrFactory::instance().getLease6(addr);
+     ASSERT_FALSE(l);
+     // CASE 2: Lease is known and belongs to this client, but to a different IAID
+     // Note that preferred, valid, T1 and T2 timers and CLTT are set to invalid
+     // value on purpose. They should be updated during RENEW.
+     Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid_, valid_iaid,
+                                501, 502, 503, 504, subnet_->getID(), 0));
+     lease->cltt_ = 123; // Let's use it as an indicator that the lease
+                         // was NOT updated.
+     ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease));
+     // Pass it to the server and hope for a REPLY
+     reply = srv->processRenew(req);
+     checkResponse(reply, DHCPV6_REPLY, transid);
+     tmp = reply->getOption(D6O_IA_NA);
+     ASSERT_TRUE(tmp);
+     // Check that IA_NA was returned and that there's an address included
+     ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
+     ASSERT_TRUE(ia);
+     checkRejectedIA_NA(ia, STATUS_NoAddrsAvail);
+     // There is a iaid mis-match, so server should respond that there is
+     // no such address to renew.
+     // CASE 3: Lease belongs to a client with different client-id
+     req->delOption(D6O_CLIENTID);
+     ia = boost::dynamic_pointer_cast<Option6IA>(req->getOption(D6O_IA_NA));
+     ia->setIAID(valid_iaid); // Now iaid in renew matches that in leasemgr
+     req->addOption(generateClientId(13)); // generate different DUID
+                                           // (with length 13)
+     reply = srv->processRenew(req);
+     checkResponse(reply, DHCPV6_REPLY, transid);
+     tmp = reply->getOption(D6O_IA_NA);
+     ASSERT_TRUE(tmp);
+     // Check that IA_NA was returned and that there's an address included
+     ia = boost::dynamic_pointer_cast<Option6IA>(tmp);
+     ASSERT_TRUE(ia);
+     checkRejectedIA_NA(ia, STATUS_NoAddrsAvail);
+     lease = LeaseMgrFactory::instance().getLease6(addr);
+     ASSERT_TRUE(lease);
+     // Verify that the lease was not updated.
+     EXPECT_EQ(123, lease->cltt_);
 -    EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease6(addr));
++    EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr));
  }
  
  // This test verifies if the status code option is generated properly.
Simple merge
index ad248c5f386adaeb5edddc6b3caa189f1934b89c,d9a4c18417c3220a3a987fbeec81735688420375..0ee4688995ec5500920c3623aff80e9c4d2c679c
@@@ -103,7 -161,34 +161,33 @@@ public
      ///
      /// @throw isc::OutOfRange if index is out of range.
      /// @return read boolean value.
-     bool readBoolean(const uint32_t index) const;
+     bool readBoolean(const uint32_t index = 0) const;
+     /// @brief Write a boolean value into a buffer.
+     ///
+     /// @param value boolean value to be written.
+     /// @param index buffer index.
+     ///
+     /// @throw isc::OutOfRange if index is out of range.
+     void writeBoolean(const bool value, const uint32_t index = 0);
+     /// @brief Read a buffer as FQDN.
+     ///
+     /// @param index buffer index.
 -    /// @param [out] len number of bytes read from a buffer.
+     ///
+     /// @throw isc::OutOfRange if buffer index is out of range.
+     /// @throw isc::dhcp::BadDataTypeCast if a buffer being read
+     /// does not hold a valid FQDN.
+     /// @return string representation if FQDN.
+     std::string readFqdn(const uint32_t index = 0) const;
+     /// @brief Write an FQDN into a buffer.
+     ///
+     /// @param fqdn text representation of FQDN.
+     /// @param index buffer index.
+     ///
+     /// @throw isc::OutOfRange if index is out of range.
+     void writeFqdn(const std::string& fqdn, const uint32_t index = 0);
  
      /// @brief Read a buffer as integer value.
      ///
      ///
      /// @return string value read from buffer.
      /// @throw isc::OutOfRange if index is out of range.
-     std::string readString(const uint32_t index) const;
+     std::string readString(const uint32_t index = 0) const;
+     /// @brief Write a string value into a buffer.
+     ///
+     /// @param text the string value to be written.
 -    /// @param buffer index.
++    /// @param index buffer index.
+     void writeString(const std::string& text,
+                      const uint32_t index = 0);
  
      /// @brief Parses received buffer.
      ///
index efeaf62c9631dad1a37624d9d33a6d66b06f9be3,e09069cc36d7810d7277cf68759b9afdb1b60b0c..5139458a60edb982f3e7243530415c001a7b22de
@@@ -269,9 -269,9 +269,9 @@@ public
      ///
      /// @param hType hardware type (will be sent in htype field)
      /// @param hlen hardware length (will be sent in hlen field)
--    /// @param macAddr pointer to hardware address
++    /// @param mac_addr pointer to hardware address
      void setHWAddr(uint8_t hType, uint8_t hlen,
 -                   const std::vector<uint8_t>& macAddr);
 +                   const std::vector<uint8_t>& mac_addr);
  
      /// Returns htype field
      ///
Simple merge
Simple merge
index f954bed1b17f469c02c700f37addc3dec6c0553d,f954bed1b17f469c02c700f37addc3dec6c0553d..a3b3b0c2108cdb1af27970c252808cf383b20a28
@@@ -1,5 -1,5 +1,5 @@@
  /**
--  @page dhcp-database-backends DHCP Database Back-Ends
++  @page dhcpDatabaseBackends DHCP Database Back-Ends
  
    All DHCP lease data is stored in some form of database, the interface
    to this being through the Lease Manager.