123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605 |
- // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- // PERFORMANCE OF THIS SOFTWARE.
- #include <exceptions/exceptions.h>
- #include <util/buffer.h>
- #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 "rdata_encoder.h"
- #include <boost/static_assert.hpp>
- #include <cassert>
- #include <cstring>
- #include <vector>
- #include <stdint.h>
- using namespace isc::dns;
- using std::vector;
- namespace isc {
- namespace datasrc {
- namespace memory {
- namespace {
- /// Specification of a single RDATA field in terms of internal encoding.
- struct RdataFieldSpec {
- enum FieldType {
- FIXEDLEN_DATA = 0, // fixed-length data field
- VARLEN_DATA, // variable-length data field
- DOMAIN_NAME // domain name
- };
- 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 {
- // 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 {
- 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);
- const uint16_t NAMEATTR_ADDITIONAL_INITIALIZER =
- static_cast<uint16_t>(NAMEATTR_ADDITIONAL);
- const uint16_t NAMEATTR_COMPADDITIONAL_INITIALIZER =
- static_cast<uint16_t>(NAMEATTR_COMPRESSIBLE | NAMEATTR_ADDITIONAL);
- // 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);
- const RdataEncodeSpec generic_data_spec = {
- n_generic_data_fields, 0, 1, generic_data_fields
- };
- // 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);
- // There are several RR types that consist of a single domain name.
- const RdataFieldSpec single_noattr_name_fields[] = {
- {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_NOATTRIBUTE_INITIALIZER}}
- };
- const RdataFieldSpec single_compressible_name_fields[] = {
- {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_COMPRESSIBLE_INITIALIZER}}
- };
- const RdataFieldSpec single_compadditional_name_fields[] = {
- {RdataFieldSpec::DOMAIN_NAME,
- {NAMEATTR_COMPRESSIBLE_INITIALIZER|NAMEATTR_COMPADDITIONAL_INITIALIZER}}
- };
- const uint16_t n_single_name_fields =
- sizeof(single_noattr_name_fields) / sizeof(RdataFieldSpec);
- // RDATA consisting of two names. There are some of this type.
- const RdataFieldSpec double_compressible_name_fields[] = {
- {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_COMPRESSIBLE_INITIALIZER}},
- {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_COMPRESSIBLE_INITIALIZER}}
- };
- const RdataFieldSpec double_noattr_name_fields[] = {
- {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_NOATTRIBUTE_INITIALIZER}},
- {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_NOATTRIBUTE_INITIALIZER}}
- };
- const uint16_t n_double_name_fields =
- sizeof(double_compressible_name_fields) / sizeof(RdataFieldSpec);
- // 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}},
- {RdataFieldSpec::FIXEDLEN_DATA, {sizeof(uint32_t) * 5}}
- };
- const uint16_t n_soa_fields = sizeof(soa_fields) / sizeof(RdataFieldSpec);
- // MX specific: 16-bit data + compressible/additional name
- const RdataFieldSpec mx_fields[] = {
- {RdataFieldSpec::FIXEDLEN_DATA, {sizeof(uint16_t)}},
- {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_COMPADDITIONAL_INITIALIZER}}
- };
- const uint16_t n_mx_fields = sizeof(mx_fields) / sizeof(RdataFieldSpec);
- // AFSDB specific: 16-bit data + no-attribute name
- const RdataFieldSpec afsdb_fields[] = {
- {RdataFieldSpec::FIXEDLEN_DATA, {sizeof(uint16_t)}},
- {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_NOATTRIBUTE_INITIALIZER}}
- };
- const uint16_t n_afsdb_fields = sizeof(afsdb_fields) / sizeof(RdataFieldSpec);
- // SRV specific: 3*16-bit data + additional name
- const RdataFieldSpec srv_fields[] = {
- {RdataFieldSpec::FIXEDLEN_DATA, {sizeof(uint16_t) * 3}},
- {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_ADDITIONAL_INITIALIZER}}
- };
- const uint16_t n_srv_fields = sizeof(srv_fields) / sizeof(RdataFieldSpec);
- // NAPTR specific: (multi-field) variable data + (additional) name
- // NAPTR requires complicated additional section handling; for now, we skip
- // the additional handling completely.
- const RdataFieldSpec naptr_fields[] = {
- {RdataFieldSpec::VARLEN_DATA, {0}},
- {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_NOATTRIBUTE_INITIALIZER}}
- };
- const uint16_t n_naptr_fields = sizeof(naptr_fields) / sizeof(RdataFieldSpec);
- // NSEC specific: no-attribute name + varlen data
- const RdataFieldSpec nsec_fields[] = {
- {RdataFieldSpec::DOMAIN_NAME, {NAMEATTR_NOATTRIBUTE_INITIALIZER}},
- {RdataFieldSpec::VARLEN_DATA, {0}}
- };
- const uint16_t n_nsec_fields = sizeof(nsec_fields) / sizeof(RdataFieldSpec);
- // 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
- {n_single_name_fields, 1, 0, single_compadditional_name_fields}, // #2: NS
- generic_data_spec, // #3
- generic_data_spec, // #4
- {n_single_name_fields, 1, 0, single_compressible_name_fields}, // #5: CNAME
- {n_soa_fields, 2, 0, soa_fields}, // #6: SOA
- generic_data_spec, // #7
- generic_data_spec, // #8
- generic_data_spec, // #9
- generic_data_spec, // #10
- generic_data_spec, // #11
- {n_single_name_fields, 1, 0, single_compressible_name_fields}, // #12: PTR
- generic_data_spec, // #13: HINFO
- {n_double_name_fields, 2, 0, double_compressible_name_fields}, // #14:HINFO
- {n_mx_fields, 1, 0, mx_fields}, // #15: MX
- generic_data_spec, // #16: TXT
- {n_double_name_fields, 2, 0, double_noattr_name_fields}, // 17: RP
- {n_afsdb_fields, 1, 0, afsdb_fields}, // #18: AFSDB
- // #19-#26
- generic_data_spec, generic_data_spec, generic_data_spec, generic_data_spec,
- generic_data_spec, generic_data_spec, generic_data_spec, generic_data_spec,
- generic_data_spec, // #27
- {n_ipv6_fields, 0, 0, single_ipv6_fields}, // #28: AAAA
- // #29-#32
- generic_data_spec, generic_data_spec, generic_data_spec, generic_data_spec,
- {n_srv_fields, 1, 0, srv_fields}, // #33: SRV
- generic_data_spec, // #34
- {n_naptr_fields, 1, 1, naptr_fields}, // #35: NAPTR
- generic_data_spec, // #36
- generic_data_spec, // #37
- generic_data_spec, // #38
- {n_single_name_fields, 1, 0, single_noattr_name_fields}, // #39 DNAME
- generic_data_spec, // #40
- generic_data_spec, // #41 (OPT)
- generic_data_spec, // #42
- generic_data_spec, // #43: DS (this is opaque for encoding purposes)
- generic_data_spec, // #44: SSHFP (this is opaque for encoding purposes)
- generic_data_spec, // #45
- generic_data_spec, // #46: RRSIG (this is opaque for encoding purposes)
- {n_nsec_fields, 1, 1, nsec_fields} // #47: NSEC
- // All others can be treated as single-field variable length data, at
- // 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);
- 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()]);
- }
- return (generic_data_spec);
- }
- // This class is a helper for RdataEncoder to divide the content of RDATA
- // fields for encoding by "abusing" the message rendering logic.
- // The idea is to identify domain name fields in the writeName() method,
- // while keeping track of the size and position of other types of data
- // around the names.
- //
- // Technically, this use of inheritance may be considered a violation of
- // Liskov Substitution Principle in that it doesn't actually compress domain
- // names, and some of the methods are not expected to be used.
- // In fact, skip() or trim() may not be make much sense in this context.
- // Nevertheless we keep this idea at the moment. Since the usage is limited
- // (it's only used within this file, and only used with \c Rdata variants),
- // it's hopefully an acceptable practice.
- class RdataFieldComposer : public AbstractMessageRenderer {
- public:
- RdataFieldComposer() : last_data_pos_(0), encode_spec_(NULL),
- current_field_(0)
- {}
- virtual ~RdataFieldComposer() {}
- virtual bool isTruncated() const { return (false); }
- virtual size_t getLengthLimit() const { return (65535); }
- virtual CompressMode getCompressMode() const { return (CASE_INSENSITIVE); }
- virtual void setTruncated() {}
- virtual void setLengthLimit(size_t) {}
- virtual void setCompressMode(CompressMode) {}
- // Called for each domain name in the RDATA, from the RDATA's toWire()
- // implementation.
- virtual void writeName(const Name& name, bool compress) {
- // First, after checking the spec consistency, see if we have other
- // data already stored in the renderer's buffer.
- if (current_field_ >= encode_spec_->field_count) {
- isc_throw(BadValue,
- "RDATA encoder encounters an unexpected name data: " <<
- name);
- }
- updateOtherData();
- // If there are data fields, current_field_ has been updated. We
- // should still be expected to have a domain name in the spec.
- if (current_field_ >= encode_spec_->field_count) {
- isc_throw(BadValue,
- "RDATA encoder encounters an unexpected name data: " <<
- name);
- }
- // At this point it's ensured we still have a field in the spec,
- // and it's a domain name field.
- const RdataFieldSpec& field =
- encode_spec_->fields[current_field_++];
- assert(field.type == RdataFieldSpec::DOMAIN_NAME);
- // It would be compressed iff the field has that attribute.
- if (compress !=
- ((field.name_attributes & NAMEATTR_COMPRESSIBLE) != 0)) {
- isc_throw(BadValue, "RDATA encoder error, inconsistent name "
- "compression policy: " << name);
- }
- const LabelSequence labels(name);
- labels.serialize(labels_placeholder_, sizeof(labels_placeholder_));
- writeData(labels_placeholder_, labels.getSerializedLength());
- last_data_pos_ += labels.getSerializedLength();
- }
- // Clear all internal states and resources for a new set of RDATA.
- void clearLocal(const RdataEncodeSpec* encode_spec) {
- AbstractMessageRenderer::clear();
- encode_spec_ = encode_spec;
- data_lengths_.clear();
- last_data_pos_ = 0;
- }
- // Called at the beginning of an RDATA.
- void startRdata() {
- current_field_ = 0;
- }
- // Called at the end of an RDATA.
- void endRdata() {
- // Handle any remaining data (there should be no more name). Then
- // we should reach the end of the fields.
- if (current_field_ < encode_spec_->field_count) {
- updateOtherData();
- }
- if (current_field_ != encode_spec_->field_count) {
- isc_throw(BadValue, "RDATA encoder finds missing field");
- }
- }
- // Hold the lengths of variable length fields, in the order of their
- // appearance. For convenience, allow the encoder to refer to it
- // directly.
- vector<uint16_t> data_lengths_;
- private:
- // We use generict write* methods, with the exception of writeName.
- // So new data can arrive without us knowing it, this considers all new
- // data to be just data, checking consistency with the field spec, and
- // if it contains variable-length field, record its length.
- size_t last_data_pos_;
- void updateOtherData() {
- const size_t cur_pos = getLength();
- size_t data_len = cur_pos - last_data_pos_;
- while (current_field_ < encode_spec_->field_count) {
- const RdataFieldSpec& field = encode_spec_->fields[current_field_];
- if (field.type == RdataFieldSpec::DOMAIN_NAME) {
- return;
- }
- ++current_field_;
- if (field.type == RdataFieldSpec::FIXEDLEN_DATA) {
- if (data_len < field.fixeddata_len) {
- isc_throw(BadValue,
- "RDATA encoding: available data too short "
- "for the type");
- }
- data_len -= field.fixeddata_len;
- continue;
- }
- // We are looking at a variable-length data field. For encoding
- // purposes, it's a single field covering all data, even if it
- // may consist of multiple fields as DNS RDATA (e.g. TXT).
- if (data_len > 0xffff) {
- isc_throw(RdataEncodingError, "RDATA field is too large: "
- << data_len << " bytes");
- }
- data_lengths_.push_back(data_len);
- data_len = 0;
- break;
- }
- // We've reached the end of the RDATA or just consumed a variable
- // length data field. So we should have eaten all available data
- // at this moment.
- if (data_len != 0) {
- isc_throw(BadValue, "redundant data for encoding in RDATA");
- }
- last_data_pos_ = cur_pos;
- }
- // The RDATA field spec of the current session. Set at the beginning of
- // each session.
- const RdataEncodeSpec* encode_spec_;
- // the RDATA field (for encoding) currently handled. Reset to 0 for
- // each RDATA of the session.
- size_t current_field_;
- // Placeholder to convert a name object to a label sequence.
- uint8_t labels_placeholder_[LabelSequence::MAX_SERIALIZED_LENGTH];
- };
- } // end of unnamed namespace
- struct RdataEncoder::RdataEncoderImpl {
- RdataEncoderImpl() : encode_spec_(NULL), rrsig_buffer_(0),
- rdata_count_(0)
- {}
- const RdataEncodeSpec* encode_spec_; // encode spec of current RDATA set
- RdataFieldComposer field_composer_;
- util::OutputBuffer rrsig_buffer_;
- size_t rdata_count_;
- vector<uint16_t> rrsig_lengths_;
- };
- RdataEncoder::RdataEncoder() :
- impl_(new RdataEncoderImpl)
- {}
- RdataEncoder::~RdataEncoder() {
- delete impl_;
- }
- void
- RdataEncoder::start(RRClass rrclass, RRType rrtype) {
- if (rrtype == RRType::RRSIG()) {
- isc_throw(BadValue, "RRSIG cannot be encoded as main RDATA type");
- }
- impl_->encode_spec_ = &getRdataEncodeSpec(rrclass, rrtype);
- impl_->field_composer_.clearLocal(impl_->encode_spec_);
- impl_->rrsig_buffer_.clear();
- impl_->rdata_count_ = 0;
- impl_->rrsig_lengths_.clear();
- }
- void
- RdataEncoder::addRdata(const rdata::Rdata& rdata) {
- if (impl_->encode_spec_ == NULL) {
- isc_throw(InvalidOperation,
- "RdataEncoder::addRdata performed before start");
- }
- impl_->field_composer_.startRdata();
- rdata.toWire(impl_->field_composer_);
- impl_->field_composer_.endRdata();
- ++impl_->rdata_count_;
- }
- void
- RdataEncoder::addSIGRdata(const rdata::Rdata& sig_rdata) {
- if (impl_->encode_spec_ == NULL) {
- isc_throw(InvalidOperation,
- "RdataEncoder::addSIGRdata performed before start");
- }
- const size_t cur_pos = impl_->rrsig_buffer_.getLength();
- sig_rdata.toWire(impl_->rrsig_buffer_);
- const size_t rrsig_datalen = impl_->rrsig_buffer_.getLength() - cur_pos;
- if (rrsig_datalen > 0xffff) {
- isc_throw(RdataEncodingError, "RRSIG is too large: "
- << rrsig_datalen << " bytes");
- }
- impl_->rrsig_lengths_.push_back(rrsig_datalen);
- }
- size_t
- RdataEncoder::getStorageLength() const {
- if (impl_->encode_spec_ == NULL) {
- isc_throw(InvalidOperation,
- "RdataEncoder::getStorageLength performed before start");
- }
- return (sizeof(uint16_t) * impl_->field_composer_.data_lengths_.size() +
- sizeof(uint16_t) * impl_->rrsig_lengths_.size() +
- impl_->rrsig_buffer_.getLength() +
- impl_->field_composer_.getLength());
- }
- void
- RdataEncoder::encode(void* buf, size_t buf_len) const {
- if (impl_->encode_spec_ == NULL) {
- isc_throw(InvalidOperation,
- "RdataEncoder::encode performed before start");
- }
- if (buf == NULL) {
- isc_throw(BadValue,
- "RdataEncoder::encode NULL buffer is given");
- }
- if (getStorageLength() > buf_len) {
- isc_throw(BadValue, "RdataEncoder::encode short buffer given");
- }
- uint8_t* const dp_beg = reinterpret_cast<uint8_t*>(buf);
- uint8_t* dp = dp_beg;
- uint16_t* lenp = reinterpret_cast<uint16_t*>(buf);
- // Encode list of lengths for variable length fields (if any)
- if (!impl_->field_composer_.data_lengths_.empty()) {
- const size_t varlen_fields_len =
- impl_->field_composer_.data_lengths_.size() * sizeof(uint16_t);
- std::memcpy(lenp, &impl_->field_composer_.data_lengths_[0],
- varlen_fields_len);
- lenp += impl_->field_composer_.data_lengths_.size();
- dp += varlen_fields_len;
- }
- // Encode list of lengths for RRSIGs (if any)
- if (!impl_->rrsig_lengths_.empty()) {
- const size_t rrsigs_len =
- impl_->rrsig_lengths_.size() * sizeof(uint16_t);
- std::memcpy(lenp, &impl_->rrsig_lengths_[0], rrsigs_len);
- dp += rrsigs_len;
- }
- // Encode main RDATA
- std::memcpy(dp, impl_->field_composer_.getData(),
- impl_->field_composer_.getLength());
- dp += impl_->field_composer_.getLength();
- // Encode RRSIGs, if any
- std::memcpy(dp, impl_->rrsig_buffer_.getData(),
- impl_->rrsig_buffer_.getLength());
- dp += impl_->rrsig_buffer_.getLength();
- // The validation at the entrance must ensure this
- assert(buf_len >= dp - dp_beg);
- }
- namespace testing {
- void
- foreachRdataField(RRClass rrclass, RRType rrtype,
- size_t rdata_count,
- 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;
- size_t varlen_count = 0;
- size_t name_count = 0;
- for (size_t count = 0; count < rdata_count; ++count) {
- 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.at(off),
- field_spec.fixeddata_len);
- }
- off += field_spec.fixeddata_len;
- break;
- case RdataFieldSpec::VARLEN_DATA:
- {
- const size_t varlen = varlen_list.at(varlen_count);
- if (data_callback && varlen > 0) {
- data_callback(&encoded_data.at(off), varlen);
- }
- off += varlen;
- ++varlen_count;
- break;
- }
- case RdataFieldSpec::DOMAIN_NAME:
- {
- ++name_count;
- const LabelSequence labels(&encoded_data.at(off));
- if (name_callback) {
- name_callback(labels, field_spec.name_attributes);
- }
- off += labels.getSerializedLength();
- break;
- }
- }
- }
- }
- assert(name_count == encode_spec.name_count * rdata_count);
- assert(varlen_count == encode_spec.varlen_count * rdata_count);
- }
- void
- foreachRRSig(const vector<uint8_t>& encoded_data,
- const vector<uint16_t>& rrsiglen_list,
- DataCallback data_callback)
- {
- size_t rrsig_totallen = 0;
- for (vector<uint16_t>::const_iterator it = rrsiglen_list.begin();
- it != rrsiglen_list.end();
- ++it) {
- rrsig_totallen += *it;
- }
- assert(encoded_data.size() >= rrsig_totallen);
- const uint8_t* dp = &encoded_data[encoded_data.size() - rrsig_totallen];
- for (size_t i = 0; i < rrsiglen_list.size(); ++i) {
- data_callback(dp, rrsiglen_list[i]);
- dp += rrsiglen_list[i];
- }
- }
- } // namespace testing
- } // namespace memory
- } // namespace datasrc
- } // datasrc isc
|