The Result, empty callbacks, etc.
// PERFORMANCE OF THIS SOFTWARE.
#include "rdata_encoder.h"
-#include "rdata_field.h"
#include <exceptions/exceptions.h>
#include <cstring>
#include <vector>
-#include <stdint.h>
-
using namespace isc::dns;
using std::vector;
#ifndef DATASRC_MEMORY_RDATA_ENCODER_H
#define DATASRC_MEMORY_RDATA_ENCODER_H 1
+#include "rdata_field.h"
+
#include <exceptions/exceptions.h>
#include <dns/labelsequence.h>
Exception(file, line, what) {}
};
-/// \brief Attributes of domain name fields of encoded RDATA.
-///
-/// The enum values define special traits of the name that can affect how
-/// it should be handled in rendering or query processing.
-enum RdataNameAttributes {
- NAMEATTR_NONE = 0, ///< No special attributes
- NAMEATTR_COMPRESSIBLE = 1, ///< Name should be compressed when rendered
- NAMEATTR_ADDITIONAL = (NAMEATTR_COMPRESSIBLE << 1) ///< Name requires
- ///< Additional section
- ///< handling
-};
-
/// \brief RDATA encoder.
///
/// This class provides interfaces to encode a set of RDATA of a specific
#include "rdata_field.h"
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
#include <boost/static_assert.hpp>
using namespace isc::dns;
#ifndef DATASRC_MEMORY_RDATA_FIELD
#define DATASRC_MEMORY_RDATA_FIELD
-#include "rdata_encoder.h"
+#include <stdint.h>
/// \file rdata_field.h
///
namespace datasrc {
namespace memory {
+/// \brief Attributes of domain name fields of encoded RDATA.
+///
+/// The enum values define special traits of the name that can affect how
+/// it should be handled in rendering or query processing.
+enum RdataNameAttributes {
+ NAMEATTR_NONE = 0, ///< No special attributes
+ NAMEATTR_COMPRESSIBLE = 1, ///< Name should be compressed when rendered
+ NAMEATTR_ADDITIONAL = (NAMEATTR_COMPRESSIBLE << 1) ///< Name requires
+ ///< Additional section
+ ///< handling
+};
+
/// Specification of a single RDATA field in terms of internal encoding.
struct RdataFieldSpec {
enum FieldType {
// PERFORMANCE OF THIS SOFTWARE.
#include "rdata_reader.h"
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+void
+RdataReader::emptyNameAction(const dns::LabelSequence&, unsigned) {
+ // Do nothing here. On purpose, it's not unfinished.
+}
+
+void
+RdataReader::emptyDataAction(const uint8_t*, size_t) {
+ // Do nothing here. On purpose, it's not unfinished.
+}
+
+RdataReader::Result::Result(const dns::LabelSequence& label,
+ unsigned attributes) :
+ label_(label),
+ data_(NULL),
+ size_(0),
+ type_(NAME),
+ compressible_((attributes & NAMEATTR_COMPRESSIBLE) != 0),
+ additional_((attributes & NAMEATTR_ADDITIONAL) != 0)
+{}
+
+RdataReader::Result::Result(const uint8_t* data, size_t size) :
+ label_(dns::Name::ROOT_NAME()),
+ data_(data),
+ size_(size),
+ type_(DATA),
+ compressible_(false),
+ additional_(false)
+{}
+
+}
+}
+}
#ifndef DATASRC_MEMORY_RDATA_READER_H
#define DATASRC_MEMORY_RDATA_READER_H 1
+#include "rdata_field.h"
+
#include <boost/function.hpp>
+#include <dns/labelsequence.h>
+#include <dns/name.h>
+
namespace isc {
// Some forward declarations
namespace dns{
-class LabelSequence;
class RRClass;
class RRType;
}
/// ...
/// }
///
-/// RDataReader reader(RRClass::IN(), RRType::AAAA(), size, data,
+/// RdataReader reader(RRClass::IN(), RRType::AAAA(), size, data,
/// &handleLabel, handleData);
/// reader.iterate();
/// \endcode
/// there's no much difference on the technical side.
///
/// \code
-/// RDataReader reader(RRClass::IN(), RRType::AAAA(), size, data,
+/// RdataReader reader(RRClass::IN(), RRType::AAAA(), size, data,
/// &handleLabel, handleData);
-/// RDataReader::Result data;
+/// RdataReader::Result data;
/// while (data = reader.next()) {
/// switch(data.type()) {
-/// case RDataReader::NAME:
+/// case RdataReader::NAME:
/// ...
/// break;
-/// case RDataReader::DATA:
+/// case RdataReader::DATA:
/// ...
/// break;
/// default: assert(0); // Can not happen
/// }
/// }
/// \endcode
-class RDataReader {
+class RdataReader {
public:
/// \brief Function called on each name encountered in the data.
- typedef boost::function<void(const dns::LabelSequence&, unsigned int)>
+ typedef boost::function<void(const dns::LabelSequence&, unsigned)>
NameAction;
/// \brief Function called on each data field in the data.
typedef boost::function<void(const uint8_t*, size_t)> DataAction;
/// 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);
+ unsigned attributes);
/// \brief a DataAction that does nothing.
///
/// This is a DataAction function that does nothing. It is used
/// \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,
+ 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);
///
/// Each time you call next() or nextSig(), it returns some data.
/// This holds the data.
+ ///
+ /// It is valid only for as long as the RdataReader that returned it.
+ ///
+ /// All the methods can be called under any circumstances. However,
+ /// if the required property is not valid for the given type (eg.
+ /// when calling size() on type() == NAME), it returns some "empty"
+ /// value (0, NULL, or the like).
class Result {
public:
+ /// \brief Default constructor
+ ///
+ /// It creates an empty result (with no data) of type END.
+ Result() :
+ // TODO: Do we maybe want to have a static one to copy
+ // instead of constructing new one from the root Name?
+ label_(dns::Name::ROOT_NAME()),
+ data_(NULL),
+ size_(0),
+ type_(END),
+ compressible_(false),
+ additional_(false)
+ {}
+ /// \brief Constructor from a domain label
+ ///
+ /// Creates the NAME type result. Used internally from RdataReader.
+ ///
+ /// \param label The label to hold
+ /// \param attributes The attributes, as stored by the serialized
+ /// data.
+ Result(const dns::LabelSequence& label, unsigned attributes);
+ /// \brief Constructor from data
+ ///
+ /// Creates the DATA type result. Used internally from RdataReader.
+ ///
+ /// \param data The data pointer to hold.
+ /// \param size The size to hold.
+ Result(const uint8_t* data, size_t size);
/// \brief The type of data returned.
- DataType type() const;
+ DataType type() const { return (type_); }
/// \brief The raw data.
///
/// This is only valid if type() == DATA.
- const uint8_t* data() const;
+ const uint8_t* data() const { return (data_); }
/// \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;
+ size_t size() const { return (size_); }
/// \brief The domain label.
///
/// This holds the domain label. It is only valid if type() == NAME.
- const dns::LabelSequence& label() const;
+ const dns::LabelSequence& label() const { return (label_); }
/// \brief Is the name in label() compressible?
///
/// This is valid only if type() == NAME.
- bool compressible() const;
+ bool compressible() const { return (compressible_); }
+ /// \brief Does the name expect additional processing?
+ ///
+ /// This is valid only if type() == NAME.
+ bool additional() const { return (additional_); }
/// \brief If there are data returned.
///
/// This returns if there are any data at all returned. This is
operator bool() const {
return (type() != END);
}
+ private:
+ dns::LabelSequence label_;
+ const uint8_t* data_;
+ size_t size_;
+ DataType type_;
+ bool compressible_;
+ bool additional_;
};
/// \brief Step to next piece of data.
const vector<uint8_t>& encoded_data,
MessageRenderer& renderer)
{
- RDataReader reader(rrclass, rrtype, encoded_data.size(),
+ RdataReader reader(rrclass, rrtype, encoded_data.size(),
&encoded_data[0]);
- RDataReader::Result field;
+ RdataReader::Result field;
while (field = reader.next()) {
switch (field.type()) {
- case RDataReader::DATA:
+ case RdataReader::DATA:
renderer.writeData(field.data(), field.size());
break;
- case RDataReader::NAME:
+ case RdataReader::NAME:
renderer.writeName(field.label(), field.compressible());
break;
default:
while (field = reader.nextSig()) {
switch (field.type()) {
- case RDataReader::DATA:
+ case RdataReader::DATA:
renderer.writeData(field.data(), field.size());
break;
default: // There are also no NAME fields in RRSigs
const vector<uint8_t>& encoded_data,
MessageRenderer& renderer)
{
- RDataReader reader(rrclass, rrtype, encoded_data.size(),
+ RdataReader reader(rrclass, rrtype, encoded_data.size(),
&encoded_data[0],
boost::bind(renderNameField, &renderer,
additionalRequired(rrtype), _1, _2),
const vector<uint8_t>& encoded_data,
MessageRenderer& renderer)
{
- RDataReader reader(rrclass, rrtype, encoded_data.size(),
+ RdataReader reader(rrclass, rrtype, encoded_data.size(),
&encoded_data[0],
boost::bind(renderNameField, &renderer,
additionalRequired(rrtype), _1, _2),
encoder_.start(RRClass::IN(), RRType::A());
EXPECT_THROW(encoder_.addSIGRdata(big_sigrdata), RdataEncodingError);
}
+
+// Test the result returns what it was constructed with.
+TEST_F(RdataSerializationTest, readerResult) {
+ // Default constructor
+ RdataReader::Result empty;
+ // Everything should be at the "empty" values, type END
+ EXPECT_EQ(RdataReader::END, empty.type());
+ EXPECT_EQ(NULL, empty.data());
+ EXPECT_EQ(0, empty.size());
+ EXPECT_TRUE(empty.label().equals(LabelSequence(Name::ROOT_NAME())));
+ EXPECT_FALSE(empty);
+ EXPECT_FALSE(empty.compressible());
+ EXPECT_FALSE(empty.additional());
+ // Constructor from label sequence
+ LabelSequence seq(Name("example.org"));
+ RdataReader::Result compressible(seq, NAMEATTR_COMPRESSIBLE);
+ EXPECT_EQ(RdataReader::NAME, compressible.type());
+ EXPECT_EQ(NULL, compressible.data());
+ EXPECT_EQ(0, compressible.size());
+ EXPECT_TRUE(compressible.label().equals(seq));
+ EXPECT_TRUE(compressible);
+ EXPECT_TRUE(compressible.compressible());
+ EXPECT_FALSE(empty.additional());
+ RdataReader::Result incompressible(seq, NAMEATTR_ADDITIONAL);
+ EXPECT_EQ(RdataReader::NAME, incompressible.type());
+ EXPECT_EQ(NULL, incompressible.data());
+ EXPECT_EQ(0, incompressible.size());
+ EXPECT_TRUE(incompressible.label().equals(seq));
+ EXPECT_TRUE(incompressible);
+ EXPECT_FALSE(incompressible.compressible());
+ EXPECT_TRUE(empty.additional());
+ // Constructor from data
+ uint8_t byte;
+ RdataReader::Result data(&byte, 1);
+ EXPECT_EQ(RdataReader::DATA, data.type());
+ EXPECT_EQ(&byte, data.data());
+ EXPECT_EQ(1, data.size());
+ EXPECT_TRUE(data.label().equals(LabelSequence(Name::ROOT_NAME())));
+ EXPECT_FALSE(data);
+ EXPECT_FALSE(data.compressible());
+ EXPECT_FALSE(empty.additional());
+}
}