messagerenderer.h 16.5 KB
Newer Older
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

18
#include <util/buffer.h>
19

20
21
#include <boost/noncopyable.hpp>

22
namespace isc {
23

24
25
26
namespace dns {
// forward declarations
class Name;
27
class LabelSequence;
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.
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.
38
///
39
/// A renderer class is mainly intended to be used as a helper for a more
40
/// comprehensive \c Message class internally; normal applications won't have
41
/// to care about details of this class.
42
///
JINMEI Tatuya's avatar
JINMEI Tatuya committed
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.
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.
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.
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 {
77
78
79
80
public:
    /// \brief Compression mode constants.
    ///
    /// The \c CompressMode enum type represents the name compression mode
81
    /// for renderer classes.
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
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()
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:
106
107
108
    ///
    /// \name Constructors and Destructor
    //@{
109
    /// \brief The default constructor.
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).
113
    AbstractMessageRenderer();
JINMEI Tatuya's avatar
JINMEI Tatuya committed
114

115
public:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
116
    /// \brief The destructor.
117
    virtual ~AbstractMessageRenderer() {}
118
    //@}
119
120
protected:
    /// \brief Return the output buffer we render into.
121
122
    const isc::util::OutputBuffer& getBuffer() const { return (*buffer_); }
    isc::util::OutputBuffer& getBuffer() { return (*buffer_); }
123
private:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
124
    /// \brief Local (default) buffer to store data.
125
126
    isc::util::OutputBuffer local_buffer_;

JINMEI Tatuya's avatar
JINMEI Tatuya committed
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().
132
133
    ///
    /// It was decided that there's no need to have this in every subclass,
JINMEI Tatuya's avatar
JINMEI Tatuya committed
134
135
    /// at least not now, and this reduces code size and gives compiler a
    /// better chance to optimise.
136
    isc::util::OutputBuffer* buffer_;
137
public:
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.
147
    const void* getData() const {
148
        return (buffer_->getData());
149
    }
150

151
    /// \brief Return the length of data written in the internal buffer.
152
    size_t getLength() const {
153
        return (buffer_->getLength());
154
    }
155

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;

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.
176
177
178
179
    ///
    /// This method never throws an exception.
    ///
    /// \return The current compression mode.
180
    virtual CompressMode getCompressMode() const = 0;
181
182
183
184
185
186
    //@}

    ///
    /// \name Setter Methods
    ///
    //@{
JINMEI Tatuya's avatar
JINMEI Tatuya committed
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.
    ///
212
    /// \param buffer A pointer to a temporary output buffer or NULL for reset
JINMEI Tatuya's avatar
JINMEI Tatuya committed
213
    /// it.
214
215
    void setBuffer(isc::util::OutputBuffer* buffer);

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;

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.
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;
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.
249
    void skip(size_t len) {
250
        buffer_->skip(len);
251
    }
252

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.
263
    void trim(size_t len) {
264
        buffer_->trim(len);
265
    }
266

JINMEI Tatuya's avatar
JINMEI Tatuya committed
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.
271
    virtual void clear();
272

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.
276
    void writeUint8(const uint8_t data) {
277
        buffer_->writeUint8(data);
278
    }
279

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.
284
    void writeUint16(uint16_t data) {
285
        buffer_->writeUint16(data);
286
    }
287

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, <code>pos + 2 < getLength()</code>;
    /// 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.
299
    void writeUint16At(uint16_t data, size_t pos) {
300
        buffer_->writeUint16At(data, pos);
301
    }
302

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.
307
    void writeUint32(uint32_t data) {
308
        buffer_->writeUint32(data);
309
    }
310

311
    /// \brief Copy an arbitrary length of data into the internal buffer
312
    /// of the renderer object.
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.
318
    void writeData(const void *data, size_t len) {
319
        buffer_->writeData(data, len);
320
    }
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.
335
336
    /// \param compress A boolean indicating whether to enable name
    /// compression.
337
    virtual void writeName(const Name& name, bool compress = true) = 0;
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.
349
    virtual void writeName(const LabelSequence& ls, bool compress = true) = 0;
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.
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.
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);
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);
389

390
391
    virtual void clear();
    virtual void writeName(const Name& name, bool compress = true);
392
    virtual void writeName(const LabelSequence& ls, bool compress = true);
393

394
private:
395
    struct MessageRendererImpl;
396
397
398
399
400
401
402
403
404
    MessageRendererImpl* impl_;
};
}
}
#endif // __MESSAGERENDERER_H

// Local Variables: 
// mode: c++
// End: