Branch data Line data Source code
1 : : // Copyright (C) 2010 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 __RDATAFIELDS_H
16 : : #define __RDATAFIELDS_H 1
17 : :
18 : : #include <stdint.h>
19 : :
20 : : #include <cstddef>
21 : :
22 : : namespace isc {
23 : : namespace util {
24 : : class OutputBuffer;
25 : : }
26 : : namespace dns {
27 : : class AbstractMessageRenderer;
28 : :
29 : : namespace rdata {
30 : : class Rdata;
31 : :
32 : : /// A low-level, RR type-independent representation of DNS RDATA.
33 : : ///
34 : : /// <b>Purpose of the Class</b>
35 : : ///
36 : : /// This class intends to help "serialization" of the content of RDATA
37 : : /// in a space-efficient manner. Specific derived classes of \c Rdata
38 : : /// focus on the convenience of accessing RDATA fields for RR type-specific
39 : : /// protocol operations, and can be inefficient in terms of space.
40 : : /// For example, a DNS character string may be internally represented as a
41 : : /// \c std::string object with all of the overhead of the richer class.
42 : : /// If an application needs to maintain a very large number of RRs and it
43 : : /// does not have to perform RR specific operation so often, it may make more
44 : : /// sense to store the data in memory in a lower-level but space efficient
45 : : /// form.
46 : : ///
47 : : /// Another purpose of this class is to improve rendering performance for
48 : : /// RDATA. If the only requirement were space efficiency, it would be just
49 : : /// sufficient to convert the \c RDATA into a binary sequence in the wire
50 : : /// format. However, to render the data in a DNS message, we'd have to
51 : : /// re-construct a corresponding \c Rdata object in the case where name
52 : : /// compression is necessary. This is not desirable, and this class is
53 : : /// provided to avoid such unnecessary overhead.
54 : : ///
55 : : /// <b>Data Format</b>
56 : : ///
57 : : /// To meet these goals, this class helps convert an \c Rdata object into
58 : : /// two pieces of information: Wire-format representation of the \c Rdata
59 : : /// and associated meta information for efficient rendering.
60 : : ///
61 : : /// Specifically, it maintains the wire-format data as a sequence of typed
62 : : /// fields. The types are:
63 : : /// - Compressible name: a domain name as an RDATA field that can be compressed
64 : : /// - Incompressible name: a domain name as an RDATA field that cannot be
65 : : /// compressed
66 : : /// - Other data: any other fields of RDATA, which should be treated as opaque
67 : : ///
68 : : /// (See also the description of \c RdataFields::Type)
69 : : /// Whether a name can or cannot be compressed is determined according to
70 : : /// RFC3597.
71 : : ///
72 : : /// A "other data" field may not always correspond to a single RDATA field.
73 : : /// A \c RdataFields field (of other data) is just a contiguous region of the
74 : : /// wire-format data that does not involve name compression.
75 : : /// For example, the SOA RDATA begins with two "compressible" names followed
76 : : /// by 5 32-bit fields.
77 : : /// In \c RdataFields the last 5 fields would be considered a single 20-byte
78 : : /// field.
79 : : ///
80 : : /// Each \c RdataFields field is identified by the \c FieldSpec structure,
81 : : /// which provides the type and length of the field.
82 : : /// An \c RdataFields object internally maintains a sequence of \c FieldSpec
83 : : /// objects in a form of plain C-style array, which can be referenced via
84 : : /// a pointer returned by the \c getFieldSpecData() method.
85 : : /// The \c \c FieldSpec for a specific field can also be retrieved by the
86 : : /// \c getFieldSpec() method.
87 : : ///
88 : : /// The following diagram shows the internal memory representation of
89 : : /// an SOA RDATA in the form of \c RdataFields object and how an application
90 : : /// can get access to the memory region.
91 : : /** \verbatim
92 : : accessible via |0 getDataLength() bytes
93 : : getData()----------> <MNAME><RNAME><Rest of the data>
94 : : <---------- 3 * sizeof(FieldSpec) bytes ------------->
95 : : getFieldSpecData()-> { compressible name { compressible name { other data
96 : : len: MNAME-len } len: RNAME-len } len: 20 }
97 : : \endverbatim
98 : : */
99 : : /// where MNAME and RNAME are wire format representations of the MNAME and
100 : : /// RNAME fields of the SOA RDATA, respectively, and "Rest of the data"
101 : : /// encodes the remaining 20 bytes of the RDATA in network byte order.
102 : : ///
103 : : /// <b>Usage of the Class</b>
104 : : ///
105 : : /// One major and common use case of the \c RdataFields class is to convert
106 : : /// a \c Rdata object (possibly given from a DNS message or some configuration
107 : : /// source such as a zone file) in the serialized format and store a copy of
108 : : /// the data somewhere in memory. The following code sample implements this
109 : : /// scenario:
110 : : /// \code // assume "rdata" is a reference type to Rdata
111 : : /// const RdataFields fields(rdata);
112 : : /// const unsigned int fields_size = fields.getFieldDataSize();
113 : : /// memcpy(some_place, fields.getFieldSpecData(), fields_size);
114 : : /// const size_t data_length = fields.getDataLength();
115 : : /// memcpy(other_place, fields.getData(), data_length);
116 : : /// // (fields_size and data_length should be stored somewhere, too)
117 : : /// \endcode
118 : : ///
119 : : /// Another typical usage is to render the stored data in the wire format
120 : : /// as efficiently as possible. The following code is an example of such
121 : : /// usage:
122 : : /// \code // assume "renderer" is of type MessageRenderer
123 : : /// // retrieve data_length and fields_size from the storage
124 : : /// RdataFields(some_place, fields_size, other_place,
125 : : /// data_length).toWire(renderer);
126 : : /// \endcode
127 : : ///
128 : : /// <b>Notes to Users</b>
129 : : ///
130 : : /// The main purposes of this class is to help efficient operation
131 : : /// for some (limited classes of) performance sensitive application.
132 : : /// For this reason the interface and implementation rely on relatively
133 : : /// lower-level, riskier primitives such as passing around bare pointers.
134 : : ///
135 : : /// It is therefore discouraged to use this class for general purpose
136 : : /// applications that do not need to maximize performance in terms of either
137 : : /// memory footprint or rendering speed.
138 : : /// All functionality provided by this class can be achieved via higher level
139 : : /// interfaces such as the \c Rdata class variants.
140 : : /// Normal applications should use those interfaces.
141 : : ///
142 : : /// The data format is public information so that an application can examine
143 : : /// and use selected parts of data. For example, an application may want to
144 : : /// encode domain names in RDATA in a different way while storing the other
145 : : /// data in a separate place.
146 : : /// However, at this moment the format is still in flux, and it may not
147 : : /// be compatible with future versions (see below).
148 : : ///
149 : : /// <b>Development Notes</b>
150 : : ///
151 : : /// We should conduct benchmark tests to measure rendering performance.
152 : : ///
153 : : /// The current implementation needs to re-construct name objects from
154 : : /// compressible and incompressible name fields as wire-format data.
155 : : /// This is not efficient, and we'll probably want to improve this in a
156 : : /// future version. One possibility is to store offset information as well
157 : : /// as the name data (at the cost of increasing memory footprint), and
158 : : /// to use the pair of data for faster rendering.
159 : : class RdataFields {
160 : : public:
161 : : /// Types of \c RdataFields fields.
162 : : ///
163 : : /// \c COMPRESSIBLE_NAME and \c INCOMPRESSIBLE_NAME represent a domain
164 : : /// name used as a field of an RDATA that can and cannot be compressed
165 : : /// per RFC3597.
166 : : /// \c DATA means all other types of fields.
167 : : enum Type {
168 : : DATA, ///< Plain data.
169 : : COMPRESSIBLE_NAME, ///< A domain name subject to name compression.
170 : : INCOMPRESSIBLE_NAME ///< A domain name that shouldn't be compressed.
171 : : };
172 : :
173 : : /// Structure that specifies a single \c RdataFields field.
174 : : ///
175 : : /// This is a straightforward pair of the type and length of a single
176 : : /// \c RdataFields field.
177 : : ///
178 : : /// In some cases an application may want to do deeper inspection of
179 : : /// some \c RdataFields field(s). For example, an application may want
180 : : /// to construct a \c Name object for each domain name field of an RDATA
181 : : /// and use it for some special purpose.
182 : : /// The \c FieldSpec structure provides necessary parameters to get access
183 : : /// to a specific \c RdataFields field.
184 : : ///
185 : : /// The following code snippet implements the above example scenario:
186 : : /// \code // assume "fields" is of type RdataFields
187 : : /// size_t offset = 0;
188 : : /// for (int i = 0; i < fields.getFieldCount(); ++i) {
189 : : /// const FieldSpec spec = fields.getFieldSpec(i);
190 : : /// if (spec.type == RdataFields::COMPRESSIBLE_NAME ||
191 : : /// spec.type == RdataFields::INCOMPRESSIBLE_NAME) {
192 : : /// InputBuffer ibuffer(fields.getData() + offset, spec.len);
193 : : /// Name name(ibuffer);
194 : : /// // do something with name
195 : : /// }
196 : : /// offset += spec.len;
197 : : /// } \endcode
198 : : ///
199 : : /// Note that the offset is not included in \c FieldSpec.
200 : : /// This is because such deeper inspection would be a relatively rare
201 : : /// operation while it is desirable to keep this structure as small as
202 : : /// possible for the purpose of space efficiency.
203 : : /// Also, if and when an application wants to look into a specific field,
204 : : /// it would be quite likely that the application iterates over all fields
205 : : /// and does something special for selected fields like the above example.
206 : : /// In that case the application can easily and efficiently identify the
207 : : /// necessary offset, again, as shown in the above code example.
208 : : ///
209 : : /// \todo We might find that 16bits per field is generally too much and
210 : : /// squeeze the two bit type into it as well, having 14bit length
211 : : /// (in the rare case of having too long field, it could be split into
212 : : /// multiple ones). That would save 2 bytes per item (one for the type,
213 : : /// one for padding).
214 : 0 : struct FieldSpec {
215 : : FieldSpec(Type type_param, uint16_t len_param) :
216 : 20 : type(type_param), len(len_param)
217 : : {}
218 : : Type type; ///< The type of the field.
219 : : uint16_t len; ///< The length of the field in bytes.
220 : : };
221 : :
222 : : ///
223 : : /// \name Constructors and Destructor.
224 : : ///
225 : : /// \b Note:
226 : : /// The copy constructor and the assignment operator are intentionally
227 : : /// defined as private, making this class non copyable.
228 : : //@{
229 : : private:
230 : : RdataFields(const RdataFields& source);
231 : : RdataFields& operator=(const RdataFields& source);
232 : :
233 : : public:
234 : : /// Constructor from Rdata.
235 : : ///
236 : : /// This constructor converts the data of a given \c Rdata object into
237 : : /// an \c RdataFields object so that the resulting data can be stored
238 : : /// in memory in a space-efficient way.
239 : : ///
240 : : /// It makes a local copy of the original data and dynamically allocates
241 : : /// necessary memory, so is not very efficient.
242 : : /// The basic idea is to perform the expensive conversion once and keep
243 : : /// using the result as long as possible to improve overall performance
244 : : /// in a longer term.
245 : : ///
246 : : /// If the internal resource allocation fails, a corresponding standard
247 : : /// exception will be thrown.
248 : : /// The current implementation of this constructor internally calls
249 : : /// the <code>Rdata::toWire(AbstractMessageRenderer&) const</code> method
250 : : /// for the conversion.
251 : : /// If that method throws an exception it will be propagated to the caller
252 : : /// of this constructor.
253 : : ///
254 : : /// \param rdata The RDATA for which the \c RdataFields to be constructed.
255 : : RdataFields(const Rdata& rdata);
256 : :
257 : : /// Constructor from field parameters.
258 : : ///
259 : : /// The intended usage of this version of constructor is to form a
260 : : /// structured representation of \c RDATA encoded by the other
261 : : /// constructor so that the resulting object can be used for subsequent
262 : : /// operations such as rendering in the wire format.
263 : : /// This version is intended to be efficient by not making any copy
264 : : /// of variable length data or expensive data inspection.
265 : : ///
266 : : /// This constructor is basically exception free, except against bogus
267 : : /// input parameters.
268 : : /// Specifically, the parameters must meet the following conditions;
269 : : /// otherwise an exception of class \c InvalidParameter will be thrown.
270 : : /// - \c fields can be \c NULL if and only if \c nfields is 0
271 : : /// - \c data can be \c NULL if and only if \c data_length is 0
272 : : /// - the sum of the lengths of \c fields entries must be equal to
273 : : /// \c data_length
274 : : ///
275 : : /// This constructor assumes that the memory region pointed by \c data (if
276 : : /// non \c NULL) is encoded as a sequence of valid \c RdataFields fields,
277 : : /// and does not perform deep inspection on each field.
278 : : /// In particular, for fields of type \c COMPRESSIBLE_NAME or
279 : : /// \c INCOMPRESSIBLE_NAME, this constructor assumes the corresponding
280 : : /// memory region is a valid representation of domain name.
281 : : /// Otherwise, a subsequent method call such as
282 : : /// <code>toWire(AbstractMessageRenderer&) const</code>
283 : : /// may trigger an unexpected exception. It also expects the fields reside
284 : : /// on address that is valid for them (eg. it has valid alignment), see
285 : : /// getFieldSpecData() for details.
286 : : ///
287 : : /// It is the caller's responsibility to ensure this assumption.
288 : : /// In general, this constructor is expected to be used for serialized data
289 : : /// generated by the other constructor from a valid \c Rdata.
290 : : /// The result is not guaranteed if the data is generated in any other
291 : : /// ways.
292 : : ///
293 : : /// The resulting \c RdataFields object does not maintain a copy of
294 : : /// \c fields or \c data. It is the caller's responsibility to ensure
295 : : /// the memory regions pointed to by these parameters are valid and intact
296 : : /// as long as the \c RdataFields object is used.
297 : : ///
298 : : /// \param fields An array of \c FieldSpec entries. This can be \c NULL.
299 : : /// \param fields_length The total length of the \c fields.
300 : : /// \param data A pointer to memory region for the entire RDATA. This can
301 : : /// be NULL.
302 : : /// \param data_length The length of \c data in bytes.
303 : : RdataFields(const void* fields, const unsigned int fields_length,
304 : : const void* data, const size_t data_length);
305 : :
306 : : /// The destructor.
307 : : ~RdataFields();
308 : : //@}
309 : :
310 : : ///
311 : : /// \name Getter Methods
312 : : ///
313 : : //@{
314 : : /// \brief Return the length of the entire RDATA encoded in the
315 : : /// \c RdataFields in bytes.
316 : : ///
317 : : /// This method never throws an exception.
318 : 0 : unsigned int getDataLength() const { return (data_length_); }
319 : :
320 : : /// \brief Return a pointer to the RDATA encoded in the \c RdataFields.
321 : : ///
322 : : /// The RdataFields holds ownership of the data.
323 : : ///
324 : : /// This method never throws an exception.
325 : 0 : const void* getData() const { return (data_); }
326 : :
327 : : /// \brief Return the number of bytes the buffer returned by
328 : : /// getFieldSpecData() will occupy.
329 : : ///
330 : : /// This method never throws an exception.
331 : 0 : unsigned int getFieldSpecDataSize() const { return (nfields_ *
332 : 0 : sizeof (*fields_)); }
333 : :
334 : : /// \brief Return the number of specs fields.
335 : : ///
336 : : /// It specifies the range of parameter for getFieldSpec().
337 : : ///
338 : : /// This method never throws.
339 : 0 : unsigned int getFieldCount() const { return (nfields_); }
340 : :
341 : : /// \brief Return a pointer to a sequence of \c FieldSpec for the
342 : : /// \c RdataFields.
343 : : ///
344 : : /// This should be treated as an opaque internal representation you can
345 : : /// just store off somewhere and use it to construct a new RdataFields.
346 : : /// from it. If you are really interested, you can typecast it to
347 : : /// FieldSpec * (which is what it really is internally).
348 : : ///
349 : : /// The RdataFields holds ownership of the data.
350 : : ///
351 : : /// \note You should, however, be aware of alignment issues. The pointer
352 : : /// you pass to the constructor must be an address where the FieldSpec
353 : : /// can live. If you store it at a wrong address (eg. even one with
354 : : /// current implementation on most architectures), it might lead bad
355 : : /// things from slow access to SIGBUS. The easiest way is not to
356 : : /// interleave the fields with data from getData(). It is OK to place
357 : : /// all the fields first (even from multiple RdataFields) and then
358 : : /// place all the data after them.
359 : : ///
360 : : /// This method never throws an exception.
361 : 0 : const void* getFieldSpecData() const {
362 : 0 : return (fields_);
363 : : }
364 : :
365 : : /// \brief Return the specification of the field identified by the given
366 : : /// index.
367 : : ///
368 : : /// \c field_id is the field index, which must be in the range of
369 : : /// <code>[0, getFieldCount())</code>. 0 means the first field, and
370 : : /// <code>getFieldCount()-1</code> means the last.
371 : : ///
372 : : /// If the given index is not in the valid range, an exception of class
373 : : /// \c OutOfRange will be thrown.
374 : : /// This method never throws an exception otherwise.
375 : : ///
376 : : /// \param field_id The index of an \c RdataFields field to be returned.
377 : : /// \return A \c FieldSpec structure that contains the information of
378 : : /// the \c field_id-th field.
379 : : FieldSpec getFieldSpec(const unsigned int field_id) const;
380 : : //@}
381 : :
382 : : ///
383 : : /// \name Converter Methods
384 : : ///
385 : : //@{
386 : : /// \brief Render the RdataFields in the wire format with name compression.
387 : : ///
388 : : /// This method may require resource allocation in \c renderer.
389 : : /// If it fails, a corresponding standard exception will be thrown.
390 : : /// It should not throw any other exception as long as the \c RdataFields
391 : : /// object was constructed from valid parameters (see the description of
392 : : /// constructors). The result is not guaranteed if it's constructed in
393 : : /// any other ways.
394 : : ///
395 : : /// \param renderer DNS message rendering context that encapsulates the
396 : : /// output buffer and name compression information.
397 : : void toWire(AbstractMessageRenderer& renderer) const;
398 : :
399 : : /// \brief Render the RdataFields in the wire format without name
400 : : /// compression.
401 : : ///
402 : : /// This method may require resource allocation in \c buffer.
403 : : /// If it fails, a corresponding standard exception will be thrown.
404 : : ///
405 : : /// \param buffer An output buffer to store the wire data.
406 : : void toWire(isc::util::OutputBuffer& buffer) const;
407 : : //@}
408 : :
409 : : private:
410 : : const FieldSpec* fields_;
411 : : unsigned int nfields_;
412 : : const uint8_t* data_;
413 : : size_t data_length_;
414 : :
415 : : // hide further details within the implementation and don't create vectors
416 : : // every time we don't need them.
417 : : struct RdataFieldsDetail;
418 : : RdataFieldsDetail* detail_;
419 : : };
420 : : }
421 : : }
422 : : }
423 : : #endif // __RDATAFIELDS_H
424 : :
425 : : // Local Variables:
426 : : // mode: c++
427 : : // End:
|