blob: 442f9dc28993b8701958634f293d1a62730da814 [file] [log] [blame]
Shock Jiang698e6ed2014-11-09 11:22:24 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Yumin Xia2c509c22017-02-09 14:37:36 -08002/*
Yumin Xia55a7cc42017-05-14 18:43:34 -07003 * Copyright (c) 2014-2018, Regents of the University of California.
Shock Jiang698e6ed2014-11-09 11:22:24 -08004 *
5 * This file is part of NDNS (Named Data Networking Domain Name Service).
6 * See AUTHORS.md for complete list of NDNS authors and contributors.
7 *
8 * NDNS is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * NDNS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * NDNS, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "iterative-query-controller.hpp"
21#include "logger.hpp"
22#include <iostream>
23
24namespace ndn {
25namespace ndns {
26NDNS_LOG_INIT("IterQueryCtr")
27
28IterativeQueryController::IterativeQueryController(const Name& dstLabel,
29 const name::Component& rrType,
30 const time::milliseconds& interestLifetime,
31 const QuerySucceedCallback& onSucceed,
32 const QueryFailCallback& onFail,
Shock Jiang5d5928c2014-12-03 13:41:22 -080033 Face& face,
Yumin Xiad8b75fc2017-04-05 15:00:21 -070034 security::v2::Validator* validator,
35 ndn::InMemoryStorage* cache)
Shock Jiang698e6ed2014-11-09 11:22:24 -080036 : QueryController(dstLabel, rrType, interestLifetime, onSucceed, onFail, face)
Shock Jiang5d5928c2014-12-03 13:41:22 -080037 , m_validator(validator)
Shock Jiang698e6ed2014-11-09 11:22:24 -080038 , m_step(QUERY_STEP_QUERY_NS)
39 , m_nFinishedComps(0)
40 , m_nTryComps(1)
Yumin Xiad8b75fc2017-04-05 15:00:21 -070041 , m_nsCache(cache)
Shock Jiang698e6ed2014-11-09 11:22:24 -080042{
Shock Jiang698e6ed2014-11-09 11:22:24 -080043}
44
45void
46IterativeQueryController::onTimeout(const Interest& interest)
47{
48 NDNS_LOG_INFO("[* !! *] timeout happens: " << interest.getName());
49 NDNS_LOG_TRACE(*this);
50 this->abort();
51}
52
53void
54IterativeQueryController::abort()
55{
56 NDNS_LOG_DEBUG("abort iterative query");
57 if (m_onFail != nullptr)
58 m_onFail(0, "abort");
59 else
60 NDNS_LOG_TRACE("m_onFail is 0");
61
62}
63
64void
65IterativeQueryController::onData(const ndn::Interest& interest, const Data& data)
66{
Yumin Xiaa484ba72016-11-10 20:40:12 -080067 NdnsContentType contentType = NdnsContentType(data.getContentType());
Shock Jiang698e6ed2014-11-09 11:22:24 -080068
Yumin Xiaa484ba72016-11-10 20:40:12 -080069 NDNS_LOG_TRACE("[* -> *] get a " << contentType
Shock Jiang698e6ed2014-11-09 11:22:24 -080070 << " Response: " << data.getName());
Yumin Xia55a7cc42017-05-14 18:43:34 -070071
72 const Data* toBeValidatedData = nullptr;
73 if (contentType == NDNS_NACK) {
74 m_doe = Data(data.getContent().blockFromValue());
75 toBeValidatedData = &m_doe;
76 contentType = NDNS_DOE;
Shock Jiang5d5928c2014-12-03 13:41:22 -080077 }
78 else {
Yumin Xia55a7cc42017-05-14 18:43:34 -070079 toBeValidatedData = &data;
80 }
81
82 if (m_validator == nullptr) {
83 this->onDataValidated(*toBeValidatedData, contentType);
84 }
85 else {
86 m_validator->validate(*toBeValidatedData,
Yumin Xiaa484ba72016-11-10 20:40:12 -080087 bind(&IterativeQueryController::onDataValidated, this, _1, contentType),
Yumin Xia2c509c22017-02-09 14:37:36 -080088 [this] (const Data& data, const security::v2::ValidationError& err) {
89 NDNS_LOG_WARN("data: " << data.getName() << " fails verification");
Shock Jiang5d5928c2014-12-03 13:41:22 -080090 this->abort();
91 }
92 );
93 }
94}
Yumin Xia55a7cc42017-05-14 18:43:34 -070095
Shock Jiang5d5928c2014-12-03 13:41:22 -080096void
Yumin Xia2c509c22017-02-09 14:37:36 -080097IterativeQueryController::onDataValidated(const Data& data, NdnsContentType contentType)
Shock Jiang5d5928c2014-12-03 13:41:22 -080098{
Yumin Xiad8b75fc2017-04-05 15:00:21 -070099 if (m_nsCache != nullptr && contentType == NDNS_LINK) {
100 m_nsCache->insert(data);
101 }
102
Shock Jiang698e6ed2014-11-09 11:22:24 -0800103 switch (m_step) {
104 case QUERY_STEP_QUERY_NS:
Yumin Xia55a7cc42017-05-14 18:43:34 -0700105 if (contentType == NDNS_DOE) {
106 // check if requested record is absent by looking up in doe
107 if (isAbsentByDoe(data)) {
108 m_step = QUERY_STEP_QUERY_RR;
109 }
110 else {
111 std::ostringstream oss;
112 oss << "In onDataValidated, absence of record can not be infered from DoE.";
113 oss << " Last query:" << m_lastLabelType << " ";
114 oss << *this;
115 BOOST_THROW_EXCEPTION(std::runtime_error(oss.str()));
116 }
Shock Jiang698e6ed2014-11-09 11:22:24 -0800117 }
Yumin Xiaa484ba72016-11-10 20:40:12 -0800118 else if (contentType == NDNS_LINK) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800119 Link link(data.wireEncode());
120 if (link.getDelegationList().empty()) {
Yumin Xiaa484ba72016-11-10 20:40:12 -0800121 m_lastLink = Block();
Yumin Xia2c509c22017-02-09 14:37:36 -0800122 }
123 else {
124 m_lastLink = data.wireEncode();
Yumin Xia4e561892016-10-21 10:48:01 -0700125 }
Yumin Xiaa484ba72016-11-10 20:40:12 -0800126
127 // for NS query, if already received, just return, instead of more queries until NACK
Shock Jiang698e6ed2014-11-09 11:22:24 -0800128 if (m_nFinishedComps + m_nTryComps == m_dstLabel.size() && m_rrType == label::NS_RR_TYPE) {
129 // NS_RR_TYPE is different, since its record is stored at higher level
130 m_step = QUERY_STEP_ANSWER_STUB;
131 }
132 else {
133 m_nFinishedComps += m_nTryComps;
134 m_nTryComps = 1;
135 }
136 }
Yumin Xiaa484ba72016-11-10 20:40:12 -0800137 else if (contentType == NDNS_AUTH) {
Shock Jiang698e6ed2014-11-09 11:22:24 -0800138 m_nTryComps += 1;
139 }
Yumin Xia2c509c22017-02-09 14:37:36 -0800140 else {
Yumin Xiaa484ba72016-11-10 20:40:12 -0800141 std::ostringstream oss;
142 oss << *this;
143 NDNS_LOG_WARN("get unexpected Response for QUERY_NS: " << oss.str());
Shock Jiang698e6ed2014-11-09 11:22:24 -0800144 }
Yumin Xiadb8e9372017-04-09 14:05:32 -0700145
Shock Jiang698e6ed2014-11-09 11:22:24 -0800146 if (m_nFinishedComps + m_nTryComps > m_dstLabel.size()) {
147 if (m_rrType == label::NS_RR_TYPE) {
148 m_step = QUERY_STEP_ANSWER_STUB;
149 }
150 else
151 m_step = QUERY_STEP_QUERY_RR;
152 }
153 break;
154 case QUERY_STEP_QUERY_RR:
155 m_step = QUERY_STEP_ANSWER_STUB;
156 break;
157 default:
158 NDNS_LOG_WARN("get unexpected Response at State " << *this);
159 // throw std::runtime_error("call makeLatestInterest() unexpected: " << *this);
160 // do not throw except since it may be duplicated Data
161 m_step = QUERY_STEP_ABORT;
162 break;
163 }
164
165 if (!hasEnded())
166 this->express(this->makeLatestInterest()); // express new Expres
167 else if (m_step == QUERY_STEP_ANSWER_STUB) {
168 NDNS_LOG_TRACE("query ends: " << *this);
Yumin Xia2c509c22017-02-09 14:37:36 -0800169 Response re = this->parseFinalResponse(data);
Shock Jiang698e6ed2014-11-09 11:22:24 -0800170 if (m_onSucceed != nullptr)
Yumin Xia2c509c22017-02-09 14:37:36 -0800171 m_onSucceed(data, re);
Shock Jiang698e6ed2014-11-09 11:22:24 -0800172 else
173 NDNS_LOG_TRACE("succeed callback is nullptr");
174 }
175 else if (m_step == QUERY_STEP_ABORT)
176 this->abort();
177}
178
179bool
180IterativeQueryController::hasEnded()
181{
182 return (m_step != QUERY_STEP_QUERY_NS && m_step != QUERY_STEP_QUERY_RR);
183}
184
185void
186IterativeQueryController::start()
187{
Shock Jiang5d5928c2014-12-03 13:41:22 -0800188 if (m_dstLabel.size() == m_nFinishedComps)
189 m_step = QUERY_STEP_QUERY_RR;
190
Shock Jiang698e6ed2014-11-09 11:22:24 -0800191 Interest interest = this->makeLatestInterest();
192 express(interest);
193}
194
195
196void
197IterativeQueryController::express(const Interest& interest)
198{
Yumin Xiad8b75fc2017-04-05 15:00:21 -0700199 if (m_nsCache != nullptr) {
200 shared_ptr<const Data> cachedData = m_nsCache->find(interest);
201 if (cachedData != nullptr) {
202 NDNS_LOG_DEBUG("[* cached *] NS record has been cached before: "
203 << interest.getName());
204 onData(interest, *cachedData);
205 return ;
206 }
207 }
208
Shock Jiang698e6ed2014-11-09 11:22:24 -0800209 NDNS_LOG_DEBUG("[* <- *] send a Query: " << interest.getName());
210 m_face.expressInterest(interest,
211 bind(&IterativeQueryController::onData, this, _1, _2),
Alexander Afanasyevf4193ea2017-06-12 15:35:13 -0700212 bind(&IterativeQueryController::onTimeout, this, _1), // nack
Shock Jiang698e6ed2014-11-09 11:22:24 -0800213 bind(&IterativeQueryController::onTimeout, this, _1)
214 );
215}
216
217
218const Response
219IterativeQueryController::parseFinalResponse(const Data& data)
220{
221 Response re;
222 Name zone = m_dstLabel.getPrefix(m_nFinishedComps);
Yumin Xia6343c5b2016-10-20 15:45:50 -0700223 re.fromData(zone, data);
Shock Jiang698e6ed2014-11-09 11:22:24 -0800224 return re;
225}
226
227const Interest
228IterativeQueryController::makeLatestInterest()
229{
230 // NDNS_LOG_TRACE("get latest Interest");
231 Query query;
232 //const Name& dstLabel = m_query.getRrLabel();
233
234 query.setZone(m_dstLabel.getPrefix(m_nFinishedComps));
235 query.setInterestLifetime(m_interestLifetime);
Yumin Xia4e561892016-10-21 10:48:01 -0700236
237 // addLink
238 if (m_lastLink.hasWire()) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800239 query.setDelegationListFromLink(Link(m_lastLink));
Yumin Xia4e561892016-10-21 10:48:01 -0700240 }
241
Shock Jiang698e6ed2014-11-09 11:22:24 -0800242 switch (m_step) {
243 case QUERY_STEP_QUERY_NS:
244 query.setQueryType(label::NDNS_ITERATIVE_QUERY);
245 query.setRrLabel(m_dstLabel.getSubName(m_nFinishedComps, m_nTryComps));
246 query.setRrType(label::NS_RR_TYPE);
247 break;
248 case QUERY_STEP_QUERY_RR:
Yumin Xia918343d2017-03-17 19:04:55 -0700249 query.setQueryType(label::NDNS_ITERATIVE_QUERY);
Shock Jiang698e6ed2014-11-09 11:22:24 -0800250 query.setRrLabel(m_dstLabel.getSubName(m_nFinishedComps));
251 query.setRrType(m_rrType);
252 break;
253 default:
254 std::ostringstream oss;
255 oss << *this;
256 NDNS_LOG_WARN("unexpected state: " << oss.str());
Yumin Xia2c509c22017-02-09 14:37:36 -0800257 BOOST_THROW_EXCEPTION(std::runtime_error("call makeLatestInterest() unexpected: "
258 + oss.str()));
Shock Jiang698e6ed2014-11-09 11:22:24 -0800259 }
260
Yumin Xia55a7cc42017-05-14 18:43:34 -0700261 m_lastLabelType = Name(query.getRrLabel()).append(query.getRrType());
Shock Jiang698e6ed2014-11-09 11:22:24 -0800262 Interest interest = query.toInterest();
263 return interest;
264}
265
Yumin Xia55a7cc42017-05-14 18:43:34 -0700266bool
267IterativeQueryController::isAbsentByDoe(const Data& data) const
268{
269 std::pair<Name, Name> range = Response::wireDecodeDoe(data.getContent());
270
271 // should not be simple <, use our own definition of compare
272 if (range.first < m_lastLabelType && m_lastLabelType < range.second) {
273 return true;
274 }
275 if (range.second < range.first &&
276 (m_lastLabelType < range.first || range.second < m_lastLabelType)) {
277 return true;
278 }
279 return false;
280}
281
Shock Jiang698e6ed2014-11-09 11:22:24 -0800282std::ostream&
283operator<<(std::ostream& os, const IterativeQueryController::QueryStep step)
284{
285 switch (step) {
286 case IterativeQueryController::QUERY_STEP_QUERY_NS:
287 os << "QueryNS";
288 break;
289 case IterativeQueryController::QUERY_STEP_QUERY_RR:
290 os << "QueryRR";
291 break;
292 case IterativeQueryController::QUERY_STEP_ANSWER_STUB:
293 os << "AnswerStub";
294 break;
295 case IterativeQueryController::QUERY_STEP_ABORT:
296 os << "Abort";
297 break;
298 default:
299 os << "UNKNOW";
300 break;
301 }
302 return os;
303}
304
305std::ostream&
306operator<<(std::ostream& os, const IterativeQueryController& ctr)
307{
308 os << "InterativeQueryController: dstLabel=" << ctr.getDstLabel()
309 << " rrType=" << ctr.getRrType()
310 << " currentStep=" << ctr.getStep()
311 << " nFinishedComps=" << ctr.getNFinishedComps()
312 << " nTryComp=" << ctr.getNTryComps()
313 ;
314
315 return os;
316}
317
318} // namespace ndns
319} // namespace ndn