[svn] commit: r391 - in /branches/jinmei-dnsmessageapi/src/lib/dns/cpp: messagerenderer.cc messagerenderer.h
BIND 10 source code commits
bind10-changes at lists.isc.org
Sat Dec 19 03:16:26 UTC 2009
Author: jinmei
Date: Sat Dec 19 03:16:26 2009
New Revision: 391
Log:
documented the message renderer class
Modified:
branches/jinmei-dnsmessageapi/src/lib/dns/cpp/messagerenderer.cc
branches/jinmei-dnsmessageapi/src/lib/dns/cpp/messagerenderer.h
Modified: branches/jinmei-dnsmessageapi/src/lib/dns/cpp/messagerenderer.cc
==============================================================================
--- branches/jinmei-dnsmessageapi/src/lib/dns/cpp/messagerenderer.cc (original)
+++ branches/jinmei-dnsmessageapi/src/lib/dns/cpp/messagerenderer.cc Sat Dec 19 03:16:26 2009
@@ -27,23 +27,48 @@
namespace isc {
namespace dns {
+namespace { // hide internal-only names from the public namespaces
+///
+/// \brief The \c NameCompressNode class represents a pointer to a name
+/// rendered in the internal buffer for the \c MessageRendererImpl object.
+///
+/// A \c MessageRendererImpl object maintains a set of the \c NameCompressNode
+/// objects, and searches the set for the position of the longest match
+/// (ancestor) name against each new name to be rendered into the buffer.
struct NameCompressNode {
NameCompressNode(const OutputBuffer& buffer, size_t pos, size_t len) :
buffer_(buffer), pos_(pos), len_(len) {}
+ /// The buffer in which the corresponding name is rendered.
const OutputBuffer& buffer_;
+ /// The position (offset from the beginning) in the buffer where the
+ /// name starts.
uint16_t pos_;
+ /// The length of the corresponding name.
uint16_t len_;
};
///
-/// Helper class to give ordering for MessageRendererImpl::nodeset_.
-///
+/// \brief The \c NameCompare class is a functor that gives ordering among
+/// \c NameCompressNode objects stored in \c MessageRendererImpl::nodeset_.
+///
+/// Its only public method as a functor, \c operator(), gives the ordering
+/// between two \c NameCompressNode objects in terms of equivalence, that is,
+/// returns whether one is "less than" the other.
+/// For our purpose we only need to distinguish two different names, so the
+/// ordering is different from the canonical DNS name order used in DNSSEC;
+/// basically, it gives the case-insensitive ordering of the two names as their
+/// textual representation.
struct NameCompare : public std::binary_function<NameCompressNode,
NameCompressNode,
bool> {
///
/// Returns true if n1 < n2 as a result of case-insensitive comparison;
/// otherwise return false.
+ ///
+ /// The name corresponding to \c n1 or \c n2 may be compressed, in which
+ /// case we must follow the compression pointer in the associated buffer.
+ /// The helper private method \c nextPosition() gives the position in the
+ /// buffer for the next character, taking into account compression.
///
bool operator()(const NameCompressNode& n1,
const NameCompressNode& n2) const
@@ -71,13 +96,16 @@
return (false);
}
+private:
uint16_t nextPosition(const OutputBuffer& buffer,
uint16_t pos, uint16_t& llen) const
{
if (llen == 0) {
int i = 0;
- while ((buffer[pos] & 0xc0) == 0xc0) {
- pos = (buffer[pos] & 0x3f) * 256 + buffer[pos + 1];
+ while ((buffer[pos] & Name::COMPRESS_POINTER_MARK8) ==
+ Name::COMPRESS_POINTER_MARK8) {
+ pos = (buffer[pos] & ~Name::COMPRESS_POINTER_MARK8) *
+ 256 + buffer[pos + 1];
// This loop should stop as long as the buffer has been
// constructed validly and the search/insert argument is based
@@ -92,19 +120,36 @@
return (pos);
}
};
-
+}
+
+///
+/// \brief The \c MessageRendererImpl class is the actual implementation of
+/// \c MessageRenderer.
+///
+/// The implementation is hidden from applications. We can refer to specific
+/// members of this class only within this file.
+///
struct MessageRendererImpl {
+ /// \brief Constructor from an output buffer.
+ ///
+ /// \param buffer An \c OutputBuffer object to which wire format data is
+ /// written.
MessageRendererImpl(OutputBuffer& buffer) :
buffer_(buffer), nbuffer_(Name::MAX_WIRE) {}
+ /// The buffer that holds the entire DNS message.
OutputBuffer& buffer_;
+ /// A local working buffer to convert each given name into wire format.
+ /// This could be a local variable of the \c writeName() method, but
+ /// we keep it in the class so that we can reuse it and avoid construction
+ /// overhead.
OutputBuffer nbuffer_;
+ /// A set of compression pointers.
std::set<NameCompressNode, NameCompare> nodeset_;
};
-MessageRenderer::MessageRenderer(OutputBuffer& buffer)
-{
- impl_ = new MessageRendererImpl(buffer);
-}
+MessageRenderer::MessageRenderer(OutputBuffer& buffer) :
+ impl_(new MessageRendererImpl(buffer))
+{}
MessageRenderer::~MessageRenderer()
{
@@ -120,6 +165,8 @@
unsigned int i;
std::set<NameCompressNode>::const_iterator n;
+ // Find the longest ancestor name in the rendered set that matches the
+ // given name.
for (i = 0; i < impl_->nbuffer_.getLength(); i += impl_->nbuffer_[i] + 1) {
// skip the trailing null label
if (impl_->nbuffer_[i] == 0) {
@@ -133,22 +180,25 @@
}
}
+ // Record the current offset before extending the buffer.
size_t offset = impl_->buffer_.getLength();
- // write uncompress part...
+ // Write uncompress part...
impl_->buffer_.writeData(impl_->nbuffer_.getData(),
compress ? i : impl_->nbuffer_.getLength());
if (compress && n != impl_->nodeset_.end()) {
// ...and compression pointer if available.
uint16_t pointer = (*n).pos_;
- pointer |= 0xc000;
+ pointer |= Name::COMPRESS_POINTER_MARK16;
impl_->buffer_.writeUint16(pointer);
}
+ // Finally, add to the set the newly rendered name and its ancestors that
+ // have not been in the set.
for (unsigned int j = 0; j < i; j += impl_->nbuffer_[j] + 1) {
if (impl_->nbuffer_[j] == 0) {
continue;
}
- if (offset + j >= 0x4000) {
+ if (offset + j > Name::MAX_COMPRESS_POINTER) {
break;
}
impl_->nodeset_.insert(NameCompressNode(impl_->buffer_, offset + j,
Modified: branches/jinmei-dnsmessageapi/src/lib/dns/cpp/messagerenderer.h
==============================================================================
--- branches/jinmei-dnsmessageapi/src/lib/dns/cpp/messagerenderer.h (original)
+++ branches/jinmei-dnsmessageapi/src/lib/dns/cpp/messagerenderer.h Sat Dec 19 03:16:26 2009
@@ -24,10 +24,87 @@
class Name;
class MessageRendererImpl;
+///
+/// \brief The \c MessageRenderer class encapsulates implementation details
+/// of rendering a DNS message into a buffer in wire format.
+///
+/// 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
+/// 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.
+///
+/// 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.
+///
+/// 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.
+///
+/// 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 {
public:
+ ///
+ /// \name Constructors and Destructor
+ //@{
+ /// \brief Constructor from an output buffer.
+ ///
+ /// \param buffer An \c OutputBuffer object to which wire format data is
+ /// written.
MessageRenderer(OutputBuffer& buffer);
+ /// \brief The default 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 user's responsibility to do any necessary cleanup for the
+ /// \c buffer.
~MessageRenderer();
+ //@}
+
+ ///
+ /// \name Rendering Methods
+ ///
+ //@{
+ /// \brief Write a \c Name object into the internal buffer in wire format,
+ /// with or without name compression.
+ ///
+ /// If the optional parameter \c compress is \c true, this method tries to
+ /// compress the \c name if possible, searching the entire message that has
+ /// been rendered. Otherwise name compression is omitted. Its default
+ /// value is \c true.
+ ///
+ /// Note: even if \c compress is \c true, the position of the \c name (and
+ /// possibly its ancestor names) in the message is recorded and may be used
+ /// for compressing subsequent names.
+ ///
+ /// \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);
private:
MessageRendererImpl* impl_;
More information about the bind10-changes
mailing list