Commit 1a324c83 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

sync with turnk


git-svn-id: svn://bind10.isc.org/svn/bind10/branches/jinmei-dnsrdata2@971 e5f2f494-b856-4b98-b285-d166d9295462
parent 304a78a8
......@@ -15,6 +15,7 @@ libdns_la_SOURCES += rrclass.h rrclass.cc rrtype.h rrtype.cc rrttl.h rrttl.cc
libdns_la_SOURCES += rdata.h rdata.cc
libdns_la_SOURCES += rdataclass.h rdataclass.cc
libdns_la_SOURCES += rrset.h rrset.cc
libdns_la_SOURCES += rrsetlist.h rrsetlist.cc
libdns_la_SOURCES += question.h question.cc
libdns_la_SOURCES += message.h message.cc
libdns_la_SOURCES += base64.h base64.cc
......
......@@ -25,7 +25,6 @@
#include "rrtype.h"
using namespace std;
using namespace isc::dns;
namespace isc {
namespace dns {
......@@ -69,13 +68,6 @@ Question::toWire(MessageRenderer& renderer) const
return (1); // number of "entries"
}
bool
Question::operator==(const Question& other) const
{
return (name_ == other.name_ && rrtype_ == other.rrtype_ &&
rrclass_ == other.rrclass_);
}
ostream&
operator<<(std::ostream& os, const Question& question)
{
......
......@@ -18,6 +18,7 @@
#define __QUESTION_H 1
#include <iostream>
#include <string>
#include <boost/shared_ptr.hpp>
......@@ -29,46 +30,225 @@ namespace isc {
namespace dns {
class InputBuffer;
class MessageRenderer;
class Question;
/// \brief A pointer-like type pointing to an \c Question object.
typedef boost::shared_ptr<Question> QuestionPtr;
/// \brief A pointer-like type pointing to an (immutable) \c Question object.
typedef boost::shared_ptr<const Question> ConstQuestionPtr;
/// \brief The \c Question class encapsulates the common search key of DNS
/// lookup, consisting of owner name, RR type and RR class.
///
/// The primarily intended use case of this class is an entry of the question
/// section of DNS messages.
/// This could also be used as a general purpose lookup key, e.g., in a
/// custom implementation of DNS database.
///
/// In this initial implementation, the \c Question class is defined as
/// a <em>concrete class</em>; it's not expected to be inherited by
/// a user-defined customized class.
/// It may be worth noting that it's different from the design of the
/// RRset classes (\c AbstractRRset and its derived classes).
/// The RRset classes form an inheritance hierarchy from the base abstract
/// class.
/// This may look odd in that an "RRset" and "Question" are similar from the
/// protocol point of view: Both are used as a semantics unit of DNS messages;
/// both share the same set of components, name, RR type and RR class.
///
/// In fact, BIND9 didn't introduce a separate data structure for Questions,
/// and use the same \c "rdataset" structure for both RRsets and Questions.
/// We could take the same approach, but chose to adopt the different design.
/// One reason for that is because a Question and an RRset are still
/// different, and a Question might not be cleanly defined if (e.g.) it were
/// a derived class of some "RRset-like" class.
/// For example, we couldn't give a reasonable semantics for \c %getTTL() or
/// \c %setTTL() methods for a Question, since it's not associated with the
/// TTL.
/// In fact, the BIND9 implementation ended up often separating the case where
/// a \c "rdataset" is from the Question section of a DNS message and the
/// case where it comes from other sections.
/// If we cannot treat them completely transparently anyway, separating the
/// class (type) would make more sense because we can exploit compilation
/// time type checks.
///
/// On the other hand, we do not expect a strong need for customizing the
/// \c Question class, unlike the RRset.
/// Handling the Question section of a DNS message is relatively a
/// simple work comparing to RRset-involved operations, so a unified
/// straightforward implementation should suffice for any use cases
/// including performance sensitive ones.
///
/// This is a straightforward implementation of a "DNS question", modeling
/// an entry of the question section of DNS messages.
/// This could also be used as an input parameter for lookups into internal
/// data sources.
/// We may, however, still want to have customized version of Question
/// for, e.g, highly optimized behavior, and may revisit this design choice
/// as we have more experiences with this implementation.
///
/// Open issue: we may want to introduce an abstract base class so that we
/// can have multiple concrete implementations (e.g. for better performance)
/// of the base class in a polymorphic way.
/// One disadvantage of defining RRsets and Questions as unrelated classes
/// is that we cannot handle them in a polymorphic way.
/// For example, we might want to iterate over DNS message sections and
/// render the data in the wire format, whether it's an RRset or a Question.
/// If a \c Question were a derived class of some common RRset-like class,
/// we could do this by calling <code>rrset_or_question->%toWire()</code>.
/// But the actual design doesn't allow this approach, which may require
/// duplicate code for almost the same operation.
/// To mitigate this problem, we intentionally used the same names
/// with the same signature for some common methods of \c Question and
/// \c AbstractRRset such as \c %getName() or \c %toWire().
/// So the user class may use a template function that is applicable to both
/// \c Question and \c RRset to avoid writing duplicate code logic.
class Question {
///
/// \name Constructors and Destructor
///
/// We use the default versions of destructor, copy constructor,
/// and assignment operator.
///
/// The default constructor is hidden as a result of defining the other
/// constructors. This is intentional; we don't want to allow a
/// \c Question object to be constructed with an invalid state.
//@{
public:
/// \brief Constructor from wire-format data.
///
/// It simply constructs a set of \c Name, \c RRType, and \c RRClass
/// object from the \c buffer in this order, and constructs a
/// \c Question object in a straightforward way.
///
/// It may throw an exception if the construction of these component
/// classes fails.
///
/// \param buffer A buffer storing the wire format data.
Question(InputBuffer& buffer);
/// \brief Constructor from fixed parameters of the \c Question.
///
/// This constructor is basically expected to be exception free, but
/// copying the name may involve resource allocation, and if it fails
/// the corresponding standard exception will be thrown.
///
/// \param name The owner name of the \c Question.
/// \param rrclass The RR class of the \c Question.
/// \param rrtype The RR type of the \c Question.
Question(const Name& name, const RRClass& rrclass, const RRType& rrtype) :
name_(name), rrtype_(rrtype), rrclass_(rrclass)
{}
//@}
///
/// \name Getter methods
/// \name Getter Methods
///
//@{
/// \brief Returns the owner name of the \c Question.
///
/// This method never throws an exception.
///
/// \return A reference to a \c Name class object corresponding to the
/// \c Question owner name.
const Name& getName() const { return (name_); }
/// \brief Returns the RR Class of the \c Question.
///
/// This method never throws an exception.
///
/// \return A reference to a \c RRClass class object corresponding to the
/// RR class of the \c Question.
const RRType& getType() const { return (rrtype_); }
/// \brief Returns the RR Type of the \c Question.
///
/// This method never throws an exception.
///
/// \return A reference to a \c RRType class object corresponding to the
/// RR type of the \c Question.
const RRClass& getClass() const { return (rrclass_); }
//@}
///
/// \name Converter Methods
///
//@{
/// \brief Convert the Question to a string.
///
/// Unlike other similar methods of this library, this method terminates
/// the resulting string with a trailing newline character
/// (following the BIND9 convention).
///
/// This method simply calls the \c %toText() methods of the corresponding
/// \c Name, \c RRType and \c RRClass classes for this \c Question, and
/// these methods may throw an exception.
/// In particular, if resource allocation fails, a corresponding standard
/// exception will be thrown.
///
/// \return A string representation of the \c Question.
std::string toText() const;
unsigned int toWire(OutputBuffer& buffer) const;
/// \brief Render the Question in the wire format with name compression.
///
/// This method simply calls the \c %toWire() methods of the corresponding
/// \c Name, \c RRType and \c RRClass classes for this \c Question, and
/// these methods may throw an exception.
/// In particular, if resource allocation fails, a corresponding standard
/// exception will be thrown.
///
/// This method returns 1, which is the number of "questions" contained
/// in the \c Question.
/// This is a meaningless value, but is provided to be consistent with
/// the corresponding method of \c AbstractRRset (see the detailed
/// class description).
///
/// The owner name will be compressed if possible, although it's an
/// unlikely event in practice because the %Question section a DNS
/// message normally doesn't contain multiple question entries and
/// it's located right after the Header section.
/// Nevertheless, \c renderer records the information of the owner name
/// so that it can be pointed by other RRs in other sections (which is
/// more likely to happen).
///
/// In theory, an attempt to render a Question may cause truncation
/// (when the Question section contains a large number of entries),
/// but this implementation doesn't catch that situation.
/// It would make the code unnecessarily complicated (though perhaps
/// slightly) for almost impossible case in practice.
/// An upper layer will handle the pathological case as a general error.
///
/// \param renderer DNS message rendering context that encapsulates the
/// output buffer and name compression information.
/// \return 1
unsigned int toWire(MessageRenderer& renderer) const;
bool operator==(const Question& other) const;
bool operator!=(const Question& other) const
{ return !(*this == other); }
/// \brief Render the Question in the wire format without name compression.
///
/// This method behaves like the render version except it doesn't compress
/// the owner name.
/// See \c toWire(MessageRenderer& renderer)const.
///
/// \param buffer An output buffer to store the wire data.
/// \return 1
unsigned int toWire(OutputBuffer& buffer) const;
//@}
private:
Name name_;
RRType rrtype_;
RRClass rrclass_;
};
/// \brief Insert the \c Question as a string into stream.
///
/// This method convert the \c question into a string and inserts it into the
/// output stream \c os.
///
/// This function overloads the global \c operator<< to behave as described in
/// \c %ostream::%operator<< but applied to Question objects.
///
/// \param os A \c std::ostream object on which the insertion operation is
/// performed.
/// \param question A reference to a \c Question object output by the
/// operation.
/// \return A reference to the same \c std::ostream object referenced by
/// parameter \c os after the insertion operation.
std::ostream& operator<<(std::ostream& os, const Question& question);
} // end of namespace dns
} // end of namespace isc
......
......@@ -71,6 +71,7 @@ class Rdata;
/// object of some concrete derived class of \c Rdata.
///
typedef boost::shared_ptr<Rdata> RdataPtr;
typedef boost::shared_ptr<const Rdata> ConstRdataPtr;
/// \brief Possible maximum length of RDATA, which is the maximum unsigned
/// 16 bit value.
......
......@@ -39,10 +39,35 @@ SOA::SOA(InputBuffer& buffer, size_t rdata_len) :
buffer.readData(numdata_, sizeof(numdata_));
}
SOA::SOA(const std::string& soastr) :
mname_("."), rname_(".")
SOA::SOA(const string& soastr) :
mname_("."), rname_(".") // quick hack workaround
{
dns_throw(InvalidRdataText, "Not implemented yet");
istringstream iss(soastr);
string token;
iss >> token;
if (iss.bad() || iss.fail()) {
dns_throw(InvalidRdataText, "Invalid SOA MNAME");
}
mname_ = Name(token);
iss >> token;
if (iss.bad() || iss.fail()) {
dns_throw(InvalidRdataText, "Invalid SOA RNAME");
}
rname_ = Name(token);
uint32_t serial, refresh, retry, expire, minimum;
iss >> serial >> refresh >> retry >> expire >> minimum;
if (iss.rdstate() != ios::eofbit) {
dns_throw(InvalidRdataText, "Invalid SOA format");
}
OutputBuffer buffer(20);
buffer.writeUint32(serial);
buffer.writeUint32(refresh);
buffer.writeUint32(retry);
buffer.writeUint32(expire);
buffer.writeUint32(minimum);
memcpy(numdata_, buffer.getData(), buffer.getLength());
}
SOA::SOA(const Name& mname, const Name& rname, uint32_t serial,
......
......@@ -46,16 +46,20 @@ AbstractRRset::toText() const
string s;
RdataIteratorPtr it = getRdataIterator();
for (it->first(); !it->isLast(); it->next()) {
s += getName().toText() + " " +
getTTL().toText() + " " +
getClass().toText() + " " +
getType().toText() + " " +
it->getCurrent().toText() + "\n";
it->first();
if (it->isLast()) {
dns_throw(EmptyRRset, "ToText() is attempted for an empty RRset");
}
do {
s += getName().toText() + " " + getTTL().toText() + " " +
getClass().toText() + " " + getType().toText() + " " +
it->getCurrent().toText() + "\n";
it->next();
} while (!it->isLast());
return (s);
}
}
namespace {
template <typename T>
......@@ -65,9 +69,14 @@ rrsetToWire(const AbstractRRset& rrset, T& output)
unsigned int n = 0;
RdataIteratorPtr it = rrset.getRdataIterator();
it->first();
if (it->isLast()) {
dns_throw(EmptyRRset, "ToWire() is attempted for an empty RRset");
}
// sort the set of Rdata based on rrset-order and sortlist, and possible
// other options. Details to be considered.
for (it->first(); !it->isLast(); it->next(), ++n) {
do {
rrset.getName().toWire(output);
rrset.getType().toWire(output);
rrset.getClass().toWire(output);
......@@ -77,7 +86,10 @@ rrsetToWire(const AbstractRRset& rrset, T& output)
output.skip(sizeof(uint16_t)); // leave the space for RDLENGTH
it->getCurrent().toWire(output);
output.writeUint16At(output.getLength() - pos - sizeof(uint16_t), pos);
}
it->next();
++n;
} while (!it->isLast());
return (n);
}
......@@ -102,7 +114,10 @@ operator<<(ostream& os, const AbstractRRset& rrset)
return (os);
}
struct BasicRRsetImpl {
/// \brief This encapsulates the actual implementation of the \c BasicRRset
/// class. It's hidden from applications.
class BasicRRsetImpl {
public:
BasicRRsetImpl(const Name& name, const RRClass& rrclass,
const RRType& rrtype, const RRTTL& ttl) :
name_(name), rrclass_(rrclass), rrtype_(rrtype), ttl_(ttl) {}
......@@ -110,7 +125,10 @@ struct BasicRRsetImpl {
RRClass rrclass_;
RRType rrtype_;
RRTTL ttl_;
vector<RdataPtr> rdatalist_;
// XXX: "list" is not a good name: It in fact isn't a list; more conceptual
// name than a data structure name is generally better. But since this
// is only used in the internal implementation we'll live with it.
vector<ConstRdataPtr> rdatalist_;
};
BasicRRset::BasicRRset(const Name& name, const RRClass& rrclass,
......@@ -125,11 +143,17 @@ BasicRRset::~BasicRRset()
}
void
BasicRRset::addRdata(const RdataPtr rdata)
BasicRRset::addRdata(ConstRdataPtr rdata)
{
impl_->rdatalist_.push_back(rdata);
}
void
BasicRRset::addRdata(const Rdata& rdata)
{
AbstractRRset::addRdata(rdata);
}
unsigned int
BasicRRset::getRdataCount() const
{
......@@ -160,18 +184,42 @@ BasicRRset::getTTL() const
return (impl_->ttl_);
}
void
BasicRRset::setName(const Name& name)
{
impl_->name_ = name;
}
void
BasicRRset::setTTL(const RRTTL& ttl)
{
impl_->ttl_ = ttl;
}
string
BasicRRset::toText() const
{
return (AbstractRRset::toText());
}
unsigned int
BasicRRset::toWire(OutputBuffer& buffer) const
{
return (AbstractRRset::toWire(buffer));
}
unsigned int
BasicRRset::toWire(MessageRenderer& renderer) const
{
return (AbstractRRset::toWire(renderer));
}
namespace {
class BasicRdataIterator : public RdataIterator {
private:
BasicRdataIterator() {}
public:
BasicRdataIterator(const std::vector<rdata::RdataPtr>& datavector) :
BasicRdataIterator(const std::vector<rdata::ConstRdataPtr>& datavector) :
datavector_(&datavector) {}
~BasicRdataIterator() {}
virtual void first() { it_ = datavector_->begin(); }
......@@ -179,8 +227,8 @@ public:
virtual const rdata::Rdata& getCurrent() const { return (**it_); }
virtual bool isLast() const { return (it_ == datavector_->end()); }
private:
const std::vector<rdata::RdataPtr>* datavector_;
std::vector<rdata::RdataPtr>::const_iterator it_;
const std::vector<rdata::ConstRdataPtr>* datavector_;
std::vector<rdata::ConstRdataPtr>::const_iterator it_;
};
}
......
This diff is collapsed.
// 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.
// $Id$
#include <algorithm>
#include <string>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/foreach.hpp>
#include "rrsetlist.h"
using namespace std;
using namespace isc::dns;
namespace isc {
namespace dns {
void
RRsetList::addRRset(const RRsetPtr rrsetptr)
{
const RRsetPtr rrset_found = findRRset(rrsetptr->getType(),
rrsetptr->getClass());
if (rrset_found) {
dns_throw(DuplicateRRset, "");
}
rrsets_.push_back(rrsetptr);
}
const RRsetPtr
RRsetList::findRRset(const RRsetPtr rrsetptr)
{
BOOST_FOREACH(const RRsetPtr t, rrsets_) {
if (rrsetptr == t) {
return rrsetptr;
}
}
return RRsetPtr();
}
const RRsetPtr
RRsetList::findRRset(const RRType& rrtype, const RRClass& rrclass)
{
BOOST_FOREACH(const RRsetPtr rrsetptr, rrsets_) {
const AbstractRRset* rrset = rrsetptr.get();
if ((rrset->getClass() == rrclass) && (rrset->getType() == rrtype)) {
return rrsetptr;
}
}
return RRsetPtr();
}
}
}
// 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.
// $Id$
#ifndef __RRSETLIST_H
#define __RRSETLIST_H 1
#include <iostream>
#include <vector>
#include <boost/shared_ptr.hpp>
#include "rrset.h"
#include "rrclass.h"
#include "rrtype.h"
namespace isc {
namespace dns {
class DuplicateRRset : public Exception {
public:
DuplicateRRset(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
class RRsetList {
public:
void addRRset(const RRsetPtr new_rrsetptr);
const RRsetPtr findRRset(const RRType& rrtype,
const RRClass& rrclass = RRClass::IN());
const RRsetPtr findRRset(const RRsetPtr);
const RRsetPtr operator[](RRType t) { return (this->findRRset(t)); }
typedef std::vector<RRsetPtr>::const_iterator const_iterator;
const_iterator begin() const { return (rrsets_.begin()); }
const_iterator end() const { return (rrsets_.end)(); }
typedef std::vector<RRsetPtr>::iterator iterator;
iterator begin() { return (rrsets_.begin()); }
iterator end() { return (rrsets_.end)(); }
size_t size() const { return (rrsets_.size()); }
private:
std::vector<RRsetPtr> rrsets_;
};
} // end of namespace dns
} // end of namespace isc
#endif // __RRSETLIST_H
// Local Variables:
// mode: c++
// End:
// 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