NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.5: NDN, CCN, CCNx, content centric networks
API Documentation
dispatcher.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2019 Regents of the University of California.
4  *
5  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6  *
7  * 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.
10  *
11  * 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.
14  *
15  * 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.
20  */
21 
23 #include "ndn-cxx/lp/tags.hpp"
24 #include "ndn-cxx/util/logger.hpp"
25 
27 
28 namespace ndn {
29 namespace mgmt {
30 
31 const time::milliseconds DEFAULT_FRESHNESS_PERIOD = 1_s;
32 
35 {
36  return [] (const Name& prefix,
37  const Interest& interest,
38  const ControlParameters* params,
39  const AcceptContinuation& accept,
40  const RejectContinuation& reject) {
41  accept("");
42  };
43 }
44 
46  const security::SigningInfo& signingInfo,
47  size_t imsCapacity)
48  : m_face(face)
49  , m_keyChain(keyChain)
50  , m_signingInfo(signingInfo)
51  , m_storage(m_face.getIoService(), imsCapacity)
52 {
53 }
54 
55 Dispatcher::~Dispatcher() = default;
56 
57 void
58 Dispatcher::addTopPrefix(const Name& prefix, bool wantRegister,
59  const security::SigningInfo& signingInfo)
60 {
61  bool hasOverlap = std::any_of(m_topLevelPrefixes.begin(), m_topLevelPrefixes.end(),
62  [&prefix] (const auto& x) {
63  return x.first.isPrefixOf(prefix) || prefix.isPrefixOf(x.first);
64  });
65  if (hasOverlap) {
66  NDN_THROW(std::out_of_range("top-level prefix overlaps"));
67  }
68 
69  TopPrefixEntry& topPrefixEntry = m_topLevelPrefixes[prefix];
70 
71  if (wantRegister) {
72  topPrefixEntry.registeredPrefix = m_face.registerPrefix(prefix,
73  nullptr,
74  [] (const Name&, const std::string& reason) {
75  NDN_THROW(std::runtime_error("prefix registration failed: " + reason));
76  },
77  signingInfo);
78  }
79 
80  for (const auto& entry : m_handlers) {
81  Name fullPrefix = Name(prefix).append(entry.first);
82  auto filterHdl = m_face.setInterestFilter(fullPrefix, bind(entry.second, prefix, _2));
83  topPrefixEntry.interestFilters.push_back(filterHdl);
84  }
85 }
86 
87 void
89 {
90  m_topLevelPrefixes.erase(prefix);
91 }
92 
93 bool
94 Dispatcher::isOverlappedWithOthers(const PartialName& relPrefix) const
95 {
96  bool hasOverlapWithHandlers =
97  std::any_of(m_handlers.begin(), m_handlers.end(),
98  [&] (const auto& entry) {
99  return entry.first.isPrefixOf(relPrefix) || relPrefix.isPrefixOf(entry.first);
100  });
101  bool hasOverlapWithStreams =
102  std::any_of(m_streams.begin(), m_streams.end(),
103  [&] (const auto& entry) {
104  return entry.first.isPrefixOf(relPrefix) || relPrefix.isPrefixOf(entry.first);
105  });
106 
107  return hasOverlapWithHandlers || hasOverlapWithStreams;
108 }
109 
110 void
111 Dispatcher::afterAuthorizationRejected(RejectReply act, const Interest& interest)
112 {
113  if (act == RejectReply::STATUS403) {
114  sendControlResponse(ControlResponse(403, "authorization rejected"), interest);
115  }
116 }
117 
118 void
119 Dispatcher::queryStorage(const Name& prefix, const Interest& interest,
120  const InterestHandler& missContinuation)
121 {
122  auto data = m_storage.find(interest);
123  if (data == nullptr) {
124  // invoke missContinuation to process this Interest if the query fails.
125  if (missContinuation)
126  missContinuation(prefix, interest);
127  }
128  else {
129  // send the fetched data through face if query succeeds.
130  sendOnFace(*data);
131  }
132 }
133 
134 void
135 Dispatcher::sendData(const Name& dataName, const Block& content, const MetaInfo& metaInfo,
136  SendDestination option, time::milliseconds imsFresh)
137 {
138  auto data = make_shared<Data>(dataName);
139  data->setContent(content).setMetaInfo(metaInfo).setFreshnessPeriod(DEFAULT_FRESHNESS_PERIOD);
140 
141  m_keyChain.sign(*data, m_signingInfo);
142 
143  if (option == SendDestination::IMS || option == SendDestination::FACE_AND_IMS) {
144  lp::CachePolicy policy;
146  data->setTag(make_shared<lp::CachePolicyTag>(policy));
147  m_storage.insert(*data, imsFresh);
148  }
149 
150  if (option == SendDestination::FACE || option == SendDestination::FACE_AND_IMS) {
151  sendOnFace(*data);
152  }
153 }
154 
155 void
156 Dispatcher::sendOnFace(const Data& data)
157 {
158  try {
159  m_face.put(data);
160  }
161  catch (const Face::Error& e) {
162  NDN_LOG_ERROR("sendOnFace: " << e.what());
163  }
164 }
165 
166 void
167 Dispatcher::processControlCommandInterest(const Name& prefix,
168  const Name& relPrefix,
169  const Interest& interest,
170  const ControlParametersParser& parser,
171  const Authorization& authorization,
172  const AuthorizationAcceptedCallback& accepted,
173  const AuthorizationRejectedCallback& rejected)
174 {
175  // /<prefix>/<relPrefix>/<parameters>
176  size_t parametersLoc = prefix.size() + relPrefix.size();
177  const name::Component& pc = interest.getName().get(parametersLoc);
178 
179  shared_ptr<ControlParameters> parameters;
180  try {
181  parameters = parser(pc);
182  }
183  catch (const tlv::Error&) {
184  return;
185  }
186 
187  AcceptContinuation accept = [=] (const auto& req) { accepted(req, prefix, interest, parameters); };
188  RejectContinuation reject = [=] (RejectReply reply) { rejected(reply, interest); };
189  authorization(prefix, interest, parameters.get(), accept, reject);
190 }
191 
192 void
193 Dispatcher::processAuthorizedControlCommandInterest(const std::string& requester,
194  const Name& prefix,
195  const Interest& interest,
196  const shared_ptr<ControlParameters>& parameters,
197  const ValidateParameters& validateParams,
198  const ControlCommandHandler& handler)
199 {
200  if (validateParams(*parameters)) {
201  handler(prefix, interest, *parameters,
202  [=] (const auto& resp) { this->sendControlResponse(resp, interest); });
203  }
204  else {
205  sendControlResponse(ControlResponse(400, "failed in validating parameters"), interest);
206  }
207 }
208 
209 void
210 Dispatcher::sendControlResponse(const ControlResponse& resp, const Interest& interest, bool isNack)
211 {
212  MetaInfo metaInfo;
213  if (isNack) {
214  metaInfo.setType(tlv::ContentType_Nack);
215  }
216 
217  // control response is always sent out through the face
218  sendData(interest.getName(), resp.wireEncode(), metaInfo,
219  SendDestination::FACE, DEFAULT_FRESHNESS_PERIOD);
220 }
221 
222 void
224  Authorization authorize,
225  StatusDatasetHandler handle)
226 {
227  if (!m_topLevelPrefixes.empty()) {
228  NDN_THROW(std::domain_error("one or more top-level prefix has been added"));
229  }
230 
231  if (isOverlappedWithOthers(relPrefix)) {
232  NDN_THROW(std::out_of_range("status dataset name overlaps"));
233  }
234 
235  AuthorizationAcceptedCallback accepted =
236  bind(&Dispatcher::processAuthorizedStatusDatasetInterest, this, _1, _2, _3, std::move(handle));
237  AuthorizationRejectedCallback rejected =
238  bind(&Dispatcher::afterAuthorizationRejected, this, _1, _2);
239 
240  // follow the general path if storage is a miss
241  InterestHandler missContinuation = bind(&Dispatcher::processStatusDatasetInterest, this, _1, _2,
242  std::move(authorize), std::move(accepted), std::move(rejected));
243 
244  m_handlers[relPrefix] = [this, miss = std::move(missContinuation)] (auto&&... args) {
245  this->queryStorage(std::forward<decltype(args)>(args)..., miss);
246  };
247 }
248 
249 void
250 Dispatcher::processStatusDatasetInterest(const Name& prefix,
251  const Interest& interest,
252  const Authorization& authorization,
253  const AuthorizationAcceptedCallback& accepted,
254  const AuthorizationRejectedCallback& rejected)
255 {
256  const Name& interestName = interest.getName();
257  bool endsWithVersionOrSegment = interestName.size() >= 1 &&
258  (interestName[-1].isVersion() || interestName[-1].isSegment());
259  if (endsWithVersionOrSegment) {
260  return;
261  }
262 
263  AcceptContinuation accept = [=] (const auto& req) { accepted(req, prefix, interest, nullptr); };
264  RejectContinuation reject = [=] (RejectReply reply) { rejected(reply, interest); };
265  authorization(prefix, interest, nullptr, accept, reject);
266 }
267 
268 void
269 Dispatcher::processAuthorizedStatusDatasetInterest(const std::string& requester,
270  const Name& prefix,
271  const Interest& interest,
272  const StatusDatasetHandler& handler)
273 {
274  StatusDatasetContext context(interest,
275  bind(&Dispatcher::sendStatusDatasetSegment, this, _1, _2, _3, _4),
276  bind(&Dispatcher::sendControlResponse, this, _1, interest, true));
277  handler(prefix, interest, context);
278 }
279 
280 void
281 Dispatcher::sendStatusDatasetSegment(const Name& dataName, const Block& content,
282  time::milliseconds imsFresh, bool isFinalBlock)
283 {
284  // the first segment will be sent to both places (the face and the in-memory storage)
285  // other segments will be inserted to the in-memory storage only
286  auto destination = SendDestination::IMS;
287  if (dataName[-1].toSegment() == 0) {
288  destination = SendDestination::FACE_AND_IMS;
289  }
290 
291  MetaInfo metaInfo;
292  if (isFinalBlock) {
293  metaInfo.setFinalBlock(dataName[-1]);
294  }
295 
296  sendData(dataName, content, metaInfo, destination, imsFresh);
297 }
298 
301 {
302  if (!m_topLevelPrefixes.empty()) {
303  NDN_THROW(std::domain_error("one or more top-level prefix has been added"));
304  }
305 
306  if (isOverlappedWithOthers(relPrefix)) {
307  NDN_THROW(std::out_of_range("notification stream name overlaps"));
308  }
309 
310  // register a handler for the subscriber of this notification stream
311  // keep silent if Interest does not match a stored notification
312  m_handlers[relPrefix] = [this] (auto&&... args) {
313  this->queryStorage(std::forward<decltype(args)>(args)..., nullptr);
314  };
315  m_streams[relPrefix] = 0;
316 
317  return [=] (const Block& b) { postNotification(b, relPrefix); };
318 }
319 
320 void
321 Dispatcher::postNotification(const Block& notification, const PartialName& relPrefix)
322 {
323  if (m_topLevelPrefixes.size() != 1) {
324  NDN_LOG_WARN("postNotification: no top-level prefix or too many top-level prefixes");
325  return;
326  }
327 
328  Name streamName(m_topLevelPrefixes.begin()->first);
329  streamName.append(relPrefix);
330  streamName.appendSequenceNumber(m_streams[streamName]++);
331 
332  // notification is sent out via the face after inserting into the in-memory storage,
333  // because a request may be pending in the PIT
334  sendData(streamName, notification, {}, SendDestination::FACE_AND_IMS, DEFAULT_FRESHNESS_PERIOD);
335 }
336 
337 } // namespace mgmt
338 } // namespace ndn
NDN_LOG_INIT
#define NDN_LOG_INIT(name)
declare a log module
Definition: logger.hpp:81
ndn::lp::CachePolicyType::NO_CACHE
@ NO_CACHE
ndn::mgmt::AcceptContinuation
std::function< void(const std::string &requester)> AcceptContinuation
a function to be called if authorization is successful
Definition: dispatcher.hpp:45
nonstd::optional_lite::std11::move
T & move(T &t)
Definition: optional.hpp:421
ndn::tlv::Interest
@ Interest
Definition: tlv.hpp:65
ndn::mgmt::ValidateParameters
std::function< bool(const ControlParameters &params)> ValidateParameters
a function to validate input ControlParameters
Definition: dispatcher.hpp:90
ndn::Name::size
size_t size() const
Returns the number of components.
Definition: name.hpp:153
ndn::mgmt::RejectReply
RejectReply
indicate how to reply in case authorization is rejected
Definition: dispatcher.hpp:49
ndn::security::SigningInfo
Signing parameters passed to KeyChain.
Definition: signing-info.hpp:42
ndn::nfd::ControlResponse
mgmt::ControlResponse ControlResponse
Definition: control-response.hpp:30
ndn::mgmt::StatusDatasetHandler
std::function< void(const Name &prefix, const Interest &interest, StatusDatasetContext &context)> StatusDatasetHandler
a function to handle a StatusDataset request
Definition: dispatcher.hpp:118
ndn::lp::CachePolicy::setPolicy
CachePolicy & setPolicy(CachePolicyType policy)
set policy type code
Definition: cache-policy.cpp:128
ndn::mgmt::PostNotification
std::function< void(const Block &notification)> PostNotification
a function to post a notification
Definition: dispatcher.hpp:124
ndn::Face
Provide a communication channel with local or remote NDN forwarder.
Definition: face.hpp:90
ndn::Face::registerPrefix
RegisteredPrefixHandle registerPrefix(const Name &prefix, const RegisterPrefixSuccessCallback &onSuccess, const RegisterPrefixFailureCallback &onFailure, const security::SigningInfo &signingInfo=security::SigningInfo(), uint64_t flags=nfd::ROUTE_FLAG_CHILD_INHERIT)
Register prefix with the connected NDN forwarder.
Definition: face.cpp:219
ndn::mgmt::ControlParameters
base class for a struct that contains ControlCommand parameters
Definition: control-parameters.hpp:33
ndn::Face::put
void put(Data data)
Publish data packet.
Definition: face.cpp:161
ndn::lp::CachePolicy
represents a CachePolicy header field
Definition: cache-policy.hpp:48
ndn::mgmt::Dispatcher::addStatusDataset
void addStatusDataset(const PartialName &relPrefix, Authorization authorize, StatusDatasetHandler handle)
register a StatusDataset or a prefix under which StatusDatasets can be requested
Definition: dispatcher.cpp:223
ndn::mgmt::DEFAULT_FRESHNESS_PERIOD
const time::milliseconds DEFAULT_FRESHNESS_PERIOD
Definition: dispatcher.cpp:31
ndn::Name
Represents an absolute name.
Definition: name.hpp:44
ndn::Block::get
const Block & get(uint32_t type) const
Return the first sub-element of the specified TLV-TYPE.
Definition: block.cpp:414
ns3::ndn::Name
Name
Definition: ndn-common.cpp:25
dispatcher.hpp
ndn::security::v2::KeyChain
The interface of signing key management.
Definition: key-chain.hpp:47
ndn::mgmt::Dispatcher::~Dispatcher
virtual ~Dispatcher()
ndn::tlv::ContentType_Nack
@ ContentType_Nack
application-level nack
Definition: tlv.hpp:160
NDN_THROW
#define NDN_THROW(e)
Definition: exception.hpp:61
ndn::mgmt::makeAcceptAllAuthorization
Authorization makeAcceptAllAuthorization()
return an Authorization that accepts all Interests, with empty string as requester
Definition: dispatcher.cpp:34
ndn::mgmt::Authorization
std::function< void(const Name &prefix, const Interest &interest, const ControlParameters *params, const AcceptContinuation &accept, const RejectContinuation &reject)> Authorization
a function that performs authorization
Definition: dispatcher.hpp:77
ndn::mgmt::Dispatcher::addTopPrefix
void addTopPrefix(const Name &prefix, bool wantRegister=true, const security::SigningInfo &signingInfo=security::SigningInfo())
add a top-level prefix
Definition: dispatcher.cpp:58
ndn::Interest
Represents an Interest packet.
Definition: interest.hpp:44
logger.hpp
NDN_LOG_WARN
#define NDN_LOG_WARN(expression)
Definition: logger.hpp:101
ndn::tlv::Data
@ Data
Definition: tlv.hpp:66
ndn::mgmt::ControlCommandHandler
std::function< void(const Name &prefix, const Interest &interest, const ControlParameters &params, const CommandContinuation &done)> ControlCommandHandler
a function to handle an authorized ControlCommand
Definition: dispatcher.hpp:106
ndn::mgmt::RejectReply::STATUS403
@ STATUS403
reply with a ControlResponse where StatusCode is 403
ndn::name::Component
Represents a name component.
Definition: name-component.hpp:94
ndn::Block
Represents a TLV element of NDN packet format.
Definition: block.hpp:43
ndn::mgmt::Dispatcher::Dispatcher
Dispatcher(Face &face, KeyChain &keyChain, const security::SigningInfo &signingInfo=security::SigningInfo(), size_t imsCapacity=256)
constructor
Definition: dispatcher.cpp:45
ndn::mgmt::Dispatcher
represents a dispatcher on server side of NFD Management protocol
Definition: dispatcher.hpp:131
ndn::mgmt::Dispatcher::addNotificationStream
PostNotification addNotificationStream(const PartialName &relPrefix)
register a NotificationStream
Definition: dispatcher.cpp:300
ndn::mgmt
Definition: control-parameters.hpp:28
ndn::Interest::getName
const Name & getName() const noexcept
Definition: interest.hpp:121
tags.hpp
ndn::mgmt::RejectContinuation
std::function< void(RejectReply reply)> RejectContinuation
a function to be called if authorization is rejected
Definition: dispatcher.hpp:60
ndn::tlv::MetaInfo
@ MetaInfo
Definition: tlv.hpp:78
ndn::security::v2::KeyChain::sign
void sign(Data &data, const SigningInfo &params=getDefaultSigningInfo())
Sign data according to the supplied signing information.
Definition: key-chain.cpp:450
ndn::mgmt::Dispatcher::removeTopPrefix
void removeTopPrefix(const Name &prefix)
remove a top-level prefix
Definition: dispatcher.cpp:88
ndn
Copyright (c) 2011-2015 Regents of the University of California.
Definition: ndn-strategy-choice-helper.hpp:34
NDN_LOG_ERROR
#define NDN_LOG_ERROR(expression)
Definition: logger.hpp:102
ndn::Face::setInterestFilter
RegisteredPrefixHandle setInterestFilter(const InterestFilter &filter, const InterestCallback &onInterest, const RegisterPrefixFailureCallback &onFailure, const security::SigningInfo &signingInfo=security::SigningInfo(), uint64_t flags=nfd::ROUTE_FLAG_CHILD_INHERIT)
Set InterestFilter to dispatch incoming matching interest to onInterest callback and register the fil...
Definition: face.cpp:177