Commit b791d348 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[2389] updater lexer support in AAAA constructor.

it was already implemented, but more test cases and doc were now added.
some other cleanups are made.
parent befd69aa
......@@ -24,6 +24,8 @@
#include <stdint.h>
#include <string.h>
#include <cerrno>
#include <cstring>
#include <string>
#include <arpa/inet.h> // XXX: for inet_pton/ntop(), not exist in C++ standards
......@@ -35,24 +37,70 @@ using namespace isc::util;
// BEGIN_ISC_NAMESPACE
// BEGIN_RDATA_NAMESPACE
AAAA::AAAA(const std::string& addrstr) {
if (inet_pton(AF_INET6, addrstr.c_str(), &addr_) != 1) {
isc_throw(InvalidRdataText,
"IN/AAAA RDATA construction from text failed: "
"Address cannot be converted: " << addrstr);
namespace {
void
convertToIPv6Addr(const char* src, size_t src_len, void* dst) {
if (src_len != strlen(src)) {
isc_throw(InvalidRdataText, "Bad IN/AAAA RDATA text: "
"extra character: '" << src << "'");
}
const int result = inet_pton(AF_INET6, src, dst);
if (result == 0) {
isc_throw(InvalidRdataText, "Bad IN/AAAA RDATA text: '" << src << "'");
} else if (result < 0) {
isc_throw(isc::Unexpected,
"Unexpected failure in parsing IN/AAAA RDATA text: '"
<< src << "': " << std::strerror(errno));
}
}
}
/// \brief Constructor from string.
///
/// The given string must be a valid textual representation of an IPv6
/// address as specified in RFC1886.
///
/// No extra character should be contained in \c addrstr other than the
/// textual address. These include spaces and the nul character.
///
/// \throw InvalidRdata The text extracted by the lexer isn't recognized as
/// a valid IPv6 address.
/// \throw Unexpected Unexpected system error in conversion (this should be
/// very rare).
///
/// \param addrstr Textual representation of IPv6 address to be used as the
/// RDATA.
AAAA::AAAA(const std::string& addrstr) {
convertToIPv6Addr(addrstr.c_str(), addrstr.size(), addr_);
}
/// \brief Constructor with a context of MasterLexer.
///
/// The \c lexer should point to the beginning of valid textual representation
/// of a class IN AAAA RDATA.
///
/// The acceptable form of the textual address is generally the same as the
/// string version of the constructor, but this version is slightly more
/// flexible. See the similar constructor of \c in::A class; the same
/// notes apply here.
///
/// \throw MasterLexer::LexerError General parsing error such as missing field.
/// \throw InvalidRdata The text extracted by the lexer isn't recognized as
/// a valid IPv6 address.
/// \throw Unexpected Unexpected system error in conversion (this should be
/// very rare).
///
/// \param lexer A \c MasterLexer object parsing a master file for the
/// RDATA to be created
AAAA::AAAA(MasterLexer& lexer, const Name*,
MasterLoader::Options, MasterLoaderCallbacks&)
{
const MasterToken& token = lexer.getNextToken(MasterToken::STRING);
if (inet_pton(AF_INET6, token.getStringRegion().beg, &addr_) != 1) {
isc_throw(InvalidRdataText, "Failed to convert '"
<< token.getString() << "' to IN/AAAA RDATA");
}
convertToIPv6Addr(token.getStringRegion().beg, token.getStringRegion().len,
addr_);
}
/// \brief Copy constructor.
AAAA::AAAA(InputBuffer& buffer, size_t rdata_len) {
if (rdata_len != sizeof(addr_)) {
isc_throw(DNSMessageFORMERR,
......@@ -72,6 +120,7 @@ AAAA::AAAA(const AAAA& other) : Rdata() {
memcpy(addr_, other.addr_, sizeof(addr_));
}
/// \brief Return a textual form of the underlying IPv6 address of the RDATA.
void
AAAA::toWire(OutputBuffer& buffer) const {
buffer.writeData(&addr_, sizeof(addr_));
......@@ -86,7 +135,8 @@ string
AAAA::toText() const {
char addr_string[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
if (inet_ntop(AF_INET6, &addr_, addr_string, sizeof(addr_string)) == NULL) {
if (inet_ntop(AF_INET6, &addr_, addr_string, sizeof(addr_string))
== NULL) {
isc_throw(Unexpected,
"Failed to convert IN/AAAA RDATA to textual IPv6 address");
}
......@@ -94,6 +144,9 @@ AAAA::toText() const {
return (string(addr_string));
}
/// \brief Compare two in::AAAA RDATAs.
///
/// In effect, it compares the two RDATA as an unsigned 128-bit integer.
int
AAAA::compare(const Rdata& other) const {
const AAAA& other_a = dynamic_cast<const AAAA&>(other);
......
......@@ -33,18 +33,75 @@ using namespace isc::dns::rdata;
namespace {
class Rdata_IN_AAAA_Test : public RdataTest {
// there's nothing to specialize
protected:
Rdata_IN_AAAA_Test() : rdata_in_aaaa("2001:db8::1234") {}
// Common check to see the result of in::A Rdata construction either from
// std::string or with MasterLexer object. If it's expected to succeed
// the result should be identical to the commonly used test data
// (rdata_in_a); otherwise it should result in the exception specified as
// the template parameter.
template <typename ExForString, typename ExForLexer>
void checkFromText(const string& in_aaaa_txt,
bool throw_str_version = true,
bool throw_lexer_version = true)
{
if (throw_str_version) {
EXPECT_THROW(in::AAAA in_aaaa(in_aaaa_txt), ExForString);
} else {
EXPECT_EQ(0, in::AAAA(in_aaaa_txt).compare(rdata_in_aaaa));
}
std::stringstream ss(in_aaaa_txt);
MasterLexer lexer;
lexer.pushSource(ss);
if (throw_lexer_version) {
EXPECT_THROW(in::AAAA soa(lexer, NULL, MasterLoader::DEFAULT,
loader_cb), ExForLexer);
} else {
EXPECT_EQ(0, in::AAAA(lexer, NULL, MasterLoader::DEFAULT,
loader_cb).compare(rdata_in_aaaa));
}
}
const in::AAAA rdata_in_aaaa;
};
const in::AAAA rdata_in_aaaa("2001:db8::1234");
const uint8_t wiredata_in_aaaa[] = {
0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x12, 0x34 };
TEST_F(Rdata_IN_AAAA_Test, createFromText) {
rdata_in_aaaa.compare(in::AAAA(string("2001:db8::1234")));
EXPECT_THROW(in::AAAA("192.0.2.1"), InvalidRdataText);
EXPECT_THROW(in::AAAA("xxx"), InvalidRdataText);
// Normal case: no exception for either case, so the exception type
// doesn't matter.
checkFromText<isc::Exception, isc::Exception>("2001:db8::1234", false,
false);
// should reject an IP4 address.
checkFromText<InvalidRdataText, InvalidRdataText>("192.0.2.1");
// or any meaningless text as an IPv6 address
checkFromText<InvalidRdataText, InvalidRdataText>("xxx");
// trailing white space: only string version throws
checkFromText<InvalidRdataText, InvalidRdataText>("2001:db8::1234 ",
true, false);
// same for beginning white space.
checkFromText<InvalidRdataText, InvalidRdataText>(" 2001:db8::1234",
true, false);
// same for trailing non-space garbage (note that lexer version still
// ignore it; it's expected to be detected at a higher layer).
checkFromText<InvalidRdataText, InvalidRdataText>("2001:db8::1234 xxx",
true, false);
// nul character after a valid textual representation.
string nul_after_addr = "2001:db8::1234";
nul_after_addr.push_back(0);
checkFromText<InvalidRdataText, InvalidRdataText>(nul_after_addr, true,
true);
// a valid address surrounded by parentheses; only okay with lexer
checkFromText<InvalidRdataText, InvalidRdataText>("(2001:db8::1234)", true,
false);
}
TEST_F(Rdata_IN_AAAA_Test, createFromWire) {
......
......@@ -197,8 +197,8 @@ TEST_F(RdataTest, createRdataWithLexer) {
EXPECT_FALSE(createRdata(RRType::AAAA(), RRClass::IN(), lexer, NULL,
MasterLoader::MANY_ERRORS, callbacks));
callback.check(src_name, line, CreateRdataCallback::ERROR,
"createRdata from text failed: Failed to convert "
"'192.0.2.1' to IN/AAAA RDATA");
"createRdata from text failed: Bad IN/AAAA RDATA text: "
"'192.0.2.1'");
// Input is valid and parse will succeed, but with a warning that the
// file is not ended with a newline.
......
Supports Markdown
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