]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[2414] Merge branch 'master' into trac2414
authorStephen Morris <stephen@isc.org>
Wed, 7 Nov 2012 17:46:02 +0000 (17:46 +0000)
committerStephen Morris <stephen@isc.org>
Wed, 7 Nov 2012 17:46:02 +0000 (17:46 +0000)
Conflicts:
src/bin/dhcp6/dhcp6_messages.mes
src/bin/dhcp6/dhcp6_srv.cc
src/bin/dhcp6/dhcp6_srv.h
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
src/lib/dhcp/addr_utilities.cc
src/lib/dhcp/tests/cfgmgr_unittest.cc

Files automerged successfully:
    src/lib/dhcp/alloc_engine.cc
    src/lib/dhcp/subnet.h
    src/lib/dhcp/tests/alloc_engine_unittest.cc

1  2 
src/bin/dhcp6/dhcp6_messages.mes
src/bin/dhcp6/dhcp6_srv.cc
src/bin/dhcp6/dhcp6_srv.h
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
src/lib/dhcp/addr_utilities.cc
src/lib/dhcp/alloc_engine.cc
src/lib/dhcp/subnet.h
src/lib/dhcp/tests/alloc_engine_unittest.cc
src/lib/dhcp/tests/cfgmgr_unittest.cc

index d5d3b721cb9b0b771823f8b93424d0ece31d5081,aee34b5e23ff3200dfa8ae5de959dba809784239..5f9cd02b68cdf7070181be56e15b5e24ab8d1a90
@@@ -141,18 -110,16 +141,28 @@@ This is a debug message issued during t
  It lists some information about the parameters with which the server
  is running.
  
 +% DHCP6_SUBNET_SELECTED the %1 subnet was selected for client assignment
 +This is a debug message informing that a given subnet was selected. It will
 +be used for address and option assignment. This is one of the early steps
 +in the processing of incoming client message.
 +
 +% DHCP6_SUBNET_SELECTION_FAILED failed to select a subnet for incoming packet, src=%1 type=%2
 +This warning message is output when a packet was received from a subnet for
 +which the DHCPv6 server has not been configured. The cause is most likely due
 +to a misconfiguration of the server. The packet processing will continue, but
 +the response will only contain generic configuration parameters and no
 +addresses or prefixes.
 +
+ % DHCP6_NO_SUBNET_DEF_OPT failed to find subnet for address %1 when adding default options
+ This warning message indicates that when attempting to add default options to a response,
+ the server found that it was not configured to support the subnet from which the DHCPv6
+ request was received.  The packet has been ignored.
+ % DHCP6_NO_SUBNET_REQ_OPT failed to find subnet for address %1 when adding requested options
+ This warning message indicates that when attempting to add requested options to a response,
+ the server found that it was not configured to support the subnet from which the DHCPv6
+ request was received.  The packet has been ignored.
  % DHCP6_CONFIG_LOAD_FAIL failed to load configuration: %1
  This critical error message indicates that the initial DHCPv6
  configuration has failed. The server will start, but nothing will be
index ad3e1d70ffcb741bb171b3e5a31d01db24ec1070,946bccb52eeb4097e68bec0eb1c3cab54602d417..a7490359dd3cd4e798e42971f79ad7e6026074f2
  #include <exceptions/exceptions.h>
  #include <util/io_utilities.h>
  #include <util/range_utilities.h>
 +#include <dhcp/duid.h>
 +#include <dhcp/lease_mgr.h>
 +#include <dhcp/cfgmgr.h>
 +#include <dhcp/option6_iaaddr.h>
 +
 +// @todo: Replace this with MySQL_LeaseMgr (or a LeaseMgr factory)
 +// once it is merged
 +#include <dhcp/memfile_lease_mgr.h>
  
+ #include <boost/foreach.hpp>
  using namespace isc;
  using namespace isc::asiolink;
  using namespace isc::dhcp;
@@@ -49,26 -51,35 +55,29 @@@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port) 
  
      LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_OPEN_SOCKET).arg(port);
  
