BIND 10 experiments/fix-dhcp-test, updated. 5ce777ade02d9aea66ff3ff01e36822d3533302b [experiments/fix-dhcp-test] Merge branch 'master' into experiments/fix-dhcp-test
BIND 10 source code commits
bind10-changes at lists.isc.org
Mon Nov 19 10:17:14 UTC 2012
The branch, experiments/fix-dhcp-test has been updated
via 5ce777ade02d9aea66ff3ff01e36822d3533302b (commit)
via bbb0752c34f7712864b596f208cefd9746eab287 (commit)
via 33283af8e0f551ef3481817561ffddd0c9e5df88 (commit)
via 834fa9e8f5097c6fd06845620f68547a97da8ff8 (commit)
via 3ba0299ad2b5151e9c822977ec0d1b4df00dbf52 (commit)
via d2551c3b2bddcc80c496a59e85e390687776c24d (commit)
via e650a0f7e51fc4158d001d04e30ffc239875d9f8 (commit)
via 744d1be57ae311af05de0ee9572feee0c8b157e7 (commit)
via 3ef8b3161b927c0b427066b026145c4082e47573 (commit)
via 53e4c255e0054ee8d1dbe880e6853a4487c47d70 (commit)
via b37e972c6c6a7b9eeb09addab58516a1df74c15b (commit)
via 74985768e65ba323fac4444945c2d238fdbe24c9 (commit)
via 49d6a081b5e38e6ac463e71ae4daac8c6c4829d7 (commit)
via 718e97a589b6d3cbdfed7b768f7fbfaba232b709 (commit)
via b5bb87e8d4d010086f5192d3aa262d4856520b32 (commit)
via 96decbf08111574c5e60bd1d347c8ee2d599dd48 (commit)
via 1f5a07747ded3f395228265f10e4a67fa39e3468 (commit)
via 8ecc1a5e16969fc876c242d552423bd29205bdcc (commit)
via 4ca7528d681202ee567497f74b63010553799635 (commit)
via 987ef574df88ee226330fefd78a2b44eb5cda3b0 (commit)
via e2fa09ea1099e01daa5eff881c2ba80d69cfea70 (commit)
via 6b937eae7c5681857e0ce74bfee392f19890001b (commit)
via d42376ab7473a4af01c74db5f5a4ad35c66f8d52 (commit)
via 938ab8a39de2ae162b6e016bba718a2d6b874171 (commit)
via f57c0b95732d9e1c7f6d0cb8a91541d411eb66a3 (commit)
via 71eee20bd4e2688770303a8c51ea895916f49c75 (commit)
via e4fe372ea63d2115ca2e15866f0ef032fb05e0ca (commit)
via c4b0294b5bf4a9d32fb18ab62ca572f492788d72 (commit)
via 470aa3b8ecb855b0a9f6ad75b44c4f30bf35de8a (commit)
via be50a0c801d9203ca670e6cc9fa32e3461bc2d88 (commit)
via 487d2cb888f96ca8ab5325dbfa7dfc620e16db54 (commit)
via 4bc7823ddb3d480a7e3ff259722832cee64bec22 (commit)
via 2332578b7a7c6a25e8f24eaafd08c1f0f507f382 (commit)
via bc457a13e13b10079985213922c579634e20ca11 (commit)
via 0d08fcb9a4218410fa08bbb7b70802de5af04525 (commit)
via 5ba2cab585357a99f0bfadeb8f8488150e40f923 (commit)
via 9e1942f5eab1a46932990fe9dd85a8c02ac40a11 (commit)
via 6c30834cb78baa51e6776452069ceda87d34864c (commit)
via ca8a13ddaaee0ba86f57095f6f93ac2ce381d599 (commit)
via 51a1d8147f00f69419af1a5980f4e8fcedb5bb87 (commit)
via 10d9112a1eefa19109036da9e4a39bc4ba836021 (commit)
via aa753912fc89315d57601cf73ee18f88afced529 (commit)
via 2adb0227e8ad12a657fc80462928a51a3ceffae3 (commit)
via 7c8b1108b5df315e79aaa5b6ab21a655b24168cd (commit)
via 238254d39204ae3b2e6fba3f540b14132ff1bc43 (commit)
via 8872c15e883710475348463a87916d589c428031 (commit)
via 3d71b86e777c7280043a1191bbeb0bb115f88078 (commit)
via 931c0c2e32baaf74559c82165c7f1a89c0d3054d (commit)
via 705bbc32ba3fdf13602d015420720fb94f6a7f11 (commit)
via cec4bf4314a6c8deaeadf10c5d95bc812480653a (commit)
via 80c2a36861978d77f7a1649ba32a316996376221 (commit)
via ecace4bc156ef36fdade632f5656ce8886b2433f (commit)
via 0ff35f6ed78f78cd23ddb0747d2f97e152e7b774 (commit)
via 56f0319afe0f63710358a2fd123e9865f1a13758 (commit)
via 45088a0f850de1724eff8daff9fdc2303887ee13 (commit)
via 65dd63b2c9e72794b0029c5071e9fbf948321ccd (commit)
via 9478cb0fdc9896568928701bda3101b0a2fbcf16 (commit)
via d2103c888085b93e48731258fb7900c01a921734 (commit)
from 06dc00552bdf7eed9e316b5bc486f50c016be287 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 5ce777ade02d9aea66ff3ff01e36822d3533302b
Merge: 06dc005 bbb0752
Author: Jelte Jansen <jelte at isc.org>
Date: Mon Nov 19 11:17:06 2012 +0100
[experiments/fix-dhcp-test] Merge branch 'master' into experiments/fix-dhcp-test
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 42 +-
README | 10 +-
configure.ac | 2 +
doc/guide/bind10-guide.xml | 1467 +++++++++++++++-----
src/bin/auth/query.cc | 4 +-
src/bin/auth/tests/Makefile.am | 1 +
src/bin/auth/tests/query_inmemory_unittest.cc | 123 ++
src/bin/auth/tests/testdata/Makefile.am | 1 +
src/bin/auth/tests/testdata/example.zone | 121 ++
src/bin/bindctl/moduleinfo.py | 3 +-
src/bin/dhcp4/ctrl_dhcp4_srv.cc | 9 +-
src/bin/dhcp4/ctrl_dhcp4_srv.h | 4 +-
src/bin/dhcp4/dhcp4_log.cc | 2 +-
src/bin/dhcp4/dhcp4_log.h | 2 +-
src/bin/dhcp4/dhcp4_messages.mes | 10 +-
src/bin/dhcp4/dhcp4_srv.cc | 8 +-
src/bin/dhcp4/dhcp4_srv.h | 4 +-
src/bin/dhcp4/main.cc | 7 +-
src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc | 14 +-
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc | 16 +-
src/bin/dhcp4/tests/dhcp4_unittests.cc | 4 +-
src/bin/dhcp6/Makefile.am | 2 +-
src/bin/dhcp6/config_parser.cc | 33 +-
src/bin/dhcp6/config_parser.h | 9 +-
src/bin/dhcp6/ctrl_dhcp6_srv.cc | 15 +-
src/bin/dhcp6/ctrl_dhcp6_srv.h | 8 +-
src/bin/dhcp6/dhcp6_log.cc | 2 +-
src/bin/dhcp6/dhcp6_log.h | 4 +-
src/bin/dhcp6/dhcp6_messages.mes | 120 +-
src/bin/dhcp6/dhcp6_srv.cc | 26 +-
src/bin/dhcp6/dhcp6_srv.h | 12 +-
src/bin/dhcp6/main.cc | 19 +-
src/bin/dhcp6/tests/Makefile.am | 2 +-
src/bin/dhcp6/tests/config_parser_unittest.cc | 25 +-
src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc | 12 +-
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc | 20 +-
src/bin/dhcp6/tests/dhcp6_unittests.cc | 4 +-
src/bin/stats/stats_messages.mes | 8 +-
src/bin/xfrout/xfrout_messages.mes | 8 +-
src/lib/Makefile.am | 2 +-
src/lib/datasrc/Makefile.am | 1 +
src/lib/datasrc/client_list.cc | 16 +-
src/lib/datasrc/datasrc_messages.mes | 13 +-
.../exceptions.h} | 35 +-
src/lib/datasrc/memory/memory_client.h | 8 +-
src/lib/datasrc/memory/zone_data_loader.cc | 6 +-
src/lib/datasrc/memory/zone_data_loader.h | 5 +-
src/lib/datasrc/memory/zone_data_updater.cc | 2 +-
src/lib/datasrc/memory/zone_data_updater.h | 10 +-
src/lib/datasrc/tests/client_list_unittest.cc | 33 +-
.../datasrc/tests/memory/memory_client_unittest.cc | 10 +-
src/lib/datasrc/tests/testdata/example.edu-broken | 11 +
src/lib/datasrc/tests/testdata/example.net-empty | 1 +
src/lib/datasrc/zone.h | 5 +-
src/lib/dhcp/Makefile.am | 39 +-
src/lib/dhcp/duid.cc | 10 +-
src/lib/dhcp/duid.h | 2 +
src/lib/dhcp/iface_mgr.cc | 21 +-
src/lib/dhcp/iface_mgr.h | 12 +-
src/lib/dhcp/iface_mgr_linux.cc | 11 +-
src/lib/dhcp/libdhcp++.cc | 16 +-
src/lib/dhcp/libdhcp++.h | 7 +-
src/lib/dhcp/option.cc | 17 +-
src/lib/dhcp/option.h | 14 +-
src/lib/dhcp/option4_addrlst.cc | 16 +-
src/lib/dhcp/option4_addrlst.h | 20 +-
src/lib/dhcp/option6_addrlst.cc | 17 +-
src/lib/dhcp/option6_addrlst.h | 9 +-
src/lib/dhcp/option6_ia.cc | 12 +-
src/lib/dhcp/option6_ia.h | 9 +-
src/lib/dhcp/option6_iaaddr.cc | 17 +-
src/lib/dhcp/option6_iaaddr.h | 10 +-
src/lib/dhcp/option6_int.h | 6 +-
src/lib/dhcp/option6_int_array.h | 6 +-
src/lib/dhcp/option_data_types.h | 6 +-
src/lib/dhcp/option_definition.cc | 2 +-
src/lib/dhcp/option_definition.h | 15 +-
src/lib/dhcp/pkt4.cc | 7 +-
src/lib/dhcp/pkt4.h | 15 +-
src/lib/dhcp/pkt6.cc | 4 +-
src/lib/dhcp/pkt6.h | 13 +-
src/lib/dhcp/tests/Makefile.am | 42 +-
src/lib/dhcp/tests/duid_unittest.cc | 14 +-
src/lib/dhcp/tests/iface_mgr_unittest.cc | 20 +-
src/lib/dhcp/tests/libdhcp++_unittest.cc | 17 +-
src/lib/dhcp/tests/option4_addrlst_unittest.cc | 12 +-
src/lib/dhcp/tests/option6_addrlst_unittest.cc | 12 +-
src/lib/dhcp/tests/option6_ia_unittest.cc | 12 +-
src/lib/dhcp/tests/option6_iaaddr_unittest.cc | 12 +-
src/lib/dhcp/tests/option6_int_array_unittest.cc | 3 +-
src/lib/dhcp/tests/option6_int_unittest.cc | 3 +-
src/lib/dhcp/tests/option_definition_unittest.cc | 6 +-
src/lib/dhcp/tests/option_unittest.cc | 16 +-
src/lib/dhcp/tests/pkt4_unittest.cc | 22 +-
src/lib/dhcp/tests/pkt6_unittest.cc | 15 +-
src/lib/dhcp/tests/run_unittests.cc | 3 +-
src/lib/{dhcp => dhcpsrv}/Makefile.am | 37 +-
src/lib/{dhcp => dhcpsrv}/addr_utilities.cc | 5 +-
src/lib/{dhcp => dhcpsrv}/addr_utilities.h | 0
src/lib/{dhcp => dhcpsrv}/alloc_engine.cc | 7 +-
src/lib/{dhcp => dhcpsrv}/alloc_engine.h | 9 +-
src/lib/{dhcp => dhcpsrv}/cfgmgr.cc | 2 +-
src/lib/{dhcp => dhcpsrv}/cfgmgr.h | 18 +-
src/lib/{dhcp => dhcpsrv}/database_backends.dox | 0
src/lib/{dhcp => dhcpsrv}/dhcpdb_create.mysql | 0
src/lib/{dhcp => dhcpsrv}/lease_mgr.cc | 2 +-
src/lib/{dhcp => dhcpsrv}/lease_mgr.h | 18 +-
src/lib/{dhcp => dhcpsrv}/lease_mgr_factory.cc | 6 +-
src/lib/{dhcp => dhcpsrv}/lease_mgr_factory.h | 5 +-
src/lib/{dhcp => dhcpsrv}/memfile_lease_mgr.cc | 4 +-
src/lib/{dhcp => dhcpsrv}/memfile_lease_mgr.h | 47 +-
src/lib/{dhcp => dhcpsrv}/mysql_lease_mgr.cc | 7 +-
src/lib/{dhcp => dhcpsrv}/mysql_lease_mgr.h | 31 +-
src/lib/{dhcp => dhcpsrv}/pool.cc | 4 +-
src/lib/{dhcp => dhcpsrv}/pool.h | 4 +-
src/lib/{dhcp => dhcpsrv}/subnet.cc | 5 +-
src/lib/{dhcp => dhcpsrv}/subnet.h | 9 +-
src/lib/{dhcp => dhcpsrv}/tests/Makefile.am | 53 +-
.../tests/addr_utilities_unittest.cc | 10 +-
.../tests/alloc_engine_unittest.cc | 15 +-
src/lib/{dhcp => dhcpsrv}/tests/cfgmgr_unittest.cc | 10 +-
.../tests/lease_mgr_factory_unittest.cc | 10 +-
.../{dhcp => dhcpsrv}/tests/lease_mgr_unittest.cc | 50 +-
.../tests/memfile_lease_mgr_unittest.cc | 31 +-
.../tests/mysql_lease_mgr_unittest.cc | 54 +-
src/lib/{dhcp => dhcpsrv}/tests/pool_unittest.cc | 9 +-
src/lib/{dhcp => dhcpsrv}/tests/run_unittests.cc | 5 +-
src/lib/{dhcp => dhcpsrv}/tests/schema_copy.h | 0
src/lib/{dhcp => dhcpsrv}/tests/subnet_unittest.cc | 7 +-
.../{dhcp => dhcpsrv}/tests/triplet_unittest.cc | 9 +-
src/lib/{dhcp => dhcpsrv}/triplet.h | 0
tests/lettuce/configurations/auth/.gitignore | 1 +
.../auth_badzone.config.orig} | 5 +-
tests/lettuce/data/example.com-broken | 11 +
tests/lettuce/data/example.net-empty | 1 +
tests/lettuce/features/auth_badzone.feature | 49 +
tests/lettuce/features/terrain/terrain.py | 2 +
tests/tools/perfdhcp/templates/Makefile.am | 2 -
138 files changed, 2319 insertions(+), 1118 deletions(-)
create mode 100644 src/bin/auth/tests/query_inmemory_unittest.cc
create mode 100644 src/bin/auth/tests/testdata/example.zone
copy src/lib/{python/isc/datasrc/configurableclientlist_python.h => datasrc/exceptions.h} (54%)
create mode 100644 src/lib/datasrc/tests/testdata/example.edu-broken
create mode 100644 src/lib/datasrc/tests/testdata/example.net-empty
copy src/lib/{dhcp => dhcpsrv}/Makefile.am (52%)
rename src/lib/{dhcp => dhcpsrv}/addr_utilities.cc (99%)
rename src/lib/{dhcp => dhcpsrv}/addr_utilities.h (100%)
rename src/lib/{dhcp => dhcpsrv}/alloc_engine.cc (99%)
rename src/lib/{dhcp => dhcpsrv}/alloc_engine.h (99%)
rename src/lib/{dhcp => dhcpsrv}/cfgmgr.cc (99%)
rename src/lib/{dhcp => dhcpsrv}/cfgmgr.h (99%)
rename src/lib/{dhcp => dhcpsrv}/database_backends.dox (100%)
rename src/lib/{dhcp => dhcpsrv}/dhcpdb_create.mysql (100%)
rename src/lib/{dhcp => dhcpsrv}/lease_mgr.cc (99%)
rename src/lib/{dhcp => dhcpsrv}/lease_mgr.h (97%)
rename src/lib/{dhcp => dhcpsrv}/lease_mgr_factory.cc (96%)
rename src/lib/{dhcp => dhcpsrv}/lease_mgr_factory.h (99%)
rename src/lib/{dhcp => dhcpsrv}/memfile_lease_mgr.cc (99%)
rename src/lib/{dhcp => dhcpsrv}/memfile_lease_mgr.h (87%)
rename src/lib/{dhcp => dhcpsrv}/mysql_lease_mgr.cc (99%)
rename src/lib/{dhcp => dhcpsrv}/mysql_lease_mgr.h (97%)
rename src/lib/{dhcp => dhcpsrv}/pool.cc (98%)
rename src/lib/{dhcp => dhcpsrv}/pool.h (99%)
rename src/lib/{dhcp => dhcpsrv}/subnet.cc (99%)
rename src/lib/{dhcp => dhcpsrv}/subnet.h (99%)
copy src/lib/{dhcp => dhcpsrv}/tests/Makefile.am (55%)
rename src/lib/{dhcp => dhcpsrv}/tests/addr_utilities_unittest.cc (98%)
rename src/lib/{dhcp => dhcpsrv}/tests/alloc_engine_unittest.cc (98%)
rename src/lib/{dhcp => dhcpsrv}/tests/cfgmgr_unittest.cc (99%)
rename src/lib/{dhcp => dhcpsrv}/tests/lease_mgr_factory_unittest.cc (97%)
rename src/lib/{dhcp => dhcpsrv}/tests/lease_mgr_unittest.cc (88%)
rename src/lib/{dhcp => dhcpsrv}/tests/memfile_lease_mgr_unittest.cc (87%)
rename src/lib/{dhcp => dhcpsrv}/tests/mysql_lease_mgr_unittest.cc (95%)
rename src/lib/{dhcp => dhcpsrv}/tests/pool_unittest.cc (99%)
copy src/lib/{dhcp => dhcpsrv}/tests/run_unittests.cc (93%)
rename src/lib/{dhcp => dhcpsrv}/tests/schema_copy.h (100%)
rename src/lib/{dhcp => dhcpsrv}/tests/subnet_unittest.cc (99%)
rename src/lib/{dhcp => dhcpsrv}/tests/triplet_unittest.cc (98%)
rename src/lib/{dhcp => dhcpsrv}/triplet.h (100%)
copy tests/lettuce/configurations/{example.org.inmem.config => auth/auth_badzone.config.orig} (73%)
create mode 100644 tests/lettuce/data/example.com-broken
create mode 100644 tests/lettuce/data/example.net-empty
create mode 100644 tests/lettuce/features/auth_badzone.feature
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 631c33c..2c485b4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+508. [bug] stephen
+ Split the DHCP library into two directories, each with its own
+ Makefile. This properly solves the problem whereby a "make"
+ operation with multiple threads could fail because of the
+ dependencies between two libraries in the same directory.
+ (Trac #2475, git 834fa9e8f5097c6fd06845620f68547a97da8ff8)
+
+bind10-devel-20121115 released on November 15, 2012
+
+507. [doc] jelte
+ Added a chapter about the use of the bindctl command tool to
+ to the BIND 10 guide.
+ (Trac #2305, git c4b0294b5bf4a9d32fb18ab62ca572f492788d72)
+
+506. [security] jinmei
+ Fixed a use-after-free case in handling DNAME record with the
+ in-memory data source. This could lead to a crash of b10-auth
+ if it serves a zone containing a DNAME RR from the in-memory
+ data source. This bug was introduced at bind10-devel-20120927.
+ (Trac #2471, git 2b1793ac78f972ddb1ae2fd092a7f539902223ff)
+
505. [bug] jelte
Fixed a bug in b10-xfrin where a wrong call was made during the
final check of a TSIG-signed transfer, incorrectly rejecting the
@@ -6,13 +27,15 @@
504. [bug]* naokikambe
Fixed an XML format viewed from b10-stats-httpd. Regarding
- per-zone counters as zones of Xfrout, a part of the item values wasn't
- an exact XML format. A zone name can be specified in URI as
- /bind10/statistics/xml/Xfrout/zones/example.org/xfrreqdone. XSD and XSL
- formats are also changed to constant ones due to these changes.
+ per-zone counters as zones of Xfrout, a part of the item
+ values wasn't an exact XML format. A zone name can be
+ specified in URI as
+ /bind10/statistics/xml/Xfrout/zones/example.org/xfrreqdone.
+ XSD and XSL formats are also changed to constant ones due
+ to these changes.
(Trac #2298, git 512d2d46f3cb431bcdbf8d90af27bff8874ba075)
-503. [func] Stephen
+503. [func] Stephen
Add initial version of a MySQL backend for the DHCP code. This
implements the basic IPv6 lease access functions - add lease, delete
lease and update lease. The backend is enabled by specifying
@@ -21,12 +44,12 @@
be built on systems without MySQL installed.
(Trac #2342, git c7defffb89bd0f3fdd7ad2437c78950bcb86ad37)
-502. [func] vorner
+502. [func] vorner
TTLs can be specified with units as well as number of seconds now.
This allows specifications like "1D3H".
(Trac #2384, git 44c321c37e17347f33ced9d0868af0c891ff422b)
-501. [func] tomek
+501. [func] tomek
Added DHCPv6 allocation engine, now used in the processing of DHCPv6
messages.
(Trac #2414, git b3526430f02aa3dc3273612524d23137b8f1fe87)
@@ -51,8 +74,9 @@
Implemented DHCPv6 option values configuration using configuration
manager. In order to set values for data fields carried by the
particular option, user specifies the string of hexadecimal digits
- that is in turn converted to binary data and stored into option buffer.
- More user friendly way of option content specification is planned.
+ that is in turn converted to binary data and stored into option
+ buffer. More user friendly way of option content specification is
+ planned.
(Trac #2318, git e75c686cd9c14f4d6c2a242a0a0853314704fee9)
497. [bug] jinmei
diff --git a/README b/README
index 4ef941e..e9d052c 100644
--- a/README
+++ b/README
@@ -1,16 +1,11 @@
-This is the source for the development version of BIND 10.
+This is the source for the BIND 10 suite.
BIND is the popular implementation of a DNS server, developer
interfaces, and DNS tools. BIND 10 is a rewrite of BIND 9 and ISC
DHCP. BIND 10 is written in C++ and Python and provides a modular
environment for serving, maintaining, and developing DNS and DHCP.
-BIND10-devel is new development leading up to the production
-BIND 10 release. It contains prototype code and experimental
-interfaces. Nevertheless it is ready to use now for testing the
-new BIND 10 infrastructure ideas.
-
This release includes the bind10 master process, b10-msgq message
bus, b10-auth authoritative DNS server (with SQLite3 and in-memory
backends), b10-resolver recursive or forwarding DNS server, b10-cmdctl
@@ -62,3 +57,6 @@ For operating system specific tips see the wiki at:
http://bind10.isc.org/wiki/SystemSpecificNotes
Please see the wiki and the doc/ directory for various documentation.
+
+The BIND 10 suite is started by running "bind10". Note that the
+default configuration does not run any DNS or DHCP servers.
diff --git a/configure.ac b/configure.ac
index 95f95c6..b0ca18a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1264,6 +1264,8 @@ AC_CONFIG_FILES([Makefile
src/lib/dns/benchmarks/Makefile
src/lib/dhcp/Makefile
src/lib/dhcp/tests/Makefile
+ src/lib/dhcpsrv/Makefile
+ src/lib/dhcpsrv/tests/Makefile
src/lib/exceptions/Makefile
src/lib/exceptions/tests/Makefile
src/lib/datasrc/Makefile
diff --git a/doc/guide/bind10-guide.xml b/doc/guide/bind10-guide.xml
index 6065616..d585b63 100644
--- a/doc/guide/bind10-guide.xml
+++ b/doc/guide/bind10-guide.xml
@@ -84,8 +84,7 @@
</para>
<para>
- This guide covers the experimental prototype of
- BIND 10 version &__VERSION__;.
+ This guide covers BIND 10 version &__VERSION__;.
</para>
<section>
@@ -168,8 +167,8 @@
However, these processes are started, stopped, and maintained
by a single command, <command>bind10</command>.
This command starts a master process which will start other
- processes as needed.
- The processes started by the <command>bind10</command>
+ required processes and other processes when configured.
+ The processes that may be started by the <command>bind10</command>
command have names starting with "b10-", including:
</para>
@@ -285,8 +284,7 @@
</para>
<para>
- These are ran by <command>bind10</command>
- and do not need to be manually started independently.
+ These do not need to be manually started independently.
</para>
</section>
@@ -367,6 +365,105 @@ var/
</chapter>
+ <chapter id="quickstart">
+ <title>Quick start</title>
+
+ <para>
+ This quickly covers the standard steps for installing
+ and deploying BIND 10.
+ For further details, full customizations, and troubleshooting,
+ see the respective chapters in the BIND 10 guide.
+ </para>
+
+ <section id="quick-start-auth-dns">
+ <title>Quick start guide for authoritative DNS service</title>
+
+ <orderedlist>
+
+ <listitem>
+ <simpara>
+ Install required run-time and build dependencies.
+ </simpara>
+ </listitem>
+
+ <listitem>
+ <simpara>
+ Download the BIND 10 source tar file from
+ <ulink url="ftp://ftp.isc.org/isc/bind10/"/>.
+ </simpara>
+ </listitem>
+
+ <listitem>
+ <para>Extract the tar file:
+ <screen>$ <userinput>gzcat bind10-<replaceable>VERSION</replaceable>.tar.gz | tar -xvf -</userinput></screen>
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Go into the source and run configure:
+ <screen>$ <userinput>cd bind10-<replaceable>VERSION</replaceable></userinput>
+ $ <userinput>./configure</userinput></screen>
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Build it:
+ <screen>$ <userinput>make</userinput></screen>
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Install it as root (to default /usr/local):
+ <screen>$ <userinput>make install</userinput></screen>
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Start the server (as root):
+ <screen>$ <userinput>/usr/local/sbin/bind10</userinput></screen>
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>In another console, enable the authoritative DNS service
+ (by using the <command>bindctl</command> utility to configure
+ the <command>b10-auth</command> component to run):
+ <screen>$ <userinput>bindctl</userinput></screen>
+ (Login with the provided default username and password.)
+ <screen>
+> <userinput>config add Boss/components b10-auth</userinput>
+> <userinput>config set Boss/components/b10-auth/special auth</userinput>
+> <userinput>config set Boss/components/b10-auth/kind needed</userinput>
+> <userinput>config commit</userinput>
+> <userinput>quit</userinput>
+ </screen>
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Test it; for example:
+ <screen>$ <userinput>dig @127.0.0.1 -c CH -t TXT version.bind</userinput></screen>
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>Load desired zone file(s), for example:
+ <screen>$ <userinput>b10-loadzone <replaceable>your.zone.example.org</replaceable></userinput></screen>
+ </para>
+ </listitem>
+
+ <listitem>
+ <simpara>
+ Test the new zone.
+ </simpara>
+ </listitem>
+
+ </orderedlist>
+
+ </section>
+
+ </chapter>
+
<chapter id="installation">
<title>Installation</title>
@@ -514,90 +611,6 @@ as a dependency earlier -->
</section>
- <section id="quickstart">
- <title>Quick start</title>
- <note>
- <simpara>
- This quickly covers the standard steps for installing
- and deploying BIND 10 as an authoritative name server using
- its defaults. For troubleshooting, full customizations and further
- details, see the respective chapters in the BIND 10 guide.
- </simpara>
- </note>
-
- <para>
- To quickly get started with BIND 10, follow these steps.
- </para>
-
- <orderedlist>
-
- <listitem>
- <simpara>
- Install required run-time and build dependencies.
- </simpara>
- </listitem>
-
- <listitem>
- <simpara>
- Download the BIND 10 source tar file from
- <ulink url="ftp://ftp.isc.org/isc/bind10/"/>.
- </simpara>
- </listitem>
-
- <listitem>
- <para>Extract the tar file:
- <screen>$ <userinput>gzcat bind10-<replaceable>VERSION</replaceable>.tar.gz | tar -xvf -</userinput></screen>
- </para>
- </listitem>
-
- <listitem>
- <para>Go into the source and run configure:
- <screen>$ <userinput>cd bind10-<replaceable>VERSION</replaceable></userinput>
- $ <userinput>./configure</userinput></screen>
- </para>
- </listitem>
-
- <listitem>
- <para>Build it:
- <screen>$ <userinput>make</userinput></screen>
- </para>
- </listitem>
-
- <listitem>
- <para>Install it (to default /usr/local):
- <screen>$ <userinput>make install</userinput></screen>
- </para>
- </listitem>
-
- <listitem>
- <para>Start the server:
- <screen>$ <userinput>/usr/local/sbin/bind10</userinput></screen>
- </para>
- </listitem>
-
- <listitem>
-<!-- TODO: this is wrong; b10-auth is not started by default any more -->
- <para>Test it; for example:
- <screen>$ <userinput>dig @127.0.0.1 -c CH -t TXT authors.bind</userinput></screen>
- </para>
- </listitem>
-
- <listitem>
- <para>Load desired zone file(s), for example:
- <screen>$ <userinput>b10-loadzone <replaceable>your.zone.example.org</replaceable></userinput></screen>
- </para>
- </listitem>
-
- <listitem>
- <simpara>
- Test the new zone.
- </simpara>
- </listitem>
-
- </orderedlist>
-
- </section>
-
<section id="install">
<title>Installation from source</title>
<para>
@@ -674,7 +687,7 @@ as a dependency earlier -->
</section>
- <section>
+ <section id="configure">
<title>Configure before the build</title>
<para>
BIND 10 uses the GNU Build System to discover build environment
@@ -744,7 +757,10 @@ as a dependency earlier -->
If the configure fails, it may be due to missing or old
dependencies.
</para>
-
+
+ <note>
+ <para>For notes on configuring and building DHCPv6 with MySQL see <xref linkend="dhcp6-install">.</xref></para>
+ </note>
</section>
<section>
@@ -820,16 +836,26 @@ as a dependency earlier -->
<command>b10-cmdctl</command> for administration tools to
communicate with the system, and
<command>b10-stats</command> for statistics collection.
+ The DNS and DHCP servers are not started by default.
+ The configuration of components to start is covered in
+ <xref linkend="bind10.components"/>.
</para>
<section id="start">
<title>Starting BIND 10</title>
<para>
- To start the BIND 10 service, simply run <command>bind10</command>.
+ To start the BIND 10 service, simply run <command>bind10</command>
+ as root.
+ It will run in the foreground and your shell prompt will not
+ be available. It will output various log messages as it starts up
+ and is used.
Run it with the <option>--verbose</option> switch to
get additional debugging or diagnostic output.
</para>
-<!-- TODO: note it doesn't go into background -->
+
+<!-- TODO: user switch -->
+
+<!-- TODO: example: nohup /usr/local/sbin/bind10 1>bind10.log 2>&1 -->
<note>
<para>
@@ -841,156 +867,6 @@ as a dependency earlier -->
</note>
</section>
- <section id="bind10.config">
- <title>Configuration to start processes</title>
-
- <para>
- The processes to be used can be configured for
- <command>bind10</command> to start, with the exception
- of the required <command>b10-sockcreator</command>,
- <command>b10-msgq</command> and <command>b10-cfgmgr</command>
- components.
- The configuration is in the <varname>Boss/components</varname>
- section. Each element represents one component, which is
- an abstraction of a process.
- </para>
-
- <para>
- To add a process to the set, let's say the resolver (which
- is not started by default), you would do this:
- <screen>> <userinput>config add Boss/components b10-resolver</userinput>
-> <userinput>config set Boss/components/b10-resolver/special resolver</userinput>
-> <userinput>config set Boss/components/b10-resolver/kind needed</userinput>
-> <userinput>config set Boss/components/b10-resolver/priority 10</userinput>
-> <userinput>config commit</userinput></screen></para>
-
- <para>
- Now, what it means. We add an entry called
- <quote>b10-resolver</quote>. It is both a name used to
- reference this component in the configuration and the name
- of the process to start. Then we set some parameters on
- how to start it.
- </para>
-
- <para>
- The <varname>special</varname> setting is for components
- that need some kind of special care during startup or
- shutdown. Unless specified, the component is started in a
- usual way. This is the list of components that need to be
- started in a special way, with the value of special used
- for them:
-<!-- TODO: this still doesn't explain why they are special -->
- <table>
- <title>Special startup components</title>
- <tgroup cols='3' align='left'>
- <colspec colname='component'/>
- <colspec colname='special'/>
- <colspec colname='description'/>
- <thead><row><entry>Component</entry><entry>Special</entry><entry>Description</entry></row></thead>
- <tbody>
- <row><entry>b10-auth</entry><entry>auth</entry><entry>Authoritative DNS server</entry></row>
- <row><entry>b10-resolver</entry><entry>resolver</entry><entry>DNS resolver</entry></row>
- <row><entry>b10-cmdctl</entry><entry>cmdctl</entry><entry>Command control (remote control interface)</entry></row>
- <!-- TODO Either add xfrin and xfrout as well or clean up the workarounds in boss before the release -->
- </tbody>
- </tgroup>
- </table>
- </para>
-
- <para>
- The <varname>kind</varname> specifies how a failure of the
- component should be handled. If it is set to
- <quote>dispensable</quote> (the default unless you set
- something else), it will get started again if it fails. If
- it is set to <quote>needed</quote> and it fails at startup,
- the whole <command>bind10</command> shuts down and exits
- with an error exit code. But if it fails some time later, it
- is just started again. If you set it to <quote>core</quote>,
- you indicate that the system is not usable without the
- component and if such component fails, the system shuts
- down no matter when the failure happened. This is the
- behaviour of the core components (the ones you can't turn
- off), but you can declare any other components as core as
- well if you wish (but you can turn these off, they just
- can't fail).
- </para>
-
- <para>
- The <varname>priority</varname> defines order in which the
- components should start. The ones with higher numbers are
- started sooner than the ones with lower ones. If you don't
- set it, 0 (zero) is used as the priority. Usually, leaving
- it at the default is enough.
- </para>
-
- <para>
- There are other parameters we didn't use in our example.
- One of them is <varname>address</varname>. It is the address
- used by the component on the <command>b10-msgq</command>
- message bus. The special components already know their
- address, but the usual ones don't. The address is by
- convention the thing after <emphasis>b10-</emphasis>, with
- the first letter capitalized (eg. <command>b10-stats</command>
- would have <quote>Stats</quote> as its address).
-<!-- TODO: this should be simplified so we don't even have to document it -->
- </para>
-
-<!-- TODO: what does "The special components already know their
-address, but the usual ones don't." mean? -->
-
-<!-- TODO: document params when is enabled -->
-
- <para>
- The last one is <varname>process</varname>. It is the name
- of the process to be started. It defaults to the name of
- the component if not set, but you can use this to override
- it. (The special components also already know their
- executable name.)
- </para>
-
- <!-- TODO Add parameters when they work, not implemented yet-->
-
- <note>
- <para>
- The configuration is quite powerful, but that includes
- a lot of space for mistakes. You could turn off the
- <command>b10-cmdctl</command>, but then you couldn't
- change it back the usual way, as it would require it to
- be running (you would have to find and edit the configuration
- directly). Also, some modules might have dependencies:
- <command>b10-stats-httpd</command> needs
- <command>b10-stats</command>, <command>b10-xfrout</command>
- needs <command>b10-auth</command> to be running, etc.
-
-<!-- TODO: should we define dependencies? -->
-
- </para>
- <para>
- In short, you should think twice before disabling something here.
- </para>
- </note>
- <para>
- It is possible to start some components multiple times (currently
- <command>b10-auth</command> and <command>b10-resolver</command>).
- You might want to do that to gain more performance (each one uses only
- single core). Just put multiple entries under different names, like
- this, with the same config:
- <screen>> <userinput>config add Boss/components b10-resolver-2</userinput>
-> <userinput>config set Boss/components/b10-resolver-2/special resolver</userinput>
-> <userinput>config set Boss/components/b10-resolver-2/kind needed</userinput>
-> <userinput>config commit</userinput></screen>
- </para>
- <para>
- However, this is work in progress and the support is not yet complete.
- For example, each resolver will have its own cache, each authoritative
- server will keep its own copy of in-memory data and there could be
- problems with locking the sqlite database, if used. The configuration
- might be changed to something more convenient in future.
- Other components don't expect such a situation, so it would
- probably not do what you want. Such support is yet to be
- implemented.
- </para>
- </section>
</chapter>
@@ -1046,7 +922,7 @@ address, but the usual ones don't." mean? -->
<!-- TODO -->
<note>
<para>
- The development prototype release only provides
+ The current release only provides
<command>bindctl</command> as a user interface to
<command>b10-cmdctl</command>.
Upcoming releases will provide another interactive command-line
@@ -1268,13 +1144,21 @@ TODO
<title>Control and configure user interface</title>
<note><para>
- For this development prototype release, <command>bindctl</command>
+ For the current release, <command>bindctl</command>
is the only user interface. It is expected that upcoming
releases will provide another interactive command-line
interface and a web-based interface for controlling and
configuring BIND 10.
</para></note>
+ <note><para>
+ <command>bindctl</command> has an internal command history, as
+ well as tab-completion for most of the commands and arguments.
+ However, these are only enabled if the python readline module
+ is available on the system. If not, neither of these
+ features will be supported.
+ </para></note>
+
<para>
The <command>bindctl</command> tool provides an interactive
prompt for configuring, controlling, and querying the BIND 10
@@ -1284,22 +1168,590 @@ TODO
communicate to any other components directly.
</para>
-<!-- TODO: explain and show interface -->
+ <section id="bindctl_commandline_options">
+ <title>bindctl command-line options</title>
+ <variablelist>
+ <varlistentry>
+ <term>-a <replaceable><address></replaceable>, --address=<replaceable><address></replaceable></term>
+ <listitem>
+ <simpara>
+ IP address that BIND 10's <command>b10-cmdctl</command>
+ module is listening on. By default, this is 127.0.0.1.
+ </simpara>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>-c <replaceable><certificate file></replaceable>, --certificate-chain=<replaceable><certificate file></replaceable></term>
+ <listitem>
+ <simpara>
+ PEM-formatted server certificate file. When this option is
+ given, <command>bindctl</command> will verify the server
+ certificate using the given file as the root of the
+ certificate chain. If not specified, <command>bindctl
+ </command> does not validate the certificate.
+ </simpara>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>--csv-file-dir=<replaceable><csv file></replaceable></term>
+ <listitem>
+ <simpara>
+ <command>bindctl</command> stores the username and
+ password for logging in in a file called
+ <filename>default_user.csv</filename>;
+ this option specifies the directory where this file is
+ stored and read from. When not specified,
+ <filename>~/.bind10/</filename> is used.
+ <note>Currently, this file contains an unencrypted password.</note>
+ </simpara>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>-h, --help</term>
+ <listitem>
+ <simpara>
+ Shows a short overview of the command-line options of
+ <command>bindctl</command>, and exits.
+ </simpara>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>--version</term>
+ <listitem>
+ <simpara>
+ Shows the version of <command>bindctl</command>, and exits.
+ </simpara>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>-p <replaceable><port number></replaceable>, --port=<replaceable><port number></replaceable></term>
+ <listitem>
+ <simpara>
+ Port number that BIND 10's <command>b10-cmdctl</command>
+ module is listening on. By default, this is port 8080.
+ </simpara>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
- <para>
- Configuration changes are actually commands to
- <command>b10-cfgmgr</command>. So when <command>bindctl</command>
- sends a configuration, it is sent to <command>b10-cmdctl</command>
- (over a HTTPS connection); then <command>b10-cmdctl</command>
- sends the command (over a <command>b10-msgq</command> command
- channel) to <command>b10-cfgmgr</command> which then stores
- the details and relays (over a <command>b10-msgq</command> command
- channel) the configuration on to the specified module.
- </para>
+ <section id="bindctl_general_syntax">
+ <title>General syntax of bindctl commands</title>
+ The <command>bindctl</command> tool is an interactive
+ command-line tool, with dynamic commands depending on the
+ BIND 10 modules that are running. There are a number of
+ fixed commands that have no module and that are always
+ available.
+
+ The general syntax of a command is
+
+ <screen><userinput><module> <command> <replaceable>[argument(s)]</replaceable></userinput></screen>
+
+ For example, the Boss module has a 'shutdown' command to shut down
+ BIND 10, with an optional argument 'help':
+
+ <screen>> <userinput>Boss shutdown help</userinput>
+Command shutdown (Shut down BIND 10)
+ help (Get help for command)
+This command has no parameters
+ </screen>
+ There are no mandatory arguments, only the optional 'help'.
+ </section>
+
+ <section id="bindctl_help">
+ <title>Bindctl help</title>
+ <command>help</command> is both a command and an option that is available to all other commands. When run as a command directly, it shows the available modules.
+ <screen>> <userinput>help</userinput>
+usage: <module name> <command name> [param1 = value1 [, param2 = value2]]
+Type Tab character to get the hint of module/command/parameters.
+Type "help(? h)" for help on bindctl.
+Type "<module_name> help" for help on the specific module.
+Type "<module_name> <command_name> help" for help on the specific command.
+
+Available module names:
+<emphasis>(list of modules)</emphasis>
+ </screen>
+
+ When 'help' is used as a command to a module, it shows the supported commands for the module; for example:
+ <screen>> <userinput>Boss help</userinput>
+Module Boss Master process
+Available commands:
+ help Get help for module.
+ shutdown Shut down BIND 10
+ ping Ping the boss process
+ show_processes
+ List the running BIND 10 processes
+ </screen>
+
+ And when added to a module command, it shows the description and parameters of that specific command; for example:
+ <screen>> <userinput>Auth loadzone help</userinput>
+Command loadzone ((Re)load a specified zone)
+ help (Get help for command)
+Parameters:
+ class (string, optional)
+ origin (string, mandatory)
+ </screen>
+
+ </section>
+
+ <section id="bindctl_command_arguments">
+ <title>Command arguments</title>
+ <simpara>
+ Commands can have arguments, which can be either optional or
+ mandatory. They can be specified by name
+ (e.g. <command><replaceable><command></replaceable> <replaceable><argument name>=<argument value></replaceable></command>), or positionally,
+ (e.g. <command><replaceable><command></replaceable> <replaceable><argument value 1></replaceable> <replaceable><argument value 2></replaceable></command>).
+ </simpara>
+ <simpara>
+ <command><replaceable><command></replaceable> <replaceable>help</replaceable></command>
+ shows the arguments a command supports and which of those are
+ mandatory, and in which order the arguments are expected if
+ positional arguments are used.
+ </simpara>
+ <simpara>
+ For example, the <command>loadzone</command> command of the Auth
+ module, as shown in the last example of the previous section, has
+ two arguments, one of which is optional. The positional arguments in
+ this case are class first and origin second; for example:
+ <screen>> <userinput>Auth loadzone IN example.com.</userinput></screen>
+ But since the class is optional (defaulting to IN), leaving it out
+ works as well:
+ <screen>> <userinput>Auth loadzone example.com.</userinput></screen>
+ </simpara>
+ <simpara>
+ The arguments can also be provided with their names, in which
+ case the order does not matter:
+ <screen>> <userinput>Auth loadzone origin="example.com." class="IN"</userinput></screen>
+ </simpara>
+ </section>
+
+ <section id="bindctl_module_commands">
+ <title>Module commands</title>
+ Each module has its own set of commands (if any), which will only be
+ available if the module is running. For instance, the
+ Auth module has a <command>loadzone</command> command.
+ The commands a module provides are documented in
+ this guide in the section of that module or in the module's
+ corresponding manual page.
+ </section>
+
+ <section>
+ <title>Configuration commands</title>
+ Configuration commands are used to view and change the configuration
+ of BIND 10 and its modules. Module configuration is only shown if
+ that module is running, but similar to commands, there are a number
+ of top-level configuration items that are always available (for
+ instance <varname>tsig_keys</varname> and
+ <varname>data_sources</varname>).
+
+ Configuration changes (set, unset, add and remove) are done locally
+ first, and have no immediate effect. The changes can be viewed with
+ <command>config diff</command>, and either reverted
+ (<command>config revert</command>), or committed
+ (<command>config commit</command>).
+ In the latter case, all local changes are submitted
+ to the configuration manager, which verifies them, and if they are
+ accepted, applied and saved in persistent storage.
+
+ When identifying items in configuration commands, the format is
+ <screen><userinput>Module/example/item</userinput></screen>
+ Sub-elements of names, lists and sets (see <xref linkend=
+ "bindctl_configuration_data_types"/>) are separated with the '/'
+ character, and list indices are identified with [<replaceable><index></replaceable>]; for example:
+
+ <screen><userinput>Module/example/list[2]/foo</userinput></screen>
+
+ <section id="bindctl_configuration_command_list">
+ <title>List of configuration commands</title>
+ The following configuration commands are available:
+ <variablelist>
+ <varlistentry>
+ <term>show [all] [item name]</term>
+ <listitem>
+ <simpara>
+ Shows the current configuration of the given item. If 'all'
+ is given, it will recurse through the entire set, and show
+ every nested value.
+ </simpara>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>show_json [item name]</term>
+ <listitem>
+ <simpara>
+ Shows the full configuration of the given item in JSON format.
+ </simpara>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>add <item name> [value]</term>
+ <listitem>
+ <simpara>
+ Add an entry to configuration list or a named set (see <xref
+ linkend="bindctl_configuration_data_types"/>).
+ When adding to a list, the command has one optional
+ argument, a value to add to the list. The value must
+ be in correct JSON and complete. When adding to a
+ named set, it has one mandatory parameter (the name to
+ add), and an optional parameter value, similar to when
+ adding to a list. In either case, when no value is
+ given, an entry will be constructed with default
+ values.
+ </simpara>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>remove</term>
+ <listitem>
+ <simpara>
+ Remove an item from a configuration list or a named set.
+ When removing an item for a list, either the index needs to
+ be specified, or the complete value of the element to remove
+ must be specified (in JSON format).
+ </simpara>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>set <item name> <value></term>
+ <listitem>
+ <simpara>
+ Directly set the value of the given item to the given value.
+ </simpara>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>unset <item name></term>
+ <listitem>
+ <simpara>
+ Remove any user-specified value for the given item.
+ </simpara>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>diff</term>
+ <listitem>
+ <simpara>
+ Show all current local changes that have not been
+ committed yet.
+ </simpara>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>revert</term>
+ <listitem>
+ <simpara>
+ Revert all local changes without committing them.
+ </simpara>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>commit</term>
+ <listitem>
+ <simpara>
+ Send all local changes to the configuration manager, which
+ will validate them, and apply them if validation succeeds.
+ </simpara>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>go</term>
+ <listitem>
+ <simpara>
+ Go to a specific configuration part, similar to the 'cd'
+ command in a shell.
+ <note>There are a number of problems with the current
+ implementation of go within <command>bindctl</command>,
+ and we recommend not using it for general cases.</note>
+ </simpara>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
- <para>
- </para>
+ <section id="bindctl_configuration_data_types">
+ <title>Configuration data types</title>
+ Configuration data can be of different types, which can be modified
+ in ways that depend on the types. There are a few syntax
+ restrictions on these types, but only basic ones. Modules may impose
+ additional restrictions on the values of elements.
+ <variablelist>
+ <varlistentry>
+ <term>integer</term>
+ <listitem>
+ <simpara>
+ A basic integer; can be set directly with <command>config set</command>, to any integer value.
+ </simpara>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>real</term>
+ <listitem>
+ <simpara>
+ A basic floating point number; can be set directly with <command>config set</command>, to any floating point value.
+ </simpara>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>boolean</term>
+ <listitem>
+ <simpara>
+ A basic boolean value; can be set directly with <command>config set</command>, to either <command>true</command> or <command>false</command>.
+ </simpara>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>string</term>
+ <listitem>
+ <simpara>
+ A basic string value; can be set directly with <command>config set,</command> so any string. Double quotation marks are optional.
+ </simpara>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>null</term>
+ <listitem>
+ <simpara>
+ This is a special type representing 'no value at all'; usable in compound structures that have optional elements that are not set.
+ </simpara>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>maps</term>
+ <listitem>
+ <simpara>
+ Maps are (pre-defined) compound collections of other
+ elements of any other type. They are not usually
+ modified directly, but their elements are. Every
+ top-level element for a module is a map containing
+ the configuration values for that map, which can
+ themselves be maps again. For instance, the Auth
+ module configuration is a map containing the
+ elements '<varname>listen_on</varname>' (list) and '<varname>tcp_recv_timeout</varname>'
+ (integer). When changing one of its values, they can
+ be modified directly with <command>config set
+ Auth/tcp_recv_timeout 3000</command>.
+ </simpara>
+ <simpara>
+ Some map entries are optional. If they are, and
+ currently have a value, the value can be unset by
+ using either <command>config unset
+ <replaceable><item name></replaceable>
+ </command> or <command>config set
+ <replaceable><item name></replaceable>
+ null</command>.
+
+ </simpara>
+ <simpara>
+ Maps <emphasis>can</emphasis> be modified as a whole,
+ but using the full JSON representation of
+ the entire map to set.
+
+ Since this involves a lot of text, this is usually
+ not recommended.
+ </simpara>
+ <simpara>
+ Another example is the Logging virtual module, which
+ is, like any module, a map, but it only contains one
+ element: a list of loggers. Normally, an
+ administrator would only modify that list (or its
+ elements) directly, but it is possible to set the
+ entire map in one command; for example:
+ <command> config set Logging { "loggers": [] } </command>
+ </simpara>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>list</term>
+ <listitem>
+ <simpara>
+ A list is a compound list of other elements of the
+ same type. Elements can be added with <command>config
+ add <replaceable><list name> [value]</replaceable></command>, and removed with
+ <command>config remove <replaceable><list name> [value]</replaceable></command> or
+ <command>config remove <replaceable><list name></replaceable><replaceable><index></replaceable></command>.
+ The index is of the form <emphasis>square bracket, number,
+ square bracket</emphasis> (e.g.
+ <command>[0]</command>), and it immediately follows
+ the list name (there is no separator or space
+ between them). List indices start with 0 for the
+ first element.
+ </simpara>
+ <simpara>
+ For addition, if the value is omitted, an entry with
+ default values will be added. For removal, either
+ the index or the full value (in JSON format) needs
+ to be specified.
+ </simpara>
+ <simpara>
+ Lists can also be used with
+ <command>config set</command>,
+ but like maps, only by specifying the
+ entire list value in JSON format.
+ </simpara>
+ <simpara>
+ For example, this command shows the port number used for the second element of the list <varname>listen_on</varname> in the Auth module:
+ <command> config show Auth/listen_on[1]/port</command>
+ </simpara>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>named set</term>
+ <listitem>
+ <simpara>
+ Named sets are similar to lists, in that they are
+ sets of elements of the same type, but they are not
+ indexed by numbers, but by strings.
+ </simpara>
+ <simpara>
+ Values can be added with
+ <command>config add <replaceable><item name> <string> [value]</replaceable></command>
+ where 'string' is the name of the element. If 'value'
+ is ommitted, default values will be used. Elements
+ can be removed with <command>config remove
+ <replaceable><item
+ name> <string></replaceable></command>
+ </simpara>
+ <simpara>
+ Elements in a named set can be addressed similarly
+ to maps.
+ </simpara>
+ <simpara>
+ For example, the <command>Boss/components</command>
+ elements is a named set;
+ adding, showing, and then removing an element
+ can be done with the following three commands (note
+ the '/'-character versus the space before
+ 'example_module'):
+ </simpara>
+ <simpara>
+ <command>config add Boss/components example_module</command>
+ </simpara>
+ <simpara>
+ <command>config show Boss/components/example_module</command>
+ </simpara>
+ <simpara>
+ <command>config remove Boss/components example_module</command>
+ </simpara>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>any</term>
+ <listitem>
+ <simpara>
+ The 'any' type is a special type that can have any
+ form. Apart from that, it must consist of elements as
+ described in this chapter, there is no restriction
+ on which element types are used. This type is used
+ in places where different data formats could be
+ used. Element modification commands depend on the
+ actual type of the value. For instance, if the value
+ of an 'any' element is a list, <command>config add
+ </command> and <command>config remove</command> work
+ as for other lists.
+ </simpara>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ </section>
+
+ <section>
+ <title>The execute command</title>
+ The <command>execute</command> command executes a set of commands,
+ either from a file
+ or from a pre-defined set. Currently, the only predefined set is
+ <command>init_authoritative_server</command>, which adds
+ <command>b10-auth</command>, <command>b10-xfrin</command>, and
+ <command>b10-xfrout</command> to the set of components to be
+ started by BIND 10. This
+ pre-defined set does not commit the changes, so these modules do not
+ show up for commands or configuration until the user enters
+ <command>config commit</command> after
+ <command>execute init_authoritative_server</command>. For example:
+
+ <screen>> <userinput>execute init_authoritative_server</userinput></screen>
+
+ <screen>> <userinput>execute file /tmp/example_commands</userinput></screen>
+
+ The optional argument <command>show</command> displays the exact set of
+ commands that would be executed; for example:
+
+ <screen>> <userinput>execute init_authoritative_server show</userinput>
+!echo adding Authoritative server component
+config add /Boss/components b10-auth
+config set /Boss/components/b10-auth/kind needed
+config set /Boss/components/b10-auth/special auth
+!echo adding Xfrin component
+config add /Boss/components b10-xfrin
+config set /Boss/components/b10-xfrin/address Xfrin
+config set /Boss/components/b10-xfrin/kind dispensable
+!echo adding Xfrout component
+config add /Boss/components b10-xfrout
+config set /Boss/components/b10-xfrout/address Xfrout
+config set /Boss/components/b10-xfrout/kind dispensable
+!echo adding Zone Manager component
+config add /Boss/components b10-zonemgr
+config set /Boss/components/b10-zonemgr/address Zonemgr
+config set /Boss/components/b10-zonemgr/kind dispensable
+!echo Components added. Please enter "config commit" to
+!echo finalize initial setup and run the components.
+ </screen>
+
+ The optional <command>show</command> argument may also be used when
+ executing a script from a file; for example:
+
+ <screen>> <userinput>execute file /tmp/example_commands show</userinput></screen>
+
+ <section id="bindctl_execute_directives">
+ <title>Execute directives</title>
+ Within sets of commands to be run with the <command>execute</command>
+ command, a number of directives are supported:
+ <variablelist>
+ <varlistentry>
+ <term>!echo <replaceable><string></replaceable></term>
+ <listitem>
+ <simpara>
+ Prints the given string to <command>bindctl</command>'s
+ output.
+ </simpara>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>!verbose on</term>
+ <listitem>
+ <simpara>
+ Enables verbose mode; all following commands that are to
+ be executed are also printed.
+ </simpara>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>!verbose off</term>
+ <listitem>
+ <simpara>
+ Disables verbose mode; following commands that are to
+ be executed are no longer printed.
+ </simpara>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section id="bindctl_execute_notes">
+ <title>Notes on execute scripts</title>
+ Within scripts, you can add or remove modules with the normal
+ configuration commands for <command>Boss/components</command>.
+ However, as module
+ configuration and commands do not show up until the module is
+ running, it is currently not possible to add a module and set
+ its configuration in one script. This will be addressed in the
+ future, but for now the only option is to add and configure
+ modules in separate commands and execute scripts.
+ </section>
+ </section>
</chapter>
<chapter id="common">
@@ -1599,6 +2051,185 @@ AND_MATCH := "ALL": [ RULE_RAW, RULE_RAW, ... ]
</section>
</chapter>
+ <chapter id="bind10.config">
+ <title>bind10 Control and Configuration</title>
+
+ <para>
+ This chapter explains how to control and configure the
+ <command>bind10</command> parent.
+ The startup of this resident process that runs the BIND 10
+ daemons is covered in <xref linkend="bind10"/>.
+ </para>
+
+ <section id="bind10.shutdown">
+ <title>Stopping bind10</title>
+ <para>
+ The BIND 10 suite may be shut down by stopping the
+ parent <command>bind10</command> process. This may be done
+ by running the <userinput>Boss shutdown</userinput> command
+ at the <command>bindctl</command> prompt.
+ </para>
+ </section>
+
+ <section id="bind10.components">
+ <title>Configuration to start processes</title>
+
+ <para>
+ The processes to be used can be configured for
+ <command>bind10</command> to start, with the exception
+ of the required <command>b10-sockcreator</command>,
+ <command>b10-msgq</command> and <command>b10-cfgmgr</command>
+ components.
+ The configuration is in the <varname>Boss/components</varname>
+ section. Each element represents one component, which is
+ an abstraction of a process.
+ </para>
+
+ <para>
+ To add a process to the set, let's say the resolver (which
+ is not started by default), you would do this:
+ <screen>> <userinput>config add Boss/components b10-resolver</userinput>
+> <userinput>config set Boss/components/b10-resolver/special resolver</userinput>
+> <userinput>config set Boss/components/b10-resolver/kind needed</userinput>
+> <userinput>config set Boss/components/b10-resolver/priority 10</userinput>
+> <userinput>config commit</userinput></screen></para>
+
+ <para>
+ Now, what it means. We add an entry called
+ <quote>b10-resolver</quote>. It is both a name used to
+ reference this component in the configuration and the name
+ of the process to start. Then we set some parameters on
+ how to start it.
+ </para>
+
+ <para>
+ The <varname>special</varname> setting is for components
+ that need some kind of special care during startup or
+ shutdown. Unless specified, the component is started in a
+ usual way. This is the list of components that need to be
+ started in a special way, with the value of special used
+ for them:
+<!-- TODO: this still doesn't explain why they are special -->
+ <table>
+ <title>Special startup components</title>
+ <tgroup cols='3' align='left'>
+ <colspec colname='component'/>
+ <colspec colname='special'/>
+ <colspec colname='description'/>
+ <thead><row><entry>Component</entry><entry>Special</entry><entry>Description</entry></row></thead>
+ <tbody>
+ <row><entry>b10-auth</entry><entry>auth</entry><entry>Authoritative DNS server</entry></row>
+ <row><entry>b10-resolver</entry><entry>resolver</entry><entry>DNS resolver</entry></row>
+ <row><entry>b10-cmdctl</entry><entry>cmdctl</entry><entry>Command control (remote control interface)</entry></row>
+ <!-- TODO Either add xfrin and xfrout as well or clean up the workarounds in boss before the release -->
+ </tbody>
+ </tgroup>
+ </table>
+ </para>
+
+ <para>
+ The <varname>kind</varname> specifies how a failure of the
+ component should be handled. If it is set to
+ <quote>dispensable</quote> (the default unless you set
+ something else), it will get started again if it fails. If
+ it is set to <quote>needed</quote> and it fails at startup,
+ the whole <command>bind10</command> shuts down and exits
+ with an error exit code. But if it fails some time later, it
+ is just started again. If you set it to <quote>core</quote>,
+ you indicate that the system is not usable without the
+ component and if such component fails, the system shuts
+ down no matter when the failure happened. This is the
+ behaviour of the core components (the ones you can't turn
+ off), but you can declare any other components as core as
+ well if you wish (but you can turn these off, they just
+ can't fail).
+ </para>
+
+ <para>
+ The <varname>priority</varname> defines order in which the
+ components should start. The ones with higher numbers are
+ started sooner than the ones with lower ones. If you don't
+ set it, 0 (zero) is used as the priority. Usually, leaving
+ it at the default is enough.
+ </para>
+
+ <para>
+ There are other parameters we didn't use in our example.
+ One of them is <varname>address</varname>. It is the address
+ used by the component on the <command>b10-msgq</command>
+ message bus. The special components already know their
+ address, but the usual ones don't. The address is by
+ convention the thing after <emphasis>b10-</emphasis>, with
+ the first letter capitalized (eg. <command>b10-stats</command>
+ would have <quote>Stats</quote> as its address).
+<!-- TODO: this should be simplified so we don't even have to document it -->
+ </para>
+
+<!-- TODO: what does "The special components already know their
+address, but the usual ones don't." mean? -->
+
+<!-- TODO: document params when is enabled -->
+
+ <para>
+ The last one is <varname>process</varname>. It is the name
+ of the process to be started. It defaults to the name of
+ the component if not set, but you can use this to override
+ it. (The special components also already know their
+ executable name.)
+ </para>
+
+ <!-- TODO Add parameters when they work, not implemented yet-->
+
+ <note>
+ <para>
+ The configuration is quite powerful, but that includes
+ a lot of space for mistakes. You could turn off the
+ <command>b10-cmdctl</command>, but then you couldn't
+ change it back the usual way, as it would require it to
+ be running (you would have to find and edit the configuration
+ directly). Also, some modules might have dependencies:
+ <command>b10-stats-httpd</command> needs
+ <command>b10-stats</command>, <command>b10-xfrout</command>
+ needs <command>b10-auth</command> to be running, etc.
+
+<!-- TODO: should we define dependencies? -->
+
+ </para>
+ <para>
+ In short, you should think twice before disabling something here.
+ </para>
+ </note>
+ <para>
+ It is possible to start some components multiple times (currently
+ <command>b10-auth</command> and <command>b10-resolver</command>).
+ You might want to do that to gain more performance (each one uses only
+ single core). Just put multiple entries under different names, like
+ this, with the same config:
+ <screen>> <userinput>config add Boss/components b10-resolver-2</userinput>
+> <userinput>config set Boss/components/b10-resolver-2/special resolver</userinput>
+> <userinput>config set Boss/components/b10-resolver-2/kind needed</userinput>
+> <userinput>config commit</userinput></screen>
+ </para>
+ <para>
+ However, this is work in progress and the support is not yet complete.
+ For example, each resolver will have its own cache, each authoritative
+ server will keep its own copy of in-memory data and there could be
+ problems with locking the sqlite database, if used. The configuration
+ might be changed to something more convenient in future.
+ Other components don't expect such a situation, so it would
+ probably not do what you want. Such support is yet to be
+ implemented.
+ </para>
+
+ <para>
+ The running processes started by <command>bind10</command>
+ may be listed by running <userinput>Boss show_processes</userinput>
+ using <command>bindctl</command>.
+ </para>
+
+ </section>
+ </chapter>
+
<chapter id="authserver">
<title>Authoritative Server</title>
@@ -1660,8 +2291,7 @@ can use various data source backends.
By default, this is empty.
<note><simpara>
- In this development version, currently this is only used for the
- memory data source.
+ Currently this is only used for the memory data source.
Only the IN class is supported at this time.
By default, the memory data source is disabled.
Also, currently the zone file must be canonical such as
@@ -1739,7 +2369,7 @@ can use various data source backends.
(it defaults to <quote>memory</quote>).
<note><simpara>
- In this development version, currently this only supports the
+ Currently this only supports the
IN class and the memory data source.
</simpara></note>
</simpara>
@@ -1797,7 +2427,7 @@ can use various data source backends.
</para>
<note><para>
- In the development prototype release, <command>b10-auth</command>
+ In the current release, <command>b10-auth</command>
can serve data from a SQLite3 data source backend and from master
files.
Upcoming versions will be able to use multiple different
@@ -1997,7 +2627,7 @@ can use various data source backends.
<note>
<para>
- In the development prototype release, only the SQLite3 back
+ In the current release, only the SQLite3 back
end is used by <command>b10-loadzone</command>.
By default, it stores the zone data in
<filename>/usr/local/var/bind10-devel/zone.sqlite3</filename>
@@ -2078,8 +2708,8 @@ TODO
<para>
As noted above, <command>b10-xfrin</command> uses AXFR for
zone transfers by default. To enable IXFR for zone transfers
- for a particular zone, set the <userinput>use_ixfr</userinput>
- configuration parameter to <userinput>true</userinput>.
+ for a particular zone, set the <varname>use_ixfr</varname>
+ configuration parameter to <quote>true</quote>.
In the above example of configuration sequence, you'll need
to add the following before performing <userinput>commit</userinput>:
<screen>> <userinput>config set Xfrin/zones[0]/use_ixfr true</userinput></screen>
@@ -2338,7 +2968,8 @@ what is XfroutClient xfr_client??
underlying data source storing the zone data be writable.
In the current implementation this means the zone must be stored
in an SQLite3-based data source.
- Also, in this development version, the <command>b10-ddns</command>
+<!-- TODO -->
+ Also, in this current version, the <command>b10-ddns</command>
component configures itself with the data source referring to the
<varname>database_file</varname> configuration parameter of
<command>b10-auth</command>.
@@ -2694,20 +3325,20 @@ then change those defaults with config set Resolver/forward_addresses[0]/address
<note>
<para>
- As of December 2011, both DHCPv4 and DHCPv6 components are
- skeleton servers. That means that while they are capable of
- performing DHCP configuration, they are not fully functional
- yet. In particular, neither has functional lease
- databases. This means that they will assign the same, fixed,
+ As of November 2012, the DHCPv4 component is a
+ skeleton server. That means that while it is capable of
+ performing DHCP configuration, it is not fully functional.
+ In particular, it does not have a functional lease
+ database. This means that they will assign the same, fixed,
hardcoded addresses to any client that will ask. See <xref
- linkend="dhcp4-limit"/> and <xref linkend="dhcp6-limit"/> for
+ linkend="dhcp4-limit"/> for a
detailed description.
</para>
</note>
<section id="dhcp4-usage">
<title>DHCPv4 Server Usage</title>
- <para>BIND 10 provides the DHCPv4 server component since December
+ <para>BIND 10 has provided the DHCPv4 server component since December
2011. It is a skeleton server and can be described as an early
prototype that is not fully functional yet. It is mature enough
to conduct first tests in lab environment, but it has
@@ -2724,10 +3355,8 @@ then change those defaults with config set Resolver/forward_addresses[0]/address
> <userinput>config commit</userinput></screen></para>
<para>
- To shutdown running <command>b10-dhcp4</command>, please use the
+ To stop running <command>b10-dhcp4</command>, please use the
following command:
- <screen>> <userinput>Dhcp4 shutdown</userinput></screen>
- or
<screen>> <userinput>config remove Boss/components b10-dhcp4</userinput>
> <userinput>config commit</userinput></screen></para>
@@ -2835,8 +3464,8 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1";</screen>
<simpara><command>b10-dhcp4</command> does not support
BOOTP. That is a design choice. This limitation is
permanent. If you have legacy nodes that can't use DHCP and
- require BOOTP support, please use latest version of ISC DHCP
- <ulink url="http://www.isc.org/software/dhcp"/>.</simpara>
+ require BOOTP support, please use the latest version of ISC DHCP
+ via <ulink url="http://www.isc.org/software/dhcp"/>.</simpara>
</listitem>
<listitem>
<simpara>Interface detection is currently working on Linux
@@ -2867,8 +3496,8 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1";</screen>
<chapter id="dhcp6">
<title>DHCPv6 Server</title>
- <para>Dynamic Host Configuration Protocol for IPv6 (DHCPv6) is
- specified in RFC3315. BIND 10 provides DHCPv6 server implementation
+ <para>The Dynamic Host Configuration Protocol for IPv6 (DHCPv6) is
+ specified in RFC3315. BIND 10 provides a DHCPv6 server implementation
that is described in this chapter. For a description of the DHCPv4
server implementation, see <xref linkend="dhcp4"/>.
</para>
@@ -2880,32 +3509,92 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1";</screen>
url="https://lists.isc.org/mailman/listinfo/bind10-dev">BIND 10
developers mailing list</ulink>.</para>
- <para>The DHCPv4 and DHCPv6 components in BIND 10 architecture are
- internally code named <quote>Kea</quote>.</para>
-
<note>
<para>
- As of December 2011, both DHCPv4 and DHCPv6 components are
- skeleton servers. That means that while they are capable of
- performing DHCP configuration, they are not fully functional
- yet. In particular, neither has functional lease
- databases. This means that they will assign the same, fixed,
- hardcoded addresses to any client that will ask. See <xref
- linkend="dhcp4-limit"/> and <xref linkend="dhcp6-limit"/> for
- detailed description.
+ As of November 2012, the DHCPv6 component is partially functioning,
+ having the following capabilities:
</para>
+ <itemizedlist>
+ <listitem>
+ <simpara>DHCPv6 server able to allocate leases (but not renew them).</simpara>
+ </listitem>
+ <listitem>
+ <simpara>Some configuration available through the BIND 10 configuration mechanism.</simpara>
+ </listitem>
+ <listitem>
+ <simpara>Lease storage in a MySQL database.</simpara>
+ </listitem>
+ </itemizedlist>
</note>
- <section id="dhcp6-usage">
- <title>DHCPv6 Server Usage</title>
+ <section id="dhcp6-install">
+ <title>DHCPv6 Server Build and Installation</title>
<para>
- BIND 10 provides the DHCPv6 server component since September
- 2011. It is a skeleton server and can be described as an early
- prototype that is not fully functional yet. It is mature
- enough to conduct first tests in lab environment, but it has
- significant limitations. See <xref linkend="dhcp6-limit"/> for
- details.
+ DHCPv6 is part of the BIND 10 suite of programs and is built as part of
+ the build of BIND 10. With the use of MySQL, some additional
+ installation steps are needed:
</para>
+ <section>
+ <title>Install MySQL</title>
+ <para>
+ Install MySQL according to the instructions for your system. The client development
+ libraries must be installed.
+ </para>
+ </section>
+ <section>
+ <title>Build and Install BIND 10</title>
+ <para>
+ Build and install BIND 10 as described in <xref linkend="installation"/>, with
+ the following modification: to enable the MySQL database code, the
+ "configure" step (see <xref linkend="configure"/>), specify the location of the
+ MySQL configuration program "mysql_config" with the "--with-mysql-config" switch,
+ i.e.
+ <screen><userinput>./configure [other-options] --with-dhcp-mysql</userinput></screen>
+ ...if MySQL was installed in the default location, or:
+ <screen><userinput>./configure [other-options] --with-dhcp-mysql=<replaceable><path-to-mysql_config></replaceable></userinput></screen>
+ ...if not.
+ </para>
+ </section>
+ <section>
+ <title>Create MySQL Database and BIND 10 User</title>
+ <para>
+ The next task is to create both the DHCPv6 lease database and the user under which the DHCPv6 server will
+ access it. Although the intention is to have the name of the database and the user configurable,
+ at the moment they are hard-coded as "kea", as is the associated password. ("kea" is an internal
+ code name for BIND 10 DHCP.) There are a number of steps required:
+ </para>
+ <para>
+ 1. Log into MySQL as "root":
+ <screen>$ <userinput>mysql -u root -p</userinput>
+Enter password:<userinput/>
+ :<userinput/>
+mysql></screen>
+ </para>
+ <para>
+ 2. Create the database:
+ <screen>mysql> <userinput>CREATE DATABASE kea;</userinput></screen>
+ </para>
+ <para>
+ 3. Create the database tables:
+ <screen>mysql> <userinput>CONNECT kea;</userinput>
+mysql> <userinput>SOURCE <replaceable><path-to-bind10></replaceable>/share/bind10-devel/dhcpdb_create.mysql</userinput></screen>
+ </para>
+ <para>
+ 4. Create the user under which BIND 10 will access the database and grant it access to the database tables:
+ <screen>mysql> <userinput>CREATE USER 'kea'@'localhost' IDENTIFIED BY 'kea';</userinput>
+mysql> <userinput>GRANT ALL ON kea.* TO 'kea'@'localhost';</userinput></screen>
+ </para>
+ <para>
+ 5. Exit MySQL:
+ <screen>mysql> <userinput>quit</userinput>
+Bye<userinput/>
+$</screen>
+ </para>
+ </section>
+ </section>
+
+ <section id="dhcp6-usage">
+ <title>DHCPv6 Server Usage</title>
<para>
<command>b10-dhcp6</command> is a BIND 10 component and is being
@@ -2917,10 +3606,8 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1";</screen>
</para>
<para>
- To shutdown running <command>b10-dhcp6</command>, please use the
+ To stop running <command>b10-dhcp6</command>, use the
following command:
- <screen>> <userinput>Dhcp6 shutdown</userinput></screen>
- or
<screen>> <userinput>config remove Boss/components b10-dhcp6</userinput>
> <userinput>config commit</userinput></screen>
</para>
@@ -2929,12 +3616,11 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1";</screen>
During start-up the server will detect available network interfaces
and will attempt to open UDP sockets on all interfaces that
are up, running, are not loopback, are multicast-capable, and
- have IPv6 address assigned.
-
- The server will then listen to incoming traffic. Currently
- supported client messages are SOLICIT and REQUEST. The server
+ have IPv6 address assigned. It will then listen to incoming traffic. The
+ currently supported client messages are SOLICIT and REQUEST. The server
will respond to them with ADVERTISE and REPLY, respectively.
-
+ </para>
+ <para>
Since the DHCPv6 server opens privileged ports, it requires root
access. Make sure you run this daemon as root.
</para>
@@ -2944,11 +3630,10 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1";</screen>
<section id="dhcp6-config">
<title>DHCPv6 Server Configuration</title>
<para>
- Once the server is started, it can be configured. To view the
+ Once the server has been started, it can be configured. To view the
current configuration, use the following command in <command>bindctl</command>:
- <screen>
- > <userinput>config show Dhcp6</userinput></screen>
- When starting Dhcp6 daemon for the first time, the default configuration
+ <screen>> <userinput>config show Dhcp6</userinput></screen>
+ When starting the Dhcp6 daemon for the first time, the default configuration
will be available. It will look similar to this:
<screen>
> <userinput>config show Dhcp6</userinput>
@@ -2967,14 +3652,14 @@ Dhcp6/subnet6 [] list (default)</screen>
<screen>
> <userinput>config set Dhcp6/valid-lifetime 7200</userinput>
> <userinput>config commit</userinput></screen>
- Please note that most Dhcp6 parameters are of global scope
+ Most Dhcp6 parameters are of global scope
and apply to all defined subnets, unless they are overridden on a
per-subnet basis.
</para>
<para>
- The essential role of DHCPv6 server is address assignment. The server
- has to be configured with at least one subnet and one pool of dynamic
+ The essential role of a DHCPv6 server is address assignment. For this,
+ the server has to be configured with at least one subnet and one pool of dynamic
addresses to be managed. For example, assume that the server
is connected to a network segment that uses the 2001:db8:1::/64
prefix. The Administrator of that network has decided that addresses from range
@@ -2990,7 +3675,7 @@ Dhcp6/subnet6 [] list (default)</screen>
enclosed in square brackets, even though only one range of addresses
is specified.</para>
<para>It is possible to define more than one pool in a
- subnet: continuing the previous example, further assume that
+ subnet: continuing the previous example, further assume that
2001:db8:1:0:5::/80 should be also be managed by the server. It could be written as
2001:db8:1:0:5:: to 2001:db8:1::5:ffff:ffff:ffff, but typing so many 'f's
is cumbersome. It can be expressed more simply as 2001:db8:1:0:5::/80. Both
@@ -3026,24 +3711,49 @@ Dhcp6/subnet6 [] list (default)</screen>
2001:db8:: address may be assigned as well. If you want to avoid this,
please use min-max notation.
</para>
-
<para>
- Note: Although configuration is now accepted, it is not internally used
- by they server yet. At this stage of development, the only way to alter
- server configuration is to modify its source code. To do so, please edit
- src/bin/dhcp6/dhcp6_srv.cc file, modify the following parameters and
- recompile:
+ Options can also be configured: the following commands configure
+ the DNS-SERVERS option for all subnets with the following addresses:
+ 2001:db8:1::1 and 2001:db8:1::2
<screen>
-const std::string HARDCODED_LEASE = "2001:db8:1::1234:abcd";
-const uint32_t HARDCODED_T1 = 1500; // in seconds
-const uint32_t HARDCODED_T2 = 2600; // in seconds
-const uint32_t HARDCODED_PREFERRED_LIFETIME = 3600; // in seconds
-const uint32_t HARDCODED_VALID_LIFETIME = 7200; // in seconds
-const std::string HARDCODED_DNS_SERVER = "2001:db8:1::1";</screen>
-
- Lease database and configuration support is planned for 2012.
+> <userinput>config add Dhcp6/option-data</userinput>
+> <userinput>config set Dhcp6/option-data[0]/name "dns-servers"</userinput>
+> <userinput>config set Dhcp6/option-data[0]/code 23</userinput>
+> <userinput>config set Dhcp6/option-data[0]/data "2001 0DB8 0001 0000 0000 0000</userinput>
+ <userinput>0000 0001 2001 0DB8 0001 0000 0000 0000 0000 0002"</userinput>
+> <userinput>config commit</userinput>
+ </screen>
+ (The value for the setting of the "data" element is split across two
+ lines in this document for clarity: when entering the command, all the
+ string should be entered on the same line.)
</para>
-
+ <para>
+ Currently the only way to set option data is to specify the
+ data as a string of hexadecimal digits. It is planned to allow
+ alternative ways of specifying the data as a comma-separated list,
+ e.g. "2001:db8:1::1,2001:db8:1::2".
+ </para>
+ <para>
+ As with global settings, it is also possible to override options on a
+ per-subnet basis, e.g. the following commands override the global DNS
+ servers option for a particular subnet, setting a single DNS server with
+ address 2001:db8:1::3.
+ <screen>
+> <userinput>config add Dhcp6/subnet6[0]/option-data</userinput>
+> <userinput>config set Dhcp6/subnet6[0]/option-data[0]/name "dns-servers"</userinput>
+> <userinput>config set Dhcp6/subnet6[0]/option-data[0]/code 23</userinput>
+> <userinput>config set Dhcp6/subnet6[0]/option-data[0]/data "2001 0DB8 0001 0000</userinput>
+ <userinput>0000 0000 0000 0003"</userinput>
+> <userinput>config commit</userinput></screen>
+ (As before, the setting of the "data" element has been split across two
+ lines for clarity.)
+ </para>
+ <note>
+ <para>
+ With this version of BIND 10, there are a number of known limitations
+ and problems in the DHCPv6 server. See <xref linkend="dhcp6-limit"/>.
+ </para>
+ </note>
</section>
<section id="dhcp6-std">
@@ -3064,30 +3774,39 @@ const std::string HARDCODED_DNS_SERVER = "2001:db8:1::1";</screen>
<section id="dhcp6-limit">
<title>DHCPv6 Server Limitations</title>
- <para> These are the current limitations of the DHCPv6 server
+ <para> These are the current limitations and known problems
+ with the the DHCPv6 server
software. Most of them are reflections of the early stage of
development and should be treated as <quote>not implemented
yet</quote>, rather than actual limitations.</para>
<para>
<itemizedlist>
<listitem>
- <simpara>Relayed traffic is not supported.</simpara>
+ <para>The DHCPv6 server has only been tested on Debian
+ operating systems. There are known problems with the
+ handling of packets in CentOS and RHEL.</para>
</listitem>
<listitem>
- <simpara><command>b10-dhcp6</command> provides a single,
- fixed, hardcoded lease to any client that asks. There is no
- lease manager implemented. If two clients request addresses,
- they will both get the same fixed address.</simpara>
+ <para>Relayed traffic is not supported.</para>
+ </listitem>
+ <listitem>
+ <para><command>b10-dhcp6</command> only supports
+ a limited number of configuration options.</para>
</listitem>
<listitem>
- <simpara><command>b10-dhcp6</command> does not support any
- configuration mechanisms yet. The whole configuration is
- currently hardcoded. The only way to tweak configuration
- is to directly modify source code. See see <xref
- linkend="dhcp6-config"/> for details.</simpara>
+ <para>
+ On startup, the DHCPv6 server does not get the full configuration from
+ BIND 10. To remedy this, after starting BIND 10, modify any parameter
+ and commit the changes, e.g.
+ <screen>
+> <userinput>config show Dhcp6/renew-timer</userinput>
+Dhcp6/renew-timer 1000 integer (default)
+> <userinput>config set Dhcp6/renew-timer 1001</userinput>
+> <userinput>config commit</userinput></screen>
+ </para>
</listitem>
<listitem>
- <simpara>Upon start, the server will open sockets on all
+ <para>Upon start, the server will open sockets on all
interfaces that are not loopback, are up, running and are
multicast capable and have IPv6 address. Support for
multiple interfaces is not coded in reception routines yet,
@@ -3095,34 +3814,29 @@ const std::string HARDCODED_DNS_SERVER = "2001:db8:1::1";</screen>
interfaces and <command>b10-dhcp6</command> happens to
listen on wrong interface, the easiest way to work around
this problem is to turn down other interfaces. This
- limitation will be fixed shortly.</simpara>
+ limitation will be fixed shortly.</para>
</listitem>
<listitem>
- <simpara>ORO (Option Request Option, a list of options
- requested by a client) is currently ignored and server
- assigns DNS SERVER option.</simpara>
+ <para>ORO (Option Request Option, a list of options
+ requested by a client) is currently unsupported.</para>
</listitem>
<listitem>
- <simpara>Temporary addresses are not supported yet.</simpara>
+ <para>Temporary addresses are not supported.</para>
</listitem>
<listitem>
- <simpara>Prefix delegation is not supported yet.</simpara>
+ <para>Prefix delegation is not supported.</para>
</listitem>
<listitem>
- <simpara>Address renewal (RENEW), rebinding (REBIND),
+ <para>Address renewal (RENEW), rebinding (REBIND),
confirmation (CONFIRM), duplication report (DECLINE) and
- release (RELEASE) are not supported yet.</simpara>
+ release (RELEASE) are not supported.</para>
</listitem>
<listitem>
- <simpara>DNS Update is not supported yet.</simpara>
+ <para>DNS Update is not supported.</para>
</listitem>
<listitem>
- <simpara>Interface detection is currently working on Linux
- only. See <xref linkend="iface-detect"/> for details.</simpara>
- </listitem>
- <listitem>
- <simpara>-v (verbose) command line option is currently the
- default, and cannot be disabled.</simpara>
+ <para>Interface detection is currently working on Linux
+ only. See <xref linkend="iface-detect"/> for details.</para>
</listitem>
</itemizedlist>
</para>
@@ -3132,38 +3846,53 @@ const std::string HARDCODED_DNS_SERVER = "2001:db8:1::1";</screen>
<chapter id="libdhcp">
<title>libdhcp++ library</title>
- <para>libdhcp++ is a common library written in C++ that handles
- many DHCP-related tasks, like DHCPv4 and DHCPv6 packets parsing,
- manipulation and assembly, option parsing, manipulation and
- assembly, network interface detection and socket operations, like
- socket creations, data transmission and reception and socket
- closing.
+ <para>
+ libdhcp++ is a common library written in C++ that handles
+ many DHCP-related tasks, including
+ <itemizedlist>
+ <listitem>
+ <simpara>DHCPv4 and DHCPv6 packets parsing, manipulation and assembly</simpara>
+ </listitem>
+ <listitem>
+ <simpara>Option parsing, manipulation and assembly</simpara>
+ </listitem>
+ <listitem>
+ <simpara>Network interface detection</simpara>
+ </listitem>
+ <listitem>
+ <simpara>Socket operations such as creation, data transmission and reception and socket closing.</simpara>
+ </listitem>
+ </itemizedlist>
</para>
<para>
While this library is currently used by
<command>b10-dhcp4</command> and <command>b10-dhcp6</command>
- only, it is designed to be portable, universal library useful for
+ only, it is designed to be a portable, universal library, useful for
any kind of DHCP-related software.
</para>
+<!-- TODO: point to doxygen docs -->
+
<section id="iface-detect">
<title>Interface detection</title>
- <para>Both DHCPv4 and DHCPv6 components share network
+ <para>Both the DHCPv4 and DHCPv6 components share network
interface detection routines. Interface detection is
currently only supported on Linux systems.</para>
- <para>For non-Linux systems, there is currently stub
- implementation provided. Interface manager detects loopback
+ <para>For non-Linux systems, there is currently a stub
+ implementation provided. The interface manager detects loopback
interfaces only as their name (lo or lo0) can be easily predicted.
Please contact the BIND 10 development team if you are interested
in running DHCP components on systems other than Linux.</para>
</section>
+<!--
<section id="packet-handling">
<title>DHCPv4/DHCPv6 packet handling</title>
<para>TODO: Describe packet handling here, with pointers to wiki</para>
</section>
+-->
</chapter>
@@ -3670,7 +4399,7 @@ Logging/loggers [] list
<!-- TODO: adding the empty loggers makes no sense -->
<para>
- <screen><userinput>> config add Logging/loggers</userinput>
+ <screen>> <userinput>config add Logging/loggers</userinput>
> <userinput>config show Logging</userinput>
Logging/loggers/ list (modified)
</screen>
diff --git a/src/bin/auth/query.cc b/src/bin/auth/query.cc
index 69278d4..5b71565 100644
--- a/src/bin/auth/query.cc
+++ b/src/bin/auth/query.cc
@@ -410,9 +410,9 @@ Query::process(datasrc::ClientList& client_list,
*/
assert(db_context->rrset->getRdataCount() > 0);
// Get the data of DNAME
+ RdataIteratorPtr rit = db_context->rrset->getRdataIterator();
const rdata::generic::DNAME& dname(
- dynamic_cast<const rdata::generic::DNAME&>(
- db_context->rrset->getRdataIterator()->getCurrent()));
+ dynamic_cast<const rdata::generic::DNAME&>(rit->getCurrent()));
// The yet unmatched prefix dname
const Name prefix(qname_->split(0, qname_->getLabelCount() -
db_context->rrset->getName().getLabelCount()));
diff --git a/src/bin/auth/tests/Makefile.am b/src/bin/auth/tests/Makefile.am
index 6a91309..42f202b 100644
--- a/src/bin/auth/tests/Makefile.am
+++ b/src/bin/auth/tests/Makefile.am
@@ -50,6 +50,7 @@ run_unittests_SOURCES += config_syntax_unittest.cc
run_unittests_SOURCES += command_unittest.cc
run_unittests_SOURCES += common_unittest.cc
run_unittests_SOURCES += query_unittest.cc
+run_unittests_SOURCES += query_inmemory_unittest.cc
run_unittests_SOURCES += statistics_unittest.cc
run_unittests_SOURCES += test_datasrc_clients_mgr.h test_datasrc_clients_mgr.cc
run_unittests_SOURCES += datasrc_clients_builder_unittest.cc
diff --git a/src/bin/auth/tests/query_inmemory_unittest.cc b/src/bin/auth/tests/query_inmemory_unittest.cc
new file mode 100644
index 0000000..f587ba2
--- /dev/null
+++ b/src/bin/auth/tests/query_inmemory_unittest.cc
@@ -0,0 +1,123 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dns/name.h>
+#include <dns/message.h>
+#include <dns/rcode.h>
+#include <dns/opcode.h>
+
+#include <cc/data.h>
+
+#include <datasrc/client_list.h>
+
+#include <auth/query.h>
+
+#include <testutils/dnsmessage_test.h>
+
+#include <gtest/gtest.h>
+
+#include <string>
+
+using namespace isc::dns;
+using namespace isc::auth;
+using namespace isc::testutils;
+using isc::datasrc::ConfigurableClientList;
+using std::string;
+
+namespace {
+
+// The DNAME to do tests against
+const char* const dname_txt =
+ "dname.example.com. 3600 IN DNAME "
+ "somethinglong.dnametarget.example.com.\n";
+// This is not inside the zone, this is created at runtime
+const char* const synthetized_cname_txt =
+ "www.dname.example.com. 3600 IN CNAME "
+ "www.somethinglong.dnametarget.example.com.\n";
+
+// This is a subset of QueryTest using (subset of) the same test data, but
+// with the production in-memory data source. Both tests should be eventually
+// unified to avoid duplicates.
+class InMemoryQueryTest : public ::testing::Test {
+protected:
+ InMemoryQueryTest() : list(RRClass::IN()), response(Message::RENDER) {
+ response.setRcode(Rcode::NOERROR());
+ response.setOpcode(Opcode::QUERY());
+ list.configure(isc::data::Element::fromJSON(
+ "[{\"type\": \"MasterFiles\","
+ " \"cache-enable\": true, "
+ " \"params\": {\"example.com\": \"" +
+ string(TEST_OWN_DATA_DIR "/example.zone") +
+ "\"}}]"), true);
+ }
+
+ ConfigurableClientList list;
+ Message response;
+ Query query;
+};
+
+// A wrapper to check resulting response message commonly used in
+// tests below.
+// check_origin needs to be specified only when the authority section has
+// an SOA RR. The interface is not generic enough but should be okay
+// for our test cases in practice.
+void
+responseCheck(Message& response, const isc::dns::Rcode& rcode,
+ unsigned int flags, const unsigned int ancount,
+ const unsigned int nscount, const unsigned int arcount,
+ const char* const expected_answer,
+ const char* const expected_authority,
+ const char* const expected_additional,
+ const Name& check_origin = Name::ROOT_NAME())
+{
+ // In our test cases QID, Opcode, and QDCOUNT should be constant, so
+ // we don't bother the test cases specifying these values.
+ headerCheck(response, response.getQid(), rcode, Opcode::QUERY().getCode(),
+ flags, 0, ancount, nscount, arcount);
+ if (expected_answer != NULL) {
+ rrsetsCheck(expected_answer,
+ response.beginSection(Message::SECTION_ANSWER),
+ response.endSection(Message::SECTION_ANSWER),
+ check_origin);
+ }
+ if (expected_authority != NULL) {
+ rrsetsCheck(expected_authority,
+ response.beginSection(Message::SECTION_AUTHORITY),
+ response.endSection(Message::SECTION_AUTHORITY),
+ check_origin);
+ }
+ if (expected_additional != NULL) {
+ rrsetsCheck(expected_additional,
+ response.beginSection(Message::SECTION_ADDITIONAL),
+ response.endSection(Message::SECTION_ADDITIONAL));
+ }
+}
+
+/*
+ * Test a query under a domain with DNAME. We should get a synthetized CNAME
+ * as well as the DNAME.
+ *
+ * TODO: Once we have CNAME chaining, check it works with synthetized CNAMEs
+ * as well. This includes tests pointing inside the zone, outside the zone,
+ * pointing to NXRRSET and NXDOMAIN cases (similarly as with CNAME).
+ */
+TEST_F(InMemoryQueryTest, DNAME) {
+ query.process(list, Name("www.dname.example.com"), RRType::A(),
+ response);
+
+ responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 0, 0,
+ (string(dname_txt) + synthetized_cname_txt).c_str(),
+ NULL, NULL);
+}
+}
diff --git a/src/bin/auth/tests/testdata/Makefile.am b/src/bin/auth/tests/testdata/Makefile.am
index 7e42b70..a4ea1a5 100644
--- a/src/bin/auth/tests/testdata/Makefile.am
+++ b/src/bin/auth/tests/testdata/Makefile.am
@@ -21,6 +21,7 @@ EXTRA_DIST += simpleresponse_fromWire.spec
EXTRA_DIST += spec.spec
EXTRA_DIST += example.com
+EXTRA_DIST += example.zone
EXTRA_DIST += example.sqlite3
.spec.wire:
diff --git a/src/bin/auth/tests/testdata/example.zone b/src/bin/auth/tests/testdata/example.zone
new file mode 100644
index 0000000..efbbaf2
--- /dev/null
+++ b/src/bin/auth/tests/testdata/example.zone
@@ -0,0 +1,121 @@
+;;
+;; This is a complete (but crafted and somewhat broken) zone file used
+;; in query tests.
+;;
+
+example.com. 3600 IN SOA . . 0 0 0 0 0
+example.com. 3600 IN NS glue.delegation.example.com.
+example.com. 3600 IN NS noglue.example.com.
+example.com. 3600 IN NS example.net.
+example.com. 3600 IN DS 57855 5 1 B6DCD485719ADCA18E5F3D48A2331627FDD3 636B
+glue.delegation.example.com. 3600 IN A 192.0.2.153
+glue.delegation.example.com. 3600 IN AAAA 2001:db8::53
+noglue.example.com. 3600 IN A 192.0.2.53
+delegation.example.com. 3600 IN NS glue.delegation.example.com.
+delegation.example.com. 3600 IN NS noglue.example.com.
+delegation.example.com. 3600 IN NS cname.example.com.
+delegation.example.com. 3600 IN NS example.org.
+;; Borrowed from the RFC4035
+delegation.example.com. 3600 IN DS 57855 5 1 B6DCD485719ADCA18E5F3D48A2331627FDD3 636B
+mx.example.com. 3600 IN MX 10 www.example.com.
+mx.example.com. 3600 IN MX 20 mailer.example.org.
+mx.example.com. 3600 IN MX 30 mx.delegation.example.com.
+www.example.com. 3600 IN A 192.0.2.80
+cname.example.com. 3600 IN CNAME www.example.com.
+cnamenxdom.example.com. 3600 IN CNAME nxdomain.example.com.
+;; CNAME Leading out of zone
+cnameout.example.com. 3600 IN CNAME www.example.org.
+;; The DNAME to do tests against
+dname.example.com. 3600 IN DNAME somethinglong.dnametarget.example.com.
+;; Some data at the dname node (allowed by RFC 2672)
+dname.example.com. 3600 IN A 192.0.2.5
+;; The rest of data won't be referenced from the test cases.
+cnamemailer.example.com. 3600 IN CNAME www.example.com.
+cnamemx.example.com. 3600 IN MX 10 cnamemailer.example.com.
+mx.delegation.example.com. 3600 IN A 192.0.2.100
+;; Wildcards
+*.wild.example.com. 3600 IN A 192.0.2.7
+*.wild.example.com. 3600 IN NSEC www.example.com. A NSEC RRSIG
+*.cnamewild.example.com. 3600 IN CNAME www.example.org.
+*.cnamewild.example.com. 3600 IN NSEC delegation.example.com. CNAME NSEC RRSIG
+;; Wildcard_nxrrset
+*.uwild.example.com. 3600 IN A 192.0.2.9
+*.uwild.example.com. 3600 IN NSEC www.uwild.example.com. A NSEC RRSIG
+www.uwild.example.com. 3600 IN A 192.0.2.11
+www.uwild.example.com. 3600 IN NSEC *.wild.example.com. A NSEC RRSIG
+;; Wildcard empty
+b.*.t.example.com. 3600 IN A 192.0.2.13
+b.*.t.example.com. 3600 IN NSEC *.uwild.example.com. A NSEC RRSIG
+t.example.com. 3600 IN A 192.0.2.15
+t.example.com. 3600 IN NSEC b.*.t.example.com. A NSEC RRSIG
+;; Used in NXDOMAIN proof test. We are going to test some unusual case where
+;; the best possible wildcard is below the "next domain" of the NSEC RR that
+;; proves the NXDOMAIN, i.e.,
+;; mx.example.com. (exist)
+;; (.no.example.com. (qname, NXDOMAIN)
+;; ).no.example.com. (exist)
+;; *.no.example.com. (best possible wildcard, not exist)
+).no.example.com. 3600 IN AAAA 2001:db8::53
+;; NSEC records.
+example.com. 3600 IN NSEC cname.example.com. NS SOA NSEC RRSIG
+mx.example.com. 3600 IN NSEC ).no.example.com. MX NSEC RRSIG
+).no.example.com. 3600 IN NSEC nz.no.example.com. AAAA NSEC RRSIG
+;; We'll also test the case where a single NSEC proves both NXDOMAIN and the
+;; non existence of wildcard. The following records will be used for that
+;; test.
+;; ).no.example.com. (exist, whose NSEC proves everything)
+;; *.no.example.com. (best possible wildcard, not exist)
+;; nx.no.example.com. (NXDOMAIN)
+;; nz.no.example.com. (exist)
+nz.no.example.com. 3600 IN AAAA 2001:db8::5300
+nz.no.example.com. 3600 IN NSEC noglue.example.com. AAAA NSEC RRSIG
+noglue.example.com. 3600 IN NSEC nonsec.example.com. A
+
+;; NSEC for the normal NXRRSET case
+www.example.com. 3600 IN NSEC example.com. A NSEC RRSIG
+
+;; Authoritative data without NSEC
+nonsec.example.com. 3600 IN A 192.0.2.0
+
+;; NSEC3 RRs. You may also need to add mapping to MockZoneFinder::hash_map_.
+0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example.com. 3600 IN NSEC3 1 1 12 aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA NSEC3PARAM RRSIG
+0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example.com. 3600 IN RRSIG NSEC3 5 3 3600 20000101000000 20000201000000 12345 example.com. FAKEFAKEFAKE
+q04jkcevqvmu85r014c7dkba38o0ji5r.example.com. 3600 IN NSEC3 1 1 12 aabbccdd r53bq7cc2uvmubfu5ocmm6pers9tk9en A RRSIG
+q04jkcevqvmu85r014c7dkba38o0ji5r.example.com. 3600 IN RRSIG NSEC3 5 3 3600 20000101000000 20000201000000 12345 example.com. FAKEFAKEFAKE
+
+;; NSEC3 for wild.example.com (used in wildcard tests, will be added on
+;; demand not to confuse other tests)
+ji6neoaepv8b5o6k4ev33abha8ht9fgc.example.com. 3600 IN NSEC3 1 1 12 aabbccdd r53bq7cc2uvmubfu5ocmm6pers9tk9en
+
+;; NSEC3 for cnamewild.example.com (used in wildcard tests, will be added on
+;; demand not to confuse other tests)
+k8udemvp1j2f7eg6jebps17vp3n8i58h.example.com. 3600 IN NSEC3 1 1 12 aabbccdd r53bq7cc2uvmubfu5ocmm6pers9tk9en
+
+;; NSEC3 for *.uwild.example.com (will be added on demand not to confuse
+;; other tests)
+b4um86eghhds6nea196smvmlo4ors995.example.com. 3600 IN NSEC3 1 1 12 aabbccdd r53bq7cc2uvmubfu5ocmm6pers9tk9en A RRSIG
+;; NSEC3 for uwild.example.com. (will be added on demand)
+t644ebqk9bibcna874givr6joj62mlhv.example.com. 3600 IN NSEC3 1 1 12 aabbccdd r53bq7cc2uvmubfu5ocmm6pers9tk9en A RRSIG
+
+;; (Secure) delegation data; Delegation with DS record
+signed-delegation.example.com. 3600 IN NS ns.example.net.
+signed-delegation.example.com. 3600 IN DS 12345 8 2 764501411DE58E8618945054A3F620B36202E115D015A7773F4B78E0F952CECA
+
+;; (Secure) delegation data; Delegation without DS record (and both NSEC
+;; and NSEC3 denying its existence)
+unsigned-delegation.example.com. 3600 IN NS ns.example.net.
+unsigned-delegation.example.com. 3600 IN NSEC unsigned-delegation-optout.example.com. NS RRSIG NSEC
+;; This one will be added on demand
+q81r598950igr1eqvc60aedlq66425b5.example.com. 3600 IN NSEC3 1 1 12 aabbccdd 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom NS RRSIG
+
+;; Delegation without DS record, and no direct matching NSEC3 record
+unsigned-delegation-optout.example.com. 3600 IN NS ns.example.net.
+unsigned-delegation-optout.example.com. 3600 IN NSEC *.uwild.example.com. NS RRSIG NSEC
+
+;; (Secure) delegation data; Delegation where the DS lookup will raise an
+;; exception.
+bad-delegation.example.com. 3600 IN NS ns.example.net.
+
+;; Delegation from an unsigned parent. There's no DS, and there's no NSEC
+;; or NSEC3 that proves it.
+nosec-delegation.example.com. 3600 IN NS ns.nosec.example.net.
diff --git a/src/bin/bindctl/moduleinfo.py b/src/bin/bindctl/moduleinfo.py
index 6c3a304..33114d8 100644
--- a/src/bin/bindctl/moduleinfo.py
+++ b/src/bin/bindctl/moduleinfo.py
@@ -221,7 +221,8 @@ class ModuleInfo:
def module_help(self):
"""Prints the help info for this module to stdout"""
- print("Module ", self, "\nAvailable commands:")
+ print("Module " + str(self))
+ print("Available commands:")
for k in self.commands.values():
n = k.get_name()
if len(n) >= CONST_BINDCTL_HELP_INDENT_WIDTH:
diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.cc b/src/bin/dhcp4/ctrl_dhcp4_srv.cc
index 4bd3103..b02bf72 100644
--- a/src/bin/dhcp4/ctrl_dhcp4_srv.cc
+++ b/src/bin/dhcp4/ctrl_dhcp4_srv.cc
@@ -14,21 +14,20 @@
#include <config.h>
-#include <cassert>
-#include <iostream>
-
#include <asiolink/asiolink.h>
#include <cc/data.h>
#include <cc/session.h>
-#include <cc/session.h>
#include <config/ccsession.h>
+#include <dhcp/iface_mgr.h>
#include <dhcp4/ctrl_dhcp4_srv.h>
#include <dhcp4/dhcp4_log.h>
#include <dhcp4/spec_config.h>
-#include <dhcp/iface_mgr.h>
#include <exceptions/exceptions.h>
#include <util/buffer.h>
+#include <cassert>
+#include <iostream>
+
using namespace isc::asiolink;
using namespace isc::cc;
using namespace isc::config;
diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.h b/src/bin/dhcp4/ctrl_dhcp4_srv.h
index 688b1db..9fd7668 100644
--- a/src/bin/dhcp4/ctrl_dhcp4_srv.h
+++ b/src/bin/dhcp4/ctrl_dhcp4_srv.h
@@ -15,11 +15,11 @@
#ifndef CTRL_DHCPV4_SRV_H
#define CTRL_DHCPV4_SRV_H
-#include <dhcp4/dhcp4_srv.h>
#include <asiolink/asiolink.h>
+#include <cc/data.h>
#include <cc/session.h>
#include <config/ccsession.h>
-#include <cc/data.h>
+#include <dhcp4/dhcp4_srv.h>
namespace isc {
namespace dhcp {
diff --git a/src/bin/dhcp4/dhcp4_log.cc b/src/bin/dhcp4/dhcp4_log.cc
index 678223b..32c5a47 100644
--- a/src/bin/dhcp4/dhcp4_log.cc
+++ b/src/bin/dhcp4/dhcp4_log.cc
@@ -14,7 +14,7 @@
/// Defines the logger used by the top-level component of b10-dhcp4.
-#include "dhcp4_log.h"
+#include <dhcp4/dhcp4_log.h>
namespace isc {
namespace dhcp {
diff --git a/src/bin/dhcp4/dhcp4_log.h b/src/bin/dhcp4/dhcp4_log.h
index b042ea4..07d009a 100644
--- a/src/bin/dhcp4/dhcp4_log.h
+++ b/src/bin/dhcp4/dhcp4_log.h
@@ -15,8 +15,8 @@
#ifndef DHCP4_LOG_H
#define DHCP4_LOG_H
-#include <log/macros.h>
#include <log/logger_support.h>
+#include <log/macros.h>
#include <dhcp4/dhcp4_messages.h>
namespace isc {
diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes
index 63ddbfc..392b332 100644
--- a/src/bin/dhcp4/dhcp4_messages.mes
+++ b/src/bin/dhcp4/dhcp4_messages.mes
@@ -42,17 +42,17 @@ server is about to open sockets on the specified port.
The IPv4 DHCP server has received a packet that it is unable to
interpret. The reason why the packet is invalid is included in the message.
-% DHCP4_PACKET_RECEIVE_FAIL error on attempt to receive packet: %1
-The IPv4 DHCP server tried to receive a packet but an error
-occured during this attempt. The reason for the error is included in
-the message.
-
% DHCP4_PACKET_RECEIVED %1 (type %2) packet received on interface %3
A debug message noting that the server has received the specified type of
packet on the specified interface. Note that a packet marked as UNKNOWN
may well be a valid DHCP packet, just a type not expected by the server
(e.g. it will report a received OFFER packet as UNKNOWN).
+% DHCP4_PACKET_RECEIVE_FAIL error on attempt to receive packet: %1
+The IPv4 DHCP server tried to receive a packet but an error
+occured during this attempt. The reason for the error is included in
+the message.
+
% DHCP4_PACKET_SEND_FAIL failed to send DHCPv4 packet: %1
This error is output if the IPv4 DHCP server fails to send an assembled
DHCP message to a client. The reason for the error is included in the
diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc
index 67943c5..59edc01 100644
--- a/src/bin/dhcp4/dhcp4_srv.cc
+++ b/src/bin/dhcp4/dhcp4_srv.cc
@@ -12,13 +12,13 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <asiolink/io_address.h>
#include <dhcp/dhcp4.h>
-#include <dhcp/pkt4.h>
#include <dhcp/iface_mgr.h>
-#include <dhcp4/dhcp4_srv.h>
-#include <dhcp4/dhcp4_log.h>
-#include <asiolink/io_address.h>
#include <dhcp/option4_addrlst.h>
+#include <dhcp/pkt4.h>
+#include <dhcp4/dhcp4_log.h>
+#include <dhcp4/dhcp4_srv.h>
using namespace isc;
using namespace isc::asiolink;
diff --git a/src/bin/dhcp4/dhcp4_srv.h b/src/bin/dhcp4/dhcp4_srv.h
index f677259..48ccde6 100644
--- a/src/bin/dhcp4/dhcp4_srv.h
+++ b/src/bin/dhcp4/dhcp4_srv.h
@@ -15,10 +15,12 @@
#ifndef DHCPV4_SRV_H
#define DHCPV4_SRV_H
-#include <boost/noncopyable.hpp>
#include <dhcp/dhcp4.h>
#include <dhcp/pkt4.h>
#include <dhcp/option.h>
+
+#include <boost/noncopyable.hpp>
+
#include <iostream>
namespace isc {
diff --git a/src/bin/dhcp4/main.cc b/src/bin/dhcp4/main.cc
index 31f0b02..bd3be1b 100644
--- a/src/bin/dhcp4/main.cc
+++ b/src/bin/dhcp4/main.cc
@@ -13,14 +13,15 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
-#include <iostream>
-
-#include <boost/lexical_cast.hpp>
#include <dhcp4/ctrl_dhcp4_srv.h>
#include <dhcp4/dhcp4_log.h>
#include <log/logger_support.h>
+#include <boost/lexical_cast.hpp>
+
+#include <iostream>
+
using namespace isc::dhcp;
using namespace std;
diff --git a/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc b/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc
index 5af0cc9..fd4e90e 100644
--- a/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc
+++ b/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc
@@ -13,16 +13,18 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
-#include <iostream>
+
+#include <config/ccsession.h>
+#include <dhcp/dhcp4.h>
+#include <dhcp4/ctrl_dhcp4_srv.h>
+
+#include <gtest/gtest.h>
+
#include <fstream>
+#include <iostream>
#include <sstream>
#include <arpa/inet.h>
-#include <gtest/gtest.h>
-
-#include <dhcp/dhcp4.h>
-#include <dhcp4/ctrl_dhcp4_srv.h>
-#include <config/ccsession.h>
using namespace std;
using namespace isc;
diff --git a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
index fca06ad..ac6f0bb 100644
--- a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
+++ b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
@@ -13,17 +13,19 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
-#include <iostream>
-#include <fstream>
#include <sstream>
-#include <arpa/inet.h>
-#include <gtest/gtest.h>
-
+#include <asiolink/io_address.h>
#include <dhcp/dhcp4.h>
-#include <dhcp4/dhcp4_srv.h>
#include <dhcp/option.h>
-#include <asiolink/io_address.h>
+#include <dhcp4/dhcp4_srv.h>
+
+#include <gtest/gtest.h>
+
+#include <fstream>
+#include <iostream>
+
+#include <arpa/inet.h>
using namespace std;
using namespace isc;
diff --git a/src/bin/dhcp4/tests/dhcp4_unittests.cc b/src/bin/dhcp4/tests/dhcp4_unittests.cc
index ebc72fb..0ed61b7 100644
--- a/src/bin/dhcp4/tests/dhcp4_unittests.cc
+++ b/src/bin/dhcp4/tests/dhcp4_unittests.cc
@@ -12,10 +12,10 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <stdio.h>
-#include <gtest/gtest.h>
#include <log/logger_support.h>
+#include <gtest/gtest.h>
+
int
main(int argc, char* argv[]) {
diff --git a/src/bin/dhcp6/Makefile.am b/src/bin/dhcp6/Makefile.am
index 55fe619..1d9766f 100644
--- a/src/bin/dhcp6/Makefile.am
+++ b/src/bin/dhcp6/Makefile.am
@@ -64,7 +64,7 @@ b10_dhcp6_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
-b10_dhcp6_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcpsrv.la
+b10_dhcp6_LDADD += $(top_builddir)/src/lib/dhcpsrv/libb10-dhcpsrv.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
b10_dhcp6_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
diff --git a/src/bin/dhcp6/config_parser.cc b/src/bin/dhcp6/config_parser.cc
index da393ac..d6f3afe 100644
--- a/src/bin/dhcp6/config_parser.cc
+++ b/src/bin/dhcp6/config_parser.cc
@@ -12,27 +12,30 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <stdint.h>
-#include <iostream>
-#include <vector>
-#include <map>
-#include <boost/foreach.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/scoped_ptr.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/algorithm/string.hpp>
-#include <util/encode/hex.h>
#include <asiolink/io_address.h>
#include <cc/data.h>
#include <config/ccsession.h>
-#include <log/logger_support.h>
#include <dhcp/libdhcp++.h>
-#include <dhcp/triplet.h>
-#include <dhcp/pool.h>
-#include <dhcp/subnet.h>
-#include <dhcp/cfgmgr.h>
#include <dhcp6/config_parser.h>
#include <dhcp6/dhcp6_log.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/pool.h>
+#include <dhcpsrv/subnet.h>
+#include <dhcpsrv/triplet.h>
+#include <log/logger_support.h>
+#include <util/encode/hex.h>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <iostream>
+#include <map>
+#include <vector>
+
+#include <stdint.h>
using namespace std;
using namespace isc::data;
diff --git a/src/bin/dhcp6/config_parser.h b/src/bin/dhcp6/config_parser.h
index 6758c99..9f7c3ae 100644
--- a/src/bin/dhcp6/config_parser.h
+++ b/src/bin/dhcp6/config_parser.h
@@ -12,13 +12,14 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <string>
-#include <exceptions/exceptions.h>
-#include <cc/data.h>
-
#ifndef DHCP6_CONFIG_PARSER_H
#define DHCP6_CONFIG_PARSER_H
+#include <cc/data.h>
+#include <exceptions/exceptions.h>
+
+#include <string>
+
namespace isc {
namespace dhcp {
diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.cc b/src/bin/dhcp6/ctrl_dhcp6_srv.cc
index 7370583..5d4d990 100644
--- a/src/bin/dhcp6/ctrl_dhcp6_srv.cc
+++ b/src/bin/dhcp6/ctrl_dhcp6_srv.cc
@@ -14,22 +14,22 @@
#include <config.h>
-#include <cassert>
-#include <iostream>
-
#include <asiolink/asiolink.h>
#include <cc/data.h>
#include <cc/session.h>
#include <cc/session.h>
#include <config/ccsession.h>
+#include <dhcp/iface_mgr.h>
+#include <dhcp6/config_parser.h>
#include <dhcp6/ctrl_dhcp6_srv.h>
#include <dhcp6/dhcp6_log.h>
#include <dhcp6/spec_config.h>
-#include <dhcp6/config_parser.h>
-#include <dhcp/iface_mgr.h>
#include <exceptions/exceptions.h>
#include <util/buffer.h>
+#include <cassert>
+#include <iostream>
+
using namespace isc::asiolink;
using namespace isc::cc;
using namespace isc::config;
@@ -42,6 +42,7 @@ using namespace std;
namespace isc {
namespace dhcp {
+
ControlledDhcpv6Srv* ControlledDhcpv6Srv::server_ = NULL;
ConstElementPtr
@@ -149,8 +150,8 @@ void ControlledDhcpv6Srv::disconnectSession() {
IfaceMgr::instance().set_session_socket(IfaceMgr::INVALID_SOCKET, NULL);
}
-ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t port /*= DHCP6_SERVER_PORT*/)
- :Dhcpv6Srv(port), cc_session_(NULL), config_session_(NULL) {
+ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t port, const char* dbconfig)
+ : Dhcpv6Srv(port, dbconfig), cc_session_(NULL), config_session_(NULL) {
server_ = this; // remember this instance for use in callback
}
diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.h b/src/bin/dhcp6/ctrl_dhcp6_srv.h
index 91fc80a..22cb3b6 100644
--- a/src/bin/dhcp6/ctrl_dhcp6_srv.h
+++ b/src/bin/dhcp6/ctrl_dhcp6_srv.h
@@ -15,11 +15,11 @@
#ifndef CTRL_DHCPV6_SRV_H
#define CTRL_DHCPV6_SRV_H
-#include <dhcp6/dhcp6_srv.h>
#include <asiolink/asiolink.h>
+#include <cc/data.h>
#include <cc/session.h>
#include <config/ccsession.h>
-#include <cc/data.h>
+#include <dhcp6/dhcp6_srv.h>
namespace isc {
namespace dhcp {
@@ -41,7 +41,9 @@ public:
/// @brief Constructor
///
/// @param port UDP port to be opened for DHCP traffic
- ControlledDhcpv6Srv(uint16_t port = DHCP6_SERVER_PORT);
+ /// @param dbconfig Lease manager database configuration string
+ ControlledDhcpv6Srv(uint16_t port = DHCP6_SERVER_PORT,
+ const char* dbconfig = "type=memfile");
/// @brief Destructor.
~ControlledDhcpv6Srv();
diff --git a/src/bin/dhcp6/dhcp6_log.cc b/src/bin/dhcp6/dhcp6_log.cc
index d893834..875f595 100644
--- a/src/bin/dhcp6/dhcp6_log.cc
+++ b/src/bin/dhcp6/dhcp6_log.cc
@@ -14,7 +14,7 @@
/// Defines the logger used by the top-level component of b10-dhcp6.
-#include "dhcp6_log.h"
+#include <dhcp6/dhcp6_log.h>
namespace isc {
namespace dhcp {
diff --git a/src/bin/dhcp6/dhcp6_log.h b/src/bin/dhcp6/dhcp6_log.h
index fb3c3f9..23202da 100644
--- a/src/bin/dhcp6/dhcp6_log.h
+++ b/src/bin/dhcp6/dhcp6_log.h
@@ -15,9 +15,9 @@
#ifndef DHCP6_LOG_H
#define DHCP6_LOG_H
-#include <log/macros.h>
-#include <log/logger_support.h>
#include <dhcp6/dhcp6_messages.h>
+#include <log/logger_support.h>
+#include <log/macros.h>
namespace isc {
namespace dhcp {
diff --git a/src/bin/dhcp6/dhcp6_messages.mes b/src/bin/dhcp6/dhcp6_messages.mes
index 5f9cd02..6b82344 100644
--- a/src/bin/dhcp6/dhcp6_messages.mes
+++ b/src/bin/dhcp6/dhcp6_messages.mes
@@ -26,62 +26,99 @@ to establish a session with the BIND 10 control channel.
A debug message listing the command (and possible arguments) received
from the BIND 10 control system by the IPv6 DHCP server.
+% DHCP6_CONFIG_COMPLETE DHCPv6 server has completed configuration: %1
+This is an informational message announcing the successful processing of a
+new configuration. it is output during server startup, and when an updated
+configuration is committed by the administrator. Additional information
+may be provided.
+
+% 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
+served until the configuration has been corrected.
+
+% DHCP6_CONFIG_NEW_SUBNET a new subnet has been added to configuration: %1
+This is an informational message reporting that the configuration has
+been extended to include the specified subnet.
+
+% DHCP6_CONFIG_OPTION_DUPLICATE multiple options with the code: %1 added to the subnet: %2
+This warning message is issued on attempt to configure multiple options with the
+same option code for the particular subnet. Adding multiple options is uncommon
+for DHCPv6, yet it is not prohibited.
+
+% DHCP6_CONFIG_START DHCPv6 server is processing the following configuration: %1
+This is a debug message that is issued every time the server receives a
+configuration. That happens start up and also when a server configuration
+change is committed by the administrator.
+
% DHCP6_CONFIG_UPDATE updated configuration received: %1
A debug message indicating that the IPv6 DHCP server has received an
updated configuration from the BIND 10 configuration system.
-% DHCP6_DB_BACKEND_STARTED Lease database started (backend type: %1)
+% DHCP6_DB_BACKEND_STARTED lease database started (type: %1, name: %2)
This informational message is printed every time DHCPv6 is started.
It indicates what database backend type is being to store lease and
other information.
-% DHCP6_NOT_RUNNING IPv6 DHCP server is not running
-A warning message is issued when an attempt is made to shut down the
-IPv6 DHCP server but it is not running.
-
-% DHCP6_NO_INTERFACES failed to detect any network interfaces
-During startup the IPv6 DHCP server failed to detect any network
-interfaces and is therefore shutting down.
-
-% DHCP6_OPEN_SOCKET opening sockets on port %1
-A debug message issued during startup, this indicates that the IPv6 DHCP
-server is about to open sockets on the specified port.
-
-% DHCP6_LEASE_ADVERT Lease %1 advertised (client duid=%2, iaid=%3)
+% DHCP6_LEASE_ADVERT lease %1 advertised (client duid=%2, iaid=%3)
This debug message indicates that the server successfully advertised
a lease. It is up to the client to choose one server out of othe advertised
and continue allocation with that server. This is a normal behavior and
indicates successful operation.
-% DHCP6_LEASE_ALLOC lease %1 has been allocated (client duid=%2, iaid=%3)
-This debug message indicates that the server successfully granted (in
-response to client's REQUEST message) a lease. This is a normal behavior
-and incicates successful operation.
-
% DHCP6_LEASE_ADVERT_FAIL failed to advertise a lease for client duid=%1, iaid=%2
This message indicates that the server failed to advertise (in response to
received SOLICIT) a lease for a given client. There may be many reasons for
such failure. Each specific failure is logged in a separate log entry.
+% DHCP6_LEASE_ALLOC lease %1 has been allocated (client duid=%2, iaid=%3)
+This debug message indicates that the server successfully granted (in
+response to client's REQUEST message) a lease. This is a normal behavior
+and incicates successful operation.
+
% DHCP6_LEASE_ALLOC_FAIL failed to grant a lease for client duid=%1, iaid=%2
This message indicates that the server failed to grant (in response to
received REQUEST) a lease for a given client. There may be many reasons for
such failure. Each specific failure is logged in a separate log entry.
+% DHCP6_NOT_RUNNING IPv6 DHCP server is not running
+A warning message is issued when an attempt is made to shut down the
+IPv6 DHCP server but it is not running.
+
+% DHCP6_NO_INTERFACES failed to detect any network interfaces
+During startup the IPv6 DHCP server failed to detect any network
+interfaces and is therefore shutting down.
+
+% 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_OPEN_SOCKET opening sockets on port %1
+A debug message issued during startup, this indicates that the IPv6 DHCP
+server is about to open sockets on the specified port.
+
% DHCP6_PACKET_PARSE_FAIL failed to parse incoming packet
The IPv6 DHCP server has received a packet that it is unable to interpret.
-% DHCP6_PACKET_RECEIVE_FAIL error on attempt to receive packet: %1
-The IPv6 DHCP server tried to receive a packet but an error
-occured during this attempt. The reason for the error is included in
-the message.
-
% DHCP6_PACKET_RECEIVED %1 packet received
A debug message noting that the server has received the specified type
of packet. Note that a packet marked as UNKNOWN may well be a valid
DHCP packet, just a type not expected by the server (e.g. it will report
a received OFFER packet as UNKNOWN).
+% DHCP6_PACKET_RECEIVE_FAIL error on attempt to receive packet: %1
+The IPv6 DHCP server tried to receive a packet but an error
+occured during this attempt. The reason for the error is included in
+the message.
+
% DHCP6_PACKET_SEND_FAIL failed to send DHCPv6 packet: %1
This error is output if the IPv6 DHCP server fails to send an assembled
DHCP message to a client. The reason for the error is included in the
@@ -152,38 +189,3 @@ 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
-served until the configuration has been corrected.
-
-% DHCP6_CONFIG_START DHCPv6 server is processing the following configuration: %1
-This is a debug message that is issued every time the server receives a
-configuration. That happens start up and also when a server configuration
-change is committed by the administrator.
-
-% DHCP6_CONFIG_NEW_SUBNET a new subnet has been added to configuration: %1
-This is an informational message reporting that the configuration has
-been extended to include the specified subnet.
-
-% DHCP6_CONFIG_COMPLETE DHCPv6 server has completed configuration: %1
-This is an informational message announcing the successful processing of a
-new configuration. it is output during server startup, and when an updated
-configuration is committed by the administrator. Additional information
-may be provided.
-
-% DHCP6_CONFIG_OPTION_DUPLICATE multiple options with the code: %1 added to the subnet: %2
-This warning message is issued on attempt to configure multiple options with the
-same option code for the particular subnet. Adding multiple options is uncommon
-for DHCPv6, yet it is not prohibited.
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index 1c76b75..2a5798d 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -14,33 +14,32 @@
#include <config.h>
-#include <stdlib.h>
-#include <time.h>
-
#include <asiolink/io_address.h>
-#include <dhcp6/dhcp6_log.h>
-#include <dhcp6/dhcp6_srv.h>
#include <dhcp/dhcp6.h>
+#include <dhcp/duid.h>
#include <dhcp/iface_mgr.h>
#include <dhcp/libdhcp++.h>
#include <dhcp/option6_addrlst.h>
-#include <dhcp/option6_iaaddr.h>
#include <dhcp/option6_ia.h>
+#include <dhcp/option6_iaaddr.h>
+#include <dhcp/option6_iaaddr.h>
#include <dhcp/option6_int_array.h>
#include <dhcp/pkt6.h>
-#include <dhcp/subnet.h>
-#include <dhcp/cfgmgr.h>
+#include <dhcp6/dhcp6_log.h>
+#include <dhcp6/dhcp6_srv.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/lease_mgr.h>
+#include <dhcpsrv/lease_mgr_factory.h>
+#include <dhcpsrv/subnet.h>
#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/lease_mgr_factory.h>
-#include <dhcp/cfgmgr.h>
-#include <dhcp/option6_iaaddr.h>
#include <boost/foreach.hpp>
+#include <stdlib.h>
+#include <time.h>
+
using namespace isc;
using namespace isc::asiolink;
using namespace isc::dhcp;
@@ -80,6 +79,7 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port, const char* dbconfig)
// Instantiate LeaseMgr
LeaseMgrFactory::create(dbconfig);
LOG_INFO(dhcp6_logger, DHCP6_DB_BACKEND_STARTED)
+ .arg(LeaseMgrFactory::instance().getType())
.arg(LeaseMgrFactory::instance().getName());
// Instantiate allocation engine
diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h
index f4f0f0c..b4ce8b1 100644
--- a/src/bin/dhcp6/dhcp6_srv.h
+++ b/src/bin/dhcp6/dhcp6_srv.h
@@ -15,20 +15,20 @@
#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/duid.h>
#include <dhcp/option.h>
#include <dhcp/option6_ia.h>
#include <dhcp/option_definition.h>
#include <dhcp/pkt6.h>
-#include <dhcp/subnet.h>
+#include <dhcpsrv/alloc_engine.h>
+#include <dhcpsrv/subnet.h>
-namespace isc {
+#include <boost/noncopyable.hpp>
+
+#include <iostream>
+namespace isc {
namespace dhcp {
/// @brief DHCPv6 server service.
///
diff --git a/src/bin/dhcp6/main.cc b/src/bin/dhcp6/main.cc
index 8eaf60c..ae299e5 100644
--- a/src/bin/dhcp6/main.cc
+++ b/src/bin/dhcp6/main.cc
@@ -13,14 +13,15 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
-#include <iostream>
-
-#include <boost/lexical_cast.hpp>
#include <dhcp6/ctrl_dhcp6_srv.h>
#include <dhcp6/dhcp6_log.h>
#include <log/logger_support.h>
+#include <boost/lexical_cast.hpp>
+
+#include <iostream>
+
using namespace isc::dhcp;
using namespace std;
@@ -34,6 +35,16 @@ using namespace std;
/// Dhcpv6Srv and other classes, see \ref dhcpv6Session.
namespace {
+// @todo: Replace the next line by extraction from configuration parameters
+// This is the "dbconfig" string for the MySQL database. It is likely
+// that a long-term solution will be to create the instance of the lease manager
+// somewhere other than the Dhcpv6Srv constructor, to give time to extract
+// the connection string from the configuration database.
+#ifdef HAVE_MYSQL
+const char* DBCONFIG = "type=mysql name=kea user=kea password=kea host=localhost";
+#else
+const char* DBCONFIG = "type=memfile";
+#endif
const char* const DHCP6_NAME = "b10-dhcp6";
@@ -102,7 +113,7 @@ main(int argc, char* argv[]) {
int ret = EXIT_SUCCESS;
try {
- ControlledDhcpv6Srv server(port_number);
+ ControlledDhcpv6Srv server(port_number, DBCONFIG);
if (!stand_alone) {
try {
server.establishSession();
diff --git a/src/bin/dhcp6/tests/Makefile.am b/src/bin/dhcp6/tests/Makefile.am
index 78caa2f..b01b877 100644
--- a/src/bin/dhcp6/tests/Makefile.am
+++ b/src/bin/dhcp6/tests/Makefile.am
@@ -65,7 +65,7 @@ dhcp6_unittests_LDADD = $(GTEST_LDADD)
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
-dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcpsrv.la
+dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcpsrv/libb10-dhcpsrv.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
dhcp6_unittests_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
diff --git a/src/bin/dhcp6/tests/config_parser_unittest.cc b/src/bin/dhcp6/tests/config_parser_unittest.cc
index 95c7897..2064e72 100644
--- a/src/bin/dhcp6/tests/config_parser_unittest.cc
+++ b/src/bin/dhcp6/tests/config_parser_unittest.cc
@@ -13,22 +13,23 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
-#include <iostream>
-#include <fstream>
-#include <sstream>
-#include <boost/foreach.hpp>
-
-#include <arpa/inet.h>
-#include <gtest/gtest.h>
-
-#include <dhcp6/dhcp6_srv.h>
-#include <dhcp6/config_parser.h>
#include <config/ccsession.h>
#include <dhcp/libdhcp++.h>
-#include <dhcp/subnet.h>
-#include <dhcp/cfgmgr.h>
#include <dhcp/option6_ia.h>
+#include <dhcp6/config_parser.h>
+#include <dhcp6/dhcp6_srv.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/subnet.h>
+
+#include <boost/foreach.hpp>
+#include <gtest/gtest.h>
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
+#include <arpa/inet.h>
using namespace std;
using namespace isc;
diff --git a/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc
index 1e88f83..ea359fc 100644
--- a/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc
+++ b/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc
@@ -13,16 +13,18 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
+
+#include <dhcp/dhcp6.h>
+#include <dhcp6/ctrl_dhcp6_srv.h>
+#include <config/ccsession.h>
+
+#include <gtest/gtest.h>
+
#include <iostream>
#include <fstream>
#include <sstream>
#include <arpa/inet.h>
-#include <gtest/gtest.h>
-
-#include <dhcp/dhcp6.h>
-#include <dhcp6/ctrl_dhcp6_srv.h>
-#include <config/ccsession.h>
using namespace std;
using namespace isc;
diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
index afb05d1..335fb7b 100644
--- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
+++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
@@ -14,20 +14,10 @@
#include <config.h>
-#include <fstream>
-#include <iostream>
-#include <sstream>
-
-#include <gtest/gtest.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/duid.h>
-#include <dhcp/lease_mgr.h>
-#include <dhcp/lease_mgr_factory.h>
#include <dhcp/option.h>
#include <dhcp/option6_addrlst.h>
#include <dhcp/option6_ia.h>
@@ -35,9 +25,19 @@
#include <dhcp/option6_int_array.h>
#include <dhcp6/config_parser.h>
#include <dhcp6/dhcp6_srv.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/lease_mgr.h>
+#include <dhcpsrv/lease_mgr_factory.h>
#include <util/buffer.h>
#include <util/range_utilities.h>
+#include <boost/scoped_ptr.hpp>
+#include <gtest/gtest.h>
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
using namespace isc;
using namespace isc::asiolink;
using namespace isc::config;
diff --git a/src/bin/dhcp6/tests/dhcp6_unittests.cc b/src/bin/dhcp6/tests/dhcp6_unittests.cc
index 360fb71..d9695e9 100644
--- a/src/bin/dhcp6/tests/dhcp6_unittests.cc
+++ b/src/bin/dhcp6/tests/dhcp6_unittests.cc
@@ -12,10 +12,10 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <stdio.h>
-#include <gtest/gtest.h>
#include <log/logger_support.h>
+#include <gtest/gtest.h>
+
int
main(int argc, char* argv[]) {
diff --git a/src/bin/stats/stats_messages.mes b/src/bin/stats/stats_messages.mes
index 2b70df9..3960c26 100644
--- a/src/bin/stats/stats_messages.mes
+++ b/src/bin/stats/stats_messages.mes
@@ -24,6 +24,10 @@ The stats module was unable to connect to the BIND 10 command and
control bus. A likely problem is that the message bus daemon
(b10-msgq) is not running. The stats module will now shut down.
+% STATS_RECEIVED_INVALID_STATISTICS_DATA received invalid statistics data from %1
+Invalid statistics data has been received from the module while
+polling and it has been discarded.
+
% STATS_RECEIVED_NEW_CONFIG received new configuration: %1
This debug message is printed when the stats module has received a
configuration update from the configuration manager.
@@ -53,10 +57,6 @@ response indicating that it is running normally.
An unknown command has been sent to the stats module. The stats module
will respond with an error and the command will be ignored.
-% STATS_RECEIVED_INVALID_STATISTICS_DATA received invalid statistics data from %1
-Invalid statistics data has been received from the module while
-polling and it has been discarded.
-
% STATS_SEND_STATISTICS_REQUEST requesting %1 to send statistics
This debug message is printed when a request is sent to the module
to send its data to the stats module.
diff --git a/src/bin/xfrout/xfrout_messages.mes b/src/bin/xfrout/xfrout_messages.mes
index bef6080..97b7a31 100644
--- a/src/bin/xfrout/xfrout_messages.mes
+++ b/src/bin/xfrout/xfrout_messages.mes
@@ -107,10 +107,6 @@ received from the configuration manager.
The xfrout daemon received a command on the command channel that
NOTIFY packets should be sent for the given zone.
-% XFROUT_RECEIVED_GETSTATS_COMMAND received command to get statistics data
-The xfrout daemon received a command on the command channel that
-statistics data should be sent to the stats daemon.
-
% XFROUT_PARSE_QUERY_ERROR error parsing query: %1
There was a parse error while reading an incoming query. The parse
error is shown in the log message. A remote client sent a packet we
@@ -151,6 +147,10 @@ given host. This is because of ACLs. The %2 represents the IP
address and port of the peer requesting the transfer, and the %3
represents the zone name and class.
+% XFROUT_RECEIVED_GETSTATS_COMMAND received command to get statistics data
+The xfrout daemon received a command on the command channel that
+statistics data should be sent to the stats daemon.
+
% XFROUT_RECEIVED_SHUTDOWN_COMMAND shutdown command received
The xfrout daemon received a shutdown command from the command channel
and will now shut down.
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 9ebd541..f636c0d 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -1,3 +1,3 @@
SUBDIRS = exceptions util log cryptolink dns cc config acl xfr bench \
asiolink asiodns nsas cache resolve testutils datasrc \
- server_common python dhcp statistics
+ server_common python dhcp dhcpsrv statistics
diff --git a/src/lib/datasrc/Makefile.am b/src/lib/datasrc/Makefile.am
index eccc147..f24d62c 100644
--- a/src/lib/datasrc/Makefile.am
+++ b/src/lib/datasrc/Makefile.am
@@ -26,6 +26,7 @@ lib_LTLIBRARIES = libb10-datasrc.la
libb10_datasrc_la_SOURCES = data_source.h
libb10_datasrc_la_SOURCES += rbnode_rrset.h
libb10_datasrc_la_SOURCES += rbtree.h
+libb10_datasrc_la_SOURCES += exceptions.h
libb10_datasrc_la_SOURCES += zonetable.h zonetable.cc
libb10_datasrc_la_SOURCES += zone.h zone_finder.cc zone_finder_context.cc
libb10_datasrc_la_SOURCES += result.h
diff --git a/src/lib/datasrc/client_list.cc b/src/lib/datasrc/client_list.cc
index e7fb63b..0750fb6 100644
--- a/src/lib/datasrc/client_list.cc
+++ b/src/lib/datasrc/client_list.cc
@@ -14,12 +14,14 @@
#include "client_list.h"
+#include "exceptions.h"
#include "client.h"
#include "factory.h"
#include "memory/memory_client.h"
#include "memory/zone_table_segment.h"
#include "memory/zone_writer.h"
#include "memory/zone_data_loader.h"
+#include "memory/zone_data_updater.h"
#include "logger.h"
#include <dns/masterload.h>
#include <util/memory_segment_local.h>
@@ -37,6 +39,7 @@ using boost::shared_ptr;
using boost::dynamic_pointer_cast;
using isc::datasrc::memory::InMemoryClient;
using isc::datasrc::memory::ZoneTableSegment;
+using isc::datasrc::memory::ZoneDataUpdater;
namespace isc {
namespace datasrc {
@@ -175,9 +178,9 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
try {
cache->load(origin,
paramConf->get(*it)->stringValue());
- } catch (const isc::dns::MasterLoadError& mle) {
- LOG_ERROR(logger, DATASRC_MASTERLOAD_ERROR)
- .arg(mle.what());
+ } catch (const ZoneLoaderException& e) {
+ LOG_ERROR(logger, DATASRC_LOAD_FROM_FILE_ERROR)
+ .arg(origin).arg(e.what());
}
} else {
ZoneIteratorPtr iterator;
@@ -192,7 +195,12 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
isc_throw(isc::Unexpected, "Got NULL iterator "
"for zone " << origin);
}
- cache->load(origin, *iterator);
+ try {
+ cache->load(origin, *iterator);
+ } catch (const ZoneLoaderException& e) {
+ LOG_ERROR(logger, DATASRC_LOAD_FROM_ITERATOR_ERROR)
+ .arg(origin).arg(e.what());
+ }
}
}
}
diff --git a/src/lib/datasrc/datasrc_messages.mes b/src/lib/datasrc/datasrc_messages.mes
index 94b4d42..3359d24 100644
--- a/src/lib/datasrc/datasrc_messages.mes
+++ b/src/lib/datasrc/datasrc_messages.mes
@@ -305,10 +305,15 @@ Therefore, the zone will not be available for this process. If this is
a problem, you should move the zone to some database backend (sqlite3, for
example) and use it from there.
-% DATASRC_MASTERLOAD_ERROR %1
-An error was found in the zone data for a MasterFiles zone. The zone
-is not loaded. The specific error is shown in the message, and should
-be addressed.
+% DATASRC_LOAD_FROM_FILE_ERROR Error loading zone %1: %2
+An error was found in the zone data when it was being loaded from a
+file. The zone was not loaded. The specific error is shown in the
+message, and should be addressed.
+
+% DATASRC_LOAD_FROM_ITERATOR_ERROR Error loading zone %1: %2
+An error was found in the zone data when it was being loaded from
+another data source. The zone was not loaded. The specific error is
+shown in the message, and should be addressed.
% DATASRC_MEM_ADD_RRSET adding RRset '%1/%2' into zone '%3'
Debug information. An RRset is being added to the in-memory data source.
diff --git a/src/lib/datasrc/exceptions.h b/src/lib/datasrc/exceptions.h
new file mode 100644
index 0000000..749b955
--- /dev/null
+++ b/src/lib/datasrc/exceptions.h
@@ -0,0 +1,47 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef DATASRC_EXCEPTIONS_H
+#define DATASRC_EXCEPTIONS_H 1
+
+#include <exceptions/exceptions.h>
+
+namespace isc {
+namespace datasrc {
+
+/// Base class for a number of exceptions that are thrown while working
+/// with zones.
+struct ZoneException : public Exception {
+ ZoneException(const char* file, size_t line, const char* what) :
+ Exception(file, line, what)
+ {}
+};
+
+/// Base class for a number of exceptions that are thrown when zones are
+/// being loaded. This is a recoverable exception. It should be possible
+/// to skip the bad zone and continue loading/serving other zones.
+struct ZoneLoaderException : public ZoneException {
+ ZoneLoaderException(const char* file, size_t line, const char* what) :
+ ZoneException(file, line, what)
+ {}
+};
+
+} // namespace datasrc
+} // namespace isc
+
+#endif // DATASRC_EXCEPTIONS
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/memory/memory_client.h b/src/lib/datasrc/memory/memory_client.h
index 3218c75..169421f 100644
--- a/src/lib/datasrc/memory/memory_client.h
+++ b/src/lib/datasrc/memory/memory_client.h
@@ -87,11 +87,11 @@ public:
/// current content. The masterfile parsing ability is kind of limited,
/// see isc::dns::masterLoad.
///
- /// This throws isc::dns::MasterLoadError if there is problem with loading
- /// (missing file, malformed, it contains different zone, etc - see
- /// isc::dns::masterLoad for details).
+ /// This throws isc::dns::MasterLoadError or AddError if there are
+ /// problems with loading (missing file, malformed data, unexpected
+ /// zone, etc. - see isc::dns::masterLoad for details).
///
- /// In case of internal problems, OutOfZone, NullRRset or AssertError could
+ /// In case of internal problems, NullRRset or AssertError could
/// be thrown, but they should not be expected. Exceptions caused by
/// allocation may be thrown as well.
///
diff --git a/src/lib/datasrc/memory/zone_data_loader.cc b/src/lib/datasrc/memory/zone_data_loader.cc
index d759901..d0a43a3 100644
--- a/src/lib/datasrc/memory/zone_data_loader.cc
+++ b/src/lib/datasrc/memory/zone_data_loader.cc
@@ -207,7 +207,11 @@ void
masterLoadWrapper(const char* const filename, const Name& origin,
const RRClass& zone_class, LoadCallback callback)
{
- masterLoad(filename, origin, zone_class, boost::bind(callback, _1));
+ try {
+ masterLoad(filename, origin, zone_class, boost::bind(callback, _1));
+ } catch (MasterLoadError& e) {
+ isc_throw(ZoneLoaderException, e.what());
+ }
}
// The installer called from the iterator version of loadZoneData().
diff --git a/src/lib/datasrc/memory/zone_data_loader.h b/src/lib/datasrc/memory/zone_data_loader.h
index 6f02fcb..6b409ec 100644
--- a/src/lib/datasrc/memory/zone_data_loader.h
+++ b/src/lib/datasrc/memory/zone_data_loader.h
@@ -15,6 +15,7 @@
#ifndef DATASRC_ZONE_DATA_LOADER_H
#define DATASRC_ZONE_DATA_LOADER_H 1
+#include <datasrc/exceptions.h>
#include <datasrc/memory/zone_data.h>
#include <datasrc/iterator.h>
#include <dns/name.h>
@@ -29,9 +30,9 @@ namespace memory {
///
/// This is thrown if an empty zone would be created during
/// \c loadZoneData().
-struct EmptyZone : public InvalidParameter {
+struct EmptyZone : public ZoneLoaderException {
EmptyZone(const char* file, size_t line, const char* what) :
- InvalidParameter(file, line, what)
+ ZoneLoaderException(file, line, what)
{}
};
diff --git a/src/lib/datasrc/memory/zone_data_updater.cc b/src/lib/datasrc/memory/zone_data_updater.cc
index 037eeb4..3df8c66 100644
--- a/src/lib/datasrc/memory/zone_data_updater.cc
+++ b/src/lib/datasrc/memory/zone_data_updater.cc
@@ -158,7 +158,7 @@ ZoneDataUpdater::validate(const isc::dns::ConstRRsetPtr rrset) const {
LOG_ERROR(logger,
DATASRC_MEMORY_MEM_OUT_OF_ZONE).arg(rrset->getName()).
arg(zone_name_);
- isc_throw(OutOfZone,
+ isc_throw(AddError,
"The name " << rrset->getName() <<
" is not contained in zone " << zone_name_);
}
diff --git a/src/lib/datasrc/memory/zone_data_updater.h b/src/lib/datasrc/memory/zone_data_updater.h
index 341d8ae..fa9a6af 100644
--- a/src/lib/datasrc/memory/zone_data_updater.h
+++ b/src/lib/datasrc/memory/zone_data_updater.h
@@ -15,6 +15,7 @@
#ifndef DATASRC_ZONE_DATA_UPDATER_H
#define DATASRC_ZONE_DATA_UPDATER_H 1
+#include <datasrc/exceptions.h>
#include <datasrc/memory/zone_data.h>
#include <datasrc/memory/rdata_serialization.h>
#include <dns/name.h>
@@ -94,14 +95,9 @@ public:
///
/// This is thrown against general error cases in adding an RRset
/// to the zone.
- ///
- /// Note: this exception would cover cases for \c OutOfZone or
- /// \c NullRRset. We'll need to clarify and unify the granularity
- /// of exceptions eventually. For now, exceptions are added as
- /// developers see the need for it.
- struct AddError : public InvalidParameter {
+ struct AddError : public ZoneLoaderException {
AddError(const char* file, size_t line, const char* what) :
- InvalidParameter(file, line, what)
+ ZoneLoaderException(file, line, what)
{}
};
diff --git a/src/lib/datasrc/tests/client_list_unittest.cc b/src/lib/datasrc/tests/client_list_unittest.cc
index d1ff852..6769e9b 100644
--- a/src/lib/datasrc/tests/client_list_unittest.cc
+++ b/src/lib/datasrc/tests/client_list_unittest.cc
@@ -827,27 +827,48 @@ TEST_F(ListTest, masterFiles) {
}
TEST_F(ListTest, BadMasterFile) {
- // Configure two zone correctly, and one with the wrong origin
- // (resulting in an out-of-zone data error)
- // Configuration should succeed, and the correct zones should
- // be loaded. Neither the 'bad' origin or the zone it used
- // should be loaded
+ // Configuration should succeed, and the good zones in the list
+ // below should be loaded. No bad zones should be loaded.
const ConstElementPtr elem(Element::fromJSON("["
"{"
" \"type\": \"MasterFiles\","
" \"cache-enable\": true,"
" \"params\": {"
+
+ // good zone
" \"example.com.\": \"" TEST_DATA_DIR "/example.com.flattened\","
+
+ // bad zone (empty file)
+ " \"example.net.\": \"" TEST_DATA_DIR "/example.net-empty\","
+
+ // bad zone (data doesn't validate: see the file for details)
+ " \"example.edu.\": \"" TEST_DATA_DIR "/example.edu-broken\","
+
+ // bad zone (file doesn't exist)
+ " \"example.info.\": \"" TEST_DATA_DIR "/example.info-nonexist\","
+
+ // bad zone (data doesn't match the zone name)
" \"foo.bar.\": \"" TEST_DATA_DIR "/example.org.nsec3-signed\","
+
+ // good zone
" \".\": \"" TEST_DATA_DIR "/root.zone\""
+
" }"
"}]"));
- list_->configure(elem, true);
+
+ EXPECT_NO_THROW({
+ // This should not throw even if there are any zone loading
+ // errors.
+ list_->configure(elem, true);
+ });
positiveResult(list_->find(Name("example.com."), true), ds_[0],
Name("example.com."), true, "example.com", true);
EXPECT_TRUE(negative_result_ == list_->find(Name("example.org."), true));
EXPECT_TRUE(negative_result_ == list_->find(Name("foo.bar"), true));
+ EXPECT_TRUE(negative_result_ == list_->find(Name("example.net."), true));
+ EXPECT_TRUE(negative_result_ == list_->find(Name("example.edu."), true));
+ EXPECT_TRUE(negative_result_ == list_->find(Name("example.info."), true));
positiveResult(list_->find(Name(".")), ds_[0], Name("."), true, "root",
true);
}
diff --git a/src/lib/datasrc/tests/memory/memory_client_unittest.cc b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
index c1d2f30..38f6eff 100644
--- a/src/lib/datasrc/tests/memory/memory_client_unittest.cc
+++ b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
@@ -186,7 +186,7 @@ TEST_F(MemoryClientTest, loadRRsetDoesntMatchOrigin) {
// in an exception.
EXPECT_THROW(client_->load(Name("example.com"),
TEST_DATA_DIR "/example.org-empty.zone"),
- MasterLoadError);
+ ZoneLoaderException);
}
TEST_F(MemoryClientTest, loadErrorsInParsingZoneMustNotLeak1) {
@@ -195,7 +195,7 @@ TEST_F(MemoryClientTest, loadErrorsInParsingZoneMustNotLeak1) {
// allocations.
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR "/example.org-broken1.zone"),
- MasterLoadError);
+ ZoneLoaderException);
// Teardown checks for memory segment leaks
}
@@ -205,14 +205,14 @@ TEST_F(MemoryClientTest, loadErrorsInParsingZoneMustNotLeak2) {
// allocations.
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR "/example.org-broken2.zone"),
- MasterLoadError);
+ ZoneLoaderException);
// Teardown checks for memory segment leaks
}
TEST_F(MemoryClientTest, loadNonExistentZoneFile) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR "/somerandomfilename"),
- MasterLoadError);
+ ZoneLoaderException);
// Teardown checks for memory segment leaks
}
@@ -478,7 +478,7 @@ TEST_F(MemoryClientTest, loadOutOfZoneThrows) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-out-of-zone.zone"),
- MasterLoadError);
+ ZoneLoaderException);
// Teardown checks for memory segment leaks
}
diff --git a/src/lib/datasrc/tests/testdata/example.edu-broken b/src/lib/datasrc/tests/testdata/example.edu-broken
new file mode 100644
index 0000000..dde11cf
--- /dev/null
+++ b/src/lib/datasrc/tests/testdata/example.edu-broken
@@ -0,0 +1,11 @@
+example.edu. 3600 IN SOA ns1.example.edu. admin.example.edu. 1234 3600 1800 2419200 7200
+example.edu. 3600 IN NS ns1.example.edu.
+example.edu. 3600 IN NS ns2.example.edu.
+example.edu. 3600 IN MX 10 mail.example.edu.
+www.example.edu. 3600 IN A 192.0.2.1
+ns1.example.edu. 3600 IN A 192.0.2.3
+ns2.example.edu. 3600 IN A 192.0.2.4
+
+;; DNAME + NS (non-apex) throws ZoneDataUpdater::AddError
+ns1.example.edu. 3600 IN DNAME foo.example.edu.
+ns1.example.edu. 3600 IN NS bar.example.edu.
diff --git a/src/lib/datasrc/tests/testdata/example.net-empty b/src/lib/datasrc/tests/testdata/example.net-empty
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/src/lib/datasrc/tests/testdata/example.net-empty
@@ -0,0 +1 @@
+
diff --git a/src/lib/datasrc/zone.h b/src/lib/datasrc/zone.h
index 9572ed0..0d7438d 100644
--- a/src/lib/datasrc/zone.h
+++ b/src/lib/datasrc/zone.h
@@ -19,6 +19,7 @@
#include <dns/rrset.h>
#include <dns/rrtype.h>
+#include <datasrc/exceptions.h>
#include <datasrc/result.h>
#include <utility>
@@ -31,10 +32,10 @@ namespace datasrc {
///
/// This is thrown when a method is called for a name or RRset which
/// is not in or below the zone.
-class OutOfZone : public Exception {
+class OutOfZone : public ZoneException {
public:
OutOfZone(const char* file, size_t line, const char* what) :
- isc::Exception(file, line, what) {}
+ ZoneException(file, line, what) {}
};
/// \brief The base class to search a zone for RRsets
diff --git a/src/lib/dhcp/Makefile.am b/src/lib/dhcp/Makefile.am
index 017a13e..1c74446 100644
--- a/src/lib/dhcp/Makefile.am
+++ b/src/lib/dhcp/Makefile.am
@@ -2,10 +2,6 @@ SUBDIRS = . tests
AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
AM_CPPFLAGS += $(BOOST_INCLUDES)
-if HAVE_MYSQL
-AM_CPPFLAGS += $(MYSQL_CPPFLAGS)
-endif
-
AM_CXXFLAGS = $(B10_CXXFLAGS)
# Some versions of GCC warn about some versions of Boost regarding
@@ -16,13 +12,14 @@ AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
CLEANFILES = *.gcno *.gcda
-lib_LTLIBRARIES = libb10-dhcp++.la libb10-dhcpsrv.la
+lib_LTLIBRARIES = libb10-dhcp++.la
libb10_dhcp___la_SOURCES =
-libb10_dhcp___la_SOURCES += libdhcp++.cc libdhcp++.h
+libb10_dhcp___la_SOURCES += duid.cc duid.h
libb10_dhcp___la_SOURCES += iface_mgr.cc iface_mgr.h
libb10_dhcp___la_SOURCES += iface_mgr_bsd.cc
libb10_dhcp___la_SOURCES += iface_mgr_linux.cc
libb10_dhcp___la_SOURCES += iface_mgr_sun.cc
+libb10_dhcp___la_SOURCES += libdhcp++.cc libdhcp++.h
libb10_dhcp___la_SOURCES += option.cc option.h
libb10_dhcp___la_SOURCES += option_data_types.h
libb10_dhcp___la_SOURCES += option_definition.cc option_definition.h
@@ -42,38 +39,10 @@ libb10_dhcp___la_LIBADD = $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
libb10_dhcp___la_LIBADD += $(top_builddir)/src/lib/util/libb10-util.la
libb10_dhcp___la_LDFLAGS = -no-undefined -version-info 2:0:0
-libb10_dhcpsrv_la_SOURCES =
-libb10_dhcpsrv_la_SOURCES += addr_utilities.cc addr_utilities.h
-libb10_dhcpsrv_la_SOURCES += alloc_engine.cc alloc_engine.h
-libb10_dhcpsrv_la_SOURCES += cfgmgr.cc cfgmgr.h
-libb10_dhcpsrv_la_SOURCES += duid.cc duid.h
-libb10_dhcpsrv_la_SOURCES += lease_mgr.cc lease_mgr.h
-libb10_dhcpsrv_la_SOURCES += lease_mgr_factory.cc lease_mgr_factory.h
-libb10_dhcpsrv_la_SOURCES += memfile_lease_mgr.cc memfile_lease_mgr.h
-if HAVE_MYSQL
-libb10_dhcpsrv_la_SOURCES += mysql_lease_mgr.cc mysql_lease_mgr.h
-endif
-libb10_dhcpsrv_la_SOURCES += pool.cc pool.h
-libb10_dhcpsrv_la_SOURCES += subnet.cc subnet.h
-libb10_dhcpsrv_la_SOURCES += triplet.h
-
-libb10_dhcpsrv_la_CXXFLAGS = $(AM_CXXFLAGS)
-libb10_dhcpsrv_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
-libb10_dhcpsrv_la_LIBADD = $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
-libb10_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/util/libb10-util.la
-libb10_dhcpsrv_la_LDFLAGS = -no-undefined -version-info 2:0:0
-if HAVE_MYSQL
-libb10_dhcpsrv_la_LDFLAGS += $(MYSQL_LIBS)
-endif
-
-EXTRA_DIST = README database_backends.dox
+EXTRA_DIST = README
if USE_CLANGPP
# Disable unused parameter warning caused by some of the
# Boost headers when compiling with clang.
libb10_dhcp___la_CXXFLAGS += -Wno-unused-parameter
endif
-
-# Distribute MySQL schema creation script
-EXTRA_DIST += dhcpdb_create.mysql
-dist_pkgdata_DATA = dhcpdb_create.mysql
diff --git a/src/lib/dhcp/addr_utilities.cc b/src/lib/dhcp/addr_utilities.cc
deleted file mode 100644
index 6ac3f14..0000000
--- a/src/lib/dhcp/addr_utilities.cc
+++ /dev/null
@@ -1,188 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <string.h>
-#include <exceptions/exceptions.h>
-#include <dhcp/addr_utilities.h>
-
-using namespace isc;
-using namespace isc::asiolink;
-
-namespace {
-
-/// @brief mask used for first/last address calculation in a IPv4 prefix
-///
-/// Using a static mask is faster than calculating it dynamically every time.
-const uint32_t bitMask4[] = { 0xffffffff, 0x7fffffff, 0x3fffffff, 0x1fffffff,
- 0x0fffffff, 0x07ffffff, 0x03ffffff, 0x01ffffff,
- 0x00ffffff, 0x007fffff, 0x003fffff, 0x001fffff,
- 0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff,
- 0x0000ffff, 0x00007fff, 0x00003fff, 0x00001fff,
- 0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff,
- 0x000000ff, 0x0000007f, 0x0000003f, 0x0000001f,
- 0x0000000f, 0x00000007, 0x00000003, 0x00000001,
- 0x00000000 };
-
-/// @brief mask used for first/last address calculation in a IPv6 prefix
-const uint8_t bitMask6[]= { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
-
-/// @brief calculates the first IPv6 address in a IPv6 prefix
-///
-/// Note: This is a private function. Do not use it directly.
-/// Please use firstAddrInPrefix() instead.
-///
-/// @param prefix IPv6 prefix
-/// @param len prefix length
-isc::asiolink::IOAddress firstAddrInPrefix6(const isc::asiolink::IOAddress& prefix,
- uint8_t len) {
- if (len > 128) {
- isc_throw(isc::BadValue,
- "Too large netmask. 0..128 is allowed in IPv6");
- }
-
- // 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
- // part. Otherwise we need to handle the byte that has to be partially
- // zeroed.
- if (len % 8 != 0) {
-
- // Get the appropriate mask. It has relevant bits (those that should
- // stay) set and irrelevant (those that should be wiped) cleared.
- uint8_t mask = bitMask6[len % 8];
-
- // Let's leave only whatever the mask says should not be cleared.
- packed[len / 8] = packed[len / 8] & mask;
-
- // Since we have just dealt with this byte, let's move the prefix length
- // to the beginning of the next byte (len is expressed in bits).
- len = (len / 8 + 1) * 8;
- }
-
- // Clear out the remaining bits.
- for (int i = len / 8; i < sizeof(packed); ++i) {
- packed[i] = 0x0;
- }
-
- // Finally, let's wrap this into nice and easy IOAddress object.
- return (isc::asiolink::IOAddress::from_bytes(AF_INET6, packed));
-}
-
-/// @brief calculates the first IPv4 address in a IPv4 prefix
-///
-/// Note: This is a private function. Do not use it directly.
-/// Please use firstAddrInPrefix() instead.
-///
-/// @param prefix IPv4 prefix
-/// @param len netmask length (0-32)
-isc::asiolink::IOAddress firstAddrInPrefix4(const isc::asiolink::IOAddress& prefix,
- uint8_t len) {
- if (len > 32) {
- isc_throw(isc::BadValue, "Too large netmask. 0..32 is allowed in IPv4");
- }
-
- uint32_t addr = prefix;
- return (IOAddress(addr & (~bitMask4[len])));
-}
-
-/// @brief calculates the last IPv4 address in a IPv4 prefix
-///
-/// Note: This is a private function. Do not use it directly.
-/// Please use firstAddrInPrefix() instead.
-///
-/// @param prefix IPv4 prefix that we calculate first address for
-/// @param len netmask length (0-32)
-isc::asiolink::IOAddress lastAddrInPrefix4(const isc::asiolink::IOAddress& prefix,
- uint8_t len) {
- if (len > 32) {
- isc_throw(isc::BadValue, "Too large netmask. 0..32 is allowed in IPv4");
- }
-
- uint32_t addr = prefix;
- return (IOAddress(addr | bitMask4[len]));
-}
-
-/// @brief calculates the last IPv6 address in a IPv6 prefix
-///
-/// Note: This is a private function. Do not use it directly.
-/// Please use lastAddrInPrefix() instead.
-///
-/// @param prefix IPv6 prefix that we calculate first address for
-/// @param len netmask length (0-128)
-isc::asiolink::IOAddress lastAddrInPrefix6(const isc::asiolink::IOAddress& prefix,
- uint8_t len) {
- if (len > 128) {
- isc_throw(isc::BadValue,
- "Too large netmask. 0..128 is allowed in IPv6");
- }
-
- // 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
- // with ones. Otherwise we need to handle the byte that has to be partially
- // zeroed.
- if (len % 8 != 0) {
- // Get the appropriate mask. It has relevant bits (those that should
- // stay) set and irrelevant (those that should be set to 1) cleared.
- uint8_t mask = bitMask6[len % 8];
-
- // Let's set those irrelevant bits with 1. It would be perhaps
- // easier to not use negation here and invert bitMask6 content. However,
- // with this approach, we can use the same mask in first and last
- // address calculations.
- packed[len / 8] = packed[len / 8] | ~mask;
-
- // Since we have just dealt with this byte, let's move the prefix length
- // to the beginning of the next byte (len is expressed in bits).
- len = (len / 8 + 1) * 8;
- }
-
- // Finally set remaining bits to 1.
- for (int i = len / 8; i < sizeof(packed); ++i) {
- packed[i] = 0xff;
- }
-
- // Finally, let's wrap this into nice and easy IOAddress object.
- return (isc::asiolink::IOAddress::from_bytes(AF_INET6, packed));
-}
-
-}; // end of anonymous namespace
-
-namespace isc {
-namespace dhcp {
-
-isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefix,
- uint8_t len) {
- if (prefix.getFamily() == AF_INET) {
- return firstAddrInPrefix4(prefix, len);
- } else {
- return firstAddrInPrefix6(prefix, len);
- }
-}
-
-isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix,
- uint8_t len) {
- if (prefix.getFamily() == AF_INET) {
- return lastAddrInPrefix4(prefix, len);
- } else {
- return lastAddrInPrefix6(prefix, len);
- }
-}
-
-};
-};
diff --git a/src/lib/dhcp/addr_utilities.h b/src/lib/dhcp/addr_utilities.h
deleted file mode 100644
index a1d856c..0000000
--- a/src/lib/dhcp/addr_utilities.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef ADDR_UTILITIES_H
-#define ADDR_UTILITIES_H
-
-#include <asiolink/io_address.h>
-
-namespace isc {
-namespace dhcp {
-
-/// This code is based on similar code from the Dibbler project. I, Tomasz Mrugalski,
-/// as a sole creator of that code hereby release it under BSD license for the benefit
-/// of the BIND10 project.
-
-/// @brief returns a first address in a given prefix
-///
-/// Example: For 2001:db8:1::deaf:beef and length /120 the function will return
-/// 2001:db8:1::dead:be00. See also @ref lastAddrInPrefix.
-///
-/// @todo It currently works for v6 only and will throw if v4 address is passed.
-///
-/// @param prefix and address that belongs to a prefix
-/// @param len prefix length
-///
-/// @return first address from a prefix
-isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefix,
- uint8_t len);
-
-/// @brief returns a last address in a given prefix
-///
-/// Example: For 2001:db8:1::deaf:beef and length /112 the function will return
-/// 2001:db8:1::dead:ffff. See also @ref firstAddrInPrefix.
-///
-/// @todo It currently works for v6 only and will throw if v4 address is passed.
-///
-/// @param prefix and address that belongs to a prefix
-/// @param len prefix length
-///
-/// @return first address from a prefix
-isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix,
- uint8_t len);
-
-};
-};
-
-#endif // ADDR_UTILITIES_H
diff --git a/src/lib/dhcp/alloc_engine.cc b/src/lib/dhcp/alloc_engine.cc
deleted file mode 100644
index 53ef7f3..0000000
--- a/src/lib/dhcp/alloc_engine.cc
+++ /dev/null
@@ -1,276 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <alloc_engine.h>
-#include <lease_mgr_factory.h>
-#include <string.h>
-
-#include <cstring>
-
-using namespace isc::asiolink;
-
-namespace isc {
-namespace dhcp {
-
-AllocEngine::IterativeAllocator::IterativeAllocator()
- :Allocator() {
-}
-
-isc::asiolink::IOAddress
-AllocEngine::IterativeAllocator::increaseAddress(const isc::asiolink::IOAddress& addr) {
- uint8_t packed[V6ADDRESS_LEN];
- int len;
-
- // First we copy the whole address as 16 bytes.
- if (addr.getFamily()==AF_INET) {
- // IPv4
- std::memcpy(packed, addr.getAddress().to_v4().to_bytes().data(), 4);
- len = 4;
- } else {
- // IPv6
- std::memcpy(packed, addr.getAddress().to_v6().to_bytes().data(), 16);
- len = 16;
- }
-
- for (int i = len - 1; i >= 0; --i) {
- ++packed[i];
- if (packed[i] != 0) {
- break;
- }
- }
-
- return (IOAddress::from_bytes(addr.getFamily(), packed));
-}
-
-
-isc::asiolink::IOAddress
-AllocEngine::IterativeAllocator::pickAddress(const Subnet6Ptr& subnet,
- const DuidPtr&,
- const IOAddress&) {
-
- // Let's get the last allocated address. It is usually set correctly,
- // but there are times when it won't be (like after removing a pool or
- // perhaps restaring the server).
- IOAddress last = subnet->getLastAllocated();
-
- const Pool6Collection& pools = subnet->getPools();
-
- if (pools.size() == 0) {
- isc_throw(AllocFailed, "No pools defined in selected subnet");
- }
-
- // first we need to find a pool the last address belongs to.
- Pool6Collection::const_iterator it;
- for (it = pools.begin(); it != pools.end(); ++it) {
- if ((*it)->inRange(last)) {
- break;
- }
- }
-
- // last one was bogus for one of several reasons:
- // - we just booted up and that's the first address we're allocating
- // - a subnet was removed or other reconfiguration just completed
- // - perhaps allocation algorithm was changed
- if (it == pools.end()) {
- // ok to access first element directly. We checked that pools is non-empty
- IOAddress next = pools[0]->getFirstAddress();
- subnet->setLastAllocated(next);
- return (next);
- }
-
- // Ok, we have a pool that the last address belonged to, let's use it.
-
- IOAddress next = increaseAddress(last); // basically addr++
- if ((*it)->inRange(next)) {
- // the next one is in the pool as well, so we haven't hit pool boundary yet
- subnet->setLastAllocated(next);
- return (next);
- }
-
- // We hit pool boundary, let's try to jump to the next pool and try again
- ++it;
- if (it == pools.end()) {
- // Really out of luck today. That was the last pool. Let's rewind
- // to the beginning.
- next = pools[0]->getFirstAddress();
- subnet->setLastAllocated(next);
- return (next);
- }
-
- // there is a next pool, let's try first adddress from it
- next = (*it)->getFirstAddress();
- subnet->setLastAllocated(next);
- return (next);
-}
-
-AllocEngine::HashedAllocator::HashedAllocator()
- :Allocator() {
- isc_throw(NotImplemented, "Hashed allocator is not implemented");
-}
-
-
-isc::asiolink::IOAddress
-AllocEngine::HashedAllocator::pickAddress(const Subnet6Ptr&,
- const DuidPtr&,
- const IOAddress&) {
- isc_throw(NotImplemented, "Hashed allocator is not implemented");
-}
-
-AllocEngine::RandomAllocator::RandomAllocator()
- :Allocator() {
- isc_throw(NotImplemented, "Random allocator is not implemented");
-}
-
-
-isc::asiolink::IOAddress
-AllocEngine::RandomAllocator::pickAddress(const Subnet6Ptr&,
- const DuidPtr&,
- const IOAddress&) {
- isc_throw(NotImplemented, "Random allocator is not implemented");
-}
-
-
-AllocEngine::AllocEngine(AllocType engine_type, unsigned int attempts)
- :attempts_(attempts) {
- switch (engine_type) {
- case ALLOC_ITERATIVE:
- allocator_ = boost::shared_ptr<Allocator>(new IterativeAllocator());
- break;
- case ALLOC_HASHED:
- allocator_ = boost::shared_ptr<Allocator>(new HashedAllocator());
- break;
- case ALLOC_RANDOM:
- allocator_ = boost::shared_ptr<Allocator>(new RandomAllocator());
- break;
-
- default:
- isc_throw(BadValue, "Invalid/unsupported allocation algorithm");
- }
-}
-
-Lease6Ptr
-AllocEngine::allocateAddress6(const Subnet6Ptr& subnet,
- const DuidPtr& duid,
- uint32_t iaid,
- const IOAddress& hint,
- bool fake_allocation /* = false */ ) {
-
- // That check is not necessary. We create allocator in AllocEngine
- // constructor
- if (!allocator_) {
- isc_throw(InvalidOperation, "No allocator selected");
- }
-
- // check if there's existing lease for that subnet/duid/iaid combination.
- Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(*duid, iaid, subnet->getID());
- if (existing) {
- // we have a lease already. This is a returning client, probably after
- // his reboot.
- return (existing);
- }
-
- // check if the hint is in pool and is available
- if (subnet->inPool(hint)) {
- existing = LeaseMgrFactory::instance().getLease6(hint);
- if (!existing) {
- /// @todo: check if the hint is reserved once we have host support
- /// implemented
-
- // the hint is valid and not currently used, let's create a lease for it
- Lease6Ptr lease = createLease(subnet, duid, iaid, hint, fake_allocation);
-
- // It can happen that the lease allocation failed (we could have lost
- // the race condition. That means that the hint is lo longer usable and
- // we need to continue the regular allocation path.
- if (lease) {
- return (lease);
- }
- }
- }
-
- unsigned int i = attempts_;
- do {
- IOAddress candidate = allocator_->pickAddress(subnet, duid, hint);
-
- /// @todo: check if the address is reserved once we have host support
- /// implemented
-
- Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(candidate);
- // there's no existing lease for selected candidate, so it is
- // free. Let's allocate it.
- if (!existing) {
- Lease6Ptr lease = createLease(subnet, duid, iaid, candidate,
- fake_allocation);
- if (lease) {
- return (lease);
- }
-
- // Although the address was free just microseconds ago, it may have
- // been taken just now. If the lease insertion fails, we continue
- // allocation attempts.
- }
-
- // continue trying allocation until we run out of attempts
- // (or attempts are set to 0, which means infinite)
- --i;
- } while ( i || !attempts_);
-
- isc_throw(AllocFailed, "Failed to allocate address after " << attempts_
- << " tries");
-}
-
-Lease6Ptr AllocEngine::createLease(const Subnet6Ptr& subnet,
- const DuidPtr& duid,
- uint32_t iaid,
- const IOAddress& addr,
- bool fake_allocation /*= false */ ) {
-
- Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid, iaid,
- subnet->getPreferred(), subnet->getValid(),
- subnet->getT1(), subnet->getT2(), subnet->getID()));
-
- if (!fake_allocation) {
- // That is a real (REQUEST) allocation
- bool status = LeaseMgrFactory::instance().addLease(lease);
-
- if (status) {
-
- return (lease);
- } else {
- // One of many failures with LeaseMgr (e.g. lost connection to the
- // database, database failed etc.). One notable case for that
- // is that we are working in multi-process mode and we lost a race
- // (some other process got that address first)
- return (Lease6Ptr());
- }
- } else {
- // That is only fake (SOLICIT without rapid-commit) allocation
-
- // It is for advertise only. We should not insert the lease into LeaseMgr,
- // but rather check that we could have inserted it.
- Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(addr);
- if (!existing) {
- return (lease);
- } else {
- return (Lease6Ptr());
- }
- }
-}
-
-AllocEngine::~AllocEngine() {
- // no need to delete allocator. smart_ptr will do the trick for us
-}
-
-}; // end of isc::dhcp namespace
-}; // end of isc namespace
diff --git a/src/lib/dhcp/alloc_engine.h b/src/lib/dhcp/alloc_engine.h
deleted file mode 100644
index 496703a..0000000
--- a/src/lib/dhcp/alloc_engine.h
+++ /dev/null
@@ -1,228 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef ALLOC_ENGINE_H
-#define ALLOC_ENGINE_H
-
-#include <boost/shared_ptr.hpp>
-#include <boost/noncopyable.hpp>
-#include <dhcp/duid.h>
-#include <dhcp/subnet.h>
-#include <asiolink/io_address.h>
-#include <dhcp/lease_mgr.h>
-
-namespace isc {
-namespace dhcp {
-
-/// An exception that is thrown when allocation module fails (e.g. due to
-/// lack of available addresses)
-class AllocFailed : public isc::Exception {
-public:
-
- /// @brief constructor
- ///
- /// @param file name of the file, where exception occurred
- /// @param line line of the file, where exception occurred
- /// @param what text description of the issue that caused exception
- AllocFailed(const char* file, size_t line, const char* what)
- : isc::Exception(file, line, what) {}
-};
-
-/// @brief DHCPv4 and DHCPv6 allocation engine
-///
-/// This class represents DHCP allocation engine. It is responsible
-/// for picking subnets, choosing and allocating a lease, extending,
-/// renewing, releasing and possibly expiring leases.
-///
-/// @todo: Does not handle out of leases well
-/// @todo: Does not handle out of allocation attempts well
-class AllocEngine : public boost::noncopyable {
-protected:
-
- /// @brief base class for all address/prefix allocation algorithms
- ///
- /// This is an abstract class that should not be used directly, but rather
- /// specialized implementations should be used instead.
- class Allocator {
- public:
-
- /// @brief picks one address out of available pools in a given subnet
- ///
- /// This method returns one address from the available pools in the
- /// specified subnet. It should not check if the address is used or
- /// reserved - AllocEngine will check that and will call pickAddress
- /// again if necessary. The number of times this method is called will
- /// increase as the number of available leases will decrease.
- virtual isc::asiolink::IOAddress
- pickAddress(const Subnet6Ptr& subnet, const DuidPtr& duid,
- const isc::asiolink::IOAddress& hint) = 0;
-
- /// @brief virtual destructor
- virtual ~Allocator() {
- }
- protected:
- };
-
- /// @brief Address/prefix allocator that iterates over all addresses
- ///
- /// This class implements iterative algorithm that returns all addresses in
- /// a pool iteratively, one after another. Once the last address is reached,
- /// it starts allocating from the beginning of the first pool (i.e. it loops
- /// over).
- class IterativeAllocator : public Allocator {
- public:
-
- /// @brief default constructor
- ///
- /// Does not do anything
- IterativeAllocator();
-
- /// @brief returns the next address from pools in a subnet
- ///
- /// @param subnet next address will be returned from pool of that subnet
- /// @param duid Client's DUID (ignored)
- /// @param hint client's hint (ignored)
- /// @return the next address
- virtual isc::asiolink::IOAddress
- pickAddress(const Subnet6Ptr& subnet,
- const DuidPtr& duid,
- const isc::asiolink::IOAddress& hint);
- private:
-
- /// @brief returns an address by one
- /// @param addr address to be increased
- /// @return address increased by one
- isc::asiolink::IOAddress increaseAddress(const isc::asiolink::IOAddress& addr);
-
- };
-
- /// @brief Address/prefix allocator that gets an address based on a hash
- ///
- /// @todo: This is a skeleton class for now and is missing implementation.
- class HashedAllocator : public Allocator {
- public:
-
- /// @brief default constructor (does nothing)
- HashedAllocator();
-
- /// @brief returns an address based on hash calculated from client's DUID.
- ///
- /// @todo: Implement this method
- ///
- /// @param subnet an address will be picked from pool of that subnet
- /// @param duid Client's DUID
- /// @param hint a hint (last address that was picked)
- /// @return selected address
- virtual isc::asiolink::IOAddress pickAddress(const Subnet6Ptr& subnet,
- const DuidPtr& duid,
- const isc::asiolink::IOAddress& hint);
- };
-
- /// @brief Random allocator that picks address randomly
- ///
- /// @todo: This is a skeleton class for now and is missing implementation.
- class RandomAllocator : public Allocator {
- public:
-
- /// @brief default constructor (does nothing)
- RandomAllocator();
-
- /// @brief returns an random address from pool of specified subnet
- ///
- /// @todo: Implement this method
- ///
- /// @param subnet an address will be picked from pool of that subnet
- /// @param duid Client's DUID (ignored)
- /// @param hint the last address that was picked (ignored)
- /// @return a random address from the pool
- virtual isc::asiolink::IOAddress
- pickAddress(const Subnet6Ptr& subnet, const DuidPtr& duid,
- const isc::asiolink::IOAddress& hint);
- };
-
- public:
-
- /// @brief specifies allocation type
- typedef enum {
- ALLOC_ITERATIVE, // iterative - one address after another
- ALLOC_HASHED, // hashed - client's DUID/client-id is hashed
- ALLOC_RANDOM // random - an address is randomly selected
- } AllocType;
-
-
- /// @brief Default constructor.
- ///
- /// Instantiates necessary services, required to run DHCPv6 server.
- /// In particular, creates IfaceMgr that will be responsible for
- /// network interaction. Will instantiate lease manager, and load
- /// old or create new DUID.
- ///
- /// @param engine_type selects allocation algorithm
- /// @param attempts number of attempts for each lease allocation before
- /// we give up (0 means unlimited)
- AllocEngine(AllocType engine_type, unsigned int attempts);
-
- /// @brief Allocates an IPv6 lease
- ///
- /// This method uses currently selected allocator to pick an address from
- /// specified subnet, creates a lease for that address and then inserts
- /// it into LeaseMgr (if this allocation is not fake).
- ///
- /// @param subnet subnet the allocation should come from
- /// @param duid Client'd DUID
- /// @param iaid iaid field from the IA_NA container that client sent
- /// @param hint a hint that the client provided
- /// @param fake_allocation is this real i.e. REQUEST (false) or just picking
- /// an address for SOLICIT that is not really allocated (true)
- /// @return Allocated IPv6 lease (or NULL if allocation failed)
- Lease6Ptr
- allocateAddress6(const Subnet6Ptr& subnet,
- const DuidPtr& duid,
- uint32_t iaid,
- const isc::asiolink::IOAddress& hint,
- bool fake_allocation);
-
- /// @brief Destructor. Used during DHCPv6 service shutdown.
- virtual ~AllocEngine();
-private:
-
- /// @brief creates a lease and inserts it in LeaseMgr if necessary
- ///
- /// Creates a lease based on specified parameters and tries to insert it
- /// into the database. That may fail in some cases, i.e. when there is another
- /// allocation process and we lost a race to a specific lease.
- ///
- /// @param subnet subnet the lease is allocated from
- /// @param duid client's DUID
- /// @param iaid IAID from the IA_NA container the client sent to us
- /// @param addr an address that was selected and is confirmed to be available
- /// @param fake_allocation is this real i.e. REQUEST (false) or just picking
- /// an address for SOLICIT that is not really allocated (true)
- /// @return allocated lease (or NULL in the unlikely case of the lease just
- /// becomed unavailable)
- Lease6Ptr createLease(const Subnet6Ptr& subnet, const DuidPtr& duid,
- uint32_t iaid, const isc::asiolink::IOAddress& addr,
- bool fake_allocation = false);
-
- /// @brief a pointer to currently used allocator
- boost::shared_ptr<Allocator> allocator_;
-
- /// @brief number of attempts before we give up lease allocation (0=unlimited)
- unsigned int attempts_;
-};
-
-}; // namespace isc::dhcp
-}; // namespace isc
-
-#endif // ALLOC_ENGINE_H
diff --git a/src/lib/dhcp/cfgmgr.cc b/src/lib/dhcp/cfgmgr.cc
deleted file mode 100644
index 0e7c8f4..0000000
--- a/src/lib/dhcp/cfgmgr.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <asiolink/io_address.h>
-#include <dhcp/cfgmgr.h>
-
-using namespace isc::asiolink;
-using namespace isc::util;
-
-namespace isc {
-namespace dhcp {
-
-
-
-
-CfgMgr&
-CfgMgr::instance() {
- static CfgMgr cfg_mgr;
- return (cfg_mgr);
-}
-
-Subnet6Ptr
-CfgMgr::getSubnet6(const isc::asiolink::IOAddress& hint) {
-
- // If there's only one subnet configured, let's just use it
- // The idea is to keep small deployments easy. In a small network - one
- // router that also runs DHCPv6 server. Users specifies a single pool and
- // expects it to just work. Without this, the server would complain that it
- // doesn't have IP address on its interfaces that matches that
- // configuration. Such requirement makes sense in IPv4, but not in IPv6.
- // The server does not need to have a global address (using just link-local
- // is ok for DHCPv6 server) from the pool it serves.
- if ((subnets6_.size() == 1) && hint.getAddress().to_v6().is_link_local()) {
- return (subnets6_[0]);
- }
-
- // If there is more than one, we need to choose the proper one
- for (Subnet6Collection::iterator subnet = subnets6_.begin();
- subnet != subnets6_.end(); ++subnet) {
- if ((*subnet)->inRange(hint)) {
- return (*subnet);
- }
- }
-
- // sorry, we don't support that subnet
- return (Subnet6Ptr());
-}
-
-Subnet6Ptr CfgMgr::getSubnet6(OptionPtr /*interfaceId*/) {
- /// @todo: Implement get subnet6 by interface-id (for relayed traffic)
- isc_throw(NotImplemented, "Relayed DHCPv6 traffic is not supported yet.");
-}
-
-void CfgMgr::addSubnet6(const Subnet6Ptr& subnet) {
- /// @todo: Check that this new subnet does not cross boundaries of any
- /// other already defined subnet.
- subnets6_.push_back(subnet);
-}
-
-Subnet4Ptr
-CfgMgr::getSubnet4(const isc::asiolink::IOAddress& hint) {
-
- // If there's only one subnet configured, let's just use it
- // The idea is to keep small deployments easy. In a small network - one
- // router that also runs DHCPv6 server. Users specifies a single pool and
- // expects it to just work. Without this, the server would complain that it
- // doesn't have IP address on its interfaces that matches that
- // configuration. Such requirement makes sense in IPv4, but not in IPv6.
- // The server does not need to have a global address (using just link-local
- // is ok for DHCPv6 server) from the pool it serves.
- if (subnets4_.size() == 1) {
- return (subnets4_[0]);
- }
-
- // If there is more than one, we need to choose the proper one
- for (Subnet4Collection::iterator subnet = subnets4_.begin();
- subnet != subnets4_.end(); ++subnet) {
- if ((*subnet)->inRange(hint)) {
- return (*subnet);
- }
- }
-
- // sorry, we don't support that subnet
- return (Subnet4Ptr());
-}
-
-void CfgMgr::addSubnet4(const Subnet4Ptr& subnet) {
- /// @todo: Check that this new subnet does not cross boundaries of any
- /// other already defined subnet.
- subnets4_.push_back(subnet);
-}
-
-CfgMgr::CfgMgr() {
-}
-
-CfgMgr::~CfgMgr() {
-}
-
-}; // end of isc::dhcp namespace
-}; // end of isc namespace
diff --git a/src/lib/dhcp/cfgmgr.h b/src/lib/dhcp/cfgmgr.h
deleted file mode 100644
index ea8125f..0000000
--- a/src/lib/dhcp/cfgmgr.h
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef CFGMGR_H
-#define CFGMGR_H
-
-#include <string>
-#include <map>
-#include <vector>
-#include <boost/shared_ptr.hpp>
-#include <boost/noncopyable.hpp>
-#include <asiolink/io_address.h>
-#include <util/buffer.h>
-#include <dhcp/option.h>
-#include <dhcp/pool.h>
-#include <dhcp/subnet.h>
-
-namespace isc {
-namespace dhcp {
-
-
-/// @brief Configuration Manager
-///
-/// This singleton class holds the whole configuration for DHCPv4 and DHCPv6
-/// servers. It currently holds information about zero or more subnets6.
-/// Each subnet may contain zero or more pools. Pool4 and Pool6 is the most
-/// basic "chunk" of configuration. It contains a range of assigneable
-/// addresses.
-///
-/// Below is a sketch of configuration inheritance (not implemented yet).
-/// Let's investigate the following configuration:
-///
-/// preferred-lifetime 500;
-/// valid-lifetime 1000;
-/// subnet6 2001:db8:1::/48 {
-/// pool6 2001::db8:1::1 - 2001::db8:1::ff;
-/// };
-/// subnet6 2001:db8:2::/48 {
-/// valid-lifetime 2000;
-/// pool6 2001::db8:2::1 - 2001::db8:2::ff;
-/// };
-/// Parameters defined in a global scope are applicable to everything until
-/// they are overwritten in a smaller scope, in this case subnet6.
-/// In the example above, the first subnet6 has preferred lifetime of 500s
-/// and a valid lifetime of 1000s. The second subnet has preferred lifetime
-/// of 500s, but valid lifetime of 2000s.
-///
-/// Parameter inheritance is likely to be implemented in configuration handling
-/// routines, so there is no storage capability in a global scope for
-/// subnet-specific parameters.
-///
-/// @todo: Implement Subnet4 support (ticket #2237)
-/// @todo: Implement option definition support
-/// @todo: Implement parameter inheritance
-class CfgMgr : public boost::noncopyable {
-public:
-
- /// @brief returns a single instance of Configuration Manager
- ///
- /// CfgMgr is a singleton and this method is the only way of
- /// accessing it.
- static CfgMgr& instance();
-
- /// @brief get IPv6 subnet by address
- ///
- /// Finds a matching subnet, based on an address. This can be used
- /// in two cases: when trying to find an appropriate lease based on
- /// a) relay link address (that must be the address that is on link)
- /// b) our global address on the interface the message was received on
- /// (for directly connected clients)
- ///
- /// @param hint an address that belongs to a searched subnet
- Subnet6Ptr getSubnet6(const isc::asiolink::IOAddress& hint);
-
- /// @brief get IPv6 subnet by interface-id
- ///
- /// Another possibility to find a subnet is based on interface-id.
- ///
- /// @param interface_id content of interface-id option returned by a relay
- /// @todo This method is not currently supported.
- Subnet6Ptr getSubnet6(OptionPtr interface_id);
-
- /// @brief adds an IPv6 subnet
- void addSubnet6(const Subnet6Ptr& subnet);
-
- /// @todo: Add subnet6 removal routines. Currently it is not possible
- /// to remove subnets. The only case where subnet6 removal would be
- /// needed is a dynamic server reconfiguration - a use case that is not
- /// planned to be supported any time soon.
-
- /// @brief removes all subnets
- ///
- /// This method removes all existing subnets. It is used during
- /// reconfiguration - old configuration is wiped and new definitions
- /// are used to recreate subnets.
- ///
- /// @todo Implement more intelligent approach. Note that comparison
- /// between old and new configuration is tricky. For example: is
- /// 2000::/64 and 2000::/48 the same subnet or is it something
- /// completely new?
- void deleteSubnets6() {
- subnets6_.clear();
- }
-
- /// @brief get IPv4 subnet by address
- ///
- /// Finds a matching subnet, based on an address. This can be used
- /// in two cases: when trying to find an appropriate lease based on
- /// a) relay link address (that must be the address that is on link)
- /// b) our global address on the interface the message was received on
- /// (for directly connected clients)
- ///
- /// @param hint an address that belongs to a searched subnet
- Subnet4Ptr getSubnet4(const isc::asiolink::IOAddress& hint);
-
- /// @brief adds a subnet4
- void addSubnet4(const Subnet4Ptr& subnet);
-
- /// @brief removes all IPv4 subnets
- void removeSubnets4();
-protected:
-
- /// @brief Protected constructor.
- ///
- /// This constructor is protected for 2 reasons. First, it forbids any
- /// instantiations of this class (CfgMgr is a singleton). Second, it
- /// allows derived class to instantiate it. That is useful for testing
- /// purposes.
- CfgMgr();
-
- /// @brief virtual desctructor
- virtual ~CfgMgr();
-
- /// @brief a container for IPv6 subnets.
- ///
- /// That is a simple vector of pointers. It does not make much sense to
- /// optimize access time (e.g. using a map), because typical search
- /// pattern will use calling inRange() method on each subnet until
- /// a match is found.
- Subnet6Collection subnets6_;
-
- /// @brief a container for IPv4 subnets.
- ///
- /// That is a simple vector of pointers. It does not make much sense to
- /// optimize access time (e.g. using a map), because typical search
- /// pattern will use calling inRange() method on each subnet until
- /// a match is found.
- Subnet4Collection subnets4_;
-};
-
-} // namespace isc::dhcp
-} // namespace isc
-
-#endif // CFGMGR_H
diff --git a/src/lib/dhcp/database_backends.dox b/src/lib/dhcp/database_backends.dox
deleted file mode 100644
index 8eeb5c5..0000000
--- a/src/lib/dhcp/database_backends.dox
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- @page dhcp-database-backends DHCP Database Back-Ends
-
- All DHCP lease data is stored in some form of database, the interface
- to this being through the Lease Manager.
-
- All backend classes such as isc::dhcp::MySqlLeaseMgr are derived from
- the abstract isc::dhcp::LeaseMgr class. This provides methods to
- create, retrieve, modify and delete leases in the database.
-
- @section dhcpdb-instantiation Instantiation of Lease Managers
-
- A lease manager is instantiated through the LeaseMgrFactory class. This
- has three methods:
-
- - isc::dhcp::LeaseMgrFactory::create - Creates a singleton Lease
- Manager of the appropriate type.
- - isc::dhcp::LeaseMgrFactory::instance - Returns a reference to the
- the instance of the Lease Manager.
- - isc::dhcp::LeaseMgrFactory::destroy - Destroys the singleton lease manager.
-
- The selection of the Lease Manager (and thus the backend database) is
- controlled by the connection string passed to
- isc::dhcp::LeaseMgrFactory::create. This is a set of "keyword=value" pairs
- (no embedded spaces), each pair separated by a space from the others, e.g.
-
- \code
- type=mysql user=keatest password=keatest name=keatest host=localhost
- \endcode
-
- The following keywords are used for all backends:
-
- - <b>type</b> - specifies the type of database backend. The following values
- for the type keyword are supported:
- - <b>mysql</b> - Use MySQL as the database
-
- The following sections list the database-specific keywords:
-
- @subsection dhcpdb-keywords-mysql MySQL connection string keywords
-
- - <b>host</b> - host on which the selected database is running. If not
- supplied, "localhost" is assumed.
- - <b>name</b> - name of the MySQL database to access. There is no default -
- this must always be supplied.
- - <b>password</b> - password for the selected user ID (see below). If not
- specified, no password is used.
- - <b>user</b> - database user ID under which the database is accessed. If not
- specified, no user ID is used - the database is assumed to be open.
-
-
- @section dhcp-backend-unittest Running Unit Tests
-
- With the use of databases requiring separate authorisation, there are
- certain database-specific pre-requisites for successfully running the unit
- tests. These are listed in the following sections.
-
- @subsection dhcp-mysql-unittest MySQL
-
- A database called <i>keatest</i> needs to be set up using the MySQL
- <b>CREATE DATABASE</b> command. A database user, also called <i>keatest</i>
- (with a password <i>keatest</i>) must be given full privileges in that
- database. The unit tests create the schema in the database before each test
- and delete it afterwards.
- */
diff --git a/src/lib/dhcp/dhcpdb_create.mysql b/src/lib/dhcp/dhcpdb_create.mysql
deleted file mode 100644
index 7a292ec..0000000
--- a/src/lib/dhcp/dhcpdb_create.mysql
+++ /dev/null
@@ -1,115 +0,0 @@
-# Copyright (C) 2012 Internet Systems Consortium.
-#
-# Permission to use, copy, modify, and 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 INTERNET SYSTEMS CONSORTIUM
-# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# INTERNET SYSTEMS CONSORTIUM 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.
-
-# This is the BIND 10 DHCP schema specification for MySQL.
-#
-# The schema is reasonably portable (with the exception of the engine
-# specification, which is MySQL-specific). Minor changes might be needed for
-# other databases.
-
-# To create the schema, either type the command:
-#
-# mysql -u <user> -p <password> <database> < dhcpdb_create.mysql
-#
-# ... at the command prompt, or log in to the MySQL database and at the "mysql>"
-# prompt, issue the command:
-#
-# source dhcpdb_create.mysql
-
-
-# Holds the IPv4 leases.
-CREATE TABLE lease4 (
- address INT UNSIGNED PRIMARY KEY NOT NULL, # IPv4 address
- hwaddr VARBINARY(20), # Hardware address
- client_id VARBINARY(128), # Client ID
- lease_time INT UNSIGNED, # Length of the lease (seconds)
- expire TIMESTAMP, # Expiration time of the lease
- subnet_id INT UNSIGNED # Subnet identification
- ) ENGINE = INNODB;
-
-# Holds the IPv6 leases.
-# N.B. The use of a VARCHAR for the address is temporary for development:
-# it will eventually be replaced by BINARY(16).
-CREATE TABLE lease6 (
- address VARCHAR(40) PRIMARY KEY NOT NULL, # IPv6 address
- duid VARBINARY(128), # DUID
- valid_lifetime INT UNSIGNED, # Length of the lease (seconds)
- expire TIMESTAMP, # Expiration time of the lease
- subnet_id INT UNSIGNED, # Subnet identification
- pref_lifetime INT UNSIGNED, # Preferred lifetime
- lease_type TINYINT, # Lease type (see lease6_types
- # table for possible values)
- iaid INT UNSIGNED, # See Section 10 of RFC 3315
- prefix_len TINYINT UNSIGNED # For IA_PD only
- ) ENGINE = INNODB;
-
-# ... and a definition of lease6 types. This table is a convenience for
-# users of the database - if they want to view the lease table and use the
-# type names, they can join this table with the lease6 table
-CREATE TABLE lease6_types (
- lease_type TINYINT PRIMARY KEY NOT NULL, # Lease type code.
- name VARCHAR(5) # Name of the lease type
- );
-START TRANSACTION;
-INSERT INTO lease6_types VALUES (0, "IA_NA"); # Non-temporary v6 addresses
-INSERT INTO lease6_types VALUES (1, "IA_TA"); # Temporary v6 addresses
-INSERT INTO lease6_types VALUES (2, "IA_PD"); # Prefix delegations
-COMMIT;
-
-# Finally, the version of the schema. We start at 0.1 during development.
-# This table is only modified during schema upgrades. For historical reasons
-# (related to the names of the columns in the BIND 10 DNS database file), the
-# first column is called "version" and not "major".
-CREATE TABLE schema_version (
- version INT PRIMARY KEY NOT NULL, # Major version number
- minor INT # Minor version number
- );
-START TRANSACTION;
-INSERT INTO schema_version VALUES (0, 1);
-COMMIT;
-
-# Notes:
-#
-# Indexes
-# =======
-# It is likely that additional indexes will be needed. However, the
-# increase in lookup performance from these will come at the expense
-# of a decrease in performance during insert operations due to the need
-# to update the indexes. For this reason, the need for additional indexes
-# will be determined by experiment during performance tests.
-#
-# The most likely additional indexes will cover the following columns:
-#
-# expire
-# To speed up the deletion of expired leases from the database.
-#
-# hwaddr and client_id
-# For lease stability: if a client requests a new lease, try to find an
-# existing or recently expired lease for it so that it can keep using the
-# same IP address.
-#
-# Field Sizes
-# ===========
-# If any of the VARxxx field sizes are altered, the lengths in the MySQL
-# backend source file (mysql_lease_mgr.cc) must be correspondingly changed.
-#
-# Portability
-# ===========
-# The "ENGINE = INNODB" on some tables is not portablea to another database
-# and will need to be removed.
-#
-# Some columns contain binary data so are stored as VARBINARY instead of
-# VARCHAR. This may be non-portable between databases: in this case, the
-# definition should be changed to VARCHAR.
diff --git a/src/lib/dhcp/duid.cc b/src/lib/dhcp/duid.cc
index 01dcfe1..c3f46da 100644
--- a/src/lib/dhcp/duid.cc
+++ b/src/lib/dhcp/duid.cc
@@ -12,13 +12,15 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <dhcp/duid.h>
#include <exceptions/exceptions.h>
-#include <stdint.h>
#include <util/io_utilities.h>
-#include <dhcp/duid.h>
-#include <vector>
-#include <sstream>
+
#include <iomanip>
+#include <sstream>
+#include <vector>
+
+#include <stdint.h>
namespace isc {
namespace dhcp {
diff --git a/src/lib/dhcp/duid.h b/src/lib/dhcp/duid.h
index be575dd..001e362 100644
--- a/src/lib/dhcp/duid.h
+++ b/src/lib/dhcp/duid.h
@@ -16,7 +16,9 @@
#define DUID_H
#include <asiolink/io_address.h>
+
#include <vector>
+
#include <stdint.h>
#include <unistd.h>
diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc
index 1c2a11c..2f1199e 100644
--- a/src/lib/dhcp/iface_mgr.cc
+++ b/src/lib/dhcp/iface_mgr.cc
@@ -13,22 +13,27 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
-#include <sstream>
-#include <fstream>
-#include <string.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/select.h>
+
+// This must be included before udp_endpoint.h
#include <asio.hpp>
+#include <asiolink/io_error.h>
+#include <asiolink/udp_endpoint.h>
#include <dhcp/dhcp4.h>
#include <dhcp/dhcp6.h>
#include <dhcp/iface_mgr.h>
#include <exceptions/exceptions.h>
-#include <asiolink/udp_endpoint.h>
-#include <asiolink/io_error.h>
#include <util/io/pktinfo_utilities.h>
+
+#include <fstream>
+#include <sstream>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <sys/select.h>
+
using namespace std;
using namespace isc::asiolink;
using namespace isc::util::io::internal;
diff --git a/src/lib/dhcp/iface_mgr.h b/src/lib/dhcp/iface_mgr.h
index 1b15595..a669a6d 100644
--- a/src/lib/dhcp/iface_mgr.h
+++ b/src/lib/dhcp/iface_mgr.h
@@ -15,16 +15,18 @@
#ifndef IFACE_MGR_H
#define IFACE_MGR_H
-#include <list>
-#include <boost/shared_ptr.hpp>
-#include <boost/scoped_array.hpp>
-#include <boost/noncopyable.hpp>
#include <asiolink/io_address.h>
-#include <dhcp/dhcp6.h>
#include <dhcp/dhcp4.h>
+#include <dhcp/dhcp6.h>
#include <dhcp/pkt4.h>
#include <dhcp/pkt6.h>
+#include <boost/noncopyable.hpp>
+#include <boost/scoped_array.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <list>
+
namespace isc {
namespace dhcp {
diff --git a/src/lib/dhcp/iface_mgr_linux.cc b/src/lib/dhcp/iface_mgr_linux.cc
index d7ebe1a..38189aa 100644
--- a/src/lib/dhcp/iface_mgr_linux.cc
+++ b/src/lib/dhcp/iface_mgr_linux.cc
@@ -31,18 +31,17 @@
#if defined(OS_LINUX)
+#include <asiolink/io_address.h>
#include <dhcp/iface_mgr.h>
#include <exceptions/exceptions.h>
+#include <util/io/sockaddr_util.h>
+
+#include <boost/array.hpp>
+#include <boost/static_assert.hpp>
#include <stdint.h>
#include <net/if.h>
#include <linux/rtnetlink.h>
-#include <boost/array.hpp>
-#include <boost/static_assert.hpp>
-#include <dhcp/iface_mgr.h>
-#include <exceptions/exceptions.h>
-#include <asiolink/io_address.h>
-#include <util/io/sockaddr_util.h>
using namespace std;
using namespace isc;
diff --git a/src/lib/dhcp/lease_mgr.cc b/src/lib/dhcp/lease_mgr.cc
deleted file mode 100644
index c7dba6c..0000000
--- a/src/lib/dhcp/lease_mgr.cc
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <dhcp/lease_mgr.h>
-#include <exceptions/exceptions.h>
-
-#include <boost/foreach.hpp>
-#include <boost/algorithm/string.hpp>
-
-#include <algorithm>
-#include <iostream>
-#include <iterator>
-#include <map>
-#include <sstream>
-#include <string>
-
-#include <time.h>
-
-using namespace std;
-
-using namespace isc::dhcp;
-
-Lease6::Lease6(LeaseType type, const isc::asiolink::IOAddress& addr, DuidPtr duid,
- uint32_t iaid, uint32_t preferred, uint32_t valid, uint32_t t1,
- uint32_t t2, SubnetID subnet_id, uint8_t prefixlen)
- :type_(type), addr_(addr), prefixlen_(prefixlen), iaid_(iaid), duid_(duid),
- preferred_lft_(preferred), valid_lft_(valid), t1_(t1), t2_(t2),
- subnet_id_(subnet_id), fixed_(false), fqdn_fwd_(false),
- fqdn_rev_(false) {
- if (!duid) {
- isc_throw(InvalidOperation, "DUID must be specified for a lease");
- }
-
- cltt_ = time(NULL);
-}
-
-std::string LeaseMgr::getParameter(const std::string& name) const {
- ParameterMap::const_iterator param = parameters_.find(name);
- if (param == parameters_.end()) {
- isc_throw(BadValue, "Parameter not found");
- }
- return (param->second);
-}
-
-std::string
-Lease6::toText() {
- ostringstream stream;
-
- stream << "Type: " << static_cast<int>(type_) << " (";
- switch (type_) {
- case Lease6::LEASE_IA_NA:
- stream << "IA_NA)\n";
- break;
- case Lease6::LEASE_IA_TA:
- stream << "IA_TA)\n";
- break;
- case Lease6::LEASE_IA_PD:
- stream << "IA_PD)\n";
- break;
- default:
- stream << "unknown)\n";
- }
- stream << "Address: " << addr_.toText() << "\n"
- << "Prefix length: " << static_cast<int>(prefixlen_) << "\n"
- << "IAID: " << iaid_ << "\n"
- << "Pref life: " << preferred_lft_ << "\n"
- << "Valid life: " << valid_lft_ << "\n"
- << "Cltt: " << cltt_ << "\n"
- << "Subnet ID: " << subnet_id_ << "\n";
-
- return (stream.str());
-}
-
-bool
-Lease6::operator==(const Lease6& other) const {
- return (
- type_ == other.type_ &&
- addr_ == other.addr_ &&
- prefixlen_ == other.prefixlen_ &&
- iaid_ == other.iaid_ &&
- *duid_ == *other.duid_ &&
- preferred_lft_ == other.preferred_lft_ &&
- valid_lft_ == other.valid_lft_ &&
- cltt_ == other.cltt_ &&
- subnet_id_ == other.subnet_id_
- );
-}
diff --git a/src/lib/dhcp/lease_mgr.h b/src/lib/dhcp/lease_mgr.h
deleted file mode 100644
index 40c20cd..0000000
--- a/src/lib/dhcp/lease_mgr.h
+++ /dev/null
@@ -1,565 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef LEASE_MGR_H
-#define LEASE_MGR_H
-
-#include <asiolink/io_address.h>
-#include <dhcp/duid.h>
-#include <dhcp/option.h>
-#include <dhcp/subnet.h>
-#include <exceptions/exceptions.h>
-
-#include <boost/noncopyable.hpp>
-#include <boost/shared_ptr.hpp>
-
-#include <fstream>
-#include <map>
-#include <string>
-#include <utility>
-#include <vector>
-
-/// @file dhcp/lease_mgr.h
-/// @brief An abstract API for lease database
-///
-/// This file contains declarations of Lease4, Lease6 and LeaseMgr classes.
-/// They are essential components of the interface to any database backend.
-/// Each concrete database backend (e.g. MySQL) will define a class derived
-/// from LeaseMgr class.
-///
-/// Failover considerations:
-/// There are no intermediate plans to implement DHCPv4 failover
-/// (draft-ietf-dhc-failover-12.txt). Currently (Oct. 2012) the DHCPv6 failover
-/// is being defined in DHC WG in IETF (draft-ietf-dhcpv6-failover-requirements,
-/// draft-ietf-dhcpv6-dailover-design), but the work is not advanced enough
-/// for implementation plans yet. v4 failover requires additional parameters
-/// to be kept with a lease. It is likely that v6 failover will require similar
-/// fields. Such implementation will require database schema extension.
-/// We have designed a way to expand/upgrade schemas during upgrades: a database
-/// schema is versioned and sanity checks about required version will be done
-/// upon start and/or upgrade. With this mechanism in place, we can add new
-/// fields to the database. In particular we can use that capability to
-/// introduce failover related fields.
-///
-/// However, there is another approach that can be reliably used to provide
-/// failover, even without the actual failover protocol implemented. As the
-/// first backend will use MySQL, we will be able to use Multi-Master capability
-/// offered by MySQL and use two separatate Kea instances connecting to the
-/// same database.
-///
-/// Nevertheless, we hope to have failover protocol eventually implemented in
-/// the Kea.
-
-#include <iostream>
-
-namespace isc {
-namespace dhcp {
-
-/// @brief Exception thrown if name of database is not specified
-class NoDatabaseName : public Exception {
-public:
- NoDatabaseName(const char* file, size_t line, const char* what) :
- isc::Exception(file, line, what) {}
-};
-
-/// @brief Exception thrown on failure to open database
-class DbOpenError : public Exception {
-public:
- DbOpenError(const char* file, size_t line, const char* what) :
- isc::Exception(file, line, what) {}
-};
-
-/// @brief Exception thrown on failure to execute a database function
-class DbOperationError : public Exception {
-public:
- DbOperationError(const char* file, size_t line, const char* what) :
- isc::Exception(file, line, what) {}
-};
-
-/// @brief Attempt to update lease that was not there
-class NoSuchLease : public Exception {
-public:
- NoSuchLease(const char* file, size_t line, const char* what) :
- isc::Exception(file, line, what) {}
-};
-
-/// @brief Structure that holds a lease for IPv4 address
-///
-/// For performance reasons it is a simple structure, not a class. If we chose
-/// make it a class, all fields would have to made private and getters/setters
-/// would be required. As this is a critical part of the code that will be used
-/// extensively, direct access is warranted.
-struct Lease4 {
- /// IPv4 address
- isc::asiolink::IOAddress addr_;
-
- /// @brief Address extension
- ///
- /// It is envisaged that in some cases IPv4 address will be accompanied with some
- /// additional data. One example of such use are Address + Port solutions (or
- /// Port-restricted Addresses), where several clients may get the same address, but
- /// different port ranges. This feature is not expected to be widely used.
- /// Under normal circumstances, the value should be 0.
- uint32_t ext_;
-
- /// @brief hardware address
- std::vector<uint8_t> hwaddr_;
-
- /// @brief client identifier
- boost::shared_ptr<ClientId> client_id_;
-
- /// @brief renewal timer
- ///
- /// Specifies renewal time. Although technically it is a property of IA container,
- /// not the address itself, since our data model does not define separate IA
- /// entity, we are keeping it in the lease. In case of multiple addresses/prefixes
- /// for the same IA, each must have consistent T1 and T2 values. Specified in
- /// seconds since cltt.
- uint32_t t1_;
-
- /// @brief rebinding timer
- ///
- /// Specifies rebinding time. Although technically it is a property of IA container,
- /// not the address itself, since our data model does not define separate IA
- /// entity, we are keeping it in the lease. In case of multiple addresses/prefixes
- /// for the same IA, each must have consistent T1 and T2 values. Specified in
- /// seconds since cltt.
- uint32_t t2_;
-
- /// @brief valid lifetime
- ///
- /// Expressed as number of seconds since cltt
- uint32_t valid_lft_;
-
- /// @brief client last transmission time
- ///
- /// Specifies a timestamp, when last transmission from a client was received.
- time_t cltt_;
-
- /// @brief Subnet identifier
- ///
- /// Specifies subnet-id of the subnet that the lease belongs to
- SubnetID subnet_id_;
-
- /// @brief Is this a fixed lease?
- ///
- /// Fixed leases are kept after they are released/expired.
- bool fixed_;
-
- /// @brief client hostname
- ///
- /// This field may be empty
- std::string hostname_;
-
- /// @brief did we update AAAA record for this lease?
- bool fqdn_fwd_;
-
- /// @brief did we update PTR record for this lease?
- bool fqdn_rev_;
-
- /// @brief Lease comments.
- ///
- /// Currently not used. It may be used for keeping comments made by the
- /// system administrator.
- std::string comments_;
-
- /// @todo: Add DHCPv4 failover related fields here
-
- /// @brief Constructor
- ///
- /// Initialize fields that don't have a default constructor.
- /// @todo Remove this
- Lease4() : addr_(0) {}
-};
-
-/// @brief Pointer to a Lease4 structure.
-typedef boost::shared_ptr<Lease4> Lease4Ptr;
-
-/// @brief A collection of IPv4 leases.
-typedef std::vector< boost::shared_ptr<Lease4Ptr> > Lease4Collection;
-
-/// @brief Structure that holds a lease for IPv6 address and/or prefix
-///
-/// For performance reasons it is a simple structure, not a class. Had we chose to
-/// make it a class, all fields would have to be made private and getters/setters
-/// would be required. As this is a critical part of the code that will be used
-/// extensively, direct access rather than through getters/setters is warranted.
-struct Lease6 {
- typedef enum {
- LEASE_IA_NA, /// the lease contains non-temporary IPv6 address
- LEASE_IA_TA, /// the lease contains temporary IPv6 address
- LEASE_IA_PD /// the lease contains IPv6 prefix (for prefix delegation)
- } LeaseType;
-
- Lease6(LeaseType type, const isc::asiolink::IOAddress& addr, DuidPtr duid,
- uint32_t iaid, uint32_t preferred, uint32_t valid, uint32_t t1,
- uint32_t t2, SubnetID subnet_id, uint8_t prefixlen_ = 0);
-
- /// @brief specifies lease type (normal addr, temporary addr, prefix)
- LeaseType type_;
-
- /// IPv6 address
- isc::asiolink::IOAddress addr_;
-
- /// IPv6 prefix length (used only for PD)
- uint8_t prefixlen_;
-
- /// @brief IAID
- ///
- /// Identity Association IDentifier. DHCPv6 stores all addresses and prefixes
- /// in IA containers (IA_NA, IA_TA, IA_PD). Most containers may appear more
- /// than once in a message. To differentiate between them, IAID field is present
- uint32_t iaid_;
-
- /// @brief client identifier
- boost::shared_ptr<DUID> duid_;
-
- /// @brief preferred lifetime
- ///
- /// This parameter specifies preferred lifetime since the lease was assigned/renewed
- /// (cltt), expressed in seconds.
- uint32_t preferred_lft_;
-
- /// @brief valid lifetime
- ///
- /// This parameter specified valid lifetime since the lease was assigned/renewed
- /// (cltt), expressed in seconds.
- uint32_t valid_lft_;
-
- /// @brief T1 timer
- ///
- /// Specifies renewal time. Although technically it is a property of IA container,
- /// not the address itself, since our data model does not define separate IA
- /// entity, we are keeping it in the lease. In case of multiple addresses/prefixes
- /// for the same IA, each must have consistent T1 and T2 values. Specified in
- /// seconds since cltt.
- /// This value will also be useful for failover to calculate the next expected
- /// client transmission time.
- uint32_t t1_;
-
- /// @brief T2 timer
- ///
- /// Specifies rebinding time. Although technically it is a property of IA container,
- /// not the address itself, since our data model does not define separate IA
- /// entity, we are keeping it in the lease. In case of multiple addresses/prefixes
- /// for the same IA, each must have consistent T1 and T2 values. Specified in
- /// seconds since cltt.
- uint32_t t2_;
-
- /// @brief client last transmission time
- ///
- /// Specifies a timestamp, when last transmission from a client was received.
- time_t cltt_;
-
- /// @brief Subnet identifier
- ///
- /// Specifies subnet-id of the subnet that the lease belongs to
- SubnetID subnet_id_;
-
- /// @brief Is this a fixed lease?
- ///
- /// Fixed leases are kept after they are released/expired.
- bool fixed_;
-
- /// @brief client hostname
- ///
- /// This field may be empty
- std::string hostname_;
-
- /// @brief did we update AAAA record for this lease?
- bool fqdn_fwd_;
-
- /// @brief did we update PTR record for this lease?
- bool fqdn_rev_;
-
- /// @brief Lease comments
- ///
- /// This field is currently not used.
- std::string comments_;
-
- /// @todo: Add DHCPv6 failover related fields here
-
- /// @brief Constructor
- ///
- /// Initialize fields that don't have a default constructor.
- Lease6() : addr_("::") {}
-
- /// @brief Convert Lease6 to Printable Form
- ///
- /// @return String form of the lease
- std::string toText();
-
- /// @brief Compare two leases for equality
- ///
- /// @param other lease6 object with which to compare
- bool operator==(const Lease6& other) const;
-
- /// @brief Compare two leases for inequality
- ///
- /// @param other lease6 object with which to compare
- bool operator!=(const Lease6& other) const {
- return (!operator==(other));
- }
-
-};
-
-/// @brief Pointer to a Lease6 structure.
-typedef boost::shared_ptr<Lease6> Lease6Ptr;
-
-/// @brief Const pointer to a Lease6 structure.
-typedef boost::shared_ptr<const Lease6> ConstLease6Ptr;
-
-/// @brief A collection of IPv6 leases.
-typedef std::vector<Lease6Ptr> Lease6Collection;
-
-/// @brief Abstract Lease Manager
-///
-/// This is an abstract API for lease database backends. It provides unified
-/// interface to all backends. As this is an abstract class, it should not
-/// 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.
-class LeaseMgr {
-public:
- /// Client Hardware address
- typedef std::vector<uint8_t> HWAddr;
-
- /// Database configuration parameter map
- typedef std::map<std::string, std::string> ParameterMap;
-
- /// @brief Constructor
- ///
- /// @param parameters A data structure relating keywords and values
- /// concerned with the database.
- LeaseMgr(const ParameterMap& parameters) : parameters_(parameters)
- {}
-
- /// @brief Destructor
- virtual ~LeaseMgr()
- {}
-
- /// @brief Adds an IPv4 lease.
- ///
- /// @param lease lease to be added
- ///
- /// @result true if the lease was added, false if not (because a lease
- /// with the same address was already there).
- virtual bool addLease(const Lease4Ptr& lease) = 0;
-
- /// @brief Adds an IPv6 lease.
- ///
- /// @param lease lease to be added
- ///
- /// @result true if the lease was added, false if not (because a lease
- /// with the same address was already there).
- virtual bool addLease(const Lease6Ptr& lease) = 0;
-
- /// @brief Returns IPv4 lease for specified IPv4 address and subnet_id
- ///
- /// This method is used to get a lease for specific subnet_id. There can be
- /// at most one lease for any given subnet, so this method returns a single
- /// pointer.
- ///
- /// @param addr address of the searched lease
- /// @param subnet_id ID of the subnet the lease must belong to
- ///
- /// @return smart pointer to the lease (or NULL if a lease is not found)
- virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr,
- SubnetID subnet_id) const = 0;
-
- /// @brief Returns an IPv4 lease for specified IPv4 address
- ///
- /// This method return a lease that is associated with a given address.
- /// For other query types (by hardware addr, by client-id) there can be
- /// several leases in different subnets (e.g. for mobile clients that
- /// got address in different subnets). However, for a single address
- /// there can be only one lease, so this method returns a pointer to
- /// a single lease, not a container of leases.
- ///
- /// @param addr address of the searched lease
- ///
- /// @return smart pointer to the lease (or NULL if a lease is not found)
- virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr) const = 0;
-
- /// @brief Returns existing IPv4 leases for specified hardware address.
- ///
- /// Although in the usual case there will be only one lease, for mobile
- /// clients or clients with multiple static/fixed/reserved leases there
- /// can be more than one. Thus return type is a container, not a single
- /// pointer.
- ///
- /// @param hwaddr hardware address of the client
- ///
- /// @return lease collection
- virtual Lease4Collection getLease4(const HWAddr& hwaddr) const = 0;
-
- /// @brief Returns existing IPv4 leases for specified hardware address
- /// and a subnet
- ///
- /// There can be at most one lease for a given HW address in a single
- /// pool, so this method with either return a single lease or NULL.
- ///
- /// @param hwaddr hardware address of the client
- /// @param subnet_id identifier of the subnet that lease must belong to
- ///
- /// @return a pointer to the lease (or NULL if a lease is not found)
- virtual Lease4Ptr getLease4(const HWAddr& hwaddr,
- SubnetID subnet_id) const = 0;
-
- /// @brief Returns existing IPv4 lease for specified client-id
- ///
- /// Although in the usual case there will be only one lease, for mobile
- /// clients or clients with multiple static/fixed/reserved leases there
- /// can be more than one. Thus return type is a container, not a single
- /// pointer.
- ///
- /// @param clientid client identifier
- ///
- /// @return lease collection
- virtual Lease4Collection getLease4(const ClientId& clientid) const = 0;
-
- /// @brief Returns existing IPv4 lease for specified client-id
- ///
- /// There can be at most one lease for a given HW address in a single
- /// pool, so this method with either return a single lease or NULL.
- ///
- /// @param clientid client identifier
- /// @param subnet_id identifier of the subnet that lease must belong to
- ///
- /// @return a pointer to the lease (or NULL if a lease is not found)
- virtual Lease4Ptr getLease4(const ClientId& clientid,
- SubnetID subnet_id) const = 0;
-
- /// @brief Returns existing IPv6 lease for a given IPv6 address.
- ///
- /// For a given address, we assume that there will be only one lease.
- /// The assumtion here is that there will not be site or link-local
- /// addresses used, so there is no way of having address duplication.
- ///
- /// @param addr address of the searched lease
- ///
- /// @return smart pointer to the lease (or NULL if a lease is not found)
- virtual Lease6Ptr getLease6(const isc::asiolink::IOAddress& addr) const = 0;
-
- /// @brief Returns existing IPv6 leases for a given DUID+IA combination
- ///
- /// Although in the usual case there will be only one lease, for mobile
- /// clients or clients with multiple static/fixed/reserved leases there
- /// can be more than one. Thus return type is a container, not a single
- /// pointer.
- ///
- /// @param duid client DUID
- /// @param iaid IA identifier
- ///
- /// @return smart pointer to the lease (or NULL if a lease is not found)
- virtual Lease6Collection getLease6(const DUID& duid,
- uint32_t iaid) const = 0;
-
- /// @brief Returns existing IPv6 lease for a given DUID+IA combination
- ///
- /// @param duid client DUID
- /// @param iaid IA identifier
- /// @param subnet_id subnet id of the subnet the lease belongs to
- ///
- /// @return smart pointer to the lease (or NULL if a lease is not found)
- virtual Lease6Ptr getLease6(const DUID& duid, uint32_t iaid,
- SubnetID subnet_id) const = 0;
-
- /// @brief Updates IPv4 lease.
- ///
- /// @param lease4 The lease to be updated.
- ///
- /// If no such lease is present, an exception will be thrown.
- virtual void updateLease4(const Lease4Ptr& lease4) = 0;
-
- /// @brief Updates IPv6 lease.
- ///
- /// @param lease6 The lease to be updated.
- virtual void updateLease6(const Lease6Ptr& lease6) = 0;
-
- /// @brief Deletes a lease.
- ///
- /// @param addr IPv4 address of the lease to be deleted.
- ///
- /// @return true if deletion was successful, false if no such lease exists
- virtual bool deleteLease4(const isc::asiolink::IOAddress& addr) = 0;
-
- /// @brief Deletes a lease.
- ///
- /// @param addr IPv6 address of the lease to be deleted.
- ///
- /// @return true if deletion was successful, false if no such lease exists
- virtual bool deleteLease6(const isc::asiolink::IOAddress& addr) = 0;
-
- /// @brief Returns backend name.
- ///
- /// Each backend have specific name, e.g. "mysql" or "sqlite".
- virtual std::string getName() const = 0;
-
- /// @brief Returns description of the backend.
- ///
- /// This description may be multiline text that describes the backend.
- virtual std::string getDescription() const = 0;
-
- /// @brief Returns backend version.
- ///
- /// @return Version number as a pair of unsigned integers. "first" is the
- /// major version number, "second" the minor number.
- ///
- /// @todo: We will need to implement 3 version functions eventually:
- /// A. abstract API version
- /// B. backend version
- /// C. database version (stored in the database scheme)
- ///
- /// and then check that:
- /// B>=A and B=C (it is ok to have newer backend, as it should be backward
- /// compatible)
- /// Also if B>C, some database upgrade procedure may be triggered
- virtual std::pair<uint32_t, uint32_t> getVersion() const = 0;
-
- /// @brief Commit Transactions
- ///
- /// Commits all pending database operations. On databases that don't
- /// support transactions, this is a no-op.
- virtual void commit() = 0;
-
- /// @brief Rollback Transactions
- ///
- /// Rolls back all pending database operations. On databases that don't
- /// support transactions, this is a no-op.
- virtual void rollback() = 0;
-
- /// @todo: Add host management here
- /// As host reservation is outside of scope for 2012, support for hosts
- /// is currently postponed.
-
- /// @brief returns value of the parameter
- std::string getParameter(const std::string& name) const;
-
-private:
- /// @brief list of parameters passed in dbconfig
- ///
- /// That will be mostly used for storing database name, username,
- /// password and other parameters required for DB access. It is not
- /// intended to keep any DHCP-related parameters.
- ParameterMap parameters_;
-};
-
-}; // end of isc::dhcp namespace
-}; // end of isc namespace
-
-#endif // LEASE_MGR_H
diff --git a/src/lib/dhcp/lease_mgr_factory.cc b/src/lib/dhcp/lease_mgr_factory.cc
deleted file mode 100644
index 7e75633..0000000
--- a/src/lib/dhcp/lease_mgr_factory.cc
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include "config.h"
-
-#include <dhcp/lease_mgr_factory.h>
-#include <dhcp/memfile_lease_mgr.h>
-#ifdef HAVE_MYSQL
-#include <dhcp/mysql_lease_mgr.h>
-#endif
-
-#include <boost/algorithm/string.hpp>
-#include <boost/foreach.hpp>
-#include <boost/scoped_ptr.hpp>
-
-#include <algorithm>
-#include <iostream>
-#include <iterator>
-#include <map>
-#include <sstream>
-#include <utility>
-
-using namespace std;
-
-namespace isc {
-namespace dhcp {
-
-boost::scoped_ptr<LeaseMgr>&
-LeaseMgrFactory::getLeaseMgrPtr() {
- static boost::scoped_ptr<LeaseMgr> leaseMgrPtr;
- return (leaseMgrPtr);
-}
-
-LeaseMgr::ParameterMap
-LeaseMgrFactory::parse(const std::string& dbconfig) {
- LeaseMgr::ParameterMap mapped_tokens;
-
- if (!dbconfig.empty()) {
- vector<string> tokens;
-
- // We need to pass a string to is_any_of, not just char*. Otherwise
- // there are cryptic warnings on Debian6 running g++ 4.4 in
- // /usr/include/c++/4.4/bits/stl_algo.h:2178 "array subscript is above
- // array bounds"
- boost::split(tokens, dbconfig, boost::is_any_of( string("\t ") ));
- BOOST_FOREACH(std::string token, tokens) {
- size_t pos = token.find("=");
- if (pos != string::npos) {
- string name = token.substr(0, pos);
- string value = token.substr(pos + 1);
- mapped_tokens.insert(make_pair(name, value));
- } else {
- isc_throw(InvalidParameter, "Cannot parse " << token
- << ", expected format is name=value");
- }
- }
- }
-
- return (mapped_tokens);
-}
-
-void
-LeaseMgrFactory::create(const std::string& dbconfig) {
- const std::string type = "type";
-
- // Is "type" present?
- LeaseMgr::ParameterMap parameters = parse(dbconfig);
- if (parameters.find(type) == parameters.end()) {
- isc_throw(InvalidParameter, "Database configuration parameters do not "
- "contain the 'type' keyword");
- }
-
- // Yes, check what it is.
-#ifdef HAVE_MYSQL
- if (parameters[type] == string("mysql")) {
- getLeaseMgrPtr().reset(new MySqlLeaseMgr(parameters));
- return;
- }
-#endif
- if (parameters[type] == string("memfile")) {
- getLeaseMgrPtr().reset(new Memfile_LeaseMgr(parameters));
- return;
- }
-
- // Get here on no match
- isc_throw(InvalidType, "Database configuration parameter 'type' does "
- "not specify a supported database backend");
-}
-
-void
-LeaseMgrFactory::destroy() {
- getLeaseMgrPtr().reset();
-}
-
-LeaseMgr&
-LeaseMgrFactory::instance() {
- LeaseMgr* lmptr = getLeaseMgrPtr().get();
- if (lmptr == NULL) {
- isc_throw(NoLeaseManager, "no current lease manager is available");
- }
- return (*lmptr);
-}
-
-
-}; // namespace dhcp
-}; // namespace isc
diff --git a/src/lib/dhcp/lease_mgr_factory.h b/src/lib/dhcp/lease_mgr_factory.h
deleted file mode 100644
index c691e12..0000000
--- a/src/lib/dhcp/lease_mgr_factory.h
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef LEASE_MGR_FACTORY_H
-#define LEASE_MGR_FACTORY_H
-
-#include <string>
-#include <dhcp/lease_mgr.h>
-#include <exceptions/exceptions.h>
-
-namespace isc {
-namespace dhcp {
-
-/// @brief Invalid type exception
-///
-/// Thrown when the factory doesn't recognise the type of the backend.
-class InvalidType : public Exception {
-public:
- InvalidType(const char* file, size_t line, const char* what) :
- isc::Exception(file, line, what) {}
-};
-
-/// @brief No lease manager exception
-///
-/// Thrown if an attempt is made to get a reference to the current lease
-/// manager and none is currently available.
-class NoLeaseManager : public Exception {
-public:
- NoLeaseManager(const char* file, size_t line, const char* what) :
- isc::Exception(file, line, what) {}
-};
-
-/// @brief Lease Manager Factory
-///
-/// This class comprises nothing but static methods used to create a lease
-/// manager. It analyzes the database information passed to the creation
-/// function and instantiates an appropriate lease manager based on the type
-/// requested.
-///
-/// Strictly speaking these functions could be stand-alone functions. However,
-/// it is convenient to encapsulate them in a class for naming purposes.
-///
-/// @todo: Will need to develop some form of registration mechanism for
-/// user-supplied backends (so that there is no need to modify the code).
-class LeaseMgrFactory {
-public:
- /// @brief Create an instance of a lease manager.
- ///
- /// Each database backend has its own lease manager type. This static
- /// method sets the "current" lease manager to be a manager of the
- /// appropriate type. The actual lease manager is returned by the
- /// "instance" method.
- ///
- /// @note When called, the current lease manager is <b>always</b> destroyed
- /// and a new one created - even if the parameters are the same.
- ///
- /// dbconfig is a generic way of passing parameters. Parameters are passed
- /// in the "name=value" format, separated by spaces. The data MUST include
- /// a keyword/value pair of the form "type=dbtype" giving the database
- /// type, e.q. "mysql" or "sqlite3".
- ///
- /// @param dbconfig Database configuration parameters. These are in
- /// the form of "keyword=value" pairs, separated by spaces. These
- /// are back-end specific, although must include the "type" keyword
- /// which gives the backend in use.
- ///
- /// @throw isc::InvalidParameter dbconfig string does not contain the "type"
- /// keyword.
- /// @throw isc::dhcp::InvalidType The "type" keyword in dbconfig does not
- /// identify a supported backend.
- static void create(const std::string& dbconfig);
-
- /// @brief Destroy lease manager
- ///
- /// Destroys the current lease manager object. This should have the effect
- /// of closing the database connection. The method is a no-op if no
- /// lease manager is available.
- static void destroy();
-
- /// @brief Return Current Lease Manager
- ///
- /// Returns an instance of the "current" lease manager. An exception
- /// will be thrown if none is available.
- ///
- /// @throw isc::dhcp::NoLeaseManager No lease manager is available: use
- /// create() to create one before calling this method.
- static LeaseMgr& instance();
-
- /// @brief Parse Database Parameters
- ///
- /// Parses the string of "keyword=value" pairs and separates them
- /// out into the map.
- ///
- /// @param dbconfig Database configuration string
- ///
- /// @return std::map<std::string, std::string> Map of keyword/value pairs.
- static LeaseMgr::ParameterMap parse(const std::string& dbconfig);
-
-private:
- /// @brief Hold pointer to lease manager
- ///
- /// Holds a pointer to the singleton lease manager. The singleton
- /// is encapsulated in this method to avoid a "static initialization
- /// fiasco" if defined in an external static variable.
- static boost::scoped_ptr<LeaseMgr>& getLeaseMgrPtr();
-
-};
-
-}; // end of isc::dhcp namespace
-}; // end of isc namespace
-
-#endif // LEASE_MGR_FACTORY_H
diff --git a/src/lib/dhcp/libdhcp++.cc b/src/lib/dhcp/libdhcp++.cc
index 99a3b91..7fb88bf 100644
--- a/src/lib/dhcp/libdhcp++.cc
+++ b/src/lib/dhcp/libdhcp++.cc
@@ -12,19 +12,21 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <boost/shared_array.hpp>
-#include <boost/shared_ptr.hpp>
-#include <util/buffer.h>
-#include <exceptions/exceptions.h>
-#include <dhcp/libdhcp++.h>
-#include "config.h"
+#include <config.h>
+
#include <dhcp/dhcp4.h>
#include <dhcp/dhcp6.h>
+#include <dhcp/libdhcp++.h>
#include <dhcp/option.h>
#include <dhcp/option6_ia.h>
#include <dhcp/option6_iaaddr.h>
-#include <dhcp/option_definition.h>
#include <dhcp/option6_int_array.h>
+#include <dhcp/option_definition.h>
+#include <exceptions/exceptions.h>
+#include <util/buffer.h>
+
+#include <boost/shared_array.hpp>
+#include <boost/shared_ptr.hpp>
using namespace std;
using namespace isc::dhcp;
diff --git a/src/lib/dhcp/libdhcp++.h b/src/lib/dhcp/libdhcp++.h
index b848ad3..c773fd7 100644
--- a/src/lib/dhcp/libdhcp++.h
+++ b/src/lib/dhcp/libdhcp++.h
@@ -12,12 +12,13 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#ifndef LIBDHCP_H_
-#define LIBDHCP_H_
+#ifndef LIBDHCP_H
+#define LIBDHCP_H
#include <dhcp/option_definition.h>
#include <dhcp/pkt6.h>
#include <util/buffer.h>
+
#include <iostream>
namespace isc {
@@ -164,4 +165,4 @@ private:
}
}
-#endif
+#endif // LIBDHCP_H
diff --git a/src/lib/dhcp/memfile_lease_mgr.cc b/src/lib/dhcp/memfile_lease_mgr.cc
deleted file mode 100644
index 1424b39..0000000
--- a/src/lib/dhcp/memfile_lease_mgr.cc
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <iostream>
-
-#include <dhcp/memfile_lease_mgr.h>
-
-using namespace isc::dhcp;
-
-Memfile_LeaseMgr::Memfile_LeaseMgr(const ParameterMap& parameters)
- : LeaseMgr(parameters) {
- std::cout << "Warning: Using memfile database backend. It is usable for" << std::endl;
- std::cout << "Warning: limited testing only. File support not implemented yet." << std::endl;
- std::cout << "Warning: Leases will be lost after restart." << std::endl;
-}
-
-Memfile_LeaseMgr::~Memfile_LeaseMgr() {
-}
-
-bool Memfile_LeaseMgr::addLease(const Lease4Ptr&) {
- return (false);
-}
-
-bool Memfile_LeaseMgr::addLease(const Lease6Ptr& lease) {
- if (getLease6(lease->addr_)) {
- // there is a lease with specified address already
- return (false);
- }
- storage6_.insert(lease);
- return (true);
-}
-
-Lease4Ptr Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress&) const {
- return (Lease4Ptr());
-}
-
-Lease4Collection Memfile_LeaseMgr::getLease4(const HWAddr& ) const {
- return (Lease4Collection());
-}
-
-Lease4Ptr Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress&,
- SubnetID) const {
- return (Lease4Ptr());
-}
-
-Lease4Ptr Memfile_LeaseMgr::getLease4(const HWAddr&,
- SubnetID) const {
- return (Lease4Ptr());
-}
-
-
-Lease4Ptr Memfile_LeaseMgr::getLease4(const ClientId&,
- SubnetID) const {
- return (Lease4Ptr());
-}
-
-Lease4Collection Memfile_LeaseMgr::getLease4(const ClientId& ) const {
- return (Lease4Collection());
-}
-
-Lease6Ptr Memfile_LeaseMgr::getLease6(const isc::asiolink::IOAddress& addr) const {
- Lease6Storage::iterator l = storage6_.find(addr);
- if (l == storage6_.end()) {
- return (Lease6Ptr());
- } else {
- return (*l);
- }
-}
-
-Lease6Collection Memfile_LeaseMgr::getLease6(const DUID& , uint32_t ) const {
- return (Lease6Collection());
-}
-
-Lease6Ptr Memfile_LeaseMgr::getLease6(const DUID& duid, uint32_t iaid,
- SubnetID subnet_id) const {
- /// @todo: Slow, naive implementation. Write it using additional indexes
- for (Lease6Storage::iterator l = storage6_.begin(); l != storage6_.end(); ++l) {
- if ( (*((*l)->duid_) == duid) &&
- ( (*l)->iaid_ == iaid) &&
- ( (*l)->subnet_id_ == subnet_id)) {
- return (*l);
- }
- }
- return (Lease6Ptr());
-}
-
-void Memfile_LeaseMgr::updateLease4(const Lease4Ptr& ) {
-}
-
-void Memfile_LeaseMgr::updateLease6(const Lease6Ptr& ) {
-
-}
-
-bool Memfile_LeaseMgr::deleteLease4(const isc::asiolink::IOAddress&) {
- return (false);
-}
-
-bool Memfile_LeaseMgr::deleteLease6(const isc::asiolink::IOAddress& addr) {
- Lease6Storage::iterator l = storage6_.find(addr);
- if (l == storage6_.end()) {
- // no such lease
- return (false);
- } else {
- storage6_.erase(l);
- return (true);
- }
-}
-
-std::string Memfile_LeaseMgr::getDescription() const {
- return (std::string("This is a dummy memfile backend implementation.\n"
- "It does not offer any useful lease management and its only\n"
- "purpose is to test abstract lease manager API."));
-}
-
-void
-Memfile_LeaseMgr::commit() {
-}
-
-void
-Memfile_LeaseMgr::rollback() {
-}
diff --git a/src/lib/dhcp/memfile_lease_mgr.h b/src/lib/dhcp/memfile_lease_mgr.h
deleted file mode 100644
index cb02360..0000000
--- a/src/lib/dhcp/memfile_lease_mgr.h
+++ /dev/null
@@ -1,241 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef MEMFILE_LEASE_MGR_H
-#define MEMFILE_LEASE_MGR_H
-
-#include <boost/multi_index_container.hpp>
-#include <boost/multi_index/indexed_by.hpp>
-#include <boost/multi_index/ordered_index.hpp>
-#include <boost/multi_index/member.hpp>
-
-#include <dhcp/lease_mgr.h>
-
-namespace isc {
-namespace dhcp {
-
-// This is a concrete implementation of a Lease database.
-//
-// It is for testing purposes only. It is NOT a production code.
-//
-// It does not do anything useful now, and is used for abstract LeaseMgr
-// class testing. It may later evolve into more useful backend if the
-// need arises. We can reuse code from memfile benchmark. See code in
-// tests/tools/dhcp-ubench/memfile_bench.{cc|h}
-class Memfile_LeaseMgr : public LeaseMgr {
-public:
-
- /// @brief The sole lease manager constructor
- ///
- /// dbconfig is a generic way of passing parameters. Parameters
- /// are passed in the "name=value" format, separated by spaces.
- /// Values may be enclosed in double quotes, if needed.
- ///
- /// @param parameters A data structure relating keywords and values
- /// concerned with the database.
- Memfile_LeaseMgr(const ParameterMap& parameters);
-
- /// @brief Destructor (closes file)
- virtual ~Memfile_LeaseMgr();
-
- /// @brief Adds an IPv4 lease.
- ///
- /// @todo Not implemented yet
- /// @param lease lease to be added
- virtual bool addLease(const Lease4Ptr& lease);
-
- /// @brief Adds an IPv6 lease.
- ///
- /// @param lease lease to be added
- virtual bool addLease(const Lease6Ptr& lease);
-
- /// @brief Returns existing IPv4 lease for specified IPv4 address.
- ///
- /// @todo Not implemented yet
- /// @param addr address of the searched lease
- ///
- /// @return a collection of leases
- virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr) const;
-
- /// @brief Returns existing IPv4 lease for specific address and subnet
- ///
- /// @todo Not implemented yet
- /// @param addr address of the searched lease
- /// @param subnet_id ID of the subnet the lease must belong to
- ///
- /// @return smart pointer to the lease (or NULL if a lease is not found)
- virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr,
- SubnetID subnet_id) const;
-
- /// @brief Returns existing IPv4 leases for specified hardware address.
- ///
- /// @todo Not implemented yet
- ///
- /// Although in the usual case there will be only one lease, for mobile
- /// clients or clients with multiple static/fixed/reserved leases there
- /// can be more than one. Thus return type is a container, not a single
- /// pointer.
- ///
- /// @param hwaddr hardware address of the client
- ///
- /// @return lease collection
- virtual Lease4Collection getLease4(const HWAddr& hwaddr) const;
-
- /// @brief Returns existing IPv4 leases for specified hardware address
- /// and a subnet
- ///
- /// @todo Not implemented yet
- ///
- /// There can be at most one lease for a given HW address in a single
- /// pool, so this method with either return a single lease or NULL.
- ///
- /// @param hwaddr hardware address of the client
- /// @param subnet_id identifier of the subnet that lease must belong to
- ///
- /// @return a pointer to the lease (or NULL if a lease is not found)
- virtual Lease4Ptr getLease4(const HWAddr& hwaddr,
- SubnetID subnet_id) const;
-
- /// @brief Returns existing IPv4 lease for specified client-id
- ///
- /// @todo Not implemented yet
- ///
- /// @param clientid client identifier
- virtual Lease4Collection getLease4(const ClientId& clientid) const;
-
- /// @brief Returns existing IPv4 lease for specified client-id
- ///
- /// There can be at most one lease for a given HW address in a single
- /// pool, so this method with either return a single lease or NULL.
- ///
- /// @todo Not implemented yet
- ///
- /// @param clientid client identifier
- /// @param subnet_id identifier of the subnet that lease must belong to
- ///
- /// @return a pointer to the lease (or NULL if a lease is not found)
- virtual Lease4Ptr getLease4(const ClientId& clientid,
- SubnetID subnet_id) const;
-
- /// @brief Returns existing IPv6 lease for a given IPv6 address.
- ///
- /// @param addr address of the searched lease
- ///
- /// @return smart pointer to the lease (or NULL if a lease is not found)
- Lease6Ptr getLease6(const isc::asiolink::IOAddress& addr) const;
-
- /// @brief Returns existing IPv6 lease for a given DUID+IA combination
- ///
- /// @todo Not implemented yet
- ///
- /// @param duid client DUID
- /// @param iaid IA identifier
- ///
- /// @return collection of IPv6 leases
- Lease6Collection getLease6(const DUID& duid, uint32_t iaid) const;
-
- /// @brief Returns existing IPv6 lease for a given DUID+IA combination
- ///
- /// @todo Not implemented yet
- ///
- /// @param duid client DUID
- /// @param iaid IA identifier
- /// @param subnet_id identifier of the subnet the lease must belong to
- ///
- /// @return smart pointer to the lease (or NULL if a lease is not found)
- Lease6Ptr getLease6(const DUID& duid, uint32_t iaid, SubnetID subnet_id) const;
-
- /// @brief Updates IPv4 lease.
- ///
- /// @todo Not implemented yet
- ///
- /// @param lease4 The lease to be updated.
- ///
- /// If no such lease is present, an exception will be thrown.
- void updateLease4(const Lease4Ptr& lease4);
-
- /// @brief Updates IPv4 lease.
- ///
- /// @todo Not implemented yet
- ///
- /// @param lease6 The lease to be updated.
- ///
- /// If no such lease is present, an exception will be thrown.
- void updateLease6(const Lease6Ptr& lease6);
-
- /// @brief Deletes a lease.
- ///
- /// @param addr IPv4 address of the lease to be deleted.
- ///
- /// @return true if deletion was successful, false if no such lease exists
- virtual bool deleteLease4(const isc::asiolink::IOAddress& addr);
-
- /// @brief Deletes a lease.
- ///
- /// @param addr IPv4 address of the lease to be deleted.
- ///
- /// @return true if deletion was successful, false if no such lease exists
- bool deleteLease6(const isc::asiolink::IOAddress& addr);
-
- /// @brief Returns backend name.
- ///
- /// Each backend have specific name, e.g. "mysql" or "sqlite".
- std::string getName() const { return ("memfile"); }
-
- /// @brief Returns description of the backend.
- ///
- /// This description may be multiline text that describes the backend.
- std::string getDescription() const;
-
- /// @brief Returns backend version.
- virtual std::pair<uint32_t, uint32_t> getVersion() const {
- return (std::make_pair(1, 0));
- }
-
- /// @brief Commit Transactions
- ///
- /// Commits all pending database operations. On databases that don't
- /// support transactions, this is a no-op.
- virtual void commit();
-
- /// @brief Rollback Transactions
- ///
- /// Rolls back all pending database operations. On databases that don't
- /// support transactions, this is a no-op.
- virtual void rollback();
-
- using LeaseMgr::getParameter;
-
-protected:
-
- typedef boost::multi_index_container< // this is a multi-index container...
- Lease6Ptr, // it will hold shared_ptr to leases6
- boost::multi_index::indexed_by< // and will be sorted by
- // IPv6 address that are unique. That particular key is a member
- // of the Lease6 structure, is of type IOAddress and can be accessed
- // by doing &Lease6::addr_
- boost::multi_index::ordered_unique<
- boost::multi_index::member<Lease6, isc::asiolink::IOAddress, &Lease6::addr_>
- >
- >
- > Lease6Storage; // Let the whole contraption be called Lease6Storage.
-
- Lease6Storage storage6_;
-};
-
-}; // end of isc::dhcp namespace
-}; // end of isc namespace
-
-#endif // MEMFILE_LEASE_MGR
-
diff --git a/src/lib/dhcp/mysql_lease_mgr.cc b/src/lib/dhcp/mysql_lease_mgr.cc
deleted file mode 100644
index f030cd3..0000000
--- a/src/lib/dhcp/mysql_lease_mgr.cc
+++ /dev/null
@@ -1,1139 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-
-#include <dhcp/mysql_lease_mgr.h>
-#include <asiolink/io_address.h>
-
-#include <mysql/mysqld_error.h>
-
-#include <iostream>
-#include <iomanip>
-#include <string>
-#include <time.h>
-
-using namespace isc;
-using namespace isc::dhcp;
-using namespace std;
-
-namespace {
-///@{
-/// @brief Maximum Size of Database Fields
-///
-/// The following constants define buffer sizes for variable length database
-/// fields. The values should be greater than or equal to the length set in
-/// the schema definition.
-///
-/// The exception is the length of any VARCHAR fields: these should be set
-/// greater than or equal to the length of the field plus 2: this allows for
-/// the insertion of a trailing null regardless of whether the data returned
-/// contains a trailing null (the documentation is not clear on this point).
-
-const size_t ADDRESS6_TEXT_MAX_LEN = 42; // Max size of a IPv6 text buffer
-const size_t DUID_MAX_LEN = 128; // Max size of a DUID
-///@}
-
-/// @brief MySQL Selection Statements
-///
-/// Each statement is associated with the index, used by the various methods
-/// to access the prepared statement.
-struct TaggedStatement {
- MySqlLeaseMgr::StatementIndex index;
- const char* text;
-};
-
-TaggedStatement tagged_statements[] = {
- {MySqlLeaseMgr::DELETE_LEASE6,
- "DELETE FROM lease6 WHERE address = ?"},
- {MySqlLeaseMgr::GET_LEASE6_ADDR,
- "SELECT address, duid, valid_lifetime, "
- "expire, subnet_id, pref_lifetime, "
- "lease_type, iaid, prefix_len "
- "FROM lease6 "
- "WHERE address = ?"},
- {MySqlLeaseMgr::GET_LEASE6_DUID_IAID,
- "SELECT address, duid, valid_lifetime, "
- "expire, subnet_id, pref_lifetime, "
- "lease_type, iaid, prefix_len "
- "FROM lease6 "
- "WHERE duid = ? AND iaid = ?"},
- {MySqlLeaseMgr::GET_LEASE6_DUID_IAID_SUBID,
- "SELECT address, duid, valid_lifetime, "
- "expire, subnet_id, pref_lifetime, "
- "lease_type, iaid, prefix_len "
- "FROM lease6 "
- "WHERE duid = ? AND iaid = ? AND subnet_id = ?"},
- {MySqlLeaseMgr::GET_VERSION,
- "SELECT version, minor FROM schema_version"},
- {MySqlLeaseMgr::INSERT_LEASE6,
- "INSERT INTO lease6(address, duid, valid_lifetime, "
- "expire, subnet_id, pref_lifetime, "
- "lease_type, iaid, prefix_len) "
- "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"},
- {MySqlLeaseMgr::UPDATE_LEASE6,
- "UPDATE lease6 SET address = ?, duid = ?, "
- "valid_lifetime = ?, expire = ?, subnet_id = ?, "
- "pref_lifetime = ?, lease_type = ?, iaid = ?, "
- "prefix_len = ? "
- "WHERE address = ?"},
- // End of list sentinel
- {MySqlLeaseMgr::NUM_STATEMENTS, NULL}
-};
-
-}; // Anonymous namespace
-
-namespace isc {
-namespace dhcp {
-
-
-
-/// @brief Exchange MySQL and Lease6 Data
-///
-/// On any MySQL operation, arrays of MYSQL_BIND structures must be built to
-/// describe the parameters in the prepared statements. Where information is
-/// inserted or retrieved - INSERT, UPDATE, SELECT - a large amount of that
-/// structure is identical - it defines data values in the Lease6 structure.
-/// This class handles the creation of that array.
-///
-/// Owing to the MySQL API, the process requires some intermediate variables
-/// to hold things like length etc. This object holds the intermediate
-/// variables as well.
-///
-/// @note There are no unit tests for this class. It is tested indirectly
-/// in all MySqlLeaseMgr::xxx6() calls where it is used.
-
-class MySqlLease6Exchange {
-public:
- /// @brief Constructor
- ///
- /// Apart from the initialization of false_ and true_, the initialization
- /// of addr6_length_, duid_length_, addr6_buffer_ and duid_buffer_ are
- /// to satisfy cppcheck: none are really needed, as all variables are
- /// initialized/set in the methods.
- MySqlLease6Exchange() : addr6_length_(0), duid_length_(0),
- false_(0), true_(1) {
- memset(addr6_buffer_, 0, sizeof(addr6_buffer_));
- memset(duid_buffer_, 0, sizeof(duid_buffer_));
- }
-
- /// @brief Create MYSQL_BIND objects for Lease6 Pointer
- ///
- /// Fills in the MYSQL_BIND objects for the Lease6 passed to it.
- ///
- /// @param lease Lease object to be added to the database.
- ///
- /// @return Vector of MySQL BIND objects representing the data to be added.
- std::vector<MYSQL_BIND> createBindForSend(const Lease6Ptr& lease) {
- // Store lease object to ensure it remains valid.
- lease_ = lease;
-
- // Ensure bind_ array clear for constructing the MYSQL_BIND structures
- // for this lease.
- memset(bind_, 0, sizeof(bind_));
-
- // address: varchar(40)
- addr6_ = lease_->addr_.toText();
- addr6_length_ = addr6_.size();
-
- // In the following statement, the string is being read. However, the
- // MySQL C interface does not use "const", so the "buffer" element
- // is declared as "char*" instead of "const char*". To resolve this,
- // the "const" is discarded. (Note that the address of addr6_.c_str()
- // is guaranteed to be valid until the next non-const operation on
- // addr6_.)
- //
- // Note that the const_cast could be avoided by copying the string to
- // a writeable buffer and storing the address of that in the "buffer"
- // element. However, this introduces a copy operation (with additional
- // overhead) purely to get round the strictures introduced by design of
- // the MySQL interface (which uses the area pointed to by "buffer" as
- // input when specifying query parameters and as output when retrieving
- // data). For that reason, "const_cast" has been used.
- bind_[0].buffer_type = MYSQL_TYPE_STRING;
- bind_[0].buffer = const_cast<char*>(addr6_.c_str());
- bind_[0].buffer_length = addr6_length_;
- bind_[0].length = &addr6_length_;
-
- // duid: varchar(128)
- duid_ = lease_->duid_->getDuid();
- duid_length_ = duid_.size();
-
- bind_[1].buffer_type = MYSQL_TYPE_BLOB;
- bind_[1].buffer = reinterpret_cast<char*>(&(duid_[0]));
- bind_[1].buffer_length = duid_length_;
- bind_[1].length = &duid_length_;
-
- // valid lifetime: unsigned int
- bind_[2].buffer_type = MYSQL_TYPE_LONG;
- bind_[2].buffer = reinterpret_cast<char*>(&lease->valid_lft_);
- bind_[2].is_unsigned = true_;
-
- // expire: timestamp
- // The lease structure holds the client last transmission time (cltt_)
- // For convenience for external tools, this is converted to lease
- /// expiry time (expire). The relationship is given by:
- //
- // expire = cltt_ + valid_lft_
- //
- // @TODO Handle overflows
- MySqlLeaseMgr::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_,
- expire_);
- bind_[3].buffer_type = MYSQL_TYPE_TIMESTAMP;
- bind_[3].buffer = reinterpret_cast<char*>(&expire_);
- bind_[3].buffer_length = sizeof(expire_);
-
- // subnet_id: unsigned int
- // Can use lease_->subnet_id_ directly as it is of type uint32_t.
- bind_[4].buffer_type = MYSQL_TYPE_LONG;
- bind_[4].buffer = reinterpret_cast<char*>(&lease_->subnet_id_);
- bind_[4].is_unsigned = true_;
-
- // pref_lifetime: unsigned int
- // Can use lease_->preferred_lft_ directly as it is of type uint32_t.
- bind_[5].buffer_type = MYSQL_TYPE_LONG;
- bind_[5].buffer = reinterpret_cast<char*>(&lease_->preferred_lft_);
- bind_[5].is_unsigned = true_;
-
- // lease_type: tinyint
- // Must convert to uint8_t as lease_->type_ is a LeaseType variable
- lease_type_ = lease_->type_;
- bind_[6].buffer_type = MYSQL_TYPE_TINY;
- bind_[6].buffer = reinterpret_cast<char*>(&lease_type_);
- bind_[6].is_unsigned = true_;
-
- // iaid: unsigned int
- // Can use lease_->iaid_ directly as it is of type uint32_t.
- bind_[7].buffer_type = MYSQL_TYPE_LONG;
- bind_[7].buffer = reinterpret_cast<char*>(&lease_->iaid_);
- bind_[7].is_unsigned = true_;
-
- // prefix_len: unsigned tinyint
- // Can use lease_->prefixlen_ directly as it is uint32_t.
- bind_[8].buffer_type = MYSQL_TYPE_TINY;
- bind_[8].buffer = reinterpret_cast<char*>(&lease_->prefixlen_);
- bind_[8].is_unsigned = true_;
-
- // Add the data to the vector. Note the end element is one after the
- // end of the array.
- return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[9]));
- }
-
- /// @brief Create BIND array to receive data
- ///
- /// Creates a MYSQL_BIND array to receive Lease6 data from the database.
- /// After data is successfully received, getLeaseData() is used to copy
- /// it to a Lease6 object.
- ///
- /// @return Vector of MySQL BIND objects.
- std::vector<MYSQL_BIND> createBindForReceive() {
-
- // Ensure both the array of MYSQL_BIND structures and the error array
- // are clear.
- memset(bind_, 0, sizeof(bind_));
- memset(error_, 0, sizeof(error_));
-
- // address: varchar
- // A Lease6_ address has a maximum of 39 characters. The array is
- // a few bites longer than this to guarantee that we can always null
- // terminate it.
- addr6_length_ = sizeof(addr6_buffer_) - 1;
- bind_[0].buffer_type = MYSQL_TYPE_STRING;
- bind_[0].buffer = addr6_buffer_;
- bind_[0].buffer_length = addr6_length_;
- bind_[0].length = &addr6_length_;
- bind_[0].error = &error_[0];
-
- // client_id: varbinary(128)
- duid_length_ = sizeof(duid_buffer_);
- bind_[1].buffer_type = MYSQL_TYPE_BLOB;
- bind_[1].buffer = reinterpret_cast<char*>(duid_buffer_);
- bind_[1].buffer_length = duid_length_;
- bind_[1].length = &duid_length_;
- bind_[1].error = &error_[1];
-
- // lease_time: unsigned int
- bind_[2].buffer_type = MYSQL_TYPE_LONG;
- bind_[2].buffer = reinterpret_cast<char*>(&valid_lifetime_);
- bind_[2].is_unsigned = true_;
- bind_[2].error = &error_[2];
-
- // expire: timestamp
- bind_[3].buffer_type = MYSQL_TYPE_TIMESTAMP;
- bind_[3].buffer = reinterpret_cast<char*>(&expire_);
- bind_[3].buffer_length = sizeof(expire_);
- bind_[3].error = &error_[3];
-
- // subnet_id: unsigned int
- bind_[4].buffer_type = MYSQL_TYPE_LONG;
- bind_[4].buffer = reinterpret_cast<char*>(&subnet_id_);
- bind_[4].is_unsigned = true_;
- bind_[4].error = &error_[4];
-
- // pref_lifetime: unsigned int
- bind_[5].buffer_type = MYSQL_TYPE_LONG;
- bind_[5].buffer = reinterpret_cast<char*>(&pref_lifetime_);
- bind_[5].is_unsigned = true_;
- bind_[5].error = &error_[5];
-
- // lease_type: tinyint
- bind_[6].buffer_type = MYSQL_TYPE_TINY;
- bind_[6].buffer = reinterpret_cast<char*>(&lease_type_);
- bind_[6].is_unsigned = true_;
- bind_[6].error = &error_[6];
-
- // iaid: unsigned int
- bind_[7].buffer_type = MYSQL_TYPE_LONG;
- bind_[7].buffer = reinterpret_cast<char*>(&iaid_);
- bind_[7].is_unsigned = true_;
- bind_[7].error = &error_[7];
-
- // prefix_len: unsigned tinyint
- bind_[8].buffer_type = MYSQL_TYPE_TINY;
- bind_[8].buffer = reinterpret_cast<char*>(&prefixlen_);
- bind_[8].is_unsigned = true_;
- bind_[8].error = &error_[8];
-
- // Add the data to the vector. Note the end element is one after the
- // end of the array.
- return(std::vector<MYSQL_BIND>(&bind_[0], &bind_[9]));
- }
-
- /// @brief Copy Received Data into Lease6 Object
- ///
- /// Called after the MYSQL_BIND array created by createBindForReceive()
- /// has been used, this copies data from the internal member vairables
- /// into a Lease6 object.
- ///
- /// @return Lease6Ptr Pointer to a Lease6 object holding the relevant
- /// data.
- ///
- /// @throw isc::BadValue Unable to convert Lease Type value in database
- Lease6Ptr getLeaseData() {
-
- // Create the object to be returned.
- Lease6Ptr result(new Lease6());
-
- // Put the data in the lease object
-
- // The address buffer is declared larger than the buffer size passed
- // to the access function so that we can always append a null byte.
- addr6_buffer_[addr6_length_] = '\0';
- std::string address = addr6_buffer_;
-
- // Set the other data, converting time as needed.
- result->addr_ = isc::asiolink::IOAddress(address);
- result->duid_.reset(new DUID(duid_buffer_, duid_length_));
- MySqlLeaseMgr::convertFromDatabaseTime(expire_, valid_lifetime_,
- result->cltt_);
- result->valid_lft_ = valid_lifetime_;
- result->subnet_id_ = subnet_id_;
- result->preferred_lft_ = pref_lifetime_;
-
- // We can't convert from a numeric value to an enum, hence:
- switch (lease_type_) {
- case Lease6::LEASE_IA_NA:
- result->type_ = Lease6::LEASE_IA_NA;
- break;
-
- case Lease6::LEASE_IA_TA:
- result->type_ = Lease6::LEASE_IA_TA;
- break;
-
- case Lease6::LEASE_IA_PD:
- result->type_ = Lease6::LEASE_IA_PD;
- break;
-
- default:
- isc_throw(BadValue, "invalid lease type returned (" <<
- lease_type_ << ") for lease with address " <<
- result->addr_.toText() << ". Only 0, 1, or 2 "
- "are allowed.");
- }
- result->iaid_ = iaid_;
- result->prefixlen_ = prefixlen_;
-
- return (result);
- }
-
-private:
- // Note: All array lengths are equal to the corresponding variable in the
- // schema.
- std::string addr6_; ///< String form of address
- char addr6_buffer_[ADDRESS6_TEXT_MAX_LEN]; ///< Character
- ///< array form of V6 address
- unsigned long addr6_length_; ///< Length of the address
- MYSQL_BIND bind_[9]; ///< Static array for speed of access
- std::vector<uint8_t> duid_; ///< Client identification
- uint8_t duid_buffer_[DUID_MAX_LEN]; ///< Buffer form of DUID
- unsigned long duid_length_; ///< Length of the DUID
- my_bool error_[9]; ///< For error reporting
- MYSQL_TIME expire_; ///< Lease expiry time
- const my_bool false_; ///< "false" for MySql
- uint32_t iaid_; ///< Identity association ID
- Lease6Ptr lease_; ///< Pointer to lease object
- uint32_t valid_lifetime_; ///< Lease time
- uint8_t lease_type_; ///< Lease type
- uint8_t prefixlen_; ///< Prefix length
- uint32_t pref_lifetime_; ///< Preferred lifetime
- uint32_t subnet_id_; ///< Subnet identification
- const my_bool true_; ///< "true_" for MySql
-};
-
-
-/// @brief Fetch and Release MySQL Results
-///
-/// When a MySQL statement is exected, to fetch the results the function
-/// mysql_stmt_fetch() must be called. As well as getting data, this
-/// allocated internal state. Subsequent calls to mysql_stmt_fetch
-/// can be made, but when all the data is retrieved, mysql_stmt_free_result
-/// must be called to free up the resources allocated.
-///
-/// Created prior to the first fetch, this class's destructor calls
-/// mysql_stmt_free_result, so eliminating the need for an explicit release
-/// in the method using mysql_stmt_free_result. In this way, it guarantees
-/// that the resources are released even if the MySqlLeaseMgr method concerned
-/// exits via an exception.
-class MySqlFreeResult {
-public:
-
- /// @brief Constructor
- ///
- /// Store the pointer to the statement for which data is being fetched.
- ///
- /// Note that according to the MySQL documentation, mysql_stmt_free_result
- /// only releases resources if a cursor has been allocated for the
- /// statement. This implies that it is a no-op if none have been. Either
- /// way, any error from mysql_stmt_free_result is ignored. (Generating
- /// an exception is not much help, as it will only confuse things if the
- /// method calling mysql_stmt_fetch is exiting via an exception.)
- MySqlFreeResult(MYSQL_STMT* statement) : statement_(statement)
- {}
-
- /// @brief Destructor
- ///
- /// Frees up fetch context if a fetch has been successfully executed.
- ~MySqlFreeResult() {
- (void) mysql_stmt_free_result(statement_);
- }
-
-private:
- MYSQL_STMT* statement_; ///< Statement for which results are freed
-};
-
-
-// MySqlLeaseMgr Methods
-
-MySqlLeaseMgr::MySqlLeaseMgr(const LeaseMgr::ParameterMap& parameters)
- : LeaseMgr(parameters), mysql_(NULL) {
-
- // Allocate context for MySQL - it is destroyed in the destructor.
- mysql_ = mysql_init(NULL);
- if (mysql_ == NULL) {
- isc_throw(DbOpenError, "unable to initialize MySQL");
- }
-
- // Open the database
- openDatabase();
-
- // Disable autocommit
- my_bool result = mysql_autocommit(mysql_, 0);
- if (result != 0) {
- isc_throw(DbOperationError, mysql_error(mysql_));
- }
-
- // Prepare all statements likely to be used.
- prepareStatements();
-
- // Create the exchange object for use in exchanging data between the
- // program and the database.
- exchange6_.reset(new MySqlLease6Exchange());
-}
-
-
-MySqlLeaseMgr::~MySqlLeaseMgr() {
- // Free up the prepared statements, ignoring errors. (What would we do
- // about them - we're destroying this object and are not really concerned
- // with errors on a database connection that it about to go away.)
- for (int i = 0; i < statements_.size(); ++i) {
- if (statements_[i] != NULL) {
- (void) mysql_stmt_close(statements_[i]);
- statements_[i] = NULL;
- }
- }
-
- // Close the database
- mysql_close(mysql_);
- mysql_ = NULL;
-}
-
-
-// Time conversion methods.
-//
-// Note that the MySQL TIMESTAMP data type (used for "expire") converts data
-// from the current timezone to UTC for storage, and from UTC to the current
-// timezone for retrieval.
-//
-// This causes no problems providing that:
-// a) cltt is given in local time
-// b) We let the system take care of timezone conversion when converting
-// from a time read from the database into a local time.
-
-void
-MySqlLeaseMgr::convertToDatabaseTime(time_t cltt, uint32_t valid_lifetime,
- MYSQL_TIME& expire) {
-
- // Calculate expiry time and convert to various date/time fields.
- // @TODO: handle overflows
- time_t expire_time = cltt + valid_lifetime;
-
- // Convert to broken-out time
- struct tm expire_tm;
- (void) localtime_r(&expire_time, &expire_tm);
-
- // Place in output expire structure.
- expire.year = expire_tm.tm_year + 1900;
- expire.month = expire_tm.tm_mon + 1; // Note different base
- expire.day = expire_tm.tm_mday;
- expire.hour = expire_tm.tm_hour;
- expire.minute = expire_tm.tm_min;
- expire.second = expire_tm.tm_sec;
- expire.second_part = 0; // No fractional seconds
- expire.neg = static_cast<my_bool>(0); // Not negative
-}
-
-void
-MySqlLeaseMgr::convertFromDatabaseTime(const MYSQL_TIME& expire,
- uint32_t valid_lifetime, time_t& cltt) {
-
- // Copy across fields from MYSQL_TIME structure.
- struct tm expire_tm;
- memset(&expire_tm, 0, sizeof(expire_tm));
-
- expire_tm.tm_year = expire.year - 1900;
- expire_tm.tm_mon = expire.month - 1;
- expire_tm.tm_mday = expire.day;
- expire_tm.tm_hour = expire.hour;
- expire_tm.tm_min = expire.minute;
- expire_tm.tm_sec = expire.second;
- expire_tm.tm_isdst = -1; // Let the system work out about DST
-
- // Convert to local time
- cltt = mktime(&expire_tm) - valid_lifetime;
-}
-
-
-void
-MySqlLeaseMgr::openDatabase() {
-
- // Set up the values of the parameters
- const char* host = "localhost";
- string shost;
- try {
- shost = getParameter("host");
- host = shost.c_str();
- } catch (...) {
- // No host. Fine, we'll use "localhost"
- }
-
- const char* user = NULL;
- string suser;
- try {
- suser = getParameter("user");
- user = suser.c_str();
- } catch (...) {
- // No user. Fine, we'll use NULL
- ;
- }
-
- const char* password = NULL;
- string spassword;
- try {
- spassword = getParameter("password");
- password = spassword.c_str();
- } catch (...) {
- // No password. Fine, we'll use NULL
- ;
- }
-
- const char* name = NULL;
- string sname;
- try {
- sname = getParameter("name");
- name = sname.c_str();
- } catch (...) {
- // No database name. Throw a "NoName" exception
- isc_throw(NoDatabaseName, "must specified a name for the database");
- }
-
- // Set options for the connection:
- // - automatic reconnection
- my_bool auto_reconnect = 1;
- int result = mysql_options(mysql_, MYSQL_OPT_RECONNECT, &auto_reconnect);
- if (result != 0) {
- isc_throw(DbOpenError, "unable to set auto-reconnect option: " <<
- mysql_error(mysql_));
- }
-
- // Open the database.
- //
- // The option CLIENT_FOUND_ROWS is specified so that in an UPDATE,
- // the affected rows are the number of rows found that match the
- // WHERE clause of the SQL statement, not the rows changed. The reason
- // here is that MySQL apparently does not update a row if data has not
- // changed and so the "affected rows" (retrievable from MySQL) is zero.
- // This makes it hard to distinguish whether the UPDATE changed no rows
- // because no row matching the WHERE clause was found, or because a
- // row was found by no data was altered.
- MYSQL* status = mysql_real_connect(mysql_, host, user, password, name,
- 0, NULL, CLIENT_FOUND_ROWS);
- if (status != mysql_) {
- isc_throw(DbOpenError, mysql_error(mysql_));
- }
-}
-
-
-void
-MySqlLeaseMgr::prepareStatement(StatementIndex index, const char* text) {
- // Validate that there is space for the statement in the statements array
- // and that nothing has been placed there before.
- if ((index >= statements_.size()) || (statements_[index] != NULL)) {
- isc_throw(InvalidParameter, "invalid prepared statement index (" <<
- static_cast<int>(index) << ") or indexed prepared " <<
- "statement is not null");
- }
-
- // All OK, so prepare the statement
- text_statements_[index] = std::string(text);
-
- statements_[index] = mysql_stmt_init(mysql_);
- if (statements_[index] == NULL) {
- isc_throw(DbOperationError, "unable to allocate MySQL prepared "
- "statement structure" << mysql_error(mysql_));
- }
-
- int status = mysql_stmt_prepare(statements_[index], text, strlen(text));
- if (status != 0) {
- isc_throw(DbOperationError, "unable to prepare MySQL statement <" <<
- text << ">, reason: " << mysql_error(mysql_));
- }
-}
-
-
-void
-MySqlLeaseMgr::prepareStatements() {
- // Allocate space for all statements
- statements_.clear();
- statements_.resize(NUM_STATEMENTS, NULL);
-
- text_statements_.clear();
- text_statements_.resize(NUM_STATEMENTS, std::string(""));
-
- // Created the MySQL prepared statements for each DML statement.
- for (int i = 0; tagged_statements[i].text != NULL; ++i) {
- prepareStatement(tagged_statements[i].index,
- tagged_statements[i].text);
- }
-}
-
-
-bool
-MySqlLeaseMgr::addLease(const Lease4Ptr& /* lease */) {
- isc_throw(NotImplemented, "MySqlLeaseMgr::addLease(const Lease4Ptr&) "
- "not implemented yet");
- return (false);
-}
-
-
-bool
-MySqlLeaseMgr::addLease(const Lease6Ptr& lease) {
- const StatementIndex stindex = INSERT_LEASE6;
-
- // Create the MYSQL_BIND array for the lease
- std::vector<MYSQL_BIND> bind = exchange6_->createBindForSend(lease);
-
- // Bind the parameters to the statement
- int status = mysql_stmt_bind_param(statements_[stindex], &bind[0]);
- checkError(status, stindex, "unable to bind parameters");
-
- // Execute the statement
- status = mysql_stmt_execute(statements_[stindex]);
- if (status != 0) {
-
- // Failure: check for the special case of duplicate entry. If this is
- // the case, we return false to indicate that the row was not added.
- // Otherwise we throw an exception.
- if (mysql_errno(mysql_) == ER_DUP_ENTRY) {
- return (false);
- }
- checkError(status, stindex, "unable to execute");
- }
-
- // Insert succeeded
- return (true);
-}
-
-
-Lease4Ptr
-MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& /* addr */,
- SubnetID /* subnet_id */) const {
- isc_throw(NotImplemented, "MySqlLeaseMgr::getLease4(const IOAddress&, SubnetID) "
- "not implemented yet");
- return (Lease4Ptr());
-}
-
-
-Lease4Ptr
-MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& /* addr */) const {
- isc_throw(NotImplemented, "MySqlLeaseMgr::getLease4(const IOAddress&) "
- "not implemented yet");
- return (Lease4Ptr());
-}
-
-
-Lease4Collection
-MySqlLeaseMgr::getLease4(const HWAddr& /* hwaddr */) const {
- isc_throw(NotImplemented, "MySqlLeaseMgr::getLease4(const HWAddr&) "
- "not implemented yet");
- return (Lease4Collection());
-}
-
-
-Lease4Ptr
-MySqlLeaseMgr::getLease4(const HWAddr& /* hwaddr */,
- SubnetID /* subnet_id */) const {
- isc_throw(NotImplemented, "MySqlLeaseMgr::getLease4(const HWAddr&, SubnetID) "
- "not implemented yet");
- return (Lease4Ptr());
-}
-
-
-Lease4Collection
-MySqlLeaseMgr::getLease4(const ClientId& /* clientid */) const {
- isc_throw(NotImplemented, "MySqlLeaseMgr::getLease4(const ClientID&) "
- "not implemented yet");
- return (Lease4Collection());
-}
-
-
-Lease4Ptr
-MySqlLeaseMgr::getLease4(const ClientId& /* clientid */,
- SubnetID /* subnet_id */) const {
- isc_throw(NotImplemented, "MySqlLeaseMgr::getLease4(const ClientID&, SubnetID) "
- "not implemented yet");
- return (Lease4Ptr());
-}
-
-
-// A convenience function used in the various getLease6() methods. It binds
-// the selection parameters to the prepared statement, and binds the variables
-// that will receive the data. These are stored in the MySqlLease6Exchange
-// object associated with the lease manager and converted to a Lease6 object
-// when retrieved.
-void
-MySqlLeaseMgr::bind6AndExecute(StatementIndex stindex, MYSQL_BIND* inbind) const {
-
- // Bind the input parameters to the statement
- int status = mysql_stmt_bind_param(statements_[stindex], inbind);
- checkError(status, stindex, "unable to bind WHERE clause parameter");
-
- // Set up the SELECT clause
- std::vector<MYSQL_BIND> outbind = exchange6_->createBindForReceive();
-
- // Bind the output parameters to the statement
- status = mysql_stmt_bind_result(statements_[stindex], &outbind[0]);
- checkError(status, stindex, "unable to bind SELECT caluse parameters");
-
- // Execute the statement
- status = mysql_stmt_execute(statements_[stindex]);
- checkError(status, stindex, "unable to execute");
-}
-
-
-Lease6Ptr
-MySqlLeaseMgr::getLease6(const isc::asiolink::IOAddress& addr) const {
- const StatementIndex stindex = GET_LEASE6_ADDR;
-
- // Set up the WHERE clause value
- MYSQL_BIND inbind[1];
- memset(inbind, 0, sizeof(inbind));
-
- std::string addr6 = addr.toText();
- unsigned long addr6_length = addr6.size();
-
- // See the earlier description of the use of "const_cast" when accessing
- // the address for an explanation of the reason.
- inbind[0].buffer_type = MYSQL_TYPE_STRING;
- inbind[0].buffer = const_cast<char*>(addr6.c_str());
- inbind[0].buffer_length = addr6_length;
- inbind[0].length = &addr6_length;
-
- // Bind the input parameters to the statement and bind the output
- // to fields in the exchange object, then execute the prepared statement.
- bind6AndExecute(stindex, inbind);
-
- // Fetch the data and set up the "release" object to release associated
- // resources when this method exits.
- MySqlFreeResult fetch_release(statements_[stindex]);
- int status = mysql_stmt_fetch(statements_[stindex]);
-
- Lease6Ptr result;
- if (status == 0) {
- try {
- result = exchange6_->getLeaseData();
- } catch (const isc::BadValue& ex) {
- // Lease type is returned, to rethrow the exception with a bit
- // more data.
- isc_throw(BadValue, ex.what() << ". Statement is <" <<
- text_statements_[stindex] << ">");
- }
-
- // As the address is the primary key in the table, we can't return
- // two rows, so we don't bother checking whether multiple rows have
- // been returned.
-
- } else if (status == 1) {
- checkError(status, stindex, "unable to fetch results");
-
- } else {
- // @TODO Handle truncation
- // We are ignoring truncation for now, so the only other result is
- // no data was found. In that case, we return a null Lease6 structure.
- // This has already been set, so no action is needed.
- }
-
- return (result);
-}
-
-
-Lease6Collection
-MySqlLeaseMgr::getLease6(const DUID& duid, uint32_t iaid) const {
- const StatementIndex stindex = GET_LEASE6_DUID_IAID;
-
- // Set up the WHERE clause value
- MYSQL_BIND inbind[2];
- memset(inbind, 0, sizeof(inbind));
-
- // In the following statement, the DUID is being read. However, the
- // MySQL C interface does not use "const", so the "buffer" element
- // is declared as "char*" instead of "const char*". To resolve this,
- // the "const" is discarded before the uint8_t* is cast to char*.
- //
- // Note that the const_cast could be avoided by copying the DUID to
- // a writeable buffer and storing the address of that in the "buffer"
- // element. However, this introduces a copy operation (with additional
- // overhead) purely to get round the strictures introduced by design of
- // the MySQL interface (which uses the area pointed to by "buffer" as
- // input when specifying query parameters and as output when retrieving
- // data). For that reason, "const_cast" has been used.
- const vector<uint8_t>& duid_vector = duid.getDuid();
- unsigned long duid_length = duid_vector.size();
- inbind[0].buffer_type = MYSQL_TYPE_BLOB;
- inbind[0].buffer = reinterpret_cast<char*>(
- const_cast<uint8_t*>(&duid_vector[0]));
- inbind[0].buffer_length = duid_length;
- inbind[0].length = &duid_length;
-
- // IAID
- inbind[1].buffer_type = MYSQL_TYPE_LONG;
- inbind[1].buffer = reinterpret_cast<char*>(&iaid);
- inbind[1].is_unsigned = static_cast<my_bool>(1);
-
- // Bind the input parameters to the statement and bind the output
- // to fields in the exchange object, then execute the prepared statement.
- bind6AndExecute(stindex, inbind);
-
- // Ensure that all the lease information is retrieved in one go to avoid
- // overhead of going back and forth between client and server.
- int status = mysql_stmt_store_result(statements_[stindex]);
- checkError(status, stindex, "unable to set up for storing all results");
-
- // Fetch the data. There could be multiple rows, so we need to iterate
- // until all data has been retrieved.
- Lease6Collection result;
-
- // Set up the fetch "release" object to release resources associated
- // with the call to mysql_stmt_fetch when this method exits, then
- // retrieve the data.
- MySqlFreeResult fetch_release(statements_[stindex]);
- while ((status = mysql_stmt_fetch(statements_[stindex])) == 0) {
- try {
- Lease6Ptr lease = exchange6_->getLeaseData();
- result.push_back(lease);
-
- } catch (const isc::BadValue& ex) {
- // Rethrow the exception with a bit more data.
- isc_throw(BadValue, ex.what() << ". Statement is <" <<
- text_statements_[stindex] << ">");
- }
- }
-
- // How did the fetch end?
- if (status == 1) {
- // Error - unable to fecth results
- checkError(status, stindex, "unable to fetch results");
- } else if (status == MYSQL_DATA_TRUNCATED) {
- // @TODO Handle truncation
- ;
- }
-
- return (result);
-}
-
-
-Lease6Ptr
-MySqlLeaseMgr::getLease6(const DUID& duid, uint32_t iaid,
- SubnetID subnet_id) const {
- const StatementIndex stindex = GET_LEASE6_DUID_IAID_SUBID;
-
- // Set up the WHERE clause value
- MYSQL_BIND inbind[3];
- memset(inbind, 0, sizeof(inbind));
-
- // See the earlier description of the use of "const_cast" when accessing
- // the DUID for an explanation of the reason.
- const vector<uint8_t>& duid_vector = duid.getDuid();
- unsigned long duid_length = duid_vector.size();
- inbind[0].buffer_type = MYSQL_TYPE_BLOB;
- inbind[0].buffer = reinterpret_cast<char*>(
- const_cast<uint8_t*>(&duid_vector[0]));
- inbind[0].buffer_length = duid_length;
- inbind[0].length = &duid_length;
-
- // IAID
- inbind[1].buffer_type = MYSQL_TYPE_LONG;
- inbind[1].buffer = reinterpret_cast<char*>(&iaid);
- inbind[1].is_unsigned = static_cast<my_bool>(1);
-
- // Subnet ID
- inbind[2].buffer_type = MYSQL_TYPE_LONG;
- inbind[2].buffer = reinterpret_cast<char*>(&subnet_id);
- inbind[2].is_unsigned = static_cast<my_bool>(1);
-
- // Bind the input parameters to the statement and bind the output
- // to fields in the exchange object, then execute the prepared statement.
- bind6AndExecute(stindex, inbind);
-
- // Fetch the data and set up the "release" object to release associated
- // resources when this method exits then retrieve the data.
- Lease6Ptr result;
- MySqlFreeResult fetch_release(statements_[stindex]);
- int status = mysql_stmt_fetch(statements_[stindex]);
- if (status == 0) {
- try {
- result = exchange6_->getLeaseData();
-
- // TODO: check for more than one row returned. At present, just
- // ignore the excess and take the first.
-
- } catch (const isc::BadValue& ex) {
- // Lease type is returned, to rethrow the exception with a bit
- // more data.
- isc_throw(BadValue, ex.what() << ". Statement is <" <<
- text_statements_[stindex] << ">");
- }
-
- // As the address is the primary key in the table, we can't return
- // two rows, so we don't bother checking whether multiple rows have
- // been returned.
-
- } else if (status == 1) {
- checkError(status, stindex, "unable to fetch results");
-
- } else {
- // @TODO Handle truncation
- // We are ignoring truncation for now, so the only other result is
- // no data was found. In that case, we return a null Lease6 structure.
- // This has already been set, so the action is a no-op.
- }
-
- return (result);
-}
-
-
-void
-MySqlLeaseMgr::updateLease4(const Lease4Ptr& /* lease4 */) {
- isc_throw(NotImplemented, "MySqlLeaseMgr::updateLease4(const Lease4Ptr&) "
- "not implemented yet");
-}
-
-
-void
-MySqlLeaseMgr::updateLease6(const Lease6Ptr& lease) {
- const StatementIndex stindex = UPDATE_LEASE6;
-
- // Create the MYSQL_BIND array for the data being updated
- std::vector<MYSQL_BIND> bind = exchange6_->createBindForSend(lease);
-
- // Set up the WHERE clause value
- MYSQL_BIND where;
- memset(&where, 0, sizeof(where));
-
- std::string addr6 = lease->addr_.toText();
- unsigned long addr6_length = addr6.size();
-
- // See the earlier description of the use of "const_cast" when accessing
- // the address for an explanation of the reason.
- where.buffer_type = MYSQL_TYPE_STRING;
- where.buffer = const_cast<char*>(addr6.c_str());
- where.buffer_length = addr6_length;
- where.length = &addr6_length;
- bind.push_back(where);
-
- // Bind the parameters to the statement
- int status = mysql_stmt_bind_param(statements_[stindex], &bind[0]);
- checkError(status, stindex, "unable to bind parameters");
-
- // Execute
- status = mysql_stmt_execute(statements_[stindex]);
- checkError(status, stindex, "unable to execute");
-
- // See how many rows were affected. The statement should only delete a
- // single row.
- int affected_rows = mysql_stmt_affected_rows(statements_[stindex]);
- if (affected_rows == 0) {
- isc_throw(NoSuchLease, "unable to update lease for address " <<
- addr6 << " as it does not exist");
- } else if (affected_rows > 1) {
- // Should not happen - primary key constraint should only have selected
- // one row.
- isc_throw(DbOperationError, "apparently updated more than one lease "
- "that had the address " << addr6);
- }
-}
-
-
-bool
-MySqlLeaseMgr::deleteLease4(const isc::asiolink::IOAddress& /* addr */) {
- isc_throw(NotImplemented, "MySqlLeaseMgr::deleteLease4(const IOAddress&) "
- "not implemented yet");
- return (false);
-}
-
-
-bool
-MySqlLeaseMgr::deleteLease6(const isc::asiolink::IOAddress& addr) {
- const StatementIndex stindex = DELETE_LEASE6;
-
- // Set up the WHERE clause value
- MYSQL_BIND inbind[1];
- memset(inbind, 0, sizeof(inbind));
-
- std::string addr6 = addr.toText();
- unsigned long addr6_length = addr6.size();
-
- // See the earlier description of the use of "const_cast" when accessing
- // the address for an explanation of the reason.
- inbind[0].buffer_type = MYSQL_TYPE_STRING;
- inbind[0].buffer = const_cast<char*>(addr6.c_str());
- inbind[0].buffer_length = addr6_length;
- inbind[0].length = &addr6_length;
-
- // Bind the input parameters to the statement
- int status = mysql_stmt_bind_param(statements_[stindex], inbind);
- checkError(status, stindex, "unable to bind WHERE clause parameter");
-
- // Execute
- status = mysql_stmt_execute(statements_[stindex]);
- checkError(status, stindex, "unable to execute");
-
- // See how many rows were affected. Note that the statement may delete
- // multiple rows.
- return (mysql_stmt_affected_rows(statements_[stindex]) > 0);
-}
-
-
-std::string
-MySqlLeaseMgr::getName() const {
- std::string name = "";
- try {
- name = getParameter("name");
- } catch (...) {
- ;
- }
- return (name);
-}
-
-
-std::string
-MySqlLeaseMgr::getDescription() const {
- return (std::string("MySQL Database"));
-}
-
-
-std::pair<uint32_t, uint32_t>
-MySqlLeaseMgr::getVersion() const {
- const StatementIndex stindex = GET_VERSION;
-
- uint32_t major; // Major version number
- uint32_t minor; // Minor version number
-
- // Execute the prepared statement
- int status = mysql_stmt_execute(statements_[stindex]);
- if (status != 0) {
- isc_throw(DbOperationError, "unable to execute <"
- << text_statements_[stindex] << "> - reason: " <<
- mysql_error(mysql_));
- }
-
- // Bind the output of the statement to the appropriate variables.
- MYSQL_BIND bind[2];
- memset(bind, 0, sizeof(bind));
-
- bind[0].buffer_type = MYSQL_TYPE_LONG;
- bind[0].is_unsigned = 1;
- bind[0].buffer = &major;
- bind[0].buffer_length = sizeof(major);
-
- bind[1].buffer_type = MYSQL_TYPE_LONG;
- bind[1].is_unsigned = 1;
- bind[1].buffer = &minor;
- bind[1].buffer_length = sizeof(minor);
-
- status = mysql_stmt_bind_result(statements_[stindex], bind);
- if (status != 0) {
- isc_throw(DbOperationError, "unable to bind result set: " <<
- mysql_error(mysql_));
- }
-
- // Fetch the data and set up the "release" object to release associated
- // resources when this method exits then retrieve the data.
- MySqlFreeResult fetch_release(statements_[stindex]);
- status = mysql_stmt_fetch(statements_[stindex]);
- if (status != 0) {
- isc_throw(DbOperationError, "unable to obtain result set: " <<
- mysql_error(mysql_));
- }
-
- return (std::make_pair(major, minor));
-}
-
-
-void
-MySqlLeaseMgr::commit() {
- if (mysql_commit(mysql_) != 0) {
- isc_throw(DbOperationError, "commit failed: " << mysql_error(mysql_));
- }
-}
-
-
-void
-MySqlLeaseMgr::rollback() {
- if (mysql_rollback(mysql_) != 0) {
- isc_throw(DbOperationError, "rollback failed: " << mysql_error(mysql_));
- }
-}
-
-}; // end of isc::dhcp namespace
-}; // end of isc namespace
diff --git a/src/lib/dhcp/mysql_lease_mgr.h b/src/lib/dhcp/mysql_lease_mgr.h
deleted file mode 100644
index 8712c33..0000000
--- a/src/lib/dhcp/mysql_lease_mgr.h
+++ /dev/null
@@ -1,444 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef MYSQL_LEASE_MGR_H
-#define MYSQL_LEASE_MGR_H
-
-#include <time.h>
-#include <boost/scoped_ptr.hpp>
-#include <mysql.h>
-#include <dhcp/lease_mgr.h>
-
-namespace isc {
-namespace dhcp {
-
-// Define the current database schema values
-
-const uint32_t CURRENT_VERSION_VERSION = 0;
-const uint32_t CURRENT_VERSION_MINOR = 1;
-
-
-// Forward declaration of the Lease6 exchange object. This class is defined
-// in the .cc file.
-class MySqlLease6Exchange;
-
-
-/// @brief MySQL Lease Manager
-///
-/// This is a concrete API for the backend for the MySQL database.
-class MySqlLeaseMgr : public LeaseMgr {
-public:
- /// @brief Constructor
- ///
- /// Uses the following keywords in the parameters passed to it to
- /// connect to the database:
- /// - name - Name of the database to which to connect (mandatory)
- /// - host - Host to which to connect (optional, defaults to "localhost")
- /// - user - Username under which to connect (optional)
- /// - password - Password for "user" on the database (optional)
- ///
- /// If the database is successfully opened, the version number in the
- /// schema_version table will be checked against hard-coded value in
- /// the implementation file.
- ///
- /// Finally, all the SQL commands are pre-compiled.
- ///
- /// @param parameters A data structure relating keywords and values
- /// concerned with the database.
- ///
- /// @throw isc::dhcp::NoDatabaseName Mandatory database name not given
- /// @throw isc::dhcp::DbOpenError Error opening the database
- /// @throw isc::dhcp::DbOperationError An operation on the open database has
- /// failed.
- MySqlLeaseMgr(const ParameterMap& parameters);
-
- /// @brief Destructor (closes database)
- virtual ~MySqlLeaseMgr();
-
- /// @brief Adds an IPv4 lease.
- ///
- /// @param lease lease to be added
- ///
- /// @result true if the lease was added, false if not (because a lease
- /// with the same address was already there).
- ///
- /// @throw isc::dhcp::DbOperationError An operation on the open database has
- /// failed.
- virtual bool addLease(const Lease4Ptr& lease);
-
- /// @brief Adds an IPv6 lease.
- ///
- /// @param lease lease to be added
- ///
- /// @result true if the lease was added, false if not (because a lease
- /// with the same address was already there).
- ///
- /// @throw isc::dhcp::DbOperationError An operation on the open database has
- /// failed.
- virtual bool addLease(const Lease6Ptr& lease);
-
- /// @brief Return IPv4 lease for specified IPv4 address and subnet_id
- ///
- /// This method is used to get a lease for specific subnet_id. There can be
- /// at most one lease for any given subnet, so this method returns a single
- /// pointer.
- ///
- /// @param addr address of the sought lease
- /// @param subnet_id ID of the subnet the lease must belong to
- ///
- /// @return smart pointer to the lease (or NULL if a lease is not found)
- virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr,
- SubnetID subnet_id) const;
-
- /// @brief Returns an IPv4 lease for specified IPv4 address
- ///
- /// This method return a lease that is associated with a given address.
- /// For other query types (by hardware addr, by DUID) there can be
- /// several leases in different subnets (e.g. for mobile clients that
- /// got address in different subnets). However, for a single address
- /// there can be only one lease, so this method returns a pointer to
- /// a single lease, not a container of leases.
- ///
- /// @param addr address of the searched lease
- ///
- /// @return smart pointer to the lease (or NULL if a lease is not found)
- virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr) const;
-
-
- /// @brief Returns existing IPv4 leases for specified hardware address.
- ///
- /// Although in the usual case there will be only one lease, for mobile
- /// clients or clients with multiple static/fixed/reserved leases there
- /// can be more than one. Thus return type is a container, not a single
- /// pointer.
- ///
- /// @param hwaddr hardware address of the client
- ///
- /// @return lease collection
- virtual Lease4Collection getLease4(const HWAddr& hwaddr) const;
-
- /// @brief Returns existing IPv4 leases for specified hardware address
- /// and a subnet
- ///
- /// There can be at most one lease for a given HW address in a single
- /// pool, so this method with either return a single lease or NULL.
- ///
- /// @param hwaddr hardware address of the client
- /// @param subnet_id identifier of the subnet that lease must belong to
- ///
- /// @return a pointer to the lease (or NULL if a lease is not found)
- virtual Lease4Ptr getLease4(const HWAddr& hwaddr,
- SubnetID subnet_id) const;
-
- /// @brief Returns existing IPv4 lease for specified client-id
- ///
- /// Although in the usual case there will be only one lease, for mobile
- /// clients or clients with multiple static/fixed/reserved leases there
- /// can be more than one. Thus return type is a container, not a single
- /// pointer.
- ///
- /// @param clientid client identifier
- ///
- /// @return lease collection
- virtual Lease4Collection getLease4(const ClientId& clientid) const;
-
- /// @brief Returns existing IPv4 lease for specified client-id
- ///
- /// There can be at most one lease for a given HW address in a single
- /// pool, so this method with either return a single lease or NULL.
- ///
- /// @param clientid client identifier
- /// @param subnet_id identifier of the subnet that lease must belong to
- ///
- /// @return a pointer to the lease (or NULL if a lease is not found)
- virtual Lease4Ptr getLease4(const ClientId& clientid,
- SubnetID subnet_id) const;
-
- /// @brief Returns existing IPv6 lease for a given IPv6 address.
- ///
- /// For a given address, we assume that there will be only one lease.
- /// The assumtion here is that there will not be site or link-local
- /// addresses used, so there is no way of having address duplication.
- ///
- /// @param addr address of the searched lease
- ///
- /// @return smart pointer to the lease (or NULL if a lease is not found)
- ///
- /// @throw isc::BadValue record retrieved from database had an invalid
- /// lease type field.
- /// @throw isc::dhcp::DbOperationError An operation on the open database has
- /// failed.
- virtual Lease6Ptr getLease6(const isc::asiolink::IOAddress& addr) const;
-
- /// @brief Returns existing IPv6 leases for a given DUID+IA combination
- ///
- /// Although in the usual case there will be only one lease, for mobile
- /// clients or clients with multiple static/fixed/reserved leases there
- /// can be more than one. Thus return type is a container, not a single
- /// pointer.
- ///
- /// @param duid client DUID
- /// @param iaid IA identifier
- ///
- /// @return smart pointer to the lease (or NULL if a lease is not found)
- virtual Lease6Collection getLease6(const DUID& duid,
- uint32_t iaid) const;
-
- /// @brief Returns existing IPv6 lease for a given DUID+IA combination
- ///
- /// @param duid client DUID
- /// @param iaid IA identifier
- /// @param subnet_id subnet id of the subnet the lease belongs to
- ///
- /// @return smart pointer to the lease (or NULL if a lease is not found)
- virtual Lease6Ptr getLease6(const DUID& duid, uint32_t iaid,
- SubnetID subnet_id) const;
-
- /// @brief Updates IPv4 lease.
- ///
- /// @param lease4 The lease to be updated.
- ///
- /// If no such lease is present, an exception will be thrown.
- virtual void updateLease4(const Lease4Ptr& lease4);
-
- /// @brief Updates IPv6 lease.
- ///
- /// @param lease6 The lease to be updated.
- ///
- /// @throw isc::dhcp::NoSuchLease Attempt to update a lease that did not
- /// exist.
- /// @throw isc::dhcp::DbOperationError An operation on the open database has
- /// failed.
- virtual void updateLease6(const Lease6Ptr& lease6);
-
- /// @brief Deletes an IPv4 lease.
- ///
- /// @param addr IPv4 address of the lease to be deleted.
- ///
- /// @return true if deletion was successful, false if no such lease exists
- virtual bool deleteLease4(const isc::asiolink::IOAddress& addr);
-
- /// @brief Deletes an IPv6 lease.
- ///
- /// @param addr IPv6 address of the lease to be deleted.
- ///
- /// @return true if deletion was successful, false if no such lease exists
- ///
- /// @throw isc::dhcp::DbOperationError An operation on the open database has
- /// failed.
- virtual bool deleteLease6(const isc::asiolink::IOAddress& addr);
-
- /// @brief Returns backend name.
- ///
- /// Each backend have specific name, e.g. "mysql" or "sqlite".
- virtual std::string getName() const;
-
- /// @brief Returns description of the backend.
- ///
- /// This description may be multiline text that describes the backend.
- virtual std::string getDescription() const;
-
- /// @brief Returns backend version.
- ///
- /// @return Version number as a pair of unsigned integers. "first" is the
- /// major version number, "second" the minor number.
- ///
- /// @todo: We will need to implement 3 version functions eventually:
- /// A. abstract API version
- /// B. backend version
- /// C. database version (stored in the database scheme)
- ///
- /// and then check that:
- /// B>=A and B=C (it is ok to have newer backend, as it should be backward
- /// compatible)
- /// Also if B>C, some database upgrade procedure may be triggered
- ///
- /// @throw isc::dhcp::DbOperationError An operation on the open database has
- /// failed.
- virtual std::pair<uint32_t, uint32_t> getVersion() const;
-
- /// @brief Commit Transactions
- ///
- /// Commits all pending database operations. On databases that don't
- /// support transactions, this is a no-op.
- ///
- /// @throw DbOperationError Iif the commit failed.
- virtual void commit();
-
- /// @brief Rollback Transactions
- ///
- /// Rolls back all pending database operations. On databases that don't
- /// support transactions, this is a no-op.
- ///
- /// @throw DbOperationError If the rollback failed.
- virtual void rollback();
-
- ///@{
- /// The following methods are used to convert between times and time
- /// intervals stored in the Lease object, and the times stored in the
- /// database. The reason for the difference is because in the DHCP server,
- /// the cltt (Client Time Since Last Transmission) is the natural data; in
- /// the lease file - which may be read by the user - it is the expiry time
- /// of the lease.
-
- /// @brief Convert Lease Time to Database Times
- ///
- /// Within the DHCP servers, times are stored as client last transmit time
- /// and valid lifetime. In the database, the information is stored as
- /// valid lifetime and "expire" (time of expiry of the lease). They are
- /// related by the equation:
- ///
- /// - expire = client last transmit time + valid lifetime
- ///
- /// This method converts from the times in the lease object into times
- /// able to be added to the database.
- ///
- /// @param cltt Client last transmit time
- /// @param valid_lifetime Valid lifetime
- /// @param expire Reference to MYSQL_TIME object where the expiry time of
- /// the lease will be put.
- static
- void convertToDatabaseTime(time_t cltt, uint32_t valid_lifetime,
- MYSQL_TIME& expire);
-
- /// @brief Convert Database Time to Lease Times
- ///
- /// Within the database, time is stored as "expire" (time of expiry of the
- /// lease) and valid lifetime. In the DHCP server, the information is
- /// stored client last transmit time and valid lifetime. These are related
- /// by the equation:
- ///
- /// - client last transmit time = expire - valid_lifetime
- ///
- /// This method converts from the times in the database into times
- /// able to be inserted into the lease object.
- ///
- /// @param expire Reference to MYSQL_TIME object from where the expiry
- /// time of the lease is taken.
- /// @param valid_lifetime lifetime of the lease.
- /// @param cltt Reference to location where client last transmit time
- /// is put.
- static
- void convertFromDatabaseTime(const MYSQL_TIME& expire,
- uint32_t valid_lifetime, time_t& cltt);
- ///@}
-
- /// @brief Statement Tags
- ///
- /// The contents of the enum are indexes into the list of SQL statements
- enum StatementIndex {
- DELETE_LEASE6, // Delete from lease6 by address
- GET_LEASE6_ADDR, // Get lease6 by address
- GET_LEASE6_DUID_IAID, // Get lease6 by DUID and IAID
- GET_LEASE6_DUID_IAID_SUBID, // Get lease6 by DUID, IAID and Subnet ID
- GET_VERSION, // Obtain version number
- INSERT_LEASE6, // Add entry to lease6 table
- UPDATE_LEASE6, // Update a Lease6 entry
- NUM_STATEMENTS // Number of statements
- };
-
-private:
- /// @brief Prepare Single Statement
- ///
- /// Creates a prepared statement from the text given and adds it to the
- /// statements_ vector at the given index.
- ///
- /// @param index Index into the statements_ vector into which the text
- /// should be placed. The vector must be big enough for the index
- /// to be valid, else an exception will be thrown.
- /// @param text Text of the SQL statement to be prepared.
- ///
- /// @throw isc::dhcp::DbOperationError An operation on the open database has
- /// failed.
- /// @throw isc::InvalidParameter 'index' is not valid for the vector.
- void prepareStatement(StatementIndex index, const char* text);
-
- /// @brief Prepare statements
- ///
- /// Creates the prepared statements for all of the SQL statements used
- /// by the MySQL backend.
- ///
- /// @throw isc::dhcp::DbOperationError An operation on the open database has
- /// failed.
- /// @throw isc::InvalidParameter 'index' is not valid for the vector. This
- /// represents an internal error within the code.
- void prepareStatements();
-
- /// @brief Open Database
- ///
- /// Opens the database using the information supplied in the parameters
- /// passed to the constructor.
- ///
- /// @throw NoDatabaseName Mandatory database name not given
- /// @throw DbOpenError Error opening the database
- void openDatabase();
-
- /// @brief Binds Parameters and Executes
- ///
- /// This method abstracts a lot of common processing from the getXxxx()
- /// methods. It binds the parameters passed to it to the appropriate
- /// prepared statement, and binds the variables in the exchange6 object to
- /// the output parameters of the statement. It then executes the prepared
- /// statement.
- ///
- /// The data can be retrieved using mysql_stmt_fetch and the getLeaseData()
- /// method on the exchange6 object.
- ///
- /// @param stindex Index of prepared statement to be executed
- /// @param inbind Array of MYSQL_BIND objects representing the parameters.
- /// (Note that the number is determined by the number of parameters
- /// in the statement.)
- ///
- /// @throw isc::dhcp::DbOperationError An operation on the open database has
- /// failed.
- void bind6AndExecute(StatementIndex stindex, MYSQL_BIND* inbind) const;
-
- /// @brief Check Error and Throw Exception
- ///
- /// Virtually all MySQL functions return a status which, if non-zero,
- /// indicates an error. This inline function conceals a lot of error
- /// checking/exception-throwing code.
- ///
- /// @param status Status code: non-zero implies an error
- /// @param index Index of statement that caused the error
- /// @param what High-level description of the error
- ///
- /// @throw isc::dhcp::DbOperationError An operation on the open database has
- /// failed.
- inline void checkError(int status, StatementIndex index,
- const char* what) const {
- if (status != 0) {
- isc_throw(DbOperationError, what << " for <" <<
- text_statements_[index] << ">, reason: " <<
- mysql_error(mysql_) << " (error code " <<
- mysql_errno(mysql_) << ")");
- }
- }
-
- // Members
-
- /// Used for transfer of data to/from the database. This is a pointed-to
- /// object as its contents may change in "const" calls, while the rest
- /// of this object does not. (At alternative would be to declare it as
- /// "mutable".)
- boost::scoped_ptr<MySqlLease6Exchange> exchange6_;
- MYSQL* mysql_; ///< MySQL context object
- std::vector<std::string> text_statements_; ///< Raw text of statements
- std::vector<MYSQL_STMT*> statements_; ///< Prepared statements
-};
-
-}; // end of isc::dhcp namespace
-}; // end of isc namespace
-
-#endif // MYSQL_LEASE_MGR_H
diff --git a/src/lib/dhcp/option.cc b/src/lib/dhcp/option.cc
index fb441f9..d2be1d2 100644
--- a/src/lib/dhcp/option.cc
+++ b/src/lib/dhcp/option.cc
@@ -12,16 +12,17 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <string.h>
-#include <stdint.h>
-#include <arpa/inet.h>
-#include <sstream>
+#include <dhcp/libdhcp++.h>
+#include <dhcp/option.h>
+#include <exceptions/exceptions.h>
+#include <util/io_utilities.h>
+
#include <iomanip>
-#include "exceptions/exceptions.h"
-#include "util/io_utilities.h"
+#include <sstream>
-#include "dhcp/option.h"
-#include "dhcp/libdhcp++.h"
+#include <arpa/inet.h>
+#include <stdint.h>
+#include <string.h>
using namespace std;
using namespace isc::util;
diff --git a/src/lib/dhcp/option.h b/src/lib/dhcp/option.h
index 4617c26..920ef13 100644
--- a/src/lib/dhcp/option.h
+++ b/src/lib/dhcp/option.h
@@ -12,14 +12,16 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#ifndef OPTION_H_
-#define OPTION_H_
+#ifndef OPTION_H
+#define OPTION_H
+
+#include <util/buffer.h>
+
+#include <boost/shared_ptr.hpp>
-#include <string>
#include <map>
+#include <string>
#include <vector>
-#include <boost/shared_ptr.hpp>
-#include <util/buffer.h>
namespace isc {
namespace dhcp {
@@ -329,4 +331,4 @@ protected:
} // namespace isc::dhcp
} // namespace isc
-#endif
+#endif // OPTION_H
diff --git a/src/lib/dhcp/option4_addrlst.cc b/src/lib/dhcp/option4_addrlst.cc
index 4b0224f..76341b2 100644
--- a/src/lib/dhcp/option4_addrlst.cc
+++ b/src/lib/dhcp/option4_addrlst.cc
@@ -12,15 +12,17 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <string.h>
-#include <stdint.h>
-#include <arpa/inet.h>
-#include <sstream>
-#include <iomanip>
-#include <exceptions/exceptions.h>
#include <asiolink/io_address.h>
-#include <util/io_utilities.h>
#include <dhcp/option4_addrlst.h>
+#include <exceptions/exceptions.h>
+#include <util/io_utilities.h>
+
+#include <iomanip>
+#include <sstream>
+
+#include <arpa/inet.h>
+#include <stdint.h>
+#include <string.h>
using namespace std;
using namespace isc::util;
diff --git a/src/lib/dhcp/option4_addrlst.h b/src/lib/dhcp/option4_addrlst.h
index 01a8a4b..b266cbf 100644
--- a/src/lib/dhcp/option4_addrlst.h
+++ b/src/lib/dhcp/option4_addrlst.h
@@ -12,17 +12,19 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#ifndef OPTION4_ADDRLST_H_
-#define OPTION4_ADDRLST_H_
+#ifndef OPTION4_ADDRLST_H
+#define OPTION4_ADDRLST_H
-#include <string>
-#include <map>
-#include <vector>
-#include <boost/shared_ptr.hpp>
-#include <boost/shared_array.hpp>
#include <asiolink/io_address.h>
-#include <util/buffer.h>
#include <dhcp/option.h>
+#include <util/buffer.h>
+
+#include <boost/shared_array.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <map>
+#include <string>
+#include <vector>
namespace isc {
namespace dhcp {
@@ -162,4 +164,4 @@ protected:
} // namespace isc::dhcp
} // namespace isc
-#endif
+#endif // OPTION4_ADDRLST_H
diff --git a/src/lib/dhcp/option6_addrlst.cc b/src/lib/dhcp/option6_addrlst.cc
index d23b700..1af10b5 100644
--- a/src/lib/dhcp/option6_addrlst.cc
+++ b/src/lib/dhcp/option6_addrlst.cc
@@ -12,16 +12,17 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <stdint.h>
-#include <arpa/inet.h>
+#include <asiolink/io_address.h>
+#include <dhcp/dhcp6.h>
+#include <dhcp/libdhcp++.h>
+#include <dhcp/option6_addrlst.h>
+#include <exceptions/exceptions.h>
+#include <util/io_utilities.h>
+
#include <sstream>
-#include "exceptions/exceptions.h"
-#include "asiolink/io_address.h"
-#include "util/io_utilities.h"
-#include "dhcp/libdhcp++.h"
-#include "dhcp/option6_addrlst.h"
-#include "dhcp/dhcp6.h"
+#include <arpa/inet.h>
+#include <stdint.h>
using namespace std;
using namespace isc;
diff --git a/src/lib/dhcp/option6_addrlst.h b/src/lib/dhcp/option6_addrlst.h
index 209d2dd..b9c0deb 100644
--- a/src/lib/dhcp/option6_addrlst.h
+++ b/src/lib/dhcp/option6_addrlst.h
@@ -12,13 +12,14 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#ifndef OPTION6_ADDRLST_H_
-#define OPTION6_ADDRLST_H_
+#ifndef OPTION6_ADDRLST_H
+#define OPTION6_ADDRLST_H
-#include <vector>
#include <asiolink/io_address.h>
#include <dhcp/option.h>
+#include <vector>
+
namespace isc {
namespace dhcp {
@@ -96,4 +97,4 @@ protected:
} // isc::dhcp namespace
} // isc namespace
-#endif /* OPTION_ADDRLST_H_ */
+#endif // OPTION_ADDRLST_H
diff --git a/src/lib/dhcp/option6_ia.cc b/src/lib/dhcp/option6_ia.cc
index beba75f..9e4e01e 100644
--- a/src/lib/dhcp/option6_ia.cc
+++ b/src/lib/dhcp/option6_ia.cc
@@ -12,16 +12,16 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <stdint.h>
-#include <arpa/inet.h>
-#include <sstream>
-
-#include <exceptions/exceptions.h>
+#include <dhcp/dhcp6.h>
#include <dhcp/libdhcp++.h>
#include <dhcp/option6_ia.h>
-#include <dhcp/dhcp6.h>
+#include <exceptions/exceptions.h>
#include <util/io_utilities.h>
+#include <arpa/inet.h>
+#include <sstream>
+#include <stdint.h>
+
using namespace std;
using namespace isc::util;
diff --git a/src/lib/dhcp/option6_ia.h b/src/lib/dhcp/option6_ia.h
index c2089d4..54624d0 100644
--- a/src/lib/dhcp/option6_ia.h
+++ b/src/lib/dhcp/option6_ia.h
@@ -12,11 +12,12 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#ifndef OPTION_IA_H_
-#define OPTION_IA_H_
+#ifndef OPTION_IA_H
+#define OPTION_IA_H
+
+#include <dhcp/option.h>
#include <stdint.h>
-#include "option.h"
namespace isc {
namespace dhcp {
@@ -112,4 +113,4 @@ protected:
} // isc::dhcp namespace
} // isc namespace
-#endif /* OPTION_IA_H_ */
+#endif // OPTION_IA_H
diff --git a/src/lib/dhcp/option6_iaaddr.cc b/src/lib/dhcp/option6_iaaddr.cc
index 084a5f3..b021ce9 100644
--- a/src/lib/dhcp/option6_iaaddr.cc
+++ b/src/lib/dhcp/option6_iaaddr.cc
@@ -12,16 +12,17 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <stdint.h>
-#include <arpa/inet.h>
+#include <asiolink/io_address.h>
+#include <dhcp/dhcp6.h>
+#include <dhcp/libdhcp++.h>
+#include <dhcp/option6_iaaddr.h>
+#include <exceptions/exceptions.h>
+#include <util/io_utilities.h>
+
#include <sstream>
-#include "exceptions/exceptions.h"
-#include "dhcp/libdhcp++.h"
-#include "dhcp/option6_iaaddr.h"
-#include "dhcp/dhcp6.h"
-#include "asiolink/io_address.h"
-#include "util/io_utilities.h"
+#include <stdint.h>
+#include <arpa/inet.h>
using namespace std;
using namespace isc::asiolink;
diff --git a/src/lib/dhcp/option6_iaaddr.h b/src/lib/dhcp/option6_iaaddr.h
index e6e2c16..28c5abc 100644
--- a/src/lib/dhcp/option6_iaaddr.h
+++ b/src/lib/dhcp/option6_iaaddr.h
@@ -12,11 +12,11 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#ifndef OPTION6_IAADDR_H_
-#define OPTION6_IAADDR_H_
+#ifndef OPTION6_IAADDR_H
+#define OPTION6_IAADDR_H
-#include "asiolink/io_address.h"
-#include "dhcp/option.h"
+#include <asiolink/io_address.h>
+#include <dhcp/option.h>
namespace isc {
namespace dhcp {
@@ -120,4 +120,4 @@ protected:
} // isc::dhcp namespace
} // isc namespace
-#endif /* OPTION_IA_H_ */
+#endif // OPTION_IA_H
diff --git a/src/lib/dhcp/option6_int.h b/src/lib/dhcp/option6_int.h
index 5fd5c19..2c51389 100644
--- a/src/lib/dhcp/option6_int.h
+++ b/src/lib/dhcp/option6_int.h
@@ -12,8 +12,8 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#ifndef OPTION6_INT_H_
-#define OPTION6_INT_H_
+#ifndef OPTION6_INT_H
+#define OPTION6_INT_H
#include <dhcp/libdhcp++.h>
#include <dhcp/option.h>
@@ -186,4 +186,4 @@ private:
} // isc::dhcp namespace
} // isc namespace
-#endif /* OPTION6_INT_H_ */
+#endif // OPTION6_INT_H
diff --git a/src/lib/dhcp/option6_int_array.h b/src/lib/dhcp/option6_int_array.h
index 57aad1e..aba05a1 100644
--- a/src/lib/dhcp/option6_int_array.h
+++ b/src/lib/dhcp/option6_int_array.h
@@ -12,8 +12,8 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#ifndef OPTION6_INT_ARRAY_H_
-#define OPTION6_INT_ARRAY_H_
+#ifndef OPTION6_INT_ARRAY_H
+#define OPTION6_INT_ARRAY_H
#include <dhcp/libdhcp++.h>
#include <dhcp/option.h>
@@ -225,4 +225,4 @@ private:
} // isc::dhcp namespace
} // isc namespace
-#endif /* OPTION6_INT_ARRAY_H_ */
+#endif // OPTION6_INT_ARRAY_H
diff --git a/src/lib/dhcp/option_data_types.h b/src/lib/dhcp/option_data_types.h
index 4e8d8a6..0ad14d2 100644
--- a/src/lib/dhcp/option_data_types.h
+++ b/src/lib/dhcp/option_data_types.h
@@ -12,8 +12,8 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#ifndef OPTION_DATA_TYPES_H_
-#define OPTION_DATA_TYPES_H_
+#ifndef OPTION_DATA_TYPES_H
+#define OPTION_DATA_TYPES_H
#include <exceptions/exceptions.h>
@@ -86,4 +86,4 @@ struct OptionDataTypes<uint32_t> {
} // isc::dhcp namespace
} // isc namespace
-#endif /* OPTION_DATA_TYPES_H_ */
+#endif // OPTION_DATA_TYPES_H
diff --git a/src/lib/dhcp/option_definition.cc b/src/lib/dhcp/option_definition.cc
index 87b3216..ea3ced6 100644
--- a/src/lib/dhcp/option_definition.cc
+++ b/src/lib/dhcp/option_definition.cc
@@ -13,13 +13,13 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <dhcp/dhcp6.h>
-#include <dhcp/option_definition.h>
#include <dhcp/option4_addrlst.h>
#include <dhcp/option6_addrlst.h>
#include <dhcp/option6_ia.h>
#include <dhcp/option6_iaaddr.h>
#include <dhcp/option6_int.h>
#include <dhcp/option6_int_array.h>
+#include <dhcp/option_definition.h>
using namespace std;
using namespace isc::util;
diff --git a/src/lib/dhcp/option_definition.h b/src/lib/dhcp/option_definition.h
index 166765f..d9b7f98 100644
--- a/src/lib/dhcp/option_definition.h
+++ b/src/lib/dhcp/option_definition.h
@@ -12,16 +12,17 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#ifndef OPTION_DEFINITION_H_
-#define OPTION_DEFINITION_H_
+#ifndef OPTION_DEFINITION_H
+#define OPTION_DEFINITION_H
-#include <dhcp/option_data_types.h>
#include <dhcp/option.h>
-#include <boost/shared_ptr.hpp>
-#include <boost/multi_index_container.hpp>
+#include <dhcp/option_data_types.h>
+
#include <boost/multi_index/hashed_index.hpp>
-#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/mem_fun.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/shared_ptr.hpp>
namespace isc {
namespace dhcp {
@@ -461,4 +462,4 @@ typedef std::pair<OptionDefContainerTypeIndex::const_iterator,
} // namespace isc::dhcp
} // namespace isc
-#endif
+#endif // OPTION_DEFINITION_H
diff --git a/src/lib/dhcp/pkt4.cc b/src/lib/dhcp/pkt4.cc
index 405277d..5be8211 100644
--- a/src/lib/dhcp/pkt4.cc
+++ b/src/lib/dhcp/pkt4.cc
@@ -12,11 +12,12 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <dhcp/pkt4.h>
-#include <dhcp/libdhcp++.h>
+#include <asiolink/io_address.h>
#include <dhcp/dhcp4.h>
+#include <dhcp/libdhcp++.h>
+#include <dhcp/pkt4.h>
#include <exceptions/exceptions.h>
-#include <asiolink/io_address.h>
+
#include <iostream>
#include <sstream>
diff --git a/src/lib/dhcp/pkt4.h b/src/lib/dhcp/pkt4.h
index b72c03e..e09069c 100644
--- a/src/lib/dhcp/pkt4.h
+++ b/src/lib/dhcp/pkt4.h
@@ -15,14 +15,17 @@
#ifndef PKT4_H
#define PKT4_H
+#include <asiolink/io_address.h>
+#include <util/buffer.h>
+#include <dhcp/option.h>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/shared_ptr.hpp>
+
#include <iostream>
-#include <time.h>
#include <vector>
-#include <boost/shared_ptr.hpp>
-#include <boost/date_time/posix_time/posix_time.hpp>
-#include "asiolink/io_address.h"
-#include "util/buffer.h"
-#include "dhcp/option.h"
+
+#include <time.h>
namespace isc {
diff --git a/src/lib/dhcp/pkt6.cc b/src/lib/dhcp/pkt6.cc
index 330c97f..12597c3 100644
--- a/src/lib/dhcp/pkt6.cc
+++ b/src/lib/dhcp/pkt6.cc
@@ -12,11 +12,11 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-
#include <dhcp/dhcp6.h>
-#include <dhcp/pkt6.h>
#include <dhcp/libdhcp++.h>
+#include <dhcp/pkt6.h>
#include <exceptions/exceptions.h>
+
#include <iostream>
#include <sstream>
diff --git a/src/lib/dhcp/pkt6.h b/src/lib/dhcp/pkt6.h
index b3a3567..5782737 100644
--- a/src/lib/dhcp/pkt6.h
+++ b/src/lib/dhcp/pkt6.h
@@ -15,13 +15,16 @@
#ifndef PKT6_H
#define PKT6_H
+#include <asiolink/io_address.h>
+#include <dhcp/option.h>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/shared_array.hpp>
+#include <boost/shared_ptr.hpp>
+
#include <iostream>
+
#include <time.h>
-#include <boost/shared_ptr.hpp>
-#include <boost/shared_array.hpp>
-#include <boost/date_time/posix_time/posix_time.hpp>
-#include "asiolink/io_address.h"
-#include "dhcp/option.h"
namespace isc {
diff --git a/src/lib/dhcp/pool.cc b/src/lib/dhcp/pool.cc
deleted file mode 100644
index 1cf47a3..0000000
--- a/src/lib/dhcp/pool.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <asiolink/io_address.h>
-#include <dhcp/addr_utilities.h>
-#include <dhcp/pool.h>
-
-using namespace isc::asiolink;
-
-namespace isc {
-namespace dhcp {
-
-Pool::Pool(const isc::asiolink::IOAddress& first,
- const isc::asiolink::IOAddress& last)
- :id_(getNextID()), first_(first), last_(last) {
-}
-
-bool Pool::inRange(const isc::asiolink::IOAddress& addr) const {
- return (first_.smallerEqual(addr) && addr.smallerEqual(last_));
-}
-
-Pool4::Pool4(const isc::asiolink::IOAddress& first,
- const isc::asiolink::IOAddress& last)
- :Pool(first, last) {
- // check if specified address boundaries are sane
- if (first.getFamily() != AF_INET || last.getFamily() != AF_INET) {
- isc_throw(BadValue, "Invalid Pool4 address boundaries: not IPv4");
- }
-
- if (last < first) {
- isc_throw(BadValue, "Upper boundary is smaller than lower boundary.");
- }
-}
-
-Pool4::Pool4(const isc::asiolink::IOAddress& prefix,
- uint8_t prefix_len)
- :Pool(prefix, IOAddress("0.0.0.0")) {
-
- // check if the prefix is sane
- if (prefix.getFamily() != AF_INET) {
- isc_throw(BadValue, "Invalid Pool4 address boundaries: not IPv4");
- }
-
- // check if the prefix length is sane
- if (prefix_len == 0 || prefix_len > 32) {
- isc_throw(BadValue, "Invalid prefix length");
- }
-
- // Let's now calculate the last address in defined pool
- last_ = lastAddrInPrefix(prefix, prefix_len);
-}
-
-
-Pool6::Pool6(Pool6Type type, const isc::asiolink::IOAddress& first,
- const isc::asiolink::IOAddress& last)
- :Pool(first, last), type_(type), prefix_len_(0) {
-
- // check if specified address boundaries are sane
- if (first.getFamily() != AF_INET6 || last.getFamily() != AF_INET6) {
- isc_throw(BadValue, "Invalid Pool6 address boundaries: not IPv6");
- }
-
- if (last < first) {
- isc_throw(BadValue, "Upper boundary is smaller than lower boundary.");
- // This check is a bit strict. If we decide that it is too strict,
- // we need to comment it and uncomment lines below.
- // On one hand, letting the user specify 2001::f - 2001::1 is nice, but
- // on the other hand, 2001::1 may be a typo and the user really meant
- // 2001::1:0 (or 1 followed by some hex digit), so a at least a warning
- // would be useful.
-
- // first_ = last;
- // last_ = first;
- }
-
- // TYPE_PD is not supported by this constructor. first-last style
- // parameters are for IA and TA only. There is another dedicated
- // constructor for that (it uses prefix/length)
- if ((type != TYPE_IA) && (type != TYPE_TA)) {
- isc_throw(BadValue, "Invalid Pool6 type specified");
- }
-}
-
-Pool6::Pool6(Pool6Type type, const isc::asiolink::IOAddress& prefix,
- uint8_t prefix_len)
- :Pool(prefix, IOAddress("::")),
- type_(type), prefix_len_(prefix_len) {
-
- // check if the prefix is sane
- if (prefix.getFamily() != AF_INET6) {
- isc_throw(BadValue, "Invalid Pool6 address boundaries: not IPv6");
- }
-
- // check if the prefix length is sane
- if (prefix_len == 0 || prefix_len > 128) {
- isc_throw(BadValue, "Invalid prefix length");
- }
-
- /// @todo: We should probably implement checks against weird addresses
- /// here, like ::, starting with fe80, starting with ff etc. .
-
- // Let's now calculate the last address in defined pool
- last_ = lastAddrInPrefix(prefix, prefix_len);
-}
-
-}; // end of isc::dhcp namespace
-}; // end of isc namespace
diff --git a/src/lib/dhcp/pool.h b/src/lib/dhcp/pool.h
deleted file mode 100644
index dd68fdd..0000000
--- a/src/lib/dhcp/pool.h
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef POOL_H
-#define POOL_H
-
-#include <vector>
-#include <asiolink/io_address.h>
-#include <boost/shared_ptr.hpp>
-
-namespace isc {
-namespace dhcp {
-
-/// @brief base class for Pool4 and Pool6
-///
-/// Stores information about pool of IPv4 or IPv6 addresses.
-/// That is a basic component of a configuration.
-class Pool {
-
-public:
-
- /// @brief returns Pool-id
- ///
- /// @return pool-id value
- /// Pool-id is an unique value that can be used to identify a pool.
- uint32_t getId() const {
- return (id_);
- }
-
- /// @brief Returns the first address in a pool.
- ///
- /// @return first address in a pool
- const isc::asiolink::IOAddress& getFirstAddress() const {
- return (first_);
- }
-
- /// @brief Returns the last address in a pool.
- /// @return last address in a pool
- const isc::asiolink::IOAddress& getLastAddress() const {
- return (last_);
- }
-
- /// @brief Checks if a given address is in the range.
- ///
- /// @return true, if the address is in pool
- bool inRange(const isc::asiolink::IOAddress& addr) const;
-
-protected:
-
- /// @brief protected constructor
- ///
- /// This constructor is protected to prevent anyone from instantiating
- /// Pool class directly. Instances of Pool4 and Pool6 should be created
- /// instead.
- Pool(const isc::asiolink::IOAddress& first,
- const isc::asiolink::IOAddress& last);
-
- /// @brief returns the next unique Pool-ID
- ///
- /// @return the next unique Pool-ID
- static uint32_t getNextID() {
- static uint32_t id = 0;
- return (id++);
- }
-
- /// @brief pool-id
- ///
- /// This ID is used to identify this specific pool.
- uint32_t id_;
-
- /// @brief The first address in a pool
- isc::asiolink::IOAddress first_;
-
- /// @brief The last address in a pool
- isc::asiolink::IOAddress last_;
-
- /// @brief Comments field
- ///
- /// @todo: This field is currently not used.
- std::string comments_;
-};
-
-/// @brief Pool information for IPv4 addresses
-///
-/// It holds information about pool4, i.e. a range of IPv4 address space that
-/// is configured for DHCP allocation.
-class Pool4 : public Pool {
-public:
- /// @brief the constructor for Pool4 "min-max" style definition
- ///
- /// @param first the first address in a pool
- /// @param last the last address in a pool
- Pool4(const isc::asiolink::IOAddress& first,
- const isc::asiolink::IOAddress& last);
-
- /// @brief the constructor for Pool4 "prefix/len" style definition
- ///
- /// @param prefix specifies prefix of the pool
- /// @param prefix_len specifies length of the prefix of the pool
- Pool4(const isc::asiolink::IOAddress& prefix,
- uint8_t prefix_len);
-};
-
-/// @brief a pointer an IPv4 Pool
-typedef boost::shared_ptr<Pool4> Pool4Ptr;
-
-/// @brief a container for IPv4 Pools
-typedef std::vector<Pool4Ptr> Pool4Collection;
-
-/// @brief Pool information for IPv6 addresses and prefixes
-///
-/// It holds information about pool6, i.e. a range of IPv6 address space that
-/// is configured for DHCP allocation.
-class Pool6 : public Pool {
-public:
-
- /// @brief specifies Pool type
- ///
- /// Currently there are 3 pool types defined in DHCPv6:
- /// - Non-temporary addresses (conveyed in IA_NA)
- /// - Temporary addresses (conveyed in IA_TA)
- /// - Delegated Prefixes (conveyed in IA_PD)
- /// There is a new one being worked on (IA_PA, see draft-ietf-dhc-host-gen-id), but
- /// support for it is not planned for now.
- typedef enum {
- TYPE_IA,
- TYPE_TA,
- TYPE_PD
- } Pool6Type;
-
- /// @brief the constructor for Pool6 "min-max" style definition
- ///
- /// @param type type of the pool (IA, TA or PD)
- /// @param first the first address in a pool
- /// @param last the last address in a pool
- Pool6(Pool6Type type, const isc::asiolink::IOAddress& first,
- const isc::asiolink::IOAddress& last);
-
- /// @brief the constructor for Pool6 "prefix/len" style definition
- ///
- /// @param type type of the pool (IA, TA or PD)
- /// @param prefix specifies prefix of the pool
- /// @param prefix_len specifies length of the prefix of the pool
- Pool6(Pool6Type type, const isc::asiolink::IOAddress& prefix,
- uint8_t prefix_len);
-
- /// @brief returns pool type
- ///
- /// @return pool type
- Pool6Type getType() const {
- return (type_);
- }
-
-private:
- /// @brief defines a pool type
- Pool6Type type_;
-
- /// @brief prefix length
- /// used by TYPE_PD only (zeroed for other types)
- uint8_t prefix_len_;
-};
-
-/// @brief a pointer an IPv6 Pool
-typedef boost::shared_ptr<Pool6> Pool6Ptr;
-
-/// @brief a container for IPv6 Pools
-typedef std::vector<Pool6Ptr> Pool6Collection;
-
-} // end of isc::dhcp namespace
-} // end of isc namespace
-
-
-#endif // POOL_H
diff --git a/src/lib/dhcp/subnet.cc b/src/lib/dhcp/subnet.cc
deleted file mode 100644
index 28f2391..0000000
--- a/src/lib/dhcp/subnet.cc
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <dhcp/addr_utilities.h>
-#include <asiolink/io_address.h>
-#include <dhcp/subnet.h>
-#include <sstream>
-
-using namespace isc::asiolink;
-
-namespace isc {
-namespace dhcp {
-
-Subnet::Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
- const Triplet<uint32_t>& t1,
- const Triplet<uint32_t>& t2,
- const Triplet<uint32_t>& valid_lifetime)
- :id_(getNextID()), prefix_(prefix), prefix_len_(len), t1_(t1),
- t2_(t2), valid_(valid_lifetime),
- last_allocated_(lastAddrInPrefix(prefix, len)) {
- if ( (prefix.getFamily() == AF_INET6 && len > 128) ||
- (prefix.getFamily() == AF_INET && len > 32) ) {
- isc_throw(BadValue, "Invalid prefix length specified for subnet: " << len);
- }
-}
-
-bool Subnet::inRange(const isc::asiolink::IOAddress& addr) const {
- IOAddress first = firstAddrInPrefix(prefix_, prefix_len_);
- IOAddress last = lastAddrInPrefix(prefix_, prefix_len_);
-
- return ((first <= addr) && (addr <= last));
-}
-
-void
-Subnet::addOption(OptionPtr& option, bool persistent /* = false */) {
- validateOption(option);
- options_.push_back(OptionDescriptor(option, persistent));
-}
-
-void
-Subnet::delOptions() {
- options_.clear();
-}
-
-std::string Subnet::toText() const {
- std::stringstream tmp;
- tmp << prefix_.toText() << "/" << static_cast<unsigned int>(prefix_len_);
- return (tmp.str());
-}
-
-Subnet4::Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
- const Triplet<uint32_t>& t1,
- const Triplet<uint32_t>& t2,
- const Triplet<uint32_t>& valid_lifetime)
- :Subnet(prefix, length, t1, t2, valid_lifetime) {
- if (prefix.getFamily() != AF_INET) {
- isc_throw(BadValue, "Non IPv4 prefix " << prefix.toText()
- << " specified in subnet4");
- }
-}
-
-void Subnet4::addPool4(const Pool4Ptr& pool) {
- IOAddress first_addr = pool->getFirstAddress();
- IOAddress last_addr = pool->getLastAddress();
-
- if (!inRange(first_addr) || !inRange(last_addr)) {
- isc_throw(BadValue, "Pool4 (" << first_addr.toText() << "-" << last_addr.toText()
- << " does not belong in this (" << prefix_ << "/" << prefix_len_
- << ") subnet4");
- }
-
- /// @todo: Check that pools do not overlap
-
- pools_.push_back(pool);
-}
-
-Pool4Ptr Subnet4::getPool4(const isc::asiolink::IOAddress& hint /* = IOAddress("::")*/ ) {
- Pool4Ptr candidate;
- for (Pool4Collection::iterator pool = pools_.begin(); pool != pools_.end(); ++pool) {
-
- // if we won't find anything better, then let's just use the first pool
- if (!candidate) {
- candidate = *pool;
- }
-
- // if the client provided a pool and there's a pool that hint is valid in,
- // then let's use that pool
- if ((*pool)->inRange(hint)) {
- return (*pool);
- }
- }
- return (candidate);
-}
-
-void
-Subnet4::validateOption(const OptionPtr& option) const {
- if (!option) {
- isc_throw(isc::BadValue, "option configured for subnet must not be NULL");
- } else if (option->getUniverse() != Option::V4) {
- isc_throw(isc::BadValue, "expected V4 option to be added to the subnet");
- }
-}
-
-bool Subnet4::inPool(const isc::asiolink::IOAddress& addr) const {
-
- // Let's start with checking if it even belongs to that subnet.
- if (!inRange(addr)) {
- return (false);
- }
-
- for (Pool4Collection::const_iterator pool = pools_.begin(); pool != pools_.end(); ++pool) {
- if ((*pool)->inRange(addr)) {
- return (true);
- }
- }
- // there's no pool that address belongs to
- return (false);
-}
-
-Subnet6::Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
- const Triplet<uint32_t>& t1,
- const Triplet<uint32_t>& t2,
- const Triplet<uint32_t>& preferred_lifetime,
- const Triplet<uint32_t>& valid_lifetime)
- :Subnet(prefix, length, t1, t2, valid_lifetime),
- preferred_(preferred_lifetime){
- if (prefix.getFamily() != AF_INET6) {
- isc_throw(BadValue, "Non IPv6 prefix " << prefix.toText()
- << " specified in subnet6");
- }
-}
-
-void Subnet6::addPool6(const Pool6Ptr& pool) {
- IOAddress first_addr = pool->getFirstAddress();
- IOAddress last_addr = pool->getLastAddress();
-
- if (!inRange(first_addr) || !inRange(last_addr)) {
- isc_throw(BadValue, "Pool6 (" << first_addr.toText() << "-" << last_addr.toText()
- << " does not belong in this (" << prefix_ << "/" << prefix_len_
- << ") subnet6");
- }
-
- /// @todo: Check that pools do not overlap
-
- pools_.push_back(pool);
-}
-
-Pool6Ptr Subnet6::getPool6(const isc::asiolink::IOAddress& hint /* = IOAddress("::")*/ ) {
- Pool6Ptr candidate;
- for (Pool6Collection::iterator pool = pools_.begin(); pool != pools_.end(); ++pool) {
-
- // if we won't find anything better, then let's just use the first pool
- if (!candidate) {
- candidate = *pool;
- }
-
- // if the client provided a pool and there's a pool that hint is valid in,
- // then let's use that pool
- if ((*pool)->inRange(hint)) {
- return (*pool);
- }
- }
- return (candidate);
-}
-
-void
-Subnet6::validateOption(const OptionPtr& option) const {
- if (!option) {
- isc_throw(isc::BadValue, "option configured for subnet must not be NULL");
- } else if (option->getUniverse() != Option::V6) {
- isc_throw(isc::BadValue, "expected V6 option to be added to the subnet");
- }
-}
-
-bool Subnet6::inPool(const isc::asiolink::IOAddress& addr) const {
-
- // Let's start with checking if it even belongs to that subnet.
- if (!inRange(addr)) {
- return (false);
- }
-
- for (Pool6Collection::const_iterator pool = pools_.begin(); pool != pools_.end(); ++pool) {
- if ((*pool)->inRange(addr)) {
- return (true);
- }
- }
- // there's no pool that address belongs to
- return (false);
-}
-
-} // end of isc::dhcp namespace
-} // end of isc namespace
diff --git a/src/lib/dhcp/subnet.h b/src/lib/dhcp/subnet.h
deleted file mode 100644
index fcedda6..0000000
--- a/src/lib/dhcp/subnet.h
+++ /dev/null
@@ -1,517 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef SUBNET_H
-#define SUBNET_H
-
-#include <asiolink/io_address.h>
-#include <dhcp/pool.h>
-#include <dhcp/triplet.h>
-#include <dhcp/option.h>
-#include <boost/shared_ptr.hpp>
-#include <boost/multi_index_container.hpp>
-#include <boost/multi_index/hashed_index.hpp>
-#include <boost/multi_index/sequenced_index.hpp>
-#include <boost/multi_index/mem_fun.hpp>
-#include <boost/multi_index/member.hpp>
-
-namespace isc {
-namespace dhcp {
-
-/// @brief a base class for Subnet4 and Subnet6
-///
-/// This class presents a common base for IPv4 and IPv6 subnets.
-/// In a physical sense, a subnet defines a single network link with all devices
-/// attached to it. In most cases all devices attached to a single link can
-/// share the same parameters. Therefore Subnet holds several values that are
-/// typically shared by all hosts: renew timer (T1), rebind timer (T2) and
-/// leased addresses lifetime (valid-lifetime). It also holds the set
-/// of DHCP option instances configured for the subnet. These options are
-/// included in DHCP messages being sent to clients which are connected
-/// to the particular subnet.
-///
-/// @todo: Implement support for options here
-
-
-/// @brief Unique indentifier for a subnet (both v4 and v6)
-typedef uint32_t SubnetID;
-
-class Subnet {
-public:
-
- /// @brief Option descriptor.
- ///
- /// Option descriptor holds information about option configured for
- /// a particular subnet. This information comprises the actual option
- /// instance and information whether this option is sent to DHCP client
- /// only on request (persistent = false) or always (persistent = true).
- struct OptionDescriptor {
- /// Option instance.
- OptionPtr option;
- /// Persistent flag, if true option is always sent to the client,
- /// if false option is sent to the client on request.
- bool persistent;
-
- /// @brief Constructor.
- ///
- /// @param opt option
- /// @param persist if true option is always sent.
- OptionDescriptor(OptionPtr& opt, bool persist)
- : option(opt), persistent(persist) {};
-
- /// @brief Constructor
- ///
- /// @param persist if true option is always sent.
- OptionDescriptor(bool persist)
- : option(OptionPtr()), persistent(persist) {};
- };
-
- /// @brief Extractor class to extract key with another key.
- ///
- /// This class solves the problem of accessing index key values
- /// that are stored in objects nested in other objects.
- /// Each OptionDescriptor structure contains the OptionPtr object.
- /// The value retured by one of its accessors (getType) is used
- /// as an indexing value in the multi_index_container defined below.
- /// There is no easy way to mark that value returned by Option::getType
- /// should be an index of this multi_index_container. There are standard
- /// key extractors such as 'member' or 'mem_fun' but they are not
- /// sufficient here. The former can be used to mark that member of
- /// the structure that is held in the container should be used as an
- /// indexing value. The latter can be used if the indexing value is
- /// a product of the class being held in the container. In this complex
- /// scenario when the indexing value is a product of the function that
- /// is wrapped by the structure, this new extractor template has to be
- /// defined. The template class provides a 'chain' of two extractors
- /// to access the value returned by nested object and to use it as
- /// indexing value.
- /// For some more examples of complex keys see:
- /// http://www.cs.brown.edu/~jwicks/boost/libs/multi_index/doc/index.html
- ///
- /// @tparam KeyExtractor1 extractor used to access data in
- /// OptionDescriptor::option
- /// @tparam KeyExtractor2 extractor used to access
- /// OptionDescriptor::option member.
- template<typename KeyExtractor1, typename KeyExtractor2>
- class KeyFromKey {
- public:
- typedef typename KeyExtractor1::result_type result_type;
-
- /// @brief Constructor.
- KeyFromKey()
- : key1_(KeyExtractor1()), key2_(KeyExtractor2()) { };
-
- /// @brief Extract key with another key.
- ///
- /// @param arg the key value.
- ///
- /// @tparam key value type.
- template<typename T>
- result_type operator() (T& arg) const {
- return (key1_(key2_(arg)));
- }
- private:
- KeyExtractor1 key1_; ///< key 1.
- KeyExtractor2 key2_; ///< key 2.
- };
-
- /// @brief Multi index container for DHCP option descriptors.
- ///
- /// This container comprises three indexes to access option
- /// descriptors:
- /// - sequenced index: used to access elements in the order they
- /// have been added to the container,
- /// - option type index: used to search option descriptors containing
- /// options with specific option code (aka option type).
- /// - persistency flag index: used to search option descriptors with
- /// 'persistent' flag set to true.
- ///
- /// This container is the equivalent of three separate STL containers:
- /// - std::list of all options,
- /// - std::multimap of options with option code used as a multimap key,
- /// - std::multimap of option descriptors with option persistency flag
- /// used as a multimap key.
- /// The major advantage of this container over 3 separate STL containers
- /// is automatic synchronization of all indexes when elements are added,
- /// removed or modified in the container. With separate containers,
- /// the synchronization would have to be guaranteed by the Subnet class
- /// code. This would increase code complexity and presumably it would
- /// be much harder to add new search criteria (indexes).
- ///
- /// @todo we may want to search for options using option spaces when
- /// they are implemented.
- ///
- /// @see http://www.boost.org/doc/libs/1_51_0/libs/multi_index/doc/index.html
- typedef boost::multi_index_container<
- // Container comprises elements of OptionDescriptor type.
- OptionDescriptor,
- // Here we start enumerating various indexes.
- boost::multi_index::indexed_by<
- // Sequenced index allows accessing elements in the same way
- // as elements in std::list.
- // Sequenced is an index #0.
- boost::multi_index::sequenced<>,
- // Start definition of index #1.
- boost::multi_index::hashed_non_unique<
- // KeyFromKey is the index key extractor that allows accessing
- // option type being held by the OptionPtr through
- // OptionDescriptor structure.
- KeyFromKey<
- // Use option type as the index key. The type is held
- // in OptionPtr object so we have to call Option::getType
- // to retrieve this key for each element.
- boost::multi_index::mem_fun<
- Option,
- uint16_t,
- &Option::getType
- >,
- // Indicate that OptionPtr is a member of
- // OptionDescriptor structure.
- boost::multi_index::member<
- OptionDescriptor,
- OptionPtr,
- &OptionDescriptor::option
- >
- >
- >,
- // Start definition of index #2.
- // Use 'persistent' struct member as a key.
- boost::multi_index::hashed_non_unique<
- boost::multi_index::member<
- OptionDescriptor,
- bool,
- &OptionDescriptor::persistent
- >
- >
- >
- > OptionContainer;
-
- /// Type of the index #1 - option type.
- typedef OptionContainer::nth_index<1>::type OptionContainerTypeIndex;
- /// Pair of iterators to represent the range of options having the
- /// same option type value. The first element in this pair represents
- /// the begining of the range, the second element represents the end.
- typedef std::pair<OptionContainerTypeIndex::const_iterator,
- OptionContainerTypeIndex::const_iterator> OptionContainerTypeRange;
- /// Type of the index #2 - option persistency flag.
- typedef OptionContainer::nth_index<2>::type OptionContainerPersistIndex;
-
- /// @brief checks if specified address is in range
- bool inRange(const isc::asiolink::IOAddress& addr) const;
-
- /// @brief Add new option instance to the collection.
- ///
- /// @param option option instance.
- /// @param persistent if true, send an option regardless if client
- /// requested it or not.
- ///
- /// @throw isc::BadValue if invalid option provided.
- void addOption(OptionPtr& option, bool persistent = false);
-
- /// @brief Delete all options configured for the subnet.
- void delOptions();
-
- /// @brief checks if the specified address is in pools
- ///
- /// Note the difference between inSubnet() and inPool(). For a given
- /// subnet (e.g. 2001::/64) there may be one or more pools defined
- /// that may or may not cover entire subnet, e.g. pool 2001::1-2001::10).
- /// inPool() returning true implies inSubnet(), but the reverse implication
- /// is not always true. For the given example, 2001::1234:abcd would return
- /// true for inSubnet(), but false for inPool() check.
- ///
- /// @param addr this address will be checked if it belongs to any pools in
- /// that subnet
- /// @return true if the address is in any of the pools
- virtual bool inPool(const isc::asiolink::IOAddress& addr) const = 0;
-
- /// @brief return valid-lifetime for addresses in that prefix
- Triplet<uint32_t> getValid() const {
- return (valid_);
- }
-
- /// @brief returns T1 (renew timer), expressed in seconds
- Triplet<uint32_t> getT1() const {
- return (t1_);
- }
-
- /// @brief returns T2 (rebind timer), expressed in seconds
- Triplet<uint32_t> getT2() const {
- return (t2_);
- }
-
- /// @brief Return a collection of options.
- ///
- /// @return reference to collection of options configured for a subnet.
- /// The returned reference is valid as long as the Subnet object which
- /// returned it still exists.
- const OptionContainer& getOptions() const {
- return (options_);
- }
-
- /// @brief returns the last address that was tried from this pool
- ///
- /// This method returns the last address that was attempted to be allocated
- /// from this subnet. This is used as helper information for the next
- /// iteration of the allocation algorithm.
- ///
- /// @todo: Define map<SubnetID, IOAddress> somewhere in the
- /// AllocEngine::IterativeAllocator and keep the data there
- ///
- /// @return address that was last tried from this pool
- isc::asiolink::IOAddress getLastAllocated() const {
- return (last_allocated_);
- }
-
- /// @brief sets the last address that was tried from this pool
- ///
- /// This method sets the last address that was attempted to be allocated
- /// from this subnet. This is used as helper information for the next
- /// iteration of the allocation algorithm.
- ///
- /// @todo: Define map<SubnetID, IOAddress> somewhere in the
- /// AllocEngine::IterativeAllocator and keep the data there
- void setLastAllocated(const isc::asiolink::IOAddress& addr) {
- last_allocated_ = addr;
- }
-
- /// @brief returns unique ID for that subnet
- /// @return unique ID for that subnet
- SubnetID getID() const { return (id_); }
-
- /// @brief returns subnet parameters (prefix and prefix length)
- ///
- /// @return (prefix, prefix length) pair
- std::pair<isc::asiolink::IOAddress, uint8_t> get() const {
- return (std::make_pair(prefix_, prefix_len_));
- }
-
- /// @brief returns textual representation of the subnet (e.g. "2001:db8::/64")
- ///
- /// @return textual representation
- virtual std::string toText() const;
-
-protected:
- /// @brief protected constructor
- //
- /// By making the constructor protected, we make sure that noone will
- /// ever instantiate that class. Pool4 and Pool6 should be used instead.
- Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
- const Triplet<uint32_t>& t1,
- const Triplet<uint32_t>& t2,
- const Triplet<uint32_t>& valid_lifetime);
-
- /// @brief virtual destructor
- ///
- /// A virtual destructor is needed because other classes
- /// derive from this class.
- virtual ~Subnet() { };
-
- /// @brief returns the next unique Subnet-ID
- ///
- /// @return the next unique Subnet-ID
- static SubnetID getNextID() {
- static SubnetID id = 0;
- return (id++);
- }
-
- /// @brief Check if option is valid and can be added to a subnet.
- ///
- /// @param option option to be validated.
- virtual void validateOption(const OptionPtr& option) const = 0;
-
- /// @brief subnet-id
- ///
- /// Subnet-id is a unique value that can be used to find or identify
- /// a Subnet4 or Subnet6.
- SubnetID id_;
-
- /// @brief a prefix of the subnet
- isc::asiolink::IOAddress prefix_;
-
- /// @brief a prefix length of the subnet
- uint8_t prefix_len_;
-
- /// @brief a tripet (min/default/max) holding allowed renew timer values
- Triplet<uint32_t> t1_;
-
- /// @brief a tripet (min/default/max) holding allowed rebind timer values
- Triplet<uint32_t> t2_;
-
- /// @brief a tripet (min/default/max) holding allowed valid lifetime values
- Triplet<uint32_t> valid_;
-
- /// @brief a collection of DHCP options configured for a subnet.
- OptionContainer options_;
-
- /// @brief last allocated address
- ///
- /// This is the last allocated address that was previously allocated from
- /// this particular subnet. Some allocation algorithms (e.g. iterative) use
- /// that value, others do not. It should be noted that although the value
- /// is usually correct, there are cases when it is invalid, e.g. after
- /// removing a pool, restarting or changing allocation algorithms. For
- /// that purpose it should be only considered a help that should not be
- /// fully trusted.
- isc::asiolink::IOAddress last_allocated_;
-};
-
-/// @brief A configuration holder for IPv4 subnet.
-///
-/// This class represents an IPv4 subnet.
-class Subnet4 : public Subnet {
-public:
-
- /// @brief Constructor with all parameters
- ///
- /// @param prefix Subnet4 prefix
- /// @param length prefix length
- /// @param t1 renewal timer (in seconds)
- /// @param t2 rebind timer (in seconds)
- /// @param valid_lifetime preferred lifetime of leases (in seconds)
- Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
- const Triplet<uint32_t>& t1,
- const Triplet<uint32_t>& t2,
- const Triplet<uint32_t>& valid_lifetime);
-
- /// @brief Returns a pool that specified address belongs to
- ///
- /// @param hint address that the returned pool should cover (optional)
- /// @return Pointer to found pool4 (or NULL)
- Pool4Ptr getPool4(const isc::asiolink::IOAddress& hint =
- isc::asiolink::IOAddress("0.0.0.0"));
-
- /// @brief Adds a new pool.
- /// @param pool pool to be added
- void addPool4(const Pool4Ptr& pool);
-
- /// @brief returns all pools
- ///
- /// The reference is only valid as long as the object that returned it.
- ///
- /// @return a collection of all pools
- const Pool4Collection& getPools() const {
- return pools_;
- }
-
- /// @brief checks if the specified address is in pools
- ///
- /// See the description in \ref Subnet::inPool().
- ///
- /// @param addr this address will be checked if it belongs to any pools in that subnet
- /// @return true if the address is in any of the pools
- bool inPool(const isc::asiolink::IOAddress& addr) const;
-
-protected:
-
- /// @brief Check if option is valid and can be added to a subnet.
- ///
- /// @param option option to be validated.
- ///
- /// @throw isc::BadValue if provided option is invalid.
- virtual void validateOption(const OptionPtr& option) const;
-
- /// @brief collection of pools in that list
- Pool4Collection pools_;
-};
-
-/// @brief A pointer to a Subnet4 object
-typedef boost::shared_ptr<Subnet4> Subnet4Ptr;
-
-/// @brief A collection of Subnet6 objects
-typedef std::vector<Subnet4Ptr> Subnet4Collection;
-
-
-/// @brief A configuration holder for IPv6 subnet.
-///
-/// This class represents an IPv6 subnet.
-class Subnet6 : public Subnet {
-public:
-
- /// @brief Constructor with all parameters
- ///
- /// @param prefix Subnet6 prefix
- /// @param length prefix length
- /// @param t1 renewal timer (in seconds)
- /// @param t2 rebind timer (in seconds)
- /// @param preferred_lifetime preferred lifetime of leases (in seconds)
- /// @param valid_lifetime preferred lifetime of leases (in seconds)
- Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
- const Triplet<uint32_t>& t1,
- const Triplet<uint32_t>& t2,
- const Triplet<uint32_t>& preferred_lifetime,
- const Triplet<uint32_t>& valid_lifetime);
-
- /// @brief Returns preverred lifetime (in seconds)
- ///
- /// @return a triplet with preferred lifetime
- Triplet<uint32_t> getPreferred() const {
- return (preferred_);
- }
-
- /// @brief Returns a pool that specified address belongs to
- ///
- /// @param hint address that the returned pool should cover (optional)
- /// @return Pointer to found pool6 (or NULL)
- Pool6Ptr getPool6(const isc::asiolink::IOAddress& hint =
- isc::asiolink::IOAddress("::"));
-
- /// @brief Adds a new pool.
- /// @param pool pool to be added
- void addPool6(const Pool6Ptr& pool);
-
- /// @brief returns all pools
- ///
- /// The reference is only valid as long as the object that
- /// returned it.
- ///
- /// @return a collection of all pools
- const Pool6Collection& getPools() const {
- return pools_;
- }
-
- /// @brief checks if the specified address is in pools
- ///
- /// See the description in \ref Subnet::inPool().
- ///
- /// @param addr this address will be checked if it belongs to any pools in that subnet
- /// @return true if the address is in any of the pools
- bool inPool(const isc::asiolink::IOAddress& addr) const;
-
-protected:
-
- /// @brief Check if option is valid and can be added to a subnet.
- ///
- /// @param option option to be validated.
- ///
- /// @throw isc::BadValue if provided option is invalid.
- virtual void validateOption(const OptionPtr& option) const;
-
- /// @brief collection of pools in that list
- Pool6Collection pools_;
-
- /// @brief a triplet with preferred lifetime (in seconds)
- Triplet<uint32_t> preferred_;
-};
-
-/// @brief A pointer to a Subnet6 object
-typedef boost::shared_ptr<Subnet6> Subnet6Ptr;
-
-/// @brief A collection of Subnet6 objects
-typedef std::vector<Subnet6Ptr> Subnet6Collection;
-
-} // end of isc::dhcp namespace
-} // end of isc namespace
-
-#endif // SUBNET_T
diff --git a/src/lib/dhcp/tests/Makefile.am b/src/lib/dhcp/tests/Makefile.am
index bf5e2e7..945f822 100644
--- a/src/lib/dhcp/tests/Makefile.am
+++ b/src/lib/dhcp/tests/Makefile.am
@@ -4,9 +4,6 @@ AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
AM_CPPFLAGS += $(BOOST_INCLUDES)
AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/lib/dhcp/tests\"
AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
-# Temp
-AM_CPPFLAGS += -I/usr/include/mysql -DBIG_JOINS=1 -fno-strict-aliasing
-AM_CPPFLAGS += -DUNIV_LINUX
AM_CXXFLAGS = $(B10_CXXFLAGS)
@@ -27,7 +24,8 @@ TESTS_ENVIRONMENT = \
TESTS =
if HAVE_GTEST
-TESTS += libdhcp++_unittests libdhcpsrv_unittests
+TESTS += libdhcp++_unittests
+
libdhcp___unittests_SOURCES = run_unittests.cc
libdhcp___unittests_SOURCES += iface_mgr_unittest.cc
libdhcp___unittests_SOURCES += libdhcp++_unittest.cc
@@ -41,48 +39,18 @@ libdhcp___unittests_SOURCES += option_definition_unittest.cc
libdhcp___unittests_SOURCES += option_unittest.cc
libdhcp___unittests_SOURCES += pkt4_unittest.cc
libdhcp___unittests_SOURCES += pkt6_unittest.cc
-libdhcp___unittests_SOURCES += schema_copy.h
+libdhcp___unittests_SOURCES += duid_unittest.cc
libdhcp___unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
-libdhcp___unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
-libdhcp___unittests_CXXFLAGS = $(AM_CXXFLAGS)
-
-libdhcpsrv_unittests_SOURCES = run_unittests.cc
-libdhcpsrv_unittests_SOURCES += addr_utilities_unittest.cc
-libdhcpsrv_unittests_SOURCES += alloc_engine_unittest.cc
-libdhcpsrv_unittests_SOURCES += cfgmgr_unittest.cc
-libdhcpsrv_unittests_SOURCES += duid_unittest.cc
-libdhcpsrv_unittests_SOURCES += lease_mgr_factory_unittest.cc
-libdhcpsrv_unittests_SOURCES += lease_mgr_unittest.cc
-libdhcpsrv_unittests_SOURCES += memfile_lease_mgr_unittest.cc
-if HAVE_MYSQL
-libdhcpsrv_unittests_SOURCES += mysql_lease_mgr_unittest.cc
-endif
-libdhcpsrv_unittests_SOURCES += pool_unittest.cc
-libdhcpsrv_unittests_SOURCES += subnet_unittest.cc
-libdhcpsrv_unittests_SOURCES += triplet_unittest.cc
-
-libdhcpsrv_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
-libdhcpsrv_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
-libdhcpsrv_unittests_CXXFLAGS = $(AM_CXXFLAGS)
-libdhcpsrv_unittests_LDADD = $(GTEST_LDADD)
-libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
-libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
-libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcpsrv.la
-libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
-libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
-if HAVE_MYSQL
-libdhcpsrv_unittests_CPPFLAGS += $(MYSQL_CPPFLAGS)
-libdhcpsrv_unittests_LDFLAGS += $(MYSQL_LIBS)
-endif
+libdhcp___unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+libdhcp___unittests_CXXFLAGS = $(AM_CXXFLAGS)
if USE_CLANGPP
# This is to workaround unused variables tcout and tcerr in
# log4cplus's streams.h and unused parameters from some of the
# Boost headers.
libdhcp___unittests_CXXFLAGS += -Wno-unused-variable -Wno-unused-parameter
-libdhcpsrv_unittests_CXXFLAGS += -Wno-unused-variable -Wno-unused-parameter
endif
libdhcp___unittests_LDADD = $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
diff --git a/src/lib/dhcp/tests/addr_utilities_unittest.cc b/src/lib/dhcp/tests/addr_utilities_unittest.cc
deleted file mode 100644
index 2ea4e2a..0000000
--- a/src/lib/dhcp/tests/addr_utilities_unittest.cc
+++ /dev/null
@@ -1,154 +0,0 @@
-
-// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include <gtest/gtest.h>
-#include <vector>
-
-#include <dhcp/addr_utilities.h>
-
-using namespace std;
-using namespace isc::dhcp;
-using namespace isc::asiolink;
-
-// This test verifies that lastAddrInPrefix is able to handle IPv4 operations.
-TEST(AddrUtilitiesTest, lastAddrInPrefix4) {
- IOAddress addr1("192.0.2.1");
-
- // Prefixes rounded to addresses are easy...
- EXPECT_EQ("192.255.255.255", lastAddrInPrefix(addr1, 8).toText());
- EXPECT_EQ("192.0.255.255", lastAddrInPrefix(addr1, 16).toText());
- EXPECT_EQ("192.0.2.255", lastAddrInPrefix(addr1, 24).toText());
-
- // these are trickier
- EXPECT_EQ("192.0.2.127", lastAddrInPrefix(addr1, 25).toText());
- EXPECT_EQ("192.0.2.63", lastAddrInPrefix(addr1, 26).toText());
- EXPECT_EQ("192.0.2.31", lastAddrInPrefix(addr1, 27).toText());
- EXPECT_EQ("192.0.2.15", lastAddrInPrefix(addr1, 28).toText());
- EXPECT_EQ("192.0.2.7", lastAddrInPrefix(addr1, 29).toText());
- EXPECT_EQ("192.0.2.3", lastAddrInPrefix(addr1, 30).toText());
-
- // that doesn't make much sense as /31 subnet consists of network address
- // and a broadcast address, with 0 usable addresses.
- EXPECT_EQ("192.0.2.1", lastAddrInPrefix(addr1, 31).toText());
- EXPECT_EQ("192.0.2.1", lastAddrInPrefix(addr1, 32).toText());
-
- // Let's check extreme cases
- IOAddress anyAddr("0.0.0.0");
- EXPECT_EQ("127.255.255.255", lastAddrInPrefix(anyAddr, 1).toText());
- EXPECT_EQ("255.255.255.255", lastAddrInPrefix(anyAddr, 0).toText());
- EXPECT_EQ("0.0.0.0", lastAddrInPrefix(anyAddr, 32).toText());
-}
-
-// This test checks if firstAddrInPrefix is able to handle IPv4 operations.
-TEST(AddrUtilitiesTest, firstAddrInPrefix4) {
- IOAddress addr1("192.223.2.255");
-
- // Prefixes rounded to addresses are easy...
- EXPECT_EQ("192.0.0.0", firstAddrInPrefix(addr1, 8).toText());
- EXPECT_EQ("192.223.0.0", firstAddrInPrefix(addr1, 16).toText());
- EXPECT_EQ("192.223.2.0", firstAddrInPrefix(addr1, 24).toText());
-
- // these are trickier
- EXPECT_EQ("192.223.2.128", firstAddrInPrefix(addr1, 25).toText());
- EXPECT_EQ("192.223.2.192", firstAddrInPrefix(addr1, 26).toText());
- EXPECT_EQ("192.223.2.224", firstAddrInPrefix(addr1, 27).toText());
- EXPECT_EQ("192.223.2.240", firstAddrInPrefix(addr1, 28).toText());
- EXPECT_EQ("192.223.2.248", firstAddrInPrefix(addr1, 29).toText());
- EXPECT_EQ("192.223.2.252", firstAddrInPrefix(addr1, 30).toText());
-
- // that doesn't make much sense as /31 subnet consists of network address
- // and a broadcast address, with 0 usable addresses.
- EXPECT_EQ("192.223.2.254", firstAddrInPrefix(addr1, 31).toText());
- EXPECT_EQ("192.223.2.255", firstAddrInPrefix(addr1, 32).toText());
-
- // Let's check extreme cases.
- IOAddress bcast("255.255.255.255");
- EXPECT_EQ("128.0.0.0", firstAddrInPrefix(bcast, 1).toText());
- EXPECT_EQ("0.0.0.0", firstAddrInPrefix(bcast, 0).toText());
- EXPECT_EQ("255.255.255.255", firstAddrInPrefix(bcast, 32).toText());
-
-}
-
-/// This test checks if lastAddrInPrefix properly supports IPv6 operations
-TEST(AddrUtilitiesTest, lastAddrInPrefix6) {
- IOAddress addr1("2001:db8:1:1234:5678:abcd:1234:beef");
-
- // Prefixes rounded to nibbles are easy...
- EXPECT_EQ("2001:db8:1:1234:5678:abcd:1234:ffff",
- lastAddrInPrefix(addr1, 112).toText());
- EXPECT_EQ("2001:db8:1:1234:5678:abcd:123f:ffff",
- lastAddrInPrefix(addr1, 108).toText());
- EXPECT_EQ("2001:db8:1:1234:5678:abcd:12ff:ffff",
- lastAddrInPrefix(addr1, 104).toText());
- EXPECT_EQ("2001:db8:1:1234:ffff:ffff:ffff:ffff",
- lastAddrInPrefix(addr1, 64).toText());
-
- IOAddress addr2("2001::");
-
- // These are tricker, though, as they are done in 1 bit increments
-
- // the last address in 2001::/127 pool should be 2001::1
- EXPECT_EQ("2001::1", lastAddrInPrefix(addr2, 127).toText());
-
- EXPECT_EQ("2001::3", lastAddrInPrefix(addr2, 126).toText());
- EXPECT_EQ("2001::7", lastAddrInPrefix(addr2, 125).toText());
- EXPECT_EQ("2001::f", lastAddrInPrefix(addr2, 124).toText());
- EXPECT_EQ("2001::1f", lastAddrInPrefix(addr2, 123).toText());
- EXPECT_EQ("2001::3f", lastAddrInPrefix(addr2, 122).toText());
- EXPECT_EQ("2001::7f", lastAddrInPrefix(addr2, 121).toText());
- EXPECT_EQ("2001::ff", lastAddrInPrefix(addr2, 120).toText());
-
- // Let's check extreme cases
- IOAddress anyAddr("::");
- EXPECT_EQ("7fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
- lastAddrInPrefix(anyAddr, 1).toText());
- EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
- lastAddrInPrefix(anyAddr, 0).toText());
- EXPECT_EQ("::", lastAddrInPrefix(anyAddr, 128).toText());
-}
-
-/// This test checks if firstAddrInPrefix properly supports IPv6 operations
-TEST(AddrUtilitiesTest, firstAddrInPrefix6) {
- IOAddress addr1("2001:db8:1:1234:5678:1234:abcd:beef");
-
- // Prefixes rounded to nibbles are easy...
- EXPECT_EQ("2001:db8:1:1234:5678:1234::",
- firstAddrInPrefix(addr1, 96).toText());
- EXPECT_EQ("2001:db8:1:1234:5678:1230::",
- firstAddrInPrefix(addr1, 92).toText());
- EXPECT_EQ("2001:db8:1:1234:5678:1200::",
- firstAddrInPrefix(addr1, 88).toText());
- EXPECT_EQ("2001:db8:1:1234::",
- firstAddrInPrefix(addr1, 64).toText());
-
- IOAddress addr2("2001::ffff");
-
- // These are tricker, though, as they are done in 1 bit increments
-
- // the first address in 2001::/127 pool should be 2001::1
- EXPECT_EQ("2001::fffe", firstAddrInPrefix(addr2, 127).toText());
-
- EXPECT_EQ("2001::fffc", firstAddrInPrefix(addr2, 126).toText());
- EXPECT_EQ("2001::fff8", firstAddrInPrefix(addr2, 125).toText());
- EXPECT_EQ("2001::fff0", firstAddrInPrefix(addr2, 124).toText());
- EXPECT_EQ("2001::ffe0", firstAddrInPrefix(addr2, 123).toText());
- EXPECT_EQ("2001::ffc0", firstAddrInPrefix(addr2, 122).toText());
- EXPECT_EQ("2001::ff80", firstAddrInPrefix(addr2, 121).toText());
- EXPECT_EQ("2001::ff00", firstAddrInPrefix(addr2, 120).toText());
-}
diff --git a/src/lib/dhcp/tests/alloc_engine_unittest.cc b/src/lib/dhcp/tests/alloc_engine_unittest.cc
deleted file mode 100644
index 456ad53..0000000
--- a/src/lib/dhcp/tests/alloc_engine_unittest.cc
+++ /dev/null
@@ -1,337 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-#include <asiolink/io_address.h>
-#include <dhcp/lease_mgr.h>
-#include <dhcp/lease_mgr_factory.h>
-#include <dhcp/duid.h>
-#include <dhcp/alloc_engine.h>
-#include <dhcp/cfgmgr.h>
-#include <dhcp/memfile_lease_mgr.h>
-#include <boost/shared_ptr.hpp>
-#include <boost/scoped_ptr.hpp>
-#include <iostream>
-#include <sstream>
-#include <map>
-#include <gtest/gtest.h>
-
-using namespace std;
-using namespace isc;
-using namespace isc::asiolink;
-using namespace isc::dhcp;
-
-namespace {
-
-class NakedAllocEngine : public AllocEngine {
-public:
- NakedAllocEngine(AllocEngine::AllocType engine_type, unsigned int attempts)
- :AllocEngine(engine_type, attempts) {
- }
- using AllocEngine::Allocator;
- using AllocEngine::IterativeAllocator;
-};
-
-// empty class for now, but may be extended once Addr6 becomes bigger
-class AllocEngineTest : public ::testing::Test {
-public:
- AllocEngineTest() {
- duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0x42)));
- iaid_ = 42;
-
- // instantiate cfg_mgr
- CfgMgr& cfg_mgr = CfgMgr::instance();
-
- subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
- pool_ = Pool6Ptr(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1::10"),
- IOAddress("2001:db8:1::20")));
- subnet_->addPool6(pool_);
- cfg_mgr.addSubnet6(subnet_);
-
- factory_.create("type=memfile");
- }
-
- void checkLease6(const Lease6Ptr& lease) {
- // that is belongs to the right subnet
- EXPECT_EQ(lease->subnet_id_, subnet_->getID());
- EXPECT_TRUE(subnet_->inRange(lease->addr_));
- EXPECT_TRUE(subnet_->inPool(lease->addr_));
-
- // that it have proper parameters
- EXPECT_EQ(iaid_, lease->iaid_);
- EXPECT_EQ(subnet_->getValid(), lease->valid_lft_);
- EXPECT_EQ(subnet_->getPreferred(), lease->preferred_lft_);
- EXPECT_EQ(subnet_->getT1(), lease->t1_);
- EXPECT_EQ(subnet_->getT2(), lease->t2_);
- EXPECT_EQ(0, lease->prefixlen_); // this is IA_NA, not IA_PD
- EXPECT_TRUE(false == lease->fqdn_fwd_);
- EXPECT_TRUE(false == lease->fqdn_rev_);
- EXPECT_TRUE(*lease->duid_ == *duid_);
- // @todo: check cltt
- }
-
- ~AllocEngineTest() {
- factory_.destroy();
- }
-
- DuidPtr duid_;
- uint32_t iaid_;
- Subnet6Ptr subnet_;
- Pool6Ptr pool_;
- LeaseMgrFactory factory_;
-};
-
-// This test checks if the Allocation Engine can be instantiated and that it
-// parses parameters string properly.
-TEST_F(AllocEngineTest, constructor) {
- boost::scoped_ptr<AllocEngine> x;
-
- // Hashed and random allocators are not supported yet
- ASSERT_THROW(x.reset(new AllocEngine(AllocEngine::ALLOC_HASHED, 5)), NotImplemented);
- ASSERT_THROW(x.reset(new AllocEngine(AllocEngine::ALLOC_RANDOM, 5)), NotImplemented);
-
- ASSERT_NO_THROW(x.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
-}
-
-/// @todo: This method is taken from mysql_lease_mgr_utilities.cc from ticket
-/// #2342. Get rid of one instance once the code is merged
-void
-detailCompareLease6(const Lease6Ptr& first, const Lease6Ptr& second) {
- EXPECT_EQ(first->type_, second->type_);
-
- // Compare address strings - odd things happen when they are different
- // as the EXPECT_EQ appears to call the operator uint32_t() function,
- // which causes an exception to be thrown for IPv6 addresses.
- EXPECT_EQ(first->addr_.toText(), second->addr_.toText());
- EXPECT_EQ(first->prefixlen_, second->prefixlen_);
- EXPECT_EQ(first->iaid_, second->iaid_);
- EXPECT_TRUE(*first->duid_ == *second->duid_);
- EXPECT_EQ(first->preferred_lft_, second->preferred_lft_);
- EXPECT_EQ(first->valid_lft_, second->valid_lft_);
- EXPECT_EQ(first->cltt_, second->cltt_);
- EXPECT_EQ(first->subnet_id_, second->subnet_id_);
-}
-
-
-// This test checks if the simple allocation can succeed
-TEST_F(AllocEngineTest, simpleAlloc) {
- 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("::"),
- false);
-
- // check that we got a lease
- ASSERT_TRUE(lease);
-
- // do all checks on the lease
- checkLease6(lease);
-
- // Check that the lease is indeed in LeaseMgr
- Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->addr_);
- ASSERT_TRUE(from_mgr);
-
- // Now check that the lease in LeaseMgr has the same parameters
- detailCompareLease6(lease, from_mgr);
-}
-
-// This test checks if the fake allocation (for SOLICIT) can succeed
-TEST_F(AllocEngineTest, fakeAlloc) {
- 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("::"),
- true);
-
- // check that we got a lease
- ASSERT_TRUE(lease);
-
- // do all checks on the lease
- checkLease6(lease);
-
- // Check that the lease is NOT in LeaseMgr
- Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->addr_);
- ASSERT_FALSE(from_mgr);
-}
-
-// This test checks if the allocation with a hint that is valid (in range,
-// in pool and free) can succeed
-TEST_F(AllocEngineTest, allocWithValidHint) {
- 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("2001:db8:1::15"),
- false);
-
- // check that we got a lease
- ASSERT_TRUE(lease);
-
- // we should get what we asked for
- EXPECT_EQ(lease->addr_.toText(), "2001:db8:1::15");
-
- // do all checks on the lease
- checkLease6(lease);
-
- // Check that the lease is indeed in LeaseMgr
- Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->addr_);
- ASSERT_TRUE(from_mgr);
-
- // Now check that the lease in LeaseMgr has the same parameters
- detailCompareLease6(lease, from_mgr);
-}
-
-// 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) {
- 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
- DuidPtr duid2 = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0xff)));
- Lease6Ptr used(new Lease6(Lease6::LEASE_IA_NA, IOAddress("2001:db8:1::1f"),
- duid2, 1, 2, 3, 4, 5, subnet_->getID()));
- ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
-
- // another client comes in and request an address that is in pool, but
- // unfortunately it is used already. The same address must not be allocated
- // twice.
- Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
- IOAddress("2001:db8:1::1f"),
- false);
- // check that we got a lease
- ASSERT_TRUE(lease);
-
- // allocated address must be different
- EXPECT_TRUE(used->addr_.toText() != lease->addr_.toText());
-
- // we should NOT get what we asked for, because it is used already
- EXPECT_TRUE(lease->addr_.toText() != "2001:db8:1::1f");
-
- // do all checks on the lease
- checkLease6(lease);
-
- // Check that the lease is indeed in LeaseMgr
- Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->addr_);
- ASSERT_TRUE(from_mgr);
-
- // Now check that the lease in LeaseMgr has the same parameters
- detailCompareLease6(lease, from_mgr);
-}
-
-// 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) {
- 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
- // supported lease. Allocation engine should ignore it and carry on
- // with the normal allocation
- Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
- IOAddress("3000::abc"),
- false);
- // check that we got a lease
- ASSERT_TRUE(lease);
-
- // we should NOT get what we asked for, because it is used already
- EXPECT_TRUE(lease->addr_.toText() != "3000::abc");
-
- // do all checks on the lease
- checkLease6(lease);
-
- // Check that the lease is indeed in LeaseMgr
- Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->addr_);
- ASSERT_TRUE(from_mgr);
-
- // Now check that the lease in LeaseMgr has the same parameters
- detailCompareLease6(lease, from_mgr);
-}
-
-// This test verifies that the allocator picks addresses that belong to the
-// pool
-TEST_F(AllocEngineTest, IterativeAllocator) {
- boost::scoped_ptr<NakedAllocEngine::Allocator>
- alloc(new NakedAllocEngine::IterativeAllocator());
-
- for (int i = 0; i < 1000; ++i) {
- IOAddress candidate = alloc->pickAddress(subnet_, duid_, IOAddress("::"));
- EXPECT_TRUE(subnet_->inPool(candidate));
- }
-}
-
-
-// This test verifies that the iterative allocator really walks over all addresses
-// in all pools in specified subnet. It also must not pick the same address twice
-// unless it runs out of pool space and must start over.
-TEST_F(AllocEngineTest, IterativeAllocator_manyPools) {
- NakedAllocEngine::IterativeAllocator* alloc = new NakedAllocEngine::IterativeAllocator();
-
- // let's start from 2, as there is 2001:db8:1::10 - 2001:db8:1::20 pool already.
- for (int i = 2; i < 10; ++i) {
- stringstream min, max;
-
- min << "2001:db8:1::" << hex << i*16 + 1;
- max << "2001:db8:1::" << hex << i*16 + 9;
-
- Pool6Ptr pool(new Pool6(Pool6::TYPE_IA, IOAddress(min.str()),
- IOAddress(max.str())));
- // cout << "Adding pool: " << min.str() << "-" << max.str() << endl;
- subnet_->addPool6(pool);
- }
-
- int total = 17 + 8*9; // first pool (::10 - ::20) has 17 addresses in it,
- // there are 8 extra pools with 9 addresses in each.
-
- // Let's keep picked addresses here and check their uniqueness.
- std::map<IOAddress, int> generated_addrs;
- int cnt = 0;
- while (++cnt) {
- IOAddress candidate = alloc->pickAddress(subnet_, duid_, IOAddress("::"));
- EXPECT_TRUE(subnet_->inPool(candidate));
-
- // One way to easily verify that the iterative allocator really works is
- // to uncomment the following line and observe its output that it
- // covers all defined subnets.
- // cout << candidate.toText() << endl;
-
- if (generated_addrs.find(candidate) == generated_addrs.end()) {
- // we haven't had this
- generated_addrs[candidate] = 0;
- } else {
- // we have seen this address before. That should mean that we
- // iterated over all addresses.
- if (generated_addrs.size() == total) {
- // we have exactly the number of address in all pools
- break;
- }
- ADD_FAILURE() << "Too many or not enough unique addresses generated.";
- break;
- }
-
- if ( cnt>total ) {
- ADD_FAILURE() << "Too many unique addresses generated.";
- break;
- }
- }
-
- delete alloc;
-}
-
-}; // end of anonymous namespace
diff --git a/src/lib/dhcp/tests/cfgmgr_unittest.cc b/src/lib/dhcp/tests/cfgmgr_unittest.cc
deleted file mode 100644
index 5cc6345..0000000
--- a/src/lib/dhcp/tests/cfgmgr_unittest.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-#include <iostream>
-#include <sstream>
-#include <arpa/inet.h>
-#include <gtest/gtest.h>
-#include <dhcp/cfgmgr.h>
-#include <exceptions/exceptions.h>
-
-using namespace std;
-using namespace isc::asiolink;
-using namespace isc::dhcp;
-using namespace isc::util;
-using namespace isc;
-
-// don't import the entire boost namespace. It will unexpectedly hide uint8_t
-// for some systems.
-using boost::scoped_ptr;
-
-namespace {
-
-class CfgMgrTest : public ::testing::Test {
-public:
- CfgMgrTest() {
- }
-
- ~CfgMgrTest() {
- CfgMgr::instance().deleteSubnets6();
- }
-};
-
-
-// This test verifies if the configuration manager is able to hold and return
-// valid leases
-TEST_F(CfgMgrTest, subnet4) {
- CfgMgr& cfg_mgr = CfgMgr::instance();
-
- Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.2.0"), 26, 1, 2, 3));
- Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.64"), 26, 1, 2, 3));
- Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.2.128"), 26, 1, 2, 3));
-
- // there shouldn't be any subnet configured at this stage
- EXPECT_EQ( Subnet4Ptr(), cfg_mgr.getSubnet4(IOAddress("192.0.2.0")));
-
- cfg_mgr.addSubnet4(subnet1);
-
- // Now we have only one subnet, any request will be served from it
- EXPECT_EQ(subnet1, cfg_mgr.getSubnet4(IOAddress("192.0.2.63")));
-
- // Now we add more subnets and check that both old and new subnets
- // are accessible.
- cfg_mgr.addSubnet4(subnet2);
- cfg_mgr.addSubnet4(subnet3);
-
- EXPECT_EQ(subnet3, cfg_mgr.getSubnet4(IOAddress("192.0.2.191")));
- EXPECT_EQ(subnet1, cfg_mgr.getSubnet4(IOAddress("192.0.2.15")));
- EXPECT_EQ(subnet2, cfg_mgr.getSubnet4(IOAddress("192.0.2.85")));
-
- // Try to find an address that does not belong to any subnet
- EXPECT_EQ(Subnet4Ptr(), cfg_mgr.getSubnet4(IOAddress("192.0.2.192")));
-}
-
-// This test verifies if the configuration manager is able to hold and return
-// valid leases
-
-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));
- Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
-
- // there shouldn't be any subnet configured at this stage
- EXPECT_EQ( Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("2000::1")));
-
- cfg_mgr.addSubnet6(subnet1);
-
- // Now we have only one subnet, any request will be served from it
- EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2000::1")));
-
- // If we have only a single subnet and the request came from a local
- // address, let's use that subnet
- EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("fe80::dead:beef")));
-
- cfg_mgr.addSubnet6(subnet2);
- cfg_mgr.addSubnet6(subnet3);
-
- EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(IOAddress("4000::123")));
- EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::dead:beef")));
- EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("5000::1")));
-
- cfg_mgr.deleteSubnets6();
- EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("200::123")));
- EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("3000::123")));
- EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("4000::123")));
-}
-
-} // end of anonymous namespace
diff --git a/src/lib/dhcp/tests/duid_unittest.cc b/src/lib/dhcp/tests/duid_unittest.cc
index 435d2d2..9db4c35 100644
--- a/src/lib/dhcp/tests/duid_unittest.cc
+++ b/src/lib/dhcp/tests/duid_unittest.cc
@@ -13,14 +13,18 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
+
+#include <asiolink/io_address.h>
+#include <dhcp/duid.h>
+#include <exceptions/exceptions.h>
+
+#include <boost/scoped_ptr.hpp>
+#include <gtest/gtest.h>
+
#include <iostream>
#include <sstream>
+
#include <arpa/inet.h>
-#include <gtest/gtest.h>
-#include <exceptions/exceptions.h>
-#include <boost/scoped_ptr.hpp>
-#include <asiolink/io_address.h>
-#include <dhcp/duid.h>
using namespace std;
using namespace isc;
diff --git a/src/lib/dhcp/tests/iface_mgr_unittest.cc b/src/lib/dhcp/tests/iface_mgr_unittest.cc
index 462910b..11cbf34 100644
--- a/src/lib/dhcp/tests/iface_mgr_unittest.cc
+++ b/src/lib/dhcp/tests/iface_mgr_unittest.cc
@@ -13,19 +13,21 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
-#include <iostream>
-#include <fstream>
-#include <sstream>
-#include <unistd.h>
-#include <arpa/inet.h>
+#include <asiolink/io_address.h>
+#include <dhcp/dhcp4.h>
+#include <dhcp/iface_mgr.h>
+#include <dhcp/pkt6.h>
+
#include <boost/scoped_ptr.hpp>
#include <gtest/gtest.h>
-#include <asiolink/io_address.h>
-#include <dhcp/pkt6.h>
-#include <dhcp/iface_mgr.h>
-#include <dhcp/dhcp4.h>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
+#include <arpa/inet.h>
+#include <unistd.h>
using namespace std;
using namespace isc;
diff --git a/src/lib/dhcp/tests/lease_mgr_factory_unittest.cc b/src/lib/dhcp/tests/lease_mgr_factory_unittest.cc
deleted file mode 100644
index 37063b2..0000000
--- a/src/lib/dhcp/tests/lease_mgr_factory_unittest.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-#include <iostream>
-#include <sstream>
-#include <gtest/gtest.h>
-
-#include <asiolink/io_address.h>
-#include <dhcp/lease_mgr_factory.h>
-
-using namespace std;
-using namespace isc::dhcp;
-
-// This set of tests only check the parsing functions of LeaseMgrFactory.
-// Tests of the LeaseMgr create/instance/destroy are implicitly carried out
-// in the tests for the different concrete lease managers (e.g. MySqlLeaseMgr).
-
-namespace {
-// empty class for now, but may be extended once Addr6 becomes bigger
-class LeaseMgrFactoryTest : public ::testing::Test {
-public:
- LeaseMgrFactoryTest() {
- }
-};
-
-// This test checks if the LeaseMgr can be instantiated and that it
-// parses parameters string properly.
-TEST_F(LeaseMgrFactoryTest, parse) {
-
- std::map<std::string, std::string> parameters = LeaseMgrFactory::parse(
- "param1=value1 param2=value2 param3=value3");
-
- EXPECT_EQ("value1", parameters["param1"]);
- EXPECT_EQ("value2", parameters["param2"]);
- EXPECT_TRUE(parameters.find("type") == parameters.end());
-}
-
-}; // end of anonymous namespace
diff --git a/src/lib/dhcp/tests/lease_mgr_unittest.cc b/src/lib/dhcp/tests/lease_mgr_unittest.cc
deleted file mode 100644
index 64ce9b1..0000000
--- a/src/lib/dhcp/tests/lease_mgr_unittest.cc
+++ /dev/null
@@ -1,280 +0,0 @@
-// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-#include <iostream>
-#include <sstream>
-#include <gtest/gtest.h>
-
-#include <asiolink/io_address.h>
-#include <dhcp/lease_mgr.h>
-
-using namespace std;
-using namespace isc;
-using namespace isc::asiolink;
-using namespace isc::dhcp;
-
-// This is a concrete implementation of a Lease database. It does not do
-// anything useful and is used for abstract LeaseMgr class testing.
-class ConcreteLeaseMgr : public LeaseMgr {
-public:
-
- /// @brief The sole lease manager constructor
- ///
- /// dbconfig is a generic way of passing parameters. Parameters
- /// are passed in the "name=value" format, separated by spaces.
- /// Values may be enclosed in double quotes, if needed.
- ///
- /// @param parameters A data structure relating keywords and values
- /// concerned with the database.
- ConcreteLeaseMgr(const LeaseMgr::ParameterMap& parameters)
- : LeaseMgr(parameters)
- {}
-
- /// @brief Destructor
- virtual ~ConcreteLeaseMgr()
- {}
-
- /// @brief Adds an IPv4 lease.
- ///
- /// @param lease lease to be added
- virtual bool addLease(const Lease4Ptr&) {
- return (false);
- }
-
- /// @brief Adds an IPv6 lease.
- ///
- /// @param lease lease to be added
- virtual bool addLease(const Lease6Ptr&) {
- return (false);
- }
-
- /// @brief Returns existing IPv4 lease for specified IPv4 address.
- ///
- /// @param addr address of the searched lease
- ///
- /// @return smart pointer to the lease (or NULL if a lease is not found)
- virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress&) const {
- return (Lease4Ptr());
- }
-
- /// @brief Returns existing IPv4 lease for specific address and subnet
- /// @param addr address of the searched lease
- /// @param subnet_id ID of the subnet the lease must belong to
- ///
- /// @return smart pointer to the lease (or NULL if a lease is not found)
- virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress&,
- SubnetID) const {
- return (Lease4Ptr());
- }
-
- /// @brief Returns existing IPv4 leases for specified hardware address.
- ///
- /// Although in the usual case there will be only one lease, for mobile
- /// clients or clients with multiple static/fixed/reserved leases there
- /// can be more than one. Thus return type is a container, not a single
- /// pointer.
- ///
- /// @param hwaddr hardware address of the client
- ///
- /// @return lease collection
- virtual Lease4Collection getLease4(const HWAddr&) const {
- return (Lease4Collection());
- }
-
- /// @brief Returns existing IPv4 leases for specified hardware address
- /// and a subnet
- ///
- /// There can be at most one lease for a given HW address in a single
- /// pool, so this method with either return a single lease or NULL.
- ///
- /// @param hwaddr hardware address of the client
- /// @param subnet_id identifier of the subnet that lease must belong to
- ///
- /// @return a pointer to the lease (or NULL if a lease is not found)
- virtual Lease4Ptr getLease4(const HWAddr&, SubnetID) const {
- return (Lease4Ptr());
- }
-
- /// @brief Returns existing IPv4 lease for specified client-id
- ///
- /// @param clientid client identifier
- ///
- /// @return lease collection
- virtual Lease4Collection getLease4(const ClientId&) const {
- return (Lease4Collection());
- }
-
- /// @brief Returns existing IPv4 lease for specified client-id
- ///
- /// There can be at most one lease for a given HW address in a single
- /// pool, so this method with either return a single lease or NULL.
- ///
- /// @param clientid client identifier
- /// @param subnet_id identifier of the subnet that lease must belong to
- ///
- /// @return a pointer to the lease (or NULL if a lease is not found)
- virtual Lease4Ptr getLease4(const ClientId&, SubnetID) const {
- return (Lease4Ptr());
- }
-
- /// @brief Returns existing IPv6 lease for a given IPv6 address.
- ///
- /// @param addr address of the searched lease
- ///
- /// @return smart pointer to the lease (or NULL if a lease is not found)
- Lease6Ptr getLease6(const isc::asiolink::IOAddress&) const {
- return (Lease6Ptr());
- }
-
- /// @brief Returns existing IPv6 lease for a given DUID+IA combination
- ///
- /// @param duid client DUID
- /// @param iaid IA identifier
- ///
- /// @return collection of IPv6 leases
- Lease6Collection getLease6(const DUID&, uint32_t) const {
- return (Lease6Collection());
- }
-
- /// @brief Returns existing IPv6 lease for a given DUID+IA combination
- ///
- /// @param duid client DUID
- /// @param iaid IA identifier
- /// @param subnet_id identifier of the subnet the lease must belong to
- ///
- /// @return smart pointer to the lease (or NULL if a lease is not found)
- Lease6Ptr getLease6(const DUID&, uint32_t, SubnetID) const {
- return (Lease6Ptr());
- }
-
- /// @brief Updates IPv4 lease.
- ///
- /// @param lease4 The lease to be updated.
- ///
- /// If no such lease is present, an exception will be thrown.
- void updateLease4(const Lease4Ptr&) {}
-
- /// @brief Updates IPv4 lease.
- ///
- /// @param lease4 The lease to be updated.
- ///
- /// If no such lease is present, an exception will be thrown.
- void updateLease6(const Lease6Ptr&) {}
-
- /// @brief Deletes a lease.
- ///
- /// @param addr IPv4 address of the lease to be deleted.
- ///
- /// @return true if deletion was successful, false if no such lease exists
- bool deleteLease4(const isc::asiolink::IOAddress&) {
- return (false);
- }
-
- /// @brief Deletes a lease.
- ///
- /// @param addr IPv4 address of the lease to be deleted.
- ///
- /// @return true if deletion was successful, false if no such lease exists
- bool deleteLease6(const isc::asiolink::IOAddress&) {
- return (false);
- }
-
- /// @brief Returns backend name.
- ///
- /// Each backend have specific name, e.g. "mysql" or "sqlite".
- std::string getName() const {
- return (std::string("concrete"));
- }
-
- /// @brief Returns description of the backend.
- ///
- /// This description may be multiline text that describes the backend.
- std::string getDescription() const {
- return (std::string("This is a dummy concrete backend implementation."));
- }
-
- /// @brief Returns backend version.
- std::pair<uint32_t, uint32_t> getVersion() const {
- return (make_pair(uint32_t(0), uint32_t(0)));
- }
-
- /// @brief Commit transactions
- void commit() {
- }
-
- /// @brief Rollback transactions
- void rollback() {
- }
-};
-
-namespace {
-// empty class for now, but may be extended once Addr6 becomes bigger
-class LeaseMgrTest : public ::testing::Test {
-public:
- LeaseMgrTest() {
- }
-};
-
-// This test checks if the LeaseMgr can be instantiated and that it
-// parses parameters string properly.
-TEST_F(LeaseMgrTest, getParameter) {
-
- LeaseMgr::ParameterMap pmap;
- pmap[std::string("param1")] = std::string("value1");
- pmap[std::string("param2")] = std::string("value2");
- ConcreteLeaseMgr leasemgr(pmap);
-
- EXPECT_EQ("value1", leasemgr.getParameter("param1"));
- EXPECT_EQ("value2", leasemgr.getParameter("param2"));
- EXPECT_THROW(leasemgr.getParameter("param3"), BadValue);
-}
-
-// There's no point in calling any other methods in LeaseMgr, as they
-// are purely virtual, so we would only call ConcreteLeaseMgr methods.
-// Those methods are just stubs that do not return anything.
-
-// Lease6 is also defined in lease_mgr.h, so is tested in this file as well.
-// This test checks if the Lease6 structure can be instantiated correctly
-TEST(Lease6, Lease6Constructor) {
-
- IOAddress addr("2001:db8:1::456");
-
- uint8_t llt[] = {0, 1, 2, 3, 4, 5, 6, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
- DuidPtr duid(new DUID(llt, sizeof(llt)));
-
- uint32_t iaid = 7; // just a number
-
- SubnetID subnet_id = 8; // just another number
-
- Lease6Ptr x(new Lease6(Lease6::LEASE_IA_NA, addr,
- duid, iaid, 100, 200, 50, 80,
- subnet_id));
-
- EXPECT_TRUE(x->addr_ == addr);
- EXPECT_TRUE(*x->duid_ == *duid);
- EXPECT_TRUE(x->iaid_ == iaid);
- EXPECT_TRUE(x->subnet_id_ == subnet_id);
- EXPECT_TRUE(x->type_ == Lease6::LEASE_IA_NA);
- EXPECT_TRUE(x->preferred_lft_ == 100);
- EXPECT_TRUE(x->valid_lft_ == 200);
- EXPECT_TRUE(x->t1_ == 50);
- EXPECT_TRUE(x->t2_ == 80);
-
- // Lease6 must be instantiated with a DUID, not with NULL pointer
- EXPECT_THROW(new Lease6(Lease6::LEASE_IA_NA, addr,
- DuidPtr(), iaid, 100, 200, 50, 80,
- subnet_id), InvalidOperation);
-}
-}; // end of anonymous namespace
diff --git a/src/lib/dhcp/tests/libdhcp++_unittest.cc b/src/lib/dhcp/tests/libdhcp++_unittest.cc
index 0c9dc89..c8a3271 100644
--- a/src/lib/dhcp/tests/libdhcp++_unittest.cc
+++ b/src/lib/dhcp/tests/libdhcp++_unittest.cc
@@ -13,20 +13,23 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
-#include <iostream>
-#include <sstream>
-#include <arpa/inet.h>
-#include <gtest/gtest.h>
-#include <util/buffer.h>
+
#include <dhcp/dhcp4.h>
#include <dhcp/dhcp6.h>
#include <dhcp/libdhcp++.h>
+#include <dhcp/option6_addrlst.h>
#include <dhcp/option6_ia.h>
#include <dhcp/option6_iaaddr.h>
#include <dhcp/option6_int.h>
#include <dhcp/option6_int_array.h>
-#include <dhcp/option6_addrlst.h>
-#include "config.h"
+#include <util/buffer.h>
+
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <sstream>
+
+#include <arpa/inet.h>
using namespace std;
using namespace isc;
diff --git a/src/lib/dhcp/tests/memfile_lease_mgr_unittest.cc b/src/lib/dhcp/tests/memfile_lease_mgr_unittest.cc
deleted file mode 100644
index c625a16..0000000
--- a/src/lib/dhcp/tests/memfile_lease_mgr_unittest.cc
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-#include <iostream>
-#include <sstream>
-#include <gtest/gtest.h>
-#include <asiolink/io_address.h>
-
-#include <dhcp/lease_mgr.h>
-#include <dhcp/duid.h>
-#include <dhcp/memfile_lease_mgr.h>
-
-using namespace std;
-using namespace isc;
-using namespace isc::asiolink;
-using namespace isc::dhcp;
-
-namespace {
-// empty class for now, but may be extended once Addr6 becomes bigger
-class MemfileLeaseMgrTest : public ::testing::Test {
-public:
- MemfileLeaseMgrTest() {
- }
-};
-
-// This test checks if the LeaseMgr can be instantiated and that it
-// parses parameters string properly.
-TEST_F(MemfileLeaseMgrTest, constructor) {
-
- const LeaseMgr::ParameterMap pmap; // Empty parameter map
- boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr;
-
- ASSERT_NO_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)));
-}
-
-// There's no point in calling any other methods in LeaseMgr, as they
-// are purely virtual, so we would only call Memfile_LeaseMgr methods.
-// Those methods are just stubs that does not return anything.
-// It seems likely that we will need to extend the memfile code for
-// allocation engine tests, so we may implement tests that call
-// Memfile_LeaseMgr methods then.
-
-TEST_F(MemfileLeaseMgrTest, addGetDelete) {
- const LeaseMgr::ParameterMap pmap; // Empty parameter map
- boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr(new Memfile_LeaseMgr(pmap));
-
- IOAddress addr("2001:db8:1::456");
-
- uint8_t llt[] = {0, 1, 2, 3, 4, 5, 6, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
- DuidPtr duid(new DUID(llt, sizeof(llt)));
-
- uint32_t iaid = 7; // just a number
-
- SubnetID subnet_id = 8; // just another number
-
- Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr,
- duid, iaid, 100, 200, 50, 80,
- subnet_id));
-
- EXPECT_TRUE(lease_mgr->addLease(lease));
-
- // should not be allowed to add a second lease with the same address
- EXPECT_FALSE(lease_mgr->addLease(lease));
-
- Lease6Ptr x = lease_mgr->getLease6(IOAddress("2001:db8:1::234"));
- EXPECT_EQ(Lease6Ptr(), x);
-
- x = lease_mgr->getLease6(IOAddress("2001:db8:1::456"));
- ASSERT_TRUE(x);
-
- EXPECT_EQ(x->addr_.toText(), addr.toText());
- EXPECT_TRUE(*x->duid_ == *duid);
- EXPECT_EQ(x->iaid_, iaid);
- EXPECT_EQ(x->subnet_id_, subnet_id);
-
- // These are not important from lease management perspective, but
- // let's check them anyway.
- EXPECT_EQ(x->type_, Lease6::LEASE_IA_NA);
- EXPECT_EQ(x->preferred_lft_, 100);
- EXPECT_EQ(x->valid_lft_, 200);
- EXPECT_EQ(x->t1_, 50);
- EXPECT_EQ(x->t2_, 80);
-
- // Test getLease6(duid, iaid, subnet_id) - positive case
- Lease6Ptr y = lease_mgr->getLease6(*duid, iaid, subnet_id);
- ASSERT_TRUE(y);
- EXPECT_TRUE(*y->duid_ == *duid);
- EXPECT_EQ(y->iaid_, iaid);
- EXPECT_EQ(y->addr_.toText(), addr.toText());
-
- // Test getLease6(duid, iaid, subnet_id) - wrong iaid
- uint32_t invalid_iaid = 9; // no such iaid
- y = lease_mgr->getLease6(*duid, invalid_iaid, subnet_id);
- EXPECT_FALSE(y);
-
- uint32_t invalid_subnet_id = 999;
- y = lease_mgr->getLease6(*duid, iaid, invalid_subnet_id);
- EXPECT_FALSE(y);
-
- // truncated duid
- DuidPtr invalid_duid(new DUID(llt, sizeof(llt) - 1));
- y = lease_mgr->getLease6(*invalid_duid, iaid, subnet_id);
- EXPECT_FALSE(y);
-
- // should return false - there's no such address
- EXPECT_FALSE(lease_mgr->deleteLease6(IOAddress("2001:db8:1::789")));
-
- // this one should succeed
- EXPECT_TRUE(lease_mgr->deleteLease6(IOAddress("2001:db8:1::456")));
-
- // after the lease is deleted, it should really be gone
- x = lease_mgr->getLease6(IOAddress("2001:db8:1::456"));
- EXPECT_EQ(Lease6Ptr(), x);
-}
-
-// TODO: Write more memfile tests
-
-}; // end of anonymous namespace
diff --git a/src/lib/dhcp/tests/mysql_lease_mgr_unittest.cc b/src/lib/dhcp/tests/mysql_lease_mgr_unittest.cc
deleted file mode 100644
index a9b09ff..0000000
--- a/src/lib/dhcp/tests/mysql_lease_mgr_unittest.cc
+++ /dev/null
@@ -1,732 +0,0 @@
-// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-#include <iostream>
-#include <sstream>
-#include <utility>
-#include <string>
-#include <gtest/gtest.h>
-
-#include <asiolink/io_address.h>
-#include <dhcp/lease_mgr_factory.h>
-#include <dhcp/mysql_lease_mgr.h>
-
-using namespace isc;
-using namespace isc::asiolink;
-using namespace isc::dhcp;
-using namespace std;
-
-namespace {
-
-// Creation of the schema
-#include "schema_copy.h"
-
-// IPv6 addresseses
-const char* ADDRESS_0 = "2001:db8::0";
-const char* ADDRESS_1 = "2001:db8::1";
-const char* ADDRESS_2 = "2001:db8::2";
-const char* ADDRESS_3 = "2001:db8::3";
-const char* ADDRESS_4 = "2001:db8::4";
-const char* ADDRESS_5 = "2001:db8::5";
-const char* ADDRESS_6 = "2001:db8::6";
-const char* ADDRESS_7 = "2001:db8::7";
-
-// Connection strings. Assume:
-// Database: keatest
-// Username: keatest
-// Password: keatest
-const char* VALID_TYPE = "type=mysql";
-const char* INVALID_TYPE = "type=unknown";
-const char* VALID_NAME = "name=keatest";
-const char* INVALID_NAME = "name=invalidname";
-const char* VALID_HOST = "host=localhost";
-const char* INVALID_HOST = "host=invalidhost";
-const char* VALID_USER = "user=keatest";
-const char* INVALID_USER = "user=invaliduser";
-const char* VALID_PASSWORD = "password=keatest";
-const char* INVALID_PASSWORD = "password=invalid";
-
-// Given a combination of strings above, produce a connection string.
-string connectionString(const char* type, const char* name, const char* host,
- const char* user, const char* password) {
- const string space = " ";
- string result = "";
-
- if (type != NULL) {
- result += string(type);
- }
-
- if (name != NULL) {
- if (! result.empty()) {
- result += space;
- }
- result += string(name);
- }
-
- if (host != NULL) {
- if (! result.empty()) {
- result += space;
- }
- result += string(host);
- }
-
- if (user != NULL) {
- if (! result.empty()) {
- result += space;
- }
- result += string(user);
- }
-
- if (password != NULL) {
- if (! result.empty()) {
- result += space;
- }
- result += string(password);
- }
-
- return (result);
-}
-
-// Return valid connection string
-string
-validConnectionString() {
- return (connectionString(VALID_TYPE, VALID_NAME, VALID_HOST,
- VALID_USER, VALID_PASSWORD));
-}
-
-// @brief Clear everything from the database
-//
-// There is no error checking in this code: if something fails, one of the
-// tests will fall over.
-void destroySchema() {
- // Initialise
- MYSQL handle;
- (void) mysql_init(&handle);
-
- // Open database
- (void) mysql_real_connect(&handle, "localhost", "keatest",
- "keatest", "keatest", 0, NULL, 0);
-
- // Get rid of everything in it.
- for (int i = 0; destroy_statement[i] != NULL; ++i) {
- (void) mysql_query(&handle, destroy_statement[i]);
- }
-
- // ... and close
- (void) mysql_close(&handle);
-}
-
-// @brief Create the Schema
-//
-// Creates all the tables in what is assumed to be an empty database.
-//
-// There is no error checking in this code: if it fails, one of the tests
-// will fall over.
-void createSchema() {
- // Initialise
- MYSQL handle;
- (void) mysql_init(&handle);
-
- // Open database
- (void) mysql_real_connect(&handle, "localhost", "keatest",
- "keatest", "keatest", 0, NULL, 0);
-
- // Get rid of everything in it.
- for (int i = 0; create_statement[i] != NULL; ++i) {
- (void) mysql_query(&handle, create_statement[i]);
- }
-
- // ... and close
- (void) mysql_close(&handle);
-}
-
-// Note: Doxygen "///" not used - even though Doxygen is used to
-// document class and methods - to avoid the comments appearing
-// in the programming manual.
-
-// @brief Test Fixture Class
-//
-// Opens the database prior to each test and closes it afterwards.
-// All pending transactions are deleted prior to closure.
-
-class MySqlLeaseMgrTest : public ::testing::Test {
-public:
- // @brief Constructor
- //
- // Deletes everything from the database and opens it.
- MySqlLeaseMgrTest() :
- L0_ADDRESS(ADDRESS_0), L0_IOADDRESS(L0_ADDRESS),
- L1_ADDRESS(ADDRESS_1), L1_IOADDRESS(L1_ADDRESS),
- L2_ADDRESS(ADDRESS_2), L2_IOADDRESS(L2_ADDRESS),
- L3_ADDRESS(ADDRESS_3), L3_IOADDRESS(L3_ADDRESS),
- L4_ADDRESS(ADDRESS_4), L4_IOADDRESS(L4_ADDRESS),
- L5_ADDRESS(ADDRESS_5), L5_IOADDRESS(L5_ADDRESS),
- L6_ADDRESS(ADDRESS_6), L6_IOADDRESS(L6_ADDRESS),
- L7_ADDRESS(ADDRESS_7), L7_IOADDRESS(L7_ADDRESS) {
-
- destroySchema();
- createSchema();
- try {
- LeaseMgrFactory::create(validConnectionString());
- } catch (...) {
- std::cerr << "*** ERROR: unable to open database. The test\n"
- "*** environment is broken and must be fixed before\n"
- "*** the MySQL tests will run correctly.\n"
- "*** The reason for the problem is described in the\n"
- "*** accompanying exception output.\n";
- throw;
- }
- lmptr_ = &(LeaseMgrFactory::instance());
- }
-
- // @brief Destructor
- //
- // Rolls back all pending transactions. The deletion of the
- // lmptr_ member variable will close the database. Then
- // reopen it and delete everything created by the test.
- virtual ~MySqlLeaseMgrTest() {
- lmptr_->rollback();
- LeaseMgrFactory::destroy();
- destroySchema();
- }
-
- // @brief Reopen the database
- //
- // Closes the database and re-open it. Anything committed should be
- // visible.
- void reopen() {
- LeaseMgrFactory::destroy();
- LeaseMgrFactory::create(validConnectionString());
- lmptr_ = &(LeaseMgrFactory::instance());
- }
-
- // @brief Initialize Lease6 Fields
- //
- // Returns a pointer to a Lease6 structure. Different values are put
- // in the lease according to the address passed.
- //
- // This is just a convenience function for the test methods.
- //
- // @param address Address to use for the initialization
- //
- // @return Lease6Ptr. This will not point to anything if the initialization
- // failed (e.g. unknown address).
- Lease6Ptr initializeLease6(std::string address) {
- Lease6Ptr lease(new Lease6());
-
- // Set the address of the lease
- lease->addr_ = IOAddress(address);
-
- // Initialize unused fields.
- lease->t1_ = 0; // Not saved
- lease->t2_ = 0; // Not saved
- lease->fixed_ = false; // Unused
- lease->hostname_ = std::string(""); // Unused
- lease->fqdn_fwd_ = false; // Unused
- lease->fqdn_rev_ = false; // Unused
- lease->comments_ = std::string(""); // Unused
-
- // Set the other parameters. For historical reasons, L0_ADDRESS is not used.
- if (address == L0_ADDRESS) {
- lease->type_ = Lease6::LEASE_IA_TA;
- lease->prefixlen_ = 4;
- lease->iaid_ = 142;
- lease->duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0x77)));
- lease->preferred_lft_ = 900; // Preferred lifetime
- lease->valid_lft_ = 8677; // Actual lifetime
- lease->cltt_ = 168256; // Current time of day
- lease->subnet_id_ = 23; // Arbitrary number
-
- } else if (address == L1_ADDRESS) {
- lease->type_ = Lease6::LEASE_IA_TA;
- lease->prefixlen_ = 0;
- lease->iaid_ = 42;
- lease->duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0x42)));
- lease->preferred_lft_ = 3600; // Preferred lifetime
- lease->valid_lft_ = 3677; // Actual lifetime
- lease->cltt_ = 123456; // Current time of day
- lease->subnet_id_ = 73; // Arbitrary number
-
- } else if (address == L2_ADDRESS) {
- lease->type_ = Lease6::LEASE_IA_PD;
- lease->prefixlen_ = 7;
- lease->iaid_ = 89;
- lease->duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0x3a)));
- lease->preferred_lft_ = 1800; // Preferred lifetime
- lease->valid_lft_ = 5412; // Actual lifetime
- lease->cltt_ = 234567; // Current time of day
- lease->subnet_id_ = 73; // Same as for L1_ADDRESS
-
- } else if (address == L3_ADDRESS) {
- lease->type_ = Lease6::LEASE_IA_NA;
- lease->prefixlen_ = 28;
- lease->iaid_ = 0xfffffffe;
- vector<uint8_t> duid;
- for (uint8_t i = 31; i < 126; ++i) {
- duid.push_back(i);
- }
- lease->duid_ = boost::shared_ptr<DUID>(new DUID(duid));
-
- // The times used in the next tests are deliberately restricted - we
- // should be able to cope with valid lifetimes up to 0xffffffff.
- // However, this will lead to overflows.
- // @TODO: test overflow conditions when code has been fixed
- lease->preferred_lft_ = 7200; // Preferred lifetime
- lease->valid_lft_ = 7000; // Actual lifetime
- lease->cltt_ = 234567; // Current time of day
- lease->subnet_id_ = 37; // Different from L1 and L2
-
- } else if (address == L4_ADDRESS) {
- // Same DUID and IAID as L1_ADDRESS
- lease->type_ = Lease6::LEASE_IA_PD;
- lease->prefixlen_ = 15;
- lease->iaid_ = 42;
- lease->duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0x42)));
- lease->preferred_lft_ = 4800; // Preferred lifetime
- lease->valid_lft_ = 7736; // Actual lifetime
- lease->cltt_ = 222456; // Current time of day
- lease->subnet_id_ = 75; // Arbitrary number
-
- } else if (address == L5_ADDRESS) {
- // Same DUID and IAID as L1_ADDRESS
- lease->type_ = Lease6::LEASE_IA_PD;
- lease->prefixlen_ = 24;
- lease->iaid_ = 42;
- lease->duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0x42)));
- lease->preferred_lft_ = 5400; // Preferred lifetime
- lease->valid_lft_ = 7832; // Actual lifetime
- lease->cltt_ = 227476; // Current time of day
- lease->subnet_id_ = 175; // Arbitrary number
-
- } else if (address == L6_ADDRESS) {
- // Same DUID as L1_ADDRESS
- lease->type_ = Lease6::LEASE_IA_PD;
- lease->prefixlen_ = 24;
- lease->iaid_ = 93;
- lease->duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0x42)));
- lease->preferred_lft_ = 5400; // Preferred lifetime
- lease->valid_lft_ = 1832; // Actual lifetime
- lease->cltt_ = 627476; // Current time of day
- lease->subnet_id_ = 112; // Arbitrary number
-
- } else if (address == L7_ADDRESS) {
- // Same IAID as L1_ADDRESS
- lease->type_ = Lease6::LEASE_IA_PD;
- lease->prefixlen_ = 24;
- lease->iaid_ = 42;
- lease->duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0xe5)));
- lease->preferred_lft_ = 5600; // Preferred lifetime
- lease->valid_lft_ = 7975; // Actual lifetime
- lease->cltt_ = 213876; // Current time of day
- lease->subnet_id_ = 19; // Arbitrary number
-
- } else {
- // Unknown address, return an empty pointer.
- lease.reset();
-
- }
-
- return (lease);
- }
-
- // @brief Creates Leases for the test
- //
- // Creates all leases for the test and checks that they are different.
- //
- // @return vector<Lease6Ptr> Vector of pointers to leases
- vector<Lease6Ptr> createLeases6() {
-
- // Create leases
- vector<Lease6Ptr> leases;
- leases.push_back(initializeLease6(L0_ADDRESS));
- leases.push_back(initializeLease6(L1_ADDRESS));
- leases.push_back(initializeLease6(L2_ADDRESS));
- leases.push_back(initializeLease6(L3_ADDRESS));
- leases.push_back(initializeLease6(L4_ADDRESS));
- leases.push_back(initializeLease6(L5_ADDRESS));
- leases.push_back(initializeLease6(L6_ADDRESS));
- leases.push_back(initializeLease6(L7_ADDRESS));
-
- EXPECT_EQ(8, leases.size());
-
- // Check they were created
- for (int i = 0; i < leases.size(); ++i) {
- EXPECT_TRUE(leases[i]);
- }
-
- // Check they are different
- for (int i = 0; i < (leases.size() - 1); ++i) {
- for (int j = (i + 1); j < leases.size(); ++j) {
- EXPECT_TRUE(leases[i] != leases[j]);
- }
- }
-
- return (leases);
- }
-
-
- // Member variables
-
- LeaseMgr* lmptr_; // Pointer to the lease manager
-
- string L0_ADDRESS; // String form of address 1
- IOAddress L0_IOADDRESS; // IOAddress form of L1_ADDRESS
-
- string L1_ADDRESS; // String form of address 1
- IOAddress L1_IOADDRESS; // IOAddress form of L1_ADDRESS
-
- string L2_ADDRESS; // String form of address 2
- IOAddress L2_IOADDRESS; // IOAddress form of L2_ADDRESS
-
- string L3_ADDRESS; // String form of address 3
- IOAddress L3_IOADDRESS; // IOAddress form of L3_ADDRESS
-
- string L4_ADDRESS; // String form of address 4
- IOAddress L4_IOADDRESS; // IOAddress form of L4_ADDRESS
-
- string L5_ADDRESS; // String form of address 5
- IOAddress L5_IOADDRESS; // IOAddress form of L5_ADDRESS
-
- string L6_ADDRESS; // String form of address 6
- IOAddress L6_IOADDRESS; // IOAddress form of L6_ADDRESS
-
- string L7_ADDRESS; // String form of address 7
- IOAddress L7_IOADDRESS; // IOAddress form of L7_ADDRESS
-};
-
-
-// @brief Check that Database Can Be Opened
-//
-// This test checks if the MySqlLeaseMgr can be instantiated. This happens
-// only if the database can be opened. Note that this is not part of the
-// MySqlLeaseMgr test fixure set. This test checks that the database can be
-// opened: the fixtures assume that and check basic operations.
-
-TEST(MySqlOpenTest, OpenDatabase) {
-
- // Schema needs to be created for the test to work.
- destroySchema();
- createSchema();
-
- // Check that lease manager open the database opens correctly and tidy up.
- // If it fails, print the error message.
- try {
- LeaseMgrFactory::create(validConnectionString());
- EXPECT_NO_THROW((void) LeaseMgrFactory::instance());
- LeaseMgrFactory::destroy();
- } catch (const isc::Exception& ex) {
- FAIL() << "*** ERROR: unable to open database, reason:\n"
- << " " << ex.what() << "\n"
- << "*** The test environment is broken and must be fixed\n"
- << "*** before the MySQL tests will run correctly.\n";
- }
-
- // Check that attempting to get an instance of the lease manager when
- // none is set throws an exception.
- EXPECT_THROW(LeaseMgrFactory::instance(), NoLeaseManager);
-
- // Check that wrong specification of backend throws an exception.
- // (This is really a check on LeaseMgrFactory, but is convenient to
- // perform here.)
- EXPECT_THROW(LeaseMgrFactory::create(connectionString(
- NULL, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
- InvalidParameter);
- EXPECT_THROW(LeaseMgrFactory::create(connectionString(
- INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
- InvalidType);
-
- // Check that invalid login data causes an exception.
- EXPECT_THROW(LeaseMgrFactory::create(connectionString(
- VALID_TYPE, INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
- DbOpenError);
- EXPECT_THROW(LeaseMgrFactory::create(connectionString(
- VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)),
- DbOpenError);
- EXPECT_THROW(LeaseMgrFactory::create(connectionString(
- VALID_TYPE, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
- DbOpenError);
- EXPECT_THROW(LeaseMgrFactory::create(connectionString(
- VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)),
- DbOpenError);
-
- // Check for missing parameters
- EXPECT_THROW(LeaseMgrFactory::create(connectionString(
- VALID_TYPE, NULL, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
- NoDatabaseName);
-
- // Tidy up after the test
- destroySchema();
-}
-
-// @brief Check conversion functions
-TEST_F(MySqlLeaseMgrTest, CheckTimeConversion) {
- const time_t cltt = time(NULL);
- const uint32_t valid_lft = 86400; // 1 day
- struct tm tm_expire;
- MYSQL_TIME mysql_expire;
-
- // Work out what the broken-down time will be for one day
- // after the current time.
- time_t expire_time = cltt + valid_lft;
- (void) localtime_r(&expire_time, &tm_expire);
-
- // Convert to the database time
- MySqlLeaseMgr::convertToDatabaseTime(cltt, valid_lft, mysql_expire);
-
- // Are the times the same?
- EXPECT_EQ(tm_expire.tm_year + 1900, mysql_expire.year);
- EXPECT_EQ(tm_expire.tm_mon + 1, mysql_expire.month);
- EXPECT_EQ(tm_expire.tm_mday, mysql_expire.day);
- EXPECT_EQ(tm_expire.tm_hour, mysql_expire.hour);
- EXPECT_EQ(tm_expire.tm_min, mysql_expire.minute);
- EXPECT_EQ(tm_expire.tm_sec, mysql_expire.second);
- EXPECT_EQ(0, mysql_expire.second_part);
- EXPECT_EQ(0, mysql_expire.neg);
-
- // Convert back
- time_t converted_cltt = 0;
- MySqlLeaseMgr::convertFromDatabaseTime(mysql_expire, valid_lft, converted_cltt);
- EXPECT_EQ(cltt, converted_cltt);
-}
-
-
-// @brief Check getName() returns correct database name
-TEST_F(MySqlLeaseMgrTest, getName) {
- EXPECT_EQ(std::string("keatest"), lmptr_->getName());
-
- // @TODO: check for the negative
-}
-
-// @brief Check that getVersion() works
-TEST_F(MySqlLeaseMgrTest, CheckVersion) {
- // Check version
- pair<uint32_t, uint32_t> version;
- ASSERT_NO_THROW(version = lmptr_->getVersion());
- EXPECT_EQ(CURRENT_VERSION_VERSION, version.first);
- EXPECT_EQ(CURRENT_VERSION_MINOR, version.second);
-}
-
-void
-detailCompareLease6(const Lease6Ptr& first, const Lease6Ptr& second) {
- EXPECT_EQ(first->type_, second->type_);
-
- // Compare address strings - odd things happen when they are different
- // as the EXPECT_EQ appears to call the operator uint32_t() function,
- // which causes an exception to be thrown for IPv6 addresses.
- EXPECT_EQ(first->addr_.toText(), second->addr_.toText());
- EXPECT_EQ(first->prefixlen_, second->prefixlen_);
- EXPECT_EQ(first->iaid_, second->iaid_);
- EXPECT_TRUE(*first->duid_ == *second->duid_);
- EXPECT_EQ(first->preferred_lft_, second->preferred_lft_);
- EXPECT_EQ(first->valid_lft_, second->valid_lft_);
- EXPECT_EQ(first->cltt_, second->cltt_);
- EXPECT_EQ(first->subnet_id_, second->subnet_id_);
-}
-
-
-// @brief Check individual Lease6 methods
-//
-// Checks that the add/update/delete works. All are done within one
-// test so that "rollback" can be used to remove trace of the tests
-// from the database.
-//
-// Tests where a collection of leases can be returned are in the test
-// Lease6Collection.
-TEST_F(MySqlLeaseMgrTest, BasicLease6) {
- // Get the leases to be used for the test.
- vector<Lease6Ptr> leases = createLeases6();
-
- // Start the tests. Add three leases to the database, read them back and
- // check they are what we think they are.
- EXPECT_TRUE(lmptr_->addLease(leases[1]));
- EXPECT_TRUE(lmptr_->addLease(leases[2]));
- EXPECT_TRUE(lmptr_->addLease(leases[3]));
- lmptr_->commit();
-
- // Reopen the database to ensure that they actually got stored.
- reopen();
-
- Lease6Ptr l_returned = lmptr_->getLease6(L1_IOADDRESS);
- EXPECT_TRUE(l_returned);
- detailCompareLease6(leases[1], l_returned);
-
- l_returned = lmptr_->getLease6(L2_IOADDRESS);
- EXPECT_TRUE(l_returned);
- detailCompareLease6(leases[2], l_returned);
-
- l_returned = lmptr_->getLease6(L3_IOADDRESS);
- EXPECT_TRUE(l_returned);
- detailCompareLease6(leases[3], l_returned);
-
- // Check that we can't add a second lease with the same address
- EXPECT_FALSE(lmptr_->addLease(leases[1]));
-
- // Delete a lease, check that it's gone, and that we can't delete it
- // a second time.
- EXPECT_TRUE(lmptr_->deleteLease6(L1_IOADDRESS));
- l_returned = lmptr_->getLease6(L1_IOADDRESS);
- EXPECT_FALSE(l_returned);
- EXPECT_FALSE(lmptr_->deleteLease6(L1_IOADDRESS));
-
- // Check that the second address is still there.
- l_returned = lmptr_->getLease6(L2_IOADDRESS);
- EXPECT_TRUE(l_returned);
- detailCompareLease6(leases[2], l_returned);
-}
-
-// @brief Check GetLease6 methods - Access by DUID/IAID
-//
-// Adds leases to the database and checks that they can be accessed via
-// a combination of DIUID and IAID.
-TEST_F(MySqlLeaseMgrTest, GetLease6Extended1) {
- // Get the leases to be used for the test.
- vector<Lease6Ptr> leases = createLeases6();
- EXPECT_LE(6, leases.size()); // Expect to access leases 0 through 5
-
- // Add them to the database
- for (int i = 0; i < leases.size(); ++i) {
- EXPECT_TRUE(lmptr_->addLease(leases[i]));
- }
-
- // Get the leases matching the DUID and IAID of lease[1].
- Lease6Collection returned = lmptr_->getLease6(*leases[1]->duid_,
- leases[1]->iaid_);
-
- // Should be three leases, matching leases[1], [4] and [5].
- ASSERT_EQ(3, returned.size());
-
- // Easiest way to check is to look at the addresses.
- vector<string> addresses;
- for (Lease6Collection::const_iterator i = returned.begin();
- i != returned.end(); ++i) {
- addresses.push_back((*i)->addr_.toText());
- }
- sort(addresses.begin(), addresses.end());
- EXPECT_EQ(L1_ADDRESS, addresses[0]);
- EXPECT_EQ(L4_ADDRESS, addresses[1]);
- EXPECT_EQ(L5_ADDRESS, addresses[2]);
-
- // Check that nothing is returned when either the IAID or DUID match
- // nothing.
- returned = lmptr_->getLease6(*leases[1]->duid_, leases[1]->iaid_ + 1);
- EXPECT_EQ(0, returned.size());
-
- // Alter the leases[1] DUID to match nothing in the database.
- vector<uint8_t> duid_vector = leases[1]->duid_->getDuid();
- ++duid_vector[0];
- DUID new_duid(duid_vector);
- returned = lmptr_->getLease6(new_duid, leases[1]->iaid_);
- EXPECT_EQ(0, returned.size());
-}
-
-
-
-// @brief Check GetLease6 methods - Access by DUID/IAID/SubnetID
-//
-// Adds leases to the database and checks that they can be accessed via
-// a combination of DIUID and IAID.
-TEST_F(MySqlLeaseMgrTest, GetLease6Extended2) {
- // Get the leases to be used for the test.
- vector<Lease6Ptr> leases = createLeases6();
- EXPECT_LE(6, leases.size()); // Expect to access leases 0 through 5
-
- // Add them to the database
- for (int i = 0; i < leases.size(); ++i) {
- EXPECT_TRUE(lmptr_->addLease(leases[i]));
- }
-
- // Get the leases matching the DUID and IAID of lease[1].
- Lease6Ptr returned = lmptr_->getLease6(*leases[1]->duid_,
- leases[1]->iaid_,
- leases[1]->subnet_id_);
- ASSERT_TRUE(returned);
- EXPECT_TRUE(*returned == *leases[1]);
-
- // Modify each of the three parameters (DUID, IAID, Subnet ID) and
- // check that nothing is returned.
- returned = lmptr_->getLease6(*leases[1]->duid_, leases[1]->iaid_ + 1,
- leases[1]->subnet_id_);
- EXPECT_FALSE(returned);
-
- returned = lmptr_->getLease6(*leases[1]->duid_, leases[1]->iaid_,
- leases[1]->subnet_id_ + 1);
- EXPECT_FALSE(returned);
-
- // Alter the leases[1] DUID to match nothing in the database.
- vector<uint8_t> duid_vector = leases[1]->duid_->getDuid();
- ++duid_vector[0];
- DUID new_duid(duid_vector);
- returned = lmptr_->getLease6(new_duid, leases[1]->iaid_,
- leases[1]->subnet_id_);
- EXPECT_FALSE(returned);
-}
-
-
-
-// @brief Lease6 Update Tests
-//
-// Checks that we are able to update a lease in the database.
-TEST_F(MySqlLeaseMgrTest, UpdateLease6) {
- // Get the leases to be used for the test.
- vector<Lease6Ptr> leases = createLeases6();
- EXPECT_LE(3, leases.size()); // Expect to access leases 0 through 5
-
- // Add a lease to the database and check that the lease is there.
- EXPECT_TRUE(lmptr_->addLease(leases[1]));
- lmptr_->commit();
-
- reopen();
- Lease6Ptr l_returned = lmptr_->getLease6(L1_IOADDRESS);
- EXPECT_TRUE(l_returned);
- detailCompareLease6(leases[1], l_returned);
-
- // Modify some fields in lease 1 (not the address) and update it.
- ++leases[1]->iaid_;
- leases[1]->type_ = Lease6::LEASE_IA_PD;
- leases[1]->valid_lft_ *= 2;
- lmptr_->updateLease6(leases[1]);
- lmptr_->commit();
- reopen();
-
- // ... and check what is returned is what is expected.
- l_returned.reset();
- l_returned = lmptr_->getLease6(L1_IOADDRESS);
- EXPECT_TRUE(l_returned);
- detailCompareLease6(leases[1], l_returned);
-
- // Alter the lease again and check.
- ++leases[1]->iaid_;
- leases[1]->type_ = Lease6::LEASE_IA_TA;
- leases[1]->cltt_ += 6;
- leases[1]->prefixlen_ = 93;
- lmptr_->updateLease6(leases[1]);
-
- l_returned.reset();
- l_returned = lmptr_->getLease6(L1_IOADDRESS);
- EXPECT_TRUE(l_returned);
- detailCompareLease6(leases[1], l_returned);
-
- // Check we can do an update without changing data.
- lmptr_->updateLease6(leases[1]);
- l_returned.reset();
- l_returned = lmptr_->getLease6(L1_IOADDRESS);
- EXPECT_TRUE(l_returned);
- detailCompareLease6(leases[1], l_returned);
-
- // Try updating a lease not in the database.
- EXPECT_THROW(lmptr_->updateLease6(leases[2]), isc::dhcp::NoSuchLease);
-}
-
-}; // Of anonymous namespace
diff --git a/src/lib/dhcp/tests/option4_addrlst_unittest.cc b/src/lib/dhcp/tests/option4_addrlst_unittest.cc
index d4ecf80..a8e60f6 100644
--- a/src/lib/dhcp/tests/option4_addrlst_unittest.cc
+++ b/src/lib/dhcp/tests/option4_addrlst_unittest.cc
@@ -13,16 +13,20 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
-#include <iostream>
-#include <sstream>
-#include <arpa/inet.h>
-#include <gtest/gtest.h>
+
#include <asiolink/io_address.h>
#include <dhcp/dhcp4.h>
#include <dhcp/option.h>
#include <dhcp/option4_addrlst.h>
#include <util/buffer.h>
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <sstream>
+
+#include <arpa/inet.h>
+
using namespace std;
using namespace isc;
using namespace isc::dhcp;
diff --git a/src/lib/dhcp/tests/option6_addrlst_unittest.cc b/src/lib/dhcp/tests/option6_addrlst_unittest.cc
index 89d4f7c..96db59c 100644
--- a/src/lib/dhcp/tests/option6_addrlst_unittest.cc
+++ b/src/lib/dhcp/tests/option6_addrlst_unittest.cc
@@ -13,16 +13,20 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
-#include <iostream>
-#include <sstream>
-#include <arpa/inet.h>
-#include <gtest/gtest.h>
+
#include <asiolink/io_address.h>
#include <dhcp/dhcp6.h>
#include <dhcp/option.h>
#include <dhcp/option6_addrlst.h>
#include <util/buffer.h>
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <sstream>
+
+#include <arpa/inet.h>
+
using namespace std;
using namespace isc;
using namespace isc::dhcp;
diff --git a/src/lib/dhcp/tests/option6_ia_unittest.cc b/src/lib/dhcp/tests/option6_ia_unittest.cc
index 47af50e..bc72242 100644
--- a/src/lib/dhcp/tests/option6_ia_unittest.cc
+++ b/src/lib/dhcp/tests/option6_ia_unittest.cc
@@ -13,11 +13,6 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
-#include <iostream>
-#include <sstream>
-
-#include <arpa/inet.h>
-#include <gtest/gtest.h>
#include <dhcp/dhcp6.h>
#include <dhcp/option.h>
@@ -25,6 +20,13 @@
#include <dhcp/option6_iaaddr.h>
#include <util/buffer.h>
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <sstream>
+
+#include <arpa/inet.h>
+
using namespace std;
using namespace isc;
using namespace isc::dhcp;
diff --git a/src/lib/dhcp/tests/option6_iaaddr_unittest.cc b/src/lib/dhcp/tests/option6_iaaddr_unittest.cc
index e351d17..8c87d80 100644
--- a/src/lib/dhcp/tests/option6_iaaddr_unittest.cc
+++ b/src/lib/dhcp/tests/option6_iaaddr_unittest.cc
@@ -13,17 +13,19 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
-#include <iostream>
-#include <sstream>
-
-#include <arpa/inet.h>
-#include <gtest/gtest.h>
#include <dhcp/dhcp6.h>
#include <dhcp/option.h>
#include <dhcp/option6_iaaddr.h>
#include <util/buffer.h>
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <sstream>
+
+#include <arpa/inet.h>
+
using namespace std;
using namespace isc;
using namespace isc::dhcp;
diff --git a/src/lib/dhcp/tests/option6_int_array_unittest.cc b/src/lib/dhcp/tests/option6_int_array_unittest.cc
index 581d4e1..3a8640a 100644
--- a/src/lib/dhcp/tests/option6_int_array_unittest.cc
+++ b/src/lib/dhcp/tests/option6_int_array_unittest.cc
@@ -13,10 +13,11 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
+
#include <dhcp/dhcp6.h>
#include <dhcp/option.h>
-#include <dhcp/option6_int_array.h>
#include <dhcp/option6_iaaddr.h>
+#include <dhcp/option6_int_array.h>
#include <util/buffer.h>
#include <boost/pointer_cast.hpp>
diff --git a/src/lib/dhcp/tests/option6_int_unittest.cc b/src/lib/dhcp/tests/option6_int_unittest.cc
index 3d39a1a..c9eac9c 100644
--- a/src/lib/dhcp/tests/option6_int_unittest.cc
+++ b/src/lib/dhcp/tests/option6_int_unittest.cc
@@ -13,10 +13,11 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
+
#include <dhcp/dhcp6.h>
#include <dhcp/option.h>
-#include <dhcp/option6_int.h>
#include <dhcp/option6_iaaddr.h>
+#include <dhcp/option6_int.h>
#include <util/buffer.h>
#include <boost/pointer_cast.hpp>
diff --git a/src/lib/dhcp/tests/option_definition_unittest.cc b/src/lib/dhcp/tests/option_definition_unittest.cc
index 7e92680..bdf3edf 100644
--- a/src/lib/dhcp/tests/option_definition_unittest.cc
+++ b/src/lib/dhcp/tests/option_definition_unittest.cc
@@ -14,7 +14,6 @@
#include <config.h>
-#include <exceptions/exceptions.h>
#include <asiolink/io_address.h>
#include <dhcp/dhcp4.h>
#include <dhcp/dhcp6.h>
@@ -25,10 +24,11 @@
#include <dhcp/option6_int.h>
#include <dhcp/option6_int_array.h>
#include <dhcp/option_definition.h>
+#include <exceptions/exceptions.h>
-#include <gtest/gtest.h>
-#include <boost/shared_ptr.hpp>
#include <boost/pointer_cast.hpp>
+#include <boost/shared_ptr.hpp>
+#include <gtest/gtest.h>
using namespace std;
using namespace isc;
diff --git a/src/lib/dhcp/tests/option_unittest.cc b/src/lib/dhcp/tests/option_unittest.cc
index 9b046f0..50d143f 100644
--- a/src/lib/dhcp/tests/option_unittest.cc
+++ b/src/lib/dhcp/tests/option_unittest.cc
@@ -13,17 +13,19 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
-#include <iostream>
-#include <sstream>
-#include <arpa/inet.h>
-#include <gtest/gtest.h>
-#include <boost/shared_ptr.hpp>
+#include <dhcp/dhcp6.h>
+#include <dhcp/option.h>
#include <exceptions/exceptions.h>
#include <util/buffer.h>
-#include "dhcp/dhcp6.h"
-#include "dhcp/option.h"
+#include <boost/shared_ptr.hpp>
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <sstream>
+
+#include <arpa/inet.h>
using namespace std;
using namespace isc;
diff --git a/src/lib/dhcp/tests/pkt4_unittest.cc b/src/lib/dhcp/tests/pkt4_unittest.cc
index 9c8cc05..37af9c6 100644
--- a/src/lib/dhcp/tests/pkt4_unittest.cc
+++ b/src/lib/dhcp/tests/pkt4_unittest.cc
@@ -13,18 +13,22 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
-#include <iostream>
-#include <sstream>
-#include <arpa/inet.h>
-#include <gtest/gtest.h>
-#include <boost/static_assert.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/shared_array.hpp>
-#include <util/buffer.h>
+
#include <asiolink/io_address.h>
-#include <dhcp/pkt4.h>
#include <dhcp/dhcp4.h>
+#include <dhcp/pkt4.h>
#include <exceptions/exceptions.h>
+#include <util/buffer.h>
+
+#include <boost/shared_array.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/static_assert.hpp>
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <sstream>
+
+#include <arpa/inet.h>
using namespace std;
using namespace isc;
diff --git a/src/lib/dhcp/tests/pkt6_unittest.cc b/src/lib/dhcp/tests/pkt6_unittest.cc
index d6ca9b1..b2dd16a 100644
--- a/src/lib/dhcp/tests/pkt6_unittest.cc
+++ b/src/lib/dhcp/tests/pkt6_unittest.cc
@@ -13,16 +13,19 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
-#include <iostream>
-#include <sstream>
-#include <arpa/inet.h>
-#include <boost/date_time/posix_time/posix_time.hpp>
-#include <gtest/gtest.h>
#include <asiolink/io_address.h>
+#include <dhcp/dhcp6.h>
#include <dhcp/option.h>
#include <dhcp/pkt6.h>
-#include <dhcp/dhcp6.h>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <sstream>
+
+#include <arpa/inet.h>
using namespace std;
using namespace isc;
diff --git a/src/lib/dhcp/tests/pool_unittest.cc b/src/lib/dhcp/tests/pool_unittest.cc
deleted file mode 100644
index e596278..0000000
--- a/src/lib/dhcp/tests/pool_unittest.cc
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-#include <iostream>
-#include <vector>
-#include <sstream>
-#include <gtest/gtest.h>
-#include <dhcp/pool.h>
-#include <asiolink/io_address.h>
-
-using boost::scoped_ptr;
-using namespace isc;
-using namespace isc::dhcp;
-using namespace isc::asiolink;
-
-namespace {
-
-TEST(Pool4Test, constructor_first_last) {
-
- // let's construct 192.0.2.1-192.0.2.255 pool
- Pool4 pool1(IOAddress("192.0.2.1"), IOAddress("192.0.2.255"));
-
- EXPECT_EQ(IOAddress("192.0.2.1"), pool1.getFirstAddress());
- EXPECT_EQ(IOAddress("192.0.2.255"), pool1.getLastAddress());
-
- // This is Pool4, IPv6 addresses do not belong here
- EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::1"),
- IOAddress("192.168.0.5")), BadValue);
- EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.168.0.2"),
- IOAddress("2001:db8::1")), BadValue);
-
- // Should throw. Range should be 192.0.2.1-192.0.2.2, not
- // the other way around.
- EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.0.2.2"),
- IOAddress("192.0.2.1")), BadValue);
-}
-
-TEST(Pool4Test, constructor_prefix_len) {
-
- // let's construct 2001:db8:1::/96 pool
- Pool4 pool1(IOAddress("192.0.2.0"), 25);
-
- EXPECT_EQ("192.0.2.0", pool1.getFirstAddress().toText());
- EXPECT_EQ("192.0.2.127", pool1.getLastAddress().toText());
-
- // No such thing as /33 prefix
- EXPECT_THROW(Pool4(IOAddress("192.0.2.1"), 33), BadValue);
-
- // /0 prefix does not make sense
- EXPECT_THROW(Pool4(IOAddress("192.0.2.0"), 0), BadValue);
-
- // This is Pool6, IPv4 addresses do not belong here
- EXPECT_THROW(Pool4(IOAddress("2001:db8::1"), 20), BadValue);
-}
-
-TEST(Pool4Test, in_range) {
- Pool4 pool1(IOAddress("192.0.2.10"), IOAddress("192.0.2.20"));
-
- EXPECT_FALSE(pool1.inRange(IOAddress("192.0.2.0")));
- EXPECT_TRUE(pool1.inRange(IOAddress("192.0.2.10")));
- EXPECT_TRUE(pool1.inRange(IOAddress("192.0.2.17")));
- EXPECT_TRUE(pool1.inRange(IOAddress("192.0.2.20")));
- EXPECT_FALSE(pool1.inRange(IOAddress("192.0.2.21")));
- EXPECT_FALSE(pool1.inRange(IOAddress("192.0.2.255")));
- EXPECT_FALSE(pool1.inRange(IOAddress("255.255.255.255")));
- EXPECT_FALSE(pool1.inRange(IOAddress("0.0.0.0")));
-}
-
-// This test creates 100 pools and verifies that their IDs are unique.
-TEST(Pool4Test, unique_id) {
-
- const int num_pools = 100;
- std::vector<Pool4Ptr> pools;
-
- for (int i = 0; i < num_pools; ++i) {
- pools.push_back(Pool4Ptr(new Pool4(IOAddress("192.0.2.0"),
- IOAddress("192.0.2.255"))));
- }
-
- for (int i = 0; i < num_pools; ++i) {
- for (int j = i + 1; j < num_pools; ++j) {
- if (pools[i]->getId() == pools[j]->getId()) {
- FAIL() << "Pool-ids must be unique";
- }
- }
- }
-
-}
-
-
-TEST(Pool6Test, constructor_first_last) {
-
- // let's construct 2001:db8:1:: - 2001:db8:1::ffff:ffff:ffff:ffff pool
- Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::"),
- IOAddress("2001:db8:1::ffff:ffff:ffff:ffff"));
-
- EXPECT_EQ(Pool6::TYPE_IA, pool1.getType());
- EXPECT_EQ(IOAddress("2001:db8:1::"), pool1.getFirstAddress());
- EXPECT_EQ(IOAddress("2001:db8:1::ffff:ffff:ffff:ffff"),
- pool1.getLastAddress());
-
- // This is Pool6, IPv4 addresses do not belong here
- EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::1"),
- IOAddress("192.168.0.5")), BadValue);
- EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.168.0.2"),
- IOAddress("2001:db8::1")), BadValue);
-
- // Should throw. Range should be 2001:db8::1 - 2001:db8::2, not
- // the other way around.
- EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::2"),
- IOAddress("2001:db8::1")), BadValue);
-}
-
-TEST(Pool6Test, constructor_prefix_len) {
-
- // let's construct 2001:db8:1::/96 pool
- Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::"), 96);
-
- EXPECT_EQ(Pool6::TYPE_IA, pool1.getType());
- EXPECT_EQ("2001:db8:1::", pool1.getFirstAddress().toText());
- EXPECT_EQ("2001:db8:1::ffff:ffff", pool1.getLastAddress().toText());
-
- // No such thing as /130 prefix
- EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::"), 130),
- BadValue);
-
- // /0 prefix does not make sense
- EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::"), 0),
- BadValue);
-
- // This is Pool6, IPv4 addresses do not belong here
- EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.168.0.2"), 96),
- BadValue);
-}
-
-TEST(Pool6Test, in_range) {
- Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::1"),
- IOAddress("2001:db8:1::f"));
-
- EXPECT_FALSE(pool1.inRange(IOAddress("2001:db8:1::")));
- EXPECT_TRUE(pool1.inRange(IOAddress("2001:db8:1::1")));
- EXPECT_TRUE(pool1.inRange(IOAddress("2001:db8:1::7")));
- EXPECT_TRUE(pool1.inRange(IOAddress("2001:db8:1::f")));
- EXPECT_FALSE(pool1.inRange(IOAddress("2001:db8:1::10")));
- EXPECT_FALSE(pool1.inRange(IOAddress("::")));
-}
-
-// This test creates 100 pools and verifies that their IDs are unique.
-TEST(Pool6Test, unique_id) {
-
- const int num_pools = 100;
- std::vector<Pool6Ptr> pools;
-
- for (int i = 0; i < num_pools; ++i) {
- pools.push_back(Pool6Ptr(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1::"),
- IOAddress("2001:db8:1::ffff:ffff:ffff:ffff"))));
- }
-
- for (int i = 0; i < num_pools; ++i) {
- for (int j = i + 1; j < num_pools; ++j) {
- if (pools[i]->getId() == pools[j]->getId()) {
- FAIL() << "Pool-ids must be unique";
- }
- }
- }
-
-}
-
-}; // end of anonymous namespace
diff --git a/src/lib/dhcp/tests/run_unittests.cc b/src/lib/dhcp/tests/run_unittests.cc
index 0126645..bd32c4d 100644
--- a/src/lib/dhcp/tests/run_unittests.cc
+++ b/src/lib/dhcp/tests/run_unittests.cc
@@ -12,9 +12,10 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <gtest/gtest.h>
#include <log/logger_support.h>
+#include <gtest/gtest.h>
+
int
main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
diff --git a/src/lib/dhcp/tests/schema_copy.h b/src/lib/dhcp/tests/schema_copy.h
deleted file mode 100644
index 1dd796d..0000000
--- a/src/lib/dhcp/tests/schema_copy.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef SCHEMA_COPY_H
-#define SCHEMA_COPY_H
-
-namespace {
-
-// What follows is a set of statements that creates a copy of the schema
-// in the test database. It is used by the MySQL unit test prior to each
-// test.
-//
-// Each SQL statement is a single string. The statements are not terminated
-// by semicolons, and the strings must end with a comma. The final line
-// statement must be NULL (not in quotes)
-
-// THIS MUST BE KEPT UP TO DATE AND UPDATED IF THE SCHEMA CHANGES
-
-// Deletion of existing tables.
-
-const char* destroy_statement[] = {
- "DROP TABLE lease4",
- "DROP TABLE lease6",
- "DROP TABLE lease6_types",
- "DROP TABLE schema_version",
- NULL
-};
-
-// Creation of the new tables.
-
-const char* create_statement[] = {
- "CREATE TABLE lease4 ("
- "address INT UNSIGNED PRIMARY KEY NOT NULL,"
- "hwaddr VARBINARY(20),"
- "client_id VARBINARY(128),"
- "lease_time INT UNSIGNED,"
- "expire TIMESTAMP,"
- "subnet_id INT UNSIGNED"
- ") ENGINE = INNODB",
-
- "CREATE TABLE lease6 ("
- "address VARCHAR(40) PRIMARY KEY NOT NULL,"
- "duid VARBINARY(128),"
- "valid_lifetime INT UNSIGNED,"
- "expire TIMESTAMP,"
- "subnet_id INT UNSIGNED,"
- "pref_lifetime INT UNSIGNED,"
- "lease_type TINYINT,"
- "iaid INT UNSIGNED,"
- "prefix_len TINYINT UNSIGNED"
- ") ENGINE = INNODB",
-
- "CREATE TABLE lease6_types ("
- "lease_type TINYINT PRIMARY KEY NOT NULL,"
- "name VARCHAR(5)"
- ")",
-
- "INSERT INTO lease6_types VALUES (0, \"IA_NA\")",
- "INSERT INTO lease6_types VALUES (1, \"IA_TA\")",
- "INSERT INTO lease6_types VALUES (2, \"IA_PD\")",
-
- "CREATE TABLE schema_version ("
- "version INT PRIMARY KEY NOT NULL,"
- "minor INT"
- ")",
-
- "INSERT INTO schema_version VALUES (0, 1)",
-
- NULL
-};
-
-}; // Anonymous namespace
-
-#endif // SCHEMA_COPY_H
diff --git a/src/lib/dhcp/tests/subnet_unittest.cc b/src/lib/dhcp/tests/subnet_unittest.cc
deleted file mode 100644
index 0d9c546..0000000
--- a/src/lib/dhcp/tests/subnet_unittest.cc
+++ /dev/null
@@ -1,447 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-
-#include <config.h>
-#include <dhcp/subnet.h>
-#include <dhcp/option.h>
-#include <exceptions/exceptions.h>
-#include <boost/scoped_ptr.hpp>
-#include <gtest/gtest.h>
-#include <asiolink/io_address.h>
-
-// don't import the entire boost namespace. It will unexpectedly hide uint8_t
-// for some systems.
-using boost::scoped_ptr;
-using namespace isc;
-using namespace isc::dhcp;
-using namespace isc::asiolink;
-
-namespace {
-
-TEST(Subnet4Test, constructor) {
- EXPECT_NO_THROW(Subnet4 subnet1(IOAddress("192.0.2.2"), 16,
- 1, 2, 3));
-
- EXPECT_THROW(Subnet4 subnet2(IOAddress("192.0.2.0"), 33, 1, 2, 3),
- BadValue); // invalid prefix length
- EXPECT_THROW(Subnet4 subnet3(IOAddress("2001:db8::1"), 24, 1, 2, 3),
- BadValue); // IPv6 addresses are not allowed in Subnet4
-}
-
-TEST(Subnet4Test, in_range) {
- Subnet4 subnet(IOAddress("192.0.2.1"), 24, 1000, 2000, 3000);
-
- EXPECT_EQ(1000, subnet.getT1());
- EXPECT_EQ(2000, subnet.getT2());
- EXPECT_EQ(3000, subnet.getValid());
-
- EXPECT_FALSE(subnet.inRange(IOAddress("192.0.0.0")));
- EXPECT_TRUE(subnet.inRange(IOAddress("192.0.2.0")));
- EXPECT_TRUE(subnet.inRange(IOAddress("192.0.2.1")));
- EXPECT_TRUE(subnet.inRange(IOAddress("192.0.2.255")));
- EXPECT_FALSE(subnet.inRange(IOAddress("192.0.3.0")));
- EXPECT_FALSE(subnet.inRange(IOAddress("0.0.0.0")));
- EXPECT_FALSE(subnet.inRange(IOAddress("255.255.255.255")));
-}
-
-TEST(Subnet4Test, Pool4InSubnet4) {
-
- Subnet4Ptr subnet(new Subnet4(IOAddress("192.1.2.0"), 24, 1, 2, 3));
-
- Pool4Ptr pool1(new Pool4(IOAddress("192.1.2.0"), 25));
- Pool4Ptr pool2(new Pool4(IOAddress("192.1.2.128"), 26));
- Pool4Ptr pool3(new Pool4(IOAddress("192.1.2.192"), 30));
-
- subnet->addPool4(pool1);
-
- // If there's only one pool, get that pool
- Pool4Ptr mypool = subnet->getPool4();
- EXPECT_EQ(mypool, pool1);
-
-
- subnet->addPool4(pool2);
- subnet->addPool4(pool3);
-
- // If there are more than one pool and we didn't provide hint, we
- // should get the first pool
- mypool = subnet->getPool4();
-
- EXPECT_EQ(mypool, pool1);
-
- // If we provide a hint, we should get a pool that this hint belongs to
- mypool = subnet->getPool4(IOAddress("192.1.2.195"));
-
- EXPECT_EQ(mypool, pool3);
-
-}
-
-TEST(Subnet4Test, Subnet4_Pool4_checks) {
-
- Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 8, 1, 2, 3));
-
- // this one is in subnet
- Pool4Ptr pool1(new Pool4(IOAddress("192.255.0.0"), 16));
- subnet->addPool4(pool1);
-
- // this one is larger than the subnet!
- Pool4Ptr pool2(new Pool4(IOAddress("193.0.0.0"), 24));
-
- EXPECT_THROW(subnet->addPool4(pool2), BadValue);
-
- // this one is totally out of blue
- Pool4Ptr pool3(new Pool4(IOAddress("1.2.3.4"), 16));
- EXPECT_THROW(subnet->addPool4(pool3), BadValue);
-}
-
-TEST(Subnet4Test, addInvalidOption) {
- // Create the V4 subnet.
- Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 8, 1, 2, 3));
-
- // Some dummy option code.
- uint16_t code = 100;
- // Create option with invalid universe (V6 instead of V4).
- // Attempt to add this option should result in exception.
- OptionPtr option1(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
- EXPECT_THROW(subnet->addOption(option1), isc::BadValue);
-
- // Create NULL pointer option. Attempt to add NULL option
- // should result in exception.
- OptionPtr option2;
- ASSERT_FALSE(option2);
- EXPECT_THROW(subnet->addOption(option2), isc::BadValue);
-}
-
-// This test verifies that inRange() and inPool() methods work properly.
-TEST(Subnet4Test, inRangeinPool) {
- Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.0.0"), 8, 1, 2, 3));
-
- // this one is in subnet
- Pool4Ptr pool1(new Pool4(IOAddress("192.2.0.0"), 16));
- subnet->addPool4(pool1);
-
- // 192.1.1.1 belongs to the subnet...
- EXPECT_TRUE(subnet->inRange(IOAddress("192.1.1.1")));
-
- // ... but it does not belong to any pool within
- EXPECT_FALSE(subnet->inPool(IOAddress("192.1.1.1")));
-
- // the last address that is in range, but out of pool
- EXPECT_TRUE(subnet->inRange(IOAddress("192.1.255.255")));
- EXPECT_FALSE(subnet->inPool(IOAddress("192.1.255.255")));
-
- // the first address that is in range, in pool
- EXPECT_TRUE(subnet->inRange(IOAddress("192.2.0.0")));
- EXPECT_TRUE (subnet->inPool(IOAddress("192.2.0.0")));
-
- // let's try something in the middle as well
- EXPECT_TRUE(subnet->inRange(IOAddress("192.2.3.4")));
- EXPECT_TRUE (subnet->inPool(IOAddress("192.2.3.4")));
-
- // the last address that is in range, in pool
- EXPECT_TRUE(subnet->inRange(IOAddress("192.2.255.255")));
- EXPECT_TRUE (subnet->inPool(IOAddress("192.2.255.255")));
-
- // the first address that is in range, but out of pool
- EXPECT_TRUE(subnet->inRange(IOAddress("192.3.0.0")));
- EXPECT_FALSE(subnet->inPool(IOAddress("192.3.0.0")));
-}
-
-// This test checks if the toText() method returns text representation
-TEST(Subnet4Test, toText) {
- Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3));
- EXPECT_EQ("192.0.2.0/24", subnet->toText());
-}
-
-// This test checks if the get() method returns proper parameters
-TEST(Subnet4Test, get) {
- Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 28, 1, 2, 3));
- EXPECT_EQ("192.0.2.0", subnet->get().first.toText());
- EXPECT_EQ(28, subnet->get().second);
-}
-
-// Tests for Subnet6
-
-TEST(Subnet6Test, constructor) {
-
- EXPECT_NO_THROW(Subnet6 subnet1(IOAddress("2001:db8:1::"), 64,
- 1, 2, 3, 4));
-
- EXPECT_THROW(Subnet6 subnet2(IOAddress("2001:db8:1::"), 129, 1, 2, 3, 4),
- BadValue); // invalid prefix length
- EXPECT_THROW(Subnet6 subnet3(IOAddress("192.168.0.0"), 32, 1, 2, 3, 4),
- BadValue); // IPv4 addresses are not allowed in Subnet6
-}
-
-TEST(Subnet6Test, in_range) {
- Subnet6 subnet(IOAddress("2001:db8:1::"), 64, 1000, 2000, 3000, 4000);
-
- EXPECT_EQ(1000, subnet.getT1());
- EXPECT_EQ(2000, subnet.getT2());
- EXPECT_EQ(3000, subnet.getPreferred());
- EXPECT_EQ(4000, subnet.getValid());
-
- EXPECT_FALSE(subnet.inRange(IOAddress("2001:db8:0:ffff:ffff:ffff:ffff:ffff")));
- EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::0")));
- EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::1")));
- EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::ffff:ffff:ffff:ffff")));
- EXPECT_FALSE(subnet.inRange(IOAddress("2001:db8:1:1::")));
- EXPECT_FALSE(subnet.inRange(IOAddress("::")));
-}
-
-TEST(Subnet6Test, Pool6InSubnet6) {
-
- Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
-
- Pool6Ptr pool1(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:1::"), 64));
- Pool6Ptr pool2(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:2::"), 64));
- Pool6Ptr pool3(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:3::"), 64));
-
- subnet->addPool6(pool1);
-
- // If there's only one pool, get that pool
- Pool6Ptr mypool = subnet->getPool6();
- EXPECT_EQ(mypool, pool1);
-
-
- subnet->addPool6(pool2);
- subnet->addPool6(pool3);
-
- // If there are more than one pool and we didn't provide hint, we
- // should get the first pool
- mypool = subnet->getPool6();
-
- EXPECT_EQ(mypool, pool1);
-
- // If we provide a hint, we should get a pool that this hint belongs to
- mypool = subnet->getPool6(IOAddress("2001:db8:1:3::dead:beef"));
-
- EXPECT_EQ(mypool, pool3);
-}
-
-TEST(Subnet6Test, Subnet6_Pool6_checks) {
-
- Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
-
- // this one is in subnet
- Pool6Ptr pool1(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:1::"), 64));
- subnet->addPool6(pool1);
-
- // this one is larger than the subnet!
- Pool6Ptr pool2(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::"), 48));
-
- EXPECT_THROW(subnet->addPool6(pool2), BadValue);
-
-
- // this one is totally out of blue
- Pool6Ptr pool3(new Pool6(Pool6::TYPE_IA, IOAddress("3000::"), 16));
- EXPECT_THROW(subnet->addPool6(pool3), BadValue);
-
-
- Pool6Ptr pool4(new Pool6(Pool6::TYPE_IA, IOAddress("4001:db8:1::"), 80));
- EXPECT_THROW(subnet->addPool6(pool4), BadValue);
-}
-
-TEST(Subnet6Test, addOptions) {
- // Create as subnet to add options to it.
- Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
-
- // Differentiate options by their codes (100-109)
- for (uint16_t code = 100; code < 110; ++code) {
- OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
- ASSERT_NO_THROW(subnet->addOption(option));
- }
-
- // Get options from the Subnet and check if all 10 are there.
- Subnet::OptionContainer options = subnet->getOptions();
- ASSERT_EQ(10, options.size());
-
- // Validate codes of added options.
- uint16_t expected_code = 100;
- for (Subnet::OptionContainer::const_iterator option_desc = options.begin();
- option_desc != options.end(); ++option_desc) {
- ASSERT_TRUE(option_desc->option);
- EXPECT_EQ(expected_code, option_desc->option->getType());
- ++expected_code;
- }
-
- subnet->delOptions();
-
- options = subnet->getOptions();
- EXPECT_EQ(0, options.size());
-}
-
-TEST(Subnet6Test, addNonUniqueOptions) {
- // Create as subnet to add options to it.
- Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
-
- // Create a set of options with non-unique codes.
- for (int i = 0; i < 2; ++i) {
- // In the inner loop we create options with unique codes (100-109).
- for (uint16_t code = 100; code < 110; ++code) {
- OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
- ASSERT_NO_THROW(subnet->addOption(option));
- }
- }
-
- // Sanity check that all options are there.
- Subnet::OptionContainer options = subnet->getOptions();
- ASSERT_EQ(20, options.size());
-
- // Use container index #1 to get the options by their codes.
- Subnet::OptionContainerTypeIndex& idx = options.get<1>();
- // Look for the codes 100-109.
- for (uint16_t code = 100; code < 110; ++ code) {
- // For each code we should get two instances of options.
- std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
- Subnet::OptionContainerTypeIndex::const_iterator> range =
- idx.equal_range(code);
- // Distance between iterators indicates how many options
- // have been retured for the particular code.
- ASSERT_EQ(2, distance(range.first, range.second));
- // Check that returned options actually have the expected option code.
- for (Subnet::OptionContainerTypeIndex::const_iterator option_desc = range.first;
- option_desc != range.second; ++option_desc) {
- ASSERT_TRUE(option_desc->option);
- EXPECT_EQ(code, option_desc->option->getType());
- }
- }
-
- // Let's try to find some non-exiting option.
- const uint16_t non_existing_code = 150;
- std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
- Subnet::OptionContainerTypeIndex::const_iterator> range =
- idx.equal_range(non_existing_code);
- // Empty set is expected.
- EXPECT_EQ(0, distance(range.first, range.second));
-
- subnet->delOptions();
-
- options = subnet->getOptions();
- EXPECT_EQ(0, options.size());
-}
-
-TEST(Subnet6Test, addInvalidOption) {
- // Create as subnet to add options to it.
- Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
-
- // Some dummy option code.
- uint16_t code = 100;
- // Create option with invalid universe (V4 instead of V6).
- // Attempt to add this option should result in exception.
- OptionPtr option1(new Option(Option::V4, code, OptionBuffer(10, 0xFF)));
- EXPECT_THROW(subnet->addOption(option1), isc::BadValue);
-
- // Create NULL pointer option. Attempt to add NULL option
- // should result in exception.
- OptionPtr option2;
- ASSERT_FALSE(option2);
- EXPECT_THROW(subnet->addOption(option2), isc::BadValue);
-}
-
-TEST(Subnet6Test, addPersistentOption) {
- // Create as subnet to add options to it.
- Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
-
- // Add 10 options to the subnet with option codes 100 - 109.
- for (uint16_t code = 100; code < 110; ++code) {
- OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
- // We create 10 options and want some of them to be flagged
- // persistent and some non-persistent. Persistent options are
- // those that server sends to clients regardless if they ask
- // for them or not. We pick 3 out of 10 options and mark them
- // non-persistent and 7 other options persistent.
- // Code values: 102, 105 and 108 are divisable by 3
- // and options with these codes will be flagged non-persistent.
- // Options with other codes will be flagged persistent.
- bool persistent = (code % 3) ? true : false;
- ASSERT_NO_THROW(subnet->addOption(option, persistent));
- }
-
- // Get added options from the subnet.
- Subnet::OptionContainer options = subnet->getOptions();
-
- // options.get<2> returns reference to container index #2. This
- // index is used to access options by the 'persistent' flag.
- Subnet::OptionContainerPersistIndex& idx = options.get<2>();
-
- // Get all persistent options.
- std::pair<Subnet::OptionContainerPersistIndex::const_iterator,
- Subnet::OptionContainerPersistIndex::const_iterator> range_persistent =
- idx.equal_range(true);
- // 3 out of 10 options have been flagged persistent.
- ASSERT_EQ(7, distance(range_persistent.first, range_persistent.second));
-
- // Get all non-persistent options.
- std::pair<Subnet::OptionContainerPersistIndex::const_iterator,
- Subnet::OptionContainerPersistIndex::const_iterator> range_non_persistent =
- idx.equal_range(false);
- // 7 out of 10 options have been flagged persistent.
- ASSERT_EQ(3, distance(range_non_persistent.first, range_non_persistent.second));
-
- subnet->delOptions();
-
- options = subnet->getOptions();
- EXPECT_EQ(0, options.size());
-}
-
-// This test verifies that inRange() and inPool() methods work properly.
-TEST(Subnet6Test, inRangeinPool) {
- Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8::"), 32, 1, 2, 3, 4));
-
- // this one is in subnet
- Pool6Ptr pool1(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::10"),
- IOAddress("2001:db8::20")));
- subnet->addPool6(pool1);
-
- // 192.1.1.1 belongs to the subnet...
- EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::1")));
- // ... but it does not belong to any pool within
- EXPECT_FALSE(subnet->inPool(IOAddress("2001:db8::1")));
-
- // the last address that is in range, but out of pool
- EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::f")));
- EXPECT_FALSE(subnet->inPool(IOAddress("2001:db8::f")));
-
- // the first address that is in range, in pool
- EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::10")));
- EXPECT_TRUE (subnet->inPool(IOAddress("2001:db8::10")));
-
- // let's try something in the middle as well
- EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::18")));
- EXPECT_TRUE (subnet->inPool(IOAddress("2001:db8::18")));
-
- // the last address that is in range, in pool
- EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::20")));
- EXPECT_TRUE (subnet->inPool(IOAddress("2001:db8::20")));
-
- // the first address that is in range, but out of pool
- EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::21")));
- EXPECT_FALSE(subnet->inPool(IOAddress("2001:db8::21")));
-}
-
-// This test checks if the toText() method returns text representation
-TEST(Subnet6Test, toText) {
- Subnet6 subnet(IOAddress("2001:db8::"), 32, 1, 2, 3, 4);
- EXPECT_EQ("2001:db8::/32", subnet.toText());
-}
-
-// This test checks if the get() method returns proper parameters
-TEST(Subnet6Test, get) {
- Subnet6 subnet(IOAddress("2001:db8::"), 32, 1, 2, 3, 4);
- EXPECT_EQ("2001:db8::", subnet.get().first.toText());
- EXPECT_EQ(32, subnet.get().second);
-}
-
-};
diff --git a/src/lib/dhcp/tests/triplet_unittest.cc b/src/lib/dhcp/tests/triplet_unittest.cc
deleted file mode 100644
index 727eb8a..0000000
--- a/src/lib/dhcp/tests/triplet_unittest.cc
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <config.h>
-#include <stdint.h>
-#include <gtest/gtest.h>
-#include <dhcp/triplet.h>
-#include <exceptions/exceptions.h>
-
-using namespace isc::dhcp;
-using namespace isc;
-
-namespace {
-
-// constructor validation
-TEST(TripletTest, constructor) {
-
- const uint32_t min = 10;
- const uint32_t value = 20;
- const uint32_t max = 30;
-
- Triplet<uint32_t> x(min, value, max);
-
- EXPECT_EQ(min, x.getMin());
- EXPECT_EQ(value, x.get());
- EXPECT_EQ(max, x.getMax());
-
- // requested values below min should return allowed min value
- EXPECT_EQ(min, x.get(min - 5));
-
- EXPECT_EQ(min, x.get(min));
-
- // requesting a value from within the range (min < x < max) should
- // return the requested value
- EXPECT_EQ(17, x.get(17));
-
- EXPECT_EQ(max, x.get(max));
-
- EXPECT_EQ(max, x.get(max + 5));
-
- // this will be boring. It is expected to return 42 no matter what
- Triplet<uint32_t> y(42);
-
- EXPECT_EQ(42, y.getMin()); // min, default and max are equal to 42
- EXPECT_EQ(42, y.get()); // it returns ...
- EXPECT_EQ(42, y.getMax()); // the exact value...
-
- // requested values below or above are ignore
- EXPECT_EQ(42, y.get(5)); // all...
- EXPECT_EQ(42, y.get(42)); // the...
- EXPECT_EQ(42, y.get(80)); // time!
-}
-
-// Triplets must be easy to use.
-// Simple to/from int conversions must be done on the fly.
-TEST(TripletTest, operator) {
-
- uint32_t x = 47;
-
- Triplet<uint32_t> foo(1,2,3);
- Triplet<uint32_t> bar(4,5,6);
-
- foo = bar;
-
- EXPECT_EQ(4, foo.getMin());
- EXPECT_EQ(5, foo.get());
- EXPECT_EQ(6, foo.getMax());
-
- // assignment operator: uint32_t => triplet
- Triplet<uint32_t> y(0);
- y = x;
-
- EXPECT_EQ(x, y.get());
-
- // let's try the other way around: triplet => uint32_t
- uint32_t z = 0;
- z = y;
-
- EXPECT_EQ(x, z);
-}
-
-// check if specified values are sane
-TEST(TripletTest, sanity_check) {
-
- // min is larger than default
- EXPECT_THROW(Triplet<uint32_t>(6,5,5), BadValue);
-
- // max is smaller than default
- EXPECT_THROW(Triplet<uint32_t>(5,5,4), BadValue);
-
-}
-
-}; // end of anonymous namespace
diff --git a/src/lib/dhcp/triplet.h b/src/lib/dhcp/triplet.h
deleted file mode 100644
index d9388fe..0000000
--- a/src/lib/dhcp/triplet.h
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef TRIPLET_H
-#define TRIPLET_H
-
-#include <exceptions/exceptions.h>
-
-namespace isc {
-namespace dhcp {
-
-/// @brief this template specifies a parameter value
-///
-/// This template class is used to store configuration parameters, like lifetime or T1.
-/// It defines 3 parameters: min, default, and max value. There are 2 constructors:
-/// - simple (just one value that sets all parameters)
-/// - extended (that sets default value and two thresholds)
-/// It will be used with integer types. It provides necessary operators, so
-/// it can be assigned to a plain integer or integer assigned to a Triplet.
-/// See TripletTest.operator test for details on an easy Triplet usage.
-template <class T>
-class Triplet {
-public:
-
- /// @brief base type to Triple conversion
- ///
- /// Typically: uint32_t to Triplet assignment. It is very convenient
- /// to be able to simply write Triplet<uint32_t> x = 7;
- Triplet<T> operator=(T other) {
- min_ = other;
- default_ = other;
- max_ = other;
- return *this;
- }
-
- /// @brief triplet to base type conversion
- ///
- /// Typically: Triplet to uint32_t assignment. It is very convenient
- /// to be able to simply write uint32_t z = x; (where x is a Triplet)
- operator T() const {
- return (default_);
- }
-
- /// @brief sets a fixed value
- ///
- /// This constructor assigns a fixed (i.e. no range, just a single value)
- /// value.
- Triplet(T value)
- :min_(value), default_(value), max_(value) {
- }
-
- /// @brief sets the default value and thresholds
- ///
- /// @throw BadValue if min <= def <= max rule is violated
- Triplet(T min, T def, T max)
- :min_(min), default_(def), max_(max) {
- if ( (min_ > def) || (def > max_) ) {
- isc_throw(BadValue, "Invalid triplet values.");
- }
- }
-
- /// @brief returns a minimum allowed value
- T getMin() const { return min_;}
-
- /// @brief returns the default value
- T get() const { return default_;}
-
- /// @brief returns value with a hint
- ///
- /// DHCP protocol treats any values sent by a client as hints.
- /// This is a method that implements that. We can assign any value
- /// from configured range that client asks.
- T get(T hint) const {
- if (hint <= min_) {
- return (min_);
- }
-
- if (hint >= max_) {
- return (max_);
- }
-
- return (hint);
- }
-
- /// @brief returns a maximum allowed value
- T getMax() const { return max_; }
-
-protected:
-
- /// @brief the minimum value
- T min_;
-
- /// @brief the default value
- T default_;
-
- /// @brief the maximum value
- T max_;
-};
-
-
-} // namespace isc::dhcp
-} // namespace isc
-
-#endif // ifdef TRIPLET_H
diff --git a/src/lib/dhcpsrv/Makefile.am b/src/lib/dhcpsrv/Makefile.am
new file mode 100644
index 0000000..e205aee
--- /dev/null
+++ b/src/lib/dhcpsrv/Makefile.am
@@ -0,0 +1,52 @@
+SUBDIRS = . tests
+
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+if HAVE_MYSQL
+AM_CPPFLAGS += $(MYSQL_CPPFLAGS)
+endif
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+# Some versions of GCC warn about some versions of Boost regarding
+# missing initializer for members in its posix_time.
+# https://svn.boost.org/trac/boost/ticket/3477
+# But older GCC compilers don't have the flag.
+AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
+
+CLEANFILES = *.gcno *.gcda
+
+lib_LTLIBRARIES = libb10-dhcpsrv.la
+libb10_dhcpsrv_la_SOURCES =
+libb10_dhcpsrv_la_SOURCES += addr_utilities.cc addr_utilities.h
+libb10_dhcpsrv_la_SOURCES += alloc_engine.cc alloc_engine.h
+libb10_dhcpsrv_la_SOURCES += cfgmgr.cc cfgmgr.h
+libb10_dhcpsrv_la_SOURCES += lease_mgr.cc lease_mgr.h
+libb10_dhcpsrv_la_SOURCES += lease_mgr_factory.cc lease_mgr_factory.h
+libb10_dhcpsrv_la_SOURCES += memfile_lease_mgr.cc memfile_lease_mgr.h
+if HAVE_MYSQL
+libb10_dhcpsrv_la_SOURCES += mysql_lease_mgr.cc mysql_lease_mgr.h
+endif
+libb10_dhcpsrv_la_SOURCES += pool.cc pool.h
+libb10_dhcpsrv_la_SOURCES += subnet.cc subnet.h
+libb10_dhcpsrv_la_SOURCES += triplet.h
+
+libb10_dhcpsrv_la_CXXFLAGS = $(AM_CXXFLAGS)
+libb10_dhcpsrv_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
+libb10_dhcpsrv_la_LIBADD = $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+libb10_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
+libb10_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/util/libb10-util.la
+libb10_dhcpsrv_la_LDFLAGS = -no-undefined -version-info 2:0:0
+if HAVE_MYSQL
+libb10_dhcpsrv_la_LDFLAGS += $(MYSQL_LIBS)
+endif
+
+if USE_CLANGPP
+# Disable unused parameter warning caused by some of the
+# Boost headers when compiling with clang.
+libb10_dhcpsrv_la_CXXFLAGS += -Wno-unused-parameter
+endif
+
+# Distribute MySQL schema creation script and backend documentation
+EXTRA_DIST = dhcpdb_create.mysql database_backends.dox
+dist_pkgdata_DATA = dhcpdb_create.mysql
diff --git a/src/lib/dhcpsrv/addr_utilities.cc b/src/lib/dhcpsrv/addr_utilities.cc
new file mode 100644
index 0000000..a519016
--- /dev/null
+++ b/src/lib/dhcpsrv/addr_utilities.cc
@@ -0,0 +1,189 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dhcpsrv/addr_utilities.h>
+#include <exceptions/exceptions.h>
+
+#include <string.h>
+
+using namespace isc;
+using namespace isc::asiolink;
+
+namespace {
+
+/// @brief mask used for first/last address calculation in a IPv4 prefix
+///
+/// Using a static mask is faster than calculating it dynamically every time.
+const uint32_t bitMask4[] = { 0xffffffff, 0x7fffffff, 0x3fffffff, 0x1fffffff,
+ 0x0fffffff, 0x07ffffff, 0x03ffffff, 0x01ffffff,
+ 0x00ffffff, 0x007fffff, 0x003fffff, 0x001fffff,
+ 0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff,
+ 0x0000ffff, 0x00007fff, 0x00003fff, 0x00001fff,
+ 0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff,
+ 0x000000ff, 0x0000007f, 0x0000003f, 0x0000001f,
+ 0x0000000f, 0x00000007, 0x00000003, 0x00000001,
+ 0x00000000 };
+
+/// @brief mask used for first/last address calculation in a IPv6 prefix
+const uint8_t bitMask6[]= { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
+
+/// @brief calculates the first IPv6 address in a IPv6 prefix
+///
+/// Note: This is a private function. Do not use it directly.
+/// Please use firstAddrInPrefix() instead.
+///
+/// @param prefix IPv6 prefix
+/// @param len prefix length
+isc::asiolink::IOAddress firstAddrInPrefix6(const isc::asiolink::IOAddress& prefix,
+ uint8_t len) {
+ if (len > 128) {
+ isc_throw(isc::BadValue,
+ "Too large netmask. 0..128 is allowed in IPv6");
+ }
+
+ // 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
+ // part. Otherwise we need to handle the byte that has to be partially
+ // zeroed.
+ if (len % 8 != 0) {
+
+ // Get the appropriate mask. It has relevant bits (those that should
+ // stay) set and irrelevant (those that should be wiped) cleared.
+ uint8_t mask = bitMask6[len % 8];
+
+ // Let's leave only whatever the mask says should not be cleared.
+ packed[len / 8] = packed[len / 8] & mask;
+
+ // Since we have just dealt with this byte, let's move the prefix length
+ // to the beginning of the next byte (len is expressed in bits).
+ len = (len / 8 + 1) * 8;
+ }
+
+ // Clear out the remaining bits.
+ for (int i = len / 8; i < sizeof(packed); ++i) {
+ packed[i] = 0x0;
+ }
+
+ // Finally, let's wrap this into nice and easy IOAddress object.
+ return (isc::asiolink::IOAddress::from_bytes(AF_INET6, packed));
+}
+
+/// @brief calculates the first IPv4 address in a IPv4 prefix
+///
+/// Note: This is a private function. Do not use it directly.
+/// Please use firstAddrInPrefix() instead.
+///
+/// @param prefix IPv4 prefix
+/// @param len netmask length (0-32)
+isc::asiolink::IOAddress firstAddrInPrefix4(const isc::asiolink::IOAddress& prefix,
+ uint8_t len) {
+ if (len > 32) {
+ isc_throw(isc::BadValue, "Too large netmask. 0..32 is allowed in IPv4");
+ }
+
+ uint32_t addr = prefix;
+ return (IOAddress(addr & (~bitMask4[len])));
+}
+
+/// @brief calculates the last IPv4 address in a IPv4 prefix
+///
+/// Note: This is a private function. Do not use it directly.
+/// Please use firstAddrInPrefix() instead.
+///
+/// @param prefix IPv4 prefix that we calculate first address for
+/// @param len netmask length (0-32)
+isc::asiolink::IOAddress lastAddrInPrefix4(const isc::asiolink::IOAddress& prefix,
+ uint8_t len) {
+ if (len > 32) {
+ isc_throw(isc::BadValue, "Too large netmask. 0..32 is allowed in IPv4");
+ }
+
+ uint32_t addr = prefix;
+ return (IOAddress(addr | bitMask4[len]));
+}
+
+/// @brief calculates the last IPv6 address in a IPv6 prefix
+///
+/// Note: This is a private function. Do not use it directly.
+/// Please use lastAddrInPrefix() instead.
+///
+/// @param prefix IPv6 prefix that we calculate first address for
+/// @param len netmask length (0-128)
+isc::asiolink::IOAddress lastAddrInPrefix6(const isc::asiolink::IOAddress& prefix,
+ uint8_t len) {
+ if (len > 128) {
+ isc_throw(isc::BadValue,
+ "Too large netmask. 0..128 is allowed in IPv6");
+ }
+
+ // 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
+ // with ones. Otherwise we need to handle the byte that has to be partially
+ // zeroed.
+ if (len % 8 != 0) {
+ // Get the appropriate mask. It has relevant bits (those that should
+ // stay) set and irrelevant (those that should be set to 1) cleared.
+ uint8_t mask = bitMask6[len % 8];
+
+ // Let's set those irrelevant bits with 1. It would be perhaps
+ // easier to not use negation here and invert bitMask6 content. However,
+ // with this approach, we can use the same mask in first and last
+ // address calculations.
+ packed[len / 8] = packed[len / 8] | ~mask;
+
+ // Since we have just dealt with this byte, let's move the prefix length
+ // to the beginning of the next byte (len is expressed in bits).
+ len = (len / 8 + 1) * 8;
+ }
+
+ // Finally set remaining bits to 1.
+ for (int i = len / 8; i < sizeof(packed); ++i) {
+ packed[i] = 0xff;
+ }
+
+ // Finally, let's wrap this into nice and easy IOAddress object.
+ return (isc::asiolink::IOAddress::from_bytes(AF_INET6, packed));
+}
+
+}; // end of anonymous namespace
+
+namespace isc {
+namespace dhcp {
+
+isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefix,
+ uint8_t len) {
+ if (prefix.getFamily() == AF_INET) {
+ return firstAddrInPrefix4(prefix, len);
+ } else {
+ return firstAddrInPrefix6(prefix, len);
+ }
+}
+
+isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix,
+ uint8_t len) {
+ if (prefix.getFamily() == AF_INET) {
+ return lastAddrInPrefix4(prefix, len);
+ } else {
+ return lastAddrInPrefix6(prefix, len);
+ }
+}
+
+};
+};
diff --git a/src/lib/dhcpsrv/addr_utilities.h b/src/lib/dhcpsrv/addr_utilities.h
new file mode 100644
index 0000000..a1d856c
--- /dev/null
+++ b/src/lib/dhcpsrv/addr_utilities.h
@@ -0,0 +1,58 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef ADDR_UTILITIES_H
+#define ADDR_UTILITIES_H
+
+#include <asiolink/io_address.h>
+
+namespace isc {
+namespace dhcp {
+
+/// This code is based on similar code from the Dibbler project. I, Tomasz Mrugalski,
+/// as a sole creator of that code hereby release it under BSD license for the benefit
+/// of the BIND10 project.
+
+/// @brief returns a first address in a given prefix
+///
+/// Example: For 2001:db8:1::deaf:beef and length /120 the function will return
+/// 2001:db8:1::dead:be00. See also @ref lastAddrInPrefix.
+///
+/// @todo It currently works for v6 only and will throw if v4 address is passed.
+///
+/// @param prefix and address that belongs to a prefix
+/// @param len prefix length
+///
+/// @return first address from a prefix
+isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefix,
+ uint8_t len);
+
+/// @brief returns a last address in a given prefix
+///
+/// Example: For 2001:db8:1::deaf:beef and length /112 the function will return
+/// 2001:db8:1::dead:ffff. See also @ref firstAddrInPrefix.
+///
+/// @todo It currently works for v6 only and will throw if v4 address is passed.
+///
+/// @param prefix and address that belongs to a prefix
+/// @param len prefix length
+///
+/// @return first address from a prefix
+isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix,
+ uint8_t len);
+
+};
+};
+
+#endif // ADDR_UTILITIES_H
diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc
new file mode 100644
index 0000000..4f20276
--- /dev/null
+++ b/src/lib/dhcpsrv/alloc_engine.cc
@@ -0,0 +1,277 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dhcpsrv/alloc_engine.h>
+#include <dhcpsrv/lease_mgr_factory.h>
+
+#include <cstring>
+
+#include <string.h>
+
+using namespace isc::asiolink;
+
+namespace isc {
+namespace dhcp {
+
+AllocEngine::IterativeAllocator::IterativeAllocator()
+ :Allocator() {
+}
+
+isc::asiolink::IOAddress
+AllocEngine::IterativeAllocator::increaseAddress(const isc::asiolink::IOAddress& addr) {
+ uint8_t packed[V6ADDRESS_LEN];
+ int len;
+
+ // First we copy the whole address as 16 bytes.
+ if (addr.getFamily()==AF_INET) {
+ // IPv4
+ std::memcpy(packed, addr.getAddress().to_v4().to_bytes().data(), 4);
+ len = 4;
+ } else {
+ // IPv6
+ std::memcpy(packed, addr.getAddress().to_v6().to_bytes().data(), 16);
+ len = 16;
+ }
+
+ for (int i = len - 1; i >= 0; --i) {
+ ++packed[i];
+ if (packed[i] != 0) {
+ break;
+ }
+ }
+
+ return (IOAddress::from_bytes(addr.getFamily(), packed));
+}
+
+
+isc::asiolink::IOAddress
+AllocEngine::IterativeAllocator::pickAddress(const Subnet6Ptr& subnet,
+ const DuidPtr&,
+ const IOAddress&) {
+
+ // Let's get the last allocated address. It is usually set correctly,
+ // but there are times when it won't be (like after removing a pool or
+ // perhaps restaring the server).
+ IOAddress last = subnet->getLastAllocated();
+
+ const Pool6Collection& pools = subnet->getPools();
+
+ if (pools.size() == 0) {
+ isc_throw(AllocFailed, "No pools defined in selected subnet");
+ }
+
+ // first we need to find a pool the last address belongs to.
+ Pool6Collection::const_iterator it;
+ for (it = pools.begin(); it != pools.end(); ++it) {
+ if ((*it)->inRange(last)) {
+ break;
+ }
+ }
+
+ // last one was bogus for one of several reasons:
+ // - we just booted up and that's the first address we're allocating
+ // - a subnet was removed or other reconfiguration just completed
+ // - perhaps allocation algorithm was changed
+ if (it == pools.end()) {
+ // ok to access first element directly. We checked that pools is non-empty
+ IOAddress next = pools[0]->getFirstAddress();
+ subnet->setLastAllocated(next);
+ return (next);
+ }
+
+ // Ok, we have a pool that the last address belonged to, let's use it.
+
+ IOAddress next = increaseAddress(last); // basically addr++
+ if ((*it)->inRange(next)) {
+ // the next one is in the pool as well, so we haven't hit pool boundary yet
+ subnet->setLastAllocated(next);
+ return (next);
+ }
+
+ // We hit pool boundary, let's try to jump to the next pool and try again
+ ++it;
+ if (it == pools.end()) {
+ // Really out of luck today. That was the last pool. Let's rewind
+ // to the beginning.
+ next = pools[0]->getFirstAddress();
+ subnet->setLastAllocated(next);
+ return (next);
+ }
+
+ // there is a next pool, let's try first adddress from it
+ next = (*it)->getFirstAddress();
+ subnet->setLastAllocated(next);
+ return (next);
+}
+
+AllocEngine::HashedAllocator::HashedAllocator()
+ :Allocator() {
+ isc_throw(NotImplemented, "Hashed allocator is not implemented");
+}
+
+
+isc::asiolink::IOAddress
+AllocEngine::HashedAllocator::pickAddress(const Subnet6Ptr&,
+ const DuidPtr&,
+ const IOAddress&) {
+ isc_throw(NotImplemented, "Hashed allocator is not implemented");
+}
+
+AllocEngine::RandomAllocator::RandomAllocator()
+ :Allocator() {
+ isc_throw(NotImplemented, "Random allocator is not implemented");
+}
+
+
+isc::asiolink::IOAddress
+AllocEngine::RandomAllocator::pickAddress(const Subnet6Ptr&,
+ const DuidPtr&,
+ const IOAddress&) {
+ isc_throw(NotImplemented, "Random allocator is not implemented");
+}
+
+
+AllocEngine::AllocEngine(AllocType engine_type, unsigned int attempts)
+ :attempts_(attempts) {
+ switch (engine_type) {
+ case ALLOC_ITERATIVE:
+ allocator_ = boost::shared_ptr<Allocator>(new IterativeAllocator());
+ break;
+ case ALLOC_HASHED:
+ allocator_ = boost::shared_ptr<Allocator>(new HashedAllocator());
+ break;
+ case ALLOC_RANDOM:
+ allocator_ = boost::shared_ptr<Allocator>(new RandomAllocator());
+ break;
+
+ default:
+ isc_throw(BadValue, "Invalid/unsupported allocation algorithm");
+ }
+}
+
+Lease6Ptr
+AllocEngine::allocateAddress6(const Subnet6Ptr& subnet,
+ const DuidPtr& duid,
+ uint32_t iaid,
+ const IOAddress& hint,
+ bool fake_allocation /* = false */ ) {
+
+ // That check is not necessary. We create allocator in AllocEngine
+ // constructor
+ if (!allocator_) {
+ isc_throw(InvalidOperation, "No allocator selected");
+ }
+
+ // check if there's existing lease for that subnet/duid/iaid combination.
+ Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(*duid, iaid, subnet->getID());
+ if (existing) {
+ // we have a lease already. This is a returning client, probably after
+ // his reboot.
+ return (existing);
+ }
+
+ // check if the hint is in pool and is available
+ if (subnet->inPool(hint)) {
+ existing = LeaseMgrFactory::instance().getLease6(hint);
+ if (!existing) {
+ /// @todo: check if the hint is reserved once we have host support
+ /// implemented
+
+ // the hint is valid and not currently used, let's create a lease for it
+ Lease6Ptr lease = createLease(subnet, duid, iaid, hint, fake_allocation);
+
+ // It can happen that the lease allocation failed (we could have lost
+ // the race condition. That means that the hint is lo longer usable and
+ // we need to continue the regular allocation path.
+ if (lease) {
+ return (lease);
+ }
+ }
+ }
+
+ unsigned int i = attempts_;
+ do {
+ IOAddress candidate = allocator_->pickAddress(subnet, duid, hint);
+
+ /// @todo: check if the address is reserved once we have host support
+ /// implemented
+
+ Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(candidate);
+ // there's no existing lease for selected candidate, so it is
+ // free. Let's allocate it.
+ if (!existing) {
+ Lease6Ptr lease = createLease(subnet, duid, iaid, candidate,
+ fake_allocation);
+ if (lease) {
+ return (lease);
+ }
+
+ // Although the address was free just microseconds ago, it may have
+ // been taken just now. If the lease insertion fails, we continue
+ // allocation attempts.
+ }
+
+ // continue trying allocation until we run out of attempts
+ // (or attempts are set to 0, which means infinite)
+ --i;
+ } while ( i || !attempts_);
+
+ isc_throw(AllocFailed, "Failed to allocate address after " << attempts_
+ << " tries");
+}
+
+Lease6Ptr AllocEngine::createLease(const Subnet6Ptr& subnet,
+ const DuidPtr& duid,
+ uint32_t iaid,
+ const IOAddress& addr,
+ bool fake_allocation /*= false */ ) {
+
+ Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr, duid, iaid,
+ subnet->getPreferred(), subnet->getValid(),
+ subnet->getT1(), subnet->getT2(), subnet->getID()));
+
+ if (!fake_allocation) {
+ // That is a real (REQUEST) allocation
+ bool status = LeaseMgrFactory::instance().addLease(lease);
+
+ if (status) {
+
+ return (lease);
+ } else {
+ // One of many failures with LeaseMgr (e.g. lost connection to the
+ // database, database failed etc.). One notable case for that
+ // is that we are working in multi-process mode and we lost a race
+ // (some other process got that address first)
+ return (Lease6Ptr());
+ }
+ } else {
+ // That is only fake (SOLICIT without rapid-commit) allocation
+
+ // It is for advertise only. We should not insert the lease into LeaseMgr,
+ // but rather check that we could have inserted it.
+ Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(addr);
+ if (!existing) {
+ return (lease);
+ } else {
+ return (Lease6Ptr());
+ }
+ }
+}
+
+AllocEngine::~AllocEngine() {
+ // no need to delete allocator. smart_ptr will do the trick for us
+}
+
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
diff --git a/src/lib/dhcpsrv/alloc_engine.h b/src/lib/dhcpsrv/alloc_engine.h
new file mode 100644
index 0000000..940b1f4
--- /dev/null
+++ b/src/lib/dhcpsrv/alloc_engine.h
@@ -0,0 +1,229 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef ALLOC_ENGINE_H
+#define ALLOC_ENGINE_H
+
+#include <asiolink/io_address.h>
+#include <dhcp/duid.h>
+#include <dhcpsrv/subnet.h>
+#include <dhcpsrv/lease_mgr.h>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+
+namespace isc {
+namespace dhcp {
+
+/// An exception that is thrown when allocation module fails (e.g. due to
+/// lack of available addresses)
+class AllocFailed : public isc::Exception {
+public:
+
+ /// @brief constructor
+ ///
+ /// @param file name of the file, where exception occurred
+ /// @param line line of the file, where exception occurred
+ /// @param what text description of the issue that caused exception
+ AllocFailed(const char* file, size_t line, const char* what)
+ : isc::Exception(file, line, what) {}
+};
+
+/// @brief DHCPv4 and DHCPv6 allocation engine
+///
+/// This class represents DHCP allocation engine. It is responsible
+/// for picking subnets, choosing and allocating a lease, extending,
+/// renewing, releasing and possibly expiring leases.
+///
+/// @todo: Does not handle out of leases well
+/// @todo: Does not handle out of allocation attempts well
+class AllocEngine : public boost::noncopyable {
+protected:
+
+ /// @brief base class for all address/prefix allocation algorithms
+ ///
+ /// This is an abstract class that should not be used directly, but rather
+ /// specialized implementations should be used instead.
+ class Allocator {
+ public:
+
+ /// @brief picks one address out of available pools in a given subnet
+ ///
+ /// This method returns one address from the available pools in the
+ /// specified subnet. It should not check if the address is used or
+ /// reserved - AllocEngine will check that and will call pickAddress
+ /// again if necessary. The number of times this method is called will
+ /// increase as the number of available leases will decrease.
+ virtual isc::asiolink::IOAddress
+ pickAddress(const Subnet6Ptr& subnet, const DuidPtr& duid,
+ const isc::asiolink::IOAddress& hint) = 0;
+
+ /// @brief virtual destructor
+ virtual ~Allocator() {
+ }
+ protected:
+ };
+
+ /// @brief Address/prefix allocator that iterates over all addresses
+ ///
+ /// This class implements iterative algorithm that returns all addresses in
+ /// a pool iteratively, one after another. Once the last address is reached,
+ /// it starts allocating from the beginning of the first pool (i.e. it loops
+ /// over).
+ class IterativeAllocator : public Allocator {
+ public:
+
+ /// @brief default constructor
+ ///
+ /// Does not do anything
+ IterativeAllocator();
+
+ /// @brief returns the next address from pools in a subnet
+ ///
+ /// @param subnet next address will be returned from pool of that subnet
+ /// @param duid Client's DUID (ignored)
+ /// @param hint client's hint (ignored)
+ /// @return the next address
+ virtual isc::asiolink::IOAddress
+ pickAddress(const Subnet6Ptr& subnet,
+ const DuidPtr& duid,
+ const isc::asiolink::IOAddress& hint);
+ private:
+
+ /// @brief returns an address by one
+ /// @param addr address to be increased
+ /// @return address increased by one
+ isc::asiolink::IOAddress increaseAddress(const isc::asiolink::IOAddress& addr);
+
+ };
+
+ /// @brief Address/prefix allocator that gets an address based on a hash
+ ///
+ /// @todo: This is a skeleton class for now and is missing implementation.
+ class HashedAllocator : public Allocator {
+ public:
+
+ /// @brief default constructor (does nothing)
+ HashedAllocator();
+
+ /// @brief returns an address based on hash calculated from client's DUID.
+ ///
+ /// @todo: Implement this method
+ ///
+ /// @param subnet an address will be picked from pool of that subnet
+ /// @param duid Client's DUID
+ /// @param hint a hint (last address that was picked)
+ /// @return selected address
+ virtual isc::asiolink::IOAddress pickAddress(const Subnet6Ptr& subnet,
+ const DuidPtr& duid,
+ const isc::asiolink::IOAddress& hint);
+ };
+
+ /// @brief Random allocator that picks address randomly
+ ///
+ /// @todo: This is a skeleton class for now and is missing implementation.
+ class RandomAllocator : public Allocator {
+ public:
+
+ /// @brief default constructor (does nothing)
+ RandomAllocator();
+
+ /// @brief returns an random address from pool of specified subnet
+ ///
+ /// @todo: Implement this method
+ ///
+ /// @param subnet an address will be picked from pool of that subnet
+ /// @param duid Client's DUID (ignored)
+ /// @param hint the last address that was picked (ignored)
+ /// @return a random address from the pool
+ virtual isc::asiolink::IOAddress
+ pickAddress(const Subnet6Ptr& subnet, const DuidPtr& duid,
+ const isc::asiolink::IOAddress& hint);
+ };
+
+ public:
+
+ /// @brief specifies allocation type
+ typedef enum {
+ ALLOC_ITERATIVE, // iterative - one address after another
+ ALLOC_HASHED, // hashed - client's DUID/client-id is hashed
+ ALLOC_RANDOM // random - an address is randomly selected
+ } AllocType;
+
+
+ /// @brief Default constructor.
+ ///
+ /// Instantiates necessary services, required to run DHCPv6 server.
+ /// In particular, creates IfaceMgr that will be responsible for
+ /// network interaction. Will instantiate lease manager, and load
+ /// old or create new DUID.
+ ///
+ /// @param engine_type selects allocation algorithm
+ /// @param attempts number of attempts for each lease allocation before
+ /// we give up (0 means unlimited)
+ AllocEngine(AllocType engine_type, unsigned int attempts);
+
+ /// @brief Allocates an IPv6 lease
+ ///
+ /// This method uses currently selected allocator to pick an address from
+ /// specified subnet, creates a lease for that address and then inserts
+ /// it into LeaseMgr (if this allocation is not fake).
+ ///
+ /// @param subnet subnet the allocation should come from
+ /// @param duid Client'd DUID
+ /// @param iaid iaid field from the IA_NA container that client sent
+ /// @param hint a hint that the client provided
+ /// @param fake_allocation is this real i.e. REQUEST (false) or just picking
+ /// an address for SOLICIT that is not really allocated (true)
+ /// @return Allocated IPv6 lease (or NULL if allocation failed)
+ Lease6Ptr
+ allocateAddress6(const Subnet6Ptr& subnet,
+ const DuidPtr& duid,
+ uint32_t iaid,
+ const isc::asiolink::IOAddress& hint,
+ bool fake_allocation);
+
+ /// @brief Destructor. Used during DHCPv6 service shutdown.
+ virtual ~AllocEngine();
+private:
+
+ /// @brief creates a lease and inserts it in LeaseMgr if necessary
+ ///
+ /// Creates a lease based on specified parameters and tries to insert it
+ /// into the database. That may fail in some cases, i.e. when there is another
+ /// allocation process and we lost a race to a specific lease.
+ ///
+ /// @param subnet subnet the lease is allocated from
+ /// @param duid client's DUID
+ /// @param iaid IAID from the IA_NA container the client sent to us
+ /// @param addr an address that was selected and is confirmed to be available
+ /// @param fake_allocation is this real i.e. REQUEST (false) or just picking
+ /// an address for SOLICIT that is not really allocated (true)
+ /// @return allocated lease (or NULL in the unlikely case of the lease just
+ /// becomed unavailable)
+ Lease6Ptr createLease(const Subnet6Ptr& subnet, const DuidPtr& duid,
+ uint32_t iaid, const isc::asiolink::IOAddress& addr,
+ bool fake_allocation = false);
+
+ /// @brief a pointer to currently used allocator
+ boost::shared_ptr<Allocator> allocator_;
+
+ /// @brief number of attempts before we give up lease allocation (0=unlimited)
+ unsigned int attempts_;
+};
+
+}; // namespace isc::dhcp
+}; // namespace isc
+
+#endif // ALLOC_ENGINE_H
diff --git a/src/lib/dhcpsrv/cfgmgr.cc b/src/lib/dhcpsrv/cfgmgr.cc
new file mode 100644
index 0000000..3c46b13
--- /dev/null
+++ b/src/lib/dhcpsrv/cfgmgr.cc
@@ -0,0 +1,111 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <asiolink/io_address.h>
+#include <dhcpsrv/cfgmgr.h>
+
+using namespace isc::asiolink;
+using namespace isc::util;
+
+namespace isc {
+namespace dhcp {
+
+
+
+
+CfgMgr&
+CfgMgr::instance() {
+ static CfgMgr cfg_mgr;
+ return (cfg_mgr);
+}
+
+Subnet6Ptr
+CfgMgr::getSubnet6(const isc::asiolink::IOAddress& hint) {
+
+ // If there's only one subnet configured, let's just use it
+ // The idea is to keep small deployments easy. In a small network - one
+ // router that also runs DHCPv6 server. Users specifies a single pool and
+ // expects it to just work. Without this, the server would complain that it
+ // doesn't have IP address on its interfaces that matches that
+ // configuration. Such requirement makes sense in IPv4, but not in IPv6.
+ // The server does not need to have a global address (using just link-local
+ // is ok for DHCPv6 server) from the pool it serves.
+ if ((subnets6_.size() == 1) && hint.getAddress().to_v6().is_link_local()) {
+ return (subnets6_[0]);
+ }
+
+ // If there is more than one, we need to choose the proper one
+ for (Subnet6Collection::iterator subnet = subnets6_.begin();
+ subnet != subnets6_.end(); ++subnet) {
+ if ((*subnet)->inRange(hint)) {
+ return (*subnet);
+ }
+ }
+
+ // sorry, we don't support that subnet
+ return (Subnet6Ptr());
+}
+
+Subnet6Ptr CfgMgr::getSubnet6(OptionPtr /*interfaceId*/) {
+ /// @todo: Implement get subnet6 by interface-id (for relayed traffic)
+ isc_throw(NotImplemented, "Relayed DHCPv6 traffic is not supported yet.");
+}
+
+void CfgMgr::addSubnet6(const Subnet6Ptr& subnet) {
+ /// @todo: Check that this new subnet does not cross boundaries of any
+ /// other already defined subnet.
+ subnets6_.push_back(subnet);
+}
+
+Subnet4Ptr
+CfgMgr::getSubnet4(const isc::asiolink::IOAddress& hint) {
+
+ // If there's only one subnet configured, let's just use it
+ // The idea is to keep small deployments easy. In a small network - one
+ // router that also runs DHCPv6 server. Users specifies a single pool and
+ // expects it to just work. Without this, the server would complain that it
+ // doesn't have IP address on its interfaces that matches that
+ // configuration. Such requirement makes sense in IPv4, but not in IPv6.
+ // The server does not need to have a global address (using just link-local
+ // is ok for DHCPv6 server) from the pool it serves.
+ if (subnets4_.size() == 1) {
+ return (subnets4_[0]);
+ }
+
+ // If there is more than one, we need to choose the proper one
+ for (Subnet4Collection::iterator subnet = subnets4_.begin();
+ subnet != subnets4_.end(); ++subnet) {
+ if ((*subnet)->inRange(hint)) {
+ return (*subnet);
+ }
+ }
+
+ // sorry, we don't support that subnet
+ return (Subnet4Ptr());
+}
+
+void CfgMgr::addSubnet4(const Subnet4Ptr& subnet) {
+ /// @todo: Check that this new subnet does not cross boundaries of any
+ /// other already defined subnet.
+ subnets4_.push_back(subnet);
+}
+
+CfgMgr::CfgMgr() {
+}
+
+CfgMgr::~CfgMgr() {
+}
+
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
diff --git a/src/lib/dhcpsrv/cfgmgr.h b/src/lib/dhcpsrv/cfgmgr.h
new file mode 100644
index 0000000..5bff64a
--- /dev/null
+++ b/src/lib/dhcpsrv/cfgmgr.h
@@ -0,0 +1,167 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef CFGMGR_H
+#define CFGMGR_H
+
+#include <asiolink/io_address.h>
+#include <dhcp/option.h>
+#include <dhcpsrv/pool.h>
+#include <dhcpsrv/subnet.h>
+#include <util/buffer.h>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace isc {
+namespace dhcp {
+
+
+/// @brief Configuration Manager
+///
+/// This singleton class holds the whole configuration for DHCPv4 and DHCPv6
+/// servers. It currently holds information about zero or more subnets6.
+/// Each subnet may contain zero or more pools. Pool4 and Pool6 is the most
+/// basic "chunk" of configuration. It contains a range of assigneable
+/// addresses.
+///
+/// Below is a sketch of configuration inheritance (not implemented yet).
+/// Let's investigate the following configuration:
+///
+/// preferred-lifetime 500;
+/// valid-lifetime 1000;
+/// subnet6 2001:db8:1::/48 {
+/// pool6 2001::db8:1::1 - 2001::db8:1::ff;
+/// };
+/// subnet6 2001:db8:2::/48 {
+/// valid-lifetime 2000;
+/// pool6 2001::db8:2::1 - 2001::db8:2::ff;
+/// };
+/// Parameters defined in a global scope are applicable to everything until
+/// they are overwritten in a smaller scope, in this case subnet6.
+/// In the example above, the first subnet6 has preferred lifetime of 500s
+/// and a valid lifetime of 1000s. The second subnet has preferred lifetime
+/// of 500s, but valid lifetime of 2000s.
+///
+/// Parameter inheritance is likely to be implemented in configuration handling
+/// routines, so there is no storage capability in a global scope for
+/// subnet-specific parameters.
+///
+/// @todo: Implement Subnet4 support (ticket #2237)
+/// @todo: Implement option definition support
+/// @todo: Implement parameter inheritance
+class CfgMgr : public boost::noncopyable {
+public:
+
+ /// @brief returns a single instance of Configuration Manager
+ ///
+ /// CfgMgr is a singleton and this method is the only way of
+ /// accessing it.
+ static CfgMgr& instance();
+
+ /// @brief get IPv6 subnet by address
+ ///
+ /// Finds a matching subnet, based on an address. This can be used
+ /// in two cases: when trying to find an appropriate lease based on
+ /// a) relay link address (that must be the address that is on link)
+ /// b) our global address on the interface the message was received on
+ /// (for directly connected clients)
+ ///
+ /// @param hint an address that belongs to a searched subnet
+ Subnet6Ptr getSubnet6(const isc::asiolink::IOAddress& hint);
+
+ /// @brief get IPv6 subnet by interface-id
+ ///
+ /// Another possibility to find a subnet is based on interface-id.
+ ///
+ /// @param interface_id content of interface-id option returned by a relay
+ /// @todo This method is not currently supported.
+ Subnet6Ptr getSubnet6(OptionPtr interface_id);
+
+ /// @brief adds an IPv6 subnet
+ void addSubnet6(const Subnet6Ptr& subnet);
+
+ /// @todo: Add subnet6 removal routines. Currently it is not possible
+ /// to remove subnets. The only case where subnet6 removal would be
+ /// needed is a dynamic server reconfiguration - a use case that is not
+ /// planned to be supported any time soon.
+
+ /// @brief removes all subnets
+ ///
+ /// This method removes all existing subnets. It is used during
+ /// reconfiguration - old configuration is wiped and new definitions
+ /// are used to recreate subnets.
+ ///
+ /// @todo Implement more intelligent approach. Note that comparison
+ /// between old and new configuration is tricky. For example: is
+ /// 2000::/64 and 2000::/48 the same subnet or is it something
+ /// completely new?
+ void deleteSubnets6() {
+ subnets6_.clear();
+ }
+
+ /// @brief get IPv4 subnet by address
+ ///
+ /// Finds a matching subnet, based on an address. This can be used
+ /// in two cases: when trying to find an appropriate lease based on
+ /// a) relay link address (that must be the address that is on link)
+ /// b) our global address on the interface the message was received on
+ /// (for directly connected clients)
+ ///
+ /// @param hint an address that belongs to a searched subnet
+ Subnet4Ptr getSubnet4(const isc::asiolink::IOAddress& hint);
+
+ /// @brief adds a subnet4
+ void addSubnet4(const Subnet4Ptr& subnet);
+
+ /// @brief removes all IPv4 subnets
+ void removeSubnets4();
+protected:
+
+ /// @brief Protected constructor.
+ ///
+ /// This constructor is protected for 2 reasons. First, it forbids any
+ /// instantiations of this class (CfgMgr is a singleton). Second, it
+ /// allows derived class to instantiate it. That is useful for testing
+ /// purposes.
+ CfgMgr();
+
+ /// @brief virtual desctructor
+ virtual ~CfgMgr();
+
+ /// @brief a container for IPv6 subnets.
+ ///
+ /// That is a simple vector of pointers. It does not make much sense to
+ /// optimize access time (e.g. using a map), because typical search
+ /// pattern will use calling inRange() method on each subnet until
+ /// a match is found.
+ Subnet6Collection subnets6_;
+
+ /// @brief a container for IPv4 subnets.
+ ///
+ /// That is a simple vector of pointers. It does not make much sense to
+ /// optimize access time (e.g. using a map), because typical search
+ /// pattern will use calling inRange() method on each subnet until
+ /// a match is found.
+ Subnet4Collection subnets4_;
+};
+
+} // namespace isc::dhcp
+} // namespace isc
+
+#endif // CFGMGR_H
diff --git a/src/lib/dhcpsrv/database_backends.dox b/src/lib/dhcpsrv/database_backends.dox
new file mode 100644
index 0000000..8eeb5c5
--- /dev/null
+++ b/src/lib/dhcpsrv/database_backends.dox
@@ -0,0 +1,64 @@
+/**
+ @page dhcp-database-backends DHCP Database Back-Ends
+
+ All DHCP lease data is stored in some form of database, the interface
+ to this being through the Lease Manager.
+
+ All backend classes such as isc::dhcp::MySqlLeaseMgr are derived from
+ the abstract isc::dhcp::LeaseMgr class. This provides methods to
+ create, retrieve, modify and delete leases in the database.
+
+ @section dhcpdb-instantiation Instantiation of Lease Managers
+
+ A lease manager is instantiated through the LeaseMgrFactory class. This
+ has three methods:
+
+ - isc::dhcp::LeaseMgrFactory::create - Creates a singleton Lease
+ Manager of the appropriate type.
+ - isc::dhcp::LeaseMgrFactory::instance - Returns a reference to the
+ the instance of the Lease Manager.
+ - isc::dhcp::LeaseMgrFactory::destroy - Destroys the singleton lease manager.
+
+ The selection of the Lease Manager (and thus the backend database) is
+ controlled by the connection string passed to
+ isc::dhcp::LeaseMgrFactory::create. This is a set of "keyword=value" pairs
+ (no embedded spaces), each pair separated by a space from the others, e.g.
+
+ \code
+ type=mysql user=keatest password=keatest name=keatest host=localhost
+ \endcode
+
+ The following keywords are used for all backends:
+
+ - <b>type</b> - specifies the type of database backend. The following values
+ for the type keyword are supported:
+ - <b>mysql</b> - Use MySQL as the database
+
+ The following sections list the database-specific keywords:
+
+ @subsection dhcpdb-keywords-mysql MySQL connection string keywords
+
+ - <b>host</b> - host on which the selected database is running. If not
+ supplied, "localhost" is assumed.
+ - <b>name</b> - name of the MySQL database to access. There is no default -
+ this must always be supplied.
+ - <b>password</b> - password for the selected user ID (see below). If not
+ specified, no password is used.
+ - <b>user</b> - database user ID under which the database is accessed. If not
+ specified, no user ID is used - the database is assumed to be open.
+
+
+ @section dhcp-backend-unittest Running Unit Tests
+
+ With the use of databases requiring separate authorisation, there are
+ certain database-specific pre-requisites for successfully running the unit
+ tests. These are listed in the following sections.
+
+ @subsection dhcp-mysql-unittest MySQL
+
+ A database called <i>keatest</i> needs to be set up using the MySQL
+ <b>CREATE DATABASE</b> command. A database user, also called <i>keatest</i>
+ (with a password <i>keatest</i>) must be given full privileges in that
+ database. The unit tests create the schema in the database before each test
+ and delete it afterwards.
+ */
diff --git a/src/lib/dhcpsrv/dhcpdb_create.mysql b/src/lib/dhcpsrv/dhcpdb_create.mysql
new file mode 100644
index 0000000..7a292ec
--- /dev/null
+++ b/src/lib/dhcpsrv/dhcpdb_create.mysql
@@ -0,0 +1,115 @@
+# Copyright (C) 2012 Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and 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 INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM 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.
+
+# This is the BIND 10 DHCP schema specification for MySQL.
+#
+# The schema is reasonably portable (with the exception of the engine
+# specification, which is MySQL-specific). Minor changes might be needed for
+# other databases.
+
+# To create the schema, either type the command:
+#
+# mysql -u <user> -p <password> <database> < dhcpdb_create.mysql
+#
+# ... at the command prompt, or log in to the MySQL database and at the "mysql>"
+# prompt, issue the command:
+#
+# source dhcpdb_create.mysql
+
+
+# Holds the IPv4 leases.
+CREATE TABLE lease4 (
+ address INT UNSIGNED PRIMARY KEY NOT NULL, # IPv4 address
+ hwaddr VARBINARY(20), # Hardware address
+ client_id VARBINARY(128), # Client ID
+ lease_time INT UNSIGNED, # Length of the lease (seconds)
+ expire TIMESTAMP, # Expiration time of the lease
+ subnet_id INT UNSIGNED # Subnet identification
+ ) ENGINE = INNODB;
+
+# Holds the IPv6 leases.
+# N.B. The use of a VARCHAR for the address is temporary for development:
+# it will eventually be replaced by BINARY(16).
+CREATE TABLE lease6 (
+ address VARCHAR(40) PRIMARY KEY NOT NULL, # IPv6 address
+ duid VARBINARY(128), # DUID
+ valid_lifetime INT UNSIGNED, # Length of the lease (seconds)
+ expire TIMESTAMP, # Expiration time of the lease
+ subnet_id INT UNSIGNED, # Subnet identification
+ pref_lifetime INT UNSIGNED, # Preferred lifetime
+ lease_type TINYINT, # Lease type (see lease6_types
+ # table for possible values)
+ iaid INT UNSIGNED, # See Section 10 of RFC 3315
+ prefix_len TINYINT UNSIGNED # For IA_PD only
+ ) ENGINE = INNODB;
+
+# ... and a definition of lease6 types. This table is a convenience for
+# users of the database - if they want to view the lease table and use the
+# type names, they can join this table with the lease6 table
+CREATE TABLE lease6_types (
+ lease_type TINYINT PRIMARY KEY NOT NULL, # Lease type code.
+ name VARCHAR(5) # Name of the lease type
+ );
+START TRANSACTION;
+INSERT INTO lease6_types VALUES (0, "IA_NA"); # Non-temporary v6 addresses
+INSERT INTO lease6_types VALUES (1, "IA_TA"); # Temporary v6 addresses
+INSERT INTO lease6_types VALUES (2, "IA_PD"); # Prefix delegations
+COMMIT;
+
+# Finally, the version of the schema. We start at 0.1 during development.
+# This table is only modified during schema upgrades. For historical reasons
+# (related to the names of the columns in the BIND 10 DNS database file), the
+# first column is called "version" and not "major".
+CREATE TABLE schema_version (
+ version INT PRIMARY KEY NOT NULL, # Major version number
+ minor INT # Minor version number
+ );
+START TRANSACTION;
+INSERT INTO schema_version VALUES (0, 1);
+COMMIT;
+
+# Notes:
+#
+# Indexes
+# =======
+# It is likely that additional indexes will be needed. However, the
+# increase in lookup performance from these will come at the expense
+# of a decrease in performance during insert operations due to the need
+# to update the indexes. For this reason, the need for additional indexes
+# will be determined by experiment during performance tests.
+#
+# The most likely additional indexes will cover the following columns:
+#
+# expire
+# To speed up the deletion of expired leases from the database.
+#
+# hwaddr and client_id
+# For lease stability: if a client requests a new lease, try to find an
+# existing or recently expired lease for it so that it can keep using the
+# same IP address.
+#
+# Field Sizes
+# ===========
+# If any of the VARxxx field sizes are altered, the lengths in the MySQL
+# backend source file (mysql_lease_mgr.cc) must be correspondingly changed.
+#
+# Portability
+# ===========
+# The "ENGINE = INNODB" on some tables is not portablea to another database
+# and will need to be removed.
+#
+# Some columns contain binary data so are stored as VARBINARY instead of
+# VARCHAR. This may be non-portable between databases: in this case, the
+# definition should be changed to VARCHAR.
diff --git a/src/lib/dhcpsrv/lease_mgr.cc b/src/lib/dhcpsrv/lease_mgr.cc
new file mode 100644
index 0000000..5f4dc2f
--- /dev/null
+++ b/src/lib/dhcpsrv/lease_mgr.cc
@@ -0,0 +1,98 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dhcpsrv/lease_mgr.h>
+#include <exceptions/exceptions.h>
+
+#include <boost/foreach.hpp>
+#include <boost/algorithm/string.hpp>
+
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+#include <map>
+#include <sstream>
+#include <string>
+
+#include <time.h>
+
+using namespace std;
+
+using namespace isc::dhcp;
+
+Lease6::Lease6(LeaseType type, const isc::asiolink::IOAddress& addr, DuidPtr duid,
+ uint32_t iaid, uint32_t preferred, uint32_t valid, uint32_t t1,
+ uint32_t t2, SubnetID subnet_id, uint8_t prefixlen)
+ :type_(type), addr_(addr), prefixlen_(prefixlen), iaid_(iaid), duid_(duid),
+ preferred_lft_(preferred), valid_lft_(valid), t1_(t1), t2_(t2),
+ subnet_id_(subnet_id), fixed_(false), fqdn_fwd_(false),
+ fqdn_rev_(false) {
+ if (!duid) {
+ isc_throw(InvalidOperation, "DUID must be specified for a lease");
+ }
+
+ cltt_ = time(NULL);
+}
+
+std::string LeaseMgr::getParameter(const std::string& name) const {
+ ParameterMap::const_iterator param = parameters_.find(name);
+ if (param == parameters_.end()) {
+ isc_throw(BadValue, "Parameter not found");
+ }
+ return (param->second);
+}
+
+std::string
+Lease6::toText() {
+ ostringstream stream;
+
+ stream << "Type: " << static_cast<int>(type_) << " (";
+ switch (type_) {
+ case Lease6::LEASE_IA_NA:
+ stream << "IA_NA)\n";
+ break;
+ case Lease6::LEASE_IA_TA:
+ stream << "IA_TA)\n";
+ break;
+ case Lease6::LEASE_IA_PD:
+ stream << "IA_PD)\n";
+ break;
+ default:
+ stream << "unknown)\n";
+ }
+ stream << "Address: " << addr_.toText() << "\n"
+ << "Prefix length: " << static_cast<int>(prefixlen_) << "\n"
+ << "IAID: " << iaid_ << "\n"
+ << "Pref life: " << preferred_lft_ << "\n"
+ << "Valid life: " << valid_lft_ << "\n"
+ << "Cltt: " << cltt_ << "\n"
+ << "Subnet ID: " << subnet_id_ << "\n";
+
+ return (stream.str());
+}
+
+bool
+Lease6::operator==(const Lease6& other) const {
+ return (
+ type_ == other.type_ &&
+ addr_ == other.addr_ &&
+ prefixlen_ == other.prefixlen_ &&
+ iaid_ == other.iaid_ &&
+ *duid_ == *other.duid_ &&
+ preferred_lft_ == other.preferred_lft_ &&
+ valid_lft_ == other.valid_lft_ &&
+ cltt_ == other.cltt_ &&
+ subnet_id_ == other.subnet_id_
+ );
+}
diff --git a/src/lib/dhcpsrv/lease_mgr.h b/src/lib/dhcpsrv/lease_mgr.h
new file mode 100644
index 0000000..0e1f8d8
--- /dev/null
+++ b/src/lib/dhcpsrv/lease_mgr.h
@@ -0,0 +1,577 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef LEASE_MGR_H
+#define LEASE_MGR_H
+
+#include <asiolink/io_address.h>
+#include <dhcp/duid.h>
+#include <dhcp/option.h>
+#include <dhcpsrv/subnet.h>
+#include <exceptions/exceptions.h>
+
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <fstream>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+/// @file dhcp/lease_mgr.h
+/// @brief An abstract API for lease database
+///
+/// This file contains declarations of Lease4, Lease6 and LeaseMgr classes.
+/// They are essential components of the interface to any database backend.
+/// Each concrete database backend (e.g. MySQL) will define a class derived
+/// from LeaseMgr class.
+///
+/// Failover considerations:
+/// There are no intermediate plans to implement DHCPv4 failover
+/// (draft-ietf-dhc-failover-12.txt). Currently (Oct. 2012) the DHCPv6 failover
+/// is being defined in DHC WG in IETF (draft-ietf-dhcpv6-failover-requirements,
+/// draft-ietf-dhcpv6-dailover-design), but the work is not advanced enough
+/// for implementation plans yet. v4 failover requires additional parameters
+/// to be kept with a lease. It is likely that v6 failover will require similar
+/// fields. Such implementation will require database schema extension.
+/// We have designed a way to expand/upgrade schemas during upgrades: a database
+/// schema is versioned and sanity checks about required version will be done
+/// upon start and/or upgrade. With this mechanism in place, we can add new
+/// fields to the database. In particular we can use that capability to
+/// introduce failover related fields.
+///
+/// However, there is another approach that can be reliably used to provide
+/// failover, even without the actual failover protocol implemented. As the
+/// first backend will use MySQL, we will be able to use Multi-Master capability
+/// offered by MySQL and use two separatate Kea instances connecting to the
+/// same database.
+///
+/// Nevertheless, we hope to have failover protocol eventually implemented in
+/// the Kea.
+
+#include <iostream>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Exception thrown if name of database is not specified
+class NoDatabaseName : public Exception {
+public:
+ NoDatabaseName(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) {}
+};
+
+/// @brief Exception thrown on failure to open database
+class DbOpenError : public Exception {
+public:
+ DbOpenError(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) {}
+};
+
+/// @brief Exception thrown on failure to execute a database function
+class DbOperationError : public Exception {
+public:
+ DbOperationError(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) {}
+};
+
+/// @brief Attempt to update lease that was not there
+class NoSuchLease : public Exception {
+public:
+ NoSuchLease(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) {}
+};
+
+/// @brief Structure that holds a lease for IPv4 address
+///
+/// For performance reasons it is a simple structure, not a class. If we chose
+/// make it a class, all fields would have to made private and getters/setters
+/// would be required. As this is a critical part of the code that will be used
+/// extensively, direct access is warranted.
+struct Lease4 {
+ /// IPv4 address
+ isc::asiolink::IOAddress addr_;
+
+ /// @brief Address extension
+ ///
+ /// It is envisaged that in some cases IPv4 address will be accompanied with some
+ /// additional data. One example of such use are Address + Port solutions (or
+ /// Port-restricted Addresses), where several clients may get the same address, but
+ /// different port ranges. This feature is not expected to be widely used.
+ /// Under normal circumstances, the value should be 0.
+ uint32_t ext_;
+
+ /// @brief hardware address
+ std::vector<uint8_t> hwaddr_;
+
+ /// @brief client identifier
+ boost::shared_ptr<ClientId> client_id_;
+
+ /// @brief renewal timer
+ ///
+ /// Specifies renewal time. Although technically it is a property of IA container,
+ /// not the address itself, since our data model does not define separate IA
+ /// entity, we are keeping it in the lease. In case of multiple addresses/prefixes
+ /// for the same IA, each must have consistent T1 and T2 values. Specified in
+ /// seconds since cltt.
+ uint32_t t1_;
+
+ /// @brief rebinding timer
+ ///
+ /// Specifies rebinding time. Although technically it is a property of IA container,
+ /// not the address itself, since our data model does not define separate IA
+ /// entity, we are keeping it in the lease. In case of multiple addresses/prefixes
+ /// for the same IA, each must have consistent T1 and T2 values. Specified in
+ /// seconds since cltt.
+ uint32_t t2_;
+
+ /// @brief valid lifetime
+ ///
+ /// Expressed as number of seconds since cltt
+ uint32_t valid_lft_;
+
+ /// @brief client last transmission time
+ ///
+ /// Specifies a timestamp, when last transmission from a client was received.
+ time_t cltt_;
+
+ /// @brief Subnet identifier
+ ///
+ /// Specifies subnet-id of the subnet that the lease belongs to
+ SubnetID subnet_id_;
+
+ /// @brief Is this a fixed lease?
+ ///
+ /// Fixed leases are kept after they are released/expired.
+ bool fixed_;
+
+ /// @brief client hostname
+ ///
+ /// This field may be empty
+ std::string hostname_;
+
+ /// @brief did we update AAAA record for this lease?
+ bool fqdn_fwd_;
+
+ /// @brief did we update PTR record for this lease?
+ bool fqdn_rev_;
+
+ /// @brief Lease comments.
+ ///
+ /// Currently not used. It may be used for keeping comments made by the
+ /// system administrator.
+ std::string comments_;
+
+ /// @todo: Add DHCPv4 failover related fields here
+
+ /// @brief Constructor
+ ///
+ /// Initialize fields that don't have a default constructor.
+ /// @todo Remove this
+ Lease4() : addr_(0) {}
+};
+
+/// @brief Pointer to a Lease4 structure.
+typedef boost::shared_ptr<Lease4> Lease4Ptr;
+
+/// @brief A collection of IPv4 leases.
+typedef std::vector< boost::shared_ptr<Lease4Ptr> > Lease4Collection;
+
+/// @brief Structure that holds a lease for IPv6 address and/or prefix
+///
+/// For performance reasons it is a simple structure, not a class. Had we chose to
+/// make it a class, all fields would have to be made private and getters/setters
+/// would be required. As this is a critical part of the code that will be used
+/// extensively, direct access rather than through getters/setters is warranted.
+struct Lease6 {
+ typedef enum {
+ LEASE_IA_NA, /// the lease contains non-temporary IPv6 address
+ LEASE_IA_TA, /// the lease contains temporary IPv6 address
+ LEASE_IA_PD /// the lease contains IPv6 prefix (for prefix delegation)
+ } LeaseType;
+
+ Lease6(LeaseType type, const isc::asiolink::IOAddress& addr, DuidPtr duid,
+ uint32_t iaid, uint32_t preferred, uint32_t valid, uint32_t t1,
+ uint32_t t2, SubnetID subnet_id, uint8_t prefixlen_ = 0);
+
+ /// @brief specifies lease type (normal addr, temporary addr, prefix)
+ LeaseType type_;
+
+ /// IPv6 address
+ isc::asiolink::IOAddress addr_;
+
+ /// IPv6 prefix length (used only for PD)
+ uint8_t prefixlen_;
+
+ /// @brief IAID
+ ///
+ /// Identity Association IDentifier. DHCPv6 stores all addresses and prefixes
+ /// in IA containers (IA_NA, IA_TA, IA_PD). Most containers may appear more
+ /// than once in a message. To differentiate between them, IAID field is present
+ uint32_t iaid_;
+
+ /// @brief client identifier
+ boost::shared_ptr<DUID> duid_;
+
+ /// @brief preferred lifetime
+ ///
+ /// This parameter specifies preferred lifetime since the lease was assigned/renewed
+ /// (cltt), expressed in seconds.
+ uint32_t preferred_lft_;
+
+ /// @brief valid lifetime
+ ///
+ /// This parameter specified valid lifetime since the lease was assigned/renewed
+ /// (cltt), expressed in seconds.
+ uint32_t valid_lft_;
+
+ /// @brief T1 timer
+ ///
+ /// Specifies renewal time. Although technically it is a property of IA container,
+ /// not the address itself, since our data model does not define separate IA
+ /// entity, we are keeping it in the lease. In case of multiple addresses/prefixes
+ /// for the same IA, each must have consistent T1 and T2 values. Specified in
+ /// seconds since cltt.
+ /// This value will also be useful for failover to calculate the next expected
+ /// client transmission time.
+ uint32_t t1_;
+
+ /// @brief T2 timer
+ ///
+ /// Specifies rebinding time. Although technically it is a property of IA container,
+ /// not the address itself, since our data model does not define separate IA
+ /// entity, we are keeping it in the lease. In case of multiple addresses/prefixes
+ /// for the same IA, each must have consistent T1 and T2 values. Specified in
+ /// seconds since cltt.
+ uint32_t t2_;
+
+ /// @brief client last transmission time
+ ///
+ /// Specifies a timestamp, when last transmission from a client was received.
+ time_t cltt_;
+
+ /// @brief Subnet identifier
+ ///
+ /// Specifies subnet-id of the subnet that the lease belongs to
+ SubnetID subnet_id_;
+
+ /// @brief Is this a fixed lease?
+ ///
+ /// Fixed leases are kept after they are released/expired.
+ bool fixed_;
+
+ /// @brief client hostname
+ ///
+ /// This field may be empty
+ std::string hostname_;
+
+ /// @brief did we update AAAA record for this lease?
+ bool fqdn_fwd_;
+
+ /// @brief did we update PTR record for this lease?
+ bool fqdn_rev_;
+
+ /// @brief Lease comments
+ ///
+ /// This field is currently not used.
+ std::string comments_;
+
+ /// @todo: Add DHCPv6 failover related fields here
+
+ /// @brief Constructor
+ ///
+ /// Initialize fields that don't have a default constructor.
+ Lease6() : addr_("::") {}
+
+ /// @brief Convert Lease6 to Printable Form
+ ///
+ /// @return String form of the lease
+ std::string toText();
+
+ /// @brief Compare two leases for equality
+ ///
+ /// @param other lease6 object with which to compare
+ bool operator==(const Lease6& other) const;
+
+ /// @brief Compare two leases for inequality
+ ///
+ /// @param other lease6 object with which to compare
+ bool operator!=(const Lease6& other) const {
+ return (!operator==(other));
+ }
+
+};
+
+/// @brief Pointer to a Lease6 structure.
+typedef boost::shared_ptr<Lease6> Lease6Ptr;
+
+/// @brief Const pointer to a Lease6 structure.
+typedef boost::shared_ptr<const Lease6> ConstLease6Ptr;
+
+/// @brief A collection of IPv6 leases.
+typedef std::vector<Lease6Ptr> Lease6Collection;
+
+/// @brief Abstract Lease Manager
+///
+/// This is an abstract API for lease database backends. It provides unified
+/// interface to all backends. As this is an abstract class, it should not
+/// 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.
+class LeaseMgr {
+public:
+ /// Client Hardware address
+ typedef std::vector<uint8_t> HWAddr;
+
+ /// Database configuration parameter map
+ typedef std::map<std::string, std::string> ParameterMap;
+
+ /// @brief Constructor
+ ///
+ /// @param parameters A data structure relating keywords and values
+ /// concerned with the database.
+ LeaseMgr(const ParameterMap& parameters) : parameters_(parameters)
+ {}
+
+ /// @brief Destructor
+ virtual ~LeaseMgr()
+ {}
+
+ /// @brief Adds an IPv4 lease.
+ ///
+ /// @param lease lease to be added
+ ///
+ /// @result true if the lease was added, false if not (because a lease
+ /// with the same address was already there).
+ virtual bool addLease(const Lease4Ptr& lease) = 0;
+
+ /// @brief Adds an IPv6 lease.
+ ///
+ /// @param lease lease to be added
+ ///
+ /// @result true if the lease was added, false if not (because a lease
+ /// with the same address was already there).
+ virtual bool addLease(const Lease6Ptr& lease) = 0;
+
+ /// @brief Returns IPv4 lease for specified IPv4 address and subnet_id
+ ///
+ /// This method is used to get a lease for specific subnet_id. There can be
+ /// at most one lease for any given subnet, so this method returns a single
+ /// pointer.
+ ///
+ /// @param addr address of the searched lease
+ /// @param subnet_id ID of the subnet the lease must belong to
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr,
+ SubnetID subnet_id) const = 0;
+
+ /// @brief Returns an IPv4 lease for specified IPv4 address
+ ///
+ /// This method return a lease that is associated with a given address.
+ /// For other query types (by hardware addr, by client-id) there can be
+ /// several leases in different subnets (e.g. for mobile clients that
+ /// got address in different subnets). However, for a single address
+ /// there can be only one lease, so this method returns a pointer to
+ /// a single lease, not a container of leases.
+ ///
+ /// @param addr address of the searched lease
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr) const = 0;
+
+ /// @brief Returns existing IPv4 leases for specified hardware address.
+ ///
+ /// Although in the usual case there will be only one lease, for mobile
+ /// clients or clients with multiple static/fixed/reserved leases there
+ /// can be more than one. Thus return type is a container, not a single
+ /// pointer.
+ ///
+ /// @param hwaddr hardware address of the client
+ ///
+ /// @return lease collection
+ virtual Lease4Collection getLease4(const HWAddr& hwaddr) const = 0;
+
+ /// @brief Returns existing IPv4 leases for specified hardware address
+ /// and a subnet
+ ///
+ /// There can be at most one lease for a given HW address in a single
+ /// pool, so this method with either return a single lease or NULL.
+ ///
+ /// @param hwaddr hardware address of the client
+ /// @param subnet_id identifier of the subnet that lease must belong to
+ ///
+ /// @return a pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(const HWAddr& hwaddr,
+ SubnetID subnet_id) const = 0;
+
+ /// @brief Returns existing IPv4 lease for specified client-id
+ ///
+ /// Although in the usual case there will be only one lease, for mobile
+ /// clients or clients with multiple static/fixed/reserved leases there
+ /// can be more than one. Thus return type is a container, not a single
+ /// pointer.
+ ///
+ /// @param clientid client identifier
+ ///
+ /// @return lease collection
+ virtual Lease4Collection getLease4(const ClientId& clientid) const = 0;
+
+ /// @brief Returns existing IPv4 lease for specified client-id
+ ///
+ /// There can be at most one lease for a given HW address in a single
+ /// pool, so this method with either return a single lease or NULL.
+ ///
+ /// @param clientid client identifier
+ /// @param subnet_id identifier of the subnet that lease must belong to
+ ///
+ /// @return a pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(const ClientId& clientid,
+ SubnetID subnet_id) const = 0;
+
+ /// @brief Returns existing IPv6 lease for a given IPv6 address.
+ ///
+ /// For a given address, we assume that there will be only one lease.
+ /// The assumtion here is that there will not be site or link-local
+ /// addresses used, so there is no way of having address duplication.
+ ///
+ /// @param addr address of the searched lease
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease6Ptr getLease6(const isc::asiolink::IOAddress& addr) const = 0;
+
+ /// @brief Returns existing IPv6 leases for a given DUID+IA combination
+ ///
+ /// Although in the usual case there will be only one lease, for mobile
+ /// clients or clients with multiple static/fixed/reserved leases there
+ /// can be more than one. Thus return type is a container, not a single
+ /// pointer.
+ ///
+ /// @param duid client DUID
+ /// @param iaid IA identifier
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease6Collection getLease6(const DUID& duid,
+ uint32_t iaid) const = 0;
+
+ /// @brief Returns existing IPv6 lease for a given DUID+IA combination
+ ///
+ /// @param duid client DUID
+ /// @param iaid IA identifier
+ /// @param subnet_id subnet id of the subnet the lease belongs to
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease6Ptr getLease6(const DUID& duid, uint32_t iaid,
+ SubnetID subnet_id) const = 0;
+
+ /// @brief Updates IPv4 lease.
+ ///
+ /// @param lease4 The lease to be updated.
+ ///
+ /// If no such lease is present, an exception will be thrown.
+ virtual void updateLease4(const Lease4Ptr& lease4) = 0;
+
+ /// @brief Updates IPv6 lease.
+ ///
+ /// @param lease6 The lease to be updated.
+ virtual void updateLease6(const Lease6Ptr& lease6) = 0;
+
+ /// @brief Deletes a lease.
+ ///
+ /// @param addr IPv4 address of the lease to be deleted.
+ ///
+ /// @return true if deletion was successful, false if no such lease exists
+ virtual bool deleteLease4(const isc::asiolink::IOAddress& addr) = 0;
+
+ /// @brief Deletes a lease.
+ ///
+ /// @param addr IPv6 address of the lease to be deleted.
+ ///
+ /// @return true if deletion was successful, false if no such lease exists
+ virtual bool deleteLease6(const isc::asiolink::IOAddress& addr) = 0;
+
+ /// @brief Return backend type
+ ///
+ /// Returns the type of the backend (e.g. "mysql", "memfile" etc.)
+ ///
+ /// @return Type of the backend.
+ virtual std::string getType() const = 0;
+
+ /// @brief Returns backend name.
+ ///
+ /// If the backend is a database, this is the name of the database or the
+ /// file. Otherwise it is just the same as the type.
+ ///
+ /// @return Name of the backend.
+ virtual std::string getName() const = 0;
+
+ /// @brief Returns description of the backend.
+ ///
+ /// This description may be multiline text that describes the backend.
+ ///
+ /// @return Description of the backend.
+ virtual std::string getDescription() const = 0;
+
+ /// @brief Returns backend version.
+ ///
+ /// @return Version number as a pair of unsigned integers. "first" is the
+ /// major version number, "second" the minor number.
+ ///
+ /// @todo: We will need to implement 3 version functions eventually:
+ /// A. abstract API version
+ /// B. backend version
+ /// C. database version (stored in the database scheme)
+ ///
+ /// and then check that:
+ /// B>=A and B=C (it is ok to have newer backend, as it should be backward
+ /// compatible)
+ /// Also if B>C, some database upgrade procedure may be triggered
+ virtual std::pair<uint32_t, uint32_t> getVersion() const = 0;
+
+ /// @brief Commit Transactions
+ ///
+ /// Commits all pending database operations. On databases that don't
+ /// support transactions, this is a no-op.
+ virtual void commit() = 0;
+
+ /// @brief Rollback Transactions
+ ///
+ /// Rolls back all pending database operations. On databases that don't
+ /// support transactions, this is a no-op.
+ virtual void rollback() = 0;
+
+ /// @todo: Add host management here
+ /// As host reservation is outside of scope for 2012, support for hosts
+ /// is currently postponed.
+
+ /// @brief returns value of the parameter
+ virtual std::string getParameter(const std::string& name) const;
+
+private:
+ /// @brief list of parameters passed in dbconfig
+ ///
+ /// That will be mostly used for storing database name, username,
+ /// password and other parameters required for DB access. It is not
+ /// intended to keep any DHCP-related parameters.
+ ParameterMap parameters_;
+};
+
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
+
+#endif // LEASE_MGR_H
diff --git a/src/lib/dhcpsrv/lease_mgr_factory.cc b/src/lib/dhcpsrv/lease_mgr_factory.cc
new file mode 100644
index 0000000..47c53ed
--- /dev/null
+++ b/src/lib/dhcpsrv/lease_mgr_factory.cc
@@ -0,0 +1,117 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include "config.h"
+
+#include <dhcpsrv/lease_mgr_factory.h>
+#include <dhcpsrv/memfile_lease_mgr.h>
+#ifdef HAVE_MYSQL
+#include <dhcpsrv/mysql_lease_mgr.h>
+#endif
+
+#include <boost/algorithm/string.hpp>
+#include <boost/foreach.hpp>
+#include <boost/scoped_ptr.hpp>
+
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+#include <map>
+#include <sstream>
+#include <utility>
+
+using namespace std;
+
+namespace isc {
+namespace dhcp {
+
+boost::scoped_ptr<LeaseMgr>&
+LeaseMgrFactory::getLeaseMgrPtr() {
+ static boost::scoped_ptr<LeaseMgr> leaseMgrPtr;
+ return (leaseMgrPtr);
+}
+
+LeaseMgr::ParameterMap
+LeaseMgrFactory::parse(const std::string& dbconfig) {
+ LeaseMgr::ParameterMap mapped_tokens;
+
+ if (!dbconfig.empty()) {
+ vector<string> tokens;
+
+ // We need to pass a string to is_any_of, not just char*. Otherwise
+ // there are cryptic warnings on Debian6 running g++ 4.4 in
+ // /usr/include/c++/4.4/bits/stl_algo.h:2178 "array subscript is above
+ // array bounds"
+ boost::split(tokens, dbconfig, boost::is_any_of( string("\t ") ));
+ BOOST_FOREACH(std::string token, tokens) {
+ size_t pos = token.find("=");
+ if (pos != string::npos) {
+ string name = token.substr(0, pos);
+ string value = token.substr(pos + 1);
+ mapped_tokens.insert(make_pair(name, value));
+ } else {
+ isc_throw(InvalidParameter, "Cannot parse " << token
+ << ", expected format is name=value");
+ }
+ }
+ }
+
+ return (mapped_tokens);
+}
+
+void
+LeaseMgrFactory::create(const std::string& dbconfig) {
+ const std::string type = "type";
+
+ // Is "type" present?
+ LeaseMgr::ParameterMap parameters = parse(dbconfig);
+ if (parameters.find(type) == parameters.end()) {
+ isc_throw(InvalidParameter, "Database configuration parameters do not "
+ "contain the 'type' keyword");
+ }
+
+ // Yes, check what it is.
+#ifdef HAVE_MYSQL
+ if (parameters[type] == string("mysql")) {
+ getLeaseMgrPtr().reset(new MySqlLeaseMgr(parameters));
+ return;
+ }
+#endif
+ if (parameters[type] == string("memfile")) {
+ getLeaseMgrPtr().reset(new Memfile_LeaseMgr(parameters));
+ return;
+ }
+
+ // Get here on no match
+ isc_throw(InvalidType, "Database configuration parameter 'type' does "
+ "not specify a supported database backend");
+}
+
+void
+LeaseMgrFactory::destroy() {
+ getLeaseMgrPtr().reset();
+}
+
+LeaseMgr&
+LeaseMgrFactory::instance() {
+ LeaseMgr* lmptr = getLeaseMgrPtr().get();
+ if (lmptr == NULL) {
+ isc_throw(NoLeaseManager, "no current lease manager is available");
+ }
+ return (*lmptr);
+}
+
+
+}; // namespace dhcp
+}; // namespace isc
diff --git a/src/lib/dhcpsrv/lease_mgr_factory.h b/src/lib/dhcpsrv/lease_mgr_factory.h
new file mode 100644
index 0000000..338c941
--- /dev/null
+++ b/src/lib/dhcpsrv/lease_mgr_factory.h
@@ -0,0 +1,124 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef LEASE_MGR_FACTORY_H
+#define LEASE_MGR_FACTORY_H
+
+#include <dhcpsrv/lease_mgr.h>
+#include <exceptions/exceptions.h>
+
+#include <string>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Invalid type exception
+///
+/// Thrown when the factory doesn't recognise the type of the backend.
+class InvalidType : public Exception {
+public:
+ InvalidType(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) {}
+};
+
+/// @brief No lease manager exception
+///
+/// Thrown if an attempt is made to get a reference to the current lease
+/// manager and none is currently available.
+class NoLeaseManager : public Exception {
+public:
+ NoLeaseManager(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) {}
+};
+
+/// @brief Lease Manager Factory
+///
+/// This class comprises nothing but static methods used to create a lease
+/// manager. It analyzes the database information passed to the creation
+/// function and instantiates an appropriate lease manager based on the type
+/// requested.
+///
+/// Strictly speaking these functions could be stand-alone functions. However,
+/// it is convenient to encapsulate them in a class for naming purposes.
+///
+/// @todo: Will need to develop some form of registration mechanism for
+/// user-supplied backends (so that there is no need to modify the code).
+class LeaseMgrFactory {
+public:
+ /// @brief Create an instance of a lease manager.
+ ///
+ /// Each database backend has its own lease manager type. This static
+ /// method sets the "current" lease manager to be a manager of the
+ /// appropriate type. The actual lease manager is returned by the
+ /// "instance" method.
+ ///
+ /// @note When called, the current lease manager is <b>always</b> destroyed
+ /// and a new one created - even if the parameters are the same.
+ ///
+ /// dbconfig is a generic way of passing parameters. Parameters are passed
+ /// in the "name=value" format, separated by spaces. The data MUST include
+ /// a keyword/value pair of the form "type=dbtype" giving the database
+ /// type, e.q. "mysql" or "sqlite3".
+ ///
+ /// @param dbconfig Database configuration parameters. These are in
+ /// the form of "keyword=value" pairs, separated by spaces. These
+ /// are back-end specific, although must include the "type" keyword
+ /// which gives the backend in use.
+ ///
+ /// @throw isc::InvalidParameter dbconfig string does not contain the "type"
+ /// keyword.
+ /// @throw isc::dhcp::InvalidType The "type" keyword in dbconfig does not
+ /// identify a supported backend.
+ static void create(const std::string& dbconfig);
+
+ /// @brief Destroy lease manager
+ ///
+ /// Destroys the current lease manager object. This should have the effect
+ /// of closing the database connection. The method is a no-op if no
+ /// lease manager is available.
+ static void destroy();
+
+ /// @brief Return Current Lease Manager
+ ///
+ /// Returns an instance of the "current" lease manager. An exception
+ /// will be thrown if none is available.
+ ///
+ /// @throw isc::dhcp::NoLeaseManager No lease manager is available: use
+ /// create() to create one before calling this method.
+ static LeaseMgr& instance();
+
+ /// @brief Parse Database Parameters
+ ///
+ /// Parses the string of "keyword=value" pairs and separates them
+ /// out into the map.
+ ///
+ /// @param dbconfig Database configuration string
+ ///
+ /// @return std::map<std::string, std::string> Map of keyword/value pairs.
+ static LeaseMgr::ParameterMap parse(const std::string& dbconfig);
+
+private:
+ /// @brief Hold pointer to lease manager
+ ///
+ /// Holds a pointer to the singleton lease manager. The singleton
+ /// is encapsulated in this method to avoid a "static initialization
+ /// fiasco" if defined in an external static variable.
+ static boost::scoped_ptr<LeaseMgr>& getLeaseMgrPtr();
+
+};
+
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
+
+#endif // LEASE_MGR_FACTORY_H
diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.cc b/src/lib/dhcpsrv/memfile_lease_mgr.cc
new file mode 100644
index 0000000..8a59b73
--- /dev/null
+++ b/src/lib/dhcpsrv/memfile_lease_mgr.cc
@@ -0,0 +1,132 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dhcpsrv/memfile_lease_mgr.h>
+
+#include <iostream>
+
+using namespace isc::dhcp;
+
+Memfile_LeaseMgr::Memfile_LeaseMgr(const ParameterMap& parameters)
+ : LeaseMgr(parameters) {
+ std::cout << "Warning: Using memfile database backend. It is usable for" << std::endl;
+ std::cout << "Warning: limited testing only. File support not implemented yet." << std::endl;
+ std::cout << "Warning: Leases will be lost after restart." << std::endl;
+}
+
+Memfile_LeaseMgr::~Memfile_LeaseMgr() {
+}
+
+bool Memfile_LeaseMgr::addLease(const Lease4Ptr&) {
+ return (false);
+}
+
+bool Memfile_LeaseMgr::addLease(const Lease6Ptr& lease) {
+ if (getLease6(lease->addr_)) {
+ // there is a lease with specified address already
+ return (false);
+ }
+ storage6_.insert(lease);
+ return (true);
+}
+
+Lease4Ptr Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress&) const {
+ return (Lease4Ptr());
+}
+
+Lease4Collection Memfile_LeaseMgr::getLease4(const HWAddr& ) const {
+ return (Lease4Collection());
+}
+
+Lease4Ptr Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress&,
+ SubnetID) const {
+ return (Lease4Ptr());
+}
+
+Lease4Ptr Memfile_LeaseMgr::getLease4(const HWAddr&,
+ SubnetID) const {
+ return (Lease4Ptr());
+}
+
+
+Lease4Ptr Memfile_LeaseMgr::getLease4(const ClientId&,
+ SubnetID) const {
+ return (Lease4Ptr());
+}
+
+Lease4Collection Memfile_LeaseMgr::getLease4(const ClientId& ) const {
+ return (Lease4Collection());
+}
+
+Lease6Ptr Memfile_LeaseMgr::getLease6(const isc::asiolink::IOAddress& addr) const {
+ Lease6Storage::iterator l = storage6_.find(addr);
+ if (l == storage6_.end()) {
+ return (Lease6Ptr());
+ } else {
+ return (*l);
+ }
+}
+
+Lease6Collection Memfile_LeaseMgr::getLease6(const DUID& , uint32_t ) const {
+ return (Lease6Collection());
+}
+
+Lease6Ptr Memfile_LeaseMgr::getLease6(const DUID& duid, uint32_t iaid,
+ SubnetID subnet_id) const {
+ /// @todo: Slow, naive implementation. Write it using additional indexes
+ for (Lease6Storage::iterator l = storage6_.begin(); l != storage6_.end(); ++l) {
+ if ( (*((*l)->duid_) == duid) &&
+ ( (*l)->iaid_ == iaid) &&
+ ( (*l)->subnet_id_ == subnet_id)) {
+ return (*l);
+ }
+ }
+ return (Lease6Ptr());
+}
+
+void Memfile_LeaseMgr::updateLease4(const Lease4Ptr& ) {
+}
+
+void Memfile_LeaseMgr::updateLease6(const Lease6Ptr& ) {
+
+}
+
+bool Memfile_LeaseMgr::deleteLease4(const isc::asiolink::IOAddress&) {
+ return (false);
+}
+
+bool Memfile_LeaseMgr::deleteLease6(const isc::asiolink::IOAddress& addr) {
+ Lease6Storage::iterator l = storage6_.find(addr);
+ if (l == storage6_.end()) {
+ // no such lease
+ return (false);
+ } else {
+ storage6_.erase(l);
+ return (true);
+ }
+}
+
+std::string Memfile_LeaseMgr::getDescription() const {
+ return (std::string("This is a dummy memfile backend implementation.\n"
+ "It does not offer any useful lease management and its only\n"
+ "purpose is to test abstract lease manager API."));
+}
+
+void
+Memfile_LeaseMgr::commit() {
+}
+
+void
+Memfile_LeaseMgr::rollback() {
+}
diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.h b/src/lib/dhcpsrv/memfile_lease_mgr.h
new file mode 100644
index 0000000..d9b40e5
--- /dev/null
+++ b/src/lib/dhcpsrv/memfile_lease_mgr.h
@@ -0,0 +1,258 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef MEMFILE_LEASE_MGR_H
+#define MEMFILE_LEASE_MGR_H
+
+#include <dhcpsrv/lease_mgr.h>
+
+#include <boost/multi_index/indexed_by.hpp>
+#include <boost/multi_index/member.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index_container.hpp>
+
+namespace isc {
+namespace dhcp {
+
+// This is a concrete implementation of a Lease database.
+//
+// It is for testing purposes only. It is NOT a production code.
+//
+// It does not do anything useful now, and is used for abstract LeaseMgr
+// class testing. It may later evolve into more useful backend if the
+// need arises. We can reuse code from memfile benchmark. See code in
+// tests/tools/dhcp-ubench/memfile_bench.{cc|h}
+class Memfile_LeaseMgr : public LeaseMgr {
+public:
+
+ /// @brief The sole lease manager constructor
+ ///
+ /// dbconfig is a generic way of passing parameters. Parameters
+ /// are passed in the "name=value" format, separated by spaces.
+ /// Values may be enclosed in double quotes, if needed.
+ ///
+ /// @param parameters A data structure relating keywords and values
+ /// concerned with the database.
+ Memfile_LeaseMgr(const ParameterMap& parameters);
+
+ /// @brief Destructor (closes file)
+ virtual ~Memfile_LeaseMgr();
+
+ /// @brief Adds an IPv4 lease.
+ ///
+ /// @todo Not implemented yet
+ /// @param lease lease to be added
+ virtual bool addLease(const Lease4Ptr& lease);
+
+ /// @brief Adds an IPv6 lease.
+ ///
+ /// @param lease lease to be added
+ virtual bool addLease(const Lease6Ptr& lease);
+
+ /// @brief Returns existing IPv4 lease for specified IPv4 address.
+ ///
+ /// @todo Not implemented yet
+ /// @param addr address of the searched lease
+ ///
+ /// @return a collection of leases
+ virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr) const;
+
+ /// @brief Returns existing IPv4 lease for specific address and subnet
+ ///
+ /// @todo Not implemented yet
+ /// @param addr address of the searched lease
+ /// @param subnet_id ID of the subnet the lease must belong to
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr,
+ SubnetID subnet_id) const;
+
+ /// @brief Returns existing IPv4 leases for specified hardware address.
+ ///
+ /// @todo Not implemented yet
+ ///
+ /// Although in the usual case there will be only one lease, for mobile
+ /// clients or clients with multiple static/fixed/reserved leases there
+ /// can be more than one. Thus return type is a container, not a single
+ /// pointer.
+ ///
+ /// @param hwaddr hardware address of the client
+ ///
+ /// @return lease collection
+ virtual Lease4Collection getLease4(const HWAddr& hwaddr) const;
+
+ /// @brief Returns existing IPv4 leases for specified hardware address
+ /// and a subnet
+ ///
+ /// @todo Not implemented yet
+ ///
+ /// There can be at most one lease for a given HW address in a single
+ /// pool, so this method with either return a single lease or NULL.
+ ///
+ /// @param hwaddr hardware address of the client
+ /// @param subnet_id identifier of the subnet that lease must belong to
+ ///
+ /// @return a pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(const HWAddr& hwaddr,
+ SubnetID subnet_id) const;
+
+ /// @brief Returns existing IPv4 lease for specified client-id
+ ///
+ /// @todo Not implemented yet
+ ///
+ /// @param clientid client identifier
+ virtual Lease4Collection getLease4(const ClientId& clientid) const;
+
+ /// @brief Returns existing IPv4 lease for specified client-id
+ ///
+ /// There can be at most one lease for a given HW address in a single
+ /// pool, so this method with either return a single lease or NULL.
+ ///
+ /// @todo Not implemented yet
+ ///
+ /// @param clientid client identifier
+ /// @param subnet_id identifier of the subnet that lease must belong to
+ ///
+ /// @return a pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(const ClientId& clientid,
+ SubnetID subnet_id) const;
+
+ /// @brief Returns existing IPv6 lease for a given IPv6 address.
+ ///
+ /// @param addr address of the searched lease
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease6Ptr getLease6(const isc::asiolink::IOAddress& addr) const;
+
+ /// @brief Returns existing IPv6 lease for a given DUID+IA combination
+ ///
+ /// @todo Not implemented yet
+ ///
+ /// @param duid client DUID
+ /// @param iaid IA identifier
+ ///
+ /// @return collection of IPv6 leases
+ virtual Lease6Collection getLease6(const DUID& duid, uint32_t iaid) const;
+
+ /// @brief Returns existing IPv6 lease for a given DUID+IA combination
+ ///
+ /// @todo Not implemented yet
+ ///
+ /// @param duid client DUID
+ /// @param iaid IA identifier
+ /// @param subnet_id identifier of the subnet the lease must belong to
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease6Ptr getLease6(const DUID& duid, uint32_t iaid, SubnetID subnet_id) const;
+
+ /// @brief Updates IPv4 lease.
+ ///
+ /// @todo Not implemented yet
+ ///
+ /// @param lease4 The lease to be updated.
+ ///
+ /// If no such lease is present, an exception will be thrown.
+ virtual void updateLease4(const Lease4Ptr& lease4);
+
+ /// @brief Updates IPv4 lease.
+ ///
+ /// @todo Not implemented yet
+ ///
+ /// @param lease6 The lease to be updated.
+ ///
+ /// If no such lease is present, an exception will be thrown.
+ virtual void updateLease6(const Lease6Ptr& lease6);
+
+ /// @brief Deletes a lease.
+ ///
+ /// @param addr IPv4 address of the lease to be deleted.
+ ///
+ /// @return true if deletion was successful, false if no such lease exists
+ virtual bool deleteLease4(const isc::asiolink::IOAddress& addr);
+
+ /// @brief Deletes a lease.
+ ///
+ /// @param addr IPv4 address of the lease to be deleted.
+ ///
+ /// @return true if deletion was successful, false if no such lease exists
+ virtual bool deleteLease6(const isc::asiolink::IOAddress& addr);
+
+ /// @brief Return backend type
+ ///
+ /// Returns the type of the backend.
+ ///
+ /// @return Type of the backend.
+ virtual std::string getType() const {
+ return (std::string("memfile"));
+ }
+
+ /// @brief Returns backend name.
+ ///
+ /// As there is no variation, in this case we return the type of the
+ /// backend.
+ ///
+ /// @return Name of the backend.
+ virtual std::string getName() const {
+ return ("memfile");
+ }
+
+ /// @brief Returns description of the backend.
+ ///
+ /// This description may be multiline text that describes the backend.
+ ///
+ /// @return Description of the backend.
+ virtual std::string getDescription() const;
+
+ /// @brief Returns backend version.
+ ///
+ /// @return Version number as a pair of unsigned integers. "first" is the
+ /// major version number, "second" the minor number.
+ virtual std::pair<uint32_t, uint32_t> getVersion() const {
+ return (std::make_pair(1, 0));
+ }
+
+ /// @brief Commit Transactions
+ ///
+ /// Commits all pending database operations. On databases that don't
+ /// support transactions, this is a no-op.
+ virtual void commit();
+
+ /// @brief Rollback Transactions
+ ///
+ /// Rolls back all pending database operations. On databases that don't
+ /// support transactions, this is a no-op.
+ virtual void rollback();
+
+protected:
+
+ typedef boost::multi_index_container< // this is a multi-index container...
+ Lease6Ptr, // it will hold shared_ptr to leases6
+ boost::multi_index::indexed_by< // and will be sorted by
+ // IPv6 address that are unique. That particular key is a member
+ // of the Lease6 structure, is of type IOAddress and can be accessed
+ // by doing &Lease6::addr_
+ boost::multi_index::ordered_unique<
+ boost::multi_index::member<Lease6, isc::asiolink::IOAddress, &Lease6::addr_>
+ >
+ >
+ > Lease6Storage; // Let the whole contraption be called Lease6Storage.
+
+ Lease6Storage storage6_;
+};
+
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
+
+#endif // MEMFILE_LEASE_MGR
+
diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.cc b/src/lib/dhcpsrv/mysql_lease_mgr.cc
new file mode 100644
index 0000000..a3387ac
--- /dev/null
+++ b/src/lib/dhcpsrv/mysql_lease_mgr.cc
@@ -0,0 +1,1140 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <asiolink/io_address.h>
+#include <dhcpsrv/mysql_lease_mgr.h>
+
+#include <mysql/mysqld_error.h>
+
+#include <iostream>
+#include <iomanip>
+#include <string>
+#include <time.h>
+
+using namespace isc;
+using namespace isc::dhcp;
+using namespace std;
+
+namespace {
+///@{
+/// @brief Maximum Size of Database Fields
+///
+/// The following constants define buffer sizes for variable length database
+/// fields. The values should be greater than or equal to the length set in
+/// the schema definition.
+///
+/// The exception is the length of any VARCHAR fields: these should be set
+/// greater than or equal to the length of the field plus 2: this allows for
+/// the insertion of a trailing null regardless of whether the data returned
+/// contains a trailing null (the documentation is not clear on this point).
+
+const size_t ADDRESS6_TEXT_MAX_LEN = 42; // Max size of a IPv6 text buffer
+const size_t DUID_MAX_LEN = 128; // Max size of a DUID
+///@}
+
+/// @brief MySQL Selection Statements
+///
+/// Each statement is associated with the index, used by the various methods
+/// to access the prepared statement.
+struct TaggedStatement {
+ MySqlLeaseMgr::StatementIndex index;
+ const char* text;
+};
+
+TaggedStatement tagged_statements[] = {
+ {MySqlLeaseMgr::DELETE_LEASE6,
+ "DELETE FROM lease6 WHERE address = ?"},
+ {MySqlLeaseMgr::GET_LEASE6_ADDR,
+ "SELECT address, duid, valid_lifetime, "
+ "expire, subnet_id, pref_lifetime, "
+ "lease_type, iaid, prefix_len "
+ "FROM lease6 "
+ "WHERE address = ?"},
+ {MySqlLeaseMgr::GET_LEASE6_DUID_IAID,
+ "SELECT address, duid, valid_lifetime, "
+ "expire, subnet_id, pref_lifetime, "
+ "lease_type, iaid, prefix_len "
+ "FROM lease6 "
+ "WHERE duid = ? AND iaid = ?"},
+ {MySqlLeaseMgr::GET_LEASE6_DUID_IAID_SUBID,
+ "SELECT address, duid, valid_lifetime, "
+ "expire, subnet_id, pref_lifetime, "
+ "lease_type, iaid, prefix_len "
+ "FROM lease6 "
+ "WHERE duid = ? AND iaid = ? AND subnet_id = ?"},
+ {MySqlLeaseMgr::GET_VERSION,
+ "SELECT version, minor FROM schema_version"},
+ {MySqlLeaseMgr::INSERT_LEASE6,
+ "INSERT INTO lease6(address, duid, valid_lifetime, "
+ "expire, subnet_id, pref_lifetime, "
+ "lease_type, iaid, prefix_len) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"},
+ {MySqlLeaseMgr::UPDATE_LEASE6,
+ "UPDATE lease6 SET address = ?, duid = ?, "
+ "valid_lifetime = ?, expire = ?, subnet_id = ?, "
+ "pref_lifetime = ?, lease_type = ?, iaid = ?, "
+ "prefix_len = ? "
+ "WHERE address = ?"},
+ // End of list sentinel
+ {MySqlLeaseMgr::NUM_STATEMENTS, NULL}
+};
+
+}; // Anonymous namespace
+
+namespace isc {
+namespace dhcp {
+
+
+
+/// @brief Exchange MySQL and Lease6 Data
+///
+/// On any MySQL operation, arrays of MYSQL_BIND structures must be built to
+/// describe the parameters in the prepared statements. Where information is
+/// inserted or retrieved - INSERT, UPDATE, SELECT - a large amount of that
+/// structure is identical - it defines data values in the Lease6 structure.
+/// This class handles the creation of that array.
+///
+/// Owing to the MySQL API, the process requires some intermediate variables
+/// to hold things like length etc. This object holds the intermediate
+/// variables as well.
+///
+/// @note There are no unit tests for this class. It is tested indirectly
+/// in all MySqlLeaseMgr::xxx6() calls where it is used.
+
+class MySqlLease6Exchange {
+public:
+ /// @brief Constructor
+ ///
+ /// Apart from the initialization of false_ and true_, the initialization
+ /// of addr6_length_, duid_length_, addr6_buffer_ and duid_buffer_ are
+ /// to satisfy cppcheck: none are really needed, as all variables are
+ /// initialized/set in the methods.
+ MySqlLease6Exchange() : addr6_length_(0), duid_length_(0),
+ false_(0), true_(1) {
+ memset(addr6_buffer_, 0, sizeof(addr6_buffer_));
+ memset(duid_buffer_, 0, sizeof(duid_buffer_));
+ }
+
+ /// @brief Create MYSQL_BIND objects for Lease6 Pointer
+ ///
+ /// Fills in the MYSQL_BIND objects for the Lease6 passed to it.
+ ///
+ /// @param lease Lease object to be added to the database.
+ ///
+ /// @return Vector of MySQL BIND objects representing the data to be added.
+ std::vector<MYSQL_BIND> createBindForSend(const Lease6Ptr& lease) {
+ // Store lease object to ensure it remains valid.
+ lease_ = lease;
+
+ // Ensure bind_ array clear for constructing the MYSQL_BIND structures
+ // for this lease.
+ memset(bind_, 0, sizeof(bind_));
+
+ // address: varchar(40)
+ addr6_ = lease_->addr_.toText();
+ addr6_length_ = addr6_.size();
+
+ // In the following statement, the string is being read. However, the
+ // MySQL C interface does not use "const", so the "buffer" element
+ // is declared as "char*" instead of "const char*". To resolve this,
+ // the "const" is discarded. (Note that the address of addr6_.c_str()
+ // is guaranteed to be valid until the next non-const operation on
+ // addr6_.)
+ //
+ // Note that the const_cast could be avoided by copying the string to
+ // a writeable buffer and storing the address of that in the "buffer"
+ // element. However, this introduces a copy operation (with additional
+ // overhead) purely to get round the strictures introduced by design of
+ // the MySQL interface (which uses the area pointed to by "buffer" as
+ // input when specifying query parameters and as output when retrieving
+ // data). For that reason, "const_cast" has been used.
+ bind_[0].buffer_type = MYSQL_TYPE_STRING;
+ bind_[0].buffer = const_cast<char*>(addr6_.c_str());
+ bind_[0].buffer_length = addr6_length_;
+ bind_[0].length = &addr6_length_;
+
+ // duid: varchar(128)
+ duid_ = lease_->duid_->getDuid();
+ duid_length_ = duid_.size();
+
+ bind_[1].buffer_type = MYSQL_TYPE_BLOB;
+ bind_[1].buffer = reinterpret_cast<char*>(&(duid_[0]));
+ bind_[1].buffer_length = duid_length_;
+ bind_[1].length = &duid_length_;
+
+ // valid lifetime: unsigned int
+ bind_[2].buffer_type = MYSQL_TYPE_LONG;
+ bind_[2].buffer = reinterpret_cast<char*>(&lease->valid_lft_);
+ bind_[2].is_unsigned = true_;
+
+ // expire: timestamp
+ // The lease structure holds the client last transmission time (cltt_)
+ // For convenience for external tools, this is converted to lease
+ /// expiry time (expire). The relationship is given by:
+ //
+ // expire = cltt_ + valid_lft_
+ //
+ // @TODO Handle overflows
+ MySqlLeaseMgr::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_,
+ expire_);
+ bind_[3].buffer_type = MYSQL_TYPE_TIMESTAMP;
+ bind_[3].buffer = reinterpret_cast<char*>(&expire_);
+ bind_[3].buffer_length = sizeof(expire_);
+
+ // subnet_id: unsigned int
+ // Can use lease_->subnet_id_ directly as it is of type uint32_t.
+ bind_[4].buffer_type = MYSQL_TYPE_LONG;
+ bind_[4].buffer = reinterpret_cast<char*>(&lease_->subnet_id_);
+ bind_[4].is_unsigned = true_;
+
+ // pref_lifetime: unsigned int
+ // Can use lease_->preferred_lft_ directly as it is of type uint32_t.
+ bind_[5].buffer_type = MYSQL_TYPE_LONG;
+ bind_[5].buffer = reinterpret_cast<char*>(&lease_->preferred_lft_);
+ bind_[5].is_unsigned = true_;
+
+ // lease_type: tinyint
+ // Must convert to uint8_t as lease_->type_ is a LeaseType variable
+ lease_type_ = lease_->type_;
+ bind_[6].buffer_type = MYSQL_TYPE_TINY;
+ bind_[6].buffer = reinterpret_cast<char*>(&lease_type_);
+ bind_[6].is_unsigned = true_;
+
+ // iaid: unsigned int
+ // Can use lease_->iaid_ directly as it is of type uint32_t.
+ bind_[7].buffer_type = MYSQL_TYPE_LONG;
+ bind_[7].buffer = reinterpret_cast<char*>(&lease_->iaid_);
+ bind_[7].is_unsigned = true_;
+
+ // prefix_len: unsigned tinyint
+ // Can use lease_->prefixlen_ directly as it is uint32_t.
+ bind_[8].buffer_type = MYSQL_TYPE_TINY;
+ bind_[8].buffer = reinterpret_cast<char*>(&lease_->prefixlen_);
+ bind_[8].is_unsigned = true_;
+
+ // Add the data to the vector. Note the end element is one after the
+ // end of the array.
+ return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[9]));
+ }
+
+ /// @brief Create BIND array to receive data
+ ///
+ /// Creates a MYSQL_BIND array to receive Lease6 data from the database.
+ /// After data is successfully received, getLeaseData() is used to copy
+ /// it to a Lease6 object.
+ ///
+ /// @return Vector of MySQL BIND objects.
+ std::vector<MYSQL_BIND> createBindForReceive() {
+
+ // Ensure both the array of MYSQL_BIND structures and the error array
+ // are clear.
+ memset(bind_, 0, sizeof(bind_));
+ memset(error_, 0, sizeof(error_));
+
+ // address: varchar
+ // A Lease6_ address has a maximum of 39 characters. The array is
+ // a few bites longer than this to guarantee that we can always null
+ // terminate it.
+ addr6_length_ = sizeof(addr6_buffer_) - 1;
+ bind_[0].buffer_type = MYSQL_TYPE_STRING;
+ bind_[0].buffer = addr6_buffer_;
+ bind_[0].buffer_length = addr6_length_;
+ bind_[0].length = &addr6_length_;
+ bind_[0].error = &error_[0];
+
+ // client_id: varbinary(128)
+ duid_length_ = sizeof(duid_buffer_);
+ bind_[1].buffer_type = MYSQL_TYPE_BLOB;
+ bind_[1].buffer = reinterpret_cast<char*>(duid_buffer_);
+ bind_[1].buffer_length = duid_length_;
+ bind_[1].length = &duid_length_;
+ bind_[1].error = &error_[1];
+
+ // lease_time: unsigned int
+ bind_[2].buffer_type = MYSQL_TYPE_LONG;
+ bind_[2].buffer = reinterpret_cast<char*>(&valid_lifetime_);
+ bind_[2].is_unsigned = true_;
+ bind_[2].error = &error_[2];
+
+ // expire: timestamp
+ bind_[3].buffer_type = MYSQL_TYPE_TIMESTAMP;
+ bind_[3].buffer = reinterpret_cast<char*>(&expire_);
+ bind_[3].buffer_length = sizeof(expire_);
+ bind_[3].error = &error_[3];
+
+ // subnet_id: unsigned int
+ bind_[4].buffer_type = MYSQL_TYPE_LONG;
+ bind_[4].buffer = reinterpret_cast<char*>(&subnet_id_);
+ bind_[4].is_unsigned = true_;
+ bind_[4].error = &error_[4];
+
+ // pref_lifetime: unsigned int
+ bind_[5].buffer_type = MYSQL_TYPE_LONG;
+ bind_[5].buffer = reinterpret_cast<char*>(&pref_lifetime_);
+ bind_[5].is_unsigned = true_;
+ bind_[5].error = &error_[5];
+
+ // lease_type: tinyint
+ bind_[6].buffer_type = MYSQL_TYPE_TINY;
+ bind_[6].buffer = reinterpret_cast<char*>(&lease_type_);
+ bind_[6].is_unsigned = true_;
+ bind_[6].error = &error_[6];
+
+ // iaid: unsigned int
+ bind_[7].buffer_type = MYSQL_TYPE_LONG;
+ bind_[7].buffer = reinterpret_cast<char*>(&iaid_);
+ bind_[7].is_unsigned = true_;
+ bind_[7].error = &error_[7];
+
+ // prefix_len: unsigned tinyint
+ bind_[8].buffer_type = MYSQL_TYPE_TINY;
+ bind_[8].buffer = reinterpret_cast<char*>(&prefixlen_);
+ bind_[8].is_unsigned = true_;
+ bind_[8].error = &error_[8];
+
+ // Add the data to the vector. Note the end element is one after the
+ // end of the array.
+ return(std::vector<MYSQL_BIND>(&bind_[0], &bind_[9]));
+ }
+
+ /// @brief Copy Received Data into Lease6 Object
+ ///
+ /// Called after the MYSQL_BIND array created by createBindForReceive()
+ /// has been used, this copies data from the internal member vairables
+ /// into a Lease6 object.
+ ///
+ /// @return Lease6Ptr Pointer to a Lease6 object holding the relevant
+ /// data.
+ ///
+ /// @throw isc::BadValue Unable to convert Lease Type value in database
+ Lease6Ptr getLeaseData() {
+
+ // Create the object to be returned.
+ Lease6Ptr result(new Lease6());
+
+ // Put the data in the lease object
+
+ // The address buffer is declared larger than the buffer size passed
+ // to the access function so that we can always append a null byte.
+ addr6_buffer_[addr6_length_] = '\0';
+ std::string address = addr6_buffer_;
+
+ // Set the other data, converting time as needed.
+ result->addr_ = isc::asiolink::IOAddress(address);
+ result->duid_.reset(new DUID(duid_buffer_, duid_length_));
+ MySqlLeaseMgr::convertFromDatabaseTime(expire_, valid_lifetime_,
+ result->cltt_);
+ result->valid_lft_ = valid_lifetime_;
+ result->subnet_id_ = subnet_id_;
+ result->preferred_lft_ = pref_lifetime_;
+
+ // We can't convert from a numeric value to an enum, hence:
+ switch (lease_type_) {
+ case Lease6::LEASE_IA_NA:
+ result->type_ = Lease6::LEASE_IA_NA;
+ break;
+
+ case Lease6::LEASE_IA_TA:
+ result->type_ = Lease6::LEASE_IA_TA;
+ break;
+
+ case Lease6::LEASE_IA_PD:
+ result->type_ = Lease6::LEASE_IA_PD;
+ break;
+
+ default:
+ isc_throw(BadValue, "invalid lease type returned (" <<
+ lease_type_ << ") for lease with address " <<
+ result->addr_.toText() << ". Only 0, 1, or 2 "
+ "are allowed.");
+ }
+ result->iaid_ = iaid_;
+ result->prefixlen_ = prefixlen_;
+
+ return (result);
+ }
+
+private:
+ // Note: All array lengths are equal to the corresponding variable in the
+ // schema.
+ std::string addr6_; ///< String form of address
+ char addr6_buffer_[ADDRESS6_TEXT_MAX_LEN]; ///< Character
+ ///< array form of V6 address
+ unsigned long addr6_length_; ///< Length of the address
+ MYSQL_BIND bind_[9]; ///< Static array for speed of access
+ std::vector<uint8_t> duid_; ///< Client identification
+ uint8_t duid_buffer_[DUID_MAX_LEN]; ///< Buffer form of DUID
+ unsigned long duid_length_; ///< Length of the DUID
+ my_bool error_[9]; ///< For error reporting
+ MYSQL_TIME expire_; ///< Lease expiry time
+ const my_bool false_; ///< "false" for MySql
+ uint32_t iaid_; ///< Identity association ID
+ Lease6Ptr lease_; ///< Pointer to lease object
+ uint32_t valid_lifetime_; ///< Lease time
+ uint8_t lease_type_; ///< Lease type
+ uint8_t prefixlen_; ///< Prefix length
+ uint32_t pref_lifetime_; ///< Preferred lifetime
+ uint32_t subnet_id_; ///< Subnet identification
+ const my_bool true_; ///< "true_" for MySql
+};
+
+
+/// @brief Fetch and Release MySQL Results
+///
+/// When a MySQL statement is exected, to fetch the results the function
+/// mysql_stmt_fetch() must be called. As well as getting data, this
+/// allocated internal state. Subsequent calls to mysql_stmt_fetch
+/// can be made, but when all the data is retrieved, mysql_stmt_free_result
+/// must be called to free up the resources allocated.
+///
+/// Created prior to the first fetch, this class's destructor calls
+/// mysql_stmt_free_result, so eliminating the need for an explicit release
+/// in the method using mysql_stmt_free_result. In this way, it guarantees
+/// that the resources are released even if the MySqlLeaseMgr method concerned
+/// exits via an exception.
+class MySqlFreeResult {
+public:
+
+ /// @brief Constructor
+ ///
+ /// Store the pointer to the statement for which data is being fetched.
+ ///
+ /// Note that according to the MySQL documentation, mysql_stmt_free_result
+ /// only releases resources if a cursor has been allocated for the
+ /// statement. This implies that it is a no-op if none have been. Either
+ /// way, any error from mysql_stmt_free_result is ignored. (Generating
+ /// an exception is not much help, as it will only confuse things if the
+ /// method calling mysql_stmt_fetch is exiting via an exception.)
+ MySqlFreeResult(MYSQL_STMT* statement) : statement_(statement)
+ {}
+
+ /// @brief Destructor
+ ///
+ /// Frees up fetch context if a fetch has been successfully executed.
+ ~MySqlFreeResult() {
+ (void) mysql_stmt_free_result(statement_);
+ }
+
+private:
+ MYSQL_STMT* statement_; ///< Statement for which results are freed
+};
+
+
+// MySqlLeaseMgr Methods
+
+MySqlLeaseMgr::MySqlLeaseMgr(const LeaseMgr::ParameterMap& parameters)
+ : LeaseMgr(parameters), mysql_(NULL) {
+
+ // Allocate context for MySQL - it is destroyed in the destructor.
+ mysql_ = mysql_init(NULL);
+ if (mysql_ == NULL) {
+ isc_throw(DbOpenError, "unable to initialize MySQL");
+ }
+
+ // Open the database
+ openDatabase();
+
+ // Enable autocommit. For maximum speed, the global parameter
+ // innodb_flush_log_at_trx_commit should be set to 2.
+ my_bool result = mysql_autocommit(mysql_, 1);
+ if (result != 0) {
+ isc_throw(DbOperationError, mysql_error(mysql_));
+ }
+
+ // Prepare all statements likely to be used.
+ prepareStatements();
+
+ // Create the exchange object for use in exchanging data between the
+ // program and the database.
+ exchange6_.reset(new MySqlLease6Exchange());
+}
+
+
+MySqlLeaseMgr::~MySqlLeaseMgr() {
+ // Free up the prepared statements, ignoring errors. (What would we do
+ // about them - we're destroying this object and are not really concerned
+ // with errors on a database connection that it about to go away.)
+ for (int i = 0; i < statements_.size(); ++i) {
+ if (statements_[i] != NULL) {
+ (void) mysql_stmt_close(statements_[i]);
+ statements_[i] = NULL;
+ }
+ }
+
+ // Close the database
+ mysql_close(mysql_);
+ mysql_ = NULL;
+}
+
+
+// Time conversion methods.
+//
+// Note that the MySQL TIMESTAMP data type (used for "expire") converts data
+// from the current timezone to UTC for storage, and from UTC to the current
+// timezone for retrieval.
+//
+// This causes no problems providing that:
+// a) cltt is given in local time
+// b) We let the system take care of timezone conversion when converting
+// from a time read from the database into a local time.
+
+void
+MySqlLeaseMgr::convertToDatabaseTime(time_t cltt, uint32_t valid_lifetime,
+ MYSQL_TIME& expire) {
+
+ // Calculate expiry time and convert to various date/time fields.
+ // @TODO: handle overflows
+ time_t expire_time = cltt + valid_lifetime;
+
+ // Convert to broken-out time
+ struct tm expire_tm;
+ (void) localtime_r(&expire_time, &expire_tm);
+
+ // Place in output expire structure.
+ expire.year = expire_tm.tm_year + 1900;
+ expire.month = expire_tm.tm_mon + 1; // Note different base
+ expire.day = expire_tm.tm_mday;
+ expire.hour = expire_tm.tm_hour;
+ expire.minute = expire_tm.tm_min;
+ expire.second = expire_tm.tm_sec;
+ expire.second_part = 0; // No fractional seconds
+ expire.neg = static_cast<my_bool>(0); // Not negative
+}
+
+void
+MySqlLeaseMgr::convertFromDatabaseTime(const MYSQL_TIME& expire,
+ uint32_t valid_lifetime, time_t& cltt) {
+
+ // Copy across fields from MYSQL_TIME structure.
+ struct tm expire_tm;
+ memset(&expire_tm, 0, sizeof(expire_tm));
+
+ expire_tm.tm_year = expire.year - 1900;
+ expire_tm.tm_mon = expire.month - 1;
+ expire_tm.tm_mday = expire.day;
+ expire_tm.tm_hour = expire.hour;
+ expire_tm.tm_min = expire.minute;
+ expire_tm.tm_sec = expire.second;
+ expire_tm.tm_isdst = -1; // Let the system work out about DST
+
+ // Convert to local time
+ cltt = mktime(&expire_tm) - valid_lifetime;
+}
+
+
+void
+MySqlLeaseMgr::openDatabase() {
+
+ // Set up the values of the parameters
+ const char* host = "localhost";
+ string shost;
+ try {
+ shost = getParameter("host");
+ host = shost.c_str();
+ } catch (...) {
+ // No host. Fine, we'll use "localhost"
+ }
+
+ const char* user = NULL;
+ string suser;
+ try {
+ suser = getParameter("user");
+ user = suser.c_str();
+ } catch (...) {
+ // No user. Fine, we'll use NULL
+ ;
+ }
+
+ const char* password = NULL;
+ string spassword;
+ try {
+ spassword = getParameter("password");
+ password = spassword.c_str();
+ } catch (...) {
+ // No password. Fine, we'll use NULL
+ ;
+ }
+
+ const char* name = NULL;
+ string sname;
+ try {
+ sname = getParameter("name");
+ name = sname.c_str();
+ } catch (...) {
+ // No database name. Throw a "NoName" exception
+ isc_throw(NoDatabaseName, "must specified a name for the database");
+ }
+
+ // Set options for the connection:
+ // - automatic reconnection
+ my_bool auto_reconnect = 1;
+ int result = mysql_options(mysql_, MYSQL_OPT_RECONNECT, &auto_reconnect);
+ if (result != 0) {
+ isc_throw(DbOpenError, "unable to set auto-reconnect option: " <<
+ mysql_error(mysql_));
+ }
+
+ // Open the database.
+ //
+ // The option CLIENT_FOUND_ROWS is specified so that in an UPDATE,
+ // the affected rows are the number of rows found that match the
+ // WHERE clause of the SQL statement, not the rows changed. The reason
+ // here is that MySQL apparently does not update a row if data has not
+ // changed and so the "affected rows" (retrievable from MySQL) is zero.
+ // This makes it hard to distinguish whether the UPDATE changed no rows
+ // because no row matching the WHERE clause was found, or because a
+ // row was found by no data was altered.
+ MYSQL* status = mysql_real_connect(mysql_, host, user, password, name,
+ 0, NULL, CLIENT_FOUND_ROWS);
+ if (status != mysql_) {
+ isc_throw(DbOpenError, mysql_error(mysql_));
+ }
+}
+
+
+void
+MySqlLeaseMgr::prepareStatement(StatementIndex index, const char* text) {
+ // Validate that there is space for the statement in the statements array
+ // and that nothing has been placed there before.
+ if ((index >= statements_.size()) || (statements_[index] != NULL)) {
+ isc_throw(InvalidParameter, "invalid prepared statement index (" <<
+ static_cast<int>(index) << ") or indexed prepared " <<
+ "statement is not null");
+ }
+
+ // All OK, so prepare the statement
+ text_statements_[index] = std::string(text);
+
+ statements_[index] = mysql_stmt_init(mysql_);
+ if (statements_[index] == NULL) {
+ isc_throw(DbOperationError, "unable to allocate MySQL prepared "
+ "statement structure" << mysql_error(mysql_));
+ }
+
+ int status = mysql_stmt_prepare(statements_[index], text, strlen(text));
+ if (status != 0) {
+ isc_throw(DbOperationError, "unable to prepare MySQL statement <" <<
+ text << ">, reason: " << mysql_error(mysql_));
+ }
+}
+
+
+void
+MySqlLeaseMgr::prepareStatements() {
+ // Allocate space for all statements
+ statements_.clear();
+ statements_.resize(NUM_STATEMENTS, NULL);
+
+ text_statements_.clear();
+ text_statements_.resize(NUM_STATEMENTS, std::string(""));
+
+ // Created the MySQL prepared statements for each DML statement.
+ for (int i = 0; tagged_statements[i].text != NULL; ++i) {
+ prepareStatement(tagged_statements[i].index,
+ tagged_statements[i].text);
+ }
+}
+
+
+bool
+MySqlLeaseMgr::addLease(const Lease4Ptr& /* lease */) {
+ isc_throw(NotImplemented, "MySqlLeaseMgr::addLease(const Lease4Ptr&) "
+ "not implemented yet");
+ return (false);
+}
+
+
+bool
+MySqlLeaseMgr::addLease(const Lease6Ptr& lease) {
+ const StatementIndex stindex = INSERT_LEASE6;
+
+ // Create the MYSQL_BIND array for the lease
+ std::vector<MYSQL_BIND> bind = exchange6_->createBindForSend(lease);
+
+ // Bind the parameters to the statement
+ int status = mysql_stmt_bind_param(statements_[stindex], &bind[0]);
+ checkError(status, stindex, "unable to bind parameters");
+
+ // Execute the statement
+ status = mysql_stmt_execute(statements_[stindex]);
+ if (status != 0) {
+
+ // Failure: check for the special case of duplicate entry. If this is
+ // the case, we return false to indicate that the row was not added.
+ // Otherwise we throw an exception.
+ if (mysql_errno(mysql_) == ER_DUP_ENTRY) {
+ return (false);
+ }
+ checkError(status, stindex, "unable to execute");
+ }
+
+ // Insert succeeded
+ return (true);
+}
+
+
+Lease4Ptr
+MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& /* addr */,
+ SubnetID /* subnet_id */) const {
+ isc_throw(NotImplemented, "MySqlLeaseMgr::getLease4(const IOAddress&, SubnetID) "
+ "not implemented yet");
+ return (Lease4Ptr());
+}
+
+
+Lease4Ptr
+MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& /* addr */) const {
+ isc_throw(NotImplemented, "MySqlLeaseMgr::getLease4(const IOAddress&) "
+ "not implemented yet");
+ return (Lease4Ptr());
+}
+
+
+Lease4Collection
+MySqlLeaseMgr::getLease4(const HWAddr& /* hwaddr */) const {
+ isc_throw(NotImplemented, "MySqlLeaseMgr::getLease4(const HWAddr&) "
+ "not implemented yet");
+ return (Lease4Collection());
+}
+
+
+Lease4Ptr
+MySqlLeaseMgr::getLease4(const HWAddr& /* hwaddr */,
+ SubnetID /* subnet_id */) const {
+ isc_throw(NotImplemented, "MySqlLeaseMgr::getLease4(const HWAddr&, SubnetID) "
+ "not implemented yet");
+ return (Lease4Ptr());
+}
+
+
+Lease4Collection
+MySqlLeaseMgr::getLease4(const ClientId& /* clientid */) const {
+ isc_throw(NotImplemented, "MySqlLeaseMgr::getLease4(const ClientID&) "
+ "not implemented yet");
+ return (Lease4Collection());
+}
+
+
+Lease4Ptr
+MySqlLeaseMgr::getLease4(const ClientId& /* clientid */,
+ SubnetID /* subnet_id */) const {
+ isc_throw(NotImplemented, "MySqlLeaseMgr::getLease4(const ClientID&, SubnetID) "
+ "not implemented yet");
+ return (Lease4Ptr());
+}
+
+
+// A convenience function used in the various getLease6() methods. It binds
+// the selection parameters to the prepared statement, and binds the variables
+// that will receive the data. These are stored in the MySqlLease6Exchange
+// object associated with the lease manager and converted to a Lease6 object
+// when retrieved.
+void
+MySqlLeaseMgr::bind6AndExecute(StatementIndex stindex, MYSQL_BIND* inbind) const {
+
+ // Bind the input parameters to the statement
+ int status = mysql_stmt_bind_param(statements_[stindex], inbind);
+ checkError(status, stindex, "unable to bind WHERE clause parameter");
+
+ // Set up the SELECT clause
+ std::vector<MYSQL_BIND> outbind = exchange6_->createBindForReceive();
+
+ // Bind the output parameters to the statement
+ status = mysql_stmt_bind_result(statements_[stindex], &outbind[0]);
+ checkError(status, stindex, "unable to bind SELECT caluse parameters");
+
+ // Execute the statement
+ status = mysql_stmt_execute(statements_[stindex]);
+ checkError(status, stindex, "unable to execute");
+}
+
+
+Lease6Ptr
+MySqlLeaseMgr::getLease6(const isc::asiolink::IOAddress& addr) const {
+ const StatementIndex stindex = GET_LEASE6_ADDR;
+
+ // Set up the WHERE clause value
+ MYSQL_BIND inbind[1];
+ memset(inbind, 0, sizeof(inbind));
+
+ std::string addr6 = addr.toText();
+ unsigned long addr6_length = addr6.size();
+
+ // See the earlier description of the use of "const_cast" when accessing
+ // the address for an explanation of the reason.
+ inbind[0].buffer_type = MYSQL_TYPE_STRING;
+ inbind[0].buffer = const_cast<char*>(addr6.c_str());
+ inbind[0].buffer_length = addr6_length;
+ inbind[0].length = &addr6_length;
+
+ // Bind the input parameters to the statement and bind the output
+ // to fields in the exchange object, then execute the prepared statement.
+ bind6AndExecute(stindex, inbind);
+
+ // Fetch the data and set up the "release" object to release associated
+ // resources when this method exits.
+ MySqlFreeResult fetch_release(statements_[stindex]);
+ int status = mysql_stmt_fetch(statements_[stindex]);
+
+ Lease6Ptr result;
+ if (status == 0) {
+ try {
+ result = exchange6_->getLeaseData();
+ } catch (const isc::BadValue& ex) {
+ // Lease type is returned, to rethrow the exception with a bit
+ // more data.
+ isc_throw(BadValue, ex.what() << ". Statement is <" <<
+ text_statements_[stindex] << ">");
+ }
+
+ // As the address is the primary key in the table, we can't return
+ // two rows, so we don't bother checking whether multiple rows have
+ // been returned.
+
+ } else if (status == 1) {
+ checkError(status, stindex, "unable to fetch results");
+
+ } else {
+ // @TODO Handle truncation
+ // We are ignoring truncation for now, so the only other result is
+ // no data was found. In that case, we return a null Lease6 structure.
+ // This has already been set, so no action is needed.
+ }
+
+ return (result);
+}
+
+
+Lease6Collection
+MySqlLeaseMgr::getLease6(const DUID& duid, uint32_t iaid) const {
+ const StatementIndex stindex = GET_LEASE6_DUID_IAID;
+
+ // Set up the WHERE clause value
+ MYSQL_BIND inbind[2];
+ memset(inbind, 0, sizeof(inbind));
+
+ // In the following statement, the DUID is being read. However, the
+ // MySQL C interface does not use "const", so the "buffer" element
+ // is declared as "char*" instead of "const char*". To resolve this,
+ // the "const" is discarded before the uint8_t* is cast to char*.
+ //
+ // Note that the const_cast could be avoided by copying the DUID to
+ // a writeable buffer and storing the address of that in the "buffer"
+ // element. However, this introduces a copy operation (with additional
+ // overhead) purely to get round the strictures introduced by design of
+ // the MySQL interface (which uses the area pointed to by "buffer" as
+ // input when specifying query parameters and as output when retrieving
+ // data). For that reason, "const_cast" has been used.
+ const vector<uint8_t>& duid_vector = duid.getDuid();
+ unsigned long duid_length = duid_vector.size();
+ inbind[0].buffer_type = MYSQL_TYPE_BLOB;
+ inbind[0].buffer = reinterpret_cast<char*>(
+ const_cast<uint8_t*>(&duid_vector[0]));
+ inbind[0].buffer_length = duid_length;
+ inbind[0].length = &duid_length;
+
+ // IAID
+ inbind[1].buffer_type = MYSQL_TYPE_LONG;
+ inbind[1].buffer = reinterpret_cast<char*>(&iaid);
+ inbind[1].is_unsigned = static_cast<my_bool>(1);
+
+ // Bind the input parameters to the statement and bind the output
+ // to fields in the exchange object, then execute the prepared statement.
+ bind6AndExecute(stindex, inbind);
+
+ // Ensure that all the lease information is retrieved in one go to avoid
+ // overhead of going back and forth between client and server.
+ int status = mysql_stmt_store_result(statements_[stindex]);
+ checkError(status, stindex, "unable to set up for storing all results");
+
+ // Fetch the data. There could be multiple rows, so we need to iterate
+ // until all data has been retrieved.
+ Lease6Collection result;
+
+ // Set up the fetch "release" object to release resources associated
+ // with the call to mysql_stmt_fetch when this method exits, then
+ // retrieve the data.
+ MySqlFreeResult fetch_release(statements_[stindex]);
+ while ((status = mysql_stmt_fetch(statements_[stindex])) == 0) {
+ try {
+ Lease6Ptr lease = exchange6_->getLeaseData();
+ result.push_back(lease);
+
+ } catch (const isc::BadValue& ex) {
+ // Rethrow the exception with a bit more data.
+ isc_throw(BadValue, ex.what() << ". Statement is <" <<
+ text_statements_[stindex] << ">");
+ }
+ }
+
+ // How did the fetch end?
+ if (status == 1) {
+ // Error - unable to fecth results
+ checkError(status, stindex, "unable to fetch results");
+ } else if (status == MYSQL_DATA_TRUNCATED) {
+ // @TODO Handle truncation
+ ;
+ }
+
+ return (result);
+}
+
+
+Lease6Ptr
+MySqlLeaseMgr::getLease6(const DUID& duid, uint32_t iaid,
+ SubnetID subnet_id) const {
+ const StatementIndex stindex = GET_LEASE6_DUID_IAID_SUBID;
+
+ // Set up the WHERE clause value
+ MYSQL_BIND inbind[3];
+ memset(inbind, 0, sizeof(inbind));
+
+ // See the earlier description of the use of "const_cast" when accessing
+ // the DUID for an explanation of the reason.
+ const vector<uint8_t>& duid_vector = duid.getDuid();
+ unsigned long duid_length = duid_vector.size();
+ inbind[0].buffer_type = MYSQL_TYPE_BLOB;
+ inbind[0].buffer = reinterpret_cast<char*>(
+ const_cast<uint8_t*>(&duid_vector[0]));
+ inbind[0].buffer_length = duid_length;
+ inbind[0].length = &duid_length;
+
+ // IAID
+ inbind[1].buffer_type = MYSQL_TYPE_LONG;
+ inbind[1].buffer = reinterpret_cast<char*>(&iaid);
+ inbind[1].is_unsigned = static_cast<my_bool>(1);
+
+ // Subnet ID
+ inbind[2].buffer_type = MYSQL_TYPE_LONG;
+ inbind[2].buffer = reinterpret_cast<char*>(&subnet_id);
+ inbind[2].is_unsigned = static_cast<my_bool>(1);
+
+ // Bind the input parameters to the statement and bind the output
+ // to fields in the exchange object, then execute the prepared statement.
+ bind6AndExecute(stindex, inbind);
+
+ // Fetch the data and set up the "release" object to release associated
+ // resources when this method exits then retrieve the data.
+ Lease6Ptr result;
+ MySqlFreeResult fetch_release(statements_[stindex]);
+ int status = mysql_stmt_fetch(statements_[stindex]);
+ if (status == 0) {
+ try {
+ result = exchange6_->getLeaseData();
+
+ // TODO: check for more than one row returned. At present, just
+ // ignore the excess and take the first.
+
+ } catch (const isc::BadValue& ex) {
+ // Lease type is returned, to rethrow the exception with a bit
+ // more data.
+ isc_throw(BadValue, ex.what() << ". Statement is <" <<
+ text_statements_[stindex] << ">");
+ }
+
+ // As the address is the primary key in the table, we can't return
+ // two rows, so we don't bother checking whether multiple rows have
+ // been returned.
+
+ } else if (status == 1) {
+ checkError(status, stindex, "unable to fetch results");
+
+ } else {
+ // @TODO Handle truncation
+ // We are ignoring truncation for now, so the only other result is
+ // no data was found. In that case, we return a null Lease6 structure.
+ // This has already been set, so the action is a no-op.
+ }
+
+ return (result);
+}
+
+
+void
+MySqlLeaseMgr::updateLease4(const Lease4Ptr& /* lease4 */) {
+ isc_throw(NotImplemented, "MySqlLeaseMgr::updateLease4(const Lease4Ptr&) "
+ "not implemented yet");
+}
+
+
+void
+MySqlLeaseMgr::updateLease6(const Lease6Ptr& lease) {
+ const StatementIndex stindex = UPDATE_LEASE6;
+
+ // Create the MYSQL_BIND array for the data being updated
+ std::vector<MYSQL_BIND> bind = exchange6_->createBindForSend(lease);
+
+ // Set up the WHERE clause value
+ MYSQL_BIND where;
+ memset(&where, 0, sizeof(where));
+
+ std::string addr6 = lease->addr_.toText();
+ unsigned long addr6_length = addr6.size();
+
+ // See the earlier description of the use of "const_cast" when accessing
+ // the address for an explanation of the reason.
+ where.buffer_type = MYSQL_TYPE_STRING;
+ where.buffer = const_cast<char*>(addr6.c_str());
+ where.buffer_length = addr6_length;
+ where.length = &addr6_length;
+ bind.push_back(where);
+
+ // Bind the parameters to the statement
+ int status = mysql_stmt_bind_param(statements_[stindex], &bind[0]);
+ checkError(status, stindex, "unable to bind parameters");
+
+ // Execute
+ status = mysql_stmt_execute(statements_[stindex]);
+ checkError(status, stindex, "unable to execute");
+
+ // See how many rows were affected. The statement should only delete a
+ // single row.
+ int affected_rows = mysql_stmt_affected_rows(statements_[stindex]);
+ if (affected_rows == 0) {
+ isc_throw(NoSuchLease, "unable to update lease for address " <<
+ addr6 << " as it does not exist");
+ } else if (affected_rows > 1) {
+ // Should not happen - primary key constraint should only have selected
+ // one row.
+ isc_throw(DbOperationError, "apparently updated more than one lease "
+ "that had the address " << addr6);
+ }
+}
+
+
+bool
+MySqlLeaseMgr::deleteLease4(const isc::asiolink::IOAddress& /* addr */) {
+ isc_throw(NotImplemented, "MySqlLeaseMgr::deleteLease4(const IOAddress&) "
+ "not implemented yet");
+ return (false);
+}
+
+
+bool
+MySqlLeaseMgr::deleteLease6(const isc::asiolink::IOAddress& addr) {
+ const StatementIndex stindex = DELETE_LEASE6;
+
+ // Set up the WHERE clause value
+ MYSQL_BIND inbind[1];
+ memset(inbind, 0, sizeof(inbind));
+
+ std::string addr6 = addr.toText();
+ unsigned long addr6_length = addr6.size();
+
+ // See the earlier description of the use of "const_cast" when accessing
+ // the address for an explanation of the reason.
+ inbind[0].buffer_type = MYSQL_TYPE_STRING;
+ inbind[0].buffer = const_cast<char*>(addr6.c_str());
+ inbind[0].buffer_length = addr6_length;
+ inbind[0].length = &addr6_length;
+
+ // Bind the input parameters to the statement
+ int status = mysql_stmt_bind_param(statements_[stindex], inbind);
+ checkError(status, stindex, "unable to bind WHERE clause parameter");
+
+ // Execute
+ status = mysql_stmt_execute(statements_[stindex]);
+ checkError(status, stindex, "unable to execute");
+
+ // See how many rows were affected. Note that the statement may delete
+ // multiple rows.
+ return (mysql_stmt_affected_rows(statements_[stindex]) > 0);
+}
+
+
+std::string
+MySqlLeaseMgr::getName() const {
+ std::string name = "";
+ try {
+ name = getParameter("name");
+ } catch (...) {
+ ;
+ }
+ return (name);
+}
+
+
+std::string
+MySqlLeaseMgr::getDescription() const {
+ return (std::string("MySQL Database"));
+}
+
+
+std::pair<uint32_t, uint32_t>
+MySqlLeaseMgr::getVersion() const {
+ const StatementIndex stindex = GET_VERSION;
+
+ uint32_t major; // Major version number
+ uint32_t minor; // Minor version number
+
+ // Execute the prepared statement
+ int status = mysql_stmt_execute(statements_[stindex]);
+ if (status != 0) {
+ isc_throw(DbOperationError, "unable to execute <"
+ << text_statements_[stindex] << "> - reason: " <<
+ mysql_error(mysql_));
+ }
+
+ // Bind the output of the statement to the appropriate variables.
+ MYSQL_BIND bind[2];
+ memset(bind, 0, sizeof(bind));
+
+ bind[0].buffer_type = MYSQL_TYPE_LONG;
+ bind[0].is_unsigned = 1;
+ bind[0].buffer = &major;
+ bind[0].buffer_length = sizeof(major);
+
+ bind[1].buffer_type = MYSQL_TYPE_LONG;
+ bind[1].is_unsigned = 1;
+ bind[1].buffer = &minor;
+ bind[1].buffer_length = sizeof(minor);
+
+ status = mysql_stmt_bind_result(statements_[stindex], bind);
+ if (status != 0) {
+ isc_throw(DbOperationError, "unable to bind result set: " <<
+ mysql_error(mysql_));
+ }
+
+ // Fetch the data and set up the "release" object to release associated
+ // resources when this method exits then retrieve the data.
+ MySqlFreeResult fetch_release(statements_[stindex]);
+ status = mysql_stmt_fetch(statements_[stindex]);
+ if (status != 0) {
+ isc_throw(DbOperationError, "unable to obtain result set: " <<
+ mysql_error(mysql_));
+ }
+
+ return (std::make_pair(major, minor));
+}
+
+
+void
+MySqlLeaseMgr::commit() {
+ if (mysql_commit(mysql_) != 0) {
+ isc_throw(DbOperationError, "commit failed: " << mysql_error(mysql_));
+ }
+}
+
+
+void
+MySqlLeaseMgr::rollback() {
+ if (mysql_rollback(mysql_) != 0) {
+ isc_throw(DbOperationError, "rollback failed: " << mysql_error(mysql_));
+ }
+}
+
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.h b/src/lib/dhcpsrv/mysql_lease_mgr.h
new file mode 100644
index 0000000..1884da6
--- /dev/null
+++ b/src/lib/dhcpsrv/mysql_lease_mgr.h
@@ -0,0 +1,449 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef MYSQL_LEASE_MGR_H
+#define MYSQL_LEASE_MGR_H
+
+#include <dhcpsrv/lease_mgr.h>
+
+#include <boost/scoped_ptr.hpp>
+#include <mysql/mysql.h>
+
+#include <time.h>
+
+namespace isc {
+namespace dhcp {
+
+// Define the current database schema values
+
+const uint32_t CURRENT_VERSION_VERSION = 0;
+const uint32_t CURRENT_VERSION_MINOR = 1;
+
+
+// Forward declaration of the Lease6 exchange object. This class is defined
+// in the .cc file.
+class MySqlLease6Exchange;
+
+
+/// @brief MySQL Lease Manager
+///
+/// This is a concrete API for the backend for the MySQL database.
+class MySqlLeaseMgr : public LeaseMgr {
+public:
+ /// @brief Constructor
+ ///
+ /// Uses the following keywords in the parameters passed to it to
+ /// connect to the database:
+ /// - name - Name of the database to which to connect (mandatory)
+ /// - host - Host to which to connect (optional, defaults to "localhost")
+ /// - user - Username under which to connect (optional)
+ /// - password - Password for "user" on the database (optional)
+ ///
+ /// If the database is successfully opened, the version number in the
+ /// schema_version table will be checked against hard-coded value in
+ /// the implementation file.
+ ///
+ /// Finally, all the SQL commands are pre-compiled.
+ ///
+ /// @param parameters A data structure relating keywords and values
+ /// concerned with the database.
+ ///
+ /// @throw isc::dhcp::NoDatabaseName Mandatory database name not given
+ /// @throw isc::dhcp::DbOpenError Error opening the database
+ /// @throw isc::dhcp::DbOperationError An operation on the open database has
+ /// failed.
+ MySqlLeaseMgr(const ParameterMap& parameters);
+
+ /// @brief Destructor (closes database)
+ virtual ~MySqlLeaseMgr();
+
+ /// @brief Adds an IPv4 lease.
+ ///
+ /// @param lease lease to be added
+ ///
+ /// @result true if the lease was added, false if not (because a lease
+ /// with the same address was already there).
+ ///
+ /// @throw isc::dhcp::DbOperationError An operation on the open database has
+ /// failed.
+ virtual bool addLease(const Lease4Ptr& lease);
+
+ /// @brief Adds an IPv6 lease.
+ ///
+ /// @param lease lease to be added
+ ///
+ /// @result true if the lease was added, false if not (because a lease
+ /// with the same address was already there).
+ ///
+ /// @throw isc::dhcp::DbOperationError An operation on the open database has
+ /// failed.
+ virtual bool addLease(const Lease6Ptr& lease);
+
+ /// @brief Return IPv4 lease for specified IPv4 address and subnet_id
+ ///
+ /// This method is used to get a lease for specific subnet_id. There can be
+ /// at most one lease for any given subnet, so this method returns a single
+ /// pointer.
+ ///
+ /// @param addr address of the sought lease
+ /// @param subnet_id ID of the subnet the lease must belong to
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr,
+ SubnetID subnet_id) const;
+
+ /// @brief Returns an IPv4 lease for specified IPv4 address
+ ///
+ /// This method return a lease that is associated with a given address.
+ /// For other query types (by hardware addr, by DUID) there can be
+ /// several leases in different subnets (e.g. for mobile clients that
+ /// got address in different subnets). However, for a single address
+ /// there can be only one lease, so this method returns a pointer to
+ /// a single lease, not a container of leases.
+ ///
+ /// @param addr address of the searched lease
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr) const;
+
+
+ /// @brief Returns existing IPv4 leases for specified hardware address.
+ ///
+ /// Although in the usual case there will be only one lease, for mobile
+ /// clients or clients with multiple static/fixed/reserved leases there
+ /// can be more than one. Thus return type is a container, not a single
+ /// pointer.
+ ///
+ /// @param hwaddr hardware address of the client
+ ///
+ /// @return lease collection
+ virtual Lease4Collection getLease4(const HWAddr& hwaddr) const;
+
+ /// @brief Returns existing IPv4 leases for specified hardware address
+ /// and a subnet
+ ///
+ /// There can be at most one lease for a given HW address in a single
+ /// pool, so this method with either return a single lease or NULL.
+ ///
+ /// @param hwaddr hardware address of the client
+ /// @param subnet_id identifier of the subnet that lease must belong to
+ ///
+ /// @return a pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(const HWAddr& hwaddr,
+ SubnetID subnet_id) const;
+
+ /// @brief Returns existing IPv4 lease for specified client-id
+ ///
+ /// Although in the usual case there will be only one lease, for mobile
+ /// clients or clients with multiple static/fixed/reserved leases there
+ /// can be more than one. Thus return type is a container, not a single
+ /// pointer.
+ ///
+ /// @param clientid client identifier
+ ///
+ /// @return lease collection
+ virtual Lease4Collection getLease4(const ClientId& clientid) const;
+
+ /// @brief Returns existing IPv4 lease for specified client-id
+ ///
+ /// There can be at most one lease for a given HW address in a single
+ /// pool, so this method with either return a single lease or NULL.
+ ///
+ /// @param clientid client identifier
+ /// @param subnet_id identifier of the subnet that lease must belong to
+ ///
+ /// @return a pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(const ClientId& clientid,
+ SubnetID subnet_id) const;
+
+ /// @brief Returns existing IPv6 lease for a given IPv6 address.
+ ///
+ /// For a given address, we assume that there will be only one lease.
+ /// The assumtion here is that there will not be site or link-local
+ /// addresses used, so there is no way of having address duplication.
+ ///
+ /// @param addr address of the searched lease
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ ///
+ /// @throw isc::BadValue record retrieved from database had an invalid
+ /// lease type field.
+ /// @throw isc::dhcp::DbOperationError An operation on the open database has
+ /// failed.
+ virtual Lease6Ptr getLease6(const isc::asiolink::IOAddress& addr) const;
+
+ /// @brief Returns existing IPv6 leases for a given DUID+IA combination
+ ///
+ /// Although in the usual case there will be only one lease, for mobile
+ /// clients or clients with multiple static/fixed/reserved leases there
+ /// can be more than one. Thus return type is a container, not a single
+ /// pointer.
+ ///
+ /// @param duid client DUID
+ /// @param iaid IA identifier
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease6Collection getLease6(const DUID& duid,
+ uint32_t iaid) const;
+
+ /// @brief Returns existing IPv6 lease for a given DUID+IA combination
+ ///
+ /// @param duid client DUID
+ /// @param iaid IA identifier
+ /// @param subnet_id subnet id of the subnet the lease belongs to
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease6Ptr getLease6(const DUID& duid, uint32_t iaid,
+ SubnetID subnet_id) const;
+
+ /// @brief Updates IPv4 lease.
+ ///
+ /// @param lease4 The lease to be updated.
+ ///
+ /// If no such lease is present, an exception will be thrown.
+ virtual void updateLease4(const Lease4Ptr& lease4);
+
+ /// @brief Updates IPv6 lease.
+ ///
+ /// @param lease6 The lease to be updated.
+ ///
+ /// @throw isc::dhcp::NoSuchLease Attempt to update a lease that did not
+ /// exist.
+ /// @throw isc::dhcp::DbOperationError An operation on the open database has
+ /// failed.
+ virtual void updateLease6(const Lease6Ptr& lease6);
+
+ /// @brief Deletes an IPv4 lease.
+ ///
+ /// @param addr IPv4 address of the lease to be deleted.
+ ///
+ /// @return true if deletion was successful, false if no such lease exists
+ virtual bool deleteLease4(const isc::asiolink::IOAddress& addr);
+
+ /// @brief Deletes an IPv6 lease.
+ ///
+ /// @param addr IPv6 address of the lease to be deleted.
+ ///
+ /// @return true if deletion was successful, false if no such lease exists
+ ///
+ /// @throw isc::dhcp::DbOperationError An operation on the open database has
+ /// failed.
+ virtual bool deleteLease6(const isc::asiolink::IOAddress& addr);
+
+ /// @brief Return backend type
+ ///
+ /// Returns the type of the backend (e.g. "mysql", "memfile" etc.)
+ ///
+ /// @return Type of the backend.
+ virtual std::string getType() const {
+ return (std::string("mysql"));
+ }
+
+ /// @brief Returns backend name.
+ ///
+ /// Each backend have specific name, e.g. "mysql" or "sqlite".
+ ///
+ /// @return Name of the backend.
+ virtual std::string getName() const;
+
+ /// @brief Returns description of the backend.
+ ///
+ /// This description may be multiline text that describes the backend.
+ ///
+ /// @return Description of the backend.
+ virtual std::string getDescription() const;
+
+ /// @brief Returns backend version.
+ ///
+ /// @return Version number as a pair of unsigned integers. "first" is the
+ /// major version number, "second" the minor number.
+ ///
+ /// @throw isc::dhcp::DbOperationError An operation on the open database has
+ /// failed.
+ virtual std::pair<uint32_t, uint32_t> getVersion() const;
+
+ /// @brief Commit Transactions
+ ///
+ /// Commits all pending database operations. On databases that don't
+ /// support transactions, this is a no-op.
+ ///
+ /// @throw DbOperationError Iif the commit failed.
+ virtual void commit();
+
+ /// @brief Rollback Transactions
+ ///
+ /// Rolls back all pending database operations. On databases that don't
+ /// support transactions, this is a no-op.
+ ///
+ /// @throw DbOperationError If the rollback failed.
+ virtual void rollback();
+
+ ///@{
+ /// The following methods are used to convert between times and time
+ /// intervals stored in the Lease object, and the times stored in the
+ /// database. The reason for the difference is because in the DHCP server,
+ /// the cltt (Client Time Since Last Transmission) is the natural data; in
+ /// the lease file - which may be read by the user - it is the expiry time
+ /// of the lease.
+
+ /// @brief Convert Lease Time to Database Times
+ ///
+ /// Within the DHCP servers, times are stored as client last transmit time
+ /// and valid lifetime. In the database, the information is stored as
+ /// valid lifetime and "expire" (time of expiry of the lease). They are
+ /// related by the equation:
+ ///
+ /// - expire = client last transmit time + valid lifetime
+ ///
+ /// This method converts from the times in the lease object into times
+ /// able to be added to the database.
+ ///
+ /// @param cltt Client last transmit time
+ /// @param valid_lifetime Valid lifetime
+ /// @param expire Reference to MYSQL_TIME object where the expiry time of
+ /// the lease will be put.
+ static
+ void convertToDatabaseTime(time_t cltt, uint32_t valid_lifetime,
+ MYSQL_TIME& expire);
+
+ /// @brief Convert Database Time to Lease Times
+ ///
+ /// Within the database, time is stored as "expire" (time of expiry of the
+ /// lease) and valid lifetime. In the DHCP server, the information is
+ /// stored client last transmit time and valid lifetime. These are related
+ /// by the equation:
+ ///
+ /// - client last transmit time = expire - valid_lifetime
+ ///
+ /// This method converts from the times in the database into times
+ /// able to be inserted into the lease object.
+ ///
+ /// @param expire Reference to MYSQL_TIME object from where the expiry
+ /// time of the lease is taken.
+ /// @param valid_lifetime lifetime of the lease.
+ /// @param cltt Reference to location where client last transmit time
+ /// is put.
+ static
+ void convertFromDatabaseTime(const MYSQL_TIME& expire,
+ uint32_t valid_lifetime, time_t& cltt);
+ ///@}
+
+ /// @brief Statement Tags
+ ///
+ /// The contents of the enum are indexes into the list of SQL statements
+ enum StatementIndex {
+ DELETE_LEASE6, // Delete from lease6 by address
+ GET_LEASE6_ADDR, // Get lease6 by address
+ GET_LEASE6_DUID_IAID, // Get lease6 by DUID and IAID
+ GET_LEASE6_DUID_IAID_SUBID, // Get lease6 by DUID, IAID and Subnet ID
+ GET_VERSION, // Obtain version number
+ INSERT_LEASE6, // Add entry to lease6 table
+ UPDATE_LEASE6, // Update a Lease6 entry
+ NUM_STATEMENTS // Number of statements
+ };
+
+private:
+ /// @brief Prepare Single Statement
+ ///
+ /// Creates a prepared statement from the text given and adds it to the
+ /// statements_ vector at the given index.
+ ///
+ /// @param index Index into the statements_ vector into which the text
+ /// should be placed. The vector must be big enough for the index
+ /// to be valid, else an exception will be thrown.
+ /// @param text Text of the SQL statement to be prepared.
+ ///
+ /// @throw isc::dhcp::DbOperationError An operation on the open database has
+ /// failed.
+ /// @throw isc::InvalidParameter 'index' is not valid for the vector.
+ void prepareStatement(StatementIndex index, const char* text);
+
+ /// @brief Prepare statements
+ ///
+ /// Creates the prepared statements for all of the SQL statements used
+ /// by the MySQL backend.
+ ///
+ /// @throw isc::dhcp::DbOperationError An operation on the open database has
+ /// failed.
+ /// @throw isc::InvalidParameter 'index' is not valid for the vector. This
+ /// represents an internal error within the code.
+ void prepareStatements();
+
+ /// @brief Open Database
+ ///
+ /// Opens the database using the information supplied in the parameters
+ /// passed to the constructor.
+ ///
+ /// @throw NoDatabaseName Mandatory database name not given
+ /// @throw DbOpenError Error opening the database
+ void openDatabase();
+
+ /// @brief Binds Parameters and Executes
+ ///
+ /// This method abstracts a lot of common processing from the getXxxx()
+ /// methods. It binds the parameters passed to it to the appropriate
+ /// prepared statement, and binds the variables in the exchange6 object to
+ /// the output parameters of the statement. It then executes the prepared
+ /// statement.
+ ///
+ /// The data can be retrieved using mysql_stmt_fetch and the getLeaseData()
+ /// method on the exchange6 object.
+ ///
+ /// @param stindex Index of prepared statement to be executed
+ /// @param inbind Array of MYSQL_BIND objects representing the parameters.
+ /// (Note that the number is determined by the number of parameters
+ /// in the statement.)
+ ///
+ /// @throw isc::dhcp::DbOperationError An operation on the open database has
+ /// failed.
+ void bind6AndExecute(StatementIndex stindex, MYSQL_BIND* inbind) const;
+
+ /// @brief Check Error and Throw Exception
+ ///
+ /// Virtually all MySQL functions return a status which, if non-zero,
+ /// indicates an error. This inline function conceals a lot of error
+ /// checking/exception-throwing code.
+ ///
+ /// @param status Status code: non-zero implies an error
+ /// @param index Index of statement that caused the error
+ /// @param what High-level description of the error
+ ///
+ /// @throw isc::dhcp::DbOperationError An operation on the open database has
+ /// failed.
+ inline void checkError(int status, StatementIndex index,
+ const char* what) const {
+ if (status != 0) {
+ isc_throw(DbOperationError, what << " for <" <<
+ text_statements_[index] << ">, reason: " <<
+ mysql_error(mysql_) << " (error code " <<
+ mysql_errno(mysql_) << ")");
+ }
+ }
+
+ // Members
+
+ /// Used for transfer of data to/from the database. This is a pointed-to
+ /// object as its contents may change in "const" calls, while the rest
+ /// of this object does not. (At alternative would be to declare it as
+ /// "mutable".)
+ boost::scoped_ptr<MySqlLease6Exchange> exchange6_;
+ MYSQL* mysql_; ///< MySQL context object
+ std::vector<std::string> text_statements_; ///< Raw text of statements
+ std::vector<MYSQL_STMT*> statements_; ///< Prepared statements
+};
+
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
+
+#endif // MYSQL_LEASE_MGR_H
diff --git a/src/lib/dhcpsrv/pool.cc b/src/lib/dhcpsrv/pool.cc
new file mode 100644
index 0000000..9c91acb
--- /dev/null
+++ b/src/lib/dhcpsrv/pool.cc
@@ -0,0 +1,118 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <asiolink/io_address.h>
+#include <dhcpsrv/addr_utilities.h>
+#include <dhcpsrv/pool.h>
+
+using namespace isc::asiolink;
+
+namespace isc {
+namespace dhcp {
+
+Pool::Pool(const isc::asiolink::IOAddress& first,
+ const isc::asiolink::IOAddress& last)
+ :id_(getNextID()), first_(first), last_(last) {
+}
+
+bool Pool::inRange(const isc::asiolink::IOAddress& addr) const {
+ return (first_.smallerEqual(addr) && addr.smallerEqual(last_));
+}
+
+Pool4::Pool4(const isc::asiolink::IOAddress& first,
+ const isc::asiolink::IOAddress& last)
+ :Pool(first, last) {
+ // check if specified address boundaries are sane
+ if (first.getFamily() != AF_INET || last.getFamily() != AF_INET) {
+ isc_throw(BadValue, "Invalid Pool4 address boundaries: not IPv4");
+ }
+
+ if (last < first) {
+ isc_throw(BadValue, "Upper boundary is smaller than lower boundary.");
+ }
+}
+
+Pool4::Pool4(const isc::asiolink::IOAddress& prefix,
+ uint8_t prefix_len)
+ :Pool(prefix, IOAddress("0.0.0.0")) {
+
+ // check if the prefix is sane
+ if (prefix.getFamily() != AF_INET) {
+ isc_throw(BadValue, "Invalid Pool4 address boundaries: not IPv4");
+ }
+
+ // check if the prefix length is sane
+ if (prefix_len == 0 || prefix_len > 32) {
+ isc_throw(BadValue, "Invalid prefix length");
+ }
+
+ // Let's now calculate the last address in defined pool
+ last_ = lastAddrInPrefix(prefix, prefix_len);
+}
+
+
+Pool6::Pool6(Pool6Type type, const isc::asiolink::IOAddress& first,
+ const isc::asiolink::IOAddress& last)
+ :Pool(first, last), type_(type), prefix_len_(0) {
+
+ // check if specified address boundaries are sane
+ if (first.getFamily() != AF_INET6 || last.getFamily() != AF_INET6) {
+ isc_throw(BadValue, "Invalid Pool6 address boundaries: not IPv6");
+ }
+
+ if (last < first) {
+ isc_throw(BadValue, "Upper boundary is smaller than lower boundary.");
+ // This check is a bit strict. If we decide that it is too strict,
+ // we need to comment it and uncomment lines below.
+ // On one hand, letting the user specify 2001::f - 2001::1 is nice, but
+ // on the other hand, 2001::1 may be a typo and the user really meant
+ // 2001::1:0 (or 1 followed by some hex digit), so a at least a warning
+ // would be useful.
+
+ // first_ = last;
+ // last_ = first;
+ }
+
+ // TYPE_PD is not supported by this constructor. first-last style
+ // parameters are for IA and TA only. There is another dedicated
+ // constructor for that (it uses prefix/length)
+ if ((type != TYPE_IA) && (type != TYPE_TA)) {
+ isc_throw(BadValue, "Invalid Pool6 type specified");
+ }
+}
+
+Pool6::Pool6(Pool6Type type, const isc::asiolink::IOAddress& prefix,
+ uint8_t prefix_len)
+ :Pool(prefix, IOAddress("::")),
+ type_(type), prefix_len_(prefix_len) {
+
+ // check if the prefix is sane
+ if (prefix.getFamily() != AF_INET6) {
+ isc_throw(BadValue, "Invalid Pool6 address boundaries: not IPv6");
+ }
+
+ // check if the prefix length is sane
+ if (prefix_len == 0 || prefix_len > 128) {
+ isc_throw(BadValue, "Invalid prefix length");
+ }
+
+ /// @todo: We should probably implement checks against weird addresses
+ /// here, like ::, starting with fe80, starting with ff etc. .
+
+ // Let's now calculate the last address in defined pool
+ last_ = lastAddrInPrefix(prefix, prefix_len);
+}
+
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
diff --git a/src/lib/dhcpsrv/pool.h b/src/lib/dhcpsrv/pool.h
new file mode 100644
index 0000000..eb5e5e2
--- /dev/null
+++ b/src/lib/dhcpsrv/pool.h
@@ -0,0 +1,186 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef POOL_H
+#define POOL_H
+
+#include <asiolink/io_address.h>
+
+#include <boost/shared_ptr.hpp>
+
+#include <vector>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief base class for Pool4 and Pool6
+///
+/// Stores information about pool of IPv4 or IPv6 addresses.
+/// That is a basic component of a configuration.
+class Pool {
+
+public:
+
+ /// @brief returns Pool-id
+ ///
+ /// @return pool-id value
+ /// Pool-id is an unique value that can be used to identify a pool.
+ uint32_t getId() const {
+ return (id_);
+ }
+
+ /// @brief Returns the first address in a pool.
+ ///
+ /// @return first address in a pool
+ const isc::asiolink::IOAddress& getFirstAddress() const {
+ return (first_);
+ }
+
+ /// @brief Returns the last address in a pool.
+ /// @return last address in a pool
+ const isc::asiolink::IOAddress& getLastAddress() const {
+ return (last_);
+ }
+
+ /// @brief Checks if a given address is in the range.
+ ///
+ /// @return true, if the address is in pool
+ bool inRange(const isc::asiolink::IOAddress& addr) const;
+
+protected:
+
+ /// @brief protected constructor
+ ///
+ /// This constructor is protected to prevent anyone from instantiating
+ /// Pool class directly. Instances of Pool4 and Pool6 should be created
+ /// instead.
+ Pool(const isc::asiolink::IOAddress& first,
+ const isc::asiolink::IOAddress& last);
+
+ /// @brief returns the next unique Pool-ID
+ ///
+ /// @return the next unique Pool-ID
+ static uint32_t getNextID() {
+ static uint32_t id = 0;
+ return (id++);
+ }
+
+ /// @brief pool-id
+ ///
+ /// This ID is used to identify this specific pool.
+ uint32_t id_;
+
+ /// @brief The first address in a pool
+ isc::asiolink::IOAddress first_;
+
+ /// @brief The last address in a pool
+ isc::asiolink::IOAddress last_;
+
+ /// @brief Comments field
+ ///
+ /// @todo: This field is currently not used.
+ std::string comments_;
+};
+
+/// @brief Pool information for IPv4 addresses
+///
+/// It holds information about pool4, i.e. a range of IPv4 address space that
+/// is configured for DHCP allocation.
+class Pool4 : public Pool {
+public:
+ /// @brief the constructor for Pool4 "min-max" style definition
+ ///
+ /// @param first the first address in a pool
+ /// @param last the last address in a pool
+ Pool4(const isc::asiolink::IOAddress& first,
+ const isc::asiolink::IOAddress& last);
+
+ /// @brief the constructor for Pool4 "prefix/len" style definition
+ ///
+ /// @param prefix specifies prefix of the pool
+ /// @param prefix_len specifies length of the prefix of the pool
+ Pool4(const isc::asiolink::IOAddress& prefix,
+ uint8_t prefix_len);
+};
+
+/// @brief a pointer an IPv4 Pool
+typedef boost::shared_ptr<Pool4> Pool4Ptr;
+
+/// @brief a container for IPv4 Pools
+typedef std::vector<Pool4Ptr> Pool4Collection;
+
+/// @brief Pool information for IPv6 addresses and prefixes
+///
+/// It holds information about pool6, i.e. a range of IPv6 address space that
+/// is configured for DHCP allocation.
+class Pool6 : public Pool {
+public:
+
+ /// @brief specifies Pool type
+ ///
+ /// Currently there are 3 pool types defined in DHCPv6:
+ /// - Non-temporary addresses (conveyed in IA_NA)
+ /// - Temporary addresses (conveyed in IA_TA)
+ /// - Delegated Prefixes (conveyed in IA_PD)
+ /// There is a new one being worked on (IA_PA, see draft-ietf-dhc-host-gen-id), but
+ /// support for it is not planned for now.
+ typedef enum {
+ TYPE_IA,
+ TYPE_TA,
+ TYPE_PD
+ } Pool6Type;
+
+ /// @brief the constructor for Pool6 "min-max" style definition
+ ///
+ /// @param type type of the pool (IA, TA or PD)
+ /// @param first the first address in a pool
+ /// @param last the last address in a pool
+ Pool6(Pool6Type type, const isc::asiolink::IOAddress& first,
+ const isc::asiolink::IOAddress& last);
+
+ /// @brief the constructor for Pool6 "prefix/len" style definition
+ ///
+ /// @param type type of the pool (IA, TA or PD)
+ /// @param prefix specifies prefix of the pool
+ /// @param prefix_len specifies length of the prefix of the pool
+ Pool6(Pool6Type type, const isc::asiolink::IOAddress& prefix,
+ uint8_t prefix_len);
+
+ /// @brief returns pool type
+ ///
+ /// @return pool type
+ Pool6Type getType() const {
+ return (type_);
+ }
+
+private:
+ /// @brief defines a pool type
+ Pool6Type type_;
+
+ /// @brief prefix length
+ /// used by TYPE_PD only (zeroed for other types)
+ uint8_t prefix_len_;
+};
+
+/// @brief a pointer an IPv6 Pool
+typedef boost::shared_ptr<Pool6> Pool6Ptr;
+
+/// @brief a container for IPv6 Pools
+typedef std::vector<Pool6Ptr> Pool6Collection;
+
+} // end of isc::dhcp namespace
+} // end of isc namespace
+
+
+#endif // POOL_H
diff --git a/src/lib/dhcpsrv/subnet.cc b/src/lib/dhcpsrv/subnet.cc
new file mode 100644
index 0000000..78da250
--- /dev/null
+++ b/src/lib/dhcpsrv/subnet.cc
@@ -0,0 +1,204 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <asiolink/io_address.h>
+#include <dhcpsrv/addr_utilities.h>
+#include <dhcpsrv/subnet.h>
+
+#include <sstream>
+
+using namespace isc::asiolink;
+
+namespace isc {
+namespace dhcp {
+
+Subnet::Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
+ const Triplet<uint32_t>& t1,
+ const Triplet<uint32_t>& t2,
+ const Triplet<uint32_t>& valid_lifetime)
+ :id_(getNextID()), prefix_(prefix), prefix_len_(len), t1_(t1),
+ t2_(t2), valid_(valid_lifetime),
+ last_allocated_(lastAddrInPrefix(prefix, len)) {
+ if ( (prefix.getFamily() == AF_INET6 && len > 128) ||
+ (prefix.getFamily() == AF_INET && len > 32) ) {
+ isc_throw(BadValue, "Invalid prefix length specified for subnet: " << len);
+ }
+}
+
+bool Subnet::inRange(const isc::asiolink::IOAddress& addr) const {
+ IOAddress first = firstAddrInPrefix(prefix_, prefix_len_);
+ IOAddress last = lastAddrInPrefix(prefix_, prefix_len_);
+
+ return ((first <= addr) && (addr <= last));
+}
+
+void
+Subnet::addOption(OptionPtr& option, bool persistent /* = false */) {
+ validateOption(option);
+ options_.push_back(OptionDescriptor(option, persistent));
+}
+
+void
+Subnet::delOptions() {
+ options_.clear();
+}
+
+std::string Subnet::toText() const {
+ std::stringstream tmp;
+ tmp << prefix_.toText() << "/" << static_cast<unsigned int>(prefix_len_);
+ return (tmp.str());
+}
+
+Subnet4::Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
+ const Triplet<uint32_t>& t1,
+ const Triplet<uint32_t>& t2,
+ const Triplet<uint32_t>& valid_lifetime)
+ :Subnet(prefix, length, t1, t2, valid_lifetime) {
+ if (prefix.getFamily() != AF_INET) {
+ isc_throw(BadValue, "Non IPv4 prefix " << prefix.toText()
+ << " specified in subnet4");
+ }
+}
+
+void Subnet4::addPool4(const Pool4Ptr& pool) {
+ IOAddress first_addr = pool->getFirstAddress();
+ IOAddress last_addr = pool->getLastAddress();
+
+ if (!inRange(first_addr) || !inRange(last_addr)) {
+ isc_throw(BadValue, "Pool4 (" << first_addr.toText() << "-" << last_addr.toText()
+ << " does not belong in this (" << prefix_ << "/" << prefix_len_
+ << ") subnet4");
+ }
+
+ /// @todo: Check that pools do not overlap
+
+ pools_.push_back(pool);
+}
+
+Pool4Ptr Subnet4::getPool4(const isc::asiolink::IOAddress& hint /* = IOAddress("::")*/ ) {
+ Pool4Ptr candidate;
+ for (Pool4Collection::iterator pool = pools_.begin(); pool != pools_.end(); ++pool) {
+
+ // if we won't find anything better, then let's just use the first pool
+ if (!candidate) {
+ candidate = *pool;
+ }
+
+ // if the client provided a pool and there's a pool that hint is valid in,
+ // then let's use that pool
+ if ((*pool)->inRange(hint)) {
+ return (*pool);
+ }
+ }
+ return (candidate);
+}
+
+void
+Subnet4::validateOption(const OptionPtr& option) const {
+ if (!option) {
+ isc_throw(isc::BadValue, "option configured for subnet must not be NULL");
+ } else if (option->getUniverse() != Option::V4) {
+ isc_throw(isc::BadValue, "expected V4 option to be added to the subnet");
+ }
+}
+
+bool Subnet4::inPool(const isc::asiolink::IOAddress& addr) const {
+
+ // Let's start with checking if it even belongs to that subnet.
+ if (!inRange(addr)) {
+ return (false);
+ }
+
+ for (Pool4Collection::const_iterator pool = pools_.begin(); pool != pools_.end(); ++pool) {
+ if ((*pool)->inRange(addr)) {
+ return (true);
+ }
+ }
+ // there's no pool that address belongs to
+ return (false);
+}
+
+Subnet6::Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
+ const Triplet<uint32_t>& t1,
+ const Triplet<uint32_t>& t2,
+ const Triplet<uint32_t>& preferred_lifetime,
+ const Triplet<uint32_t>& valid_lifetime)
+ :Subnet(prefix, length, t1, t2, valid_lifetime),
+ preferred_(preferred_lifetime){
+ if (prefix.getFamily() != AF_INET6) {
+ isc_throw(BadValue, "Non IPv6 prefix " << prefix.toText()
+ << " specified in subnet6");
+ }
+}
+
+void Subnet6::addPool6(const Pool6Ptr& pool) {
+ IOAddress first_addr = pool->getFirstAddress();
+ IOAddress last_addr = pool->getLastAddress();
+
+ if (!inRange(first_addr) || !inRange(last_addr)) {
+ isc_throw(BadValue, "Pool6 (" << first_addr.toText() << "-" << last_addr.toText()
+ << " does not belong in this (" << prefix_ << "/" << prefix_len_
+ << ") subnet6");
+ }
+
+ /// @todo: Check that pools do not overlap
+
+ pools_.push_back(pool);
+}
+
+Pool6Ptr Subnet6::getPool6(const isc::asiolink::IOAddress& hint /* = IOAddress("::")*/ ) {
+ Pool6Ptr candidate;
+ for (Pool6Collection::iterator pool = pools_.begin(); pool != pools_.end(); ++pool) {
+
+ // if we won't find anything better, then let's just use the first pool
+ if (!candidate) {
+ candidate = *pool;
+ }
+
+ // if the client provided a pool and there's a pool that hint is valid in,
+ // then let's use that pool
+ if ((*pool)->inRange(hint)) {
+ return (*pool);
+ }
+ }
+ return (candidate);
+}
+
+void
+Subnet6::validateOption(const OptionPtr& option) const {
+ if (!option) {
+ isc_throw(isc::BadValue, "option configured for subnet must not be NULL");
+ } else if (option->getUniverse() != Option::V6) {
+ isc_throw(isc::BadValue, "expected V6 option to be added to the subnet");
+ }
+}
+
+bool Subnet6::inPool(const isc::asiolink::IOAddress& addr) const {
+
+ // Let's start with checking if it even belongs to that subnet.
+ if (!inRange(addr)) {
+ return (false);
+ }
+
+ for (Pool6Collection::const_iterator pool = pools_.begin(); pool != pools_.end(); ++pool) {
+ if ((*pool)->inRange(addr)) {
+ return (true);
+ }
+ }
+ // there's no pool that address belongs to
+ return (false);
+}
+
+} // end of isc::dhcp namespace
+} // end of isc namespace
diff --git a/src/lib/dhcpsrv/subnet.h b/src/lib/dhcpsrv/subnet.h
new file mode 100644
index 0000000..aa1ef1f
--- /dev/null
+++ b/src/lib/dhcpsrv/subnet.h
@@ -0,0 +1,518 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef SUBNET_H
+#define SUBNET_H
+
+#include <boost/shared_ptr.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+#include <boost/multi_index/mem_fun.hpp>
+#include <boost/multi_index/member.hpp>
+
+#include <asiolink/io_address.h>
+#include <dhcp/option.h>
+#include <dhcpsrv/pool.h>
+#include <dhcpsrv/triplet.h>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief a base class for Subnet4 and Subnet6
+///
+/// This class presents a common base for IPv4 and IPv6 subnets.
+/// In a physical sense, a subnet defines a single network link with all devices
+/// attached to it. In most cases all devices attached to a single link can
+/// share the same parameters. Therefore Subnet holds several values that are
+/// typically shared by all hosts: renew timer (T1), rebind timer (T2) and
+/// leased addresses lifetime (valid-lifetime). It also holds the set
+/// of DHCP option instances configured for the subnet. These options are
+/// included in DHCP messages being sent to clients which are connected
+/// to the particular subnet.
+///
+/// @todo: Implement support for options here
+
+
+/// @brief Unique indentifier for a subnet (both v4 and v6)
+typedef uint32_t SubnetID;
+
+class Subnet {
+public:
+
+ /// @brief Option descriptor.
+ ///
+ /// Option descriptor holds information about option configured for
+ /// a particular subnet. This information comprises the actual option
+ /// instance and information whether this option is sent to DHCP client
+ /// only on request (persistent = false) or always (persistent = true).
+ struct OptionDescriptor {
+ /// Option instance.
+ OptionPtr option;
+ /// Persistent flag, if true option is always sent to the client,
+ /// if false option is sent to the client on request.
+ bool persistent;
+
+ /// @brief Constructor.
+ ///
+ /// @param opt option
+ /// @param persist if true option is always sent.
+ OptionDescriptor(OptionPtr& opt, bool persist)
+ : option(opt), persistent(persist) {};
+
+ /// @brief Constructor
+ ///
+ /// @param persist if true option is always sent.
+ OptionDescriptor(bool persist)
+ : option(OptionPtr()), persistent(persist) {};
+ };
+
+ /// @brief Extractor class to extract key with another key.
+ ///
+ /// This class solves the problem of accessing index key values
+ /// that are stored in objects nested in other objects.
+ /// Each OptionDescriptor structure contains the OptionPtr object.
+ /// The value retured by one of its accessors (getType) is used
+ /// as an indexing value in the multi_index_container defined below.
+ /// There is no easy way to mark that value returned by Option::getType
+ /// should be an index of this multi_index_container. There are standard
+ /// key extractors such as 'member' or 'mem_fun' but they are not
+ /// sufficient here. The former can be used to mark that member of
+ /// the structure that is held in the container should be used as an
+ /// indexing value. The latter can be used if the indexing value is
+ /// a product of the class being held in the container. In this complex
+ /// scenario when the indexing value is a product of the function that
+ /// is wrapped by the structure, this new extractor template has to be
+ /// defined. The template class provides a 'chain' of two extractors
+ /// to access the value returned by nested object and to use it as
+ /// indexing value.
+ /// For some more examples of complex keys see:
+ /// http://www.cs.brown.edu/~jwicks/boost/libs/multi_index/doc/index.html
+ ///
+ /// @tparam KeyExtractor1 extractor used to access data in
+ /// OptionDescriptor::option
+ /// @tparam KeyExtractor2 extractor used to access
+ /// OptionDescriptor::option member.
+ template<typename KeyExtractor1, typename KeyExtractor2>
+ class KeyFromKey {
+ public:
+ typedef typename KeyExtractor1::result_type result_type;
+
+ /// @brief Constructor.
+ KeyFromKey()
+ : key1_(KeyExtractor1()), key2_(KeyExtractor2()) { };
+
+ /// @brief Extract key with another key.
+ ///
+ /// @param arg the key value.
+ ///
+ /// @tparam key value type.
+ template<typename T>
+ result_type operator() (T& arg) const {
+ return (key1_(key2_(arg)));
+ }
+ private:
+ KeyExtractor1 key1_; ///< key 1.
+ KeyExtractor2 key2_; ///< key 2.
+ };
+
+ /// @brief Multi index container for DHCP option descriptors.
+ ///
+ /// This container comprises three indexes to access option
+ /// descriptors:
+ /// - sequenced index: used to access elements in the order they
+ /// have been added to the container,
+ /// - option type index: used to search option descriptors containing
+ /// options with specific option code (aka option type).
+ /// - persistency flag index: used to search option descriptors with
+ /// 'persistent' flag set to true.
+ ///
+ /// This container is the equivalent of three separate STL containers:
+ /// - std::list of all options,
+ /// - std::multimap of options with option code used as a multimap key,
+ /// - std::multimap of option descriptors with option persistency flag
+ /// used as a multimap key.
+ /// The major advantage of this container over 3 separate STL containers
+ /// is automatic synchronization of all indexes when elements are added,
+ /// removed or modified in the container. With separate containers,
+ /// the synchronization would have to be guaranteed by the Subnet class
+ /// code. This would increase code complexity and presumably it would
+ /// be much harder to add new search criteria (indexes).
+ ///
+ /// @todo we may want to search for options using option spaces when
+ /// they are implemented.
+ ///
+ /// @see http://www.boost.org/doc/libs/1_51_0/libs/multi_index/doc/index.html
+ typedef boost::multi_index_container<
+ // Container comprises elements of OptionDescriptor type.
+ OptionDescriptor,
+ // Here we start enumerating various indexes.
+ boost::multi_index::indexed_by<
+ // Sequenced index allows accessing elements in the same way
+ // as elements in std::list.
+ // Sequenced is an index #0.
+ boost::multi_index::sequenced<>,
+ // Start definition of index #1.
+ boost::multi_index::hashed_non_unique<
+ // KeyFromKey is the index key extractor that allows accessing
+ // option type being held by the OptionPtr through
+ // OptionDescriptor structure.
+ KeyFromKey<
+ // Use option type as the index key. The type is held
+ // in OptionPtr object so we have to call Option::getType
+ // to retrieve this key for each element.
+ boost::multi_index::mem_fun<
+ Option,
+ uint16_t,
+ &Option::getType
+ >,
+ // Indicate that OptionPtr is a member of
+ // OptionDescriptor structure.
+ boost::multi_index::member<
+ OptionDescriptor,
+ OptionPtr,
+ &OptionDescriptor::option
+ >
+ >
+ >,
+ // Start definition of index #2.
+ // Use 'persistent' struct member as a key.
+ boost::multi_index::hashed_non_unique<
+ boost::multi_index::member<
+ OptionDescriptor,
+ bool,
+ &OptionDescriptor::persistent
+ >
+ >
+ >
+ > OptionContainer;
+
+ /// Type of the index #1 - option type.
+ typedef OptionContainer::nth_index<1>::type OptionContainerTypeIndex;
+ /// Pair of iterators to represent the range of options having the
+ /// same option type value. The first element in this pair represents
+ /// the begining of the range, the second element represents the end.
+ typedef std::pair<OptionContainerTypeIndex::const_iterator,
+ OptionContainerTypeIndex::const_iterator> OptionContainerTypeRange;
+ /// Type of the index #2 - option persistency flag.
+ typedef OptionContainer::nth_index<2>::type OptionContainerPersistIndex;
+
+ /// @brief checks if specified address is in range
+ bool inRange(const isc::asiolink::IOAddress& addr) const;
+
+ /// @brief Add new option instance to the collection.
+ ///
+ /// @param option option instance.
+ /// @param persistent if true, send an option regardless if client
+ /// requested it or not.
+ ///
+ /// @throw isc::BadValue if invalid option provided.
+ void addOption(OptionPtr& option, bool persistent = false);
+
+ /// @brief Delete all options configured for the subnet.
+ void delOptions();
+
+ /// @brief checks if the specified address is in pools
+ ///
+ /// Note the difference between inSubnet() and inPool(). For a given
+ /// subnet (e.g. 2001::/64) there may be one or more pools defined
+ /// that may or may not cover entire subnet, e.g. pool 2001::1-2001::10).
+ /// inPool() returning true implies inSubnet(), but the reverse implication
+ /// is not always true. For the given example, 2001::1234:abcd would return
+ /// true for inSubnet(), but false for inPool() check.
+ ///
+ /// @param addr this address will be checked if it belongs to any pools in
+ /// that subnet
+ /// @return true if the address is in any of the pools
+ virtual bool inPool(const isc::asiolink::IOAddress& addr) const = 0;
+
+ /// @brief return valid-lifetime for addresses in that prefix
+ Triplet<uint32_t> getValid() const {
+ return (valid_);
+ }
+
+ /// @brief returns T1 (renew timer), expressed in seconds
+ Triplet<uint32_t> getT1() const {
+ return (t1_);
+ }
+
+ /// @brief returns T2 (rebind timer), expressed in seconds
+ Triplet<uint32_t> getT2() const {
+ return (t2_);
+ }
+
+ /// @brief Return a collection of options.
+ ///
+ /// @return reference to collection of options configured for a subnet.
+ /// The returned reference is valid as long as the Subnet object which
+ /// returned it still exists.
+ const OptionContainer& getOptions() const {
+ return (options_);
+ }
+
+ /// @brief returns the last address that was tried from this pool
+ ///
+ /// This method returns the last address that was attempted to be allocated
+ /// from this subnet. This is used as helper information for the next
+ /// iteration of the allocation algorithm.
+ ///
+ /// @todo: Define map<SubnetID, IOAddress> somewhere in the
+ /// AllocEngine::IterativeAllocator and keep the data there
+ ///
+ /// @return address that was last tried from this pool
+ isc::asiolink::IOAddress getLastAllocated() const {
+ return (last_allocated_);
+ }
+
+ /// @brief sets the last address that was tried from this pool
+ ///
+ /// This method sets the last address that was attempted to be allocated
+ /// from this subnet. This is used as helper information for the next
+ /// iteration of the allocation algorithm.
+ ///
+ /// @todo: Define map<SubnetID, IOAddress> somewhere in the
+ /// AllocEngine::IterativeAllocator and keep the data there
+ void setLastAllocated(const isc::asiolink::IOAddress& addr) {
+ last_allocated_ = addr;
+ }
+
+ /// @brief returns unique ID for that subnet
+ /// @return unique ID for that subnet
+ SubnetID getID() const { return (id_); }
+
+ /// @brief returns subnet parameters (prefix and prefix length)
+ ///
+ /// @return (prefix, prefix length) pair
+ std::pair<isc::asiolink::IOAddress, uint8_t> get() const {
+ return (std::make_pair(prefix_, prefix_len_));
+ }
+
+ /// @brief returns textual representation of the subnet (e.g. "2001:db8::/64")
+ ///
+ /// @return textual representation
+ virtual std::string toText() const;
+
+protected:
+ /// @brief protected constructor
+ //
+ /// By making the constructor protected, we make sure that noone will
+ /// ever instantiate that class. Pool4 and Pool6 should be used instead.
+ Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
+ const Triplet<uint32_t>& t1,
+ const Triplet<uint32_t>& t2,
+ const Triplet<uint32_t>& valid_lifetime);
+
+ /// @brief virtual destructor
+ ///
+ /// A virtual destructor is needed because other classes
+ /// derive from this class.
+ virtual ~Subnet() { };
+
+ /// @brief returns the next unique Subnet-ID
+ ///
+ /// @return the next unique Subnet-ID
+ static SubnetID getNextID() {
+ static SubnetID id = 0;
+ return (id++);
+ }
+
+ /// @brief Check if option is valid and can be added to a subnet.
+ ///
+ /// @param option option to be validated.
+ virtual void validateOption(const OptionPtr& option) const = 0;
+
+ /// @brief subnet-id
+ ///
+ /// Subnet-id is a unique value that can be used to find or identify
+ /// a Subnet4 or Subnet6.
+ SubnetID id_;
+
+ /// @brief a prefix of the subnet
+ isc::asiolink::IOAddress prefix_;
+
+ /// @brief a prefix length of the subnet
+ uint8_t prefix_len_;
+
+ /// @brief a tripet (min/default/max) holding allowed renew timer values
+ Triplet<uint32_t> t1_;
+
+ /// @brief a tripet (min/default/max) holding allowed rebind timer values
+ Triplet<uint32_t> t2_;
+
+ /// @brief a tripet (min/default/max) holding allowed valid lifetime values
+ Triplet<uint32_t> valid_;
+
+ /// @brief a collection of DHCP options configured for a subnet.
+ OptionContainer options_;
+
+ /// @brief last allocated address
+ ///
+ /// This is the last allocated address that was previously allocated from
+ /// this particular subnet. Some allocation algorithms (e.g. iterative) use
+ /// that value, others do not. It should be noted that although the value
+ /// is usually correct, there are cases when it is invalid, e.g. after
+ /// removing a pool, restarting or changing allocation algorithms. For
+ /// that purpose it should be only considered a help that should not be
+ /// fully trusted.
+ isc::asiolink::IOAddress last_allocated_;
+};
+
+/// @brief A configuration holder for IPv4 subnet.
+///
+/// This class represents an IPv4 subnet.
+class Subnet4 : public Subnet {
+public:
+
+ /// @brief Constructor with all parameters
+ ///
+ /// @param prefix Subnet4 prefix
+ /// @param length prefix length
+ /// @param t1 renewal timer (in seconds)
+ /// @param t2 rebind timer (in seconds)
+ /// @param valid_lifetime preferred lifetime of leases (in seconds)
+ Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
+ const Triplet<uint32_t>& t1,
+ const Triplet<uint32_t>& t2,
+ const Triplet<uint32_t>& valid_lifetime);
+
+ /// @brief Returns a pool that specified address belongs to
+ ///
+ /// @param hint address that the returned pool should cover (optional)
+ /// @return Pointer to found pool4 (or NULL)
+ Pool4Ptr getPool4(const isc::asiolink::IOAddress& hint =
+ isc::asiolink::IOAddress("0.0.0.0"));
+
+ /// @brief Adds a new pool.
+ /// @param pool pool to be added
+ void addPool4(const Pool4Ptr& pool);
+
+ /// @brief returns all pools
+ ///
+ /// The reference is only valid as long as the object that returned it.
+ ///
+ /// @return a collection of all pools
+ const Pool4Collection& getPools() const {
+ return pools_;
+ }
+
+ /// @brief checks if the specified address is in pools
+ ///
+ /// See the description in \ref Subnet::inPool().
+ ///
+ /// @param addr this address will be checked if it belongs to any pools in that subnet
+ /// @return true if the address is in any of the pools
+ bool inPool(const isc::asiolink::IOAddress& addr) const;
+
+protected:
+
+ /// @brief Check if option is valid and can be added to a subnet.
+ ///
+ /// @param option option to be validated.
+ ///
+ /// @throw isc::BadValue if provided option is invalid.
+ virtual void validateOption(const OptionPtr& option) const;
+
+ /// @brief collection of pools in that list
+ Pool4Collection pools_;
+};
+
+/// @brief A pointer to a Subnet4 object
+typedef boost::shared_ptr<Subnet4> Subnet4Ptr;
+
+/// @brief A collection of Subnet6 objects
+typedef std::vector<Subnet4Ptr> Subnet4Collection;
+
+
+/// @brief A configuration holder for IPv6 subnet.
+///
+/// This class represents an IPv6 subnet.
+class Subnet6 : public Subnet {
+public:
+
+ /// @brief Constructor with all parameters
+ ///
+ /// @param prefix Subnet6 prefix
+ /// @param length prefix length
+ /// @param t1 renewal timer (in seconds)
+ /// @param t2 rebind timer (in seconds)
+ /// @param preferred_lifetime preferred lifetime of leases (in seconds)
+ /// @param valid_lifetime preferred lifetime of leases (in seconds)
+ Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
+ const Triplet<uint32_t>& t1,
+ const Triplet<uint32_t>& t2,
+ const Triplet<uint32_t>& preferred_lifetime,
+ const Triplet<uint32_t>& valid_lifetime);
+
+ /// @brief Returns preverred lifetime (in seconds)
+ ///
+ /// @return a triplet with preferred lifetime
+ Triplet<uint32_t> getPreferred() const {
+ return (preferred_);
+ }
+
+ /// @brief Returns a pool that specified address belongs to
+ ///
+ /// @param hint address that the returned pool should cover (optional)
+ /// @return Pointer to found pool6 (or NULL)
+ Pool6Ptr getPool6(const isc::asiolink::IOAddress& hint =
+ isc::asiolink::IOAddress("::"));
+
+ /// @brief Adds a new pool.
+ /// @param pool pool to be added
+ void addPool6(const Pool6Ptr& pool);
+
+ /// @brief returns all pools
+ ///
+ /// The reference is only valid as long as the object that
+ /// returned it.
+ ///
+ /// @return a collection of all pools
+ const Pool6Collection& getPools() const {
+ return pools_;
+ }
+
+ /// @brief checks if the specified address is in pools
+ ///
+ /// See the description in \ref Subnet::inPool().
+ ///
+ /// @param addr this address will be checked if it belongs to any pools in that subnet
+ /// @return true if the address is in any of the pools
+ bool inPool(const isc::asiolink::IOAddress& addr) const;
+
+protected:
+
+ /// @brief Check if option is valid and can be added to a subnet.
+ ///
+ /// @param option option to be validated.
+ ///
+ /// @throw isc::BadValue if provided option is invalid.
+ virtual void validateOption(const OptionPtr& option) const;
+
+ /// @brief collection of pools in that list
+ Pool6Collection pools_;
+
+ /// @brief a triplet with preferred lifetime (in seconds)
+ Triplet<uint32_t> preferred_;
+};
+
+/// @brief A pointer to a Subnet6 object
+typedef boost::shared_ptr<Subnet6> Subnet6Ptr;
+
+/// @brief A collection of Subnet6 objects
+typedef std::vector<Subnet6Ptr> Subnet6Collection;
+
+} // end of isc::dhcp namespace
+} // end of isc namespace
+
+#endif // SUBNET_T
diff --git a/src/lib/dhcpsrv/tests/Makefile.am b/src/lib/dhcpsrv/tests/Makefile.am
new file mode 100644
index 0000000..8de5fda
--- /dev/null
+++ b/src/lib/dhcpsrv/tests/Makefile.am
@@ -0,0 +1,70 @@
+SUBDIRS = .
+
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/lib/dhcp/tests\"
+AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+# Some versions of GCC warn about some versions of Boost regarding
+# missing initializer for members in its posix_time.
+# https://svn.boost.org/trac/boost/ticket/3477
+# But older GCC compilers don't have the flag.
+AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS_ENVIRONMENT = \
+ $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
+
+TESTS =
+if HAVE_GTEST
+TESTS += libdhcpsrv_unittests
+
+libdhcpsrv_unittests_SOURCES = run_unittests.cc
+libdhcpsrv_unittests_SOURCES += addr_utilities_unittest.cc
+libdhcpsrv_unittests_SOURCES += alloc_engine_unittest.cc
+libdhcpsrv_unittests_SOURCES += cfgmgr_unittest.cc
+libdhcpsrv_unittests_SOURCES += lease_mgr_factory_unittest.cc
+libdhcpsrv_unittests_SOURCES += lease_mgr_unittest.cc
+libdhcpsrv_unittests_SOURCES += memfile_lease_mgr_unittest.cc
+if HAVE_MYSQL
+libdhcpsrv_unittests_SOURCES += mysql_lease_mgr_unittest.cc
+endif
+libdhcpsrv_unittests_SOURCES += pool_unittest.cc
+libdhcpsrv_unittests_SOURCES += schema_copy.h
+libdhcpsrv_unittests_SOURCES += subnet_unittest.cc
+libdhcpsrv_unittests_SOURCES += triplet_unittest.cc
+
+libdhcpsrv_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
+if HAVE_MYSQL
+libdhcpsrv_unittests_CPPFLAGS += $(MYSQL_CPPFLAGS)
+endif
+
+libdhcpsrv_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+if HAVE_MYSQL
+libdhcpsrv_unittests_LDFLAGS += $(MYSQL_LIBS)
+endif
+
+libdhcpsrv_unittests_CXXFLAGS = $(AM_CXXFLAGS)
+if USE_CLANGPP
+# This is to workaround unused variables tcout and tcerr in
+# log4cplus's streams.h and unused parameters from some of the
+# Boost headers.
+libdhcpsrv_unittests_CXXFLAGS += -Wno-unused-variable -Wno-unused-parameter
+endif
+
+libdhcpsrv_unittests_LDADD = $(top_builddir)/src/lib/dhcpsrv/libb10-dhcpsrv.la
+libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
+libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
+libdhcpsrv_unittests_LDADD += $(GTEST_LDADD)
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/dhcpsrv/tests/addr_utilities_unittest.cc b/src/lib/dhcpsrv/tests/addr_utilities_unittest.cc
new file mode 100644
index 0000000..19f08a9
--- /dev/null
+++ b/src/lib/dhcpsrv/tests/addr_utilities_unittest.cc
@@ -0,0 +1,156 @@
+
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <dhcpsrv/addr_utilities.h>
+
+#include <gtest/gtest.h>
+
+#include <vector>
+
+#include <stdint.h>
+#include <stdlib.h>
+
+using namespace std;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+
+// This test verifies that lastAddrInPrefix is able to handle IPv4 operations.
+TEST(AddrUtilitiesTest, lastAddrInPrefix4) {
+ IOAddress addr1("192.0.2.1");
+
+ // Prefixes rounded to addresses are easy...
+ EXPECT_EQ("192.255.255.255", lastAddrInPrefix(addr1, 8).toText());
+ EXPECT_EQ("192.0.255.255", lastAddrInPrefix(addr1, 16).toText());
+ EXPECT_EQ("192.0.2.255", lastAddrInPrefix(addr1, 24).toText());
+
+ // these are trickier
+ EXPECT_EQ("192.0.2.127", lastAddrInPrefix(addr1, 25).toText());
+ EXPECT_EQ("192.0.2.63", lastAddrInPrefix(addr1, 26).toText());
+ EXPECT_EQ("192.0.2.31", lastAddrInPrefix(addr1, 27).toText());
+ EXPECT_EQ("192.0.2.15", lastAddrInPrefix(addr1, 28).toText());
+ EXPECT_EQ("192.0.2.7", lastAddrInPrefix(addr1, 29).toText());
+ EXPECT_EQ("192.0.2.3", lastAddrInPrefix(addr1, 30).toText());
+
+ // that doesn't make much sense as /31 subnet consists of network address
+ // and a broadcast address, with 0 usable addresses.
+ EXPECT_EQ("192.0.2.1", lastAddrInPrefix(addr1, 31).toText());
+ EXPECT_EQ("192.0.2.1", lastAddrInPrefix(addr1, 32).toText());
+
+ // Let's check extreme cases
+ IOAddress anyAddr("0.0.0.0");
+ EXPECT_EQ("127.255.255.255", lastAddrInPrefix(anyAddr, 1).toText());
+ EXPECT_EQ("255.255.255.255", lastAddrInPrefix(anyAddr, 0).toText());
+ EXPECT_EQ("0.0.0.0", lastAddrInPrefix(anyAddr, 32).toText());
+}
+
+// This test checks if firstAddrInPrefix is able to handle IPv4 operations.
+TEST(AddrUtilitiesTest, firstAddrInPrefix4) {
+ IOAddress addr1("192.223.2.255");
+
+ // Prefixes rounded to addresses are easy...
+ EXPECT_EQ("192.0.0.0", firstAddrInPrefix(addr1, 8).toText());
+ EXPECT_EQ("192.223.0.0", firstAddrInPrefix(addr1, 16).toText());
+ EXPECT_EQ("192.223.2.0", firstAddrInPrefix(addr1, 24).toText());
+
+ // these are trickier
+ EXPECT_EQ("192.223.2.128", firstAddrInPrefix(addr1, 25).toText());
+ EXPECT_EQ("192.223.2.192", firstAddrInPrefix(addr1, 26).toText());
+ EXPECT_EQ("192.223.2.224", firstAddrInPrefix(addr1, 27).toText());
+ EXPECT_EQ("192.223.2.240", firstAddrInPrefix(addr1, 28).toText());
+ EXPECT_EQ("192.223.2.248", firstAddrInPrefix(addr1, 29).toText());
+ EXPECT_EQ("192.223.2.252", firstAddrInPrefix(addr1, 30).toText());
+
+ // that doesn't make much sense as /31 subnet consists of network address
+ // and a broadcast address, with 0 usable addresses.
+ EXPECT_EQ("192.223.2.254", firstAddrInPrefix(addr1, 31).toText());
+ EXPECT_EQ("192.223.2.255", firstAddrInPrefix(addr1, 32).toText());
+
+ // Let's check extreme cases.
+ IOAddress bcast("255.255.255.255");
+ EXPECT_EQ("128.0.0.0", firstAddrInPrefix(bcast, 1).toText());
+ EXPECT_EQ("0.0.0.0", firstAddrInPrefix(bcast, 0).toText());
+ EXPECT_EQ("255.255.255.255", firstAddrInPrefix(bcast, 32).toText());
+
+}
+
+/// This test checks if lastAddrInPrefix properly supports IPv6 operations
+TEST(AddrUtilitiesTest, lastAddrInPrefix6) {
+ IOAddress addr1("2001:db8:1:1234:5678:abcd:1234:beef");
+
+ // Prefixes rounded to nibbles are easy...
+ EXPECT_EQ("2001:db8:1:1234:5678:abcd:1234:ffff",
+ lastAddrInPrefix(addr1, 112).toText());
+ EXPECT_EQ("2001:db8:1:1234:5678:abcd:123f:ffff",
+ lastAddrInPrefix(addr1, 108).toText());
+ EXPECT_EQ("2001:db8:1:1234:5678:abcd:12ff:ffff",
+ lastAddrInPrefix(addr1, 104).toText());
+ EXPECT_EQ("2001:db8:1:1234:ffff:ffff:ffff:ffff",
+ lastAddrInPrefix(addr1, 64).toText());
+
+ IOAddress addr2("2001::");
+
+ // These are tricker, though, as they are done in 1 bit increments
+
+ // the last address in 2001::/127 pool should be 2001::1
+ EXPECT_EQ("2001::1", lastAddrInPrefix(addr2, 127).toText());
+
+ EXPECT_EQ("2001::3", lastAddrInPrefix(addr2, 126).toText());
+ EXPECT_EQ("2001::7", lastAddrInPrefix(addr2, 125).toText());
+ EXPECT_EQ("2001::f", lastAddrInPrefix(addr2, 124).toText());
+ EXPECT_EQ("2001::1f", lastAddrInPrefix(addr2, 123).toText());
+ EXPECT_EQ("2001::3f", lastAddrInPrefix(addr2, 122).toText());
+ EXPECT_EQ("2001::7f", lastAddrInPrefix(addr2, 121).toText());
+ EXPECT_EQ("2001::ff", lastAddrInPrefix(addr2, 120).toText());
+
+ // Let's check extreme cases
+ IOAddress anyAddr("::");
+ EXPECT_EQ("7fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
+ lastAddrInPrefix(anyAddr, 1).toText());
+ EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
+ lastAddrInPrefix(anyAddr, 0).toText());
+ EXPECT_EQ("::", lastAddrInPrefix(anyAddr, 128).toText());
+}
+
+/// This test checks if firstAddrInPrefix properly supports IPv6 operations
+TEST(AddrUtilitiesTest, firstAddrInPrefix6) {
+ IOAddress addr1("2001:db8:1:1234:5678:1234:abcd:beef");
+
+ // Prefixes rounded to nibbles are easy...
+ EXPECT_EQ("2001:db8:1:1234:5678:1234::",
+ firstAddrInPrefix(addr1, 96).toText());
+ EXPECT_EQ("2001:db8:1:1234:5678:1230::",
+ firstAddrInPrefix(addr1, 92).toText());
+ EXPECT_EQ("2001:db8:1:1234:5678:1200::",
+ firstAddrInPrefix(addr1, 88).toText());
+ EXPECT_EQ("2001:db8:1:1234::",
+ firstAddrInPrefix(addr1, 64).toText());
+
+ IOAddress addr2("2001::ffff");
+
+ // These are tricker, though, as they are done in 1 bit increments
+
+ // the first address in 2001::/127 pool should be 2001::1
+ EXPECT_EQ("2001::fffe", firstAddrInPrefix(addr2, 127).toText());
+
+ EXPECT_EQ("2001::fffc", firstAddrInPrefix(addr2, 126).toText());
+ EXPECT_EQ("2001::fff8", firstAddrInPrefix(addr2, 125).toText());
+ EXPECT_EQ("2001::fff0", firstAddrInPrefix(addr2, 124).toText());
+ EXPECT_EQ("2001::ffe0", firstAddrInPrefix(addr2, 123).toText());
+ EXPECT_EQ("2001::ffc0", firstAddrInPrefix(addr2, 122).toText());
+ EXPECT_EQ("2001::ff80", firstAddrInPrefix(addr2, 121).toText());
+ EXPECT_EQ("2001::ff00", firstAddrInPrefix(addr2, 120).toText());
+}
diff --git a/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc b/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
new file mode 100644
index 0000000..dcfb68b
--- /dev/null
+++ b/src/lib/dhcpsrv/tests/alloc_engine_unittest.cc
@@ -0,0 +1,340 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <asiolink/io_address.h>
+#include <dhcp/duid.h>
+#include <dhcpsrv/alloc_engine.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/lease_mgr.h>
+#include <dhcpsrv/lease_mgr_factory.h>
+#include <dhcpsrv/memfile_lease_mgr.h>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <sstream>
+#include <map>
+
+using namespace std;
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+
+namespace {
+
+class NakedAllocEngine : public AllocEngine {
+public:
+ NakedAllocEngine(AllocEngine::AllocType engine_type, unsigned int attempts)
+ :AllocEngine(engine_type, attempts) {
+ }
+ using AllocEngine::Allocator;
+ using AllocEngine::IterativeAllocator;
+};
+
+// empty class for now, but may be extended once Addr6 becomes bigger
+class AllocEngineTest : public ::testing::Test {
+public:
+ AllocEngineTest() {
+ duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0x42)));
+ iaid_ = 42;
+
+ // instantiate cfg_mgr
+ CfgMgr& cfg_mgr = CfgMgr::instance();
+
+ subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
+ pool_ = Pool6Ptr(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1::10"),
+ IOAddress("2001:db8:1::20")));
+ subnet_->addPool6(pool_);
+ cfg_mgr.addSubnet6(subnet_);
+
+ factory_.create("type=memfile");
+ }
+
+ void checkLease6(const Lease6Ptr& lease) {
+ // that is belongs to the right subnet
+ EXPECT_EQ(lease->subnet_id_, subnet_->getID());
+ EXPECT_TRUE(subnet_->inRange(lease->addr_));
+ EXPECT_TRUE(subnet_->inPool(lease->addr_));
+
+ // that it have proper parameters
+ EXPECT_EQ(iaid_, lease->iaid_);
+ EXPECT_EQ(subnet_->getValid(), lease->valid_lft_);
+ EXPECT_EQ(subnet_->getPreferred(), lease->preferred_lft_);
+ EXPECT_EQ(subnet_->getT1(), lease->t1_);
+ EXPECT_EQ(subnet_->getT2(), lease->t2_);
+ EXPECT_EQ(0, lease->prefixlen_); // this is IA_NA, not IA_PD
+ EXPECT_TRUE(false == lease->fqdn_fwd_);
+ EXPECT_TRUE(false == lease->fqdn_rev_);
+ EXPECT_TRUE(*lease->duid_ == *duid_);
+ // @todo: check cltt
+ }
+
+ ~AllocEngineTest() {
+ factory_.destroy();
+ }
+
+ DuidPtr duid_;
+ uint32_t iaid_;
+ Subnet6Ptr subnet_;
+ Pool6Ptr pool_;
+ LeaseMgrFactory factory_;
+};
+
+// This test checks if the Allocation Engine can be instantiated and that it
+// parses parameters string properly.
+TEST_F(AllocEngineTest, constructor) {
+ boost::scoped_ptr<AllocEngine> x;
+
+ // Hashed and random allocators are not supported yet
+ ASSERT_THROW(x.reset(new AllocEngine(AllocEngine::ALLOC_HASHED, 5)), NotImplemented);
+ ASSERT_THROW(x.reset(new AllocEngine(AllocEngine::ALLOC_RANDOM, 5)), NotImplemented);
+
+ ASSERT_NO_THROW(x.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 100)));
+}
+
+/// @todo: This method is taken from mysql_lease_mgr_utilities.cc from ticket
+/// #2342. Get rid of one instance once the code is merged
+void
+detailCompareLease6(const Lease6Ptr& first, const Lease6Ptr& second) {
+ EXPECT_EQ(first->type_, second->type_);
+
+ // Compare address strings - odd things happen when they are different
+ // as the EXPECT_EQ appears to call the operator uint32_t() function,
+ // which causes an exception to be thrown for IPv6 addresses.
+ EXPECT_EQ(first->addr_.toText(), second->addr_.toText());
+ EXPECT_EQ(first->prefixlen_, second->prefixlen_);
+ EXPECT_EQ(first->iaid_, second->iaid_);
+ EXPECT_TRUE(*first->duid_ == *second->duid_);
+ EXPECT_EQ(first->preferred_lft_, second->preferred_lft_);
+ EXPECT_EQ(first->valid_lft_, second->valid_lft_);
+ EXPECT_EQ(first->cltt_, second->cltt_);
+ EXPECT_EQ(first->subnet_id_, second->subnet_id_);
+}
+
+
+// This test checks if the simple allocation can succeed
+TEST_F(AllocEngineTest, simpleAlloc) {
+ 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("::"),
+ false);
+
+ // check that we got a lease
+ ASSERT_TRUE(lease);
+
+ // do all checks on the lease
+ checkLease6(lease);
+
+ // Check that the lease is indeed in LeaseMgr
+ Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->addr_);
+ ASSERT_TRUE(from_mgr);
+
+ // Now check that the lease in LeaseMgr has the same parameters
+ detailCompareLease6(lease, from_mgr);
+}
+
+// This test checks if the fake allocation (for SOLICIT) can succeed
+TEST_F(AllocEngineTest, fakeAlloc) {
+ 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("::"),
+ true);
+
+ // check that we got a lease
+ ASSERT_TRUE(lease);
+
+ // do all checks on the lease
+ checkLease6(lease);
+
+ // Check that the lease is NOT in LeaseMgr
+ Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->addr_);
+ ASSERT_FALSE(from_mgr);
+}
+
+// This test checks if the allocation with a hint that is valid (in range,
+// in pool and free) can succeed
+TEST_F(AllocEngineTest, allocWithValidHint) {
+ 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("2001:db8:1::15"),
+ false);
+
+ // check that we got a lease
+ ASSERT_TRUE(lease);
+
+ // we should get what we asked for
+ EXPECT_EQ(lease->addr_.toText(), "2001:db8:1::15");
+
+ // do all checks on the lease
+ checkLease6(lease);
+
+ // Check that the lease is indeed in LeaseMgr
+ Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->addr_);
+ ASSERT_TRUE(from_mgr);
+
+ // Now check that the lease in LeaseMgr has the same parameters
+ detailCompareLease6(lease, from_mgr);
+}
+
+// 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) {
+ 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
+ DuidPtr duid2 = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0xff)));
+ Lease6Ptr used(new Lease6(Lease6::LEASE_IA_NA, IOAddress("2001:db8:1::1f"),
+ duid2, 1, 2, 3, 4, 5, subnet_->getID()));
+ ASSERT_TRUE(LeaseMgrFactory::instance().addLease(used));
+
+ // another client comes in and request an address that is in pool, but
+ // unfortunately it is used already. The same address must not be allocated
+ // twice.
+ Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
+ IOAddress("2001:db8:1::1f"),
+ false);
+ // check that we got a lease
+ ASSERT_TRUE(lease);
+
+ // allocated address must be different
+ EXPECT_TRUE(used->addr_.toText() != lease->addr_.toText());
+
+ // we should NOT get what we asked for, because it is used already
+ EXPECT_TRUE(lease->addr_.toText() != "2001:db8:1::1f");
+
+ // do all checks on the lease
+ checkLease6(lease);
+
+ // Check that the lease is indeed in LeaseMgr
+ Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->addr_);
+ ASSERT_TRUE(from_mgr);
+
+ // Now check that the lease in LeaseMgr has the same parameters
+ detailCompareLease6(lease, from_mgr);
+}
+
+// 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) {
+ 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
+ // supported lease. Allocation engine should ignore it and carry on
+ // with the normal allocation
+ Lease6Ptr lease = engine->allocateAddress6(subnet_, duid_, iaid_,
+ IOAddress("3000::abc"),
+ false);
+ // check that we got a lease
+ ASSERT_TRUE(lease);
+
+ // we should NOT get what we asked for, because it is used already
+ EXPECT_TRUE(lease->addr_.toText() != "3000::abc");
+
+ // do all checks on the lease
+ checkLease6(lease);
+
+ // Check that the lease is indeed in LeaseMgr
+ Lease6Ptr from_mgr = LeaseMgrFactory::instance().getLease6(lease->addr_);
+ ASSERT_TRUE(from_mgr);
+
+ // Now check that the lease in LeaseMgr has the same parameters
+ detailCompareLease6(lease, from_mgr);
+}
+
+// This test verifies that the allocator picks addresses that belong to the
+// pool
+TEST_F(AllocEngineTest, IterativeAllocator) {
+ boost::scoped_ptr<NakedAllocEngine::Allocator>
+ alloc(new NakedAllocEngine::IterativeAllocator());
+
+ for (int i = 0; i < 1000; ++i) {
+ IOAddress candidate = alloc->pickAddress(subnet_, duid_, IOAddress("::"));
+ EXPECT_TRUE(subnet_->inPool(candidate));
+ }
+}
+
+
+// This test verifies that the iterative allocator really walks over all addresses
+// in all pools in specified subnet. It also must not pick the same address twice
+// unless it runs out of pool space and must start over.
+TEST_F(AllocEngineTest, IterativeAllocator_manyPools) {
+ NakedAllocEngine::IterativeAllocator* alloc = new NakedAllocEngine::IterativeAllocator();
+
+ // let's start from 2, as there is 2001:db8:1::10 - 2001:db8:1::20 pool already.
+ for (int i = 2; i < 10; ++i) {
+ stringstream min, max;
+
+ min << "2001:db8:1::" << hex << i*16 + 1;
+ max << "2001:db8:1::" << hex << i*16 + 9;
+
+ Pool6Ptr pool(new Pool6(Pool6::TYPE_IA, IOAddress(min.str()),
+ IOAddress(max.str())));
+ // cout << "Adding pool: " << min.str() << "-" << max.str() << endl;
+ subnet_->addPool6(pool);
+ }
+
+ int total = 17 + 8*9; // first pool (::10 - ::20) has 17 addresses in it,
+ // there are 8 extra pools with 9 addresses in each.
+
+ // Let's keep picked addresses here and check their uniqueness.
+ std::map<IOAddress, int> generated_addrs;
+ int cnt = 0;
+ while (++cnt) {
+ IOAddress candidate = alloc->pickAddress(subnet_, duid_, IOAddress("::"));
+ EXPECT_TRUE(subnet_->inPool(candidate));
+
+ // One way to easily verify that the iterative allocator really works is
+ // to uncomment the following line and observe its output that it
+ // covers all defined subnets.
+ // cout << candidate.toText() << endl;
+
+ if (generated_addrs.find(candidate) == generated_addrs.end()) {
+ // we haven't had this
+ generated_addrs[candidate] = 0;
+ } else {
+ // we have seen this address before. That should mean that we
+ // iterated over all addresses.
+ if (generated_addrs.size() == total) {
+ // we have exactly the number of address in all pools
+ break;
+ }
+ ADD_FAILURE() << "Too many or not enough unique addresses generated.";
+ break;
+ }
+
+ if ( cnt>total ) {
+ ADD_FAILURE() << "Too many unique addresses generated.";
+ break;
+ }
+ }
+
+ delete alloc;
+}
+
+}; // end of anonymous namespace
diff --git a/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc b/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc
new file mode 100644
index 0000000..7b23bcf
--- /dev/null
+++ b/src/lib/dhcpsrv/tests/cfgmgr_unittest.cc
@@ -0,0 +1,115 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <dhcpsrv/cfgmgr.h>
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <sstream>
+
+#include <arpa/inet.h>
+
+using namespace std;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+using namespace isc::util;
+using namespace isc;
+
+// don't import the entire boost namespace. It will unexpectedly hide uint8_t
+// for some systems.
+using boost::scoped_ptr;
+
+namespace {
+
+class CfgMgrTest : public ::testing::Test {
+public:
+ CfgMgrTest() {
+ }
+
+ ~CfgMgrTest() {
+ CfgMgr::instance().deleteSubnets6();
+ }
+};
+
+
+// This test verifies if the configuration manager is able to hold and return
+// valid leases
+TEST_F(CfgMgrTest, subnet4) {
+ CfgMgr& cfg_mgr = CfgMgr::instance();
+
+ Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.2.0"), 26, 1, 2, 3));
+ Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.64"), 26, 1, 2, 3));
+ Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.2.128"), 26, 1, 2, 3));
+
+ // there shouldn't be any subnet configured at this stage
+ EXPECT_EQ( Subnet4Ptr(), cfg_mgr.getSubnet4(IOAddress("192.0.2.0")));
+
+ cfg_mgr.addSubnet4(subnet1);
+
+ // Now we have only one subnet, any request will be served from it
+ EXPECT_EQ(subnet1, cfg_mgr.getSubnet4(IOAddress("192.0.2.63")));
+
+ // Now we add more subnets and check that both old and new subnets
+ // are accessible.
+ cfg_mgr.addSubnet4(subnet2);
+ cfg_mgr.addSubnet4(subnet3);
+
+ EXPECT_EQ(subnet3, cfg_mgr.getSubnet4(IOAddress("192.0.2.191")));
+ EXPECT_EQ(subnet1, cfg_mgr.getSubnet4(IOAddress("192.0.2.15")));
+ EXPECT_EQ(subnet2, cfg_mgr.getSubnet4(IOAddress("192.0.2.85")));
+
+ // Try to find an address that does not belong to any subnet
+ EXPECT_EQ(Subnet4Ptr(), cfg_mgr.getSubnet4(IOAddress("192.0.2.192")));
+}
+
+// This test verifies if the configuration manager is able to hold and return
+// valid leases
+
+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));
+ Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
+
+ // there shouldn't be any subnet configured at this stage
+ EXPECT_EQ( Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("2000::1")));
+
+ cfg_mgr.addSubnet6(subnet1);
+
+ // Now we have only one subnet, any request will be served from it
+ EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2000::1")));
+
+ // If we have only a single subnet and the request came from a local
+ // address, let's use that subnet
+ EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("fe80::dead:beef")));
+
+ cfg_mgr.addSubnet6(subnet2);
+ cfg_mgr.addSubnet6(subnet3);
+
+ EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(IOAddress("4000::123")));
+ EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::dead:beef")));
+ EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("5000::1")));
+
+ cfg_mgr.deleteSubnets6();
+ EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("200::123")));
+ EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("3000::123")));
+ EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("4000::123")));
+}
+
+} // end of anonymous namespace
diff --git a/src/lib/dhcpsrv/tests/lease_mgr_factory_unittest.cc b/src/lib/dhcpsrv/tests/lease_mgr_factory_unittest.cc
new file mode 100644
index 0000000..40ecba3
--- /dev/null
+++ b/src/lib/dhcpsrv/tests/lease_mgr_factory_unittest.cc
@@ -0,0 +1,52 @@
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <asiolink/io_address.h>
+#include <dhcpsrv/lease_mgr_factory.h>
+
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <sstream>
+
+using namespace std;
+using namespace isc::dhcp;
+
+// This set of tests only check the parsing functions of LeaseMgrFactory.
+// Tests of the LeaseMgr create/instance/destroy are implicitly carried out
+// in the tests for the different concrete lease managers (e.g. MySqlLeaseMgr).
+
+namespace {
+// empty class for now, but may be extended once Addr6 becomes bigger
+class LeaseMgrFactoryTest : public ::testing::Test {
+public:
+ LeaseMgrFactoryTest() {
+ }
+};
+
+// This test checks if the LeaseMgr can be instantiated and that it
+// parses parameters string properly.
+TEST_F(LeaseMgrFactoryTest, parse) {
+
+ std::map<std::string, std::string> parameters = LeaseMgrFactory::parse(
+ "param1=value1 param2=value2 param3=value3");
+
+ EXPECT_EQ("value1", parameters["param1"]);
+ EXPECT_EQ("value2", parameters["param2"]);
+ EXPECT_TRUE(parameters.find("type") == parameters.end());
+}
+
+}; // end of anonymous namespace
diff --git a/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc
new file mode 100644
index 0000000..74a0fb4
--- /dev/null
+++ b/src/lib/dhcpsrv/tests/lease_mgr_unittest.cc
@@ -0,0 +1,296 @@
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <asiolink/io_address.h>
+#include <dhcpsrv/lease_mgr.h>
+
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <sstream>
+
+using namespace std;
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+
+// This is a concrete implementation of a Lease database. It does not do
+// anything useful and is used for abstract LeaseMgr class testing.
+class ConcreteLeaseMgr : public LeaseMgr {
+public:
+
+ /// @brief The sole lease manager constructor
+ ///
+ /// dbconfig is a generic way of passing parameters. Parameters
+ /// are passed in the "name=value" format, separated by spaces.
+ /// Values may be enclosed in double quotes, if needed.
+ ///
+ /// @param parameters A data structure relating keywords and values
+ /// concerned with the database.
+ ConcreteLeaseMgr(const LeaseMgr::ParameterMap& parameters)
+ : LeaseMgr(parameters)
+ {}
+
+ /// @brief Destructor
+ virtual ~ConcreteLeaseMgr()
+ {}
+
+ /// @brief Adds an IPv4 lease.
+ ///
+ /// @param lease lease to be added
+ virtual bool addLease(const Lease4Ptr&) {
+ return (false);
+ }
+
+ /// @brief Adds an IPv6 lease.
+ ///
+ /// @param lease lease to be added
+ virtual bool addLease(const Lease6Ptr&) {
+ return (false);
+ }
+
+ /// @brief Returns existing IPv4 lease for specified IPv4 address.
+ ///
+ /// @param addr address of the searched lease
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress&) const {
+ return (Lease4Ptr());
+ }
+
+ /// @brief Returns existing IPv4 lease for specific address and subnet
+ /// @param addr address of the searched lease
+ /// @param subnet_id ID of the subnet the lease must belong to
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress&,
+ SubnetID) const {
+ return (Lease4Ptr());
+ }
+
+ /// @brief Returns existing IPv4 leases for specified hardware address.
+ ///
+ /// Although in the usual case there will be only one lease, for mobile
+ /// clients or clients with multiple static/fixed/reserved leases there
+ /// can be more than one. Thus return type is a container, not a single
+ /// pointer.
+ ///
+ /// @param hwaddr hardware address of the client
+ ///
+ /// @return lease collection
+ virtual Lease4Collection getLease4(const HWAddr&) const {
+ return (Lease4Collection());
+ }
+
+ /// @brief Returns existing IPv4 leases for specified hardware address
+ /// and a subnet
+ ///
+ /// There can be at most one lease for a given HW address in a single
+ /// pool, so this method with either return a single lease or NULL.
+ ///
+ /// @param hwaddr hardware address of the client
+ /// @param subnet_id identifier of the subnet that lease must belong to
+ ///
+ /// @return a pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(const HWAddr&, SubnetID) const {
+ return (Lease4Ptr());
+ }
+
+ /// @brief Returns existing IPv4 lease for specified client-id
+ ///
+ /// @param clientid client identifier
+ ///
+ /// @return lease collection
+ virtual Lease4Collection getLease4(const ClientId&) const {
+ return (Lease4Collection());
+ }
+
+ /// @brief Returns existing IPv4 lease for specified client-id
+ ///
+ /// There can be at most one lease for a given HW address in a single
+ /// pool, so this method with either return a single lease or NULL.
+ ///
+ /// @param clientid client identifier
+ /// @param subnet_id identifier of the subnet that lease must belong to
+ ///
+ /// @return a pointer to the lease (or NULL if a lease is not found)
+ virtual Lease4Ptr getLease4(const ClientId&, SubnetID) const {
+ return (Lease4Ptr());
+ }
+
+ /// @brief Returns existing IPv6 lease for a given IPv6 address.
+ ///
+ /// @param addr address of the searched lease
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease6Ptr getLease6(const isc::asiolink::IOAddress&) const {
+ return (Lease6Ptr());
+ }
+
+ /// @brief Returns existing IPv6 lease for a given DUID+IA combination
+ ///
+ /// @param duid client DUID
+ /// @param iaid IA identifier
+ ///
+ /// @return collection of IPv6 leases
+ virtual Lease6Collection getLease6(const DUID&, uint32_t) const {
+ return (Lease6Collection());
+ }
+
+ /// @brief Returns existing IPv6 lease for a given DUID+IA combination
+ ///
+ /// @param duid client DUID
+ /// @param iaid IA identifier
+ /// @param subnet_id identifier of the subnet the lease must belong to
+ ///
+ /// @return smart pointer to the lease (or NULL if a lease is not found)
+ virtual Lease6Ptr getLease6(const DUID&, uint32_t, SubnetID) const {
+ return (Lease6Ptr());
+ }
+
+ /// @brief Updates IPv4 lease.
+ ///
+ /// @param lease4 The lease to be updated.
+ ///
+ /// If no such lease is present, an exception will be thrown.
+ virtual void updateLease4(const Lease4Ptr&) {}
+
+ /// @brief Updates IPv4 lease.
+ ///
+ /// @param lease4 The lease to be updated.
+ ///
+ /// If no such lease is present, an exception will be thrown.
+ virtual void updateLease6(const Lease6Ptr&) {}
+
+ /// @brief Deletes a lease.
+ ///
+ /// @param addr IPv4 address of the lease to be deleted.
+ ///
+ /// @return true if deletion was successful, false if no such lease exists
+ virtual bool deleteLease4(const isc::asiolink::IOAddress&) {
+ return (false);
+ }
+
+ /// @brief Deletes a lease.
+ ///
+ /// @param addr IPv4 address of the lease to be deleted.
+ ///
+ /// @return true if deletion was successful, false if no such lease exists
+ virtual bool deleteLease6(const isc::asiolink::IOAddress&) {
+ return (false);
+ }
+
+ /// @brief Returns backend type.
+ ///
+ /// Returns the type of the backend (e.g. "mysql", "memfile" etc.)
+ ///
+ /// @return Type of the backend.
+ virtual std::string getType() const {
+ return (std::string("concrete"));
+ }
+
+ /// @brief Returns backend name.
+ ///
+ /// If the backend is a database, this is the name of the database or the
+ /// file. Otherwise it is just the same as the type.
+ ///
+ /// @return Name of the backend.
+ virtual std::string getName() const {
+ return (std::string("concrete"));
+ }
+
+ /// @brief Returns description of the backend.
+ ///
+ /// This description may be multiline text that describes the backend.
+ ///
+ /// @return Description of the backend.
+ virtual std::string getDescription() const {
+ return (std::string("This is a dummy concrete backend implementation."));
+ }
+
+ /// @brief Returns backend version.
+ virtual std::pair<uint32_t, uint32_t> getVersion() const {
+ return (make_pair(uint32_t(0), uint32_t(0)));
+ }
+
+ /// @brief Commit transactions
+ virtual void commit() {
+ }
+
+ /// @brief Rollback transactions
+ virtual void rollback() {
+ }
+};
+
+namespace {
+// empty class for now, but may be extended once Addr6 becomes bigger
+class LeaseMgrTest : public ::testing::Test {
+public:
+ LeaseMgrTest() {
+ }
+};
+
+// This test checks if the LeaseMgr can be instantiated and that it
+// parses parameters string properly.
+TEST_F(LeaseMgrTest, getParameter) {
+
+ LeaseMgr::ParameterMap pmap;
+ pmap[std::string("param1")] = std::string("value1");
+ pmap[std::string("param2")] = std::string("value2");
+ ConcreteLeaseMgr leasemgr(pmap);
+
+ EXPECT_EQ("value1", leasemgr.getParameter("param1"));
+ EXPECT_EQ("value2", leasemgr.getParameter("param2"));
+ EXPECT_THROW(leasemgr.getParameter("param3"), BadValue);
+}
+
+// There's no point in calling any other methods in LeaseMgr, as they
+// are purely virtual, so we would only call ConcreteLeaseMgr methods.
+// Those methods are just stubs that do not return anything.
+
+// Lease6 is also defined in lease_mgr.h, so is tested in this file as well.
+// This test checks if the Lease6 structure can be instantiated correctly
+TEST(Lease6, Lease6Constructor) {
+
+ IOAddress addr("2001:db8:1::456");
+
+ uint8_t llt[] = {0, 1, 2, 3, 4, 5, 6, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+ DuidPtr duid(new DUID(llt, sizeof(llt)));
+
+ uint32_t iaid = 7; // just a number
+
+ SubnetID subnet_id = 8; // just another number
+
+ Lease6Ptr x(new Lease6(Lease6::LEASE_IA_NA, addr,
+ duid, iaid, 100, 200, 50, 80,
+ subnet_id));
+
+ EXPECT_TRUE(x->addr_ == addr);
+ EXPECT_TRUE(*x->duid_ == *duid);
+ EXPECT_TRUE(x->iaid_ == iaid);
+ EXPECT_TRUE(x->subnet_id_ == subnet_id);
+ EXPECT_TRUE(x->type_ == Lease6::LEASE_IA_NA);
+ EXPECT_TRUE(x->preferred_lft_ == 100);
+ EXPECT_TRUE(x->valid_lft_ == 200);
+ EXPECT_TRUE(x->t1_ == 50);
+ EXPECT_TRUE(x->t2_ == 80);
+
+ // Lease6 must be instantiated with a DUID, not with NULL pointer
+ EXPECT_THROW(new Lease6(Lease6::LEASE_IA_NA, addr,
+ DuidPtr(), iaid, 100, 200, 50, 80,
+ subnet_id), InvalidOperation);
+}
+}; // end of anonymous namespace
diff --git a/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc
new file mode 100644
index 0000000..0f026f2
--- /dev/null
+++ b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc
@@ -0,0 +1,135 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <asiolink/io_address.h>
+#include <dhcp/duid.h>
+#include <dhcpsrv/lease_mgr.h>
+#include <dhcpsrv/memfile_lease_mgr.h>
+
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <sstream>
+
+using namespace std;
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+
+namespace {
+// empty class for now, but may be extended once Addr6 becomes bigger
+class MemfileLeaseMgrTest : public ::testing::Test {
+public:
+ MemfileLeaseMgrTest() {
+ }
+};
+
+// This test checks if the LeaseMgr can be instantiated and that it
+// parses parameters string properly.
+TEST_F(MemfileLeaseMgrTest, constructor) {
+
+ const LeaseMgr::ParameterMap pmap; // Empty parameter map
+ boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr;
+
+ ASSERT_NO_THROW(lease_mgr.reset(new Memfile_LeaseMgr(pmap)));
+}
+
+// Checks if the getType() and getName() methods both return "memfile".
+TEST_F(MemfileLeaseMgrTest, getTypeAndName) {
+ const LeaseMgr::ParameterMap pmap; // Empty parameter map
+ boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr(new Memfile_LeaseMgr(pmap));
+
+ EXPECT_EQ(std::string("memfile"), lease_mgr->getType());
+ EXPECT_EQ(std::string("memfile"), lease_mgr->getName());
+}
+
+// Checks that adding/getting/deleting a Lease6 object works.
+TEST_F(MemfileLeaseMgrTest, addGetDelete6) {
+ const LeaseMgr::ParameterMap pmap; // Empty parameter map
+ boost::scoped_ptr<Memfile_LeaseMgr> lease_mgr(new Memfile_LeaseMgr(pmap));
+
+ IOAddress addr("2001:db8:1::456");
+
+ uint8_t llt[] = {0, 1, 2, 3, 4, 5, 6, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+ DuidPtr duid(new DUID(llt, sizeof(llt)));
+
+ uint32_t iaid = 7; // just a number
+
+ SubnetID subnet_id = 8; // just another number
+
+ Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr,
+ duid, iaid, 100, 200, 50, 80,
+ subnet_id));
+
+ EXPECT_TRUE(lease_mgr->addLease(lease));
+
+ // should not be allowed to add a second lease with the same address
+ EXPECT_FALSE(lease_mgr->addLease(lease));
+
+ Lease6Ptr x = lease_mgr->getLease6(IOAddress("2001:db8:1::234"));
+ EXPECT_EQ(Lease6Ptr(), x);
+
+ x = lease_mgr->getLease6(IOAddress("2001:db8:1::456"));
+ ASSERT_TRUE(x);
+
+ EXPECT_EQ(x->addr_.toText(), addr.toText());
+ EXPECT_TRUE(*x->duid_ == *duid);
+ EXPECT_EQ(x->iaid_, iaid);
+ EXPECT_EQ(x->subnet_id_, subnet_id);
+
+ // These are not important from lease management perspective, but
+ // let's check them anyway.
+ EXPECT_EQ(x->type_, Lease6::LEASE_IA_NA);
+ EXPECT_EQ(x->preferred_lft_, 100);
+ EXPECT_EQ(x->valid_lft_, 200);
+ EXPECT_EQ(x->t1_, 50);
+ EXPECT_EQ(x->t2_, 80);
+
+ // Test getLease6(duid, iaid, subnet_id) - positive case
+ Lease6Ptr y = lease_mgr->getLease6(*duid, iaid, subnet_id);
+ ASSERT_TRUE(y);
+ EXPECT_TRUE(*y->duid_ == *duid);
+ EXPECT_EQ(y->iaid_, iaid);
+ EXPECT_EQ(y->addr_.toText(), addr.toText());
+
+ // Test getLease6(duid, iaid, subnet_id) - wrong iaid
+ uint32_t invalid_iaid = 9; // no such iaid
+ y = lease_mgr->getLease6(*duid, invalid_iaid, subnet_id);
+ EXPECT_FALSE(y);
+
+ uint32_t invalid_subnet_id = 999;
+ y = lease_mgr->getLease6(*duid, iaid, invalid_subnet_id);
+ EXPECT_FALSE(y);
+
+ // truncated duid
+ DuidPtr invalid_duid(new DUID(llt, sizeof(llt) - 1));
+ y = lease_mgr->getLease6(*invalid_duid, iaid, subnet_id);
+ EXPECT_FALSE(y);
+
+ // should return false - there's no such address
+ EXPECT_FALSE(lease_mgr->deleteLease6(IOAddress("2001:db8:1::789")));
+
+ // this one should succeed
+ EXPECT_TRUE(lease_mgr->deleteLease6(IOAddress("2001:db8:1::456")));
+
+ // after the lease is deleted, it should really be gone
+ x = lease_mgr->getLease6(IOAddress("2001:db8:1::456"));
+ EXPECT_EQ(Lease6Ptr(), x);
+}
+
+// TODO: Write more memfile tests
+
+}; // end of anonymous namespace
diff --git a/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc
new file mode 100644
index 0000000..930bc06
--- /dev/null
+++ b/src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc
@@ -0,0 +1,754 @@
+// Copyright (C) 2011-2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <asiolink/io_address.h>
+#include <dhcpsrv/lease_mgr_factory.h>
+#include <dhcpsrv/mysql_lease_mgr.h>
+
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <utility>
+
+using namespace isc;
+using namespace isc::asiolink;
+using namespace isc::dhcp;
+using namespace std;
+
+namespace {
+
+// Creation of the schema
+#include "schema_copy.h"
+
+// IPv6 addresseses
+const char* ADDRESS_0 = "2001:db8::0";
+const char* ADDRESS_1 = "2001:db8::1";
+const char* ADDRESS_2 = "2001:db8::2";
+const char* ADDRESS_3 = "2001:db8::3";
+const char* ADDRESS_4 = "2001:db8::4";
+const char* ADDRESS_5 = "2001:db8::5";
+const char* ADDRESS_6 = "2001:db8::6";
+const char* ADDRESS_7 = "2001:db8::7";
+
+// Connection strings. Assume:
+// Database: keatest
+// Username: keatest
+// Password: keatest
+const char* VALID_TYPE = "type=mysql";
+const char* INVALID_TYPE = "type=unknown";
+const char* VALID_NAME = "name=keatest";
+const char* INVALID_NAME = "name=invalidname";
+const char* VALID_HOST = "host=localhost";
+const char* INVALID_HOST = "host=invalidhost";
+const char* VALID_USER = "user=keatest";
+const char* INVALID_USER = "user=invaliduser";
+const char* VALID_PASSWORD = "password=keatest";
+const char* INVALID_PASSWORD = "password=invalid";
+
+// Given a combination of strings above, produce a connection string.
+string connectionString(const char* type, const char* name, const char* host,
+ const char* user, const char* password) {
+ const string space = " ";
+ string result = "";
+
+ if (type != NULL) {
+ result += string(type);
+ }
+
+ if (name != NULL) {
+ if (! result.empty()) {
+ result += space;
+ }
+ result += string(name);
+ }
+
+ if (host != NULL) {
+ if (! result.empty()) {
+ result += space;
+ }
+ result += string(host);
+ }
+
+ if (user != NULL) {
+ if (! result.empty()) {
+ result += space;
+ }
+ result += string(user);
+ }
+
+ if (password != NULL) {
+ if (! result.empty()) {
+ result += space;
+ }
+ result += string(password);
+ }
+
+ return (result);
+}
+
+// Return valid connection string
+string
+validConnectionString() {
+ return (connectionString(VALID_TYPE, VALID_NAME, VALID_HOST,
+ VALID_USER, VALID_PASSWORD));
+}
+
+// @brief Clear everything from the database
+//
+// There is no error checking in this code: if something fails, one of the
+// tests will fall over.
+void destroySchema() {
+ // Initialise
+ MYSQL handle;
+ (void) mysql_init(&handle);
+
+ // Open database
+ (void) mysql_real_connect(&handle, "localhost", "keatest",
+ "keatest", "keatest", 0, NULL, 0);
+
+ // Get rid of everything in it.
+ for (int i = 0; destroy_statement[i] != NULL; ++i) {
+ (void) mysql_query(&handle, destroy_statement[i]);
+ }
+
+ // ... and close
+ (void) mysql_close(&handle);
+}
+
+// @brief Create the Schema
+//
+// Creates all the tables in what is assumed to be an empty database.
+//
+// There is no error checking in this code: if it fails, one of the tests
+// will fall over.
+void createSchema() {
+ // Initialise
+ MYSQL handle;
+ (void) mysql_init(&handle);
+
+ // Open database
+ (void) mysql_real_connect(&handle, "localhost", "keatest",
+ "keatest", "keatest", 0, NULL, 0);
+
+ // Get rid of everything in it.
+ for (int i = 0; create_statement[i] != NULL; ++i) {
+ (void) mysql_query(&handle, create_statement[i]);
+ }
+
+ // ... and close
+ (void) mysql_close(&handle);
+}
+
+// Note: Doxygen "///" not used - even though Doxygen is used to
+// document class and methods - to avoid the comments appearing
+// in the programming manual.
+
+// @brief Test Fixture Class
+//
+// Opens the database prior to each test and closes it afterwards.
+// All pending transactions are deleted prior to closure.
+
+class MySqlLeaseMgrTest : public ::testing::Test {
+public:
+ // @brief Constructor
+ //
+ // Deletes everything from the database and opens it.
+ MySqlLeaseMgrTest() :
+ L0_ADDRESS(ADDRESS_0), L0_IOADDRESS(L0_ADDRESS),
+ L1_ADDRESS(ADDRESS_1), L1_IOADDRESS(L1_ADDRESS),
+ L2_ADDRESS(ADDRESS_2), L2_IOADDRESS(L2_ADDRESS),
+ L3_ADDRESS(ADDRESS_3), L3_IOADDRESS(L3_ADDRESS),
+ L4_ADDRESS(ADDRESS_4), L4_IOADDRESS(L4_ADDRESS),
+ L5_ADDRESS(ADDRESS_5), L5_IOADDRESS(L5_ADDRESS),
+ L6_ADDRESS(ADDRESS_6), L6_IOADDRESS(L6_ADDRESS),
+ L7_ADDRESS(ADDRESS_7), L7_IOADDRESS(L7_ADDRESS) {
+
+ destroySchema();
+ createSchema();
+ try {
+ LeaseMgrFactory::create(validConnectionString());
+ } catch (...) {
+ std::cerr << "*** ERROR: unable to open database. The test\n"
+ "*** environment is broken and must be fixed before\n"
+ "*** the MySQL tests will run correctly.\n"
+ "*** The reason for the problem is described in the\n"
+ "*** accompanying exception output.\n";
+ throw;
+ }
+ lmptr_ = &(LeaseMgrFactory::instance());
+ }
+
+ // @brief Destructor
+ //
+ // Rolls back all pending transactions. The deletion of the
+ // lmptr_ member variable will close the database. Then
+ // reopen it and delete everything created by the test.
+ virtual ~MySqlLeaseMgrTest() {
+ lmptr_->rollback();
+ LeaseMgrFactory::destroy();
+ destroySchema();
+ }
+
+ // @brief Reopen the database
+ //
+ // Closes the database and re-open it. Anything committed should be
+ // visible.
+ void reopen() {
+ LeaseMgrFactory::destroy();
+ LeaseMgrFactory::create(validConnectionString());
+ lmptr_ = &(LeaseMgrFactory::instance());
+ }
+
+ // @brief Initialize Lease6 Fields
+ //
+ // Returns a pointer to a Lease6 structure. Different values are put
+ // in the lease according to the address passed.
+ //
+ // This is just a convenience function for the test methods.
+ //
+ // @param address Address to use for the initialization
+ //
+ // @return Lease6Ptr. This will not point to anything if the initialization
+ // failed (e.g. unknown address).
+ Lease6Ptr initializeLease6(std::string address) {
+ Lease6Ptr lease(new Lease6());
+
+ // Set the address of the lease
+ lease->addr_ = IOAddress(address);
+
+ // Initialize unused fields.
+ lease->t1_ = 0; // Not saved
+ lease->t2_ = 0; // Not saved
+ lease->fixed_ = false; // Unused
+ lease->hostname_ = std::string(""); // Unused
+ lease->fqdn_fwd_ = false; // Unused
+ lease->fqdn_rev_ = false; // Unused
+ lease->comments_ = std::string(""); // Unused
+
+ // Set the other parameters. For historical reasons, L0_ADDRESS is not used.
+ if (address == L0_ADDRESS) {
+ lease->type_ = Lease6::LEASE_IA_TA;
+ lease->prefixlen_ = 4;
+ lease->iaid_ = 142;
+ lease->duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0x77)));
+ lease->preferred_lft_ = 900; // Preferred lifetime
+ lease->valid_lft_ = 8677; // Actual lifetime
+ lease->cltt_ = 168256; // Current time of day
+ lease->subnet_id_ = 23; // Arbitrary number
+
+ } else if (address == L1_ADDRESS) {
+ lease->type_ = Lease6::LEASE_IA_TA;
+ lease->prefixlen_ = 0;
+ lease->iaid_ = 42;
+ lease->duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0x42)));
+ lease->preferred_lft_ = 3600; // Preferred lifetime
+ lease->valid_lft_ = 3677; // Actual lifetime
+ lease->cltt_ = 123456; // Current time of day
+ lease->subnet_id_ = 73; // Arbitrary number
+
+ } else if (address == L2_ADDRESS) {
+ lease->type_ = Lease6::LEASE_IA_PD;
+ lease->prefixlen_ = 7;
+ lease->iaid_ = 89;
+ lease->duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0x3a)));
+ lease->preferred_lft_ = 1800; // Preferred lifetime
+ lease->valid_lft_ = 5412; // Actual lifetime
+ lease->cltt_ = 234567; // Current time of day
+ lease->subnet_id_ = 73; // Same as for L1_ADDRESS
+
+ } else if (address == L3_ADDRESS) {
+ lease->type_ = Lease6::LEASE_IA_NA;
+ lease->prefixlen_ = 28;
+ lease->iaid_ = 0xfffffffe;
+ vector<uint8_t> duid;
+ for (uint8_t i = 31; i < 126; ++i) {
+ duid.push_back(i);
+ }
+ lease->duid_ = boost::shared_ptr<DUID>(new DUID(duid));
+
+ // The times used in the next tests are deliberately restricted - we
+ // should be able to cope with valid lifetimes up to 0xffffffff.
+ // However, this will lead to overflows.
+ // @TODO: test overflow conditions when code has been fixed
+ lease->preferred_lft_ = 7200; // Preferred lifetime
+ lease->valid_lft_ = 7000; // Actual lifetime
+ lease->cltt_ = 234567; // Current time of day
+ lease->subnet_id_ = 37; // Different from L1 and L2
+
+ } else if (address == L4_ADDRESS) {
+ // Same DUID and IAID as L1_ADDRESS
+ lease->type_ = Lease6::LEASE_IA_PD;
+ lease->prefixlen_ = 15;
+ lease->iaid_ = 42;
+ lease->duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0x42)));
+ lease->preferred_lft_ = 4800; // Preferred lifetime
+ lease->valid_lft_ = 7736; // Actual lifetime
+ lease->cltt_ = 222456; // Current time of day
+ lease->subnet_id_ = 75; // Arbitrary number
+
+ } else if (address == L5_ADDRESS) {
+ // Same DUID and IAID as L1_ADDRESS
+ lease->type_ = Lease6::LEASE_IA_PD;
+ lease->prefixlen_ = 24;
+ lease->iaid_ = 42;
+ lease->duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0x42)));
+ lease->preferred_lft_ = 5400; // Preferred lifetime
+ lease->valid_lft_ = 7832; // Actual lifetime
+ lease->cltt_ = 227476; // Current time of day
+ lease->subnet_id_ = 175; // Arbitrary number
+
+ } else if (address == L6_ADDRESS) {
+ // Same DUID as L1_ADDRESS
+ lease->type_ = Lease6::LEASE_IA_PD;
+ lease->prefixlen_ = 24;
+ lease->iaid_ = 93;
+ lease->duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0x42)));
+ lease->preferred_lft_ = 5400; // Preferred lifetime
+ lease->valid_lft_ = 1832; // Actual lifetime
+ lease->cltt_ = 627476; // Current time of day
+ lease->subnet_id_ = 112; // Arbitrary number
+
+ } else if (address == L7_ADDRESS) {
+ // Same IAID as L1_ADDRESS
+ lease->type_ = Lease6::LEASE_IA_PD;
+ lease->prefixlen_ = 24;
+ lease->iaid_ = 42;
+ lease->duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0xe5)));
+ lease->preferred_lft_ = 5600; // Preferred lifetime
+ lease->valid_lft_ = 7975; // Actual lifetime
+ lease->cltt_ = 213876; // Current time of day
+ lease->subnet_id_ = 19; // Arbitrary number
+
+ } else {
+ // Unknown address, return an empty pointer.
+ lease.reset();
+
+ }
+
+ return (lease);
+ }
+
+ // @brief Creates Leases for the test
+ //
+ // Creates all leases for the test and checks that they are different.
+ //
+ // @return vector<Lease6Ptr> Vector of pointers to leases
+ vector<Lease6Ptr> createLeases6() {
+
+ // Create leases
+ vector<Lease6Ptr> leases;
+ leases.push_back(initializeLease6(L0_ADDRESS));
+ leases.push_back(initializeLease6(L1_ADDRESS));
+ leases.push_back(initializeLease6(L2_ADDRESS));
+ leases.push_back(initializeLease6(L3_ADDRESS));
+ leases.push_back(initializeLease6(L4_ADDRESS));
+ leases.push_back(initializeLease6(L5_ADDRESS));
+ leases.push_back(initializeLease6(L6_ADDRESS));
+ leases.push_back(initializeLease6(L7_ADDRESS));
+
+ EXPECT_EQ(8, leases.size());
+
+ // Check they were created
+ for (int i = 0; i < leases.size(); ++i) {
+ EXPECT_TRUE(leases[i]);
+ }
+
+ // Check they are different
+ for (int i = 0; i < (leases.size() - 1); ++i) {
+ for (int j = (i + 1); j < leases.size(); ++j) {
+ EXPECT_TRUE(leases[i] != leases[j]);
+ }
+ }
+
+ return (leases);
+ }
+
+
+ // Member variables
+
+ LeaseMgr* lmptr_; // Pointer to the lease manager
+
+ string L0_ADDRESS; // String form of address 1
+ IOAddress L0_IOADDRESS; // IOAddress form of L1_ADDRESS
+
+ string L1_ADDRESS; // String form of address 1
+ IOAddress L1_IOADDRESS; // IOAddress form of L1_ADDRESS
+
+ string L2_ADDRESS; // String form of address 2
+ IOAddress L2_IOADDRESS; // IOAddress form of L2_ADDRESS
+
+ string L3_ADDRESS; // String form of address 3
+ IOAddress L3_IOADDRESS; // IOAddress form of L3_ADDRESS
+
+ string L4_ADDRESS; // String form of address 4
+ IOAddress L4_IOADDRESS; // IOAddress form of L4_ADDRESS
+
+ string L5_ADDRESS; // String form of address 5
+ IOAddress L5_IOADDRESS; // IOAddress form of L5_ADDRESS
+
+ string L6_ADDRESS; // String form of address 6
+ IOAddress L6_IOADDRESS; // IOAddress form of L6_ADDRESS
+
+ string L7_ADDRESS; // String form of address 7
+ IOAddress L7_IOADDRESS; // IOAddress form of L7_ADDRESS
+};
+
+
+// @brief Check that Database Can Be Opened
+//
+// This test checks if the MySqlLeaseMgr can be instantiated. This happens
+// only if the database can be opened. Note that this is not part of the
+// MySqlLeaseMgr test fixure set. This test checks that the database can be
+// opened: the fixtures assume that and check basic operations.
+
+TEST(MySqlOpenTest, OpenDatabase) {
+
+ // Schema needs to be created for the test to work.
+ destroySchema();
+ createSchema();
+
+ // Check that lease manager open the database opens correctly and tidy up.
+ // If it fails, print the error message.
+ try {
+ LeaseMgrFactory::create(validConnectionString());
+ EXPECT_NO_THROW((void) LeaseMgrFactory::instance());
+ LeaseMgrFactory::destroy();
+ } catch (const isc::Exception& ex) {
+ FAIL() << "*** ERROR: unable to open database, reason:\n"
+ << " " << ex.what() << "\n"
+ << "*** The test environment is broken and must be fixed\n"
+ << "*** before the MySQL tests will run correctly.\n";
+ }
+
+ // Check that attempting to get an instance of the lease manager when
+ // none is set throws an exception.
+ EXPECT_THROW(LeaseMgrFactory::instance(), NoLeaseManager);
+
+ // Check that wrong specification of backend throws an exception.
+ // (This is really a check on LeaseMgrFactory, but is convenient to
+ // perform here.)
+ EXPECT_THROW(LeaseMgrFactory::create(connectionString(
+ NULL, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
+ InvalidParameter);
+ EXPECT_THROW(LeaseMgrFactory::create(connectionString(
+ INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
+ InvalidType);
+
+ // Check that invalid login data causes an exception.
+ EXPECT_THROW(LeaseMgrFactory::create(connectionString(
+ VALID_TYPE, INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
+ DbOpenError);
+ EXPECT_THROW(LeaseMgrFactory::create(connectionString(
+ VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)),
+ DbOpenError);
+ EXPECT_THROW(LeaseMgrFactory::create(connectionString(
+ VALID_TYPE, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
+ DbOpenError);
+ EXPECT_THROW(LeaseMgrFactory::create(connectionString(
+ VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)),
+ DbOpenError);
+
+ // Check for missing parameters
+ EXPECT_THROW(LeaseMgrFactory::create(connectionString(
+ VALID_TYPE, NULL, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
+ NoDatabaseName);
+
+ // Tidy up after the test
+ destroySchema();
+}
+
+// @brief Check the getType() method
+//
+// getType() returns a string giving the type of the backend, which should
+// always be "mysql".
+TEST_F(MySqlLeaseMgrTest, getType) {
+ EXPECT_EQ(std::string("mysql"), lmptr_->getType());
+}
+
+// @brief Check conversion functions
+//
+// The server works using cltt and valid_filetime. In the database, the
+// information is stored as expire_time and valid-lifetime, which are
+// related by
+//
+// expire_time = cltt + valid_lifetime
+//
+// This test checks that the conversion is correct. It does not check that the
+// data is entered into the database correctly, only that the MYSQL_TIME
+// structure used for the entry is correctly set up.
+TEST_F(MySqlLeaseMgrTest, checkTimeConversion) {
+ const time_t cltt = time(NULL);
+ const uint32_t valid_lft = 86400; // 1 day
+ struct tm tm_expire;
+ MYSQL_TIME mysql_expire;
+
+ // Work out what the broken-down time will be for one day
+ // after the current time.
+ time_t expire_time = cltt + valid_lft;
+ (void) localtime_r(&expire_time, &tm_expire);
+
+ // Convert to the database time
+ MySqlLeaseMgr::convertToDatabaseTime(cltt, valid_lft, mysql_expire);
+
+ // Are the times the same?
+ EXPECT_EQ(tm_expire.tm_year + 1900, mysql_expire.year);
+ EXPECT_EQ(tm_expire.tm_mon + 1, mysql_expire.month);
+ EXPECT_EQ(tm_expire.tm_mday, mysql_expire.day);
+ EXPECT_EQ(tm_expire.tm_hour, mysql_expire.hour);
+ EXPECT_EQ(tm_expire.tm_min, mysql_expire.minute);
+ EXPECT_EQ(tm_expire.tm_sec, mysql_expire.second);
+ EXPECT_EQ(0, mysql_expire.second_part);
+ EXPECT_EQ(0, mysql_expire.neg);
+
+ // Convert back
+ time_t converted_cltt = 0;
+ MySqlLeaseMgr::convertFromDatabaseTime(mysql_expire, valid_lft, converted_cltt);
+ EXPECT_EQ(cltt, converted_cltt);
+}
+
+
+// @brief Check getName() returns correct database name
+TEST_F(MySqlLeaseMgrTest, getName) {
+ EXPECT_EQ(std::string("keatest"), lmptr_->getName());
+
+ // @TODO: check for the negative
+}
+
+// @brief Check that getVersion() returns the expected version
+TEST_F(MySqlLeaseMgrTest, checkVersion) {
+ // Check version
+ pair<uint32_t, uint32_t> version;
+ ASSERT_NO_THROW(version = lmptr_->getVersion());
+ EXPECT_EQ(CURRENT_VERSION_VERSION, version.first);
+ EXPECT_EQ(CURRENT_VERSION_MINOR, version.second);
+}
+
+// @brief Compare two Lease6 structures for equality
+void
+detailCompareLease6(const Lease6Ptr& first, const Lease6Ptr& second) {
+ EXPECT_EQ(first->type_, second->type_);
+
+ // Compare address strings. Comparison of address objects is not used, as
+ // odd things happen when they are different: the EXPECT_EQ macro appears to
+ // call the operator uint32_t() function, which causes an exception to be
+ // thrown for IPv6 addresses.
+ EXPECT_EQ(first->addr_.toText(), second->addr_.toText());
+ EXPECT_EQ(first->prefixlen_, second->prefixlen_);
+ EXPECT_EQ(first->iaid_, second->iaid_);
+ EXPECT_TRUE(*first->duid_ == *second->duid_);
+ EXPECT_EQ(first->preferred_lft_, second->preferred_lft_);
+ EXPECT_EQ(first->valid_lft_, second->valid_lft_);
+ EXPECT_EQ(first->cltt_, second->cltt_);
+ EXPECT_EQ(first->subnet_id_, second->subnet_id_);
+}
+
+
+// @brief Check individual Lease6 methods
+//
+// Checks that the add/update/delete works. All are done within one
+// test so that "rollback" can be used to remove trace of the tests
+// from the database.
+//
+// Tests where a collection of leases can be returned are in the test
+// Lease6Collection.
+TEST_F(MySqlLeaseMgrTest, basicLease6) {
+ // Get the leases to be used for the test.
+ vector<Lease6Ptr> leases = createLeases6();
+
+ // Start the tests. Add three leases to the database, read them back and
+ // check they are what we think they are.
+ EXPECT_TRUE(lmptr_->addLease(leases[1]));
+ EXPECT_TRUE(lmptr_->addLease(leases[2]));
+ EXPECT_TRUE(lmptr_->addLease(leases[3]));
+ lmptr_->commit();
+
+ // Reopen the database to ensure that they actually got stored.
+ reopen();
+
+ Lease6Ptr l_returned = lmptr_->getLease6(L1_IOADDRESS);
+ EXPECT_TRUE(l_returned);
+ detailCompareLease6(leases[1], l_returned);
+
+ l_returned = lmptr_->getLease6(L2_IOADDRESS);
+ EXPECT_TRUE(l_returned);
+ detailCompareLease6(leases[2], l_returned);
+
+ l_returned = lmptr_->getLease6(L3_IOADDRESS);
+ EXPECT_TRUE(l_returned);
+ detailCompareLease6(leases[3], l_returned);
+
+ // Check that we can't add a second lease with the same address
+ EXPECT_FALSE(lmptr_->addLease(leases[1]));
+
+ // Delete a lease, check that it's gone, and that we can't delete it
+ // a second time.
+ EXPECT_TRUE(lmptr_->deleteLease6(L1_IOADDRESS));
+ l_returned = lmptr_->getLease6(L1_IOADDRESS);
+ EXPECT_FALSE(l_returned);
+ EXPECT_FALSE(lmptr_->deleteLease6(L1_IOADDRESS));
+
+ // Check that the second address is still there.
+ l_returned = lmptr_->getLease6(L2_IOADDRESS);
+ EXPECT_TRUE(l_returned);
+ detailCompareLease6(leases[2], l_returned);
+}
+
+// @brief Check GetLease6 methods - Access by DUID/IAID
+//
+// Adds leases to the database and checks that they can be accessed via
+// a combination of DIUID and IAID.
+TEST_F(MySqlLeaseMgrTest, getLease6Extended1) {
+ // Get the leases to be used for the test.
+ vector<Lease6Ptr> leases = createLeases6();
+ EXPECT_LE(6, leases.size()); // Expect to access leases 0 through 5
+
+ // Add them to the database
+ for (int i = 0; i < leases.size(); ++i) {
+ EXPECT_TRUE(lmptr_->addLease(leases[i]));
+ }
+
+ // Get the leases matching the DUID and IAID of lease[1].
+ Lease6Collection returned = lmptr_->getLease6(*leases[1]->duid_,
+ leases[1]->iaid_);
+
+ // Should be three leases, matching leases[1], [4] and [5].
+ ASSERT_EQ(3, returned.size());
+
+ // Easiest way to check is to look at the addresses.
+ vector<string> addresses;
+ for (Lease6Collection::const_iterator i = returned.begin();
+ i != returned.end(); ++i) {
+ addresses.push_back((*i)->addr_.toText());
+ }
+ sort(addresses.begin(), addresses.end());
+ EXPECT_EQ(L1_ADDRESS, addresses[0]);
+ EXPECT_EQ(L4_ADDRESS, addresses[1]);
+ EXPECT_EQ(L5_ADDRESS, addresses[2]);
+
+ // Check that nothing is returned when either the IAID or DUID match
+ // nothing.
+ returned = lmptr_->getLease6(*leases[1]->duid_, leases[1]->iaid_ + 1);
+ EXPECT_EQ(0, returned.size());
+
+ // Alter the leases[1] DUID to match nothing in the database.
+ vector<uint8_t> duid_vector = leases[1]->duid_->getDuid();
+ ++duid_vector[0];
+ DUID new_duid(duid_vector);
+ returned = lmptr_->getLease6(new_duid, leases[1]->iaid_);
+ EXPECT_EQ(0, returned.size());
+}
+
+
+
+// @brief Check GetLease6 methods - Access by DUID/IAID/SubnetID
+//
+// Adds leases to the database and checks that they can be accessed via
+// a combination of DIUID and IAID.
+TEST_F(MySqlLeaseMgrTest, getLease6Extended2) {
+ // Get the leases to be used for the test.
+ vector<Lease6Ptr> leases = createLeases6();
+ EXPECT_LE(6, leases.size()); // Expect to access leases 0 through 5
+
+ // Add them to the database
+ for (int i = 0; i < leases.size(); ++i) {
+ EXPECT_TRUE(lmptr_->addLease(leases[i]));
+ }
+
+ // Get the leases matching the DUID and IAID of lease[1].
+ Lease6Ptr returned = lmptr_->getLease6(*leases[1]->duid_,
+ leases[1]->iaid_,
+ leases[1]->subnet_id_);
+ ASSERT_TRUE(returned);
+ EXPECT_TRUE(*returned == *leases[1]);
+
+ // Modify each of the three parameters (DUID, IAID, Subnet ID) and
+ // check that nothing is returned.
+ returned = lmptr_->getLease6(*leases[1]->duid_, leases[1]->iaid_ + 1,
+ leases[1]->subnet_id_);
+ EXPECT_FALSE(returned);
+
+ returned = lmptr_->getLease6(*leases[1]->duid_, leases[1]->iaid_,
+ leases[1]->subnet_id_ + 1);
+ EXPECT_FALSE(returned);
+
+ // Alter the leases[1] DUID to match nothing in the database.
+ vector<uint8_t> duid_vector = leases[1]->duid_->getDuid();
+ ++duid_vector[0];
+ DUID new_duid(duid_vector);
+ returned = lmptr_->getLease6(new_duid, leases[1]->iaid_,
+ leases[1]->subnet_id_);
+ EXPECT_FALSE(returned);
+}
+
+
+
+// @brief Lease6 Update Tests
+//
+// Checks that we are able to update a lease in the database.
+TEST_F(MySqlLeaseMgrTest, updateLease6) {
+ // Get the leases to be used for the test.
+ vector<Lease6Ptr> leases = createLeases6();
+ EXPECT_LE(3, leases.size()); // Expect to access leases 0 through 5
+
+ // Add a lease to the database and check that the lease is there.
+ EXPECT_TRUE(lmptr_->addLease(leases[1]));
+ lmptr_->commit();
+
+ reopen();
+ Lease6Ptr l_returned = lmptr_->getLease6(L1_IOADDRESS);
+ EXPECT_TRUE(l_returned);
+ detailCompareLease6(leases[1], l_returned);
+
+ // Modify some fields in lease 1 (not the address) and update it.
+ ++leases[1]->iaid_;
+ leases[1]->type_ = Lease6::LEASE_IA_PD;
+ leases[1]->valid_lft_ *= 2;
+ lmptr_->updateLease6(leases[1]);
+ lmptr_->commit();
+ reopen();
+
+ // ... and check what is returned is what is expected.
+ l_returned.reset();
+ l_returned = lmptr_->getLease6(L1_IOADDRESS);
+ EXPECT_TRUE(l_returned);
+ detailCompareLease6(leases[1], l_returned);
+
+ // Alter the lease again and check.
+ ++leases[1]->iaid_;
+ leases[1]->type_ = Lease6::LEASE_IA_TA;
+ leases[1]->cltt_ += 6;
+ leases[1]->prefixlen_ = 93;
+ lmptr_->updateLease6(leases[1]);
+
+ l_returned.reset();
+ l_returned = lmptr_->getLease6(L1_IOADDRESS);
+ EXPECT_TRUE(l_returned);
+ detailCompareLease6(leases[1], l_returned);
+
+ // Check we can do an update without changing data.
+ lmptr_->updateLease6(leases[1]);
+ l_returned.reset();
+ l_returned = lmptr_->getLease6(L1_IOADDRESS);
+ EXPECT_TRUE(l_returned);
+ detailCompareLease6(leases[1], l_returned);
+
+ // Try updating a lease not in the database.
+ EXPECT_THROW(lmptr_->updateLease6(leases[2]), isc::dhcp::NoSuchLease);
+}
+
+}; // Of anonymous namespace
diff --git a/src/lib/dhcpsrv/tests/pool_unittest.cc b/src/lib/dhcpsrv/tests/pool_unittest.cc
new file mode 100644
index 0000000..4e18a3c
--- /dev/null
+++ b/src/lib/dhcpsrv/tests/pool_unittest.cc
@@ -0,0 +1,184 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <asiolink/io_address.h>
+#include <dhcpsrv/pool.h>
+
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <vector>
+#include <sstream>
+
+using boost::scoped_ptr;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+
+namespace {
+
+TEST(Pool4Test, constructor_first_last) {
+
+ // let's construct 192.0.2.1-192.0.2.255 pool
+ Pool4 pool1(IOAddress("192.0.2.1"), IOAddress("192.0.2.255"));
+
+ EXPECT_EQ(IOAddress("192.0.2.1"), pool1.getFirstAddress());
+ EXPECT_EQ(IOAddress("192.0.2.255"), pool1.getLastAddress());
+
+ // This is Pool4, IPv6 addresses do not belong here
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::1"),
+ IOAddress("192.168.0.5")), BadValue);
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.168.0.2"),
+ IOAddress("2001:db8::1")), BadValue);
+
+ // Should throw. Range should be 192.0.2.1-192.0.2.2, not
+ // the other way around.
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.0.2.2"),
+ IOAddress("192.0.2.1")), BadValue);
+}
+
+TEST(Pool4Test, constructor_prefix_len) {
+
+ // let's construct 2001:db8:1::/96 pool
+ Pool4 pool1(IOAddress("192.0.2.0"), 25);
+
+ EXPECT_EQ("192.0.2.0", pool1.getFirstAddress().toText());
+ EXPECT_EQ("192.0.2.127", pool1.getLastAddress().toText());
+
+ // No such thing as /33 prefix
+ EXPECT_THROW(Pool4(IOAddress("192.0.2.1"), 33), BadValue);
+
+ // /0 prefix does not make sense
+ EXPECT_THROW(Pool4(IOAddress("192.0.2.0"), 0), BadValue);
+
+ // This is Pool6, IPv4 addresses do not belong here
+ EXPECT_THROW(Pool4(IOAddress("2001:db8::1"), 20), BadValue);
+}
+
+TEST(Pool4Test, in_range) {
+ Pool4 pool1(IOAddress("192.0.2.10"), IOAddress("192.0.2.20"));
+
+ EXPECT_FALSE(pool1.inRange(IOAddress("192.0.2.0")));
+ EXPECT_TRUE(pool1.inRange(IOAddress("192.0.2.10")));
+ EXPECT_TRUE(pool1.inRange(IOAddress("192.0.2.17")));
+ EXPECT_TRUE(pool1.inRange(IOAddress("192.0.2.20")));
+ EXPECT_FALSE(pool1.inRange(IOAddress("192.0.2.21")));
+ EXPECT_FALSE(pool1.inRange(IOAddress("192.0.2.255")));
+ EXPECT_FALSE(pool1.inRange(IOAddress("255.255.255.255")));
+ EXPECT_FALSE(pool1.inRange(IOAddress("0.0.0.0")));
+}
+
+// This test creates 100 pools and verifies that their IDs are unique.
+TEST(Pool4Test, unique_id) {
+
+ const int num_pools = 100;
+ std::vector<Pool4Ptr> pools;
+
+ for (int i = 0; i < num_pools; ++i) {
+ pools.push_back(Pool4Ptr(new Pool4(IOAddress("192.0.2.0"),
+ IOAddress("192.0.2.255"))));
+ }
+
+ for (int i = 0; i < num_pools; ++i) {
+ for (int j = i + 1; j < num_pools; ++j) {
+ if (pools[i]->getId() == pools[j]->getId()) {
+ FAIL() << "Pool-ids must be unique";
+ }
+ }
+ }
+
+}
+
+
+TEST(Pool6Test, constructor_first_last) {
+
+ // let's construct 2001:db8:1:: - 2001:db8:1::ffff:ffff:ffff:ffff pool
+ Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::"),
+ IOAddress("2001:db8:1::ffff:ffff:ffff:ffff"));
+
+ EXPECT_EQ(Pool6::TYPE_IA, pool1.getType());
+ EXPECT_EQ(IOAddress("2001:db8:1::"), pool1.getFirstAddress());
+ EXPECT_EQ(IOAddress("2001:db8:1::ffff:ffff:ffff:ffff"),
+ pool1.getLastAddress());
+
+ // This is Pool6, IPv4 addresses do not belong here
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::1"),
+ IOAddress("192.168.0.5")), BadValue);
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.168.0.2"),
+ IOAddress("2001:db8::1")), BadValue);
+
+ // Should throw. Range should be 2001:db8::1 - 2001:db8::2, not
+ // the other way around.
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::2"),
+ IOAddress("2001:db8::1")), BadValue);
+}
+
+TEST(Pool6Test, constructor_prefix_len) {
+
+ // let's construct 2001:db8:1::/96 pool
+ Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::"), 96);
+
+ EXPECT_EQ(Pool6::TYPE_IA, pool1.getType());
+ EXPECT_EQ("2001:db8:1::", pool1.getFirstAddress().toText());
+ EXPECT_EQ("2001:db8:1::ffff:ffff", pool1.getLastAddress().toText());
+
+ // No such thing as /130 prefix
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::"), 130),
+ BadValue);
+
+ // /0 prefix does not make sense
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::"), 0),
+ BadValue);
+
+ // This is Pool6, IPv4 addresses do not belong here
+ EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.168.0.2"), 96),
+ BadValue);
+}
+
+TEST(Pool6Test, in_range) {
+ Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::1"),
+ IOAddress("2001:db8:1::f"));
+
+ EXPECT_FALSE(pool1.inRange(IOAddress("2001:db8:1::")));
+ EXPECT_TRUE(pool1.inRange(IOAddress("2001:db8:1::1")));
+ EXPECT_TRUE(pool1.inRange(IOAddress("2001:db8:1::7")));
+ EXPECT_TRUE(pool1.inRange(IOAddress("2001:db8:1::f")));
+ EXPECT_FALSE(pool1.inRange(IOAddress("2001:db8:1::10")));
+ EXPECT_FALSE(pool1.inRange(IOAddress("::")));
+}
+
+// This test creates 100 pools and verifies that their IDs are unique.
+TEST(Pool6Test, unique_id) {
+
+ const int num_pools = 100;
+ std::vector<Pool6Ptr> pools;
+
+ for (int i = 0; i < num_pools; ++i) {
+ pools.push_back(Pool6Ptr(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1::"),
+ IOAddress("2001:db8:1::ffff:ffff:ffff:ffff"))));
+ }
+
+ for (int i = 0; i < num_pools; ++i) {
+ for (int j = i + 1; j < num_pools; ++j) {
+ if (pools[i]->getId() == pools[j]->getId()) {
+ FAIL() << "Pool-ids must be unique";
+ }
+ }
+ }
+
+}
+
+}; // end of anonymous namespace
diff --git a/src/lib/dhcpsrv/tests/run_unittests.cc b/src/lib/dhcpsrv/tests/run_unittests.cc
new file mode 100644
index 0000000..d333a6f
--- /dev/null
+++ b/src/lib/dhcpsrv/tests/run_unittests.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <log/logger_support.h>
+
+#include <gtest/gtest.h>
+
+int
+main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+ isc::log::initLogger();
+
+ int result = RUN_ALL_TESTS();
+
+ return (result);
+}
diff --git a/src/lib/dhcpsrv/tests/schema_copy.h b/src/lib/dhcpsrv/tests/schema_copy.h
new file mode 100644
index 0000000..1dd796d
--- /dev/null
+++ b/src/lib/dhcpsrv/tests/schema_copy.h
@@ -0,0 +1,85 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef SCHEMA_COPY_H
+#define SCHEMA_COPY_H
+
+namespace {
+
+// What follows is a set of statements that creates a copy of the schema
+// in the test database. It is used by the MySQL unit test prior to each
+// test.
+//
+// Each SQL statement is a single string. The statements are not terminated
+// by semicolons, and the strings must end with a comma. The final line
+// statement must be NULL (not in quotes)
+
+// THIS MUST BE KEPT UP TO DATE AND UPDATED IF THE SCHEMA CHANGES
+
+// Deletion of existing tables.
+
+const char* destroy_statement[] = {
+ "DROP TABLE lease4",
+ "DROP TABLE lease6",
+ "DROP TABLE lease6_types",
+ "DROP TABLE schema_version",
+ NULL
+};
+
+// Creation of the new tables.
+
+const char* create_statement[] = {
+ "CREATE TABLE lease4 ("
+ "address INT UNSIGNED PRIMARY KEY NOT NULL,"
+ "hwaddr VARBINARY(20),"
+ "client_id VARBINARY(128),"
+ "lease_time INT UNSIGNED,"
+ "expire TIMESTAMP,"
+ "subnet_id INT UNSIGNED"
+ ") ENGINE = INNODB",
+
+ "CREATE TABLE lease6 ("
+ "address VARCHAR(40) PRIMARY KEY NOT NULL,"
+ "duid VARBINARY(128),"
+ "valid_lifetime INT UNSIGNED,"
+ "expire TIMESTAMP,"
+ "subnet_id INT UNSIGNED,"
+ "pref_lifetime INT UNSIGNED,"
+ "lease_type TINYINT,"
+ "iaid INT UNSIGNED,"
+ "prefix_len TINYINT UNSIGNED"
+ ") ENGINE = INNODB",
+
+ "CREATE TABLE lease6_types ("
+ "lease_type TINYINT PRIMARY KEY NOT NULL,"
+ "name VARCHAR(5)"
+ ")",
+
+ "INSERT INTO lease6_types VALUES (0, \"IA_NA\")",
+ "INSERT INTO lease6_types VALUES (1, \"IA_TA\")",
+ "INSERT INTO lease6_types VALUES (2, \"IA_PD\")",
+
+ "CREATE TABLE schema_version ("
+ "version INT PRIMARY KEY NOT NULL,"
+ "minor INT"
+ ")",
+
+ "INSERT INTO schema_version VALUES (0, 1)",
+
+ NULL
+};
+
+}; // Anonymous namespace
+
+#endif // SCHEMA_COPY_H
diff --git a/src/lib/dhcpsrv/tests/subnet_unittest.cc b/src/lib/dhcpsrv/tests/subnet_unittest.cc
new file mode 100644
index 0000000..9ebef9c
--- /dev/null
+++ b/src/lib/dhcpsrv/tests/subnet_unittest.cc
@@ -0,0 +1,448 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <asiolink/io_address.h>
+#include <dhcp/option.h>
+#include <dhcpsrv/subnet.h>
+#include <exceptions/exceptions.h>
+
+#include <boost/scoped_ptr.hpp>
+#include <gtest/gtest.h>
+
+// don't import the entire boost namespace. It will unexpectedly hide uint8_t
+// for some systems.
+using boost::scoped_ptr;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+
+namespace {
+
+TEST(Subnet4Test, constructor) {
+ EXPECT_NO_THROW(Subnet4 subnet1(IOAddress("192.0.2.2"), 16,
+ 1, 2, 3));
+
+ EXPECT_THROW(Subnet4 subnet2(IOAddress("192.0.2.0"), 33, 1, 2, 3),
+ BadValue); // invalid prefix length
+ EXPECT_THROW(Subnet4 subnet3(IOAddress("2001:db8::1"), 24, 1, 2, 3),
+ BadValue); // IPv6 addresses are not allowed in Subnet4
+}
+
+TEST(Subnet4Test, in_range) {
+ Subnet4 subnet(IOAddress("192.0.2.1"), 24, 1000, 2000, 3000);
+
+ EXPECT_EQ(1000, subnet.getT1());
+ EXPECT_EQ(2000, subnet.getT2());
+ EXPECT_EQ(3000, subnet.getValid());
+
+ EXPECT_FALSE(subnet.inRange(IOAddress("192.0.0.0")));
+ EXPECT_TRUE(subnet.inRange(IOAddress("192.0.2.0")));
+ EXPECT_TRUE(subnet.inRange(IOAddress("192.0.2.1")));
+ EXPECT_TRUE(subnet.inRange(IOAddress("192.0.2.255")));
+ EXPECT_FALSE(subnet.inRange(IOAddress("192.0.3.0")));
+ EXPECT_FALSE(subnet.inRange(IOAddress("0.0.0.0")));
+ EXPECT_FALSE(subnet.inRange(IOAddress("255.255.255.255")));
+}
+
+TEST(Subnet4Test, Pool4InSubnet4) {
+
+ Subnet4Ptr subnet(new Subnet4(IOAddress("192.1.2.0"), 24, 1, 2, 3));
+
+ Pool4Ptr pool1(new Pool4(IOAddress("192.1.2.0"), 25));
+ Pool4Ptr pool2(new Pool4(IOAddress("192.1.2.128"), 26));
+ Pool4Ptr pool3(new Pool4(IOAddress("192.1.2.192"), 30));
+
+ subnet->addPool4(pool1);
+
+ // If there's only one pool, get that pool
+ Pool4Ptr mypool = subnet->getPool4();
+ EXPECT_EQ(mypool, pool1);
+
+
+ subnet->addPool4(pool2);
+ subnet->addPool4(pool3);
+
+ // If there are more than one pool and we didn't provide hint, we
+ // should get the first pool
+ mypool = subnet->getPool4();
+
+ EXPECT_EQ(mypool, pool1);
+
+ // If we provide a hint, we should get a pool that this hint belongs to
+ mypool = subnet->getPool4(IOAddress("192.1.2.195"));
+
+ EXPECT_EQ(mypool, pool3);
+
+}
+
+TEST(Subnet4Test, Subnet4_Pool4_checks) {
+
+ Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 8, 1, 2, 3));
+
+ // this one is in subnet
+ Pool4Ptr pool1(new Pool4(IOAddress("192.255.0.0"), 16));
+ subnet->addPool4(pool1);
+
+ // this one is larger than the subnet!
+ Pool4Ptr pool2(new Pool4(IOAddress("193.0.0.0"), 24));
+
+ EXPECT_THROW(subnet->addPool4(pool2), BadValue);
+
+ // this one is totally out of blue
+ Pool4Ptr pool3(new Pool4(IOAddress("1.2.3.4"), 16));
+ EXPECT_THROW(subnet->addPool4(pool3), BadValue);
+}
+
+TEST(Subnet4Test, addInvalidOption) {
+ // Create the V4 subnet.
+ Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 8, 1, 2, 3));
+
+ // Some dummy option code.
+ uint16_t code = 100;
+ // Create option with invalid universe (V6 instead of V4).
+ // Attempt to add this option should result in exception.
+ OptionPtr option1(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
+ EXPECT_THROW(subnet->addOption(option1), isc::BadValue);
+
+ // Create NULL pointer option. Attempt to add NULL option
+ // should result in exception.
+ OptionPtr option2;
+ ASSERT_FALSE(option2);
+ EXPECT_THROW(subnet->addOption(option2), isc::BadValue);
+}
+
+// This test verifies that inRange() and inPool() methods work properly.
+TEST(Subnet4Test, inRangeinPool) {
+ Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.0.0"), 8, 1, 2, 3));
+
+ // this one is in subnet
+ Pool4Ptr pool1(new Pool4(IOAddress("192.2.0.0"), 16));
+ subnet->addPool4(pool1);
+
+ // 192.1.1.1 belongs to the subnet...
+ EXPECT_TRUE(subnet->inRange(IOAddress("192.1.1.1")));
+
+ // ... but it does not belong to any pool within
+ EXPECT_FALSE(subnet->inPool(IOAddress("192.1.1.1")));
+
+ // the last address that is in range, but out of pool
+ EXPECT_TRUE(subnet->inRange(IOAddress("192.1.255.255")));
+ EXPECT_FALSE(subnet->inPool(IOAddress("192.1.255.255")));
+
+ // the first address that is in range, in pool
+ EXPECT_TRUE(subnet->inRange(IOAddress("192.2.0.0")));
+ EXPECT_TRUE (subnet->inPool(IOAddress("192.2.0.0")));
+
+ // let's try something in the middle as well
+ EXPECT_TRUE(subnet->inRange(IOAddress("192.2.3.4")));
+ EXPECT_TRUE (subnet->inPool(IOAddress("192.2.3.4")));
+
+ // the last address that is in range, in pool
+ EXPECT_TRUE(subnet->inRange(IOAddress("192.2.255.255")));
+ EXPECT_TRUE (subnet->inPool(IOAddress("192.2.255.255")));
+
+ // the first address that is in range, but out of pool
+ EXPECT_TRUE(subnet->inRange(IOAddress("192.3.0.0")));
+ EXPECT_FALSE(subnet->inPool(IOAddress("192.3.0.0")));
+}
+
+// This test checks if the toText() method returns text representation
+TEST(Subnet4Test, toText) {
+ Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3));
+ EXPECT_EQ("192.0.2.0/24", subnet->toText());
+}
+
+// This test checks if the get() method returns proper parameters
+TEST(Subnet4Test, get) {
+ Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 28, 1, 2, 3));
+ EXPECT_EQ("192.0.2.0", subnet->get().first.toText());
+ EXPECT_EQ(28, subnet->get().second);
+}
+
+// Tests for Subnet6
+
+TEST(Subnet6Test, constructor) {
+
+ EXPECT_NO_THROW(Subnet6 subnet1(IOAddress("2001:db8:1::"), 64,
+ 1, 2, 3, 4));
+
+ EXPECT_THROW(Subnet6 subnet2(IOAddress("2001:db8:1::"), 129, 1, 2, 3, 4),
+ BadValue); // invalid prefix length
+ EXPECT_THROW(Subnet6 subnet3(IOAddress("192.168.0.0"), 32, 1, 2, 3, 4),
+ BadValue); // IPv4 addresses are not allowed in Subnet6
+}
+
+TEST(Subnet6Test, in_range) {
+ Subnet6 subnet(IOAddress("2001:db8:1::"), 64, 1000, 2000, 3000, 4000);
+
+ EXPECT_EQ(1000, subnet.getT1());
+ EXPECT_EQ(2000, subnet.getT2());
+ EXPECT_EQ(3000, subnet.getPreferred());
+ EXPECT_EQ(4000, subnet.getValid());
+
+ EXPECT_FALSE(subnet.inRange(IOAddress("2001:db8:0:ffff:ffff:ffff:ffff:ffff")));
+ EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::0")));
+ EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::1")));
+ EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::ffff:ffff:ffff:ffff")));
+ EXPECT_FALSE(subnet.inRange(IOAddress("2001:db8:1:1::")));
+ EXPECT_FALSE(subnet.inRange(IOAddress("::")));
+}
+
+TEST(Subnet6Test, Pool6InSubnet6) {
+
+ Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
+
+ Pool6Ptr pool1(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:1::"), 64));
+ Pool6Ptr pool2(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:2::"), 64));
+ Pool6Ptr pool3(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:3::"), 64));
+
+ subnet->addPool6(pool1);
+
+ // If there's only one pool, get that pool
+ Pool6Ptr mypool = subnet->getPool6();
+ EXPECT_EQ(mypool, pool1);
+
+
+ subnet->addPool6(pool2);
+ subnet->addPool6(pool3);
+
+ // If there are more than one pool and we didn't provide hint, we
+ // should get the first pool
+ mypool = subnet->getPool6();
+
+ EXPECT_EQ(mypool, pool1);
+
+ // If we provide a hint, we should get a pool that this hint belongs to
+ mypool = subnet->getPool6(IOAddress("2001:db8:1:3::dead:beef"));
+
+ EXPECT_EQ(mypool, pool3);
+}
+
+TEST(Subnet6Test, Subnet6_Pool6_checks) {
+
+ Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
+
+ // this one is in subnet
+ Pool6Ptr pool1(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:1::"), 64));
+ subnet->addPool6(pool1);
+
+ // this one is larger than the subnet!
+ Pool6Ptr pool2(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::"), 48));
+
+ EXPECT_THROW(subnet->addPool6(pool2), BadValue);
+
+
+ // this one is totally out of blue
+ Pool6Ptr pool3(new Pool6(Pool6::TYPE_IA, IOAddress("3000::"), 16));
+ EXPECT_THROW(subnet->addPool6(pool3), BadValue);
+
+
+ Pool6Ptr pool4(new Pool6(Pool6::TYPE_IA, IOAddress("4001:db8:1::"), 80));
+ EXPECT_THROW(subnet->addPool6(pool4), BadValue);
+}
+
+TEST(Subnet6Test, addOptions) {
+ // Create as subnet to add options to it.
+ Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
+
+ // Differentiate options by their codes (100-109)
+ for (uint16_t code = 100; code < 110; ++code) {
+ OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
+ ASSERT_NO_THROW(subnet->addOption(option));
+ }
+
+ // Get options from the Subnet and check if all 10 are there.
+ Subnet::OptionContainer options = subnet->getOptions();
+ ASSERT_EQ(10, options.size());
+
+ // Validate codes of added options.
+ uint16_t expected_code = 100;
+ for (Subnet::OptionContainer::const_iterator option_desc = options.begin();
+ option_desc != options.end(); ++option_desc) {
+ ASSERT_TRUE(option_desc->option);
+ EXPECT_EQ(expected_code, option_desc->option->getType());
+ ++expected_code;
+ }
+
+ subnet->delOptions();
+
+ options = subnet->getOptions();
+ EXPECT_EQ(0, options.size());
+}
+
+TEST(Subnet6Test, addNonUniqueOptions) {
+ // Create as subnet to add options to it.
+ Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
+
+ // Create a set of options with non-unique codes.
+ for (int i = 0; i < 2; ++i) {
+ // In the inner loop we create options with unique codes (100-109).
+ for (uint16_t code = 100; code < 110; ++code) {
+ OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
+ ASSERT_NO_THROW(subnet->addOption(option));
+ }
+ }
+
+ // Sanity check that all options are there.
+ Subnet::OptionContainer options = subnet->getOptions();
+ ASSERT_EQ(20, options.size());
+
+ // Use container index #1 to get the options by their codes.
+ Subnet::OptionContainerTypeIndex& idx = options.get<1>();
+ // Look for the codes 100-109.
+ for (uint16_t code = 100; code < 110; ++ code) {
+ // For each code we should get two instances of options.
+ std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
+ Subnet::OptionContainerTypeIndex::const_iterator> range =
+ idx.equal_range(code);
+ // Distance between iterators indicates how many options
+ // have been retured for the particular code.
+ ASSERT_EQ(2, distance(range.first, range.second));
+ // Check that returned options actually have the expected option code.
+ for (Subnet::OptionContainerTypeIndex::const_iterator option_desc = range.first;
+ option_desc != range.second; ++option_desc) {
+ ASSERT_TRUE(option_desc->option);
+ EXPECT_EQ(code, option_desc->option->getType());
+ }
+ }
+
+ // Let's try to find some non-exiting option.
+ const uint16_t non_existing_code = 150;
+ std::pair<Subnet::OptionContainerTypeIndex::const_iterator,
+ Subnet::OptionContainerTypeIndex::const_iterator> range =
+ idx.equal_range(non_existing_code);
+ // Empty set is expected.
+ EXPECT_EQ(0, distance(range.first, range.second));
+
+ subnet->delOptions();
+
+ options = subnet->getOptions();
+ EXPECT_EQ(0, options.size());
+}
+
+TEST(Subnet6Test, addInvalidOption) {
+ // Create as subnet to add options to it.
+ Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
+
+ // Some dummy option code.
+ uint16_t code = 100;
+ // Create option with invalid universe (V4 instead of V6).
+ // Attempt to add this option should result in exception.
+ OptionPtr option1(new Option(Option::V4, code, OptionBuffer(10, 0xFF)));
+ EXPECT_THROW(subnet->addOption(option1), isc::BadValue);
+
+ // Create NULL pointer option. Attempt to add NULL option
+ // should result in exception.
+ OptionPtr option2;
+ ASSERT_FALSE(option2);
+ EXPECT_THROW(subnet->addOption(option2), isc::BadValue);
+}
+
+TEST(Subnet6Test, addPersistentOption) {
+ // Create as subnet to add options to it.
+ Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
+
+ // Add 10 options to the subnet with option codes 100 - 109.
+ for (uint16_t code = 100; code < 110; ++code) {
+ OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
+ // We create 10 options and want some of them to be flagged
+ // persistent and some non-persistent. Persistent options are
+ // those that server sends to clients regardless if they ask
+ // for them or not. We pick 3 out of 10 options and mark them
+ // non-persistent and 7 other options persistent.
+ // Code values: 102, 105 and 108 are divisable by 3
+ // and options with these codes will be flagged non-persistent.
+ // Options with other codes will be flagged persistent.
+ bool persistent = (code % 3) ? true : false;
+ ASSERT_NO_THROW(subnet->addOption(option, persistent));
+ }
+
+ // Get added options from the subnet.
+ Subnet::OptionContainer options = subnet->getOptions();
+
+ // options.get<2> returns reference to container index #2. This
+ // index is used to access options by the 'persistent' flag.
+ Subnet::OptionContainerPersistIndex& idx = options.get<2>();
+
+ // Get all persistent options.
+ std::pair<Subnet::OptionContainerPersistIndex::const_iterator,
+ Subnet::OptionContainerPersistIndex::const_iterator> range_persistent =
+ idx.equal_range(true);
+ // 3 out of 10 options have been flagged persistent.
+ ASSERT_EQ(7, distance(range_persistent.first, range_persistent.second));
+
+ // Get all non-persistent options.
+ std::pair<Subnet::OptionContainerPersistIndex::const_iterator,
+ Subnet::OptionContainerPersistIndex::const_iterator> range_non_persistent =
+ idx.equal_range(false);
+ // 7 out of 10 options have been flagged persistent.
+ ASSERT_EQ(3, distance(range_non_persistent.first, range_non_persistent.second));
+
+ subnet->delOptions();
+
+ options = subnet->getOptions();
+ EXPECT_EQ(0, options.size());
+}
+
+// This test verifies that inRange() and inPool() methods work properly.
+TEST(Subnet6Test, inRangeinPool) {
+ Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8::"), 32, 1, 2, 3, 4));
+
+ // this one is in subnet
+ Pool6Ptr pool1(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::10"),
+ IOAddress("2001:db8::20")));
+ subnet->addPool6(pool1);
+
+ // 192.1.1.1 belongs to the subnet...
+ EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::1")));
+ // ... but it does not belong to any pool within
+ EXPECT_FALSE(subnet->inPool(IOAddress("2001:db8::1")));
+
+ // the last address that is in range, but out of pool
+ EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::f")));
+ EXPECT_FALSE(subnet->inPool(IOAddress("2001:db8::f")));
+
+ // the first address that is in range, in pool
+ EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::10")));
+ EXPECT_TRUE (subnet->inPool(IOAddress("2001:db8::10")));
+
+ // let's try something in the middle as well
+ EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::18")));
+ EXPECT_TRUE (subnet->inPool(IOAddress("2001:db8::18")));
+
+ // the last address that is in range, in pool
+ EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::20")));
+ EXPECT_TRUE (subnet->inPool(IOAddress("2001:db8::20")));
+
+ // the first address that is in range, but out of pool
+ EXPECT_TRUE(subnet->inRange(IOAddress("2001:db8::21")));
+ EXPECT_FALSE(subnet->inPool(IOAddress("2001:db8::21")));
+}
+
+// This test checks if the toText() method returns text representation
+TEST(Subnet6Test, toText) {
+ Subnet6 subnet(IOAddress("2001:db8::"), 32, 1, 2, 3, 4);
+ EXPECT_EQ("2001:db8::/32", subnet.toText());
+}
+
+// This test checks if the get() method returns proper parameters
+TEST(Subnet6Test, get) {
+ Subnet6 subnet(IOAddress("2001:db8::"), 32, 1, 2, 3, 4);
+ EXPECT_EQ("2001:db8::", subnet.get().first.toText());
+ EXPECT_EQ(32, subnet.get().second);
+}
+
+};
diff --git a/src/lib/dhcpsrv/tests/triplet_unittest.cc b/src/lib/dhcpsrv/tests/triplet_unittest.cc
new file mode 100644
index 0000000..e80177e
--- /dev/null
+++ b/src/lib/dhcpsrv/tests/triplet_unittest.cc
@@ -0,0 +1,107 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <dhcpsrv/triplet.h>
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+
+#include <stdint.h>
+
+using namespace isc::dhcp;
+using namespace isc;
+
+namespace {
+
+// constructor validation
+TEST(TripletTest, constructor) {
+
+ const uint32_t min = 10;
+ const uint32_t value = 20;
+ const uint32_t max = 30;
+
+ Triplet<uint32_t> x(min, value, max);
+
+ EXPECT_EQ(min, x.getMin());
+ EXPECT_EQ(value, x.get());
+ EXPECT_EQ(max, x.getMax());
+
+ // requested values below min should return allowed min value
+ EXPECT_EQ(min, x.get(min - 5));
+
+ EXPECT_EQ(min, x.get(min));
+
+ // requesting a value from within the range (min < x < max) should
+ // return the requested value
+ EXPECT_EQ(17, x.get(17));
+
+ EXPECT_EQ(max, x.get(max));
+
+ EXPECT_EQ(max, x.get(max + 5));
+
+ // this will be boring. It is expected to return 42 no matter what
+ Triplet<uint32_t> y(42);
+
+ EXPECT_EQ(42, y.getMin()); // min, default and max are equal to 42
+ EXPECT_EQ(42, y.get()); // it returns ...
+ EXPECT_EQ(42, y.getMax()); // the exact value...
+
+ // requested values below or above are ignore
+ EXPECT_EQ(42, y.get(5)); // all...
+ EXPECT_EQ(42, y.get(42)); // the...
+ EXPECT_EQ(42, y.get(80)); // time!
+}
+
+// Triplets must be easy to use.
+// Simple to/from int conversions must be done on the fly.
+TEST(TripletTest, operator) {
+
+ uint32_t x = 47;
+
+ Triplet<uint32_t> foo(1,2,3);
+ Triplet<uint32_t> bar(4,5,6);
+
+ foo = bar;
+
+ EXPECT_EQ(4, foo.getMin());
+ EXPECT_EQ(5, foo.get());
+ EXPECT_EQ(6, foo.getMax());
+
+ // assignment operator: uint32_t => triplet
+ Triplet<uint32_t> y(0);
+ y = x;
+
+ EXPECT_EQ(x, y.get());
+
+ // let's try the other way around: triplet => uint32_t
+ uint32_t z = 0;
+ z = y;
+
+ EXPECT_EQ(x, z);
+}
+
+// check if specified values are sane
+TEST(TripletTest, sanity_check) {
+
+ // min is larger than default
+ EXPECT_THROW(Triplet<uint32_t>(6,5,5), BadValue);
+
+ // max is smaller than default
+ EXPECT_THROW(Triplet<uint32_t>(5,5,4), BadValue);
+
+}
+
+}; // end of anonymous namespace
diff --git a/src/lib/dhcpsrv/triplet.h b/src/lib/dhcpsrv/triplet.h
new file mode 100644
index 0000000..d9388fe
--- /dev/null
+++ b/src/lib/dhcpsrv/triplet.h
@@ -0,0 +1,115 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef TRIPLET_H
+#define TRIPLET_H
+
+#include <exceptions/exceptions.h>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief this template specifies a parameter value
+///
+/// This template class is used to store configuration parameters, like lifetime or T1.
+/// It defines 3 parameters: min, default, and max value. There are 2 constructors:
+/// - simple (just one value that sets all parameters)
+/// - extended (that sets default value and two thresholds)
+/// It will be used with integer types. It provides necessary operators, so
+/// it can be assigned to a plain integer or integer assigned to a Triplet.
+/// See TripletTest.operator test for details on an easy Triplet usage.
+template <class T>
+class Triplet {
+public:
+
+ /// @brief base type to Triple conversion
+ ///
+ /// Typically: uint32_t to Triplet assignment. It is very convenient
+ /// to be able to simply write Triplet<uint32_t> x = 7;
+ Triplet<T> operator=(T other) {
+ min_ = other;
+ default_ = other;
+ max_ = other;
+ return *this;
+ }
+
+ /// @brief triplet to base type conversion
+ ///
+ /// Typically: Triplet to uint32_t assignment. It is very convenient
+ /// to be able to simply write uint32_t z = x; (where x is a Triplet)
+ operator T() const {
+ return (default_);
+ }
+
+ /// @brief sets a fixed value
+ ///
+ /// This constructor assigns a fixed (i.e. no range, just a single value)
+ /// value.
+ Triplet(T value)
+ :min_(value), default_(value), max_(value) {
+ }
+
+ /// @brief sets the default value and thresholds
+ ///
+ /// @throw BadValue if min <= def <= max rule is violated
+ Triplet(T min, T def, T max)
+ :min_(min), default_(def), max_(max) {
+ if ( (min_ > def) || (def > max_) ) {
+ isc_throw(BadValue, "Invalid triplet values.");
+ }
+ }
+
+ /// @brief returns a minimum allowed value
+ T getMin() const { return min_;}
+
+ /// @brief returns the default value
+ T get() const { return default_;}
+
+ /// @brief returns value with a hint
+ ///
+ /// DHCP protocol treats any values sent by a client as hints.
+ /// This is a method that implements that. We can assign any value
+ /// from configured range that client asks.
+ T get(T hint) const {
+ if (hint <= min_) {
+ return (min_);
+ }
+
+ if (hint >= max_) {
+ return (max_);
+ }
+
+ return (hint);
+ }
+
+ /// @brief returns a maximum allowed value
+ T getMax() const { return max_; }
+
+protected:
+
+ /// @brief the minimum value
+ T min_;
+
+ /// @brief the default value
+ T default_;
+
+ /// @brief the maximum value
+ T max_;
+};
+
+
+} // namespace isc::dhcp
+} // namespace isc
+
+#endif // ifdef TRIPLET_H
diff --git a/tests/lettuce/configurations/auth/.gitignore b/tests/lettuce/configurations/auth/.gitignore
index 07f1b7d..8165b69 100644
--- a/tests/lettuce/configurations/auth/.gitignore
+++ b/tests/lettuce/configurations/auth/.gitignore
@@ -1 +1,2 @@
+/auth_badzone.config
/auth_basic.config
diff --git a/tests/lettuce/configurations/auth/auth_badzone.config.orig b/tests/lettuce/configurations/auth/auth_badzone.config.orig
new file mode 100644
index 0000000..ab11bc9
--- /dev/null
+++ b/tests/lettuce/configurations/auth/auth_badzone.config.orig
@@ -0,0 +1,38 @@
+{
+ "version": 2,
+ "Logging": {
+ "loggers": [{
+ "severity": "DEBUG",
+ "name": "*",
+ "debuglevel": 99
+ }]
+ },
+ "Auth": {
+ "listen_on": [{
+ "port": 47806,
+ "address": "127.0.0.1"
+ }]
+ },
+ "data_sources": {
+ "classes": {
+ "IN": [
+ {
+ "type": "MasterFiles",
+ "cache-enable": true,
+ "params": {
+ "example.org": "data/example.org",
+ "example.com": "data/example.com-broken",
+ "example.net": "data/example.net-empty",
+ "example.info": "data/example.info-doesnt-exist"
+ }
+ }
+ ]
+ }
+ },
+ "Boss": {
+ "components": {
+ "b10-auth": { "kind": "needed", "special": "auth" },
+ "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
+ }
+ }
+}
diff --git a/tests/lettuce/data/example.com-broken b/tests/lettuce/data/example.com-broken
new file mode 100644
index 0000000..ceef6c3
--- /dev/null
+++ b/tests/lettuce/data/example.com-broken
@@ -0,0 +1,11 @@
+example.com. 3600 IN SOA ns1.example.com. admin.example.com. 1234 3600 1800 2419200 7200
+example.com. 3600 IN NS ns1.example.com.
+example.com. 3600 IN NS ns2.example.com.
+example.com. 3600 IN MX 10 mail.example.com.
+www.example.com. 3600 IN A 192.0.2.1
+ns1.example.com. 3600 IN A 192.0.2.3
+ns2.example.com. 3600 IN A 192.0.2.4
+
+;; DNAME + NS (non-apex) throws ZoneDataUpdater::AddError
+ns1.example.com. 3600 IN DNAME foo.example.com.
+ns1.example.com. 3600 IN NS bar.example.com.
diff --git a/tests/lettuce/data/example.net-empty b/tests/lettuce/data/example.net-empty
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/tests/lettuce/data/example.net-empty
@@ -0,0 +1 @@
+
diff --git a/tests/lettuce/features/auth_badzone.feature b/tests/lettuce/features/auth_badzone.feature
new file mode 100644
index 0000000..edc1a64
--- /dev/null
+++ b/tests/lettuce/features/auth_badzone.feature
@@ -0,0 +1,49 @@
+Feature: Authoritative DNS server with a bad zone
+ This feature set is for testing the execution of the b10-auth
+ component when one zone is broken, whereas others are fine. In this
+ case, b10-auth should not reject the data source, but reject the bad
+ zone only and serve the good zones anyway.
+
+ Scenario: Bad zone
+ Given I have bind10 running with configuration auth/auth_badzone.config
+
+ # loading example.com, example.net and example.info zones fail.
+ # Note: wait for these messages right away as otherwise they
+ # will be logged and we cannot use the 'new' keyword to wait for
+ # 3 different log messages. *There could still be a race here if
+ # auth starts very quickly.*
+ And wait for new bind10 stderr message DATASRC_LOAD_FROM_FILE_ERROR
+ And wait for new bind10 stderr message DATASRC_LOAD_FROM_FILE_ERROR
+ And wait for new bind10 stderr message DATASRC_LOAD_FROM_FILE_ERROR
+
+ And wait for bind10 stderr message BIND10_STARTED_CC
+ And wait for bind10 stderr message CMDCTL_STARTED
+ And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+ bind10 module Auth should be running
+ And bind10 module Resolver should not be running
+
+ A query for www.example.org should have rcode NOERROR
+ The last query response should have flags qr aa rd
+ The last query response should have ancount 1
+ The last query response should have nscount 2
+ The last query response should have adcount 2
+
+ The answer section of the last query response should be
+ """
+ www.example.org. 3600 IN A 192.0.2.1
+ """
+ The authority section of the last query response should be
+ """
+ example.org. 3600 IN NS ns1.example.org.
+ example.org. 3600 IN NS ns2.example.org.
+ """
+ The additional section of the last query response should be
+ """
+ ns1.example.org. 3600 IN A 192.0.2.3
+ ns2.example.org. 3600 IN A 192.0.2.4
+ """
+
+ A query for www.example.com should have rcode REFUSED
+ A query for www.example.net should have rcode REFUSED
+ A query for www.example.info should have rcode REFUSED
diff --git a/tests/lettuce/features/terrain/terrain.py b/tests/lettuce/features/terrain/terrain.py
index 74cdfea..bc05341 100644
--- a/tests/lettuce/features/terrain/terrain.py
+++ b/tests/lettuce/features/terrain/terrain.py
@@ -51,6 +51,8 @@ copylist = [
"configurations/bindctl/bindctl.config"],
["configurations/auth/auth_basic.config.orig",
"configurations/auth/auth_basic.config"],
+ ["configurations/auth/auth_badzone.config.orig",
+ "configurations/auth/auth_badzone.config"],
["configurations/resolver/resolver_basic.config.orig",
"configurations/resolver/resolver_basic.config"],
["configurations/multi_instance/multi_auth.config.orig",
diff --git a/tests/tools/perfdhcp/templates/Makefile.am b/tests/tools/perfdhcp/templates/Makefile.am
index 33930a7..c22787f 100644
--- a/tests/tools/perfdhcp/templates/Makefile.am
+++ b/tests/tools/perfdhcp/templates/Makefile.am
@@ -5,8 +5,6 @@ SUBDIRS = .
CLEANFILES = test1.hex test2.hex test3.hex test4.hex test5.hex
perfdhcpdir = $(pkgdatadir)
-perfdhcp_DATA = discover-example.hex request4-example.hex
-perfdhcp_DATA += solicit-example.hex request6-example.hex
EXTRA_DIST = discover-example.hex request4-example.hex
EXTRA_DIST += solicit-example.hex request6-example.hex
More information about the bind10-changes
mailing list