blob: 340eec723a25813127b04868dc0f945cd6327d7e [file] [log] [blame]
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento0f830802018-01-16 23:58:58 -05002/*
Junxiao Shi07115cc2019-01-23 19:00:59 +00003 * Copyright (c) 2014-2019 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.
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
Davide Pesavento7e780642018-11-24 15:51:34 -050031#include "ndn-cxx/face.hpp"
32#include "ndn-cxx/util/concepts.hpp"
33#include "ndn-cxx/util/scheduler.hpp"
Davide Pesavento7e780642018-11-24 15:51:34 -050034#include "ndn-cxx/util/signal.hpp"
35#include "ndn-cxx/util/time.hpp"
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070036
37namespace ndn {
38namespace util {
39
Junxiao Shi18244e82016-12-03 15:42:01 +000040class NotificationSubscriberBase : noncopyable
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070041{
42public:
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070043 virtual
Junxiao Shi18244e82016-12-03 15:42:01 +000044 ~NotificationSubscriberBase();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070045
46 /** \return InterestLifetime of Interests to retrieve notifications
Junxiao Shi18244e82016-12-03 15:42:01 +000047 *
48 * This must be greater than FreshnessPeriod of Notification Data packets,
49 * to ensure correct operation of this subscriber implementation.
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070050 */
51 time::milliseconds
52 getInterestLifetime() const
53 {
54 return m_interestLifetime;
55 }
56
57 bool
58 isRunning() const
59 {
60 return m_isRunning;
61 }
62
63 /** \brief start or resume receiving notifications
64 * \note onNotification must have at least one listener,
65 * otherwise this operation has no effect.
66 */
67 void
Junxiao Shi18244e82016-12-03 15:42:01 +000068 start();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070069
70 /** \brief stop receiving notifications
71 */
72 void
Junxiao Shi18244e82016-12-03 15:42:01 +000073 stop();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070074
Junxiao Shi18244e82016-12-03 15:42:01 +000075protected:
76 /** \brief construct a NotificationSubscriber
77 * \note The subscriber is not started after construction.
78 * User should add one or more handlers to onNotification, and invoke .start().
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070079 */
Junxiao Shi18244e82016-12-03 15:42:01 +000080 NotificationSubscriberBase(Face& face, const Name& prefix,
81 time::milliseconds interestLifetime);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070082
83private:
84 void
Junxiao Shi18244e82016-12-03 15:42:01 +000085 sendInitialInterest();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070086
87 void
Junxiao Shi18244e82016-12-03 15:42:01 +000088 sendNextInterest();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070089
Junxiao Shi946a51c2018-11-24 00:25:57 +000090 void
91 sendInterest(const Interest& interest);
92
Junxiao Shi18244e82016-12-03 15:42:01 +000093 virtual bool
94 hasSubscriber() const = 0;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070095
96 /** \brief Check if the subscriber is or should be stopped.
97 * \return true if the subscriber is stopped.
98 */
99 bool
Junxiao Shi18244e82016-12-03 15:42:01 +0000100 shouldStop();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700101
102 void
Junxiao Shi18244e82016-12-03 15:42:01 +0000103 afterReceiveData(const Data& data);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700104
Junxiao Shi18244e82016-12-03 15:42:01 +0000105 /** \brief decode the Data as a notification, and deliver it to subscribers
106 * \return whether decode was successful
107 */
108 virtual bool
109 decodeAndDeliver(const Data& data) = 0;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700110
111 void
Junxiao Shi18244e82016-12-03 15:42:01 +0000112 afterReceiveNack(const lp::Nack& nack);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700113
114 void
Junxiao Shi18244e82016-12-03 15:42:01 +0000115 afterTimeout();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700116
Teng Liangf8bf1b02016-07-17 11:54:19 -0700117 time::milliseconds
Junxiao Shi18244e82016-12-03 15:42:01 +0000118 exponentialBackoff(lp::Nack nack);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700119
Junxiao Shi18244e82016-12-03 15:42:01 +0000120public:
121 /** \brief fires when a NACK is received
122 */
123 signal::Signal<NotificationSubscriberBase, lp::Nack> onNack;
Teng Liangf8bf1b02016-07-17 11:54:19 -0700124
Junxiao Shi18244e82016-12-03 15:42:01 +0000125 /** \brief fires when no Notification is received within .getInterestLifetime period
126 */
127 signal::Signal<NotificationSubscriberBase> onTimeout;
Teng Liangf8bf1b02016-07-17 11:54:19 -0700128
Junxiao Shi18244e82016-12-03 15:42:01 +0000129 /** \brief fires when a Data packet in the Notification Stream cannot be decoded as Notification
130 */
131 signal::Signal<NotificationSubscriberBase, Data> onDecodeError;
Teng Liangf8bf1b02016-07-17 11:54:19 -0700132
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700133private:
134 Face& m_face;
135 Name m_prefix;
136 bool m_isRunning;
Junxiao Shi946a51c2018-11-24 00:25:57 +0000137 uint64_t m_lastSequenceNum;
138 uint64_t m_lastNackSequenceNum;
Teng Liangf8bf1b02016-07-17 11:54:19 -0700139 uint64_t m_attempts;
Davide Pesaventofd612312019-03-15 18:45:46 -0400140 Scheduler m_scheduler;
141 scheduler::ScopedEventId m_nackEvent;
Junxiao Shi4fdcb272019-02-11 15:05:46 -0700142 ScopedPendingInterestHandle m_lastInterest;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700143 time::milliseconds m_interestLifetime;
144};
145
Junxiao Shi18244e82016-12-03 15:42:01 +0000146/** \brief provides a subscriber of Notification Stream
147 * \sa https://redmine.named-data.net/projects/nfd/wiki/Notification
148 * \tparam Notification type of Notification item, appears in payload of Data packets
149 */
150template<typename Notification>
151class NotificationSubscriber : public NotificationSubscriberBase
152{
153public:
154 BOOST_CONCEPT_ASSERT((boost::DefaultConstructible<Notification>));
155 BOOST_CONCEPT_ASSERT((WireDecodable<Notification>));
156
157 /** \brief construct a NotificationSubscriber
158 * \note The subscriber is not started after construction.
159 * User should add one or more handlers to onNotification, and invoke .start().
160 */
161 NotificationSubscriber(Face& face, const Name& prefix,
Davide Pesavento0f830802018-01-16 23:58:58 -0500162 time::milliseconds interestLifetime = 1_min)
Junxiao Shi18244e82016-12-03 15:42:01 +0000163 : NotificationSubscriberBase(face, prefix, interestLifetime)
164 {
165 }
166
167public:
168 /** \brief fires when a Notification is received
169 * \note Removing all handlers will cause the subscriber to stop.
170 */
171 signal::Signal<NotificationSubscriber, Notification> onNotification;
172
173private:
Davide Pesavento57c07df2016-12-11 18:41:45 -0500174 bool
Junxiao Shi18244e82016-12-03 15:42:01 +0000175 hasSubscriber() const override
176 {
177 return !onNotification.isEmpty();
178 }
179
Davide Pesavento57c07df2016-12-11 18:41:45 -0500180 bool
Junxiao Shi18244e82016-12-03 15:42:01 +0000181 decodeAndDeliver(const Data& data) override
182 {
183 Notification notification;
184 try {
185 notification.wireDecode(data.getContent().blockFromValue());
186 }
187 catch (const tlv::Error&) {
188 return false;
189 }
190
191 onNotification(notification);
192 return true;
193 }
194};
195
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700196} // namespace util
197} // namespace ndn
198
199#endif // NDN_UTIL_NOTIFICATION_SUBSCRIBER_HPP