NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.3: NDN, CCN, CCNx, content centric networks
API Documentation
face-impl.hpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2017 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 #ifndef NDN_DETAIL_FACE_IMPL_HPP
23 #define NDN_DETAIL_FACE_IMPL_HPP
24 
25 #include "../face.hpp"
27 #include "lp-field-tag.hpp"
28 #include "pending-interest.hpp"
29 #include "registered-prefix.hpp"
30 #include "../lp/packet.hpp"
31 #include "../lp/tags.hpp"
32 #include "../mgmt/nfd/command-options.hpp"
33 #include "../mgmt/nfd/controller.hpp"
34 #include "../transport/tcp-transport.hpp"
35 #include "../transport/unix-transport.hpp"
36 #include "../util/config-file.hpp"
37 #include "../util/logger.hpp"
38 #include "../util/scheduler.hpp"
39 #include "../util/signal.hpp"
40 
42 // INFO level: prefix registration, etc.
43 //
44 // DEBUG level: packet logging.
45 // Each log entry starts with a direction symbol ('<' denotes an outgoing packet, '>' denotes an
46 // incoming packet) and a packet type symbol ('I' denotes an Interest, 'D' denotes a Data, 'N'
47 // denotes a Nack). Interest is printed as its string representation, Data is printed as name only,
48 // Nack is printed as the Interest followed by the Nack reason and delimited by a '~' symbol. A
49 // log line about an incoming packet may be followed by zero or more lines about Interest matching
50 // InterestFilter, Data satisfying Interest, or Nack rejecting Interest, which are also written at
51 // DEBUG level.
52 //
53 // TRACE level: more detailed unstructured messages.
54 
55 namespace ndn {
56 
59 class Face::Impl : noncopyable
60 {
61 public:
62  using PendingInterestTable = ContainerWithOnEmptySignal<shared_ptr<PendingInterest>>;
63  using InterestFilterTable = std::list<shared_ptr<InterestFilterRecord>>;
64  using RegisteredPrefixTable = ContainerWithOnEmptySignal<shared_ptr<RegisteredPrefix>>;
65 
66  explicit
68  : m_face(face)
69  , m_scheduler(m_face.getIoService())
70  , m_processEventsTimeoutEvent(m_scheduler)
71  {
72  auto postOnEmptyPitOrNoRegisteredPrefixes = [this] {
73  m_scheduler.scheduleEvent(time::seconds(0), bind(&Impl::onEmptyPitOrNoRegisteredPrefixes, this));
74  // without this extra "post", transport can get paused (-async_read) and then resumed
75  // (+async_read) from within onInterest/onData callback. After onInterest/onData
76  // finishes, there is another +async_read with the same memory block. A few of such
77  // async_read duplications can cause various effects and result in segfault.
78  };
79 
80  m_pendingInterestTable.onEmpty.connect(postOnEmptyPitOrNoRegisteredPrefixes);
81  m_registeredPrefixTable.onEmpty.connect(postOnEmptyPitOrNoRegisteredPrefixes);
82  }
83 
84 public: // consumer
85  void
86  asyncExpressInterest(shared_ptr<const Interest> interest,
87  const DataCallback& afterSatisfied,
88  const NackCallback& afterNacked,
89  const TimeoutCallback& afterTimeout)
90  {
91  this->ensureConnected(true);
92 
93  const Interest& interest2 = *interest;
94  auto i = m_pendingInterestTable.insert(make_shared<PendingInterest>(
95  std::move(interest), afterSatisfied, afterNacked, afterTimeout, ref(m_scheduler))).first;
96  PendingInterest& entry = **i;
97  entry.setDeleter([this, i] { m_pendingInterestTable.erase(i); });
98 
99  lp::Packet lpPacket;
100  addFieldFromTag<lp::NextHopFaceIdField, lp::NextHopFaceIdTag>(lpPacket, interest2);
101  addFieldFromTag<lp::CongestionMarkField, lp::CongestionMarkTag>(lpPacket, interest2);
102 
103  entry.recordForwarding();
104  m_face.m_transport->send(finishEncoding(std::move(lpPacket), interest2.wireEncode(),
105  'I', interest2.getName()));
106  }
107 
108  void
109  asyncRemovePendingInterest(const PendingInterestId* pendingInterestId)
110  {
111  m_pendingInterestTable.remove_if(MatchPendingInterestId(pendingInterestId));
112  }
113 
114  void
116  {
117  m_pendingInterestTable.clear();
118  }
119 
122  bool
124  {
125  bool hasAppMatch = false, hasForwarderMatch = false;
126  for (auto i = m_pendingInterestTable.begin(); i != m_pendingInterestTable.end(); ) {
127  shared_ptr<PendingInterest> entry = *i;
128  if (!entry->getInterest()->matchesData(data)) {
129  ++i;
130  continue;
131  }
132 
133  NDN_LOG_DEBUG(" satisfying " << *entry->getInterest() << " from " << entry->getOrigin());
134  i = m_pendingInterestTable.erase(i);
135 
136  if (entry->getOrigin() == PendingInterestOrigin::APP) {
137  hasAppMatch = true;
138  entry->invokeDataCallback(data);
139  }
140  else {
141  hasForwarderMatch = true;
142  }
143  }
144  // if Data matches no pending Interest record, it is sent to the forwarder as unsolicited Data
145  return hasForwarderMatch || !hasAppMatch;
146  }
147 
150  optional<lp::Nack>
152  {
153  optional<lp::Nack> outNack;
154  for (auto i = m_pendingInterestTable.begin(); i != m_pendingInterestTable.end(); ) {
155  shared_ptr<PendingInterest> entry = *i;
156  if (!nack.getInterest().matchesInterest(*entry->getInterest())) {
157  ++i;
158  continue;
159  }
160 
161  NDN_LOG_DEBUG(" nacking " << *entry->getInterest() << " from " << entry->getOrigin());
162 
163  optional<lp::Nack> outNack1 = entry->recordNack(nack);
164  if (!outNack1) {
165  ++i;
166  continue;
167  }
168 
169  if (entry->getOrigin() == PendingInterestOrigin::APP) {
170  entry->invokeNackCallback(*outNack1);
171  }
172  else {
173  outNack = outNack1;
174  }
175  i = m_pendingInterestTable.erase(i);
176  }
177  // send "least severe" Nack from any PendingInterest record originated from forwarder, because
178  // it is unimportant to consider Nack reason for the unlikely case when forwarder sends multiple
179  // Interests to an app in a short while
180  return outNack;
181  }
182 
183 public: // producer
184  void
185  asyncSetInterestFilter(shared_ptr<InterestFilterRecord> interestFilterRecord)
186  {
187  NDN_LOG_INFO("setting InterestFilter: " << interestFilterRecord->getFilter());
188  m_interestFilterTable.push_back(std::move(interestFilterRecord));
189  }
190 
191  void
192  asyncUnsetInterestFilter(const InterestFilterId* interestFilterId)
193  {
194  InterestFilterTable::iterator i = std::find_if(m_interestFilterTable.begin(),
195  m_interestFilterTable.end(),
196  MatchInterestFilterId(interestFilterId));
197  if (i != m_interestFilterTable.end()) {
198  NDN_LOG_INFO("unsetting InterestFilter: " << (*i)->getFilter());
199  m_interestFilterTable.erase(i);
200  }
201  }
202 
203  void
204  processIncomingInterest(shared_ptr<const Interest> interest)
205  {
206  const Interest& interest2 = *interest;
207  auto i = m_pendingInterestTable.insert(make_shared<PendingInterest>(
208  std::move(interest), ref(m_scheduler))).first;
209  // InterestCallback may put Data right away and delete the entry from PendingInterestTable.
210  // shared_ptr is retained to ensure PendingInterest instance is valid throughout the loop.
211  shared_ptr<PendingInterest> entry = *i;
212  entry->setDeleter([this, i] { m_pendingInterestTable.erase(i); });
213 
214  for (const auto& filter : m_interestFilterTable) {
215  if (filter->doesMatch(interest2.getName())) {
216  NDN_LOG_DEBUG(" matches " << filter->getFilter());
217  entry->recordForwarding();
218  filter->invokeInterestCallback(interest2);
219  }
220  }
221  }
222 
223  void
224  asyncPutData(const Data& data)
225  {
226  bool shouldSendToForwarder = satisfyPendingInterests(data);
227  if (!shouldSendToForwarder) {
228  return;
229  }
230 
231  this->ensureConnected(true);
232 
233  lp::Packet lpPacket;
234  addFieldFromTag<lp::CachePolicyField, lp::CachePolicyTag>(lpPacket, data);
235  addFieldFromTag<lp::CongestionMarkField, lp::CongestionMarkTag>(lpPacket, data);
236 
237  m_face.m_transport->send(finishEncoding(std::move(lpPacket), data.wireEncode(),
238  'D', data.getName()));
239  }
240 
241  void
242  asyncPutNack(const lp::Nack& nack)
243  {
244  optional<lp::Nack> outNack = nackPendingInterests(nack);
245  if (!outNack) {
246  return;
247  }
248 
249  this->ensureConnected(true);
250 
251  lp::Packet lpPacket;
252  lpPacket.add<lp::NackField>(outNack->getHeader());
253  addFieldFromTag<lp::CongestionMarkField, lp::CongestionMarkTag>(lpPacket, *outNack);
254 
255  const Interest& interest = outNack->getInterest();
256  m_face.m_transport->send(finishEncoding(std::move(lpPacket), interest.wireEncode(),
257  'N', interest.getName()));
258  }
259 
260 public: // prefix registration
261  const RegisteredPrefixId*
262  registerPrefix(const Name& prefix,
263  shared_ptr<InterestFilterRecord> filter,
264  const RegisterPrefixSuccessCallback& onSuccess,
265  const RegisterPrefixFailureCallback& onFailure,
266  uint64_t flags,
267  const nfd::CommandOptions& options)
268  {
269  NDN_LOG_INFO("registering prefix: " << prefix);
270  auto record = make_shared<RegisteredPrefix>(prefix, filter, options);
271 
272  nfd::ControlParameters params;
273  params.setName(prefix);
274  params.setFlags(flags);
275  m_face.m_nfdController->start<nfd::RibRegisterCommand>(
276  params,
277  [=] (const nfd::ControlParameters&) { this->afterPrefixRegistered(record, onSuccess); },
278  [=] (const nfd::ControlResponse& resp) {
279  NDN_LOG_INFO("register prefix failed: " << record->getPrefix());
280  onFailure(record->getPrefix(), resp.getText());
281  },
282  options);
283 
284  return reinterpret_cast<const RegisteredPrefixId*>(record.get());
285  }
286 
287  void
288  afterPrefixRegistered(shared_ptr<RegisteredPrefix> registeredPrefix,
289  const RegisterPrefixSuccessCallback& onSuccess)
290  {
291  NDN_LOG_INFO("registered prefix: " << registeredPrefix->getPrefix());
292  m_registeredPrefixTable.insert(registeredPrefix);
293 
294  if (registeredPrefix->getFilter() != nullptr) {
295  // it was a combined operation
296  m_interestFilterTable.push_back(registeredPrefix->getFilter());
297  }
298 
299  if (onSuccess != nullptr) {
300  onSuccess(registeredPrefix->getPrefix());
301  }
302  }
303 
304  void
305  asyncUnregisterPrefix(const RegisteredPrefixId* registeredPrefixId,
306  const UnregisterPrefixSuccessCallback& onSuccess,
307  const UnregisterPrefixFailureCallback& onFailure)
308  {
309  auto i = std::find_if(m_registeredPrefixTable.begin(),
310  m_registeredPrefixTable.end(),
311  MatchRegisteredPrefixId(registeredPrefixId));
312  if (i != m_registeredPrefixTable.end()) {
313  RegisteredPrefix& record = **i;
314  const shared_ptr<InterestFilterRecord>& filter = record.getFilter();
315 
316  if (filter != nullptr) {
317  // it was a combined operation
318  m_interestFilterTable.remove(filter);
319  }
320 
321  NDN_LOG_INFO("unregistering prefix: " << record.getPrefix());
322 
323  nfd::ControlParameters params;
324  params.setName(record.getPrefix());
325  m_face.m_nfdController->start<nfd::RibUnregisterCommand>(
326  params,
327  [=] (const nfd::ControlParameters&) { this->finalizeUnregisterPrefix(i, onSuccess); },
328  [=] (const nfd::ControlResponse& resp) {
329  NDN_LOG_INFO("unregister prefix failed: " << params.getName());
330  onFailure(resp.getText());
331  },
332  record.getCommandOptions());
333  }
334  else {
335  if (onFailure != nullptr) {
336  onFailure("Unrecognized PrefixId");
337  }
338  }
339 
340  // there cannot be two registered prefixes with the same id
341  }
342 
343  void
345  const UnregisterPrefixSuccessCallback& onSuccess)
346  {
347  NDN_LOG_INFO("unregistered prefix: " << (*item)->getPrefix());
348  m_registeredPrefixTable.erase(item);
349 
350  if (onSuccess != nullptr) {
351  onSuccess();
352  }
353  }
354 
355 public: // IO routine
356  void
357  ensureConnected(bool wantResume)
358  {
359  if (!m_face.m_transport->isConnected())
360  m_face.m_transport->connect(m_face.getIoService(),
361  [=] (const Block& wire) { m_face.onReceiveElement(wire); });
362 
363  if (wantResume && !m_face.m_transport->isReceiving()) {
364  m_face.m_transport->resume();
365  }
366  }
367 
368  void
370  {
371  if (m_pendingInterestTable.empty() && m_registeredPrefixTable.empty()) {
372  m_face.m_transport->pause();
373  }
374  }
375 
376 private:
385  Block
386  finishEncoding(lp::Packet&& lpPacket, Block wire, char pktType, const Name& name)
387  {
388  if (!lpPacket.empty()) {
389  lpPacket.add<lp::FragmentField>(std::make_pair(wire.begin(), wire.end()));
390  wire = lpPacket.wireEncode();
391  }
392 
393  if (wire.size() > MAX_NDN_PACKET_SIZE) {
394  BOOST_THROW_EXCEPTION(Face::OversizedPacketError(pktType, name, wire.size()));
395  }
396 
397  return wire;
398  }
399 
400 private:
401  Face& m_face;
402  util::Scheduler m_scheduler;
403  util::scheduler::ScopedEventId m_processEventsTimeoutEvent;
404 
405  PendingInterestTable m_pendingInterestTable;
406  InterestFilterTable m_interestFilterTable;
407  RegisteredPrefixTable m_registeredPrefixTable;
408 
409  friend class Face;
410 };
411 
412 } // namespace ndn
413 
414 #endif // NDN_DETAIL_FACE_IMPL_HPP
#define NDN_LOG_INFO(expression)
Definition: logger.hpp:36
Copyright (c) 2011-2015 Regents of the University of California.
ContainerWithOnEmptySignal< shared_ptr< RegisteredPrefix >> RegisteredPrefixTable
Definition: face-impl.hpp:64
void ensureConnected(bool wantResume)
Definition: face-impl.hpp:357
function< void(const std::string &)> UnregisterPrefixFailureCallback
Callback invoked when unregisterPrefix or unsetInterestFilter command fails.
Definition: face.hpp:90
void asyncExpressInterest(shared_ptr< const Interest > interest, const DataCallback &afterSatisfied, const NackCallback &afterNacked, const TimeoutCallback &afterTimeout)
Definition: face-impl.hpp:86
represents parameters in a ControlCommand request or response
implementation detail of Face
Definition: face-impl.hpp:59
std::list< shared_ptr< InterestFilterRecord >> InterestFilterTable
Definition: face-impl.hpp:63
Packet & add(const typename FIELD::ValueType &value)
add a FIELD with value
Definition: packet.hpp:153
Impl(Face &face)
Definition: face-impl.hpp:67
const Interest & getInterest() const
Definition: nack.hpp:53
ControlParameters & setFlags(uint64_t flags)
void asyncUnsetInterestFilter(const InterestFilterId *interestFilterId)
Definition: face-impl.hpp:192
void asyncSetInterestFilter(shared_ptr< InterestFilterRecord > interestFilterRecord)
Definition: face-impl.hpp:185
void asyncUnregisterPrefix(const RegisteredPrefixId *registeredPrefixId, const UnregisterPrefixSuccessCallback &onSuccess, const UnregisterPrefixFailureCallback &onFailure)
Definition: face-impl.hpp:305
void asyncPutNack(const lp::Nack &nack)
Definition: face-impl.hpp:242
represents a Network Nack
Definition: nack.hpp:40
void asyncPutData(const Data &data)
Definition: face-impl.hpp:224
Table::const_iterator iterator
Definition: cs-internal.hpp:41
#define NDN_LOG_INIT(name)
declare a log module
Definition: logger.hpp:32
ContainerWithOnEmptySignal< shared_ptr< PendingInterest >> PendingInterestTable
Definition: face-impl.hpp:62
#define NDN_LOG_DEBUG(expression)
Definition: logger.hpp:35
mgmt::ControlResponse ControlResponse
friend class Face
Definition: face-impl.hpp:409
void finalizeUnregisterPrefix(RegisteredPrefixTable::iterator item, const UnregisterPrefixSuccessCallback &onSuccess)
Definition: face-impl.hpp:344
Provide a communication channel with local or remote NDN forwarder.
Definition: face.hpp:95
void asyncRemoveAllPendingInterests()
Definition: face-impl.hpp:115
const RegisteredPrefixId * registerPrefix(const Name &prefix, shared_ptr< InterestFilterRecord > filter, const RegisterPrefixSuccessCallback &onSuccess, const RegisterPrefixFailureCallback &onFailure, uint64_t flags, const nfd::CommandOptions &options)
Definition: face-impl.hpp:262
function< void(const Name &, const std::string &)> RegisterPrefixFailureCallback
Callback invoked when registerPrefix or setInterestFilter command fails.
Definition: face.hpp:80
void processIncomingInterest(shared_ptr< const Interest > interest)
Definition: face-impl.hpp:204
function< void(const Name &)> RegisterPrefixSuccessCallback
Callback invoked when registerPrefix or setInterestFilter command succeeds.
Definition: face.hpp:75
bool satisfyPendingInterests(const Data &data)
Definition: face-impl.hpp:123
boost::asio::io_service & getIoService()
Return nullptr (cannot use IoService in simulations), preserved for API compatibility.
Definition: face.hpp:468
bool matchesInterest(const Interest &other) const
Check if Interest matches other interest.
Definition: interest.cpp:291
ControlParameters & setName(const Name &name)
function< void()> UnregisterPrefixSuccessCallback
Callback invoked when unregisterPrefix or unsetInterestFilter command succeeds.
Definition: face.hpp:85
void asyncRemovePendingInterest(const PendingInterestId *pendingInterestId)
Definition: face-impl.hpp:109
Interest was received from this app via Face::expressInterest API.
function< void(const Interest &)> TimeoutCallback
Callback invoked when expressed Interest times out.
Definition: face.hpp:65
function< void(const Interest &, const lp::Nack &)> NackCallback
Callback invoked when Nack is sent in response to expressed Interest.
Definition: face.hpp:60
function< void(const Interest &, const Data &)> DataCallback
Callback invoked when expressed Interest gets satisfied with a Data packet.
Definition: face.hpp:55
void onEmptyPitOrNoRegisteredPrefixes()
Definition: face-impl.hpp:369
const size_t MAX_NDN_PACKET_SIZE
practical limit of network layer packet size
Definition: tlv.hpp:39
optional< lp::Nack > nackPendingInterests(const lp::Nack &nack)
Definition: face-impl.hpp:151
void afterPrefixRegistered(shared_ptr< RegisteredPrefix > registeredPrefix, const RegisterPrefixSuccessCallback &onSuccess)
Definition: face-impl.hpp:288