Branch data Line data Source code
1 : : // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
2 : : //
3 : : // Permission to use, copy, modify, and/or distribute this software for any
4 : : // purpose with or without fee is hereby granted, provided that the above
5 : : // copyright notice and this permission notice appear in all copies.
6 : : //
7 : : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
8 : : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9 : : // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
10 : : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11 : : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
12 : : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13 : : // PERFORMANCE OF THIS SOFTWARE.
14 : :
15 : : #ifndef __QUERY_H
16 : : #define __QUERY_H
17 : :
18 : : #include <boost/shared_ptr.hpp>
19 : :
20 : : #include <datasrc/cache.h>
21 : : #include <datasrc/data_source.h>
22 : :
23 : : #include <dns/name.h>
24 : : #include <dns/message.h>
25 : : #include <dns/rrtype.h>
26 : : #include <dns/rrclass.h>
27 : :
28 : : #include <queue>
29 : :
30 : : namespace isc {
31 : : namespace datasrc {
32 : :
33 : : class Query;
34 : : typedef boost::shared_ptr<Query> QueryPtr;
35 : :
36 : : // An individual task to be carried out by the query logic
37 : : class QueryTask {
38 : : private:
39 : : /// Note: The copy constructor and the assignment operator are intentionally
40 : : /// defined as private.
41 : : QueryTask(const QueryTask& source);
42 : : QueryTask& operator=(const QueryTask& source);
43 : : public:
44 : : // XXX: Members are currently public, but should probably be
45 : : // moved to private and wrapped in get() functions later.
46 : :
47 : : // The \c Query that this \c QueryTask was created to service.
48 : : const Query& q;
49 : :
50 : : // The standard query tuple: qname/qclass/qtype.
51 : : // Note that qtype is ignored in the GLUE_QUERY/NOGLUE_QUERY case.
52 : : const isc::dns::Name qname;
53 : : const isc::dns::RRClass qclass;
54 : : const isc::dns::RRType qtype;
55 : :
56 : : // The section of the reply into which the data should be
57 : : // written after it has been fetched from the data source.
58 : : const isc::dns::Message::Section section;
59 : :
60 : : // The op field indicates the operation to be carried out by
61 : : // this query task:
62 : : //
63 : : // - SIMPLE_QUERY: look for a match for qname/qclass/qtype
64 : : // in local data (regardless of whether it is above or below
65 : : // a zone cut).
66 : : //
67 : : // - AUTH_QUERY: look for a match for qname/qclass/qtype, or
68 : : // for qname/qclass/CNAME, or for a referral.
69 : : //
70 : : // - GLUE_QUERY: look for matches with qname/qclass/A
71 : : // OR qname/class/AAAA in local data, regardless of
72 : : // authority, for use in glue. (This can be implemented
73 : : // as two successive SIMPLE_QUERY tasks, but might be
74 : : // optimized by the concrete data source implementation
75 : : // by turning it into a single database lookup.)
76 : : //
77 : : // - NOGLUE_QUERY: same as GLUE_QUERY except that answers
78 : : // are rejected if they are below a zone cut.
79 : : //
80 : : // - REF_QUERY: look for matches for qname/qclass/NS,
81 : : // qname/qclass/DS, and qname/qclass/DNAME. Used
82 : : // to search for a zone cut.
83 : :
84 : : const enum Op {
85 : : SIMPLE_QUERY,
86 : : AUTH_QUERY,
87 : : GLUE_QUERY,
88 : : NOGLUE_QUERY,
89 : : REF_QUERY
90 : : } op;
91 : :
92 : : // The state field indicates the state of the query; it controls
93 : : // the next step after processing each query task.
94 : : //
95 : : // - GETANSWER: We are looking for the answer to a primary query.
96 : : // (The qname of the task should exactly match the qname of the
97 : : // query.) If we have no match, the query has failed.
98 : : //
99 : : // - GETADDITIONAL: We are filling in additional data, either
100 : : // as a result of finding NS or MX records via a GETANSWER
101 : : // query task, or as a result of finding NS records when
102 : : // getting authority-section data.
103 : : //
104 : : // - FOLLOWCNAME: We are looking for the target of a CNAME RR that
105 : : // was found via a previous GETANSWER query task. If we have no
106 : : // match, the query is still successful.
107 : : //
108 : : // (NOTE: It is only necessary to set a task state when pushing
109 : : // tasks onto the query task queue, which in turn is only necessary
110 : : // when it's uncertain which data source will be authoritative for the
111 : : // data. That's why there is no GETAUTHORITY task state; when
112 : : // processing an answer, either positive or negative, the authoritative
113 : : // data source will already have been discovered, and can be queried
114 : : // directly.)
115 : :
116 : : enum State {
117 : : GETANSWER,
118 : : GETADDITIONAL,
119 : : FOLLOWCNAME
120 : : } state;
121 : :
122 : : // Response flags to indicate conditions encountered while
123 : : // processing this task.
124 : : uint32_t flags;
125 : :
126 : : // Constructors
127 : : QueryTask(const Query& q, const isc::dns::Name& n,
128 : : const isc::dns::RRType& t,
129 : : const isc::dns::Message::Section sect);
130 : : QueryTask(const Query& q, const isc::dns::Name& n,
131 : : const isc::dns::RRType& t,
132 : : const isc::dns::Message::Section sect, Op o);
133 : : QueryTask(const Query& q, const isc::dns::Name& n,
134 : : const isc::dns::RRType& t,
135 : : const isc::dns::Message::Section sect,
136 : : const State st);
137 : : QueryTask(const Query& q, const isc::dns::Name& n,
138 : : const isc::dns::RRType& t,
139 : : const isc::dns::Message::Section sect,
140 : : Op o, State st);
141 : :
142 : : // These are special constructors for particular query task types,
143 : : // to simplify the code.
144 : : //
145 : : // A simple query doesn't need to specify section or state.
146 : : QueryTask(const Query& q, const isc::dns::Name& n,
147 : : const isc::dns::RRType& t, Op o);
148 : : // A referral query doesn't need to specify section, state, or type.
149 : : QueryTask(const Query& q, const isc::dns::Name& n, Op o);
150 : : // A glue (or noglue) query doesn't need to specify type.
151 : : QueryTask(const Query& q, const isc::dns::Name& n,
152 : : const isc::dns::Message::Section sect, Op o, State st);
153 : :
154 : : ~QueryTask();
155 : : };
156 : :
157 : : typedef boost::shared_ptr<QueryTask> QueryTaskPtr;
158 : : typedef std::queue<QueryTaskPtr> QueryTaskQueue;
159 : :
160 : : // Data Source query
161 : : class Query {
162 : : public:
163 : : // The state of a query: pending or answered.
164 : : enum Status {
165 : : PENDING,
166 : : ANSWERED
167 : : };
168 : :
169 : : ///
170 : : /// \name Constructors, Assignment Operator and Destructor.
171 : : ///
172 : : /// Note: The copy constructor and the assignment operator are intentionally
173 : : /// defined as private.
174 : : //@{
175 : : private:
176 : : Query(const Query& source);
177 : : Query& operator=(const Query& source);
178 : : public:
179 : : // Query constructor
180 : : Query(isc::dns::Message& m, HotCache& c, bool dnssec);
181 : : /// \brief The destructor.
182 : : virtual ~Query();
183 : : //@}
184 : :
185 : : // wantAdditional() == true indicates that additional-section data
186 : : // should be looked up while processing this query. false indicates
187 : : // that we're only interested in answer-section data
188 : 0 : bool wantAdditional() { return (want_additional_); }
189 : : void setWantAdditional(bool d) { want_additional_ = d; }
190 : :
191 : : // wantDnssec() == true indicates that DNSSEC data should be retrieved
192 : : // from the data source when this query is being processed
193 : 0 : bool wantDnssec() const { return (want_dnssec_); }
194 : : void setWantDnssec(bool d) { want_dnssec_ = d; }
195 : :
196 : 0 : const isc::dns::Name& qname() const { return (*qname_); }
197 : 0 : const isc::dns::RRClass& qclass() const { return (*qclass_); }
198 : 0 : const isc::dns::RRType& qtype() const { return (*qtype_); }
199 : :
200 : : // Note: these can't be constant member functions because they expose
201 : : // writable 'handles' of internal member variables. It's questionable
202 : : // whether we need these accessors in the first place because the
203 : : // corresponding members are public (which itself is not a good practice
204 : : // but it's a different topic), but at the moment we keep them.
205 : : // We should definitely revisit the design later.
206 : 0 : isc::dns::Message& message() { return (*message_); }
207 : : QueryTaskQueue& tasks() { return (querytasks_); }
208 : :
209 : 0 : Status status() const { return (status_); }
210 : 0 : void setStatus(Status s) { status_ = s; }
211 : :
212 : : // Limit CNAME chains to 16 per query, to avoid loops
213 : 0 : inline bool tooMany() {
214 [ + + ][ # # ]: 27 : if (++restarts_ > MAX_RESTARTS) {
215 : : return (true);
216 : : }
217 : 0 : return (false);
218 : : }
219 : :
220 : 0 : void setDatasrc(DataSrc* ds) { datasrc_ = ds; }
221 : : DataSrc* datasrc() const { return (datasrc_); }
222 : :
223 : : // \brief The query cache. This is a static member of class \c Query;
224 : : // the same cache will be used by all instances.
225 : 0 : HotCache& getCache() const { return (*cache_); }
226 : :
227 : : private:
228 : : Status status_;
229 : :
230 : : const isc::dns::Name* qname_;
231 : : const isc::dns::RRClass* qclass_;
232 : : const isc::dns::RRType* qtype_;
233 : :
234 : : HotCache* cache_;
235 : : DataSrc* datasrc_;
236 : :
237 : : isc::dns::Message* message_;
238 : : QueryTaskQueue querytasks_;
239 : :
240 : : bool want_additional_;
241 : : bool want_dnssec_;
242 : :
243 : : static const int MAX_RESTARTS = 16;
244 : : int restarts_;
245 : : };
246 : :
247 : : }
248 : : }
249 : :
250 : :
251 : : #endif
252 : :
253 : : // Local Variables:
254 : : // mode: c++
255 : : // End:
|