blob: 9387a24884585986f0007746ff6334f5434ba35e [file] [log] [blame]
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Davide Pesaventob5f8bcc2017-02-05 17:58:05 -05003 * Copyright (c) 2014-2016 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.
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070010 *
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
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070028#ifndef NDN_UTIL_NOTIFICATION_SUBSCRIBER_HPP
29#define NDN_UTIL_NOTIFICATION_SUBSCRIBER_HPP
30
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070031#include "../face.hpp"
Junxiao Shi728873f2015-01-20 16:01:26 -070032#include "signal.hpp"
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070033#include "concepts.hpp"
Teng Liangf8bf1b02016-07-17 11:54:19 -070034#include "time.hpp"
Teng Liangf8bf1b02016-07-17 11:54:19 -070035#include "scheduler.hpp"
36#include "scheduler-scoped-event-id.hpp"
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070037#include <boost/concept_check.hpp>
38
39namespace ndn {
40namespace util {
41
Junxiao Shi18244e82016-12-03 15:42:01 +000042class NotificationSubscriberBase : noncopyable
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070043{
44public:
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070045 virtual
Junxiao Shi18244e82016-12-03 15:42:01 +000046 ~NotificationSubscriberBase();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070047
48 /** \return InterestLifetime of Interests to retrieve notifications
Junxiao Shi18244e82016-12-03 15:42:01 +000049 *
50 * This must be greater than FreshnessPeriod of Notification Data packets,
51 * to ensure correct operation of this subscriber implementation.
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070052 */
53 time::milliseconds
54 getInterestLifetime() const
55 {
56 return m_interestLifetime;
57 }
58
59 bool
60 isRunning() const
61 {
62 return m_isRunning;
63 }
64
65 /** \brief start or resume receiving notifications
66 * \note onNotification must have at least one listener,
67 * otherwise this operation has no effect.
68 */
69 void
Junxiao Shi18244e82016-12-03 15:42:01 +000070 start();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070071
72 /** \brief stop receiving notifications
73 */
74 void
Junxiao Shi18244e82016-12-03 15:42:01 +000075 stop();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070076
Junxiao Shi18244e82016-12-03 15:42:01 +000077protected:
78 /** \brief construct a NotificationSubscriber
79 * \note The subscriber is not started after construction.
80 * User should add one or more handlers to onNotification, and invoke .start().
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070081 */
Junxiao Shi18244e82016-12-03 15:42:01 +000082 NotificationSubscriberBase(Face& face, const Name& prefix,
83 time::milliseconds interestLifetime);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070084
85private:
86 void
Junxiao Shi18244e82016-12-03 15:42:01 +000087 sendInitialInterest();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070088
89 void
Junxiao Shi18244e82016-12-03 15:42:01 +000090 sendNextInterest();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070091
Junxiao Shi18244e82016-12-03 15:42:01 +000092 virtual bool
93 hasSubscriber() const = 0;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070094
95 /** \brief Check if the subscriber is or should be stopped.
96 * \return true if the subscriber is stopped.
97 */
98 bool
Junxiao Shi18244e82016-12-03 15:42:01 +000099 shouldStop();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700100
101 void
Junxiao Shi18244e82016-12-03 15:42:01 +0000102 afterReceiveData(const Data& data);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700103
Junxiao Shi18244e82016-12-03 15:42:01 +0000104 /** \brief decode the Data as a notification, and deliver it to subscribers
105 * \return whether decode was successful
106 */
107 virtual bool
108 decodeAndDeliver(const Data& data) = 0;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700109
110 void
Junxiao Shi18244e82016-12-03 15:42:01 +0000111 afterReceiveNack(const lp::Nack& nack);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700112
113 void
Junxiao Shi18244e82016-12-03 15:42:01 +0000114 afterTimeout();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700115
Teng Liangf8bf1b02016-07-17 11:54:19 -0700116 time::milliseconds
Junxiao Shi18244e82016-12-03 15:42:01 +0000117 exponentialBackoff(lp::Nack nack);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700118
Junxiao Shi18244e82016-12-03 15:42:01 +0000119public:
120 /** \brief fires when a NACK is received
121 */
122 signal::Signal<NotificationSubscriberBase, lp::Nack> onNack;
Teng Liangf8bf1b02016-07-17 11:54:19 -0700123
Junxiao Shi18244e82016-12-03 15:42:01 +0000124 /** \brief fires when no Notification is received within .getInterestLifetime period
125 */
126 signal::Signal<NotificationSubscriberBase> onTimeout;
Teng Liangf8bf1b02016-07-17 11:54:19 -0700127
Junxiao Shi18244e82016-12-03 15:42:01 +0000128 /** \brief fires when a Data packet in the Notification Stream cannot be decoded as Notification
129 */
130 signal::Signal<NotificationSubscriberBase, Data> onDecodeError;
Teng Liangf8bf1b02016-07-17 11:54:19 -0700131
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700132private:
133 Face& m_face;
134 Name m_prefix;
135 bool m_isRunning;
136 uint64_t m_lastSequenceNo;
Teng Liangf8bf1b02016-07-17 11:54:19 -0700137 uint64_t m_lastNackSequenceNo;
138 uint64_t m_attempts;
139 util::scheduler::Scheduler m_scheduler;
140 util::scheduler::ScopedEventId m_nackEvent;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700141 const PendingInterestId* m_lastInterestId;
142 time::milliseconds m_interestLifetime;
143};
144
Junxiao Shi18244e82016-12-03 15:42:01 +0000145/** \brief provides a subscriber of Notification Stream
146 * \sa https://redmine.named-data.net/projects/nfd/wiki/Notification
147 * \tparam Notification type of Notification item, appears in payload of Data packets
148 */
149template<typename Notification>
150class NotificationSubscriber : public NotificationSubscriberBase
151{
152public:
153 BOOST_CONCEPT_ASSERT((boost::DefaultConstructible<Notification>));
154 BOOST_CONCEPT_ASSERT((WireDecodable<Notification>));
155
156 /** \brief construct a NotificationSubscriber
157 * \note The subscriber is not started after construction.
158 * User should add one or more handlers to onNotification, and invoke .start().
159 */
160 NotificationSubscriber(Face& face, const Name& prefix,
161 time::milliseconds interestLifetime = time::seconds(60))
162 : NotificationSubscriberBase(face, prefix, interestLifetime)
163 {
164 }
165
166public:
167 /** \brief fires when a Notification is received
168 * \note Removing all handlers will cause the subscriber to stop.
169 */
170 signal::Signal<NotificationSubscriber, Notification> onNotification;
171
172private:
Davide Pesavento57c07df2016-12-11 18:41:45 -0500173 bool
Junxiao Shi18244e82016-12-03 15:42:01 +0000174 hasSubscriber() const override
175 {
176 return !onNotification.isEmpty();
177 }
178
Davide Pesavento57c07df2016-12-11 18:41:45 -0500179 bool
Junxiao Shi18244e82016-12-03 15:42:01 +0000180 decodeAndDeliver(const Data& data) override
181 {
182 Notification notification;
183 try {
184 notification.wireDecode(data.getContent().blockFromValue());
185 }
186 catch (const tlv::Error&) {
187 return false;
188 }
189
190 onNotification(notification);
191 return true;
192 }
193};
194
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700195} // namespace util
196} // namespace ndn
197
198#endif // NDN_UTIL_NOTIFICATION_SUBSCRIBER_HPP