Commit 301cadd1 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[trac61] documented the functions. not the main subject this ticket,

but it was missing so far and should be provided.
parent fa007383
......@@ -38,12 +38,12 @@ isLeap(const int y) {
return ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0);
}
int
unsigned int
yearSecs(const int year) {
return ((isLeap(year) ? 366 : 365 ) * 86400);
}
int
unsigned int
monthSecs(const int month, const int year) {
return ((days[month] + ((month == 1 && isLeap(year)) ? 1 : 0 )) * 86400);
}
......@@ -53,15 +53,15 @@ namespace isc {
namespace dns {
string
timeToText64(uint64_t t) {
timeToText64(uint64_t value) {
struct tm tm;
int secs;
unsigned int secs;
// We cannot rely on gmtime() because time_t may not be of 64 bit
// integer. The following conversion logic is borrowed from BIND 9.
tm.tm_year = 70;
while ((secs = yearSecs(tm.tm_year + 1900)) <= t) {
t -= secs;
while ((secs = yearSecs(tm.tm_year + 1900)) <= value) {
value -= secs;
++tm.tm_year;
if (tm.tm_year + 1900 > 9999) {
isc_throw(InvalidTime,
......@@ -70,26 +70,26 @@ timeToText64(uint64_t t) {
}
}
tm.tm_mon = 0;
while ((secs = monthSecs(tm.tm_mon, tm.tm_year + 1900)) <= t) {
t -= secs;
while ((secs = monthSecs(tm.tm_mon, tm.tm_year + 1900)) <= value) {
value -= secs;
tm.tm_mon++;
}
tm.tm_mday = 1;
while (86400 <= t) {
t -= 86400;
while (86400 <= value) {
value -= 86400;
++tm.tm_mday;
}
tm.tm_hour = 0;
while (3600 <= t) {
t -= 3600;
while (3600 <= value) {
value -= 3600;
++tm.tm_hour;
}
tm.tm_min = 0;
while (60 <= t) {
t -= 60;
while (60 <= value) {
value -= 60;
++tm.tm_min;
}
tm.tm_sec = t; // now t < 60, so this substitution is safe.
tm.tm_sec = value; // now t < 60, so this substitution is safe.
ostringstream oss;
oss << setfill('0')
......@@ -130,14 +130,14 @@ gettimeofdayWrapper() {
}
string
timeToText32(const uint32_t timeval) {
timeToText32(const uint32_t value) {
// We first adjust the time to the closest epoch based on the current time.
// Note that the following variables must be signed in order to handle
// time until year 2038 correctly.
const int64_t start = gettimeofdayWrapper() - 0x7fffffff;
int64_t base = 0;
int64_t t;
while ((t = (base + timeval)) < start) {
while ((t = (base + value)) < start) {
base += 0x100000000LL;
}
......@@ -203,6 +203,8 @@ timeFromText64(const string& time_txt) {
uint32_t
timeFromText32(const string& time_txt) {
// The implicit conversion from uint64_t to uint32_t should just work here,
// because we only need to drop higher 32 bits.
return (timeFromText64(time_txt));
}
}
......
......@@ -39,17 +39,102 @@ public:
isc::Exception(file, line, what) {}
};
uint32_t
timeFromText32(const std::string& time_txt);
///
/// \name DNSSEC time conversion functions.
///
/// These functions convert between times represented in seconds (in integer)
/// since epoch and those in the textual form used in the RRSIG records.
/// For integers we provide both 32-bit and 64-bit versions.
/// The RRSIG expiration and inception fields are both 32-bit unsigned
/// integers, so 32-bit versions would be more useful for protocol operations.
/// However, with 32-bit integers we need to take into account wrap-around
/// points and compare values using the serial number arithmetic as specified
/// in RFC4034, which would be more error prone. We therefore provide 64-bit
/// versions, too.
///
/// The timezone is always UTC for these functions.
//@{
/// Convert textual DNSSEC time to integer, 64-bit version.
///
/// The textual form must only consist of digits and be in the form of
/// YYYYMMDDHHmmSS, where:
/// - YYYY must be between 1970 and 9999
/// - MM must be between 01 and 12
/// - DD must be between 01 and 31 and must be a valid day for the month
/// represented in 'MM'. For example, if MM is 04, DD cannot be 31.
/// DD can be 29 when MM is 02 only when YYYY is a leap year.
/// - HH must be between 00 and 23
/// - mm must be between 00 and 59
/// - SS must be between 00 and 60
///
/// For all fields the range includes the begin and end values. Note that
/// 60 is allowed for 'SS', intending a leap second, although in real operation
/// it's unlikely to be specified.
///
/// If the given text is valid, this function converts it to an unsigned
/// 64-bit number of seconds since epoch (1 January 1970 00:00:00) and returns
/// the converted value. 64 bits are sufficient to represent all possible
/// values for the valid format uniquely, so there is no overflow.
///
/// \note RFC4034 also defines the textual form of an unsigned decimal integer
/// for the corresponding time in seconds. This function doesn't support
/// this form, and if given it throws an exception of class \c InvalidTime.
///
/// \exception InvalidTime The given textual representation is invalid.
///
/// \param time_txt Textual time in the form of YYYYMMDDHHmmSS
/// \return Seconds since epoch corresponding to \c time_txt
uint64_t
timeFromText64(const std::string& time_txt);
/// Convert textual DNSSEC time to integer, 32-bit version.
///
/// This version is the same as \c timeFromText64() except that the return
/// value is wrapped around to an unsigned 32-bit integer, simply dropping
/// the upper 32 bits.
uint32_t
timeFromText32(const std::string& time_txt);
/// Convert integral DNSSEC time to textual form, 64-bit version.
///
/// This function takes an integer that would be seconds since epoch and
/// converts it in the form of YYYYMMDDHHmmSS. For example, if \c value is
/// 0, it returns "19700101000000". If the value corresponds to a point
/// of time on and after year 10,000, which cannot be represented in the
/// YYYY... form, an exception of class \c InvalidTime will be thrown.
///
/// \exception InvalidTime The given time specifies on or after year 10,000.
/// \exception Other A standard exception, if resource allocation for the
/// returned text fails.
///
/// \param value Seconds since epoch to be converted.
/// \return Textual representation of \c value in the form of YYYYMMDDHHmmSS.
std::string
timeToText32(const uint32_t timeval);
timeToText64(uint64_t value);
/// Convert integral DNSSEC time to textual form, 32-bit version.
///
/// This version is the same as \c timeToText64(), but the time value
/// is expected to be the lower 32 bits of the full 64-bit value.
/// These two will be different on and after a certain point of time
/// in year 2106, so this function internally resolves the ambiguity
/// using the current system time at the time of function call;
/// it first identifies the range of [N*2^32 - 2^31, N*2^32 + 2^31)
/// that contains the current time, and interprets \c value in the context
/// of that range. It then applies the same process as \c timeToText64().
///
/// There is one important exception in this processing, however.
/// Until 19 Jan 2038 03:14:08 (2^31 seconds since epoch), this range
/// would contain time before epoch. In order to ensure the returned
/// value is also a valid input to \c timeFromText, this function uses
/// a special range [0, 2^32) until that time. As a result, all upper
/// half of the 32-bit values are treated as a future time. For example,
/// 2^32-1 (the highest value in 32-bit unsigned integers) will be converted
/// to "21060207062815", instead of "19691231235959".
std::string
timeToText64(uint64_t t);
timeToText32(uint32_t value);
//@}
}
}
......
......@@ -54,7 +54,8 @@ TEST_F(DNSSECTimeTest, fromText) {
EXPECT_THROW(timeFromText32("2011 101120000"), InvalidTime);
EXPECT_THROW(timeFromText32("201101011200-0"), InvalidTime);
// Short length
// Short length (or "decimal integer" version of representation;
// it's valid per RFC4034, but is not supported in this implementation)
EXPECT_THROW(timeFromText32("20100223"), InvalidTime);
// Leap year checks
......
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