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

initial implementation of trac#404: in-memory serialized representation of RDATA


git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac404@3430 e5f2f494-b856-4b98-b285-d166d9295462
parent e04950d3
......@@ -73,6 +73,7 @@ libdns___la_SOURCES += name.h name.cc
libdns___la_SOURCES += opcode.h opcode.cc
libdns___la_SOURCES += rcode.h rcode.cc
libdns___la_SOURCES += rdata.h rdata.cc
libdns___la_SOURCES += rdatafields.h rdatafields.cc
libdns___la_SOURCES += rrclass.cc
libdns___la_SOURCES += rrparamregistry.h
libdns___la_SOURCES += rrset.h rrset.cc
......
......@@ -109,7 +109,7 @@ def import_classheader(class_txt, type_txt, type_code, file):
content += '''
class InputBuffer;
class OutputBuffer;
class MessageRenderer;\n\n'''
class AbstractMessageRenderer;\n\n'''
if re.match('\s+// BEGIN_COMMON_MEMBERS$', line):
content += '''
explicit ''' + type_utxt + '''(const std::string& type_str);
......@@ -117,7 +117,7 @@ class MessageRenderer;\n\n'''
''' + type_utxt + '''(const ''' + type_utxt + '''& other);
virtual std::string toText() const;
virtual void toWire(OutputBuffer& buffer) const;
virtual void toWire(MessageRenderer& renderer) const;
virtual void toWire(AbstractMessageRenderer& renderer) const;
virtual int compare(const Rdata& other) const;\n\n'''
rdata_header.close()
return content
......
......@@ -23,58 +23,46 @@ namespace dns {
class OutputBuffer;
class Name;
/// \brief The \c AbstractMessageRenderer class is an abstract base class
/// that provides common interfaces for rendering a DNS message into a buffer
/// in wire format.
///
/// \brief The \c MessageRenderer class encapsulates implementation details
/// of rendering a DNS message into a buffer in wire format.
/// A specific derived class of \c AbstractMessageRenderer (we call it
/// a renderer class hereafter) is simply responsible for name compression at
/// least in the current design. A renderer class object (conceptually)
/// manages the positions of names rendered in some sort of buffer and uses
/// that information to render subsequent names with compression.
///
/// In effect, it's simply responsible for name compression at least in the
/// current implementation. A \c MessageRenderer class object manages the
/// positions of names rendered in a buffer and uses that information to render
/// subsequent names with compression.
///
/// This class is mainly intended to be used as a helper for a more
/// A renderer class is mainly intended to be used as a helper for a more
/// comprehensive \c Message class internally; normal applications won't have
/// to care about this class.
///
/// A \c MessageRenderer class object is constructed with a \c OutputBuffer
/// object, which is the buffer into which the rendered %data will be written.
/// Normally the buffer is expected to be empty on construction, but it doesn't
/// have to be so; the \c MessageRenderer object will start rendering from the
/// end of the buffer at the time of construction. However, if the
/// pre-existing portion of the buffer contains DNS names, these names won't
/// be considered for name compression.
/// to care about details of this class.
///
/// Once a \c MessageRenderer object is constructed with a buffer, it is
/// generally expected that all rendering operations are performed via the
/// \c MessageRenderer object. If the application modifies the buffer in
/// parallel with the \c MessageRenderer, the result will be undefined.
/// Once a renderer class object is constructed with a buffer, it is
/// generally expected that all rendering operations are performed via that
/// object. If the application modifies the buffer in
/// parallel with the renderer, the result will be undefined.
///
/// Note to developers: we introduced a separate class for name compression
/// because previous benchmark with BIND9 showed compression affects overall
/// response performance very much. By having a separate class dedicated for
/// this purpose, we'll be able to change the internal implementation of name
/// compression in the future without affecting other part of the API and
/// implementation. For the same reason, we adopt the "pimpl" idiom in the
/// class definition (i.e., using a pointer to a \c MessageRendererImpl class,
/// which is defined with the class implementation, not in the header file):
/// we may want to modify the compression implementation without modifying the
/// header file thereby requesting rebuild the package.
/// implementation.
///
/// Furthermore, we may eventually want to allow other developers to develop
/// and use their own compression implementation. Should such a case become
/// realistic, we may want to make the \c MessageRendererImpl class an abstract
/// base class and let concrete derived classes have their own implementations.
/// At the moment we don't the strong need for it, so we rather avoid over
/// abstraction and keep the definition simpler.
class MessageRenderer {
/// In addition, by introducing a class hierarchy from
/// \c AbstractMessageRenderer, we allow an application to use a customized
/// renderer class for specific purposes. For example, a high performance
/// DNS server may want to use an optimized renderer class assuming some
/// specific underlying data representation.
class AbstractMessageRenderer {
public:
/// \brief Compression mode constants.
///
/// The \c CompressMode enum type represents the name compression mode
/// for the \c MessageRenderer.
/// for renderer classes.
/// \c CASE_INSENSITIVE means compress names in case-insensitive manner;
/// \c CASE_SENSITIVE means compress names in case-sensitive manner.
/// By default, \c MessageRenderer compresses names in case-insensitive
/// By default, a renderer compresses names in case-insensitive
/// manner.
/// Compression mode can be dynamically modified by the
/// \c setCompressMode() method.
......@@ -82,7 +70,7 @@ public:
/// is not an intended usage. In this case the names already compressed
/// are intact; only names being compressed after the mode change are
/// affected by the change.
/// If the internal \c MessageRenderer is reinitialized by the \c clear()
/// If a renderer class object is reinitialized by the \c clear()
/// method, the compression mode will be reset to the default, which is
/// \c CASE_INSENSITIVE
///
......@@ -95,23 +83,18 @@ public:
CASE_INSENSITIVE, //!< Compress names case-insensitive manner (default)
CASE_SENSITIVE //!< Compress names case-sensitive manner
};
public:
protected:
///
/// \name Constructors and Destructor
//@{
/// \brief Constructor from an output buffer.
/// \brief The default constructor.
///
/// \param buffer An \c OutputBuffer object to which wire format data is
/// written.
MessageRenderer(OutputBuffer& buffer);
/// This is intentionally defined as \c protected as this base class should
/// never be instantiated (except as part of a derived class).
AbstractMessageRenderer() {}
public:
/// \brief The destructor.
///
/// The destructor does nothing on the given \c buffer on construction;
/// in fact, it is expected that the user will use the resulting buffer
/// for some post rendering purposes (e.g., send the data to the network).
/// It's the user's responsibility to do any necessary cleanup for the
/// \c buffer.
~MessageRenderer();
virtual ~AbstractMessageRenderer() {}
//@}
///
......@@ -123,9 +106,11 @@ public:
///
/// This method works exactly same as the same method of the \c OutputBuffer
/// class; all notes for \c OutputBuffer apply.
const void* getData() const;
virtual const void* getData() const = 0;
/// \brief Return the length of data written in the internal buffer.
size_t getLength() const;
virtual size_t getLength() const = 0;
/// \brief Return whether truncation has occurred while rendering.
///
/// Once the return value of this method is \c true, it doesn't make sense
......@@ -135,20 +120,22 @@ public:
/// This method never throws an exception.
///
/// \return true if truncation has occurred; otherwise \c false.
bool isTruncated() const;
virtual bool isTruncated() const = 0;
/// \brief Return the maximum length of rendered data that can fit in the
/// corresponding DNS message without truncation.
///
/// This method never throws an exception.
///
/// \return The maximum length in bytes.
size_t getLengthLimit() const;
/// \brief Return the compression mode of the \c MessageRenderer.
virtual size_t getLengthLimit() const = 0;
/// \brief Return the compression mode of the renderer class object.
///
/// This method never throws an exception.
///
/// \return The current compression mode.
CompressMode getCompressMode() const;
virtual CompressMode getCompressMode() const = 0;
//@}
///
......@@ -159,20 +146,22 @@ public:
/// rendering.
///
/// This method never throws an exception.
void setTruncated();
virtual void setTruncated() = 0;
/// \brief Set the maximum length of rendered data that can fit in the
/// corresponding DNS message without truncation.
///
/// This method never throws an exception.
///
/// \param len The maximum length in bytes.
void setLengthLimit(size_t len);
/// \brief Set the compression mode of the \c MessageRenderer.
virtual void setLengthLimit(size_t len) = 0;
/// \brief Set the compression mode of the renderer class object.
///
/// This method never throws an exception.
///
/// \param mode A \c CompressMode value representing the compression mode.
void setCompressMode(CompressMode mode);
virtual void setCompressMode(CompressMode mode) = 0;
//@}
///
......@@ -186,7 +175,8 @@ public:
/// that is to be filled in later, e.g, by \ref writeUint16At().
///
/// \param len The length of the gap to be inserted in bytes.
void skip(size_t len);
virtual void skip(size_t len) = 0;
/// \brief Trim the specified length of data from the end of the internal
/// buffer.
///
......@@ -197,21 +187,25 @@ public:
/// be thrown.
///
/// \param len The length of data that should be trimmed.
void trim(size_t len);
virtual void trim(size_t len) = 0;
/// \brief Clear the internal buffer and other internal resources.
///
/// This method can be used to re-initialize and reuse the renderer
/// without constructing a new one.
void clear();
virtual void clear() = 0;
/// \brief Write an unsigned 8-bit integer into the internal buffer.
///
/// \param data The 8-bit integer to be written into the internal buffer.
void writeUint8(uint8_t data);
virtual void writeUint8(uint8_t data) = 0;
/// \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);
virtual void writeUint16(uint16_t data) = 0;
/// \brief Write an unsigned 16-bit integer in host byte order at the
/// specified position of the internal buffer in network byte order.
///
......@@ -223,26 +217,23 @@ public:
///
/// \param data The 16-bit integer to be written into the internal buffer.
/// \param pos The beginning position in the buffer to write the data.
void writeUint16At(uint16_t data, size_t pos);
virtual void writeUint16At(uint16_t data, size_t pos) = 0;
/// \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);
virtual void writeUint32(uint32_t data) = 0;
/// \brief Copy an arbitrary length of data into the internal buffer
/// of the \c MessageRenderer.
/// of the renderer object.
///
/// No conversion on the copied data is performed.
///
/// \param data A pointer to the data to be copied into the internal buffer.
/// \param len The length of the data in bytes.
void writeData(const void *data, size_t len);
//@}
virtual void writeData(const void *data, size_t len) = 0;
///
/// \name Rendering Methods
///
//@{
/// \brief Write a \c Name object into the internal buffer in wire format,
/// with or without name compression.
///
......@@ -257,7 +248,50 @@ public:
///
/// \param name A \c Name object to be written.
/// \param compress A boolean indicating whether to enable name compression.
void writeName(const Name& name, bool compress = true);
virtual void writeName(const Name& name, bool compress = true) = 0;
//@}
};
/// The \c MessageRenderer is a concrete derived class of
/// \c AbstractMessageRenderer as a general purpose implementation of the
/// renderer interfaces.
///
/// A \c MessageRenderer object is constructed with a \c OutputBuffer
/// object, which is the buffer into which the rendered %data will be written.
/// Normally the buffer is expected to be empty on construction, but it doesn't
/// have to be so; the renderer object will start rendering from the
/// end of the buffer at the time of construction. However, if the
/// pre-existing portion of the buffer contains DNS names, these names won't
/// be considered for name compression.
class MessageRenderer : public AbstractMessageRenderer {
public:
using AbstractMessageRenderer::CASE_INSENSITIVE;
using AbstractMessageRenderer::CASE_SENSITIVE;
/// \brief Constructor from an output buffer.
///
/// \param buffer An \c OutputBuffer object to which wire format data is
/// written.
MessageRenderer(OutputBuffer& buffer);
virtual ~MessageRenderer();
virtual const void* getData() const;
virtual size_t getLength() const;
virtual bool isTruncated() const;
virtual size_t getLengthLimit() const;
virtual CompressMode getCompressMode() const;
virtual void setTruncated();
virtual void setLengthLimit(size_t len);
virtual void setCompressMode(CompressMode mode);
virtual void skip(size_t len);
virtual void trim(size_t len);
virtual void clear();
virtual void writeUint8(uint8_t data);
virtual void writeUint16(uint16_t data);
virtual void writeUint16At(uint16_t data, size_t pos);
virtual void writeUint32(uint32_t data);
virtual void writeData(const void *data, size_t len);
virtual void writeName(const Name& name, bool compress = true);
private:
struct MessageRendererImpl;
MessageRendererImpl* impl_;
......
......@@ -29,7 +29,6 @@
using namespace std;
using isc::dns::NameComparisonResult;
using isc::dns::MessageRenderer;
namespace isc {
namespace dns {
......@@ -405,7 +404,7 @@ Name::toWire(OutputBuffer& buffer) const {
}
void
Name::toWire(MessageRenderer& renderer) const {
Name::toWire(AbstractMessageRenderer& renderer) const {
renderer.writeName(*this);
}
......
......@@ -28,7 +28,7 @@ namespace isc {
namespace dns {
class InputBuffer;
class OutputBuffer;
class MessageRenderer;
class AbstractMessageRenderer;
///
/// \brief A standard DNS module exception that is thrown if the name parser
......@@ -349,7 +349,7 @@ public:
///
/// \param renderer DNS message rendering context that encapsulates the
/// output buffer and name compression information.
void toWire(MessageRenderer& renderer) const;
void toWire(AbstractMessageRenderer& renderer) const;
/// \brief Render the <code>Name</code> in the wire format without
/// compression.
......
......@@ -230,7 +230,7 @@ Generic::toWire(OutputBuffer& buffer) const {
}
void
Generic::toWire(MessageRenderer& renderer) const {
Generic::toWire(AbstractMessageRenderer& renderer) const {
renderer.writeData(&impl_->data_[0], impl_->data_.size());
}
......
......@@ -27,7 +27,7 @@ namespace isc {
namespace dns {
class InputBuffer;
class OutputBuffer;
class MessageRenderer;
class AbstractMessageRenderer;
class RRType;
class RRClass;
class Name;
......@@ -180,7 +180,7 @@ public:
///
/// \param renderer DNS message rendering context that encapsulates the
/// output buffer in which the \c Rdata is to be stored.
virtual void toWire(MessageRenderer& renderer) const = 0;
virtual void toWire(AbstractMessageRenderer& renderer) const = 0;
//@}
///
......@@ -329,7 +329,7 @@ public:
///
/// \param renderer DNS message rendering context that encapsulates the
/// output buffer in which the \c Generic object is to be stored.
virtual void toWire(MessageRenderer& renderer) const;
virtual void toWire(AbstractMessageRenderer& renderer) const;
//@}
///
/// \name Comparison method
......
......@@ -48,7 +48,7 @@ A::toWire(OutputBuffer& buffer UNUSED_PARAM) const {
}
void
A::toWire(MessageRenderer& renderer UNUSED_PARAM) const {
A::toWire(AbstractMessageRenderer& renderer UNUSED_PARAM) const {
// TBD
}
......
......@@ -54,7 +54,7 @@ CNAME::toWire(OutputBuffer& buffer) const {
}
void
CNAME::toWire(MessageRenderer& renderer) const {
CNAME::toWire(AbstractMessageRenderer& renderer) const {
renderer.writeName(cname_);
}
......
......@@ -54,7 +54,7 @@ DNAME::toWire(OutputBuffer& buffer) const {
}
void
DNAME::toWire(MessageRenderer& renderer) const {
DNAME::toWire(AbstractMessageRenderer& renderer) const {
renderer.writeName(dname_);
}
......
......@@ -136,7 +136,7 @@ DNSKEY::toWire(OutputBuffer& buffer) const {
}
void
DNSKEY::toWire(MessageRenderer& renderer) const {
DNSKEY::toWire(AbstractMessageRenderer& renderer) const {
renderer.writeUint16(impl_->flags_);
renderer.writeUint8(impl_->protocol_);
renderer.writeUint8(impl_->algorithm_);
......
......@@ -132,7 +132,7 @@ DS::toWire(OutputBuffer& buffer) const {
}
void
DS::toWire(MessageRenderer& renderer) const {
DS::toWire(AbstractMessageRenderer& renderer) const {
renderer.writeUint16(impl_->tag_);
renderer.writeUint8(impl_->algorithm_);
renderer.writeUint8(impl_->digest_type_);
......
......@@ -73,7 +73,7 @@ MX::toWire(OutputBuffer& buffer) const {
}
void
MX::toWire(MessageRenderer& renderer) const {
MX::toWire(AbstractMessageRenderer& renderer) const {
renderer.writeUint16(preference_);
renderer.writeName(mxname_);
}
......
......@@ -50,7 +50,7 @@ NS::toWire(OutputBuffer& buffer) const {
}
void
NS::toWire(MessageRenderer& renderer) const {
NS::toWire(AbstractMessageRenderer& renderer) const {
renderer.writeName(nsname_);
}
......
......@@ -249,7 +249,7 @@ NSEC3::toWire(OutputBuffer& buffer) const {
}
void
NSEC3::toWire(MessageRenderer& renderer) const {
NSEC3::toWire(AbstractMessageRenderer& renderer) const {
renderer.writeUint8(impl_->hashalg_);
renderer.writeUint8(impl_->flags_);
renderer.writeUint16(impl_->iterations_);
......
......@@ -136,7 +136,7 @@ NSEC3PARAM::toWire(OutputBuffer& buffer) const {
}
void
NSEC3PARAM::toWire(MessageRenderer& renderer) const {
NSEC3PARAM::toWire(AbstractMessageRenderer& renderer) const {
renderer.writeUint8(impl_->hashalg_);
renderer.writeUint8(impl_->flags_);
renderer.writeUint16(impl_->iterations_);
......
......@@ -208,7 +208,7 @@ NSEC::toWire(OutputBuffer& buffer) const {
}
void
NSEC::toWire(MessageRenderer& renderer) const {
NSEC::toWire(AbstractMessageRenderer& renderer) const {
impl_->nextname_.toWire(renderer);
renderer.writeData(&impl_->typebits_[0], impl_->typebits_.size());
}
......
......@@ -58,7 +58,7 @@ OPT::toWire(OutputBuffer& buffer UNUSED_PARAM) const {
}
void
OPT::toWire(MessageRenderer& renderer UNUSED_PARAM) const {
OPT::toWire(AbstractMessageRenderer& renderer UNUSED_PARAM) const {
// nothing to do, as this simple version doesn't support any options.
}
......
......@@ -55,7 +55,7 @@ PTR::toWire(OutputBuffer& buffer) const {
}
void
PTR::toWire(MessageRenderer& renderer) const {
PTR::toWire(AbstractMessageRenderer& renderer) const {
renderer.writeName(ptr_name_);
}
......
......@@ -187,7 +187,7 @@ RRSIG::toWire(OutputBuffer& buffer) const {
}
void
RRSIG::toWire(MessageRenderer& renderer) const {
RRSIG::toWire(AbstractMessageRenderer& renderer) const {
impl_->covered_.toWire(renderer);
renderer.writeUint8(impl_->algorithm_);
renderer.writeUint8(impl_->labels_);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment