blob: be36d31e682ca53f9b88a77b7e47371c2c9e1fd4 [file] [log] [blame]
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Davide Pesaventoe1789892017-02-26 15:50:52 -05003 * Copyright (c) 2014-2017 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
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
38namespace ndn {
39namespace util {
40
Junxiao Shi18244e82016-12-03 15:42:01 +000041class NotificationSubscriberBase : noncopyable
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070042{
43public:
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070044 virtual
Junxiao Shi18244e82016-12-03 15:42:01 +000045 ~NotificationSubscriberBase();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070046
47 /** \return InterestLifetime of Interests to retrieve notifications
Junxiao Shi18244e82016-12-03 15:42:01 +000048 *
49 * This must be greater than FreshnessPeriod of Notification Data packets,
50 * to ensure correct operation of this subscriber implementation.
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070051 */
52 time::milliseconds
53 getInterestLifetime() const
54 {
55 return m_interestLifetime;
56 }
57
58 bool
59 isRunning() const
60 {
61 return m_isRunning;
62 }
63
64 /** \brief start or resume receiving notifications
65 * \note onNotification must have at least one listener,
66 * otherwise this operation has no effect.
67 */
68 void
Junxiao Shi18244e82016-12-03 15:42:01 +000069 start();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070070
71 /** \brief stop receiving notifications
72 */
73 void
Junxiao Shi18244e82016-12-03 15:42:01 +000074 stop();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070075
Junxiao Shi18244e82016-12-03 15:42:01 +000076protected:
77 /** \brief construct a NotificationSubscriber
78 * \note The subscriber is not started after construction.
79 * User should add one or more handlers to onNotification, and invoke .start().
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070080 */
Junxiao Shi18244e82016-12-03 15:42:01 +000081 NotificationSubscriberBase(Face& face, const Name& prefix,
82 time::milliseconds interestLifetime);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070083
84private:
85 void
Junxiao Shi18244e82016-12-03 15:42:01 +000086 sendInitialInterest();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070087
88 void
Junxiao Shi18244e82016-12-03 15:42:01 +000089 sendNextInterest();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070090
Junxiao Shi18244e82016-12-03 15:42:01 +000091 virtual bool
92 hasSubscriber() const = 0;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070093
94 /** \brief Check if the subscriber is or should be stopped.
95 * \return true if the subscriber is stopped.
96 */
97 bool
Junxiao Shi18244e82016-12-03 15:42:01 +000098 shouldStop();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070099
100 void
Junxiao Shi18244e82016-12-03 15:42:01 +0000101 afterReceiveData(const Data& data);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700102
Junxiao Shi18244e82016-12-03 15:42:01 +0000103 /** \brief decode the Data as a notification, and deliver it to subscribers
104 * \return whether decode was successful
105 */
106 virtual bool
107 decodeAndDeliver(const Data& data) = 0;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700108
109 void
Junxiao Shi18244e82016-12-03 15:42:01 +0000110 afterReceiveNack(const lp::Nack& nack);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700111
112 void
Junxiao Shi18244e82016-12-03 15:42:01 +0000113 afterTimeout();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700114
Teng Liangf8bf1b02016-07-17 11:54:19 -0700115 time::milliseconds
Junxiao Shi18244e82016-12-03 15:42:01 +0000116 exponentialBackoff(lp::Nack nack);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700117
Junxiao Shi18244e82016-12-03 15:42:01 +0000118public:
119 /** \brief fires when a NACK is received
120 */
121 signal::Signal<NotificationSubscriberBase, lp::Nack> onNack;
Teng Liangf8bf1b02016-07-17 11:54:19 -0700122
Junxiao Shi18244e82016-12-03 15:42:01 +0000123 /** \brief fires when no Notification is received within .getInterestLifetime period
124 */
125 signal::Signal<NotificationSubscriberBase> onTimeout;
Teng Liangf8bf1b02016-07-17 11:54:19 -0700126
Junxiao Shi18244e82016-12-03 15:42:01 +0000127 /** \brief fires when a Data packet in the Notification Stream cannot be decoded as Notification
128 */
129 signal::Signal<NotificationSubscriberBase, Data> onDecodeError;
Teng Liangf8bf1b02016-07-17 11:54:19 -0700130
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700131private:
132 Face& m_face;
133 Name m_prefix;
134 bool m_isRunning;
135 uint64_t m_lastSequenceNo;
Teng Liangf8bf1b02016-07-17 11:54:19 -0700136 uint64_t m_lastNackSequenceNo;
137 uint64_t m_attempts;
138 util::scheduler::Scheduler m_scheduler;
139 util::scheduler::ScopedEventId m_nackEvent;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700140 const PendingInterestId* m_lastInterestId;
141 time::milliseconds m_interestLifetime;
142};
143
Junxiao Shi18244e82016-12-03 15:42:01 +0000144/** \brief provides a subscriber of Notification Stream
145 * \sa https://redmine.named-data.net/projects/nfd/wiki/Notification
146 * \tparam Notification type of Notification item, appears in payload of Data packets
147 */
148template<typename Notification>
149class NotificationSubscriber : public NotificationSubscriberBase
150{
151public:
152 BOOST_CONCEPT_ASSERT((boost::DefaultConstructible<Notification>));
153 BOOST_CONCEPT_ASSERT((WireDecodable<Notification>));
154
155 /** \brief construct a NotificationSubscriber
156 * \note The subscriber is not started after construction.
157 * User should add one or more handlers to onNotification, and invoke .start().
158 */
159 NotificationSubscriber(Face& face, const Name& prefix,
160 time::milliseconds interestLifetime = time::seconds(60))
161 : NotificationSubscriberBase(face, prefix, interestLifetime)
162 {
163 }
164
165public:
166 /** \brief fires when a Notification is received
167 * \note Removing all handlers will cause the subscriber to stop.
168 */
169 signal::Signal<NotificationSubscriber, Notification> onNotification;
170
171private:
Davide Pesavento57c07df2016-12-11 18:41:45 -0500172 bool
Junxiao Shi18244e82016-12-03 15:42:01 +0000173 hasSubscriber() const override
174 {
175 return !onNotification.isEmpty();
176 }
177
Davide Pesavento57c07df2016-12-11 18:41:45 -0500178 bool
Junxiao Shi18244e82016-12-03 15:42:01 +0000179 decodeAndDeliver(const Data& data) override
180 {
181 Notification notification;
182 try {
183 notification.wireDecode(data.getContent().blockFromValue());
184 }
185 catch (const tlv::Error&) {
186 return false;
187 }
188
189 onNotification(notification);
190 return true;
191 }
192};
193
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700194} // namespace util
195} // namespace ndn
196
197#endif // NDN_UTIL_NOTIFICATION_SUBSCRIBER_HPP