rdataset.h 16.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Copyright (C) 2012  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 DATASRC_MEMORY_RDATASET_H
#define DATASRC_MEMORY_RDATASET_H 1

#include <util/memory_segment.h>

20
#include <dns/rrclass.h>
21
22
23
24
#include <dns/rrtype.h>
#include <dns/rrset.h>
#include <dns/rrttl.h>

25
#include <boost/interprocess/offset_ptr.hpp>
26
#include <boost/noncopyable.hpp>
27

28
29
#include <stdint.h>

30
31
32
namespace isc {
namespace datasrc {
namespace memory {
33
class RdataEncoder;
34

35
36
37
38
39
40
41
42
43
44
/// \brief General error on creating RdataSet.
///
/// This is thrown when creating \c RdataSet encounters a rare, unsupported
/// situation.
class RdataSetError : public Exception {
public:
    RdataSetError(const char* file, size_t line, const char* what) :
        Exception(file, line, what) {}
};

45
46
47
48
49
50
51
52
/// \brief Memory-efficient representation of RRset data with RRSIGs.
///
/// This class provides memory-efficient and lightweight interface to various
/// attributes of an RRset, which may or may not be signed with RRSIGs.
///
/// This class is primarily intended to be used in the in-memory data source
/// implementation, and is not supposed to be used by general applications.
/// The major design goals is to keep required memory footprint for the given
53
54
55
/// amount of data as small as possible, while providing a reasonably
/// efficient interface to examine the data, focusing on zone lookup and DNS
/// message rendering.
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
///
/// It encodes a specific set of RRset and (when signed) its RRSIGs, excluding
/// the owner name and the RR class.  The owner name is supposed to be
/// maintained by the application outside this class (the intended place to
/// store this information is a \c DomainTree node, although this
/// implementation does not rely on that intent).  The RR class must be the
/// same in a single zone, and it's simply a waste if we have it with each
/// RRset.  The RR class information is therefore expected to be maintained
/// outside this class.
///
/// This class imposes some limitations on the number of RDATAs of the RRset
/// and RRSIG: a (non RRSIG) RRset containing more than 8191 (2^13 - 1)
/// or an RRSIG containing more than 65535 (2^16 - 1) RDATAs cannot be
/// maintained in this class.  The former restriction comes from the
/// following observation: any RR in wire format in a DNS message must at
/// least contain 10 bytes of data (for RR type, class, TTL and RDATA length),
/// and since a valid DNS message must not be larger than 65535 bytes,
/// no valid DNS response can contain more than 6554 RRs.  So, in practice,
/// it should be reasonable even if we reject very large RRsets that would
/// not fit in a DNS message.  For the same reason we restrict the number of
/// RRSIGs, although due to internal implementation details the limitation
/// is more relaxed for RRSIGs.
///
/// \note (This is pure implementation details) By limiting the number of
/// RDATAs so it will fit in a 13-bit integer, we can use 3 more bits in a
/// 2-byte integer for other purposes.  We use this additional field to
/// represent the number of RRSIGs up to 6, while using the value of 7 to mean
/// there are more than 6 RRSIGs.  In the vast majority of real world
/// deployment, an RRset should normally have only a few RRSIGs, and 6 should
/// normally be more than sufficient.  So we can cover most practical cases
/// regarding the number of records with this 2-byte field.
///
/// A set of objects of this class (which would be \c RdataSets of various
/// types of the same owner name) will often be maintained in a single linked
/// list.  The class has a member variable to make the link.
///
/// This class is designed so an instance can be stored in a shared
/// memory region.  So it only contains straightforward data (e.g., it
/// doesn't hold a pointer to an object of some base class that
/// contains virtual methods), and the pointer member (see the
/// previous paragraph) is represented as an offset pointer.  For the
/// same reason this class should never have virtual methods (and as a
/// result, should never be inherited in practice).  When this class
/// is extended these properties must be preserved.
///
/// The \c RdataSet class itself only contains a subset of attributes that
/// it is conceptually expected to contain.  The rest of the attributes
/// are encoded in a consecutive memory region immediately following the main
/// \c RdataSet object.  The memory layout would be as follows:
/// \verbatim
/// RdataSet object
/// (optional) uint16_t: number of RRSIGs, if it's larger than 6 (see above)
/// encoded RDATA (generated by RdataEncoder) \endverbatim
///
/// This is shown here only for reference purposes.  The application must not
/// assume any particular format of data in this region directly; it must
/// get access to it via public interfaces provided in the main \c RdataSet
/// class.
114
class RdataSet : boost::noncopyable {
115
public:
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
    /// \brief Allocate and construct \c RdataSet
    ///
    /// This static method allocates memory for a new \c RdataSet
    /// object for the set of an RRset and (if it's supposed to be signed)
    /// RRSIG from the given memory segment, constructs the object, and
    /// returns a pointer to it.
    ///
    /// Normally the (non RRSIG) RRset is given (\c rrset is not NULL) while
    /// its RRSIG (\c sig_rrset) may or may not be provided.  But it's also
    /// expected that in some rare (mostly broken) cases there can be an RRSIG
    /// RR in a zone without having the covered RRset in the zone.  To handle
    /// such cases, this class allows to only hold RRSIG, in which case
    /// \c rrset can be NULL.  At least \c rrset or \c sig_rrset must be
    /// non NULL, however.  Also, if non NULL, the RRset must not be empty,
    /// that is, it must contain at least one RDATA.
    ///
    /// The RR type of \c rrset must not be RRSIG; the RR type of \c sig_rrset
    /// must be RRSIG.
    ///
    /// When both \c rrset and \c sig_rrset are provided (both are non
    /// NULL), the latter must validly cover the former: the RR class
    /// must be identical; the type covered field of any RDATA of \c
    /// sig_rrset must be identical to the RR type of \c rrset.  The owner
    /// name of these RRsets must also be identical, but this implementation
    /// doesn't require it because \c RdataSet itself does not rely on the
    /// owner name, and it should be pretty likely that this condition is met
    /// in the context where this class is used (and, name comparison is
    /// relatively expensive, and if we end up comparing them twice the
    /// overhead can be non negligible).
    ///
    /// If any of the above conditions isn't met, an isc::BadValue exception
    /// will be thrown; basically, there should be a bug in the caller if this
    /// happens.
    ///
    /// Due to implementation limitations, this class cannot contain more than
    /// 8191 RDATAs for the non RRISG RRset; also, it cannot contain more than
    /// 65535 RRSIGs.  If the given RRset(s) fail to meet this condition,
    /// an \c RdataSetError exception will be thrown.
    ///
    /// \throw isc::BadValue Given RRset(s) are invalid (see the description)
    /// \throw RdataSetError Number of RDATAs exceed the limits
    /// \throw std::bad_alloc Memory allocation fails.
    ///
    /// \param mem_sgmt A \c MemorySegment from which memory for the new
    /// \c RdataSet is allocated.
    /// \param encoder The RDATA encoder to encode \c rrset and \c sig_rrset
    /// with the \c RdataSet to be created.
    /// \param rrset A (non RRSIG) RRset from which the \c RdataSet is to be
    /// created.  Can be NULL if sig_rrset is not.
    /// \param sig_rrset An RRSIG RRset from which the \c RdataSet is to be
    /// created.  Can be NULL if rrset is not.
    ///
    /// \return A pointer to the created \c RdataSet.
169
170
171
172
    static RdataSet* create(util::MemorySegment& mem_sgmt,
                            RdataEncoder& encoder,
                            dns::ConstRRsetPtr rrset,
                            dns::ConstRRsetPtr sig_rrset);
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193

