|
@@ -18,51 +18,178 @@
|
|
|
#include <boost/function.hpp>
|
|
|
|
|
|
namespace isc {
|
|
|
+// Some forward declarations
|
|
|
namespace dns{
|
|
|
class LabelSequence;
|
|
|
class RRClass;
|
|
|
class RRType;
|
|
|
}
|
|
|
+
|
|
|
namespace datasrc {
|
|
|
namespace memory {
|
|
|
|
|
|
+/// \brief Class to read serialized rdata
|
|
|
+///
|
|
|
+/// This class allows you to read the data encoded by RDataEncoder.
|
|
|
+/// It is rather low-level -- it provides sequence of data fields
|
|
|
+/// and names. It does not give you convenient Rdata or RRset class.
|
|
|
+///
|
|
|
+/// It allows two types of operation. First one is by providing callbacks
|
|
|
+/// to the constructor and then iterating by repeatedly calling next, or
|
|
|
+/// calling iterate once. The callbacks are then called with each part of
|
|
|
+/// the data.
|
|
|
+///
|
|
|
+/// \code
|
|
|
+/// void handleLabel(const dns::LabelSequence& label, unsigned int flags) {
|
|
|
+/// ...
|
|
|
+/// }
|
|
|
+/// void handleData(const uint8_t* data, size_t size) {
|
|
|
+/// ...
|
|
|
+/// }
|
|
|
+///
|
|
|
+/// RDataReader reader(RRClass::IN(), RRType::AAAA(), size, data,
|
|
|
+/// &handleLabel, handleData);
|
|
|
+/// reader.iterate();
|
|
|
+/// \endcode
|
|
|
+///
|
|
|
+/// The other way is to use the return value of next() and loop through
|
|
|
+/// it manually. It has the inconvenience of having the type condition, but
|
|
|
+/// the code is in one place. The used way is matter of personal preferrence,
|
|
|
+/// there's no much difference on the technical side.
|
|
|
+///
|
|
|
+/// \code
|
|
|
+/// RDataReader reader(RRClass::IN(), RRType::AAAA(), size, data,
|
|
|
+/// &handleLabel, handleData);
|
|
|
+/// RDataReader::Result data;
|
|
|
+/// while (data = reader.next()) {
|
|
|
+/// switch(data.type()) {
|
|
|
+/// case RDataReader::NAME:
|
|
|
+/// ...
|
|
|
+/// break;
|
|
|
+/// case RDataReader::DATA:
|
|
|
+/// ...
|
|
|
+/// break;
|
|
|
+/// default: assert(0); // Can not happen
|
|
|
+/// }
|
|
|
+/// }
|
|
|
+/// \endcode
|
|
|
class RDataReader {
|
|
|
public:
|
|
|
- // The sequence and attributes
|
|
|
+ /// \brief Function called on each name encountered in the data.
|
|
|
typedef boost::function<void(const dns::LabelSequence&, unsigned int)>
|
|
|
NameAction;
|
|
|
+ /// \brief Function called on each data field in the data.
|
|
|
typedef boost::function<void(const uint8_t*, size_t)> DataAction;
|
|
|
|
|
|
- // For the default parameters.
|
|
|
+ /// \brief a NameAction that does nothing.
|
|
|
+ ///
|
|
|
+ /// This is a NameAction function that does nothing. It is used
|
|
|
+ /// as a default in the constructor.
|
|
|
static void emptyNameAction(const dns::LabelSequence& label,
|
|
|
unsigned int attributes);
|
|
|
+ /// \brief a DataAction that does nothing.
|
|
|
+ ///
|
|
|
+ /// This is a DataAction function that does nothing. It is used
|
|
|
+ /// as a default in the constructor.
|
|
|
static void emptyDataAction(const uint8_t* data, size_t size);
|
|
|
|
|
|
+ /// \brief Constructor
|
|
|
+ ///
|
|
|
+ /// This constructs the reader on top of some serialized data.
|
|
|
+ /// It does not copy the data, you have to make sure the data
|
|
|
+ /// is valid for the whole life of this object and that they
|
|
|
+ /// don't change.
|
|
|
+ ///
|
|
|
+ /// \param rrclass The class the encoded rdata belongs to.
|
|
|
+ /// \param rrtype The type of the encode rdata.
|
|
|
+ /// \param size Number of bytes the data have in serialized form.
|
|
|
+ /// \param data The actual data.
|
|
|
+ /// \param name_action The callback to be called on each encountered name.
|
|
|
+ /// \param data_action The callback to be called on each data chunk.
|
|
|
RDataReader(const dns::RRClass& rrclass, const dns::RRType& rrtype,
|
|
|
size_t size, const uint8_t* data,
|
|
|
const NameAction& name_action = &emptyNameAction,
|
|
|
const DataAction& data_action = &emptyDataAction);
|
|
|
|
|
|
- enum Action {
|
|
|
- NAME,
|
|
|
- DATA,
|
|
|
- END
|
|
|
+ /// \brief The type of data returned from this iteration.
|
|
|
+ enum DataType {
|
|
|
+ NAME, ///< This iteration returns domain label
|
|
|
+ DATA, ///< This iteration returns unstructuder data
|
|
|
+ END ///< No more data to return
|
|
|
};
|
|
|
|
|
|
+ /// \brief Data from one iteration
|
|
|
+ ///
|
|
|
+ /// Each time you call next() or nextSig(), it returns some data.
|
|
|
+ /// This holds the data.
|
|
|
class Result {
|
|
|
public:
|
|
|
- Action action() const;
|
|
|
+ /// \brief The type of data returned.
|
|
|
+ DataType type() const;
|
|
|
+ /// \brief The raw data.
|
|
|
+ ///
|
|
|
+ /// This is only valid if type() == DATA.
|
|
|
const uint8_t* data() const;
|
|
|
+ /// \brief The size of the raw data.
|
|
|
+ ///
|
|
|
+ /// This is the number of bytes the data takes. It is valid only
|
|
|
+ /// if type() == DATA.
|
|
|
size_t size() const;
|
|
|
+ /// \brief The domain label.
|
|
|
+ ///
|
|
|
+ /// This holds the domain label. It is only valid if type() == NAME.
|
|
|
const dns::LabelSequence& sequence;
|
|
|
+ /// \brief If there are data returned.
|
|
|
+ ///
|
|
|
+ /// This returns if there are any data at all returned. This is
|
|
|
+ /// equivalent to action != END, but it allows for more convenient
|
|
|
+ /// code of a loop through the data.
|
|
|
operator bool() const {
|
|
|
return (action() != END);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+ /// \brief Step to next piece of data.
|
|
|
+ ///
|
|
|
+ /// This returns the next available data. Also, the apropriate hook
|
|
|
+ /// (name_action or data_action, depending on the data type) as passed
|
|
|
+ /// to the constructor is called.
|
|
|
+ ///
|
|
|
+ /// If there are no more data, a Result with type END is returned and
|
|
|
+ /// no callback is called.
|
|
|
Result next();
|
|
|
+ /// \brief Call next() until the end.
|
|
|
+ ///
|
|
|
+ /// This is just convenience method to iterate through all the data.
|
|
|
+ /// It calls next until it reaches the end (it does not revind before,
|
|
|
+ /// therefore if you already called next() yourself, it does not start
|
|
|
+ /// at the beginning).
|
|
|
+ ///
|
|
|
+ /// The method only makes sense if you set the callbacks in constructor.
|
|
|
+ void iterate() {
|
|
|
+ while (next()) { }
|
|
|
+ }
|
|
|
+ /// \brief Step to next piece of RRSig data.
|
|
|
+ ///
|
|
|
+ /// This is almost the same as next(), but it iterates through the
|
|
|
+ /// associated RRSig data, not the data for the given RRType.
|
|
|
+ Result nextSig();
|
|
|
+ /// \brief Iterate through all RRSig data.
|
|
|
+ ///
|
|
|
+ /// This is almost the same as iterate(), but it iterates through the
|
|
|
+ /// RRSig data instead.
|
|
|
+ void iterateSig() {
|
|
|
+ while (nextSig()) { }
|
|
|
+ }
|
|
|
+ /// \brief Rewind the iterator to the beginnig of data.
|
|
|
+ ///
|
|
|
+ /// The following next() and nextSig() will start iterating from the
|
|
|
+ /// beginning again.
|
|
|
void rewind();
|
|
|
|
|
|
+ /// \brief Returns the size of associated data.
|
|
|
+ ///
|
|
|
+ /// This just returns whatever was passed to the constructor as size.
|
|
|
size_t getSize() const;
|
|
|
};
|
|
|
|