2015-03-04 13:32:18 +01:00
|
|
|
// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
|
2012-10-16 16:39:32 +01:00
|
|
|
//
|
|
|
|
// 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>
|
2012-10-22 16:07:34 +01:00
|
|
|
|
2012-10-20 22:52:25 +01:00
|
|
|
#include <asiolink/io_address.h>
|
2012-12-04 11:32:08 +00:00
|
|
|
#include <dhcp/duid.h>
|
2013-01-10 16:32:24 +01:00
|
|
|
#include <dhcp/hwaddr.h>
|
2012-12-14 22:19:31 +00:00
|
|
|
#include <dhcpsrv/dhcpsrv_log.h>
|
2012-11-16 11:19:19 +00:00
|
|
|
#include <dhcpsrv/mysql_lease_mgr.h>
|
2012-10-16 16:39:32 +01:00
|
|
|
|
2012-11-30 15:49:42 +00:00
|
|
|
#include <boost/static_assert.hpp>
|
2013-03-14 08:50:20 -04:00
|
|
|
#include <mysqld_error.h>
|
2012-11-08 12:14:10 +00:00
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <iomanip>
|
2015-09-07 13:29:17 +02:00
|
|
|
#include <limits.h>
|
2012-12-14 22:19:31 +00:00
|
|
|
#include <sstream>
|
2012-11-08 12:14:10 +00:00
|
|
|
#include <string>
|
|
|
|
#include <time.h>
|
|
|
|
|
2012-10-24 19:18:33 +01:00
|
|
|
using namespace isc;
|
2012-11-04 20:20:21 +00:00
|
|
|
using namespace isc::dhcp;
|
2012-10-17 18:37:22 +01:00
|
|
|
using namespace std;
|
|
|
|
|
2012-11-26 19:17:27 +00:00
|
|
|
/// @file
|
|
|
|
///
|
|
|
|
/// This file holds the implementation of the Lease Manager using MySQL. The
|
|
|
|
/// implementation uses MySQL's C API, as it comes as standard with the MySQL
|
|
|
|
/// client libraries.
|
|
|
|
///
|
|
|
|
/// In general, each of the database access methods corresponds to one SQL
|
|
|
|
/// statement. To avoid the overhead of parsing a statement every time it is
|
|
|
|
/// used, when the database is opened "prepared statements" are created -
|
|
|
|
/// essentially doing the SQL parsing up front. Every time a method is used
|
|
|
|
/// to access data, the corresponding prepared statement is referenced. Each
|
|
|
|
/// prepared statement contains a set of placeholders for data, each
|
|
|
|
/// placeholder being for:
|
|
|
|
///
|
|
|
|
/// - data being added to the database (as in adding or updating a lease)
|
|
|
|
/// - data being retrieved from the database (as in getting lease information)
|
|
|
|
/// - selection criteria used to determine which records to update/retrieve.
|
|
|
|
///
|
|
|
|
/// All such data is associated with the prepared statment using an array of
|
|
|
|
/// MYSQL_BIND structures. Each element in the array corresponds to one
|
|
|
|
/// parameter in the prepared statement - the first element in the array is
|
|
|
|
/// associated with the first parameter, the second element with the second
|
|
|
|
/// parameter etc.
|
|
|
|
///
|
|
|
|
/// Within this file, the setting up of the MYSQL_BIND arrays for data being
|
|
|
|
/// passed to and retrieved from the database is handled in the
|
|
|
|
/// isc::dhcp::MySqlLease4Exchange and isc::dhcp::MySqlLease6Exchange classes.
|
|
|
|
/// The classes also hold intermediate variables required for exchanging some
|
|
|
|
/// of the data.
|
|
|
|
///
|
|
|
|
/// With these exchange objects in place, many of the methods follow similar
|
|
|
|
/// logic:
|
|
|
|
/// - Set up the MYSQL_BIND array for data being transferred to/from the
|
|
|
|
/// database. For data being transferred to the database, some of the
|
|
|
|
/// data is extracted from the lease to intermediate variables, whilst
|
|
|
|
/// in other cases the MYSQL_BIND arrays point to the data in the lease.
|
|
|
|
/// - Set up the MYSQL_BIND array for the data selection parameters.
|
|
|
|
/// - Bind these arrays to the prepared statement.
|
|
|
|
/// - Execute the statement.
|
|
|
|
/// - If there is output, copy the data from the bound variables to the output
|
|
|
|
/// lease object.
|
|
|
|
|
2012-10-24 14:12:06 +01:00
|
|
|
namespace {
|
|
|
|
///@{
|
2012-11-23 18:23:21 +00:00
|
|
|
|
|
|
|
/// @brief Maximum size of database fields
|
2012-10-24 14:12:06 +01:00
|
|
|
///
|
|
|
|
/// The following constants define buffer sizes for variable length database
|
|
|
|
/// fields. The values should be greater than or equal to the length set in
|
|
|
|
/// the schema definition.
|
|
|
|
///
|
2012-11-30 15:49:42 +00:00
|
|
|
/// The exception is the length of any VARCHAR fields: buffers for these should
|
|
|
|
/// be set greater than or equal to the length of the field plus 1: this allows
|
|
|
|
/// for the insertion of a trailing null whatever data is returned.
|
2012-10-24 14:12:06 +01:00
|
|
|
|
2012-11-30 15:49:42 +00:00
|
|
|
/// @brief Maximum size of an IPv6 address represented as a text string.
|
|
|
|
///
|
|
|
|
/// This is 32 hexadecimal characters written in 8 groups of four, plus seven
|
|
|
|
/// colon separators.
|
|
|
|
const size_t ADDRESS6_TEXT_MAX_LEN = 39;
|
|
|
|
|
2012-11-23 18:23:21 +00:00
|
|
|
/// @brief MySQL True/False constants
|
|
|
|
///
|
|
|
|
/// Declare typed values so as to avoid problems of data conversion. These
|
|
|
|
/// are local to the file but are given the prefix MLM (MySql Lease Manager) to
|
2012-11-30 15:49:42 +00:00
|
|
|
/// avoid any likely conflicts with variables in header files named TRUE or
|
2012-11-26 19:17:27 +00:00
|
|
|
/// FALSE.
|
2012-11-23 18:23:21 +00:00
|
|
|
|
|
|
|
const my_bool MLM_FALSE = 0; ///< False value
|
|
|
|
const my_bool MLM_TRUE = 1; ///< True value
|
|
|
|
|
2013-08-26 17:30:56 +02:00
|
|
|
/// @brief Maximum length of the hostname stored in DNS.
|
|
|
|
///
|
|
|
|
/// This length is restricted by the length of the domain-name carried
|
|
|
|
/// in the Client FQDN %Option (see RFC4702 and RFC4704).
|
|
|
|
const size_t HOSTNAME_MAX_LEN = 255;
|
|
|
|
|
2012-10-24 14:12:06 +01:00
|
|
|
///@}
|
2012-11-04 20:20:21 +00:00
|
|
|
|
|
|
|
/// @brief MySQL Selection Statements
|
|
|
|
///
|
2012-11-23 18:23:21 +00:00
|
|
|
/// Each statement is associated with an index, which is used to reference the
|
|
|
|
/// associated prepared statement.
|
|
|
|
|
2012-11-04 20:20:21 +00:00
|
|
|
struct TaggedStatement {
|
|
|
|
MySqlLeaseMgr::StatementIndex index;
|
|
|
|
const char* text;
|
|
|
|
};
|
|
|
|
|
|
|
|
TaggedStatement tagged_statements[] = {
|
2012-11-21 12:44:18 +00:00
|
|
|
{MySqlLeaseMgr::DELETE_LEASE4,
|
|
|
|
"DELETE FROM lease4 WHERE address = ?"},
|
2015-09-07 13:58:22 +02:00
|
|
|
{MySqlLeaseMgr::DELETE_LEASE4_STATE_EXPIRED,
|
|
|
|
"DELETE FROM lease4 "
|
|
|
|
"WHERE state = ? AND expire < ?"},
|
2012-11-04 20:20:21 +00:00
|
|
|
{MySqlLeaseMgr::DELETE_LEASE6,
|
|
|
|
"DELETE FROM lease6 WHERE address = ?"},
|
2015-09-07 13:58:22 +02:00
|
|
|
{MySqlLeaseMgr::DELETE_LEASE6_STATE_EXPIRED,
|
|
|
|
"DELETE FROM lease6 "
|
|
|
|
"WHERE state = ? AND expire < ?"},
|
2012-11-23 12:47:40 +00:00
|
|
|
{MySqlLeaseMgr::GET_LEASE4_ADDR,
|
|
|
|
"SELECT address, hwaddr, client_id, "
|
2013-08-26 17:30:56 +02:00
|
|
|
"valid_lifetime, expire, subnet_id, "
|
2015-09-07 10:47:30 +02:00
|
|
|
"fqdn_fwd, fqdn_rev, hostname, "
|
|
|
|
"state "
|
2012-11-23 12:47:40 +00:00
|
|
|
"FROM lease4 "
|
|
|
|
"WHERE address = ?"},
|
|
|
|
{MySqlLeaseMgr::GET_LEASE4_CLIENTID,
|
|
|
|
"SELECT address, hwaddr, client_id, "
|
2013-08-26 17:30:56 +02:00
|
|
|
"valid_lifetime, expire, subnet_id, "
|
2015-09-07 10:47:30 +02:00
|
|
|
"fqdn_fwd, fqdn_rev, hostname, "
|
|
|
|
"state "
|
2012-11-23 12:47:40 +00:00
|
|
|
"FROM lease4 "
|
|
|
|
"WHERE client_id = ?"},
|
2012-11-23 13:48:42 +00:00
|
|
|
{MySqlLeaseMgr::GET_LEASE4_CLIENTID_SUBID,
|
|
|
|
"SELECT address, hwaddr, client_id, "
|
2013-08-26 17:30:56 +02:00
|
|
|
"valid_lifetime, expire, subnet_id, "
|
2015-09-07 10:47:30 +02:00
|
|
|
"fqdn_fwd, fqdn_rev, hostname, "
|
|
|
|
"state "
|
2012-11-23 13:48:42 +00:00
|
|
|
"FROM lease4 "
|
|
|
|
"WHERE client_id = ? AND subnet_id = ?"},
|
2012-11-23 12:05:55 +00:00
|
|
|
{MySqlLeaseMgr::GET_LEASE4_HWADDR,
|
|
|
|
"SELECT address, hwaddr, client_id, "
|
2013-08-26 17:30:56 +02:00
|
|
|
"valid_lifetime, expire, subnet_id, "
|
2015-09-07 10:47:30 +02:00
|
|
|
"fqdn_fwd, fqdn_rev, hostname, "
|
|
|
|
"state "
|
2012-11-23 12:05:55 +00:00
|
|
|
"FROM lease4 "
|
|
|
|
"WHERE hwaddr = ?"},
|
2012-11-23 12:23:17 +00:00
|
|
|
{MySqlLeaseMgr::GET_LEASE4_HWADDR_SUBID,
|
|
|
|
"SELECT address, hwaddr, client_id, "
|
2013-08-26 17:30:56 +02:00
|
|
|
"valid_lifetime, expire, subnet_id, "
|
2015-09-07 10:47:30 +02:00
|
|
|
"fqdn_fwd, fqdn_rev, hostname, "
|
|
|
|
"state "
|
2012-11-23 12:23:17 +00:00
|
|
|
"FROM lease4 "
|
|
|
|
"WHERE hwaddr = ? AND subnet_id = ?"},
|
2015-09-07 13:29:17 +02:00
|
|
|
{MySqlLeaseMgr::GET_LEASE4_EXPIRE,
|
|
|
|
"SELECT address, hwaddr, client_id, "
|
|
|
|
"valid_lifetime, expire, subnet_id, "
|
|
|
|
"fqdn_fwd, fqdn_rev, hostname, "
|
|
|
|
"state "
|
|
|
|
"FROM lease4 "
|
|
|
|
"WHERE state != ? AND expire < ? "
|
|
|
|
"ORDER BY expire "
|
|
|
|
"LIMIT ?"},
|
2012-11-04 20:20:21 +00:00
|
|
|
{MySqlLeaseMgr::GET_LEASE6_ADDR,
|
|
|
|
"SELECT address, duid, valid_lifetime, "
|
|
|
|
"expire, subnet_id, pref_lifetime, "
|
2013-08-26 17:30:56 +02:00
|
|
|
"lease_type, iaid, prefix_len, "
|
2014-11-06 19:36:46 +01:00
|
|
|
"fqdn_fwd, fqdn_rev, hostname, "
|
2015-09-07 10:47:30 +02:00
|
|
|
"hwaddr, hwtype, hwaddr_source, "
|
|
|
|
"state "
|
2012-11-04 20:20:21 +00:00
|
|
|
"FROM lease6 "
|
2013-09-18 06:06:37 -04:00
|
|
|
"WHERE address = ? AND lease_type = ?"},
|
2012-11-04 20:20:21 +00:00
|
|
|
{MySqlLeaseMgr::GET_LEASE6_DUID_IAID,
|
|
|
|
"SELECT address, duid, valid_lifetime, "
|
|
|
|
"expire, subnet_id, pref_lifetime, "
|
2013-08-26 17:30:56 +02:00
|
|
|
"lease_type, iaid, prefix_len, "
|
2014-11-06 19:36:46 +01:00
|
|
|
"fqdn_fwd, fqdn_rev, hostname, "
|
2015-09-07 10:47:30 +02:00
|
|
|
"hwaddr, hwtype, hwaddr_source, "
|
|
|
|
"state "
|
2012-11-04 20:20:21 +00:00
|
|
|
"FROM lease6 "
|
2013-09-13 10:05:28 -04:00
|
|
|
"WHERE duid = ? AND iaid = ? AND lease_type = ?"},
|
2012-11-04 20:20:21 +00:00
|
|
|
{MySqlLeaseMgr::GET_LEASE6_DUID_IAID_SUBID,
|
|
|
|
"SELECT address, duid, valid_lifetime, "
|
|
|
|
"expire, subnet_id, pref_lifetime, "
|
2013-08-26 17:30:56 +02:00
|
|
|
"lease_type, iaid, prefix_len, "
|
2014-11-06 19:36:46 +01:00
|
|
|
"fqdn_fwd, fqdn_rev, hostname, "
|
2015-09-07 10:47:30 +02:00
|
|
|
"hwaddr, hwtype, hwaddr_source, "
|
|
|
|
"state "
|
2012-11-04 20:20:21 +00:00
|
|
|
"FROM lease6 "
|
2013-09-13 10:05:28 -04:00
|
|
|
"WHERE duid = ? AND iaid = ? AND subnet_id = ? "
|
|
|
|
"AND lease_type = ?"},
|
2015-09-07 13:29:17 +02:00
|
|
|
{MySqlLeaseMgr::GET_LEASE6_EXPIRE,
|
|
|
|
"SELECT address, duid, valid_lifetime, "
|
|
|
|
"expire, subnet_id, pref_lifetime, "
|
|
|
|
"lease_type, iaid, prefix_len, "
|
|
|
|
"fqdn_fwd, fqdn_rev, hostname, "
|
|
|
|
"hwaddr, hwtype, hwaddr_source, "
|
|
|
|
"state "
|
|
|
|
"FROM lease6 "
|
|
|
|
"WHERE state != ? AND expire < ? "
|
|
|
|
"ORDER BY expire "
|
|
|
|
"LIMIT ?"},
|
2012-11-04 20:20:21 +00:00
|
|
|
{MySqlLeaseMgr::GET_VERSION,
|
|
|
|
"SELECT version, minor FROM schema_version"},
|
2012-11-21 12:44:18 +00:00
|
|
|
{MySqlLeaseMgr::INSERT_LEASE4,
|
|
|
|
"INSERT INTO lease4(address, hwaddr, client_id, "
|
2013-08-26 17:30:56 +02:00
|
|
|
"valid_lifetime, expire, subnet_id, "
|
2015-09-07 10:47:30 +02:00
|
|
|
"fqdn_fwd, fqdn_rev, hostname, state) "
|
|
|
|
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
|
2012-11-04 20:20:21 +00:00
|
|
|
{MySqlLeaseMgr::INSERT_LEASE6,
|
|
|
|
"INSERT INTO lease6(address, duid, valid_lifetime, "
|
|
|
|
"expire, subnet_id, pref_lifetime, "
|
2013-08-26 17:30:56 +02:00
|
|
|
"lease_type, iaid, prefix_len, "
|
2014-11-06 19:36:46 +01:00
|
|
|
"fqdn_fwd, fqdn_rev, hostname, "
|
2015-09-07 10:47:30 +02:00
|
|
|
"hwaddr, hwtype, hwaddr_source, "
|
|
|
|
"state) "
|
|
|
|
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
|
2012-11-23 14:08:00 +00:00
|
|
|
{MySqlLeaseMgr::UPDATE_LEASE4,
|
|
|
|
"UPDATE lease4 SET address = ?, hwaddr = ?, "
|
|
|
|
"client_id = ?, valid_lifetime = ?, expire = ?, "
|
2013-08-26 17:30:56 +02:00
|
|
|
"subnet_id = ?, fqdn_fwd = ?, fqdn_rev = ?, "
|
2015-09-07 10:47:30 +02:00
|
|
|
"hostname = ?, state = ? "
|
2012-11-23 14:08:00 +00:00
|
|
|
"WHERE address = ?"},
|
2012-11-04 20:20:21 +00:00
|
|
|
{MySqlLeaseMgr::UPDATE_LEASE6,
|
|
|
|
"UPDATE lease6 SET address = ?, duid = ?, "
|
|
|
|
"valid_lifetime = ?, expire = ?, subnet_id = ?, "
|
|
|
|
"pref_lifetime = ?, lease_type = ?, iaid = ?, "
|
2013-08-26 17:30:56 +02:00
|
|
|
"prefix_len = ?, fqdn_fwd = ?, fqdn_rev = ?, "
|
2015-09-07 10:47:30 +02:00
|
|
|
"hostname = ?, hwaddr = ?, hwtype = ?, hwaddr_source = ?, "
|
|
|
|
"state = ? "
|
2012-11-04 20:20:21 +00:00
|
|
|
"WHERE address = ?"},
|
|
|
|
// End of list sentinel
|
|
|
|
{MySqlLeaseMgr::NUM_STATEMENTS, NULL}
|
2012-10-24 14:12:06 +01:00
|
|
|
};
|
|
|
|
|
2012-11-04 20:20:21 +00:00
|
|
|
}; // Anonymous namespace
|
|
|
|
|
2012-12-14 22:19:31 +00:00
|
|
|
|
|
|
|
|
2012-10-16 16:39:32 +01:00
|
|
|
namespace isc {
|
|
|
|
namespace dhcp {
|
|
|
|
|
2012-11-30 15:49:42 +00:00
|
|
|
/// @brief Common MySQL and Lease Data Methods
|
|
|
|
///
|
|
|
|
/// The MySqlLease4Exchange and MySqlLease6Exchange classes provide the
|
|
|
|
/// functionaility to set up binding information between variables in the
|
|
|
|
/// program and data extracted from the database. This class is the common
|
|
|
|
/// base to both of them, containing some common methods.
|
|
|
|
|
|
|
|
class MySqlLeaseExchange {
|
|
|
|
public:
|
|
|
|
/// @brief Set error indicators
|
|
|
|
///
|
|
|
|
/// Sets the error indicator for each of the MYSQL_BIND elements. It points
|
|
|
|
/// the "error" field within an element of the input array to the
|
|
|
|
/// corresponding element of the passed error array.
|
|
|
|
///
|
|
|
|
/// @param bind Array of BIND elements
|
|
|
|
/// @param error Array of error elements. If there is an error in getting
|
|
|
|
/// data associated with one of the "bind" elements, the
|
|
|
|
/// corresponding element in the error array is set to MLM_TRUE.
|
|
|
|
/// @param count Size of each of the arrays.
|
2015-03-04 15:02:04 +01:00
|
|
|
static void setErrorIndicators(MYSQL_BIND* bind, my_bool* error,
|
|
|
|
size_t count) {
|
2012-11-30 15:49:42 +00:00
|
|
|
for (size_t i = 0; i < count; ++i) {
|
|
|
|
error[i] = MLM_FALSE;
|
|
|
|
bind[i].error = reinterpret_cast<char*>(&error[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Return columns in error
|
|
|
|
///
|
|
|
|
/// If an error is returned from a fetch (in particular, a truncated
|
|
|
|
/// status), this method can be called to get the names of the fields in
|
|
|
|
/// error. It returns a string comprising the names of the fields
|
|
|
|
/// separated by commas. In the case of there being no error indicators
|
|
|
|
/// set, it returns the string "(None)".
|
|
|
|
///
|
|
|
|
/// @param error Array of error elements. An element is set to MLM_TRUE
|
|
|
|
/// if the corresponding column in the database is the source of
|
|
|
|
/// the error.
|
|
|
|
/// @param names Array of column names, the same size as the error array.
|
|
|
|
/// @param count Size of each of the arrays.
|
2015-03-04 15:02:04 +01:00
|
|
|
static std::string getColumnsInError(my_bool* error, std::string* names,
|
|
|
|
size_t count) {
|
2012-11-30 15:49:42 +00:00
|
|
|
std::string result = "";
|
|
|
|
|
|
|
|
// Accumulate list of column names
|
|
|
|
for (size_t i = 0; i < count; ++i) {
|
|
|
|
if (error[i] == MLM_TRUE) {
|
|
|
|
if (!result.empty()) {
|
|
|
|
result += ", ";
|
|
|
|
}
|
|
|
|
result += names[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result.empty()) {
|
|
|
|
result = "(None)";
|
|
|
|
}
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2012-11-21 12:44:18 +00:00
|
|
|
/// @brief Exchange MySQL and Lease4 Data
|
|
|
|
///
|
|
|
|
/// On any MySQL operation, arrays of MYSQL_BIND structures must be built to
|
|
|
|
/// describe the parameters in the prepared statements. Where information is
|
|
|
|
/// inserted or retrieved - INSERT, UPDATE, SELECT - a large amount of that
|
2012-11-23 18:23:21 +00:00
|
|
|
/// structure is identical. This class handles the creation of that array.
|
2012-11-21 12:44:18 +00:00
|
|
|
///
|
|
|
|
/// Owing to the MySQL API, the process requires some intermediate variables
|
2012-11-26 19:17:27 +00:00
|
|
|
/// to hold things like data length etc. This object holds those variables.
|
2012-11-21 12:44:18 +00:00
|
|
|
///
|
|
|
|
/// @note There are no unit tests for this class. It is tested indirectly
|
|
|
|
/// in all MySqlLeaseMgr::xxx4() calls where it is used.
|
|
|
|
|
2012-11-30 15:49:42 +00:00
|
|
|
class MySqlLease4Exchange : public MySqlLeaseExchange {
|
2012-12-07 20:25:25 +00:00
|
|
|
/// @brief Set number of database columns for this lease structure
|
2015-09-07 10:47:30 +02:00
|
|
|
static const size_t LEASE_COLUMNS = 10;
|
2012-11-30 15:49:42 +00:00
|
|
|
|
2012-12-07 20:25:25 +00:00
|
|
|
public:
|
2012-11-21 12:44:18 +00:00
|
|
|
/// @brief Constructor
|
|
|
|
///
|
2012-11-30 15:49:42 +00:00
|
|
|
/// The initialization of the variables here is only to satisfy cppcheck -
|
2012-11-23 18:23:21 +00:00
|
|
|
/// all variables are initialized/set in the methods before they are used.
|
2013-08-30 16:18:40 +02:00
|
|
|
MySqlLease4Exchange() : addr4_(0), hwaddr_length_(0), client_id_length_(0),
|
2014-11-06 19:36:46 +01:00
|
|
|
client_id_null_(MLM_FALSE),
|
2015-06-24 13:41:20 +02:00
|
|
|
subnet_id_(0), valid_lifetime_(0),
|
2015-09-07 10:47:30 +02:00
|
|
|
fqdn_fwd_(false), fqdn_rev_(false), hostname_length_(0),
|
|
|
|
state_(0) {
|
2012-11-21 12:44:18 +00:00
|
|
|
memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
|
|
|
|
memset(client_id_buffer_, 0, sizeof(client_id_buffer_));
|
2013-08-30 16:18:40 +02:00
|
|
|
memset(hostname_buffer_, 0, sizeof(hostname_buffer_));
|
2012-11-30 15:49:42 +00:00
|
|
|
std::fill(&error_[0], &error_[LEASE_COLUMNS], MLM_FALSE);
|
2013-02-25 17:07:58 +01:00
|
|
|
|
2012-11-30 15:49:42 +00:00
|
|
|
// Set the column names (for error messages)
|
|
|
|
columns_[0] = "address";
|
|
|
|
columns_[1] = "hwaddr";
|
|
|
|
columns_[2] = "client_id";
|
|
|
|
columns_[3] = "valid_lifetime";
|
|
|
|
columns_[4] = "expire";
|
|
|
|
columns_[5] = "subnet_id";
|
2013-08-26 17:30:56 +02:00
|
|
|
columns_[6] = "fqdn_fwd";
|
|
|
|
columns_[7] = "fqdn_rev";
|
|
|
|
columns_[8] = "hostname";
|
2015-09-07 10:47:30 +02:00
|
|
|
columns_[9] = "state";
|
|
|
|
BOOST_STATIC_ASSERT(9 < LEASE_COLUMNS);
|
2012-11-21 12:44:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Create MYSQL_BIND objects for Lease4 Pointer
|
|
|
|
///
|
2012-11-23 18:23:21 +00:00
|
|
|
/// Fills in the MYSQL_BIND array for sending data in the Lease4 object to
|
|
|
|
/// the database.
|
2012-11-21 12:44:18 +00:00
|
|
|
///
|
2012-11-23 18:23:21 +00:00
|
|
|
/// @param lease Lease object to be added to the database. None of the
|
|
|
|
/// fields in the lease are modified - the lease data is only read.
|
2012-11-21 12:44:18 +00:00
|
|
|
///
|
|
|
|
/// @return Vector of MySQL BIND objects representing the data to be added.
|
|
|
|
std::vector<MYSQL_BIND> createBindForSend(const Lease4Ptr& lease) {
|
2012-11-23 18:23:21 +00:00
|
|
|
|
2012-11-21 12:44:18 +00:00
|
|
|
// Store lease object to ensure it remains valid.
|
|
|
|
lease_ = lease;
|
|
|
|
|
2012-11-23 18:23:21 +00:00
|
|
|
// Initialize prior to constructing the array of MYSQL_BIND structures.
|
2013-03-07 15:21:00 +01:00
|
|
|
// It sets all fields, including is_null, to zero, so we need to set
|
|
|
|
// is_null only if it should be true. This gives up minor performance
|
|
|
|
// benefit while being safe approach. For improved readability, the
|
|
|
|
// code that explicitly sets is_null is there, but is commented out.
|
2012-11-21 12:44:18 +00:00
|
|
|
memset(bind_, 0, sizeof(bind_));
|
|
|
|
|
2012-11-23 18:23:21 +00:00
|
|
|
// Set up the structures for the various components of the lease4
|
|
|
|
// structure.
|
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
try {
|
|
|
|
// Address: uint32_t
|
|
|
|
// The address in the Lease structure is an IOAddress object. Convert
|
|
|
|
// this to an integer for storage.
|
|
|
|
addr4_ = static_cast<uint32_t>(lease_->addr_);
|
|
|
|
bind_[0].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
bind_[0].buffer = reinterpret_cast<char*>(&addr4_);
|
|
|
|
bind_[0].is_unsigned = MLM_TRUE;
|
|
|
|
// bind_[0].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-11-21 12:44:18 +00:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
// hwaddr: varbinary(128)
|
|
|
|
// For speed, we avoid copying the data into temporary storage and
|
|
|
|
// instead extract it from the lease structure directly.
|
|
|
|
hwaddr_length_ = lease_->hwaddr_->hwaddr_.size();
|
|
|
|
bind_[1].buffer_type = MYSQL_TYPE_BLOB;
|
|
|
|
bind_[1].buffer = reinterpret_cast<char*>(&(lease_->hwaddr_->hwaddr_[0]));
|
|
|
|
bind_[1].buffer_length = hwaddr_length_;
|
|
|
|
bind_[1].length = &hwaddr_length_;
|
|
|
|
// bind_[1].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-11-21 12:44:18 +00:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
// client_id: varbinary(128)
|
|
|
|
if (lease_->client_id_) {
|
|
|
|
client_id_ = lease_->client_id_->getClientId();
|
|
|
|
client_id_length_ = client_id_.size();
|
|
|
|
bind_[2].buffer_type = MYSQL_TYPE_BLOB;
|
|
|
|
bind_[2].buffer = reinterpret_cast<char*>(&client_id_[0]);
|
|
|
|
bind_[2].buffer_length = client_id_length_;
|
|
|
|
bind_[2].length = &client_id_length_;
|
|
|
|
// bind_[2].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
|
|
|
} else {
|
|
|
|
bind_[2].buffer_type = MYSQL_TYPE_NULL;
|
|
|
|
|
|
|
|
// According to http://dev.mysql.com/doc/refman/5.5/en/
|
|
|
|
// c-api-prepared-statement-data-structures.html, the other
|
|
|
|
// fields doesn't matter if type is set to MYSQL_TYPE_NULL,
|
|
|
|
// but let's set them to some sane values in case earlier versions
|
|
|
|
// didn't have that assumption.
|
|
|
|
client_id_null_ = MLM_TRUE;
|
|
|
|
bind_[2].buffer = NULL;
|
|
|
|
bind_[2].is_null = &client_id_null_;
|
|
|
|
}
|
|
|
|
|
|
|
|
// valid lifetime: unsigned int
|
|
|
|
bind_[3].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
bind_[3].buffer = reinterpret_cast<char*>(&lease_->valid_lft_);
|
|
|
|
bind_[3].is_unsigned = MLM_TRUE;
|
|
|
|
// bind_[3].is_null = &MLM_FALSE; // commented out for performance
|
2013-03-07 15:21:00 +01:00
|
|
|
// reasons, see memset() above
|
2012-11-21 12:44:18 +00:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
// expire: timestamp
|
|
|
|
// The lease structure holds the client last transmission time (cltt_)
|
|
|
|
// For convenience for external tools, this is converted to lease
|
|
|
|
// expiry time (expire). The relationship is given by:
|
|
|
|
//
|
|
|
|
// expire = cltt_ + valid_lft_
|
|
|
|
MySqlLeaseMgr::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_,
|
|
|
|
expire_);
|
|
|
|
bind_[4].buffer_type = MYSQL_TYPE_TIMESTAMP;
|
|
|
|
bind_[4].buffer = reinterpret_cast<char*>(&expire_);
|
|
|
|
bind_[4].buffer_length = sizeof(expire_);
|
|
|
|
// bind_[4].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-11-21 12:44:18 +00:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
// subnet_id: unsigned int
|
|
|
|
// Can use lease_->subnet_id_ directly as it is of type uint32_t.
|
|
|
|
bind_[5].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
bind_[5].buffer = reinterpret_cast<char*>(&lease_->subnet_id_);
|
|
|
|
bind_[5].is_unsigned = MLM_TRUE;
|
|
|
|
// bind_[5].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-11-21 12:44:18 +00:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
// fqdn_fwd: boolean
|
|
|
|
bind_[6].buffer_type = MYSQL_TYPE_TINY;
|
|
|
|
bind_[6].buffer = reinterpret_cast<char*>(&lease_->fqdn_fwd_);
|
|
|
|
bind_[6].is_unsigned = MLM_TRUE;
|
|
|
|
// bind_[6].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-11-21 12:44:18 +00:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
// fqdn_rev: boolean
|
|
|
|
bind_[7].buffer_type = MYSQL_TYPE_TINY;
|
|
|
|
bind_[7].buffer = reinterpret_cast<char*>(&lease_->fqdn_rev_);
|
|
|
|
bind_[7].is_unsigned = MLM_TRUE;
|
|
|
|
// bind_[7].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2013-08-26 17:30:56 +02:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
// hostname: varchar(255)
|
|
|
|
bind_[8].buffer_type = MYSQL_TYPE_VARCHAR;
|
|
|
|
bind_[8].buffer = const_cast<char*>(lease_->hostname_.c_str());
|
|
|
|
bind_[8].buffer_length = lease_->hostname_.length();
|
|
|
|
// bind_[8].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2013-08-26 17:30:56 +02:00
|
|
|
|
2015-09-07 10:47:30 +02:00
|
|
|
// state: uint32_t.
|
|
|
|
bind_[9].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
bind_[9].buffer = reinterpret_cast<char*>(&lease_->state_);
|
|
|
|
bind_[9].is_unsigned = MLM_TRUE;
|
|
|
|
// bind_[9].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2015-03-04 14:50:37 +01:00
|
|
|
// Add the error flags
|
|
|
|
setErrorIndicators(bind_, error_, LEASE_COLUMNS);
|
2013-08-26 17:30:56 +02:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
// .. and check that we have the numbers correct at compile time.
|
2015-09-07 10:47:30 +02:00
|
|
|
BOOST_STATIC_ASSERT(9 < LEASE_COLUMNS);
|
2012-11-30 15:49:42 +00:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
} catch (const std::exception& ex) {
|
|
|
|
isc_throw(DbOperationError,
|
|
|
|
"Could not create bind array from Lease4: "
|
|
|
|
<< lease_->addr_.toText() << ", reason: " << ex.what());
|
|
|
|
}
|
2012-11-30 15:49:42 +00:00
|
|
|
|
2012-11-21 12:44:18 +00:00
|
|
|
// Add the data to the vector. Note the end element is one after the
|
|
|
|
// end of the array.
|
2012-11-30 15:49:42 +00:00
|
|
|
return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
|
2012-11-21 12:44:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Create BIND array to receive data
|
|
|
|
///
|
|
|
|
/// Creates a MYSQL_BIND array to receive Lease4 data from the database.
|
2012-11-23 18:23:21 +00:00
|
|
|
/// After data is successfully received, getLeaseData() can be used to copy
|
2012-11-21 12:44:18 +00:00
|
|
|
/// it to a Lease6 object.
|
|
|
|
///
|
|
|
|
std::vector<MYSQL_BIND> createBindForReceive() {
|
|
|
|
|
2012-11-26 19:17:27 +00:00
|
|
|
// Initialize MYSQL_BIND array.
|
2013-03-07 15:21:00 +01:00
|
|
|
// It sets all fields, including is_null, to zero, so we need to set
|
|
|
|
// is_null only if it should be true. This gives up minor performance
|
|
|
|
// benefit while being safe approach. For improved readability, the
|
|
|
|
// code that explicitly sets is_null is there, but is commented out.
|
2012-11-21 12:44:18 +00:00
|
|
|
memset(bind_, 0, sizeof(bind_));
|
|
|
|
|
|
|
|
// address: uint32_t
|
|
|
|
bind_[0].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
bind_[0].buffer = reinterpret_cast<char*>(&addr4_);
|
2012-11-23 18:23:21 +00:00
|
|
|
bind_[0].is_unsigned = MLM_TRUE;
|
2013-03-07 15:21:00 +01:00
|
|
|
// bind_[0].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-11-21 12:44:18 +00:00
|
|
|
|
|
|
|
// hwaddr: varbinary(20)
|
|
|
|
hwaddr_length_ = sizeof(hwaddr_buffer_);
|
|
|
|
bind_[1].buffer_type = MYSQL_TYPE_BLOB;
|
|
|
|
bind_[1].buffer = reinterpret_cast<char*>(hwaddr_buffer_);
|
|
|
|
bind_[1].buffer_length = hwaddr_length_;
|
|
|
|
bind_[1].length = &hwaddr_length_;
|
2013-03-07 15:21:00 +01:00
|
|
|
// bind_[1].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-11-21 12:44:18 +00:00
|
|
|
|
|
|
|
// client_id: varbinary(128)
|
|
|
|
client_id_length_ = sizeof(client_id_buffer_);
|
|
|
|
bind_[2].buffer_type = MYSQL_TYPE_BLOB;
|
|
|
|
bind_[2].buffer = reinterpret_cast<char*>(client_id_buffer_);
|
|
|
|
bind_[2].buffer_length = client_id_length_;
|
|
|
|
bind_[2].length = &client_id_length_;
|
2013-02-21 16:50:59 +01:00
|
|
|
bind_[2].is_null = &client_id_null_;
|
2013-03-07 15:21:00 +01:00
|
|
|
// bind_[2].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-11-21 12:44:18 +00:00
|
|
|
|
|
|
|
// lease_time: unsigned int
|
|
|
|
bind_[3].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
bind_[3].buffer = reinterpret_cast<char*>(&valid_lifetime_);
|
2012-11-23 18:23:21 +00:00
|
|
|
bind_[3].is_unsigned = MLM_TRUE;
|
2013-03-07 15:21:00 +01:00
|
|
|
// bind_[3].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-11-21 12:44:18 +00:00
|
|
|
|
|
|
|
// expire: timestamp
|
|
|
|
bind_[4].buffer_type = MYSQL_TYPE_TIMESTAMP;
|
|
|
|
bind_[4].buffer = reinterpret_cast<char*>(&expire_);
|
|
|
|
bind_[4].buffer_length = sizeof(expire_);
|
2013-03-07 15:21:00 +01:00
|
|
|
// bind_[4].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-11-21 12:44:18 +00:00
|
|
|
|
|
|
|
// subnet_id: unsigned int
|
|
|
|
bind_[5].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
bind_[5].buffer = reinterpret_cast<char*>(&subnet_id_);
|
2012-11-23 18:23:21 +00:00
|
|
|
bind_[5].is_unsigned = MLM_TRUE;
|
2013-03-07 15:21:00 +01:00
|
|
|
// bind_[5].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-11-21 12:44:18 +00:00
|
|
|
|
2013-08-26 17:30:56 +02:00
|
|
|
// fqdn_fwd: boolean
|
|
|
|
bind_[6].buffer_type = MYSQL_TYPE_TINY;
|
|
|
|
bind_[6].buffer = reinterpret_cast<char*>(&fqdn_fwd_);
|
|
|
|
bind_[6].is_unsigned = MLM_TRUE;
|
|
|
|
// bind_[6].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
|
|
|
|
|
|
|
// fqdn_rev: boolean
|
|
|
|
bind_[7].buffer_type = MYSQL_TYPE_TINY;
|
|
|
|
bind_[7].buffer = reinterpret_cast<char*>(&fqdn_rev_);
|
|
|
|
bind_[7].is_unsigned = MLM_TRUE;
|
|
|
|
// bind_[7].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
|
|
|
|
|
|
|
// hostname: varchar(255)
|
|
|
|
hostname_length_ = sizeof(hostname_buffer_);
|
|
|
|
bind_[8].buffer_type = MYSQL_TYPE_STRING;
|
|
|
|
bind_[8].buffer = reinterpret_cast<char*>(hostname_buffer_);
|
|
|
|
bind_[8].buffer_length = hostname_length_;
|
|
|
|
bind_[8].length = &hostname_length_;
|
|
|
|
// bind_[8].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
|
|
|
|
2015-09-07 10:47:30 +02:00
|
|
|
// state: uint32_t
|
|
|
|
bind_[9].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
bind_[9].buffer = reinterpret_cast<char*>(&state_);
|
|
|
|
bind_[9].is_unsigned = MLM_TRUE;
|
|
|
|
// bind_[9].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
|
|
|
|
2012-11-30 15:49:42 +00:00
|
|
|
// Add the error flags
|
|
|
|
setErrorIndicators(bind_, error_, LEASE_COLUMNS);
|
|
|
|
|
|
|
|
// .. and check that we have the numbers correct at compile time.
|
2015-09-07 10:47:30 +02:00
|
|
|
BOOST_STATIC_ASSERT(9 < LEASE_COLUMNS);
|
2012-11-30 15:49:42 +00:00
|
|
|
|
2012-11-21 12:44:18 +00:00
|
|
|
// Add the data to the vector. Note the end element is one after the
|
|
|
|
// end of the array.
|
2012-11-30 15:49:42 +00:00
|
|
|
return(std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
|
2012-11-21 12:44:18 +00:00
|
|
|
}
|
|
|
|
|
2015-09-07 10:47:30 +02:00
|
|
|
/// @brief Copy Received Data into Lease4 Object
|
2012-11-21 12:44:18 +00:00
|
|
|
///
|
|
|
|
/// Called after the MYSQL_BIND array created by createBindForReceive()
|
2012-11-23 18:23:21 +00:00
|
|
|
/// has been used, this copies data from the internal member variables
|
2015-09-07 10:47:30 +02:00
|
|
|
/// into a Lease4 object.
|
2012-11-21 12:44:18 +00:00
|
|
|
///
|
2012-11-23 18:23:21 +00:00
|
|
|
/// @return Lease4Ptr Pointer to a Lease6 object holding the relevant
|
2012-11-21 12:44:18 +00:00
|
|
|
/// data.
|
|
|
|
Lease4Ptr getLeaseData() {
|
2012-11-23 18:23:21 +00:00
|
|
|
// Convert times received from the database to times for the lease
|
|
|
|
// structure
|
2012-11-21 12:44:18 +00:00
|
|
|
time_t cltt = 0;
|
|
|
|
MySqlLeaseMgr::convertFromDatabaseTime(expire_, valid_lifetime_, cltt);
|
|
|
|
|
2013-02-21 16:50:59 +01:00
|
|
|
if (client_id_null_==MLM_TRUE) {
|
|
|
|
// There's no client-id, so we pass client-id_length_ set to 0
|
|
|
|
client_id_length_ = 0;
|
|
|
|
}
|
|
|
|
|
2013-08-27 13:36:00 +02:00
|
|
|
// Hostname is passed to Lease4 as a string object. We have to create
|
|
|
|
// it from the buffer holding hostname and the buffer length.
|
|
|
|
std::string hostname(hostname_buffer_,
|
|
|
|
hostname_buffer_ + hostname_length_);
|
|
|
|
|
2014-10-21 19:36:53 +02:00
|
|
|
// Recreate the hardware address.
|
|
|
|
HWAddrPtr hwaddr(new HWAddr(hwaddr_buffer_, hwaddr_length_, HTYPE_ETHER));
|
|
|
|
|
2012-12-28 17:43:13 +01:00
|
|
|
// note that T1 and T2 are not stored
|
2015-09-07 10:47:30 +02:00
|
|
|
Lease4Ptr lease(new Lease4(addr4_, hwaddr,
|
2012-11-21 12:44:18 +00:00
|
|
|
client_id_buffer_, client_id_length_,
|
2013-08-27 13:36:00 +02:00
|
|
|
valid_lifetime_, 0, 0, cltt, subnet_id_,
|
2015-09-07 10:47:30 +02:00
|
|
|
fqdn_fwd_, fqdn_rev_, hostname));
|
|
|
|
lease->state_ = state_;
|
|
|
|
return (lease);
|
2012-11-21 12:44:18 +00:00
|
|
|
}
|
|
|
|
|
2012-11-30 15:49:42 +00:00
|
|
|
/// @brief Return columns in error
|
|
|
|
///
|
|
|
|
/// If an error is returned from a fetch (in particular, a truncated
|
|
|
|
/// status), this method can be called to get the names of the fields in
|
|
|
|
/// error. It returns a string comprising the names of the fields
|
|
|
|
/// separated by commas. In the case of there being no error indicators
|
|
|
|
/// set, it returns the string "(None)".
|
|
|
|
///
|
|
|
|
/// @return Comma-separated list of columns in error, or the string
|
|
|
|
/// "(None)".
|
|
|
|
std::string getErrorColumns() {
|
|
|
|
return (getColumnsInError(error_, columns_, LEASE_COLUMNS));
|
|
|
|
}
|
|
|
|
|
2012-11-21 12:44:18 +00:00
|
|
|
private:
|
2012-11-30 15:49:42 +00:00
|
|
|
|
2012-11-21 12:44:18 +00:00
|
|
|
// Note: All array lengths are equal to the corresponding variable in the
|
2012-11-23 18:23:21 +00:00
|
|
|
// schema.
|
|
|
|
// Note: Arrays are declared fixed length for speed of creation
|
2012-11-21 12:44:18 +00:00
|
|
|
uint32_t addr4_; ///< IPv4 address
|
2012-11-30 15:49:42 +00:00
|
|
|
MYSQL_BIND bind_[LEASE_COLUMNS]; ///< Bind array
|
|
|
|
std::string columns_[LEASE_COLUMNS];///< Column names
|
|
|
|
my_bool error_[LEASE_COLUMNS]; ///< Error array
|
2012-11-21 12:44:18 +00:00
|
|
|
std::vector<uint8_t> hwaddr_; ///< Hardware address
|
2013-03-15 14:19:42 -04:00
|
|
|
uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
|
2012-11-23 18:23:21 +00:00
|
|
|
///< Hardware address buffer
|
2012-11-21 12:44:18 +00:00
|
|
|
unsigned long hwaddr_length_; ///< Hardware address length
|
|
|
|
std::vector<uint8_t> client_id_; ///< Client identification
|
2012-12-04 11:32:08 +00:00
|
|
|
uint8_t client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
|
2012-11-23 18:23:21 +00:00
|
|
|
///< Client ID buffer
|
2012-11-21 12:44:18 +00:00
|
|
|
unsigned long client_id_length_; ///< Client ID address length
|
2013-02-21 16:50:59 +01:00
|
|
|
my_bool client_id_null_; ///< Is Client ID null?
|
|
|
|
|
2012-11-21 12:44:18 +00:00
|
|
|
MYSQL_TIME expire_; ///< Lease expiry time
|
|
|
|
Lease4Ptr lease_; ///< Pointer to lease object
|
|
|
|
uint32_t subnet_id_; ///< Subnet identification
|
2012-11-21 19:38:26 +00:00
|
|
|
uint32_t valid_lifetime_; ///< Lease time
|
2013-08-26 17:30:56 +02:00
|
|
|
|
|
|
|
my_bool fqdn_fwd_; ///< Has forward DNS update been
|
|
|
|
///< performed
|
|
|
|
my_bool fqdn_rev_; ///< Has reverse DNS update been
|
|
|
|
///< performed
|
|
|
|
char hostname_buffer_[HOSTNAME_MAX_LEN];
|
|
|
|
///< Client hostname
|
|
|
|
unsigned long hostname_length_; ///< Client hostname length
|
2015-09-07 10:47:30 +02:00
|
|
|
uint32_t state_; ///< Lease state
|
2013-08-26 17:30:56 +02:00
|
|
|
|
2012-11-21 12:44:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-10-22 13:01:40 +01:00
|
|
|
/// @brief Exchange MySQL and Lease6 Data
|
2012-10-22 10:49:51 +01:00
|
|
|
///
|
2012-10-24 19:18:33 +01:00
|
|
|
/// On any MySQL operation, arrays of MYSQL_BIND structures must be built to
|
|
|
|
/// describe the parameters in the prepared statements. Where information is
|
2012-10-29 19:19:36 +00:00
|
|
|
/// inserted or retrieved - INSERT, UPDATE, SELECT - a large amount of that
|
2012-11-23 18:23:21 +00:00
|
|
|
/// structure is identical. This class handles the creation of that array.
|
2012-10-22 10:49:51 +01:00
|
|
|
///
|
2012-10-22 13:01:40 +01:00
|
|
|
/// Owing to the MySQL API, the process requires some intermediate variables
|
2012-11-26 19:17:27 +00:00
|
|
|
/// to hold things like data length etc. This object holds those variables.
|
2012-11-08 12:14:10 +00:00
|
|
|
///
|
|
|
|
/// @note There are no unit tests for this class. It is tested indirectly
|
|
|
|
/// in all MySqlLeaseMgr::xxx6() calls where it is used.
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2012-11-30 15:49:42 +00:00
|
|
|
class MySqlLease6Exchange : public MySqlLeaseExchange {
|
2012-12-07 20:25:25 +00:00
|
|
|
/// @brief Set number of database columns for this lease structure
|
2015-09-07 10:47:30 +02:00
|
|
|
static const size_t LEASE_COLUMNS = 16;
|
2012-11-30 15:49:42 +00:00
|
|
|
|
2012-10-22 10:49:51 +01:00
|
|
|
public:
|
|
|
|
/// @brief Constructor
|
2012-11-03 18:26:57 +00:00
|
|
|
///
|
2012-11-23 18:23:21 +00:00
|
|
|
/// The initialization of the variables here is nonly to satisfy cppcheck -
|
|
|
|
/// all variables are initialized/set in the methods before they are used.
|
2013-08-30 16:18:40 +02:00
|
|
|
MySqlLease6Exchange() : addr6_length_(0), duid_length_(0),
|
2015-06-27 09:12:29 +02:00
|
|
|
iaid_(0), lease_type_(0), prefixlen_(0),
|
2015-06-24 13:41:20 +02:00
|
|
|
pref_lifetime_(0), subnet_id_(0), valid_lifetime_(0),
|
2013-08-30 16:18:40 +02:00
|
|
|
fqdn_fwd_(false), fqdn_rev_(false),
|
2014-11-06 19:36:46 +01:00
|
|
|
hostname_length_(0), hwaddr_length_(0),
|
2015-09-07 10:47:30 +02:00
|
|
|
hwaddr_null_(MLM_FALSE), hwtype_(0), hwaddr_source_(0),
|
|
|
|
state_(0) {
|
2012-11-03 18:26:57 +00:00
|
|
|
memset(addr6_buffer_, 0, sizeof(addr6_buffer_));
|
|
|
|
memset(duid_buffer_, 0, sizeof(duid_buffer_));
|
2013-08-30 16:18:40 +02:00
|
|
|
memset(hostname_buffer_, 0, sizeof(hostname_buffer_));
|
2014-11-06 19:36:46 +01:00
|
|
|
memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_));
|
2012-11-30 15:49:42 +00:00
|
|
|
std::fill(&error_[0], &error_[LEASE_COLUMNS], MLM_FALSE);
|
2013-02-25 17:07:58 +01:00
|
|
|
|
2012-11-30 15:49:42 +00:00
|
|
|
// Set the column names (for error messages)
|
2013-08-26 17:30:56 +02:00
|
|
|
columns_[0] = "address";
|
|
|
|
columns_[1] = "duid";
|
|
|
|
columns_[2] = "valid_lifetime";
|
|
|
|
columns_[3] = "expire";
|
|
|
|
columns_[4] = "subnet_id";
|
|
|
|
columns_[5] = "pref_lifetime";
|
|
|
|
columns_[6] = "lease_type";
|
|
|
|
columns_[7] = "iaid";
|
|
|
|
columns_[8] = "prefix_len";
|
|
|
|
columns_[9] = "fqdn_fwd";
|
|
|
|
columns_[10] = "fqdn_rev";
|
|
|
|
columns_[11] = "hostname";
|
2014-11-06 19:36:46 +01:00
|
|
|
columns_[12] = "hwaddr";
|
|
|
|
columns_[13] = "hwtype";
|
|
|
|
columns_[14] = "hwaddr_source";
|
2015-09-07 10:47:30 +02:00
|
|
|
columns_[15] = "state";
|
|
|
|
BOOST_STATIC_ASSERT(15 < LEASE_COLUMNS);
|
2012-10-22 10:49:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Create MYSQL_BIND objects for Lease6 Pointer
|
|
|
|
///
|
2012-11-23 18:23:21 +00:00
|
|
|
/// Fills in the MYSQL_BIND array for sending data in the Lease4 object to
|
|
|
|
/// the database.
|
2012-10-22 10:49:51 +01:00
|
|
|
///
|
2012-11-06 12:58:10 +00:00
|
|
|
/// @param lease Lease object to be added to the database.
|
|
|
|
///
|
|
|
|
/// @return Vector of MySQL BIND objects representing the data to be added.
|
|
|
|
std::vector<MYSQL_BIND> createBindForSend(const Lease6Ptr& lease) {
|
2012-10-22 10:49:51 +01:00
|
|
|
// Store lease object to ensure it remains valid.
|
|
|
|
lease_ = lease;
|
|
|
|
|
2012-10-29 19:19:36 +00:00
|
|
|
// Ensure bind_ array clear for constructing the MYSQL_BIND structures
|
|
|
|
// for this lease.
|
2013-03-07 15:21:00 +01:00
|
|
|
// It sets all fields, including is_null, to zero, so we need to set
|
|
|
|
// is_null only if it should be true. This gives up minor performance
|
|
|
|
// benefit while being safe approach. For improved readability, the
|
|
|
|
// code that explicitly sets is_null is there, but is commented out.
|
2012-10-22 10:49:51 +01:00
|
|
|
memset(bind_, 0, sizeof(bind_));
|
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
try {
|
|
|
|
// address: varchar(39)
|
|
|
|
addr6_ = lease_->addr_.toText();
|
|
|
|
addr6_length_ = addr6_.size();
|
|
|
|
|
|
|
|
// In the following statement, the string is being read. However, the
|
|
|
|
// MySQL C interface does not use "const", so the "buffer" element
|
|
|
|
// is declared as "char*" instead of "const char*". To resolve this,
|
|
|
|
// the "const" is discarded. (Note that the address of addr6_.c_str()
|
|
|
|
// is guaranteed to be valid until the next non-const operation on
|
|
|
|
// addr6_.)
|
|
|
|
//
|
|
|
|
// The const_cast could be avoided by copying the string to a writeable
|
|
|
|
// buffer and storing the address of that in the "buffer" element.
|
|
|
|
// However, this introduces a copy operation (with additional overhead)
|
|
|
|
// purely to get round the structures introduced by design of the
|
|
|
|
// MySQL interface (which uses the area pointed to by "buffer" as input
|
|
|
|
// when specifying query parameters and as output when retrieving data).
|
|
|
|
// For that reason, "const_cast" has been used.
|
|
|
|
bind_[0].buffer_type = MYSQL_TYPE_STRING;
|
|
|
|
bind_[0].buffer = const_cast<char*>(addr6_.c_str());
|
|
|
|
bind_[0].buffer_length = addr6_length_;
|
|
|
|
bind_[0].length = &addr6_length_;
|
|
|
|
// bind_[0].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-10-22 10:49:51 +01:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
// duid: varchar(128)
|
|
|
|
if (!lease_->duid_) {
|
|
|
|
isc_throw(DbOperationError, "lease6 for address " << addr6_
|
|
|
|
<< " is missing mandatory client-id.");
|
|
|
|
}
|
|
|
|
duid_ = lease_->duid_->getDuid();
|
|
|
|
duid_length_ = duid_.size();
|
|
|
|
|
|
|
|
bind_[1].buffer_type = MYSQL_TYPE_BLOB;
|
|
|
|
bind_[1].buffer = reinterpret_cast<char*>(&(duid_[0]));
|
|
|
|
bind_[1].buffer_length = duid_length_;
|
|
|
|
bind_[1].length = &duid_length_;
|
|
|
|
// bind_[1].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-10-22 10:49:51 +01:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
// valid lifetime: unsigned int
|
|
|
|
bind_[2].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
bind_[2].buffer = reinterpret_cast<char*>(&lease_->valid_lft_);
|
|
|
|
bind_[2].is_unsigned = MLM_TRUE;
|
|
|
|
// bind_[2].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-10-22 10:49:51 +01:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
// expire: timestamp
|
|
|
|
// The lease structure holds the client last transmission time (cltt_)
|
|
|
|
// For convenience for external tools, this is converted to lease
|
|
|
|
/// expiry time (expire). The relationship is given by:
|
|
|
|
//
|
|
|
|
// expire = cltt_ + valid_lft_
|
|
|
|
//
|
|
|
|
MySqlLeaseMgr::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_,
|
|
|
|
expire_);
|
|
|
|
bind_[3].buffer_type = MYSQL_TYPE_TIMESTAMP;
|
|
|
|
bind_[3].buffer = reinterpret_cast<char*>(&expire_);
|
|
|
|
bind_[3].buffer_length = sizeof(expire_);
|
|
|
|
// bind_[3].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-10-22 10:49:51 +01:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
// subnet_id: unsigned int
|
|
|
|
// Can use lease_->subnet_id_ directly as it is of type uint32_t.
|
|
|
|
bind_[4].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
bind_[4].buffer = reinterpret_cast<char*>(&lease_->subnet_id_);
|
|
|
|
bind_[4].is_unsigned = MLM_TRUE;
|
|
|
|
// bind_[4].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-10-22 10:49:51 +01:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
// pref_lifetime: unsigned int
|
|
|
|
// Can use lease_->preferred_lft_ directly as it is of type uint32_t.
|
|
|
|
bind_[5].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
bind_[5].buffer = reinterpret_cast<char*>(&lease_->preferred_lft_);
|
|
|
|
bind_[5].is_unsigned = MLM_TRUE;
|
|
|
|
// bind_[5].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-10-22 10:49:51 +01:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
// lease_type: tinyint
|
|
|
|
// Must convert to uint8_t as lease_->type_ is a LeaseType variable.
|
|
|
|
lease_type_ = lease_->type_;
|
|
|
|
bind_[6].buffer_type = MYSQL_TYPE_TINY;
|
|
|
|
bind_[6].buffer = reinterpret_cast<char*>(&lease_type_);
|
|
|
|
bind_[6].is_unsigned = MLM_TRUE;
|
|
|
|
// bind_[6].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-10-22 10:49:51 +01:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
// iaid: unsigned int
|
|
|
|
// Can use lease_->iaid_ directly as it is of type uint32_t.
|
|
|
|
bind_[7].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
bind_[7].buffer = reinterpret_cast<char*>(&lease_->iaid_);
|
|
|
|
bind_[7].is_unsigned = MLM_TRUE;
|
|
|
|
// bind_[7].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-10-22 10:49:51 +01:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
// prefix_len: unsigned tinyint
|
|
|
|
// Can use lease_->prefixlen_ directly as it is uint32_t.
|
|
|
|
bind_[8].buffer_type = MYSQL_TYPE_TINY;
|
|
|
|
bind_[8].buffer = reinterpret_cast<char*>(&lease_->prefixlen_);
|
|
|
|
bind_[8].is_unsigned = MLM_TRUE;
|
|
|
|
// bind_[8].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-10-22 10:49:51 +01:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
// fqdn_fwd: boolean
|
|
|
|
bind_[9].buffer_type = MYSQL_TYPE_TINY;
|
|
|
|
bind_[9].buffer = reinterpret_cast<char*>(&lease_->fqdn_fwd_);
|
|
|
|
bind_[9].is_unsigned = MLM_TRUE;
|
|
|
|
// bind_[7].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-10-22 10:49:51 +01:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
// fqdn_rev: boolean
|
|
|
|
bind_[10].buffer_type = MYSQL_TYPE_TINY;
|
|
|
|
bind_[10].buffer = reinterpret_cast<char*>(&lease_->fqdn_rev_);
|
|
|
|
bind_[10].is_unsigned = MLM_TRUE;
|
|
|
|
// bind_[10].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
|
|
|
|
|
|
|
// hostname: varchar(255)
|
|
|
|
bind_[11].buffer_type = MYSQL_TYPE_VARCHAR;
|
|
|
|
bind_[11].buffer = const_cast<char*>(lease_->hostname_.c_str());
|
|
|
|
bind_[11].buffer_length = lease_->hostname_.length();
|
|
|
|
// bind_[11].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
|
|
|
|
|
|
|
// hwaddr: varbinary(20) - hardware/MAC address
|
|
|
|
HWAddrPtr hwaddr = lease_->hwaddr_;
|
|
|
|
if (hwaddr) {
|
|
|
|
hwaddr_ = hwaddr->hwaddr_;
|
|
|
|
hwaddr_length_ = hwaddr->hwaddr_.size();
|
|
|
|
|
|
|
|
bind_[12].buffer_type = MYSQL_TYPE_BLOB;
|
|
|
|
bind_[12].buffer = reinterpret_cast<char*>(&(hwaddr_[0]));
|
|
|
|
bind_[12].buffer_length = hwaddr_length_;
|
|
|
|
bind_[12].length = &hwaddr_length_;
|
|
|
|
} else {
|
|
|
|
bind_[12].buffer_type = MYSQL_TYPE_NULL;
|
|
|
|
|
|
|
|
// According to http://dev.mysql.com/doc/refman/5.5/en/
|
|
|
|
// c-api-prepared-statement-data-structures.html, the other
|
|
|
|
// fields doesn't matter if type is set to MYSQL_TYPE_NULL,
|
|
|
|
// but let's set them to some sane values in case earlier versions
|
|
|
|
// didn't have that assumption.
|
|
|
|
hwaddr_null_ = MLM_TRUE;
|
|
|
|
bind_[12].buffer = NULL;
|
|
|
|
bind_[12].is_null = &hwaddr_null_;
|
|
|
|
}
|
2013-08-26 17:30:56 +02:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
// hwtype
|
|
|
|
if (hwaddr) {
|
|
|
|
hwtype_ = lease->hwaddr_->htype_;
|
|
|
|
bind_[13].buffer_type = MYSQL_TYPE_SHORT;
|
|
|
|
bind_[13].buffer = reinterpret_cast<char*>(&hwtype_);
|
|
|
|
bind_[13].is_unsigned = MLM_TRUE;
|
|
|
|
} else {
|
|
|
|
hwtype_ = 0;
|
|
|
|
bind_[13].buffer_type = MYSQL_TYPE_NULL;
|
|
|
|
// According to http://dev.mysql.com/doc/refman/5.5/en/
|
|
|
|
// c-api-prepared-statement-data-structures.html, the other
|
|
|
|
// fields doesn't matter if type is set to MYSQL_TYPE_NULL,
|
|
|
|
// but let's set them to some sane values in case earlier versions
|
|
|
|
// didn't have that assumption.
|
|
|
|
hwaddr_null_ = MLM_TRUE;
|
|
|
|
bind_[13].buffer = NULL;
|
|
|
|
bind_[13].is_null = &hwaddr_null_;
|
|
|
|
}
|
2013-08-26 17:30:56 +02:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
/// Hardware source
|
|
|
|
if (hwaddr) {
|
|
|
|
hwaddr_source_ = lease->hwaddr_->source_;
|
|
|
|
bind_[14].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
bind_[14].buffer = reinterpret_cast<char*>(&hwaddr_source_);
|
|
|
|
bind_[14].is_unsigned = MLM_TRUE;
|
|
|
|
} else {
|
|
|
|
hwaddr_source_ = 0;
|
|
|
|
|
|
|
|
bind_[14].buffer_type = MYSQL_TYPE_NULL;
|
|
|
|
// According to http://dev.mysql.com/doc/refman/5.5/en/
|
|
|
|
// c-api-prepared-statement-data-structures.html, the other
|
|
|
|
// fields doesn't matter if type is set to MYSQL_TYPE_NULL,
|
|
|
|
// but let's set them to some sane values in case earlier versions
|
|
|
|
// didn't have that assumption.
|
|
|
|
hwaddr_null_ = MLM_TRUE;
|
|
|
|
bind_[14].buffer = NULL;
|
|
|
|
bind_[14].is_null = &hwaddr_null_;
|
|
|
|
}
|
2013-08-26 17:30:56 +02:00
|
|
|
|
2015-09-07 10:47:30 +02:00
|
|
|
// state: uint32_t
|
|
|
|
bind_[15].buffer_type = MYSQL_TYPE_LONG;
|
2015-09-07 13:29:17 +02:00
|
|
|
bind_[15].buffer = reinterpret_cast<char*>(&lease_->state_);
|
2015-09-07 10:47:30 +02:00
|
|
|
bind_[15].is_unsigned = MLM_TRUE;
|
|
|
|
// bind_[15].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
// Add the error flags
|
|
|
|
setErrorIndicators(bind_, error_, LEASE_COLUMNS);
|
2014-11-06 19:36:46 +01:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
// .. and check that we have the numbers correct at compile time.
|
|
|
|
BOOST_STATIC_ASSERT(14 < LEASE_COLUMNS);
|
2014-11-06 19:36:46 +01:00
|
|
|
|
2015-03-04 14:50:37 +01:00
|
|
|
} catch (const std::exception& ex) {
|
|
|
|
isc_throw(DbOperationError,
|
|
|
|
"Could not create bind array from Lease6: "
|
|
|
|
<< lease_->addr_.toText() << ", reason: " << ex.what());
|
2014-11-06 19:36:46 +01:00
|
|
|
}
|
|
|
|
|
2012-10-29 19:19:36 +00:00
|
|
|
// Add the data to the vector. Note the end element is one after the
|
|
|
|
// end of the array.
|
2012-11-30 15:49:42 +00:00
|
|
|
return (std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
|
2012-10-22 10:49:51 +01:00
|
|
|
}
|
|
|
|
|
2012-10-22 13:01:40 +01:00
|
|
|
/// @brief Create BIND array to receive data
|
|
|
|
///
|
|
|
|
/// Creates a MYSQL_BIND array to receive Lease6 data from the database.
|
|
|
|
/// After data is successfully received, getLeaseData() is used to copy
|
|
|
|
/// it to a Lease6 object.
|
|
|
|
///
|
2012-11-23 18:23:21 +00:00
|
|
|
/// @return Vector of MySQL BIND objects passed to the MySQL data retrieval
|
|
|
|
/// functions.
|
2012-11-06 12:58:10 +00:00
|
|
|
std::vector<MYSQL_BIND> createBindForReceive() {
|
2012-10-29 19:19:36 +00:00
|
|
|
|
2012-11-26 19:17:27 +00:00
|
|
|
// Initialize MYSQL_BIND array.
|
2013-03-07 15:21:00 +01:00
|
|
|
// It sets all fields, including is_null, to zero, so we need to set
|
|
|
|
// is_null only if it should be true. This gives up minor performance
|
|
|
|
// benefit while being safe approach. For improved readability, the
|
|
|
|
// code that explicitly sets is_null is there, but is commented out.
|
2012-10-22 13:01:40 +01:00
|
|
|
memset(bind_, 0, sizeof(bind_));
|
|
|
|
|
2012-11-30 15:49:42 +00:00
|
|
|
// address: varchar(39)
|
2012-10-22 13:01:40 +01:00
|
|
|
// A Lease6_ address has a maximum of 39 characters. The array is
|
2012-11-30 15:49:42 +00:00
|
|
|
// one byte longer than this to guarantee that we can always null
|
|
|
|
// terminate it whatever is returned.
|
2012-10-22 13:01:40 +01:00
|
|
|
addr6_length_ = sizeof(addr6_buffer_) - 1;
|
|
|
|
bind_[0].buffer_type = MYSQL_TYPE_STRING;
|
|
|
|
bind_[0].buffer = addr6_buffer_;
|
|
|
|
bind_[0].buffer_length = addr6_length_;
|
|
|
|
bind_[0].length = &addr6_length_;
|
2013-03-07 15:21:00 +01:00
|
|
|
// bind_[0].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-10-22 13:01:40 +01:00
|
|
|
|
|
|
|
// client_id: varbinary(128)
|
2012-10-24 14:27:43 +01:00
|
|
|
duid_length_ = sizeof(duid_buffer_);
|
2012-10-24 21:28:24 +01:00
|
|
|
bind_[1].buffer_type = MYSQL_TYPE_BLOB;
|
|
|
|
bind_[1].buffer = reinterpret_cast<char*>(duid_buffer_);
|
|
|
|
bind_[1].buffer_length = duid_length_;
|
|
|
|
bind_[1].length = &duid_length_;
|
2013-03-07 15:21:00 +01:00
|
|
|
// bind_[1].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-10-22 13:01:40 +01:00
|
|
|
|
|
|
|
// lease_time: unsigned int
|
2012-10-24 21:28:24 +01:00
|
|
|
bind_[2].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
bind_[2].buffer = reinterpret_cast<char*>(&valid_lifetime_);
|
2012-11-23 18:23:21 +00:00
|
|
|
bind_[2].is_unsigned = MLM_TRUE;
|
2013-03-07 15:21:00 +01:00
|
|
|
// bind_[2].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-10-22 13:01:40 +01:00
|
|
|
|
|
|
|
// expire: timestamp
|
2012-10-24 21:28:24 +01:00
|
|
|
bind_[3].buffer_type = MYSQL_TYPE_TIMESTAMP;
|
|
|
|
bind_[3].buffer = reinterpret_cast<char*>(&expire_);
|
|
|
|
bind_[3].buffer_length = sizeof(expire_);
|
2013-03-07 15:21:00 +01:00
|
|
|
// bind_[3].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-10-22 13:01:40 +01:00
|
|
|
|
|
|
|
// subnet_id: unsigned int
|
2012-10-24 21:28:24 +01:00
|
|
|
bind_[4].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
bind_[4].buffer = reinterpret_cast<char*>(&subnet_id_);
|
2012-11-23 18:23:21 +00:00
|
|
|
bind_[4].is_unsigned = MLM_TRUE;
|
2013-03-07 15:21:00 +01:00
|
|
|
// bind_[4].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-10-24 21:28:24 +01:00
|
|
|
|
|
|
|
// pref_lifetime: unsigned int
|
2012-10-22 13:01:40 +01:00
|
|
|
bind_[5].buffer_type = MYSQL_TYPE_LONG;
|
2012-10-24 21:28:24 +01:00
|
|
|
bind_[5].buffer = reinterpret_cast<char*>(&pref_lifetime_);
|
2012-11-23 18:23:21 +00:00
|
|
|
bind_[5].is_unsigned = MLM_TRUE;
|
2013-03-07 15:21:00 +01:00
|
|
|
// bind_[5].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-10-22 13:01:40 +01:00
|
|
|
|
2012-10-24 21:28:24 +01:00
|
|
|
// lease_type: tinyint
|
|
|
|
bind_[6].buffer_type = MYSQL_TYPE_TINY;
|
|
|
|
bind_[6].buffer = reinterpret_cast<char*>(&lease_type_);
|
2012-11-23 18:23:21 +00:00
|
|
|
bind_[6].is_unsigned = MLM_TRUE;
|
2013-03-07 15:21:00 +01:00
|
|
|
// bind_[6].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-10-22 13:01:40 +01:00
|
|
|
|
2012-10-24 21:28:24 +01:00
|
|
|
// iaid: unsigned int
|
|
|
|
bind_[7].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
bind_[7].buffer = reinterpret_cast<char*>(&iaid_);
|
2012-11-23 18:23:21 +00:00
|
|
|
bind_[7].is_unsigned = MLM_TRUE;
|
2013-03-07 15:21:00 +01:00
|
|
|
// bind_[7].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2012-10-22 13:01:40 +01:00
|
|
|
// prefix_len: unsigned tinyint
|
2012-10-24 21:28:24 +01:00
|
|
|
bind_[8].buffer_type = MYSQL_TYPE_TINY;
|
|
|
|
bind_[8].buffer = reinterpret_cast<char*>(&prefixlen_);
|
2012-11-23 18:23:21 +00:00
|
|
|
bind_[8].is_unsigned = MLM_TRUE;
|
2013-03-07 15:21:00 +01:00
|
|
|
// bind_[8].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-10-22 13:01:40 +01:00
|
|
|
|
2013-08-26 17:30:56 +02:00
|
|
|
// fqdn_fwd: boolean
|
|
|
|
bind_[9].buffer_type = MYSQL_TYPE_TINY;
|
|
|
|
bind_[9].buffer = reinterpret_cast<char*>(&fqdn_fwd_);
|
|
|
|
bind_[9].is_unsigned = MLM_TRUE;
|
|
|
|
// bind_[9].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
|
|
|
|
|
|
|
// fqdn_rev: boolean
|
|
|
|
bind_[10].buffer_type = MYSQL_TYPE_TINY;
|
|
|
|
bind_[10].buffer = reinterpret_cast<char*>(&fqdn_rev_);
|
|
|
|
bind_[10].is_unsigned = MLM_TRUE;
|
|
|
|
// bind_[10].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
|
|
|
|
|
|
|
// hostname: varchar(255)
|
|
|
|
hostname_length_ = sizeof(hostname_buffer_);
|
|
|
|
bind_[11].buffer_type = MYSQL_TYPE_STRING;
|
|
|
|
bind_[11].buffer = reinterpret_cast<char*>(hostname_buffer_);
|
|
|
|
bind_[11].buffer_length = hostname_length_;
|
|
|
|
bind_[11].length = &hostname_length_;
|
|
|
|
// bind_[11].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
|
|
|
|
2014-11-06 19:36:46 +01:00
|
|
|
// hardware address
|
|
|
|
// hwaddr: varbinary(20)
|
|
|
|
hwaddr_null_ = MLM_FALSE;
|
|
|
|
hwaddr_length_ = sizeof(hwaddr_buffer_);
|
|
|
|
bind_[12].buffer_type = MYSQL_TYPE_BLOB;
|
|
|
|
bind_[12].buffer = reinterpret_cast<char*>(hwaddr_buffer_);
|
|
|
|
bind_[12].buffer_length = hwaddr_length_;
|
|
|
|
bind_[12].length = &hwaddr_length_;
|
|
|
|
bind_[12].is_null = &hwaddr_null_;
|
|
|
|
|
|
|
|
// hardware type: unsigned short int (16 bits)
|
|
|
|
bind_[13].buffer_type = MYSQL_TYPE_SHORT;
|
|
|
|
bind_[13].buffer = reinterpret_cast<char*>(&hwtype_);
|
|
|
|
bind_[13].is_unsigned = MLM_TRUE;
|
|
|
|
|
|
|
|
// hardware source: unsigned int (32 bits)
|
|
|
|
bind_[14].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
bind_[14].buffer = reinterpret_cast<char*>(&hwaddr_source_);
|
|
|
|
bind_[14].is_unsigned = MLM_TRUE;
|
|
|
|
|
2015-09-07 10:47:30 +02:00
|
|
|
// state: uint32_t
|
|
|
|
bind_[15].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
bind_[15].buffer = reinterpret_cast<char*>(&state_);
|
|
|
|
bind_[15].is_unsigned = MLM_TRUE;
|
|
|
|
// bind_[15].is_null = &MLM_FALSE; // commented out for performance
|
|
|
|
// reasons, see memset() above
|
2012-11-30 15:49:42 +00:00
|
|
|
// Add the error flags
|
|
|
|
setErrorIndicators(bind_, error_, LEASE_COLUMNS);
|
|
|
|
|
|
|
|
// .. and check that we have the numbers correct at compile time.
|
2015-09-07 10:47:30 +02:00
|
|
|
BOOST_STATIC_ASSERT(15 < LEASE_COLUMNS);
|
2012-11-30 15:49:42 +00:00
|
|
|
|
2012-10-29 19:19:36 +00:00
|
|
|
// Add the data to the vector. Note the end element is one after the
|
|
|
|
// end of the array.
|
2012-11-30 15:49:42 +00:00
|
|
|
return(std::vector<MYSQL_BIND>(&bind_[0], &bind_[LEASE_COLUMNS]));
|
2012-10-22 13:01:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @brief Copy Received Data into Lease6 Object
|
|
|
|
///
|
|
|
|
/// Called after the MYSQL_BIND array created by createBindForReceive()
|
2012-11-26 19:17:27 +00:00
|
|
|
/// has been used, this copies data from the internal member variables
|
2012-10-22 13:01:40 +01:00
|
|
|
/// into a Lease6 object.
|
|
|
|
///
|
|
|
|
/// @return Lease6Ptr Pointer to a Lease6 object holding the relevant
|
|
|
|
/// data.
|
|
|
|
///
|
2012-11-08 12:14:10 +00:00
|
|
|
/// @throw isc::BadValue Unable to convert Lease Type value in database
|
2012-10-22 13:01:40 +01:00
|
|
|
Lease6Ptr getLeaseData() {
|
2012-10-24 15:36:54 +01:00
|
|
|
// The address buffer is declared larger than the buffer size passed
|
|
|
|
// to the access function so that we can always append a null byte.
|
2012-11-23 18:23:21 +00:00
|
|
|
// Create the IOAddress object corresponding to the received data.
|
2012-10-22 13:01:40 +01:00
|
|
|
addr6_buffer_[addr6_length_] = '\0';
|
|
|
|
std::string address = addr6_buffer_;
|
2012-11-23 18:23:21 +00:00
|
|
|
isc::asiolink::IOAddress addr(address);
|
2012-10-22 13:01:40 +01:00
|
|
|
|
2012-11-23 18:23:21 +00:00
|
|
|
// Set the lease type in a variable of the appropriate data type, which
|
2012-11-26 19:17:27 +00:00
|
|
|
// has been initialized with an arbitrary (but valid) value.
|
2013-09-18 15:44:48 +02:00
|
|
|
Lease::Type type = Lease::TYPE_NA;
|
2012-10-22 13:01:40 +01:00
|
|
|
switch (lease_type_) {
|
2013-09-18 15:44:48 +02:00
|
|
|
case Lease::TYPE_NA:
|
|
|
|
type = Lease::TYPE_NA;
|
2012-10-22 13:01:40 +01:00
|
|
|
break;
|
|
|
|
|
2013-09-18 15:44:48 +02:00
|
|
|
case Lease::TYPE_TA:
|
|
|
|
type = Lease::TYPE_TA;
|
2012-10-22 13:01:40 +01:00
|
|
|
break;
|
|
|
|
|
2013-09-18 15:44:48 +02:00
|
|
|
case Lease::TYPE_PD:
|
|
|
|
type = Lease::TYPE_PD;
|
2012-10-22 13:01:40 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2012-10-24 19:18:33 +01:00
|
|
|
isc_throw(BadValue, "invalid lease type returned (" <<
|
2013-09-06 14:51:59 +02:00
|
|
|
static_cast<int>(lease_type_) << ") for lease with "
|
|
|
|
<< "address " << address << ". Only 0, 1, or 2 are "
|
|
|
|
<< "allowed.");
|
2012-10-22 13:01:40 +01:00
|
|
|
}
|
2012-11-23 18:23:21 +00:00
|
|
|
|
|
|
|
// Set up DUID,
|
|
|
|
DuidPtr duid_ptr(new DUID(duid_buffer_, duid_length_));
|
|
|
|
|
2013-08-27 13:36:00 +02:00
|
|
|
// Hostname is passed to Lease6 as a string object, so we have to
|
|
|
|
// create it from the hostname buffer and length.
|
|
|
|
std::string hostname(hostname_buffer_,
|
|
|
|
hostname_buffer_ + hostname_length_);
|
|
|
|
|
2014-11-06 19:36:46 +01:00
|
|
|
/// Set hardware address if it was set
|
2014-10-21 19:36:53 +02:00
|
|
|
HWAddrPtr hwaddr;
|
2014-11-06 19:36:46 +01:00
|
|
|
if (hwaddr_null_ == MLM_FALSE) {
|
|
|
|
hwaddr.reset(new HWAddr(hwaddr_buffer_, hwaddr_length_, hwtype_));
|
|
|
|
hwaddr->source_ = hwaddr_source_;
|
|
|
|
}
|
2014-10-21 19:36:53 +02:00
|
|
|
|
2012-11-23 18:23:21 +00:00
|
|
|
// Create the lease and set the cltt (after converting from the
|
|
|
|
// expire time retrieved from the database).
|
|
|
|
Lease6Ptr result(new Lease6(type, addr, duid_ptr, iaid_,
|
|
|
|
pref_lifetime_, valid_lifetime_, 0, 0,
|
2013-08-27 13:36:00 +02:00
|
|
|
subnet_id_, fqdn_fwd_, fqdn_rev_,
|
2014-10-21 19:36:53 +02:00
|
|
|
hostname, hwaddr, prefixlen_));
|
2012-11-23 18:23:21 +00:00
|
|
|
time_t cltt = 0;
|
|
|
|
MySqlLeaseMgr::convertFromDatabaseTime(expire_, valid_lifetime_, cltt);
|
|
|
|
result->cltt_ = cltt;
|
2012-10-22 13:01:40 +01:00
|
|
|
|
2015-09-07 10:47:30 +02:00
|
|
|
// Set state.
|
|
|
|
result->state_ = state_;
|
|
|
|
|
2012-10-22 13:01:40 +01:00
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2012-11-30 15:49:42 +00:00
|
|
|
/// @brief Return columns in error
|
|
|
|
///
|
|
|
|
/// If an error is returned from a fetch (in particular, a truncated
|
|
|
|
/// status), this method can be called to get the names of the fields in
|
|
|
|
/// error. It returns a string comprising the names of the fields
|
|
|
|
/// separated by commas. In the case of there being no error indicators
|
|
|
|
/// set, it returns the string "(None)".
|
|
|
|
///
|
|
|
|
/// @return Comma-separated list of columns in error, or the string
|
|
|
|
/// "(None)".
|
|
|
|
std::string getErrorColumns() {
|
|
|
|
return (getColumnsInError(error_, columns_, LEASE_COLUMNS));
|
|
|
|
}
|
|
|
|
|
2012-10-22 10:49:51 +01:00
|
|
|
private:
|
2012-11-06 12:58:10 +00:00
|
|
|
// Note: All array lengths are equal to the corresponding variable in the
|
2012-10-22 13:01:40 +01:00
|
|
|
// schema.
|
2012-11-21 12:44:18 +00:00
|
|
|
// Note: arrays are declared fixed length for speed of creation
|
2012-10-22 10:49:51 +01:00
|
|
|
std::string addr6_; ///< String form of address
|
2013-02-25 17:07:58 +01:00
|
|
|
char addr6_buffer_[ADDRESS6_TEXT_MAX_LEN + 1]; ///< Character
|
2012-10-24 14:12:06 +01:00
|
|
|
///< array form of V6 address
|
2012-10-22 10:49:51 +01:00
|
|
|
unsigned long addr6_length_; ///< Length of the address
|
2012-11-30 15:49:42 +00:00
|
|
|
MYSQL_BIND bind_[LEASE_COLUMNS]; ///< Bind array
|
|
|
|
std::string columns_[LEASE_COLUMNS];///< Column names
|
2012-10-24 14:27:43 +01:00
|
|
|
std::vector<uint8_t> duid_; ///< Client identification
|
2012-12-04 11:32:08 +00:00
|
|
|
uint8_t duid_buffer_[DUID::MAX_DUID_LEN]; ///< Buffer form of DUID
|
2012-10-24 14:27:43 +01:00
|
|
|
unsigned long duid_length_; ///< Length of the DUID
|
2012-11-30 15:49:42 +00:00
|
|
|
my_bool error_[LEASE_COLUMNS]; ///< Error indicators
|
2012-10-22 10:49:51 +01:00
|
|
|
MYSQL_TIME expire_; ///< Lease expiry time
|
2012-10-22 13:01:40 +01:00
|
|
|
uint32_t iaid_; ///< Identity association ID
|
2012-10-22 10:49:51 +01:00
|
|
|
Lease6Ptr lease_; ///< Pointer to lease object
|
|
|
|
uint8_t lease_type_; ///< Lease type
|
2012-10-22 13:01:40 +01:00
|
|
|
uint8_t prefixlen_; ///< Prefix length
|
|
|
|
uint32_t pref_lifetime_; ///< Preferred lifetime
|
|
|
|
uint32_t subnet_id_; ///< Subnet identification
|
2012-11-21 19:38:26 +00:00
|
|
|
uint32_t valid_lifetime_; ///< Lease time
|
2013-08-26 17:30:56 +02:00
|
|
|
my_bool fqdn_fwd_; ///< Has forward DNS update been
|
|
|
|
///< performed
|
|
|
|
my_bool fqdn_rev_; ///< Has reverse DNS update been
|
|
|
|
///< performed
|
|
|
|
char hostname_buffer_[HOSTNAME_MAX_LEN];
|
|
|
|
///< Client hostname
|
|
|
|
unsigned long hostname_length_; ///< Client hostname length
|
2014-11-06 19:36:46 +01:00
|
|
|
uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
|
|
|
|
///< Buffer for Hardware address
|
|
|
|
std::vector<uint8_t> hwaddr_; ///< Hardware address (optional)
|
|
|
|
unsigned long hwaddr_length_; ///< Aux. variable denoting hwaddr_ size()
|
|
|
|
my_bool hwaddr_null_; ///< Used when HWAddr is null
|
|
|
|
uint16_t hwtype_; ///< Hardware type
|
|
|
|
uint32_t hwaddr_source_; ///< Source of the hardware address
|
2015-09-07 10:47:30 +02:00
|
|
|
uint32_t state_; ///< Lease state.
|
2012-10-22 10:49:51 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2012-11-08 12:14:10 +00:00
|
|
|
/// @brief Fetch and Release MySQL Results
|
|
|
|
///
|
2013-03-08 10:32:43 -06:00
|
|
|
/// When a MySQL statement is expected, to fetch the results the function
|
2012-11-08 12:14:10 +00:00
|
|
|
/// mysql_stmt_fetch() must be called. As well as getting data, this
|
2012-11-23 18:23:21 +00:00
|
|
|
/// allocates internal state. Subsequent calls to mysql_stmt_fetch can be
|
|
|
|
/// made, but when all the data is retrieved, mysql_stmt_free_result must be
|
|
|
|
/// called to free up the resources allocated.
|
2012-11-08 12:14:10 +00:00
|
|
|
///
|
2012-11-08 12:50:34 +00:00
|
|
|
/// Created prior to the first fetch, this class's destructor calls
|
|
|
|
/// mysql_stmt_free_result, so eliminating the need for an explicit release
|
2012-11-23 18:23:21 +00:00
|
|
|
/// in the method calling mysql_stmt_free_result. In this way, it guarantees
|
2012-11-08 12:50:34 +00:00
|
|
|
/// that the resources are released even if the MySqlLeaseMgr method concerned
|
|
|
|
/// exits via an exception.
|
2012-11-23 18:23:21 +00:00
|
|
|
|
2012-11-08 12:50:34 +00:00
|
|
|
class MySqlFreeResult {
|
|
|
|
public:
|
|
|
|
|
|
|
|
/// @brief Constructor
|
|
|
|
///
|
|
|
|
/// Store the pointer to the statement for which data is being fetched.
|
|
|
|
///
|
|
|
|
/// Note that according to the MySQL documentation, mysql_stmt_free_result
|
|
|
|
/// only releases resources if a cursor has been allocated for the
|
|
|
|
/// statement. This implies that it is a no-op if none have been. Either
|
|
|
|
/// way, any error from mysql_stmt_free_result is ignored. (Generating
|
|
|
|
/// an exception is not much help, as it will only confuse things if the
|
|
|
|
/// method calling mysql_stmt_fetch is exiting via an exception.)
|
|
|
|
MySqlFreeResult(MYSQL_STMT* statement) : statement_(statement)
|
|
|
|
{}
|
|
|
|
|
|
|
|
/// @brief Destructor
|
|
|
|
///
|
|
|
|
/// Frees up fetch context if a fetch has been successfully executed.
|
|
|
|
~MySqlFreeResult() {
|
|
|
|
(void) mysql_stmt_free_result(statement_);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
MYSQL_STMT* statement_; ///< Statement for which results are freed
|
|
|
|
};
|
2012-11-08 12:14:10 +00:00
|
|
|
|
2012-11-21 19:38:26 +00:00
|
|
|
// MySqlLeaseMgr Constructor and Destructor
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2013-02-25 17:07:58 +01:00
|
|
|
MySqlLeaseMgr::MySqlLeaseMgr(const LeaseMgr::ParameterMap& parameters)
|
2013-03-07 15:48:51 +01:00
|
|
|
: LeaseMgr(parameters) {
|
2012-10-24 19:18:33 +01:00
|
|
|
|
2012-11-23 18:23:21 +00:00
|
|
|
// Open the database.
|
2012-10-24 19:18:33 +01:00
|
|
|
openDatabase();
|
|
|
|
|
2012-11-26 19:17:27 +00:00
|
|
|
// Enable autocommit. To avoid a flush to disk on every commit, the global
|
|
|
|
// parameter innodb_flush_log_at_trx_commit should be set to 2. This will
|
|
|
|
// cause the changes to be written to the log, but flushed to disk in the
|
2012-12-03 15:35:36 +00:00
|
|
|
// background every second. Setting the parameter to that value will speed
|
|
|
|
// up the system, but at the risk of losing data if the system crashes.
|
2012-11-13 12:06:48 +00:00
|
|
|
my_bool result = mysql_autocommit(mysql_, 1);
|
2012-10-24 19:18:33 +01:00
|
|
|
if (result != 0) {
|
|
|
|
isc_throw(DbOperationError, mysql_error(mysql_));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prepare all statements likely to be used.
|
|
|
|
prepareStatements();
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2012-11-21 12:44:18 +00:00
|
|
|
// Create the exchange objects for use in exchanging data between the
|
2012-11-06 12:58:10 +00:00
|
|
|
// program and the database.
|
2012-11-21 12:44:18 +00:00
|
|
|
exchange4_.reset(new MySqlLease4Exchange());
|
2012-11-06 12:58:10 +00:00
|
|
|
exchange6_.reset(new MySqlLease6Exchange());
|
2012-10-24 19:18:33 +01:00
|
|
|
}
|
|
|
|
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2012-10-24 19:18:33 +01:00
|
|
|
MySqlLeaseMgr::~MySqlLeaseMgr() {
|
|
|
|
// Free up the prepared statements, ignoring errors. (What would we do
|
2012-11-23 18:23:21 +00:00
|
|
|
// about them? We're destroying this object and are not really concerned
|
|
|
|
// with errors on a database connection that is about to go away.)
|
2012-10-24 19:18:33 +01:00
|
|
|
for (int i = 0; i < statements_.size(); ++i) {
|
|
|
|
if (statements_[i] != NULL) {
|
|
|
|
(void) mysql_stmt_close(statements_[i]);
|
|
|
|
statements_[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
2013-03-07 23:00:23 +00:00
|
|
|
|
|
|
|
// There is no need to close the database in this destructor: it is
|
|
|
|
// closed in the destructor of the mysql_ member variable.
|
2012-10-24 19:18:33 +01:00
|
|
|
}
|
|
|
|
|
2015-06-19 14:30:51 +02:00
|
|
|
std::string
|
|
|
|
MySqlLeaseMgr::getDBVersion() {
|
|
|
|
std::stringstream tmp;
|
|
|
|
tmp << "MySQL backend " << CURRENT_VERSION_VERSION;
|
|
|
|
tmp << "." << CURRENT_VERSION_MINOR;
|
2015-06-20 15:13:23 +02:00
|
|
|
tmp << ", library " << mysql_get_client_info();
|
2015-06-19 14:30:51 +02:00
|
|
|
return (tmp.str());
|
|
|
|
}
|
|
|
|
|
2012-10-22 10:49:51 +01:00
|
|
|
|
2012-10-20 22:52:25 +01:00
|
|
|
// 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
|
2012-10-24 15:36:54 +01:00
|
|
|
// timezone for retrieval.
|
|
|
|
//
|
|
|
|
// This causes no problems providing that:
|
|
|
|
// a) cltt is given in local time
|
|
|
|
// b) We let the system take care of timezone conversion when converting
|
|
|
|
// from a time read from the database into a local time.
|
2012-10-20 22:52:25 +01:00
|
|
|
|
2015-09-07 13:29:17 +02:00
|
|
|
void
|
|
|
|
MySqlLeaseMgr::convertToDatabaseTime(const time_t input_time,
|
|
|
|
MYSQL_TIME& output_time) {
|
|
|
|
|
|
|
|
// Convert to broken-out time
|
|
|
|
struct tm time_tm;
|
|
|
|
(void) localtime_r(&input_time, &time_tm);
|
|
|
|
|
|
|
|
// Place in output expire structure.
|
|
|
|
output_time.year = time_tm.tm_year + 1900;
|
|
|
|
output_time.month = time_tm.tm_mon + 1; // Note different base
|
|
|
|
output_time.day = time_tm.tm_mday;
|
|
|
|
output_time.hour = time_tm.tm_hour;
|
|
|
|
output_time.minute = time_tm.tm_min;
|
|
|
|
output_time.second = time_tm.tm_sec;
|
|
|
|
output_time.second_part = 0; // No fractional seconds
|
|
|
|
output_time.neg = my_bool(0); // Not negative
|
|
|
|
}
|
|
|
|
|
2012-10-20 22:52:25 +01:00
|
|
|
void
|
2015-03-04 16:19:36 +01:00
|
|
|
MySqlLeaseMgr::convertToDatabaseTime(const time_t cltt,
|
|
|
|
const uint32_t valid_lifetime,
|
|
|
|
MYSQL_TIME& expire) {
|
2012-10-20 22:52:25 +01:00
|
|
|
|
2015-03-04 13:32:18 +01:00
|
|
|
// Calculate expiry time. Store it in the 64-bit value so as we can detect
|
|
|
|
// overflows.
|
|
|
|
int64_t expire_time_64 = static_cast<int64_t>(cltt) +
|
2015-03-04 14:50:37 +01:00
|
|
|
static_cast<int64_t>(valid_lifetime);
|
2015-03-04 13:32:18 +01:00
|
|
|
|
2015-03-11 20:20:09 +01:00
|
|
|
// Even on 64-bit systems MySQL doesn't seem to accept the timestamps
|
|
|
|
// beyond the max value of int32_t.
|
2015-03-04 13:32:18 +01:00
|
|
|
if (expire_time_64 > LeaseMgr::MAX_DB_TIME) {
|
|
|
|
isc_throw(BadValue, "Time value is too large: " << expire_time_64);
|
|
|
|
}
|
|
|
|
|
2015-09-07 13:29:17 +02:00
|
|
|
convertToDatabaseTime(static_cast<time_t>(expire_time_64), expire);
|
2012-10-20 22:52:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-10-22 16:07:34 +01:00
|
|
|
MySqlLeaseMgr::convertFromDatabaseTime(const MYSQL_TIME& expire,
|
2012-10-24 15:36:54 +01:00
|
|
|
uint32_t valid_lifetime, time_t& cltt) {
|
2012-10-20 22:52:25 +01:00
|
|
|
|
|
|
|
// Copy across fields from MYSQL_TIME structure.
|
|
|
|
struct tm expire_tm;
|
2012-10-24 15:36:54 +01:00
|
|
|
memset(&expire_tm, 0, sizeof(expire_tm));
|
2012-10-20 22:52:25 +01:00
|
|
|
|
|
|
|
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;
|
2013-02-25 17:07:58 +01:00
|
|
|
expire_tm.tm_isdst = -1; // Let the system work out about DST
|
2012-10-20 22:52:25 +01:00
|
|
|
|
|
|
|
// Convert to local time
|
2012-10-24 15:36:54 +01:00
|
|
|
cltt = mktime(&expire_tm) - valid_lifetime;
|
2012-10-20 22:52:25 +01:00
|
|
|
}
|
|
|
|
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2012-11-21 19:38:26 +00:00
|
|
|
|
2012-11-23 18:23:21 +00:00
|
|
|
// Open the database using the parameters passed to the constructor.
|
2012-11-21 19:38:26 +00:00
|
|
|
|
2012-10-17 18:37:22 +01:00
|
|
|
void
|
|
|
|
MySqlLeaseMgr::openDatabase() {
|
|
|
|
|
|
|
|
// Set up the values of the parameters
|
2012-10-24 19:18:33 +01:00
|
|
|
const char* host = "localhost";
|
2012-10-17 18:37:22 +01:00
|
|
|
string shost;
|
|
|
|
try {
|
|
|
|
shost = getParameter("host");
|
|
|
|
host = shost.c_str();
|
|
|
|
} catch (...) {
|
2012-12-03 15:35:36 +00:00
|
|
|
// No host. Fine, we'll use "localhost"
|
2012-10-17 18:37:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const char* user = NULL;
|
|
|
|
string suser;
|
|
|
|
try {
|
|
|
|
suser = getParameter("user");
|
|
|
|
user = suser.c_str();
|
|
|
|
} catch (...) {
|
2012-12-03 15:35:36 +00:00
|
|
|
// No user. Fine, we'll use NULL
|
2012-10-17 18:37:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const char* password = NULL;
|
|
|
|
string spassword;
|
|
|
|
try {
|
|
|
|
spassword = getParameter("password");
|
|
|
|
password = spassword.c_str();
|
|
|
|
} catch (...) {
|
2012-12-03 15:35:36 +00:00
|
|
|
// No password. Fine, we'll use NULL
|
2012-10-17 18:37:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const char* name = NULL;
|
|
|
|
string sname;
|
|
|
|
try {
|
|
|
|
sname = getParameter("name");
|
|
|
|
name = sname.c_str();
|
|
|
|
} catch (...) {
|
2012-10-24 19:34:38 +01:00
|
|
|
// No database name. Throw a "NoName" exception
|
|
|
|
isc_throw(NoDatabaseName, "must specified a name for the database");
|
2012-10-17 18:37:22 +01:00
|
|
|
}
|
|
|
|
|
2012-10-24 21:18:13 +01:00
|
|
|
// Set options for the connection:
|
2013-02-25 17:07:58 +01:00
|
|
|
//
|
2012-11-23 18:23:21 +00:00
|
|
|
// Automatic reconnection: after a period of inactivity, the client will
|
|
|
|
// disconnect from the database. This option causes it to automatically
|
|
|
|
// reconnect when another operation is about to be done.
|
|
|
|
my_bool auto_reconnect = MLM_TRUE;
|
2012-10-24 21:18:13 +01:00
|
|
|
int result = mysql_options(mysql_, MYSQL_OPT_RECONNECT, &auto_reconnect);
|
|
|
|
if (result != 0) {
|
|
|
|
isc_throw(DbOpenError, "unable to set auto-reconnect option: " <<
|
|
|
|
mysql_error(mysql_));
|
|
|
|
}
|
|
|
|
|
2013-09-18 06:06:37 -04:00
|
|
|
// Set SQL mode options for the connection: SQL mode governs how what
|
2013-03-15 14:19:42 -04:00
|
|
|
// constitutes insertable data for a given column, and how to handle
|
|
|
|
// invalid data. We want to ensure we get the strictest behavior and
|
|
|
|
// to reject invalid data with an error.
|
2013-04-09 06:55:06 -04:00
|
|
|
const char *sql_mode = "SET SESSION sql_mode ='STRICT_ALL_TABLES'";
|
2013-03-15 14:19:42 -04:00
|
|
|
result = mysql_options(mysql_, MYSQL_INIT_COMMAND, sql_mode);
|
|
|
|
if (result != 0) {
|
|
|
|
isc_throw(DbOpenError, "unable to set SQL mode options: " <<
|
|
|
|
mysql_error(mysql_));
|
|
|
|
}
|
|
|
|
|
2012-10-29 19:19:36 +00:00
|
|
|
// Open the database.
|
|
|
|
//
|
|
|
|
// The option CLIENT_FOUND_ROWS is specified so that in an UPDATE,
|
|
|
|
// the affected rows are the number of rows found that match the
|
|
|
|
// WHERE clause of the SQL statement, not the rows changed. The reason
|
|
|
|
// here is that MySQL apparently does not update a row if data has not
|
|
|
|
// changed and so the "affected rows" (retrievable from MySQL) is zero.
|
|
|
|
// This makes it hard to distinguish whether the UPDATE changed no rows
|
|
|
|
// because no row matching the WHERE clause was found, or because a
|
2012-11-21 19:38:26 +00:00
|
|
|
// row was found but no data was altered.
|
2012-10-17 18:37:22 +01:00
|
|
|
MYSQL* status = mysql_real_connect(mysql_, host, user, password, name,
|
2012-10-29 19:19:36 +00:00
|
|
|
0, NULL, CLIENT_FOUND_ROWS);
|
2012-10-17 18:37:22 +01:00
|
|
|
if (status != mysql_) {
|
|
|
|
isc_throw(DbOpenError, mysql_error(mysql_));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-26 19:17:27 +00:00
|
|
|
// Prepared statement setup. The textual form of an SQL statement is stored
|
2012-11-21 19:38:26 +00:00
|
|
|
// in a vector of strings (text_statements_) and is used in the output of
|
|
|
|
// error messages. The SQL statement is also compiled into a "prepared
|
|
|
|
// statement" (stored in statements_), which avoids the overhead of compilation
|
2012-11-26 19:17:27 +00:00
|
|
|
// during use. As prepared statements have resources allocated to them, the
|
|
|
|
// class destructor explicitly destroys them.
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2012-10-18 11:33:51 +01:00
|
|
|
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)) {
|
2012-10-24 19:18:33 +01:00
|
|
|
isc_throw(InvalidParameter, "invalid prepared statement index (" <<
|
|
|
|
static_cast<int>(index) << ") or indexed prepared " <<
|
|
|
|
"statement is not null");
|
2012-10-18 11:33:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// All OK, so prepare the statement
|
2012-10-24 19:18:33 +01:00
|
|
|
text_statements_[index] = std::string(text);
|
2012-10-18 11:33:51 +01:00
|
|
|
statements_[index] = mysql_stmt_init(mysql_);
|
|
|
|
if (statements_[index] == NULL) {
|
|
|
|
isc_throw(DbOperationError, "unable to allocate MySQL prepared "
|
2012-11-23 18:23:21 +00:00
|
|
|
"statement structure, reason: " << mysql_error(mysql_));
|
2012-10-18 11:33:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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_));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2012-10-18 11:33:51 +01:00
|
|
|
void
|
|
|
|
MySqlLeaseMgr::prepareStatements() {
|
|
|
|
// Allocate space for all statements
|
|
|
|
statements_.clear();
|
|
|
|
statements_.resize(NUM_STATEMENTS, NULL);
|
2013-02-25 17:07:58 +01:00
|
|
|
|
2012-10-24 19:18:33 +01:00
|
|
|
text_statements_.clear();
|
|
|
|
text_statements_.resize(NUM_STATEMENTS, std::string(""));
|
2012-10-18 11:33:51 +01:00
|
|
|
|
2012-11-04 20:20:21 +00:00
|
|
|
// Created the MySQL prepared statements for each DML statement.
|
|
|
|
for (int i = 0; tagged_statements[i].text != NULL; ++i) {
|
|
|
|
prepareStatement(tagged_statements[i].index,
|
|
|
|
tagged_statements[i].text);
|
|
|
|
}
|
2012-10-18 11:33:51 +01:00
|
|
|
}
|
|
|
|
|
2012-11-23 18:23:21 +00:00
|
|
|
// Add leases to the database. The two public methods accept a lease object
|
2012-12-03 15:35:36 +00:00
|
|
|
// (either V4 of V6), bind the contents to the appropriate prepared
|
2012-11-23 18:23:21 +00:00
|
|
|
// statement, then call common code to execute the statement.
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2012-10-16 16:39:32 +01:00
|
|
|
bool
|
2012-11-26 19:17:27 +00:00
|
|
|
MySqlLeaseMgr::addLeaseCommon(StatementIndex stindex,
|
|
|
|
std::vector<MYSQL_BIND>& bind) {
|
2012-10-20 22:52:25 +01:00
|
|
|
|
|
|
|
// Bind the parameters to the statement
|
2012-11-04 20:20:21 +00:00
|
|
|
int status = mysql_stmt_bind_param(statements_[stindex], &bind[0]);
|
|
|
|
checkError(status, stindex, "unable to bind parameters");
|
2012-10-20 22:52:25 +01:00
|
|
|
|
|
|
|
// Execute the statement
|
2012-11-04 20:20:21 +00:00
|
|
|
status = mysql_stmt_execute(statements_[stindex]);
|
2012-10-22 16:07:34 +01:00
|
|
|
if (status != 0) {
|
|
|
|
|
|
|
|
// Failure: check for the special case of duplicate entry. If this is
|
|
|
|
// the case, we return false to indicate that the row was not added.
|
|
|
|
// Otherwise we throw an exception.
|
|
|
|
if (mysql_errno(mysql_) == ER_DUP_ENTRY) {
|
|
|
|
return (false);
|
|
|
|
}
|
2012-11-04 20:20:21 +00:00
|
|
|
checkError(status, stindex, "unable to execute");
|
2012-10-22 16:07:34 +01:00
|
|
|
}
|
2012-10-20 22:52:25 +01:00
|
|
|
|
2012-10-22 16:07:34 +01:00
|
|
|
// Insert succeeded
|
|
|
|
return (true);
|
2012-10-16 16:39:32 +01:00
|
|
|
}
|
|
|
|
|
2012-11-21 12:44:18 +00:00
|
|
|
bool
|
|
|
|
MySqlLeaseMgr::addLease(const Lease4Ptr& lease) {
|
2012-12-18 13:11:17 +00:00
|
|
|
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
|
|
|
|
DHCPSRV_MYSQL_ADD_ADDR4).arg(lease->addr_.toText());
|
2012-12-14 22:19:31 +00:00
|
|
|
|
2012-11-21 12:44:18 +00:00
|
|
|
// Create the MYSQL_BIND array for the lease
|
|
|
|
std::vector<MYSQL_BIND> bind = exchange4_->createBindForSend(lease);
|
|
|
|
|
|
|
|
// ... and drop to common code.
|
2012-11-26 19:17:27 +00:00
|
|
|
return (addLeaseCommon(INSERT_LEASE4, bind));
|
2012-11-21 12:44:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
MySqlLeaseMgr::addLease(const Lease6Ptr& lease) {
|
2012-12-18 13:11:17 +00:00
|
|
|
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
|
2013-09-13 10:05:28 -04:00
|
|
|
DHCPSRV_MYSQL_ADD_ADDR6).arg(lease->addr_.toText())
|
|
|
|
.arg(lease->type_);
|
2012-12-14 22:19:31 +00:00
|
|
|
|
2012-11-21 12:44:18 +00:00
|
|
|
// Create the MYSQL_BIND array for the lease
|
|
|
|
std::vector<MYSQL_BIND> bind = exchange6_->createBindForSend(lease);
|
|
|
|
|
|
|
|
// ... and drop to common code.
|
2012-11-26 19:17:27 +00:00
|
|
|
return (addLeaseCommon(INSERT_LEASE6, bind));
|
2012-11-21 19:38:26 +00:00
|
|
|
}
|
|
|
|
|
2012-11-23 18:23:21 +00:00
|
|
|
// Extraction of leases from the database.
|
|
|
|
//
|
|
|
|
// All getLease() methods ultimately call getLeaseCollection(). This
|
|
|
|
// binds the input parameters passed to it with the appropriate prepared
|
|
|
|
// statement and executes the statement. It then gets the results from the
|
|
|
|
// database. getlease() methods that expect a single result back call it
|
|
|
|
// with the "single" parameter set true: this causes an exception to be
|
|
|
|
// generated if multiple records can be retrieved from the result set. (Such
|
|
|
|
// an occurrence either indicates corruption in the database, or that an
|
|
|
|
// assumption that a query can only return a single record is incorrect.)
|
|
|
|
// Methods that require a collection of records have "single" set to the
|
|
|
|
// default value of false. The logic is the same for both Lease4 and Lease6
|
|
|
|
// objects, so the code is templated.
|
|
|
|
//
|
|
|
|
// Methods that require a collection of objects access this method through
|
|
|
|
// two interface methods (also called getLeaseCollection()). These are
|
|
|
|
// short enough as to be defined in the header file: all they do is to supply
|
|
|
|
// the appropriate MySqlLeaseXExchange object depending on the type of the
|
|
|
|
// LeaseCollection objects passed to them.
|
|
|
|
//
|
|
|
|
// Methods that require a single object to be returned access the method
|
|
|
|
// through two interface methods (called getLease()). As well as supplying
|
|
|
|
// the appropriate exchange object, they convert between lease collection
|
|
|
|
// holding zero or one leases into an appropriate Lease object.
|
2012-11-23 12:05:55 +00:00
|
|
|
|
|
|
|
template <typename Exchange, typename LeaseCollection>
|
|
|
|
void MySqlLeaseMgr::getLeaseCollection(StatementIndex stindex,
|
2012-11-26 19:17:27 +00:00
|
|
|
MYSQL_BIND* bind,
|
2012-11-23 12:05:55 +00:00
|
|
|
Exchange& exchange,
|
2012-11-23 18:23:21 +00:00
|
|
|
LeaseCollection& result,
|
|
|
|
bool single) const {
|
2012-11-23 12:05:55 +00:00
|
|
|
|
2012-11-26 19:17:27 +00:00
|
|
|
// Bind the selection parameters to the statement
|
|
|
|
int status = mysql_stmt_bind_param(statements_[stindex], bind);
|
|
|
|
checkError(status, stindex, "unable to bind WHERE clause parameter");
|
|
|
|
|
|
|
|
// Set up the MYSQL_BIND array for the data being returned and bind it to
|
|
|
|
// the statement.
|
|
|
|
std::vector<MYSQL_BIND> outbind = exchange->createBindForReceive();
|
|
|
|
status = mysql_stmt_bind_result(statements_[stindex], &outbind[0]);
|
|
|
|
checkError(status, stindex, "unable to bind SELECT clause parameters");
|
|
|
|
|
|
|
|
// Execute the statement
|
|
|
|
status = mysql_stmt_execute(statements_[stindex]);
|
|
|
|
checkError(status, stindex, "unable to execute");
|
2012-11-23 12:05:55 +00:00
|
|
|
|
|
|
|
// Ensure that all the lease information is retrieved in one go to avoid
|
|
|
|
// overhead of going back and forth between client and server.
|
2012-11-26 19:17:27 +00:00
|
|
|
status = mysql_stmt_store_result(statements_[stindex]);
|
2012-11-23 12:05:55 +00:00
|
|
|
checkError(status, stindex, "unable to set up for storing all results");
|
|
|
|
|
|
|
|
// Set up the fetch "release" object to release resources associated
|
|
|
|
// with the call to mysql_stmt_fetch when this method exits, then
|
|
|
|
// retrieve the data.
|
|
|
|
MySqlFreeResult fetch_release(statements_[stindex]);
|
2012-11-23 18:23:21 +00:00
|
|
|
int count = 0;
|
2012-11-23 12:05:55 +00:00
|
|
|
while ((status = mysql_stmt_fetch(statements_[stindex])) == 0) {
|
|
|
|
try {
|
|
|
|
result.push_back(exchange->getLeaseData());
|
|
|
|
|
|
|
|
} catch (const isc::BadValue& ex) {
|
|
|
|
// Rethrow the exception with a bit more data.
|
|
|
|
isc_throw(BadValue, ex.what() << ". Statement is <" <<
|
|
|
|
text_statements_[stindex] << ">");
|
|
|
|
}
|
2012-11-23 18:23:21 +00:00
|
|
|
|
|
|
|
if (single && (++count > 1)) {
|
|
|
|
isc_throw(MultipleRecords, "multiple records were found in the "
|
|
|
|
"database where only one was expected for query "
|
|
|
|
<< text_statements_[stindex]);
|
|
|
|
}
|
2012-11-23 12:05:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// How did the fetch end?
|
|
|
|
if (status == 1) {
|
2012-11-23 18:23:21 +00:00
|
|
|
// Error - unable to fetch results
|
2012-11-23 12:05:55 +00:00
|
|
|
checkError(status, stindex, "unable to fetch results");
|
|
|
|
} else if (status == MYSQL_DATA_TRUNCATED) {
|
2012-11-30 15:49:42 +00:00
|
|
|
// Data truncated - throw an exception indicating what was at fault
|
2012-12-04 11:32:08 +00:00
|
|
|
isc_throw(DataTruncated, text_statements_[stindex]
|
|
|
|
<< " returned truncated data: columns affected are "
|
2012-11-30 15:49:42 +00:00
|
|
|
<< exchange->getErrorColumns());
|
2012-11-23 12:05:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-26 19:17:27 +00:00
|
|
|
void MySqlLeaseMgr::getLease(StatementIndex stindex, MYSQL_BIND* bind,
|
2012-11-23 18:23:21 +00:00
|
|
|
Lease4Ptr& result) const {
|
|
|
|
// Create appropriate collection object and get all leases matching
|
|
|
|
// the selection criteria. The "single" paraeter is true to indicate
|
|
|
|
// that the called method should throw an exception if multiple
|
|
|
|
// matching records are found: this particular method is called when only
|
|
|
|
// one or zero matches is expected.
|
|
|
|
Lease4Collection collection;
|
2012-11-26 19:17:27 +00:00
|
|
|
getLeaseCollection(stindex, bind, exchange4_, collection, true);
|
2012-11-23 18:23:21 +00:00
|
|
|
|
|
|
|
// Return single record if present, else clear the lease.
|
|
|
|
if (collection.empty()) {
|
|
|
|
result.reset();
|
|
|
|
} else {
|
|
|
|
result = *collection.begin();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-26 19:17:27 +00:00
|
|
|
|
|
|
|
void MySqlLeaseMgr::getLease(StatementIndex stindex, MYSQL_BIND* bind,
|
2012-11-23 18:23:21 +00:00
|
|
|
Lease6Ptr& result) const {
|
|
|
|
// Create appropriate collection object and get all leases matching
|
|
|
|
// the selection criteria. The "single" paraeter is true to indicate
|
|
|
|
// that the called method should throw an exception if multiple
|
|
|
|
// matching records are found: this particular method is called when only
|
|
|
|
// one or zero matches is expected.
|
|
|
|
Lease6Collection collection;
|
2012-11-26 19:17:27 +00:00
|
|
|
getLeaseCollection(stindex, bind, exchange6_, collection, true);
|
2012-11-23 18:23:21 +00:00
|
|
|
|
|
|
|
// Return single record if present, else clear the lease.
|
|
|
|
if (collection.empty()) {
|
|
|
|
result.reset();
|
|
|
|
} else {
|
|
|
|
result = *collection.begin();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Basic lease access methods. Obtain leases from the database using various
|
|
|
|
// criteria.
|
|
|
|
|
2012-10-16 16:39:32 +01:00
|
|
|
Lease4Ptr
|
2012-11-21 12:44:18 +00:00
|
|
|
MySqlLeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const {
|
2012-12-18 13:11:17 +00:00
|
|
|
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
|
|
|
|
DHCPSRV_MYSQL_GET_ADDR4).arg(addr.toText());
|
2012-12-14 22:19:31 +00:00
|
|
|
|
2012-11-21 12:44:18 +00:00
|
|
|
// Set up the WHERE clause value
|
|
|
|
MYSQL_BIND inbind[1];
|
|
|
|
memset(inbind, 0, sizeof(inbind));
|
|
|
|
|
|
|
|
uint32_t addr4 = static_cast<uint32_t>(addr);
|
|
|
|
inbind[0].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
inbind[0].buffer = reinterpret_cast<char*>(&addr4);
|
2012-11-23 18:23:21 +00:00
|
|
|
inbind[0].is_unsigned = MLM_TRUE;
|
2012-11-21 12:44:18 +00:00
|
|
|
|
2012-11-23 12:05:55 +00:00
|
|
|
// Get the data
|
2012-11-21 12:44:18 +00:00
|
|
|
Lease4Ptr result;
|
2012-11-23 18:23:21 +00:00
|
|
|
getLease(GET_LEASE4_ADDR, inbind, result);
|
2012-11-21 12:44:18 +00:00
|
|
|
|
|
|
|
return (result);
|
2012-10-16 16:39:32 +01:00
|
|
|
}
|
|
|
|
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2012-10-16 16:39:32 +01:00
|
|
|
Lease4Collection
|
2012-11-23 12:05:55 +00:00
|
|
|
MySqlLeaseMgr::getLease4(const HWAddr& hwaddr) const {
|
2012-12-18 13:11:17 +00:00
|
|
|
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
|
2013-01-10 16:32:24 +01:00
|
|
|
DHCPSRV_MYSQL_GET_HWADDR).arg(hwaddr.toText());
|
2012-12-14 22:19:31 +00:00
|
|
|
|
2012-11-23 12:05:55 +00:00
|
|
|
// Set up the WHERE clause value
|
|
|
|
MYSQL_BIND inbind[1];
|
|
|
|
memset(inbind, 0, sizeof(inbind));
|
|
|
|
|
|
|
|
// As "buffer" is "char*" - even though the data is being read - we need
|
|
|
|
// to cast away the "const"ness as well as reinterpreting the data as
|
|
|
|
// a "char*". (We could avoid the "const_cast" by copying the data to a
|
|
|
|
// local variable, but as the data is only being read, this introduces
|
|
|
|
// an unnecessary copy).
|
2013-01-10 16:32:24 +01:00
|
|
|
unsigned long hwaddr_length = hwaddr.hwaddr_.size();
|
|
|
|
uint8_t* data = const_cast<uint8_t*>(&hwaddr.hwaddr_[0]);
|
2012-11-23 12:05:55 +00:00
|
|
|
|
|
|
|
inbind[0].buffer_type = MYSQL_TYPE_BLOB;
|
|
|
|
inbind[0].buffer = reinterpret_cast<char*>(data);
|
|
|
|
inbind[0].buffer_length = hwaddr_length;
|
|
|
|
inbind[0].length = &hwaddr_length;
|
|
|
|
|
|
|
|
// Get the data
|
|
|
|
Lease4Collection result;
|
2012-11-23 18:23:21 +00:00
|
|
|
getLeaseCollection(GET_LEASE4_HWADDR, inbind, result);
|
2012-11-23 12:05:55 +00:00
|
|
|
|
|
|
|
return (result);
|
2012-10-16 16:39:32 +01:00
|
|
|
}
|
|
|
|
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2012-10-16 16:39:32 +01:00
|
|
|
Lease4Ptr
|
2012-11-23 12:23:17 +00:00
|
|
|
MySqlLeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
|
2012-12-18 13:11:17 +00:00
|
|
|
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
|
|
|
|
DHCPSRV_MYSQL_GET_SUBID_HWADDR)
|
2013-01-10 16:32:24 +01:00
|
|
|
.arg(subnet_id).arg(hwaddr.toText());
|
2012-12-14 22:19:31 +00:00
|
|
|
|
2012-11-23 12:23:17 +00:00
|
|
|
// Set up the WHERE clause value
|
|
|
|
MYSQL_BIND inbind[2];
|
|
|
|
memset(inbind, 0, sizeof(inbind));
|
|
|
|
|
|
|
|
// As "buffer" is "char*" - even though the data is being read - we need
|
|
|
|
// to cast away the "const"ness as well as reinterpreting the data as
|
|
|
|
// a "char*". (We could avoid the "const_cast" by copying the data to a
|
|
|
|
// local variable, but as the data is only being read, this introduces
|
|
|
|
// an unnecessary copy).
|
2013-01-10 16:32:24 +01:00
|
|
|
unsigned long hwaddr_length = hwaddr.hwaddr_.size();
|
|
|
|
uint8_t* data = const_cast<uint8_t*>(&hwaddr.hwaddr_[0]);
|
2012-11-23 12:23:17 +00:00
|
|
|
|
|
|
|
inbind[0].buffer_type = MYSQL_TYPE_BLOB;
|
|
|
|
inbind[0].buffer = reinterpret_cast<char*>(data);
|
|
|
|
inbind[0].buffer_length = hwaddr_length;
|
|
|
|
inbind[0].length = &hwaddr_length;
|
|
|
|
|
|
|
|
inbind[1].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
inbind[1].buffer = reinterpret_cast<char*>(&subnet_id);
|
2012-11-23 18:23:21 +00:00
|
|
|
inbind[1].is_unsigned = MLM_TRUE;
|
2012-11-23 12:23:17 +00:00
|
|
|
|
|
|
|
// Get the data
|
|
|
|
Lease4Ptr result;
|
2012-11-23 18:23:21 +00:00
|
|
|
getLease(GET_LEASE4_HWADDR_SUBID, inbind, result);
|
2012-11-23 12:23:17 +00:00
|
|
|
|
|
|
|
return (result);
|
2012-10-16 16:39:32 +01:00
|
|
|
}
|
|
|
|
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2012-10-16 16:39:32 +01:00
|
|
|
Lease4Collection
|
2012-11-23 12:47:40 +00:00
|
|
|
MySqlLeaseMgr::getLease4(const ClientId& clientid) const {
|
2012-12-18 13:11:17 +00:00
|
|
|
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
|
|
|
|
DHCPSRV_MYSQL_GET_CLIENTID).arg(clientid.toText());
|
2012-12-14 22:19:31 +00:00
|
|
|
|
2012-11-23 12:47:40 +00:00
|
|
|
// Set up the WHERE clause value
|
|
|
|
MYSQL_BIND inbind[1];
|
|
|
|
memset(inbind, 0, sizeof(inbind));
|
|
|
|
|
|
|
|
std::vector<uint8_t> client_data = clientid.getClientId();
|
|
|
|
unsigned long client_data_length = client_data.size();
|
|
|
|
inbind[0].buffer_type = MYSQL_TYPE_BLOB;
|
|
|
|
inbind[0].buffer = reinterpret_cast<char*>(&client_data[0]);
|
|
|
|
inbind[0].buffer_length = client_data_length;
|
|
|
|
inbind[0].length = &client_data_length;
|
|
|
|
|
|
|
|
// Get the data
|
|
|
|
Lease4Collection result;
|
2012-11-23 18:23:21 +00:00
|
|
|
getLeaseCollection(GET_LEASE4_CLIENTID, inbind, result);
|
2012-11-23 12:47:40 +00:00
|
|
|
|
|
|
|
return (result);
|
2012-10-16 16:39:32 +01:00
|
|
|
}
|
|
|
|
|
2013-11-15 12:03:21 +01:00
|
|
|
Lease4Ptr
|
|
|
|
MySqlLeaseMgr::getLease4(const ClientId&, const HWAddr&, SubnetID) const {
|
|
|
|
/// This function is currently not implemented because allocation engine
|
|
|
|
/// searches for the lease using HW address or client identifier.
|
|
|
|
/// It never uses both parameters in the same time. We need to
|
|
|
|
/// consider if this function is needed at all.
|
|
|
|
isc_throw(NotImplemented, "The MySqlLeaseMgr::getLease4 function was"
|
|
|
|
" called, but it is not implemented");
|
|
|
|
}
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2012-10-16 16:39:32 +01:00
|
|
|
Lease4Ptr
|
2012-11-23 13:48:42 +00:00
|
|
|
MySqlLeaseMgr::getLease4(const ClientId& clientid, SubnetID subnet_id) const {
|
2012-12-18 13:11:17 +00:00
|
|
|
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
|
|
|
|
DHCPSRV_MYSQL_GET_SUBID_CLIENTID)
|
|
|
|
.arg(subnet_id).arg(clientid.toText());
|
2012-12-14 22:19:31 +00:00
|
|
|
|
2012-11-23 13:48:42 +00:00
|
|
|
// Set up the WHERE clause value
|
|
|
|
MYSQL_BIND inbind[2];
|
|
|
|
memset(inbind, 0, sizeof(inbind));
|
2012-10-16 16:39:32 +01:00
|
|
|
|
2012-11-23 13:48:42 +00:00
|
|
|
std::vector<uint8_t> client_data = clientid.getClientId();
|
|
|
|
unsigned long client_data_length = client_data.size();
|
|
|
|
inbind[0].buffer_type = MYSQL_TYPE_BLOB;
|
|
|
|
inbind[0].buffer = reinterpret_cast<char*>(&client_data[0]);
|
|
|
|
inbind[0].buffer_length = client_data_length;
|
|
|
|
inbind[0].length = &client_data_length;
|
|
|
|
|
|
|
|
inbind[1].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
inbind[1].buffer = reinterpret_cast<char*>(&subnet_id);
|
2012-11-23 18:23:21 +00:00
|
|
|
inbind[1].is_unsigned = MLM_TRUE;
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2012-11-23 13:48:42 +00:00
|
|
|
// Get the data
|
|
|
|
Lease4Ptr result;
|
2012-11-23 18:23:21 +00:00
|
|
|
getLease(GET_LEASE4_CLIENTID_SUBID, inbind, result);
|
2012-11-23 13:48:42 +00:00
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
2012-11-06 12:58:10 +00:00
|
|
|
|
|
|
|
|
2012-10-16 16:39:32 +01:00
|
|
|
Lease6Ptr
|
2013-09-18 15:44:48 +02:00
|
|
|
MySqlLeaseMgr::getLease6(Lease::Type lease_type,
|
2013-09-06 14:51:59 +02:00
|
|
|
const isc::asiolink::IOAddress& addr) const {
|
2012-12-18 13:11:17 +00:00
|
|
|
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
|
2013-09-13 10:05:28 -04:00
|
|
|
DHCPSRV_MYSQL_GET_ADDR6).arg(addr.toText())
|
|
|
|
.arg(lease_type);
|
2012-12-14 22:19:31 +00:00
|
|
|
|
2012-10-20 22:52:25 +01:00
|
|
|
// Set up the WHERE clause value
|
2013-09-13 10:05:28 -04:00
|
|
|
MYSQL_BIND inbind[2];
|
2012-10-20 22:52:25 +01:00
|
|
|
memset(inbind, 0, sizeof(inbind));
|
|
|
|
|
|
|
|
std::string addr6 = addr.toText();
|
|
|
|
unsigned long addr6_length = addr6.size();
|
|
|
|
|
2012-11-08 12:14:10 +00:00
|
|
|
// See the earlier description of the use of "const_cast" when accessing
|
|
|
|
// the address for an explanation of the reason.
|
2012-10-20 22:52:25 +01:00
|
|
|
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;
|
|
|
|
|
2013-09-13 10:05:28 -04:00
|
|
|
// LEASE_TYPE
|
|
|
|
inbind[1].buffer_type = MYSQL_TYPE_TINY;
|
|
|
|
inbind[1].buffer = reinterpret_cast<char*>(&lease_type);
|
|
|
|
inbind[1].is_unsigned = MLM_TRUE;
|
|
|
|
|
2012-10-22 13:01:40 +01:00
|
|
|
Lease6Ptr result;
|
2012-11-23 18:23:21 +00:00
|
|
|
getLease(GET_LEASE6_ADDR, inbind, result);
|
2012-10-20 22:52:25 +01:00
|
|
|
|
|
|
|
return (result);
|
2012-10-16 16:39:32 +01:00
|
|
|
}
|
|
|
|
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2012-10-16 16:39:32 +01:00
|
|
|
Lease6Collection
|
2013-09-18 15:44:48 +02:00
|
|
|
MySqlLeaseMgr::getLeases6(Lease::Type lease_type,
|
2013-09-06 19:30:35 +02:00
|
|
|
const DUID& duid, uint32_t iaid) const {
|
2012-12-18 13:11:17 +00:00
|
|
|
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
|
2013-09-13 10:05:28 -04:00
|
|
|
DHCPSRV_MYSQL_GET_IAID_DUID).arg(iaid).arg(duid.toText())
|
|
|
|
.arg(lease_type);
|
2012-11-04 20:20:21 +00:00
|
|
|
|
2012-11-03 18:26:57 +00:00
|
|
|
// Set up the WHERE clause value
|
2013-09-13 10:05:28 -04:00
|
|
|
MYSQL_BIND inbind[3];
|
2012-11-03 18:26:57 +00:00
|
|
|
memset(inbind, 0, sizeof(inbind));
|
|
|
|
|
2012-11-08 12:14:10 +00:00
|
|
|
// In the following statement, the DUID is being read. However, the
|
|
|
|
// MySQL C interface does not use "const", so the "buffer" element
|
|
|
|
// is declared as "char*" instead of "const char*". To resolve this,
|
|
|
|
// the "const" is discarded before the uint8_t* is cast to char*.
|
2012-11-09 16:11:24 +00:00
|
|
|
//
|
|
|
|
// Note that the const_cast could be avoided by copying the DUID to
|
|
|
|
// a writeable buffer and storing the address of that in the "buffer"
|
|
|
|
// element. However, this introduces a copy operation (with additional
|
2012-11-30 15:49:42 +00:00
|
|
|
// overhead) purely to get round the structures introduced by design of
|
2012-11-09 16:11:24 +00:00
|
|
|
// the MySQL interface (which uses the area pointed to by "buffer" as
|
|
|
|
// input when specifying query parameters and as output when retrieving
|
|
|
|
// data). For that reason, "const_cast" has been used.
|
2012-11-03 18:26:57 +00:00
|
|
|
const vector<uint8_t>& duid_vector = duid.getDuid();
|
|
|
|
unsigned long duid_length = duid_vector.size();
|
|
|
|
inbind[0].buffer_type = MYSQL_TYPE_BLOB;
|
|
|
|
inbind[0].buffer = reinterpret_cast<char*>(
|
|
|
|
const_cast<uint8_t*>(&duid_vector[0]));
|
|
|
|
inbind[0].buffer_length = duid_length;
|
|
|
|
inbind[0].length = &duid_length;
|
|
|
|
|
|
|
|
// IAID
|
|
|
|
inbind[1].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
inbind[1].buffer = reinterpret_cast<char*>(&iaid);
|
2012-11-23 18:23:21 +00:00
|
|
|
inbind[1].is_unsigned = MLM_TRUE;
|
2012-11-03 18:26:57 +00:00
|
|
|
|
2013-09-13 10:05:28 -04:00
|
|
|
// LEASE_TYPE
|
|
|
|
inbind[2].buffer_type = MYSQL_TYPE_TINY;
|
|
|
|
inbind[2].buffer = reinterpret_cast<char*>(&lease_type);
|
|
|
|
inbind[2].is_unsigned = MLM_TRUE;
|
|
|
|
|
2012-11-23 12:05:55 +00:00
|
|
|
// ... and get the data
|
2012-11-03 18:26:57 +00:00
|
|
|
Lease6Collection result;
|
2012-11-23 18:23:21 +00:00
|
|
|
getLeaseCollection(GET_LEASE6_DUID_IAID, inbind, result);
|
2012-11-03 18:26:57 +00:00
|
|
|
|
|
|
|
return (result);
|
2012-10-16 16:39:32 +01:00
|
|
|
}
|
|
|
|
|
2013-09-06 18:16:50 +02:00
|
|
|
Lease6Collection
|
2013-09-18 15:44:48 +02:00
|
|
|
MySqlLeaseMgr::getLeases6(Lease::Type lease_type,
|
2013-09-06 18:16:50 +02:00
|
|
|
const DUID& duid, uint32_t iaid,
|
|
|
|
SubnetID subnet_id) const {
|
2012-12-18 13:11:17 +00:00
|
|
|
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
|
|
|
|
DHCPSRV_MYSQL_GET_IAID_SUBID_DUID)
|
2013-09-13 10:05:28 -04:00
|
|
|
.arg(iaid).arg(subnet_id).arg(duid.toText())
|
|
|
|
.arg(lease_type);
|
2012-11-04 20:20:21 +00:00
|
|
|
|
2012-11-04 19:57:05 +00:00
|
|
|
// Set up the WHERE clause value
|
2013-09-13 10:05:28 -04:00
|
|
|
MYSQL_BIND inbind[4];
|
2012-11-04 19:57:05 +00:00
|
|
|
memset(inbind, 0, sizeof(inbind));
|
|
|
|
|
2012-11-08 12:14:10 +00:00
|
|
|
// See the earlier description of the use of "const_cast" when accessing
|
|
|
|
// the DUID for an explanation of the reason.
|
2012-11-04 19:57:05 +00:00
|
|
|
const vector<uint8_t>& duid_vector = duid.getDuid();
|
|
|
|
unsigned long duid_length = duid_vector.size();
|
|
|
|
inbind[0].buffer_type = MYSQL_TYPE_BLOB;
|
|
|
|
inbind[0].buffer = reinterpret_cast<char*>(
|
|
|
|
const_cast<uint8_t*>(&duid_vector[0]));
|
|
|
|
inbind[0].buffer_length = duid_length;
|
|
|
|
inbind[0].length = &duid_length;
|
|
|
|
|
|
|
|
// IAID
|
|
|
|
inbind[1].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
inbind[1].buffer = reinterpret_cast<char*>(&iaid);
|
2012-11-23 18:23:21 +00:00
|
|
|
inbind[1].is_unsigned = MLM_TRUE;
|
2012-11-04 19:57:05 +00:00
|
|
|
|
|
|
|
// Subnet ID
|
|
|
|
inbind[2].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
inbind[2].buffer = reinterpret_cast<char*>(&subnet_id);
|
2012-11-23 18:23:21 +00:00
|
|
|
inbind[2].is_unsigned = MLM_TRUE;
|
2012-11-04 19:57:05 +00:00
|
|
|
|
2013-09-13 10:05:28 -04:00
|
|
|
// LEASE_TYPE
|
|
|
|
inbind[3].buffer_type = MYSQL_TYPE_TINY;
|
|
|
|
inbind[3].buffer = reinterpret_cast<char*>(&lease_type);
|
|
|
|
inbind[3].is_unsigned = MLM_TRUE;
|
2012-11-04 19:57:05 +00:00
|
|
|
|
2013-09-13 10:05:28 -04:00
|
|
|
// ... and get the data
|
|
|
|
Lease6Collection result;
|
|
|
|
getLeaseCollection(GET_LEASE6_DUID_IAID_SUBID, inbind, result);
|
2013-09-06 18:16:50 +02:00
|
|
|
|
2013-09-13 10:05:28 -04:00
|
|
|
return (result);
|
2012-10-16 16:39:32 +01:00
|
|
|
}
|
|
|
|
|
2015-08-20 19:25:38 +02:00
|
|
|
void
|
2015-09-07 13:29:17 +02:00
|
|
|
MySqlLeaseMgr::getExpiredLeases6(Lease6Collection& expired_leases,
|
|
|
|
const size_t max_leases) const {
|
|
|
|
getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE6_EXPIRE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MySqlLeaseMgr::getExpiredLeases4(Lease4Collection& expired_leases,
|
|
|
|
const size_t max_leases) const {
|
|
|
|
getExpiredLeasesCommon(expired_leases, max_leases, GET_LEASE4_EXPIRE);
|
2015-08-20 19:25:38 +02:00
|
|
|
}
|
|
|
|
|
2015-09-07 13:29:17 +02:00
|
|
|
template<typename LeaseCollection>
|
2015-08-20 19:25:38 +02:00
|
|
|
void
|
2015-09-07 13:29:17 +02:00
|
|
|
MySqlLeaseMgr::getExpiredLeasesCommon(LeaseCollection& expired_leases,
|
|
|
|
const size_t max_leases,
|
|
|
|
StatementIndex statement_index) const {
|
|
|
|
// Set up the WHERE clause value
|
|
|
|
MYSQL_BIND inbind[3];
|
|
|
|
memset(inbind, 0, sizeof(inbind));
|
|
|
|
|
|
|
|
// Exclude reclaimed leases.
|
|
|
|
uint32_t state = static_cast<uint32_t>(Lease::STATE_EXPIRED_RECLAIMED);
|
|
|
|
inbind[0].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
inbind[0].buffer = reinterpret_cast<char*>(&state);
|
|
|
|
inbind[0].is_unsigned = MLM_TRUE;
|
|
|
|
|
|
|
|
// Expiration timestamp.
|
|
|
|
MYSQL_TIME expire_time;
|
|
|
|
convertToDatabaseTime(time(NULL), expire_time);
|
|
|
|
inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
|
|
|
|
inbind[1].buffer = reinterpret_cast<char*>(&expire_time);
|
|
|
|
inbind[1].buffer_length = sizeof(expire_time);
|
|
|
|
|
|
|
|
// If the number of leases is 0, we will return all leases. This is
|
|
|
|
// achieved by setting the limit to a very high value.
|
|
|
|
uint32_t limit = max_leases > 0 ? static_cast<uint32_t>(max_leases) :
|
|
|
|
std::numeric_limits<uint32_t>::max();
|
|
|
|
inbind[2].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
inbind[2].buffer = reinterpret_cast<char*>(&limit);
|
|
|
|
inbind[2].is_unsigned = MLM_TRUE;
|
|
|
|
|
|
|
|
// Get the data
|
|
|
|
getLeaseCollection(statement_index, inbind, expired_leases);
|
2015-08-20 19:25:38 +02:00
|
|
|
}
|
|
|
|
|
2015-09-07 13:29:17 +02:00
|
|
|
|
|
|
|
|
2012-11-23 18:23:21 +00:00
|
|
|
// Update lease methods. These comprise common code that handles the actual
|
|
|
|
// update, and type-specific methods that set up the parameters for the prepared
|
|
|
|
// statement depending on the type of lease.
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2012-11-23 18:23:21 +00:00
|
|
|
template <typename LeasePtr>
|
2012-10-16 16:39:32 +01:00
|
|
|
void
|
2012-11-26 19:17:27 +00:00
|
|
|
MySqlLeaseMgr::updateLeaseCommon(StatementIndex stindex, MYSQL_BIND* bind,
|
|
|
|
const LeasePtr& lease) {
|
2012-11-23 14:08:00 +00:00
|
|
|
|
|
|
|
// Bind the parameters to the statement
|
2012-11-23 18:23:21 +00:00
|
|
|
int status = mysql_stmt_bind_param(statements_[stindex], bind);
|
2012-11-23 14:08:00 +00:00
|
|
|
checkError(status, stindex, "unable to bind parameters");
|
|
|
|
|
|
|
|
// Execute
|
|
|
|
status = mysql_stmt_execute(statements_[stindex]);
|
|
|
|
checkError(status, stindex, "unable to execute");
|
|
|
|
|
|
|
|
// See how many rows were affected. The statement should only update a
|
|
|
|
// single row.
|
|
|
|
int affected_rows = mysql_stmt_affected_rows(statements_[stindex]);
|
|
|
|
if (affected_rows == 0) {
|
|
|
|
isc_throw(NoSuchLease, "unable to update lease for address " <<
|
2014-01-07 10:49:14 +05:30
|
|
|
lease->addr_ << " as it does not exist");
|
2012-11-23 14:08:00 +00:00
|
|
|
} else if (affected_rows > 1) {
|
|
|
|
// Should not happen - primary key constraint should only have selected
|
|
|
|
// one row.
|
|
|
|
isc_throw(DbOperationError, "apparently updated more than one lease "
|
2014-01-07 10:49:14 +05:30
|
|
|
"that had the address " << lease->addr_);
|
2012-11-23 14:08:00 +00:00
|
|
|
}
|
2012-10-16 16:39:32 +01:00
|
|
|
}
|
|
|
|
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2012-11-23 18:23:21 +00:00
|
|
|
void
|
|
|
|
MySqlLeaseMgr::updateLease4(const Lease4Ptr& lease) {
|
|
|
|
const StatementIndex stindex = UPDATE_LEASE4;
|
|
|
|
|
2012-12-18 13:11:17 +00:00
|
|
|
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
|
|
|
|
DHCPSRV_MYSQL_UPDATE_ADDR4).arg(lease->addr_.toText());
|
2012-12-14 22:19:31 +00:00
|
|
|
|
2012-11-23 18:23:21 +00:00
|
|
|
// Create the MYSQL_BIND array for the data being updated
|
|
|
|
std::vector<MYSQL_BIND> bind = exchange4_->createBindForSend(lease);
|
|
|
|
|
|
|
|
// Set up the WHERE clause and append it to the MYSQL_BIND array
|
|
|
|
MYSQL_BIND where;
|
|
|
|
memset(&where, 0, sizeof(where));
|
|
|
|
|
|
|
|
uint32_t addr4 = static_cast<uint32_t>(lease->addr_);
|
|
|
|
where.buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
where.buffer = reinterpret_cast<char*>(&addr4);
|
|
|
|
where.is_unsigned = MLM_TRUE;
|
|
|
|
bind.push_back(where);
|
|
|
|
|
|
|
|
// Drop to common update code
|
2012-11-26 19:17:27 +00:00
|
|
|
updateLeaseCommon(stindex, &bind[0], lease);
|
2012-11-23 18:23:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-16 16:39:32 +01:00
|
|
|
void
|
2012-10-29 19:19:36 +00:00
|
|
|
MySqlLeaseMgr::updateLease6(const Lease6Ptr& lease) {
|
2012-11-04 20:20:21 +00:00
|
|
|
const StatementIndex stindex = UPDATE_LEASE6;
|
|
|
|
|
2012-12-18 13:11:17 +00:00
|
|
|
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
|
2013-09-13 10:05:28 -04:00
|
|
|
DHCPSRV_MYSQL_UPDATE_ADDR6).arg(lease->addr_.toText())
|
|
|
|
.arg(lease->type_);
|
2012-12-14 22:19:31 +00:00
|
|
|
|
2012-10-29 19:19:36 +00:00
|
|
|
// Create the MYSQL_BIND array for the data being updated
|
2012-11-06 12:58:10 +00:00
|
|
|
std::vector<MYSQL_BIND> bind = exchange6_->createBindForSend(lease);
|
2012-10-29 19:19:36 +00:00
|
|
|
|
|
|
|
// Set up the WHERE clause value
|
|
|
|
MYSQL_BIND where;
|
|
|
|
memset(&where, 0, sizeof(where));
|
|
|
|
|
|
|
|
std::string addr6 = lease->addr_.toText();
|
|
|
|
unsigned long addr6_length = addr6.size();
|
|
|
|
|
2012-11-08 12:14:10 +00:00
|
|
|
// See the earlier description of the use of "const_cast" when accessing
|
|
|
|
// the address for an explanation of the reason.
|
2012-10-29 19:19:36 +00:00
|
|
|
where.buffer_type = MYSQL_TYPE_STRING;
|
|
|
|
where.buffer = const_cast<char*>(addr6.c_str());
|
|
|
|
where.buffer_length = addr6_length;
|
|
|
|
where.length = &addr6_length;
|
|
|
|
bind.push_back(where);
|
|
|
|
|
2012-11-23 18:23:21 +00:00
|
|
|
// Drop to common update code
|
2012-11-26 19:17:27 +00:00
|
|
|
updateLeaseCommon(stindex, &bind[0], lease);
|
2012-11-23 18:23:21 +00:00
|
|
|
}
|
|
|
|
|
2012-12-10 11:21:24 +00:00
|
|
|
// Delete lease methods. Similar to other groups of methods, these comprise
|
|
|
|
// a per-type method that sets up the relevant MYSQL_BIND array (in this
|
|
|
|
// case, a single method for both V4 and V6 addresses) and a common method that
|
|
|
|
// handles the common processing.
|
2012-11-23 18:23:21 +00:00
|
|
|
|
2015-09-07 13:58:22 +02:00
|
|
|
uint64_t
|
2012-12-10 11:21:24 +00:00
|
|
|
MySqlLeaseMgr::deleteLeaseCommon(StatementIndex stindex, MYSQL_BIND* bind) {
|
2012-11-23 18:23:21 +00:00
|
|
|
|
|
|
|
// Bind the input parameters to the statement
|
|
|
|
int status = mysql_stmt_bind_param(statements_[stindex], bind);
|
|
|
|
checkError(status, stindex, "unable to bind WHERE clause parameter");
|
2012-10-29 19:19:36 +00:00
|
|
|
|
|
|
|
// Execute
|
2012-11-04 20:20:21 +00:00
|
|
|
status = mysql_stmt_execute(statements_[stindex]);
|
|
|
|
checkError(status, stindex, "unable to execute");
|
2012-10-29 19:19:36 +00:00
|
|
|
|
2012-11-23 18:23:21 +00:00
|
|
|
// See how many rows were affected. Note that the statement may delete
|
|
|
|
// multiple rows.
|
2015-09-07 13:58:22 +02:00
|
|
|
return (static_cast<uint64_t>(mysql_stmt_affected_rows(statements_[stindex])));
|
2012-10-16 16:39:32 +01:00
|
|
|
}
|
|
|
|
|
2012-11-23 18:23:21 +00:00
|
|
|
|
2012-10-16 16:39:32 +01:00
|
|
|
bool
|
2012-12-10 11:21:24 +00:00
|
|
|
MySqlLeaseMgr::deleteLease(const isc::asiolink::IOAddress& addr) {
|
2012-12-18 13:11:17 +00:00
|
|
|
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
|
|
|
|
DHCPSRV_MYSQL_DELETE_ADDR).arg(addr.toText());
|
2012-11-21 12:44:18 +00:00
|
|
|
|
|
|
|
// Set up the WHERE clause value
|
|
|
|
MYSQL_BIND inbind[1];
|
|
|
|
memset(inbind, 0, sizeof(inbind));
|
|
|
|
|
2012-12-10 11:21:24 +00:00
|
|
|
if (addr.isV4()) {
|
|
|
|
uint32_t addr4 = static_cast<uint32_t>(addr);
|
2012-10-16 16:39:32 +01:00
|
|
|
|
2012-12-10 11:21:24 +00:00
|
|
|
inbind[0].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
inbind[0].buffer = reinterpret_cast<char*>(&addr4);
|
|
|
|
inbind[0].is_unsigned = MLM_TRUE;
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2015-09-07 13:58:22 +02:00
|
|
|
return (deleteLeaseCommon(DELETE_LEASE4, inbind) > 0);
|
2012-10-22 16:07:34 +01:00
|
|
|
|
2012-12-10 11:21:24 +00:00
|
|
|
} else {
|
|
|
|
std::string addr6 = addr.toText();
|
|
|
|
unsigned long addr6_length = addr6.size();
|
2012-10-22 16:07:34 +01:00
|
|
|
|
2012-12-10 11:21:24 +00:00
|
|
|
// See the earlier description of the use of "const_cast" when accessing
|
|
|
|
// the address for an explanation of the reason.
|
|
|
|
inbind[0].buffer_type = MYSQL_TYPE_STRING;
|
|
|
|
inbind[0].buffer = const_cast<char*>(addr6.c_str());
|
|
|
|
inbind[0].buffer_length = addr6_length;
|
|
|
|
inbind[0].length = &addr6_length;
|
2012-10-22 16:07:34 +01:00
|
|
|
|
2015-09-07 13:58:22 +02:00
|
|
|
return (deleteLeaseCommon(DELETE_LEASE6, inbind) > 0);
|
2012-12-10 11:21:24 +00:00
|
|
|
}
|
2012-10-16 16:39:32 +01:00
|
|
|
}
|
|
|
|
|
2015-09-03 11:35:25 +02:00
|
|
|
uint64_t
|
2015-09-07 13:58:22 +02:00
|
|
|
MySqlLeaseMgr::deleteExpiredReclaimedLeases4(const uint32_t secs) {
|
|
|
|
return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE4_STATE_EXPIRED));
|
2015-08-20 19:25:38 +02:00
|
|
|
}
|
|
|
|
|
2015-09-03 11:35:25 +02:00
|
|
|
uint64_t
|
2015-09-07 13:58:22 +02:00
|
|
|
MySqlLeaseMgr::deleteExpiredReclaimedLeases6(const uint32_t secs) {
|
|
|
|
return (deleteExpiredReclaimedLeasesCommon(secs, DELETE_LEASE6_STATE_EXPIRED));
|
2015-08-20 19:25:38 +02:00
|
|
|
}
|
|
|
|
|
2015-09-07 13:58:22 +02:00
|
|
|
uint64_t
|
|
|
|
MySqlLeaseMgr::deleteExpiredReclaimedLeasesCommon(const uint32_t secs,
|
|
|
|
StatementIndex statement_index) {
|
|
|
|
// Set up the WHERE clause value
|
|
|
|
MYSQL_BIND inbind[2];
|
|
|
|
memset(inbind, 0, sizeof(inbind));
|
|
|
|
|
|
|
|
uint32_t state = static_cast<uint32_t>(Lease::STATE_EXPIRED_RECLAIMED);
|
|
|
|
inbind[0].buffer_type = MYSQL_TYPE_LONG;
|
|
|
|
inbind[0].buffer = reinterpret_cast<char*>(&state);
|
|
|
|
inbind[0].is_unsigned = MLM_TRUE;
|
|
|
|
|
|
|
|
// Expiration timestamp.
|
|
|
|
MYSQL_TIME expire_time;
|
|
|
|
convertToDatabaseTime(time(NULL) - static_cast<time_t>(secs), expire_time);
|
|
|
|
inbind[1].buffer_type = MYSQL_TYPE_TIMESTAMP;
|
|
|
|
inbind[1].buffer = reinterpret_cast<char*>(&expire_time);
|
|
|
|
inbind[1].buffer_length = sizeof(expire_time);
|
|
|
|
|
|
|
|
return (deleteLeaseCommon(statement_index, inbind));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-20 19:25:38 +02:00
|
|
|
|
2012-11-23 18:23:21 +00:00
|
|
|
// Miscellaneous database methods.
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2012-10-16 16:39:32 +01:00
|
|
|
std::string
|
|
|
|
MySqlLeaseMgr::getName() const {
|
2012-10-24 19:18:33 +01:00
|
|
|
std::string name = "";
|
|
|
|
try {
|
|
|
|
name = getParameter("name");
|
|
|
|
} catch (...) {
|
2012-12-03 15:35:36 +00:00
|
|
|
// Return an empty name
|
2012-10-24 19:18:33 +01:00
|
|
|
}
|
|
|
|
return (name);
|
2012-10-16 16:39:32 +01:00
|
|
|
}
|
|
|
|
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2012-10-16 16:39:32 +01:00
|
|
|
std::string
|
|
|
|
MySqlLeaseMgr::getDescription() const {
|
2012-11-06 12:58:10 +00:00
|
|
|
return (std::string("MySQL Database"));
|
2012-10-16 16:39:32 +01:00
|
|
|
}
|
|
|
|
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2012-10-16 16:39:32 +01:00
|
|
|
std::pair<uint32_t, uint32_t>
|
|
|
|
MySqlLeaseMgr::getVersion() const {
|
2012-11-04 20:20:21 +00:00
|
|
|
const StatementIndex stindex = GET_VERSION;
|
|
|
|
|
2012-12-18 13:11:17 +00:00
|
|
|
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
|
|
|
|
DHCPSRV_MYSQL_GET_VERSION);
|
2012-12-14 22:19:31 +00:00
|
|
|
|
2012-10-18 11:33:51 +01:00
|
|
|
uint32_t major; // Major version number
|
|
|
|
uint32_t minor; // Minor version number
|
|
|
|
|
|
|
|
// Execute the prepared statement
|
2012-11-04 20:20:21 +00:00
|
|
|
int status = mysql_stmt_execute(statements_[stindex]);
|
2012-10-18 11:33:51 +01:00
|
|
|
if (status != 0) {
|
|
|
|
isc_throw(DbOperationError, "unable to execute <"
|
2012-11-04 20:20:21 +00:00
|
|
|
<< text_statements_[stindex] << "> - reason: " <<
|
2012-10-18 11:33:51 +01:00
|
|
|
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);
|
|
|
|
|
2012-11-04 20:20:21 +00:00
|
|
|
status = mysql_stmt_bind_result(statements_[stindex], bind);
|
2012-10-18 11:33:51 +01:00
|
|
|
if (status != 0) {
|
|
|
|
isc_throw(DbOperationError, "unable to bind result set: " <<
|
|
|
|
mysql_error(mysql_));
|
|
|
|
}
|
|
|
|
|
2012-11-08 12:50:34 +00:00
|
|
|
// Fetch the data and set up the "release" object to release associated
|
|
|
|
// resources when this method exits then retrieve the data.
|
|
|
|
MySqlFreeResult fetch_release(statements_[stindex]);
|
2012-11-04 20:20:21 +00:00
|
|
|
status = mysql_stmt_fetch(statements_[stindex]);
|
2012-10-18 11:33:51 +01:00
|
|
|
if (status != 0) {
|
|
|
|
isc_throw(DbOperationError, "unable to obtain result set: " <<
|
|
|
|
mysql_error(mysql_));
|
|
|
|
}
|
|
|
|
|
|
|
|
return (std::make_pair(major, minor));
|
2012-10-16 16:39:32 +01:00
|
|
|
}
|
|
|
|
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2012-10-20 22:52:25 +01:00
|
|
|
void
|
|
|
|
MySqlLeaseMgr::commit() {
|
2012-12-18 13:11:17 +00:00
|
|
|
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MYSQL_COMMIT);
|
2012-10-20 22:52:25 +01:00
|
|
|
if (mysql_commit(mysql_) != 0) {
|
|
|
|
isc_throw(DbOperationError, "commit failed: " << mysql_error(mysql_));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-06 12:58:10 +00:00
|
|
|
|
2012-10-20 22:52:25 +01:00
|
|
|
void
|
|
|
|
MySqlLeaseMgr::rollback() {
|
2012-12-18 13:11:17 +00:00
|
|
|
LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MYSQL_ROLLBACK);
|
2012-10-20 22:52:25 +01:00
|
|
|
if (mysql_rollback(mysql_) != 0) {
|
|
|
|
isc_throw(DbOperationError, "rollback failed: " << mysql_error(mysql_));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-16 16:39:32 +01:00
|
|
|
}; // end of isc::dhcp namespace
|
|
|
|
}; // end of isc namespace
|