// Do nothing here. On purpose, it's not unfinished.
}
-RdataReader::Result::Result(const 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_(Name::ROOT_NAME()),
- data_(data),
- size_(size),
- type_(DATA),
- compressible_(false),
- additional_(false)
-{}
-
RdataReader::RdataReader(const RRClass& rrclass, const RRType& rrtype,
const uint8_t* data,
size_t rdata_count, size_t sig_count,
sig_pos_ = 0;
}
-RdataReader::Result
+RdataReader::Boundary
RdataReader::nextInternal(const NameAction& name_action,
const DataAction& data_action)
{
+
if (spec_pos_ < spec_count_) {
const RdataFieldSpec& spec(spec_.fields[(spec_pos_ ++) %
spec_.field_count]);
const LabelSequence sequence(data_ + data_pos_);
data_pos_ += sequence.getSerializedLength();
name_action(sequence, spec.name_attributes);
- return (Result(sequence, spec.name_attributes));
} else {
const size_t length(spec.type == RdataFieldSpec::FIXEDLEN_DATA ?
spec.fixeddata_len : lengths_[length_pos_ ++]);
- Result result(data_ + data_pos_, length);
+ const uint8_t* const pos = data_ + data_pos_;
data_pos_ += length;
- data_action(result.data(), result.size());
- return (result);
+ data_action(pos, length);
}
+ return (spec_pos_ % spec_.field_count == 0 ?
+ RDATA_BOUNDARY : NO_BOUNDARY);
} else {
sigs_ = data_ + data_pos_;
- return (Result());
+ return (RRSET_BOUNDARY);
}
}
-RdataReader::Result
+RdataReader::Boundary
RdataReader::next() {
return (nextInternal(name_action_, data_action_));
}
-RdataReader::Result
+RdataReader::Boundary
RdataReader::nextSig() {
if (sig_pos_ < sig_count_) {
if (sigs_ == NULL) {
// We didn't find where the signatures start yet. We do it
// by iterating the whole data and then returning the state
// back.
- size_t data_pos = data_pos_;
- size_t spec_pos = spec_pos_;
- size_t length_pos = length_pos_;
+ const size_t data_pos = data_pos_;
+ const size_t spec_pos = spec_pos_;
+ const size_t length_pos = length_pos_;
// When the next() gets to the last item, it sets the sigs_
- while (nextInternal(emptyNameAction, emptyDataAction)) {}
+ while (nextInternal(emptyNameAction, emptyDataAction) !=
+ RRSET_BOUNDARY) {}
assert(sigs_ != NULL);
// Return the state
data_pos_ = data_pos;
length_pos_ = length_pos;
}
// Extract the result
- Result result(sigs_ + sig_data_pos_, lengths_[var_count_total_ +
- sig_pos_]);
+ const size_t length = lengths_[var_count_total_ + sig_pos_];
+ const uint8_t* const pos = sigs_ + sig_data_pos_;
// Move the position of iterator.
sig_data_pos_ += lengths_[var_count_total_ + sig_pos_];
sig_pos_ ++;
// Call the callback
- data_action_(result.data(), result.size());
- return (result);
+ data_action_(pos, length);
+ return (RDATA_BOUNDARY);
} else {
- return (Result());
+ return (RRSET_BOUNDARY);
}
}
const NameAction& name_action = &emptyNameAction,
const DataAction& data_action = &emptyDataAction);
- /// \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.
- ///
- /// 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 { return (type_); }
- /// \brief The raw data.
- ///
- /// This is only valid if type() == DATA.
- 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 { return (size_); }
- /// \brief The domain label.
- ///
- /// This holds the domain label. It is only valid if type() == NAME.
- const dns::LabelSequence& label() const { return (label_); }
- /// \brief Is the name in label() compressible?
- ///
- /// This is valid only if type() == NAME.
- 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
- /// equivalent to action != END, but it allows for more convenient
- /// code of a loop through the data.
- operator bool() const {
- return (type() != END);
- }
- private:
- dns::LabelSequence label_;
- const uint8_t* data_;
- size_t size_;
- DataType type_;
- bool compressible_;
- bool additional_;
+ /// \brief Result of next() and nextSig()
+ ///
+ /// This specifies if there's any boundary in the data at the
+ /// place where the corresponding call to next() or nextSig()
+ /// finished.
+ enum Boundary {
+ NO_BOUNDARY, ///< It is in the middle of Rdata
+ RDATA_BOUNDARY, ///< At the end of single Rdata
+ RRSET_BOUNDARY ///< At the end of the RRset (past the 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();
+ /// Iterate over the next field and call appropriate hook (name_action
+ /// or data_action, depending on the type) as passed to the constructor.
+ ///
+ /// \return It returns NO_BOUNDARY if the next call to next() will process
+ /// data of the same rdata as this one. RDATA_BOUNDARY is returned when
+ /// this field is the last of the current rdata. If there are no more
+ /// data to process, no hook is called and RRSET_BOUNDARY is returned.
+ /// Therefore, at the end of the whole data, once it processes the last
+ /// field and returns RDATA_BOUNDARY and then it returns RRSET_BOUNDARY
+ /// on the next call.
+ Boundary 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()) { }
+ while (next() != RRSET_BOUNDARY) { }
+ }
+ /// \brief Call next() until the end of current rdata.
+ ///
+ /// This is a convenience method to iterate until the end of current
+ /// rdata. Notice this may cause more than one field being processed,
+ /// as some rrtypes are more complex.
+ ///
+ /// \return If there was Rdata to iterate through.
+ bool iterateRdata() {
+ while (true) {
+ switch(next()) {
+ case NO_BOUNDARY: break;
+ case RDATA_BOUNDARY: return (true);
+ case RRSET_BOUNDARY: return (false);
+ }
+ }
}
/// \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();
+ Boundary 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()) { }
+ void iterateAllSigs() {
+ while (nextSig() != RRSET_BOUNDARY) { }
+ }
+ /// \brief Iterate through the current RRSig Rdata.
+ ///
+ /// This is almote the same as iterateRdata, except it is for single
+ /// signature Rdata.
+ ///
+ /// In practice, this should process one DATA field.
+ bool iterateSingleSig() {
+ while (true) {
+ switch(next()) {
+ case NO_BOUNDARY: break;
+ case RDATA_BOUNDARY: return (true);
+ case RRSET_BOUNDARY: return (false);
+ }
+ }
}
/// \brief Rewind the iterator to the beginnig of data.
///
// The positions in data.
size_t data_pos_, spec_pos_, length_pos_;
size_t sig_pos_, sig_data_pos_;
- Result nextInternal(const NameAction& name_action,
+ Boundary nextInternal(const NameAction& name_action,
const DataAction& data_action);
};
}
};
-// Decode using reader with the return value of next
-class NextDecoder {
-public:
- static void decode(const isc::dns::RRClass& rrclass,
- const isc::dns::RRType& rrtype,
- size_t rdata_count, size_t sig_count, size_t,
- const vector<uint8_t>& encoded_data, size_t,
- MessageRenderer& renderer)
- {
- RdataReader reader(rrclass, rrtype, &encoded_data[0], rdata_count,
- sig_count);
- RdataReader::Result field;
- while ((field = reader.next())) {
- switch (field.type()) {
- case RdataReader::DATA:
- renderer.writeData(field.data(), field.size());
- break;
- case RdataReader::NAME:
- renderer.writeName(field.label(), field.compressible());
- break;
- default:
- FAIL();
- }
- }
-
- renderer.writeName(dummy_name2);
-
- while ((field = reader.nextSig())) {
- switch (field.type()) {
- case RdataReader::DATA:
- renderer.writeData(field.data(), field.size());
- break;
- default: // There are also no NAME fields in RRSigs
- FAIL();
- }
- }
- }
-};
-
-// Decode using reader with the return value of next, but after the reader
-// was used and rewund.
-class RewundDecoder {
-public:
- static void decode(const isc::dns::RRClass& rrclass,
- const isc::dns::RRType& rrtype,
- size_t rdata_count, size_t sig_count, size_t,
- const vector<uint8_t>& encoded_data, size_t,
- MessageRenderer& renderer)
- {
- RdataReader reader(rrclass, rrtype, &encoded_data[0], rdata_count,
- sig_count);
- // Use the reader first and rewind it
- reader.iterateSig();
- reader.iterate();
- reader.rewind();
- RdataReader::Result field;
- while ((field = reader.next())) {
- switch (field.type()) {
- case RdataReader::DATA:
- renderer.writeData(field.data(), field.size());
- break;
- case RdataReader::NAME:
- renderer.writeName(field.label(), field.compressible());
- break;
- default:
- FAIL();
- }
- }
-
- renderer.writeName(dummy_name2);
-
- while ((field = reader.nextSig())) {
- switch (field.type()) {
- case RdataReader::DATA:
- renderer.writeData(field.data(), field.size());
- break;
- default: // There are also no NAME fields in RRSigs
- FAIL();
- }
- }
- }
-};
-
// Check using callbacks and calling next until the end.
class CallbackDecoder {
public:
boost::bind(renderNameField, &renderer,
additionalRequired(rrtype), _1, _2),
boost::bind(renderDataField, &renderer, _1, _2));
- while (reader.next()) { }
+ while (reader.next() != RdataReader::RRSET_BOUNDARY) { }
renderer.writeName(dummy_name2);
- while (reader.nextSig()) { }
+ while (reader.nextSig() != RdataReader::RRSET_BOUNDARY) { }
}
};
boost::bind(renderDataField, &renderer, _1, _2));
reader.iterate();
renderer.writeName(dummy_name2);
- reader.iterateSig();
+ reader.iterateAllSigs();
}
};
// Now, we let all sigs to be copied to data. We disable the
// renderer for this.
current = NULL;
- reader.iterateSig();
+ reader.iterateAllSigs();
// Now return the renderer and render the rest of the data
current = &renderer;
reader.iterate();
// Now, this should not break anything and should be valid, but should
// return ends.
- EXPECT_FALSE(reader.next());
- EXPECT_FALSE(reader.nextSig());
+ EXPECT_EQ(RdataReader::RRSET_BOUNDARY, reader.next());
+ EXPECT_EQ(RdataReader::RRSET_BOUNDARY, reader.nextSig());
// Render the name and the sigs
renderer.writeName(dummy_name2);
renderer.writeData(&data[0], data.size());
}
};
-typedef ::testing::Types<ManualDecoderStyle, NextDecoder, RewundDecoder,
+typedef ::testing::Types<ManualDecoderStyle,
CallbackDecoder, IterateDecoder,
HybridDecoder<true, true>, HybridDecoder<true, false>,
HybridDecoder<false, true>,
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(compressible.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(incompressible.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_TRUE(data);
- EXPECT_FALSE(data.compressible());
- EXPECT_FALSE(data.additional());
-}
}