blob: 1d7af26130ac44bd4a235a30c12507fb80c0de4a [file] [log] [blame]
Shock Jiang698e6ed2014-11-09 11:22:24 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014, Regents of the University of California.
4 *
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,
33 Face& face)
34 : QueryController(dstLabel, rrType, interestLifetime, onSucceed, onFail, face)
35 , m_step(QUERY_STEP_QUERY_NS)
36 , m_nFinishedComps(0)
37 , m_nTryComps(1)
38{
39 if (m_dstLabel.size() == 1) // the first one is to Query RR directly
40 m_step = QUERY_STEP_QUERY_RR;
41}
42
43void
44IterativeQueryController::onTimeout(const Interest& interest)
45{
46 NDNS_LOG_INFO("[* !! *] timeout happens: " << interest.getName());
47 NDNS_LOG_TRACE(*this);
48 this->abort();
49}
50
51void
52IterativeQueryController::abort()
53{
54 NDNS_LOG_DEBUG("abort iterative query");
55 if (m_onFail != nullptr)
56 m_onFail(0, "abort");
57 else
58 NDNS_LOG_TRACE("m_onFail is 0");
59
60}
61
62void
63IterativeQueryController::onData(const ndn::Interest& interest, const Data& data)
64{
65 NdnsType ndnsType = NDNS_RAW;
66 const Block* block = data.getMetaInfo().findAppMetaInfo(ndns::tlv::NdnsType);
67 if (block != nullptr) {
68 ndnsType = static_cast<NdnsType>(readNonNegativeInteger(*block));
69 }
70
71 NDNS_LOG_TRACE("[* -> *] get a " << ndnsType
72 << " Response: " << data.getName());
73
74 switch (m_step) {
75 case QUERY_STEP_QUERY_NS:
76 if (ndnsType == NDNS_NACK) {
77 if (m_nFinishedComps + m_nTryComps == m_dstLabel.size() && m_rrType != label::NS_RR_TYPE)
78 m_step = QUERY_STEP_QUERY_RR;
79 else
80 m_step = QUERY_STEP_ANSWER_STUB;
81 }
82 else if (ndnsType == NDNS_RESP) {
83 if (m_nFinishedComps + m_nTryComps == m_dstLabel.size() && m_rrType == label::NS_RR_TYPE) {
84 // NS_RR_TYPE is different, since its record is stored at higher level
85 m_step = QUERY_STEP_ANSWER_STUB;
86 }
87 else {
88 m_nFinishedComps += m_nTryComps;
89 m_nTryComps = 1;
90 }
91 }
92 else if (ndnsType == NDNS_AUTH) {
93 m_nTryComps += 1;
94 }
95 else if (ndnsType == NDNS_RAW) {
96 std::ostringstream oss;
97 oss << *this;
98 NDNS_LOG_WARN("get unexpected Response: NDNS_RAW for QUERY_NS: " << oss.str());
99 }
100 //
101 if (m_nFinishedComps + m_nTryComps > m_dstLabel.size()) {
102 if (m_rrType == label::NS_RR_TYPE) {
103 m_step = QUERY_STEP_ANSWER_STUB;
104 }
105 else
106 m_step = QUERY_STEP_QUERY_RR;
107 }
108 break;
109 case QUERY_STEP_QUERY_RR:
110 m_step = QUERY_STEP_ANSWER_STUB;
111 break;
112 default:
113 NDNS_LOG_WARN("get unexpected Response at State " << *this);
114 // throw std::runtime_error("call makeLatestInterest() unexpected: " << *this);
115 // do not throw except since it may be duplicated Data
116 m_step = QUERY_STEP_ABORT;
117 break;
118 }
119
120 if (!hasEnded())
121 this->express(this->makeLatestInterest()); // express new Expres
122 else if (m_step == QUERY_STEP_ANSWER_STUB) {
123 NDNS_LOG_TRACE("query ends: " << *this);
124 Response re = this->parseFinalResponse(data);
125 if (m_onSucceed != nullptr)
126 m_onSucceed(data, re);
127 else
128 NDNS_LOG_TRACE("succeed callback is nullptr");
129 }
130 else if (m_step == QUERY_STEP_ABORT)
131 this->abort();
132}
133
134bool
135IterativeQueryController::hasEnded()
136{
137 return (m_step != QUERY_STEP_QUERY_NS && m_step != QUERY_STEP_QUERY_RR);
138}
139
140void
141IterativeQueryController::start()
142{
143 Interest interest = this->makeLatestInterest();
144 express(interest);
145}
146
147
148void
149IterativeQueryController::express(const Interest& interest)
150{
151 NDNS_LOG_DEBUG("[* <- *] send a Query: " << interest.getName());
152 m_face.expressInterest(interest,
153 bind(&IterativeQueryController::onData, this, _1, _2),
154 bind(&IterativeQueryController::onTimeout, this, _1)
155 );
156}
157
158
159const Response
160IterativeQueryController::parseFinalResponse(const Data& data)
161{
162 Response re;
163 Name zone = m_dstLabel.getPrefix(m_nFinishedComps);
164 re.fromData("", zone, data);
165 return re;
166}
167
168const Interest
169IterativeQueryController::makeLatestInterest()
170{
171 // NDNS_LOG_TRACE("get latest Interest");
172 Query query;
173 //const Name& dstLabel = m_query.getRrLabel();
174
175 query.setZone(m_dstLabel.getPrefix(m_nFinishedComps));
176 query.setInterestLifetime(m_interestLifetime);
177 switch (m_step) {
178 case QUERY_STEP_QUERY_NS:
179 query.setQueryType(label::NDNS_ITERATIVE_QUERY);
180 query.setRrLabel(m_dstLabel.getSubName(m_nFinishedComps, m_nTryComps));
181 query.setRrType(label::NS_RR_TYPE);
182 break;
183 case QUERY_STEP_QUERY_RR:
184 if (m_rrType == label::CERT_RR_TYPE) {
185 // this only works for dsk, and ksk needs different mechanism
186 query.setQueryType(label::NDNS_CERT_QUERY);
187 }
188 else {
189 query.setQueryType(label::NDNS_ITERATIVE_QUERY);
190 }
191 query.setRrLabel(m_dstLabel.getSubName(m_nFinishedComps));
192 query.setRrType(m_rrType);
193 break;
194 default:
195 std::ostringstream oss;
196 oss << *this;
197 NDNS_LOG_WARN("unexpected state: " << oss.str());
198 throw std::runtime_error("call makeLatestInterest() unexpected: " + oss.str());
199 }
200
201
202 Interest interest = query.toInterest();
203 return interest;
204}
205
206std::ostream&
207operator<<(std::ostream& os, const IterativeQueryController::QueryStep step)
208{
209 switch (step) {
210 case IterativeQueryController::QUERY_STEP_QUERY_NS:
211 os << "QueryNS";
212 break;
213 case IterativeQueryController::QUERY_STEP_QUERY_RR:
214 os << "QueryRR";
215 break;
216 case IterativeQueryController::QUERY_STEP_ANSWER_STUB:
217 os << "AnswerStub";
218 break;
219 case IterativeQueryController::QUERY_STEP_ABORT:
220 os << "Abort";
221 break;
222 default:
223 os << "UNKNOW";
224 break;
225 }
226 return os;
227}
228
229std::ostream&
230operator<<(std::ostream& os, const IterativeQueryController& ctr)
231{
232 os << "InterativeQueryController: dstLabel=" << ctr.getDstLabel()
233 << " rrType=" << ctr.getRrType()
234 << " currentStep=" << ctr.getStep()
235 << " nFinishedComps=" << ctr.getNFinishedComps()
236 << " nTryComp=" << ctr.getNTryComps()
237 ;
238
239 return os;
240}
241
242} // namespace ndns
243} // namespace ndn