blob: e69800ac0f13d57d837ca50667df9417f279bf04 [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);
82 interest->setMustBeFresh(true);
83 interest->setChildSelector(1);
84 interest->setInterestLifetime(getInterestLifetime());
85
86 m_lastInterestId = m_face.expressInterest(*interest,
Davide Pesaventodb4da5e2018-06-15 11:37:52 -040087 [this] (const auto&, const auto& d) { this->afterReceiveData(d); },
88 [this] (const auto&, const auto& n) { this->afterReceiveNack(n); },
89 [this] (const auto&) { this->afterTimeout(); });
Junxiao Shi18244e82016-12-03 15:42:01 +000090}
91
92void
93NotificationSubscriberBase::sendNextInterest()
94{
Davide Pesaventodb4da5e2018-06-15 11:37:52 -040095 if (shouldStop())
Junxiao Shi18244e82016-12-03 15:42:01 +000096 return;
97
98 BOOST_ASSERT(m_lastSequenceNo != std::numeric_limits<uint64_t>::max()); // overflow or missing initial reply
99
100 Name nextName = m_prefix;
101 nextName.appendSequenceNumber(m_lastSequenceNo + 1);
102
103 auto interest = make_shared<Interest>(nextName);
104 interest->setInterestLifetime(getInterestLifetime());
105
106 m_lastInterestId = m_face.expressInterest(*interest,
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400107 [this] (const auto&, const auto& d) { this->afterReceiveData(d); },
108 [this] (const auto&, const auto& n) { this->afterReceiveNack(n); },
109 [this] (const auto&) { this->afterTimeout(); });
Junxiao Shi18244e82016-12-03 15:42:01 +0000110}
111
112bool
113NotificationSubscriberBase::shouldStop()
114{
115 if (!m_isRunning)
116 return true;
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400117
118 if (!hasSubscriber() && onNack.isEmpty()) {
119 stop();
Junxiao Shi18244e82016-12-03 15:42:01 +0000120 return true;
121 }
122 return false;
123}
124
125void
126NotificationSubscriberBase::afterReceiveData(const Data& data)
127{
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400128 if (shouldStop())
Junxiao Shi18244e82016-12-03 15:42:01 +0000129 return;
130
131 try {
132 m_lastSequenceNo = data.getName().get(-1).toSequenceNumber();
133 }
134 catch (const tlv::Error&) {
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400135 onDecodeError(data);
136 sendInitialInterest();
Junxiao Shi18244e82016-12-03 15:42:01 +0000137 return;
138 }
139
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400140 if (!decodeAndDeliver(data)) {
141 onDecodeError(data);
142 sendInitialInterest();
Junxiao Shi18244e82016-12-03 15:42:01 +0000143 return;
144 }
145
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400146 sendNextInterest();
Junxiao Shi18244e82016-12-03 15:42:01 +0000147}
148
149void
150NotificationSubscriberBase::afterReceiveNack(const lp::Nack& nack)
151{
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400152 if (shouldStop())
Junxiao Shi18244e82016-12-03 15:42:01 +0000153 return;
154
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400155 onNack(nack);
Junxiao Shi18244e82016-12-03 15:42:01 +0000156
157 time::milliseconds delay = exponentialBackoff(nack);
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400158 m_nackEvent = m_scheduler.scheduleEvent(delay, [this] { sendInitialInterest(); });
Junxiao Shi18244e82016-12-03 15:42:01 +0000159}
160
161void
162NotificationSubscriberBase::afterTimeout()
163{
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400164 if (shouldStop())
Junxiao Shi18244e82016-12-03 15:42:01 +0000165 return;
166
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400167 onTimeout();
Junxiao Shi18244e82016-12-03 15:42:01 +0000168
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400169 sendInitialInterest();
Junxiao Shi18244e82016-12-03 15:42:01 +0000170}
171
172time::milliseconds
173NotificationSubscriberBase::exponentialBackoff(lp::Nack nack)
174{
175 uint64_t nackSequenceNo;
Junxiao Shi18244e82016-12-03 15:42:01 +0000176 try {
177 nackSequenceNo = nack.getInterest().getName().get(-1).toSequenceNumber();
178 }
179 catch (const tlv::Error&) {
180 nackSequenceNo = 0;
181 }
182
183 if (m_lastNackSequenceNo == nackSequenceNo) {
184 ++m_attempts;
185 }
186 else {
187 m_attempts = 1;
188 }
189
190 m_lastNackSequenceNo = nackSequenceNo;
191
Davide Pesavento5afbb0b2018-01-01 17:24:18 -0500192 return time::milliseconds(static_cast<time::milliseconds::rep>(std::pow(2, m_attempts) * 100 +
193 random::generateWord32() % 100));
Junxiao Shi18244e82016-12-03 15:42:01 +0000194}
195
196} // namespace util
197} // namespace ndn