Browse Source

[master] Merge branch 'trac3668'

Conflicts:
	src/lib/dhcpsrv/memfile_lease_mgr.cc
	src/lib/dhcpsrv/memfile_lease_mgr.h
Marcin Siodelski 10 years ago
parent
commit
2ce54eeb60
49 changed files with 608 additions and 173 deletions
  1. 0 1
      src/bin/d2/Makefile.am
  2. 2 2
      src/bin/d2/bundy_d2_controller.h
  3. 0 31
      src/bin/d2/d2_asio.h
  4. 2 2
      src/bin/d2/d2_cfg_mgr.h
  5. 2 2
      src/bin/d2/d2_config.h
  6. 3 3
      src/bin/d2/d2_process.cc
  7. 2 2
      src/bin/d2/d2_process.h
  8. 2 2
      src/bin/d2/d2_queue_mgr.cc
  9. 4 4
      src/bin/d2/d2_queue_mgr.h
  10. 2 2
      src/bin/d2/d2_update_mgr.cc
  11. 5 5
      src/bin/d2/d2_update_mgr.h
  12. 4 4
      src/bin/d2/d_controller.h
  13. 5 5
      src/bin/d2/d_process.h
  14. 2 2
      src/bin/d2/io_service_signal.cc
  15. 5 4
      src/bin/d2/io_service_signal.h
  16. 2 2
      src/bin/d2/nc_add.cc
  17. 2 2
      src/bin/d2/nc_add.h
  18. 2 2
      src/bin/d2/nc_remove.cc
  19. 2 2
      src/bin/d2/nc_remove.h
  20. 2 2
      src/bin/d2/nc_trans.cc
  21. 5 5
      src/bin/d2/nc_trans.h
  22. 6 4
      src/bin/d2/tests/d2_process_unittests.cc
  23. 8 7
      src/bin/d2/tests/d2_queue_mgr_unittests.cc
  24. 4 4
      src/bin/d2/tests/d2_update_mgr_unittests.cc
  25. 4 3
      src/bin/d2/tests/d_test_stubs.cc
  26. 5 4
      src/bin/d2/tests/d_test_stubs.h
  27. 5 4
      src/bin/d2/tests/io_service_signal_unittests.cc
  28. 4 3
      src/bin/d2/tests/nc_add_unittests.cc
  29. 4 3
      src/bin/d2/tests/nc_remove_unittests.cc
  30. 4 2
      src/bin/d2/tests/nc_test_utils.h
  31. 5 4
      src/bin/d2/tests/nc_trans_unittests.cc
  32. 6 0
      src/bin/dhcp4/dhcp4.spec
  33. 8 1
      src/bin/dhcp4/dhcp4_messages.mes
  34. 20 4
      src/bin/dhcp4/dhcp4_srv.cc
  35. 6 0
      src/bin/dhcp6/dhcp6.spec
  36. 7 0
      src/bin/dhcp6/dhcp6_messages.mes
  37. 21 9
      src/bin/dhcp6/dhcp6_srv.cc
  38. 1 1
      src/lib/asiolink/interval_timer.cc
  39. 20 3
      src/lib/asiolink/io_service.cc
  40. 10 1
      src/lib/asiolink/io_service.h
  41. 7 1
      src/lib/asiolink/tests/io_service_unittest.cc
  42. 9 0
      src/lib/dhcpsrv/dhcpsrv_messages.mes
  43. 46 5
      src/lib/dhcpsrv/lease_mgr.h
  44. 41 1
      src/lib/dhcpsrv/memfile_lease_mgr.cc
  45. 54 3
      src/lib/dhcpsrv/memfile_lease_mgr.h
  46. 21 8
      src/lib/dhcpsrv/parsers/dbaccess_parser.cc
  47. 3 4
      src/lib/dhcpsrv/parsers/dbaccess_parser.h
  48. 71 6
      src/lib/dhcpsrv/tests/dbaccess_parser_unittest.cc
  49. 153 2
      src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc

+ 0 - 1
src/bin/d2/Makefile.am

@@ -53,7 +53,6 @@ libd2_la_SOURCES  =
 libd2_la_SOURCES += d_process.h
 libd2_la_SOURCES += d_controller.cc d_controller.h
 libd2_la_SOURCES += d_cfg_mgr.cc d_cfg_mgr.h
-libd2_la_SOURCES += d2_asio.h
 libd2_la_SOURCES += d2_log.cc d2_log.h
 libd2_la_SOURCES += d2_process.cc d2_process.h
 libd2_la_SOURCES += d2_config.cc d2_config.h

+ 2 - 2
src/bin/d2/bundy_d2_controller.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2015 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
@@ -15,10 +15,10 @@
 #ifndef BUNDY_D2_CONTROLLER_H
 #define BUNDY_D2_CONTROLLER_H
 
+#include <asiolink/io_service.h>
 #include <cc/data.h>
 #include <cc/session.h>
 #include <config/ccsession.h>
-#include <d2/d2_asio.h>
 #include <d2/d2_log.h>
 #include <d2/d_controller.h>
 #include <d2/d_process.h>

+ 0 - 31
src/bin/d2/d2_asio.h

@@ -1,31 +0,0 @@
-// Copyright (C) 2013  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.
-
-#ifndef D2_ASIO_H
-#define D2_ASIO_H
-
-#include <asiolink/asiolink.h>
-
-#include <boost/shared_ptr.hpp>
-
-namespace isc {
-namespace d2 {
-
-/// @brief Defines a smart pointer to an IOService instance.
-typedef boost::shared_ptr<isc::asiolink::IOService> IOServicePtr;
-
-}; // namespace isc::d2
-}; // namespace isc
-
-#endif

+ 2 - 2
src/bin/d2/d2_cfg_mgr.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2015 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
@@ -15,9 +15,9 @@
 #ifndef D2_CFG_MGR_H
 #define D2_CFG_MGR_H
 
+#include <asiolink/io_service.h>
 #include <cc/data.h>
 #include <exceptions/exceptions.h>
-#include <d2/d2_asio.h>
 #include <d2/d_cfg_mgr.h>
 #include <d2/d2_config.h>
 

+ 2 - 2
src/bin/d2/d2_config.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2015 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
@@ -15,8 +15,8 @@
 #ifndef D2_CONFIG_H
 #define D2_CONFIG_H
 
+#include <asiolink/io_service.h>
 #include <cc/data.h>
-#include <d2/d2_asio.h>
 #include <d2/d_cfg_mgr.h>
 #include <dhcpsrv/parsers/dhcp_parsers.h>
 #include <dns/tsig.h>

