mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-16 12:50:12 +00:00
[4212] Patch as provided by Adam Kalmus
- Tomek verified that it applied cleanly, compiled and unit-tests passed.
This commit is contained in:
@@ -14,6 +14,9 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <asiolink/io_address.h>
|
||||
#include <dhcp/duid.h>
|
||||
#include <dhcp/hwaddr.h>
|
||||
@@ -51,14 +54,16 @@ const size_t HOSTNAME_MAX_LEN = 255;
|
||||
TaggedStatement tagged_statements[] = {
|
||||
{MySqlHostDataSource::INSERT_HOST,
|
||||
"INSERT INTO hosts(host_id, dhcp_identifier, dhcp_identifier_type, "
|
||||
"dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
|
||||
"dhcp4_client_classes, dhcp6_client_classes) "
|
||||
"dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
|
||||
"dhcp4_client_classes, dhcp6_client_classes) "
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"},
|
||||
{MySqlHostDataSource::INSERT_V6_RESRV,
|
||||
"INSERT INTO ipv6_reservations(host_id, address, prefix_len, type, dhcp6_iaid) "
|
||||
"VALUES (?,?,?,?,?)"},
|
||||
"INSERT INTO ipv6_reservations(reservation_id, address, prefix_len, type, "
|
||||
"dhcp6_iaid, host_id) "
|
||||
"VALUES (?,?,?,?,?,?)"},
|
||||
{MySqlHostDataSource::GET_V6_RESRV,
|
||||
"SELECT address, prefix_len, type, dhcp6_iaid FROM ipv6_reservations "
|
||||
"SELECT reservation_id, address, prefix_len, type, dhcp6_iaid, host_id "
|
||||
"FROM ipv6_reservations "
|
||||
"WHERE host_id = ?"},
|
||||
{MySqlHostDataSource::GET_HOST_HWADDR_DUID,
|
||||
"SELECT host_id, dhcp_identifier, dhcp_identifier_type, "
|
||||
@@ -97,8 +102,8 @@ TaggedStatement tagged_statements[] = {
|
||||
"dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
|
||||
"dhcp4_client_classes, dhcp6_client_classes "
|
||||
"FROM hosts h, ipv6_reservations r "
|
||||
"WHERE h.host_id = r.host_id AND r.prefix_len = ? "
|
||||
" AND r.address = ?"},
|
||||
"WHERE h.host_id = r.host_id "
|
||||
"AND r.address = ? AND r.prefix_len = ?"},
|
||||
{MySqlHostDataSource::GET_VERSION,
|
||||
"SELECT version, minor FROM schema_version"},
|
||||
{MySqlHostDataSource::NUM_STATEMENTS, NULL}
|
||||
@@ -560,7 +565,7 @@ private:
|
||||
|
||||
class MySqlIPv6ReservationExchange {
|
||||
/// @brief Set number of database columns for this reservation structure
|
||||
static const size_t RESRV_COLUMNS = 5;
|
||||
static const size_t RESRV_COLUMNS = 6;
|
||||
|
||||
public:
|
||||
|
||||
@@ -636,14 +641,15 @@ public:
|
||||
return (result);
|
||||
}
|
||||
|
||||
/// @brief Create MYSQL_BIND objects for Host Pointer
|
||||
/// @brief Create MYSQL_BIND objects for IPv6 Reservation
|
||||
///
|
||||
/// Fills in the MYSQL_BIND array for sending data in the Host object to
|
||||
/// the database.
|
||||
/// Fills in the MYSQL_BIND array for sending data in the IPv6 Reservation
|
||||
/// object to the database.
|
||||
///
|
||||
/// @param host Host object to be added to the database.
|
||||
/// None of the fields in the host reservation are modified -
|
||||
/// the host data is only read.
|
||||
/// @param resv IPv6 reservation object to be added to the database.
|
||||
/// None of the fields in the reservation are modified -
|
||||
/// the reservation data is only read.
|
||||
/// @param id ID of a host owning this reservation
|
||||
///
|
||||
/// @return Vector of MySQL BIND objects representing the data to be added.
|
||||
std::vector<MYSQL_BIND> createBindForSend(const IPv6Resrv& resv, const HostID& id) {
|
||||
@@ -662,10 +668,12 @@ public:
|
||||
// Set up the structures for the various components of the host structure.
|
||||
|
||||
try {
|
||||
// host_id : INT UNSIGNED NOT NULL
|
||||
host_id_ = static_cast<uint32_t>(NULL);
|
||||
// reservation_id INT UNSIGNED NOT NULL
|
||||
// The host_id is auto_incremented by MySQL database,
|
||||
// so we need to pass the NULL value
|
||||
reservation_id_ = static_cast<uint32_t>(NULL);
|
||||
bind_[0].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind_[0].buffer = reinterpret_cast<char*>(&host_id_);
|
||||
bind_[0].buffer = reinterpret_cast<char*>(&reservation_id_);
|
||||
bind_[0].is_unsigned = MLM_TRUE;
|
||||
|
||||
// address VARCHAR(39)
|
||||
@@ -697,10 +705,15 @@ public:
|
||||
bind_[4].buffer = reinterpret_cast<char*>(&iaid_);
|
||||
bind_[4].is_unsigned = MLM_TRUE;
|
||||
|
||||
// host_id INT UNSIGNED NOT NULL
|
||||
bind_[5].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind_[5].buffer = reinterpret_cast<char*>(&host_id_);
|
||||
bind_[5].is_unsigned = MLM_TRUE;
|
||||
|
||||
} catch (const std::exception& ex) {
|
||||
isc_throw(DbOperationError,
|
||||
"Could not create bind array from Host: "
|
||||
<< host_->getHostname() << ", reason: " << ex.what());
|
||||
"Could not create bind array from IPv6 Reservation: "
|
||||
<< resv_.toText() << ", reason: " << ex.what());
|
||||
}
|
||||
|
||||
// Add the data to the vector. Note the end element is one after the
|
||||
@@ -723,13 +736,43 @@ public:
|
||||
// code that explicitly sets is_null is there, but is commented out.
|
||||
memset(bind_, 0, sizeof(bind_));
|
||||
|
||||
/// @todo: set bind_[X] fields here.
|
||||
// reservation_id INT UNSIGNED NOT NULL
|
||||
bind_[0].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind_[0].buffer = reinterpret_cast<char*>(&reservation_id_);
|
||||
bind_[0].is_unsigned = MLM_TRUE;
|
||||
|
||||
// address VARCHAR(39)
|
||||
bind_[1].buffer_type = MYSQL_TYPE_BLOB;
|
||||
bind_[1].buffer = reinterpret_cast<char*>
|
||||
(const_cast<char*>(&address_[0]));
|
||||
bind_[1].buffer_length = address_len_;
|
||||
bind_[1].length = &address_len_;
|
||||
|
||||
// prefix_len tinyint
|
||||
bind_[2].buffer_type = MYSQL_TYPE_TINY;
|
||||
bind_[2].buffer = reinterpret_cast<char*>(&prefix_len_);
|
||||
bind_[2].is_unsigned = MLM_TRUE;
|
||||
|
||||
// type tinyint
|
||||
bind_[3].buffer_type = MYSQL_TYPE_TINY;
|
||||
bind_[3].buffer = reinterpret_cast<char*>(&type_);
|
||||
bind_[3].is_unsigned = MLM_TRUE;
|
||||
|
||||
// dhcp6_iaid INT UNSIGNED
|
||||
bind_[4].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind_[4].buffer = reinterpret_cast<char*>(&iaid_);
|
||||
bind_[4].is_unsigned = MLM_TRUE;
|
||||
|
||||
// host_id INT UNSIGNED NOT NULL
|
||||
bind_[5].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind_[5].buffer = reinterpret_cast<char*>(&host_id_);
|
||||
bind_[5].is_unsigned = MLM_TRUE;
|
||||
|
||||
// Add the error flags
|
||||
setErrorIndicators(bind_, error_, RESRV_COLUMNS);
|
||||
|
||||
// .. and check that we have the numbers correct at compile time.
|
||||
BOOST_STATIC_ASSERT(4 < RESRV_COLUMNS);
|
||||
BOOST_STATIC_ASSERT(5 < RESRV_COLUMNS);
|
||||
|
||||
// Add the data to the vector. Note the end element is one after the
|
||||
// end of the array.
|
||||
@@ -745,9 +788,31 @@ public:
|
||||
///
|
||||
/// @return IPv6Resrv object (containing IPv6 address or prefix reservation)
|
||||
IPv6Resrv getIPv6ReservData(){
|
||||
/// @todo: Implement actual extraction.
|
||||
IPv6Resrv r(IPv6Resrv::TYPE_NA, IOAddress("::"), 128);
|
||||
|
||||
// Set the IPv6 Reservation type (0 = IA_NA, 1 = IA_TA, 2 = IA_PD)
|
||||
IPv6Resrv::Type type = IPv6Resrv::TYPE_NA;
|
||||
|
||||
switch (type_) {
|
||||
case 0:
|
||||
type = IPv6Resrv::TYPE_NA;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
type = IPv6Resrv::TYPE_TA;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
type = IPv6Resrv::TYPE_PD;
|
||||
break;
|
||||
|
||||
default:
|
||||
isc_throw(BadValue,
|
||||
"invalid IPv6 reservation type returned: "
|
||||
<< static_cast<int>(type_)
|
||||
<< ". Only 0, 1 or 2 are allowed.");
|
||||
}
|
||||
|
||||
IPv6Resrv r(type, IOAddress(address_), prefix_len_);
|
||||
return (r);
|
||||
}
|
||||
|
||||
@@ -787,6 +852,7 @@ public:
|
||||
|
||||
private:
|
||||
uint64_t host_id_; /// Host unique identifier
|
||||
uint64_t reservation_id_; /// Host unique identifier
|
||||
size_t host_id_length_; /// Length of the host unique ID
|
||||
std::string address_; ///< Address (or prefix)
|
||||
size_t address_len_; ///< Length of the textual address representation
|
||||
@@ -805,9 +871,9 @@ private:
|
||||
IPv6Resrv resv_;
|
||||
|
||||
MYSQL_BIND bind_[RESRV_COLUMNS];
|
||||
std::string columns_[RESRV_COLUMNS]; /// Column names
|
||||
std::string columns_[RESRV_COLUMNS]; /// Column names
|
||||
my_bool error_[RESRV_COLUMNS]; /// Error array
|
||||
HostPtr host_; // Pointer to Host object
|
||||
HostPtr host_; /// Pointer to Host object
|
||||
};
|
||||
|
||||
// MySqlHostDataSource Constructor and Destructor
|
||||
@@ -879,21 +945,10 @@ MySqlHostDataSource::add(const HostPtr& host) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ok, there are v6 reservations. Let's insert them. But first, we need
|
||||
// to learn what's the host_id of the host we just added.
|
||||
|
||||
/// @todo: See how get6() is done in hostMgr - calls with duid only first,
|
||||
/// and if can't find it, then calls with hwaddr only.
|
||||
ConstHostPtr from_db = get6(host->getIPv6SubnetID(), host->getDuid(),
|
||||
host->getHWAddress());
|
||||
if (!from_db) {
|
||||
// Oops, we have a problem. We can't find the host we just added.
|
||||
isc_throw(DbOperationError, "Unable to retrieve the host that just "
|
||||
"had been added");
|
||||
}
|
||||
|
||||
// Gets the last inserted hosts id
|
||||
uint64_t host_id = mysql_insert_id(conn_.mysql_);
|
||||
for (IPv6ResrvIterator resv = v6resv.first; resv != v6resv.second; ++resv) {
|
||||
addResv(resv->second, from_db->getHostId());
|
||||
addResv(resv->second, host_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -926,6 +981,88 @@ MySqlHostDataSource::addQuery(StatementIndex stindex,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MySqlHostDataSource::getIPv6ReservationCollection(StatementIndex stindex,
|
||||
MYSQL_BIND* bind, boost::shared_ptr<MySqlIPv6ReservationExchange> exchange,
|
||||
IPv6ResrvCollection& result) const {
|
||||
|
||||
// Bind the selection parameters to the statement
|
||||
int status = mysql_stmt_bind_param(conn_.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(conn_.statements_[stindex], &outbind[0]);
|
||||
checkError(status, stindex, "unable to bind SELECT clause parameters");
|
||||
|
||||
// Execute the statement
|
||||
status = mysql_stmt_execute(conn_.statements_[stindex]);
|
||||
checkError(status, stindex, "unable to execute");
|
||||
|
||||
// Ensure that all the lease information is retrieved in one go to avoid
|
||||
// overhead of going back and forth between client and server.
|
||||
status = mysql_stmt_store_result(conn_.statements_[stindex]);
|
||||
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(conn_.statements_[stindex]);
|
||||
while ((status = mysql_stmt_fetch(conn_.statements_[stindex])) == 0) {
|
||||
try {
|
||||
result.insert(IPv6ResrvTuple(exchange->getIPv6ReservData().getType(),
|
||||
exchange->getIPv6ReservData()));
|
||||
|
||||
} catch (const isc::BadValue& ex) {
|
||||
// Rethrow the exception with a bit more data.
|
||||
isc_throw(BadValue, ex.what() << ". Statement is <" <<
|
||||
conn_.text_statements_[stindex] << ">");
|
||||
}
|
||||
}
|
||||
|
||||
// How did the fetch end?
|
||||
if (status == 1) {
|
||||
// Error - unable to fetch results
|
||||
checkError(status, stindex, "unable to fetch results");
|
||||
} else if (status == MYSQL_DATA_TRUNCATED) {
|
||||
// Data truncated - throw an exception indicating what was at fault
|
||||
isc_throw(DataTruncated, conn_.text_statements_[stindex]
|
||||
<< " returned truncated data: columns affected are "
|
||||
<< exchange->getErrorColumns());
|
||||
}
|
||||
}
|
||||
|
||||
IPv6ResrvCollection
|
||||
MySqlHostDataSource::getAllReservations(HostID host_id) const{
|
||||
|
||||
// Set up the WHERE clause value
|
||||
MYSQL_BIND inbind[1];
|
||||
memset(inbind, 0, sizeof(inbind));
|
||||
|
||||
uint32_t id = static_cast<uint32_t>(host_id);
|
||||
inbind[0].buffer_type = MYSQL_TYPE_LONG;
|
||||
inbind[0].buffer = reinterpret_cast<char*>(&id);
|
||||
inbind[0].is_unsigned = MLM_TRUE;
|
||||
|
||||
IPv6ResrvCollection result;
|
||||
getIPv6ReservationCollection(GET_V6_RESRV, inbind, resvExchange_, result);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
void
|
||||
MySqlHostDataSource::assignReservations(HostPtr& host) const {
|
||||
|
||||
IPv6ResrvCollection reservations;
|
||||
reservations = getAllReservations(host->getHostId());
|
||||
|
||||
for (IPv6ResrvIterator resv = reservations.begin(); resv != reservations.end(); ++resv){
|
||||
host->addReservation(resv->second);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MySqlHostDataSource::getHostCollection(StatementIndex stindex, MYSQL_BIND* bind,
|
||||
boost::shared_ptr<MySqlHostReservationExchange> exchange,
|
||||
@@ -955,9 +1092,12 @@ MySqlHostDataSource::getHostCollection(StatementIndex stindex, MYSQL_BIND* bind,
|
||||
// retrieve the data.
|
||||
MySqlFreeResult fetch_release(conn_.statements_[stindex]);
|
||||
int count = 0;
|
||||
HostPtr host;
|
||||
while ((status = mysql_stmt_fetch(conn_.statements_[stindex])) == 0) {
|
||||
try {
|
||||
result.push_back(exchange->getHostData());
|
||||
host = exchange->getHostData();
|
||||
assignReservations(host);
|
||||
result.push_back(host);
|
||||
|
||||
} catch (const isc::BadValue& ex) {
|
||||
// Rethrow the exception with a bit more data.
|
||||
@@ -1228,15 +1368,22 @@ MySqlHostDataSource::get6(const asiolink::IOAddress& prefix,
|
||||
MYSQL_BIND inbind[2];
|
||||
memset(inbind, 0, sizeof(inbind));
|
||||
|
||||
inbind[0].buffer_type = MYSQL_TYPE_LONG;
|
||||
inbind[0].buffer = reinterpret_cast<char*>(&prefix.toBytes()[0]);
|
||||
inbind[0].is_unsigned = MLM_TRUE;
|
||||
std::string addr6 = prefix.toText();
|
||||
unsigned long addr6_length = addr6.size();
|
||||
|
||||
inbind[0].buffer_type = MYSQL_TYPE_BLOB;
|
||||
inbind[0].buffer = reinterpret_cast<char*>
|
||||
(const_cast<char*>(addr6.c_str()));
|
||||
inbind[0].length = &addr6_length;
|
||||
inbind[0].buffer_length = addr6_length;
|
||||
|
||||
|
||||
uint8_t tmp = prefix_len;
|
||||
inbind[1].buffer_type = MYSQL_TYPE_LONG;
|
||||
inbind[1].buffer_type = MYSQL_TYPE_TINY;
|
||||
inbind[1].buffer = reinterpret_cast<char*>(&tmp);
|
||||
inbind[1].is_unsigned = MLM_TRUE;
|
||||
|
||||
|
||||
ConstHostCollection collection;
|
||||
getHostCollection(GET_HOST_PREFIX, inbind, hostExchange_,
|
||||
collection, true);
|
||||
|
Reference in New Issue
Block a user