Commit fc772a40 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[2094] overall documentation update

parent 2d291f69
......@@ -64,7 +64,7 @@ libdatasrc_la_LIBADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
libdatasrc_la_LIBADD += $(top_builddir)/src/lib/dns/libdns++.la
libdatasrc_la_LIBADD += $(top_builddir)/src/lib/log/liblog.la
libdatasrc_la_LIBADD += $(top_builddir)/src/lib/cc/libcc.la
libdatasrc_la_LIBADD += memory/libdatasrc_memory.la
libdatasrc_la_LIBADD += memory/libdatasrc_memory.la # convenience library
libdatasrc_la_LIBADD += $(SQLITE_LIBS)
BUILT_SOURCES = datasrc_config.h datasrc_messages.h datasrc_messages.cc
......
......@@ -38,27 +38,41 @@ namespace datasrc {
namespace memory {
namespace {
/// Specification of a single RDATA field in terms of internal encoding.
struct RdataFieldSpec {
enum FieldType {
FIXEDLEN_DATA = 0,
VARLEN_DATA,
DOMAIN_NAME
FIXEDLEN_DATA = 0, // fixed-length data field
VARLEN_DATA, // variable-length data field
DOMAIN_NAME // domain name
};
FieldType type;
const FieldType type; // field type
// type specific data. We use a union so it'll be clear only one of them
// (determined by the type) is valid. Since we want to make it as
// lightweight as possible, we use a relatively lower-level primitives
// here.
union {
uint16_t fixeddata_len;
RdataNameAttributes name_attributes;
// The length of fixed-length data field. Only valid for FIXEDLEN_DATA
const uint16_t fixeddata_len;
// Attributes of the name. Only valid for DOMAIN_NAME.
const RdataNameAttributes name_attributes;
};
};
/// Specification of RDATA in terms of internal encoding.
struct RdataEncodeSpec {
uint16_t field_count;
uint16_t name_count;
uint16_t varlen_count;
const RdataFieldSpec* fields;
const uint16_t field_count; // total number of fields (# of fields member)
const uint16_t name_count; // number of domain name fields
const uint16_t varlen_count; // number of variable-length data fields
const RdataFieldSpec* const fields; // list of field specs
};
// These constants are convenient shortcut to initialize the name_attributes
// member of RdataFieldSpec (since it's a union, we can only directly
// initialize fixeddata_len member, so we need to convert it to its type).
// These are essentially small integers, so the cast should be safe.
const uint16_t NAMEATTR_NOATTRIBUTE_INITIALIZER = static_cast<uint16_t>(0);
const uint16_t NAMEATTR_COMPRESSIBLE_INITIALIZER =
static_cast<uint16_t>(NAMEATTR_COMPRESSIBLE);
......@@ -67,33 +81,33 @@ const uint16_t NAMEATTR_ADDITIONAL_INITIALIZER =
const uint16_t NAMEATTR_COMPADDITIONAL_INITIALIZER =
static_cast<uint16_t>(NAMEATTR_COMPRESSIBLE | NAMEATTR_ADDITIONAL);
// TBD
// Many types of RDATA can be treated as a single-field, variable length
// field (in terms of our encoding). The following define such most general
// form of field spec.
const RdataFieldSpec generic_data_fields[] = {
{RdataFieldSpec::VARLEN_DATA, {0}}
};
const uint16_t n_generic_data_fields =
sizeof(generic_data_fields) / sizeof(RdataFieldSpec);
// Most general form of field spec: that consisting of single variable-len
// data field.
const RdataEncodeSpec generic_data_spec = {
n_generic_data_fields, 0, 1, generic_data_fields
};
// TBD
// RDATA consist of a single IPv4 address field.
const RdataFieldSpec single_ipv4_fields[] = {
{RdataFieldSpec::FIXEDLEN_DATA, {sizeof(uint32_t)}}
};
const uint16_t n_ipv4_fields =
sizeof(single_ipv4_fields) / sizeof(RdataFieldSpec);
// RDATA consist of a single IPv6 address field.
const RdataFieldSpec single_ipv6_fields[] = {
{RdataFieldSpec::FIXEDLEN_DATA, {16}} // 128bits = 16 bytes
};
const uint16_t n_ipv6_fields =
sizeof(single_ipv6_fields) / sizeof(RdataFieldSpec);
// TBD
// There are several RR types that consist of a single domain name.
const RdataFieldSpec single_noattr_name_fields[] = {
{RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_NOATTRIBUTE_INITIALIZER}}
};
......@@ -119,8 +133,7 @@ const RdataFieldSpec double_noattr_name_fields[] = {
const uint16_t n_double_name_fields =
sizeof(double_compressible_name_fields) / sizeof(RdataFieldSpec);
// SOA specific: two compressible names + 20-byte data
// SOA specific: two compressible names + 5*32-bit data
const RdataFieldSpec soa_fields[] = {
{RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_COMPRESSIBLE_INITIALIZER}},
{RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_COMPRESSIBLE_INITIALIZER}},
......@@ -165,7 +178,10 @@ const RdataFieldSpec nsec_fields[] = {
};
const uint16_t n_nsec_fields = sizeof(nsec_fields) / sizeof(RdataFieldSpec);
// Class IN encode specs
// Class IN encode specs. This gives a shortcut to the encode spec for
// some well-known types of RDATA specific to class IN (most of which are
// generic and can be used for other classes). The array index is the
// RR type code.
const RdataEncodeSpec encode_spec_list_in[] = {
generic_data_spec, // #0: (NONE)
{n_ipv4_fields, 0, 0, single_ipv4_fields}, // #1: A
......@@ -213,6 +229,7 @@ const RdataEncodeSpec encode_spec_list_in[] = {
// least for currently supported RR types.
};
// # of entries in encode_spec_list_in
const size_t encode_spec_list_in_size =
sizeof(encode_spec_list_in) / sizeof(encode_spec_list_in[0]);
BOOST_STATIC_ASSERT(encode_spec_list_in_size == 48);
......@@ -220,12 +237,16 @@ BOOST_STATIC_ASSERT(encode_spec_list_in_size == 48);
inline
const RdataEncodeSpec&
getRdataEncodeSpec(RRClass rrclass, RRType rrtype) {
// Special case: for classes other than IN, we treat RDATA of RR types
// that are class-IN specific as generic opaque data.
if (rrclass != RRClass::IN() &&
(rrtype == RRType::A() || rrtype == RRType::AAAA() ||
rrtype == RRType::SRV())) {
return (generic_data_spec);
}
// Otherwise, if the type is in the pre-defined range, we use the defined
// spec; otherwise we treat it as opaque data.
const uint16_t typecode = rrtype.getCode();
if (typecode < encode_spec_list_in_size) {
return (encode_spec_list_in[rrtype.getCode()]);
......@@ -247,6 +268,7 @@ getNAPTRDataLen(const rdata::Rdata& rdata) {
}
} // end of unnamed namespace
namespace testing {
void
encodeRdata(const rdata::Rdata& rdata, RRClass rrclass, RRType rrtype,
vector<uint8_t>& data_result, vector<uint16_t>& len_result)
......@@ -352,6 +374,7 @@ foreachRdataField(RRClass rrclass, RRType rrtype,
assert(name_count == encode_spec.name_count);
assert(varlen_count == encode_spec.varlen_count);
}
} // namespace testing
} // namespace memory
} // namespace datasrc
......
......@@ -28,23 +28,54 @@ namespace isc {
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_COMPRESSIBLE = 1,
NAMEATTR_ADDITIONAL = (NAMEATTR_COMPRESSIBLE << 1)
NAMEATTR_COMPRESSIBLE = 1, ///< Name should be compressed when rendered
NAMEATTR_ADDITIONAL = (NAMEATTR_COMPRESSIBLE << 1) ///< Name requires
///< Additional section
///< handling
};
// We use the following quick-hack version of encoder and "foreach"
// operator until we implement the complete versions. The plan is to
// update the test cases that use these functions with the complete
// functions/classes, and then remove the entire namespace.
namespace testing {
// "Encode" given RDATA of given RR class and type.
//
// Fixed/variable-length data fields are encoded in their wire-format;
// domain names are encoded in the form of:
// - nlen: name data length (1 byte)
// - olen: offset data length (1 byte)
// - name data (nlen bytes)
// - offset data (olen bytes)
//
// The encoded results are appended to data_result.
// If the RDATA contain variable-length data fields, the lengths of the
// these fields will be appended in len_result, in the order of appearance.
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);
// Callbacks used in foreachRdataField.
typedef boost::function<void(const dns::LabelSequence&,
RdataNameAttributes)> NameCallback;
typedef boost::function<void(const uint8_t*, size_t)> DataCallback;
// Iterate over each RDATA field (in terms of the internal encoding) stored
// in encoded_data, and call the given callback for each data (for
// domain name fields, name_callback will be called; for normal data fields
// data_callback will be called). If the encoded data contain variable-length
// data fields, varlen_list should store a sequence of their lengths, in the
// of the appearance.
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
......
......@@ -34,18 +34,25 @@
using namespace isc::dns;
using namespace isc::dns::rdata;
using namespace isc::datasrc::memory;
using namespace isc::datasrc::memory::testing;
using isc::util::unittests::matchWireData;
using std::string;
using std::vector;
namespace {
// This defines a tuple of test data used in test_rdata_list below.
struct TestRdata {
const char* const rrclass;
const char* const rrtype;
const char* const rdata;
const char* const rrclass; // RR class, textual form
const char* const rrtype; // RR type, textual form
const char* const rdata; // textual RDATA
const size_t n_varlen_fields; // expected # of variable-len fields
};
// This test data consist of all supported types of RDATA (+ some
// unusual and corner cases). We'll construct corresponding Rdata
// object from this, and compare its wire format data both generated
// by normal libdns++ interface and via encoding conversion.
const TestRdata test_rdata_list[] = {
{"IN", "A", "192.0.2.1", 0},
{"IN", "NS", "ns.example.com", 0},
......@@ -85,6 +92,8 @@ const TestRdata test_rdata_list[] = {
{NULL, NULL, NULL, 0}
};
// The following two functions will be used to generate wire format data
// from encoded representation of each RDATA.
void
renderNameField(MessageRenderer* renderer, bool additional_required,
const LabelSequence& labels, RdataNameAttributes attributes)
......@@ -102,12 +111,22 @@ renderDataField(MessageRenderer* renderer, const uint8_t* data,
}
TEST(RdataFieldSpec, checkData) {
// These two names will be rendered before and after the test RDATA,
// to check in case the RDATA contain a domain name whether it's
// compressed or not correctly. The names in the RDATA should basically
// a subdomain of example.com, so it can be compressed due to dummy_name.
// Likewise, dummy_name2 should be able to be fully compressed due to
// the name in the RDATA.
const Name dummy_name("com");
const Name dummy_name2("example.com");
MessageRenderer expected_renderer, actual_renderer;
vector<uint8_t> encoded_data;
vector<uint16_t> varlen_list;
// The set of RR types that require additional section processing.
// We'll pass it to renderNameField to check the stored attribute matches
// our expectation.
std::set<RRType> need_additionals;
need_additionals.insert(RRType::NS());
need_additionals.insert(RRType::MX());
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment