Browse Source

- added minimum level documentation
- overall cleanup


git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@1451 e5f2f494-b856-4b98-b285-d166d9295462

JINMEI Tatuya 15 years ago
parent
commit
2930018ad3
2 changed files with 245 additions and 18 deletions
  1. 32 2
      src/lib/dns/message.cc
  2. 213 16
      src/lib/dns/message.h

+ 32 - 2
src/lib/dns/message.cc

@@ -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();

+ 213 - 16
src/lib/dns/message.h

@@ -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);
 
     ///