rdata_serialization.h 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  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_RDATA_ENCODER_H
  15. #define DATASRC_MEMORY_RDATA_ENCODER_H 1
  16. #include <exceptions/exceptions.h>
  17. #include <dns/labelsequence.h>
  18. #include <dns/rdata.h>
  19. #include <dns/rrclass.h>
  20. #include <dns/rrtype.h>
  21. #include <boost/function.hpp>
  22. #include <boost/noncopyable.hpp>
  23. /// \file rdata_serialization.h
  24. ///
  25. /// This file defines a set of interfaces (classes, types, constants) to
  26. /// manipulate a given set of RDATA of the same type (normally associated with
  27. /// an RRset) that may be accompanied with RRSIGs in a memory efficient way.
  28. ///
  29. /// The entire set of RDATA is stored in a packed form in a contiguous
  30. /// memory region. It's opaque data, without containing non trivial
  31. /// data structures, so it can be located anywhere in the memory or even
  32. /// dumped to a file.
  33. ///
  34. /// Two main classes are provided: one is
  35. /// \c isc::datasrc::memory::RdataEncoder, which allows
  36. /// the application to create encoded data for a set of RDATA;
  37. /// the isc::datasrc::memory::RdataReader provides an interface to iterate
  38. /// over encoded set of RDATA for purposes such as data lookups or rendering
  39. /// the data into the wire format to create a DNS message.
  40. ///
  41. /// The actual encoding detail is private information to the implementation,
  42. /// and the application shouldn't assume anything about that except that
  43. /// each RDATA is considered to consist of one or more generic fields,
  44. /// and each field is typed as either opaque data or a domain name.
  45. /// A domain name field has additional attributes
  46. /// (see \c isc::datasrc::memory::RdataNameAttributes)
  47. /// so the application can change how the name should be handled in terms
  48. /// of the DNS protocol (e.g., whether it's subject to name compression).
  49. ///
  50. /// The following are the current implementation of internal encoding, shown
  51. /// only for reference. Applications must not assume this particular form
  52. /// for the encoded data; in fact, it can change in a future version of the
  53. /// implementation.
  54. /// \verbatim
  55. // The encoded data begin with a series of 16-bit length fields (values are
  56. // stored in the host byte order). The sequence may be empty.
  57. // uint16_t n1_1: size of 1st variable len field (if any) of 1st RDATA
  58. // uint16_t n1_2: size of 2nd variable len field of 1st RDATA
  59. // ...
  60. // uint16_t nN_M: size of last (Mth) variable len field of last (Nth) RDATA
  61. // uint16_t ns1: size of 1st RRSIG (if any) data
  62. // ...
  63. // uint16_t nsL: size of last (Lth) RRSIG data
  64. // A sequence of packed data fields follows:
  65. // uint8_t[]: data field value, length specified by nI_J (in case it's
  66. // variable-length) or by the per type field spec (in case it's
  67. // fixed-length).
  68. // or
  69. // opaque data, LabelSequence::getSerializedLength() bytes: data for a name
  70. // uint8_t[ns1]: 1st RRSIG data
  71. // ...
  72. // uint8_t[nsL]: last RRSIG data
  73. // \endverbatim
  74. ///
  75. /// As described above, this implementation treats RRSIGs as opaque data
  76. /// that don't contain any domain names. Technically, it has a "signer"
  77. /// domain name field in the sense of RFC4034. In practice, however, this
  78. /// field is essentially mere data; it's not subject to name compression,
  79. /// and since it's very likely to be a subdomain of (or equal to) the
  80. /// owner name of the corresponding RR (or, if used in a DNS message,
  81. /// some domain name that already appears before this field), so it won't
  82. /// be a target of name compression either. By treating the entire RRSIG
  83. /// as single-field data we can make the implementation simpler, and probably
  84. /// make it faster in rendering it into a DNS message.
  85. namespace isc {
  86. namespace datasrc {
  87. namespace memory {
  88. /// \brief General error in RDATA encoding.
  89. ///
  90. /// This is thrown when \c RdataEncoder encounters a rare, unsupported
  91. /// situation.
  92. class RdataEncodingError : public Exception {
  93. public:
  94. RdataEncodingError(const char* file, size_t line, const char* what) :
  95. Exception(file, line, what) {}
  96. };
  97. /// \brief RDATA encoder.
  98. ///
  99. /// This class provides interfaces to encode a set of RDATA of a specific
  100. /// RR class and type, possibly with their RRSIG RDATAs, in a memory-efficient
  101. /// format. In many cases these sets of RDATA come from a specific (signed
  102. /// or unsigned) RRset.
  103. ///
  104. /// It is expected for a single \c RdataEncoder object to be used multiple
  105. /// times for different sets of RDATA, such as in loading an entire zone
  106. /// into memory. Each encoding session begins with the \c start() method,
  107. /// which sets the context for the specific RR class and type to be encoded.
  108. /// Any number of calls to \c addRdata() or \c addSIGRdata() follow, each
  109. /// of which updates the internal state of the encoder with the encoding
  110. /// information for the given RDATA or RRSIG RDATA, respectively.
  111. /// The \c addRdata() is expected to be called with an
  112. /// \c isc::dns::rdata::Rdata object
  113. /// of the specified class and type, and \c addRdata() checks the consistency
  114. /// for the purpose of encoding (but it's not completely type safe; for
  115. /// example, it wouldn't distinguish TXT RDATA and HINFO RDATA.
  116. /// Likewise, an \c isc::dns::rdata::Rdata given to \c addSIGRdata() is
  117. /// expected to be of RRSIG, but the method does not check the assumption).
  118. ///
  119. /// After passing the complete set of RDATA and their RRSIG, the application
  120. /// is expected to call \c getStorageLength() to know the size of storage
  121. /// that is sufficient to store all encoded data. Normally the application
  122. /// would allocate a memory region of that size, and then call \c encode()
  123. /// with the prepared region. The \c encode() method dumps encoded data
  124. /// to the given memory region.
  125. ///
  126. /// The caller can reuse the \c RdataEncoder object for another set of RDATA
  127. /// by repeating the session from \c start().
  128. class RdataEncoder : boost::noncopyable {
  129. public:
  130. /// \brief Default constructor.
  131. RdataEncoder();
  132. /// \brief The destrcutor.
  133. ~RdataEncoder();
  134. /// \brief Start the encoding session.
  135. ///
  136. /// It re-initializes the internal encoder state for a new encoding
  137. /// session. The \c rrclass and \c rrtype parameters specify the
  138. /// type of RDATA to be encoded in the new session. Note that if the
  139. /// set of RDATA is signed, \c rrtype always specifies the "signed" type;
  140. /// it must not be RRSIG.
  141. ///
  142. /// \throw BadValue RRSIG is specified for rrtype.
  143. ///
  144. /// \param rrclass The RR class of RDATA to be encoded in the session.
  145. /// \param rrtype The RR type of RDATA to be encoded in the session.
  146. void start(dns::RRClass rrclass, dns::RRType rrtype);
  147. /// \brief Start the encoding session in the merge mode.
  148. ///
  149. /// This method is similar to the other version, but begins with a copy
  150. /// of previously encoded data and merges Rdata and RRSIGs into it
  151. /// that will be given via subsequent calls to \c addRdata() and
  152. /// \c addSIGRdata(). \c old_data, \c old_rdata_count, and
  153. /// \c old_sig_count correspond to parameters given to the
  154. /// \c RdataReader constructor, and must have valid values for encoded
  155. /// data by this class for the same \c rrclass and \c rrtype.
  156. /// It's the caller's responsibility to ensure this condition; if it's
  157. /// not met, the behavior will be undefined.
  158. ///
  159. /// The caller must also ensure that previously encoded data (pointed
  160. /// to by \c old_data) will be valid and intact throughout the encoding
  161. /// session started by this method. The resulting encoded data (by
  162. /// \c encode()) won't refer to the previous data, so once encoding the
  163. /// merged data is completed (and unless this encoding session continues
  164. /// for another attempt of encoding, which is unlikely), the caller can
  165. /// modify or destroy the old data.
  166. ///
  167. /// The caller must also ensure that \c old_data don't contain any
  168. /// duplicate Rdata or RRSIG. Normally the caller doesn't have to do
  169. /// anything special to meet this requirement, though, as the data
  170. /// should have been generated by an \c RdataEncoder object before,
  171. /// which guarantees that condition. But this method checks the
  172. /// assumption in case it was crafted or otherwise broken data, and
  173. /// throws an exception if that is the case.
  174. ///
  175. /// \throw Unexpected Given encoded data contain duplicate Rdata or RRSIG
  176. /// (normally shouldn't happen, see the description).
  177. ///
  178. /// \param rrclass The RR class of RDATA to be encoded in the session.
  179. /// \param rrtype The RR type of RDATA to be encoded in the session.
  180. /// \param old_data Point to previously encoded data for the same RR
  181. /// class and type.
  182. /// \param old_rdata_count The number of RDATAs stored in \c old_data.
  183. /// \param old_sig_count The number of RRSIGs stored in \c old_data.
  184. void start(dns::RRClass rrclass, dns::RRType rrtype,
  185. const void* old_data, size_t old_rdata_count,
  186. size_t old_sig_count);
  187. /// \brief Add an RDATA for encoding.
  188. ///
  189. /// This method updates internal state of the \c RdataEncoder() with the
  190. /// given RDATA so it will be part of the encoded data in a subsequent
  191. /// call to \c encode().
  192. ///
  193. /// The given \c rdata must be of the RR class and type specified at
  194. /// the prior call to \c start(). This method checks the assumption
  195. /// to some extent, but the check is not complete; this is generally
  196. /// the responsibility of the caller.
  197. ///
  198. /// This method checks if the given RDATA is a duplicate of already
  199. /// added one (including ones encoded in the old data if the session
  200. /// began with the merge mode). If it's a duplicate this method ignores
  201. /// the given RDATA and returns false; otherwise it returns true.
  202. /// The check is based on the comparison in the "canonical form" as
  203. /// described in RFC4034 Section 6.2. In particular, domain name fields
  204. /// of the RDATA are generally compared in case-insensitive manner.
  205. ///
  206. /// The caller can destroy \c rdata after this call is completed.
  207. ///
  208. /// \note This implementation does not support RDATA (or any subfield of
  209. /// it) whose size exceeds 65535 bytes (max uint16_t value). Such RDATA
  210. /// may not necessarily be considered invalid in terms of protocol
  211. /// specification, but in practice it's mostly useless because the
  212. /// corresponding RR won't fit in any valid DNS message.
  213. ///
  214. /// As long as the \c rdata is of the correct type and its size is normal,
  215. /// this method should normally be exception free. If it throws, however,
  216. /// it doesn't always provide the strong exception guarantee. In general,
  217. /// the caller needs to either destroy the encoder object or restart a
  218. /// new session from \c start() should this method throws an exception.
  219. ///
  220. /// \throw InvalidOperation called before start().
  221. /// \throw std::bad_cast The given Rdata is of different RR type.
  222. /// \throw RdataEncodingError A very unusual case, such as over 64KB RDATA.
  223. /// \throw std::bad_alloc Internal memory allocation failure.
  224. ///
  225. /// \param rdata An RDATA to be encoded in the session.
  226. /// \return true if the given RDATA was added to encode; false if
  227. /// it's a duplicate and ignored.
  228. bool addRdata(const dns::rdata::Rdata& rdata);
  229. /// \brief Add an RRSIG RDATA for encoding.
  230. ///
  231. /// This method updates internal state of the \c RdataEncoder() with the
  232. /// given RDATA, which is assumed to be of type RRSIG that covers the
  233. /// type specified at the time of \c start() for the encoding session.
  234. /// The corresponding data for the RRSIG RDATA will be encoded in a
  235. /// subsequent call to \c encode().
  236. ///
  237. /// The passed \c sig_rdata is expected to be of type RRSIG and cover
  238. /// the RR type specified at the call to \c start() to this encoding
  239. /// session. But this method does not check if it is the case at all;
  240. /// it could even accept any type of RDATA as opaque data. It's caller's
  241. /// responsibility to ensure the assumption.
  242. ///
  243. /// This method checks if the given RRSIG RDATA is a duplicate of already
  244. /// added one (including ones encoded in the old data if the session
  245. /// began with the merge mode). If it's a duplicate this method ignores
  246. /// the given RRSIG and returns false; otherwise it returns true.
  247. /// The check is based on the comparison in the "canonical form" as
  248. /// described in RFC4034 Section 6.2.
  249. ///
  250. /// The caller can destroy \c rdata after this call is completed.
  251. ///
  252. /// \note Like addRdata(), this implementation does not support
  253. /// RRSIG RDATA whose size (in the form of wire format) exceeds 65535
  254. /// bytes.
  255. ///
  256. /// The same note about exception safety as \c addRdata() applies.
  257. ///
  258. /// \throw InvalidOperation called before start().
  259. /// \throw RdataEncodingError A very unusual case, such as over 64KB RDATA.
  260. /// \throw std::bad_alloc Internal memory allocation failure.
  261. ///
  262. /// \param sig_rdata An RDATA to be encoded in the session. Supposed to
  263. /// be of type RRSIG.
  264. /// \return true if the given RRSIG RDATA was added to encode; false if
  265. /// it's a duplicate and ignored.
  266. bool addSIGRdata(const dns::rdata::Rdata& sig_rdata);
  267. /// \brief Return the length of space for encoding for the session.
  268. ///
  269. /// It returns the size of the encoded data that would be generated for
  270. /// the set of RDATA (and RRSIGs) in the encoder at the call of this
  271. /// method. It's ensured that a buffer of that size can be safely passed
  272. /// to \c encode() unless there's no other "add" method is called by then.
  273. ///
  274. /// As long as this method is called after start(), it never throws.
  275. ///
  276. /// \throw InvalidOperation called before start().
  277. ///
  278. /// \return The expected size of the encoded data at the time of the call.
  279. size_t getStorageLength() const;
  280. /// \brief Encode RDATAs of the session to a buffer.
  281. ///
  282. /// This method dumps encoded data for the stored set of RDATA and
  283. /// their RRSIGs to a given buffer. The buffer must have a size
  284. /// at least as large as the return value of a prior call to
  285. /// \c getStorageLength() (it may be larger than that).
  286. ///
  287. /// The given buffer must be aligned at the natural boundary for
  288. /// 16-bit integers. The method doesn't check this condition; it's
  289. /// caller's responsibility to ensure that. Note: the alignment
  290. /// requirement may change in a future version of this implementation.
  291. ///
  292. /// As long as this method is called after start() and the buffer is
  293. /// valid with a sufficient size, this method never throws.
  294. ///
  295. /// \throw InvalidOperation called before start().
  296. /// \throw BadValue buffer is NULL or it's too short for the encoded data.
  297. ///
  298. /// \param buf A pointer to the buffer to which encoded data are to be
  299. /// dumped.
  300. /// \param buf_len The size of the buffer in bytes.
  301. void encode(void* buf, size_t buf_len) const;
  302. private:
  303. struct RdataEncoderImpl;
  304. RdataEncoderImpl* impl_;
  305. };
  306. /// \brief Attributes of domain name fields of encoded RDATA.
  307. ///
  308. /// The enum values define special traits of the name that can affect how
  309. /// it should be handled in rendering or query processing.
  310. enum RdataNameAttributes {
  311. NAMEATTR_NONE = 0, ///< No special attributes
  312. NAMEATTR_COMPRESSIBLE = 1, ///< Name should be compressed when rendered
  313. NAMEATTR_ADDITIONAL = (NAMEATTR_COMPRESSIBLE << 1) ///< Name requires
  314. ///< Additional section
  315. ///< handling
  316. };
  317. // forward declaration, defined in a private implementation file.
  318. struct RdataEncodeSpec;
  319. /// \brief Class to read serialized rdata
  320. ///
  321. /// This class allows you to read the data encoded by RdataEncoder.
  322. /// It is rather low-level -- it provides sequence of data fields.
  323. /// Each field is either opaque data, passed as a pointer and length,
  324. /// or a name, in the form of dns::LabelSequence (which is always
  325. /// absolute) and attributes.
  326. ///
  327. /// Conceptually, these fields correspond to consecutive regions in
  328. /// wire-format representation of the RDATA, varying the type of above
  329. /// two cases depending on whether the region corresponds to a domain
  330. /// name or other data. For example, for an MX RDATA the field
  331. /// sequence will be
  332. /// - 2 bytes of opaque data (which corresponds to the MX preference)
  333. /// - a domain name (which corresponds to the MX name)
  334. ///
  335. /// If the encoded data contain multiple MX RDATAs, the same type of
  336. /// sequence continues for the number of RDATAs. Note that the opaque
  337. /// data field does not always corresponds to a specific RDATA field
  338. /// as is the 2-byte preference field of MX. For example, the field
  339. /// sequence for an SOA RDATA in terms of RdataEncoder will be:
  340. /// - a domain name (which corresponds to the SOA MNAME)
  341. /// - a domain name (which corresponds to the SOA RNAME)
  342. /// - 20 bytes of opaque data (for the rest of fields)
  343. ///
  344. /// So, if you want to construct a general purpose dns::Rdata object
  345. /// from the field sequence, you'll need to build the complete
  346. /// wire-format data, and then construct a dns::Rdata object from it.
  347. ///
  348. /// To use it, construct it with the data you got from RDataEncoder,
  349. /// provide it with callbacks and then iterate through the data.
  350. /// The callbacks are called with the data fields contained in the
  351. /// data.
  352. ///
  353. /// \code
  354. /// void handleName(const dns::LabelSequence& labels, unsigned int flags) {
  355. /// ...
  356. /// }
  357. /// void handleData(const void* data, size_t size) {
  358. /// ...
  359. /// }
  360. ///
  361. /// RdataReader reader(RRClass::IN(), RRType::AAAA(), size, data,
  362. /// rdata_count, sig_count, &handleName, &handleData);
  363. /// reader.iterate();
  364. /// \endcode
  365. ///
  366. /// If you need to do the iteration per RDATA basis rather than per data field
  367. /// basis, you can use \c iterateRdata() as follows:
  368. ///
  369. /// \code
  370. /// for (size_t i = 0; i < rdata_count; ++i)
  371. /// // maybe do something related to this RDATA
  372. /// reader.iterateRdata(); // specified actions called for this RDATA
  373. /// // maybe do some other thing related to this RDATA
  374. /// }
  375. /// if (reader.iterateRdata()) {
  376. /// isc_throw(Unexpected, "Inconsistent data");
  377. /// }
  378. /// \endcode
  379. ///
  380. /// The check after the loop is primarily for consistency
  381. /// validation, but it would also help a possible subsequent call
  382. /// to \c iterateAllSigs() if you also want to iterate over RRSIGs;
  383. /// the final call to \c iterateRdata() updates the internal state of the
  384. /// reader object so \c iterateAllSigs() can find the RRSIG data more
  385. /// efficiently. \c iterateAllSigs() will work correctly even with out
  386. /// this small optimization, but checking the consistency is a good practice
  387. /// anyway, and the optimization is an additional bonus.
  388. ///
  389. /// \note It is caller's responsibility to pass valid data here. This means
  390. /// the data returned by RdataEncoder and the corresponding class and type.
  391. /// If this is not the case, all the kinds of pointer hell might get loose.
  392. class RdataReader {
  393. public:
  394. /// \brief Function called on each name encountered in the data.
  395. typedef boost::function<void(const dns::LabelSequence&,
  396. RdataNameAttributes)> NameAction;
  397. /// \brief Function called on each data field in the data.
  398. typedef boost::function<void(const void*, size_t)> DataAction;
  399. /// \brief An NameAction that does intentionally nothing.
  400. ///
  401. /// This static method can be used as the name action parameter to
  402. /// construct \c RdataReader when the caller does not have to anything
  403. /// for name fields.
  404. static void emptyNameAction(const dns::LabelSequence&,
  405. RdataNameAttributes);
  406. /// \brief An DataAction that does intentionally nothing.
  407. ///
  408. /// This static method can be used as the data action parameter to
  409. /// construct \c RdataReader when the caller does not have to anything
  410. /// for opaque data fields.
  411. static void emptyDataAction(const void*, size_t);
  412. /// \brief Constructor
  413. ///
  414. /// This constructs the reader on top of some serialized data.
  415. /// It does not copy the data, you have to make sure the data
  416. /// is valid for the whole life of this object and that they
  417. /// don't change.
  418. ///
  419. /// \param rrclass The class the encoded rdata belongs to.
  420. /// \param rrtype The type of the encode rdata.
  421. /// \param data The actual data.
  422. /// \param rdata_count The number of Rdata encoded in the data.
  423. /// \param sig_count The number of RRSig rdata bundled with the data.
  424. /// \param name_action The callback to be called on each encountered name.
  425. /// \param data_action The callback to be called on each data chunk.
  426. RdataReader(const dns::RRClass& rrclass, const dns::RRType& rrtype,
  427. const void* data, size_t rdata_count, size_t sig_count,
  428. const NameAction& name_action, const DataAction& data_action);
  429. /// \brief Result of next() and nextSig()
  430. ///
  431. /// This specifies if there's any boundary in the data at the
  432. /// place where the corresponding call to next() or nextSig()
  433. /// finished.
  434. enum Boundary {
  435. NO_BOUNDARY, ///< It is in the middle of Rdata
  436. RDATA_BOUNDARY, ///< At the end of single Rdata
  437. RRSET_BOUNDARY ///< At the end of the RRset (past the end)
  438. };
  439. /// \brief Step to next data field.
  440. ///
  441. /// Iterate over the next field and call appropriate hook (name_action
  442. /// or data_action, depending on the type) as passed to the constructor.
  443. ///
  444. /// \return It returns NO_BOUNDARY if the next call to next() will process
  445. /// data of the same rdata as this one. RDATA_BOUNDARY is returned when
  446. /// this field is the last of the current rdata. If there are no more
  447. /// data to process, no hook is called and RRSET_BOUNDARY is returned.
  448. /// Therefore, at the end of the whole data, once it processes the last
  449. /// field and returns RDATA_BOUNDARY and then it returns RRSET_BOUNDARY
  450. /// on the next call.
  451. Boundary next();
  452. /// \brief Call next() until the end.
  453. ///
  454. /// This is just convenience method to iterate through all the data.
  455. /// It calls next until it reaches the end (it does not rewind beforehand,
  456. /// therefore if you already called next() yourself, it does not start
  457. /// at the beginning).
  458. void iterate() {
  459. while (nextInternal(name_action_, data_action_) != RRSET_BOUNDARY) {}
  460. }
  461. /// \brief Call next() until the end of current rdata.
  462. ///
  463. /// This is a convenience method to iterate until the end of current
  464. /// rdata. Notice this may cause more than one field being processed,
  465. /// as some rrtypes are more complex.
  466. ///
  467. /// \return If there was Rdata to iterate through.
  468. bool iterateRdata() {
  469. while (true) {
  470. switch (nextInternal(name_action_, data_action_)) {
  471. case NO_BOUNDARY: break;
  472. case RDATA_BOUNDARY: return (true);
  473. case RRSET_BOUNDARY: return (false);
  474. }
  475. }
  476. }
  477. /// \brief Step to next field of RRSig data.
  478. ///
  479. /// This is almost the same as next(), but it iterates through the
  480. /// associated RRSig data, not the data for the given RRType.
  481. Boundary nextSig();
  482. /// \brief Iterate through all RRSig data.
  483. ///
  484. /// This is almost the same as iterate(), but it iterates through the
  485. /// RRSig data instead.
  486. void iterateAllSigs() {
  487. while (nextSig() != RRSET_BOUNDARY) {}
  488. }
  489. /// \brief Iterate through the current RRSig Rdata.
  490. ///
  491. /// This is almote the same as iterateRdata, except it is for single
  492. /// signature Rdata.
  493. ///
  494. /// In practice, this should process one DATA field.
  495. bool iterateSingleSig() {
  496. while (true) {
  497. switch (nextSig()) {
  498. case NO_BOUNDARY:
  499. isc_throw(isc::Unexpected, "NO_BOUNDARY inside an RRSig. "
  500. "Data corruption? Bug inside RdataReader?");
  501. case RDATA_BOUNDARY: return (true);
  502. case RRSET_BOUNDARY: return (false);
  503. }
  504. }
  505. }
  506. /// \brief Rewind the iterator to the beginning of data.
  507. ///
  508. /// The following next() and nextSig() will start iterating from the
  509. /// beginning again.
  510. void rewind();
  511. /// \brief Returns the size of associated data.
  512. ///
  513. /// This should be the same as the return value of
  514. /// RdataEncoder::getStorageLength() for the same set of data.
  515. /// The intended use of this method is to tell the caller the size of
  516. /// data that were possibly dynamically allocated so that the caller can
  517. /// use it for deallocation.
  518. ///
  519. /// This method only uses the parameters given at the construction of the
  520. /// object, and does not rely on or modify other mutable states.
  521. /// In practice, when the caller wants to call this method, that would be
  522. /// the only purpose of that RdataReader object (although it doesn't have
  523. /// to be so).
  524. size_t getSize() const;
  525. private:
  526. const NameAction name_action_;
  527. const DataAction data_action_;
  528. const RdataEncodeSpec& spec_;
  529. // Total number of var-length fields, count of signatures
  530. const size_t var_count_total_, sig_count_, spec_count_;
  531. // Pointer to the beginning of length fields
  532. const uint16_t* const lengths_;
  533. // Pointer to the beginning of the data (after the lengths)
  534. const uint8_t* const data_;
  535. // Pointer to the first data signature
  536. // Will be computed during the normal RR iteration
  537. const uint8_t* sigs_;
  538. // The positions in data.
  539. size_t data_pos_, spec_pos_, length_pos_;
  540. size_t sig_pos_, sig_data_pos_;
  541. Boundary nextInternal(const NameAction& name_action,
  542. const DataAction& data_action);
  543. };
  544. } // namespace memory
  545. } // namespace datasrc
  546. } // namespace isc
  547. #endif // DATASRC_MEMORY_RDATA_ENCODER_H
  548. // Local Variables:
  549. // mode: c++
  550. // End: