Commit 3e52b2fe authored by Stephen Morris's avatar Stephen Morris
Browse files

[2342] Fix problems with time conversion

... traced to not initializing a "struct" properly.
parent 942be75a
...@@ -46,7 +46,7 @@ CREATE TABLE lease6 ( ...@@ -46,7 +46,7 @@ CREATE TABLE lease6 (
address VARCHAR(40) PRIMARY KEY NOT NULL, # IPv6 address address VARCHAR(40) PRIMARY KEY NOT NULL, # IPv6 address
hwaddr VARBINARY(20), # Hardware address hwaddr VARBINARY(20), # Hardware address
duid VARBINARY(128), # DUID duid VARBINARY(128), # DUID
lease_time INT UNSIGNED, # Length of the lease (seconds) valid_lifetime INT UNSIGNED, # Length of the lease (seconds)
expire TIMESTAMP, # Expiration time of the lease expire TIMESTAMP, # Expiration time of the lease
subnet_id INT UNSIGNED, # Subnet identification subnet_id INT UNSIGNED, # Subnet identification
pref_lifetime INT UNSIGNED, # Preferred lifetime pref_lifetime INT UNSIGNED, # Preferred lifetime
......
...@@ -111,23 +111,19 @@ public: ...@@ -111,23 +111,19 @@ public:
bind_[2].buffer_length = duid_length_; bind_[2].buffer_length = duid_length_;
bind_[2].length = &duid_length_; bind_[2].length = &duid_length_;
// The lease structure holds the client last transmission time (cltt_)
// and the valid lifetime (valid_lft_). For convenience for external
// tools, the data stored in the database is expiry time (expire) and
// lease time (lease+time). The relationship is given by:
//
// lease_time - valid_lft_
// expire = cltt_ + valid_lft_
//
MySqlLeaseMgr::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_,
expire_, lease_time_);
// lease_time: unsigned int // lease_time: unsigned int
bind_[3].buffer_type = MYSQL_TYPE_LONG; bind_[3].buffer_type = MYSQL_TYPE_LONG;
bind_[3].buffer = reinterpret_cast<char*>(&lease_time_); bind_[3].buffer = reinterpret_cast<char*>(&lease->valid_lft_);
bind_[3].is_unsigned = true_; bind_[3].is_unsigned = true_;
// expire: timestamp // 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_type = MYSQL_TYPE_TIMESTAMP;
bind_[4].buffer = reinterpret_cast<char*>(&expire_); bind_[4].buffer = reinterpret_cast<char*>(&expire_);
bind_[4].buffer_length = sizeof(expire_); bind_[4].buffer_length = sizeof(expire_);
...@@ -210,7 +206,7 @@ public: ...@@ -210,7 +206,7 @@ public:
// lease_time: unsigned int // lease_time: unsigned int
bind_[3].buffer_type = MYSQL_TYPE_LONG; bind_[3].buffer_type = MYSQL_TYPE_LONG;
bind_[3].buffer = reinterpret_cast<char*>(&lease_time_); bind_[3].buffer = reinterpret_cast<char*>(&valid_lifetime_);
bind_[3].is_unsigned = true_; bind_[3].is_unsigned = true_;
bind_[3].error = &error_[3]; bind_[3].error = &error_[3];
...@@ -269,16 +265,20 @@ public: ...@@ -269,16 +265,20 @@ public:
Lease6Ptr result(new Lease6()); Lease6Ptr result(new Lease6());
// Success - put the data in the lease object // Success - put the data in the lease object
// The address buffer is declared larger than the buffer size passed
// to the access function so that we can always append a null byte.
addr6_buffer_[addr6_length_] = '\0'; addr6_buffer_[addr6_length_] = '\0';
std::string address = addr6_buffer_; std::string address = addr6_buffer_;
result->addr_ = isc::asiolink::IOAddress(address);
// Set the other data, converting time as needed.
result->addr_ = isc::asiolink::IOAddress(address);
result->hwaddr_ = vector<uint8_t>(&hwaddr_buffer_[0], result->hwaddr_ = vector<uint8_t>(&hwaddr_buffer_[0],
&hwaddr_buffer_[hwaddr_length_]); &hwaddr_buffer_[hwaddr_length_]);
result->duid_.reset(new DUID(duid_buffer_, duid_length_)); result->duid_.reset(new DUID(duid_buffer_, duid_length_));
MySqlLeaseMgr::convertFromDatabaseTime(expire_, lease_time_, MySqlLeaseMgr::convertFromDatabaseTime(expire_, valid_lifetime_,
result->cltt_, result->cltt_);
result->valid_lft_); result->valid_lft_ = valid_lifetime_;
result->subnet_id_ = subnet_id_; result->subnet_id_ = subnet_id_;
result->preferred_lft_ = pref_lifetime_; result->preferred_lft_ = pref_lifetime_;
...@@ -323,7 +323,7 @@ private: ...@@ -323,7 +323,7 @@ private:
unsigned long hwaddr_length_; ///< Length of hardware address unsigned long hwaddr_length_; ///< Length of hardware address
uint32_t iaid_; ///< Identity association ID uint32_t iaid_; ///< Identity association ID
Lease6Ptr lease_; ///< Pointer to lease object Lease6Ptr lease_; ///< Pointer to lease object
uint32_t lease_time_; ///< Lease time uint32_t valid_lifetime_; ///< Lease time
uint8_t lease_type_; ///< Lease type uint8_t lease_type_; ///< Lease type
uint8_t prefixlen_; ///< Prefix length uint8_t prefixlen_; ///< Prefix length
uint32_t pref_lifetime_; ///< Preferred lifetime uint32_t pref_lifetime_; ///< Preferred lifetime
...@@ -337,15 +337,21 @@ private: ...@@ -337,15 +337,21 @@ private:
// //
// Note that the MySQL TIMESTAMP data type (used for "expire") converts data // 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 // from the current timezone to UTC for storage, and from UTC to the current
// timezone for retrieval. This means that the external interface - cltt - // timezone for retrieval.
// must be local time. //
// This causes no problems providing that:
// a) cltt is given in local time
// b) We let the system take care of timezone conversion when converting
// from a time read from the database into a local time.
void void
MySqlLeaseMgr::convertToDatabaseTime(time_t cltt, uint32_t valid_lft, MySqlLeaseMgr::convertToDatabaseTime(time_t cltt, uint32_t valid_lifetime,
MYSQL_TIME& expire, uint32_t& lease_time) { MYSQL_TIME& expire) {
// Calculate expiry time and convert to various date/time fields. // Calculate expiry time and convert to various date/time fields.
time_t expire_time = cltt + valid_lft; time_t expire_time = cltt + valid_lifetime;
// Convert to broken-out time
struct tm expire_tm; struct tm expire_tm;
(void) localtime_r(&expire_time, &expire_tm); (void) localtime_r(&expire_time, &expire_tm);
...@@ -358,19 +364,15 @@ MySqlLeaseMgr::convertToDatabaseTime(time_t cltt, uint32_t valid_lft, ...@@ -358,19 +364,15 @@ MySqlLeaseMgr::convertToDatabaseTime(time_t cltt, uint32_t valid_lft,
expire.second = expire_tm.tm_sec; expire.second = expire_tm.tm_sec;
expire.second_part = 0; // No fractional seconds expire.second_part = 0; // No fractional seconds
expire.neg = static_cast<my_bool>(0); // Not negative expire.neg = static_cast<my_bool>(0); // Not negative
// Set the lease time.
lease_time = valid_lft;
} }
void void
MySqlLeaseMgr::convertFromDatabaseTime(const MYSQL_TIME& expire, MySqlLeaseMgr::convertFromDatabaseTime(const MYSQL_TIME& expire,
uint32_t lease_time, time_t& cltt, uint32_t valid_lifetime, time_t& cltt) {
uint32_t& valid_lft) {
valid_lft = lease_time;
// Copy across fields from MYSQL_TIME structure. // Copy across fields from MYSQL_TIME structure.
struct tm expire_tm; struct tm expire_tm;
memset(&expire_tm, 0, sizeof(expire_tm));
expire_tm.tm_year = expire.year - 1900; expire_tm.tm_year = expire.year - 1900;
expire_tm.tm_mon = expire.month - 1; expire_tm.tm_mon = expire.month - 1;
...@@ -378,9 +380,10 @@ MySqlLeaseMgr::convertFromDatabaseTime(const MYSQL_TIME& expire, ...@@ -378,9 +380,10 @@ MySqlLeaseMgr::convertFromDatabaseTime(const MYSQL_TIME& expire,
expire_tm.tm_hour = expire.hour; expire_tm.tm_hour = expire.hour;
expire_tm.tm_min = expire.minute; expire_tm.tm_min = expire.minute;
expire_tm.tm_sec = expire.second; expire_tm.tm_sec = expire.second;
expire_tm.tm_isdst = -1; // Let the system work out about DST
// Convert to local time // Convert to local time
cltt = mktime(&expire_tm) - valid_lft; cltt = mktime(&expire_tm) - valid_lifetime;
} }
void void
...@@ -474,14 +477,14 @@ MySqlLeaseMgr::prepareStatements() { ...@@ -474,14 +477,14 @@ MySqlLeaseMgr::prepareStatements() {
"DELETE FROM lease6 WHERE address = ?"); "DELETE FROM lease6 WHERE address = ?");
prepareStatement(GET_LEASE6, prepareStatement(GET_LEASE6,
"SELECT address, hwaddr, duid, " "SELECT address, hwaddr, duid, "
"lease_time, expire, subnet_id, pref_lifetime, " "valid_lifetime, expire, subnet_id, pref_lifetime, "
"lease_type, iaid, prefix_len " "lease_type, iaid, prefix_len "
"FROM lease6 WHERE address = ?"); "FROM lease6 WHERE address = ?");
prepareStatement(GET_VERSION, prepareStatement(GET_VERSION,
"SELECT version, minor FROM schema_version"); "SELECT version, minor FROM schema_version");
prepareStatement(INSERT_LEASE6, prepareStatement(INSERT_LEASE6,
"INSERT INTO lease6(address, hwaddr, duid, " "INSERT INTO lease6(address, hwaddr, duid, "
"lease_time, expire, subnet_id, pref_lifetime, " "valid_lifetime, expire, subnet_id, pref_lifetime, "
"lease_type, iaid, prefix_len) " "lease_type, iaid, prefix_len) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
} }
......
...@@ -262,36 +262,32 @@ public: ...@@ -262,36 +262,32 @@ public:
/// @brief Convert Lease Time to Database Times /// @brief Convert Lease Time to Database Times
/// ///
/// Within the DHCP servers, times are stored as cltt (client last transmit /// Within the DHCP servers, times are stored as client last transmit time
/// time) and valid_lft (valid lifetime). In the database, the information /// and valid lifetime. In the database, the information is stored as
/// is stored as lease_time (lease time) and expire (time of expiry of the /// valid lifetime and "expire" (time of expiry of the lease). They are
/// lease). They are related by the equations: /// related by the equation:
/// ///
/// - lease_time = valid_lft /// - expire = client last transmit time + valid lifetime
/// - expire = cltt + valid_lft
/// ///
/// This method converts from the times in the lease object into times /// This method converts from the times in the lease object into times
/// able to be added to the database. /// able to be added to the database.
/// ///
/// @param cltt Client last transmit time /// @param cltt Client last transmit time
/// @param valid_lft Valid lifetime /// @param valid_lifetime Valid lifetime
/// @param expire Reference to MYSQL_TIME object where the expiry time of /// @param expire Reference to MYSQL_TIME object where the expiry time of
/// the lease will be put. /// the lease will be put.
/// @param lease_time Reference to the time_t object where the lease time
/// will be put.
static static
void convertToDatabaseTime(time_t cltt, uint32_t valid_lft, void convertToDatabaseTime(time_t cltt, uint32_t valid_lifetime,
MYSQL_TIME& expire, uint32_t& lease_time); MYSQL_TIME& expire);
/// @brief Convert Database Time to Lease Times /// @brief Convert Database Time to Lease Times
/// ///
/// Within the database, time is stored as lease_time (lease time) and /// Within the database, time is stored as "expire" (time of expiry of the
/// expire (time of expiry of the lease). In the DHCP server, the /// lease) and valid lifetime. In the DHCP server, the information is
/// information is stored as cltt (client last transmit time) and /// stored client last transmit time and valid lifetime. These are related
/// valid_lft (valid lifetime). These are related by the equations: /// by the equation:
/// ///
/// - valid_lft = lease_time /// - client last transmit time = expire - valid_lifetime
/// - cltt = expire - lease_time
/// ///
/// This method converts from the times in the database into times /// This method converts from the times in the database into times
/// able to be inserted into the lease object. /// able to be inserted into the lease object.
...@@ -301,10 +297,9 @@ public: ...@@ -301,10 +297,9 @@ public:
/// @param lease_time lifetime of the lease. /// @param lease_time lifetime of the lease.
/// @param cltt Reference to location where client last transmit time /// @param cltt Reference to location where client last transmit time
/// is put. /// is put.
/// @param valid_lft Reference to location where valid lifetime is put.
static static
void convertFromDatabaseTime(const MYSQL_TIME& expire, uint32_t lease_time, void convertFromDatabaseTime(const MYSQL_TIME& expire,
time_t& cltt, uint32_t& valid_lft); uint32_t valid_lifetime, time_t& cltt);
///@} ///@}
......
...@@ -132,21 +132,16 @@ TEST_F(MySqlLeaseMgrTest, CheckTimeConversion) { ...@@ -132,21 +132,16 @@ TEST_F(MySqlLeaseMgrTest, CheckTimeConversion) {
const time_t cltt = time(NULL); const time_t cltt = time(NULL);
const uint32_t valid_lft = 86400; // 1 day const uint32_t valid_lft = 86400; // 1 day
MYSQL_TIME expire; MYSQL_TIME expire;
uint32_t lease_time;
MySqlLeaseMgr::convertToDatabaseTime(cltt, valid_lft, expire, lease_time); MySqlLeaseMgr::convertToDatabaseTime(cltt, valid_lft, expire);
EXPECT_EQ(valid_lft, lease_time);
EXPECT_LE(2012, expire.year); // Code was written in 2012 EXPECT_LE(2012, expire.year); // Code was written in 2012
EXPECT_EQ(0, expire.second_part); EXPECT_EQ(0, expire.second_part);
EXPECT_EQ(0, expire.neg); EXPECT_EQ(0, expire.neg);
// Convert back // Convert back
time_t converted_cltt = 0; time_t converted_cltt = 0;
uint32_t converted_valid_lft = 0; MySqlLeaseMgr::convertFromDatabaseTime(expire, valid_lft, converted_cltt);
MySqlLeaseMgr::convertFromDatabaseTime(expire, lease_time, converted_cltt,
converted_valid_lft);
EXPECT_EQ(cltt, converted_cltt); EXPECT_EQ(cltt, converted_cltt);
EXPECT_EQ(valid_lft, converted_valid_lft);
} }
/// @brief Check that getVersion() works /// @brief Check that getVersion() works
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment