messagerenderer.h 16.5 KB
 JINMEI Tatuya committed Jan 26, 2010 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // Copyright (C) 2009 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. #ifndef __MESSAGERENDERER_H #define __MESSAGERENDERER_H 1  Michal 'vorner' Vaner committed Apr 19, 2011 18 #include  Michal 'vorner' Vaner committed Apr 06, 2011 19   Michal 'vorner' Vaner committed Aug 08, 2012 20 21 #include  JINMEI Tatuya committed Jan 26, 2010 22 namespace isc {  chenzhengzhang committed Apr 11, 2011 23   JINMEI Tatuya committed Jan 26, 2010 24 25 26 namespace dns { // forward declarations class Name;  Mukund Sivaraman committed Jul 12, 2012 27 class LabelSequence;  JINMEI Tatuya committed Jan 26, 2010 28   29 30 31 /// \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.  JINMEI Tatuya committed Jan 26, 2010 32 ///  33 34 35 36 37 /// 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.  JINMEI Tatuya committed Jan 26, 2010 38 ///  39 /// A renderer class is mainly intended to be used as a helper for a more  JINMEI Tatuya committed Jan 26, 2010 40 /// comprehensive \c Message class internally; normal applications won't have  41 /// to care about details of this class.  JINMEI Tatuya committed Jan 26, 2010 42 ///  JINMEI Tatuya committed Feb 24, 2012 43 44 45 46 47 48 49 50 51 /// 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  52 /// parallel with the renderer, the result will be undefined.  JINMEI Tatuya committed Jan 26, 2010 53 54 55 56 57 58 /// /// 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  59 /// implementation.  JINMEI Tatuya committed Jan 26, 2010 60 ///  61 62 63 64 65 /// 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.  Michal 'vorner' Vaner committed Apr 12, 2011 66 67 68 69 70 71 72 73 74 75 /// /// \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 behaviours.  76 class AbstractMessageRenderer {  JINMEI Tatuya committed Apr 10, 2010 77 78 79 80 public: /// \brief Compression mode constants. /// /// The \c CompressMode enum type represents the name compression mode  81  /// for renderer classes.  JINMEI Tatuya committed Apr 10, 2010 82 83  /// \c CASE_INSENSITIVE means compress names in case-insensitive manner; /// \c CASE_SENSITIVE means compress names in case-sensitive manner.  84  /// By default, a renderer compresses names in case-insensitive  JINMEI Tatuya committed Apr 10, 2010 85 86 87 88 89 90 91  /// 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.  92  /// If a renderer class object is reinitialized by the \c clear()  JINMEI Tatuya committed Apr 10, 2010 93 94 95 96 97 98 99 100 101 102 103 104  /// 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 };  105 protected:  JINMEI Tatuya committed Jan 26, 2010 106 107 108  /// /// \name Constructors and Destructor //@{  109  /// \brief The default constructor.  JINMEI Tatuya committed Jan 26, 2010 110  ///  111 112  /// This is intentionally defined as \c protected as this base class should /// never be instantiated (except as part of a derived class).  JINMEI Tatuya committed Feb 23, 2012 113  AbstractMessageRenderer();  JINMEI Tatuya committed Feb 24, 2012 114   Michal 'vorner' Vaner committed Apr 13, 2011 115 public:  JINMEI Tatuya committed Mar 04, 2010 116  /// \brief The destructor.  Michal 'vorner' Vaner committed Apr 13, 2011 117  virtual ~AbstractMessageRenderer() {}  JINMEI Tatuya committed Jan 26, 2010 118  //@}  Michal 'vorner' Vaner committed Apr 13, 2011 119 120 protected: /// \brief Return the output buffer we render into.  JINMEI Tatuya committed Feb 23, 2012 121 122  const isc::util::OutputBuffer& getBuffer() const { return (*buffer_); } isc::util::OutputBuffer& getBuffer() { return (*buffer_); }  Michal 'vorner' Vaner committed Apr 13, 2011 123 private:  JINMEI Tatuya committed Feb 24, 2012 124  /// \brief Local (default) buffer to store data.  JINMEI Tatuya committed Feb 23, 2012 125 126  isc::util::OutputBuffer local_buffer_;  JINMEI Tatuya committed Feb 24, 2012 127 128 129 130 131  /// \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().  Michal 'vorner' Vaner committed Apr 06, 2011 132 133  /// /// It was decided that there's no need to have this in every subclass,  JINMEI Tatuya committed Feb 24, 2012 134 135  /// at least not now, and this reduces code size and gives compiler a /// better chance to optimise.  JINMEI Tatuya committed Feb 23, 2012 136  isc::util::OutputBuffer* buffer_;  137 public:  JINMEI Tatuya committed Jan 26, 2010 138 139 140 141 142 143 144 145 146  /// /// \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.  Michal 'vorner' Vaner committed Apr 06, 2011 147  const void* getData() const {  JINMEI Tatuya committed Feb 23, 2012 148  return (buffer_->getData());  Michal 'vorner' Vaner committed Apr 06, 2011 149  }  150   JINMEI Tatuya committed Jan 26, 2010 151  /// \brief Return the length of data written in the internal buffer.  Michal 'vorner' Vaner committed Apr 06, 2011 152  size_t getLength() const {  JINMEI Tatuya committed Feb 23, 2012 153  return (buffer_->getLength());  Michal 'vorner' Vaner committed Apr 06, 2011 154  }  155   JINMEI Tatuya committed Mar 16, 2010 156 157 158 159 160 161 162 163 164  /// \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.  165 166  virtual bool isTruncated() const = 0;  JINMEI Tatuya committed Mar 16, 2010 167 168 169 170 171 172  /// \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.  173 174 175  virtual size_t getLengthLimit() const = 0; /// \brief Return the compression mode of the renderer class object.  JINMEI Tatuya committed Apr 10, 2010 176 177 178 179  /// /// This method never throws an exception. /// /// \return The current compression mode.  180  virtual CompressMode getCompressMode() const = 0;  JINMEI Tatuya committed Mar 08, 2010 181 182 183 184 185 186  //@} /// /// \name Setter Methods /// //@{  JINMEI Tatuya committed Feb 24, 2012 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211  /// \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. ///  JINMEI Tatuya committed Feb 28, 2012 212  /// \param buffer A pointer to a temporary output buffer or NULL for reset  JINMEI Tatuya committed Feb 24, 2012 213  /// it.  JINMEI Tatuya committed Feb 23, 2012 214 215  void setBuffer(isc::util::OutputBuffer* buffer);  JINMEI Tatuya committed Mar 16, 2010 216 217 218 219  /// \brief Mark the renderer to indicate truncation has occurred while /// rendering. /// /// This method never throws an exception.  220 221  virtual void setTruncated() = 0;  JINMEI Tatuya committed Mar 16, 2010 222 223 224 225 226 227  /// \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.  228 229 230  virtual void setLengthLimit(size_t len) = 0; /// \brief Set the compression mode of the renderer class object.  JINMEI Tatuya committed Apr 10, 2010 231 232 233 234  /// /// This method never throws an exception. /// /// \param mode A \c CompressMode value representing the compression mode.  235  virtual void setCompressMode(CompressMode mode) = 0;  JINMEI Tatuya committed Jan 26, 2010 236 237 238 239 240 241 242 243 244 245 246 247 248  //@} /// /// \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.  Michal 'vorner' Vaner committed Apr 13, 2011 249  void skip(size_t len) {  JINMEI Tatuya committed Feb 23, 2012 250  buffer_->skip(len);  Michal 'vorner' Vaner committed Apr 13, 2011 251  }  252   JINMEI Tatuya committed Mar 16, 2010 253 254 255 256 257 258 259 260 261 262  /// \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.  Michal 'vorner' Vaner committed Apr 13, 2011 263  void trim(size_t len) {  JINMEI Tatuya committed Feb 23, 2012 264  buffer_->trim(len);  Michal 'vorner' Vaner committed Apr 13, 2011 265  }  266   JINMEI Tatuya committed Jan 28, 2010 267 268 269 270  /// \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.  Michal 'vorner' Vaner committed Apr 13, 2011 271  virtual void clear();  272   JINMEI Tatuya committed Jan 26, 2010 273 274 275  /// \brief Write an unsigned 8-bit integer into the internal buffer. /// /// \param data The 8-bit integer to be written into the internal buffer.  Michal 'vorner' Vaner committed Apr 06, 2011 276  void writeUint8(const uint8_t data) {  JINMEI Tatuya committed Feb 23, 2012 277  buffer_->writeUint8(data);  Michal 'vorner' Vaner committed Apr 06, 2011 278  }  279   JINMEI Tatuya committed Jan 26, 2010 280 281 282 283  /// \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.  Michal 'vorner' Vaner committed Apr 06, 2011 284  void writeUint16(uint16_t data) {  JINMEI Tatuya committed Feb 23, 2012 285  buffer_->writeUint16(data);  Michal 'vorner' Vaner committed Apr 06, 2011 286  }  287   JINMEI Tatuya committed Jan 26, 2010 288 289 290 291 292 293 294 295 296 297 298  /// \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, pos + 2 < getLength(); /// otherwise an exception of class \c isc::dns::InvalidBufferPosition 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.  Michal 'vorner' Vaner committed Apr 06, 2011 299  void writeUint16At(uint16_t data, size_t pos) {  JINMEI Tatuya committed Feb 23, 2012 300  buffer_->writeUint16At(data, pos);  Michal 'vorner' Vaner committed Apr 06, 2011 301  }  302   JINMEI Tatuya committed Jan 26, 2010 303 304 305 306  /// \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.  Michal 'vorner' Vaner committed Apr 06, 2011 307  void writeUint32(uint32_t data) {  JINMEI Tatuya committed Feb 23, 2012 308  buffer_->writeUint32(data);  Michal 'vorner' Vaner committed Apr 06, 2011 309  }  310   JINMEI Tatuya committed Jan 26, 2010 311  /// \brief Copy an arbitrary length of data into the internal buffer  312  /// of the renderer object.  JINMEI Tatuya committed Jan 26, 2010 313 314 315 316 317  /// /// 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.  Michal 'vorner' Vaner committed Apr 06, 2011 318  void writeData(const void *data, size_t len) {  JINMEI Tatuya committed Feb 23, 2012 319  buffer_->writeData(data, len);  Michal 'vorner' Vaner committed Apr 06, 2011 320  }  JINMEI Tatuya committed Jan 26, 2010 321 322 323 324 325 326 327 328 329 330 331 332 333 334  /// \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.  JINMEI Tatuya committed Aug 29, 2012 335 336  /// \param compress A boolean indicating whether to enable name /// compression.  337  virtual void writeName(const Name& name, bool compress = true) = 0;  JINMEI Tatuya committed Aug 29, 2012 338 339 340 341 342 343 344 345 346 347 348  /// \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.  JINMEI Tatuya committed Aug 29, 2012 349  virtual void writeName(const LabelSequence& ls, bool compress = true) = 0;  Evan Hunt committed Oct 03, 2010 350  //@}  351 352 353 354 355 356 357 358 359 360 361 362 363 }; /// 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.  Michal 'vorner' Vaner committed Aug 08, 2012 364 365 class MessageRenderer : public AbstractMessageRenderer, public boost::noncopyable { // Can crash if copied  366 367 368 369 370 public: using AbstractMessageRenderer::CASE_INSENSITIVE; using AbstractMessageRenderer::CASE_SENSITIVE; /// \brief Constructor from an output buffer.  JINMEI Tatuya committed Feb 23, 2012 371  MessageRenderer();  372 373 374 375 376 377 378  virtual ~MessageRenderer(); virtual bool isTruncated() const; virtual size_t getLengthLimit() const; virtual CompressMode getCompressMode() const; virtual void setTruncated(); virtual void setLengthLimit(size_t len);  JINMEI Tatuya committed Mar 06, 2012 379 380 381 382 383 384 385 386 387  /// 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.  388  virtual void setCompressMode(CompressMode mode);  JINMEI Tatuya committed Mar 06, 2012 389   390 391  virtual void clear(); virtual void writeName(const Name& name, bool compress = true);  JINMEI Tatuya committed Aug 29, 2012 392  virtual void writeName(const LabelSequence& ls, bool compress = true);  Mukund Sivaraman committed Jul 12, 2012 393   JINMEI Tatuya committed Jan 26, 2010 394 private:  JINMEI Tatuya committed Apr 10, 2010 395  struct MessageRendererImpl;  JINMEI Tatuya committed Jan 26, 2010 396 397 398 399 400 401 402 403 404  MessageRendererImpl* impl_; }; } } #endif // __MESSAGERENDERER_H // Local Variables: // mode: c++ // End: