blob: e923e7741a82aae59dbb4393d3cfe264bc134066 [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/*
Junxiao Shi81e98762022-01-11 18:17:24 +00003 * Copyright (c) 2014-2022, 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"
Davide Pesavento948c50c2020-12-26 21:30:45 -050022
23#include <sstream>
Shock Jiang698e6ed2014-11-09 11:22:24 -080024
25namespace ndn {
26namespace ndns {
Alexander Afanasyev08d18742018-03-15 16:31:28 -040027
28NDNS_LOG_INIT(IterQueryCtr);
Shock Jiang698e6ed2014-11-09 11:22:24 -080029
30IterativeQueryController::IterativeQueryController(const Name& dstLabel,
31 const name::Component& rrType,
32 const time::milliseconds& interestLifetime,
33 const QuerySucceedCallback& onSucceed,
34 const QueryFailCallback& onFail,
Shock Jiang5d5928c2014-12-03 13:41:22 -080035 Face& face,
Alexander Afanasyev60514ec2020-06-03 14:18:53 -040036 security::Validator* validator,
Yumin Xiad8b75fc2017-04-05 15:00:21 -070037 ndn::InMemoryStorage* cache)
Shock Jiang698e6ed2014-11-09 11:22:24 -080038 : QueryController(dstLabel, rrType, interestLifetime, onSucceed, onFail, face)
Shock Jiang5d5928c2014-12-03 13:41:22 -080039 , m_validator(validator)
Shock Jiang698e6ed2014-11-09 11:22:24 -080040 , m_step(QUERY_STEP_QUERY_NS)
41 , m_nFinishedComps(0)
42 , m_nTryComps(1)
Yumin Xiad8b75fc2017-04-05 15:00:21 -070043 , m_nsCache(cache)
Shock Jiang698e6ed2014-11-09 11:22:24 -080044{
Shock Jiang698e6ed2014-11-09 11:22:24 -080045}
46
47void
48IterativeQueryController::onTimeout(const Interest& interest)
49{
50 NDNS_LOG_INFO("[* !! *] timeout happens: " << interest.getName());
51 NDNS_LOG_TRACE(*this);
52 this->abort();
53}
54
55void
56IterativeQueryController::abort()
57{
58 NDNS_LOG_DEBUG("abort iterative query");
59 if (m_onFail != nullptr)
60 m_onFail(0, "abort");
61 else
62 NDNS_LOG_TRACE("m_onFail is 0");
63
64}
65
66void
67IterativeQueryController::onData(const ndn::Interest& interest, const Data& data)
68{
Yumin Xiaa484ba72016-11-10 20:40:12 -080069 NdnsContentType contentType = NdnsContentType(data.getContentType());
Shock Jiang698e6ed2014-11-09 11:22:24 -080070
Yumin Xiaa484ba72016-11-10 20:40:12 -080071 NDNS_LOG_TRACE("[* -> *] get a " << contentType
Shock Jiang698e6ed2014-11-09 11:22:24 -080072 << " Response: " << data.getName());
Yumin Xia55a7cc42017-05-14 18:43:34 -070073
74 const Data* toBeValidatedData = nullptr;
75 if (contentType == NDNS_NACK) {
76 m_doe = Data(data.getContent().blockFromValue());
77 toBeValidatedData = &m_doe;
78 contentType = NDNS_DOE;
Shock Jiang5d5928c2014-12-03 13:41:22 -080079 }
80 else {
Yumin Xia55a7cc42017-05-14 18:43:34 -070081 toBeValidatedData = &data;
82 }
83
84 if (m_validator == nullptr) {
85 this->onDataValidated(*toBeValidatedData, contentType);
86 }
87 else {
88 m_validator->validate(*toBeValidatedData,
Yumin Xiaa484ba72016-11-10 20:40:12 -080089 bind(&IterativeQueryController::onDataValidated, this, _1, contentType),
Alexander Afanasyev60514ec2020-06-03 14:18:53 -040090 [this] (const Data& data, const security::ValidationError& err) {
Yumin Xia2c509c22017-02-09 14:37:36 -080091 NDNS_LOG_WARN("data: " << data.getName() << " fails verification");
Shock Jiang5d5928c2014-12-03 13:41:22 -080092 this->abort();
93 }
94 );
95 }
96}
Yumin Xia55a7cc42017-05-14 18:43:34 -070097
Shock Jiang5d5928c2014-12-03 13:41:22 -080098void
Yumin Xia2c509c22017-02-09 14:37:36 -080099IterativeQueryController::onDataValidated(const Data& data, NdnsContentType contentType)
Shock Jiang5d5928c2014-12-03 13:41:22 -0800100{
Yumin Xiad8b75fc2017-04-05 15:00:21 -0700101 if (m_nsCache != nullptr && contentType == NDNS_LINK) {
102 m_nsCache->insert(data);
103 }
104
Shock Jiang698e6ed2014-11-09 11:22:24 -0800105 switch (m_step) {
106 case QUERY_STEP_QUERY_NS:
Yumin Xia55a7cc42017-05-14 18:43:34 -0700107 if (contentType == NDNS_DOE) {
108 // check if requested record is absent by looking up in doe
109 if (isAbsentByDoe(data)) {
110 m_step = QUERY_STEP_QUERY_RR;
111 }
112 else {
113 std::ostringstream oss;
114 oss << "In onDataValidated, absence of record can not be infered from DoE.";
115 oss << " Last query:" << m_lastLabelType << " ";
116 oss << *this;
Davide Pesavento948c50c2020-12-26 21:30:45 -0500117 NDN_THROW(std::runtime_error(oss.str()));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700118 }
Shock Jiang698e6ed2014-11-09 11:22:24 -0800119 }
Yumin Xiaa484ba72016-11-10 20:40:12 -0800120 else if (contentType == NDNS_LINK) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800121 Link link(data.wireEncode());
122 if (link.getDelegationList().empty()) {
Yumin Xiaa484ba72016-11-10 20:40:12 -0800123 m_lastLink = Block();
Yumin Xia2c509c22017-02-09 14:37:36 -0800124 }
125 else {
126 m_lastLink = data.wireEncode();
Yumin Xia4e561892016-10-21 10:48:01 -0700127 }
Yumin Xiaa484ba72016-11-10 20:40:12 -0800128
129 // for NS query, if already received, just return, instead of more queries until NACK
Shock Jiang698e6ed2014-11-09 11:22:24 -0800130 if (m_nFinishedComps + m_nTryComps == m_dstLabel.size() && m_rrType == label::NS_RR_TYPE) {
131 // NS_RR_TYPE is different, since its record is stored at higher level
132 m_step = QUERY_STEP_ANSWER_STUB;
133 }
134 else {
135 m_nFinishedComps += m_nTryComps;
136 m_nTryComps = 1;
137 }
138 }
Yumin Xiaa484ba72016-11-10 20:40:12 -0800139 else if (contentType == NDNS_AUTH) {
Shock Jiang698e6ed2014-11-09 11:22:24 -0800140 m_nTryComps += 1;
141 }
Yumin Xia2c509c22017-02-09 14:37:36 -0800142 else {
Yumin Xiaa484ba72016-11-10 20:40:12 -0800143 std::ostringstream oss;
144 oss << *this;
145 NDNS_LOG_WARN("get unexpected Response for QUERY_NS: " << oss.str());
Shock Jiang698e6ed2014-11-09 11:22:24 -0800146 }
Yumin Xiadb8e9372017-04-09 14:05:32 -0700147
Shock Jiang698e6ed2014-11-09 11:22:24 -0800148 if (m_nFinishedComps + m_nTryComps > m_dstLabel.size()) {
149 if (m_rrType == label::NS_RR_TYPE) {
150 m_step = QUERY_STEP_ANSWER_STUB;
151 }
152 else
153 m_step = QUERY_STEP_QUERY_RR;
154 }
155 break;
156 case QUERY_STEP_QUERY_RR:
157 m_step = QUERY_STEP_ANSWER_STUB;
158 break;
159 default:
160 NDNS_LOG_WARN("get unexpected Response at State " << *this);
161 // throw std::runtime_error("call makeLatestInterest() unexpected: " << *this);
162 // do not throw except since it may be duplicated Data
163 m_step = QUERY_STEP_ABORT;
164 break;
165 }
166
167 if (!hasEnded())
168 this->express(this->makeLatestInterest()); // express new Expres
169 else if (m_step == QUERY_STEP_ANSWER_STUB) {
170 NDNS_LOG_TRACE("query ends: " << *this);
Yumin Xia2c509c22017-02-09 14:37:36 -0800171 Response re = this->parseFinalResponse(data);
Shock Jiang698e6ed2014-11-09 11:22:24 -0800172 if (m_onSucceed != nullptr)
Yumin Xia2c509c22017-02-09 14:37:36 -0800173 m_onSucceed(data, re);
Shock Jiang698e6ed2014-11-09 11:22:24 -0800174 else
175 NDNS_LOG_TRACE("succeed callback is nullptr");
176 }
177 else if (m_step == QUERY_STEP_ABORT)
178 this->abort();
179}
180
181bool
182IterativeQueryController::hasEnded()
183{
184 return (m_step != QUERY_STEP_QUERY_NS && m_step != QUERY_STEP_QUERY_RR);
185}
186
187void
188IterativeQueryController::start()
189{
Shock Jiang5d5928c2014-12-03 13:41:22 -0800190 if (m_dstLabel.size() == m_nFinishedComps)
191 m_step = QUERY_STEP_QUERY_RR;
192
Shock Jiang698e6ed2014-11-09 11:22:24 -0800193 Interest interest = this->makeLatestInterest();
194 express(interest);
195}
196
197
198void
199IterativeQueryController::express(const Interest& interest)
200{
Yumin Xiad8b75fc2017-04-05 15:00:21 -0700201 if (m_nsCache != nullptr) {
202 shared_ptr<const Data> cachedData = m_nsCache->find(interest);
203 if (cachedData != nullptr) {
204 NDNS_LOG_DEBUG("[* cached *] NS record has been cached before: "
205 << interest.getName());
206 onData(interest, *cachedData);
207 return ;
208 }
209 }
210
Shock Jiang698e6ed2014-11-09 11:22:24 -0800211 NDNS_LOG_DEBUG("[* <- *] send a Query: " << interest.getName());
212 m_face.expressInterest(interest,
213 bind(&IterativeQueryController::onData, this, _1, _2),
Alexander Afanasyevf4193ea2017-06-12 15:35:13 -0700214 bind(&IterativeQueryController::onTimeout, this, _1), // nack
Shock Jiang698e6ed2014-11-09 11:22:24 -0800215 bind(&IterativeQueryController::onTimeout, this, _1)
216 );
217}
218
219
220const Response
221IterativeQueryController::parseFinalResponse(const Data& data)
222{
223 Response re;
224 Name zone = m_dstLabel.getPrefix(m_nFinishedComps);
Yumin Xia6343c5b2016-10-20 15:45:50 -0700225 re.fromData(zone, data);
Shock Jiang698e6ed2014-11-09 11:22:24 -0800226 return re;
227}
228
229const Interest
230IterativeQueryController::makeLatestInterest()
231{
232 // NDNS_LOG_TRACE("get latest Interest");
233 Query query;
234 //const Name& dstLabel = m_query.getRrLabel();
235
236 query.setZone(m_dstLabel.getPrefix(m_nFinishedComps));
237 query.setInterestLifetime(m_interestLifetime);
Yumin Xia4e561892016-10-21 10:48:01 -0700238
239 // addLink
240 if (m_lastLink.hasWire()) {
Junxiao Shi81e98762022-01-11 18:17:24 +0000241 query.setForwardingHintFromLink(Link(m_lastLink));
Yumin Xia4e561892016-10-21 10:48:01 -0700242 }
243
Shock Jiang698e6ed2014-11-09 11:22:24 -0800244 switch (m_step) {
245 case QUERY_STEP_QUERY_NS:
246 query.setQueryType(label::NDNS_ITERATIVE_QUERY);
247 query.setRrLabel(m_dstLabel.getSubName(m_nFinishedComps, m_nTryComps));
248 query.setRrType(label::NS_RR_TYPE);
249 break;
250 case QUERY_STEP_QUERY_RR:
Yumin Xia918343d2017-03-17 19:04:55 -0700251 query.setQueryType(label::NDNS_ITERATIVE_QUERY);
Shock Jiang698e6ed2014-11-09 11:22:24 -0800252 query.setRrLabel(m_dstLabel.getSubName(m_nFinishedComps));
253 query.setRrType(m_rrType);
254 break;
255 default:
256 std::ostringstream oss;
257 oss << *this;
258 NDNS_LOG_WARN("unexpected state: " << oss.str());
Davide Pesavento948c50c2020-12-26 21:30:45 -0500259 NDN_THROW(std::runtime_error("call makeLatestInterest() unexpected: " + oss.str()));
Shock Jiang698e6ed2014-11-09 11:22:24 -0800260 }
261
Yumin Xia55a7cc42017-05-14 18:43:34 -0700262 m_lastLabelType = Name(query.getRrLabel()).append(query.getRrType());
Shock Jiang698e6ed2014-11-09 11:22:24 -0800263 Interest interest = query.toInterest();
264 return interest;
265}
266
Yumin Xia55a7cc42017-05-14 18:43:34 -0700267bool
268IterativeQueryController::isAbsentByDoe(const Data& data) const
269{
270 std::pair<Name, Name> range = Response::wireDecodeDoe(data.getContent());
271
272 // should not be simple <, use our own definition of compare
273 if (range.first < m_lastLabelType && m_lastLabelType < range.second) {
274 return true;
275 }
276 if (range.second < range.first &&
277 (m_lastLabelType < range.first || range.second < m_lastLabelType)) {
278 return true;
279 }
280 return false;
281}
282
Shock Jiang698e6ed2014-11-09 11:22:24 -0800283std::ostream&
284operator<<(std::ostream& os, const IterativeQueryController::QueryStep step)
285{
286 switch (step) {
287 case IterativeQueryController::QUERY_STEP_QUERY_NS:
288 os << "QueryNS";
289 break;
290 case IterativeQueryController::QUERY_STEP_QUERY_RR:
291 os << "QueryRR";
292 break;
293 case IterativeQueryController::QUERY_STEP_ANSWER_STUB:
294 os << "AnswerStub";
295 break;
296 case IterativeQueryController::QUERY_STEP_ABORT:
297 os << "Abort";
298 break;
299 default:
300 os << "UNKNOW";
301 break;
302 }
303 return os;
304}
305
306std::ostream&
307operator<<(std::ostream& os, const IterativeQueryController& ctr)
308{
309 os << "InterativeQueryController: dstLabel=" << ctr.getDstLabel()
310 << " rrType=" << ctr.getRrType()
311 << " currentStep=" << ctr.getStep()
312 << " nFinishedComps=" << ctr.getNFinishedComps()
313 << " nTryComp=" << ctr.getNTryComps()
314 ;
315
316 return os;
317}
318
319} // namespace ndns
320} // namespace ndn