    /// \brief Destruct and deallocate \c RdataSet
    ///
    /// Note that this method needs to know the expected RR class of the
    /// \c RdataSet.  This is because the destruction may depend on the
    /// internal data encoding that only \c RdataEncoder and \c RdataReader
    /// know, and they need to know the corresponding RR class and type to
    /// identify the internal data representation.  Since \c RdataSet itself
    /// does not hold the class information, the caller needs to provide it.
    /// Obviously, this RR class must be identical to the RR class of \c rrset
    /// (when given) or of \c sig_rrset (when \c rrset isn't given) at the
    /// \c create() time.
    ///
    /// \throw none
    ///
    /// \param mem_sgmt The \c MemorySegment that allocated memory for
    /// \c node.
    /// \param rrclass The RR class of the \c RdataSet to be destroyed.
    /// \param rdataset A non NULL pointer to a valid \c RdataSet object
    /// that was originally created by the \c create() method (the behavior
    /// is undefined if this condition isn't met).
194
195
    static void destroy(util::MemorySegment& mem_sgmt, dns::RRClass rrclass,
                        RdataSet* rdataset);
196

197
198
199
    typedef boost::interprocess::offset_ptr<RdataSet> RdataSetPtr;
    typedef boost::interprocess::offset_ptr<const RdataSet> ConstRdataSetPtr;

200
201
202
    // Note: the size and order of the members are carefully chosen to
    // maximize efficiency.  Don't change them unless there's strong reason
    // for that and the consequences are considered.
203
204
205
206
207
208
209
210
211
    // For convenience (and since this class is mostly intended to be an
    // internal definition for the in-memory data source implementation),
    // we allow the application to get access to some members directly.
    // Some others require some conversion to use in a meaningful way,
    // for which we force the application to use accessor methods in order
    // to prevent misuse.

