NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.3: 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; -*- */
29 #include "random.hpp"
30 
31 namespace ndn {
32 namespace util {
33 
35  time::milliseconds interestLifetime)
36  : m_face(face)
37  , m_prefix(prefix)
38  , m_isRunning(false)
39  , m_lastSequenceNo(std::numeric_limits<uint64_t>::max())
40  , m_lastNackSequenceNo(std::numeric_limits<uint64_t>::max())
41  , m_attempts(1)
42  , m_scheduler(face.getIoService())
43  , m_nackEvent(m_scheduler)
44  , m_interestLifetime(interestLifetime)
45 {
46 }
47 
49 
50 void
52 {
53  if (m_isRunning) // already running
54  return;
55  m_isRunning = true;
56 
57  this->sendInitialInterest();
58 }
59 
60 void
62 {
63  if (!m_isRunning) // not running
64  return;
65  m_isRunning = false;
66 
67  if (m_lastInterestId != 0)
68  m_face.removePendingInterest(m_lastInterestId);
69  m_lastInterestId = 0;
70 }
71 
72 void
73 NotificationSubscriberBase::sendInitialInterest()
74 {
75  if (this->shouldStop())
76  return;
77 
78  auto interest = make_shared<Interest>(m_prefix);
79  interest->setMustBeFresh(true);
80  interest->setChildSelector(1);
81  interest->setInterestLifetime(getInterestLifetime());
82 
83  m_lastInterestId = m_face.expressInterest(*interest,
84  bind(&NotificationSubscriberBase::afterReceiveData, this, _2),
85  bind(&NotificationSubscriberBase::afterReceiveNack, this, _2),
86  bind(&NotificationSubscriberBase::afterTimeout, this));
87 }
88 
89 void
90 NotificationSubscriberBase::sendNextInterest()
91 {
92  if (this->shouldStop())
93  return;
94 
95  BOOST_ASSERT(m_lastSequenceNo != std::numeric_limits<uint64_t>::max()); // overflow or missing initial reply
96 
97  Name nextName = m_prefix;
98  nextName.appendSequenceNumber(m_lastSequenceNo + 1);
99 
100  auto interest = make_shared<Interest>(nextName);
101  interest->setInterestLifetime(getInterestLifetime());
102 
103  m_lastInterestId = m_face.expressInterest(*interest,
104  bind(&NotificationSubscriberBase::afterReceiveData, this, _2),
105  bind(&NotificationSubscriberBase::afterReceiveNack, this, _2),
106  bind(&NotificationSubscriberBase::afterTimeout, this));
107 }
108 
109 bool
110 NotificationSubscriberBase::shouldStop()
111 {
112  if (!m_isRunning)
113  return true;
114  if (!this->hasSubscriber() && onNack.isEmpty()) {
115  this->stop();
116  return true;
117  }
118  return false;
119 }
120 
121 void
122 NotificationSubscriberBase::afterReceiveData(const Data& data)
123 {
124  if (this->shouldStop())
125  return;
126 
127  try {
128  m_lastSequenceNo = data.getName().get(-1).toSequenceNumber();
129  }
130  catch (const tlv::Error&) {
131  this->onDecodeError(data);
132  this->sendInitialInterest();
133  return;
134  }
135 
136  if (!this->decodeAndDeliver(data)) {
137  this->onDecodeError(data);
138  this->sendInitialInterest();
139  return;
140  }
141 
142  this->sendNextInterest();
143 }
144 
145 void
146 NotificationSubscriberBase::afterReceiveNack(const lp::Nack& nack)
147 {
148  if (this->shouldStop())
149  return;
150 
151  this->onNack(nack);
152 
153  time::milliseconds delay = exponentialBackoff(nack);
154  m_nackEvent = m_scheduler.scheduleEvent(delay, [this] {this->sendInitialInterest();});
155 }
156 
157 void
158 NotificationSubscriberBase::afterTimeout()
159 {
160  if (this->shouldStop())
161  return;
162 
163  this->onTimeout();
164 
165  this->sendInitialInterest();
166 }
167 
169 NotificationSubscriberBase::exponentialBackoff(lp::Nack nack)
170 {
171  uint64_t nackSequenceNo;
172 
173  try {
174  nackSequenceNo = nack.getInterest().getName().get(-1).toSequenceNumber();
175  }
176  catch (const tlv::Error&) {
177  nackSequenceNo = 0;
178  }
179 
180  if (m_lastNackSequenceNo == nackSequenceNo) {
181  ++m_attempts;
182  }
183  else {
184  m_attempts = 1;
185  }
186 
187  m_lastNackSequenceNo = nackSequenceNo;
188 
189  return time::milliseconds(static_cast<uint32_t>(pow(2, m_attempts) * 100 +
190  random::generateWord32() % 100));
191 }
192 
193 } // namespace util
194 } // namespace ndn
void start()
start or resume receiving notifications
const Name & getName() const
Definition: interest.hpp:139
Copyright (c) 2011-2015 Regents of the University of California.
time::milliseconds getInterestLifetime() const
boost::posix_time::time_duration milliseconds(long duration)
Definition: asio.hpp:117
const Interest & getInterest() const
Definition: nack.hpp:53
STL namespace.
EventId scheduleEvent(const time::nanoseconds &after, const Event &event)
Schedule a one-time event after the specified delay.
Definition: scheduler.cpp:60
represents a Network Nack
Definition: nack.hpp:40
uint32_t generateWord32()
Generate a non-cryptographically-secure random integer in the range [0, 2^32)
Definition: random.cpp:63
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:95
void delay(websocketpp::connection_hdl, long duration)
Name & appendSequenceNumber(uint64_t seqNo)
Append a sequence number component.
Definition: name.hpp:406
Represents an absolute name.
Definition: name.hpp:42
const Name & getName() const
Get name.
Definition: data.hpp:121
signal::Signal< NotificationSubscriberBase, Data > onDecodeError
fires when a Data packet in the Notification Stream cannot be decoded as Notification ...
uint64_t toSequenceNumber() const
Interpret as sequence number component using NDN naming conventions.
const PendingInterestId * expressInterest(const Interest &interest, const DataCallback &afterSatisfied, const NackCallback &afterNacked, const TimeoutCallback &afterTimeout)
Express Interest.
Definition: face.cpp:144
Represents a Data packet.
Definition: data.hpp:35
const Component & get(ssize_t i) const
Get the component at the given index.
Definition: name.hpp:164
void removePendingInterest(const PendingInterestId *pendingInterestId)
Cancel previously expressed Interest.
Definition: face.cpp:161
represents an error in TLV encoding or decoding
Definition: tlv.hpp:50
NotificationSubscriberBase(Face &face, const Name &prefix, time::milliseconds interestLifetime)
construct a NotificationSubscriber
void stop()
stop receiving notifications