2
0
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:
JINMEI Tatuya
2010-01-19 00:16:02 +00:00
25 changed files with 2545 additions and 36 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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();

View File

@@ -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) {

View File

@@ -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)
{

View File

@@ -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
///

View File

@@ -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."));

View File

@@ -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

View File

@@ -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>
///

View 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
View 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:

View 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());
}
}

View 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));
}
}
}

View 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:

View 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
View 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
View 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:

View 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
View 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
View 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:

View 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());
}
}

View File

@@ -0,0 +1,4 @@
#
# a 16 bit wire-format data (network byte order)
#
1234

View File

@@ -0,0 +1,4 @@
#
# an incomplete segment for a 16 bit wire-format data
#
12

View File

@@ -0,0 +1,4 @@
#
# a 32 bit wire-format data (network byte order)
#
12345678

View File

@@ -0,0 +1,4 @@
#
# an incomplete segment for a 32 bit wire-format data
#
123456