    RdataSetPtr next; ///< Pointer to the next \c RdataSet (when linked)
    const dns::RRType type;     ///< The RR type of the \c RdataSet
212

213
private:
214
215
216
    const uint16_t sig_rdata_count_ : 3; // # of RRSIGs, up to 6 (7 means many)
    const uint16_t rdata_count_ : 13; // # of RDATAs, up to 8191
    const uint32_t ttl_;       // TTL of the RdataSet, net byte order
217

218
219
    // Max number of normal RDATAs that can be stored in \c RdataSet.
    // It's 2^13 - 1 = 8191.
220
    static const size_t MAX_RDATA_COUNT = (1 << 13) - 1;
221
222
223

    // Max number of RRSIGs that can be stored in \c RdataSet.
    // It's 2^16 - 1 = 65535.
224
    static const size_t MAX_RRSIG_COUNT = (1 << 16) - 1;
225
226
227

    // Indicate the \c RdataSet contains many RRSIGs that require an additional
    // field for the real number of RRSIGs.  It's 2^3 - 1 = 7.
228
    static const size_t MANY_RRSIG_COUNT = (1 << 3) - 1;
229

230
public:
231
232
233
234
235
236
237
238
239
240
241
    /// \brief Return the bare pointer to the next node.
    ///
    /// In such an operation as iterating over a linked list of \c RdataSet
    /// object, using this method is generally more efficient than using
    /// the \c next member directly because it prevents unintentional
    /// creation of offset pointer objects.  While the application can
    /// get the same result by directly calling get() on \c next, it would
    /// help encourage the use of more efficient usage if we provide an
    /// explicit accessor.
    RdataSet* getNext() const { return (next.get()); }

242
    /// \brief Return the number of RDATAs stored in the \c RdataSet.
243
    size_t getRdataCount() const { return (rdata_count_); }
244
245

    /// \brief Return the number of RRSIG RDATAs stored in the \c RdataSet.
246
    size_t getSigRdataCount() const {
247
248
        if (sig_rdata_count_ < MANY_RRSIG_COUNT) {
            return (sig_rdata_count_);
249
250
251
252
        } else {
            return (*getExtSIGCountBuf());
        }
    }
253
254
255
256
257
258
259
260
261
262

    /// \brief Return a pointer to the TTL data of the \c RdataSet.
    ///
    /// The returned pointer points to a memory region that is valid at least
    /// for 32 bits, storing the TTL of the \c RdataSet in the network byte
    /// order.  It returns opaque data to make it clear that unless the wire
    /// format data is necessary (e.g., when rendering it in a DNS message),
    /// it should be converted to, e.g., an \c RRTTL object explicitly.
    ///
    /// \throw none
263
    const void* getTTLData() const { return (&ttl_); }
264
265
266
267
268
269
270

