blob: ab64adc14f0d36eca80d352903f44e21e55b9747 [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/*
3 * Copyright (c) 2014-2017, 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"
Yumin Xia2c509c22017-02-09 14:37:36 -080021#include "validator.hpp"
Shock Jiang698e6ed2014-11-09 11:22:24 -080022#include "logger.hpp"
23#include <iostream>
24
25namespace ndn {
26namespace ndns {
27NDNS_LOG_INIT("IterQueryCtr")
28
29IterativeQueryController::IterativeQueryController(const Name& dstLabel,
30 const name::Component& rrType,
31 const time::milliseconds& interestLifetime,
32 const QuerySucceedCallback& onSucceed,
33 const QueryFailCallback& onFail,
Shock Jiang5d5928c2014-12-03 13:41:22 -080034 Face& face,
Yumin Xiad8b75fc2017-04-05 15:00:21 -070035 security::v2::Validator* validator,
36 ndn::InMemoryStorage* cache)
Shock Jiang698e6ed2014-11-09 11:22:24 -080037 : QueryController(dstLabel, rrType, interestLifetime, onSucceed, onFail, face)
Shock Jiang5d5928c2014-12-03 13:41:22 -080038 , m_validator(validator)
Shock Jiang698e6ed2014-11-09 11:22:24 -080039 , m_step(QUERY_STEP_QUERY_NS)
40 , m_nFinishedComps(0)
41 , m_nTryComps(1)
Yumin Xiad8b75fc2017-04-05 15:00:21 -070042 , m_nsCache(cache)
Shock Jiang698e6ed2014-11-09 11:22:24 -080043{
Shock Jiang698e6ed2014-11-09 11:22:24 -080044}
45
46void
47IterativeQueryController::onTimeout(const Interest& interest)
48{
49 NDNS_LOG_INFO("[* !! *] timeout happens: " << interest.getName());
50 NDNS_LOG_TRACE(*this);
51 this->abort();
52}
53
54void
55IterativeQueryController::abort()
56{
57 NDNS_LOG_DEBUG("abort iterative query");
58 if (m_onFail != nullptr)
59 m_onFail(0, "abort");
60 else
61 NDNS_LOG_TRACE("m_onFail is 0");
62
63}
64
65void
66IterativeQueryController::onData(const ndn::Interest& interest, const Data& data)
67{
Yumin Xiaa484ba72016-11-10 20:40:12 -080068 NdnsContentType contentType = NdnsContentType(data.getContentType());
Shock Jiang698e6ed2014-11-09 11:22:24 -080069
Yumin Xiaa484ba72016-11-10 20:40:12 -080070 NDNS_LOG_TRACE("[* -> *] get a " << contentType
Shock Jiang698e6ed2014-11-09 11:22:24 -080071 << " Response: " << data.getName());
Shock Jiang5d5928c2014-12-03 13:41:22 -080072 if (m_validator == nullptr) {
Yumin Xia2c509c22017-02-09 14:37:36 -080073 this->onDataValidated(data, contentType);
Shock Jiang5d5928c2014-12-03 13:41:22 -080074 }
75 else {
76 m_validator->validate(data,
Yumin Xiaa484ba72016-11-10 20:40:12 -080077 bind(&IterativeQueryController::onDataValidated, this, _1, contentType),
Yumin Xia2c509c22017-02-09 14:37:36 -080078 [this] (const Data& data, const security::v2::ValidationError& err) {
79 NDNS_LOG_WARN("data: " << data.getName() << " fails verification");
Shock Jiang5d5928c2014-12-03 13:41:22 -080080 this->abort();
81 }
82 );
83 }
84}
85void
Yumin Xia2c509c22017-02-09 14:37:36 -080086IterativeQueryController::onDataValidated(const Data& data, NdnsContentType contentType)
Shock Jiang5d5928c2014-12-03 13:41:22 -080087{
Yumin Xiad8b75fc2017-04-05 15:00:21 -070088 if (m_nsCache != nullptr && contentType == NDNS_LINK) {
89 m_nsCache->insert(data);
90 }
91
Shock Jiang698e6ed2014-11-09 11:22:24 -080092 switch (m_step) {
93 case QUERY_STEP_QUERY_NS:
Yumin Xiaa484ba72016-11-10 20:40:12 -080094 if (contentType == NDNS_NACK) {
Shock Jiang06cd2142014-11-23 17:36:02 -080095 m_step = QUERY_STEP_QUERY_RR;
Shock Jiang698e6ed2014-11-09 11:22:24 -080096 }
Yumin Xiaa484ba72016-11-10 20:40:12 -080097 else if (contentType == NDNS_LINK) {
Yumin Xia2c509c22017-02-09 14:37:36 -080098 Link link(data.wireEncode());
99 if (link.getDelegationList().empty()) {
Yumin Xiaa484ba72016-11-10 20:40:12 -0800100 m_lastLink = Block();
Yumin Xia2c509c22017-02-09 14:37:36 -0800101 }
102 else {
103 m_lastLink = data.wireEncode();
Yumin Xia4e561892016-10-21 10:48:01 -0700104 }
Yumin Xiaa484ba72016-11-10 20:40:12 -0800105
106 // for NS query, if already received, just return, instead of more queries until NACK
Shock Jiang698e6ed2014-11-09 11:22:24 -0800107 if (m_nFinishedComps + m_nTryComps == m_dstLabel.size() && m_rrType == label::NS_RR_TYPE) {
108 // NS_RR_TYPE is different, since its record is stored at higher level
109 m_step = QUERY_STEP_ANSWER_STUB;
110 }
111 else {
112 m_nFinishedComps += m_nTryComps;
113 m_nTryComps = 1;
114 }
115 }
Yumin Xiaa484ba72016-11-10 20:40:12 -0800116 else if (contentType == NDNS_AUTH) {
Shock Jiang698e6ed2014-11-09 11:22:24 -0800117 m_nTryComps += 1;
118 }
Yumin Xiaa484ba72016-11-10 20:40:12 -0800119 else if (contentType == NDNS_BLOB) {
Shock Jiang698e6ed2014-11-09 11:22:24 -0800120 std::ostringstream oss;
121 oss << *this;
Yumin Xiaa484ba72016-11-10 20:40:12 -0800122 NDNS_LOG_WARN("get unexpected Response: NDNS_BLOB for QUERY_NS: " << oss.str());
Yumin Xia2c509c22017-02-09 14:37:36 -0800123 }
124 else {
Yumin Xiaa484ba72016-11-10 20:40:12 -0800125 std::ostringstream oss;
126 oss << *this;
127 NDNS_LOG_WARN("get unexpected Response for QUERY_NS: " << oss.str());
Shock Jiang698e6ed2014-11-09 11:22:24 -0800128 }
129 //
130 if (m_nFinishedComps + m_nTryComps > m_dstLabel.size()) {
131 if (m_rrType == label::NS_RR_TYPE) {
132 m_step = QUERY_STEP_ANSWER_STUB;
133 }
134 else
135 m_step = QUERY_STEP_QUERY_RR;
136 }
137 break;
138 case QUERY_STEP_QUERY_RR:
139 m_step = QUERY_STEP_ANSWER_STUB;
140 break;
141 default:
142 NDNS_LOG_WARN("get unexpected Response at State " << *this);
143 // throw std::runtime_error("call makeLatestInterest() unexpected: " << *this);
144 // do not throw except since it may be duplicated Data
145 m_step = QUERY_STEP_ABORT;
146 break;
147 }
148
149 if (!hasEnded())
150 this->express(this->makeLatestInterest()); // express new Expres
151 else if (m_step == QUERY_STEP_ANSWER_STUB) {
152 NDNS_LOG_TRACE("query ends: " << *this);
Yumin Xia2c509c22017-02-09 14:37:36 -0800153 Response re = this->parseFinalResponse(data);
Shock Jiang698e6ed2014-11-09 11:22:24 -0800154 if (m_onSucceed != nullptr)
Yumin Xia2c509c22017-02-09 14:37:36 -0800155 m_onSucceed(data, re);
Shock Jiang698e6ed2014-11-09 11:22:24 -0800156 else
157 NDNS_LOG_TRACE("succeed callback is nullptr");
158 }
159 else if (m_step == QUERY_STEP_ABORT)
160 this->abort();
161}
162
163bool
164IterativeQueryController::hasEnded()
165{
166 return (m_step != QUERY_STEP_QUERY_NS && m_step != QUERY_STEP_QUERY_RR);
167}
168
169void
170IterativeQueryController::start()
171{
Shock Jiang5d5928c2014-12-03 13:41:22 -0800172 if (m_dstLabel.size() == m_nFinishedComps)
173 m_step = QUERY_STEP_QUERY_RR;
174
Shock Jiang698e6ed2014-11-09 11:22:24 -0800175 Interest interest = this->makeLatestInterest();
176 express(interest);
177}
178
179
180void
181IterativeQueryController::express(const Interest& interest)
182{
Yumin Xiad8b75fc2017-04-05 15:00:21 -0700183 if (m_nsCache != nullptr) {
184 shared_ptr<const Data> cachedData = m_nsCache->find(interest);
185 if (cachedData != nullptr) {
186 NDNS_LOG_DEBUG("[* cached *] NS record has been cached before: "
187 << interest.getName());
188 onData(interest, *cachedData);
189 return ;
190 }
191 }
192
Shock Jiang698e6ed2014-11-09 11:22:24 -0800193 NDNS_LOG_DEBUG("[* <- *] send a Query: " << interest.getName());
194 m_face.expressInterest(interest,
195 bind(&IterativeQueryController::onData, this, _1, _2),
Alexander Afanasyevf4193ea2017-06-12 15:35:13 -0700196 bind(&IterativeQueryController::onTimeout, this, _1), // nack
Shock Jiang698e6ed2014-11-09 11:22:24 -0800197 bind(&IterativeQueryController::onTimeout, this, _1)
198 );
199}
200
201
202const Response
203IterativeQueryController::parseFinalResponse(const Data& data)
204{
205 Response re;
206 Name zone = m_dstLabel.getPrefix(m_nFinishedComps);
Yumin Xia6343c5b2016-10-20 15:45:50 -0700207 re.fromData(zone, data);
Shock Jiang698e6ed2014-11-09 11:22:24 -0800208 return re;
209}
210
211const Interest
212IterativeQueryController::makeLatestInterest()
213{
214 // NDNS_LOG_TRACE("get latest Interest");
215 Query query;
216 //const Name& dstLabel = m_query.getRrLabel();
217
218 query.setZone(m_dstLabel.getPrefix(m_nFinishedComps));
219 query.setInterestLifetime(m_interestLifetime);
Yumin Xia4e561892016-10-21 10:48:01 -0700220
221 // addLink
222 if (m_lastLink.hasWire()) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800223 query.setDelegationListFromLink(Link(m_lastLink));
Yumin Xia4e561892016-10-21 10:48:01 -0700224 }
225
Shock Jiang698e6ed2014-11-09 11:22:24 -0800226 switch (m_step) {
227 case QUERY_STEP_QUERY_NS:
228 query.setQueryType(label::NDNS_ITERATIVE_QUERY);
229 query.setRrLabel(m_dstLabel.getSubName(m_nFinishedComps, m_nTryComps));
230 query.setRrType(label::NS_RR_TYPE);
231 break;
232 case QUERY_STEP_QUERY_RR:
Yumin Xia918343d2017-03-17 19:04:55 -0700233 query.setQueryType(label::NDNS_ITERATIVE_QUERY);
Shock Jiang698e6ed2014-11-09 11:22:24 -0800234 query.setRrLabel(m_dstLabel.getSubName(m_nFinishedComps));
235 query.setRrType(m_rrType);
236 break;
237 default:
238 std::ostringstream oss;
239 oss << *this;
240 NDNS_LOG_WARN("unexpected state: " << oss.str());
Yumin Xia2c509c22017-02-09 14:37:36 -0800241 BOOST_THROW_EXCEPTION(std::runtime_error("call makeLatestInterest() unexpected: "
242 + oss.str()));
Shock Jiang698e6ed2014-11-09 11:22:24 -0800243 }
244
Shock Jiang698e6ed2014-11-09 11:22:24 -0800245 Interest interest = query.toInterest();
246 return interest;
247}
248
249std::ostream&
250operator<<(std::ostream& os, const IterativeQueryController::QueryStep step)
251{
252 switch (step) {
253 case IterativeQueryController::QUERY_STEP_QUERY_NS:
254 os << "QueryNS";
255 break;
256 case IterativeQueryController::QUERY_STEP_QUERY_RR:
257 os << "QueryRR";
258 break;
259 case IterativeQueryController::QUERY_STEP_ANSWER_STUB:
260 os << "AnswerStub";
261 break;
262 case IterativeQueryController::QUERY_STEP_ABORT:
263 os << "Abort";
264 break;
265 default:
266 os << "UNKNOW";
267 break;
268 }
269 return os;
270}
271
272std::ostream&
273operator<<(std::ostream& os, const IterativeQueryController& ctr)
274{
275 os << "InterativeQueryController: dstLabel=" << ctr.getDstLabel()
276 << " rrType=" << ctr.getRrType()
277 << " currentStep=" << ctr.getStep()
278 << " nFinishedComps=" << ctr.getNFinishedComps()
279 << " nTryComp=" << ctr.getNTryComps()
280 ;
281
282 return os;
283}
284
285} // namespace ndns
286} // namespace ndn