blob: eeedc7cf57e437de360ad4e43bd69d2b6badb5c9 [file] [log] [blame]
Yanbiao Li8ee37ed2015-05-19 12:44:04 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Yanbiao Li4b4f7542016-03-11 02:04:43 +08003 * Copyright (c) 2013-2016 Regents of the University of California.
Yanbiao Li8ee37ed2015-05-19 12:44:04 -07004 *
Alexander Afanasyev80b68e12015-09-17 17:01:04 -07005 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Yanbiao Li8ee37ed2015-05-19 12:44:04 -07006 *
Alexander Afanasyev80b68e12015-09-17 17:01:04 -07007 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070010 *
Alexander Afanasyev80b68e12015-09-17 17:01:04 -070011 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070014 *
Alexander Afanasyev80b68e12015-09-17 17:01:04 -070015 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070020 */
21
22#include "dispatcher.hpp"
Junxiao Shi43a79322016-08-08 05:48:43 +000023#include "../util/logger.hpp"
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070024
25#include <algorithm>
26
Junxiao Shi43a79322016-08-08 05:48:43 +000027NDN_LOG_INIT(ndn.mgmt.Dispatcher);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070028
29namespace ndn {
30namespace mgmt {
31
Yanbiao Li4b4f7542016-03-11 02:04:43 +080032const time::milliseconds DEFAULT_FRESHNESS_PERIOD = time::milliseconds(1000);
33
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070034Authorization
35makeAcceptAllAuthorization()
36{
37 return [] (const Name& prefix,
38 const Interest& interest,
39 const ControlParameters* params,
Junxiao Shif65a3362015-09-06 20:54:54 -070040 const AcceptContinuation& accept,
41 const RejectContinuation& reject) {
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070042 accept("");
43 };
44}
45
46Dispatcher::Dispatcher(Face& face, security::KeyChain& keyChain,
Yanbiao Li4b4f7542016-03-11 02:04:43 +080047 const security::SigningInfo& signingInfo,
48 size_t imsCapacity)
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070049 : m_face(face)
50 , m_keyChain(keyChain)
51 , m_signingInfo(signingInfo)
Yanbiao Li4b4f7542016-03-11 02:04:43 +080052 , m_storage(m_face.getIoService(), imsCapacity)
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070053{
54}
55
56Dispatcher::~Dispatcher()
57{
58 std::vector<Name> topPrefixNames;
59
60 std::transform(m_topLevelPrefixes.begin(),
61 m_topLevelPrefixes.end(),
62 std::back_inserter(topPrefixNames),
63 [] (const std::unordered_map<Name, TopPrefixEntry>::value_type& entry) {
64 return entry.second.topPrefix;
65 });
66
67 for (auto&& name : topPrefixNames) {
68 removeTopPrefix(name);
69 }
70}
71
72void
73Dispatcher::addTopPrefix(const Name& prefix,
74 bool wantRegister,
75 const security::SigningInfo& signingInfo)
76{
77 bool hasOverlap = std::any_of(m_topLevelPrefixes.begin(),
78 m_topLevelPrefixes.end(),
79 [&] (const std::unordered_map<Name, TopPrefixEntry>::value_type& x) {
80 return x.first.isPrefixOf(prefix) || prefix.isPrefixOf(x.first);
81 });
82 if (hasOverlap) {
83 BOOST_THROW_EXCEPTION(std::out_of_range("Top-level Prefixes overlapped"));
84 }
85
86 TopPrefixEntry& topPrefixEntry = m_topLevelPrefixes[prefix];;
87 topPrefixEntry.topPrefix = prefix;
88 topPrefixEntry.wantRegister = wantRegister;
89
90 if (wantRegister) {
91 RegisterPrefixFailureCallback failure = [] (const Name& name, const std::string& reason) {
92 BOOST_THROW_EXCEPTION(std::runtime_error(reason));
93 };
94 topPrefixEntry.registerPrefixId =
95 m_face.registerPrefix(prefix, bind([]{}), failure, signingInfo);
96 }
97
98 for (auto&& entry : m_handlers) {
99 Name fullPrefix = prefix;
100 fullPrefix.append(entry.first);
101
102 const InterestFilterId* interestFilterId =
103 m_face.setInterestFilter(fullPrefix, std::bind(entry.second, prefix, _2));
104
105 topPrefixEntry.interestFilters.push_back(interestFilterId);
106 }
107}
108
109void
110Dispatcher::removeTopPrefix(const Name& prefix)
111{
112 auto it = m_topLevelPrefixes.find(prefix);
113 if (it == m_topLevelPrefixes.end()) {
114 return;
115 }
116
117 const TopPrefixEntry& topPrefixEntry = it->second;
118 if (topPrefixEntry.wantRegister) {
119 m_face.unregisterPrefix(topPrefixEntry.registerPrefixId, bind([]{}), bind([]{}));
120 }
121
122 for (auto&& filter : topPrefixEntry.interestFilters) {
123 m_face.unsetInterestFilter(filter);
124 }
125
126 m_topLevelPrefixes.erase(it);
127}
128
129bool
130Dispatcher::isOverlappedWithOthers(const PartialName& relPrefix)
131{
132 bool hasOverlapWithHandlers =
133 std::any_of(m_handlers.begin(), m_handlers.end(),
134 [&] (const HandlerMap::value_type& entry) {
135 return entry.first.isPrefixOf(relPrefix) || relPrefix.isPrefixOf(entry.first);
136 });
137 bool hasOverlapWithStreams =
138 std::any_of(m_streams.begin(), m_streams.end(),
139 [&] (const std::unordered_map<PartialName, uint64_t>::value_type& entry) {
140 return entry.first.isPrefixOf(relPrefix) || relPrefix.isPrefixOf(entry.first);
141 });
142
143 return hasOverlapWithHandlers || hasOverlapWithStreams;
144}
145
146void
147Dispatcher::afterAuthorizationRejected(RejectReply act, const Interest& interest)
148{
149 if (act == RejectReply::STATUS403) {
150 sendControlResponse(ControlResponse(403, "authorization rejected"), interest);
151 }
152}
153
154void
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800155Dispatcher::queryStorage(const Name& prefix, const Interest& interest,
156 const InterestHandler& missContinuation)
157{
158 auto data = m_storage.find(interest);
159 if (data == nullptr) {
160 // invoke missContinuation to process this Interest if the query fails.
161 missContinuation(prefix, interest);
162 }
163 else {
164 // send the fetched data through face if query succeeds.
165 sendOnFace(*data);
166 }
167}
168
169void
170Dispatcher::sendData(const Name& dataName, const Block& content, const MetaInfo& metaInfo,
171 SendDestination option, time::milliseconds imsFresh)
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700172{
173 shared_ptr<Data> data = make_shared<Data>(dataName);
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800174 data->setContent(content).setMetaInfo(metaInfo).setFreshnessPeriod(DEFAULT_FRESHNESS_PERIOD);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700175
176 m_keyChain.sign(*data, m_signingInfo);
177
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800178 if (option == SendDestination::IMS || option == SendDestination::FACE_AND_IMS) {
179 lp::CachePolicy policy;
180 policy.setPolicy(lp::CachePolicyType::NO_CACHE);
181 data->setTag(make_shared<lp::CachePolicyTag>(policy));
182 m_storage.insert(*data, imsFresh);
183 }
184
185 if (option == SendDestination::FACE || option == SendDestination::FACE_AND_IMS) {
186 sendOnFace(*data);
187 }
188}
189
190void
191Dispatcher::sendOnFace(const Data& data)
192{
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700193 try {
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800194 m_face.put(data);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700195 }
Junxiao Shi43a79322016-08-08 05:48:43 +0000196 catch (const Face::Error& e) {
197 NDN_LOG_ERROR("sendOnFace: " << e.what());
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700198 }
199}
200
201void
202Dispatcher::processControlCommandInterest(const Name& prefix,
203 const Name& relPrefix,
204 const Interest& interest,
205 const ControlParametersParser& parser,
206 const Authorization& authorization,
207 const AuthorizationAcceptedCallback& accepted,
208 const AuthorizationRejectedCallback& rejected)
209{
210 // /<prefix>/<relPrefix>/<parameters>
211 size_t parametersLoc = prefix.size() + relPrefix.size();
212 const name::Component& pc = interest.getName().get(parametersLoc);
213
214 shared_ptr<ControlParameters> parameters;
215 try {
216 parameters = parser(pc);
217 }
Junxiao Shi43a79322016-08-08 05:48:43 +0000218 catch (const tlv::Error&) {
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700219 return;
220 }
221
222 AcceptContinuation accept = bind(accepted, _1, prefix, interest, parameters.get());
223 RejectContinuation reject = bind(rejected, _1, interest);
224 authorization(prefix, interest, parameters.get(), accept, reject);
225}
226
227void
228Dispatcher::processAuthorizedControlCommandInterest(const std::string& requester,
229 const Name& prefix,
230 const Interest& interest,
231 const ControlParameters* parameters,
232 const ValidateParameters& validateParams,
233 const ControlCommandHandler& handler)
234{
235 if (validateParams(*parameters)) {
236 handler(prefix, interest, *parameters,
237 bind(&Dispatcher::sendControlResponse, this, _1, interest, false));
238 }
239 else {
240 sendControlResponse(ControlResponse(400, "failed in validating parameters"), interest);
241 }
242}
243
244void
245Dispatcher::sendControlResponse(const ControlResponse& resp, const Interest& interest,
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800246 bool isNack)
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700247{
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800248 MetaInfo metaInfo;
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700249 if (isNack) {
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800250 metaInfo.setType(tlv::ContentType_Nack);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700251 }
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800252 // control response is always sent out through the face
253 sendData(interest.getName(), resp.wireEncode(), metaInfo, SendDestination::FACE,
254 DEFAULT_FRESHNESS_PERIOD);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700255}
256
257void
258Dispatcher::addStatusDataset(const PartialName& relPrefix,
Junxiao Shif65a3362015-09-06 20:54:54 -0700259 const Authorization& authorization,
260 const StatusDatasetHandler& handler)
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700261{
262 if (!m_topLevelPrefixes.empty()) {
263 BOOST_THROW_EXCEPTION(std::domain_error("one or more top-level prefix has been added"));
264 }
265
266 if (isOverlappedWithOthers(relPrefix)) {
267 BOOST_THROW_EXCEPTION(std::out_of_range("relPrefix overlapped"));
268 }
269
270 AuthorizationAcceptedCallback accepted =
271 bind(&Dispatcher::processAuthorizedStatusDatasetInterest, this,
272 _1, _2, _3, handler);
273 AuthorizationRejectedCallback rejected =
274 bind(&Dispatcher::afterAuthorizationRejected, this, _1, _2);
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800275
276 // follow the general path if storage is a miss
277 InterestHandler missContinuation = bind(&Dispatcher::processStatusDatasetInterest, this,
278 _1, _2, authorization, accepted, rejected);
279 m_handlers[relPrefix] = bind(&Dispatcher::queryStorage, this, _1, _2, missContinuation);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700280}
281
282void
283Dispatcher::processStatusDatasetInterest(const Name& prefix,
284 const Interest& interest,
285 const Authorization& authorization,
286 const AuthorizationAcceptedCallback& accepted,
287 const AuthorizationRejectedCallback& rejected)
288{
289 const Name& interestName = interest.getName();
290 bool endsWithVersionOrSegment = interestName.size() >= 1 &&
291 (interestName[-1].isVersion() || interestName[-1].isSegment());
292 if (endsWithVersionOrSegment) {
293 return;
294 }
295
296 AcceptContinuation accept = bind(accepted, _1, prefix, interest, nullptr);
297 RejectContinuation reject = bind(rejected, _1, interest);
298 authorization(prefix, interest, nullptr, accept, reject);
299}
300
301void
302Dispatcher::processAuthorizedStatusDatasetInterest(const std::string& requester,
303 const Name& prefix,
304 const Interest& interest,
305 const StatusDatasetHandler& handler)
306{
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800307 StatusDatasetContext context(interest,
308 bind(&Dispatcher::sendStatusDatasetSegment, this, _1, _2, _3, _4),
309 bind(&Dispatcher::sendControlResponse, this, _1, interest, true));
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700310 handler(prefix, interest, context);
311}
312
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800313void
314Dispatcher::sendStatusDatasetSegment(const Name& dataName, const Block& content,
315 time::milliseconds imsFresh, bool isFinalBlock)
316{
317 // the first segment will be sent to both places (the face and the in-memory storage)
318 // other segments will be inserted to the in-memory storage only
319 auto destination = SendDestination::IMS;
320 if (dataName[-1].toSegment() == 0) {
321 destination = SendDestination::FACE_AND_IMS;
322 }
323
324 MetaInfo metaInfo;
325 if (isFinalBlock) {
326 metaInfo.setFinalBlockId(dataName[-1]);
327 }
328
329 sendData(dataName, content, metaInfo, destination, imsFresh);
330}
331
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700332PostNotification
333Dispatcher::addNotificationStream(const PartialName& relPrefix)
334{
335 if (!m_topLevelPrefixes.empty()) {
Junxiao Shi43a79322016-08-08 05:48:43 +0000336 BOOST_THROW_EXCEPTION(std::domain_error("one or more top-level prefix has been added"));
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700337 }
338
339 if (isOverlappedWithOthers(relPrefix)) {
Junxiao Shi43a79322016-08-08 05:48:43 +0000340 BOOST_THROW_EXCEPTION(std::out_of_range("relPrefix overlaps with another relPrefix"));
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700341 }
342
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800343 // keep silent if Interest does not match a stored notification
344 InterestHandler missContinuation = bind([]{});
345
346 // register a handler for the subscriber of this notification stream
347 m_handlers[relPrefix] = bind(&Dispatcher::queryStorage, this, _1, _2, missContinuation);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700348 m_streams[relPrefix] = 0;
349 return bind(&Dispatcher::postNotification, this, _1, relPrefix);
350}
351
352void
353Dispatcher::postNotification(const Block& notification, const PartialName& relPrefix)
354{
355 if (m_topLevelPrefixes.empty() || m_topLevelPrefixes.size() > 1) {
Junxiao Shi43a79322016-08-08 05:48:43 +0000356 NDN_LOG_WARN("postNotification: no top-level prefix or too many top-level prefixes");
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700357 return;
358 }
359
360 Name streamName(m_topLevelPrefixes.begin()->second.topPrefix);
361 streamName.append(relPrefix);
362 streamName.appendSequenceNumber(m_streams[streamName]++);
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800363
Junxiao Shi43a79322016-08-08 05:48:43 +0000364 // notification is sent out by the face after inserting into the in-memory storage,
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800365 // because a request may be pending in the PIT
366 sendData(streamName, notification, MetaInfo(), SendDestination::FACE_AND_IMS,
367 DEFAULT_FRESHNESS_PERIOD);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700368}
369
370} // namespace mgmt
371} // namespace ndn