NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.0: NDN, CCN, CCNx, content centric networks
API Documentation
forwarder.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
26 #include "forwarder.hpp"
27 #include "core/logger.hpp"
28 #include "core/random.hpp"
29 #include "strategy.hpp"
30 #include "face/null-face.hpp"
31 
33 
34 #include <boost/random/uniform_int_distribution.hpp>
35 
36 namespace nfd {
37 
38 NFD_LOG_INIT("Forwarder");
39 
40 using fw::Strategy;
41 
42 const Name Forwarder::LOCALHOST_NAME("ndn:/localhost");
43 
45  : m_faceTable(*this)
46  , m_fib(m_nameTree)
47  , m_pit(m_nameTree)
48  , m_measurements(m_nameTree)
49  , m_strategyChoice(m_nameTree, fw::makeDefaultStrategy(*this))
50  , m_csFace(face::makeNullFace(FaceUri("contentstore://")))
51 {
52  fw::installStrategies(*this);
54 }
55 
57 {
58 }
59 
60 void
62 {
63  // check fields used by forwarding are well-formed
64  try {
65  if (interest.hasLink()) {
66  interest.getLink();
67  }
68  }
69  catch (const tlv::Error&) {
70  NFD_LOG_DEBUG("startProcessInterest face=" << face.getId() <<
71  " interest=" << interest.getName() << " malformed");
72  // It's safe to call interest.getName() because Name has been fully parsed
73  return;
74  }
75 
76  this->onIncomingInterest(face, interest);
77 }
78 
79 void
81 {
82  // check fields used by forwarding are well-formed
83  // (none needed)
84 
85  this->onIncomingData(face, data);
86 }
87 
88 void
90 {
91  // check fields used by forwarding are well-formed
92  try {
93  if (nack.getInterest().hasLink()) {
94  nack.getInterest().getLink();
95  }
96  }
97  catch (const tlv::Error&) {
98  NFD_LOG_DEBUG("startProcessNack face=" << face.getId() <<
99  " nack=" << nack.getInterest().getName() <<
100  "~" << nack.getReason() << " malformed");
101  return;
102  }
103 
104  this->onIncomingNack(face, nack);
105 }
106 
107 void
108 Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
109 {
110  // receive Interest
111  NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() <<
112  " interest=" << interest.getName());
113  interest.setTag(make_shared<lp::IncomingFaceIdTag>(inFace.getId()));
114  ++m_counters.nInInterests;
115 
116  // /localhost scope control
117  bool isViolatingLocalhost = inFace.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
118  LOCALHOST_NAME.isPrefixOf(interest.getName());
119  if (isViolatingLocalhost) {
120  NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() <<
121  " interest=" << interest.getName() << " violates /localhost");
122  // (drop)
123  return;
124  }
125 
126  // detect duplicate Nonce with Dead Nonce List
127  bool hasDuplicateNonceInDnl = m_deadNonceList.has(interest.getName(), interest.getNonce());
128  if (hasDuplicateNonceInDnl) {
129  // goto Interest loop pipeline
130  this->onInterestLoop(inFace, interest);
131  return;
132  }
133 
134  // PIT insert
135  shared_ptr<pit::Entry> pitEntry = m_pit.insert(interest).first;
136 
137  // detect duplicate Nonce in PIT entry
138  bool hasDuplicateNonceInPit = pitEntry->findNonce(interest.getNonce(), inFace) !=
140  if (hasDuplicateNonceInPit) {
141  // goto Interest loop pipeline
142  this->onInterestLoop(inFace, interest);
143  return;
144  }
145 
146  // cancel unsatisfy & straggler timer
147  this->cancelUnsatisfyAndStragglerTimer(pitEntry);
148 
149  // is pending?
150  const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
151  bool isPending = inRecords.begin() != inRecords.end();
152  if (!isPending) {
153  if (m_csFromNdnSim == nullptr) {
154  m_cs.find(interest,
155  bind(&Forwarder::onContentStoreHit, this, ref(inFace), pitEntry, _1, _2),
156  bind(&Forwarder::onContentStoreMiss, this, ref(inFace), pitEntry, _1));
157  }
158  else {
159  shared_ptr<Data> match = m_csFromNdnSim->Lookup(interest.shared_from_this());
160  if (match != nullptr) {
161  this->onContentStoreHit(inFace, pitEntry, interest, *match);
162  }
163  else {
164  this->onContentStoreMiss(inFace, pitEntry, interest);
165  }
166  }
167  }
168  else {
169  this->onContentStoreMiss(inFace, pitEntry, interest);
170  }
171 }
172 
173 void
174 Forwarder::onInterestLoop(Face& inFace, const Interest& interest)
175 {
176  // if multi-access face, drop
177  if (inFace.getLinkType() == ndn::nfd::LINK_TYPE_MULTI_ACCESS) {
178  NFD_LOG_DEBUG("onInterestLoop face=" << inFace.getId() <<
179  " interest=" << interest.getName() <<
180  " drop");
181  return;
182  }
183 
184  NFD_LOG_DEBUG("onInterestLoop face=" << inFace.getId() <<
185  " interest=" << interest.getName() <<
186  " send-Nack-duplicate");
187 
188  // send Nack with reason=DUPLICATE
189  // note: Don't enter outgoing Nack pipeline because it needs an in-record.
190  lp::Nack nack(interest);
191  nack.setReason(lp::NackReason::DUPLICATE);
192  inFace.sendNack(nack);
193 }
194 
195 void
196 Forwarder::onContentStoreMiss(const Face& inFace,
197  shared_ptr<pit::Entry> pitEntry,
198  const Interest& interest)
199 {
200  NFD_LOG_DEBUG("onContentStoreMiss interest=" << interest.getName());
201 
202  shared_ptr<Face> face = const_pointer_cast<Face>(inFace.shared_from_this());
203  // insert InRecord
204  pitEntry->insertOrUpdateInRecord(face, interest);
205 
206  // set PIT unsatisfy timer
207  this->setUnsatisfyTimer(pitEntry);
208 
209  shared_ptr<fib::Entry> fibEntry;
210  // has Link object?
211  if (!interest.hasLink()) {
212  // FIB lookup with Interest name
213  fibEntry = m_fib.findLongestPrefixMatch(*pitEntry);
214  NFD_LOG_TRACE("onContentStoreMiss noLinkObject");
215  }
216  else {
217  const Link& link = interest.getLink();
218 
219  // in producer region?
220  if (m_networkRegionTable.isInProducerRegion(link)) {
221  // FIB lookup with Interest name
222  fibEntry = m_fib.findLongestPrefixMatch(*pitEntry);
223  NFD_LOG_TRACE("onContentStoreMiss inProducerRegion");
224  }
225  // has SelectedDelegation?
226  else if (interest.hasSelectedDelegation()) {
227  // FIB lookup with SelectedDelegation
228  fibEntry = m_fib.findLongestPrefixMatch(interest.getSelectedDelegation());
229  NFD_LOG_TRACE("onContentStoreMiss hasSelectedDelegation=" << interest.getSelectedDelegation());
230  }
231  else {
232  // FIB lookup with first delegation Name
233  fibEntry = m_fib.findLongestPrefixMatch(link.getDelegations().begin()->second);
234 
235  // in default-free zone?
236  bool isDefaultFreeZone = !(fibEntry->getPrefix().size() == 0 && fibEntry->hasNextHops());
237  if (isDefaultFreeZone) {
238  // choose and set SelectedDelegation
239  for (const std::pair<uint32_t, Name>& delegation : link.getDelegations()) {
240  const Name& delegationName = delegation.second;
241  fibEntry = m_fib.findLongestPrefixMatch(delegationName);
242  if (fibEntry->hasNextHops()) {
243  const_cast<Interest&>(interest).setSelectedDelegation(delegationName);
244  NFD_LOG_TRACE("onContentStoreMiss enterDefaultFreeZone"
245  << " setSelectedDelegation=" << delegationName);
246  break;
247  }
248  }
249  }
250  else {
251  NFD_LOG_TRACE("onContentStoreMiss inConsumerRegion");
252  }
253  }
254  }
255 
256  // dispatch to strategy
257  BOOST_ASSERT(fibEntry != nullptr);
258  this->dispatchToStrategy(pitEntry, bind(&Strategy::afterReceiveInterest, _1,
259  cref(inFace), cref(interest), fibEntry, pitEntry));
260 }
261 
262 void
263 Forwarder::onContentStoreHit(const Face& inFace,
264  shared_ptr<pit::Entry> pitEntry,
265  const Interest& interest,
266  const Data& data)
267 {
268  NFD_LOG_DEBUG("onContentStoreHit interest=" << interest.getName());
269 
270  beforeSatisfyInterest(*pitEntry, *m_csFace, data);
271  this->dispatchToStrategy(pitEntry, bind(&Strategy::beforeSatisfyInterest, _1,
272  pitEntry, cref(*m_csFace), cref(data)));
273 
274  data.setTag(make_shared<lp::IncomingFaceIdTag>(face::FACEID_CONTENT_STORE));
275  // XXX should we lookup PIT for other Interests that also match csMatch?
276 
277  // set PIT straggler timer
278  this->setStragglerTimer(pitEntry, true, data.getFreshnessPeriod());
279 
280  // goto outgoing Data pipeline
281  this->onOutgoingData(data, *const_pointer_cast<Face>(inFace.shared_from_this()));
282 }
283 
284 void
285 Forwarder::onOutgoingInterest(shared_ptr<pit::Entry> pitEntry, Face& outFace,
286  bool wantNewNonce)
287 {
288  if (outFace.getId() == face::INVALID_FACEID) {
289  NFD_LOG_WARN("onOutgoingInterest face=invalid interest=" << pitEntry->getName());
290  return;
291  }
292  NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() <<
293  " interest=" << pitEntry->getName());
294 
295  // scope control
296  if (pitEntry->violatesScope(outFace)) {
297  NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() <<
298  " interest=" << pitEntry->getName() << " violates scope");
299  return;
300  }
301 
302  // pick Interest
303  // The outgoing Interest picked is the last incoming Interest that does not come from outFace.
304  // If all in-records come from outFace, it's fine to pick that.
305  // This happens when there's only one in-record that comes from outFace.
306  // The legit use is for vehicular network; otherwise, strategy shouldn't send to the sole inFace.
307 
308  pit::InRecordCollection::const_iterator pickedInRecord = std::max_element(
309  pitEntry->getInRecords().begin(), pitEntry->getInRecords().end(),
310  [&outFace] (const pit::InRecord& a, const pit::InRecord& b) {
311  bool isOutFaceA = a.getFace().get() == &outFace;
312  bool isOutFaceB = b.getFace().get() == &outFace;
313  return (isOutFaceA > isOutFaceB) ||
314  (isOutFaceA == isOutFaceB && a.getLastRenewed() < b.getLastRenewed());
315  });
316  BOOST_ASSERT(pickedInRecord != pitEntry->getInRecords().end());
317  auto interest = const_pointer_cast<Interest>(pickedInRecord->getInterest().shared_from_this());
318 
319  if (wantNewNonce) {
320  interest = make_shared<Interest>(*interest);
321  static boost::random::uniform_int_distribution<uint32_t> dist;
322  interest->setNonce(dist(getGlobalRng()));
323  }
324 
325  // insert OutRecord
326  pitEntry->insertOrUpdateOutRecord(outFace.shared_from_this(), *interest);
327 
328  // send Interest
329  outFace.sendInterest(*interest);
330  ++m_counters.nOutInterests;
331 }
332 
333 void
334 Forwarder::onInterestReject(shared_ptr<pit::Entry> pitEntry)
335 {
336  if (pitEntry->hasUnexpiredOutRecords()) {
337  NFD_LOG_ERROR("onInterestReject interest=" << pitEntry->getName() <<
338  " cannot reject forwarded Interest");
339  return;
340  }
341  NFD_LOG_DEBUG("onInterestReject interest=" << pitEntry->getName());
342 
343  // cancel unsatisfy & straggler timer
344  this->cancelUnsatisfyAndStragglerTimer(pitEntry);
345 
346  // set PIT straggler timer
347  this->setStragglerTimer(pitEntry, false);
348 }
349 
350 void
351 Forwarder::onInterestUnsatisfied(shared_ptr<pit::Entry> pitEntry)
352 {
353  NFD_LOG_DEBUG("onInterestUnsatisfied interest=" << pitEntry->getName());
354 
355  // invoke PIT unsatisfied callback
356  beforeExpirePendingInterest(*pitEntry);
357  this->dispatchToStrategy(pitEntry, bind(&Strategy::beforeExpirePendingInterest, _1,
358  pitEntry));
359 
360  // goto Interest Finalize pipeline
361  this->onInterestFinalize(pitEntry, false);
362 }
363 
364 void
365 Forwarder::onInterestFinalize(shared_ptr<pit::Entry> pitEntry, bool isSatisfied,
366  const time::milliseconds& dataFreshnessPeriod)
367 {
368  NFD_LOG_DEBUG("onInterestFinalize interest=" << pitEntry->getName() <<
369  (isSatisfied ? " satisfied" : " unsatisfied"));
370 
371  // Dead Nonce List insert if necessary
372  this->insertDeadNonceList(*pitEntry, isSatisfied, dataFreshnessPeriod, 0);
373 
374  // PIT delete
375  this->cancelUnsatisfyAndStragglerTimer(pitEntry);
376  m_pit.erase(pitEntry);
377 }
378 
379 void
380 Forwarder::onIncomingData(Face& inFace, const Data& data)
381 {
382  // receive Data
383  NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId() << " data=" << data.getName());
384  data.setTag(make_shared<lp::IncomingFaceIdTag>(inFace.getId()));
385  ++m_counters.nInData;
386 
387  // /localhost scope control
388  bool isViolatingLocalhost = inFace.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
389  LOCALHOST_NAME.isPrefixOf(data.getName());
390  if (isViolatingLocalhost) {
391  NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId() <<
392  " data=" << data.getName() << " violates /localhost");
393  // (drop)
394  return;
395  }
396 
397  // PIT match
398  pit::DataMatchResult pitMatches = m_pit.findAllDataMatches(data);
399  if (pitMatches.begin() == pitMatches.end()) {
400  // goto Data unsolicited pipeline
401  this->onDataUnsolicited(inFace, data);
402  return;
403  }
404 
405  // Remove Ptr<Packet> from the Data before inserting into cache, serving two purposes
406  // - reduce amount of memory used by cached entries
407  // - remove all tags that (e.g., hop count tag) that could have been associated with Ptr<Packet>
408  //
409  // Copying of Data is relatively cheap operation, as it copies (mostly) a collection of Blocks
410  // pointing to the same underlying memory buffer.
411  shared_ptr<Data> dataCopyWithoutPacket = make_shared<Data>(data);
412  dataCopyWithoutPacket->removeTag<ns3::ndn::Ns3PacketTag>();
413 
414  // CS insert
415  if (m_csFromNdnSim == nullptr)
416  m_cs.insert(*dataCopyWithoutPacket);
417  else
418  m_csFromNdnSim->Add(dataCopyWithoutPacket);
419 
420  std::set<Face*> pendingDownstreams;
421  // foreach PitEntry
422  for (const shared_ptr<pit::Entry>& pitEntry : pitMatches) {
423  NFD_LOG_DEBUG("onIncomingData matching=" << pitEntry->getName());
424 
425  // cancel unsatisfy & straggler timer
426  this->cancelUnsatisfyAndStragglerTimer(pitEntry);
427 
428  // remember pending downstreams
429  const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
430  for (const pit::InRecord& inRecord : inRecords) {
431  if (inRecord.getExpiry() > time::steady_clock::now()) {
432  pendingDownstreams.insert(inRecord.getFace().get());
433  }
434  }
435 
436  // invoke PIT satisfy callback
437  beforeSatisfyInterest(*pitEntry, inFace, data);
438  this->dispatchToStrategy(pitEntry, bind(&Strategy::beforeSatisfyInterest, _1,
439  pitEntry, cref(inFace), cref(data)));
440 
441  // Dead Nonce List insert if necessary (for OutRecord of inFace)
442  this->insertDeadNonceList(*pitEntry, true, data.getFreshnessPeriod(), &inFace);
443 
444  // mark PIT satisfied
445  pitEntry->deleteInRecords();
446  pitEntry->deleteOutRecord(inFace);
447 
448  // set PIT straggler timer
449  this->setStragglerTimer(pitEntry, true, data.getFreshnessPeriod());
450  }
451 
452  // foreach pending downstream
453  for (Face* pendingDownstream : pendingDownstreams) {
454  if (pendingDownstream == &inFace) {
455  continue;
456  }
457  // goto outgoing Data pipeline
458  this->onOutgoingData(data, *pendingDownstream);
459  }
460 }
461 
462 void
463 Forwarder::onDataUnsolicited(Face& inFace, const Data& data)
464 {
465  // accept to cache?
466  bool acceptToCache = inFace.getScope() == ndn::nfd::FACE_SCOPE_LOCAL;
467  if (acceptToCache) {
468  // CS insert
469  if (m_csFromNdnSim == nullptr)
470  m_cs.insert(data, true);
471  else
472  m_csFromNdnSim->Add(data.shared_from_this());
473  }
474 
475  NFD_LOG_DEBUG("onDataUnsolicited face=" << inFace.getId() <<
476  " data=" << data.getName() <<
477  (acceptToCache ? " cached" : " not cached"));
478 }
479 
480 void
481 Forwarder::onOutgoingData(const Data& data, Face& outFace)
482 {
483  if (outFace.getId() == face::INVALID_FACEID) {
484  NFD_LOG_WARN("onOutgoingData face=invalid data=" << data.getName());
485  return;
486  }
487  NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId() << " data=" << data.getName());
488 
489  // /localhost scope control
490  bool isViolatingLocalhost = outFace.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
491  LOCALHOST_NAME.isPrefixOf(data.getName());
492  if (isViolatingLocalhost) {
493  NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId() <<
494  " data=" << data.getName() << " violates /localhost");
495  // (drop)
496  return;
497  }
498 
499  // TODO traffic manager
500 
501  // send Data
502  outFace.sendData(data);
503  ++m_counters.nOutData;
504 }
505 
506 void
507 Forwarder::onIncomingNack(Face& inFace, const lp::Nack& nack)
508 {
509  // receive Nack
510  nack.setTag(make_shared<lp::IncomingFaceIdTag>(inFace.getId()));
511  ++m_counters.nInNacks;
512 
513  // if multi-access face, drop
514  if (inFace.getLinkType() == ndn::nfd::LINK_TYPE_MULTI_ACCESS) {
515  NFD_LOG_DEBUG("onIncomingNack face=" << inFace.getId() <<
516  " nack=" << nack.getInterest().getName() <<
517  "~" << nack.getReason() << " face-is-multi-access");
518  return;
519  }
520 
521  // PIT match
522  shared_ptr<pit::Entry> pitEntry = m_pit.find(nack.getInterest());
523  // if no PIT entry found, drop
524  if (pitEntry == nullptr) {
525  NFD_LOG_DEBUG("onIncomingNack face=" << inFace.getId() <<
526  " nack=" << nack.getInterest().getName() <<
527  "~" << nack.getReason() << " no-PIT-entry");
528  return;
529  }
530 
531  // has out-record?
532  pit::OutRecordCollection::iterator outRecord = pitEntry->getOutRecord(inFace);
533  // if no out-record found, drop
534  if (outRecord == pitEntry->getOutRecords().end()) {
535  NFD_LOG_DEBUG("onIncomingNack face=" << inFace.getId() <<
536  " nack=" << nack.getInterest().getName() <<
537  "~" << nack.getReason() << " no-out-record");
538  return;
539  }
540 
541  // if out-record has different Nonce, drop
542  if (nack.getInterest().getNonce() != outRecord->getLastNonce()) {
543  NFD_LOG_DEBUG("onIncomingNack face=" << inFace.getId() <<
544  " nack=" << nack.getInterest().getName() <<
545  "~" << nack.getReason() << " wrong-Nonce " <<
546  nack.getInterest().getNonce() << "!=" << outRecord->getLastNonce());
547  return;
548  }
549 
550  NFD_LOG_DEBUG("onIncomingNack face=" << inFace.getId() <<
551  " nack=" << nack.getInterest().getName() <<
552  "~" << nack.getReason() << " OK");
553 
554  // record Nack on out-record
555  outRecord->setIncomingNack(nack);
556 
557  // trigger strategy: after receive NACK
558  shared_ptr<fib::Entry> fibEntry = m_fib.findLongestPrefixMatch(*pitEntry);
559  this->dispatchToStrategy(pitEntry, bind(&Strategy::afterReceiveNack, _1,
560  cref(inFace), cref(nack), fibEntry, pitEntry));
561 }
562 
563 void
564 Forwarder::onOutgoingNack(shared_ptr<pit::Entry> pitEntry, const Face& outFace,
565  const lp::NackHeader& nack)
566 {
567  if (outFace.getId() == face::INVALID_FACEID) {
568  NFD_LOG_WARN("onOutgoingNack face=invalid" <<
569  " nack=" << pitEntry->getInterest().getName() <<
570  "~" << nack.getReason() << " no-in-record");
571  return;
572  }
573 
574  // has in-record?
575  pit::InRecordCollection::const_iterator inRecord = pitEntry->getInRecord(outFace);
576 
577  // if no in-record found, drop
578  if (inRecord == pitEntry->getInRecords().end()) {
579  NFD_LOG_DEBUG("onOutgoingNack face=" << outFace.getId() <<
580  " nack=" << pitEntry->getInterest().getName() <<
581  "~" << nack.getReason() << " no-in-record");
582  return;
583  }
584 
585  // if multi-access face, drop
586  if (outFace.getLinkType() == ndn::nfd::LINK_TYPE_MULTI_ACCESS) {
587  NFD_LOG_DEBUG("onOutgoingNack face=" << outFace.getId() <<
588  " nack=" << pitEntry->getInterest().getName() <<
589  "~" << nack.getReason() << " face-is-multi-access");
590  return;
591  }
592 
593  NFD_LOG_DEBUG("onOutgoingNack face=" << outFace.getId() <<
594  " nack=" << pitEntry->getInterest().getName() <<
595  "~" << nack.getReason() << " OK");
596 
597  // create Nack packet with the Interest from in-record
598  lp::Nack nackPkt(inRecord->getInterest());
599  nackPkt.setHeader(nack);
600 
601  // erase in-record
602  pitEntry->deleteInRecord(outFace);
603 
604  // send Nack on face
605  const_cast<Face&>(outFace).sendNack(nackPkt);
606  ++m_counters.nOutNacks;
607 }
608 
609 static inline bool
611 {
612  return a.getExpiry() < b.getExpiry();
613 }
614 
615 void
616 Forwarder::setUnsatisfyTimer(shared_ptr<pit::Entry> pitEntry)
617 {
618  const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
619  pit::InRecordCollection::const_iterator lastExpiring =
620  std::max_element(inRecords.begin(), inRecords.end(),
622 
623  time::steady_clock::TimePoint lastExpiry = lastExpiring->getExpiry();
624  time::nanoseconds lastExpiryFromNow = lastExpiry - time::steady_clock::now();
625  if (lastExpiryFromNow <= time::seconds(0)) {
626  // TODO all InRecords are already expired; will this happen?
627  }
628 
629  scheduler::cancel(pitEntry->m_unsatisfyTimer);
630  pitEntry->m_unsatisfyTimer = scheduler::schedule(lastExpiryFromNow,
631  bind(&Forwarder::onInterestUnsatisfied, this, pitEntry));
632 }
633 
634 void
635 Forwarder::setStragglerTimer(shared_ptr<pit::Entry> pitEntry, bool isSatisfied,
636  const time::milliseconds& dataFreshnessPeriod)
637 {
638  time::nanoseconds stragglerTime = time::milliseconds(100);
639 
640  scheduler::cancel(pitEntry->m_stragglerTimer);
641  pitEntry->m_stragglerTimer = scheduler::schedule(stragglerTime,
642  bind(&Forwarder::onInterestFinalize, this, pitEntry, isSatisfied, dataFreshnessPeriod));
643 }
644 
645 void
646 Forwarder::cancelUnsatisfyAndStragglerTimer(shared_ptr<pit::Entry> pitEntry)
647 {
648  scheduler::cancel(pitEntry->m_unsatisfyTimer);
649  scheduler::cancel(pitEntry->m_stragglerTimer);
650 }
651 
652 static inline void
654  const pit::OutRecord& outRecord)
655 {
656  dnl.add(pitEntry.getName(), outRecord.getLastNonce());
657 }
658 
659 void
660 Forwarder::insertDeadNonceList(pit::Entry& pitEntry, bool isSatisfied,
661  const time::milliseconds& dataFreshnessPeriod,
662  Face* upstream)
663 {
664  // need Dead Nonce List insert?
665  bool needDnl = false;
666  if (isSatisfied) {
667  bool hasFreshnessPeriod = dataFreshnessPeriod >= time::milliseconds::zero();
668  // Data never becomes stale if it doesn't have FreshnessPeriod field
669  needDnl = static_cast<bool>(pitEntry.getInterest().getMustBeFresh()) &&
670  (hasFreshnessPeriod && dataFreshnessPeriod < m_deadNonceList.getLifetime());
671  }
672  else {
673  needDnl = true;
674  }
675 
676  if (!needDnl) {
677  return;
678  }
679 
680  // Dead Nonce List insert
681  if (upstream == 0) {
682  // insert all outgoing Nonces
683  const pit::OutRecordCollection& outRecords = pitEntry.getOutRecords();
684  std::for_each(outRecords.begin(), outRecords.end(),
685  bind(&insertNonceToDnl, ref(m_deadNonceList), cref(pitEntry), _1));
686  }
687  else {
688  // insert outgoing Nonce of a specific face
689  pit::OutRecordCollection::const_iterator outRecord = pitEntry.getOutRecord(*upstream);
690  if (outRecord != pitEntry.getOutRecords().end()) {
691  m_deadNonceList.add(pitEntry.getName(), outRecord->getLastNonce());
692  }
693  }
694 }
695 
696 } // namespace nfd
signal::Signal< Forwarder, pit::Entry, Face, Data > beforeSatisfyInterest
trigger before PIT entry is satisfied
Definition: forwarder.hpp:138
std::list< InRecord > InRecordCollection
represents an unordered collection of InRecords
Definition: pit-entry.hpp:47
void setTag(shared_ptr< T > tag) const
set a tag item
Definition: tag-host.hpp:80
time_point TimePoint
Definition: time.hpp:108
void erase(shared_ptr< pit::Entry > pitEntry)
erases a PIT Entry
Definition: pit.cpp:114
shared_ptr< Face > makeNullFace(const FaceUri &uri)
Definition: null-face.cpp:37
represents the Dead Nonce list
#define NFD_LOG_DEBUG(expression)
Definition: logger.hpp:55
shared_ptr< Face > getFace() const
OutRecordCollection::iterator getOutRecord(const Face &face)
get the OutRecord for face
Definition: pit-entry.cpp:182
const Link & getLink() const
Get the link object for this interest.
Definition: interest.cpp:370
int getMustBeFresh() const
Definition: interest.hpp:412
void cancel(const EventId &eventId)
cancel a scheduled event
Definition: scheduler.cpp:53
void installStrategies(Forwarder &forwarder)
static time_point now() noexcept
Definition: time.cpp:79
represents the underlying protocol and address used by a Face
Definition: face-uri.hpp:44
const Name & getName() const
Get name of the Data packet.
Definition: data.hpp:360
FaceTable & getFaceTable()
Definition: forwarder.hpp:277
contains information about an Interest from an incoming face
Nack & setHeader(const NackHeader &header)
Definition: nack.hpp:77
shared_ptr< fib::Entry > findLongestPrefixMatch(const Name &prefix) const
performs a longest prefix match
Definition: fib.cpp:66
void startProcessInterest(Face &face, const Interest &interest)
start incoming Interest processing
Definition: forwarder.cpp:61
virtual void beforeSatisfyInterest(shared_ptr< pit::Entry > pitEntry, const Face &inFace, const Data &data)
trigger before PIT entry is satisfied
Definition: strategy.cpp:50
const time::nanoseconds & getLifetime() const
represents an Interest packet
Definition: interest.hpp:45
#define NFD_LOG_ERROR(expression)
Definition: logger.hpp:57
pit::DataMatchResult findAllDataMatches(const Data &data) const
performs a Data match
Definition: pit.cpp:97
shared_ptr< pit::Entry > find(const Interest &interest) const
finds a PIT entry for Interest
Definition: pit.hpp:166
static bool compare_InRecord_expiry(const pit::InRecord &a, const pit::InRecord &b)
Definition: forwarder.cpp:610
shared_ptr< Strategy > makeDefaultStrategy(Forwarder &forwarder)
void add(const Name &name, uint32_t nonce)
records name+nonce
const Name & getName() const
Definition: pit-entry.cpp:41
NackReason getReason() const
represents a Network Nack
Definition: nack.hpp:40
NackReason getReason() const
Definition: nack.hpp:92
Table::const_iterator iterator
Definition: cs-internal.hpp:41
virtual void beforeExpirePendingInterest(shared_ptr< pit::Entry > pitEntry)
trigger before PIT entry expires
Definition: strategy.cpp:58
#define NFD_LOG_WARN(expression)
Definition: logger.hpp:58
Name getSelectedDelegation() const
Get the name of the selected delegation.
Definition: interest.cpp:409
static void insertNonceToDnl(DeadNonceList &dnl, const pit::Entry &pitEntry, const pit::OutRecord &outRecord)
Definition: forwarder.cpp:653
void insert(const Data &data, bool isUnsolicited=false)
inserts a Data packet
Definition: cs.cpp:82
Copyright (c) 2011-2015 Regents of the University of California.
Definition: ndn-common.hpp:40
uint32_t getNonce() const
Get Interest&#39;s nonce.
Definition: interest.cpp:62
represents a PIT entry
Definition: pit-entry.hpp:69
signal::Signal< Forwarder, pit::Entry > beforeExpirePendingInterest
trigger before PIT entry expires
Definition: forwarder.hpp:143
Interest & setNonce(uint32_t nonce)
Set Interest&#39;s nonce.
Definition: interest.cpp:76
void startProcessData(Face &face, const Data &data)
start incoming Data processing
Definition: forwarder.cpp:80
bool isInProducerRegion(const Link &link) const
determines whether an Interest has reached a producer region
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:320
boost::random::mt19937 & getGlobalRng()
Definition: random.cpp:34
std::pair< shared_ptr< pit::Entry >, bool > insert(const Interest &interest)
inserts a PIT entry for Interest
Definition: pit.hpp:172
void find(const Interest &interest, const HitCallback &hitCallback, const MissCallback &missCallback) const
finds the best matching Data packet
Definition: cs.cpp:122
const OutRecordCollection & getOutRecords() const
Definition: pit-entry.hpp:204
uint32_t getLastNonce() const
std::list< OutRecord > OutRecordCollection
represents an unordered collection of OutRecords
Definition: pit-entry.hpp:51
const time::milliseconds & getFreshnessPeriod() const
Definition: data.hpp:378
time::steady_clock::TimePoint getExpiry() const
gives the time point this record expires
bool has(const Name &name, uint32_t nonce) const
determines if name+nonce exists
const Interest & getInterest() const
Definition: pit-entry.hpp:192
#define NFD_LOG_INIT(name)
Definition: logger.hpp:34
EventId schedule(const time::nanoseconds &after, const Scheduler::Event &event)
schedule an event
Definition: scheduler.cpp:47
#define NFD_LOG_TRACE(expression)
Definition: logger.hpp:54
void addReserved(shared_ptr< Face > face, FaceId faceId)
add a special Face with a reserved FaceId
Definition: face-table.cpp:74
contains information about an Interest toward an outgoing face
bool hasLink() const
Check whether the Interest contains a Link object.
Definition: interest.cpp:364
virtual void afterReceiveInterest(const Face &inFace, const Interest &interest, shared_ptr< fib::Entry > fibEntry, shared_ptr< pit::Entry > pitEntry)=0
trigger after Interest is received
virtual void afterReceiveNack(const Face &inFace, const lp::Nack &nack, shared_ptr< fib::Entry > fibEntry, shared_ptr< pit::Entry > pitEntry)
trigger after Nack is received
Definition: strategy.cpp:64
bool hasSelectedDelegation() const
Check whether the Interest includes a selected delegation.
Definition: interest.cpp:403
represents a Data packet
Definition: data.hpp:39
const FaceId FACEID_CONTENT_STORE
identifies a packet comes from the ContentStore
Definition: face.hpp:46
represents a Network NACK header
Definition: nack-header.hpp:52
const FaceId INVALID_FACEID
indicates an invalid FaceId
Definition: face.hpp:42
void startProcessNack(Face &face, const lp::Nack &nack)
start incoming Nack processing
Definition: forwarder.cpp:89
const Interest & getInterest() const
Definition: nack.hpp:53
represents an error in TLV encoding or decoding
Definition: tlv.hpp:50
const Name & getName() const
Definition: interest.hpp:218
time::steady_clock::TimePoint getLastRenewed() const
std::vector< shared_ptr< pit::Entry > > DataMatchResult
Definition: pit.hpp:42