%PDF- %PDF-
| Direktori : /backups/router/usr/local/include/kea/dns/ |
| Current File : //backups/router/usr/local/include/kea/dns/messagerenderer.h |
// Copyright (C) 2009-2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef MESSAGERENDERER_H
#define MESSAGERENDERER_H
#include <util/buffer.h>
#include <boost/noncopyable.hpp>
#include <memory>
namespace isc {
namespace dns {
// forward declarations
class Name;
class LabelSequence;
/// \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.
///
/// 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.
///
/// 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 details of this class.
///
/// By default any (derived) renderer class object is associated with
/// an internal buffer, and subsequent write operations will be performed
/// on that buffer. The rendering result can be retrieved via the
/// \c getData() method.
///
/// If an application wants a separate buffer can be (normally temporarily)
/// set for rendering operations via the \c setBuffer() method. In that case,
/// 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.
///
/// 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.
///
/// \note Some functions (like writeUint8) are not virtual. It is because
/// it is hard to imagine any version of message renderer that would
/// do anything else than just putting the data into a buffer, so we
/// provide a default implementation and having them virtual would only
/// hurt the performance with no real gain. If it would happen a different
/// implementation is really needed, we can make them virtual in future.
/// The only one that is virtual is writeName and it's because this
/// function is much more complicated, therefore there's a lot of space
/// for different implementations or different behavior.
class AbstractMessageRenderer {
public:
/// \brief Compression mode constants.
///
/// The \c CompressMode enum type represents the name compression mode
/// 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, a renderer compresses names in case-insensitive
/// manner.
/// Compression mode can be dynamically modified by the
/// \c setCompressMode() method.
/// The mode can be changed even in the middle of rendering, although this
/// 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 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
///
/// One specific case where case-sensitive compression is required is
/// AXFR as described in draft-ietf-dnsext-axfr-clarify. A primary
/// authoritative DNS server implementation using this API would specify
/// \c CASE_SENSITIVE before rendering outgoing AXFR messages.
///
enum CompressMode {
CASE_INSENSITIVE, //!< Compress names case-insensitive manner (default)
CASE_SENSITIVE //!< Compress names case-sensitive manner
};
protected:
///
/// \name Constructors and Destructor
//@{
/// \brief The default constructor.
///
/// 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.
virtual ~AbstractMessageRenderer() {}
//@}
protected:
/// \brief Return the output buffer we render into.
const isc::util::OutputBuffer& getBuffer() const { return (*buffer_); }
isc::util::OutputBuffer& getBuffer() { return (*buffer_); }
private:
/// \brief Local (default) buffer to store data.
isc::util::OutputBuffer local_buffer_;
/// \brief Buffer to store data.
///
/// Note that the class interface ensures this pointer is never null;
/// it either refers to \c local_buffer_ or to an application-supplied
/// buffer by \c setBuffer().
///
/// It was decided that there's no need to have this in every subclass,
/// at least not now, and this reduces code size and gives compiler a
/// better chance to optimize.
isc::util::OutputBuffer* buffer_;
public:
///
/// \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 {
return (buffer_->getData());
}
/// \brief Return the length of data written in the internal buffer.
size_t getLength() const {
return (buffer_->getLength());
}
/// \brief Return whether truncation has occurred while rendering.
///
/// Once the return value of this method is \c true, it doesn't make sense
/// to try rendering more data, although this class itself doesn't reject
/// the attempt.
///
/// This method never throws an exception.
///
/// \return true if truncation has occurred; otherwise \c false.
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.
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.
virtual CompressMode getCompressMode() const = 0;
//@}
///
/// \name Setter Methods
///
//@{
/// \brief Set or reset a temporary output buffer.
///
/// This method can be used for an application that manages an output
/// buffer separately from the message renderer and wants to keep reusing
/// the renderer. When the renderer is associated with the default buffer
/// and the given pointer is non null, the given buffer will be
/// (temporarily) used for subsequent message rendering; if the renderer
/// is associated with a temporary buffer and the given pointer is null,
/// the renderer will be reset with the default buffer. In the latter
/// case any additional resources (possibly specific to a derived renderer
/// class) will be cleared, but the temporary buffer is kept as the latest
/// state (which would normally store the rendering result).
///
/// This method imposes some restrictions to prevent accidental misuse
/// that could cause disruption such as dereferencing an invalid object.
/// First, a temporary buffer must not be set when the associated buffer
/// is in use, that is, any data are stored in the buffer. Also, the
/// default buffer cannot be "reset"; when null is specified a temporary
/// buffer must have been set beforehand. If these conditions aren't met
/// an isc::InvalidParameter exception will be thrown. This method is
/// exception free otherwise.
///
/// \throw isc::InvalidParameter A restrictions of the method usage isn't
/// met.
///
/// \param buffer A pointer to a temporary output buffer or null for reset
/// it.
void setBuffer(isc::util::OutputBuffer* buffer);
/// \brief Mark the renderer to indicate truncation has occurred while
/// rendering.
///
/// This method never throws an exception.
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.
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.
virtual void setCompressMode(CompressMode mode) = 0;
//@}
///
/// \name Methods for writing data into the internal buffer.
///
//@{
/// \brief Insert a specified length of gap at the end of the buffer.
///
/// The caller should not assume any particular value to be inserted.
/// This method is provided as a shortcut to make a hole in the buffer
/// 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) {
buffer_->skip(len);
}
/// \brief Trim the specified length of data from the end of the internal
/// buffer.
///
/// This method is provided for such cases as DNS message truncation.
///
/// The specified length must not exceed the current data size of the
/// buffer; otherwise an exception of class \c isc::OutOfRange will
/// be thrown.
///
/// \param len The length of data that should be trimmed.
void trim(size_t len) {
buffer_->trim(len);
}
/// \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.
virtual void clear();
/// \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(const uint8_t data) {
buffer_->writeUint8(data);
}
/// \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) {
buffer_->writeUint16(data);
}
/// \brief Write an unsigned 16-bit integer in host byte order at the
/// specified position of the internal buffer in network byte order.
///
/// The buffer must have a sufficient room to store the given data at the
/// given position, that is, <code>pos + 2 < getLength()</code>;
/// otherwise an exception of class \c isc::OutOfRange will be thrown.
/// Note also that this method never extends the internal buffer.
///
/// \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) {
buffer_->writeUint16At(data, pos);
}
/// \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) {
buffer_->writeUint32(data);
}
/// \brief Copy an arbitrary length of data into the internal buffer
/// 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) {
buffer_->writeData(data, len);
}
/// \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.
virtual void writeName(const Name& name, bool compress = true) = 0;
/// \brief Write a \c LabelSequence object into the internal buffer
/// in wire format, with or without name compression.
///
/// This is the same as the other version, which takes \c Name instead
/// of \c LabelSequence, except for the parameter type. The passed
/// \c LabelSequence must be absolute.
///
/// \param ls A \c LabelSequence object to be written.
/// \param compress A boolean indicating whether to enable name
/// compression.
virtual void writeName(const LabelSequence& ls, 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 boost::noncopyable { // Can crash if copied
public:
using AbstractMessageRenderer::CASE_INSENSITIVE;
using AbstractMessageRenderer::CASE_SENSITIVE;
MessageRenderer();
virtual ~MessageRenderer();
virtual bool isTruncated() const;
virtual size_t getLengthLimit() const;
virtual CompressMode getCompressMode() const;
virtual void setTruncated();
virtual void setLengthLimit(size_t len);
/// This implementation does not allow this call in the middle of
/// rendering (i.e. after at least one name is rendered) due to
/// restriction specific to the internal implementation. Such attempts
/// will result in an \c isc::InvalidParameter exception.
///
/// This shouldn't be too restrictive in practice; there's no known
/// practical case for such a mixed compression policy in a single
/// message.
virtual void setCompressMode(CompressMode mode);
virtual void clear();
virtual void writeName(const Name& name, bool compress = true);
virtual void writeName(const LabelSequence& ls, bool compress = true);
private:
struct MessageRendererImpl;
std::unique_ptr<MessageRendererImpl> impl_;
};
}
}
#endif // MESSAGERENDERER_H