rdataset.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. // Copyright (C) 2012 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. #ifndef DATASRC_MEMORY_RDATASET_H
  15. #define DATASRC_MEMORY_RDATASET_H 1
  16. #include <util/memory_segment.h>
  17. #include <dns/rrclass.h>
  18. #include <dns/rrtype.h>
  19. #include <dns/rrset.h>
  20. #include <dns/rrttl.h>
  21. #include <boost/interprocess/offset_ptr.hpp>
  22. #include <boost/noncopyable.hpp>
  23. #include <stdint.h>
  24. namespace isc {
  25. namespace datasrc {
  26. namespace memory {
  27. class RdataEncoder;
  28. /// \brief General error on creating RdataSet.
  29. ///
  30. /// This is thrown when creating \c RdataSet encounters a rare, unsupported
  31. /// situation.
  32. class RdataSetError : public Exception {
  33. public:
  34. RdataSetError(const char* file, size_t line, const char* what) :
  35. Exception(file, line, what) {}
  36. };
  37. /// \brief Memory-efficient representation of RRset data with RRSIGs.
  38. ///
  39. /// This class provides memory-efficient and lightweight interface to various
  40. /// attributes of an RRset, which may or may not be signed with RRSIGs.
  41. ///
  42. /// This class is primarily intended to be used in the in-memory data source
  43. /// implementation, and is not supposed to be used by general applications.
  44. /// The major design goals is to keep required memory footprint for the given
  45. /// amount of data as small as possible, while providing a reasonably
  46. /// efficient interface to examine the data, focusing on zone lookup and DNS
  47. /// message rendering.
  48. ///
  49. /// It encodes a specific set of RRset and (when signed) its RRSIGs, excluding
  50. /// the owner name and the RR class. The owner name is supposed to be
  51. /// maintained by the application outside this class (the intended place to
  52. /// store this information is a \c DomainTree node, although this
  53. /// implementation does not rely on that intent). The RR class must be the
  54. /// same in a single zone, and it's simply a waste if we have it with each
  55. /// RRset. The RR class information is therefore expected to be maintained
  56. /// outside this class.
  57. ///
  58. /// This class imposes some limitations on the number of RDATAs of the RRset
  59. /// and RRSIG: a (non RRSIG) RRset containing more than 8191 (2^13 - 1)
  60. /// or an RRSIG containing more than 65535 (2^16 - 1) RDATAs cannot be
  61. /// maintained in this class. The former restriction comes from the
  62. /// following observation: any RR in wire format in a DNS message must at
  63. /// least contain 10 bytes of data (for RR type, class, TTL and RDATA length),
  64. /// and since a valid DNS message must not be larger than 65535 bytes,
  65. /// no valid DNS response can contain more than 6554 RRs. So, in practice,
  66. /// it should be reasonable even if we reject very large RRsets that would
  67. /// not fit in a DNS message. For the same reason we restrict the number of
  68. /// RRSIGs, although due to internal implementation details the limitation
  69. /// is more relaxed for RRSIGs.
  70. ///
  71. /// \note (This is pure implementation details) By limiting the number of
  72. /// RDATAs so it will fit in a 13-bit integer, we can use 3 more bits in a
  73. /// 2-byte integer for other purposes. We use this additional field to
  74. /// represent the number of RRSIGs up to 6, while using the value of 7 to mean
  75. /// there are more than 6 RRSIGs. In the vast majority of real world
  76. /// deployment, an RRset should normally have only a few RRSIGs, and 6 should
  77. /// normally be more than sufficient. So we can cover most practical cases
  78. /// regarding the number of records with this 2-byte field.
  79. ///
  80. /// A set of objects of this class (which would be \c RdataSets of various
  81. /// types of the same owner name) will often be maintained in a single linked
  82. /// list. The class has a member variable to make the link.
  83. ///
  84. /// This class is designed so an instance can be stored in a shared
  85. /// memory region. So it only contains straightforward data (e.g., it
  86. /// doesn't hold a pointer to an object of some base class that
  87. /// contains virtual methods), and the pointer member (see the
  88. /// previous paragraph) is represented as an offset pointer. For the
  89. /// same reason this class should never have virtual methods (and as a
  90. /// result, should never be inherited in practice). When this class
  91. /// is extended these properties must be preserved.
  92. ///
  93. /// The \c RdataSet class itself only contains a subset of attributes that
  94. /// it is conceptually expected to contain. The rest of the attributes
  95. /// are encoded in a consecutive memory region immediately following the main
  96. /// \c RdataSet object. The memory layout would be as follows:
  97. /// \verbatim
  98. /// RdataSet object
  99. /// (optional) uint16_t: number of RRSIGs, if it's larger than 6 (see above)
  100. /// encoded RDATA (generated by RdataEncoder) \endverbatim
  101. ///
  102. /// This is shown here only for reference purposes. The application must not
  103. /// assume any particular format of data in this region directly; it must
  104. /// get access to it via public interfaces provided in the main \c RdataSet
  105. /// class.
  106. class RdataSet : boost::noncopyable {
  107. public:
  108. /// \brief Allocate and construct \c RdataSet
  109. ///
  110. /// This static method allocates memory for a new \c RdataSet
  111. /// object for the set of an RRset and (if it's supposed to be signed)
  112. /// RRSIG from the given memory segment, constructs the object, and
  113. /// returns a pointer to it.
  114. ///
  115. /// If the optional \c old_rdataset parameter is set to non NULL,
  116. /// the given \c RdataSet, RRset, RRSIG will be merged in the new
  117. /// \c Rdataset object: the new object will contain the union set of all
  118. /// RDATA and RRSIGs contained in these. Obviously \c old_rdataset
  119. /// must be previously generated for the same RRClass and RRType as those
  120. /// for the given RRsets; it's the caller's responsibility to ensure
  121. /// this condition. If it's not met the result will be undefined.
  122. /// No reference to \c old_rdataset is maintained in the newly
  123. /// returned \c RdataSet, so if the caller does not need \c
  124. /// old_rdataset anymore, it may be freed by the caller.
  125. ///
  126. /// In both cases, this method ensures the stored RDATA and RRSIG are
  127. /// unique. Any duplicate data (in the sense of the comparison in the
  128. /// form of canonical form of RRs as described in RFC4034) within RRset or
  129. /// RRSIG, or between data in \c old_rdataset and RRset/RRSIG will be
  130. /// unified.
  131. ///
  132. /// In general, the TTLs of the given data are expected to be the same.
  133. /// This is especially the case if the zone is signed (and RRSIG is given).
  134. /// However, if different TTLs are found among the given data, this
  135. /// method chooses the lowest one for the TTL of the resulting
  136. /// \c RdataSet. This is an implementation choice, but should be most
  137. /// compliant to the sense of Section 5.2 of RFC2181.
  138. ///
  139. /// Normally the (non RRSIG) RRset is given (\c rrset is not NULL) while
  140. /// its RRSIG (\c sig_rrset) may or may not be provided. But it's also
  141. /// expected that in some rare (mostly broken) cases there can be an RRSIG
  142. /// RR in a zone without having the covered RRset in the zone. To handle
  143. /// such cases, this class allows to only hold RRSIG, in which case
  144. /// \c rrset can be NULL. At least \c rrset or \c sig_rrset must be
  145. /// non NULL, however. Also, if non NULL, the RRset must not be empty,
  146. /// that is, it must contain at least one RDATA.
  147. ///
  148. /// The RR type of \c rrset must not be RRSIG; the RR type of \c sig_rrset
  149. /// must be RRSIG.
  150. ///
  151. /// When both \c rrset and \c sig_rrset are provided (both are non
  152. /// NULL), the latter must validly cover the former: the RR class
  153. /// must be identical; the type covered field of any RDATA of \c
  154. /// sig_rrset must be identical to the RR type of \c rrset. The owner
  155. /// name of these RRsets must also be identical, but this implementation
  156. /// doesn't require it because \c RdataSet itself does not rely on the
  157. /// owner name, and it should be pretty likely that this condition is met
  158. /// in the context where this class is used (and, name comparison is
  159. /// relatively expensive, and if we end up comparing them twice the
  160. /// overhead can be non negligible).
  161. ///
  162. /// If any of the above conditions isn't met, an isc::BadValue exception
  163. /// will be thrown; basically, there should be a bug in the caller if this
  164. /// happens.
  165. ///
  166. /// Due to implementation limitations, this class cannot contain more than
  167. /// 8191 RDATAs (after unifying duplicates) for the non RRISG RRset; also,
  168. /// it cannot contain more than 65535 RRSIGs. If the given RRset(s) fail
  169. /// to meet this condition, an \c RdataSetError exception will be thrown.
  170. ///
  171. /// This method ensures there'll be no memory leak on exception.
  172. /// But addresses allocated from \c mem_sgmt could be relocated if
  173. /// \c util::MemorySegmentGrown is thrown; the caller or its upper layer
  174. /// must be aware of that possibility and update any such addresses
  175. /// accordingly. On successful return, this method ensures there's no
  176. /// address relocation.
  177. ///
  178. /// \throw util::MemorySegmentGrown The memory segment has grown, possibly
  179. /// relocating data.
  180. /// \throw isc::BadValue Given RRset(s) are invalid (see the description)
  181. /// \throw RdataSetError Number of RDATAs exceed the limits
  182. /// \throw std::bad_alloc Memory allocation fails.
  183. ///
  184. /// \param mem_sgmt A \c MemorySegment from which memory for the new
  185. /// \c RdataSet is allocated.
  186. /// \param encoder The RDATA encoder to encode \c rrset and \c sig_rrset
  187. /// with the \c RdataSet to be created.
  188. /// \param rrset A (non RRSIG) RRset from which the \c RdataSet is to be
  189. /// created. Can be NULL if sig_rrset is not.
  190. /// \param sig_rrset An RRSIG RRset from which the \c RdataSet is to be
  191. /// created. Can be NULL if rrset is not.
  192. /// \param old_rdataset If non NULL, create RdataSet merging old_rdataset
  193. /// into given rrset and sig_rrset.
  194. ///
  195. /// \return A pointer to the created \c RdataSet.
  196. static RdataSet* create(util::MemorySegment& mem_sgmt,
  197. RdataEncoder& encoder,
  198. dns::ConstRRsetPtr rrset,
  199. dns::ConstRRsetPtr sig_rrset,
  200. const RdataSet* old_rdataset = NULL);
  201. /// \brief Destruct and deallocate \c RdataSet
  202. ///
  203. /// Note that this method needs to know the expected RR class of the
  204. /// \c RdataSet. This is because the destruction may depend on the
  205. /// internal data encoding that only \c RdataEncoder and \c RdataReader
  206. /// know, and they need to know the corresponding RR class and type to
  207. /// identify the internal data representation. Since \c RdataSet itself
  208. /// does not hold the class information, the caller needs to provide it.
  209. /// Obviously, this RR class must be identical to the RR class of \c rrset
  210. /// (when given) or of \c sig_rrset (when \c rrset isn't given) at the
  211. /// \c create() time.
  212. ///
  213. /// \throw none
  214. ///
  215. /// \param mem_sgmt The \c MemorySegment that allocated memory for
  216. /// \c node.
  217. /// \param rdataset A non NULL pointer to a valid \c RdataSet object
  218. /// \param rrclass The RR class of the \c RdataSet to be destroyed.
  219. /// that was originally created by the \c create() method (the behavior
  220. /// is undefined if this condition isn't met).
  221. static void destroy(util::MemorySegment& mem_sgmt, RdataSet* rdataset,
  222. dns::RRClass rrclass);
  223. /// \brief Find \c RdataSet of given RR type from a list (const version).
  224. ///
  225. /// This function is a convenient shortcut for commonly used operation of
  226. /// finding a given type of \c RdataSet from a linked list of them.
  227. ///
  228. /// It follows the linked list of \c RdataSet objects (via their \c next
  229. /// member) starting the given head, until it finds an object of the
  230. /// given RR type. If found, it returns a (bare) pointer to the object;
  231. /// if not found in the entire list, it returns NULL. The head pointer
  232. /// can be NULL, in which case this function will simply return NULL.
  233. ///
  234. /// By default, this method ignores an RdataSet that only contains an
  235. /// RRSIG (i.e., missing the covered RdataSet); if the optional
  236. /// sigonly_ok parameter is explicitly set to true, it matches such
  237. /// RdataSet and returns it if found.
  238. ///
  239. /// \note This function is defined as a (static) class method to
  240. /// clarify its an operation for \c RdataSet objects and to make the
  241. /// name shorter. But its implementation does not depend on private
  242. /// members of the class, and it should be kept if and when this method
  243. /// needs to be extended, unless there's a reason other than simply
  244. /// because it's already a member function.
  245. ///
  246. /// \param rdata_head A pointer to \c RdataSet from which the search
  247. /// starts. It can be NULL.
  248. /// \param type The RRType of \c RdataSet to find.
  249. /// \param sigonly_ok Whether it should find an RdataSet that only has
  250. /// RRSIG
  251. /// \return A pointer to the found \c RdataSet or NULL if none found.
  252. static const RdataSet*
  253. find(const RdataSet* rdataset_head, const dns::RRType& type,
  254. bool sigonly_ok = false)
  255. {
  256. return (find<const RdataSet>(rdataset_head, type, sigonly_ok));
  257. }
  258. /// \brief Find \c RdataSet of given RR type from a list (non const
  259. /// version).
  260. ///
  261. /// This is similar to the const version, except it takes and returns non
  262. /// const pointers.
  263. static RdataSet*
  264. find(RdataSet* rdataset_head, const dns::RRType& type,
  265. bool sigonly_ok = false)
  266. {
  267. return (find<RdataSet>(rdataset_head, type, sigonly_ok));
  268. }
  269. typedef boost::interprocess::offset_ptr<RdataSet> RdataSetPtr;
  270. typedef boost::interprocess::offset_ptr<const RdataSet> ConstRdataSetPtr;
  271. // Note: the size and order of the members are carefully chosen to
  272. // maximize efficiency. Don't change them unless there's strong reason
  273. // for that and the consequences are considered.
  274. // For convenience (and since this class is mostly intended to be an
  275. // internal definition for the in-memory data source implementation),
  276. // we allow the application to get access to some members directly.
  277. // Some others require some conversion to use in a meaningful way,
  278. // for which we force the application to use accessor methods in order
  279. // to prevent misuse.
  280. RdataSetPtr next; ///< Pointer to the next \c RdataSet (when linked)
  281. const dns::RRType type; ///< The RR type of the \c RdataSet
  282. private:
  283. const uint16_t sig_rdata_count_ : 3; // # of RRSIGs, up to 6 (7 means many)
  284. const uint16_t rdata_count_ : 13; // # of RDATAs, up to 8191
  285. const uint32_t ttl_; // TTL of the RdataSet, net byte order
  286. // Max number of normal RDATAs that can be stored in \c RdataSet.
  287. // It's 2^13 - 1 = 8191.
  288. static const size_t MAX_RDATA_COUNT = (1 << 13) - 1;
  289. // Max number of RRSIGs that can be stored in \c RdataSet.
  290. // It's 2^16 - 1 = 65535.
  291. static const size_t MAX_RRSIG_COUNT = (1 << 16) - 1;
  292. // Indicate the \c RdataSet contains many RRSIGs that require an additional
  293. // field for the real number of RRSIGs. It's 2^3 - 1 = 7.
  294. static const size_t MANY_RRSIG_COUNT = (1 << 3) - 1;
  295. public:
  296. /// \brief Return the bare pointer to the next node.
  297. ///
  298. /// In such an operation as iterating over a linked list of \c RdataSet
  299. /// object, using this method is generally more efficient than using
  300. /// the \c next member directly because it prevents unintentional
  301. /// creation of offset pointer objects. While the application can
  302. /// get the same result by directly calling get() on \c next, it would
  303. /// help encourage the use of more efficient usage if we provide an
  304. /// explicit accessor.
  305. const RdataSet* getNext() const { return (next.get()); }
  306. /// \brief Return the bare pointer to the next node, mutable version.
  307. RdataSet* getNext() { return (next.get()); }
  308. /// \brief Return the number of RDATAs stored in the \c RdataSet.
  309. size_t getRdataCount() const { return (rdata_count_); }
  310. /// \brief Return the number of RRSIG RDATAs stored in the \c RdataSet.
  311. size_t getSigRdataCount() const {
  312. if (sig_rdata_count_ < MANY_RRSIG_COUNT) {
  313. return (sig_rdata_count_);
  314. } else {
  315. return (*getExtSIGCountBuf());
  316. }
  317. }
  318. /// \brief Return a pointer to the TTL data of the \c RdataSet.
  319. ///
  320. /// The returned pointer points to a memory region that is valid at least
  321. /// for 32 bits, storing the TTL of the \c RdataSet in the network byte
  322. /// order. It returns opaque data to make it clear that unless the wire
  323. /// format data is necessary (e.g., when rendering it in a DNS message),
  324. /// it should be converted to, e.g., an \c RRTTL object explicitly.
  325. ///
  326. /// \throw none
  327. const void* getTTLData() const { return (&ttl_); }
  328. /// \brief Accessor to the memory region for encoded RDATAs.
  329. ///
  330. /// The only valid usage of the returned pointer is to pass it to
  331. /// the constructor of \c RdataReader.
  332. ///
  333. /// \throw none
  334. const void* getDataBuf() const {
  335. return (getDataBuf<const void, const RdataSet>(this));
  336. }
  337. private:
  338. /// \brief Accessor to the memory region for encoded RDATAs, mutable
  339. /// version.
  340. ///
  341. /// This version is only used within the class implementation, so it's
  342. /// defined as private.
  343. void* getDataBuf() {
  344. return (getDataBuf<void, RdataSet>(this));
  345. }
  346. // Implementation of getDataBuf(). Templated to unify the mutable and
  347. // immutable versions.
  348. template <typename RetType, typename ThisType>
  349. static RetType* getDataBuf(ThisType* rdataset) {
  350. if (rdataset->sig_rdata_count_ < MANY_RRSIG_COUNT) {
  351. return (rdataset + 1);
  352. } else {
  353. return (rdataset->getExtSIGCountBuf() + 1);
  354. }
  355. }
  356. /// \brief Accessor to the memory region for the RRSIG count field for
  357. /// a large number of RRSIGs.
  358. ///
  359. /// These are used only internally and defined as private.
  360. const uint16_t* getExtSIGCountBuf() const {
  361. return (reinterpret_cast<const uint16_t*>(this + 1));
  362. }
  363. uint16_t* getExtSIGCountBuf() {
  364. return (reinterpret_cast<uint16_t*>(this + 1));
  365. }
  366. // Shared by both mutable and immutable versions of find()
  367. template <typename RdataSetType>
  368. static RdataSetType*
  369. find(RdataSetType* rdataset_head, const dns::RRType& type, bool sigonly_ok)
  370. {
  371. for (RdataSetType* rdataset = rdataset_head;
  372. rdataset != NULL;
  373. rdataset = rdataset->getNext()) // use getNext() for efficiency
  374. {
  375. if (rdataset->type == type &&
  376. (rdataset->getRdataCount() > 0 || sigonly_ok)) {
  377. return (rdataset);
  378. }
  379. }
  380. return (NULL);
  381. }
  382. /// \brief The constructor.
  383. ///
  384. /// An object of this class is always expected to be created by the
  385. /// allocator (\c create()), so the constructor is hidden as private.
  386. ///
  387. /// It never throws an exception.
  388. RdataSet(dns::RRType type, size_t rdata_count, size_t sig_rdata_count,
  389. dns::RRTTL ttl);
  390. /// \brief The destructor.
  391. ///
  392. /// An object of this class is always expected to be destroyed explicitly
  393. /// by \c destroy(), so the destructor is hidden as private.
  394. ///
  395. /// This currently does nothing, but is explicitly defined to clarify
  396. /// it's intentionally defined as private.
  397. ~RdataSet() {}
  398. };
  399. } // namespace memory
  400. } // namespace datasrc
  401. } // namespace isc
  402. #endif // DATASRC_MEMORY_RDATASET_H
  403. // Local Variables:
  404. // mode: c++
  405. // End: