Branch data Line data Source code
1 : : // Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
2 : : //
3 : : // Permission to use, copy, modify, and/or distribute this software for any
4 : : // purpose with or without fee is hereby granted, provided that the above
5 : : // copyright notice and this permission notice appear in all copies.
6 : : //
7 : : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
8 : : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9 : : // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
10 : : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11 : : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
12 : : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13 : : // PERFORMANCE OF THIS SOFTWARE.
14 : :
15 : : #ifndef __MESSAGERENDERER_H
16 : : #define __MESSAGERENDERER_H 1
17 : :
18 : : #include <util/buffer.h>
19 : :
20 : : namespace isc {
21 : :
22 : : namespace dns {
23 : : // forward declarations
24 : : class Name;
25 : :
26 : : /// \brief The \c AbstractMessageRenderer class is an abstract base class
27 : : /// that provides common interfaces for rendering a DNS message into a buffer
28 : : /// in wire format.
29 : : ///
30 : : /// A specific derived class of \c AbstractMessageRenderer (we call it
31 : : /// a renderer class hereafter) is simply responsible for name compression at
32 : : /// least in the current design. A renderer class object (conceptually)
33 : : /// manages the positions of names rendered in some sort of buffer and uses
34 : : /// that information to render subsequent names with compression.
35 : : ///
36 : : /// A renderer class is mainly intended to be used as a helper for a more
37 : : /// comprehensive \c Message class internally; normal applications won't have
38 : : /// to care about details of this class.
39 : : ///
40 : : /// By default any (derived) renderer class object is associated with
41 : : /// an internal buffer, and subsequent write operations will be performed
42 : : /// on that buffer. The rendering result can be retrieved via the
43 : : /// \c getData() method.
44 : : ///
45 : : /// If an application wants a separate buffer can be (normally temporarily)
46 : : /// set for rendering operations via the \c setBuffer() method. In that case,
47 : : /// it is generally expected that all rendering operations are performed via
48 : : /// that object. If the application modifies the buffer in
49 : : /// parallel with the renderer, the result will be undefined.
50 : : ///
51 : : /// Note to developers: we introduced a separate class for name compression
52 : : /// because previous benchmark with BIND9 showed compression affects overall
53 : : /// response performance very much. By having a separate class dedicated for
54 : : /// this purpose, we'll be able to change the internal implementation of name
55 : : /// compression in the future without affecting other part of the API and
56 : : /// implementation.
57 : : ///
58 : : /// In addition, by introducing a class hierarchy from
59 : : /// \c AbstractMessageRenderer, we allow an application to use a customized
60 : : /// renderer class for specific purposes. For example, a high performance
61 : : /// DNS server may want to use an optimized renderer class assuming some
62 : : /// specific underlying data representation.
63 : : ///
64 : : /// \note Some functions (like writeUint8) are not virtual. It is because
65 : : /// it is hard to imagine any version of message renderer that would
66 : : /// do anything else than just putting the data into a buffer, so we
67 : : /// provide a default implementation and having them virtual would only
68 : : /// hurt the performance with no real gain. If it would happen a different
69 : : /// implementation is really needed, we can make them virtual in future.
70 : : /// The only one that is virtual is writeName and it's because this
71 : : /// function is much more complicated, therefore there's a lot of space
72 : : /// for different implementations or behaviours.
73 : : class AbstractMessageRenderer {
74 : : public:
75 : : /// \brief Compression mode constants.
76 : : ///
77 : : /// The \c CompressMode enum type represents the name compression mode
78 : : /// for renderer classes.
79 : : /// \c CASE_INSENSITIVE means compress names in case-insensitive manner;
80 : : /// \c CASE_SENSITIVE means compress names in case-sensitive manner.
81 : : /// By default, a renderer compresses names in case-insensitive
82 : : /// manner.
83 : : /// Compression mode can be dynamically modified by the
84 : : /// \c setCompressMode() method.
85 : : /// The mode can be changed even in the middle of rendering, although this
86 : : /// is not an intended usage. In this case the names already compressed
87 : : /// are intact; only names being compressed after the mode change are
88 : : /// affected by the change.
89 : : /// If a renderer class object is reinitialized by the \c clear()
90 : : /// method, the compression mode will be reset to the default, which is
91 : : /// \c CASE_INSENSITIVE
92 : : ///
93 : : /// One specific case where case-sensitive compression is required is
94 : : /// AXFR as described in draft-ietf-dnsext-axfr-clarify. A primary
95 : : /// authoritative DNS server implementation using this API would specify
96 : : /// \c CASE_SENSITIVE before rendering outgoing AXFR messages.
97 : : ///
98 : : enum CompressMode {
99 : : CASE_INSENSITIVE, //!< Compress names case-insensitive manner (default)
100 : : CASE_SENSITIVE //!< Compress names case-sensitive manner
101 : : };
102 : : protected:
103 : : ///
104 : : /// \name Constructors and Destructor
105 : : //@{
106 : : /// \brief The default constructor.
107 : : ///
108 : : /// This is intentionally defined as \c protected as this base class should
109 : : /// never be instantiated (except as part of a derived class).
110 : : AbstractMessageRenderer();
111 : :
112 : : public:
113 : : /// \brief The destructor.
114 : 1224 : virtual ~AbstractMessageRenderer() {}
115 : : //@}
116 : : protected:
117 : : /// \brief Return the output buffer we render into.
118 : : const isc::util::OutputBuffer& getBuffer() const { return (*buffer_); }
119 : 0 : isc::util::OutputBuffer& getBuffer() { return (*buffer_); }
120 : : private:
121 : : /// \brief Local (default) buffer to store data.
122 : : isc::util::OutputBuffer local_buffer_;
123 : :
124 : : /// \brief Buffer to store data.
125 : : ///
126 : : /// Note that the class interface ensures this pointer is never NULL;
127 : : /// it either refers to \c local_buffer_ or to an application-supplied
128 : : /// buffer by \c setBuffer().
129 : : ///
130 : : /// It was decided that there's no need to have this in every subclass,
131 : : /// at least not now, and this reduces code size and gives compiler a
132 : : /// better chance to optimise.
133 : : isc::util::OutputBuffer* buffer_;
134 : : public:
135 : : ///
136 : : /// \name Getter Methods
137 : : ///
138 : : //@{
139 : : /// \brief Return a pointer to the head of the data stored in the internal
140 : : /// buffer.
141 : : ///
142 : : /// This method works exactly same as the same method of the \c OutputBuffer
143 : : /// class; all notes for \c OutputBuffer apply.
144 : 0 : const void* getData() const {
145 : 0 : return (buffer_->getData());
146 : : }
147 : :
148 : : /// \brief Return the length of data written in the internal buffer.
149 : 0 : size_t getLength() const {
150 : 0 : return (buffer_->getLength());
151 : : }
152 : :
153 : : /// \brief Return whether truncation has occurred while rendering.
154 : : ///
155 : : /// Once the return value of this method is \c true, it doesn't make sense
156 : : /// to try rendering more data, although this class itself doesn't reject
157 : : /// the attempt.
158 : : ///
159 : : /// This method never throws an exception.
160 : : ///
161 : : /// \return true if truncation has occurred; otherwise \c false.
162 : : virtual bool isTruncated() const = 0;
163 : :
164 : : /// \brief Return the maximum length of rendered data that can fit in the
165 : : /// corresponding DNS message without truncation.
166 : : ///
167 : : /// This method never throws an exception.
168 : : ///
169 : : /// \return The maximum length in bytes.
170 : : virtual size_t getLengthLimit() const = 0;
171 : :
172 : : /// \brief Return the compression mode of the renderer class object.
173 : : ///
174 : : /// This method never throws an exception.
175 : : ///
176 : : /// \return The current compression mode.
177 : : virtual CompressMode getCompressMode() const = 0;
178 : : //@}
179 : :
180 : : ///
181 : : /// \name Setter Methods
182 : : ///
183 : : //@{
184 : : /// \brief Set or reset a temporary output buffer.
185 : : ///
186 : : /// This method can be used for an application that manages an output
187 : : /// buffer separately from the message renderer and wants to keep reusing
188 : : /// the renderer. When the renderer is associated with the default buffer
189 : : /// and the given pointer is non NULL, the given buffer will be
190 : : /// (temporarily) used for subsequent message rendering; if the renderer
191 : : /// is associated with a temporary buffer and the given pointer is NULL,
192 : : /// the renderer will be reset with the default buffer. In the latter
193 : : /// case any additional resources (possibly specific to a derived renderer
194 : : /// class) will be cleared, but the temporary buffer is kept as the latest
195 : : /// state (which would normally store the rendering result).
196 : : ///
197 : : /// This method imposes some restrictions to prevent accidental misuse
198 : : /// that could cause disruption such as dereferencing an invalid object.
199 : : /// First, a temporary buffer must not be set when the associated buffer
200 : : /// is in use, that is, any data are stored in the buffer. Also, the
201 : : /// default buffer cannot be "reset"; when NULL is specified a temporary
202 : : /// buffer must have been set beforehand. If these conditions aren't met
203 : : /// an isc::InvalidParameter exception will be thrown. This method is
204 : : /// exception free otherwise.
205 : : ///
206 : : /// \throw isc::InvalidParameter A restrictions of the method usage isn't
207 : : /// met.
208 : : ///
209 : : /// \param buffer A pointer to a temporary output buffer or NULL for reset
210 : : /// it.
211 : : void setBuffer(isc::util::OutputBuffer* buffer);
212 : :
213 : : /// \brief Mark the renderer to indicate truncation has occurred while
214 : : /// rendering.
215 : : ///
216 : : /// This method never throws an exception.
217 : : virtual void setTruncated() = 0;
218 : :
219 : : /// \brief Set the maximum length of rendered data that can fit in the
220 : : /// corresponding DNS message without truncation.
221 : : ///
222 : : /// This method never throws an exception.
223 : : ///
224 : : /// \param len The maximum length in bytes.
225 : : virtual void setLengthLimit(size_t len) = 0;
226 : :
227 : : /// \brief Set the compression mode of the renderer class object.
228 : : ///
229 : : /// This method never throws an exception.
230 : : ///
231 : : /// \param mode A \c CompressMode value representing the compression mode.
232 : : virtual void setCompressMode(CompressMode mode) = 0;
233 : : //@}
234 : :
235 : : ///
236 : : /// \name Methods for writing data into the internal buffer.
237 : : ///
238 : : //@{
239 : : /// \brief Insert a specified length of gap at the end of the buffer.
240 : : ///
241 : : /// The caller should not assume any particular value to be inserted.
242 : : /// This method is provided as a shortcut to make a hole in the buffer
243 : : /// that is to be filled in later, e.g, by \ref writeUint16At().
244 : : ///
245 : : /// \param len The length of the gap to be inserted in bytes.
246 : 921 : void skip(size_t len) {
247 [ + - ]: 1566 : buffer_->skip(len);
248 : 921 : }
249 : :
250 : : /// \brief Trim the specified length of data from the end of the internal
251 : : /// buffer.
252 : : ///
253 : : /// This method is provided for such cases as DNS message truncation.
254 : : ///
255 : : /// The specified length must not exceed the current data size of the
256 : : /// buffer; otherwise an exception of class \c isc::OutOfRange will
257 : : /// be thrown.
258 : : ///
259 : : /// \param len The length of data that should be trimmed.
260 : 0 : void trim(size_t len) {
261 [ + - ]: 22 : buffer_->trim(len);
262 : 0 : }
263 : :
264 : : /// \brief Clear the internal buffer and other internal resources.
265 : : ///
266 : : /// This method can be used to re-initialize and reuse the renderer
267 : : /// without constructing a new one.
268 : : virtual void clear();
269 : :
270 : : /// \brief Write an unsigned 8-bit integer into the internal buffer.
271 : : ///
272 : : /// \param data The 8-bit integer to be written into the internal buffer.
273 : 0 : void writeUint8(const uint8_t data) {
274 : 29 : buffer_->writeUint8(data);
275 : 0 : }
276 : :
277 : : /// \brief Write an unsigned 16-bit integer in host byte order into the
278 : : /// internal buffer in network byte order.
279 : : ///
280 : : /// \param data The 16-bit integer to be written into the buffer.
281 : 2 : void writeUint16(uint16_t data) {
282 [ + - ]: 6236 : buffer_->writeUint16(data);
283 : 2 : }
284 : :
285 : : /// \brief Write an unsigned 16-bit integer in host byte order at the
286 : : /// specified position of the internal buffer in network byte order.
287 : : ///
288 : : /// The buffer must have a sufficient room to store the given data at the
289 : : /// given position, that is, <code>pos + 2 < getLength()</code>;
290 : : /// otherwise an exception of class \c isc::dns::InvalidBufferPosition will
291 : : /// be thrown.
292 : : /// Note also that this method never extends the internal buffer.
293 : : ///
294 : : /// \param data The 16-bit integer to be written into the internal buffer.
295 : : /// \param pos The beginning position in the buffer to write the data.
296 : 0 : void writeUint16At(uint16_t data, size_t pos) {
297 [ + - ]: 1706 : buffer_->writeUint16At(data, pos);
298 : 0 : }
299 : :
300 : : /// \brief Write an unsigned 32-bit integer in host byte order into the
301 : : /// internal buffer in network byte order.
302 : : ///
303 : : /// \param data The 32-bit integer to be written into the buffer.
304 : 3 : void writeUint32(uint32_t data) {
305 : 974 : buffer_->writeUint32(data);
306 : 3 : }
307 : :
308 : : /// \brief Copy an arbitrary length of data into the internal buffer
309 : : /// of the renderer object.
310 : : ///
311 : : /// No conversion on the copied data is performed.
312 : : ///
313 : : /// \param data A pointer to the data to be copied into the internal buffer.
314 : : /// \param len The length of the data in bytes.
315 : 0 : void writeData(const void *data, size_t len) {
316 : 3300 : buffer_->writeData(data, len);
317 : 0 : }
318 : :
319 : : /// \brief Write a \c Name object into the internal buffer in wire format,
320 : : /// with or without name compression.
321 : : ///
322 : : /// If the optional parameter \c compress is \c true, this method tries to
323 : : /// compress the \c name if possible, searching the entire message that has
324 : : /// been rendered. Otherwise name compression is omitted. Its default
325 : : /// value is \c true.
326 : : ///
327 : : /// Note: even if \c compress is \c true, the position of the \c name (and
328 : : /// possibly its ancestor names) in the message is recorded and may be used
329 : : /// for compressing subsequent names.
330 : : ///
331 : : /// \param name A \c Name object to be written.
332 : : /// \param compress A boolean indicating whether to enable name compression.
333 : : virtual void writeName(const Name& name, bool compress = true) = 0;
334 : : //@}
335 : : };
336 : :
337 : : /// The \c MessageRenderer is a concrete derived class of
338 : : /// \c AbstractMessageRenderer as a general purpose implementation of the
339 : : /// renderer interfaces.
340 : : ///
341 : : /// A \c MessageRenderer object is constructed with a \c OutputBuffer
342 : : /// object, which is the buffer into which the rendered %data will be written.
343 : : /// Normally the buffer is expected to be empty on construction, but it doesn't
344 : : /// have to be so; the renderer object will start rendering from the
345 : : /// end of the buffer at the time of construction. However, if the
346 : : /// pre-existing portion of the buffer contains DNS names, these names won't
347 : : /// be considered for name compression.
348 : : class MessageRenderer : public AbstractMessageRenderer {
349 : : public:
350 : : using AbstractMessageRenderer::CASE_INSENSITIVE;
351 : : using AbstractMessageRenderer::CASE_SENSITIVE;
352 : :
353 : : /// \brief Constructor from an output buffer.
354 : : MessageRenderer();
355 : :
356 : : virtual ~MessageRenderer();
357 : : virtual bool isTruncated() const;
358 : : virtual size_t getLengthLimit() const;
359 : : virtual CompressMode getCompressMode() const;
360 : : virtual void setTruncated();
361 : : virtual void setLengthLimit(size_t len);
362 : :
363 : : /// This implementation does not allow this call in the middle of
364 : : /// rendering (i.e. after at least one name is rendered) due to
365 : : /// restriction specific to the internal implementation. Such attempts
366 : : /// will result in an \c isc::InvalidParameter exception.
367 : : ///
368 : : /// This shouldn't be too restrictive in practice; there's no known
369 : : /// practical case for such a mixed compression policy in a single
370 : : /// message.
371 : : virtual void setCompressMode(CompressMode mode);
372 : :
373 : : virtual void clear();
374 : : virtual void writeName(const Name& name, bool compress = true);
375 : : private:
376 : : struct MessageRendererImpl;
377 : : MessageRendererImpl* impl_;
378 : : };
379 : : }
380 : : }
381 : : #endif // __MESSAGERENDERER_H
382 : :
383 : : // Local Variables:
384 : : // mode: c++
385 : : // End:
|