From: JINMEI Tatuya Date: Thu, 19 Jul 2012 07:01:31 +0000 (-0700) Subject: [2094] overall documentation update X-Git-Tag: trac2351_base~158^2~16^2~7 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fc772a408baf60d2fa4b53e370c7cc8cb1c59e9f;p=thirdparty%2Fkea.git [2094] overall documentation update --- diff --git a/src/lib/datasrc/Makefile.am b/src/lib/datasrc/Makefile.am index 4a7f72c8db..defc7aca65 100644 --- a/src/lib/datasrc/Makefile.am +++ b/src/lib/datasrc/Makefile.am @@ -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 diff --git a/src/lib/datasrc/memory/rdata_encoder.cc b/src/lib/datasrc/memory/rdata_encoder.cc index 5edd88174e..7b6c068bb4 100644 --- a/src/lib/datasrc/memory/rdata_encoder.cc +++ b/src/lib/datasrc/memory/rdata_encoder.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(0); const uint16_t NAMEATTR_COMPRESSIBLE_INITIALIZER = static_cast(NAMEATTR_COMPRESSIBLE); @@ -67,33 +81,33 @@ const uint16_t NAMEATTR_ADDITIONAL_INITIALIZER = const uint16_t NAMEATTR_COMPADDITIONAL_INITIALIZER = static_cast(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& data_result, vector& 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 diff --git a/src/lib/datasrc/memory/rdata_encoder.h b/src/lib/datasrc/memory/rdata_encoder.h index 5ffce4b96f..39fe873009 100644 --- a/src/lib/datasrc/memory/rdata_encoder.h +++ b/src/lib/datasrc/memory/rdata_encoder.h @@ -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& data_result, std::vector& len_result); +// Callbacks used in foreachRdataField. typedef boost::function NameCallback; typedef boost::function 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& encoded_data, const std::vector& varlen_list, NameCallback name_callback, DataCallback data_callback); +} } // namespace memory } // namespace datasrc diff --git a/src/lib/datasrc/memory/tests/rdata_encoder_unittest.cc b/src/lib/datasrc/memory/tests/rdata_encoder_unittest.cc index 9a1ff10832..33c09afc0f 100644 --- a/src/lib/datasrc/memory/tests/rdata_encoder_unittest.cc +++ b/src/lib/datasrc/memory/tests/rdata_encoder_unittest.cc @@ -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 encoded_data; vector 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 need_additionals; need_additionals.insert(RRType::NS()); need_additionals.insert(RRType::MX());