+ 3 - 3
src/bin/d2/d2_process.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2014  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2015  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
@@ -26,7 +26,7 @@ namespace d2 {
 // be configurable.
 const unsigned int D2Process::QUEUE_RESTART_PERCENT =  80;
 
-D2Process::D2Process(const char* name, IOServicePtr io_service)
+D2Process::D2Process(const char* name, const asiolink::IOServicePtr& io_service)
     : DProcessBase(name, io_service, DCfgMgrBasePtr(new D2CfgMgr())),
      reconf_queue_flag_(false), shutdown_type_(SD_NORMAL) {
 
@@ -101,7 +101,7 @@ D2Process::runIO() {
     // service.  Secondly, asiolink::IOService does not provide the poll
     // method.  This is a handy method which runs all ready handlers without
     // blocking.
-    IOServicePtr& io = getIoService();
+    asiolink::IOServicePtr& io = getIoService();
     asio::io_service& asio_io_service  = io->get_io_service();
 
     // Poll runs all that are ready. If none are ready it returns immediately

+ 2 - 2
src/bin/d2/d2_process.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013, 2015 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
@@ -66,7 +66,7 @@ public:
     /// asynchronous event handling.
     ///
     /// @throw DProcessBaseError is io_service is NULL.
-    D2Process(const char* name, IOServicePtr io_service);
+    D2Process(const char* name, const asiolink::IOServicePtr& io_service);
 
     /// @brief Called after instantiation to perform initialization unique to
     /// D2.

+ 2 - 2
src/bin/d2/d2_queue_mgr.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2015 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
@@ -22,7 +22,7 @@ namespace d2 {
 // Makes constant visible to Google test macros.
 const size_t D2QueueMgr::MAX_QUEUE_DEFAULT;
 
-D2QueueMgr::D2QueueMgr(IOServicePtr& io_service, const size_t max_queue_size)
+D2QueueMgr::D2QueueMgr(asiolink::IOServicePtr& io_service, const size_t max_queue_size)
     : io_service_(io_service), max_queue_size_(max_queue_size),
       mgr_state_(NOT_INITTED), target_stop_state_(NOT_INITTED) {
     if (!io_service_) {

+ 4 - 4
src/bin/d2/d2_queue_mgr.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013, 2015 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
@@ -17,8 +17,8 @@
 
 /// @file d2_queue_mgr.h This file defines the class D2QueueMgr.
 
+#include <asiolink/io_service.h>
 #include <exceptions/exceptions.h>
-#include <d2/d2_asio.h>
 #include <dhcp_ddns/ncr_msg.h>
 #include <dhcp_ddns/ncr_io.h>
 
@@ -165,7 +165,7 @@ public:
     /// This value must be greater than zero. It defaults to MAX_QUEUE_DEFAULT.
     ///
     /// @throw D2QueueMgrError if max_queue_size is zero.
-    D2QueueMgr(IOServicePtr& io_service,
+    D2QueueMgr(asiolink::IOServicePtr& io_service,
                const size_t max_queue_size = MAX_QUEUE_DEFAULT);
 
     /// @brief Destructor
@@ -327,7 +327,7 @@ public:
     void updateStopState();
 
     /// @brief IOService that our listener should use for IO management.
-    IOServicePtr io_service_;
+    asiolink::IOServicePtr io_service_;
 
     /// @brief Dictates the maximum number of entries allowed in the queue.
     size_t max_queue_size_;

+ 2 - 2
src/bin/d2/d2_update_mgr.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013, 2015 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
@@ -26,7 +26,7 @@ namespace d2 {
 const size_t D2UpdateMgr::MAX_TRANSACTIONS_DEFAULT;
 
 D2UpdateMgr::D2UpdateMgr(D2QueueMgrPtr& queue_mgr, D2CfgMgrPtr& cfg_mgr,
-                         IOServicePtr& io_service,
+                         asiolink::IOServicePtr& io_service,
                          const size_t max_transactions)
     :queue_mgr_(queue_mgr), cfg_mgr_(cfg_mgr), io_service_(io_service) {
     if (!queue_mgr_) {

+ 5 - 5
src/bin/d2/d2_update_mgr.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013, 2015 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
@@ -17,8 +17,8 @@
 
 /// @file d2_update_mgr.h This file defines the class D2UpdateMgr.
 
+#include <asiolink/io_service.h>
 #include <exceptions/exceptions.h>
-#include <d2/d2_asio.h>
 #include <d2/d2_log.h>
 #include <d2/d2_queue_mgr.h>
 #include <d2/d2_cfg_mgr.h>
@@ -100,7 +100,7 @@ public:
     /// @throw D2UpdateMgrError if either the queue manager or configuration
     /// managers are NULL, or max transactions is less than one.
     D2UpdateMgr(D2QueueMgrPtr& queue_mgr, D2CfgMgrPtr& cfg_mgr,
-                IOServicePtr& io_service,
+                asiolink::IOServicePtr& io_service,
                 const size_t max_transactions = MAX_TRANSACTIONS_DEFAULT);
 
     /// @brief Destructor
@@ -173,7 +173,7 @@ public:
     /// @brief Gets the D2UpdateMgr's IOService.
     ///
     /// @return returns a reference to the IOService
-    const IOServicePtr& getIOService() {
+    const asiolink::IOServicePtr& getIOService() {
         return (io_service_);
     }
 
@@ -246,7 +246,7 @@ private:
     /// passed into transactions to manager their IO events.
     /// (For future reference, multi-threaded transactions would each use their
     /// own IOService instance.)
-    IOServicePtr io_service_;
+    asiolink::IOServicePtr io_service_;
 
     /// @brief Maximum number of concurrent transactions.
     size_t max_transactions_;

+ 4 - 4
src/bin/d2/d_controller.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2015 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
@@ -15,8 +15,8 @@
 #ifndef D_CONTROLLER_H
 #define D_CONTROLLER_H
 
+#include <asiolink/io_service.h>
 #include <cc/data.h>
-#include <d2/d2_asio.h>
 #include <d2/d2_log.h>
 #include <d2/d_process.h>
 #include <d2/io_service_signal.h>
@@ -320,7 +320,7 @@ protected:
     /// @brief Getter for fetching the controller's IOService
     ///
     /// @return returns a pointer reference to the IOService.
-    IOServicePtr& getIOService() {
+    asiolink::IOServicePtr& getIOService() {
         return (io_service_);
     }
 
@@ -481,7 +481,7 @@ private:
     DProcessBasePtr process_;
 
     /// @brief Shared pointer to an IOService object, used for ASIO operations.
-    IOServicePtr io_service_;
+    asiolink::IOServicePtr io_service_;
 
     /// @brief Set of registered signals to handle.
     util::SignalSetPtr signal_set_;

+ 5 - 5
src/bin/d2/d_process.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013, 2015 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
@@ -15,8 +15,8 @@
 #ifndef D_PROCESS_H
 #define D_PROCESS_H
 
+#include <asiolink/io_service.h>
 #include <cc/data.h>
-#include <d2/d2_asio.h>
 #include <d2/d_cfg_mgr.h>
 
 #include <boost/shared_ptr.hpp>
@@ -69,7 +69,7 @@ public:
     /// configuration parsing.
     ///
     /// @throw DProcessBaseError is io_service is NULL.
-    DProcessBase(const char* app_name, IOServicePtr io_service, 
+    DProcessBase(const char* app_name, asiolink::IOServicePtr io_service, 
                  DCfgMgrBasePtr cfg_mgr)
         : app_name_(app_name), io_service_(io_service), shut_down_flag_(false),
         cfg_mgr_(cfg_mgr) {
@@ -174,7 +174,7 @@ public:
     /// @brief Fetches the controller's IOService.
     ///
     /// @return a reference to the controller's IOService.
-    IOServicePtr& getIoService() {
+    asiolink::IOServicePtr& getIoService() {
         return (io_service_);
     }
 
@@ -199,7 +199,7 @@ private:
     std::string app_name_;
 
     /// @brief The IOService to be used for asynchronous event handling.
-    IOServicePtr io_service_;
+    asiolink::IOServicePtr io_service_;
 
     /// @brief Boolean flag set when shutdown has been requested.
     bool shut_down_flag_;

+ 2 - 2
src/bin/d2/io_service_signal.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2015 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
@@ -65,7 +65,7 @@ IOSignal::TimerCallback::operator()() {
     return;
 }
 
-IOSignalQueue::IOSignalQueue(IOServicePtr& io_service)
+IOSignalQueue::IOSignalQueue(asiolink::IOServicePtr& io_service)
     : io_service_(io_service), signals_() {
     if (!io_service_) {
         isc_throw(IOSignalError, "IOSignalQueue - io_serivce cannot be NULL");

+ 5 - 4
src/bin/d2/io_service_signal.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2015 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
@@ -15,7 +15,8 @@
 #ifndef IO_SERVICE_SIGNAL_H
 #define IO_SERVICE_SIGNAL_H
 
-#include <d2/d2_asio.h>
+#include <asiolink/io_service.h>
+#include <asiolink/interval_timer.h>
 #include <exceptions/exceptions.h>
 
 #include <map>
@@ -202,7 +203,7 @@ public:
     ///
     /// @param io_service the IOService to which to send signals.
     /// @throw IOSignalError if io_service is NULL.
-    IOSignalQueue (IOServicePtr& io_service);
+    IOSignalQueue (asiolink::IOServicePtr& io_service);
 
     /// @brief Destructor.
     ~IOSignalQueue();
@@ -248,7 +249,7 @@ public:
 
 private:
     /// @brief Pointer to the IOService which will receive the signals.
-    IOServicePtr io_service_;
+    asiolink::IOServicePtr io_service_;
 
     /// @brief A map of the IOSignals pushed through this queue.
     IOSignalMap signals_;

+ 2 - 2
src/bin/d2/nc_add.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2015 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
@@ -35,7 +35,7 @@ const int NameAddTransaction::FQDN_IN_USE_EVT;
 const int NameAddTransaction::FQDN_NOT_IN_USE_EVT;
 
 NameAddTransaction::
-NameAddTransaction(IOServicePtr& io_service,
+NameAddTransaction(asiolink::IOServicePtr& io_service,
                    dhcp_ddns::NameChangeRequestPtr& ncr,
                    DdnsDomainPtr& forward_domain,
                    DdnsDomainPtr& reverse_domain,

+ 2 - 2
src/bin/d2/nc_add.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013, 2015 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
@@ -91,7 +91,7 @@ public:
     ///
     /// @throw NameAddTransaction error if given request is not a CHG_ADD,
     /// NameChangeTransaction error for base class construction errors.
-    NameAddTransaction(IOServicePtr& io_service,
+    NameAddTransaction(asiolink::IOServicePtr& io_service,
                        dhcp_ddns::NameChangeRequestPtr& ncr,
                        DdnsDomainPtr& forward_domain,
                        DdnsDomainPtr& reverse_domain,

+ 2 - 2
src/bin/d2/nc_remove.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2015 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
@@ -32,7 +32,7 @@ const int NameRemoveTransaction::REMOVING_REV_PTRS_ST;
 // Currently NameRemoveTransaction does not define any events.
 
 NameRemoveTransaction::
-NameRemoveTransaction(IOServicePtr& io_service,
+NameRemoveTransaction(asiolink::IOServicePtr& io_service,
                    dhcp_ddns::NameChangeRequestPtr& ncr,
                    DdnsDomainPtr& forward_domain,
                    DdnsDomainPtr& reverse_domain,

+ 2 - 2
src/bin/d2/nc_remove.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013, 2015 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
@@ -87,7 +87,7 @@ public:
     ///
     /// @throw NameRemoveTransaction error if given request is not a CHG_REMOVE,
     /// NameChangeTransaction error for base class construction errors.
-    NameRemoveTransaction(IOServicePtr& io_service,
+    NameRemoveTransaction(asiolink::IOServicePtr& io_service,
                           dhcp_ddns::NameChangeRequestPtr& ncr,
                           DdnsDomainPtr& forward_domain,
                           DdnsDomainPtr& reverse_domain,

+ 2 - 2
src/bin/d2/nc_trans.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2015 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
@@ -44,7 +44,7 @@ const int NameChangeTransaction::NCT_DERIVED_EVENT_MIN;
 const unsigned int NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
 
 NameChangeTransaction::
-NameChangeTransaction(IOServicePtr& io_service,
+NameChangeTransaction(asiolink::IOServicePtr& io_service,
                       dhcp_ddns::NameChangeRequestPtr& ncr,
                       DdnsDomainPtr& forward_domain,
                       DdnsDomainPtr& reverse_domain,

+ 5 - 5
src/bin/d2/nc_trans.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2015 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
@@ -17,8 +17,8 @@
 
 /// @file nc_trans.h This file defines the class NameChangeTransaction.
 
+#include <asiolink/io_service.h>
 #include <exceptions/exceptions.h>
-#include <d2/d2_asio.h>
 #include <d2/d2_cfg_mgr.h>
 #include <d2/dns_client.h>
 #include <d2/state_model.h>
@@ -174,7 +174,7 @@ public:
     /// @throw NameChangeTransactionError if given an null request,
     /// if forward change is enabled but forward domain is null, if
     /// reverse change is enabled but reverse domain is null.
-    NameChangeTransaction(IOServicePtr& io_service,
+    NameChangeTransaction(asiolink::IOServicePtr& io_service,
                           dhcp_ddns::NameChangeRequestPtr& ncr,
                           DdnsDomainPtr& forward_domain,
                           DdnsDomainPtr& reverse_domain,
@@ -359,7 +359,7 @@ protected:
     /// @brief Fetches the IOService the transaction uses for IO processing.
     ///
     /// @return returns a const pointer to the IOService.
-    const IOServicePtr& getIOService() {
+    const asiolink::IOServicePtr& getIOService() {
         return (io_service_);
     }
 
@@ -523,7 +523,7 @@ public:
 
 private:
     /// @brief The IOService which should be used to for IO processing.
-    IOServicePtr io_service_;
+    asiolink::IOServicePtr io_service_;
 
     /// @brief The NameChangeRequest that the transaction is to fulfill.
     dhcp_ddns::NameChangeRequestPtr ncr_;

+ 6 - 4
src/bin/d2/tests/d2_process_unittests.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2015 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
@@ -13,6 +13,7 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 
+#include <asiolink/io_service.h>
 #include <config/ccsession.h>
 #include <d2/d2_process.h>
 #include <dhcp_ddns/ncr_io.h>
@@ -64,8 +65,9 @@ class D2ProcessTest : public D2Process, public ConfigParseTest {
 public:
 
     /// @brief Constructor
-    D2ProcessTest() : D2Process("d2test",
-                                IOServicePtr(new isc::asiolink::IOService())) {
+    D2ProcessTest() :
+        D2Process("d2test",
+                  asiolink::IOServicePtr(new isc::asiolink::IOService())) {
     }
 
     /// @brief Destructor
@@ -143,7 +145,7 @@ public:
 TEST(D2Process, construction) {
     // Verify that the constructor will fail if given an empty
     // io service.
-    IOServicePtr lcl_io_service;
+    asiolink::IOServicePtr lcl_io_service;
     EXPECT_THROW (D2Process("TestProcess", lcl_io_service), DProcessBaseError);
 
     // Verify that the constructor succeeds with a valid io_service

+ 8 - 7
src/bin/d2/tests/d2_queue_mgr_unittests.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013, 2015 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
@@ -12,7 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <d2/d2_asio.h>
+#include <asiolink/io_service.h>
+#include <asiolink/interval_timer.h>
 #include <d2/d2_queue_mgr.h>
 #include <dhcp_ddns/ncr_udp.h>
 #include <util/time_utilities.h>
@@ -78,7 +79,7 @@ const long TEST_TIMEOUT = 5 * 1000;
 
 /// @brief Tests that construction with max queue size of zero is not allowed.
 TEST(D2QueueMgrBasicTest, construction1) {
-    IOServicePtr io_service;
+    asiolink::IOServicePtr io_service;
 
     // Verify that constructing with null IOServicePtr is not allowed.
     EXPECT_THROW((D2QueueMgr(io_service)), D2QueueMgrError);
@@ -90,7 +91,7 @@ TEST(D2QueueMgrBasicTest, construction1) {
 
 /// @brief Tests default construction works.
 TEST(D2QueueMgrBasicTest, construction2) {
-    IOServicePtr io_service(new isc::asiolink::IOService());
+    asiolink::IOServicePtr io_service(new isc::asiolink::IOService());
 
     // Verify that valid constructor works.
     D2QueueMgrPtr queue_mgr;
@@ -101,7 +102,7 @@ TEST(D2QueueMgrBasicTest, construction2) {
 
 /// @brief Tests construction with custom queue size works properly
 TEST(D2QueueMgrBasicTest, construction3) {
-    IOServicePtr io_service(new isc::asiolink::IOService());
+    asiolink::IOServicePtr io_service(new isc::asiolink::IOService());
 
     // Verify that custom queue size constructor works.
     D2QueueMgrPtr queue_mgr;
@@ -118,7 +119,7 @@ TEST(D2QueueMgrBasicTest, construction3) {
 /// 4. Peek returns the first entry on the queue without altering queue content
 /// 5. Dequeue removes the first entry on the queue
 TEST(D2QueueMgrBasicTest, basicQueue) {
-    IOServicePtr io_service(new isc::asiolink::IOService());
+    asiolink::IOServicePtr io_service(new isc::asiolink::IOService());
 
     // Construct the manager with max queue size set to number of messages
     // we'll use.
@@ -210,7 +211,7 @@ bool checkSendVsReceived(NameChangeRequestPtr sent_ncr,
 class QueueMgrUDPTest : public virtual ::testing::Test,
                         NameChangeSender::RequestSendHandler {
 public:
-    IOServicePtr io_service_;
+    asiolink::IOServicePtr io_service_;
     NameChangeSenderPtr   sender_;
     isc::asiolink::IntervalTimer test_timer_;
     D2QueueMgrPtr queue_mgr_;

+ 4 - 4
src/bin/d2/tests/d2_update_mgr_unittests.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2015 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
@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <d2/d2_asio.h>
+#include <asiolink/io_service.h>
 #include <d2/d2_update_mgr.h>
 #include <util/time_utilities.h>
 #include <d_test_stubs.h>
@@ -42,7 +42,7 @@ public:
     ///
     /// Parameters match those needed by D2UpdateMgr.
     D2UpdateMgrWrapper(D2QueueMgrPtr& queue_mgr, D2CfgMgrPtr& cfg_mgr,
-                       IOServicePtr& io_service,
+                       asiolink::IOServicePtr& io_service,
                        const size_t max_transactions = MAX_TRANSACTIONS_DEFAULT)
         : D2UpdateMgr(queue_mgr, cfg_mgr, io_service, max_transactions) {
     }
@@ -250,7 +250,7 @@ public:
 /// 4. Default construction works and max transactions is defaulted properly
 /// 5. Construction with custom max transactions works properly
 TEST(D2UpdateMgr, construction) {
-    IOServicePtr io_service(new isc::asiolink::IOService());
+    asiolink::IOServicePtr io_service(new isc::asiolink::IOService());
     D2QueueMgrPtr queue_mgr;
     D2CfgMgrPtr cfg_mgr;
     D2UpdateMgrPtr update_mgr;

+ 4 - 3
src/bin/d2/tests/d_test_stubs.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2015 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
@@ -12,6 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <asiolink/io_service.h>
 #include <d2/d2_log.h>
 #include <d2/spec_config.h>
 #include <d2/tests/d_test_stubs.h>
@@ -51,7 +52,7 @@ SimFailure::FailureType SimFailure::failure_type_ = SimFailure::ftNoFailure;
 // Define custom process command supported by DStubProcess.
 const char*  DStubProcess::stub_proc_command_("cool_proc_cmd");
 
-DStubProcess::DStubProcess(const char* name, IOServicePtr io_service)
+DStubProcess::DStubProcess(const char* name, asiolink::IOServicePtr io_service)
     : DProcessBase(name, io_service, DCfgMgrBasePtr(new DStubCfgMgr())) {
 };
 
@@ -72,7 +73,7 @@ DStubProcess::run() {
     // To use run(), the "managing" layer must issue an io_service::stop
     // or the call to run will continue to block, and shutdown will not
     // occur.
-    IOServicePtr& io_service = getIoService();
+    asiolink::IOServicePtr& io_service = getIoService();
     while (!shouldShutdown()) {
         try {
             io_service->run_one();

+ 5 - 4
src/bin/d2/tests/d_test_stubs.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2015 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
@@ -15,11 +15,12 @@
 #ifndef D_TEST_STUBS_H
 #define D_TEST_STUBS_H
 
+#include <asiolink/io_service.h>
+
 #include <cc/data.h>
 #include <cc/session.h>
 #include <config/ccsession.h>
 
-#include <d2/d2_asio.h>
 #include <d2/d_controller.h>
 #include <d2/d_cfg_mgr.h>
 
@@ -128,7 +129,7 @@ public:
     /// asynchronous event handling.
     ///
     /// @throw DProcessBaseError is io_service is NULL.
-    DStubProcess(const char* name, IOServicePtr io_service);
+    DStubProcess(const char* name, asiolink::IOServicePtr io_service);
 
     /// @brief Invoked after process instantiation to perform initialization.
     /// This implementation supports simulating an error initializing the
@@ -423,7 +424,7 @@ public:
     /// @brief Gets the Controller's IOService.
     ///
     /// @return returns a reference to the IOService
-    IOServicePtr& getIOService() {
+    asiolink::IOServicePtr& getIOService() {
         return (getController()->io_service_);
     }
 

+ 5 - 4
src/bin/d2/tests/io_service_signal_unittests.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2015 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
@@ -12,6 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <asiolink/io_service.h>
 #include <d_test_stubs.h>
 #include <d2/io_service_signal.h>
 
@@ -29,7 +30,7 @@ namespace d2 {
 class IOSignalTest : public ::testing::Test {
 public:
     /// @brief IOService instance to process IO.
-    IOServicePtr io_service_;
+    asiolink::IOServicePtr io_service_;
     /// @brief Failsafe timer to ensure test(s) do not hang.
     isc::asiolink::IntervalTimer test_timer_;
     /// @brief Maximum time should be allowed to run.
@@ -137,7 +138,7 @@ void dummyHandler(IOSignalId) {
 
 // Tests IOSignal constructor.
 TEST(IOSignal, construction) {
-    IOServicePtr io_service(new asiolink::IOService());
+    asiolink::IOServicePtr io_service(new asiolink::IOService());
     IOSignalPtr signal;
     IOSignalPtr signal2;
 
@@ -169,7 +170,7 @@ TEST(IOSignal, construction) {
 // Tests IOSignalQueue constructors and exercises queuing methods.
 TEST(IOSignalQueue, constructionAndQueuing) {
     IOSignalQueuePtr queue;
-    IOServicePtr io_service;
+    asiolink::IOServicePtr io_service;
 
     // Verify constructing with an empty IOService will throw.
     ASSERT_THROW(queue.reset(new IOSignalQueue(io_service)), IOSignalError);

+ 4 - 3
src/bin/d2/tests/nc_add_unittests.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2014  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2015  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
@@ -12,6 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <asiolink/io_service.h>
 #include <d2/d2_cfg_mgr.h>
 #include <d2/d2_cfg_mgr.h>
 #include <d2/nc_add.h>
@@ -32,7 +33,7 @@ namespace {
 // to protected methods.
 class NameAddStub : public NameAddTransaction {
 public:
-    NameAddStub(IOServicePtr& io_service,
+    NameAddStub(asiolink::IOServicePtr& io_service,
                 dhcp_ddns::NameChangeRequestPtr& ncr,
                 DdnsDomainPtr& forward_domain,
                 DdnsDomainPtr& reverse_domain,
@@ -266,7 +267,7 @@ public:
 /// 1. Construction with invalid type of request
 /// 2. Valid construction functions properly
 TEST(NameAddTransaction, construction) {
-    IOServicePtr io_service(new isc::asiolink::IOService());
+    asiolink::IOServicePtr io_service(new isc::asiolink::IOService());
     D2CfgMgrPtr cfg_mgr(new D2CfgMgr());
 
     const char* msg_str =

+ 4 - 3
src/bin/d2/tests/nc_remove_unittests.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2014  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2015 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
@@ -12,6 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <asiolink/io_service.h>
 #include <d2/d2_cfg_mgr.h>
 #include <d2/d2_cfg_mgr.h>
 #include <d2/nc_remove.h>
@@ -32,7 +33,7 @@ namespace {
 // to protected methods.
 class NameRemoveStub : public NameRemoveTransaction {
 public:
-    NameRemoveStub(IOServicePtr& io_service,
+    NameRemoveStub(asiolink::IOServicePtr& io_service,
                    dhcp_ddns::NameChangeRequestPtr& ncr,
                    DdnsDomainPtr& forward_domain,
                    DdnsDomainPtr& reverse_domain,
@@ -268,7 +269,7 @@ public:
 /// 1. Construction with invalid type of request
 /// 2. Valid construction functions properly
 TEST(NameRemoveTransaction, construction) {
-    IOServicePtr io_service(new isc::asiolink::IOService());
+    asiolink::IOServicePtr io_service(new isc::asiolink::IOService());
     D2CfgMgrPtr cfg_mgr(new D2CfgMgr());
 
     const char* msg_str =

+ 4 - 2
src/bin/d2/tests/nc_test_utils.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2015 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
@@ -17,6 +17,8 @@
 
 /// @file nc_test_utils.h prototypes for functions related transaction testing.
 
+#include <asiolink/io_service.h>
+#include <asiolink/interval_timer.h>
 #include <d2/nc_trans.h>
 
 #include <asio/ip/udp.hpp>
@@ -138,7 +140,7 @@ public:
 /// valve so tests do not hang.
 class TimedIO  {
 public:
-    IOServicePtr io_service_;
+    asiolink::IOServicePtr io_service_;
     asiolink::IntervalTimer timer_;
     int run_time_;
 

+ 5 - 4
src/bin/d2/tests/nc_trans_unittests.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013-2014  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2015  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
@@ -12,6 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <asiolink/io_service.h>
 #include <asiolink/interval_timer.h>
 #include <d2/nc_trans.h>
 #include <dns/opcode.h>
@@ -59,7 +60,7 @@ public:
     /// @brief Constructor
     ///
     /// Parameters match those needed by NameChangeTransaction.
-    NameChangeStub(IOServicePtr& io_service,
+    NameChangeStub(asiolink::IOServicePtr& io_service,
                    dhcp_ddns::NameChangeRequestPtr& ncr,
                    DdnsDomainPtr& forward_domain,
                    DdnsDomainPtr& reverse_domain,
@@ -367,7 +368,7 @@ public:
 /// requires reverse change.
 /// 4. Valid construction functions properly
 TEST(NameChangeTransaction, construction) {
-    IOServicePtr io_service(new isc::asiolink::IOService());
+    asiolink::IOServicePtr io_service(new isc::asiolink::IOService());
     D2CfgMgrPtr cfg_mgr(new D2CfgMgr());
 
     const char* msg_str =
@@ -396,7 +397,7 @@ TEST(NameChangeTransaction, construction) {
 
     // Verify that construction with a null IOServicePtr fails.
     // @todo Subject to change if multi-threading is implemented.
-    IOServicePtr empty;
+    asiolink::IOServicePtr empty;
     EXPECT_THROW(NameChangeTransaction(empty, ncr,
                                        forward_domain, reverse_domain, cfg_mgr),
                                        NameChangeTransactionError);

+ 6 - 0
src/bin/dhcp4/dhcp4.spec

@@ -197,6 +197,12 @@
                 "item_type": "boolean",
                 "item_optional": true,
                 "item_default": true
+            },
+            {
+                "item_name": "lfc-interval",
+                "item_type": "integer",
+                "item_optional": true,
+                "item_default": 0
             }
         ]
       },

+ 8 - 1
src/bin/dhcp4/dhcp4_messages.mes

@@ -1,4 +1,4 @@
-# Copyright (C) 2012-2014  Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2012-2015 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
@@ -187,6 +187,13 @@ specified client after receiving a REQUEST message from it.  There are many
 possible reasons for such a failure. Additional messages will indicate the
 reason.
 
+% DHCP4_LEASE_DATABASE_TIMERS_EXEC_FAIL failed to execute timer-based functions for lease database: %1
+A warning message executed when a server process is unable to execute
+the periodic actions for the lease database. An example of the periodic
+action is a Lease File Cleanup. One of the reasons for the failure is
+a misconfiguration of the lease database, whereby the lease database
+hasn't been selected.
+
 % DHCP4_NAME_GEN_UPDATE_FAIL failed to update the lease after generating name for a client: %1
 This message indicates the failure when trying to update the lease and/or
 options in the server's response with the hostname generated by the server

+ 20 - 4
src/bin/dhcp4/dhcp4_srv.cc

@@ -40,6 +40,7 @@
 #include <hooks/hooks_manager.h>
 #include <util/strutil.h>
 
+#include <asio.hpp>
 #include <boost/bind.hpp>
 #include <boost/foreach.hpp>
 
@@ -149,15 +150,21 @@ Dhcpv4Srv::sendPacket(const Pkt4Ptr& packet) {
 bool
 Dhcpv4Srv::run() {
     while (!shutdown_) {
-        /// @todo: calculate actual timeout once we have lease database
-        //cppcheck-suppress variableScope This is temporary anyway
-        const int timeout = 1000;
-
         // client's message and server's response
         Pkt4Ptr query;
         Pkt4Ptr rsp;
 
         try {
+            // The lease database backend may install some timers for which
+            // the handlers need to be executed periodically. Retrieve the
+            // maximum interval at which the handlers must be executed from
+            // the lease manager.
+            uint32_t timeout = LeaseMgrFactory::instance().getIOServiceExecInterval();
+            // If the returned value is zero it means that there are no
+            // timers installed, so use a default value.
+            if (timeout == 0) {
+                timeout = 1000;
+            }
             query = receivePacket(timeout);
 
         } catch (const SignalInterruptOnSelect) {
@@ -183,6 +190,15 @@ Dhcpv4Srv::run() {
         // terminate.
         handleSignal();
 
+        // Execute ready timers for the lease database, e.g. Lease File Cleanup.
+        try {
+            LeaseMgrFactory::instance().getIOService()->poll();
+
+        } catch (const std::exception& ex) {
+            LOG_WARN(dhcp4_logger, DHCP4_LEASE_DATABASE_TIMERS_EXEC_FAIL)
+                .arg(ex.what());
+        }
+
         // Timeout may be reached or signal received, which breaks select()
         // with no reception ocurred
         if (!query) {

+ 6 - 0
src/bin/dhcp6/dhcp6.spec

@@ -191,6 +191,12 @@
                 "item_type": "boolean",
                 "item_optional": true,
                 "item_default": true
+            },
+            {
+                "item_name": "lfc-interval",
+                "item_type": "integer",
+                "item_optional": true,
+                "item_default": 0
             }
         ]
       },

+ 7 - 0
src/bin/dhcp6/dhcp6_messages.mes

@@ -275,6 +275,13 @@ failed to grant a non-temporary address lease for the client. There may
 be many reasons for such failure. Each failure is logged in a separate
 log entry.
 
+% DHCP6_LEASE_DATABASE_TIMERS_EXEC_FAIL failed to execute timer-based functions for lease database: %1
+A warning message executed when a server process is unable to execute
+the periodic actions for the lease database. An example of the periodic
+action is a Lease File Cleanup. One of the reasons for the failure is
+a misconfiguration of the lease database, whereby the lease database
+hasn't been selected.
+
 % DHCP6_LEASE_NA_WITHOUT_DUID address lease for address %1 does not have a DUID
 This error message indicates a database consistency problem. The lease
 database has an entry indicating that the given address is in use,

+ 21 - 9
src/bin/dhcp6/dhcp6_srv.cc

@@ -47,6 +47,8 @@
 #include <util/io_utilities.h>
 #include <util/range_utilities.h>
 
+#include <asio.hpp>
+
 #include <boost/bind.hpp>
 #include <boost/foreach.hpp>
 #include <boost/tokenizer.hpp>
@@ -228,20 +230,21 @@ Dhcpv6Srv::testUnicast(const Pkt6Ptr& pkt) const {
 
 bool Dhcpv6Srv::run() {
     while (!shutdown_) {
-        /// @todo Calculate actual timeout to the next event (e.g. lease
-        /// expiration) once we have lease database. The idea here is that
-        /// it is possible to do everything in a single process/thread.
-        /// For now, we are just calling select for 1000 seconds. There
-        /// were some issues reported on some systems when calling select()
-        /// with too large values. Unfortunately, I don't recall the details.
-        //cppcheck-suppress variableScope This is temporary anyway
-        const int timeout = 1000;
-
         // client's message and server's response
         Pkt6Ptr query;
         Pkt6Ptr rsp;
 
         try {
+            // The lease database backend may install some timers for which
+            // the handlers need to be executed periodically. Retrieve the
+            // maximum interval at which the handlers must be executed from
+            // the lease manager.
+            uint32_t timeout = LeaseMgrFactory::instance().getIOServiceExecInterval();
+            // If the returned value is zero it means that there are no
+            // timers installed, so use a default value.
+            if (timeout == 0) {
+                timeout = 1000;
+            }
             query = receivePacket(timeout);
 
         } catch (const SignalInterruptOnSelect) {
@@ -266,6 +269,15 @@ bool Dhcpv6Srv::run() {
         // terminate.
         handleSignal();
 
+        // Execute ready timers for the lease database, e.g. Lease File Cleanup.
+        try {
+            LeaseMgrFactory::instance().getIOService()->poll();
+
+        } catch (const std::exception& ex) {
+            LOG_WARN(dhcp6_logger, DHCP6_LEASE_DATABASE_TIMERS_EXEC_FAIL)
+                .arg(ex.what());
+        }
+
         // Timeout may be reached or signal received, which breaks select()
         // with no packet received
         if (!query) {

+ 1 - 1
src/lib/asiolink/interval_timer.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011, 2104 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011, 2014 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

+ 20 - 3
src/lib/asiolink/io_service.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011,2013  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011, 2013, 2015 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
@@ -59,14 +59,26 @@ public:
     ///
     /// This method does not return control to the caller until
     /// the \c stop() method is called via some handler.
-    void run() { io_service_.run(); };
+    void run() {
+        io_service_.run();
+    };
 
     /// \brief Run the underlying event loop for a single event.
     ///
     /// This method return control to the caller as soon as the
     /// first handler has completed.  (If no handlers are ready when
     /// it is run, it will block until one is.)
-    void run_one() { io_service_.run_one();} ;
+    void run_one() {
+        io_service_.run_one();
+    };
+
+    /// \brief Run the underlying event loop for a ready events.
+    ///
+    /// This method executes handlers for all ready events and returns.
+    /// It will return immediately if there are no ready events.
+    void poll() {
+        io_service_.poll();
+    };
 
     /// \brief Stop the underlying event loop.
     ///
@@ -108,6 +120,11 @@ IOService::run_one() {
 }
 
 void
+IOService::poll() {
+    io_impl_->poll();
+}
+
+void
 IOService::stop() {
     io_impl_->stop();
 }

+ 10 - 1
src/lib/asiolink/io_service.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2011,2013  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011, 2013, 2015 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
@@ -59,6 +59,12 @@ public:
     /// it is run, it will block until one is.)
     void run_one();
 
+    /// \brief Run the underlying event loop for a ready events.
+    ///
+    /// This method executes handlers for all ready events and returns.
+    /// It will return immediately if there are no ready events.
+    void poll();
+
     /// \brief Stop the underlying event loop.
     ///
     /// This will return the control to the caller of the \c run() method.
@@ -87,6 +93,9 @@ private:
     IOServiceImpl* io_impl_;
 };
 
+/// @brief Defines a smart pointer to an IOService instance.
+typedef boost::shared_ptr<IOService> IOServicePtr;
+
 } // namespace asiolink
 } // namespace isc
 #endif // ASIOLINK_IO_SERVICE_H

+ 7 - 1
src/lib/asiolink/tests/io_service_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013, 2015  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
@@ -34,6 +34,7 @@ TEST(IOService, post) {
     // Post two events
     service.post(boost::bind(&postedEvent, &called, 1));
     service.post(boost::bind(&postedEvent, &called, 2));
+    service.post(boost::bind(&postedEvent, &called, 3));
     // They have not yet been called
     EXPECT_TRUE(called.empty());
     // Process two events
@@ -43,6 +44,11 @@ TEST(IOService, post) {
     ASSERT_EQ(2, called.size());
     EXPECT_EQ(1, called[0]);
     EXPECT_EQ(2, called[1]);
+
+    // Test that poll() executes the last handler.
+    service.poll();
+    ASSERT_EQ(3, called.size());
+    EXPECT_EQ(3, called[2]);
 }
 
 }

+ 9 - 0
src/lib/dhcpsrv/dhcpsrv_messages.mes

@@ -292,6 +292,15 @@ replaced by those read from the file.
 % DHCPSRV_MEMFILE_LEASE_LOAD loading lease %1
 A debug message issued when DHCP lease is being loaded from the file to memory.
 
+% DHCPSRV_MEMFILE_LFC_SETUP setting up the Lease File Cleanup interval to %1 sec
+An informational message logged when the Memfile lease database backend
+configures the LFC to be executed periodically. The argument holds the
+interval in seconds in which the LFC will be executed.
+
+% DHCPSRV_MEMFILE_LFC_START starting Lease File Cleanup
+An informational message issued when the Memfile lease database backend
+starts the periodic Lease File Cleanup.
+
 % DHCPSRV_MEMFILE_NO_STORAGE running in non-persistent mode, leases will be lost after restart
 A warning message issued when writes of leases to disk have been disabled
 in the configuration. This mode is useful for some kinds of performance

+ 46 - 5
src/lib/dhcpsrv/lease_mgr.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013, 2015 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
@@ -16,6 +16,7 @@
 #define LEASE_MGR_H
 
 #include <asiolink/io_address.h>
+#include <asiolink/io_service.h>
 #include <dhcp/duid.h>
 #include <dhcp/option.h>
 #include <dhcp/hwaddr.h>
@@ -117,9 +118,19 @@ public:
 /// be used directly, but rather specialized derived class should be used
 /// instead.
 ///
-/// As all methods are virtual, this class throws no exceptions.  However,
-/// methods in concrete implementations of this class may throw exceptions:
-/// see the documentation of those classes for details.
+/// This class creates an instance of the @c asiolink::IOService in the
+/// constructor. This object is required to execute the
+/// @c asiolink::IntervalTimer for the operations triggered periodically
+/// by the lease database backends which implement @c LeaseMgr interface.
+/// In order to execute the timers installed by the particular backend,
+/// the owner of the backend (e.g. DHCP server) should retrieve the pointer
+/// to the @c asiolink::IOService object by calling @c LeaseMgr::getIOService
+/// and call the appropriate functions, e.g. @c poll_one or @c run_one in a
+/// main loop.
+///
+/// This class throws no exceptions.  However, methods in concrete
+/// implementations of this class may throw exceptions: see the documentation
+/// of those classes for details.
 class LeaseMgr {
 public:
     /// @brief Defines maximum value for time that can be reliably stored.
@@ -133,7 +144,8 @@ public:
     ///
     /// @param parameters A data structure relating keywords and values
     ///        concerned with the database.
-    LeaseMgr(const ParameterMap& parameters) : parameters_(parameters)
+    LeaseMgr(const ParameterMap& parameters)
+        : parameters_(parameters), io_service_(new asiolink::IOService())
     {}
 
     /// @brief Destructor
@@ -379,6 +391,31 @@ public:
     /// @brief returns value of the parameter
     virtual std::string getParameter(const std::string& name) const;
 
+    /// @brief Returns the interval at which the @c IOService events should
+    /// be released.
+    ///
+    /// The implementations of this class may install the timers which
+    /// periodically trigger event handlers defined for them. Depending
+    /// on the intervals specified for these timers the @c IOService::poll,
+    /// @c IOService::run etc. have to be executed to allow the timers
+    /// for checking whether they have already expired and the handler
+    /// must be executed. Running the @c IOService with a lower interval
+    /// would cause the desynchronization of timers with the clock.
+    ///
+    /// @return A maximum interval in seconds at which the @c IOService
+    /// should be executed. A value of 0 means that no timers are installed
+    /// and that there is no requirement for the @c IOService to be
+    /// executed at any specific interval.
+    virtual uint32_t getIOServiceExecInterval() const {
+        return (0);
+    }
+
+    /// @brief Returns a reference to the @c IOService object used
+    /// by the Lease Manager.
+    const asiolink::IOServicePtr& getIOService() const {
+        return (io_service_);
+    }
+
 private:
     /// @brief list of parameters passed in dbconfig
     ///
@@ -386,6 +423,10 @@ private:
     /// password and other parameters required for DB access. It is not
     /// intended to keep any DHCP-related parameters.
     ParameterMap parameters_;
+
+    /// @brief Pointer to the IO service object used by the derived classes
+    /// to trigger interval timers.
+    asiolink::IOServicePtr io_service_;
 };
 
 }; // end of isc::dhcp namespace

+ 41 - 1
src/lib/dhcpsrv/memfile_lease_mgr.cc

@@ -30,7 +30,7 @@ const uint32_t MAX_LEASE_ERRORS = 100;
 using namespace isc::dhcp;
 
 Memfile_LeaseMgr::Memfile_LeaseMgr(const ParameterMap& parameters)
-    : LeaseMgr(parameters) {
+    : LeaseMgr(parameters), lfc_timer_(*getIOService()) {
     // Check the universe and use v4 file or v6 file.
     std::string universe = getParameter("universe");
     if (universe == "4") {
@@ -53,6 +53,9 @@ Memfile_LeaseMgr::Memfile_LeaseMgr(const ParameterMap& parameters)
     // operation.
     if (!persistLeases(V4) && !persistLeases(V6)) {
         LOG_WARN(dhcpsrv_logger, DHCPSRV_MEMFILE_NO_STORAGE);
+
+    } else  {
+        initTimers();
     }
 }
 
@@ -415,6 +418,11 @@ Memfile_LeaseMgr::rollback() {
               DHCPSRV_MEMFILE_ROLLBACK);
 }
 
+uint32_t
+Memfile_LeaseMgr::getIOServiceExecInterval() const {
+    return (static_cast<uint32_t>(lfc_timer_.getInterval() / 1000));
+}
+
 std::string
 Memfile_LeaseMgr::getDefaultLeaseFilePath(Universe u) const {
     std::ostringstream s;
@@ -474,6 +482,38 @@ Memfile_LeaseMgr::initLeaseFilePath(Universe u) {
     return (lease_file);
 }
 
+void
+Memfile_LeaseMgr::initTimers() {
+    std::string lfc_interval_str = "0";
+    try {
+        lfc_interval_str = getParameter("lfc-interval");
+    } catch (const std::exception& ex) {
+        // Ignore and default to 0.
+    }
+
+    uint32_t lfc_interval = 0;
+    try {
+        lfc_interval = boost::lexical_cast<uint32_t>(lfc_interval_str);
+    } catch (boost::bad_lexical_cast& ex) {
+        isc_throw(isc::BadValue, "invalid value of the lfc-interval "
+                  << lfc_interval_str << " specified");
+    }
+
+    if (lfc_interval > 0) {
+        asiolink::IntervalTimer::Callback cb =
+            boost::bind(&Memfile_LeaseMgr::lfcCallback, this);
+        LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_LFC_SETUP).arg(lfc_interval);
+        lfc_timer_.setup(cb, lfc_interval * 1000);
+    }
+}
+
+void
+Memfile_LeaseMgr::lfcCallback() {
+    /// @todo Extend this method to spawn the new process which will
+    /// perform the Lease File Cleanup in background.
+    LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_LFC_START);
+}
+
 template<typename LeaseObjectType, typename LeaseFileType, typename StorageType>
 void Memfile_LeaseMgr::
 loadLeasesFromFiles(const std::string& filename,

+ 54 - 3
src/lib/dhcpsrv/memfile_lease_mgr.h

@@ -15,6 +15,7 @@
 #ifndef MEMFILE_LEASE_MGR_H
 #define MEMFILE_LEASE_MGR_H
 
+#include <asiolink/interval_timer.h>
 #include <dhcp/hwaddr.h>
 #include <dhcpsrv/csv_lease_file4.h>
 #include <dhcpsrv/csv_lease_file6.h>
@@ -32,9 +33,24 @@ namespace dhcp {
 /// DHCPv4 and DHCPv6 leases on disk. The format of the files is determined
 /// by the @c CSVLeaseFile4 and @c CSVLeaseFile6 classes.
 ///
-/// The backend stores leases incrementally, i.e. updates to leases are appended
-/// at the end of the lease file. To record the deletion of a lease, the lease
-/// record is appended to the lease file with the valid lifetime set to 0.
+/// In order to obtain good performance, the backend stores leases
+/// incrementally, i.e. updates to leases are appended at the end of the lease
+/// file. To record the deletion of a lease, the lease record is appended to
+/// the lease file with the valid lifetime set to 0. However, this may result
+/// in a significant growth of the lease file size over time, because the lease
+/// file will contain many entries for each lease. In order to mitigate this
+/// problem, the backend implements the Lease File Cleanup mechanism which is
+/// described on the Kea wiki: http://kea.isc.org/wiki/LFCDesign.
+///
+/// The backend installs an @c asiolink::IntervalTimer to periodically execute
+/// the @c Memfile_LeaseMgr::lfcCallback. This callback function controls
+/// the startup of the background process which removes redundant information
+/// from the lease file(s). Note that the @c asiolink::IntervalTimer uses
+/// @c asiolink::IOService to execute the callback. The @c LeaseMgr class
+/// creates this object, which can be obtained by the caller using the
+/// @c LeaseMgr::getIOService. The caller should later call an appropriate
+/// method, @c asio::io_service::poll_one to execute the callback when
+/// the timer is ready.
 ///
 /// When the backend is starting up, it reads leases from the lease file (one
 /// by one) and adds them to the in-memory container as follows:
@@ -304,6 +320,19 @@ public:
     /// support transactions, this is a no-op.
     virtual void rollback();
 
+    /// @brief Returns the interval at which the @c IOService events should
+    /// be released.
+    ///
+    /// The Memfile backend may install a timer to execute the Lease File
+    /// Cleanup periodically. If this timer is installed, the method returns
+    /// the LFC interval in milliseconds.
+    ///
+    /// @return A maximum interval (in seconds) at which the @c IOService
+    /// should be executed. A value of 0 means that no timers are installed
+    /// and that there is no requirement for the @c IOService to be
+    /// executed at any specific interval.
+    virtual uint32_t getIOServiceExecInterval() const;
+
     /// @brief Returns default path to the lease file.
     ///
     /// @param u Universe (V4 or V6).
@@ -332,6 +361,25 @@ public:
 
 private:
 
+    /// @brief A callback function triggering Lease File Cleanup.
+    ///
+    /// This method is virtual so as it can be overriden and customized in
+    /// the unit tests. In particular, the unit test which checks that the
+    /// callback function has been executed would override this function
+    /// to increase the execution counter each time it is executed.
+    ///
+    /// @todo Once the callback is implemented, there is a need to
+    /// extend the documentation of this method. Currently, it simply
+    /// logs that it has been called.
+    virtual void lfcCallback();
+
+private:
+
+    /// @brief Initialize the timers used to perform repeating tasks.
+    ///
+    /// Currently only one timer is supported. This timer executes the
+    /// Lease File Cleanup periodically.
+    void initTimers();
     /// @brief Initialize the location of the lease file.
     ///
     /// This method uses the parameters passed as a map to the constructor to
@@ -401,6 +449,9 @@ private:
     /// @brief Holds the pointer to the DHCPv6 lease file IO.
     boost::shared_ptr<CSVLeaseFile6> lease_file6_;
 
+    /// @brief A timer scheduled to perform Lease File Cleanup.
+    asiolink::IntervalTimer lfc_timer_;
+
 };
 
 }; // end of isc::dhcp namespace

+ 21 - 8
src/lib/dhcpsrv/parsers/dbaccess_parser.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2015 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
@@ -18,6 +18,7 @@
 #include <dhcpsrv/parsers/dbaccess_parser.h>
 
 #include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
 
 #include <map>
 #include <string>
@@ -55,17 +56,21 @@ DbAccessParser::build(isc::data::ConstElementPtr config_value) {
     // use of it).
     values_copy["universe"] = ctx_.universe_ == Option::V4 ? "4" : "6";
 
+    int64_t lfc_interval = 0;
     // 3. Update the copy with the passed keywords.
     BOOST_FOREACH(ConfigPair param, config_value->mapValue()) {
         try {
-            // The persist parameter is the only boolean parameter at the
-            // moment. It needs special handling.
-            if (param.first != "persist") {
-                values_copy[param.first] = param.second->stringValue();
-
-            } else {
+            if (param.first == "persist") {
                 values_copy[param.first] = (param.second->boolValue() ?
                                             "true" : "false");
+
+            } else if (param.first == "lfc-interval") {
+                lfc_interval = param.second->intValue();
+                values_copy[param.first] =
+                    boost::lexical_cast<std::string>(lfc_interval);
+
+            } else {
+                values_copy[param.first] = param.second->stringValue();
             }
         } catch (const isc::data::TypeError& ex) {
             // Append position of the element.
@@ -84,13 +89,21 @@ DbAccessParser::build(isc::data::ConstElementPtr config_value) {
                   "to be accessed (" << config_value->getPosition() << ")");
     }
 
-    // b. Check if the 'type; keyword known and throw an exception if not.
+    // b. Check if the 'type' keyword known and throw an exception if not.
     string dbtype = type_ptr->second;
     if ((dbtype != "memfile") && (dbtype != "mysql") && (dbtype != "postgresql")) {
         isc_throw(BadValue, "unknown backend database type: " << dbtype
                   << " (" << config_value->getPosition() << ")");
     }
 
+    // c. Check that the lfc-interval is a number and it is within a resonable
+    // range.
+    if ((lfc_interval < 0) || (lfc_interval > std::numeric_limits<uint32_t>::max())) {
+        isc_throw(BadValue, "lfc-interval value: " << lfc_interval
+                  << " is out of range, expected value: 0.."
+                  << std::numeric_limits<uint32_t>::max());
+    }
+
     // 5. If all is OK, update the stored keyword/value pairs.  We do this by
     // swapping contents - values_copy is destroyed immediately after the
     // operation (when the method exits), so we are not interested in its new

+ 3 - 4
src/lib/dhcpsrv/parsers/dbaccess_parser.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2015 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
@@ -67,9 +67,8 @@ public:
     /// Parses the set of strings forming the database access specification and
     /// checks that all are OK.  In particular it checks:
     ///
-    /// - "type" is "memfile" or "mysql"
-    /// - If "type" is "memfile", checks that no other values are present: if
-    ///   they are, logs a warning that they will be ignored.
+    /// - "type" is "memfile", "mysql" or "postgresql"
+    /// - "lfc-interval" is a number from the range of 0 to 4294967295.
     ///
     /// Once all has been validated, constructs the database access string
     /// expected by the lease manager.

+ 71 - 6
src/lib/dhcpsrv/tests/dbaccess_parser_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2012-2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2015 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
@@ -93,13 +93,14 @@ public:
             }
 
             // Add the keyword and value - make sure that they are quoted.
-            // The only parameter which is not quoted is persist as it
-            // is a boolean value.
+            // The parameters which are not quoted are persist and
+            // lfc-interval as they are boolean and integer respectively.
             result += quote + keyval[i] + quote + colon + space;
-            if (std::string(keyval[i]) != "persist") {
-                result += quote + keyval[i + 1] + quote;
-            } else {
+            if (!quoteValue(std::string(keyval[i]))) {
                 result += keyval[i + 1];
+
+            } else {
+                result += quote + keyval[i + 1] + quote;
             }
         }
 
@@ -172,6 +173,20 @@ public:
             EXPECT_EQ(corresponding->second, actual->second);
         }
     }
+
+private:
+
+    /// @brief Checks if the value of the specified parameter should be
+    /// quoted in the configuration.
+    ///
+    /// @param parameter A parameter for which it should be checked whether
+    /// the value should be quoted or not.
+    ///
+    /// @return true if the value of the parameter should be quoted.
+     bool quoteValue(const std::string& parameter) const {
+         return ((parameter != "persist") && (parameter != "lfc-interval"));
+    }
+
 };
 
 
@@ -287,6 +302,56 @@ TEST_F(DbAccessParserTest, persistV6Memfile) {
                       config, Option::V6);
 }
 
+// This test checks that the parser accepts the valid value of the
+// lfc-interval parameter.
+TEST_F(DbAccessParserTest, validLFCInterval) {
+    const char* config[] = {"type", "memfile",
+                            "name", "/opt/kea/var/kea-leases6.csv",
+                            "lfc-interval", "3600",
+                            NULL};
+
+    string json_config = toJson(config);
+    ConstElementPtr json_elements = Element::fromJSON(json_config);
+    EXPECT_TRUE(json_elements);
+
+    TestDbAccessParser parser("lease-database", ParserContext(Option::V6));
+    ASSERT_NO_THROW(parser.build(json_elements));
+    checkAccessString("Valid LFC Interval", parser.getDbAccessParameters(),
+                      config, Option::V6);
+}
+
+// This test checks that the parser rejects the negative value of the
+// lfc-interval parameter.
+TEST_F(DbAccessParserTest, negativeLFCInterval) {
+    const char* config[] = {"type", "memfile",
+                            "name", "/opt/kea/var/kea-leases6.csv",
+                            "lfc-interval", "-1",
+                            NULL};
+
+    string json_config = toJson(config);
+    ConstElementPtr json_elements = Element::fromJSON(json_config);
+    EXPECT_TRUE(json_elements);
+
+    TestDbAccessParser parser("lease-database", ParserContext(Option::V6));
+    EXPECT_THROW(parser.build(json_elements), BadValue);
+}
+
+// This test checks that the parser rejects the too large (greater than
+// the max uint32_t) value of the lfc-interval parameter.
+TEST_F(DbAccessParserTest, largeLFCInterval) {
+    const char* config[] = {"type", "memfile",
+                            "name", "/opt/kea/var/kea-leases6.csv",
+                            "lfc-interval", "4294967296",
+                            NULL};
+
+    string json_config = toJson(config);
+    ConstElementPtr json_elements = Element::fromJSON(json_config);
+    EXPECT_TRUE(json_elements);
+
+    TestDbAccessParser parser("lease-database", ParserContext(Option::V6));
+    EXPECT_THROW(parser.build(json_elements), BadValue);
+}
+
 // Check that the parser works with a valid MySQL configuration
 TEST_F(DbAccessParserTest, validTypeMysql) {
     const char* config[] = {"type",     "mysql",

+ 153 - 2
src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc

@@ -25,6 +25,8 @@
 #include <dhcpsrv/tests/generic_lease_mgr_unittest.h>
 #include <gtest/gtest.h>
 
+#include <boost/bind.hpp>
+
 #include <iostream>
 #include <fstream>
 #include <sstream>
@@ -37,7 +39,45 @@ using namespace isc::dhcp::test;
 
 namespace {
 
-// empty class for now, but may be extended once Addr6 becomes bigger
+/// @brief Class derived from @c Memfile_LeaseMgr to test LFC timer.
+///
+/// This class provides a custom callback function which is invoked
+/// when the timer for Lease File Cleanup goes off. It is used to
+/// test that the timer is correctly installed.
+class LFCMemfileLeaseMgr : public Memfile_LeaseMgr {
+public:
+
+    /// @brief Constructor.
+    ///
+    /// Sets the counter for callbacks to 0.
+    LFCMemfileLeaseMgr(const ParameterMap& parameters)
+        : Memfile_LeaseMgr(parameters), lfc_cnt_(0) {
+    }
+
+    /// @brief Returns the number of callback executions.
+    int getLFCCount() {
+        return (lfc_cnt_);
+    }
+
+protected:
+
+    /// @brief Custom callback.
+    ///
+    /// This callback function increases the counter of callback executions.
+    /// By examining the counter value a test may verify that the callback
+    /// was triggered an expected number of times.
+    virtual void lfcCallback() {
+        ++lfc_cnt_;
+    }
+
+private:
+
+    /// @brief Counter of callback function executions.
+    int lfc_cnt_;
+
+};
+
+/// @brief Test fixture class for @c Memfile_LeaseMgr
 class MemfileLeaseMgrTest : public GenericLeaseMgrTest {
 public:
 
@@ -46,7 +86,9 @@ public:
     /// Creates memfile and stores it in lmptr_ pointer
     MemfileLeaseMgrTest() :
         io4_(getLeaseFilePath("leasefile4_0.csv")),
-        io6_(getLeaseFilePath("leasefile6_0.csv")) {
+        io6_(getLeaseFilePath("leasefile6_0.csv")),
+        io_service_(),
+        fail_on_callback_(false) {
 
         // Make sure there are no dangling files after previous tests.
         io4_.removeFile();
@@ -116,12 +158,36 @@ public:
         lmptr_ = &(LeaseMgrFactory::instance());
     }
 
+    void setTestTime(const uint32_t ms) {
+        IntervalTimer::Callback cb =
+            boost::bind(&MemfileLeaseMgrTest::testTimerCallback, this);
+        test_timer_.reset(new IntervalTimer(*io_service_));
+        test_timer_->setup(cb, ms, IntervalTimer::ONE_SHOT);
+    }
+
+    /// @brief Test timer callback function.
+    void testTimerCallback() {
+        io_service_->stop();
+        if (fail_on_callback_) {
+            FAIL() << "Test timeout reached";
+        }
+    }
+
     /// @brief Object providing access to v4 lease IO.
     LeaseFileIO io4_;
 
     /// @brief Object providing access to v6 lease IO.
     LeaseFileIO io6_;
 
+    /// @brief Test timer for the test.
+    boost::shared_ptr<IntervalTimer> test_timer_;
+
+    /// @brief IO service object used for the timer tests.
+    asiolink::IOServicePtr io_service_;
+
+    /// @brief Indicates if the @c testTimerCallback should cause test failure.
+    bool fail_on_callback_;
+
 };
 
 // This test checks if the LeaseMgr can be instantiated and that it
@@ -134,6 +200,7 @@ TEST_F(MemfileLeaseMgrTest, constructor) {
 
     EXPECT_NO_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)));
 
+    pmap["lfc-interval"] = "10";
     pmap["persist"] = "true";
     pmap["name"] = getLeaseFilePath("leasefile4_1.csv");
     EXPECT_NO_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)));
@@ -143,6 +210,10 @@ TEST_F(MemfileLeaseMgrTest, constructor) {
     pmap["persist"] = "bogus";
     pmap["name"] = getLeaseFilePath("leasefile4_1.csv");
     EXPECT_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)), isc::BadValue);
+
+    // The lfc-interval must be an integer.
+    pmap["lfc-interval"] = "bogus";
+    EXPECT_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)), isc::BadValue);
 }
 
 // Checks if the getType() and getName() methods both return "memfile".
@@ -204,6 +275,86 @@ TEST_F(MemfileLeaseMgrTest, persistLeases) {
     EXPECT_FALSE(lease_mgr->persistLeases(Memfile_LeaseMgr::V6));
 }
 
+// Check if it is possible to schedule the timer to perform the Lease
+// File Cleanup periodically.
+TEST_F(MemfileLeaseMgrTest, lfcTimer) {
+    LeaseMgr::ParameterMap pmap;
+    pmap["type"] = "memfile";
+    pmap["universe"] = "4";
+    // Specify the names of the lease files. Leases will be written.
+    pmap["name"] = getLeaseFilePath("leasefile4_0.csv");
+    pmap["lfc-interval"] = "1";
+
+    boost::scoped_ptr<LFCMemfileLeaseMgr>
+        lease_mgr(new LFCMemfileLeaseMgr(pmap));
+
+    // Check that the interval is correct.
+    EXPECT_EQ(1, lease_mgr->getIOServiceExecInterval());
+
+    io_service_ = lease_mgr->getIOService();
+
+    // Run the test for at most 2.9 seconds.
+    setTestTime(2900);
+
+    // Run the IO service to execute timers.
+    io_service_->run();
+
+    // Within 2.9 we should record two LFC executions.
+    EXPECT_EQ(2, lease_mgr->getLFCCount());
+}
+
+
+// This test checks if the LFC timer is disabled (doesn't trigger)
+// cleanups when the lfc-interval is set to 0.
+TEST_F(MemfileLeaseMgrTest, lfcTimerDisabled) {
+    LeaseMgr::ParameterMap pmap;
+    pmap["type"] = "memfile";
+    pmap["universe"] = "4";
+    pmap["name"] = getLeaseFilePath("leasefile4_0.csv");
+    // Set the LFC interval to 0, which should effectively disable it.
+    pmap["lfc-interval"] = "0";
+
+    boost::scoped_ptr<LFCMemfileLeaseMgr>
+        lease_mgr(new LFCMemfileLeaseMgr(pmap));
+
+    EXPECT_EQ(0, lease_mgr->getIOServiceExecInterval());
+
+    io_service_ = lease_mgr->getIOService();
+
+    // Run the test for at most 1.9 seconds.
+    setTestTime(1900);
+
+    // Run the IO service to execute timers.
+    io_service_->run();
+
+    // There should be no LFC execution recorded.
+    EXPECT_EQ(0, lease_mgr->getLFCCount());
+}
+
+// Test that the backend returns a correct value of the interval
+// at which the IOService must be executed to run the handlers
+// for the installed timers.
+TEST_F(MemfileLeaseMgrTest, getIOServiceExecInterval) {
+    LeaseMgr::ParameterMap pmap;
+    pmap["type"] = "memfile";
+    pmap["universe"] = "4";
+    pmap["name"] = getLeaseFilePath("leasefile4_0.csv");
+
+    // The lfc-interval is not set, so the returned value should be 0.
+    boost::scoped_ptr<LFCMemfileLeaseMgr> lease_mgr(new LFCMemfileLeaseMgr(pmap));
+    EXPECT_EQ(0, lease_mgr->getIOServiceExecInterval());
+
+    // lfc-interval = 10
+    pmap["lfc-interval"] = "10";
+    lease_mgr.reset(new LFCMemfileLeaseMgr(pmap));
+    EXPECT_EQ(10, lease_mgr->getIOServiceExecInterval());
+
+    // lfc-interval = 20
+    pmap["lfc-interval"] = "20";
+    lease_mgr.reset(new LFCMemfileLeaseMgr(pmap));
+    EXPECT_EQ(20, lease_mgr->getIOServiceExecInterval());
+
+}
 
 // Checks that adding/getting/deleting a Lease6 object works.
 TEST_F(MemfileLeaseMgrTest, addGetDelete6) {