Commit 2930018a authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

- added minimum level documentation

- overall cleanup


git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@1451 e5f2f494-b856-4b98-b285-d166d9295462
parent 82032d93
......@@ -268,11 +268,19 @@ Message::getHeaderFlag(const MessageFlag& flag) const {
void
Message::setHeaderFlag(const MessageFlag& flag) {
if (impl_->mode_ != Message::RENDER) {
isc_throw(InvalidMessageOperation,
"setHeaderFlag performed in non-render mode");
}
impl_->flags_ |= flag.getBit();
}
void
Message::clearHeaderFlag(const MessageFlag& flag) {
if (impl_->mode_ != Message::RENDER) {
isc_throw(InvalidMessageOperation,
"clearHeaderFlag performed in non-render mode");
}
impl_->flags_ &= ~flag.getBit();
}
......@@ -315,6 +323,10 @@ Message::getQid() const {
void
Message::setQid(qid_t qid) {
if (impl_->mode_ != Message::RENDER) {
isc_throw(InvalidMessageOperation,
"setQid performed in non-render mode");
}
impl_->qid_ = qid;
}
......@@ -325,6 +337,10 @@ Message::getRcode() const {
void
Message::setRcode(const Rcode& rcode) {
if (impl_->mode_ != Message::RENDER) {
isc_throw(InvalidMessageOperation,
"setRcode performed in non-render mode");
}
impl_->rcode_ = rcode;
}
......@@ -335,6 +351,10 @@ Message::getOpcode() const {
void
Message::setOpcode(const Opcode& opcode) {
if (impl_->mode_ != Message::RENDER) {
isc_throw(InvalidMessageOperation,
"setOpcode performed in non-render mode");
}
impl_->opcode_ = &opcode;
}
......@@ -345,6 +365,11 @@ Message::getRRCount(const Section& section) const {
void
Message::addRRset(const Section& section, RRsetPtr rrset, const bool sign) {
if (impl_->mode_ != Message::RENDER) {
isc_throw(InvalidMessageOperation,
"addRRset performed in non-render mode");
}
// Note: should check duplicate (TBD)
impl_->rrsets_[sectionCodeToId(section)].push_back(rrset);
impl_->counts_[section.getCode()] += rrset->getRdataCount();
......@@ -358,6 +383,11 @@ Message::addRRset(const Section& section, RRsetPtr rrset, const bool sign) {
void
Message::addQuestion(const QuestionPtr question) {
if (impl_->mode_ != Message::RENDER) {
isc_throw(InvalidMessageOperation,
"addQuestion performed in non-render mode");
}
impl_->questions_.push_back(question);
++impl_->counts_[Section::QUESTION().getCode()];
}
......@@ -814,6 +844,8 @@ Message::makeResponse()
"makeResponse() is performed in non-parse mode");
}
impl_->mode_ = Message::RENDER;
impl_->dnssec_ok_ = false;
impl_->remote_udpsize_ = impl_->udpsize_;
impl_->local_edns_ = RRsetPtr();
......@@ -822,8 +854,6 @@ Message::makeResponse()
impl_->flags_ &= MESSAGE_REPLYPRESERVE;
setHeaderFlag(MessageFlag::QR());
impl_->mode_ = Message::RENDER;
impl_->rrsets_[sectionCodeToId(Section::ANSWER())].clear();
impl_->counts_[Section::ANSWER().getCode()] = 0;
impl_->rrsets_[sectionCodeToId(Section::AUTHORITY())].clear();
......
......@@ -32,7 +32,9 @@ namespace isc {
namespace dns {
///
/// \brief A standard DNS module exception ...[TBD]
/// \brief A standard DNS module exception that is thrown if a wire format
/// message parser encounters a short length of data that don't even contain
/// the full header section.
///
class MessageTooShort : public Exception {
public:
......@@ -40,26 +42,39 @@ public:
isc::Exception(file, line, what) {}
};
///
/// \brief A standard DNS module exception that is thrown if a section iterator
/// is being constructed for an incompatible section. Specifically, this
/// happens RRset iterator is being constructed for a Question section.
///
class InvalidMessageSection : public Exception {
public:
InvalidMessageSection(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
///
/// \brief A standard DNS module exception that is thrown if a \c Message
/// class method is called that is prohibited for the current mode of
/// the message.
///
class InvalidMessageOperation : public Exception {
public:
InvalidMessageOperation(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
///
/// \brief A standard DNS module exception that is thrown if a UDP buffer size
/// smaller than the standard default maximum (DEFAULT_MAX_UDPSIZE) is
/// being specified for the message.
///
class InvalidMessageUDPSize : public Exception {
public:
InvalidMessageUDPSize(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
typedef uint8_t rcode_t; // we actually only need 4 bits of it
typedef uint8_t opcode_t; // we actually only need 4 bits of it
typedef uint16_t qid_t;
class InputBuffer;
......@@ -70,6 +85,10 @@ struct MessageImpl;
template <typename T>
struct SectionIteratorImpl;
/// \brief The \c MessageFlag class objects represent standard flag bits
/// of the header section of DNS messages.
///
/// Constant objects are defined for standard flags.
class MessageFlag {
public:
uint16_t getBit() const { return (flagbit_); }
......@@ -134,6 +153,13 @@ MessageFlag::CD()
return (f);
}
/// \brief The \c Opcode class objects represent standard OPCODEs
/// of the header section of DNS messages.
///
/// Note: since there are only 15 possible values, it may make more sense to
/// simply define an enum type to represent these values.
///
/// Constant objects are defined for standard flags.
class Opcode {
public:
uint16_t getCode() const { return (code_); }
......@@ -275,6 +301,11 @@ Opcode::RESERVED15()
return (c);
}
/// \brief The \c Rcode class objects represent standard Response Codes
/// (RCODEs) of the header section of DNS messages, and extended response
/// codes as defined in the EDNS specification.
///
/// Constant objects are defined for standard flags.
class Rcode {
public:
Rcode(uint16_t code);
......@@ -426,6 +457,17 @@ Rcode::BADVERS()
return (c);
}
/// \brief The \c Section class objects represent DNS message sections such
/// as the header, question, or answer.
///
/// Note: this class doesn't seem to be very useful. We should probably
/// revisit this design.
///
/// Note: whether or not it's represented as a class, we'll need a way
/// to represent more advanced sections such as those used in dynamic updates.
/// This is a TODO item.
///
/// Constant objects are defined for standard flags.
class Section {
public:
/// \brief Returns the relative position of the \c Section in DNS messages.
......@@ -479,6 +521,10 @@ Section::ADDITIONAL()
return (s);
}
/// \c SectionIterator is a templated class to provide standard-compatible
/// iterators for Questions and RRsets for a given DNS message section.
/// The template parameter is either \c QuestionPtr (for the question section)
/// or \c RRsetPtr (for the answer, authority, or additional section).
template <typename T>
class SectionIterator : public std::iterator<std::input_iterator_tag, T> {
public:
......@@ -500,67 +546,218 @@ private:
typedef SectionIterator<QuestionPtr> QuestionIterator;
typedef SectionIterator<RRsetPtr> RRsetIterator;
/// \brief The \c Message class encapsulates a standard DNS message.
///
/// Details of the design and interfaces of this class is still in flux.
/// Here are some notes about the current design.
///
/// Since many realistic DNS applications deal with messages, message objects
/// will be frequently used, and can be performance sensitive. To minimize
/// the performance overhead of constructing and destructing the objects,
/// this class is designed to be reusable. The \c clear() method is provided
/// for this purpose.
///
/// A \c Message class object is in either the \c PARSE or the \c RENDER mode.
/// A \c PARSE mode object is intended to be used to convert wire-format
/// message data into a complete \c Message object.
/// A \c RENDER mode object is intended to be used to convert a \c Message
/// object into wire-format data.
/// Some of the method functions of this class is limited to a specific mode.
/// In general, "set" type operations are only allowed for \c RENDER mode
/// objects.
/// The initial mode must be specified on construction, and can be changed
/// through some method functions.
///
/// This class uses the "pimpl" idiom, and hide detailed implementation
/// through the \c impl_ pointer. Since a \c Message object is expected to
/// be reused, the construction overhead of this approach should be acceptable.
///
/// Open issues (among other things):
/// - We may want to provide an "iterator" for all RRsets/RRs for convenience.
/// This will be for applications that do not care about performance much,
/// so the implementation can only be moderately efficient.
/// - may want to provide a "find" method for a specified type
/// of RR in the message.
class Message {
public:
enum Mode {
PARSE = 0,
RENDER = 1
};
///
/// \name Constructors and Destructor
///
/// Note: The copy constructor and the assignment operator are intentionally
/// defined as private. The intended use case wouldn't require copies of
/// a \c Message object; once created, it would normally be expected to
/// be reused, changing the mode from \c PARSE to \c RENDER, and vice
/// versa.
//@{
public:
/// \brief The constructor.
/// The mode of the message is specified by the \c mode parameter.
Message(Mode mode);
/// \brief The destructor.
~Message();
private:
Message(const Message& source);
Message& operator=(const Message& source);
//@}
public:
/// \brief Return whether the specified header flag bit is set in the
/// header section.
bool getHeaderFlag(const MessageFlag& flag) const;
/// \brief Set the specified header flag bit is set in the header section.
///
/// Only allowed in the \c RENDER mode.
void setHeaderFlag(const MessageFlag& flag);
/// \brief Clear the specified header flag bit is set in the header section.
///
/// Only allowed in the \c RENDER mode.
/// Note: it may make more sense to integrate this method into \c
/// \c setHeaderFlag() with an additional argument.
void clearHeaderFlag(const MessageFlag& flag);
/// \brief Return whether the message sender indicates DNSSEC is supported.
/// If EDNS is included, this corresponds to the value of the DO bit.
/// Otherwise, DNSSEC is considered not supported.
bool isDNSSECSupported() const;
/// \brief Specify whether DNSSEC is supported in the message.
///
/// Only allowed in the \c RENDER mode.
/// If EDNS is included in the message, the DO bit is set or cleared
/// according to the specified value of this method.
void setDNSSECSupported(bool on);
/// \brief Return the maximum buffer size of UDP messages for the sender
/// of the message.
///
/// The semantics of this value is different based on the mode:
/// In the \c PARSE mode, it means the buffer size of the remote node;
/// in the \c RENDER mode, it means the buffer size of the local node.
///
/// In either case, its value is the value of the UDP payload size field
/// of EDNS (when it's included) or \c DEFAULT_MAX_UDPSIZE.
///
/// Note: this interface may be confusing and may have to be revisited.
uint16_t getUDPSize() const;
/// \brief Specify the maximum buffer size of UDP messages of the local
/// node.
///
/// Only allowed in the \c RENDER mode.
/// If EDNS OPT RR is included in the message, its UDP payload size field
/// will be set to the specified value.
void setUDPSize(uint16_t size);
/// \brief Return the query ID given in the header section of the message.
qid_t getQid() const;
/// \brief Set the query ID of the header section of the message.
///
/// Only allowed in the \c RENDER mode.
void setQid(qid_t qid);
/// \brief Return the Response Code of the message.
///
/// This includes extended codes specified by an EDNS OPT RR (when
/// included). In the \c PARSE mode, if the received message contains
/// an EDNS OPT RR, the corresponding extended code is identified and
/// returned.
const Rcode& getRcode() const;
/// \brief Return the Response Code of the message.
///
/// Only allowed in the \c RENDER mode.
/// If the specified code is an EDNS extended RCODE, an EDNS OPT RR will be
/// included in the message.
void setRcode(const Rcode& rcode);
/// \brief Return the OPCODE given in the header section of the message.
const Opcode& getOpcode() const;
/// \brief Set the OPCODE of the header section of the message.
///
/// Only allowed in the \c RENDER mode.
void setOpcode(const Opcode& opcode);
std::string toText() const;
/// \brief Returns the number of RRs contained in the given section.
unsigned int getRRCount(const Section& section) const;
// Open issues:
// - may want to provide an "iterator" for all RRsets/RRs
// - may want to provide a "find" method for a specified type
// of RR in the message
/// \brief Return an iterator corresponding to the beginning of the
/// Question section of the message.
const QuestionIterator beginQuestion() const;
/// \brief Return an iterator corresponding to the end of the
/// Question section of the message.
const QuestionIterator endQuestion() const;
/// \brief Return an iterator corresponding to the beginning of the
/// given section (other than Question) of the message.
const RRsetIterator beginSection(const Section& section) const;
/// \brief Return an iterator corresponding to the end of the
/// given section (other than Question) of the message.
const RRsetIterator endSection(const Section& section) const;
/// \brief Add a (pointer like object of) Question to the message.
///
/// Only allowed in the \c RENDER mode.
void addQuestion(QuestionPtr question);
/// \brief Add a (pointer like object of) Question to the message.
///
/// This version internally creates a \c QuestionPtr object from the
/// given \c question and calls the other version of this method.
/// So this is inherently less efficient, but is provided because this
/// form may be more intuitive and may make more sense for performance
/// insensitive applications.
///
/// Only allowed in the \c RENDER mode.
void addQuestion(const Question& question);
void removeQuestion(QuestionPtr question);
/// \brief Add a (pointer like object of) RRset to the given section
/// of the message.
///
/// This interface takes into account the RRSIG possibly attached to
/// \c rrset. This interface design needs to be revisited later.
///
/// Only allowed in the \c RENDER mode.
void addRRset(const Section& section, RRsetPtr rrset, bool sign = false);
void removeRRset(const Section& section, RRsetPtr rrset);
// The following methods are not currently implemented.
//void removeQuestion(QuestionPtr question);
//void removeRRset(const Section& section, RRsetPtr rrset);
// notyet:
//void addRR(const Section& section, const RR& rr);
//void removeRR(const Section& section, const RR& rr);
/// \brief Clear the message content (if any) and reinitialize it in the
/// specified mode.
void clear(Mode mode);
// prepare for making a response from a request. This will clear the
// DNS header except those fields that should be kept for the response,
// and clear answer and the following sections.
// see also dns_message_reply() of BIND9.
/// \brief Prepare for making a response from a request.
///
/// This will clear the DNS header except those fields that should be kept
/// for the response, and clear answer and the following sections.
/// See also dns_message_reply() of BIND9.
void makeResponse();
/// \brief Render message.
/// \brief Convert the Message to a string.
std::string toText() const;
/// \brief Render the message in wire formant into a \c MessageRenderer
/// object.
void toWire(MessageRenderer& renderer);
/// \brief Parse a DNS message.
/// \brief Parse the header section of the \c Message.
void parseHeader(InputBuffer& buffer);
/// \brief Parse the \c Message.
void fromWire(InputBuffer& buffer);
///
......
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