-     // First call to instance() will create IfaceMgr (it's a singleton)
-     // it may throw something if things go wrong
+     // Initialize objects required for DHCP server operation.
      try {
 -
+         // Initialize standard DHCPv6 option definitions. This function
+         // may throw bad_alloc if system goes out of memory during the
+         // creation if option definitions. It may also throw isc::Unexpected
+         // if definitions are wrong. This would mean error in implementation.
+         initStdOptionDefs();
  
 -        // Call IfaceMgr::instance() will create instance of Interface
 -        // Manager (it's a singleton). It may throw if things go wrong.
 -        if (IfaceMgr::instance().countIfaces() == 0) {
 -            LOG_ERROR(dhcp6_logger, DHCP6_NO_INTERFACES);
 -            shutdown_ = true;
 -            return;
 +        // Port 0 is used for testing purposes. It means that the server should
 +        // not open any sockets at all. Some tests, e.g. configuration parser,
 +        // require Dhcpv6Srv object, but they don't really need it to do
 +        // anything. This speed up and simplifies the tests.
 +        if (port > 0) {
 +            if (IfaceMgr::instance().countIfaces() == 0) {
 +                LOG_ERROR(dhcp6_logger, DHCP6_NO_INTERFACES);
 +                shutdown_ = true;
 +                return;
 +            }
 +            IfaceMgr::instance().openSockets6(port);
          }
  
 -        IfaceMgr::instance().openSockets6(port);
 -
          setServerID();
  
 -        /// @todo: instantiate LeaseMgr here once it is imlpemented.
 -
      } catch (const std::exception &e) {
          LOG_ERROR(dhcp6_logger, DHCP6_SRV_CONSTRUCT_ERROR).arg(e.what());
          shutdown_ = true;
@@@ -300,188 -294,89 +309,233 @@@ void Dhcpv6Srv::copyDefaultOptions(cons
      // TODO: Should throw if there is no client-id (except anonymous INF-REQUEST)
  }
  
- void Dhcpv6Srv::appendDefaultOptions(const Pkt6Ptr& /*question*/, Pkt6Ptr& answer) {
-     // TODO: question is currently unused, but we need it at least to know
-     // message type we are answering
-     // Add server-id.
+ void Dhcpv6Srv::appendDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
+     // add server-id
      answer->addOption(getServerID());
- }
  
+     // Get the subnet object. It holds options to be sent to the client
+     // that belongs to the particular subnet.
+     Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(question->getRemoteAddr());
+     // Warn if subnet is not supported and quit.
+     if (!subnet) {
+         LOG_WARN(dhcp6_logger, DHCP6_NO_SUBNET_DEF_OPT)
+             .arg(question->getRemoteAddr().toText());
+         return;
+     }
+     // Add DNS_SERVERS option. It should have been configured.
+     const Subnet::OptionContainer& options = subnet->getOptions();
+     const Subnet::OptionContainerTypeIndex& idx = options.get<1>();
+     const Subnet::OptionContainerTypeRange range =
+         idx.equal_range(D6O_NAME_SERVERS);
+     // In theory we may have multiple options with the same
+     // option code. They are not differentiated right now
+     // until support for option spaces is implemented.
+     // Until that's the case, simply add the first found option.
+     if (std::distance(range.first, range.second) > 0) {
+         answer->addOption(range.first->option);
+     }
+ }
  
- void Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& /*question*/, Pkt6Ptr& answer) {
-     // TODO: question is currently unused, but we need to extract ORO from it
-     // and act on its content. Now we just send DNS-SERVERS option.
+ void Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
+     // Get the subnet for a particular address.
+     Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(question->getRemoteAddr());
+     if (!subnet) {
+         LOG_WARN(dhcp6_logger, DHCP6_NO_SUBNET_REQ_OPT)
+             .arg(question->getRemoteAddr().toText());
+         return;
+     }
  
 +    // Add dns-servers option.
 +    OptionPtr dnsservers(new Option6AddrLst(D6O_NAME_SERVERS,
 +                                            IOAddress(HARDCODED_DNS_SERVER)));
 +    answer->addOption(dnsservers);
++
+     // Client requests some options using ORO option. Try to
+     // get this option from client's message.
+     boost::shared_ptr<Option6IntArray<uint16_t> > option_oro =
+         boost::dynamic_pointer_cast<Option6IntArray<uint16_t> >(question->getOption(D6O_ORO));
+     // Option ORO not found. Don't do anything then.
+     if (!option_oro) {
+         return;
+     }
+     // Get the list of options that client requested.
+     const std::vector<uint16_t>& requested_opts = option_oro->getValues();
+     // Get the list of options configured for a subnet.
+     const Subnet::OptionContainer& options = subnet->getOptions();
+     const Subnet::OptionContainerTypeIndex& idx = options.get<1>();
+     // Try to match requested options with those configured for a subnet.
+     // If match is found, append configured option to the answer message.
+     BOOST_FOREACH(uint16_t opt, requested_opts) {
+         const Subnet::OptionContainerTypeRange& range = idx.equal_range(opt);
+         BOOST_FOREACH(Subnet::OptionDescriptor desc, range) {
+             answer->addOption(desc.option);
+         }
+     }
  }
  
 +OptionPtr Dhcpv6Srv::createStatusCode(uint16_t code, const std::string& text) {
 +
 +    // @todo: Implement Option6_StatusCode and rewrite this code here
 +    vector<uint8_t> data(text.c_str(), text.c_str() + text.length());
 +    data.insert(data.begin(), static_cast<uint8_t>(code % 256));
 +    data.insert(data.begin(), static_cast<uint8_t>(code >> 8));
 +    OptionPtr status(new Option(Option::V6, D6O_STATUS_CODE, data));
 +    return (status);
 +}
 +
 +Subnet6Ptr Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
 +    Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(question->getRemoteAddr());
 +
 +    return (subnet);
 +}
 +
  void Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
 -    /// TODO Rewrite this once LeaseManager is implemented.
 -
 -    // answer client's IA (this is mostly a dummy,
 -    // so let's answer only first IA and hope there is only one)
 -    boost::shared_ptr<Option> ia_opt = question->getOption(D6O_IA_NA);
 -    if (ia_opt) {
 -        // found IA
 -        Option* tmp = ia_opt.get();
 -        Option6IA* ia_req = dynamic_cast<Option6IA*>(tmp);
 -        if (ia_req) {
 -            boost::shared_ptr<Option6IA>
 -                ia_rsp(new Option6IA(D6O_IA_NA, ia_req->getIAID()));
 -            ia_rsp->setT1(HARDCODED_T1);
 -            ia_rsp->setT2(HARDCODED_T2);
 -            boost::shared_ptr<Option6IAAddr>
 -                addr(new Option6IAAddr(D6O_IAADDR,
 -                                       IOAddress(HARDCODED_LEASE),
 -                                       HARDCODED_PREFERRED_LIFETIME,
 -                                       HARDCODED_VALID_LIFETIME));
 -            ia_rsp->addOption(addr);
 -            answer->addOption(ia_rsp);
 +
 +    // We need to allocate addresses for all IA_NA options in the client's
 +    // question (i.e. SOLICIT or REQUEST) message.
 +
 +    // We need to select a subnet the client is connected in.
 +    Subnet6Ptr subnet = selectSubnet(question);
 +    if (subnet) {
 +        // This particular client is out of luck today. We do not have
 +        // information about the subnet he is connected to. This likely means
 +        // misconfiguration of the server (or some relays). We will continue to
 +        // process this message, but our response will be almost useless: no
 +        // addresses or prefixes, no subnet specific configuration etc. The only
 +        // thing this client can get is some global information (like DNS
 +        // servers).
 +        LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL_DATA, DHCP6_SUBNET_SELECTED)
 +            .arg(subnet->toText());
 +    } else {
 +        // perhaps this should be logged on some higher level? This is most likely
 +        // configuration bug.
 +        LOG_DEBUG(dhcp6_logger, DBG_DHCP6_BASIC, DHCP6_SUBNET_SELECTION_FAILED);
 +    }
 +
 +    // @todo: We should implement Option6Duid some day, but we can do without it
 +    // just fine for now
 +
 +    // Let's find client's DUID. Client is supposed to include its client-id
 +    // option almost all the time (the only exception is an anonymous inf-request,
 +    // but that is mostly a theoretical case). Our allocation engine needs DUID
 +    // and will refuse to allocate anything to anonymous clients.
 +    DuidPtr duid;
 +    OptionPtr opt_duid = question->getOption(D6O_CLIENTID);
 +    if (opt_duid) {
 +        duid = DuidPtr(new DUID(opt_duid->getData()));
 +    }
 +
 +    // Now that we have all information about the client, let's iterate over all
 +    // received options and handle IA_NA options one by one and store our
 +    // responses in answer message (ADVERTISE or REPLY).
 +    //
 +    // @todo: expand this to cover IA_PD and IA_TA once we implement support for
 +    // prefix delegation and temporary addresses.
 +    for (Option::OptionCollection::iterator opt = question->options_.begin();
 +         opt != question->options_.end(); ++opt) {
 +        switch (opt->second->getType()) {
 +        case D6O_IA_NA: {
 +            OptionPtr answer_opt = handleIA_NA(subnet, duid, question,
 +                                   boost::dynamic_pointer_cast<Option6IA>(opt->second));
 +            if (answer_opt) {
 +                answer->addOption(answer_opt);
 +            }
 +            break;
          }
 +        default:
 +            break;
 +        }
 +    }
 +}
 +
 +OptionPtr Dhcpv6Srv::handleIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid, Pkt6Ptr question,
 +                                 boost::shared_ptr<Option6IA> ia) {
 +    // If there is no subnet selected for handling this IA_NA, the only thing to do left is
 +    // to say that we are sorry, but the user won't get an address. As a convenience, we
 +    // use a different status text to indicate that (compare to the same status code,
 +    // but different wording below)
 +    if (!subnet) {
 +        // Create empty IA_NA option with IAID matching the request.
 +        boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
 +
 +        // Insert status code NoAddrsAvail.
 +        ia_rsp->addOption(createStatusCode(STATUS_NoAddrsAvail, "Sorry, no subnet available."));
 +        return (ia_rsp);
 +    }
 +
 +    // Check if the client sent us a hint in his IA_NA. Clients may send an
 +    // address in their IA_NA options as a suggestion (e.g. the last address
 +    // they used before).
 +    shared_ptr<Option6IAAddr> hintOpt = dynamic_pointer_cast<Option6IAAddr>
 +                                        (ia->getOption(D6O_IAADDR));
 +    IOAddress hint("::");
 +    if (hintOpt) {
 +        hint = hintOpt->getAddress();
      }
 +
 +    LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PROCESS_IA_NA_REQUEST)
 +        .arg(duid?duid->toText():"(no-duid)").arg(ia->getIAID())
 +        .arg(hintOpt?hint.toText():"(no hint)");
 +
 +    // "Fake" allocation is processing of SOLICIT message. We pretend to do an
 +    // allocation, but we do not put the lease in the database. That is ok,
 +    // because we do not guarantee that the user will get that exact lease. If
 +    // the user selects this server to do actual allocation (i.e. sends REQUEST)
 +    // it should include this hint. That will help us during the actual lease
 +    // allocation.
 +    bool fake_allocation = false;
 +    if (question->getType() == DHCPV6_SOLICIT) {
 +        /// @todo: Check if we support rapid commit
 +        fake_allocation = true;
 +    }
 +
 +    // Use allocation engine to pick a lease for this client. Allocation engine
 +    // will try to honour the hint, but it is just a hint - some other address
 +    // may be used instead. If fake_allocation is set to false, the lease will
 +    // be inserted into the LeaseMgr as well.
 +    Lease6Ptr lease = alloc_engine_->allocateAddress6(subnet, duid, ia->getIAID(),
 +                                                      hint, fake_allocation);
 +
 +    // Create IA_NA that we will put in the response.
 +    boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
 +
 +    if (lease) {
 +        // We have a lease! Let's wrap its content into IA_NA option
 +        // with IAADDR suboption.
 +        LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, fake_allocation?
 +                  DHCP6_LEASE_ADVERT:DHCP6_LEASE_ALLOC)
 +            .arg(lease->addr_.toText())
 +            .arg(duid?duid->toText():"(no-duid)")
 +            .arg(ia->getIAID());
 +
 +        ia_rsp->setT1(subnet->getT1());
 +        ia_rsp->setT2(subnet->getT2());
 +
 +        boost::shared_ptr<Option6IAAddr>
 +            addr(new Option6IAAddr(D6O_IAADDR,
 +                                   lease->addr_,
 +                                   lease->preferred_lft_,
 +                                   lease->valid_lft_));
 +        ia_rsp->addOption(addr);
 +
 +        // It would be possible to insert status code=0(success) as well,
 +        // but this is considered waste of bandwidth as absence of status
 +        // code is considered a success.
 +    } else {
 +        // Allocation engine did not allocate a lease. The engine logged
 +        // cause of that failure. The only thing left is to insert
 +        // status code to pass the sad news to the client.
 +
 +        LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, fake_allocation?
 +                  DHCP6_LEASE_ADVERT_FAIL:DHCP6_LEASE_ALLOC_FAIL)
 +            .arg(duid?duid->toText():"(no-duid)")
 +            .arg(ia->getIAID())
 +            .arg(subnet->toText());
 +
 +        ia_rsp->addOption(createStatusCode(STATUS_NoAddrsAvail,
 +                          "Sorry, no address could be allocated."));
 +    }
 +    return (ia_rsp);
  }
  
  Pkt6Ptr Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) {
index 3553bffb71f0c78322907336e1a47247012d54f6,254ee7c1faa7b92b5e0e5803f1f501ff4e4acb6c..0beccafc1841d54bfcb75a257bbcee22974cf6e9
  #ifndef DHCPV6_SRV_H
  #define DHCPV6_SRV_H
  
++#include <iostream>
++
  #include <boost/noncopyable.hpp>
++#include <dhcp/alloc_engine.h>
  #include <dhcp/dhcp6.h>
--#include <dhcp/pkt6.h>
- #include <dhcp/option.h>
- #include <dhcp/subnet.h>
 +#include <dhcp/duid.h>
+ #include <dhcp/option.h>
 +#include <dhcp/option6_ia.h>
- #include <dhcp/alloc_engine.h>
- #include <iostream>
+ #include <dhcp/option_definition.h>
 -#include <iostream>
++#include <dhcp/pkt6.h>
++#include <dhcp/subnet.h>
  
  namespace isc {
  
index 76f7eff1e5178d6fd31265a5d72a54bbf17ec7e9,ef53bb4f73dca08aef774fb9ddf0224d8b513db5..7e9a395e8dc6ef923db6ded457b7f56646985158
  // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  // PERFORMANCE OF THIS SOFTWARE.
  
 -#include <iostream>
+ #include <config.h>
 -#include <arpa/inet.h>
++
+ #include <fstream>
++#include <iostream>
+ #include <sstream>
+ #include <gtest/gtest.h>
  
 -#include <dhcp6/config_parser.h>
 -#include <dhcp6/dhcp6_srv.h>
 +#include <asiolink/io_address.h>
++#include <boost/scoped_ptr.hpp>
++#include <config/ccsession.h>
++#include <dhcp/cfgmgr.h>
  #include <dhcp/dhcp6.h>
 -#include <dhcp/option6_ia.h>
 +#include <dhcp/duid.h>
- #include <dhcp/cfgmgr.h>
++#include <dhcp/lease_mgr.h>
 +#include <dhcp/option.h>
+ #include <dhcp/option6_addrlst.h>
 +#include <dhcp/option6_ia.h>
 +#include <dhcp/option6_iaaddr.h>
+ #include <dhcp/option6_int_array.h>
 -#include <config/ccsession.h>
++#include <dhcp6/config_parser.h>
++#include <dhcp6/dhcp6_srv.h>
 +#include <dhcp6/dhcp6_srv.h>
  #include <util/buffer.h>
  #include <util/range_utilities.h>
- #include <dhcp/lease_mgr.h>
--#include <boost/scoped_ptr.hpp>
- #include <config.h>
- #include <iostream>
- #include <fstream>
- #include <sstream>
- #include <gtest/gtest.h>
  
--using namespace std;
++using namespace boost;
  using namespace isc;
++using namespace isc::asiolink;
++using namespace isc::asiolink;
++using namespace isc::config;
++using namespace isc::data;
  using namespace isc::dhcp;
  using namespace isc::util;
 -using namespace isc::data;
 -using namespace isc::config;
--using namespace isc::asiolink;
- using namespace boost;
++using namespace std;
  
  // namespace has to be named, because friends are defined in Dhcpv6Srv class
  // Maybe it should be isc::test?
@@@ -55,163 -60,36 +65,164 @@@ public
  
  class Dhcpv6SrvTest : public ::testing::Test {
  public:
 -    Dhcpv6SrvTest()
 -        : rcode_(-1) {
 +    // these are empty for now, but let's keep them around
-     Dhcpv6SrvTest() {
++    Dhcpv6SrvTest() : rcode_(-1) {
 +        subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 48, 1000,
 +                                         2000, 3000, 4000));
 +        pool_ = Pool6Ptr(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:1::"), 64));
 +        subnet_->addPool6(pool_);
 +
 +        CfgMgr::instance().addSubnet6(subnet_);
 +    }
 +
 +    // Generate IA_NA option with specified parameters
 +    shared_ptr<Option6IA> generateIA(uint32_t iaid, uint32_t t1, uint32_t t2) {
 +        shared_ptr<Option6IA> ia =
 +            shared_ptr<Option6IA>(new Option6IA(D6O_IA_NA, iaid));
 +        ia->setT1(t1);
 +        ia->setT2(t2);
 +        return (ia);
 +    }
 +
 +    // Generate client-id option
 +    OptionPtr generateClientId(size_t duid_size = 32) {
 +
 +        OptionBuffer clnt_duid(duid_size);
 +        for (int i = 0; i < duid_size; i++) {
 +            clnt_duid[i] = 100 + i;
 +        }
 +
 +        duid_ = DuidPtr(new DUID(clnt_duid));
 +
 +        return (OptionPtr(new Option(Option::V6, D6O_CLIENTID,
 +                                     clnt_duid.begin(),
 +                                     clnt_duid.begin() + duid_size)));
 +    }
 +
 +    // Checks if server response (ADVERTISE or REPLY) includes proper server-id.
 +    void checkServerId(const Pkt6Ptr& rsp, const OptionPtr& expected_srvid) {
 +        // check that server included its server-id
 +        OptionPtr tmp = rsp->getOption(D6O_SERVERID);
 +        EXPECT_EQ(tmp->getType(), expected_srvid->getType() );
 +        ASSERT_EQ(tmp->len(), expected_srvid->len() );
 +        EXPECT_TRUE(tmp->getData() == expected_srvid->getData());
 +    }
 +
 +    // Checks if server response (ADVERTISE or REPLY) includes proper client-id.
 +    void checkClientId(const Pkt6Ptr& rsp, const OptionPtr& expected_clientid) {
 +        // check that server included our own client-id
 +        OptionPtr tmp = rsp->getOption(D6O_CLIENTID);
 +        ASSERT_TRUE(tmp);
 +        EXPECT_EQ(expected_clientid->getType(), tmp->getType());
 +        ASSERT_EQ(expected_clientid->len(), tmp->len());
 +
 +        // check that returned client-id is valid
 +        EXPECT_TRUE(expected_clientid->getData() == tmp->getData());
 +    }
 +
 +    // Checks that server response (ADVERTISE or REPLY) contains proper IA_NA option
 +    // It returns IAADDR option for each chaining with checkIAAddr method.
 +    shared_ptr<Option6IAAddr> checkIA_NA(const Pkt6Ptr& rsp, uint32_t expected_iaid,
 +                                         uint32_t expected_t1, uint32_t expected_t2) {
 +        OptionPtr tmp = rsp->getOption(D6O_IA_NA);
 +        // Can't use ASSERT_TRUE() in method that returns something
 +        if (!tmp) {
 +            ADD_FAILURE() << "IA_NA option not present in response";
 +            return (shared_ptr<Option6IAAddr>());
 +        }
 +
 +        shared_ptr<Option6IA> ia = dynamic_pointer_cast<Option6IA>(tmp);
 +        EXPECT_EQ(expected_iaid, ia->getIAID() );
 +        EXPECT_EQ(expected_t1, ia->getT1());
 +        EXPECT_EQ(expected_t2, ia->getT2());
 +
 +        tmp = ia->getOption(D6O_IAADDR);
 +        shared_ptr<Option6IAAddr> addr = dynamic_pointer_cast<Option6IAAddr>(tmp);
 +        return (addr);
 +    }
 +
 +    // Check that generated IAADDR option contains expected address.
 +    void checkIAAddr(shared_ptr<Option6IAAddr> addr, const IOAddress& expected_addr,
 +                     uint32_t expected_preferred, uint32_t expected_valid) {
 +        // Check that the assigned address is indeed from the configured pool
 +        EXPECT_TRUE(subnet_->inPool(addr->getAddress()));
 +        EXPECT_EQ(expected_addr.toText(), addr->getAddress().toText());
 +        EXPECT_EQ(addr->getPreferred(), subnet_->getPreferred());
 +        EXPECT_EQ(addr->getValid(), subnet_->getValid());
      }
 +
 +    // Basic checks for generated response (message type and transaction-id).
 +    void checkResponse(const Pkt6Ptr& rsp, uint8_t expected_message_type,
 +                       uint32_t expected_transid) {
 +        ASSERT_TRUE(rsp);
 +        EXPECT_EQ(expected_message_type, rsp->getType());
 +        EXPECT_EQ(expected_transid, rsp->getTransid());
 +    }
 +
 +    // Checks if the lease sent to client is present in the database
 +    Lease6Ptr checkLease(const DuidPtr& duid, const OptionPtr& ia_na,
 +                         shared_ptr<Option6IAAddr> addr) {
 +        shared_ptr<Option6IA> ia = dynamic_pointer_cast<Option6IA>(ia_na);
 +
 +        Lease6Ptr lease = LeaseMgr::instance().getLease6(addr->getAddress());
 +        if (!lease) {
 +            cout << "Lease for " << addr->getAddress().toText()
 +                 << " not found in the database backend.";
 +            return (Lease6Ptr());
 +        }
 +
 +        EXPECT_EQ(addr->getAddress().toText(), lease->addr_.toText());
 +        EXPECT_TRUE(*lease->duid_ == *duid);
 +        EXPECT_EQ(ia->getIAID(), lease->iaid_);
 +        EXPECT_EQ(subnet_->getID(), lease->subnet_id_);
 +
 +        return (lease);
 +    }
 +
      ~Dhcpv6SrvTest() {
 +        CfgMgr::instance().deleteSubnets6();
      };
  
 +    // A subnet used in most tests
 +    Subnet6Ptr subnet_;
 +
 +    // A pool used in most tests
 +    Pool6Ptr pool_;
 +
 +    // A DUID used in most tests (typically as client-id)
 +    DuidPtr duid_;
++
+     int rcode_;
+     ConstElementPtr comment_;
  };
  
 +// Test verifies that the Dhcpv6_srv class can be instantiated. It checks a mode
 +// without open sockets and with sockets opened on a high port (to not require
 +// root privileges).
  TEST_F(Dhcpv6SrvTest, basic) {
      // srv has stubbed interface detection. It will read
      // interfaces.txt instead. It will pretend to have detected
      // fe80::1234 link-local address on eth0 interface. Obviously
      // an attempt to bind this socket will fail.
--    Dhcpv6Srv* srv = NULL;
++    boost::scoped_ptr<Dhcpv6Srv> srv;
++
 +    ASSERT_NO_THROW( {
 +        // Skip opening any sockets
-         srv = new Dhcpv6Srv(0);
++        srv.reset(new Dhcpv6Srv(0));
 +    });
-     delete srv;
-     ASSERT_NO_THROW( {
++    srv.reset();
+     ASSERT_NO_THROW({
          // open an unpriviledged port
--        srv = new Dhcpv6Srv(DHCP6_SERVER_PORT + 10000);
++        srv.reset(new Dhcpv6Srv(DHCP6_SERVER_PORT + 10000));
      });
 -
--    delete srv;
  }
  
 +// Test checks that DUID is generated properly
  TEST_F(Dhcpv6SrvTest, DUID) {
 -    // tests that DUID is generated properly
  
      boost::scoped_ptr<Dhcpv6Srv> srv;
 -    ASSERT_NO_THROW({
 -        srv.reset(new Dhcpv6Srv(DHCP6_SERVER_PORT + 10000));
 +    ASSERT_NO_THROW( {
 +        srv.reset(new Dhcpv6Srv(0));
      });
  
      OptionPtr srvid = srv->getServerID();
      }
  }
  
 -TEST_F(Dhcpv6SrvTest, solicitBasic) {
++TEST_F(Dhcpv6SrvTest, solicitBasic1) {
+     ConstElementPtr x;
+     string config = "{ \"interface\": [ \"all\" ],"
+         "\"preferred-lifetime\": 3000,"
+         "\"rebind-timer\": 2000, "
+         "\"renew-timer\": 1000, "
+         "\"subnet6\": [ { "
+         "    \"pool\": [ \"2001:db8:1234::/80\" ],"
+         "    \"subnet\": \"2001:db8:1234::/64\", "
+         "    \"option-data\": [ {"
+         "          \"name\": \"OPTION_DNS_SERVERS\","
+         "          \"code\": 23,"
+         "          \"data\": \"2001 0DB8 1234 FFFF 0000 0000 0000 0001"
+         "2001 0DB8 1234 FFFF 0000 0000 0000 0002\""
+         "        },"
+         "        {"
+         "          \"name\": \"OPTION_FOO\","
+         "          \"code\": 1000,"
+         "          \"data\": \"1234\""
+         "        } ]"
+         " } ],"
+         "\"valid-lifetime\": 4000 }";
+     ElementPtr json = Element::fromJSON(config);
+     boost::scoped_ptr<NakedDhcpv6Srv> srv;
 -    ASSERT_NO_THROW(srv.reset(new NakedDhcpv6Srv()));
++    ASSERT_NO_THROW(srv.reset(new NakedDhcpv6Srv(0)));
+     EXPECT_NO_THROW(x = configureDhcp6Server(*srv, json));
+     ASSERT_TRUE(x);
+     comment_ = parseAnswer(rcode_, x);
+     ASSERT_EQ(0, rcode_);
+     // a dummy content for client-id
+     OptionBuffer clntDuid(32);
+     for (int i = 0; i < 32; i++) {
+         clntDuid[i] = 100 + i;
+     }
+     Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
+     boost::shared_ptr<Option6IA> ia =
+         boost::shared_ptr<Option6IA>(new Option6IA(D6O_IA_NA, 234));
+     ia->setT1(1501);
+     ia->setT2(2601);
+     sol->addOption(ia);
+     // Let's not send address in solicit yet
+     /*    boost::shared_ptr<Option6IAAddr>
+         addr(new Option6IAAddr(D6O_IAADDR, IOAddress("2001:db8:1234:ffff::ffff"), 5001, 7001));
+     ia->addOption(addr);
+     sol->addOption(ia); */
+     // constructed very simple SOLICIT message with:
+     // - client-id option (mandatory)
+     // - IA option (a request for address, without any addresses)
+     // expected returned ADVERTISE message:
+     // - copy of client-id
+     // - server-id
+     // - IA that includes IAADDR
+     OptionPtr clientid = OptionPtr(new Option(Option::V6, D6O_CLIENTID,
+                                               clntDuid.begin(),
+                                               clntDuid.begin() + 16));
+     sol->addOption(clientid);
+     boost::shared_ptr<Pkt6> reply = srv->processSolicit(sol);
+     // check if we get response at all
+     ASSERT_TRUE(reply);
+     EXPECT_EQ(DHCPV6_ADVERTISE, reply->getType());
+     EXPECT_EQ(1234, reply->getTransid());
+     // We have not requested option with code 1000 so it should not
+     // be included in the response.
+     ASSERT_FALSE(reply->getOption(1000));
+     // Let's now request option with code 1000.
+     // We expect that server will include this option in its reply.
+     boost::shared_ptr<Option6IntArray<uint16_t> >
+         option_oro(new Option6IntArray<uint16_t>(D6O_ORO));
+     // Create vector with one code equal to 1000.
+     std::vector<uint16_t> codes(1, 1000);
+     // Pass this code to option.
+     option_oro->setValues(codes);
+     // Append ORO to SOLICIT message.
+     sol->addOption(option_oro);
+     
+     // Need to process SOLICIT again after requesting new option.
+     reply = srv->processSolicit(sol);
+     ASSERT_TRUE(reply);
+     EXPECT_EQ(DHCPV6_ADVERTISE, reply->getType());
+     OptionPtr tmp = reply->getOption(D6O_IA_NA);
+     ASSERT_TRUE(tmp);
+     boost::shared_ptr<Option6IA> reply_ia =
+         boost::dynamic_pointer_cast<Option6IA>(tmp);
+     ASSERT_TRUE(reply_ia);
+     EXPECT_EQ(234, reply_ia->getIAID());
+     // check that there's an address included
+     EXPECT_TRUE(reply_ia->getOption(D6O_IAADDR));
+     // check that server included our own client-id
+     tmp = reply->getOption(D6O_CLIENTID);
+     ASSERT_TRUE(tmp);
+     EXPECT_EQ(clientid->getType(), tmp->getType());
+     ASSERT_EQ(clientid->len(), tmp->len());
+     EXPECT_TRUE(clientid->getData() == tmp->getData());
+     // check that server included its server-id
+     tmp = reply->getOption(D6O_SERVERID);
+     EXPECT_EQ(tmp->getType(), srv->getServerID()->getType());
+     ASSERT_EQ(tmp->len(),  srv->getServerID()->len());
+     EXPECT_TRUE(tmp->getData() == srv->getServerID()->getData());
+  
+     tmp = reply->getOption(D6O_NAME_SERVERS);
+     ASSERT_TRUE(tmp);
+     
+     boost::shared_ptr<Option6AddrLst> reply_nameservers =
+         boost::dynamic_pointer_cast<Option6AddrLst>(tmp);
+     ASSERT_TRUE(reply_nameservers);
+     Option6AddrLst::AddressContainer addrs = reply_nameservers->getAddresses();
+     ASSERT_EQ(2, addrs.size());
+     EXPECT_TRUE(addrs[0] == IOAddress("2001:db8:1234:FFFF::1"));
+     EXPECT_TRUE(addrs[1] == IOAddress("2001:db8:1234:FFFF::2"));
+     // There is a dummy option with code 1000 we requested from a server.
+     // Expect that this option is in server's response.
+     tmp = reply->getOption(1000);
+     ASSERT_TRUE(tmp);
+     // Check that the option contains valid data (from configuration).
+     std::vector<uint8_t> data = tmp->getData();
+     ASSERT_EQ(2, data.size());
+     const uint8_t foo_expected[] = {
+         0x12, 0x34
+     };
+     EXPECT_EQ(0, memcmp(&data[0], foo_expected, 2));
+     // more checks to be implemented
+ }
++
 +// There are no dedicated tests for Dhcpv6Srv::handleIA_NA and Dhcpv6Srv::assignLeases
 +// as they are indirectly tested in Solicit and Request tests.
 +
 +// This test verifies that incoming SOLICIT can be handled properly, that an
 +// ADVERTISE is generated, that the response has an address and that address
 +// really belongs to the configured pool.
 +//
 +// This test sends a SOLICIT without any hint in IA_NA.
 +//
 +// constructed very simple SOLICIT message with:
 +// - client-id option (mandatory)
 +// - IA option (a request for address, without any addresses)
 +//
 +// expected returned ADVERTISE message:
 +// - copy of client-id
 +// - server-id
 +// - IA that includes IAADDR
- TEST_F(Dhcpv6SrvTest, SolicitBasic) {
++TEST_F(Dhcpv6SrvTest, SolicitBasic2) {
 +    boost::scoped_ptr<NakedDhcpv6Srv> srv;
 +    ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
 +
 +    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
 +
 +    sol->setRemoteAddr(IOAddress("fe80::abcd"));
 +
 +    sol->addOption(generateIA(234, 1500, 3000));
 +
 +    OptionPtr clientid = generateClientId();
 +
 +    sol->addOption(clientid);
 +
 +    // Pass it to the server and get an advertise
 +    Pkt6Ptr reply = srv->processSolicit(sol);
 +
 +    // check if we get response at all
 +    checkResponse(reply, DHCPV6_ADVERTISE, 1234);
 +
 +    // check that IA_NA was returned and that there's an address included
 +    shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234, subnet_->getT1(),
 +                                                subnet_->getT2());
 +
 +    // Check that the assigned address is indeed from the configured pool
 +    checkIAAddr(addr, addr->getAddress(), subnet_->getPreferred(), subnet_->getValid());
 +
 +    // check DUIDs
 +    checkServerId(reply, srv->getServerID());
 +    checkClientId(reply, clientid);
 +}
 +
 +// This test verifies that incoming SOLICIT can be handled properly, that an
 +// ADVERTISE is generated, that the response has an address and that address
 +// really belongs to the configured pool.
 +//
 +// This test sends a SOLICIT with IA_NA that contains a valid hint.
 +//
 +// constructed very simple SOLICIT message with:
 +// - client-id option (mandatory)
 +// - IA option (a request for address, with an address that belongs to the
 +//              configured pool, i.e. is valid as hint)
 +//
 +// expected returned ADVERTISE message:
 +// - copy of client-id
 +// - server-id
 +// - IA that includes IAADDR
 +TEST_F(Dhcpv6SrvTest, SolicitHint) {
 +    boost::scoped_ptr<NakedDhcpv6Srv> srv;
 +    ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
 +
 +    // Let's create a SOLICIT
 +    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
 +    sol->setRemoteAddr(IOAddress("fe80::abcd"));
 +    shared_ptr<Option6IA> ia = generateIA(234, 1500, 3000);
 +
 +    // with a valid hint
 +    IOAddress hint("2001:db8:1:1::dead:beef");
 +    ASSERT_TRUE(subnet_->inPool(hint));
 +    OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
 +    ia->addOption(hint_opt);
 +    sol->addOption(ia);
 +    OptionPtr clientid = generateClientId();
 +    sol->addOption(clientid);
 +
 +    // Pass it to the server and get an advertise
 +    Pkt6Ptr reply = srv->processSolicit(sol);
 +
 +    // check if we get response at all
 +    checkResponse(reply, DHCPV6_ADVERTISE, 1234);
 +
 +    OptionPtr tmp = reply->getOption(D6O_IA_NA);
 +    ASSERT_TRUE(tmp);
 +
 +    // check that IA_NA was returned and that there's an address included
 +    shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234, subnet_->getT1(),
 +                                                subnet_->getT2());
 +
 +    // check that we've got the address we requested
 +    checkIAAddr(addr, hint, subnet_->getPreferred(), subnet_->getValid());
 +
 +    // check DUIDs
 +    checkServerId(reply, srv->getServerID());
 +    checkClientId(reply, clientid);
 +}
 +
 +// This test verifies that incoming SOLICIT can be handled properly, that an
 +// ADVERTISE is generated, that the response has an address and that address
 +// really belongs to the configured pool.
 +//
 +// This test sends a SOLICIT with IA_NA that contains an invalid hint.
 +//
 +// constructed very simple SOLICIT message with:
 +// - client-id option (mandatory)
 +// - IA option (a request for address, with an address that does not
 +//              belong to the configured pool, i.e. is valid as hint)
 +//
 +// expected returned ADVERTISE message:
 +// - copy of client-id
 +// - server-id
 +// - IA that includes IAADDR
 +TEST_F(Dhcpv6SrvTest, SolicitInvalidHint) {
 +    boost::scoped_ptr<NakedDhcpv6Srv> srv;
 +    ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
 +
 +    // Let's create a SOLICIT
 +    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
 +    sol->setRemoteAddr(IOAddress("fe80::abcd"));
 +    shared_ptr<Option6IA> ia = generateIA(234, 1500, 3000);
 +    IOAddress hint("2001:db8:1::cafe:babe");
 +    ASSERT_FALSE(subnet_->inPool(hint));
 +    OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
 +    ia->addOption(hint_opt);
 +    sol->addOption(ia);
 +    OptionPtr clientid = generateClientId();
 +    sol->addOption(clientid);
 +
 +    // Pass it to the server and get an advertise
 +    Pkt6Ptr reply = srv->processSolicit(sol);
 +
 +    // check if we get response at all
 +    checkResponse(reply, DHCPV6_ADVERTISE, 1234);
 +
 +    // check that IA_NA was returned and that there's an address included
 +    shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234, subnet_->getT1(),
 +                                                subnet_->getT2());
 +
 +    // Check that the assigned address is indeed from the configured pool
 +    checkIAAddr(addr, addr->getAddress(), subnet_->getPreferred(), subnet_->getValid());
 +    EXPECT_TRUE(subnet_->inPool(addr->getAddress()));
 +
 +    // check DUIDs
 +    checkServerId(reply, srv->getServerID());
 +    checkClientId(reply, clientid);
 +}
 +
 +// This test checks that the server is offering different addresses to different
 +// clients in ADVERTISEs. Please note that ADVERTISE is not a guarantee that such
 +// and address will be assigned. Had the pool was very small and contained only
 +// 2 addresses, the third client would get the same advertise as the first one
 +// and this is a correct behavior. It is REQUEST that will fail for the third
 +// client. ADVERTISE is basically saying "if you send me a request, you will
 +// probably get an address like this" (there are no guarantees).
 +TEST_F(Dhcpv6SrvTest, ManySolicits) {
 +    boost::scoped_ptr<NakedDhcpv6Srv> srv;
 +    ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
 +
 +    Pkt6Ptr sol1 = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
 +    Pkt6Ptr sol2 = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 2345));
 +    Pkt6Ptr sol3 = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 3456));
 +
 +    sol1->setRemoteAddr(IOAddress("fe80::abcd"));
 +    sol2->setRemoteAddr(IOAddress("fe80::1223"));
 +    sol3->setRemoteAddr(IOAddress("fe80::3467"));
 +
 +    sol1->addOption(generateIA(1, 1500, 3000));
 +    sol2->addOption(generateIA(2, 1500, 3000));
 +    sol3->addOption(generateIA(3, 1500, 3000));
 +
 +    // different client-id sizes
 +    OptionPtr clientid1 = generateClientId(12);
 +    OptionPtr clientid2 = generateClientId(14);
 +    OptionPtr clientid3 = generateClientId(16);
 +
 +    sol1->addOption(clientid1);
 +    sol2->addOption(clientid2);
 +    sol3->addOption(clientid3);
 +
 +    // Pass it to the server and get an advertise
 +    Pkt6Ptr reply1 = srv->processSolicit(sol1);
 +    Pkt6Ptr reply2 = srv->processSolicit(sol2);
 +    Pkt6Ptr reply3 = srv->processSolicit(sol3);
 +
 +    // check if we get response at all
 +    checkResponse(reply1, DHCPV6_ADVERTISE, 1234);
 +    checkResponse(reply2, DHCPV6_ADVERTISE, 2345);
 +    checkResponse(reply3, DHCPV6_ADVERTISE, 3456);
 +
 +    // check that IA_NA was returned and that there's an address included
 +    shared_ptr<Option6IAAddr> addr1 = checkIA_NA(reply1, 1, subnet_->getT1(),
 +                                                subnet_->getT2());
 +    shared_ptr<Option6IAAddr> addr2 = checkIA_NA(reply2, 2, subnet_->getT1(),
 +                                                subnet_->getT2());
 +    shared_ptr<Option6IAAddr> addr3 = checkIA_NA(reply3, 3, subnet_->getT1(),
 +                                                subnet_->getT2());
 +
 +    // Check that the assigned address is indeed from the configured pool
 +    checkIAAddr(addr1, addr1->getAddress(), subnet_->getPreferred(), subnet_->getValid());
 +    checkIAAddr(addr2, addr2->getAddress(), subnet_->getPreferred(), subnet_->getValid());
 +    checkIAAddr(addr3, addr3->getAddress(), subnet_->getPreferred(), subnet_->getValid());
 +
 +    // check DUIDs
 +    checkServerId(reply1, srv->getServerID());
 +    checkServerId(reply2, srv->getServerID());
 +    checkServerId(reply3, srv->getServerID());
 +    checkClientId(reply1, clientid1);
 +    checkClientId(reply2, clientid2);
 +    checkClientId(reply3, clientid3);
 +
 +    // Finally check that the addresses offered are different
 +    EXPECT_NE(addr1->getAddress().toText(), addr2->getAddress().toText());
 +    EXPECT_NE(addr2->getAddress().toText(), addr3->getAddress().toText());
 +    EXPECT_NE(addr3->getAddress().toText(), addr1->getAddress().toText());
 +    cout << "Offered address to client1=" << addr1->getAddress().toText() << endl;
 +    cout << "Offered address to client2=" << addr2->getAddress().toText() << endl;
 +    cout << "Offered address to client3=" << addr3->getAddress().toText() << endl;
 +}
 +
 +
 +// This test verifies that incoming REQUEST can be handled properly, that a
 +// REPLY is generated, that the response has an address and that address
 +// really belongs to the configured pool.
 +//
 +// This test sends a REQUEST with IA_NA that contains a valid hint.
 +//
 +// constructed very simple REQUEST message with:
 +// - client-id option (mandatory)
 +// - IA option (a request for address, with an address that belongs to the
 +//              configured pool, i.e. is valid as hint)
 +//
 +// expected returned REPLY message:
 +// - copy of client-id
 +// - server-id
 +// - IA that includes IAADDR
 +TEST_F(Dhcpv6SrvTest, RequestBasic) {
 +    boost::scoped_ptr<NakedDhcpv6Srv> srv;
 +    ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
 +
 +    // Let's create a REQUEST
 +    Pkt6Ptr req = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
 +    req->setRemoteAddr(IOAddress("fe80::abcd"));
 +    shared_ptr<Option6IA> ia = generateIA(234, 1500, 3000);
 +
 +    // with a valid hint
 +    IOAddress hint("2001:db8:1:1::dead:beef");
 +    ASSERT_TRUE(subnet_->inPool(hint));
 +    OptionPtr hint_opt(new Option6IAAddr(D6O_IAADDR, hint, 300, 500));
 +    ia->addOption(hint_opt);
 +    req->addOption(ia);
 +    OptionPtr clientid = generateClientId();
 +    req->addOption(clientid);
 +
 +    // Pass it to the server and hope for a REPLY
 +    Pkt6Ptr reply = srv->processRequest(req);
 +
 +    // check if we get response at all
 +    checkResponse(reply, DHCPV6_REPLY, 1234);
 +
 +    OptionPtr tmp = reply->getOption(D6O_IA_NA);
 +    ASSERT_TRUE(tmp);
 +
 +    // check that IA_NA was returned and that there's an address included
 +    shared_ptr<Option6IAAddr> addr = checkIA_NA(reply, 234, subnet_->getT1(),
 +                                                subnet_->getT2());
 +
 +    // check that we've got the address we requested
 +    checkIAAddr(addr, hint, subnet_->getPreferred(), subnet_->getValid());
 +
 +    // check DUIDs
 +    checkServerId(reply, srv->getServerID());
 +    checkClientId(reply, clientid);
 +
 +    // check that the lease is really in the database
 +    Lease6Ptr l = checkLease(duid_, reply->getOption(D6O_IA_NA), addr);
 +    EXPECT_TRUE(l);
 +    LeaseMgr::instance().deleteLease6(addr->getAddress());
 +}
 +
 +// This test checks that the server is offering different addresses to different
 +// clients in REQUEST. Please note that ADVERTISE is not a guarantee that such
 +// and address will be assigned. Had the pool was very small and contained only
 +// 2 addresses, the third client would get the same advertise as the first one
 +// and this is a correct behavior. It is REQUEST that will fail for the third
 +// client. ADVERTISE is basically saying "if you send me a request, you will
 +// probably get an address like this" (there are no guarantees).
 +TEST_F(Dhcpv6SrvTest, ManyRequests) {
 +    boost::scoped_ptr<NakedDhcpv6Srv> srv;
 +    ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) );
 +
 +    Pkt6Ptr req1 = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 1234));
 +    Pkt6Ptr req2 = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 2345));
 +    Pkt6Ptr req3 = Pkt6Ptr(new Pkt6(DHCPV6_REQUEST, 3456));
 +
 +    req1->setRemoteAddr(IOAddress("fe80::abcd"));
 +    req2->setRemoteAddr(IOAddress("fe80::1223"));
 +    req3->setRemoteAddr(IOAddress("fe80::3467"));
 +
 +    req1->addOption(generateIA(1, 1500, 3000));
 +    req2->addOption(generateIA(2, 1500, 3000));
 +    req3->addOption(generateIA(3, 1500, 3000));
 +
 +    // different client-id sizes
 +    OptionPtr clientid1 = generateClientId(12);
 +    OptionPtr clientid2 = generateClientId(14);
 +    OptionPtr clientid3 = generateClientId(16);
 +
 +    req1->addOption(clientid1);
 +    req2->addOption(clientid2);
 +    req3->addOption(clientid3);
 +
 +    // Pass it to the server and get an advertise
 +    Pkt6Ptr reply1 = srv->processRequest(req1);
 +    Pkt6Ptr reply2 = srv->processRequest(req2);
 +    Pkt6Ptr reply3 = srv->processRequest(req3);
 +
 +    // check if we get response at all
 +    checkResponse(reply1, DHCPV6_REPLY, 1234);
 +    checkResponse(reply2, DHCPV6_REPLY, 2345);
 +    checkResponse(reply3, DHCPV6_REPLY, 3456);
 +
 +    // check that IA_NA was returned and that there's an address included
 +    shared_ptr<Option6IAAddr> addr1 = checkIA_NA(reply1, 1, subnet_->getT1(),
 +                                                subnet_->getT2());
 +    shared_ptr<Option6IAAddr> addr2 = checkIA_NA(reply2, 2, subnet_->getT1(),
 +                                                subnet_->getT2());
 +    shared_ptr<Option6IAAddr> addr3 = checkIA_NA(reply3, 3, subnet_->getT1(),
 +                                                subnet_->getT2());
 +
 +    // Check that the assigned address is indeed from the configured pool
 +    checkIAAddr(addr1, addr1->getAddress(), subnet_->getPreferred(), subnet_->getValid());
 +    checkIAAddr(addr2, addr2->getAddress(), subnet_->getPreferred(), subnet_->getValid());
 +    checkIAAddr(addr3, addr3->getAddress(), subnet_->getPreferred(), subnet_->getValid());
 +
 +    // check DUIDs
 +    checkServerId(reply1, srv->getServerID());
 +    checkServerId(reply2, srv->getServerID());
 +    checkServerId(reply3, srv->getServerID());
 +    checkClientId(reply1, clientid1);
 +    checkClientId(reply2, clientid2);
 +    checkClientId(reply3, clientid3);
 +
 +    // Finally check that the addresses offered are different
 +    EXPECT_NE(addr1->getAddress().toText(), addr2->getAddress().toText());
 +    EXPECT_NE(addr2->getAddress().toText(), addr3->getAddress().toText());
 +    EXPECT_NE(addr3->getAddress().toText(), addr1->getAddress().toText());
 +    cout << "Assigned address to client1=" << addr1->getAddress().toText() << endl;
 +    cout << "Assigned address to client2=" << addr2->getAddress().toText() << endl;
 +    cout << "Assigned address to client3=" << addr3->getAddress().toText() << endl;
 +}
 +
 +
  TEST_F(Dhcpv6SrvTest, serverReceivedPacketName) {
      // Check all possible packet types
      for (int itype = 0; itype < 256; ++itype) {
index 7032a41b165c08c068ea45f4a382148d1cff775f,db35ca61f387a02be6a0950d6fcccc3e3f2f6347..6ac3f1484bbdc0b8819665a50ae7fe83833974e5
@@@ -46,14 -45,14 +46,13 @@@ const uint8_t bitMask6[]= { 0, 0x80, 0x
  /// @param len prefix length
  isc::asiolink::IOAddress firstAddrInPrefix6(const isc::asiolink::IOAddress& prefix,
                                              uint8_t len) {
 -    uint8_t packed[V6ADDRESS_LEN];
--
      if (len > 128) {
-         isc_throw(BadValue, "IPv6 prefix length too large:" << len);
+         isc_throw(isc::BadValue,
+                   "Too large netmask. 0..128 is allowed in IPv6");
      }
  
-     uint8_t packed[V6ADDRESS_LEN];
      // First we copy the whole address as 16 bytes.
++    uint8_t packed[V6ADDRESS_LEN];
      memcpy(packed, prefix.getAddress().to_v6().to_bytes().data(), 16);
  
      // If the length is divisible by 8, it is simple. We just zero out the host
@@@ -125,13 -124,15 +124,13 @@@ isc::asiolink::IOAddress lastAddrInPref
  /// @param len netmask length (0-128)
  isc::asiolink::IOAddress lastAddrInPrefix6(const isc::asiolink::IOAddress& prefix,
                                             uint8_t len) {
 -
 -    uint8_t packed[V6ADDRESS_LEN];
 -
      if (len > 128) {
-         isc_throw(BadValue, "IPv6 prefix length too large:" << len);
+         isc_throw(isc::BadValue,
+                   "Too large netmask. 0..128 is allowed in IPv6");
      }
  
-     uint8_t packed[V6ADDRESS_LEN];
      // First we copy the whole address as 16 bytes.
++    uint8_t packed[V6ADDRESS_LEN];
      memcpy(packed, prefix.getAddress().to_v6().to_bytes().data(), 16);
  
      // if the length is divisible by 8, it is simple. We just fill the host part
index c9954c27edc3dab335613aeb369b3f209bb57bf4,8ebefdcc9253fdf3bc7cfa8ebe07575722824757..650fd5f98f7d5929ff4df56202bf249a01ca5f50
  // PERFORMANCE OF THIS SOFTWARE.
  
  #include <alloc_engine.h>
 +#include <string.h>
  
+ #include <cstring>
  using namespace isc::asiolink;
  
  namespace isc {
Simple merge
index 9e5fbe74b6cc7e976ea97c285e2806b2fa0d350c,945c8e99165290ca5ac227edba9aa5f3a0060356..91e08d802fb0991e9eda02f5a43beb4991ec5cf0
@@@ -18,8 -18,9 +18,9 @@@
  #include <dhcp/duid.h>
  #include <dhcp/alloc_engine.h>
  #include <dhcp/cfgmgr.h>
 -#include "memfile_lease_mgr.h"
 +#include <dhcp/memfile_lease_mgr.h>
  #include <boost/shared_ptr.hpp>
+ #include <boost/scoped_ptr.hpp>
  #include <iostream>
  #include <sstream>
  #include <map>
@@@ -131,9 -130,8 +130,8 @@@ detailCompareLease6(const Lease6Ptr& fi
  
  // This test checks if the simple allocation can succeed
  TEST_F(AllocEngineTest, simpleAlloc) {
-     AllocEngine* engine = NULL;
-     ASSERT_NO_THROW(engine = new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100));
 -    boost::scoped_ptr<AllocEngine>(engine);
++    boost::scoped_ptr<AllocEngine> engine;
+     ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
      ASSERT_TRUE(engine);
  
      Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_, IOAddress("::"),
  
  // This test checks if the fake allocation (for SOLICIT) can succeed
  TEST_F(AllocEngineTest, fakeAlloc) {
-     AllocEngine* engine = NULL;
-     ASSERT_NO_THROW(engine = new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100));
 -    boost::scoped_ptr<AllocEngine>(engine);
++    boost::scoped_ptr<AllocEngine> engine;
+     ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
      ASSERT_TRUE(engine);
  
      Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_, IOAddress("::"),
  // This test checks if the allocation with a hint that is valid (in range,
  // in pool and free) can succeed
  TEST_F(AllocEngineTest, allocWithValidHint) {
-     AllocEngine* engine = NULL;
-     ASSERT_NO_THROW(engine = new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100));
 -    boost::scoped_ptr<AllocEngine>(engine);
++    boost::scoped_ptr<AllocEngine> engine;
+     ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
      ASSERT_TRUE(engine);
  
      Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
  // This test checks if the allocation with a hint that is in range,
  // in pool, but is currently used) can succeed
  TEST_F(AllocEngineTest, allocWithUsedHint) {
-     AllocEngine* engine = NULL;
-     ASSERT_NO_THROW(engine = new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100));
 -    boost::scoped_ptr<AllocEngine>(engine);
++    boost::scoped_ptr<AllocEngine> engine;
+     ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
      ASSERT_TRUE(engine);
  
      // let's create a lease and put it in the LeaseMgr
  // This test checks if the allocation with a hint that is out the blue
  // can succeed. The invalid hint should be ignored completely.
  TEST_F(AllocEngineTest, allocBogusHint) {
-     AllocEngine* engine = NULL;
-     ASSERT_NO_THROW(engine = new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100));
 -    boost::scoped_ptr<AllocEngine>(engine);
++    boost::scoped_ptr<AllocEngine> engine;
+     ASSERT_NO_THROW(engine.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
      ASSERT_TRUE(engine);
  
      // Client would like to get a 3000::abc lease, which does not belong to any
index fc330ea0a4e201b22662ee5f5a5d4c1c4018df32,a1ad8653c33365807033469e1ab0cc31bd1af96f..5cc63450dbd0951d8713b517a8bfe7933d117447
@@@ -75,8 -66,10 +75,9 @@@ TEST_F(CfgMgrTest, subnet4) 
  
  // This test verifies if the configuration manager is able to hold and return
  // valid leases
 -TEST(CfgMgrTest, DISABLED_subnet6) {
 -    CfgMgr& cfg_mgr = CfgMgr::instance();
 -    ASSERT_TRUE(&cfg_mgr != 0);
 +TEST_F(CfgMgrTest, subnet6) {
 +    CfgMgr& cfg_mgr = CfgMgr::instance();
  
      Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
      Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));