Commit cd6beb6c authored by Jelte Jansen's avatar Jelte Jansen
Browse files

[trac497] added a Message::clearSection() and resolve::makeErrorMessage

clearSection is a convenience function to clear all RRsets in a message
used by makeErrorMessage, which is a helper function to quickly clear
any data built up in the answer so far, and set an error Rcode
parent 0c303cb2
......@@ -52,6 +52,7 @@ using namespace boost;
// Is this something we can use in libdns++?
namespace {
// TODO: remove
class SectionInserter {
public:
SectionInserter(MessagePtr message, const Message::Section sect) :
......@@ -65,6 +66,7 @@ namespace {
};
// TODO: move to resolve.cc
/// \brief Copies the parts relevant for a DNS answer to the
/// target message
///
......@@ -431,7 +433,8 @@ private:
// Note that the footprint may change as this function may
// need to append data to the answer we are building later.
//
// returns true if we are done
// returns true if we are done (either we have an answer or an
// error message)
// returns false if we are not done
bool handleRecursiveAnswer(const Message& incoming) {
dlog("Handle response");
......@@ -458,7 +461,8 @@ private:
// TODO: make SERVFAIL? clear currently read answers?
// just copy for now.
dlog("CNAME chain too long");
copyAnswerMessage(incoming, answer_message_);
isc::resolve::makeErrorMessage(answer_message_,
Rcode::SERVFAIL());
return true;
}
......
......@@ -338,6 +338,14 @@ Message::removeRRset(const Section section, RRsetIterator& iterator) {
return (removed);
}
void
Message::clearSection(const Section section) {
if (section >= MessageImpl::NUM_SECTIONS) {
isc_throw(OutOfRange, "Invalid message section: " << section);
}
impl_->rrsets_[section].clear();
impl_->counts_[section] = 0;
}
void
Message::addQuestion(const QuestionPtr question) {
......
......@@ -483,6 +483,11 @@ public:
/// found in the specified section.
bool removeRRset(const Section section, RRsetIterator& iterator);
/// \brief Remove all RRSets from the given Section
///
/// \param section Section to remove all rrsets from
void clearSection(const Section section);
// The following methods are not currently implemented.
//void removeQuestion(QuestionPtr question);
// notyet:
......
......@@ -297,6 +297,75 @@ TEST_F(MessageTest, removeRRset) {
EXPECT_EQ(2, message_render.getRRCount(Message::SECTION_ANSWER));
}
TEST_F(MessageTest, clearQuestionSection) {
QuestionPtr q(new Question(Name("www.example.com"), RRClass::IN(),
RRType::A()));
message_render.addQuestion(q);
ASSERT_EQ(1, message_render.getRRCount(Message::SECTION_QUESTION));
message_render.clearSection(Message::SECTION_QUESTION);
EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_QUESTION));
}
TEST_F(MessageTest, clearAnswerSection) {
// Add two RRsets, check they are present, clear the section,
// check if they are gone.
message_render.addRRset(Message::SECTION_ANSWER, rrset_a);
message_render.addRRset(Message::SECTION_ANSWER, rrset_aaaa);
ASSERT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
RRClass::IN(), RRType::A()));
ASSERT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
RRClass::IN(), RRType::AAAA()));
ASSERT_EQ(3, message_render.getRRCount(Message::SECTION_ANSWER));
message_render.clearSection(Message::SECTION_ANSWER);
EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
RRClass::IN(), RRType::A()));
EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
RRClass::IN(), RRType::AAAA()));
EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ANSWER));
}
TEST_F(MessageTest, clearAuthoritySection) {
// Add two RRsets, check they are present, clear the section,
// check if they are gone.
message_render.addRRset(Message::SECTION_AUTHORITY, rrset_a);
message_render.addRRset(Message::SECTION_AUTHORITY, rrset_aaaa);
ASSERT_TRUE(message_render.hasRRset(Message::SECTION_AUTHORITY, test_name,
RRClass::IN(), RRType::A()));
ASSERT_TRUE(message_render.hasRRset(Message::SECTION_AUTHORITY, test_name,
RRClass::IN(), RRType::AAAA()));
ASSERT_EQ(3, message_render.getRRCount(Message::SECTION_AUTHORITY));
message_render.clearSection(Message::SECTION_AUTHORITY);
EXPECT_FALSE(message_render.hasRRset(Message::SECTION_AUTHORITY, test_name,
RRClass::IN(), RRType::A()));
EXPECT_FALSE(message_render.hasRRset(Message::SECTION_AUTHORITY, test_name,
RRClass::IN(), RRType::AAAA()));
EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_AUTHORITY));
}
TEST_F(MessageTest, clearAdditionalSection) {
// Add two RRsets, check they are present, clear the section,
// check if they are gone.
message_render.addRRset(Message::SECTION_ADDITIONAL, rrset_a);
message_render.addRRset(Message::SECTION_ADDITIONAL, rrset_aaaa);
ASSERT_TRUE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
RRClass::IN(), RRType::A()));
ASSERT_TRUE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
RRClass::IN(), RRType::AAAA()));
ASSERT_EQ(3, message_render.getRRCount(Message::SECTION_ADDITIONAL));
message_render.clearSection(Message::SECTION_ADDITIONAL);
EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
RRClass::IN(), RRType::A()));
EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
RRClass::IN(), RRType::AAAA()));
EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ADDITIONAL));
}
TEST_F(MessageTest, badBeginSection) {
// valid cases are tested via other tests
EXPECT_THROW(message_render.beginSection(Message::SECTION_QUESTION),
......
......@@ -10,7 +10,7 @@ AM_CXXFLAGS = $(B10_CXXFLAGS)
CLEANFILES = *.gcno *.gcda
lib_LTLIBRARIES = libresolve.la
libresolve_la_SOURCES = resolve.h
libresolve_la_SOURCES = resolve.h resolve.cc
libresolve_la_SOURCES += resolver_interface.h
libresolve_la_SOURCES += resolver_callback.h resolver_callback.cc
libresolve_la_SOURCES += response_classifier.cc response_classifier.h
......
// Copyright (C) 2011 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 <resolve/resolve.h>
using namespace isc::dns;
namespace {
class SectionInserter {
public:
SectionInserter(MessagePtr message, const Message::Section sect) :
message_(message), section_(sect)
{}
void operator()(const RRsetPtr rrset) {
message_->addRRset(section_, rrset, true);
}
MessagePtr message_;
const Message::Section section_;
};
}
namespace isc {
namespace resolve {
void
makeErrorMessage(MessagePtr answer_message,
const Rcode::Rcode& error_code)
{
answer_message->clearSection(Message::SECTION_ANSWER);
answer_message->clearSection(Message::SECTION_AUTHORITY);
answer_message->clearSection(Message::SECTION_ADDITIONAL);
answer_message->setRcode(error_code);
}
} // namespace resolve
} // namespace isc
......@@ -15,7 +15,33 @@
#ifndef _ISC_RESOLVE_H
#define _ISC_RESOLVE_H 1
/// This file includes all other libresolve headers, and provides
/// several helper functions used in resolving.
#include <resolve/resolver_interface.h>
#include <resolve/resolver_callback.h>
#include <resolve/response_classifier.h>
namespace isc {
namespace resolve {
/// \brief Create an error response
///
/// Clears the answer, authority, and additional section of the
/// given MessagePtr and sets the given error code
///
/// Notes: Assuming you have already done initial preparations
/// on the given answer message (copy the opcode, qid and question
/// section), you can simply use this to create an error response.
///
/// \param answer_message The message to clear and place the error in
/// \param question The question to add to the
/// \param error_code The error Rcode
void
makeErrorMessage(isc::dns::MessagePtr answer_message,
const isc::dns::Rcode::Rcode& error_code);
} // namespace resolve
} // namespace isc
#endif // ISC_RESOLVE_H_
......@@ -14,6 +14,7 @@ TESTS += run_unittests
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
run_unittests_SOURCES = run_unittests.cc
run_unittests_SOURCES += resolve_unittest.cc
run_unittests_SOURCES += resolver_callback_unittest.cc
run_unittests_SOURCES += response_classifier_unittest.cc
......
// Copyright (C) 2010 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 <iostream>
#include <gtest/gtest.h>
#include <dns/message.h>
#include <dns/question.h>
#include <dns/opcode.h>
#include <dns/rcode.h>
#include <dns/rrttl.h>
#include <dns/rdata.h>
#include <resolve/resolve.h>
using namespace isc::dns;
namespace {
class ResolveHelperFunctionsTest : public ::testing::Test {
public:
ResolveHelperFunctionsTest() :
message_(new Message(Message::RENDER)),
question_(new Question(Name("www.example.com"), RRClass::IN(), RRType::A()))
{
message_->setOpcode(Opcode::QUERY());
message_->setRcode(Rcode::NOERROR());
message_->addQuestion(question_);
};
MessagePtr message_;
QuestionPtr question_;
};
TEST_F(ResolveHelperFunctionsTest, makeErrorMessageEmptyMessage) {
ASSERT_EQ(Rcode::NOERROR(), message_->getRcode());
ASSERT_EQ(1, message_->getRRCount(Message::SECTION_QUESTION));
ASSERT_EQ(0, message_->getRRCount(Message::SECTION_ANSWER));
ASSERT_EQ(0, message_->getRRCount(Message::SECTION_AUTHORITY));
ASSERT_EQ(0, message_->getRRCount(Message::SECTION_ADDITIONAL));
isc::resolve::makeErrorMessage(message_, Rcode::SERVFAIL());
EXPECT_EQ(Rcode::SERVFAIL(), message_->getRcode());
EXPECT_EQ(1, message_->getRRCount(Message::SECTION_QUESTION));
EXPECT_EQ(0, message_->getRRCount(Message::SECTION_ANSWER));
EXPECT_EQ(0, message_->getRRCount(Message::SECTION_AUTHORITY));
EXPECT_EQ(0, message_->getRRCount(Message::SECTION_ADDITIONAL));
}
TEST_F(ResolveHelperFunctionsTest, makeErrorMessageNonEmptyMessage) {
// We could reuse the same rrset in the different sections,
// but to be sure, we create separate ones
RRsetPtr answer_rrset(new RRset(Name("www.example.com"),
RRClass::IN(), RRType::TXT(),
RRTTL(3600)));
answer_rrset->addRdata(rdata::createRdata(RRType::TXT(),
RRClass::IN(),
"Answer"));
message_->addRRset(Message::SECTION_ANSWER, answer_rrset);
RRsetPtr auth_rrset(new RRset(Name("www.example.com"),
RRClass::IN(), RRType::TXT(),
RRTTL(3600)));
auth_rrset->addRdata(rdata::createRdata(RRType::TXT(),
RRClass::IN(),
"Authority"));
auth_rrset->addRdata(rdata::createRdata(RRType::TXT(),
RRClass::IN(),
"Rdata"));
message_->addRRset(Message::SECTION_AUTHORITY, auth_rrset);
RRsetPtr add_rrset(new RRset(Name("www.example.com"),
RRClass::IN(), RRType::TXT(),
RRTTL(3600)));
add_rrset->addRdata(rdata::createRdata(RRType::TXT(),
RRClass::IN(),
"Additional"));
add_rrset->addRdata(rdata::createRdata(RRType::TXT(),
RRClass::IN(),
"Rdata"));
add_rrset->addRdata(rdata::createRdata(RRType::TXT(),
RRClass::IN(),
"fields."));
message_->addRRset(Message::SECTION_ADDITIONAL, add_rrset);
ASSERT_EQ(Rcode::NOERROR(), message_->getRcode());
ASSERT_EQ(1, message_->getRRCount(Message::SECTION_QUESTION));
ASSERT_EQ(1, message_->getRRCount(Message::SECTION_ANSWER));
ASSERT_EQ(2, message_->getRRCount(Message::SECTION_AUTHORITY));
ASSERT_EQ(3, message_->getRRCount(Message::SECTION_ADDITIONAL));
isc::resolve::makeErrorMessage(message_, Rcode::FORMERR());
EXPECT_EQ(Rcode::FORMERR(), message_->getRcode());
EXPECT_EQ(1, message_->getRRCount(Message::SECTION_QUESTION));
EXPECT_EQ(0, message_->getRRCount(Message::SECTION_ANSWER));
EXPECT_EQ(0, message_->getRRCount(Message::SECTION_AUTHORITY));
EXPECT_EQ(0, message_->getRRCount(Message::SECTION_ADDITIONAL));
}
} // Anonymous namespace
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