BIND 10 trac2292, updated. 5c74085e2f4c16655e77e1bcbc308d4fb0a694f8 [2292] Get rid of the const_cast
BIND 10 source code commits
bind10-changes at lists.isc.org
Tue Oct 2 19:08:30 UTC 2012
The branch, trac2292 has been updated
discards 536d25ae8f41c90653724a1ca453b290867461e5 (commit)
via 5c74085e2f4c16655e77e1bcbc308d4fb0a694f8 (commit)
via 4babe763de5b20437e32829024f25a1b902df82f (commit)
via f5811cdff640338babcf1ca0b4cfc7a06580a4f5 (commit)
via 723885f4ab0096dbea3a21f63badb18d79f28814 (commit)
via 76fa5523da1da9778a686b39dbba5759dcea34da (commit)
via 09e793e3c71fbbc12f8f8461ceafbabc2edcbc9e (commit)
via 6f29861b92742da34be9ae76968e82222b5bfd7d (commit)
via e5bf564f734555173b5cae04757bc3f870f3463a (commit)
via 6fad0e38082ed1078acb7add13321212dccdcf88 (commit)
via ac07f31fa2182962f4e958330fc460abeac350d5 (commit)
via 34a2c9541c16578175eb928b9ea3f3c7755965d3 (commit)
via 73b258b1b4284e1017aedacee9ed75301be23e79 (commit)
via ae65cad3fbe923329f674694614e0af560c37018 (commit)
via 3690baaf0660af752b00a370fadcd60859c50ca4 (commit)
via 704ca46ac3aa9c93c9964eb3495bacd4050f042e (commit)
via 5a0aa214c3e6b52ef738ca574105bf0120ac844b (commit)
via b8f538b9fcf70394e5737269d4bed660721c245d (commit)
via 68621232d6840227c4309c1fd1ee9e1a8b26120f (commit)
via c9bae4745f58fc361ebeb0f91bb15b288e96e5cf (commit)
via daf7bbcc05e24e2e6894ac2cf59fa738cfb199bc (commit)
via d1c7c9057bb24595f9dcefe226dc7f326f390486 (commit)
via a7a5b8a6e3605e3a3788f6920a45e9fa3c215be0 (commit)
via eda12494283d717f4fb095be4ff57608f4003502 (commit)
via a66bc5d487b4b095bb9e322e33ed31c55d8af339 (commit)
via c16a30cbaf082a05c0fbd5c929bf0be6f007503f (commit)
via e9498651c8bc59ba17f353f196c0675dd7b8e2ff (commit)
This update added new revisions after undoing existing revisions. That is
to say, the old revision is not a strict subset of the new revision. This
situation occurs when you --force push a change and generate a repository
containing something like this:
* -- * -- B -- O -- O -- O (536d25ae8f41c90653724a1ca453b290867461e5)
\
N -- N -- N (5c74085e2f4c16655e77e1bcbc308d4fb0a694f8)
When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.
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 5c74085e2f4c16655e77e1bcbc308d4fb0a694f8
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Oct 2 21:05:33 2012 +0200
[2292] Get rid of the const_cast
It was needed when extracting data from a domain tree chain. The chain
now can hold mutable pointers too, so we use that (and some amount of
template bureaucracy) to avoid the cast.
While the interface changed (on the core find function, it is not
possible to pass const node chain and have a mutable node get out), it
doesn't seem to influence the current code. Also, it is a private
interface anyway, so it should be safe.
commit 4babe763de5b20437e32829024f25a1b902df82f
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue Oct 2 20:22:23 2012 +0200
[2292] Parametrize constness of the chain
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 25 ++-
src/lib/asiolink/io_address.h | 55 ++++++-
src/lib/asiolink/tests/io_address_unittest.cc | 32 ++++
src/lib/datasrc/Makefile.am | 4 +-
src/lib/datasrc/memory/domaintree.h | 56 ++++---
src/lib/datasrc/memory/memory_client.cc | 2 +-
src/lib/datasrc/memory/zone_finder.cc | 11 +-
.../datasrc/tests/memory/zone_finder_unittest.cc | 2 +-
src/lib/dhcp/Makefile.am | 14 +-
src/lib/dhcp/README | 14 +-
src/lib/dhcp/addr_utilities.cc | 96 ++++++++++++
src/lib/dhcp/addr_utilities.h | 53 +++++++
src/lib/dhcp/cfgmgr.cc | 78 ++++++++++
src/lib/dhcp/cfgmgr.h | 126 +++++++++++++++
src/lib/dhcp/pool.cc | 87 +++++++++++
src/lib/dhcp/pool.h | 155 +++++++++++++++++++
src/lib/dhcp/subnet.cc | 91 +++++++++++
src/lib/dhcp/subnet.h | 161 ++++++++++++++++++++
src/lib/dhcp/tests/Makefile.am | 21 ++-
src/lib/dhcp/tests/addr_utilities_unittest.cc | 93 +++++++++++
src/lib/dhcp/tests/cfgmgr_unittest.cc | 63 ++++++++
src/lib/dhcp/tests/pool_unittest.cc | 109 +++++++++++++
src/lib/dhcp/tests/run_unittests.cc | 1 -
src/lib/dhcp/tests/subnet_unittest.cc | 112 ++++++++++++++
src/lib/dhcp/tests/triplet_unittest.cc | 104 +++++++++++++
src/lib/dhcp/triplet.h | 110 +++++++++++++
26 files changed, 1623 insertions(+), 52 deletions(-)
create mode 100644 src/lib/dhcp/addr_utilities.cc
create mode 100644 src/lib/dhcp/addr_utilities.h
create mode 100644 src/lib/dhcp/cfgmgr.cc
create mode 100644 src/lib/dhcp/cfgmgr.h
create mode 100644 src/lib/dhcp/pool.cc
create mode 100644 src/lib/dhcp/pool.h
create mode 100644 src/lib/dhcp/subnet.cc
create mode 100644 src/lib/dhcp/subnet.h
create mode 100644 src/lib/dhcp/tests/addr_utilities_unittest.cc
create mode 100644 src/lib/dhcp/tests/cfgmgr_unittest.cc
create mode 100644 src/lib/dhcp/tests/pool_unittest.cc
create mode 100644 src/lib/dhcp/tests/subnet_unittest.cc
create mode 100644 src/lib/dhcp/tests/triplet_unittest.cc
create mode 100644 src/lib/dhcp/triplet.h
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 84d4378..53a79e1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+484. [func] tomek
+ A new library (libb10-dhcpsrv) has been created. At present, it
+ only holds the code for the DHCP Configuration Manager. Currently
+ this object only supports basic configuration storage for the DHCPv6
+ server, but that capability will be expanded.
+ (Trac #2238, git 6f29861b92742da34be9ae76968e82222b5bfd7d)
+
+bind10-devel-20120927 released on September 27, 2012
+
+483. [func] marcin
+ libdhcp++: Added new parameter to define sub-second timeout
+ for DHCP packet reception. The total timeout is now specified
+ by two parameters: first specifies integral number of
+ seconds, second (which defaults to 0) specifies fractional
+ seconds with microsecond resolution.
+ (Trac #2231, git 15560cac16e4c52129322e3cb1787e0f47cf7850)
+
482. [func] team
Memory footprint of the in-memory data source has been
substantially improved. For example, b10-auth now requires much
@@ -9,11 +26,11 @@
of the memory image. Also, loading zones in memory still suspends
query processing, so manual reloading or reloading after incoming
transfer may cause service disruption for huge zones.
- (Multiple Trac tickets)
+ (Multiple Trac tickets, Summarized in Trac #2101)
481. [bug] vorner
The abbreviated form of IP addresses in ACLs is accepted
- (eg. "from": ["127.0.01", "::1"] now works).
+ (eg. "from": ["127.0.0.1", "::1"] now works).
(Trac #2191, git 48b6e91386b46eed383126ad98dddfafc9f7e75e)
480. [doc] vorner
@@ -45,10 +62,10 @@
(Trac #2190, git e0ffa11d49ab949ee5a4ffe7682b0e6906667baa)
476. [bug] vorner
- The XfrIn now accepts transfers with some TSIG signatures omitted, as
+ The Xfrin now accepts transfers with some TSIG signatures omitted, as
allowed per RFC2845, section 4.4. This solves a compatibility
issues with Knot and NSD.
- (Trac #1375, git 7ca65cb9ec528118f370142d7e7b792fcc31c9cf)
+ (Trac #1357, git 7ca65cb9ec528118f370142d7e7b792fcc31c9cf)
475. [func] naokikambe
Added Xfrout statistics counters: notifyoutv4, notifyoutv6,
diff --git a/src/lib/asiolink/io_address.h b/src/lib/asiolink/io_address.h
index c40e5b9..a3bb61a 100644
--- a/src/lib/asiolink/io_address.h
+++ b/src/lib/asiolink/io_address.h
@@ -131,7 +131,7 @@ public:
return equals(other);
}
- // \brief Compare addresses for inequality
+ /// \brief Compare addresses for inequality
///
/// \param other Address to compare against.
///
@@ -140,7 +140,58 @@ public:
return (!equals(other));
}
- // \brief Compare addresses for inequality
+ /// \brief Checks if one address is smaller than the other
+ ///
+ /// \param other Address to compare against.
+ ///
+ /// \return true if this address is smaller than the other address.
+ ///
+ /// It is useful for comparing which address is bigger.
+ /// Operations within one protocol family are obvious.
+ /// Comparisons between v4 and v6 will allways return v4
+ /// being smaller. This follows boost::asio::ip implementation
+ bool lessThan(const IOAddress& other) const {
+ if (this->getFamily() == other.getFamily()) {
+ if (this->getFamily() == AF_INET6) {
+ return (this->asio_address_.to_v6() < other.asio_address_.to_v6());
+ } else {
+ return (this->asio_address_.to_v4() < other.asio_address_.to_v4());
+ }
+ }
+ return (this->getFamily() < other.getFamily());
+ }
+
+ /// \brief Checks if one address is smaller or equal than the other
+ ///
+ /// \param other Address to compare against.
+ ///
+ /// \return true if this address is smaller than the other address.
+ bool smallerEqual(const IOAddress& other) const {
+ if (equals(other)) {
+ return (true);
+ }
+ return (lessThan(other));
+ }
+
+ /// \brief Checks if one address is smaller than the other
+ ///
+ /// \param other Address to compare against.
+ ///
+ /// See \ref smaller_than method for details.
+ bool operator<(const IOAddress& other) const {
+ return (lessThan(other));
+ }
+
+ /// \brief Checks if one address is smaller or equal than the other
+ ///
+ /// \param other Address to compare against.
+ ///
+ /// See \ref smaller_equal method for details.
+ bool operator<=(const IOAddress& other) const {
+ return (smallerEqual(other));
+ }
+
+ /// \brief Compare addresses for inequality
///
/// \param other Address to compare against.
///
diff --git a/src/lib/asiolink/tests/io_address_unittest.cc b/src/lib/asiolink/tests/io_address_unittest.cc
index 4322283..a1a9076 100644
--- a/src/lib/asiolink/tests/io_address_unittest.cc
+++ b/src/lib/asiolink/tests/io_address_unittest.cc
@@ -99,3 +99,35 @@ TEST(IOAddressTest, uint32) {
EXPECT_EQ(addr3.toText(), "192.0.2.5");
}
+
+TEST(IOAddressTest, lessThanEqual) {
+ IOAddress addr1("192.0.2.5");
+ IOAddress addr2("192.0.2.6");
+ IOAddress addr3("0.0.0.0");
+
+ IOAddress addr4("::");
+ IOAddress addr5("2001:db8::1");
+ IOAddress addr6("2001:db8::1:0");
+ IOAddress addr7("2001:db8::1:0"); // the same as 6
+
+ // v4 comparisons
+ EXPECT_TRUE(addr1 < addr2);
+ EXPECT_FALSE(addr2 < addr1);
+ EXPECT_FALSE(addr2 <= addr1);
+ EXPECT_TRUE(addr3 < addr1);
+ EXPECT_TRUE(addr3 < addr2);
+ EXPECT_TRUE(addr3 <= addr2);
+
+ // v6 comparisons
+ EXPECT_TRUE(addr4 < addr5);
+ EXPECT_TRUE(addr5 < addr6);
+ EXPECT_FALSE(addr6 < addr5);
+ EXPECT_FALSE(addr6 <= addr5);
+
+ // v4 to v6 - v4 should always be smaller
+ EXPECT_TRUE(addr1 < addr4);
+ EXPECT_TRUE(addr3 < addr4);
+ EXPECT_TRUE(addr2 < addr5);
+
+ EXPECT_TRUE(addr6 <= addr7);
+}
diff --git a/src/lib/datasrc/Makefile.am b/src/lib/datasrc/Makefile.am
index 862de8a..eccc147 100644
--- a/src/lib/datasrc/Makefile.am
+++ b/src/lib/datasrc/Makefile.am
@@ -12,7 +12,9 @@ pkglibdir = $(libexecdir)/@PACKAGE@/backends
datasrc_config.h: datasrc_config.h.pre
$(SED) -e "s|@@PKGLIBDIR@@|$(pkglibdir)|" datasrc_config.h.pre >$@
-static.zone: static.zone.pre
+# The top config.h defines "PACKAGE_STRING". When it's changed we neeed to
+# regenerate this zone file.
+static.zone: static.zone.pre $(top_builddir)/config.h $(top_srcdir)/AUTHORS
$(SED) -e "s|@@VERSION_STRING@@|$(PACKAGE_STRING)|" $(srcdir)/static.zone.pre >$@
$(SED) -e 's/\(.*\)/AUTHORS.BIND. 0 CH TXT "\1"/' $(top_srcdir)/AUTHORS >>$@
diff --git a/src/lib/datasrc/memory/domaintree.h b/src/lib/datasrc/memory/domaintree.h
index 172a0ae..e54d8ea 100644
--- a/src/lib/datasrc/memory/domaintree.h
+++ b/src/lib/datasrc/memory/domaintree.h
@@ -684,7 +684,7 @@ DomainTreeNode<T>::predecessor() const {
/// DomainTree.
/// This is the reason why manipulation methods such as \c push() and \c pop()
/// are private (and not shown in the doxygen document).
-template <typename T>
+template <typename T, typename NodeType = const DomainTreeNode<T> >
class DomainTreeNodeChain {
/// DomainTreeNodeChain is initialized by DomainTree, only DomainTree has
/// knowledge to manipulate it.
@@ -817,7 +817,7 @@ private:
/// root node of DomainTree
///
/// \exception None
- const DomainTreeNode<T>* top() const {
+ NodeType* top() const {
assert(!isEmpty());
return (nodes_[level_count_ - 1]);
}
@@ -840,7 +840,7 @@ private:
/// otherwise the node should be the root node of DomainTree.
///
/// \exception None
- void push(const DomainTreeNode<T>* node) {
+ void push(NodeType* node) {
assert(level_count_ < RBT_MAX_LEVEL);
nodes_[level_count_++] = node;
}
@@ -852,7 +852,7 @@ private:
const static int RBT_MAX_LEVEL = isc::dns::Name::MAX_LABELS;
size_t level_count_;
- const DomainTreeNode<T>* nodes_[RBT_MAX_LEVEL];
+ NodeType* nodes_[RBT_MAX_LEVEL];
const DomainTreeNode<T>* last_compared_;
isc::dns::NameComparisonResult last_comparison_;
};
@@ -1085,9 +1085,10 @@ public:
/// Acts as described in the \ref find section.
Result find(const isc::dns::Name& name,
DomainTreeNode<T>** node) const {
- DomainTreeNodeChain<T> node_path;
+ DomainTreeNodeChain<T, DomainTreeNode<T> > node_path;
const isc::dns::LabelSequence ls(name);
- return (find<void*>(ls, node, node_path, NULL, NULL));
+ return (find<void*, DomainTreeNode<T> >(ls, node, node_path, NULL,
+ NULL));
}
/// \brief Simple find returning immutable node.
@@ -1097,9 +1098,11 @@ public:
Result find(const isc::dns::Name& name,
const DomainTreeNode<T>** node) const {
DomainTreeNodeChain<T> node_path;
- DomainTreeNode<T> *target_node = NULL;
+ const DomainTreeNode<T> *target_node = NULL;
const isc::dns::LabelSequence ls(name);
- Result ret = (find<void*>(ls, &target_node, node_path, NULL, NULL));
+ Result ret = (find<void*, const DomainTreeNode<T> >(ls, &target_node,
+ node_path, NULL,
+ NULL));
if (ret != NOTFOUND) {
*node = target_node;
}
@@ -1113,7 +1116,8 @@ public:
DomainTreeNodeChain<T>& node_path) const
{
const isc::dns::LabelSequence ls(name);
- return (find<void*>(ls, node, node_path, NULL, NULL));
+ return (find<void*, const DomainTreeNode<T> >(ls, node, node_path,
+ NULL, NULL));
}
/// \brief Simple find returning immutable node, with node_path tracking
@@ -1123,9 +1127,11 @@ public:
Result find(const isc::dns::Name& name, const DomainTreeNode<T>** node,
DomainTreeNodeChain<T>& node_path) const
{
- DomainTreeNode<T> *target_node = NULL;
+ const DomainTreeNode<T> *target_node = NULL;
const isc::dns::LabelSequence ls(name);
- Result ret = (find<void*>(ls, &target_node, node_path, NULL, NULL));
+ Result ret = (find<void*, const DomainTreeNode<T> >(ls, &target_node,
+ node_path, NULL,
+ NULL));
if (ret != NOTFOUND) {
*node = target_node;
}
@@ -1143,7 +1149,7 @@ public:
bool (*callback)(const DomainTreeNode<T>&, CBARG),
CBARG callback_arg) const
{
- DomainTreeNode<T>* target_node = NULL;
+ const DomainTreeNode<T>* target_node = NULL;
const isc::dns::LabelSequence ls(name);
Result ret = find(ls, &target_node, node_path, callback,
callback_arg);
@@ -1227,10 +1233,10 @@ public:
///
/// \return As in the description, but in case of callback returning
/// \c true, it returns immediately with the current node.
- template <typename CBARG>
+ template <typename CBARG, typename NodeType>
Result find(const isc::dns::LabelSequence& target_labels_orig,
- DomainTreeNode<T>** node,
- DomainTreeNodeChain<T>& node_path,
+ NodeType** node,
+ DomainTreeNodeChain<T, NodeType>& node_path,
bool (*callback)(const DomainTreeNode<T>&, CBARG),
CBARG callback_arg) const;
@@ -1245,9 +1251,11 @@ public:
bool (*callback)(const DomainTreeNode<T>&, CBARG),
CBARG callback_arg) const
{
- DomainTreeNode<T>* target_node = NULL;
- Result ret = find(target_labels, &target_node, node_path,
- callback, callback_arg);
+ const DomainTreeNode<T>* target_node = NULL;
+ Result ret = find<CBARG, const DomainTreeNode<T> >(target_labels,
+ &target_node,
+ node_path, callback,
+ callback_arg);
if (ret != NOTFOUND) {
*node = target_node;
}
@@ -1512,11 +1520,11 @@ DomainTree<T>::deleteHelper(util::MemorySegment& mem_sgmt,
}
template <typename T>
-template <typename CBARG>
+template <typename CBARG, typename NodeType>
typename DomainTree<T>::Result
DomainTree<T>::find(const isc::dns::LabelSequence& target_labels_orig,
- DomainTreeNode<T>** target,
- DomainTreeNodeChain<T>& node_path,
+ NodeType** target,
+ DomainTreeNodeChain<T, NodeType>& node_path,
bool (*callback)(const DomainTreeNode<T>&, CBARG),
CBARG callback_arg) const
{
@@ -1526,7 +1534,7 @@ DomainTree<T>::find(const isc::dns::LabelSequence& target_labels_orig,
" and label sequence");
}
- const DomainTreeNode<T>* node;
+ NodeType* node;
if (!node_path.isEmpty()) {
// Get the top node in the node chain
@@ -1549,7 +1557,7 @@ DomainTree<T>::find(const isc::dns::LabelSequence& target_labels_orig,
if (relation == isc::dns::NameComparisonResult::EQUAL) {
if (needsReturnEmptyNode_ || !node->isEmpty()) {
node_path.push(node);
- *target = const_cast<DomainTreeNode<T>*>(node);
+ *target = node;
ret = EXACTMATCH;
}
break;
@@ -1562,7 +1570,7 @@ DomainTree<T>::find(const isc::dns::LabelSequence& target_labels_orig,
if (relation == isc::dns::NameComparisonResult::SUBDOMAIN) {
if (needsReturnEmptyNode_ || !node->isEmpty()) {
ret = PARTIALMATCH;
- *target = const_cast<DomainTreeNode<T>*>(node);
+ *target = node;
if (callback != NULL &&
node->getFlag(DomainTreeNode<T>::FLAG_CALLBACK)) {
if ((callback)(*node, callback_arg)) {
diff --git a/src/lib/datasrc/memory/memory_client.cc b/src/lib/datasrc/memory/memory_client.cc
index a51a1a0..5f6f510 100644
--- a/src/lib/datasrc/memory/memory_client.cc
+++ b/src/lib/datasrc/memory/memory_client.cc
@@ -125,7 +125,7 @@ public:
//
// In order for wildcard matching to work correctly in the zone finder,
// we must ensure that a node for the wildcarding level exists in the
- // backend RBTree.
+ // backend ZoneTree.
// E.g. if the wildcard name is "*.sub.example." then we must ensure
// that "sub.example." exists and is marked as a wildcard level.
// Note: the "wildcarding level" is for the parent name of the wildcard
diff --git a/src/lib/datasrc/memory/zone_finder.cc b/src/lib/datasrc/memory/zone_finder.cc
index 4dddc2c..31a58d9 100644
--- a/src/lib/datasrc/memory/zone_finder.cc
+++ b/src/lib/datasrc/memory/zone_finder.cc
@@ -137,7 +137,7 @@ struct FindState {
};
// A callback called from possible zone cut nodes and nodes with DNAME.
-// This will be passed from findNode() to \c RBTree::find().
+// This will be passed from findNode() to \c ZoneTree::find().
bool cutCallback(const ZoneNode& node, FindState* state) {
// We need to look for DNAME first, there's allowed case where
// DNAME and NS coexist in the apex. DNAME is the one to notice,
@@ -264,7 +264,7 @@ createFindResult(const RRClass& rrclass,
// it should always succeed.
//
// node_path must store valid search context (in practice, it's expected
-// to be set by findNode()); otherwise the underlying RBTree implementation
+// to be set by findNode()); otherwise the underlying ZoneTree implementation
// throws.
//
// If the zone is not considered NSEC-signed or DNSSEC records were not
@@ -417,7 +417,7 @@ FindNodeResult findNode(const ZoneData& zone_data,
ZoneFinder::FindOptions options,
bool out_of_zone_ok = false)
{
- ZoneNode* node = NULL;
+ const ZoneNode* node = NULL;
FindState state((options & ZoneFinder::FIND_GLUE_OK) != 0);
const ZoneTree& tree(zone_data.getZoneTree());
@@ -490,9 +490,8 @@ FindNodeResult findNode(const ZoneData& zone_data,
// Clear the node_path so that we don't keep incorrect (NSEC)
// context
node_path.clear();
- ZoneTree::Result result = tree.find(LabelSequence(wildcard_ls),
- &node, node_path, cutCallback,
- &state);
+ ZoneTree::Result result = tree.find(wildcard_ls, &node, node_path,
+ cutCallback, &state);
// Otherwise, why would the domain_flag::WILD be there if
// there was no wildcard under it?
assert(result == ZoneTree::EXACTMATCH);
diff --git a/src/lib/datasrc/tests/memory/zone_finder_unittest.cc b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
index 494f19d..a536bf5 100644
--- a/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
@@ -897,7 +897,7 @@ InMemoryZoneFinderTest::emptyNodeCheck(
ZoneFinder::FindResultFlags expected_flags)
{
/*
- * The backend RBTree for this test should look like as follows:
+ * The backend ZoneTree for this test should look like as follows:
* example.org
* |
* baz (empty; easy case)
diff --git a/src/lib/dhcp/Makefile.am b/src/lib/dhcp/Makefile.am
index fbd4eb5..4c22b35 100644
--- a/src/lib/dhcp/Makefile.am
+++ b/src/lib/dhcp/Makefile.am
@@ -13,7 +13,7 @@ AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
CLEANFILES = *.gcno *.gcda
-lib_LTLIBRARIES = libb10-dhcp++.la
+lib_LTLIBRARIES = libb10-dhcp++.la libb10-dhcpsrv.la
libb10_dhcp___la_SOURCES =
libb10_dhcp___la_SOURCES += libdhcp++.cc libdhcp++.h
libb10_dhcp___la_SOURCES += iface_mgr.cc iface_mgr.h
@@ -29,8 +29,18 @@ libb10_dhcp___la_SOURCES += dhcp6.h dhcp4.h
libb10_dhcp___la_SOURCES += pkt6.cc pkt6.h
libb10_dhcp___la_SOURCES += pkt4.cc pkt4.h
+libb10_dhcpsrv_la_SOURCES = cfgmgr.cc cfgmgr.h
+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_SOURCES += addr_utilities.cc addr_utilities.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
+
EXTRA_DIST = README
-#EXTRA_DIST += log_messages.mes
libb10_dhcp___la_CXXFLAGS = $(AM_CXXFLAGS)
libb10_dhcp___la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
diff --git a/src/lib/dhcp/README b/src/lib/dhcp/README
index 6bd6384..c5e70f2 100644
--- a/src/lib/dhcp/README
+++ b/src/lib/dhcp/README
@@ -1,11 +1,9 @@
-This directory holds implementation for libdhcp++.
+This directory holds implementation for DHCP libraries:
+libdhcp++ - this is a generic purpose DHCP library. Please be careful
+what is put here. It is going to be shared by various servers (the "regular"
+one and the embedded as well), clients, relays and performance tools.
-Basic Ideas
-===========
+libdhcpsrv - Server specific code goes in here. It will be used by
+dhcp4 and dhcp6 server.
-
-Notes
-=====
-This work just begun. Don't expect to see much useful code here.
-We are working on it.
diff --git a/src/lib/dhcp/addr_utilities.cc b/src/lib/dhcp/addr_utilities.cc
new file mode 100644
index 0000000..ad72833
--- /dev/null
+++ b/src/lib/dhcp/addr_utilities.cc
@@ -0,0 +1,96 @@
+// 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 <dhcp/addr_utilities.h>
+
+using namespace isc::asiolink;
+
+namespace isc {
+namespace dhcp {
+
+isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefix,
+ uint8_t len) {
+
+ const static uint8_t bitMask[]= { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
+ uint8_t packed[V6ADDRESS_LEN];
+
+ // First we copy the whole address as 16 bytes.
+ 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 = bitMask[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));
+}
+
+isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix,
+ uint8_t len) {
+
+ const static uint8_t bitMask[]= { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
+ uint8_t packed[V6ADDRESS_LEN];
+
+ // First we copy the whole address as 16 bytes.
+ 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 = bitMask[len % 8];
+
+ // Let's set those irrelevant bits with 1. It would be perhaps
+ // easier to not use negation here and invert bitMask 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));
+}
+
+};
+};
diff --git a/src/lib/dhcp/addr_utilities.h b/src/lib/dhcp/addr_utilities.h
new file mode 100644
index 0000000..15532d0
--- /dev/null
+++ b/src/lib/dhcp/addr_utilities.h
@@ -0,0 +1,53 @@
+// 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>
+
+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);
+
+};
+};
diff --git a/src/lib/dhcp/cfgmgr.cc b/src/lib/dhcp/cfgmgr.cc
new file mode 100644
index 0000000..15e3ad9
--- /dev/null
+++ b/src/lib/dhcp/cfgmgr.cc
@@ -0,0 +1,78 @@
+// 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) {
+ 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);
+}
+
+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
new file mode 100644
index 0000000..5b73f2b
--- /dev/null
+++ b/src/lib/dhcp/cfgmgr.h
@@ -0,0 +1,126 @@
+// 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 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 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 a subnet6
+ 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.
+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 Subnet6
+ ///
+ /// 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_;
+};
+
+} // namespace isc::dhcp
+} // namespace isc
+
+#endif
diff --git a/src/lib/dhcp/pool.cc b/src/lib/dhcp/pool.cc
new file mode 100644
index 0000000..da8a2e3
--- /dev/null
+++ b/src/lib/dhcp/pool.cc
@@ -0,0 +1,87 @@
+// 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_));
+}
+
+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
new file mode 100644
index 0000000..8f6fd86
--- /dev/null
+++ b/src/lib/dhcp/pool.h
@@ -0,0 +1,155 @@
+// 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 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 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 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
new file mode 100644
index 0000000..a999295
--- /dev/null
+++ b/src/lib/dhcp/subnet.cc
@@ -0,0 +1,91 @@
+// 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 <dhcp/pool.h>
+
+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) {
+ 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));
+}
+
+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);
+}
+
+} // end of isc::dhcp namespace
+} // end of isc namespace
diff --git a/src/lib/dhcp/subnet.h b/src/lib/dhcp/subnet.h
new file mode 100644
index 0000000..aa59010
--- /dev/null
+++ b/src/lib/dhcp/subnet.h
@@ -0,0 +1,161 @@
+// 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 <asiolink/io_address.h>
+#include <dhcp/pool.h>
+#include <dhcp/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).
+///
+/// @todo: Implement support for options here
+class Subnet {
+public:
+ /// @brief checks if specified address is in range
+ bool inRange(const isc::asiolink::IOAddress& addr) const;
+
+ /// @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_);
+ }
+
+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 returns the next unique Subnet-ID
+ ///
+ /// @return the next unique Subnet-ID
+ static uint32_t getNextID() {
+ static uint32_t id = 0;
+ return (id++);
+ }
+
+ /// @brief subnet-id
+ ///
+ /// Subnet-id is a unique value that can be used to find or identify
+ /// a Subnet4 or Subnet6.
+ uint32_t 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 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_;
+ }
+
+protected:
+ /// @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 9e00ab0..9fd3492 100644
--- a/src/lib/dhcp/tests/Makefile.am
+++ b/src/lib/dhcp/tests/Makefile.am
@@ -24,7 +24,7 @@ TESTS_ENVIRONMENT = \
TESTS =
if HAVE_GTEST
-TESTS += libdhcp++_unittests
+TESTS += libdhcp++_unittests libdhcpsrv_unittests
libdhcp___unittests_SOURCES = run_unittests.cc
libdhcp___unittests_SOURCES += libdhcp++_unittest.cc
libdhcp___unittests_SOURCES += iface_mgr_unittest.cc
@@ -38,20 +38,37 @@ libdhcp___unittests_SOURCES += pkt4_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 += cfgmgr_unittest.cc triplet_unittest.cc
+libdhcpsrv_unittests_SOURCES += pool_unittest.cc subnet_unittest.cc
+libdhcpsrv_unittests_SOURCES += addr_utilities_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/log/libb10-log.la
+
+
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
libdhcp___unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
libdhcp___unittests_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
libdhcp___unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
libdhcp___unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+libdhcp___unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
libdhcp___unittests_LDADD += $(GTEST_LDADD)
endif
diff --git a/src/lib/dhcp/tests/addr_utilities_unittest.cc b/src/lib/dhcp/tests/addr_utilities_unittest.cc
new file mode 100644
index 0000000..8382827
--- /dev/null
+++ b/src/lib/dhcp/tests/addr_utilities_unittest.cc
@@ -0,0 +1,93 @@
+
+// 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;
+
+TEST(Pool6Test, lastAddrInPrefix) {
+ 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());
+}
+
+TEST(Pool6Test, firstAddrInPrefix) {
+ 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/cfgmgr_unittest.cc b/src/lib/dhcp/tests/cfgmgr_unittest.cc
new file mode 100644
index 0000000..a11acbf
--- /dev/null
+++ b/src/lib/dhcp/tests/cfgmgr_unittest.cc
@@ -0,0 +1,63 @@
+// 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 {
+
+// This test verifies if the configuration manager is able to hold and return
+// valid leases
+TEST(CfgMgrTest, subnet6) {
+ CfgMgr& cfg_mgr = CfgMgr::instance();
+
+ ASSERT_TRUE(&cfg_mgr != 0);
+
+ 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("2001:db8::1")));
+
+ 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")));
+
+}
+
+} // end of anonymous namespace
diff --git a/src/lib/dhcp/tests/pool_unittest.cc b/src/lib/dhcp/tests/pool_unittest.cc
new file mode 100644
index 0000000..61d4c4a
--- /dev/null
+++ b/src/lib/dhcp/tests/pool_unittest.cc
@@ -0,0 +1,109 @@
+// 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(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 db27f76..0126645 100644
--- a/src/lib/dhcp/tests/run_unittests.cc
+++ b/src/lib/dhcp/tests/run_unittests.cc
@@ -13,7 +13,6 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <gtest/gtest.h>
-
#include <log/logger_support.h>
int
diff --git a/src/lib/dhcp/tests/subnet_unittest.cc b/src/lib/dhcp/tests/subnet_unittest.cc
new file mode 100644
index 0000000..6afebb8
--- /dev/null
+++ b/src/lib/dhcp/tests/subnet_unittest.cc
@@ -0,0 +1,112 @@
+// 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 <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(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);
+
+}
+
+
+};
diff --git a/src/lib/dhcp/tests/triplet_unittest.cc b/src/lib/dhcp/tests/triplet_unittest.cc
new file mode 100644
index 0000000..727eb8a
--- /dev/null
+++ b/src/lib/dhcp/tests/triplet_unittest.cc
@@ -0,0 +1,104 @@
+// 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
new file mode 100644
index 0000000..d45f003
--- /dev/null
+++ b/src/lib/dhcp/triplet.h
@@ -0,0 +1,110 @@
+// 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 <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
More information about the bind10-changes
mailing list