Commit 33d80f86 authored by JINMEI Tatuya's avatar JINMEI Tatuya

[2429] introduce a no-throw factor of RRTTL and use it in the loader.

parent e2ff6e8c
......@@ -187,18 +187,23 @@ private:
}
}
// Try to set/reset the current TTL from a candidate TTL. It's possible
// Try to set/reset the current TTL from candidate TTL text. It's possible
// it does not actually represent a TTL (which is not immediately
// considered an error). Return true iff it's recognized as a valid TTL
// (and only in which case the current TTL is set).
bool setCurrentTTL(const string& ttl_txt) {
try {
setCurrentTTL(RRTTL(ttl_txt));
// We use the factory version instead of RRTTL constructor as we
// need to expect cases where ttl_txt does not actually represent a TTL
// but an RR class or type.
RRTTL* ttl = RRTTL::createFromText(ttl_txt, current_ttl_.get());
if (ttl != NULL) {
if (!current_ttl_) {
current_ttl_.reset(ttl);
}
limitTTL(*current_ttl_, false);
return (true);
} catch (const InvalidRRTTL&) {
return (false);
}
return (false);
}
// Determine the TTL of the current RR based on the given parsing context.
......
......@@ -57,9 +57,14 @@ Unit units[] = {
namespace isc {
namespace dns {
RRTTL::RRTTL(const std::string& ttlstr) {
namespace {
bool
parseTTLStr(const string& ttlstr, uint32_t& ttlval, string* error_txt) {
if (ttlstr.empty()) {
isc_throw(InvalidRRTTL, "Empty TTL string");
if (error_txt != NULL) {
*error_txt = "Empty TTL string";
}
return (false);
}
// We use a larger data type during the computation. This is because
// some compilers don't fail when out of range, so we check the range
......@@ -80,8 +85,10 @@ RRTTL::RRTTL(const std::string& ttlstr) {
if (unit == end) {
if (units_mode) {
// We had some units before. The last one is missing unit.
isc_throw(InvalidRRTTL, "Missing the last unit: " <<
ttlstr);
if (error_txt != NULL) {
*error_txt = "Missing the last unit: " + ttlstr;
}
return (false);
} else {
// Case without any units at all. Just convert and store
// it.
......@@ -102,12 +109,18 @@ RRTTL::RRTTL(const std::string& ttlstr) {
}
}
if (!found) {
isc_throw(InvalidRRTTL, "Unknown unit used: " << *unit <<
" in: " << ttlstr);
if (error_txt != NULL) {
*error_txt = "Unknown unit used: " +
boost::lexical_cast<string>(*unit) + " in: " + ttlstr;
}
return (false);
}
// Now extract the number.
if (unit == pos) {
isc_throw(InvalidRRTTL, "Missing number in TTL: " << ttlstr);
if (error_txt != NULL) {
*error_txt = "Missing number in TTL: " + ttlstr;
}
return (false);
}
const int64_t value = boost::lexical_cast<int64_t>(string(pos,
unit));
......@@ -118,21 +131,52 @@ RRTTL::RRTTL(const std::string& ttlstr) {
// there's no need to continue).
if (value < 0 || value > 0xffffffff || val < 0 ||
val > 0xffffffff) {
isc_throw(InvalidRRTTL, "Part of TTL out of range: " <<
ttlstr);
if (error_txt != NULL) {
*error_txt = "Part of TTL out of range: " + ttlstr;
}
return (false);
}
// Move to after the unit.
pos = unit + 1;
}
} catch (const boost::bad_lexical_cast&) {
isc_throw(InvalidRRTTL, "invalid TTL: " << ttlstr);
if (error_txt != NULL) {
*error_txt = "invalid TTL: " + ttlstr;
}
return (false);
}
if (val >= 0 && val <= 0xffffffff) {
ttlval_ = val;
ttlval = val;
} else {
isc_throw(InvalidRRTTL, "TTL out of range: " << ttlstr);
if (error_txt != NULL) {
*error_txt = "TTL out of range: " + ttlstr;
}
return (false);
}
return (true);
}
}
RRTTL::RRTTL(const std::string& ttlstr) {
string error_txt;
if (!parseTTLStr(ttlstr, ttlval_, &error_txt)) {
isc_throw(InvalidRRTTL, error_txt);
}
}
RRTTL*
RRTTL::createFromText(const string& ttlstr, RRTTL* placeholder) {
uint32_t ttlval;
if (parseTTLStr(ttlstr, ttlval, NULL)) {
if (placeholder != NULL) {
*placeholder = RRTTL(ttlval);
return (placeholder);
}
return (new RRTTL(ttlval));
}
return (NULL);
}
RRTTL::RRTTL(InputBuffer& buffer) {
......
......@@ -61,7 +61,7 @@ public:
class RRTTL {
public:
///
/// \name Constructors and Destructor
/// \name Constructors, Factory and Destructor
///
/// Note: We use the default copy constructor and the default copy
/// assignment operator intentionally.
......@@ -72,6 +72,7 @@ public:
///
/// \param ttlval An 32-bit integer of the RRTTL.
explicit RRTTL(uint32_t ttlval) : ttlval_(ttlval) {}
/// Constructor from a string.
///
/// It accepts either a decimal number, specifying number of seconds. Or,
......@@ -87,6 +88,7 @@ public:
/// \throw InvalidRRTTL in case the string is not recognized as valid
/// TTL representation.
explicit RRTTL(const std::string& ttlstr);
/// Constructor from wire-format data.
///
/// The \c buffer parameter normally stores a complete DNS message
......@@ -98,6 +100,35 @@ public:
///
/// \param buffer A buffer storing the wire format data.
explicit RRTTL(isc::util::InputBuffer& buffer);
/// A separate factory of RRTTL from text.
///
/// This static method is similar to the constructor that takes a string
/// object, but works as a factory and reports parsing failure in return
/// value. Normally the constructor version should suffice, but in some
/// cases the caller may have to expect mixture of valid and invalid input,
/// and may want to minimize the overhead of possible exception handling.
/// This version is provided for such purpose.
///
/// When the \c placeholder parameter is NULL, it creates a new RRTTL
/// object, allocating memory for it; the caller is responsible for
/// releasing the memory using the \c delete operator. If \c placeholder
/// is non NULL, it will override the placeholder object with an RRTTL
/// corresponding to the given text and return a pointer to the placeholder
/// object. This way, the caller can also minimize the overhead of memory
/// allocation if it needs to call this method many times.
///
/// If the given text does not represent a valid RRTTL, it returns NULL;
/// if \c placeholder is non NULL, it will be intact.
///
/// This function never throws the \c InvalidRRTTL exception.
///
/// \param ttlstr A string representation of the \c RRTTL.
/// \param placeholder If non NULL, an RRTTL object to be overridden
/// with an RRTTL for \c ttlstr.
/// \return A pointer to the created or overridden RRTTL object.
static RRTTL* createFromText(const std::string& ttlstr,
RRTTL* placeholder);
///
//@}
......
......@@ -20,6 +20,8 @@
#include <dns/tests/unittest_util.h>
#include <boost/scoped_ptr.hpp>
using namespace std;
using namespace isc;
using namespace isc::dns;
......@@ -85,6 +87,25 @@ TEST_F(RRTTLTest, fromText) {
EXPECT_THROW(RRTTL("4294967296"), InvalidRRTTL); // must be 32-bit
}
TEST_F(RRTTLTest, createFromText) {
// If placeholder is NULL, a new RRTTL object is allocated
boost::scoped_ptr<RRTTL> ttl_ptr;
ttl_ptr.reset(RRTTL::createFromText("3600", NULL));
ASSERT_TRUE(ttl_ptr);
EXPECT_EQ(RRTTL(3600), *ttl_ptr);
// If placeholder is non NULL, it will be overwritten
RRTTL ttl(3600);
EXPECT_NE(static_cast<RRTTL*>(NULL), RRTTL::createFromText("1800", &ttl));
EXPECT_EQ(RRTTL(1800), ttl);
// If text parsing fails, NULL is returned; if placeholder is given,
// it will be intact.
EXPECT_EQ(static_cast<RRTTL*>(NULL), RRTTL::createFromText("bad", NULL));
EXPECT_EQ(static_cast<RRTTL*>(NULL), RRTTL::createFromText("bad", &ttl));
EXPECT_EQ(RRTTL(1800), ttl);
}
void
checkUnit(unsigned multiply, char suffix) {
SCOPED_TRACE(string("Unit check with suffix ") + suffix);
......
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