mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 14:05:33 +00:00
merged RRType/Class/TTL classes
git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@474 e5f2f494-b856-4b98-b285-d166d9295462
This commit is contained in:
51
configure.ac
51
configure.ac
@@ -33,7 +33,20 @@ if test $enable_shared != "no" -a "X$GCC" = "Xyes"; then
|
||||
CXXFLAGS="$CXXFLAGS -fPIC"
|
||||
fi
|
||||
|
||||
AC_SUBST(CXXFLAGS)
|
||||
#
|
||||
# Check availablity of boost:
|
||||
#
|
||||
AC_ARG_WITH(boost,
|
||||
[ --with-boost=PATH specify a path to the boost if it's not automatically found],
|
||||
boost_path="$withval", boost_path="no")
|
||||
if test "$boost_path" != "no"
|
||||
then
|
||||
BOOST_INCLUDES="-I$boost_path/include"
|
||||
else
|
||||
BOOST_INCLUDES=
|
||||
fi
|
||||
|
||||
AC_SUBST(BOOST_INCLUDES)
|
||||
|
||||
#
|
||||
# Check availablity of gtest, which will be used for unit tests.
|
||||
@@ -64,6 +77,42 @@ AC_SUBST(GTEST_INCLUDES)
|
||||
AC_SUBST(GTEST_LDFLAGS)
|
||||
AC_SUBST(GTEST_LDADD)
|
||||
|
||||
AC_ARG_WITH(lcov,
|
||||
[ --with-lcov[=PROGRAM] enable gtest and coverage target using the specified lcov], lcov="$withval", lcov="no")
|
||||
|
||||
USE_LCOV="no"
|
||||
if test "$lcov" != "no"; then
|
||||
# force gtest if not set
|
||||
if test "$gtest_path" = "no"; then
|
||||
gtest_path="yes"
|
||||
fi
|
||||
if test "$lcov" != "yes"; then
|
||||
LCOV_PATHS=$lcov
|
||||
else
|
||||
LCOV_PATHS="/usr/bin/lcov /usr/local/bin/lcov"
|
||||
fi
|
||||
for f in $LCOV_PATHS; do
|
||||
if test -x "$f"; then
|
||||
USE_LCOV="yes"
|
||||
LCOV=$f
|
||||
fi
|
||||
done
|
||||
if test $USE_LCOV != "yes"; then
|
||||
AC_MSG_ERROR([Cannot find lcov in: $LCOV_PATHS])
|
||||
fi
|
||||
# is genhtml always in the same directory?
|
||||
GENHTML=`echo "$LCOV" | sed s/lcov$/genhtml/`
|
||||
if test ! -x $GENHTML; then
|
||||
AC_MSG_ERROR([genhtml not found, needed for lcov])
|
||||
fi
|
||||
# GCC specific?
|
||||
CXXFLAGS="$CXXFLAGS -fprofile-arcs -ftest-coverage"
|
||||
LIBS=" $LIBS -lgcov"
|
||||
fi
|
||||
|
||||
AC_SUBST(CXXFLAGS)
|
||||
AC_SUBST(LIBS)
|
||||
|
||||
# Checks for library functions.
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
|
@@ -1,5 +1,11 @@
|
||||
AM_CPPFLAGS = $(BOOST_INCLUDES)
|
||||
|
||||
CLEANFILES = *.gcno *.gcda
|
||||
|
||||
lib_LTLIBRARIES = libdns.la
|
||||
libdns_la_SOURCES = buffer.h name.cc name.h messagerenderer.h messagerenderer.cc
|
||||
libdns_la_SOURCES += rrparamregistry.h rrparamregistry.cc
|
||||
libdns_la_SOURCES += rrclass.h rrclass.cc rrtype.h rrtype.cc rrttl.h rrttl.cc
|
||||
libdns_la_SOURCES += exceptions.h exceptions.cc
|
||||
|
||||
TESTS =
|
||||
@@ -8,6 +14,9 @@ TESTS += run_unittests
|
||||
run_unittests_SOURCES = unittest_util.h unittest_util.cc
|
||||
run_unittests_SOURCES += buffer_unittest.cc name_unittest.cc
|
||||
run_unittests_SOURCES += messagerenderer_unittest.cc exceptions_unittest.cc
|
||||
run_unittests_SOURCES += rrclass_unittest.cc rrtype_unittest.cc
|
||||
run_unittests_SOURCES += rrttl_unittest.cc
|
||||
run_unittests_SOURCES += rrparamregistry_unittest.cc
|
||||
run_unittests_SOURCES += run_unittests.cc
|
||||
run_unittests_CPPFLAGS = $(GTEST_INCLUDES)
|
||||
run_unittests_LDFLAGS = $(GTEST_LDFLAGS)
|
||||
|
@@ -43,7 +43,7 @@ protected:
|
||||
|
||||
const uint8_t BufferTest::testdata[5] = {1, 2, 3, 4, 5};
|
||||
|
||||
TEST_F(BufferTest, input_buffer_read)
|
||||
TEST_F(BufferTest, inputBufferRead)
|
||||
{
|
||||
EXPECT_EQ(5, ibuffer.getLength());
|
||||
EXPECT_EQ(1, ibuffer.readUint8());
|
||||
@@ -61,7 +61,7 @@ TEST_F(BufferTest, input_buffer_read)
|
||||
EXPECT_EQ(0, memcmp(vdata, testdata, sizeof(testdata)));
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, input_buffer_exception)
|
||||
TEST_F(BufferTest, inputBufferException)
|
||||
{
|
||||
EXPECT_THROW(ibuffer.setPosition(6), isc::dns::InvalidBufferPosition);
|
||||
|
||||
@@ -79,7 +79,7 @@ TEST_F(BufferTest, input_buffer_exception)
|
||||
isc::dns::InvalidBufferPosition);
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, output_buffer_extend)
|
||||
TEST_F(BufferTest, outputBufferExtend)
|
||||
{
|
||||
EXPECT_EQ(0, obuffer.getCapacity());
|
||||
EXPECT_EQ(0, obuffer.getLength());
|
||||
@@ -88,7 +88,7 @@ TEST_F(BufferTest, output_buffer_extend)
|
||||
EXPECT_EQ(1, obuffer.getLength());
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, output_buffer_write)
|
||||
TEST_F(BufferTest, outputBufferWrite)
|
||||
{
|
||||
const uint8_t* cp;
|
||||
|
||||
@@ -121,7 +121,7 @@ TEST_F(BufferTest, output_buffer_write)
|
||||
EXPECT_EQ(0, memcmp(cp + 7, testdata, sizeof(testdata)));
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, output_buffer_writeat)
|
||||
TEST_F(BufferTest, outputBufferWriteat)
|
||||
{
|
||||
obuffer.writeUint32(data32);
|
||||
expected_size += sizeof(data32);
|
||||
@@ -140,7 +140,7 @@ TEST_F(BufferTest, output_buffer_writeat)
|
||||
isc::dns::InvalidBufferPosition);
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, output_buffer_skip)
|
||||
TEST_F(BufferTest, outputBufferSkip)
|
||||
{
|
||||
obuffer.skip(4);
|
||||
EXPECT_EQ(4, obuffer.getLength());
|
||||
@@ -149,7 +149,7 @@ TEST_F(BufferTest, output_buffer_skip)
|
||||
EXPECT_EQ(6, obuffer.getLength());
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, output_buffer_readat)
|
||||
TEST_F(BufferTest, outputBufferReadat)
|
||||
{
|
||||
obuffer.writeData(testdata, sizeof(testdata));
|
||||
for (int i = 0; i < sizeof(testdata); i ++) {
|
||||
@@ -158,7 +158,7 @@ TEST_F(BufferTest, output_buffer_readat)
|
||||
EXPECT_THROW(obuffer[sizeof(testdata)], isc::dns::InvalidBufferPosition);
|
||||
}
|
||||
|
||||
TEST_F(BufferTest, output_buffer_clear)
|
||||
TEST_F(BufferTest, outputBufferClear)
|
||||
{
|
||||
obuffer.writeData(testdata, sizeof(testdata));
|
||||
obuffer.clear();
|
||||
|
@@ -31,7 +31,7 @@ protected:
|
||||
const char* teststring;
|
||||
};
|
||||
|
||||
TEST_F(ExceptionTest, BasicMethods) {
|
||||
TEST_F(ExceptionTest, basicMethods) {
|
||||
try {
|
||||
dns_throw(Exception, teststring);
|
||||
} catch (Exception& ex) {
|
||||
@@ -42,7 +42,7 @@ TEST_F(ExceptionTest, BasicMethods) {
|
||||
}
|
||||
|
||||
// Test to see if it works as a proper derived class of std::exception.
|
||||
TEST_F(ExceptionTest, StdInheritance) {
|
||||
TEST_F(ExceptionTest, stdInheritance) {
|
||||
try {
|
||||
dns_throw(Exception, teststring);
|
||||
} catch (std::exception& ex) {
|
||||
|
@@ -127,7 +127,7 @@ private:
|
||||
/// \c MessageRenderer.
|
||||
///
|
||||
/// The implementation is hidden from applications. We can refer to specific
|
||||
/// members of this class only within this file.
|
||||
/// members of this class only within the implementation source file.
|
||||
///
|
||||
struct MessageRendererImpl {
|
||||
/// \brief Constructor from an output buffer.
|
||||
@@ -156,6 +156,30 @@ MessageRenderer::~MessageRenderer()
|
||||
delete impl_;
|
||||
}
|
||||
|
||||
void
|
||||
MessageRenderer::writeUint16(uint16_t data)
|
||||
{
|
||||
impl_->buffer_.writeUint16(data);
|
||||
}
|
||||
|
||||
void
|
||||
MessageRenderer::writeUint32(uint32_t data)
|
||||
{
|
||||
impl_->buffer_.writeUint32(data);
|
||||
}
|
||||
|
||||
const void*
|
||||
MessageRenderer::getData() const
|
||||
{
|
||||
return (impl_->buffer_.getData());
|
||||
}
|
||||
|
||||
size_t
|
||||
MessageRenderer::getLength() const
|
||||
{
|
||||
return (impl_->buffer_.getLength());
|
||||
}
|
||||
|
||||
void
|
||||
MessageRenderer::writeName(const Name& name, bool compress)
|
||||
{
|
||||
|
@@ -87,6 +87,36 @@ public:
|
||||
~MessageRenderer();
|
||||
//@}
|
||||
|
||||
///
|
||||
/// \name Getter Methods
|
||||
///
|
||||
//@{
|
||||
/// \brief Return a pointer to the head of the data stored in the internal
|
||||
/// buffer.
|
||||
///
|
||||
/// This method works exactly same as the same method of the \c OutputBuffer
|
||||
/// class; all notes for \c OutputBuffer apply.
|
||||
const void* getData() const;
|
||||
/// \brief Return the length of data written in the internal buffer.
|
||||
size_t getLength() const;
|
||||
//@}
|
||||
|
||||
///
|
||||
/// \name Methods for writing data into the internal buffer.
|
||||
///
|
||||
//@{
|
||||
/// \brief Write an unsigned 16-bit integer in host byte order into the
|
||||
/// internal buffer in network byte order.
|
||||
///
|
||||
/// \param data The 16-bit integer to be written into the buffer.
|
||||
void writeUint16(uint16_t data);
|
||||
/// \brief Write an unsigned 32-bit integer in host byte order into the
|
||||
/// internal buffer in network byte order.
|
||||
///
|
||||
/// \param data The 32-bit integer to be written into the buffer.
|
||||
void writeUint32(uint32_t data);
|
||||
//@}
|
||||
|
||||
///
|
||||
/// \name Rendering Methods
|
||||
///
|
||||
|
@@ -32,13 +32,33 @@ using isc::dns::MessageRenderer;
|
||||
namespace {
|
||||
class MessageRendererTest : public ::testing::Test {
|
||||
protected:
|
||||
MessageRendererTest() : buffer(0), renderer(buffer) {}
|
||||
MessageRendererTest() : expected_size(0), buffer(0), renderer(buffer)
|
||||
{
|
||||
data16 = (2 << 8) | 3;
|
||||
data32 = (4 << 24) | (5 << 16) | (6 << 8) | 7;
|
||||
}
|
||||
size_t expected_size;
|
||||
uint16_t data16;
|
||||
uint32_t data32;
|
||||
OutputBuffer buffer;
|
||||
MessageRenderer renderer;
|
||||
std::vector<unsigned char> data;
|
||||
static const uint8_t testdata[5];
|
||||
};
|
||||
|
||||
TEST_F(MessageRendererTest, toWire)
|
||||
const uint8_t MessageRendererTest::testdata[5] = {1, 2, 3, 4, 5};
|
||||
|
||||
// The test cases are borrowed from those for the OutputBuffer class.
|
||||
TEST_F(MessageRendererTest, writeIntger)
|
||||
{
|
||||
renderer.writeUint16(data16);
|
||||
expected_size += sizeof(data16);
|
||||
|
||||
EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
|
||||
renderer.getLength(), &testdata[1], sizeof(data16));
|
||||
}
|
||||
|
||||
TEST_F(MessageRendererTest, writeName)
|
||||
{
|
||||
UnitTestUtil::readWireData("testdata/name_toWire1", data);
|
||||
renderer.writeName(Name("a.example.com."));
|
||||
@@ -48,7 +68,7 @@ TEST_F(MessageRendererTest, toWire)
|
||||
buffer.getLength(), &data[0], data.size());
|
||||
}
|
||||
|
||||
TEST_F(MessageRendererTest, toWireInLargeBuffer)
|
||||
TEST_F(MessageRendererTest, writeNameInLargeBuffer)
|
||||
{
|
||||
size_t offset = 0x3fff;
|
||||
buffer.skip(offset);
|
||||
@@ -63,7 +83,7 @@ TEST_F(MessageRendererTest, toWireInLargeBuffer)
|
||||
&data[0], data.size());
|
||||
}
|
||||
|
||||
TEST_F(MessageRendererTest, toWireWithUncompressed)
|
||||
TEST_F(MessageRendererTest, writeNameWithUncompressed)
|
||||
{
|
||||
UnitTestUtil::readWireData("testdata/name_toWire3", data);
|
||||
renderer.writeName(Name("a.example.com."));
|
||||
@@ -73,7 +93,7 @@ TEST_F(MessageRendererTest, toWireWithUncompressed)
|
||||
buffer.getLength(), &data[0], data.size());
|
||||
}
|
||||
|
||||
TEST_F(MessageRendererTest, toWirePointerChain)
|
||||
TEST_F(MessageRendererTest, writeNamePointerChain)
|
||||
{
|
||||
UnitTestUtil::readWireData("testdata/name_toWire4", data);
|
||||
renderer.writeName(Name("a.example.com."));
|
||||
@@ -83,7 +103,7 @@ TEST_F(MessageRendererTest, toWirePointerChain)
|
||||
buffer.getLength(), &data[0], data.size());
|
||||
}
|
||||
|
||||
TEST_F(MessageRendererTest, toWireCaseCompress)
|
||||
TEST_F(MessageRendererTest, writeNameCaseCompress)
|
||||
{
|
||||
UnitTestUtil::readWireData("testdata/name_toWire1", data);
|
||||
renderer.writeName(Name("a.example.com."));
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include "name.h"
|
||||
#include "messagerenderer.h"
|
||||
|
||||
using namespace std;
|
||||
using isc::dns::NameComparisonResult;
|
||||
using isc::dns::MessageRenderer;
|
||||
|
||||
@@ -566,19 +567,6 @@ Name::isWildcard() const
|
||||
return (length_ >= 2 && ndata_[0] == 1 && ndata_[1] == '*');
|
||||
}
|
||||
|
||||
namespace { // hide the local class
|
||||
///
|
||||
/// A helper functor class to add an additional offset to an offset vector.
|
||||
///
|
||||
struct OffsetAdjuster : public std::binary_function<unsigned char,
|
||||
int, unsigned char> {
|
||||
unsigned char operator()(unsigned char ch, int offset) const
|
||||
{
|
||||
return (ch + offset);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Name
|
||||
Name::concatenate(const Name& suffix) const
|
||||
{
|
||||
@@ -610,7 +598,7 @@ Name::concatenate(const Name& suffix) const
|
||||
&this->offsets_[0] + this->labelcount_ - 1);
|
||||
transform(suffix.offsets_.begin(), suffix.offsets_.end(),
|
||||
back_inserter(retname.offsets_),
|
||||
bind2nd(OffsetAdjuster(), this->length_ - 1));
|
||||
bind2nd(plus<char>(), this->length_ - 1));
|
||||
assert(retname.offsets_.size() == labels);
|
||||
retname.labelcount_ = labels;
|
||||
|
||||
@@ -636,7 +624,7 @@ Name::split(unsigned int first, unsigned int n) const
|
||||
retname.offsets_.reserve(newlabels);
|
||||
transform(offsets_.begin() + first, offsets_.begin() + first + newlabels,
|
||||
back_inserter(retname.offsets_),
|
||||
bind2nd(OffsetAdjuster(), -offsets_[first]));
|
||||
bind2nd(plus<char>(), -offsets_[first]));
|
||||
|
||||
//
|
||||
// Set up the new name. At this point the tail of the new offsets specifies
|
||||
|
@@ -330,6 +330,7 @@ public:
|
||||
/// <code>buffer.getCapacity() - buffer.getLength() >= Name::MAX_WIRE</code>
|
||||
/// then this method should not throw an exception.
|
||||
///
|
||||
/// \param buffer An output buffer to store the wire data.
|
||||
void toWire(OutputBuffer& buffer) const;
|
||||
//@}
|
||||
|
||||
@@ -368,17 +369,17 @@ public:
|
||||
bool equals(const Name& other) const;
|
||||
|
||||
/// Same as equals()
|
||||
bool operator==(const Name& other) const { return (this->equals(other)); }
|
||||
bool operator==(const Name& other) const { return (equals(other)); }
|
||||
|
||||
/// \brief Return true iff two names are not equal.
|
||||
///
|
||||
/// This method simply negates the result of \c equal() method, and in that
|
||||
/// sense it's redundant. The separate method is provided just for
|
||||
/// convenience.
|
||||
bool nequals(const Name& other) const { return !(this->equals(other)); }
|
||||
bool nequals(const Name& other) const { return !(equals(other)); }
|
||||
|
||||
/// Same as nequals()
|
||||
bool operator!=(const Name& other) const { return (this->nequals(other)); }
|
||||
bool operator!=(const Name& other) const { return (nequals(other)); }
|
||||
|
||||
/// \brief Less-than or equal comparison for Name against <code>other</code>
|
||||
///
|
||||
|
71
src/lib/dns/cpp/rrclass.cc
Normal file
71
src/lib/dns/cpp/rrclass.cc
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
// $Id$
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "buffer.h"
|
||||
#include "exceptions.h"
|
||||
#include "messagerenderer.h"
|
||||
#include "rrparamregistry.h"
|
||||
#include "rrclass.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace isc::dns;
|
||||
|
||||
namespace isc {
|
||||
namespace dns {
|
||||
|
||||
RRClass::RRClass(const string& classstr)
|
||||
{
|
||||
classcode_ = RRParamRegistry::getRegistry().textToClassCode(classstr);
|
||||
}
|
||||
|
||||
RRClass::RRClass(InputBuffer& buffer)
|
||||
{
|
||||
if (buffer.getLength() - buffer.getPosition() < sizeof(uint16_t)) {
|
||||
dns_throw(IncompleteRRClass, "incomplete wire-format RR class");
|
||||
}
|
||||
classcode_ = buffer.readUint16();
|
||||
}
|
||||
|
||||
const string
|
||||
RRClass::toText() const
|
||||
{
|
||||
return (RRParamRegistry::getRegistry().codeToClassText(classcode_));
|
||||
}
|
||||
|
||||
void
|
||||
RRClass::toWire(OutputBuffer& buffer) const
|
||||
{
|
||||
buffer.writeUint16(classcode_);
|
||||
}
|
||||
|
||||
void
|
||||
RRClass::toWire(MessageRenderer& renderer) const
|
||||
{
|
||||
renderer.writeUint16(classcode_);
|
||||
}
|
||||
|
||||
ostream&
|
||||
operator<<(ostream& os, const RRClass& rrclass)
|
||||
{
|
||||
os << rrclass.toText();
|
||||
return (os);
|
||||
}
|
||||
}
|
||||
}
|
289
src/lib/dns/cpp/rrclass.h
Normal file
289
src/lib/dns/cpp/rrclass.h
Normal file
@@ -0,0 +1,289 @@
|
||||
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
// $Id$
|
||||
|
||||
#ifndef __RRCLASS_H
|
||||
#define __RRCLASS_H 1
|
||||
|
||||
#include "exceptions.h"
|
||||
|
||||
namespace isc {
|
||||
namespace dns {
|
||||
|
||||
// forward declarations
|
||||
class InputBuffer;
|
||||
class OutputBuffer;
|
||||
class MessageRenderer;
|
||||
|
||||
///
|
||||
/// \brief A standard DNS module exception that is thrown if an RRClass object
|
||||
/// is being constructed from an unrecognized string.
|
||||
///
|
||||
class InvalidRRClass : public Exception {
|
||||
public:
|
||||
InvalidRRClass(const char* file, size_t line, const char* what) :
|
||||
isc::dns::Exception(file, line, what) {}
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief A standard DNS module exception that is thrown if an RRClass object
|
||||
/// is being constructed from a incomplete (too short) wire-format data.
|
||||
///
|
||||
class IncompleteRRClass : public Exception {
|
||||
public:
|
||||
IncompleteRRClass(const char* file, size_t line, const char* what) :
|
||||
isc::dns::Exception(file, line, what) {}
|
||||
};
|
||||
|
||||
///
|
||||
/// The \c RRClass class encapsulates DNS resource record classes.
|
||||
///
|
||||
/// This class manages the 16-bit integer class codes in quite a straightforward
|
||||
/// way. The only non trivial task is to handle textual representations of
|
||||
/// RR classes, such as "IN", "CH", or "CLASS65534".
|
||||
///
|
||||
/// This class consults a helper \c RRParamRegistry class, which is a registry
|
||||
/// of RR related parameters and has the singleton object. This registry
|
||||
/// provides a mapping between RR class codes and their "well-known" textual
|
||||
/// representations.
|
||||
/// Parameters of RR classes defined by DNS protocol standards are automatically
|
||||
/// registered at initialization time and are ensured to be always available for
|
||||
/// applications unless the application explicitly modifies the registry.
|
||||
///
|
||||
/// For convenience, this class defines constant class objects corresponding to
|
||||
/// standard RR classes. These are generally referred to as the form of
|
||||
/// <code>RRClass::{class-text}()</code>.
|
||||
/// For example, \c RRClass::IN() is an \c RRClass object corresponding to the
|
||||
/// IN class (class code 1).
|
||||
/// Note that these constants are used through a "proxy" function.
|
||||
/// This is because they may be used to initialize another non-local (e.g.
|
||||
/// global or namespace-scope) static object as follows:
|
||||
///
|
||||
/// \code
|
||||
/// namespace foo {
|
||||
/// const RRClass default_class = RRClass::IN();
|
||||
/// } \endcode
|
||||
///
|
||||
/// In order to ensure that the constant RRClass object has been initialized
|
||||
/// before the initialization for \c default_class, we need help from
|
||||
/// the proxy function.
|
||||
///
|
||||
/// Note to developers: same note as \c RRType applies.
|
||||
class RRClass {
|
||||
public:
|
||||
///
|
||||
/// \name Constructors and Destructor
|
||||
///
|
||||
//@{
|
||||
/// Constructor from an integer class code.
|
||||
///
|
||||
/// This constructor never throws an exception.
|
||||
///
|
||||
/// \param classcode An 16-bit integer code corresponding to the RRClass.
|
||||
explicit RRClass(uint16_t classcode) : classcode_(classcode) {}
|
||||
///
|
||||
/// A valid string is one of "well-known" textual class representations
|
||||
/// such as "IN" or "CH", or in the standard format for "unknown"
|
||||
/// classes as defined in RFC3597, i.e., "CLASSnnnn".
|
||||
///
|
||||
/// More precisely, the "well-known" representations are the ones stored
|
||||
/// in the \c RRParamRegistry registry (see the class description).
|
||||
///
|
||||
/// As for the format of "CLASSnnnn", "nnnn" must represent a valid 16-bit
|
||||
/// unsigned integer, which may contain leading 0's as long as it consists
|
||||
/// of at most 5 characters (inclusive).
|
||||
/// For example, "CLASS1" and "CLASSS001" are valid and represent the same
|
||||
/// class, but "CLASS65536" and "CLASS000001" are invalid.
|
||||
/// A "CLASSnnnn" representation is valid even if the corresponding class
|
||||
/// code is registered in the \c RRParamRegistry object. For example, both
|
||||
/// "IN" and "CLASS1" are valid and represent the same class.
|
||||
///
|
||||
/// All of these representations are case insensitive; "IN" and "in", and
|
||||
/// "CLASS1" and "class1" are all valid and represent the same classes,
|
||||
/// respectively.
|
||||
///
|
||||
/// If the given string is not recognized as a valid representation of
|
||||
/// an RR class, an exception of class \c InvalidRRClass will be thrown.
|
||||
///
|
||||
/// \param classstr A string representation of the \c RRClass
|
||||
explicit RRClass(const std::string& classstr);
|
||||
/// Constructor from wire-format data.
|
||||
///
|
||||
/// The \c buffer parameter normally stores a complete DNS message
|
||||
/// containing the RRClass to be constructed. The current read position of
|
||||
/// the buffer points to the head of the class.
|
||||
///
|
||||
/// If the given data does not large enough to contain a 16-bit integer,
|
||||
/// an exception of class \c IncompleteRRClass will be thrown.
|
||||
///
|
||||
/// \param buffer A buffer storing the wire format data.
|
||||
explicit RRClass(InputBuffer& buffer);
|
||||
///
|
||||
/// We use the default copy constructor intentionally.
|
||||
//@}
|
||||
/// We use the default copy assignment operator intentionally.
|
||||
///
|
||||
|
||||
///
|
||||
/// \name Converter methods
|
||||
///
|
||||
//@{
|
||||
/// \brief Convert the \c RRClass to a string.
|
||||
///
|
||||
/// If a "well known" textual representation for the class code is
|
||||
/// registered in the RR parameter registry (see the class description),
|
||||
/// that will be used as the return value of this method. Otherwise, this
|
||||
/// method creates a new string for an "unknown" class in the format defined
|
||||
/// in RFC3597, i.e., "CLASSnnnn", and returns it.
|
||||
///
|
||||
/// If resource allocation for the string fails, a corresponding standard
|
||||
/// exception will be thrown.
|
||||
///
|
||||
/// \return A string representation of the \c RRClass.
|
||||
const std::string toText() const;
|
||||
/// \brief Render the \c RRClass in the wire format.
|
||||
///
|
||||
/// This method renders the class code in network byte order via
|
||||
/// \c renderer, which encapsulates output buffer and other rendering
|
||||
/// contexts.
|
||||
///
|
||||
/// If resource allocation in rendering process fails, a corresponding
|
||||
/// standard exception will be thrown.
|
||||
///
|
||||
/// \param buffer An output buffer to store the wire data.
|
||||
void toWire(MessageRenderer& renderer) const;
|
||||
/// \brief Render the \c RRClass in the wire format.
|
||||
///
|
||||
/// This method renders the class code in network byte order into the
|
||||
/// \c buffer.
|
||||
///
|
||||
/// If resource allocation in rendering process fails, a corresponding
|
||||
/// standard exception will be thrown.
|
||||
///
|
||||
/// \param renderer DNS message rendering context that encapsulates the
|
||||
/// output buffer in which the RRClass is to be stored.
|
||||
void toWire(OutputBuffer& buffer) const;
|
||||
//@}
|
||||
|
||||
///
|
||||
/// \name Getter Methods
|
||||
///
|
||||
//@{
|
||||
/// \brief Returns the RR class code as a 16-bit unsigned integer.
|
||||
///
|
||||
/// This method never throws an exception.
|
||||
///
|
||||
/// \return An 16-bit integer code corresponding to the RRClass.
|
||||
uint16_t getCode() const { return (classcode_); }
|
||||
//@}
|
||||
|
||||
///
|
||||
/// \name Comparison methods
|
||||
///
|
||||
//@{
|
||||
/// \brief Return true iff two RRClasses are equal.
|
||||
///
|
||||
/// Two RRClasses are equal iff their class codes are equal.
|
||||
///
|
||||
/// This method never throws an exception.
|
||||
///
|
||||
/// \param other the \c RRClass object to compare against.
|
||||
/// \return true if the two RRClasses are equal; otherwise false.
|
||||
bool equals(const RRClass& other) const
|
||||
{ return (classcode_ == other.classcode_); }
|
||||
/// \brief Same as \c equals().
|
||||
bool operator==(const RRClass& other) const { return (equals(other)); }
|
||||
|
||||
/// \brief Return true iff two RRClasses are equal.
|
||||
///
|
||||
/// This method never throws an exception.
|
||||
///
|
||||
/// \param other the \c RRClass object to compare against.
|
||||
/// \return true if the two RRClasses are not equal; otherwise false.
|
||||
bool nequals(const RRClass& other) const
|
||||
{ return (classcode_ != other.classcode_); }
|
||||
/// \brief Same as \c nequals().
|
||||
bool operator!=(const RRClass& other) const { return (nequals(other)); }
|
||||
|
||||
/// \brief Less-than comparison for RRClass against \c other
|
||||
///
|
||||
/// We define the less-than relationship based on their class codes;
|
||||
/// one RRClass is less than the other iff the code of the former is less
|
||||
/// than that of the other as unsigned integers.
|
||||
/// The relationship is meaningless in terms of DNS protocol; the only
|
||||
/// reason we define this method is that RRClass objects can be stored in
|
||||
/// STL containers without requiring user-defined less-than relationship.
|
||||
/// We therefore don't define other comparison operators.
|
||||
///
|
||||
/// This method never throws an exception.
|
||||
///
|
||||
/// \param other the \c RRClass object to compare against.
|
||||
/// \return true if \c this RRClass is less than the \c other; otherwise
|
||||
/// false.
|
||||
bool operator<(const RRClass& other) const
|
||||
{ return (classcode_ < other.classcode_); }
|
||||
|
||||
// (Some) Well-known RRclass constants
|
||||
// Note: we'll auto-generate these in a near future version. These are
|
||||
// hard-coded for a proof of concept.
|
||||
static const RRClass& IN();
|
||||
static const RRClass& CH();
|
||||
|
||||
private:
|
||||
uint16_t classcode_;
|
||||
};
|
||||
|
||||
// We'll probably auto generate this code. But in this preliminary version
|
||||
// we simply hard code some selected classes.
|
||||
// Describing these will be deferred until that point.
|
||||
inline const RRClass&
|
||||
RRClass::IN()
|
||||
{
|
||||
static RRClass rrclass(1);
|
||||
|
||||
return (rrclass);
|
||||
}
|
||||
|
||||
inline const RRClass&
|
||||
RRClass::CH()
|
||||
{
|
||||
static RRClass rrclass(3);
|
||||
|
||||
return (rrclass);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Insert the \c RRClass as a string into stream.
|
||||
///
|
||||
/// This method convert the \c rrclass into a string and inserts it into the
|
||||
/// output stream \c os.
|
||||
///
|
||||
/// This function overloads the global operator<< to behave as described in
|
||||
/// ostream::operator<< but applied to \c RRClass objects.
|
||||
///
|
||||
/// \param os A \c std::ostream object on which the insertion operation is
|
||||
/// performed.
|
||||
/// \param rrclass The \c RRClass object output by the operation.
|
||||
/// \return A reference to the same \c std::ostream object referenced by
|
||||
/// parameter \c os after the insertion operation.
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const RRClass& rrclass);
|
||||
}
|
||||
}
|
||||
#endif // __RRCLASS_H
|
||||
|
||||
// Local Variables:
|
||||
// mode: c++
|
||||
// End:
|
155
src/lib/dns/cpp/rrclass_unittest.cc
Normal file
155
src/lib/dns/cpp/rrclass_unittest.cc
Normal file
@@ -0,0 +1,155 @@
|
||||
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
// $Id$
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "buffer.h"
|
||||
#include "messagerenderer.h"
|
||||
#include "rrparamregistry.h"
|
||||
#include "rrclass.h"
|
||||
|
||||
#include "unittest_util.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace isc;
|
||||
using namespace isc::dns;
|
||||
|
||||
namespace {
|
||||
class RRClassTest : public ::testing::Test {
|
||||
protected:
|
||||
RRClassTest() : obuffer(0), renderer(obuffer) {}
|
||||
|
||||
OutputBuffer obuffer;
|
||||
MessageRenderer renderer;
|
||||
|
||||
static RRClass rrclassFactoryFromWire(const char* datafile);
|
||||
static const RRClass rrclass_1, rrclass_0x80, rrclass_0x800,
|
||||
rrclass_0x8000, rrclass_max;
|
||||
static const uint8_t wiredata[10];
|
||||
};
|
||||
|
||||
const RRClass RRClassTest::rrclass_1(1);
|
||||
const RRClass RRClassTest::rrclass_0x80(0x80);
|
||||
const RRClass RRClassTest::rrclass_0x800(0x800);
|
||||
const RRClass RRClassTest::rrclass_0x8000(0x8000);
|
||||
const RRClass RRClassTest::rrclass_max(0xffff);
|
||||
// This is wire-format data for the above sample RRClasss rendered in the
|
||||
// appearing order.
|
||||
const uint8_t RRClassTest::wiredata[10] = { 0x00, 0x01, 0x00, 0x80, 0x08,
|
||||
0x00, 0x80, 0x00, 0xff, 0xff };
|
||||
|
||||
RRClass
|
||||
RRClassTest::rrclassFactoryFromWire(const char* datafile)
|
||||
{
|
||||
std::vector<unsigned char> data;
|
||||
UnitTestUtil::readWireData(datafile, data);
|
||||
|
||||
InputBuffer buffer(&data[0], data.size());
|
||||
|
||||
return (RRClass(buffer));
|
||||
}
|
||||
|
||||
TEST_F(RRClassTest, fromText)
|
||||
{
|
||||
EXPECT_EQ("IN", RRClass("IN").toText());
|
||||
EXPECT_EQ("CH", RRClass("CH").toText());
|
||||
|
||||
EXPECT_EQ("CLASS65535", RRClass("CLASS65535").toText());
|
||||
|
||||
// some uncommon cases: see the corresponding RRType tests.
|
||||
EXPECT_EQ(53, RRClass("CLASS00053").getCode());
|
||||
EXPECT_THROW(RRClass("CLASS000053"), InvalidRRClass);
|
||||
|
||||
// bogus CLASSnnn representations: should trigger an exception
|
||||
EXPECT_THROW(RRClass("CLASS"), InvalidRRClass);
|
||||
EXPECT_THROW(RRClass("CLASS-1"), InvalidRRClass);
|
||||
EXPECT_THROW(RRClass("CLASSxxx"), InvalidRRClass);
|
||||
EXPECT_THROW(RRClass("CLASS65536"), InvalidRRClass);
|
||||
EXPECT_THROW(RRClass("CLASS6500x"), InvalidRRClass);
|
||||
EXPECT_THROW(RRClass("CLASS65000 "), InvalidRRClass);
|
||||
}
|
||||
|
||||
TEST_F(RRClassTest, fromWire)
|
||||
{
|
||||
EXPECT_EQ(0x1234,
|
||||
rrclassFactoryFromWire("testdata/rrcode16_fromWire1").getCode());
|
||||
EXPECT_THROW(rrclassFactoryFromWire("testdata/rrcode16_fromWire2"),
|
||||
IncompleteRRClass);
|
||||
}
|
||||
|
||||
TEST_F(RRClassTest, caseConstruct)
|
||||
{
|
||||
EXPECT_EQ("IN", RRClass("in").toText());
|
||||
EXPECT_EQ("CH", RRClass("ch").toText());
|
||||
EXPECT_EQ("CLASS65535", RRClass("class65535").toText());
|
||||
}
|
||||
|
||||
TEST_F(RRClassTest, toText)
|
||||
{
|
||||
EXPECT_EQ("IN", RRClass(1).toText());
|
||||
EXPECT_EQ("CLASS65000", RRClass(65000).toText());
|
||||
}
|
||||
|
||||
TEST_F(RRClassTest, toWireBuffer)
|
||||
{
|
||||
rrclass_1.toWire(obuffer);
|
||||
rrclass_0x80.toWire(obuffer);
|
||||
rrclass_0x800.toWire(obuffer);
|
||||
rrclass_0x8000.toWire(obuffer);
|
||||
rrclass_max.toWire(obuffer);
|
||||
|
||||
EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
|
||||
obuffer.getData(), obuffer.getLength(),
|
||||
wiredata, sizeof(wiredata));
|
||||
}
|
||||
|
||||
TEST_F(RRClassTest, toWireRenderer)
|
||||
{
|
||||
rrclass_1.toWire(renderer);
|
||||
rrclass_0x80.toWire(renderer);
|
||||
rrclass_0x800.toWire(renderer);
|
||||
rrclass_0x8000.toWire(renderer);
|
||||
rrclass_max.toWire(renderer);
|
||||
|
||||
EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
|
||||
obuffer.getData(), obuffer.getLength(),
|
||||
wiredata, sizeof(wiredata));
|
||||
}
|
||||
|
||||
TEST_F(RRClassTest, wellKnownClasss)
|
||||
{
|
||||
EXPECT_EQ(1, RRClass::IN().getCode());
|
||||
EXPECT_EQ("IN", RRClass::IN().toText());
|
||||
}
|
||||
|
||||
TEST_F(RRClassTest, compare)
|
||||
{
|
||||
EXPECT_TRUE(RRClass(1) == RRClass("IN"));
|
||||
EXPECT_TRUE(RRClass(1).equals(RRClass("IN")));
|
||||
EXPECT_TRUE(RRClass(0).nequals(RRClass("IN")));
|
||||
|
||||
EXPECT_TRUE(RRClass("IN") < RRClass("CH"));
|
||||
EXPECT_TRUE(RRClass(100) < RRClass(65535));
|
||||
}
|
||||
|
||||
// test operator<<. We simply confirm it appends the result of toText().
|
||||
TEST_F(RRClassTest, LeftShiftOperator)
|
||||
{
|
||||
ostringstream oss;
|
||||
oss << RRClass::IN();
|
||||
EXPECT_EQ(RRClass::IN().toText(), oss.str());
|
||||
}
|
||||
}
|
373
src/lib/dns/cpp/rrparamregistry.cc
Normal file
373
src/lib/dns/cpp/rrparamregistry.cc
Normal file
@@ -0,0 +1,373 @@
|
||||
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
// $Id$
|
||||
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include "exceptions.h"
|
||||
#include "rrparamregistry.h"
|
||||
#include "rrclass.h"
|
||||
#include "rrtype.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
|
||||
namespace isc {
|
||||
namespace dns {
|
||||
|
||||
namespace {
|
||||
///
|
||||
/// The following function and class are a helper to define case-insensitive
|
||||
/// equivalence relationship on strings. They are used in the mapping
|
||||
/// containers below.
|
||||
///
|
||||
bool
|
||||
CICharLess(char c1, char c2)
|
||||
{
|
||||
return (tolower(static_cast<unsigned char>(c1)) <
|
||||
tolower(static_cast<unsigned char>(c2)));
|
||||
}
|
||||
|
||||
struct CIStringLess :
|
||||
public binary_function<string, string, bool>
|
||||
{
|
||||
bool operator()(const string& s1, const string& s2) const
|
||||
{
|
||||
return (lexicographical_compare(s1.begin(), s1.end(),
|
||||
s2.begin(), s2.end(), CICharLess));
|
||||
}
|
||||
};
|
||||
|
||||
struct RRTypeParam {
|
||||
RRTypeParam(const string& code_string, uint16_t code) :
|
||||
code_string_(code_string), code_(code) {}
|
||||
string code_string_;
|
||||
uint16_t code_;
|
||||
|
||||
/// magic constants
|
||||
static const unsigned int MAX_CODE = 0xffff;
|
||||
static const string UNKNOWN_PREFIX;
|
||||
static const size_t UNKNOWN_PREFIXLEN;
|
||||
static const string UNKNOWN_MAX;
|
||||
static const size_t UNKNOWN_MAXLEN;
|
||||
};
|
||||
|
||||
typedef shared_ptr<RRTypeParam> RRTypeParamPtr;
|
||||
typedef map<string, RRTypeParamPtr, CIStringLess> StrRRTypeMap;
|
||||
typedef map<uint16_t, RRTypeParamPtr> CodeRRTypeMap;
|
||||
|
||||
const string RRTypeParam::UNKNOWN_PREFIX = "TYPE";
|
||||
const size_t RRTypeParam::UNKNOWN_PREFIXLEN =
|
||||
RRTypeParam::UNKNOWN_PREFIX.size();
|
||||
const string RRTypeParam::UNKNOWN_MAX = "TYPE65535";
|
||||
const size_t RRTypeParam::UNKNOWN_MAXLEN =
|
||||
RRTypeParam::UNKNOWN_MAX.size();
|
||||
|
||||
struct RRClassParam {
|
||||
RRClassParam(const string& code_string, uint16_t code) :
|
||||
code_string_(code_string), code_(code) {}
|
||||
string code_string_;
|
||||
uint16_t code_;
|
||||
|
||||
/// magic constants
|
||||
static const unsigned int MAX_CODE = 0xffff;
|
||||
static const string UNKNOWN_PREFIX;
|
||||
static const size_t UNKNOWN_PREFIXLEN;
|
||||
static const string UNKNOWN_MAX;
|
||||
static const size_t UNKNOWN_MAXLEN;
|
||||
};
|
||||
|
||||
typedef shared_ptr<RRClassParam> RRClassParamPtr;
|
||||
typedef map<string, RRClassParamPtr, CIStringLess> StrRRClassMap;
|
||||
typedef map<uint16_t, RRClassParamPtr> CodeRRClassMap;
|
||||
|
||||
const string RRClassParam::UNKNOWN_PREFIX = "CLASS";
|
||||
const size_t RRClassParam::UNKNOWN_PREFIXLEN =
|
||||
RRClassParam::UNKNOWN_PREFIX.size();
|
||||
const string RRClassParam::UNKNOWN_MAX = "CLASS65535";
|
||||
const size_t RRClassParam::UNKNOWN_MAXLEN =
|
||||
RRClassParam::UNKNOWN_MAX.size();
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief The \c RRParamRegistryImpl class is the actual implementation of
|
||||
/// \c RRParamRegistry.
|
||||
///
|
||||
/// The implementation is hidden from applications. We can refer to specific
|
||||
/// members of this class only within the implementation source file.
|
||||
///
|
||||
struct RRParamRegistryImpl {
|
||||
/// Mappings from RR type codes to textual representations.
|
||||
StrRRTypeMap str2typemap;
|
||||
/// Mappings from textual representations of RR types to integer codes.
|
||||
CodeRRTypeMap code2typemap;
|
||||
/// Mappings from RR class codes to textual representations.
|
||||
StrRRClassMap str2classmap;
|
||||
/// Mappings from textual representations of RR classes to integer codes.
|
||||
CodeRRClassMap code2classmap;
|
||||
};
|
||||
|
||||
RRParamRegistry::RRParamRegistry()
|
||||
{
|
||||
impl_ = new RRParamRegistryImpl;
|
||||
|
||||
// set up parameters for well-known RRs
|
||||
// XXX: this should eventually be more automatic.
|
||||
try {
|
||||
add("A", 1, "IN", 1);
|
||||
add("NS", 2, "IN", 1);
|
||||
|
||||
add("A", 1, "CH", 3);
|
||||
} catch (...) {
|
||||
delete impl_;
|
||||
throw;
|
||||
}
|
||||
//...
|
||||
}
|
||||
|
||||
RRParamRegistry::~RRParamRegistry()
|
||||
{
|
||||
delete impl_;
|
||||
}
|
||||
|
||||
RRParamRegistry&
|
||||
RRParamRegistry::getRegistry()
|
||||
{
|
||||
static RRParamRegistry registry;
|
||||
|
||||
return (registry);
|
||||
}
|
||||
|
||||
void
|
||||
RRParamRegistry::add(const string& typecode_string, uint16_t typecode,
|
||||
const string& classcode_string, uint16_t classcode
|
||||
/* rdata_factory (notyet) */)
|
||||
{
|
||||
// Rollback logic on failure is complicated. If adding the new type or
|
||||
// class fails, we should revert to the original state, cleaning up
|
||||
// intermediate state. But we need to make sure that we don't remove
|
||||
// existing data. addType()/addClass() will simply ignore an attempt to
|
||||
// add the same data, so the cleanup should be performed only when we add
|
||||
// something new but we fail in other part of the process.
|
||||
bool type_added = false;
|
||||
bool class_added = false;
|
||||
|
||||
try {
|
||||
type_added = addType(typecode_string, typecode);
|
||||
class_added = addClass(classcode_string, classcode);
|
||||
} catch (...) {
|
||||
if (type_added) {
|
||||
removeType(typecode);
|
||||
}
|
||||
if (class_added) {
|
||||
removeClass(classcode);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
///
|
||||
/// These are helper functions to implement case-insensitive string comparison.
|
||||
/// This could be simplified using strncasecmp(), but unfortunately it's not
|
||||
/// included in <cstring>. To be as much as portable within the C++ standard
|
||||
/// we take the "in house" approach here.
|
||||
///
|
||||
bool CICharEqual(char c1, char c2)
|
||||
{
|
||||
return (tolower(static_cast<unsigned char>(c1)) ==
|
||||
tolower(static_cast<unsigned char>(c2)));
|
||||
}
|
||||
|
||||
bool
|
||||
caseStringEqual(const string& s1, const string& s2, size_t n)
|
||||
{
|
||||
assert(s1.size() >= n && s2.size() >= n);
|
||||
|
||||
return (mismatch(s1.begin(), s1.begin() + n, s2.begin(), CICharEqual).first
|
||||
== s1.begin() + n);
|
||||
}
|
||||
|
||||
/// Code logic for RRTypes and RRClasses is mostly common except (C++) type and
|
||||
/// member names. So we define type-independent templates to describe the
|
||||
/// common logic and let concrete classes use it to avoid code duplicates.
|
||||
/// The following summarize template parameters used in the set of template
|
||||
/// functions:
|
||||
/// PT: parameter type, either RRTypeParam or RRClassParam
|
||||
/// MC: type of mapping class from code: either CodeRRTypeMap or CodeRRClassMap
|
||||
/// MS: type of mapping class from string: either StrRRTypeMap or StrRRClassMap
|
||||
/// ET: exception type for error handling: either InvalidRRType or
|
||||
/// InvalidRRClass
|
||||
template <typename PT, typename MC, typename MS, typename ET>
|
||||
inline bool
|
||||
addParam(const string& code_string, uint16_t code, MC& codemap, MS& stringmap)
|
||||
{
|
||||
// Duplicate type check
|
||||
typename MC::const_iterator found = codemap.find(code);
|
||||
if (found != codemap.end()) {
|
||||
if (found->second->code_string_ != code_string) {
|
||||
dns_throw(ET, "Duplicate RR parameter registration");
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
typedef shared_ptr<PT> ParamPtr;
|
||||
typedef pair<string, ParamPtr> StrParamPair;
|
||||
typedef pair<uint16_t, ParamPtr> CodeParamPair;
|
||||
ParamPtr param = ParamPtr(new PT(code_string, code));
|
||||
try {
|
||||
stringmap.insert(StrParamPair(code_string, param));
|
||||
codemap.insert(CodeParamPair(code, param));
|
||||
} catch (...) {
|
||||
// Rollback to the previous state: not all of the erase operations will
|
||||
// find the entry, but we don't care.
|
||||
stringmap.erase(code_string);
|
||||
codemap.erase(code);
|
||||
throw;
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
template <typename MC, typename MS>
|
||||
inline bool
|
||||
removeParam(uint16_t code, MC& codemap, MS& stringmap)
|
||||
{
|
||||
typename MC::iterator found = codemap.find(code);
|
||||
|
||||
if (found != codemap.end()) {
|
||||
size_t erased = stringmap.erase(found->second->code_string_);
|
||||
// We must have a corresponding entry of the str2 map exists
|
||||
assert(erased == 1);
|
||||
|
||||
codemap.erase(found);
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
template <typename PT, typename MS, typename ET>
|
||||
inline uint16_t
|
||||
textToCode(const string& code_str, MS& stringmap)
|
||||
{
|
||||
typename MS::const_iterator found;
|
||||
|
||||
found = stringmap.find(code_str);
|
||||
if (found != stringmap.end()) {
|
||||
return (found->second->code_);
|
||||
}
|
||||
|
||||
size_t l = code_str.size();
|
||||
if (l > PT::UNKNOWN_PREFIXLEN &&
|
||||
l <= PT::UNKNOWN_MAXLEN &&
|
||||
caseStringEqual(code_str, PT::UNKNOWN_PREFIX, PT::UNKNOWN_PREFIXLEN)) {
|
||||
unsigned int code;
|
||||
istringstream iss(code_str.substr(PT::UNKNOWN_PREFIXLEN,
|
||||
l - PT::UNKNOWN_PREFIXLEN));
|
||||
iss >> dec >> code;
|
||||
if (iss.rdstate() == ios::eofbit && code <= PT::MAX_CODE) {
|
||||
return (code);
|
||||
}
|
||||
}
|
||||
dns_throw(ET, "Unrecognized RR parameter string");
|
||||
}
|
||||
|
||||
template <typename PT, typename MC>
|
||||
inline string
|
||||
codeToText(uint16_t code, MC& codemap)
|
||||
{
|
||||
typename MC::const_iterator found;
|
||||
|
||||
found = codemap.find(code);
|
||||
if (found != codemap.end()) {
|
||||
return (found->second->code_string_);
|
||||
}
|
||||
|
||||
ostringstream ss;
|
||||
ss << code;
|
||||
return (PT::UNKNOWN_PREFIX + ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
RRParamRegistry::addType(const string& type_string, uint16_t code)
|
||||
{
|
||||
return (addParam<RRTypeParam, CodeRRTypeMap, StrRRTypeMap, RRTypeExists>
|
||||
(type_string, code, impl_->code2typemap, impl_->str2typemap));
|
||||
}
|
||||
|
||||
bool
|
||||
RRParamRegistry::removeType(uint16_t code)
|
||||
{
|
||||
return (removeParam<CodeRRTypeMap, StrRRTypeMap>(code, impl_->code2typemap,
|
||||
impl_->str2typemap));
|
||||
}
|
||||
|
||||
uint16_t
|
||||
RRParamRegistry::textToTypeCode(const string& type_string) const
|
||||
{
|
||||
return (textToCode<RRTypeParam, StrRRTypeMap,
|
||||
InvalidRRType>(type_string, impl_->str2typemap));
|
||||
}
|
||||
|
||||
string
|
||||
RRParamRegistry::codeToTypeText(uint16_t code) const
|
||||
{
|
||||
return (codeToText<RRTypeParam, CodeRRTypeMap>(code, impl_->code2typemap));
|
||||
}
|
||||
|
||||
bool
|
||||
RRParamRegistry::addClass(const string& class_string, uint16_t code)
|
||||
{
|
||||
return (addParam<RRClassParam, CodeRRClassMap, StrRRClassMap, RRClassExists>
|
||||
(class_string, code, impl_->code2classmap, impl_->str2classmap));
|
||||
}
|
||||
|
||||
bool
|
||||
RRParamRegistry::removeClass(uint16_t code)
|
||||
{
|
||||
return (removeParam<CodeRRClassMap, StrRRClassMap>(code,
|
||||
impl_->code2classmap,
|
||||
impl_->str2classmap));
|
||||
}
|
||||
|
||||
uint16_t
|
||||
RRParamRegistry::textToClassCode(const string& class_string) const
|
||||
{
|
||||
return (textToCode<RRClassParam, StrRRClassMap,
|
||||
InvalidRRClass>(class_string, impl_->str2classmap));
|
||||
}
|
||||
|
||||
string
|
||||
RRParamRegistry::codeToClassText(uint16_t code) const
|
||||
{
|
||||
return (codeToText<RRClassParam, CodeRRClassMap>(code,
|
||||
impl_->code2classmap));
|
||||
}
|
||||
}
|
||||
}
|
316
src/lib/dns/cpp/rrparamregistry.h
Normal file
316
src/lib/dns/cpp/rrparamregistry.h
Normal file
@@ -0,0 +1,316 @@
|
||||
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
// $Id$
|
||||
|
||||
#ifndef __RRPARAMREGISTRY_H
|
||||
#define __RRPARAMREGISTRY_H 1
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "exceptions.h"
|
||||
|
||||
namespace isc {
|
||||
namespace dns {
|
||||
|
||||
// forward declarations
|
||||
struct RRParamRegistryImpl;
|
||||
|
||||
///
|
||||
/// \brief A standard DNS module exception that is thrown if a new RR type is
|
||||
/// being registered with a different type string.
|
||||
///
|
||||
class RRTypeExists : public Exception {
|
||||
public:
|
||||
RRTypeExists(const char* file, size_t line, const char* what) :
|
||||
isc::dns::Exception(file, line, what) {}
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief A standard DNS module exception that is thrown if a new RR class is
|
||||
/// being registered with a different type string.
|
||||
///
|
||||
class RRClassExists : public Exception {
|
||||
public:
|
||||
RRClassExists(const char* file, size_t line, const char* what) :
|
||||
isc::dns::Exception(file, line, what) {}
|
||||
};
|
||||
|
||||
///
|
||||
/// The \c RRParamRegistry class represents a registry of parameters to
|
||||
/// manipulate DNS resource records (RRs).
|
||||
///
|
||||
/// A \c RRParamRegistry class object stores a mapping between RR types or
|
||||
/// classes and their textual representations. It will also have knowledge of
|
||||
/// how to create an RDATA object for a specific pair of RR type and class
|
||||
/// (not implemented in this version).
|
||||
///
|
||||
/// Normal applications that only handle standard DNS protocols won't have to
|
||||
/// care about this class. This is mostly an internal class to the DNS library
|
||||
/// to manage standard parameters. Some advanced applications may still need
|
||||
/// to use this class explicitly. For example, if an application wants to
|
||||
/// define and use an experimental non-standard RR type, it may want to register
|
||||
/// related protocol parameters for its convenience. This class is designed to
|
||||
/// allow such usage without modifying the library source code or rebuilding
|
||||
/// the library.
|
||||
///
|
||||
/// It is assumed that at most one instance of this class can exist so that
|
||||
/// the application uses the consistent set of registered parameters. To ensure
|
||||
/// this, this class is designed and implemented as a "singleton class": the
|
||||
/// constructor is intentionally private, and applications must get access to
|
||||
/// the single instance via the \c getRegistry() static member function.
|
||||
///
|
||||
/// In the current implementation, access to the singleton \c RRParamRegistry
|
||||
/// object is not thread safe.
|
||||
/// The application should ensure that multiple threads don't race in the
|
||||
/// first invocation of \c getRegistry(), and, if the registry needs to
|
||||
/// be changed dynamically, read and write operations are performed
|
||||
/// exclusively.
|
||||
/// Since this class should be static in common usage this restriction would
|
||||
/// be acceptable in practice.
|
||||
/// In the future, we may extend the implementation so that multiple threads can
|
||||
/// get access to the registry fully concurrently without any restriction.
|
||||
///
|
||||
/// Note: the implementation of this class is incomplete: we should at least
|
||||
/// add RDATA related parameters. This will be done in a near future version,
|
||||
/// at which point some of method signatures will be changed.
|
||||
class RRParamRegistry {
|
||||
///
|
||||
/// \name Constructors and Destructor
|
||||
///
|
||||
/// These are intentionally hidden (see the class description).
|
||||
//@{
|
||||
private:
|
||||
RRParamRegistry();
|
||||
RRParamRegistry(const RRParamRegistry& orig);
|
||||
~RRParamRegistry();
|
||||
//@}
|
||||
public:
|
||||
///
|
||||
/// \brief Return the singleton instance of \c RRParamRegistry.
|
||||
///
|
||||
/// This method is a unified access point to the singleton instance of
|
||||
/// the RR parameter registry (\c RRParamRegistry).
|
||||
/// On first invocation it internally constructs an instance of the
|
||||
/// \c RRParamRegistry class and returns a reference to it.
|
||||
/// This is a static object inside this method and will remain valid
|
||||
/// throughout the rest of the application lifetime.
|
||||
/// On subsequent calls this method simply returns a reference to the
|
||||
/// singleton object.
|
||||
///
|
||||
/// If resource allocation fails in the first invocation,
|
||||
/// a corresponding standard exception will be thrown.
|
||||
/// This method never fails otherwise. In particular, this method
|
||||
/// doesn't throw an exception once the singleton instance is constructed.
|
||||
///
|
||||
/// \return A reference to the singleton instance of \c RRParamRegistry.
|
||||
static RRParamRegistry& getRegistry();
|
||||
|
||||
///
|
||||
/// \name Registry Update Methods
|
||||
///
|
||||
//@{
|
||||
///
|
||||
/// \brief Add a set of parameters for a pair of RR type and class.
|
||||
///
|
||||
/// This method adds to the registry a specified set of RR parameters,
|
||||
/// including mappings between type/class codes and their textual
|
||||
/// representations.
|
||||
///
|
||||
/// Regarding the mappings between textual representations and integer
|
||||
/// codes, this methods behaves in the same way as \c addType() and
|
||||
/// \c addClass(). That is, it ignores any overriding attempt as
|
||||
/// long as the mapping is the same; otherwise the corresponding exception
|
||||
/// will be thrown.
|
||||
///
|
||||
/// This method provides the strong exception guarantee: unless an
|
||||
/// exception is thrown the entire specified set of parameters must be
|
||||
/// stored in the registry; if this method throws an exception the
|
||||
/// registry will remain in the state before this method is called.
|
||||
///
|
||||
/// Note: this method will be extended to support more parameters in a
|
||||
/// near future version.
|
||||
///
|
||||
/// \param type_string The textual representation of the RR type.
|
||||
/// \param type_code The integer code of the RR type.
|
||||
/// \param class_string The textual representation of the RR class.
|
||||
/// \param class_code The integer code of the RR class.
|
||||
void add(const std::string& type_string, uint16_t type_code,
|
||||
const std::string& class_string, uint16_t class_code);
|
||||
|
||||
/// \brief Add mappings between RR type code and textual representation.
|
||||
///
|
||||
/// This method adds a mapping from the type code of an RR to its textual
|
||||
/// representation and the reverse mapping in the registry.
|
||||
///
|
||||
/// If the given RR type is already registered with the same textual
|
||||
/// representation, this method simply ignores the duplicate mapping;
|
||||
/// if the given type is registered and a new pair with a different
|
||||
/// textual representation is being added,an exception of class
|
||||
/// \c RRTypeExist will be thrown.
|
||||
/// To replace an existing mapping with a different textual representation,
|
||||
/// the existing one must be removed by the \c removeType() method
|
||||
/// beforehand.
|
||||
///
|
||||
/// In addition, if resource allocation for the new mapping entries fails,
|
||||
/// a corresponding standard exception will be thrown.
|
||||
///
|
||||
/// This method provides the strong exception guarantee: unless an exception
|
||||
/// is thrown the specified mappings must be stored in the registry
|
||||
/// (although it may be an already existing one) on completion of the
|
||||
/// method; if this method throws an exception the registry will remain
|
||||
/// in the state before this method is called.
|
||||
///
|
||||
/// \param type_string The textual representation of the RR type.
|
||||
/// \param type_code The integer code of the RR type.
|
||||
/// \return \c true if a new mapping is added to the repository; \c false
|
||||
/// if the same mapping is already registered.
|
||||
bool addType(const std::string& type_string, uint16_t type_code);
|
||||
|
||||
/// \brief Remove mappings between RR type code and textual representation
|
||||
/// for a given type.
|
||||
///
|
||||
/// This method can safely be called whether or not the specified mappings
|
||||
/// exist in the registry. If not, this method simply ignores the attempt
|
||||
/// and returns \c false.
|
||||
///
|
||||
/// This method never throw an exception.
|
||||
///
|
||||
/// \param type_code The integer code of the RR type.
|
||||
/// \return \c true if mappings for the specified RR type exists and is
|
||||
/// removed; \c false if no such mapping is in the registry.
|
||||
bool removeType(uint16_t type_code);
|
||||
|
||||
/// \brief Add mappings between RR class code and textual representation.
|
||||
///
|
||||
/// This method adds a mapping from the class code of an RR to its textual
|
||||
/// representation and the reverse mapping in the registry.
|
||||
///
|
||||
/// If the given RR class is already registered with the same textual
|
||||
/// representation, this method simply ignores the duplicate mapping;
|
||||
/// if the given class is registered and a new pair with a different
|
||||
/// textual representation is being added,an exception of class
|
||||
/// \c RRClassExist will be thrown.
|
||||
/// To replace an existing mapping with a different textual representation,
|
||||
/// the existing one must be removed by the \c removeClass() method
|
||||
/// beforehand.
|
||||
///
|
||||
/// In addition, if resource allocation for the new mapping entries fails,
|
||||
/// a corresponding standard exception will be thrown.
|
||||
///
|
||||
/// This method provides the strong exception guarantee: unless an exception
|
||||
/// is thrown the specified mappings must be stored in the registry
|
||||
/// (although it may be an already existing one) on completion of the
|
||||
/// method; if this method throws an exception the registry will remain
|
||||
/// in the state before this method is called.
|
||||
///
|
||||
/// \param class_string The textual representation of the RR class.
|
||||
/// \param class_code The integer code of the RR class.
|
||||
/// \return
|
||||
bool addClass(const std::string& class_string, uint16_t class_code);
|
||||
|
||||
/// \brief Remove mappings between RR class code and textual representation
|
||||
/// for a given class.
|
||||
///
|
||||
/// This method can safely be called whether or not the specified mappings
|
||||
/// exist in the registry. If not, this method simply ignores the attempt
|
||||
/// and returns \c false.
|
||||
///
|
||||
/// This method never throw an exception.
|
||||
///
|
||||
/// \param class_code The integer code of the RR class.
|
||||
/// \return
|
||||
bool removeClass(uint16_t class_code);
|
||||
//@}
|
||||
|
||||
///
|
||||
/// \name Parameter Conversion Methods
|
||||
///
|
||||
//@{
|
||||
/// \brief Convert a textual representation of an RR type to the
|
||||
/// corresponding 16-bit integer code.
|
||||
///
|
||||
/// This method searches the \c RRParamRegistry for the mapping from the
|
||||
/// given textual representation of RR type to the corresponding integer
|
||||
/// code. If a mapping is found, it returns the associated type code;
|
||||
/// otherwise, if the given string is in the form of "TYPEnnnn", it returns
|
||||
/// the corresponding number as the type code; otherwise, it throws an
|
||||
/// exception of class \c InvalidRRType.
|
||||
///
|
||||
/// \param type_string The textual representation of the RR type.
|
||||
/// \return The RR type code for \c type_string.
|
||||
uint16_t textToTypeCode(const std::string& type_string) const;
|
||||
|
||||
/// \brief Convert type code into its textual representation.
|
||||
///
|
||||
/// This method searches the \c RRParamRegistry for the mapping from the
|
||||
/// given RR type code to its textual representation.
|
||||
/// If a mapping is found, it returns (a copy of) the associated string;
|
||||
/// otherwise, this method creates a new string in the form of "TYPEnnnn"
|
||||
/// where "nnnn" is the decimal representation of the type code, and
|
||||
/// returns the new string.
|
||||
///
|
||||
/// If resource allocation for the returned string fails,
|
||||
/// a corresponding standard exception will be thrown.
|
||||
/// This method never fails otherwise.
|
||||
///
|
||||
/// \param type_code The integer code of the RR type.
|
||||
/// \return A textual representation of the RR type for code \c type_code.
|
||||
std::string codeToTypeText(uint16_t type_code) const;
|
||||
|
||||
/// \brief Convert a textual representation of an RR class to the
|
||||
/// corresponding 16-bit integer code.
|
||||
///
|
||||
/// This method searches the \c RRParamRegistry for the mapping from the
|
||||
/// given textual representation of RR class to the corresponding integer
|
||||
/// code. If a mapping is found, it returns the associated class code;
|
||||
/// otherwise, if the given string is in the form of "CLASSnnnn", it returns
|
||||
/// the corresponding number as the class code; otherwise, it throws an
|
||||
/// exception of class \c InvalidRRClass.
|
||||
///
|
||||
/// \param class_string The textual representation of the RR class.
|
||||
/// \return The RR class code for \c class_string.
|
||||
uint16_t textToClassCode(const std::string& class_string) const;
|
||||
|
||||
/// \brief Convert class code into its textual representation.
|
||||
///
|
||||
/// This method searches the \c RRParamRegistry for the mapping from the
|
||||
/// given RR class code to its textual representation.
|
||||
/// If a mapping is found, it returns (a copy of) the associated string;
|
||||
/// otherwise, this method creates a new string in the form of "CLASSnnnn"
|
||||
/// where "nnnn" is the decimal representation of the class code, and
|
||||
/// returns the new string.
|
||||
///
|
||||
/// If resource allocation for the returned string fails,
|
||||
/// a corresponding standard exception will be thrown.
|
||||
/// This method never fails otherwise.
|
||||
///
|
||||
/// \param class_code The integer code of the RR class.
|
||||
/// \return A textual representation of the RR class for code \c class_code.
|
||||
std::string codeToClassText(uint16_t class_code) const;
|
||||
//@}
|
||||
|
||||
private:
|
||||
RRParamRegistryImpl* impl_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif // __RRPARAMREGISTRY_H
|
||||
|
||||
// Local Variables:
|
||||
// mode: c++
|
||||
// End:
|
95
src/lib/dns/cpp/rrparamregistry_unittest.cc
Normal file
95
src/lib/dns/cpp/rrparamregistry_unittest.cc
Normal file
@@ -0,0 +1,95 @@
|
||||
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
// $Id$
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "rrclass.h"
|
||||
#include "rrparamregistry.h"
|
||||
#include "rrtype.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace isc::dns;
|
||||
|
||||
namespace {
|
||||
class RRParamRegistryTest : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
ostringstream oss1;
|
||||
oss1 << test_class_code;
|
||||
test_class_unknown_str = "CLASS" + oss1.str();
|
||||
|
||||
ostringstream oss2;
|
||||
oss2 << test_type_code;
|
||||
test_type_unknown_str = "TYPE" + oss2.str();
|
||||
}
|
||||
|
||||
string test_class_unknown_str;
|
||||
string test_type_unknown_str;
|
||||
|
||||
// we assume class/type numbers are officially unassigned. If not we'll
|
||||
// need to update the test cases.
|
||||
static const uint16_t test_class_code = 65533;
|
||||
static const uint16_t test_type_code = 65534;
|
||||
static const string test_class_str;
|
||||
static const string test_type_str;
|
||||
};
|
||||
|
||||
const string RRParamRegistryTest::test_class_str("TESTCLASS");
|
||||
const string RRParamRegistryTest::test_type_str("TESTTYPE");
|
||||
|
||||
TEST_F(RRParamRegistryTest, addRemove)
|
||||
{
|
||||
RRParamRegistry::getRegistry().add(test_type_str, test_type_code,
|
||||
test_class_str, test_class_code);
|
||||
EXPECT_EQ(65533, RRClass("TESTCLASS").getCode());
|
||||
EXPECT_EQ(65534, RRType("TESTTYPE").getCode());
|
||||
|
||||
// the first removal attempt should succeed
|
||||
EXPECT_TRUE(RRParamRegistry::getRegistry().removeType(65534));
|
||||
// then toText() should treat it as an "unknown"
|
||||
EXPECT_EQ(test_type_unknown_str, RRType(test_type_code).toText());
|
||||
// attempt of removing non-existent mapping should result in 'false'
|
||||
EXPECT_FALSE(RRParamRegistry::getRegistry().removeType(65534));
|
||||
|
||||
// same set of tests for RR class.
|
||||
EXPECT_TRUE(RRParamRegistry::getRegistry().removeClass(65533));
|
||||
EXPECT_EQ(test_class_unknown_str, RRClass(test_class_code).toText());
|
||||
EXPECT_FALSE(RRParamRegistry::getRegistry().removeClass(65533));
|
||||
}
|
||||
|
||||
TEST_F(RRParamRegistryTest, addError)
|
||||
{
|
||||
// An attempt to override a pre-registered class should fail with an
|
||||
// exception, and the pre-registered one should remain in the registry.
|
||||
EXPECT_THROW(RRParamRegistry::getRegistry().add(test_type_str,
|
||||
test_type_code,
|
||||
test_class_str, 1),
|
||||
RRClassExists);
|
||||
EXPECT_EQ("IN", RRClass(1).toText());
|
||||
|
||||
// Same for RRType
|
||||
EXPECT_THROW(RRParamRegistry::getRegistry().add(test_type_str, 1,
|
||||
test_class_str,
|
||||
test_class_code),
|
||||
RRTypeExists);
|
||||
EXPECT_EQ("A", RRType(1).toText());
|
||||
}
|
||||
}
|
79
src/lib/dns/cpp/rrttl.cc
Normal file
79
src/lib/dns/cpp/rrttl.cc
Normal file
@@ -0,0 +1,79 @@
|
||||
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
// $Id$
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "buffer.h"
|
||||
#include "messagerenderer.h"
|
||||
#include "rrttl.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace isc::dns;
|
||||
|
||||
namespace isc {
|
||||
namespace dns {
|
||||
|
||||
RRTTL::RRTTL(const string& ttlstr)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
istringstream iss(ttlstr);
|
||||
iss >> dec >> val;
|
||||
if (iss.rdstate() == ios::eofbit) {
|
||||
ttlval_ = val;
|
||||
} else {
|
||||
dns_throw(InvalidRRTTL, "invalid TTL");
|
||||
}
|
||||
}
|
||||
|
||||
RRTTL::RRTTL(InputBuffer& buffer)
|
||||
{
|
||||
if (buffer.getLength() - buffer.getPosition() < sizeof(uint32_t)) {
|
||||
dns_throw(IncompleteRRTTL, "incomplete wire-format TTL value");
|
||||
}
|
||||
ttlval_ = buffer.readUint32();
|
||||
}
|
||||
|
||||
const string
|
||||
RRTTL::toText() const
|
||||
{
|
||||
ostringstream oss;
|
||||
oss << ttlval_;
|
||||
return (oss.str());
|
||||
}
|
||||
|
||||
void
|
||||
RRTTL::toWire(OutputBuffer& buffer) const
|
||||
{
|
||||
buffer.writeUint32(ttlval_);
|
||||
}
|
||||
|
||||
void
|
||||
RRTTL::toWire(MessageRenderer& renderer) const
|
||||
{
|
||||
renderer.writeUint32(ttlval_);
|
||||
}
|
||||
|
||||
ostream&
|
||||
operator<<(ostream& os, const RRTTL& rrttl)
|
||||
{
|
||||
os << rrttl.toText();
|
||||
return (os);
|
||||
}
|
||||
}
|
||||
}
|
259
src/lib/dns/cpp/rrttl.h
Normal file
259
src/lib/dns/cpp/rrttl.h
Normal file
@@ -0,0 +1,259 @@
|
||||
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
// $Id$
|
||||
|
||||
#ifndef __RRTTL_H
|
||||
#define __RRTTL_H 1
|
||||
|
||||
#include "exceptions.h"
|
||||
|
||||
namespace isc {
|
||||
namespace dns {
|
||||
|
||||
// forward declarations
|
||||
class InputBuffer;
|
||||
class OutputBuffer;
|
||||
class MessageRenderer;
|
||||
|
||||
///
|
||||
/// \brief A standard DNS module exception that is thrown if an RRTTL object
|
||||
/// is being constructed from an unrecognized string.
|
||||
///
|
||||
class InvalidRRTTL : public Exception {
|
||||
public:
|
||||
InvalidRRTTL(const char* file, size_t line, const char* what) :
|
||||
isc::dns::Exception(file, line, what) {}
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief A standard DNS module exception that is thrown if an RRTTL object
|
||||
/// is being constructed from a incomplete (too short) wire-format data.
|
||||
///
|
||||
class IncompleteRRTTL : public Exception {
|
||||
public:
|
||||
IncompleteRRTTL(const char* file, size_t line, const char* what) :
|
||||
isc::dns::Exception(file, line, what) {}
|
||||
};
|
||||
|
||||
///
|
||||
/// The \c RRTTL class encapsulates TTLs used in DNS resource records.
|
||||
///
|
||||
/// This is a straightforward class; an \c RRTTL object simply maintains a
|
||||
/// 32-bit unsigned integer corresponding to the TTL value. The main purpose
|
||||
/// of this class is to provide convenient interfaces to convert a textual
|
||||
/// representation into the integer TTL value and vice versa, and to handle
|
||||
/// wire-format representations.
|
||||
class RRTTL {
|
||||
public:
|
||||
///
|
||||
/// \name Constructors and Destructor
|
||||
///
|
||||
/// Note: We use the default copy constructor and the default copy
|
||||
/// assignment operator intentionally.
|
||||
//@{
|
||||
/// Constructor from an integer TTL value.
|
||||
///
|
||||
/// This constructor never throws an exception.
|
||||
///
|
||||
/// \param ttlval An 32-bit integer of the RRTTL.
|
||||
explicit RRTTL(uint32_t ttlval) : ttlval_(ttlval) {}
|
||||
/// Constructor from a string.
|
||||
///
|
||||
/// This version of the implementation only accepts decimal TTL values in
|
||||
/// seconds.
|
||||
/// In a near future version, we'll extend it so that we can accept more
|
||||
/// convenient ones such as "2H" or "1D".
|
||||
///
|
||||
/// If the given string is not recognized as a valid representation of
|
||||
/// an RR TTL, an exception of class \c InvalidRRTTL will be thrown.
|
||||
///
|
||||
/// \param ttlstr A string representation of the \c RRTTL
|
||||
explicit RRTTL(const std::string& ttlstr);
|
||||
/// Constructor from wire-format data.
|
||||
///
|
||||
/// The \c buffer parameter normally stores a complete DNS message
|
||||
/// containing the RRTTL to be constructed. The current read position of
|
||||
/// the buffer points to the head of the type.
|
||||
///
|
||||
/// If the given data does not large enough to contain a 16-bit integer,
|
||||
/// an exception of class \c IncompleteRRTTL will be thrown.
|
||||
///
|
||||
/// \param buffer A buffer storing the wire format data.
|
||||
explicit RRTTL(InputBuffer& buffer);
|
||||
///
|
||||
//@}
|
||||
|
||||
///
|
||||
/// \name Converter methods
|
||||
///
|
||||
//@{
|
||||
/// \brief Convert the \c RRTTL to a string.
|
||||
///
|
||||
/// This version of implementation simply converts the TTL value into the
|
||||
/// numeric textual representation. We may introduce more human-readable
|
||||
/// format depending on the context in future versions.
|
||||
///
|
||||
/// If resource allocation in rendering process fails, a corresponding
|
||||
/// standard exception will be thrown.
|
||||
///
|
||||
/// \return A string representation of the \c RRTTL.
|
||||
const std::string toText() const;
|
||||
/// \brief Render the \c RRTTL in the wire format.
|
||||
///
|
||||
/// This method renders the TTL value in network byte order via \c renderer,
|
||||
/// which encapsulates output buffer and other rendering contexts.
|
||||
///
|
||||
/// If resource allocation in rendering process fails, a corresponding
|
||||
/// standard exception will be thrown.
|
||||
///
|
||||
/// \param buffer An output buffer to store the wire data.
|
||||
void toWire(MessageRenderer& renderer) const;
|
||||
/// \brief Render the \c RRTTL in the wire format.
|
||||
///
|
||||
/// This method renders the TTL value in network byte order into the
|
||||
/// \c buffer.
|
||||
///
|
||||
/// If resource allocation in rendering process fails, a corresponding
|
||||
/// standard exception will be thrown.
|
||||
///
|
||||
/// \param renderer DNS message rendering context that encapsulates the
|
||||
/// output buffer in which the RRTTL is to be stored.
|
||||
void toWire(OutputBuffer& buffer) const;
|
||||
//@}
|
||||
|
||||
///
|
||||
/// \name Getter Methods
|
||||
///
|
||||
//@{
|
||||
/// \brief Returns the TTL value as a 32-bit unsigned integer.
|
||||
///
|
||||
/// This method never throws an exception.
|
||||
///
|
||||
/// \return An 32-bit integer corresponding to the RRTTL.
|
||||
uint32_t getValue() const { return (ttlval_); }
|
||||
//@}
|
||||
|
||||
///
|
||||
/// \name Comparison methods
|
||||
///
|
||||
/// Comparison between two \c RRTTL objects is performed in a
|
||||
/// straightforward way, that is, comparing the corresponding TTL values
|
||||
/// (which is the result of the \c getValue() method) as 32-bit unsigned
|
||||
/// integers.
|
||||
//@{
|
||||
/// \brief Return true iff two RRTTLs are equal.
|
||||
///
|
||||
/// This method never throws an exception.
|
||||
///
|
||||
/// \param other the \c RRTTL object to compare against.
|
||||
bool equals(const RRTTL& other) const
|
||||
{ return (ttlval_ == other.ttlval_); }
|
||||
/// \brief Same as \c equals().
|
||||
bool operator==(const RRTTL& other) const
|
||||
{ return (ttlval_ == other.ttlval_); }
|
||||
/// \brief Return true iff two RRTTLs are not equal.
|
||||
///
|
||||
/// This method never throws an exception.
|
||||
///
|
||||
/// \param other the \c RRTTL object to compare against.
|
||||
bool nequals(const RRTTL& other) const
|
||||
{ return (ttlval_ != other.ttlval_); }
|
||||
/// \brief Same as \c nequals().
|
||||
bool operator!=(const RRTTL& other) const
|
||||
{ return (ttlval_ != other.ttlval_); }
|
||||
/// \brief Less-than or equal comparison for RRTTL against \c other.
|
||||
///
|
||||
/// This method never throws an exception.
|
||||
///
|
||||
/// \param other the \c RRTTL object to compare against.
|
||||
/// \return true if \c this RRTTL is less than or equal to the \c other;
|
||||
/// otherwise false.
|
||||
bool leq(const RRTTL& other) const
|
||||
{ return (ttlval_ <= other.ttlval_); }
|
||||
|
||||
/// Same as \c leq()
|
||||
bool operator<=(const RRTTL& other) const
|
||||
{ return (ttlval_ <= other.ttlval_); }
|
||||
|
||||
/// \brief Greater-than or equal comparison for RRTTL against \c other.
|
||||
///
|
||||
/// This method never throws an exception.
|
||||
///
|
||||
/// \param other the \c RRTTL object to compare against.
|
||||
/// \return true if \c this RRTTL is greater than or equal to the \c other;
|
||||
/// otherwise false.
|
||||
bool geq(const RRTTL& other) const
|
||||
{ return (ttlval_ >= other.ttlval_); }
|
||||
|
||||
/// Same as \c geq()
|
||||
bool operator>=(const RRTTL& other) const
|
||||
{ return (ttlval_ >= other.ttlval_); }
|
||||
|
||||
/// \brief Less-than comparison for RRTTL against \c other.
|
||||
///
|
||||
/// This method never throws an exception.
|
||||
///
|
||||
/// \param other the \c RRTTL object to compare against.
|
||||
/// \return true if \c this RRTTL is less than the \c other;
|
||||
/// otherwise false.
|
||||
bool lthan(const RRTTL& other) const
|
||||
{ return (ttlval_ < other.ttlval_); }
|
||||
|
||||
/// Same as \c lthan()
|
||||
bool operator<(const RRTTL& other) const
|
||||
{ return (ttlval_ < other.ttlval_); }
|
||||
|
||||
/// \brief Greater-than comparison for RRTTL against \c other.
|
||||
///
|
||||
/// This method never throws an exception.
|
||||
///
|
||||
/// \param other the \c RRTTL object to compare against.
|
||||
/// \return true if \c this RRTTL is greater than the \c other;
|
||||
/// otherwise false.
|
||||
bool gthan(const RRTTL& other) const
|
||||
{ return (ttlval_ > other.ttlval_); }
|
||||
|
||||
/// Same as \c gthan()
|
||||
bool operator>(const RRTTL& other) const
|
||||
{ return (ttlval_ > other.ttlval_); }
|
||||
//@}
|
||||
|
||||
private:
|
||||
uint32_t ttlval_;
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Insert the \c RRTTL as a string into stream.
|
||||
///
|
||||
/// This method convert the \c rrttl into a string and inserts it into the
|
||||
/// output stream \c os.
|
||||
///
|
||||
/// This function overloads the global operator<< to behave as described in
|
||||
/// ostream::operator<< but applied to \c RRTTL objects.
|
||||
///
|
||||
/// \param os A \c std::ostream object on which the insertion operation is
|
||||
/// performed.
|
||||
/// \param rrttl The \c RRTTL object output by the operation.
|
||||
/// \return A reference to the same \c std::ostream object referenced by
|
||||
/// parameter \c os after the insertion operation.
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const RRTTL& rrttl);
|
||||
}
|
||||
}
|
||||
#endif // __RRTTL_H
|
||||
|
||||
// Local Variables:
|
||||
// mode: c++
|
||||
// End:
|
200
src/lib/dns/cpp/rrttl_unittest.cc
Normal file
200
src/lib/dns/cpp/rrttl_unittest.cc
Normal file
@@ -0,0 +1,200 @@
|
||||
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
// $Id$
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "buffer.h"
|
||||
#include "messagerenderer.h"
|
||||
#include "rrttl.h"
|
||||
|
||||
#include "unittest_util.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace isc;
|
||||
using namespace isc::dns;
|
||||
|
||||
namespace {
|
||||
class RRTTLTest : public ::testing::Test {
|
||||
protected:
|
||||
RRTTLTest() : obuffer(0), renderer(obuffer) {}
|
||||
|
||||
OutputBuffer obuffer;
|
||||
MessageRenderer renderer;
|
||||
|
||||
static RRTTL rrttlFactoryFromWire(const char* datafile);
|
||||
static const RRTTL ttl_0, ttl_1h, ttl_1d, ttl_32bit, ttl_max;
|
||||
static const RRTTL ttl_small, ttl_large;
|
||||
static const uint8_t wiredata[20];
|
||||
};
|
||||
|
||||
const RRTTL RRTTLTest::ttl_0(0);
|
||||
const RRTTL RRTTLTest::ttl_1h(3600);
|
||||
const RRTTL RRTTLTest::ttl_1d(86400);
|
||||
const RRTTL RRTTLTest::ttl_32bit(0x12345678);
|
||||
const RRTTL RRTTLTest::ttl_max(0xffffffff);
|
||||
|
||||
const RRTTL RRTTLTest::ttl_small(1);
|
||||
const RRTTL RRTTLTest::ttl_large(0x80000001);
|
||||
// This is wire-format data for the above sample RRTTLs rendered in the
|
||||
// appearing order.
|
||||
const uint8_t RRTTLTest::wiredata[20] = { 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x0e, 0x10,
|
||||
0x00, 0x01, 0x51, 0x80,
|
||||
0x12, 0x34, 0x56, 0x78,
|
||||
0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
RRTTL
|
||||
RRTTLTest::rrttlFactoryFromWire(const char* datafile)
|
||||
{
|
||||
std::vector<unsigned char> data;
|
||||
UnitTestUtil::readWireData(datafile, data);
|
||||
|
||||
InputBuffer buffer(&data[0], data.size());
|
||||
|
||||
return (RRTTL(buffer));
|
||||
}
|
||||
|
||||
TEST_F(RRTTLTest, fromText)
|
||||
{
|
||||
EXPECT_EQ(0, ttl_0.getValue());
|
||||
EXPECT_EQ(3600, ttl_1h.getValue());
|
||||
EXPECT_EQ(86400, ttl_1d.getValue());
|
||||
EXPECT_EQ(0x12345678, ttl_32bit.getValue());
|
||||
EXPECT_EQ(0xffffffff, ttl_max.getValue());
|
||||
|
||||
EXPECT_THROW(RRTTL("1D"), InvalidRRTTL); // we don't support this form yet
|
||||
EXPECT_THROW(RRTTL("0xdeadbeef"), InvalidRRTTL); // must be decimal
|
||||
EXPECT_THROW(RRTTL("-1"), InvalidRRTTL); // must be positive
|
||||
EXPECT_THROW(RRTTL("1.1"), InvalidRRTTL); // must be integer
|
||||
EXPECT_THROW(RRTTL("4294967296"), InvalidRRTTL); // must be 32-bit
|
||||
}
|
||||
|
||||
TEST_F(RRTTLTest, fromWire)
|
||||
{
|
||||
EXPECT_EQ(0x12345678,
|
||||
rrttlFactoryFromWire("testdata/rrcode32_fromWire1").getValue());
|
||||
EXPECT_THROW(rrttlFactoryFromWire("testdata/rrcode32_fromWire2"),
|
||||
IncompleteRRTTL);
|
||||
}
|
||||
|
||||
TEST_F(RRTTLTest, toText)
|
||||
{
|
||||
EXPECT_EQ("0", ttl_0.toText());
|
||||
EXPECT_EQ("3600", ttl_1h.toText());
|
||||
EXPECT_EQ("86400", ttl_1d.toText());
|
||||
EXPECT_EQ("305419896", ttl_32bit.toText());
|
||||
EXPECT_EQ("4294967295", ttl_max.toText());
|
||||
}
|
||||
|
||||
TEST_F(RRTTLTest, toWireBuffer)
|
||||
{
|
||||
ttl_0.toWire(obuffer);
|
||||
ttl_1h.toWire(obuffer);
|
||||
ttl_1d.toWire(obuffer);
|
||||
ttl_32bit.toWire(obuffer);
|
||||
ttl_max.toWire(obuffer);
|
||||
|
||||
EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
|
||||
obuffer.getData(), obuffer.getLength(),
|
||||
wiredata, sizeof(wiredata));
|
||||
}
|
||||
|
||||
TEST_F(RRTTLTest, toWireRenderer)
|
||||
{
|
||||
ttl_0.toWire(renderer);
|
||||
ttl_1h.toWire(renderer);
|
||||
ttl_1d.toWire(renderer);
|
||||
ttl_32bit.toWire(renderer);
|
||||
ttl_max.toWire(renderer);
|
||||
|
||||
EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
|
||||
obuffer.getData(), obuffer.getLength(),
|
||||
wiredata, sizeof(wiredata));
|
||||
}
|
||||
|
||||
TEST_F(RRTTLTest, equal)
|
||||
{
|
||||
EXPECT_TRUE(RRTTL("3600") == ttl_1h);
|
||||
EXPECT_TRUE(RRTTL("86400").equals(ttl_1d));
|
||||
|
||||
EXPECT_TRUE(ttl_1d != ttl_1h);
|
||||
EXPECT_TRUE(ttl_1d.nequals(ttl_max));
|
||||
}
|
||||
|
||||
//
|
||||
// The following set of tests confirm the result of <=, <, >=, >
|
||||
// The test logic is simple, and all tests are just straightforward variations
|
||||
// of the first one.
|
||||
//
|
||||
TEST_F(RRTTLTest, leq)
|
||||
{
|
||||
// small <= large is true
|
||||
EXPECT_TRUE(ttl_small.leq(ttl_large));
|
||||
EXPECT_TRUE(ttl_small <= ttl_large);
|
||||
|
||||
// small <= small is true
|
||||
EXPECT_TRUE(ttl_small.leq(ttl_small));
|
||||
EXPECT_TRUE(ttl_small <= ttl_small);
|
||||
|
||||
// large <= small is false
|
||||
EXPECT_FALSE(ttl_large.leq(ttl_small));
|
||||
EXPECT_FALSE(ttl_large <= ttl_small);
|
||||
}
|
||||
|
||||
TEST_F(RRTTLTest, geq)
|
||||
{
|
||||
EXPECT_TRUE(ttl_large.geq(ttl_small));
|
||||
EXPECT_TRUE(ttl_large >= ttl_small);
|
||||
|
||||
EXPECT_TRUE(ttl_large.geq(ttl_large));
|
||||
EXPECT_TRUE(ttl_large >= ttl_large);
|
||||
|
||||
EXPECT_FALSE(ttl_small.geq(ttl_large));
|
||||
EXPECT_FALSE(ttl_small >= ttl_large);
|
||||
}
|
||||
|
||||
TEST_F(RRTTLTest, lthan)
|
||||
{
|
||||
EXPECT_TRUE(ttl_small.lthan(ttl_large));
|
||||
EXPECT_TRUE(ttl_small < ttl_large);
|
||||
|
||||
EXPECT_FALSE(ttl_small.lthan(ttl_small));
|
||||
EXPECT_FALSE(ttl_small < ttl_small);
|
||||
|
||||
EXPECT_FALSE(ttl_large.lthan(ttl_small));
|
||||
EXPECT_FALSE(ttl_large < ttl_small);
|
||||
}
|
||||
|
||||
TEST_F(RRTTLTest, gthan)
|
||||
{
|
||||
EXPECT_TRUE(ttl_large.gthan(ttl_small));
|
||||
EXPECT_TRUE(ttl_large > ttl_small);
|
||||
|
||||
EXPECT_FALSE(ttl_large.gthan(ttl_large));
|
||||
EXPECT_FALSE(ttl_large > ttl_large);
|
||||
|
||||
EXPECT_FALSE(ttl_small.gthan(ttl_large));
|
||||
EXPECT_FALSE(ttl_small > ttl_large);
|
||||
}
|
||||
|
||||
// test operator<<. We simply confirm it appends the result of toText().
|
||||
TEST_F(RRTTLTest, LeftShiftOperator)
|
||||
{
|
||||
ostringstream oss;
|
||||
oss << ttl_1h;
|
||||
EXPECT_EQ(ttl_1h.toText(), oss.str());
|
||||
}
|
||||
}
|
72
src/lib/dns/cpp/rrtype.cc
Normal file
72
src/lib/dns/cpp/rrtype.cc
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
// $Id$
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "buffer.h"
|
||||
#include "exceptions.h"
|
||||
#include "messagerenderer.h"
|
||||
#include "rrparamregistry.h"
|
||||
#include "rrtype.h"
|
||||
|
||||
using namespace std;
|
||||
using isc::dns::RRType;
|
||||
using isc::dns::OutputBuffer;
|
||||
|
||||
namespace isc {
|
||||
namespace dns {
|
||||
|
||||
RRType::RRType(const string& typestr)
|
||||
{
|
||||
typecode_ = RRParamRegistry::getRegistry().textToTypeCode(typestr);
|
||||
}
|
||||
|
||||
RRType::RRType(InputBuffer& buffer)
|
||||
{
|
||||
if (buffer.getLength() - buffer.getPosition() < sizeof(uint16_t)) {
|
||||
dns_throw(IncompleteRRType, "incomplete wire-format RR type");
|
||||
}
|
||||
typecode_ = buffer.readUint16();
|
||||
}
|
||||
|
||||
const string
|
||||
RRType::toText() const
|
||||
{
|
||||
return (RRParamRegistry::getRegistry().codeToTypeText(typecode_));
|
||||
}
|
||||
|
||||
void
|
||||
RRType::toWire(OutputBuffer& buffer) const
|
||||
{
|
||||
buffer.writeUint16(typecode_);
|
||||
}
|
||||
|
||||
void
|
||||
RRType::toWire(MessageRenderer& renderer) const
|
||||
{
|
||||
renderer.writeUint16(typecode_);
|
||||
}
|
||||
|
||||
ostream&
|
||||
operator<<(ostream& os, const RRType& rrtype)
|
||||
{
|
||||
os << rrtype.toText();
|
||||
return (os);
|
||||
}
|
||||
}
|
||||
}
|
302
src/lib/dns/cpp/rrtype.h
Normal file
302
src/lib/dns/cpp/rrtype.h
Normal file
@@ -0,0 +1,302 @@
|
||||
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
// $Id$
|
||||
|
||||
#ifndef __RRTYPE_H
|
||||
#define __RRTYPE_H 1
|
||||
|
||||
#include "exceptions.h"
|
||||
|
||||
namespace isc {
|
||||
namespace dns {
|
||||
|
||||
// forward declarations
|
||||
class InputBuffer;
|
||||
class OutputBuffer;
|
||||
class MessageRenderer;
|
||||
|
||||
///
|
||||
/// \brief A standard DNS module exception that is thrown if an RRType object
|
||||
/// is being constructed from an unrecognized string.
|
||||
///
|
||||
class InvalidRRType : public Exception {
|
||||
public:
|
||||
InvalidRRType(const char* file, size_t line, const char* what) :
|
||||
isc::dns::Exception(file, line, what) {}
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief A standard DNS module exception that is thrown if an RRType object
|
||||
/// is being constructed from a incomplete (too short) wire-format data.
|
||||
///
|
||||
class IncompleteRRType : public Exception {
|
||||
public:
|
||||
IncompleteRRType(const char* file, size_t line, const char* what) :
|
||||
isc::dns::Exception(file, line, what) {}
|
||||
};
|
||||
|
||||
///
|
||||
/// The \c RRType class encapsulates DNS resource record types.
|
||||
///
|
||||
/// This class manages the 16-bit integer type codes in quite a straightforward
|
||||
/// way. The only non trivial task is to handle textual representations of
|
||||
/// RR types, such as "A", "AAAA", or "TYPE65534".
|
||||
///
|
||||
/// This class consults a helper \c RRParamRegistry class, which is a registry
|
||||
/// of RR related parameters and has the singleton object. This registry
|
||||
/// provides a mapping between RR type codes and their "well-known" textual
|
||||
/// representations.
|
||||
/// Parameters of RR types defined by DNS protocol standards are automatically
|
||||
/// registered at initialization time and are ensured to be always available for
|
||||
/// applications unless the application explicitly modifies the registry.
|
||||
///
|
||||
/// For convenience, this class defines constant class objects corresponding to
|
||||
/// standard RR types. These are generally referred to as the form of
|
||||
/// <code>RRType::{type-text}()</code>.
|
||||
/// For example, \c RRType::NS() is an \c RRType object corresponding to the NS
|
||||
/// resource record (type code 2).
|
||||
/// Note that these constants are used through a "proxy" function.
|
||||
/// This is because they may be used to initialize another non-local (e.g.
|
||||
/// global or namespace-scope) static object as follows:
|
||||
///
|
||||
/// \code
|
||||
/// namespace foo {
|
||||
/// const RRType default_type = RRType::A();
|
||||
/// } \endcode
|
||||
///
|
||||
/// In order to ensure that the constant RRType object has been initialized
|
||||
/// before the initialization for \c default_type, we need help from
|
||||
/// the proxy function.
|
||||
///
|
||||
/// In the current implementation, the initialization of the well-known
|
||||
/// static objects is not thread safe. The same consideration as the
|
||||
/// \c RRParamRegistry class applies. We may extend the implementation so
|
||||
/// that the initialization is ensured to be thread safe in a future version.
|
||||
///
|
||||
/// Note to developers: since it's expected that some of these constant
|
||||
/// \c RRType objects are frequently used in a performance sensitive path,
|
||||
/// we define these proxy functions as inline. This makes sense only when
|
||||
/// the corresponding static objects are defined only once even if they used
|
||||
/// in different source files. Sufficiently modern compilers should meet
|
||||
/// this assumption, but if we encounter memory bloat due to this problem with
|
||||
/// particular compilers we need to revisit the design or think about
|
||||
/// workaround.
|
||||
class RRType {
|
||||
public:
|
||||
///
|
||||
/// \name Constructors and Destructor
|
||||
///
|
||||
//@{
|
||||
/// Constructor from an integer type code.
|
||||
///
|
||||
/// This constructor never throws an exception.
|
||||
///
|
||||
/// \param typecode An 16-bit integer code corresponding to the RRType.
|
||||
explicit RRType(uint16_t typecode) : typecode_(typecode) {}
|
||||
/// Constructor from a string.
|
||||
///
|
||||
/// A valid string is one of "well-known" textual type representations
|
||||
/// such as "A", "AAAA", or "NS", or in the standard format for "unknown"
|
||||
/// RR types as defined in RFC3597, i.e., "TYPEnnnn".
|
||||
///
|
||||
/// More precisely, the "well-known" representations are the ones stored
|
||||
/// in the \c RRParamRegistry registry (see the class description).
|
||||
///
|
||||
/// As for the format of "TYPEnnnn", "nnnn" must represent a valid 16-bit
|
||||
/// unsigned integer, which may contain leading 0's as long as it consists
|
||||
/// of at most 5 characters (inclusive).
|
||||
/// For example, "TYPE1" and "TYPE001" are valid and represent the same
|
||||
/// RR type, but "TYPE65536" and "TYPE000001" are invalid.
|
||||
/// A "TYPEnnnn" representation is valid even if the corresponding type code
|
||||
/// is registered in the \c RRParamRegistry object. For example, both
|
||||
/// "A" and "TYPE1" are valid and represent the same RR type.
|
||||
///
|
||||
/// All of these representations are case insensitive; "NS" and "ns", and
|
||||
/// "TYPE1" and "type1" are all valid and represent the same RR types,
|
||||
/// respectively.
|
||||
///
|
||||
/// If the given string is not recognized as a valid representation of
|
||||
/// an RR type, an exception of class \c InvalidRRType will be thrown.
|
||||
///
|
||||
/// \param typestr A string representation of the \c RRType
|
||||
explicit RRType(const std::string& typestr);
|
||||
/// Constructor from wire-format data.
|
||||
///
|
||||
/// The \c buffer parameter normally stores a complete DNS message
|
||||
/// containing the RRType to be constructed. The current read position of
|
||||
/// the buffer points to the head of the type.
|
||||
///
|
||||
/// If the given data does not large enough to contain a 16-bit integer,
|
||||
/// an exception of class \c IncompleteRRType will be thrown.
|
||||
///
|
||||
/// \param buffer A buffer storing the wire format data.
|
||||
explicit RRType(InputBuffer& buffer);
|
||||
///
|
||||
/// We use the default copy constructor intentionally.
|
||||
//@}
|
||||
/// We use the default copy assignment operator intentionally.
|
||||
///
|
||||
|
||||
///
|
||||
/// \name Converter methods
|
||||
///
|
||||
//@{
|
||||
/// \brief Convert the \c RRType to a string.
|
||||
///
|
||||
/// If a "well known" textual representation for the type code is registered
|
||||
/// in the RR parameter registry (see the class description), that will be
|
||||
/// used as the return value of this method. Otherwise, this method creates
|
||||
/// a new string for an "unknown" RR type in the format defined in RFC3597,
|
||||
/// i.e., "TYPEnnnn", and returns it.
|
||||
///
|
||||
/// If resource allocation for the string fails, a corresponding standard
|
||||
/// exception will be thrown.
|
||||
///
|
||||
/// \return A string representation of the \c RRType.
|
||||
const std::string toText() const;
|
||||
/// \brief Render the \c RRType in the wire format.
|
||||
///
|
||||
/// This method renders the type code in network byte order via \c renderer,
|
||||
/// which encapsulates output buffer and other rendering contexts.
|
||||
///
|
||||
/// If resource allocation in rendering process fails, a corresponding
|
||||
/// standard exception will be thrown.
|
||||
///
|
||||
/// \param buffer An output buffer to store the wire data.
|
||||
void toWire(MessageRenderer& renderer) const;
|
||||
/// \brief Render the \c RRType in the wire format.
|
||||
///
|
||||
/// This method renders the type code in network byte order into the
|
||||
/// \c buffer.
|
||||
///
|
||||
/// If resource allocation in rendering process fails, a corresponding
|
||||
/// standard exception will be thrown.
|
||||
///
|
||||
/// \param renderer DNS message rendering context that encapsulates the
|
||||
/// output buffer in which the RRType is to be stored.
|
||||
void toWire(OutputBuffer& buffer) const;
|
||||
//@}
|
||||
|
||||
///
|
||||
/// \name Getter Methods
|
||||
///
|
||||
//@{
|
||||
/// \brief Returns the RR type code as a 16-bit unsigned integer.
|
||||
///
|
||||
/// This method never throws an exception.
|
||||
///
|
||||
/// \return An 16-bit integer code corresponding to the RRType.
|
||||
uint16_t getCode() const { return (typecode_); }
|
||||
//@}
|
||||
|
||||
///
|
||||
/// \name Comparison methods
|
||||
///
|
||||
//@{
|
||||
/// \brief Return true iff two RRTypes are equal.
|
||||
///
|
||||
/// Two RRTypes are equal iff their type codes are equal.
|
||||
///
|
||||
/// This method never throws an exception.
|
||||
///
|
||||
/// \param other the \c RRType object to compare against.
|
||||
/// \return true if the two RRTypes are equal; otherwise false.
|
||||
bool equals(const RRType& other) const
|
||||
{ return (typecode_ == other.typecode_); }
|
||||
/// \brief Same as \c equals().
|
||||
bool operator==(const RRType& other) const { return equals(other); }
|
||||
|
||||
/// \brief Return true iff two RRTypes are equal.
|
||||
///
|
||||
/// This method never throws an exception.
|
||||
///
|
||||
/// \param other the \c RRType object to compare against.
|
||||
/// \return true if the two RRTypes are not equal; otherwise false.
|
||||
bool nequals(const RRType& other) const
|
||||
{ return (typecode_ != other.typecode_); }
|
||||
/// \brief Same as \c nequals().
|
||||
bool operator!=(const RRType& other) const { return nequals(other); }
|
||||
|
||||
/// \brief Less-than comparison for RRType against \c other
|
||||
///
|
||||
/// We define the less-than relationship based on their type codes;
|
||||
/// one RRType is less than the other iff the code of the former is less
|
||||
/// than that of the other as unsigned integers.
|
||||
/// The relationship is meaningless in terms of DNS protocol; the only
|
||||
/// reason we define this method is that RRType objects can be stored in
|
||||
/// STL containers without requiring user-defined less-than relationship.
|
||||
/// We therefore don't define other comparison operators.
|
||||
///
|
||||
/// This method never throws an exception.
|
||||
///
|
||||
/// \param other the \c RRType object to compare against.
|
||||
/// \return true if \c this RRType is less than the \c other; otherwise
|
||||
/// false.
|
||||
bool operator<(const RRType& other) const
|
||||
{ return (typecode_ < other.typecode_); }
|
||||
//@}
|
||||
|
||||
// (Some) Well-known RRtype "constants"
|
||||
// Note: we'll auto-generate these in a near future version. These are
|
||||
// hard-coded for a proof of concept.
|
||||
static const RRType& A();
|
||||
static const RRType& NS();
|
||||
|
||||
private:
|
||||
uint16_t typecode_;
|
||||
};
|
||||
|
||||
// We'll probably auto generate this code. But in this preliminary version
|
||||
// we simply hard code some selected types.
|
||||
// Describing these will be deferred until that point.
|
||||
inline const RRType&
|
||||
RRType::A()
|
||||
{
|
||||
static RRType rrtype(1);
|
||||
|
||||
return (rrtype);
|
||||
}
|
||||
|
||||
inline const RRType&
|
||||
RRType::NS()
|
||||
{
|
||||
static RRType rrtype(2);
|
||||
|
||||
return (rrtype);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Insert the \c RRType as a string into stream.
|
||||
///
|
||||
/// This method convert the \c rrtype into a string and inserts it into the
|
||||
/// output stream \c os.
|
||||
///
|
||||
/// This function overloads the global operator<< to behave as described in
|
||||
/// ostream::operator<< but applied to \c RRType objects.
|
||||
///
|
||||
/// \param os A \c std::ostream object on which the insertion operation is
|
||||
/// performed.
|
||||
/// \param rrtype The \c RRType object output by the operation.
|
||||
/// \return A reference to the same \c std::ostream object referenced by
|
||||
/// parameter \c os after the insertion operation.
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const RRType& rrtype);
|
||||
}
|
||||
}
|
||||
#endif // __RRTYPE_H
|
||||
|
||||
// Local Variables:
|
||||
// mode: c++
|
||||
// End:
|
161
src/lib/dns/cpp/rrtype_unittest.cc
Normal file
161
src/lib/dns/cpp/rrtype_unittest.cc
Normal file
@@ -0,0 +1,161 @@
|
||||
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
// $Id$
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "buffer.h"
|
||||
#include "messagerenderer.h"
|
||||
#include "rrparamregistry.h"
|
||||
#include "rrtype.h"
|
||||
|
||||
#include "unittest_util.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace isc;
|
||||
using namespace isc::dns;
|
||||
|
||||
namespace {
|
||||
class RRTypeTest : public ::testing::Test {
|
||||
protected:
|
||||
RRTypeTest() : obuffer(0), renderer(obuffer) {}
|
||||
|
||||
OutputBuffer obuffer;
|
||||
MessageRenderer renderer;
|
||||
|
||||
static RRType rrtypeFactoryFromWire(const char* datafile);
|
||||
static const RRType rrtype_1, rrtype_0x80, rrtype_0x800, rrtype_0x8000,
|
||||
rrtype_max;
|
||||
static const uint8_t wiredata[10];
|
||||
};
|
||||
|
||||
const RRType RRTypeTest::rrtype_1(1);
|
||||
const RRType RRTypeTest::rrtype_0x80(0x80);
|
||||
const RRType RRTypeTest::rrtype_0x800(0x800);
|
||||
const RRType RRTypeTest::rrtype_0x8000(0x8000);
|
||||
const RRType RRTypeTest::rrtype_max(0xffff);
|
||||
// This is wire-format data for the above sample RRTypes rendered in the
|
||||
// appearing order.
|
||||
const uint8_t RRTypeTest::wiredata[10] = { 0x00, 0x01, 0x00, 0x80, 0x08,
|
||||
0x00, 0x80, 0x00, 0xff, 0xff };
|
||||
|
||||
RRType
|
||||
RRTypeTest::rrtypeFactoryFromWire(const char* datafile)
|
||||
{
|
||||
std::vector<unsigned char> data;
|
||||
UnitTestUtil::readWireData(datafile, data);
|
||||
|
||||
InputBuffer buffer(&data[0], data.size());
|
||||
|
||||
return (RRType(buffer));
|
||||
}
|
||||
|
||||
TEST_F(RRTypeTest, fromText)
|
||||
{
|
||||
EXPECT_EQ("A", RRType("A").toText());
|
||||
EXPECT_EQ("NS", RRType("NS").toText());
|
||||
|
||||
EXPECT_EQ("TYPE65535", RRType("TYPE65535").toText());
|
||||
|
||||
// something unusual, but existing implementations accept this form,
|
||||
// so do we.
|
||||
EXPECT_EQ(53, RRType("TYPE00053").getCode());
|
||||
// again, unusual, and the majority of other implementations reject it.
|
||||
// In any case, there should be no reasonable reason to accept such a
|
||||
// ridiculously long input.
|
||||
EXPECT_THROW(RRType("TYPE000053"), InvalidRRType);
|
||||
|
||||
// bogus TYPEnnn representations: should trigger an exception
|
||||
EXPECT_THROW(RRType("TYPE"), InvalidRRType);
|
||||
EXPECT_THROW(RRType("TYPE-1"), InvalidRRType);
|
||||
EXPECT_THROW(RRType("TYPExxx"), InvalidRRType);
|
||||
EXPECT_THROW(RRType("TYPE65536"), InvalidRRType);
|
||||
EXPECT_THROW(RRType("TYPE6500x"), InvalidRRType);
|
||||
EXPECT_THROW(RRType("TYPE65000 "), InvalidRRType);
|
||||
}
|
||||
|
||||
TEST_F(RRTypeTest, fromWire)
|
||||
{
|
||||
EXPECT_EQ(0x1234,
|
||||
rrtypeFactoryFromWire("testdata/rrcode16_fromWire1").getCode());
|
||||
EXPECT_THROW(rrtypeFactoryFromWire("testdata/rrcode16_fromWire2"),
|
||||
IncompleteRRType);
|
||||
}
|
||||
|
||||
// from string, lower case
|
||||
TEST_F(RRTypeTest, caseConstruct)
|
||||
{
|
||||
EXPECT_EQ("A", RRType("a").toText());
|
||||
EXPECT_EQ("NS", RRType("ns").toText());
|
||||
EXPECT_EQ("TYPE65535", RRType("type65535").toText());
|
||||
}
|
||||
|
||||
TEST_F(RRTypeTest, toText)
|
||||
{
|
||||
EXPECT_EQ("A", RRType(1).toText());
|
||||
EXPECT_EQ("TYPE65000", RRType(65000).toText());
|
||||
}
|
||||
|
||||
TEST_F(RRTypeTest, toWireBuffer)
|
||||
{
|
||||
rrtype_1.toWire(obuffer);
|
||||
rrtype_0x80.toWire(obuffer);
|
||||
rrtype_0x800.toWire(obuffer);
|
||||
rrtype_0x8000.toWire(obuffer);
|
||||
rrtype_max.toWire(obuffer);
|
||||
|
||||
EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
|
||||
obuffer.getData(), obuffer.getLength(),
|
||||
wiredata, sizeof(wiredata));
|
||||
}
|
||||
|
||||
TEST_F(RRTypeTest, toWireRenderer)
|
||||
{
|
||||
rrtype_1.toWire(renderer);
|
||||
rrtype_0x80.toWire(renderer);
|
||||
rrtype_0x800.toWire(renderer);
|
||||
rrtype_0x8000.toWire(renderer);
|
||||
rrtype_max.toWire(renderer);
|
||||
|
||||
EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
|
||||
obuffer.getData(), obuffer.getLength(),
|
||||
wiredata, sizeof(wiredata));
|
||||
}
|
||||
|
||||
TEST_F(RRTypeTest, wellKnownTypes)
|
||||
{
|
||||
EXPECT_EQ(1, RRType::A().getCode());
|
||||
EXPECT_EQ("A", RRType::A().toText());
|
||||
}
|
||||
|
||||
TEST_F(RRTypeTest, compare)
|
||||
{
|
||||
EXPECT_TRUE(RRType(1) == RRType("A"));
|
||||
EXPECT_TRUE(RRType(1).equals(RRType("A")));
|
||||
EXPECT_TRUE(RRType(0) != RRType("A"));
|
||||
EXPECT_TRUE(RRType(0).nequals(RRType("A")));
|
||||
|
||||
EXPECT_TRUE(RRType("A") < RRType("NS"));
|
||||
EXPECT_TRUE(RRType(100) < RRType(65535));
|
||||
}
|
||||
|
||||
// test operator<<. We simply confirm it appends the result of toText().
|
||||
TEST_F(RRTypeTest, LeftShiftOperator)
|
||||
{
|
||||
ostringstream oss;
|
||||
oss << RRType::A();
|
||||
EXPECT_EQ(RRType::A().toText(), oss.str());
|
||||
}
|
||||
}
|
4
src/lib/dns/cpp/testdata/rrcode16_fromWire1
vendored
Normal file
4
src/lib/dns/cpp/testdata/rrcode16_fromWire1
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
#
|
||||
# a 16 bit wire-format data (network byte order)
|
||||
#
|
||||
1234
|
4
src/lib/dns/cpp/testdata/rrcode16_fromWire2
vendored
Normal file
4
src/lib/dns/cpp/testdata/rrcode16_fromWire2
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
#
|
||||
# an incomplete segment for a 16 bit wire-format data
|
||||
#
|
||||
12
|
4
src/lib/dns/cpp/testdata/rrcode32_fromWire1
vendored
Normal file
4
src/lib/dns/cpp/testdata/rrcode32_fromWire1
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
#
|
||||
# a 32 bit wire-format data (network byte order)
|
||||
#
|
||||
12345678
|
4
src/lib/dns/cpp/testdata/rrcode32_fromWire2
vendored
Normal file
4
src/lib/dns/cpp/testdata/rrcode32_fromWire2
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
#
|
||||
# an incomplete segment for a 32 bit wire-format data
|
||||
#
|
||||
123456
|
Reference in New Issue
Block a user