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

[master] Merge branch 'trac2091b'

parents 3e4bfd2a 01d1c2a8
......@@ -297,18 +297,10 @@ encodeRdata(const rdata::Rdata& rdata, RRClass rrclass, RRType rrtype,
{
const Name name(ibuffer);
const LabelSequence labels(name);
size_t nlen;
const uint8_t* ndata = labels.getData(&nlen);
assert(nlen < 256); // nlen should fit in 8 bits
size_t olen;
uint8_t offset_holder[Name::MAX_LABELS];
labels.getOffsetData(&olen, offset_holder);
assert(olen < 256); // olen should fit in 8 bits
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);
uint8_t labels_holder[LabelSequence::MAX_SERIALIZED_LENGTH];
labels.serialize(labels_holder, sizeof(labels_holder));
data_result.insert(data_result.end(), labels_holder,
labels_holder + labels.getSerializedLength());
break;
}
}
......@@ -348,15 +340,11 @@ foreachRdataField(RRClass rrclass, RRType rrtype,
case RdataFieldSpec::DOMAIN_NAME:
{
++name_count;
const uint8_t nlen = encoded_data.at(off);
const uint8_t olen = encoded_data.at(off + 1);
const LabelSequence labels(&encoded_data.at(off));
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);
name_callback(labels, field_spec.name_attributes);
}
off += (2 + nlen + olen);
off += labels.getSerializedLength();
break;
}
}
......
......@@ -14,6 +14,8 @@
#include <exceptions/exceptions.h>
#include <util/memory_segment_local.h>
#include <dns/name.h>
#include <dns/nsec3hash.h>
#include <dns/rdataclass.h>
......@@ -120,19 +122,48 @@ typedef NSEC3Map::value_type NSEC3Pair;
// Actual zone data: Essentially a set of zone's RRs. This is defined as
// a separate structure so that it'll be replaceable on reload.
struct ZoneData {
// Note: this code is not entirely exception safe; domains_storage_ could
// leak if the constructor throws. But since it's an intermediate version
// toward a full revision and the actual risk of leak should be very small
// in practice, we leave it open for now.
ZoneData(const Name& origin) :
domains_(true),
domains_storage_(DomainTree::create(local_mem_sgmt_, true)),
domains_(*domains_storage_),
aux_wild_domains_(NULL),
origin_data_(NULL),
nsec_signed_(false)
{
// We create the node for origin (it needs to exist anyway in future)
domains_.insert(origin, &origin_data_);
domains_.insert(local_mem_sgmt_, origin, &origin_data_);
DomainPtr origin_domain(new Domain);
origin_data_->setData(origin_domain);
}
// The main data (name + RRsets)
DomainTree domains_;
~ZoneData() {
DomainTree::destroy(local_mem_sgmt_, domains_storage_);
if (aux_wild_domains_ != NULL) {
DomainTree::destroy(local_mem_sgmt_, aux_wild_domains_);
}
// The assert may be too harsh, but we assume we'll discard (rewrite)
// this code soon enough. Until then this would be a good way to
// detect any memory leak. Also, at that point we shouldn't use
// a single separate memory segment for each zone tree; normally
// zone data for multiple zones will be managed in a single segment.
assert(local_mem_sgmt_.allMemoryDeallocated());
}
// Memory segment to allocate/deallocate memory for the tree and the nodes.
// (This will eventually have to be abstract; for now we hardcode the
// specific derived segment class).
util::MemorySegmentLocal local_mem_sgmt_;
// The main data (name + RRsets). We use domains_ as a reference to
// domains_storage_ so we don't have to update the rest of the code;
// it will eventually have to be revised substantially, at which point
// we should clean this up, too.
DomainTree* domains_storage_;
DomainTree& domains_;
// An auxiliary tree for wildcard expanded data used in additional data
// processing. It contains names like "ns.wild.example" in the following
......@@ -150,11 +181,11 @@ struct ZoneData {
// should be even empty, and even if it has content it should be very
// small.
private:
scoped_ptr<DomainTree> aux_wild_domains_;
DomainTree* aux_wild_domains_;
public:
DomainTree& getAuxWildDomains() {
if (!aux_wild_domains_) {
aux_wild_domains_.reset(new DomainTree);
if (aux_wild_domains_ == NULL) {
aux_wild_domains_ = DomainTree::create(local_mem_sgmt_);
}
return (*aux_wild_domains_);
}
......@@ -448,15 +479,11 @@ ZoneData::findNode(const Name& name, RBTreeNodeChain<Domain>& node_path,
if (node->getFlag(domain_flag::WILD) && // maybe a wildcard, check only
(options & ZoneFinder::NO_WILDCARD) == 0) { // if not disabled.
if (node_path.getLastComparisonResult().getRelation() ==
NameComparisonResult::COMMONANCESTOR &&
node_path.getLastComparisonResult().getCommonLabels() > 1) {
// Wildcard canceled. Treat it as NXDOMAIN.
// Note: Because the way the tree stores relative names, we
// will have exactly one common label (the ".") in case we have
// nothing common under the node we got, and we will get
// more common labels otherwise (yes, this relies on the
// internal RBTree structure, which leaks out through this
// little bit).
NameComparisonResult::COMMONANCESTOR) {
// This means, e.g., we have *.wild.example and
// bar.foo.wild.example and are looking for
// baz.foo.wild.example. The common ancestor, foo.wild.example,
// should cancel wildcard. Treat it as NXDOMAIN.
LOG_DEBUG(logger, DBG_TRACE_DATA,
DATASRC_MEM_WILDCARD_CANCEL).arg(name);
return (ResultType(ZoneFinder::NXDOMAIN, NULL,
......@@ -857,7 +884,9 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
//
// We also perform the same trick for empty wild card names possibly
// contained in 'name' (e.g., '*.foo.example' in 'bar.*.foo.example').
void addWildcards(DomainTree& domains, const Name& name) {
void addWildcards(util::MemorySegment& mem_sgmt, DomainTree& domains,
const Name& name)
{
Name wname(name);
const unsigned int labels(wname.getLabelCount());
const unsigned int origin_labels(origin_.getLabelCount());
......@@ -870,7 +899,8 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
// Ensure a separate level exists for the "wildcarding" name,
// and mark the node as "wild".
DomainNode* node;
DomainTree::Result result(domains.insert(wname.split(1),
DomainTree::Result result(domains.insert(mem_sgmt,
wname.split(1),
&node));
assert(result == DomainTree::SUCCESS ||
result == DomainTree::ALREADYEXISTS);
......@@ -880,7 +910,7 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
// Note: for 'name' itself we do this later anyway, but the
// overhead should be marginal because wildcard names should
// be rare.
result = domains.insert(wname, &node);
result = domains.insert(mem_sgmt, wname, &node);
assert(result == DomainTree::SUCCESS ||
result == DomainTree::ALREADYEXISTS);
}
......@@ -1167,12 +1197,14 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
// tree.
// Note: this can throw an exception, breaking strong exception
// guarantee. (see also the note for contextCheck() below).
addWildcards(zone_data.domains_, rrset->getName());
addWildcards(zone_data.local_mem_sgmt_, zone_data.domains_,
rrset->getName());
// Get the node
DomainNode* node;
DomainTree::Result result = zone_data.domains_.insert(rrset->getName(),
&node);
DomainTree::Result result =
zone_data.domains_.insert(zone_data.local_mem_sgmt_,
rrset->getName(), &node);
// Just check it returns reasonable results
assert((result == DomainTree::SUCCESS ||
result == DomainTree::ALREADYEXISTS) && node!= NULL);
......@@ -1605,7 +1637,8 @@ addAdditional(RBNodeRRset* rrset, ZoneData* zone_data,
// Wildcard and glue shouldn't coexist. Make it sure here.
assert(!node->getFlag(domain_flag::GLUE));
if (zone_data->getAuxWildDomains().insert(name, &wildnode)
if (zone_data->getAuxWildDomains().insert(
zone_data->local_mem_sgmt_, name, &wildnode)
== DomainTree::SUCCESS) {
// If we first insert the node, copy the RRsets. If the
// original node was empty, we add empty data so
......@@ -1782,9 +1815,22 @@ InMemoryZoneFinder::getFileName() const {
/// member variables later for new features.
class InMemoryClient::InMemoryClientImpl {
public:
InMemoryClientImpl() : zone_count(0) {}
InMemoryClientImpl() : zone_count(0),
zone_table(ZoneTable::create(local_mem_sgmt))
{}
~InMemoryClientImpl() {
ZoneTable::destroy(local_mem_sgmt, zone_table);
// see above for the assert().
assert(local_mem_sgmt.allMemoryDeallocated());
}
// Memory segment to allocate/deallocate memory for the zone table.
// (This will eventually have to be abstract; for now we hardcode the
// specific derived segment class).
util::MemorySegmentLocal local_mem_sgmt;
unsigned int zone_count;
ZoneTable zone_table;
ZoneTable* zone_table;
};
InMemoryClient::InMemoryClient() : impl_(new InMemoryClientImpl)
......@@ -1809,7 +1855,8 @@ InMemoryClient::addZone(ZoneFinderPtr zone_finder) {
LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_ADD_ZONE).
arg(zone_finder->getOrigin()).arg(zone_finder->getClass().toText());
const result::Result result = impl_->zone_table.addZone(zone_finder);
const result::Result result =
impl_->zone_table->addZone(impl_->local_mem_sgmt, zone_finder);
if (result == result::SUCCESS) {
++impl_->zone_count;
}
......@@ -1819,7 +1866,7 @@ InMemoryClient::addZone(ZoneFinderPtr zone_finder) {
InMemoryClient::FindResult
InMemoryClient::findZone(const isc::dns::Name& name) const {
LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_FIND_ZONE).arg(name);
ZoneTable::FindResult result(impl_->zone_table.findZone(name));
ZoneTable::FindResult result(impl_->zone_table->findZone(name));
return (FindResult(result.code, result.zone));
}
......@@ -1925,7 +1972,7 @@ public:
ZoneIteratorPtr
InMemoryClient::getIterator(const Name& name, bool separate_rrs) const {
ZoneTable::FindResult result(impl_->zone_table.findZone(name));
ZoneTable::FindResult result(impl_->zone_table->findZone(name));
if (result.code != result::SUCCESS) {
isc_throw(DataSourceError, "No such zone: " + name.toText());
}
......
This diff is collapsed.
......@@ -60,6 +60,7 @@ run_unittests_SOURCES += sqlite3_unittest.cc
run_unittests_SOURCES += sqlite3_accessor_unittest.cc
run_unittests_SOURCES += memory_datasrc_unittest.cc
run_unittests_SOURCES += rbnode_rrset_unittest.cc
run_unittests_SOURCES += zonetable_unittest.cc
run_unittests_SOURCES += zone_finder_context_unittest.cc
run_unittests_SOURCES += faked_nsec3.h faked_nsec3.cc
run_unittests_SOURCES += client_list_unittest.cc
......
This diff is collapsed.
......@@ -14,6 +14,8 @@
#include <exceptions/exceptions.h>
#include <util/memory_segment_local.h>
#include <dns/name.h>
#include <dns/rrclass.h>
......@@ -40,7 +42,7 @@ TEST(ZoneTest, init) {
TEST(ZoneTest, find) {
InMemoryZoneFinder zone(RRClass::IN(), Name("example.com"));
EXPECT_EQ(ZoneFinder::NXDOMAIN,
zone.find(Name("www.example.com"), RRType::A()).code);
zone.find(Name("www.example.com"), RRType::A())->code);
}
class ZoneTableTest : public ::testing::Test {
......@@ -50,68 +52,77 @@ protected:
zone2(new InMemoryZoneFinder(RRClass::IN(),
Name("example.net"))),
zone3(new InMemoryZoneFinder(RRClass::IN(),
Name("example")))
Name("example"))),
zone_table(ZoneTable::create(mem_sgmt_))
{}
ZoneTable zone_table;
~ZoneTableTest() {
ZoneTable::destroy(mem_sgmt_, zone_table);
}
ZoneFinderPtr zone1, zone2, zone3;
isc::util::MemorySegmentLocal mem_sgmt_;
ZoneTable* zone_table;
};
TEST_F(ZoneTableTest, addZone) {
EXPECT_EQ(result::SUCCESS, zone_table.addZone(zone1));
EXPECT_EQ(result::EXIST, zone_table.addZone(zone1));
EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone1));
EXPECT_EQ(result::EXIST, zone_table->addZone(mem_sgmt_, zone1));
// names are compared in a case insensitive manner.
EXPECT_EQ(result::EXIST, zone_table.addZone(
EXPECT_EQ(result::EXIST, zone_table->addZone(
mem_sgmt_,
ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
Name("EXAMPLE.COM")))));
EXPECT_EQ(result::SUCCESS, zone_table.addZone(zone2));
EXPECT_EQ(result::SUCCESS, zone_table.addZone(zone3));
EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone2));
EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone3));
// Zone table is indexed only by name. Duplicate origin name with
// different zone class isn't allowed.
EXPECT_EQ(result::EXIST, zone_table.addZone(
EXPECT_EQ(result::EXIST, zone_table->addZone(
mem_sgmt_,
ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
Name("example.com")))));
/// Bogus zone (NULL)
EXPECT_THROW(zone_table.addZone(ZoneFinderPtr()), isc::InvalidParameter);
EXPECT_THROW(zone_table->addZone(mem_sgmt_, ZoneFinderPtr()),
isc::InvalidParameter);
}
TEST_F(ZoneTableTest, DISABLED_removeZone) {
EXPECT_EQ(result::SUCCESS, zone_table.addZone(zone1));
EXPECT_EQ(result::SUCCESS, zone_table.addZone(zone2));
EXPECT_EQ(result::SUCCESS, zone_table.addZone(zone3));
EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone1));
EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone2));
EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone3));
EXPECT_EQ(result::SUCCESS, zone_table.removeZone(Name("example.net")));
EXPECT_EQ(result::NOTFOUND, zone_table.removeZone(Name("example.net")));
EXPECT_EQ(result::SUCCESS, zone_table->removeZone(Name("example.net")));
EXPECT_EQ(result::NOTFOUND, zone_table->removeZone(Name("example.net")));
}
TEST_F(ZoneTableTest, findZone) {
EXPECT_EQ(result::SUCCESS, zone_table.addZone(zone1));
EXPECT_EQ(result::SUCCESS, zone_table.addZone(zone2));
EXPECT_EQ(result::SUCCESS, zone_table.addZone(zone3));
EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone1));
EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone2));
EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone3));
EXPECT_EQ(result::SUCCESS, zone_table.findZone(Name("example.com")).code);
EXPECT_EQ(result::SUCCESS, zone_table->findZone(Name("example.com")).code);
EXPECT_EQ(Name("example.com"),
zone_table.findZone(Name("example.com")).zone->getOrigin());
zone_table->findZone(Name("example.com")).zone->getOrigin());
EXPECT_EQ(result::NOTFOUND,
zone_table.findZone(Name("example.org")).code);
zone_table->findZone(Name("example.org")).code);
EXPECT_EQ(ConstZoneFinderPtr(),
zone_table.findZone(Name("example.org")).zone);
zone_table->findZone(Name("example.org")).zone);
// there's no exact match. the result should be the longest match,
// and the code should be PARTIALMATCH.
EXPECT_EQ(result::PARTIALMATCH,
zone_table.findZone(Name("www.example.com")).code);
zone_table->findZone(Name("www.example.com")).code);
EXPECT_EQ(Name("example.com"),
zone_table.findZone(Name("www.example.com")).zone->getOrigin());
zone_table->findZone(Name("www.example.com")).zone->getOrigin());
// make sure the partial match is indeed the longest match by adding
// a zone with a shorter origin and query again.
ZoneFinderPtr zone_com(new InMemoryZoneFinder(RRClass::IN(), Name("com")));
EXPECT_EQ(result::SUCCESS, zone_table.addZone(zone_com));
EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone_com));
EXPECT_EQ(Name("example.com"),
zone_table.findZone(Name("www.example.com")).zone->getOrigin());
zone_table->findZone(Name("www.example.com")).zone->getOrigin());
}
}
......@@ -12,13 +12,15 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <cassert>
#include <util/memory_segment.h>
#include <dns/name.h>
#include <datasrc/zonetable.h>
#include <datasrc/rbtree.h>
#include <cassert>
using namespace std;
using namespace isc::dns;
......@@ -30,8 +32,14 @@ struct ZoneTable::ZoneTableImpl {
// Type aliases to make it shorter
typedef RBTree<ZoneFinder> ZoneTree;
typedef RBNode<ZoneFinder> ZoneNode;
// The actual storage
ZoneTree zones_;
ZoneTree* zones_;
// Constructor
ZoneTableImpl(util::MemorySegment& mem_sgmt) :
zones_(ZoneTree::create(mem_sgmt))
{}
/*
* The implementation methods are here and just wrap-called in the
......@@ -40,7 +48,7 @@ struct ZoneTable::ZoneTableImpl {
*/
// Implementation of ZoneTable::addZone
result::Result addZone(ZoneFinderPtr zone) {
result::Result addZone(util::MemorySegment& mem_sgmt, ZoneFinderPtr zone) {
// Sanity check
if (!zone) {
isc_throw(InvalidParameter,
......@@ -49,7 +57,7 @@ struct ZoneTable::ZoneTableImpl {
// Get the node where we put the zone
ZoneNode* node(NULL);
switch (zones_.insert(zone->getOrigin(), &node)) {
switch (zones_->insert(mem_sgmt, zone->getOrigin(), &node)) {
// This is OK
case ZoneTree::SUCCESS:
case ZoneTree::ALREADYEXISTS:
......@@ -76,7 +84,7 @@ struct ZoneTable::ZoneTableImpl {
result::Result my_result;
// Translate the return codes
switch (zones_.find(name, &node)) {
switch (zones_->find(name, &node)) {
case ZoneTree::EXACTMATCH:
my_result = result::SUCCESS;
break;
......@@ -100,16 +108,39 @@ struct ZoneTable::ZoneTableImpl {
}
};
ZoneTable::ZoneTable() : impl_(new ZoneTableImpl)
ZoneTable::ZoneTable(util::MemorySegment& mem_sgmt) :
impl_(new ZoneTableImpl(mem_sgmt))
{}
ZoneTable::~ZoneTable() {
delete impl_;
}
ZoneTable*
ZoneTable::create(util::MemorySegment& mem_sgmt) {
// The ZoneTable constructor can throw, so we need to prevent memory leak.
// This is ugly, but for now this seems to be the only place we need
// this, and since we'll substantially revise this code soon, so we don't
// work around it by this hack at the moment.
void* p = mem_sgmt.allocate(sizeof(ZoneTable));
try {
return (new(p) ZoneTable(mem_sgmt));
} catch (...) {
mem_sgmt.deallocate(p, sizeof(ZoneTable));
throw;
}
}
void
ZoneTable::destroy(util::MemorySegment& mem_sgmt, ZoneTable* ztable) {
ZoneTableImpl::ZoneTree::destroy(mem_sgmt, ztable->impl_->zones_);
ztable->~ZoneTable();
mem_sgmt.deallocate(ztable, sizeof(ZoneTable));
}
result::Result
ZoneTable::addZone(ZoneFinderPtr zone) {
return (impl_->addZone(zone));
ZoneTable::addZone(util::MemorySegment& mem_sgmt, ZoneFinderPtr zone) {
return (impl_->addZone(mem_sgmt, zone));
}
result::Result
......
......@@ -15,12 +15,14 @@
#ifndef __ZONETABLE_H
#define __ZONETABLE_H 1
#include <boost/shared_ptr.hpp>
#include <util/memory_segment.h>
#include <dns/rrset.h>
#include <datasrc/zone.h>
#include <boost/shared_ptr.hpp>
namespace isc {
namespace dns {
class Name;
......@@ -58,18 +60,47 @@ private:
ZoneTable(const ZoneTable& source);
ZoneTable& operator=(const ZoneTable& source);
public:
/// Default constructor.
/// Constructor.
///
/// An object of this class is always expected to be created by the
/// allocator (\c create()), so the constructor is hidden as private.
///
/// This constructor internally involves resource allocation, and if
/// it fails, a corresponding standard exception will be thrown.
/// It never throws an exception otherwise.
ZoneTable();
ZoneTable(util::MemorySegment& mem_sgmt);
/// The destructor.
///
/// An object of this class is always expected to be destroyed explicitly
/// by \c destroy(), so the constructor is hidden as private.
~ZoneTable();
//@}
public:
/// \brief Allocate and construct \c ZoneTable
///
/// This static method allocates memory for a new \c ZoneTable object
/// from the given memory segment, constructs the object, and returns
/// a pointer to it.
///
/// \throw std::bad_alloc Memory allocation fails.
///
/// \param mem_sgmt A \c MemorySegment from which memory for the new
/// \c ZoneTable is allocated.
static ZoneTable* create(util::MemorySegment& mem_sgmt);
/// \brief Destruct and deallocate \c ZoneTable
///
/// \throw none
///
/// \param mem_sgmt The \c MemorySegment that allocated memory for
/// \c ztable.
/// \param ztable A non NULL pointer to a valid \c ZoneTable object
/// that was originally created by the \c create() method (the behavior
/// is undefined if this condition isn't met).
static void destroy(util::MemorySegment& mem_sgmt, ZoneTable* ztable);
/// Add a \c Zone to the \c ZoneTable.
///
/// \c Zone must not be associated with a NULL pointer; otherwise
......@@ -83,7 +114,7 @@ public:
/// added to the zone table.
/// \return \c result::EXIST The zone table already contains
/// zone of the same origin.
result::Result addZone(ZoneFinderPtr zone);
result::Result addZone(util::MemorySegment& mem_sgmt, ZoneFinderPtr zone);
/// Remove a \c Zone of the given origin name from the \c ZoneTable.
///
......
......@@ -23,62 +23,75 @@
namespace isc {
namespace dns {
LabelSequence::LabelSequence(const uint8_t* data,
const uint8_t* offsets,
size_t offsets_size) : data_(data),
offsets_(offsets),
offsets_size_(offsets_size),
first_label_(0),
last_label_(offsets_size_)
{
if (data == NULL || offsets == NULL) {
isc_throw(BadValue, "Null pointer passed to LabelSequence constructor");
}
if (offsets_size == 0) {
isc_throw(BadValue, "Zero offsets to LabelSequence constructor");
LabelSequence::LabelSequence(const void* buf) {
if (buf == NULL) {
isc_throw(BadValue,
"Null pointer passed to LabelSequence constructor");
}
if (offsets_size > Name::MAX_LABELS) {
isc_throw(BadValue, "MAX_LABELS exceeded");
const uint8_t* bp = reinterpret_cast<const uint8_t*>(buf);
first_label_ = 0;
const uint8_t offsets_len = *bp++;
if (offsets_len == 0 || offsets_len > Name::MAX_LABELS) {
isc_throw(BadValue,
"Bad offsets len in serialized LabelSequence data: "
<< static_cast<unsigned int>(offsets_len));
}
for (size_t cur_offset = 0; cur_offset < offsets_size; ++cur_offset) {
if (offsets[cur_offset] > Name::MAX_LABELLEN) {
isc_throw(BadValue, "MAX_LABEL_LEN exceeded");
}
if (cur_offset > 0 && offsets[cur_offset] <= offsets[cur_offset - 1]) {
isc_throw(BadValue, "Offset smaller than previous offset");
last_label_ = offsets_len - 1;
offsets_ = bp;
data_ = bp + offsets_len;
// Check the integrity on the offsets and the name data
const uint8_t* dp = data_;
for (size_t cur_offset = 0; cur_offset < offsets_len; ++cur_offset) {
if (offsets_[cur_offset] > Name::MAX_LABELLEN ||
dp - data_ != offsets_[cur_offset]) {
isc_throw(BadValue,