BIND 10 trac2342, updated. 93ffcbb3ecdb4f882bb833addb68908446f7ae77 [2342] Now have addLease and getLease6 methods apparently working
BIND 10 source code commits
bind10-changes at lists.isc.org
Sat Oct 20 21:54:01 UTC 2012
The branch, trac2342 has been updated
via 93ffcbb3ecdb4f882bb833addb68908446f7ae77 (commit)
via c7cb0c33363a126c12a6df098295b06b8921e7f6 (commit)
via 68953b80a3f7155b10728dabc583f9e5bbe080ed (commit)
via 6b45e5c026a844d688367308bd0b4e70b568b2e5 (commit)
via cc65a33e2a84e88a4c1703d360d18187b09a8850 (commit)
from e78384f8c6aca75a41ea000d22ecc7648513ad02 (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 93ffcbb3ecdb4f882bb833addb68908446f7ae77
Author: Stephen Morris <stephen at isc.org>
Date: Sat Oct 20 22:52:25 2012 +0100
[2342] Now have addLease and getLease6 methods apparently working
commit c7cb0c33363a126c12a6df098295b06b8921e7f6
Author: Stephen Morris <stephen at isc.org>
Date: Thu Oct 18 11:33:51 2012 +0100
[2342] getVersion() is now working
This change adds the code for prepared statement creation and the
template for retrieving information from the database.
commit 68953b80a3f7155b10728dabc583f9e5bbe080ed
Author: Stephen Morris <stephen at isc.org>
Date: Wed Oct 17 18:37:22 2012 +0100
[2342] Got the basic "open database" test working.
commit 6b45e5c026a844d688367308bd0b4e70b568b2e5
Author: Stephen Morris <stephen at isc.org>
Date: Tue Oct 16 16:39:32 2012 +0100
[2342] Added MySQL lease manager and null implementation
Also includes first unit test, which fails.
commit cc65a33e2a84e88a4c1703d360d18187b09a8850
Author: Stephen Morris <stephen at isc.org>
Date: Mon Oct 15 12:29:17 2012 +0100
[2342] Separate out lease manager creation into separate factory functions
-----------------------------------------------------------------------
Summary of changes:
src/lib/dhcp/Makefile.am | 22 +-
src/lib/dhcp/lease_mgr.cc | 44 +-
src/lib/dhcp/lease_mgr.h | 106 +++-
src/lib/dhcp/lease_mgr_factory.cc | 92 ++++
src/lib/dhcp/lease_mgr_factory.h | 77 +++
src/lib/dhcp/mysql_lease_mgr.cc | 597 ++++++++++++++++++++++
src/lib/dhcp/mysql_lease_mgr.h | 381 ++++++++++++++
src/lib/dhcp/tests/Makefile.am | 18 +-
src/lib/dhcp/tests/lease_mgr_factory_unittest.cc | 47 ++
src/lib/dhcp/tests/lease_mgr_unittest.cc | 76 +--
src/lib/dhcp/tests/mysql_lease_mgr_unittest.cc | 271 ++++++++++
11 files changed, 1626 insertions(+), 105 deletions(-)
create mode 100644 src/lib/dhcp/lease_mgr_factory.cc
create mode 100644 src/lib/dhcp/lease_mgr_factory.h
create mode 100644 src/lib/dhcp/mysql_lease_mgr.cc
create mode 100644 src/lib/dhcp/mysql_lease_mgr.h
create mode 100644 src/lib/dhcp/tests/lease_mgr_factory_unittest.cc
create mode 100644 src/lib/dhcp/tests/mysql_lease_mgr_unittest.cc
-----------------------------------------------------------------------
diff --git a/src/lib/dhcp/Makefile.am b/src/lib/dhcp/Makefile.am
index 6585a38..e208884 100644
--- a/src/lib/dhcp/Makefile.am
+++ b/src/lib/dhcp/Makefile.am
@@ -15,21 +15,23 @@ CLEANFILES = *.gcno *.gcda
lib_LTLIBRARIES = libb10-dhcp++.la libb10-dhcpsrv.la
libb10_dhcp___la_SOURCES =
-libb10_dhcp___la_SOURCES += libdhcp++.cc libdhcp++.h
-libb10_dhcp___la_SOURCES += lease_mgr.cc lease_mgr.h
+libb10_dhcp___la_SOURCES += dhcp6.h dhcp4.h
+libb10_dhcp___la_SOURCES += duid.cc duid.h
+libb10_dhcp___la_SOURCES += iface_mgr_bsd.cc
libb10_dhcp___la_SOURCES += iface_mgr.cc iface_mgr.h
libb10_dhcp___la_SOURCES += iface_mgr_linux.cc
-libb10_dhcp___la_SOURCES += iface_mgr_bsd.cc
libb10_dhcp___la_SOURCES += iface_mgr_sun.cc
-libb10_dhcp___la_SOURCES += option.cc option.h
-libb10_dhcp___la_SOURCES += option6_ia.cc option6_ia.h
-libb10_dhcp___la_SOURCES += option6_iaaddr.cc option6_iaaddr.h
-libb10_dhcp___la_SOURCES += option6_addrlst.cc option6_addrlst.h
+libb10_dhcp___la_SOURCES += lease_mgr.cc lease_mgr.h
+libb10_dhcp___la_SOURCES += lease_mgr_factory.cc lease_mgr_factory.h
+libb10_dhcp___la_SOURCES += libdhcp++.cc libdhcp++.h
+libb10_dhcp___la_SOURCES += mysql_lease_mgr.cc mysql_lease_mgr.h
libb10_dhcp___la_SOURCES += option4_addrlst.cc option4_addrlst.h
-libb10_dhcp___la_SOURCES += dhcp6.h dhcp4.h
-libb10_dhcp___la_SOURCES += pkt6.cc pkt6.h
+libb10_dhcp___la_SOURCES += option6_addrlst.cc option6_addrlst.h
+libb10_dhcp___la_SOURCES += option6_iaaddr.cc option6_iaaddr.h
+libb10_dhcp___la_SOURCES += option6_ia.cc option6_ia.h
+libb10_dhcp___la_SOURCES += option.cc option.h
libb10_dhcp___la_SOURCES += pkt4.cc pkt4.h
-libb10_dhcp___la_SOURCES += duid.cc duid.h
+libb10_dhcp___la_SOURCES += pkt6.cc pkt6.h
libb10_dhcpsrv_la_SOURCES = cfgmgr.cc cfgmgr.h
libb10_dhcpsrv_la_SOURCES += pool.cc pool.h
diff --git a/src/lib/dhcp/lease_mgr.cc b/src/lib/dhcp/lease_mgr.cc
index d09bd58..1fd64d8 100644
--- a/src/lib/dhcp/lease_mgr.cc
+++ b/src/lib/dhcp/lease_mgr.cc
@@ -12,52 +12,30 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <sstream>
+#include <algorithm>
#include <iostream>
+#include <iterator>
#include <map>
-#include <iostream>
-#include <string>
#include <sstream>
-#include <algorithm>
-#include <iterator>
-#include <exceptions/exceptions.h>
+#include <string>
+#include <utility>
+
#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>
-#include "lease_mgr.h"
+
+#include <exceptions/exceptions.h>
+#include <dhcp/lease_mgr.h>
using namespace std;
using namespace isc::dhcp;
-LeaseMgr::LeaseMgr(const std::string& dbconfig) {
-
- if (dbconfig.length() == 0) {
- return;
- }
-
- 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, -1);
- parameters_.insert(pair<string,string>(name, value));
- } else {
- isc_throw(InvalidParameter, "Cannot parse " << token
- << ", expected format is name=value");
- }
-
- }
+LeaseMgr::LeaseMgr(const LeaseMgr::ParameterMap& parameters)
+ : parameters_(parameters) {
}
std::string LeaseMgr::getParameter(const std::string& name) const {
- std::map<std::string, std::string>::const_iterator param
- = parameters_.find(name);
+ ParameterMap::const_iterator param = parameters_.find(name);
if (param == parameters_.end()) {
isc_throw(BadValue, "Parameter not found");
}
diff --git a/src/lib/dhcp/lease_mgr.h b/src/lib/dhcp/lease_mgr.h
index 4b7a1af..7315551 100644
--- a/src/lib/dhcp/lease_mgr.h
+++ b/src/lib/dhcp/lease_mgr.h
@@ -12,14 +12,20 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <string>
+#ifndef __LEASE_MGR_H
+#define __LEASE_MGR_H
+
#include <fstream>
-#include <vector>
#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
#include <asiolink/io_address.h>
#include <boost/shared_ptr.hpp>
-#include <dhcp/option.h>
#include <dhcp/duid.h>
+#include <dhcp/option.h>
+#include <exceptions/exceptions.h>
/// @file dhcp/lease_mgr.h
/// @brief An abstract API for lease database
@@ -55,6 +61,20 @@
namespace isc {
namespace dhcp {
+/// @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 specifies unique subnet identifier
/// @todo: Move this to subnet.h once ticket #2237 is merged
typedef uint32_t SubnetID;
@@ -140,6 +160,11 @@ struct Lease4 {
std::string comments_;
/// @todo: Add DHCPv4 failover related fields here
+
+ /// @brief Constructor
+ ///
+ /// Initialize fields that don't have a default constructor.
+ Lease4() : addr_(0) {}
};
/// @brief Pointer to a Lease4 structure.
@@ -251,6 +276,11 @@ struct Lease6 {
std::string comments_;
/// @todo: Add DHCPv6 failover related fields here
+
+ /// @brief Constructor
+ ///
+ /// Initialize fields that don't have a default constructor.
+ Lease6() : addr_(0) {}
};
/// @brief Pointer to a Lease6 structure.
@@ -274,14 +304,14 @@ public:
/// Client Hardware address
typedef std::vector<uint8_t> HWAddr;
+ /// Database configuration parameter map
+ typedef std::map<std::string, std::string> ParameterMap;
+
/// @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 dbconfig database configuration
- LeaseMgr(const std::string& dbconfig);
+ /// @param parameters A data structure relating keywords and values
+ /// concerned with the database.
+ LeaseMgr(const ParameterMap& parameters);
/// @brief Destructor (closes file)
virtual ~LeaseMgr();
@@ -289,12 +319,22 @@ public:
/// @brief Adds an IPv4 lease.
///
/// @param lease lease to be added
- virtual bool addLease(Lease4Ptr lease) = 0;
+ ///
+ /// @result true if the lease was added, false if not (because a lease
+ /// with the same address was already there).
+ ///
+ /// @exception DbOperationError Database function failed
+ virtual bool addLease(const Lease4Ptr& lease) = 0;
/// @brief Adds an IPv6 lease.
///
/// @param lease lease to be added
- virtual bool addLease(Lease6Ptr lease) = 0;
+ ///
+ /// @result true if the lease was added, false if not (because a lease
+ /// with the same address was already there).
+ ///
+ /// @exception DbOperationError Database function failed
+ virtual bool addLease(const Lease6Ptr& lease) = 0;
/// @brief Returns existing IPv4 lease for specified IPv4 address and subnet_id
///
@@ -306,7 +346,7 @@ public:
/// @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(isc::asiolink::IOAddress addr,
+ virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr,
SubnetID subnet_id) const = 0;
/// @brief Returns an IPv4 lease for specified IPv4 address
@@ -322,7 +362,7 @@ public:
/// @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(isc::asiolink::IOAddress addr) const = 0;
+ virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr) const = 0;
/// @brief Returns existing IPv4 leases for specified hardware address.
///
@@ -382,7 +422,7 @@ public:
/// @param addr address of the searched lease
///
/// @return smart pointer to the lease (or NULL if a lease is not found)
- virtual Lease6Ptr getLease6(isc::asiolink::IOAddress addr) const = 0;
+ virtual Lease6Ptr getLease6(const isc::asiolink::IOAddress& addr) const = 0;
/// @brief Returns existing IPv6 leases for a given DUID+IA combination
///
@@ -413,28 +453,28 @@ public:
/// @param lease4 The lease to be updated.
///
/// If no such lease is present, an exception will be thrown.
- virtual void updateLease4(Lease4Ptr lease4) = 0;
+ virtual void updateLease4(const Lease4Ptr& lease4) = 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 updateLease6(Lease6Ptr lease6) = 0;
+ 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(uint32_t addr) = 0;
+ virtual bool deleteLease4(const isc::asiolink::IOAddress& addr) = 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 deleteLease6(isc::asiolink::IOAddress addr) = 0;
+ virtual bool deleteLease6(const isc::asiolink::IOAddress& addr) = 0;
/// @brief Returns backend name.
///
@@ -448,6 +488,9 @@ public:
/// @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
@@ -457,12 +500,29 @@ public:
/// 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::string getVersion() const = 0;
+ 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.
+ ///
+ /// @exception DbOperationError if the commit failed.
+ 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.
+ ///
+ /// @exception DbOperationError if the rollback failed.
+ virtual void rollback() = 0;
/// @todo: Add host management here
/// As host reservation is outside of scope for 2012, support for hosts
/// is currently postponed.
+
protected:
/// @brief returns value of the parameter
std::string getParameter(const std::string& name) const;
@@ -472,9 +532,13 @@ protected:
/// 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.
- std::map<std::string, std::string> parameters_;
+ ParameterMap parameters_;
};
-}; // end of isc::dhcp namespace
+/// @brief Pointer to a Lease Manager
+typedef boost::shared_ptr<LeaseMgr> LeaseMgrPtr;
+}; // 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
new file mode 100644
index 0000000..0a8c3aa
--- /dev/null
+++ b/src/lib/dhcp/lease_mgr_factory.cc
@@ -0,0 +1,92 @@
+// 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"
+
+// TEMP
+#define HAVE_MYSQL 1
+
+
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+#include <map>
+#include <sstream>
+#include <string>
+#include <utility>
+
+#include <boost/foreach.hpp>
+#include <boost/algorithm/string.hpp>
+#include <exceptions/exceptions.h>
+#include <dhcp/lease_mgr_factory.h>
+#include <dhcp/mysql_lease_mgr.h>
+
+using namespace std;
+
+namespace isc {
+namespace dhcp {
+
+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);
+}
+
+LeaseMgrPtr
+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")) {
+ return LeaseMgrPtr(new MySqlLeaseMgr(parameters));
+ }
+#endif
+
+ // Get here on no match
+ isc_throw(InvalidParameter, "Database configuration parameter 'type' does "
+ "not specify a supported database backend");
+}
+
+}; // namespace dhcp
+}; // namespace isc
diff --git a/src/lib/dhcp/lease_mgr_factory.h b/src/lib/dhcp/lease_mgr_factory.h
new file mode 100644
index 0000000..11057d0
--- /dev/null
+++ b/src/lib/dhcp/lease_mgr_factory.h
@@ -0,0 +1,77 @@
+// 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 {
+ InvalidType(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.
+class LeaseMgrFactory {
+public:
+ /// @brief Create an instance of a lease manager.
+ ///
+ /// Each database backend has its own lease manager type. This static
+ /// method returns a lease manager of the appropriate type, based on the
+ /// the data in the input argument.
+ ///
+ /// 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.
+ ///
+ /// @return Implementation of lease manager for the specified database.
+ static LeaseMgrPtr create(const std::string& dbconfig);
+
+ /// @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);
+};
+
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
+
+#endif // __LEASE_MGR_FACTORY_H
diff --git a/src/lib/dhcp/mysql_lease_mgr.cc b/src/lib/dhcp/mysql_lease_mgr.cc
new file mode 100644
index 0000000..31fcfa8
--- /dev/null
+++ b/src/lib/dhcp/mysql_lease_mgr.cc
@@ -0,0 +1,597 @@
+// 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 <iomanip>
+#include <string>
+#include <config.h>
+#include <time.h>
+#include <dhcp/mysql_lease_mgr.h>
+#include <asiolink/io_address.h>
+
+using namespace std;
+
+namespace isc {
+namespace dhcp {
+
+// 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 means that the external interface - cltt -
+// must be local time.
+
+void
+MySqlLeaseMgr::convertFromLeaseTime(time_t cltt, uint32_t valid_lft,
+ MYSQL_TIME& expire, uint32_t& lease_time) {
+
+ // Calculate expiry time and convert to various date/time fields.
+ time_t expire_time = cltt + valid_lft;
+ 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
+
+ // Set the lease time.
+ lease_time = valid_lft;
+}
+
+void
+MySqlLeaseMgr::convertToLeaseTime(const MYSQL_TIME& expire, uint32_t lease_time,
+ time_t& cltt, uint32_t& valid_lft) {
+ valid_lft = lease_time;
+
+ // Copy across fields from MYSQL_TIME structure.
+ struct tm 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;
+
+ // Convert to local time
+ cltt = mktime(&expire_tm) - valid_lft;
+}
+
+void
+MySqlLeaseMgr::openDatabase() {
+
+ // Set up the values of the parameters
+ const char* host = NULL;
+ string shost;
+ try {
+ shost = getParameter("host");
+ host = shost.c_str();
+ } catch (...) {
+ // No host. Fine, we'll use NULL
+ ;
+ }
+
+ 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. Fine, we'll use NULL
+ ;
+ }
+
+ // Open the database. Use defaults for non-specified options.
+ MYSQL* status = mysql_real_connect(mysql_, host, user, password, name,
+ 0, NULL, 0);
+ 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 or "
+ "statement index not null");
+ }
+
+ // All OK, so prepare the statement
+ raw_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);
+
+ raw_statements_.clear();
+ raw_statements_.resize(NUM_STATEMENTS, std::string(""));
+
+ // Now allocate the statements
+ prepareStatement(GET_LEASE6,
+ "SELECT hwaddr, client_id, "
+ "lease_time, expire, subnet_id, pref_lifetime, "
+ "lease_type, iaid, prefix_len "
+ "FROM lease6 WHERE address = ?");
+ prepareStatement(GET_VERSION,
+ "SELECT version, minor FROM schema_version");
+ prepareStatement(INSERT_LEASE6,
+ "INSERT INTO lease6(address, hwaddr, client_id, "
+ "lease_time, expire, subnet_id, pref_lifetime, "
+ "lease_type, iaid, prefix_len) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
+}
+
+
+MySqlLeaseMgr::MySqlLeaseMgr(const LeaseMgr::ParameterMap& parameters)
+ : LeaseMgr(parameters), mysql_(NULL) {
+
+ // Allocate context for MySQL - it is destroyed in the destructor.
+ mysql_ = mysql_init(NULL);
+
+ // 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();
+}
+
+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;
+}
+
+bool
+MySqlLeaseMgr::addLease(const Lease4Ptr& /* lease */) {
+
+ return (false);
+}
+
+bool
+MySqlLeaseMgr::addLease(const Lease6Ptr& lease) {
+ my_bool MLM_FALSE = 0;
+ MYSQL_BIND bind[10];
+ memset(bind, 0, sizeof(bind));
+
+ // address: varchar(40)
+ std::string addr6 = lease->addr_.toText();
+ unsigned long addr6_length = addr6.size();
+
+ 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;
+ bind[0].is_null = &MLM_FALSE;
+
+ // hwaddr: binary(20)
+ unsigned long hwaddr_length = lease->hwaddr_.size();
+
+ bind[1].buffer_type = MYSQL_TYPE_BLOB;
+
+ bind[1].buffer = reinterpret_cast<char*>(&(lease->hwaddr_[0]));
+ bind[1].buffer_length = hwaddr_length;
+ bind[1].length = &hwaddr_length;
+ bind[1].is_null = &MLM_FALSE;
+
+ // client_id: varchar(128)
+ vector<uint8_t> clientid = lease->duid_->getDuid();
+ unsigned long clientid_length = clientid.size();
+
+ bind[2].buffer_type = MYSQL_TYPE_BLOB;
+ bind[2].buffer = reinterpret_cast<char*>(&(clientid[0]));
+ bind[2].buffer_length = clientid_length;
+ bind[2].length = &clientid_length;
+ bind[2].is_null = &MLM_FALSE;
+
+ // The lease structure holds the client last transmission time (cltt_)
+ // and the valid lifetime (valid_lft_). For convenience, the data stored
+ // in the database is expiry time (expire) and lease time (lease+time).
+ // The relationship is given by:
+ //
+ // lease_time - valid_lft_
+ // expire = cltt_ + valid_lft_
+ MYSQL_TIME mysql_expire;
+ uint32_t lease_time;
+ convertFromLeaseTime(lease->cltt_, lease->valid_lft_,
+ mysql_expire, lease_time);
+
+ // lease_time: unsigned int
+ bind[3].buffer_type = MYSQL_TYPE_LONG;
+ bind[3].buffer = reinterpret_cast<char*>(&lease_time);
+ bind[3].is_unsigned = 1;
+ bind[3].is_null = &MLM_FALSE;
+
+ // expire: timestamp
+ bind[4].buffer_type = MYSQL_TYPE_TIMESTAMP;
+ bind[4].buffer = reinterpret_cast<char*>(&mysql_expire);
+ bind[4].buffer_length = sizeof(mysql_expire);
+ bind[4].is_null = &MLM_FALSE;
+
+ // subnet_id: unsigned int
+ bind[5].buffer_type = MYSQL_TYPE_LONG;
+ bind[5].buffer = reinterpret_cast<char*>(&(lease->subnet_id_));
+ bind[5].is_unsigned = static_cast<my_bool>(1);
+ bind[5].is_null = &MLM_FALSE;
+
+ // pref_lifetime: unsigned int
+ bind[6].buffer_type = MYSQL_TYPE_LONG;
+ bind[6].buffer = reinterpret_cast<char*>(&(lease->preferred_lft_));
+ bind[6].is_unsigned = static_cast<my_bool>(1);
+ bind[6].is_null = &MLM_FALSE;
+
+ // lease_type: tinyint
+ uint8_t lease_type = lease->type_; // Needed for int -> uint8_t conversion
+ bind[7].buffer_type = MYSQL_TYPE_TINY;
+ bind[7].buffer = reinterpret_cast<char*>(&lease_type);
+ bind[7].is_unsigned = static_cast<my_bool>(1);
+ bind[7].is_null = &MLM_FALSE;
+
+ // iaid: unsigned int
+ bind[8].buffer_type = MYSQL_TYPE_LONG;
+ bind[8].buffer = reinterpret_cast<char*>(&(lease->iaid_));
+ bind[8].is_unsigned = static_cast<my_bool>(1);
+ bind[8].is_null = &MLM_FALSE;
+
+ // prefix_len: unsigned tinyint
+ bind[9].buffer_type = MYSQL_TYPE_TINY;
+ bind[9].buffer = reinterpret_cast<char*>(&(lease->prefixlen_));
+ bind[9].is_unsigned = static_cast<my_bool>(1);
+ bind[9].is_null = &MLM_FALSE;
+
+ // Bind the parameters to the statement
+ my_bool status = mysql_stmt_bind_param(statements_[INSERT_LEASE6], bind);
+ checkError(status, INSERT_LEASE6, "unable to bind parameters");
+
+ // Execute the statement
+ status = mysql_stmt_execute(statements_[INSERT_LEASE6]);
+ checkError(status, INSERT_LEASE6, "unable to execute");
+
+ // ... and find out whether a row as inserted.
+ return (mysql_stmt_affected_rows(statements_[INSERT_LEASE6]) == 1);
+}
+
+Lease4Ptr
+MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& /* addr */,
+ SubnetID /* subnet_id */) const {
+ return (Lease4Ptr());
+}
+
+Lease4Ptr
+MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& /* addr */) const {
+ return (Lease4Ptr());
+}
+
+Lease4Collection
+MySqlLeaseMgr::getLease4(const HWAddr& /* hwaddr */) const {
+ return (Lease4Collection());
+}
+
+Lease4Ptr
+MySqlLeaseMgr::getLease4(const HWAddr& /* hwaddr */,
+ SubnetID /* subnet_id */) const {
+ return (Lease4Ptr());
+}
+
+Lease4Collection
+MySqlLeaseMgr::getLease4(const ClientId& /* clientid */) const {
+ return (Lease4Collection());
+}
+
+Lease4Ptr
+MySqlLeaseMgr::getLease4(const ClientId& /* clientid */,
+ SubnetID /* subnet_id */) const {
+ return (Lease4Ptr());
+}
+
+Lease6Ptr
+MySqlLeaseMgr::getLease6(const isc::asiolink::IOAddress& addr) const {
+ my_bool MLM_FALSE = 0; // MySqlLeaseMgr false
+ my_bool MLM_TRUE = 1; // MySqlLeaseMgr true
+
+ // 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();
+
+ 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;
+ inbind[0].is_null = &MLM_FALSE;
+
+ // Bind the parameters to the statement
+ my_bool status = mysql_stmt_bind_param(statements_[GET_LEASE6], inbind);
+ checkError(status, GET_LEASE6, "unable to bind WHERE clause parameter");
+
+ // Output values
+ MYSQL_BIND outbind[9];
+ memset(outbind, 0, sizeof(outbind));
+
+ // address: Not obtained - because of the WHERE clause, it will always be
+ // the same as the input parameter.
+
+ // hwaddr: varbinary(20)
+ uint8_t hwaddr[20];
+ unsigned long hwaddr_length;
+
+ outbind[0].buffer_type = MYSQL_TYPE_BLOB;
+ outbind[0].buffer = reinterpret_cast<char*>(hwaddr);
+ outbind[0].buffer_length = sizeof(hwaddr);
+ outbind[0].length = &hwaddr_length;
+
+ // client_id: varbinary(128)
+ uint8_t clientid[128];
+ unsigned long clientid_length;
+
+ outbind[1].buffer_type = MYSQL_TYPE_BLOB;
+ outbind[1].buffer = reinterpret_cast<char*>(clientid);
+ outbind[1].buffer_length = sizeof(clientid);
+ outbind[1].length = &clientid_length;
+
+ // lease_time: unsigned int
+ unsigned lease_time;
+ outbind[2].buffer_type = MYSQL_TYPE_LONG;
+ outbind[2].buffer = reinterpret_cast<char*>(&lease_time);
+ outbind[2].is_unsigned = MLM_TRUE;
+
+ // expire: timestamp
+ MYSQL_TIME mysql_expire;
+ outbind[3].buffer_type = MYSQL_TYPE_TIMESTAMP;
+ outbind[3].buffer = reinterpret_cast<char*>(&mysql_expire);
+ outbind[3].buffer_length = sizeof(mysql_expire);
+
+ // subnet_id: unsigned int
+ unsigned subnet_id;
+ outbind[4].buffer_type = MYSQL_TYPE_LONG;
+ outbind[4].buffer = reinterpret_cast<char*>(&subnet_id);
+ outbind[4].is_unsigned = MLM_TRUE;
+
+ // pref_lifetime: unsigned int
+ unsigned pref_lifetime;
+ outbind[5].buffer_type = MYSQL_TYPE_LONG;
+ outbind[5].buffer = reinterpret_cast<char*>(&pref_lifetime);
+ outbind[5].is_unsigned = MLM_TRUE;
+
+ // lease_type: tinyint
+ uint8_t lease_type;
+ outbind[6].buffer_type = MYSQL_TYPE_TINY;
+ outbind[6].buffer = reinterpret_cast<char*>(&lease_type);
+ outbind[6].is_unsigned = MLM_TRUE;
+
+ // iaid: unsigned int
+ unsigned iaid;
+ outbind[7].buffer_type = MYSQL_TYPE_LONG;
+ outbind[7].buffer = reinterpret_cast<char*>(&iaid);
+ outbind[7].is_unsigned = MLM_TRUE;
+
+ // prefix_len: unsigned tinyint
+ uint8_t prefixlen;
+ outbind[8].buffer_type = MYSQL_TYPE_TINY;
+ outbind[8].buffer = reinterpret_cast<char*>(&prefixlen);
+ outbind[8].is_unsigned = MLM_TRUE;
+
+ // Bind the parameters to the statement
+ status = mysql_stmt_bind_result(statements_[GET_LEASE6], outbind);
+ checkError(status, GET_LEASE6, "unable to bind SELECT caluse parameters");
+
+ // Execute the statement
+ status = mysql_stmt_execute(statements_[GET_LEASE6]);
+ checkError(status, GET_LEASE6, "unable to execute");
+
+ // Fetch the data.
+ Lease6Ptr result(new Lease6());
+ status = mysql_stmt_fetch(statements_[GET_LEASE6]);
+ if (status == 0) {
+ // Success - put the data in the lease object
+ result->addr_ = addr;
+ result->hwaddr_ = vector<uint8_t>(&hwaddr[0], &hwaddr[hwaddr_length]);
+ result->duid_.reset(new DUID(clientid, clientid_length));
+ convertToLeaseTime(mysql_expire, lease_time,
+ result->cltt_, result->valid_lft_);
+ result->subnet_id_ = subnet_id;
+ result->preferred_lft_ = pref_lifetime;
+ 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 for <" <<
+ raw_statements_[GET_LEASE6] << ">");
+ }
+ result->iaid_ = iaid;
+ result->prefixlen_ = prefixlen;
+
+ // As the address is the primary key in the table, we can't return
+ // two rows, so we don't bother checking.
+
+ } else if (status == 1) {
+ checkError(status, GET_LEASE6, "unable to fetch results");
+
+ } else {
+ // We are ignoring truncation for now, so the only other result is
+ // no data was found. In that case, we returrn a null Lease6 structure.
+ // This has already been set, so ther action is a no-op.
+ }
+
+ return (result);
+}
+
+Lease6Collection
+MySqlLeaseMgr::getLease6(const DUID& /* duid */, uint32_t /* iaid */) const {
+ return (Lease6Collection());
+}
+
+Lease6Ptr
+MySqlLeaseMgr::getLease6(const DUID& /* duid */, uint32_t /* iaid */,
+ SubnetID /* subnet_id */) const {
+ return (Lease6Ptr());
+}
+
+void
+MySqlLeaseMgr::updateLease4(const Lease4Ptr& /* lease4 */) {
+}
+
+void
+MySqlLeaseMgr::updateLease6(const Lease6Ptr& /* lease6 */) {
+}
+
+bool
+MySqlLeaseMgr::deleteLease4(const isc::asiolink::IOAddress& /* addr */) {
+ return (false);
+}
+
+bool
+MySqlLeaseMgr::deleteLease6(const isc::asiolink::IOAddress& /* addr */) {
+ return (false);
+}
+
+std::string
+MySqlLeaseMgr::getName() const {
+ return (std::string(""));
+}
+
+std::string
+MySqlLeaseMgr::getDescription() const {
+ return (std::string(""));
+}
+
+std::pair<uint32_t, uint32_t>
+MySqlLeaseMgr::getVersion() const {
+ uint32_t major; // Major version number
+ uint32_t minor; // Minor version number
+
+ // Execute the prepared statement
+ int status = mysql_stmt_execute(statements_[GET_VERSION]);
+ if (status != 0) {
+ isc_throw(DbOperationError, "unable to execute <"
+ << raw_statements_[GET_VERSION] << "> - 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_[GET_VERSION], bind);
+ if (status != 0) {
+ isc_throw(DbOperationError, "unable to bind result set: " <<
+ mysql_error(mysql_));
+ }
+
+ // Get the result
+ status = mysql_stmt_fetch(statements_[GET_VERSION]);
+ 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
new file mode 100644
index 0000000..1633d62
--- /dev/null
+++ b/src/lib/dhcp/mysql_lease_mgr.h
@@ -0,0 +1,381 @@
+// 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 <mysql.h>
+#include <dhcp/lease_mgr.h>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Abstract 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
+ /// - host - Host name to which to connect
+ /// - user - Username under which to connect.
+ /// - password - Password for "user" on the database.
+ ///
+ /// 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.
+ 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).
+ ///
+ /// @exception DbOperationError Database function 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).
+ ///
+ /// @exception DbOperationError Database function failed
+ virtual bool addLease(const Lease6Ptr& lease);
+
+ /// @brief Returns existing 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;
+
+ /// @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
+ /// @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) 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)
+ 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 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& 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 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
+ 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.
+ ///
+ /// @exception DbOperationError if 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.
+ ///
+ /// @exception DbOperationError if the rollback failed.
+ virtual void rollback();
+
+ ///@{
+ /// The following methods are used to convert between times and time
+ /// intervals stored in the server 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 cltt (client last transmit
+ /// time) and valid_lft (valid lifetime). In the database, the information
+ /// is stored as lease_time (lease time) and expire (time of expiry of the
+ /// lease). They are related by the equations:
+ ///
+ /// lease_time = valid_lft
+ /// expire = cltt + valid_lft
+ ///
+ /// 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_lft Valid lifetime
+ /// @param expire Reference to MYSQL_TIME object where the expiry time of
+ /// the lease will be put.
+ /// @param lease_time Reference to the time_t object where the lease time
+ /// will be put.
+ static
+ void convertFromLeaseTime(time_t cltt, uint32_t valid_lft,
+ MYSQL_TIME& expire, uint32_t& lease_time);
+
+ /// @brief Convert Database Time to Lease Times
+ ///
+ /// Within the database, time is stored as lease_time (lease time) and
+ /// expire (time of expiry of the lease). In the DHCP server, the
+ /// information is stored as cltt (client last transmit time) and
+ /// valid_lft (valid lifetime). These arr related by the equations:
+ ///
+ /// valid_lft = lease_time
+ /// cltt = expire - lease_time
+ ///
+ /// 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 lease_time lifetime of the lease.
+ /// @param cltt Reference to location where client last transmit time
+ /// is put.
+ /// @param valid_lft Reference to location where valid lifetime is put.
+ static
+ void convertToLeaseTime(const MYSQL_TIME& expire, uint32_t lease_time,
+ time_t& cltt, uint32_t& valid_lft);
+
+ ///@}
+
+
+private:
+ /// @brief Enum of Statements
+ ///
+ /// This is provided to set indexes into a list of prepared statements.
+ enum StatementIndex {
+ GET_LEASE6,
+ GET_VERSION, // Obtain version number
+ INSERT_LEASE6, // Add entry to lease6 table
+ NUM_STATEMENTS // Number of statements
+ };
+
+ /// @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.
+ ///
+ /// @exception DbOperationError MySQL operation failed, exception will give
+ /// text indicating the reason.
+ /// @exception 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.
+ void prepareStatements();
+
+ /// @brief Open Database
+ ///
+ /// Opens the database using the information supplied in the parameters
+ /// passed to the constructor.
+ ///
+ /// @exception DbOpenError Error opening the database
+ void openDatabase();
+
+ /// @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
+ ///
+ /// @exception DbOperationError Error doing a database operation
+ inline void checkError(my_bool status, StatementIndex index,
+ const char* what) const {
+ if (status != 0) {
+ isc_throw(DbOperationError, what << " for <" <<
+ raw_statements_[index] << ">, reason: " <<
+ mysql_error(mysql_));
+ }
+ }
+
+ // Members
+ MYSQL* mysql_; ///< MySQL context object
+ std::vector<std::string> raw_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/tests/Makefile.am b/src/lib/dhcp/tests/Makefile.am
index a15d957..2f7ba45 100644
--- a/src/lib/dhcp/tests/Makefile.am
+++ b/src/lib/dhcp/tests/Makefile.am
@@ -26,26 +26,30 @@ TESTS =
if HAVE_GTEST
TESTS += libdhcp++_unittests libdhcpsrv_unittests
libdhcp___unittests_SOURCES = run_unittests.cc
-libdhcp___unittests_SOURCES += libdhcp++_unittest.cc
+libdhcp___unittests_SOURCES += duid_unittest.cc
libdhcp___unittests_SOURCES += iface_mgr_unittest.cc
+libdhcp___unittests_SOURCES += lease_mgr_factory_unittest.cc
libdhcp___unittests_SOURCES += lease_mgr_unittest.cc
+libdhcp___unittests_SOURCES += mysql_lease_mgr_unittest.cc
+libdhcp___unittests_SOURCES += libdhcp++_unittest.cc
+libdhcp___unittests_SOURCES += option4_addrlst_unittest.cc
+libdhcp___unittests_SOURCES += option6_addrlst_unittest.cc
libdhcp___unittests_SOURCES += option6_iaaddr_unittest.cc
libdhcp___unittests_SOURCES += option6_ia_unittest.cc
-libdhcp___unittests_SOURCES += option6_addrlst_unittest.cc
-libdhcp___unittests_SOURCES += option4_addrlst_unittest.cc
libdhcp___unittests_SOURCES += option_unittest.cc
-libdhcp___unittests_SOURCES += pkt6_unittest.cc
libdhcp___unittests_SOURCES += pkt4_unittest.cc
-libdhcp___unittests_SOURCES += duid_unittest.cc
+libdhcp___unittests_SOURCES += pkt6_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_SOURCES += cfgmgr_unittest.cc
+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)
diff --git a/src/lib/dhcp/tests/lease_mgr_factory_unittest.cc b/src/lib/dhcp/tests/lease_mgr_factory_unittest.cc
new file mode 100644
index 0000000..c3cb5cf
--- /dev/null
+++ b/src/lib/dhcp/tests/lease_mgr_factory_unittest.cc
@@ -0,0 +1,47 @@
+// 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;
+
+
+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
index 97659a1..897301a 100644
--- a/src/lib/dhcp/tests/lease_mgr_unittest.cc
+++ b/src/lib/dhcp/tests/lease_mgr_unittest.cc
@@ -39,8 +39,9 @@ public:
/// are passed in the "name=value" format, separated by spaces.
/// Values may be enclosed in double quotes, if needed.
///
- /// @param dbconfig database configuration
- Memfile_LeaseMgr(const std::string& dbconfig);
+ /// @param parameters A data structure relating keywords and values
+ /// concerned with the database.
+ Memfile_LeaseMgr(const LeaseMgr::ParameterMap& parameters);
/// @brief Destructor (closes file)
virtual ~Memfile_LeaseMgr();
@@ -48,26 +49,26 @@ public:
/// @brief Adds an IPv4 lease.
///
/// @param lease lease to be added
- virtual bool addLease(Lease4Ptr lease);
+ virtual bool addLease(const Lease4Ptr& lease);
/// @brief Adds an IPv6 lease.
///
/// @param lease lease to be added
- virtual bool addLease(Lease6Ptr lease);
+ virtual bool addLease(const Lease6Ptr& lease);
/// @brief Returns existing IPv4 lease for specified IPv4 address.
///
/// @param addr address of the searched lease
///
/// @return a collection of leases
- virtual Lease4Ptr getLease4(isc::asiolink::IOAddress addr) const;
+ virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr) const;
/// @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(isc::asiolink::IOAddress addr,
+ virtual Lease4Ptr getLease4(const isc::asiolink::IOAddress& addr,
SubnetID subnet_id) const;
/// @brief Returns existing IPv4 leases for specified hardware address.
@@ -117,7 +118,7 @@ public:
/// @param addr address of the searched lease
///
/// @return smart pointer to the lease (or NULL if a lease is not found)
- Lease6Ptr getLease6(isc::asiolink::IOAddress addr) const;
+ Lease6Ptr getLease6(const isc::asiolink::IOAddress& addr) const;
/// @brief Returns existing IPv6 lease for a given DUID+IA combination
///
@@ -141,28 +142,28 @@ public:
/// @param lease4 The lease to be updated.
///
/// If no such lease is present, an exception will be thrown.
- void updateLease4(Lease4Ptr lease4);
+ void updateLease4(const Lease4Ptr& lease4);
/// @brief Updates IPv4 lease.
///
/// @param lease4 The lease to be updated.
///
/// If no such lease is present, an exception will be thrown.
- void updateLease6(Lease6Ptr lease6);
+ 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
- bool deleteLease4(uint32_t addr);
+ 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(isc::asiolink::IOAddress addr);
+ bool deleteLease6(const isc::asiolink::IOAddress& addr);
/// @brief Returns backend name.
///
@@ -175,7 +176,17 @@ public:
std::string getDescription() const;
/// @brief Returns backend version.
- std::string getVersion() const { return "test-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() {
+ }
using LeaseMgr::getParameter;
@@ -184,22 +195,22 @@ protected:
};
-Memfile_LeaseMgr::Memfile_LeaseMgr(const std::string& dbconfig)
- : LeaseMgr(dbconfig) {
+Memfile_LeaseMgr::Memfile_LeaseMgr(const LeaseMgr::ParameterMap& parameters)
+ : LeaseMgr(parameters) {
}
Memfile_LeaseMgr::~Memfile_LeaseMgr() {
}
-bool Memfile_LeaseMgr::addLease(boost::shared_ptr<isc::dhcp::Lease4>) {
+bool Memfile_LeaseMgr::addLease(const boost::shared_ptr<isc::dhcp::Lease4>&) {
return (false);
}
-bool Memfile_LeaseMgr::addLease(boost::shared_ptr<isc::dhcp::Lease6>) {
+bool Memfile_LeaseMgr::addLease(const boost::shared_ptr<isc::dhcp::Lease6>&) {
return (false);
}
-Lease4Ptr Memfile_LeaseMgr::getLease4(isc::asiolink::IOAddress) const {
+Lease4Ptr Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress&) const {
return (Lease4Ptr());
}
@@ -207,7 +218,7 @@ Lease4Collection Memfile_LeaseMgr::getLease4(const HWAddr& ) const {
return (Lease4Collection());
}
-Lease4Ptr Memfile_LeaseMgr::getLease4(isc::asiolink::IOAddress ,
+Lease4Ptr Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress & ,
SubnetID) const {
return (Lease4Ptr());
}
@@ -227,7 +238,7 @@ Lease4Collection Memfile_LeaseMgr::getLease4(const ClientId& ) const {
return (Lease4Collection());
}
-Lease6Ptr Memfile_LeaseMgr::getLease6(isc::asiolink::IOAddress) const {
+Lease6Ptr Memfile_LeaseMgr::getLease6(const isc::asiolink::IOAddress&) const {
return (Lease6Ptr());
}
@@ -240,18 +251,18 @@ Lease6Ptr Memfile_LeaseMgr::getLease6(const DUID&, uint32_t,
return (Lease6Ptr());
}
-void Memfile_LeaseMgr::updateLease4(Lease4Ptr ) {
+void Memfile_LeaseMgr::updateLease4(const Lease4Ptr&) {
}
-void Memfile_LeaseMgr::updateLease6(Lease6Ptr ) {
+void Memfile_LeaseMgr::updateLease6(const Lease6Ptr&) {
}
-bool Memfile_LeaseMgr::deleteLease4(uint32_t ) {
+bool Memfile_LeaseMgr::deleteLease4(const isc::asiolink::IOAddress&) {
return (false);
}
-bool Memfile_LeaseMgr::deleteLease6(isc::asiolink::IOAddress ) {
+bool Memfile_LeaseMgr::deleteLease6(const isc::asiolink::IOAddress&) {
return (false);
}
@@ -271,19 +282,16 @@ public:
// This test checks if the LeaseMgr can be instantiated and that it
// parses parameters string properly.
-TEST_F(LeaseMgrTest, constructor) {
-
- // should not throw any exceptions here
- Memfile_LeaseMgr * leaseMgr = new Memfile_LeaseMgr("");
- delete leaseMgr;
-
- leaseMgr = new Memfile_LeaseMgr("param1=value1 param2=value2");
+TEST_F(LeaseMgrTest, getParameter) {
- EXPECT_EQ("value1", leaseMgr->getParameter("param1"));
- EXPECT_EQ("value2", leaseMgr->getParameter("param2"));
- EXPECT_THROW(leaseMgr->getParameter("param3"), BadValue);
+ LeaseMgr::ParameterMap pmap;
+ pmap[std::string("param1")] = std::string("value1");
+ pmap[std::string("param2")] = std::string("value2");
+ Memfile_LeaseMgr leasemgr(pmap);
- delete leaseMgr;
+ 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
diff --git a/src/lib/dhcp/tests/mysql_lease_mgr_unittest.cc b/src/lib/dhcp/tests/mysql_lease_mgr_unittest.cc
new file mode 100644
index 0000000..a4626d8
--- /dev/null
+++ b/src/lib/dhcp/tests/mysql_lease_mgr_unittest.cc
@@ -0,0 +1,271 @@
+// 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 {
+
+// Connection strings
+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 = " ";
+ return (string(type) + space + string(name) + space + string(host) + space +
+ string(user) + space + string(password));
+}
+
+// Return valid connection string
+string validConnectionString() {
+ return (connectionString(VALID_TYPE, VALID_NAME, VALID_HOST,
+ VALID_USER, VALID_PASSWORD));
+}
+
+/// @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
+ ///
+ /// Open the database.
+
+ MySqlLeaseMgrTest() {
+ lmptr_ = LeaseMgrFactory::create(validConnectionString());
+ }
+
+ /// @brief Destructor
+ ///
+ /// Rolls back all pending transactions. The deletion of the
+ /// lmptr_ member variable will close the database.
+
+ virtual ~MySqlLeaseMgrTest() {
+ //lmptr_->rollback();
+ }
+
+ LeaseMgrPtr lmptr_; // Pointer to the lease manager
+};
+
+
+/// @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) {
+ LeaseMgrPtr lmptr;
+
+ // Check that wrong specification of backend throws an exception.
+ // (This is really a check on LeaseMgrFactory, but is convenient to
+ // perform here.)
+ EXPECT_THROW(lmptr = LeaseMgrFactory::create(connectionString(
+ INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
+ InvalidParameter);
+
+ // Check that invalid login data causes an exception.
+ EXPECT_THROW(lmptr = LeaseMgrFactory::create(connectionString(
+ VALID_TYPE, INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
+ DbOpenError);
+ EXPECT_THROW(lmptr = LeaseMgrFactory::create(connectionString(
+ VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)),
+ DbOpenError);
+ EXPECT_THROW(lmptr = LeaseMgrFactory::create(connectionString(
+ VALID_TYPE, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
+ DbOpenError);
+ EXPECT_THROW(lmptr = LeaseMgrFactory::create(connectionString(
+ VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)),
+ DbOpenError);
+
+ // Check that database opens correctly and that version is as expected
+ ASSERT_NO_THROW(lmptr = LeaseMgrFactory::create(validConnectionString()));
+ ASSERT_TRUE(lmptr);
+}
+
+/// @brief Check conversion functions
+TEST_F(MySqlLeaseMgrTest, CheckTimeConversion) {
+ const time_t cltt = time(NULL);
+ const uint32_t valid_lft = 86400; // 1 day
+ MYSQL_TIME expire;
+ uint32_t lease_time;
+
+ MySqlLeaseMgr::convertFromLeaseTime(cltt, valid_lft, expire, lease_time);
+ EXPECT_EQ(valid_lft, lease_time);
+ EXPECT_LE(2012, expire.year); // Code was written in 2012
+ EXPECT_EQ(0, expire.second_part);
+ EXPECT_EQ(0, expire.neg);
+
+ // Convert back
+ time_t converted_cltt = 0;
+ uint32_t converted_valid_lft = 0;
+ MySqlLeaseMgr::convertToLeaseTime(expire, lease_time, converted_cltt,
+ converted_valid_lft);
+ EXPECT_EQ(cltt, converted_cltt);
+ EXPECT_EQ(valid_lft, converted_valid_lft);
+}
+
+/// @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(0, version.first);
+ EXPECT_EQ(1, version.second);
+}
+
+
+/// @brief Compare Lease4 Structure
+bool
+compareLease6(const Lease6Ptr& l1, const Lease6Ptr& l2) {
+ return (
+ l1->type_ == l2->type_ &&
+ l1->addr_ == l2->addr_ &&
+ l1->prefixlen_ == l2->prefixlen_ &&
+ l1->iaid_ == l2->iaid_ &&
+ l1->hwaddr_ == l2->hwaddr_ &&
+ *l1->duid_ == *l2->duid_ &&
+ l1->preferred_lft_ == l2->preferred_lft_ &&
+ l1->valid_lft_ == l2->valid_lft_ &&
+ l1->cltt_ == l2->cltt_ &&
+ l1->subnet_id_ == l2->subnet_id_
+ );
+}
+
+void
+detailCompareLease6(const Lease6Ptr& l1, const Lease6Ptr& l2) {
+ EXPECT_EQ(l1->type_, l2->type_);
+ EXPECT_EQ(l1->addr_, l2->addr_);
+ EXPECT_EQ(l1->prefixlen_, l2->prefixlen_);
+ EXPECT_EQ(l1->iaid_, l2->iaid_);
+ EXPECT_TRUE(l1->hwaddr_ == l2->hwaddr_);
+ EXPECT_TRUE(*l1->duid_ == *l2->duid_);
+ EXPECT_EQ(l1->preferred_lft_, l2->preferred_lft_);
+ EXPECT_EQ(l1->valid_lft_, l2->valid_lft_);
+ EXPECT_EQ(l1->cltt_, l2->cltt_);
+ EXPECT_EQ(l1->subnet_id_, l2->subnet_id_);
+}
+
+/// @brief Initialize Lease
+///
+/// Initializes the unused fields in a lease to known values for
+/// testing purposes.
+void initializeUnusedLease6(Lease6Ptr& lease) {
+ 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
+}
+
+/// @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) {
+
+ // Define the leases being used for testing.
+ const IOAddress L1_ADDRESS(std::string("2001:db8::1"));
+ Lease6Ptr l1(new Lease6());
+ initializeUnusedLease6(l1);
+
+ l1->type_ = Lease6::LEASE_IA_TA;
+ l1->addr_ = L1_ADDRESS;
+ l1->prefixlen_ = 0;
+ l1->iaid_ = 42;
+ l1->hwaddr_ = std::vector<uint8_t>(6, 0x42); // Six hex 42's
+ l1->duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0x42)));
+ l1->preferred_lft_ = 3600; // Preferred lifetime
+ l1->valid_lft_ = 3600; // Actual lifetime
+ l1->cltt_ = 123456; // Current time of day
+ l1->subnet_id_ = 73; // Arbitrary number
+
+ const IOAddress L2_ADDRESS(std::string("2001:db8::2"));
+ Lease6Ptr l2(new Lease6());
+ initializeUnusedLease6(l2);
+
+ l2->type_ = Lease6::LEASE_IA_TA;
+ l2->addr_ = L1_ADDRESS;
+ l2->prefixlen_ = 0;
+ l2->iaid_ = 89;
+ l2->hwaddr_ = std::vector<uint8_t>(6, 0xf43); // Six hex 42's
+ l2->duid_ = boost::shared_ptr<DUID>(new DUID(vector<uint8_t>(8, 0x3a)));
+ l2->preferred_lft_ = 1800; // Preferred lifetime
+ l2->valid_lft_ = 5400; // Actual lifetime
+ l2->cltt_ = 234567; // Current time of day
+ l2->subnet_id_ = l1->subnet_id_; // Same as l1
+
+ // Sanity check that the leases are different
+ ASSERT_FALSE(compareLease6(l1, l2));
+
+ // Start the tests. Add the first lease to the database. Then read it
+ // back to see whether it is what we think it is.
+ Lease6Ptr l_returned;
+
+ ASSERT_TRUE(lmptr_->addLease(l1));
+ l_returned = lmptr_->getLease6(L1_ADDRESS);
+ EXPECT_TRUE(l_returned);
+ detailCompareLease6(l1, l_returned);
+/*
+ // Delete the lease and check that it has been deleted.
+ EXPECT_TRUE(lmptr_->deleteLease6(L1_ADDRESS));
+ l_returned = lmptr_->getLease6(L1_ADDRESS);
+ EXPECT_FALSE(l_returned);
+
+ // Add the address again and check that we can't add it a second time
+ ASSERT_TRUE(lmptr_->addLease(l1));
+ ASSERT_FALSE(lmptr_->addLease(l1));
+
+ // Add the second lease
+ ASSERT_TRUE(lmptr_->addLease(l2));
+
+ // Finally, delete the lease and check we can't delete it again.
+ EXPECT_TRUE(lmptr_->deleteLease6(L1_ADDRESS));
+ EXPECT_FALSE(lmptr_->deleteLease6(L1_ADDRESS));
+ */
+}
+
+}; // end of anonymous namespace
More information about the bind10-changes
mailing list