blob: f72aa58bf4b2d6ae610b6ec13497a5a17d4bda8d [file] [log] [blame]
Junxiao Shi18244e82016-12-03 15:42:01 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento5afbb0b2018-01-01 17:24:18 -05002/*
3 * Copyright (c) 2014-2018 Regents of the University of California,
Davide Pesaventob5f8bcc2017-02-05 17:58:05 -05004 * 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.
Junxiao Shi18244e82016-12-03 15:42:01 +000010 *
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
Junxiao Shi18244e82016-12-03 15:42:01 +000028#include "notification-subscriber.hpp"
29#include "random.hpp"
30
Davide Pesavento5afbb0b2018-01-01 17:24:18 -050031#include <cmath>
32
Junxiao Shi18244e82016-12-03 15:42:01 +000033namespace ndn {
34namespace util {
35
36NotificationSubscriberBase::NotificationSubscriberBase(Face& face, const Name& prefix,
37 time::milliseconds interestLifetime)
38 : m_face(face)
39 , m_prefix(prefix)
40 , m_isRunning(false)
41 , m_lastSequenceNo(std::numeric_limits<uint64_t>::max())
42 , m_lastNackSequenceNo(std::numeric_limits<uint64_t>::max())
43 , m_attempts(1)
44 , m_scheduler(face.getIoService())
45 , m_nackEvent(m_scheduler)
Davide Pesaventodb4da5e2018-06-15 11:37:52 -040046 , m_lastInterestId(nullptr)
Junxiao Shi18244e82016-12-03 15:42:01 +000047 , m_interestLifetime(interestLifetime)
48{
49}
50
51NotificationSubscriberBase::~NotificationSubscriberBase() = default;
52
53void
54NotificationSubscriberBase::start()
55{
56 if (m_isRunning) // already running
57 return;
58 m_isRunning = true;
59
Davide Pesaventodb4da5e2018-06-15 11:37:52 -040060 sendInitialInterest();
Junxiao Shi18244e82016-12-03 15:42:01 +000061}
62
63void
64NotificationSubscriberBase::stop()
65{
66 if (!m_isRunning) // not running
67 return;
68 m_isRunning = false;
69
Davide Pesaventodb4da5e2018-06-15 11:37:52 -040070 if (m_lastInterestId != nullptr)
Junxiao Shi18244e82016-12-03 15:42:01 +000071 m_face.removePendingInterest(m_lastInterestId);
Davide Pesaventodb4da5e2018-06-15 11:37:52 -040072 m_lastInterestId = nullptr;
Junxiao Shi18244e82016-12-03 15:42:01 +000073}
74
75void
76NotificationSubscriberBase::sendInitialInterest()
77{
Davide Pesaventodb4da5e2018-06-15 11:37:52 -040078 if (shouldStop())
Junxiao Shi18244e82016-12-03 15:42:01 +000079 return;
80
81 auto interest = make_shared<Interest>(m_prefix);
Junxiao Shib55e5d32018-07-18 13:32:00 -060082 interest->setCanBePrefix(true);
Junxiao Shi18244e82016-12-03 15:42:01 +000083 interest->setMustBeFresh(true);
84 interest->setChildSelector(1);
85 interest->setInterestLifetime(getInterestLifetime());
86
87 m_lastInterestId = m_face.expressInterest(*interest,
Davide Pesaventodb4da5e2018-06-15 11:37:52 -040088 [this] (const auto&, const auto& d) { this->afterReceiveData(d); },
89 [this] (const auto&, const auto& n) { this->afterReceiveNack(n); },
90 [this] (const auto&) { this->afterTimeout(); });
Junxiao Shi18244e82016-12-03 15:42:01 +000091}
92
93void
94NotificationSubscriberBase::sendNextInterest()
95{
Davide Pesaventodb4da5e2018-06-15 11:37:52 -040096 if (shouldStop())
Junxiao Shi18244e82016-12-03 15:42:01 +000097 return;
98
99 BOOST_ASSERT(m_lastSequenceNo != std::numeric_limits<uint64_t>::max()); // overflow or missing initial reply
100
101 Name nextName = m_prefix;
102 nextName.appendSequenceNumber(m_lastSequenceNo + 1);
103
104 auto interest = make_shared<Interest>(nextName);
Junxiao Shib55e5d32018-07-18 13:32:00 -0600105 interest->setCanBePrefix(false);
Junxiao Shi18244e82016-12-03 15:42:01 +0000106 interest->setInterestLifetime(getInterestLifetime());
107
108 m_lastInterestId = m_face.expressInterest(*interest,
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400109 [this] (const auto&, const auto& d) { this->afterReceiveData(d); },
110 [this] (const auto&, const auto& n) { this->afterReceiveNack(n); },
111 [this] (const auto&) { this->afterTimeout(); });
Junxiao Shi18244e82016-12-03 15:42:01 +0000112}
113
114bool
115NotificationSubscriberBase::shouldStop()
116{
117 if (!m_isRunning)
118 return true;
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400119
120 if (!hasSubscriber() && onNack.isEmpty()) {
121 stop();
Junxiao Shi18244e82016-12-03 15:42:01 +0000122 return true;
123 }
124 return false;
125}
126
127void
128NotificationSubscriberBase::afterReceiveData(const Data& data)
129{
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400130 if (shouldStop())
Junxiao Shi18244e82016-12-03 15:42:01 +0000131 return;
132
133 try {
134 m_lastSequenceNo = data.getName().get(-1).toSequenceNumber();
135 }
136 catch (const tlv::Error&) {
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400137 onDecodeError(data);
138 sendInitialInterest();
Junxiao Shi18244e82016-12-03 15:42:01 +0000139 return;
140 }
141
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400142 if (!decodeAndDeliver(data)) {
143 onDecodeError(data);
144 sendInitialInterest();
Junxiao Shi18244e82016-12-03 15:42:01 +0000145 return;
146 }
147
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400148 sendNextInterest();
Junxiao Shi18244e82016-12-03 15:42:01 +0000149}
150
151void
152NotificationSubscriberBase::afterReceiveNack(const lp::Nack& nack)
153{
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400154 if (shouldStop())
Junxiao Shi18244e82016-12-03 15:42:01 +0000155 return;
156
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400157 onNack(nack);
Junxiao Shi18244e82016-12-03 15:42:01 +0000158
159 time::milliseconds delay = exponentialBackoff(nack);
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400160 m_nackEvent = m_scheduler.scheduleEvent(delay, [this] { sendInitialInterest(); });
Junxiao Shi18244e82016-12-03 15:42:01 +0000161}
162
163void
164NotificationSubscriberBase::afterTimeout()
165{
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400166 if (shouldStop())
Junxiao Shi18244e82016-12-03 15:42:01 +0000167 return;
168
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400169 onTimeout();
Junxiao Shi18244e82016-12-03 15:42:01 +0000170
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400171 sendInitialInterest();
Junxiao Shi18244e82016-12-03 15:42:01 +0000172}
173
174time::milliseconds
175NotificationSubscriberBase::exponentialBackoff(lp::Nack nack)
176{
177 uint64_t nackSequenceNo;
Junxiao Shi18244e82016-12-03 15:42:01 +0000178 try {
179 nackSequenceNo = nack.getInterest().getName().get(-1).toSequenceNumber();
180 }
181 catch (const tlv::Error&) {
182 nackSequenceNo = 0;
183 }
184
185 if (m_lastNackSequenceNo == nackSequenceNo) {
186 ++m_attempts;
187 }
188 else {
189 m_attempts = 1;
190 }
191
192 m_lastNackSequenceNo = nackSequenceNo;
193
Davide Pesavento5afbb0b2018-01-01 17:24:18 -0500194 return time::milliseconds(static_cast<time::milliseconds::rep>(std::pow(2, m_attempts) * 100 +
195 random::generateWord32() % 100));
Junxiao Shi18244e82016-12-03 15:42:01 +0000196}
197
198} // namespace util
199} // namespace ndn