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-2018 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 
22 #include "dispatcher.hpp"
23 #include "../lp/tags.hpp"
24 #include "../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 
56 {
57  std::vector<Name> topPrefixNames;
58  std::transform(m_topLevelPrefixes.begin(), m_topLevelPrefixes.end(),
59  std::back_inserter(topPrefixNames),
60  [] (const std::unordered_map<Name, TopPrefixEntry>::value_type& entry) {
61  return entry.second.topPrefix;
62  });
63 
64  for (const auto& name : topPrefixNames) {
66  }
67 }
68 
69 void
70 Dispatcher::addTopPrefix(const Name& prefix, bool wantRegister,
71  const security::SigningInfo& signingInfo)
72 {
73  bool hasOverlap = std::any_of(m_topLevelPrefixes.begin(), m_topLevelPrefixes.end(),
74  [&] (const std::unordered_map<Name, TopPrefixEntry>::value_type& x) {
75  return x.first.isPrefixOf(prefix) || prefix.isPrefixOf(x.first);
76  });
77  if (hasOverlap) {
78  BOOST_THROW_EXCEPTION(std::out_of_range("top-level prefix overlaps"));
79  }
80 
81  TopPrefixEntry& topPrefixEntry = m_topLevelPrefixes[prefix];
82  topPrefixEntry.topPrefix = prefix;
83 
84  if (wantRegister) {
85  topPrefixEntry.registeredPrefixId = m_face.registerPrefix(prefix,
86  nullptr,
87  [] (const Name&, const std::string& reason) {
88  BOOST_THROW_EXCEPTION(std::runtime_error("prefix registration failed: " + reason));
89  },
90  signingInfo);
91  }
92 
93  for (const auto& entry : m_handlers) {
94  Name fullPrefix = Name(prefix).append(entry.first);
95  const InterestFilterId* filter = m_face.setInterestFilter(fullPrefix, bind(entry.second, prefix, _2));
96  topPrefixEntry.interestFilters.push_back(filter);
97  }
98 }
99 
100 void
102 {
103  auto it = m_topLevelPrefixes.find(prefix);
104  if (it == m_topLevelPrefixes.end()) {
105  return;
106  }
107 
108  const TopPrefixEntry& topPrefixEntry = it->second;
109  if (topPrefixEntry.registeredPrefixId) {
110  m_face.unregisterPrefix(*topPrefixEntry.registeredPrefixId, nullptr, nullptr);
111  }
112  for (const auto& filter : topPrefixEntry.interestFilters) {
113  m_face.unsetInterestFilter(filter);
114  }
115 
116  m_topLevelPrefixes.erase(it);
117 }
118 
119 bool
120 Dispatcher::isOverlappedWithOthers(const PartialName& relPrefix) const
121 {
122  bool hasOverlapWithHandlers =
123  std::any_of(m_handlers.begin(), m_handlers.end(),
124  [&] (const std::unordered_map<PartialName, InterestHandler>::value_type& entry) {
125  return entry.first.isPrefixOf(relPrefix) || relPrefix.isPrefixOf(entry.first);
126  });
127  bool hasOverlapWithStreams =
128  std::any_of(m_streams.begin(), m_streams.end(),
129  [&] (const std::unordered_map<PartialName, uint64_t>::value_type& entry) {
130  return entry.first.isPrefixOf(relPrefix) || relPrefix.isPrefixOf(entry.first);
131  });
132 
133  return hasOverlapWithHandlers || hasOverlapWithStreams;
134 }
135 
136 void
137 Dispatcher::afterAuthorizationRejected(RejectReply act, const Interest& interest)
138 {
139  if (act == RejectReply::STATUS403) {
140  sendControlResponse(ControlResponse(403, "authorization rejected"), interest);
141  }
142 }
143 
144 void
145 Dispatcher::queryStorage(const Name& prefix, const Interest& interest,
146  const InterestHandler& missContinuation)
147 {
148  auto data = m_storage.find(interest);
149  if (data == nullptr) {
150  // invoke missContinuation to process this Interest if the query fails.
151  if (missContinuation)
152  missContinuation(prefix, interest);
153  }
154  else {
155  // send the fetched data through face if query succeeds.
156  sendOnFace(*data);
157  }
158 }
159 
160 void
161 Dispatcher::sendData(const Name& dataName, const Block& content, const MetaInfo& metaInfo,
162  SendDestination option, time::milliseconds imsFresh)
163 {
164  auto data = make_shared<Data>(dataName);
165  data->setContent(content).setMetaInfo(metaInfo).setFreshnessPeriod(DEFAULT_FRESHNESS_PERIOD);
166 
167  m_keyChain.sign(*data, m_signingInfo);
168 
169  if (option == SendDestination::IMS || option == SendDestination::FACE_AND_IMS) {
170  lp::CachePolicy policy;
172  data->setTag(make_shared<lp::CachePolicyTag>(policy));
173  m_storage.insert(*data, imsFresh);
174  }
175 
176  if (option == SendDestination::FACE || option == SendDestination::FACE_AND_IMS) {
177  sendOnFace(*data);
178  }
179 }
180 
181 void
182 Dispatcher::sendOnFace(const Data& data)
183 {
184  try {
185  m_face.put(data);
186  }
187  catch (const Face::Error& e) {
188  NDN_LOG_ERROR("sendOnFace: " << e.what());
189  }
190 }
191 
192 void
193 Dispatcher::processControlCommandInterest(const Name& prefix,
194  const Name& relPrefix,
195  const Interest& interest,
196  const ControlParametersParser& parser,
197  const Authorization& authorization,
198  const AuthorizationAcceptedCallback& accepted,
199  const AuthorizationRejectedCallback& rejected)
200 {
201  // /<prefix>/<relPrefix>/<parameters>
202  size_t parametersLoc = prefix.size() + relPrefix.size();
203  const name::Component& pc = interest.getName().get(parametersLoc);
204 
205  shared_ptr<ControlParameters> parameters;
206  try {
207  parameters = parser(pc);
208  }
209  catch (const tlv::Error&) {
210  return;
211  }
212 
213  AcceptContinuation accept = bind(accepted, _1, prefix, interest, parameters);
214  RejectContinuation reject = bind(rejected, _1, interest);
215  authorization(prefix, interest, parameters.get(), accept, reject);
216 }
217 
218 void
219 Dispatcher::processAuthorizedControlCommandInterest(const std::string& requester,
220  const Name& prefix,
221  const Interest& interest,
222  const shared_ptr<ControlParameters>& parameters,
223  const ValidateParameters& validateParams,
224  const ControlCommandHandler& handler)
225 {
226  if (validateParams(*parameters)) {
227  handler(prefix, interest, *parameters,
228  bind(&Dispatcher::sendControlResponse, this, _1, interest, false));
229  }
230  else {
231  sendControlResponse(ControlResponse(400, "failed in validating parameters"), interest);
232  }
233 }
234 
235 void
236 Dispatcher::sendControlResponse(const ControlResponse& resp, const Interest& interest, bool isNack)
237 {
238  MetaInfo metaInfo;
239  if (isNack) {
240  metaInfo.setType(tlv::ContentType_Nack);
241  }
242 
243  // control response is always sent out through the face
244  sendData(interest.getName(), resp.wireEncode(), metaInfo,
245  SendDestination::FACE, DEFAULT_FRESHNESS_PERIOD);
246 }
247 
248 void
250  const Authorization& authorization,
251  const StatusDatasetHandler& handler)
252 {
253  if (!m_topLevelPrefixes.empty()) {
254  BOOST_THROW_EXCEPTION(std::domain_error("one or more top-level prefix has been added"));
255  }
256 
257  if (isOverlappedWithOthers(relPrefix)) {
258  BOOST_THROW_EXCEPTION(std::out_of_range("status dataset name overlaps"));
259  }
260 
261  AuthorizationAcceptedCallback accepted =
262  bind(&Dispatcher::processAuthorizedStatusDatasetInterest, this, _1, _2, _3, handler);
263  AuthorizationRejectedCallback rejected =
264  bind(&Dispatcher::afterAuthorizationRejected, this, _1, _2);
265 
266  // follow the general path if storage is a miss
267  InterestHandler missContinuation = bind(&Dispatcher::processStatusDatasetInterest, this,
268  _1, _2, authorization, accepted, rejected);
269  m_handlers[relPrefix] = bind(&Dispatcher::queryStorage, this, _1, _2, missContinuation);
270 }
271 
272 void
273 Dispatcher::processStatusDatasetInterest(const Name& prefix,
274  const Interest& interest,
275  const Authorization& authorization,
276  const AuthorizationAcceptedCallback& accepted,
277  const AuthorizationRejectedCallback& rejected)
278 {
279  const Name& interestName = interest.getName();
280  bool endsWithVersionOrSegment = interestName.size() >= 1 &&
281  (interestName[-1].isVersion() || interestName[-1].isSegment());
282  if (endsWithVersionOrSegment) {
283  return;
284  }
285 
286  AcceptContinuation accept = bind(accepted, _1, prefix, interest, nullptr);
287  RejectContinuation reject = bind(rejected, _1, interest);
288  authorization(prefix, interest, nullptr, accept, reject);
289 }
290 
291 void
292 Dispatcher::processAuthorizedStatusDatasetInterest(const std::string& requester,
293  const Name& prefix,
294  const Interest& interest,
295  const StatusDatasetHandler& handler)
296 {
297  StatusDatasetContext context(interest,
298  bind(&Dispatcher::sendStatusDatasetSegment, this, _1, _2, _3, _4),
299  bind(&Dispatcher::sendControlResponse, this, _1, interest, true));
300  handler(prefix, interest, context);
301 }
302 
303 void
304 Dispatcher::sendStatusDatasetSegment(const Name& dataName, const Block& content,
305  time::milliseconds imsFresh, bool isFinalBlock)
306 {
307  // the first segment will be sent to both places (the face and the in-memory storage)
308  // other segments will be inserted to the in-memory storage only
309  auto destination = SendDestination::IMS;
310  if (dataName[-1].toSegment() == 0) {
311  destination = SendDestination::FACE_AND_IMS;
312  }
313 
314  MetaInfo metaInfo;
315  if (isFinalBlock) {
316  metaInfo.setFinalBlock(dataName[-1]);
317  }
318 
319  sendData(dataName, content, metaInfo, destination, imsFresh);
320 }
321 
324 {
325  if (!m_topLevelPrefixes.empty()) {
326  BOOST_THROW_EXCEPTION(std::domain_error("one or more top-level prefix has been added"));
327  }
328 
329  if (isOverlappedWithOthers(relPrefix)) {
330  BOOST_THROW_EXCEPTION(std::out_of_range("notification stream name overlaps"));
331  }
332 
333  // register a handler for the subscriber of this notification stream
334  // keep silent if Interest does not match a stored notification
335  m_handlers[relPrefix] = bind(&Dispatcher::queryStorage, this, _1, _2, nullptr);
336  m_streams[relPrefix] = 0;
337 
338  return bind(&Dispatcher::postNotification, this, _1, relPrefix);
339 }
340 
341 void
342 Dispatcher::postNotification(const Block& notification, const PartialName& relPrefix)
343 {
344  if (m_topLevelPrefixes.empty() || m_topLevelPrefixes.size() > 1) {
345  NDN_LOG_WARN("postNotification: no top-level prefix or too many top-level prefixes");
346  return;
347  }
348 
349  Name streamName(m_topLevelPrefixes.begin()->second.topPrefix);
350  streamName.append(relPrefix);
351  streamName.appendSequenceNumber(m_streams[streamName]++);
352 
353  // notification is sent out via the face after inserting into the in-memory storage,
354  // because a request may be pending in the PIT
355  sendData(streamName, notification, {}, SendDestination::FACE_AND_IMS, DEFAULT_FRESHNESS_PERIOD);
356 }
357 
358 } // namespace mgmt
359 } // namespace ndn
represents a CachePolicy header field
Copyright (c) 2011-2015 Regents of the University of California.
The interface of signing key management.
Definition: key-chain.hpp:46
indicates a producer generated NACK
Definition: tlv.hpp:152
std::function< void(const Block &notification)> PostNotification
a function to post a notification
Definition: dispatcher.hpp:124
represents a dispatcher on server side of NFD Management protocol
Definition: dispatcher.hpp:130
RejectReply
indicate how to reply in case authorization is rejected
Definition: dispatcher.hpp:49
const RegisteredPrefixId * setInterestFilter(const InterestFilter &interestFilter, 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:186
reply with a ControlResponse where StatusCode is 403
bool isPrefixOf(const Name &other) const
Check if this name is a prefix of another name.
Definition: name.cpp:255
CachePolicy & setPolicy(CachePolicyType policy)
set policy type code
Represents a TLV element of NDN packet format.
Definition: block.hpp:42
Represents an Interest packet.
Definition: interest.hpp:42
std::function< void(const std::string &requester)> AcceptContinuation
a function to be called if authorization is successful
Definition: dispatcher.hpp:45
Dispatcher(Face &face, KeyChain &keyChain, const security::SigningInfo &signingInfo=security::SigningInfo(), size_t imsCapacity=256)
constructor
Definition: dispatcher.cpp:45
Authorization makeAcceptAllAuthorization()
return an Authorization that accepts all Interests, with empty string as requester ...
Definition: dispatcher.cpp:34
Name & append(const Component &component)
Append a component.
Definition: name.hpp:256
Signing parameters passed to KeyChain.
void unregisterPrefix(const RegisteredPrefixId *registeredPrefixId, const UnregisterPrefixSuccessCallback &onSuccess, const UnregisterPrefixFailureCallback &onFailure)
Unregister prefix from RIB.
Definition: face.cpp:255
#define NDN_LOG_INIT(name)
declare a log module
Definition: logger.hpp:32
const Block & get(uint32_t type) const
Get the first sub element of specified TLV-TYPE.
Definition: block.cpp:425
mgmt::ControlResponse ControlResponse
std::function< void(RejectReply reply)> RejectContinuation
a function to be called if authorization is rejected
Definition: dispatcher.hpp:60
Provide a communication channel with local or remote NDN forwarder.
Definition: face.hpp:90
void addTopPrefix(const Name &prefix, bool wantRegister=true, const security::SigningInfo &signingInfo=security::SigningInfo())
add a top-level prefix
Definition: dispatcher.cpp:70
Name & appendSequenceNumber(uint64_t seqNo)
Append a sequence number component.
Definition: name.hpp:426
Represents an absolute name.
Definition: name.hpp:42
const time::milliseconds DEFAULT_FRESHNESS_PERIOD
Definition: dispatcher.cpp:31
void unsetInterestFilter(const RegisteredPrefixId *registeredPrefixId)
Remove the registered prefix entry with the registeredPrefixId.
Definition: face.cpp:239
base class for a struct that contains ControlCommand parameters
size_t size() const
Get number of components.
Definition: name.hpp:154
void sign(Data &data, const SigningInfo &params=getDefaultSigningInfo())
Sign data according to the supplied signing information.
Definition: key-chain.cpp:423
Represents a name component.
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
void addStatusDataset(const PartialName &relPrefix, const Authorization &authorization, const StatusDatasetHandler &handler)
register a StatusDataset or a prefix under which StatusDatasets can be requested
Definition: dispatcher.cpp:249
std::function< bool(const ControlParameters &params)> ValidateParameters
a function to validate input ControlParameters
Definition: dispatcher.hpp:90
void put(Data data)
Publish data packet.
Definition: face.cpp:170
void removeTopPrefix(const Name &prefix)
remove a top-level prefix
Definition: dispatcher.cpp:101
#define NDN_LOG_ERROR(expression)
Definition: logger.hpp:38
#define NDN_LOG_WARN(expression)
Definition: logger.hpp:37
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
const RegisteredPrefixId * 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:226
PostNotification addNotificationStream(const PartialName &relPrefix)
register a NotificationStream
Definition: dispatcher.cpp:323
const Name & getName() const
Definition: interest.hpp:137
std::function< void(const Name &prefix, const Interest &interest, StatusDatasetContext &context)> StatusDatasetHandler
a function to handle a StatusDataset request
Definition: dispatcher.hpp:118