1 // Copyright (C) 2010-2015 Internet Systems Consortium, Inc. ("ISC") 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, v. 2.0. If a copy of the MPL was not distributed with this 5 // file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 7 #ifndef QUESTION_H 8 #define QUESTION_H 1 9 10 #include <iostream> 11 #include <string> 12 13 #include <boost/shared_ptr.hpp> 14 15 #include <dns/name.h> 16 #include <dns/rrclass.h> 17 #include <dns/rrtype.h> 18 19 namespace isc { 20 namespace util { 21 class InputBuffer; 22 class OutputBuffer; 23 } 24 25 namespace dns { 26 27 class AbstractMessageRenderer; 28 class Question; 29 30 /// \brief A pointer-like type pointing to an \c Question object. 31 typedef boost::shared_ptr<Question> QuestionPtr; 32 33 /// \brief A pointer-like type pointing to an (immutable) \c Question object. 34 typedef boost::shared_ptr<const Question> ConstQuestionPtr; 35 36 /// \brief The \c Question class encapsulates the common search key of DNS 37 /// lookup, consisting of owner name, RR type and RR class. 38 /// 39 /// The primarily intended use case of this class is an entry of the question 40 /// section of DNS messages. 41 /// This could also be used as a general purpose lookup key, e.g., in a 42 /// custom implementation of DNS database. 43 /// 44 /// In this initial implementation, the \c Question class is defined as 45 /// a <em>concrete class</em>; it's not expected to be inherited by 46 /// a user-defined customized class. 47 /// It may be worth noting that it's different from the design of the 48 /// RRset classes (\c AbstractRRset and its derived classes). 49 /// The RRset classes form an inheritance hierarchy from the base abstract 50 /// class. 51 /// This may look odd in that an "RRset" and "Question" are similar from the 52 /// protocol point of view: Both are used as a semantics unit of DNS messages; 53 /// both share the same set of components (name, RR type and RR class). 54 /// 55 /// In fact, BIND9 didn't introduce a separate data structure for Questions, 56 /// and use the same \c "rdataset" structure for both RRsets and Questions. 57 /// We could take the same approach, but chose to adopt the different design. 58 /// One reason for that is because a Question and an RRset are still 59 /// different, and a Question might not be cleanly defined, e.g., if it were 60 /// a derived class of some "RRset-like" class. 61 /// For example, we couldn't give a reasonable semantics for \c %getTTL() or 62 /// \c %setTTL() methods for a Question, since it's not associated with the 63 /// TTL. 64 /// In fact, the BIND9 implementation ended up often separating the case where 65 /// a \c "rdataset" is from the Question section of a DNS message and the 66 /// case where it comes from other sections. 67 /// If we cannot treat them completely transparently anyway, separating the 68 /// class (type) would make more sense because we can exploit compilation 69 /// time type checks. 70 /// 71 /// On the other hand, we do not expect a strong need for customizing the 72 /// \c Question class, unlike the RRset. 73 /// Handling the "Question" section of a DNS message is relatively a 74 /// simple work comparing to RRset-involved operations, so a unified 75 /// straightforward implementation should suffice for any use cases 76 /// including performance sensitive ones. 77 /// 78 /// We may, however, still want to have a customized version of Question 79 /// for, e.g, highly optimized behavior, and may revisit this design choice 80 /// as we have more experience with this implementation. 81 /// 82 /// One disadvantage of defining RRsets and Questions as unrelated classes 83 /// is that we cannot handle them in a polymorphic way. 84 /// For example, we might want to iterate over DNS message sections and 85 /// render the data in the wire format, whether it's an RRset or a Question. 86 /// If a \c Question were a derived class of some common RRset-like class, 87 /// we could do this by calling <code>rrset_or_question->%toWire()</code>. 88 /// But the actual design doesn't allow this approach, which may require 89 /// duplicate code for almost the same operation. 90 /// To mitigate this problem, we intentionally used the same names 91 /// with the same signature for some common methods of \c Question and 92 /// \c AbstractRRset such as \c %getName() or \c %toWire(). 93 /// So the user class may use a template function that is applicable to both 94 /// \c Question and \c RRset to avoid writing duplicate code logic. 95 class Question { 96 /// 97 /// \name Constructors and Destructor 98 /// 99 /// We use the default versions of destructor, copy constructor, 100 /// and assignment operator. 101 /// 102 /// The default constructor is hidden as a result of defining the other 103 /// constructors. This is intentional; we don't want to allow a 104 /// \c Question object to be constructed with an invalid state. 105 //@{ 106 public: 107 /// \brief Constructor from wire-format data. 108 /// 109 /// It simply constructs a set of \c Name, \c RRType, and \c RRClass 110 /// object from the \c buffer in this order, and constructs a 111 /// \c Question object in a straightforward way. 112 /// 113 /// It may throw an exception if the construction of these component 114 /// classes fails. 115 /// 116 /// \param buffer A buffer storing the wire format data. 117 Question(isc::util::InputBuffer& buffer); 118 119 /// \brief Constructor from fixed parameters of the \c Question. 120 /// 121 /// This constructor is basically expected to be exception free, but 122 /// copying the name may involve resource allocation, and if it fails 123 /// the corresponding standard exception will be thrown. 124 /// 125 /// \param name The owner name of the \c Question. 126 /// \param rrclass The RR class of the \c Question. 127 /// \param rrtype The RR type of the \c Question. Question(const Name & name,const RRClass & rrclass,const RRType & rrtype)128 Question(const Name& name, const RRClass& rrclass, const RRType& rrtype) : 129 name_(name), rrtype_(rrtype), rrclass_(rrclass) 130 {} 131 //@} 132 133 /// 134 /// \name Getter Methods 135 /// 136 //@{ 137 /// \brief Returns the owner name of the \c Question. 138 /// 139 /// This method never throws an exception. 140 /// 141 /// \return A reference to a \c Name class object corresponding to the 142 /// \c Question owner name. getName()143 const Name& getName() const { return (name_); } 144 145 /// \brief Returns the RR Class of the \c Question. 146 /// 147 /// This method never throws an exception. 148 /// 149 /// \return A reference to a \c RRClass class object corresponding to the 150 /// RR class of the \c Question. getType()151 const RRType& getType() const { return (rrtype_); } 152 153 /// \brief Returns the RR Type of the \c Question. 154 /// 155 /// This method never throws an exception. 156 /// 157 /// \return A reference to a \c RRType class object corresponding to the 158 /// RR type of the \c Question. getClass()159 const RRClass& getClass() const { return (rrclass_); } 160 //@} 161 162 /// 163 /// \name Converter Methods 164 /// 165 //@{ 166 /// \brief Convert the Question to a string. 167 /// 168 /// When \c newline argument is \c true, this method terminates the 169 /// resulting string with a trailing newline character (following 170 /// the BIND9 convention). 171 /// 172 /// This method simply calls the \c %toText() methods of the corresponding 173 /// \c Name, \c RRType and \c RRClass classes for this \c Question, and 174 /// these methods may throw an exception. 175 /// In particular, if resource allocation fails, a corresponding standard 176 /// exception will be thrown. 177 /// 178 /// \param newline Whether to add a trailing newline. If true, a 179 /// trailing newline is added. If false, no trailing newline is 180 /// added. 181 /// 182 /// \return A string representation of the \c Question. 183 std::string toText(bool newline = false) const; 184 185 /// \brief Render the Question in the wire format with name compression. 186 /// 187 /// This method simply calls the \c %toWire() methods of the corresponding 188 /// \c Name, \c RRType and \c RRClass classes for this \c Question, and 189 /// these methods may throw an exception. 190 /// In particular, if resource allocation fails, a corresponding standard 191 /// exception will be thrown. 192 /// 193 /// This method returns 1, which is the number of "questions" contained 194 /// in the \c Question. 195 /// This is a meaningless value, but is provided to be consistent with 196 /// the corresponding method of \c AbstractRRset (see the detailed 197 /// class description). 198 /// 199 /// The owner name will be compressed if possible, although it's an 200 /// unlikely event in practice because the Question section a DNS 201 /// message normally doesn't contain multiple question entries and 202 /// it's located right after the Header section. 203 /// Nevertheless, \c renderer records the information of the owner name 204 /// so that it can be pointed by other RRs in other sections (which is 205 /// more likely to happen). 206 /// 207 /// It could be possible, though very rare in practice, that 208 /// an attempt to render a Question may cause truncation 209 /// (when the Question section contains a large number of entries). 210 /// In such a case this method avoid the rendering and indicate the 211 /// truncation in the \c renderer. This method returns 0 in this case. 212 /// 213 /// \param renderer DNS message rendering context that encapsulates the 214 /// output buffer and name compression information. 215 /// 216 /// \return 1 on success; 0 if it causes truncation 217 unsigned int toWire(AbstractMessageRenderer& renderer) const; 218 219 /// \brief Render the Question in the wire format without name compression. 220 /// 221 /// This method behaves like the render version except it doesn't compress 222 /// the owner name. 223 /// See \c toWire(AbstractMessageRenderer& renderer)const. 224 /// 225 /// \param buffer An output buffer to store the wire data. 226 /// \return 1 227 unsigned int toWire(isc::util::OutputBuffer& buffer) const; 228 //@} 229 230 /// 231 /// \name Comparison Operators 232 /// 233 //@{ 234 /// A "less than" operator is needed for this class so it can 235 /// function as an index to std::map. 236 bool operator <(const Question& rhs) const { 237 return (rrclass_ < rhs.rrclass_ || 238 (rrclass_ == rhs.rrclass_ && 239 (rrtype_ < rhs.rrtype_ || 240 (rrtype_ == rhs.rrtype_ && (name_ < rhs.name_))))); 241 } 242 243 /// Equality operator. Primarily used to compare the question section in 244 /// a response to that in the query. 245 /// 246 /// \param rhs Question to compare against 247 /// \return true if name, class and type are equal, false otherwise 248 bool operator==(const Question& rhs) const { 249 return ((rrclass_ == rhs.rrclass_) && (rrtype_ == rhs.rrtype_) && 250 (name_ == rhs.name_)); 251 } 252 253 /// Inequality operator. Primarily used to compare the question section in 254 /// a response to that in the query. 255 /// 256 /// \param rhs Question to compare against 257 /// \return true if one or more of the name, class and type do not match, 258 /// false otherwise. 259 bool operator!=(const Question& rhs) const { 260 return (!operator==(rhs)); 261 } 262 //@} 263 264 private: 265 Name name_; 266 RRType rrtype_; 267 RRClass rrclass_; 268 }; 269 270 /// \brief Insert the \c Question as a string into stream. 271 /// 272 /// This method convert the \c question into a string and inserts it into the 273 /// output stream \c os. 274 /// 275 /// This function overloads the global \c operator<< to behave as described in 276 /// \c %ostream::%operator<< but applied to Question objects. 277 /// 278 /// \param os A \c std::ostream object on which the insertion operation is 279 /// performed. 280 /// \param question A reference to a \c Question object output by the 281 /// operation. 282 /// \return A reference to the same \c std::ostream object referenced by 283 /// parameter \c os after the insertion operation. 284 std::ostream& operator<<(std::ostream& os, const Question& question); 285 } // end of namespace dns 286 } // end of namespace isc 287 #endif // QUESTION_H 288 289 // Local Variables: 290 // mode: c++ 291 // End: 292