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