forwarder.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2014-2019, Regents of the University of California,
4  * Arizona Board of Regents,
5  * Colorado State University,
6  * University Pierre & Marie Curie, Sorbonne University,
7  * Washington University in St. Louis,
8  * Beijing Institute of Technology,
9  * The University of Memphis.
10  *
11  * This file is part of NFD (Named Data Networking Forwarding Daemon).
12  * See AUTHORS.md for complete list of NFD authors and contributors.
13  *
14  * NFD is free software: you can redistribute it and/or modify it under the terms
15  * of the GNU General Public License as published by the Free Software Foundation,
16  * either version 3 of the License, or (at your option) any later version.
17  *
18  * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20  * PURPOSE. See the GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License along with
23  * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 #include "forwarder.hpp"
27 
28 #include "algorithm.hpp"
29 #include "best-route-strategy2.hpp"
30 #include "strategy.hpp"
31 #include "common/global.hpp"
32 #include "common/logger.hpp"
33 #include "table/cleanup.hpp"
34 
35 #include <ndn-cxx/lp/tags.hpp>
36 
37 namespace nfd {
38 
39 NFD_LOG_INIT(Forwarder);
40 
41 static Name
43 {
45 }
46 
48  : m_unsolicitedDataPolicy(make_unique<fw::DefaultUnsolicitedDataPolicy>())
49  , m_fib(m_nameTree)
50  , m_pit(m_nameTree)
51  , m_measurements(m_nameTree)
52  , m_strategyChoice(*this)
53 {
54  m_faceTable.afterAdd.connect([this] (Face& face) {
55  face.afterReceiveInterest.connect(
56  [this, &face] (const Interest& interest) {
57  this->startProcessInterest(FaceEndpoint(face, 0), interest);
58  });
59  face.afterReceiveData.connect(
60  [this, &face] (const Data& data) {
61  this->startProcessData(FaceEndpoint(face, 0), data);
62  });
63  face.afterReceiveNack.connect(
64  [this, &face] (const lp::Nack& nack) {
65  this->startProcessNack(FaceEndpoint(face, 0), nack);
66  });
67  face.onDroppedInterest.connect(
68  [this, &face] (const Interest& interest) {
69  this->onDroppedInterest(FaceEndpoint(face, 0), interest);
70  });
71  });
72 
73  m_faceTable.beforeRemove.connect([this] (Face& face) {
74  cleanupOnFaceRemoval(m_nameTree, m_fib, m_pit, face);
75  });
76 
77  m_strategyChoice.setDefaultStrategy(getDefaultStrategyName());
78 }
79 
80 Forwarder::~Forwarder() = default;
81 
82 void
83 Forwarder::onIncomingInterest(const FaceEndpoint& ingress, const Interest& interest)
84 {
85  // receive Interest
86  NFD_LOG_DEBUG("onIncomingInterest in=" << ingress << " interest=" << interest.getName());
87  interest.setTag(make_shared<lp::IncomingFaceIdTag>(ingress.face.getId()));
88  ++m_counters.nInInterests;
89 
90  // /localhost scope control
91  bool isViolatingLocalhost = ingress.face.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
92  scope_prefix::LOCALHOST.isPrefixOf(interest.getName());
93  if (isViolatingLocalhost) {
94  NFD_LOG_DEBUG("onIncomingInterest in=" << ingress
95  << " interest=" << interest.getName() << " violates /localhost");
96  // (drop)
97  return;
98  }
99 
100  // detect duplicate Nonce with Dead Nonce List
101  bool hasDuplicateNonceInDnl = m_deadNonceList.has(interest.getName(), interest.getNonce());
102  if (hasDuplicateNonceInDnl) {
103  // goto Interest loop pipeline
104  this->onInterestLoop(ingress, interest);
105  return;
106  }
107 
108  // strip forwarding hint if Interest has reached producer region
109  if (!interest.getForwardingHint().empty() &&
110  m_networkRegionTable.isInProducerRegion(interest.getForwardingHint())) {
111  NFD_LOG_DEBUG("onIncomingInterest in=" << ingress
112  << " interest=" << interest.getName() << " reaching-producer-region");
113  const_cast<Interest&>(interest).setForwardingHint({});
114  }
115 
116  // PIT insert
117  shared_ptr<pit::Entry> pitEntry = m_pit.insert(interest).first;
118 
119  // detect duplicate Nonce in PIT entry
120  int dnw = fw::findDuplicateNonce(*pitEntry, interest.getNonce(), ingress.face);
121  bool hasDuplicateNonceInPit = dnw != fw::DUPLICATE_NONCE_NONE;
122  if (ingress.face.getLinkType() == ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
123  // for p2p face: duplicate Nonce from same incoming face is not loop
124  hasDuplicateNonceInPit = hasDuplicateNonceInPit && !(dnw & fw::DUPLICATE_NONCE_IN_SAME);
125  }
126  if (hasDuplicateNonceInPit) {
127  // goto Interest loop pipeline
128  this->onInterestLoop(ingress, interest);
129  return;
130  }
131 
132  // is pending?
133  if (!pitEntry->hasInRecords()) {
134  m_cs.find(interest,
135  bind(&Forwarder::onContentStoreHit, this, ingress, pitEntry, _1, _2),
136  bind(&Forwarder::onContentStoreMiss, this, ingress, pitEntry, _1));
137  }
138  else {
139  this->onContentStoreMiss(ingress, pitEntry, interest);
140  }
141 }
142 
143 void
144 Forwarder::onInterestLoop(const FaceEndpoint& ingress, const Interest& interest)
145 {
146  // if multi-access or ad hoc face, drop
147  if (ingress.face.getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
148  NFD_LOG_DEBUG("onInterestLoop in=" << ingress
149  << " interest=" << interest.getName() << " drop");
150  return;
151  }
152 
153  NFD_LOG_DEBUG("onInterestLoop in=" << ingress << " interest=" << interest.getName()
154  << " send-Nack-duplicate");
155 
156  // send Nack with reason=DUPLICATE
157  // note: Don't enter outgoing Nack pipeline because it needs an in-record.
158  lp::Nack nack(interest);
159  nack.setReason(lp::NackReason::DUPLICATE);
160  ingress.face.sendNack(nack);
161 }
162 
163 void
164 Forwarder::onContentStoreMiss(const FaceEndpoint& ingress,
165  const shared_ptr<pit::Entry>& pitEntry, const Interest& interest)
166 {
167  NFD_LOG_DEBUG("onContentStoreMiss interest=" << interest.getName());
168  ++m_counters.nCsMisses;
169 
170  // insert in-record
171  // FIXME Strategies are not prepared to handle non-zero EndpointIds, so always insert
172  // the in-record with EndpointId=0 for now. Eventually, this pipeline will need
173  // to be refactored so that strategies can control the in-record insertion.
174  pitEntry->insertOrUpdateInRecord(ingress.face, 0, interest);
175 
176  // set PIT expiry timer to the time that the last PIT in-record expires
177  auto lastExpiring = std::max_element(pitEntry->in_begin(), pitEntry->in_end(),
178  [] (const auto& a, const auto& b) {
179  return a.getExpiry() < b.getExpiry();
180  });
181  auto lastExpiryFromNow = lastExpiring->getExpiry() - time::steady_clock::now();
182  this->setExpiryTimer(pitEntry, time::duration_cast<time::milliseconds>(lastExpiryFromNow));
183 
184  // has NextHopFaceId?
185  auto nextHopTag = interest.getTag<lp::NextHopFaceIdTag>();
186  if (nextHopTag != nullptr) {
187  // chosen NextHop face exists?
188  Face* nextHopFace = m_faceTable.get(*nextHopTag);
189  if (nextHopFace != nullptr) {
190  NFD_LOG_DEBUG("onContentStoreMiss interest=" << interest.getName()
191  << " nexthop-faceid=" << nextHopFace->getId());
192  // go to outgoing Interest pipeline
193  // scope control is unnecessary, because privileged app explicitly wants to forward
194  this->onOutgoingInterest(pitEntry, FaceEndpoint(*nextHopFace, 0), interest);
195  }
196  return;
197  }
198 
199  // dispatch to strategy: after incoming Interest
200  this->dispatchToStrategy(*pitEntry,
201  [&] (fw::Strategy& strategy) { strategy.afterReceiveInterest(ingress, interest, pitEntry); });
202 }
203 
204 void
205 Forwarder::onContentStoreHit(const FaceEndpoint& ingress, const shared_ptr<pit::Entry>& pitEntry,
206  const Interest& interest, const Data& data)
207 {
208  NFD_LOG_DEBUG("onContentStoreHit interest=" << interest.getName());
209  ++m_counters.nCsHits;
210 
211  data.setTag(make_shared<lp::IncomingFaceIdTag>(face::FACEID_CONTENT_STORE));
212  // FIXME Should we lookup PIT for other Interests that also match the data?
213 
214  pitEntry->isSatisfied = true;
215  pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
216 
217  // set PIT expiry timer to now
218  this->setExpiryTimer(pitEntry, 0_ms);
219 
220  // dispatch to strategy: after Content Store hit
221  this->dispatchToStrategy(*pitEntry,
222  [&] (fw::Strategy& strategy) { strategy.afterContentStoreHit(pitEntry, ingress, data); });
223 }
224 
225 void
226 Forwarder::onOutgoingInterest(const shared_ptr<pit::Entry>& pitEntry,
227  const FaceEndpoint& egress, const Interest& interest)
228 {
229  NFD_LOG_DEBUG("onOutgoingInterest out=" << egress << " interest=" << pitEntry->getName());
230 
231  // insert out-record
232  pitEntry->insertOrUpdateOutRecord(egress.face, egress.endpoint, interest);
233 
234  // send Interest
235  egress.face.sendInterest(interest);
236  ++m_counters.nOutInterests;
237 }
238 
239 void
240 Forwarder::onInterestFinalize(const shared_ptr<pit::Entry>& pitEntry)
241 {
242  NFD_LOG_DEBUG("onInterestFinalize interest=" << pitEntry->getName()
243  << (pitEntry->isSatisfied ? " satisfied" : " unsatisfied"));
244 
245  // Dead Nonce List insert if necessary
246  this->insertDeadNonceList(*pitEntry, nullptr);
247 
248  // Increment satisfied/unsatisfied Interests counter
249  if (pitEntry->isSatisfied) {
250  ++m_counters.nSatisfiedInterests;
251  }
252  else {
253  ++m_counters.nUnsatisfiedInterests;
254  }
255 
256  // PIT delete
257  pitEntry->expiryTimer.cancel();
258  m_pit.erase(pitEntry.get());
259 }
260 
261 void
262 Forwarder::onIncomingData(const FaceEndpoint& ingress, const Data& data)
263 {
264  // receive Data
265  NFD_LOG_DEBUG("onIncomingData in=" << ingress << " data=" << data.getName());
266  data.setTag(make_shared<lp::IncomingFaceIdTag>(ingress.face.getId()));
267  ++m_counters.nInData;
268 
269  // /localhost scope control
270  bool isViolatingLocalhost = ingress.face.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
271  scope_prefix::LOCALHOST.isPrefixOf(data.getName());
272  if (isViolatingLocalhost) {
273  NFD_LOG_DEBUG("onIncomingData in=" << ingress << " data=" << data.getName() << " violates /localhost");
274  // (drop)
275  return;
276  }
277 
278  // PIT match
279  pit::DataMatchResult pitMatches = m_pit.findAllDataMatches(data);
280  if (pitMatches.size() == 0) {
281  // goto Data unsolicited pipeline
282  this->onDataUnsolicited(ingress, data);
283  return;
284  }
285 
286  // CS insert
287  m_cs.insert(data);
288 
289  // when only one PIT entry is matched, trigger strategy: after receive Data
290  if (pitMatches.size() == 1) {
291  auto& pitEntry = pitMatches.front();
292 
293  NFD_LOG_DEBUG("onIncomingData matching=" << pitEntry->getName());
294 
295  // set PIT expiry timer to now
296  this->setExpiryTimer(pitEntry, 0_ms);
297 
298  // trigger strategy: after receive Data
299  this->dispatchToStrategy(*pitEntry,
300  [&] (fw::Strategy& strategy) { strategy.afterReceiveData(pitEntry, ingress, data); });
301 
302  // mark PIT satisfied
303  pitEntry->isSatisfied = true;
304  pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
305 
306  // Dead Nonce List insert if necessary (for out-record of inFace)
307  this->insertDeadNonceList(*pitEntry, &ingress.face);
308 
309  // delete PIT entry's out-record
310  pitEntry->deleteOutRecord(ingress.face, ingress.endpoint);
311  }
312  // when more than one PIT entry is matched, trigger strategy: before satisfy Interest,
313  // and send Data to all matched out faces
314  else {
315  std::set<std::pair<Face*, EndpointId>> pendingDownstreams;
316  auto now = time::steady_clock::now();
317 
318  for (const auto& pitEntry : pitMatches) {
319  NFD_LOG_DEBUG("onIncomingData matching=" << pitEntry->getName());
320 
321  // remember pending downstreams
322  for (const pit::InRecord& inRecord : pitEntry->getInRecords()) {
323  if (inRecord.getExpiry() > now) {
324  pendingDownstreams.emplace(&inRecord.getFace(), inRecord.getEndpointId());
325  }
326  }
327 
328  // set PIT expiry timer to now
329  this->setExpiryTimer(pitEntry, 0_ms);
330 
331  // invoke PIT satisfy callback
332  this->dispatchToStrategy(*pitEntry,
333  [&] (fw::Strategy& strategy) { strategy.beforeSatisfyInterest(pitEntry, ingress, data); });
334 
335  // mark PIT satisfied
336  pitEntry->isSatisfied = true;
337  pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
338 
339  // Dead Nonce List insert if necessary (for out-record of inFace)
340  this->insertDeadNonceList(*pitEntry, &ingress.face);
341 
342  // clear PIT entry's in and out records
343  pitEntry->clearInRecords();
344  pitEntry->deleteOutRecord(ingress.face, ingress.endpoint);
345  }
346 
347  // foreach pending downstream
348  for (const auto& pendingDownstream : pendingDownstreams) {
349  if (pendingDownstream.first->getId() == ingress.face.getId() &&
350  pendingDownstream.second == ingress.endpoint &&
351  pendingDownstream.first->getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) {
352  continue;
353  }
354  // goto outgoing Data pipeline
355  this->onOutgoingData(data, FaceEndpoint(*pendingDownstream.first, pendingDownstream.second));
356  }
357  }
358 }
359 
360 void
361 Forwarder::onDataUnsolicited(const FaceEndpoint& ingress, const Data& data)
362 {
363  // accept to cache?
364  fw::UnsolicitedDataDecision decision = m_unsolicitedDataPolicy->decide(ingress.face, data);
365  if (decision == fw::UnsolicitedDataDecision::CACHE) {
366  // CS insert
367  m_cs.insert(data, true);
368  }
369 
370  NFD_LOG_DEBUG("onDataUnsolicited in=" << ingress << " data=" << data.getName() << " decision=" << decision);
371 }
372 
373 void
374 Forwarder::onOutgoingData(const Data& data, FaceEndpoint egress)
375 {
376  if (egress.face.getId() == face::INVALID_FACEID) {
377  NFD_LOG_WARN("onOutgoingData out=(invalid) data=" << data.getName());
378  return;
379  }
380  NFD_LOG_DEBUG("onOutgoingData out=" << egress << " data=" << data.getName());
381 
382  // /localhost scope control
383  bool isViolatingLocalhost = egress.face.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
384  scope_prefix::LOCALHOST.isPrefixOf(data.getName());
385  if (isViolatingLocalhost) {
386  NFD_LOG_DEBUG("onOutgoingData out=" << egress << " data=" << data.getName() << " violates /localhost");
387  // (drop)
388  return;
389  }
390 
391  // TODO traffic manager
392 
393  // send Data
394  egress.face.sendData(data);
395  ++m_counters.nOutData;
396 }
397 
398 void
399 Forwarder::onIncomingNack(const FaceEndpoint& ingress, const lp::Nack& nack)
400 {
401  // receive Nack
402  nack.setTag(make_shared<lp::IncomingFaceIdTag>(ingress.face.getId()));
403  ++m_counters.nInNacks;
404 
405  // if multi-access or ad hoc face, drop
406  if (ingress.face.getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
407  NFD_LOG_DEBUG("onIncomingNack in=" << ingress
408  << " nack=" << nack.getInterest().getName() << "~" << nack.getReason()
409  << " link-type=" << ingress.face.getLinkType());
410  return;
411  }
412 
413  // PIT match
414  shared_ptr<pit::Entry> pitEntry = m_pit.find(nack.getInterest());
415  // if no PIT entry found, drop
416  if (pitEntry == nullptr) {
417  NFD_LOG_DEBUG("onIncomingNack in=" << ingress << " nack=" << nack.getInterest().getName()
418  << "~" << nack.getReason() << " no-PIT-entry");
419  return;
420  }
421 
422  // has out-record?
423  auto outRecord = pitEntry->getOutRecord(ingress.face, ingress.endpoint);
424  // if no out-record found, drop
425  if (outRecord == pitEntry->out_end()) {
426  NFD_LOG_DEBUG("onIncomingNack in=" << ingress << " nack=" << nack.getInterest().getName()
427  << "~" << nack.getReason() << " no-out-record");
428  return;
429  }
430 
431  // if out-record has different Nonce, drop
432  if (nack.getInterest().getNonce() != outRecord->getLastNonce()) {
433  NFD_LOG_DEBUG("onIncomingNack in=" << ingress << " nack=" << nack.getInterest().getName()
434  << "~" << nack.getReason() << " wrong-Nonce " << nack.getInterest().getNonce()
435  << "!=" << outRecord->getLastNonce());
436  return;
437  }
438 
439  NFD_LOG_DEBUG("onIncomingNack in=" << ingress << " nack=" << nack.getInterest().getName()
440  << "~" << nack.getReason() << " OK");
441 
442  // record Nack on out-record
443  outRecord->setIncomingNack(nack);
444 
445  // set PIT expiry timer to now when all out-record receive Nack
446  if (!fw::hasPendingOutRecords(*pitEntry)) {
447  this->setExpiryTimer(pitEntry, 0_ms);
448  }
449 
450  // trigger strategy: after receive NACK
451  this->dispatchToStrategy(*pitEntry,
452  [&] (fw::Strategy& strategy) { strategy.afterReceiveNack(ingress, nack, pitEntry); });
453 }
454 
455 void
456 Forwarder::onOutgoingNack(const shared_ptr<pit::Entry>& pitEntry,
457  const FaceEndpoint& egress, const lp::NackHeader& nack)
458 {
459  if (egress.face.getId() == face::INVALID_FACEID) {
460  NFD_LOG_WARN("onOutgoingNack out=(invalid)"
461  << " nack=" << pitEntry->getInterest().getName() << "~" << nack.getReason());
462  return;
463  }
464 
465  // has in-record?
466  auto inRecord = pitEntry->getInRecord(egress.face, egress.endpoint);
467 
468  // if no in-record found, drop
469  if (inRecord == pitEntry->in_end()) {
470  NFD_LOG_DEBUG("onOutgoingNack out=" << egress
471  << " nack=" << pitEntry->getInterest().getName()
472  << "~" << nack.getReason() << " no-in-record");
473  return;
474  }
475 
476  // if multi-access or ad hoc face, drop
477  if (egress.face.getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
478  NFD_LOG_DEBUG("onOutgoingNack out=" << egress
479  << " nack=" << pitEntry->getInterest().getName() << "~" << nack.getReason()
480  << " link-type=" << egress.face.getLinkType());
481  return;
482  }
483 
484  NFD_LOG_DEBUG("onOutgoingNack out=" << egress
485  << " nack=" << pitEntry->getInterest().getName()
486  << "~" << nack.getReason() << " OK");
487 
488  // create Nack packet with the Interest from in-record
489  lp::Nack nackPkt(inRecord->getInterest());
490  nackPkt.setHeader(nack);
491 
492  // erase in-record
493  pitEntry->deleteInRecord(egress.face, egress.endpoint);
494 
495  // send Nack on face
496  egress.face.sendNack(nackPkt);
497  ++m_counters.nOutNacks;
498 }
499 
500 void
501 Forwarder::onDroppedInterest(const FaceEndpoint& egress, const Interest& interest)
502 {
503  m_strategyChoice.findEffectiveStrategy(interest.getName()).onDroppedInterest(egress, interest);
504 }
505 
506 void
507 Forwarder::setExpiryTimer(const shared_ptr<pit::Entry>& pitEntry, time::milliseconds duration)
508 {
509  BOOST_ASSERT(pitEntry);
510  BOOST_ASSERT(duration >= 0_ms);
511 
512  pitEntry->expiryTimer.cancel();
513  pitEntry->expiryTimer = getScheduler().schedule(duration, [=] { onInterestFinalize(pitEntry); });
514 }
515 
516 void
517 Forwarder::insertDeadNonceList(pit::Entry& pitEntry, Face* upstream)
518 {
519  // need Dead Nonce List insert?
520  bool needDnl = true;
521  if (pitEntry.isSatisfied) {
522  BOOST_ASSERT(pitEntry.dataFreshnessPeriod >= 0_ms);
523  needDnl = static_cast<bool>(pitEntry.getInterest().getMustBeFresh()) &&
524  pitEntry.dataFreshnessPeriod < m_deadNonceList.getLifetime();
525  }
526 
527  if (!needDnl) {
528  return;
529  }
530 
531  // Dead Nonce List insert
532  if (upstream == nullptr) {
533  // insert all outgoing Nonces
534  const auto& outRecords = pitEntry.getOutRecords();
535  std::for_each(outRecords.begin(), outRecords.end(), [&] (const auto& outRecord) {
536  m_deadNonceList.add(pitEntry.getName(), outRecord.getLastNonce());
537  });
538  }
539  else {
540  // insert outgoing Nonce of a specific face
541  auto outRecord = pitEntry.getOutRecord(*upstream, 0);
542  if (outRecord != pitEntry.getOutRecords().end()) {
543  m_deadNonceList.add(pitEntry.getName(), outRecord->getLastNonce());
544  }
545  }
546 }
547 
548 } // namespace nfd
const EndpointId endpoint
bool isSatisfied
Indicates whether this PIT entry is satisfied.
Definition: pit-entry.hpp:233
void cleanupOnFaceRemoval(NameTree &nt, Fib &fib, Pit &pit, const Face &face)
cleanup tables when a face is destroyed
Definition: cleanup.cpp:31
PacketCounter nUnsatisfiedInterests
virtual void afterReceiveInterest(const FaceEndpoint &ingress, const Interest &interest, const shared_ptr< pit::Entry > &pitEntry)=0
trigger after Interest is received
static const Name & getStrategyName()
OutRecordCollection::iterator getOutRecord(const Face &face, EndpointId endpointId)
get the out-record for face and endpointId
Definition: pit-entry.cpp:96
Face * get(FaceId id) const
get face by FaceId
Definition: face-table.cpp:45
void startProcessData(const FaceEndpoint &ingress, const Data &data)
start incoming Data processing
Definition: forwarder.hpp:121
void add(const Name &name, uint32_t nonce)
Records name+nonce.
bool has(const Name &name, uint32_t nonce) const
Determines if name+nonce exists.
DropAllUnsolicitedDataPolicy DefaultUnsolicitedDataPolicy
the default UnsolicitedDataPolicy
virtual void afterReceiveNack(const FaceEndpoint &ingress, const lp::Nack &nack, const shared_ptr< pit::Entry > &pitEntry)
trigger after Nack is received
Definition: strategy.cpp:182
Scheduler & getScheduler()
Returns the global Scheduler instance for the calling thread.
Definition: global.cpp:45
in-record of same face
Definition: algorithm.hpp:63
An Interest table entry.
Definition: pit-entry.hpp:58
Represents a face-endpoint pair in the forwarder.
Copyright (c) 2014-2015, Regents of the University of California, Arizona Board of Regents...
Definition: algorithm.hpp:32
Contains information about an Interest from an incoming face.
signal::Signal< FaceTable, Face & > beforeRemove
fires before a face is removed
Definition: face-table.hpp:90
#define NFD_LOG_WARN
Definition: logger.hpp:40
time::nanoseconds getLifetime() const
signal::Signal< FaceTable, Face & > afterAdd
fires after a face is added
Definition: face-table.hpp:84
bool hasPendingOutRecords(const pit::Entry &pitEntry)
determine whether pitEntry has any pending out-records
Definition: algorithm.cpp:108
const Interest & getInterest() const
Definition: pit-entry.hpp:70
const Name LOCALHOST
ndn:/localhost
no duplicate Nonce is found
Definition: algorithm.hpp:62
virtual void afterContentStoreHit(const shared_ptr< pit::Entry > &pitEntry, const FaceEndpoint &ingress, const Data &data)
trigger after a Data is matched in CS
Definition: strategy.cpp:160
int findDuplicateNonce(const pit::Entry &pitEntry, uint32_t nonce, const Face &face)
determine whether pitEntry has duplicate Nonce nonce
Definition: algorithm.cpp:78
static Name getDefaultStrategyName()
Definition: forwarder.cpp:42
represents a forwarding strategy
Definition: strategy.hpp:37
This file contains common algorithms used by forwarding strategies.
#define NFD_LOG_DEBUG
Definition: logger.hpp:38
#define NFD_LOG_INIT(name)
Definition: logger.hpp:31
UnsolicitedDataDecision
a decision made by UnsolicitedDataPolicy
virtual void afterReceiveData(const shared_ptr< pit::Entry > &pitEntry, const FaceEndpoint &ingress, const Data &data)
trigger after Data is received
Definition: strategy.cpp:170
void startProcessInterest(const FaceEndpoint &ingress, const Interest &interest)
start incoming Interest processing
Definition: forwarder.hpp:111
the Data should be cached in the ContentStore
bool isInProducerRegion(const DelegationList &forwardingHint) const
determines whether an Interest has reached a producer region
An unordered iterable of all PIT entries matching Data.
time::milliseconds dataFreshnessPeriod
Data freshness period.
Definition: pit-entry.hpp:238
void startProcessNack(const FaceEndpoint &ingress, const lp::Nack &nack)
start incoming Nack processing
Definition: forwarder.hpp:131
const OutRecordCollection & getOutRecords() const
Definition: pit-entry.hpp:160
const FaceId FACEID_CONTENT_STORE
identifies a packet comes from the ContentStore
Definition: face.hpp:46
const FaceId INVALID_FACEID
indicates an invalid FaceId
Definition: face.hpp:42
const Name & getName() const
Definition: pit-entry.hpp:78
virtual void beforeSatisfyInterest(const shared_ptr< pit::Entry > &pitEntry, const FaceEndpoint &ingress, const Data &data)
trigger before PIT entry is satisfied
Definition: strategy.cpp:152