    /// \brief Accessor to the memory region for encoded RDATAs.
    ///
    /// The only valid usage of the returned pointer is to pass it to
    /// the constructor of \c RdataReader.
    ///
    /// \throw none
271
272
    const void* getDataBuf() const {
        return (getDataBuf<const void, const RdataSet>(this));
273
    }
274

275
private:
276
277
278
279
280
281
282
    /// \brief Accessor to the memory region for encoded RDATAs, mutable
    /// version.
    ///
    /// This version is only used within the class implementation, so it's
    /// defined as private.
    void* getDataBuf() {
        return (getDataBuf<void, RdataSet>(this));
283
    }
284
285
286

    // Implementation of getDataBuf().  Templated to unify the mutable and
    // immutable versions.
287
288
289
290
291
292
293
294
    template <typename RetType, typename ThisType>
    static RetType* getDataBuf(ThisType* rdataset) {
        if (rdataset->sig_rdata_count_ < MANY_RRSIG_COUNT) {
            return (rdataset + 1);
        } else {
            return (rdataset->getExtSIGCountBuf() + 1);
        }
    }
295

296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
    /// \brief Accessor to the memory region for the RRSIG count field for
    /// a large number of RRSIGs.
    ///
    /// These are used only internally and defined as private.
    const uint16_t* getExtSIGCountBuf() const {
        return (reinterpret_cast<const uint16_t*>(this + 1));
    }
    uint16_t* getExtSIGCountBuf() {
        return (reinterpret_cast<uint16_t*>(this + 1));
    }

    /// \brief The constructor.
    ///
    /// An object of this class is always expected to be created by the
    /// allocator (\c create()), so the constructor is hidden as private.
    ///
    /// It never throws an exception.
313
314
    RdataSet(dns::RRType type, size_t rdata_count, size_t sig_rdata_count,
             dns::RRTTL ttl);
315
316
317
318
319
320
321
322

    /// \brief The destructor.
    ///
    /// An object of this class is always expected to be destroyed explicitly
    /// by \c destroy(), so the destructor is hidden as private.
    ///
    /// This currently does nothing, but is explicitly defined to clarify
    /// it's intentionally defined as private.
323
324
325
    ~RdataSet() {}
};

326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
// Shared by both mutable and immutable versions below
template <typename RdataSetType>
RdataSetType*
findRdataSetOfType(RdataSetType* rdataset_head, dns::RRType type) {
    for (RdataSetType* rdataset = rdataset_head;
         rdataset != NULL;
         rdataset = rdataset->getNext()) // use getNext() for efficiency
    {
        if (rdataset->type == type) {
            return (rdataset);
        }
    }
    return (NULL);
}

/// \brief Find \c RdataSet of given RR type from a list (const version).
///
/// This function is a convenient shortcut for commonly used operation of
/// finding a given type of \c RdataSet from a linked list of them.
///
/// It follows the linked list of \c RdataSet objects (via their \c next
/// member) starting the given head, until it finds an object of the
/// given RR type.  If found, it returns a (bare) pointer to the object;
/// if not found in the entire list, it returns NULL.  The head pointer
/// can be NULL, in which case this function will simply return NULL.
inline const RdataSet*
findRdataSetOfType(const RdataSet* rdataset_head, dns::RRType type) {
    return (findRdataSetOfType<const RdataSet>(rdataset_head, type));
}

/// \brief Find \c RdataSet of given RR type from a list (non const version).
///
/// This is similar to the const version, except it takes and returns non
/// const pointers.
inline RdataSet*
findRdataSetOfType(RdataSet* rdataset_head, dns::RRType type) {
    return (findRdataSetOfType<RdataSet>(rdataset_head, type));
}

365
366
367
368
369
370
371
372
373
} // namespace memory
} // namespace datasrc
} // namespace isc

#endif // DATASRC_MEMORY_RDATASET_H

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