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