NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.5: NDN, CCN, CCNx, content centric networks
API Documentation
notification-subscriber.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 ndn-cxx library (NDN C++ library with eXperimental eXtensions).
12  *
13  * ndn-cxx library is free software: you can redistribute it and/or modify it under the
14  * terms of the GNU Lesser General Public License as published by the Free Software
15  * Foundation, either version 3 of the License, or (at your option) any later version.
16  *
17  * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
18  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
19  * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
20  *
21  * You should have received copies of the GNU General Public License and GNU Lesser
22  * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
23  * <http://www.gnu.org/licenses/>.
24  *
25  * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
26  */
27 
29 #include "ndn-cxx/util/random.hpp"
30 
31 #include <cmath>
32 
33 namespace ndn {
34 namespace util {
35 
37  time::milliseconds interestLifetime)
38  : m_face(face)
39  , m_prefix(prefix)
40  , m_isRunning(false)
41  , m_lastSequenceNum(std::numeric_limits<uint64_t>::max())
42  , m_lastNackSequenceNum(std::numeric_limits<uint64_t>::max())
43  , m_attempts(1)
44  , m_scheduler(face.getIoService())
45  , m_lastInterestId(nullptr)
46  , m_interestLifetime(interestLifetime)
47 {
48 }
49 
51 
52 void
54 {
55  if (m_isRunning) // already running
56  return;
57  m_isRunning = true;
58 
59  sendInitialInterest();
60 }
61 
62 void
64 {
65  if (!m_isRunning) // not running
66  return;
67  m_isRunning = false;
68 
69  if (m_lastInterestId != nullptr)
70  m_face.removePendingInterest(m_lastInterestId);
71  m_lastInterestId = nullptr;
72 }
73 
74 void
75 NotificationSubscriberBase::sendInitialInterest()
76 {
77  if (shouldStop())
78  return;
79 
80  auto interest = make_shared<Interest>(m_prefix);
81  interest->setCanBePrefix(true);
82  interest->setMustBeFresh(true);
83  interest->setInterestLifetime(m_interestLifetime);
84  sendInterest(*interest);
85 }
86 
87 void
88 NotificationSubscriberBase::sendNextInterest()
89 {
90  if (shouldStop())
91  return;
92 
93  Name nextName = m_prefix;
94  nextName.appendSequenceNumber(m_lastSequenceNum + 1);
95 
96  auto interest = make_shared<Interest>(nextName);
97  interest->setCanBePrefix(false);
98  interest->setInterestLifetime(m_interestLifetime);
99  sendInterest(*interest);
100 }
101 
102 void
103 NotificationSubscriberBase::sendInterest(const Interest& interest)
104 {
105  m_lastInterestId = m_face.expressInterest(interest,
106  [this] (const auto&, const auto& d) { this->afterReceiveData(d); },
107  [this] (const auto&, const auto& n) { this->afterReceiveNack(n); },
108  [this] (const auto&) { this->afterTimeout(); });
109 }
110 
111 bool
112 NotificationSubscriberBase::shouldStop()
113 {
114  if (!m_isRunning)
115  return true;
116 
117  if (!hasSubscriber() && onNack.isEmpty()) {
118  stop();
119  return true;
120  }
121  return false;
122 }
123 
124 void
125 NotificationSubscriberBase::afterReceiveData(const Data& data)
126 {
127  if (shouldStop())
128  return;
129 
130  try {
131  m_lastSequenceNum = data.getName().get(-1).toSequenceNumber();
132  }
133  catch (const tlv::Error&) {
134  onDecodeError(data);
135  sendInitialInterest();
136  return;
137  }
138 
139  if (!decodeAndDeliver(data)) {
140  onDecodeError(data);
141  sendInitialInterest();
142  return;
143  }
144 
145  sendNextInterest();
146 }
147 
148 void
149 NotificationSubscriberBase::afterReceiveNack(const lp::Nack& nack)
150 {
151  if (shouldStop())
152  return;
153 
154  onNack(nack);
155 
156  time::milliseconds delay = exponentialBackoff(nack);
157  m_nackEvent = m_scheduler.scheduleEvent(delay, [this] { sendInitialInterest(); });
158 }
159 
160 void
161 NotificationSubscriberBase::afterTimeout()
162 {
163  if (shouldStop())
164  return;
165 
166  onTimeout();
167 
168  sendInitialInterest();
169 }
170 
171 time::milliseconds
172 NotificationSubscriberBase::exponentialBackoff(lp::Nack nack)
173 {
174  uint64_t nackSequenceNum;
175  try {
176  nackSequenceNum = nack.getInterest().getName().get(-1).toSequenceNumber();
177  }
178  catch (const tlv::Error&) {
179  nackSequenceNum = 0;
180  }
181 
182  if (m_lastNackSequenceNum == nackSequenceNum) {
183  ++m_attempts;
184  }
185  else {
186  m_attempts = 1;
187  }
188 
189  m_lastNackSequenceNum = nackSequenceNum;
190 
191  return time::milliseconds(static_cast<time::milliseconds::rep>(std::pow(2, m_attempts) * 100 +
192  random::generateWord32() % 100));
193 }
194 
195 } // namespace util
196 } // namespace ndn
void start()
start or resume receiving notifications
Copyright (c) 2011-2015 Regents of the University of California.
uint64_t toSequenceNumber() const
Interpret as sequence number component using NDN naming conventions.
const Component & get(ssize_t i) const
Get the component at the given index.
Definition: name.hpp:157
EventId scheduleEvent(time::nanoseconds after, const EventCallback &callback)
Schedule a one-time event after the specified delay.
Definition: scheduler.cpp:103
represents a Network Nack
Definition: nack.hpp:38
uint32_t generateWord32()
Generate a non-cryptographically-secure random integer in the range [0, 2^32)
Definition: random.cpp:66
signal::Signal< NotificationSubscriberBase, lp::Nack > onNack
fires when a NACK is received
signal::Signal< NotificationSubscriberBase > onTimeout
fires when no Notification is received within .getInterestLifetime period
Provide a communication channel with local or remote NDN forwarder.
Definition: face.hpp:93
Name & appendSequenceNumber(uint64_t seqNo)
Append a sequence number component.
Definition: name.hpp:399
Represents an absolute name.
Definition: name.hpp:43
PendingInterestHandle expressInterest(const Interest &interest, const DataCallback &afterSatisfied, const NackCallback &afterNacked, const TimeoutCallback &afterTimeout)
Express Interest.
Definition: face.cpp:131
signal::Signal< NotificationSubscriberBase, Data > onDecodeError
fires when a Data packet in the Notification Stream cannot be decoded as Notification
const Interest & getInterest() const
Definition: nack.hpp:51
void removePendingInterest(const PendingInterestId *pendingInterestId)
Cancel previously expressed Interest.
Definition: face.cpp:147
NotificationSubscriberBase(Face &face, const Name &prefix, time::milliseconds interestLifetime)
construct a NotificationSubscriber
const Name & getName() const
Definition: interest.hpp:134
void stop()
stop receiving notifications