// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <dns/name.h>
+#include <dns/labelsequence.h>
+#include <dns/rdata.h>
#include <dns/rrclass.h>
#include <dns/rrtype.h>
+#include <util/buffer.h> // for test functions
+
#include "rdata_encoder.h"
+#include <vector>
+
#include <stdint.h>
using namespace isc::dns;
+using std::vector;
namespace isc {
namespace datasrc {
const uint16_t NAMEATTR_COMPADDITIONAL_INITIALIZER =
static_cast<uint16_t>(NAMEATTR_COMPRESSIBLE | NAMEATTR_ADDITIONAL);
+// TBD
const RdataFieldSpec generic_data_fields[] = {
{RdataFieldSpec::VARLEN_DATA, {0}}
};
const uint16_t generic_data_fields_count =
sizeof(generic_data_fields) / sizeof(RdataFieldSpec);
+// TBD
+const RdataFieldSpec single_ipv4_fields[] = {
+ {RdataFieldSpec::FIXEDLEN_DATA, {sizeof(uint32_t)}}
+};
+const uint16_t single_ipv4_fields_count =
+ sizeof(single_ipv4_fields) / sizeof(RdataFieldSpec);
+
+// TBD
const RdataFieldSpec generic_single_name_fields[] = {
- {RdataFieldSpec::VARLEN_DATA, {NAMEATTR_COMPADDITIONAL_INITIALIZER}}
+ {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_COMPADDITIONAL_INITIALIZER}}
};
+const uint16_t generic_single_name_fields_count =
+ sizeof(generic_single_name_fields) / sizeof(RdataFieldSpec);
// Class IN encode specs
const RdataEncodeSpec encode_spec_list_in[] = {
- {generic_data_fields_count, 0, 0, generic_data_fields} // type #0
+ {generic_data_fields_count, 0, 0, generic_data_fields}, // #0
+ {single_ipv4_fields_count, 0, 0, single_ipv4_fields}, // #1: A
+ {generic_single_name_fields_count, 0, 0, generic_single_name_fields} // NS
};
-#ifdef notyet
inline
const RdataEncodeSpec&
getRdataEncodeSpec(RRClass rrclass, RRType rrtype) {
}
return (encode_spec_list_in[0]);
}
-#endif
} // end of unnamed namespace
-#ifdef notyet
void
-testRdataEncoder(const Rdata& rdata, RRClass rrclass, RRType rrtype,
- vector<uint8_t>& result)
+encodeRdata(const rdata::Rdata& rdata, RRClass rrclass, RRType rrtype,
+ vector<uint8_t>& data_result, vector<uint16_t>& /*len_result*/)
{
+ util::OutputBuffer buffer(0);
+ rdata.toWire(buffer);
+ util::InputBuffer ibuffer(buffer.getData(), buffer.getLength());
+ vector<uint8_t> tmp; // used as temporary placeholder below
+
const RdataEncodeSpec& encode_spec = getRdataEncodeSpec(rrclass, rrtype);
for (size_t i = 0; i < encode_spec.field_count; ++i) {
- const RdataFieldSpec& field_spec = *encode_spec.fields[i];
- if (field_spec.type == RdataFieldSpec::FIXEDLEN_DATA)
- assert(encode_spec.fields[i] != NULL);
-
+ const RdataFieldSpec& field_spec = encode_spec.fields[i];
+ switch (field_spec.type) {
+ case RdataFieldSpec::FIXEDLEN_DATA:
+ tmp.resize(field_spec.fixeddata_len);
+ ibuffer.readData(&tmp[0], tmp.size());
+ data_result.insert(data_result.end(), tmp.begin(), tmp.end());
+ break;
+ case RdataFieldSpec::DOMAIN_NAME:
+ {
+ const Name name(ibuffer);
+ const LabelSequence labels(name);
+ size_t nlen;
+ const uint8_t* ndata = labels.getData(&nlen);
+ size_t olen;
+ uint8_t offset_holder[Name::MAX_LABELS];
+ labels.getOffsetData(&olen, offset_holder);
+ data_result.push_back(nlen);
+ data_result.push_back(olen);
+ data_result.insert(data_result.end(), ndata, ndata + nlen);
+ data_result.insert(data_result.end(), offset_holder,
+ offset_holder + olen);
+ break;
+ }
+ default:
+ assert(false);
+ }
+ }
+}
+
+void
+foreachRdataField(RRClass rrclass, RRType rrtype,
+ const vector<uint8_t>& encoded_data,
+ const vector<uint16_t>& /*varlen_list*/,
+ NameCallback name_callback, DataCallback data_callback)
+{
+ const RdataEncodeSpec& encode_spec = getRdataEncodeSpec(rrclass, rrtype);
+
+ size_t off = 0;
+ for (size_t i = 0; i < encode_spec.field_count; ++i) {
+ const RdataFieldSpec& field_spec = encode_spec.fields[i];
+ switch (field_spec.type) {
+ case RdataFieldSpec::FIXEDLEN_DATA:
+ if (data_callback) {
+ data_callback(&encoded_data[off], field_spec.fixeddata_len);
+ }
+ off += field_spec.fixeddata_len;
+ break;
+ case RdataFieldSpec::DOMAIN_NAME:
+ {
+ const uint8_t nlen = encoded_data.at(off);
+ const uint8_t olen = encoded_data.at(off + 1);
+ if (name_callback) {
+ const uint8_t* ndata = &encoded_data.at(off + 2);
+ const uint8_t* odata = &encoded_data.at(off + 2 + nlen);
+ name_callback(LabelSequence(ndata, odata, olen),
+ field_spec.name_attributes);
+ }
+ off += (2 + nlen + olen);
+ break;
+ }
+ default:
+ assert(false);
+ }
}
}
-#endif
} // namespace memory
} // namespace datasrc
#ifndef DATASRC_MEMORY_RDATA_ENCODER_H
#define DATASRC_MEMORY_RDATA_ENCODER_H 1
+#include <dns/labelsequence.h>
+#include <dns/rdata.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <boost/function.hpp>
+
+#include <vector>
+
namespace isc {
namespace datasrc {
namespace memory {
NAMEATTR_ADDITIONAL = (NAMEATTR_COMPRESSIBLE << 1)
};
+void encodeRdata(const dns::rdata::Rdata& rdata, dns::RRClass rrclass,
+ dns::RRType rrtype, std::vector<uint8_t>& data_result,
+ std::vector<uint16_t>& len_result);
+
+typedef boost::function<void(const dns::LabelSequence&,
+ RdataNameAttributes)> NameCallback;
+typedef boost::function<void(const uint8_t*, size_t)> DataCallback;
+
+void foreachRdataField(dns::RRClass rrclass, dns::RRType rrtype,
+ const std::vector<uint8_t>& encoded_data,
+ const std::vector<uint16_t>& varlen_list,
+ NameCallback name_callback, DataCallback data_callback);
+
} // namespace memory
} // namespace datasrc
} // namespace isc
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <dns/name.h>
+#include <dns/labelsequence.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
#include <datasrc/memory/rdata_encoder.h>
+#include <util/unittests/wiredata.h>
+
#include <gtest/gtest.h>
+#include <boost/bind.hpp>
+
+#include <set>
+#include <string>
+#include <vector>
+
+using namespace isc::dns;
+using namespace isc::dns::rdata;
using namespace isc::datasrc::memory;
+using isc::util::unittests::matchWireData;
+using std::string;
+using std::vector;
+
namespace {
-class RdataEncoderTest : public ::testing::Test {
-protected:
- RdataEncoderTest() {}
+struct TestRdata {
+ const char* const rrclass;
+ const char* const rrtype;
+ const char* const rdata;
};
+const TestRdata test_rdata_list[] = {
+ {"IN", "A", "192.0.2.1"},
+ {"IN", "NS", "ns.example.com"},
+ {NULL, NULL, NULL}
+};
+
+void
+renderNameField(MessageRenderer* renderer, bool additional_required,
+ const LabelSequence& labels, RdataNameAttributes attributes)
+{
+ EXPECT_EQ(additional_required,
+ (attributes & NAMEATTR_ADDITIONAL) != 0);
+ renderer->writeName(labels, (attributes & NAMEATTR_COMPRESSIBLE) != 0);
+}
+
+void
+renderDataField(MessageRenderer* renderer, const uint8_t* data,
+ size_t data_len)
+{
+ renderer->writeData(data, data_len);
+}
+
+TEST(RdataFieldSpec, checkData) {
+ const Name dummy_name("example.com");
+ MessageRenderer expected_renderer, actual_renderer;
+ vector<uint8_t> encoded_data;
+ vector<uint16_t> varlen_list;
+
+ std::set<RRType> need_additionals;
+ need_additionals.insert(RRType::NS());
+ need_additionals.insert(RRType::MX());
+ need_additionals.insert(RRType::SRV());
+
+ for (size_t i = 1; test_rdata_list[i].rrclass != NULL; ++i) {
+ SCOPED_TRACE(string(test_rdata_list->rrclass) + "/" +
+ test_rdata_list->rrtype);
+
+ expected_renderer.clear();
+ actual_renderer.clear();
+ expected_renderer.writeName(dummy_name);
+ actual_renderer.writeName(dummy_name);
+
+ const RRClass rrclass(test_rdata_list[i].rrclass);
+ const RRType rrtype(test_rdata_list[i].rrtype);
+ const ConstRdataPtr rdata = createRdata(rrtype, rrclass,
+ test_rdata_list[i].rdata);
+ rdata->toWire(expected_renderer);
+
+ const bool additional_required =
+ (need_additionals.find(rrtype) != need_additionals.end());
+
+ encodeRdata(*rdata, rrclass, rrtype, encoded_data, varlen_list);
+ foreachRdataField(rrclass, rrtype, encoded_data, varlen_list,
+ boost::bind(renderNameField, &actual_renderer,
+ additional_required, _1, _2),
+ boost::bind(renderDataField, &actual_renderer,
+ _1, _2));
-TEST_F(RdataEncoderTest, test1) {
- EXPECT_NE(NAMEATTR_COMPRESSIBLE, NAMEATTR_ADDITIONAL);
+ matchWireData(expected_renderer.getData(),
+ expected_renderer.getLength(),
+ actual_renderer.getData(),
+ actual_renderer.getLength());
+ }
}
}