blob: bc7345ccd35eca90ef3b77cdc5af69cf8f1faaed [file] [log] [blame]
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Teng Liangf8bf1b02016-07-17 11:54:19 -07003 * Copyright (c) 2013-2016 Regents of the University of California.
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
22/**
23 * Original copyright notice from NFD:
24 *
25 * Copyright (c) 2014, Regents of the University of California,
26 * Arizona Board of Regents,
27 * Colorado State University,
28 * University Pierre & Marie Curie, Sorbonne University,
29 * Washington University in St. Louis,
30 * Beijing Institute of Technology,
31 * The University of Memphis
32 *
33 * This file is part of NFD (Named Data Networking Forwarding Daemon).
34 * See AUTHORS.md for complete list of NFD authors and contributors.
35 *
36 * NFD is free software: you can redistribute it and/or modify it under the terms
37 * of the GNU General Public License as published by the Free Software Foundation,
38 * either version 3 of the License, or (at your option) any later version.
39 *
40 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
41 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
42 * PURPOSE. See the GNU General Public License for more details.
43 *
44 * You should have received a copy of the GNU General Public License along with
45 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
46 */
47
48#ifndef NDN_UTIL_NOTIFICATION_SUBSCRIBER_HPP
49#define NDN_UTIL_NOTIFICATION_SUBSCRIBER_HPP
50
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070051#include "../face.hpp"
Junxiao Shi728873f2015-01-20 16:01:26 -070052#include "signal.hpp"
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070053#include "concepts.hpp"
Teng Liangf8bf1b02016-07-17 11:54:19 -070054#include "time.hpp"
Teng Liangf8bf1b02016-07-17 11:54:19 -070055#include "scheduler.hpp"
56#include "scheduler-scoped-event-id.hpp"
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070057#include <boost/concept_check.hpp>
58
59namespace ndn {
60namespace util {
61
Junxiao Shi18244e82016-12-03 15:42:01 +000062class NotificationSubscriberBase : noncopyable
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070063{
64public:
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070065 virtual
Junxiao Shi18244e82016-12-03 15:42:01 +000066 ~NotificationSubscriberBase();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070067
68 /** \return InterestLifetime of Interests to retrieve notifications
Junxiao Shi18244e82016-12-03 15:42:01 +000069 *
70 * This must be greater than FreshnessPeriod of Notification Data packets,
71 * to ensure correct operation of this subscriber implementation.
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070072 */
73 time::milliseconds
74 getInterestLifetime() const
75 {
76 return m_interestLifetime;
77 }
78
79 bool
80 isRunning() const
81 {
82 return m_isRunning;
83 }
84
85 /** \brief start or resume receiving notifications
86 * \note onNotification must have at least one listener,
87 * otherwise this operation has no effect.
88 */
89 void
Junxiao Shi18244e82016-12-03 15:42:01 +000090 start();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070091
92 /** \brief stop receiving notifications
93 */
94 void
Junxiao Shi18244e82016-12-03 15:42:01 +000095 stop();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070096
Junxiao Shi18244e82016-12-03 15:42:01 +000097protected:
98 /** \brief construct a NotificationSubscriber
99 * \note The subscriber is not started after construction.
100 * User should add one or more handlers to onNotification, and invoke .start().
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700101 */
Junxiao Shi18244e82016-12-03 15:42:01 +0000102 NotificationSubscriberBase(Face& face, const Name& prefix,
103 time::milliseconds interestLifetime);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700104
105private:
106 void
Junxiao Shi18244e82016-12-03 15:42:01 +0000107 sendInitialInterest();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700108
109 void
Junxiao Shi18244e82016-12-03 15:42:01 +0000110 sendNextInterest();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700111
Junxiao Shi18244e82016-12-03 15:42:01 +0000112 virtual bool
113 hasSubscriber() const = 0;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700114
115 /** \brief Check if the subscriber is or should be stopped.
116 * \return true if the subscriber is stopped.
117 */
118 bool
Junxiao Shi18244e82016-12-03 15:42:01 +0000119 shouldStop();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700120
121 void
Junxiao Shi18244e82016-12-03 15:42:01 +0000122 afterReceiveData(const Data& data);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700123
Junxiao Shi18244e82016-12-03 15:42:01 +0000124 /** \brief decode the Data as a notification, and deliver it to subscribers
125 * \return whether decode was successful
126 */
127 virtual bool
128 decodeAndDeliver(const Data& data) = 0;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700129
130 void
Junxiao Shi18244e82016-12-03 15:42:01 +0000131 afterReceiveNack(const lp::Nack& nack);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700132
133 void
Junxiao Shi18244e82016-12-03 15:42:01 +0000134 afterTimeout();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700135
Teng Liangf8bf1b02016-07-17 11:54:19 -0700136 time::milliseconds
Junxiao Shi18244e82016-12-03 15:42:01 +0000137 exponentialBackoff(lp::Nack nack);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700138
Junxiao Shi18244e82016-12-03 15:42:01 +0000139public:
140 /** \brief fires when a NACK is received
141 */
142 signal::Signal<NotificationSubscriberBase, lp::Nack> onNack;
Teng Liangf8bf1b02016-07-17 11:54:19 -0700143
Junxiao Shi18244e82016-12-03 15:42:01 +0000144 /** \brief fires when no Notification is received within .getInterestLifetime period
145 */
146 signal::Signal<NotificationSubscriberBase> onTimeout;
Teng Liangf8bf1b02016-07-17 11:54:19 -0700147
Junxiao Shi18244e82016-12-03 15:42:01 +0000148 /** \brief fires when a Data packet in the Notification Stream cannot be decoded as Notification
149 */
150 signal::Signal<NotificationSubscriberBase, Data> onDecodeError;
Teng Liangf8bf1b02016-07-17 11:54:19 -0700151
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700152private:
153 Face& m_face;
154 Name m_prefix;
155 bool m_isRunning;
156 uint64_t m_lastSequenceNo;
Teng Liangf8bf1b02016-07-17 11:54:19 -0700157 uint64_t m_lastNackSequenceNo;
158 uint64_t m_attempts;
159 util::scheduler::Scheduler m_scheduler;
160 util::scheduler::ScopedEventId m_nackEvent;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700161 const PendingInterestId* m_lastInterestId;
162 time::milliseconds m_interestLifetime;
163};
164
Junxiao Shi18244e82016-12-03 15:42:01 +0000165/** \brief provides a subscriber of Notification Stream
166 * \sa https://redmine.named-data.net/projects/nfd/wiki/Notification
167 * \tparam Notification type of Notification item, appears in payload of Data packets
168 */
169template<typename Notification>
170class NotificationSubscriber : public NotificationSubscriberBase
171{
172public:
173 BOOST_CONCEPT_ASSERT((boost::DefaultConstructible<Notification>));
174 BOOST_CONCEPT_ASSERT((WireDecodable<Notification>));
175
176 /** \brief construct a NotificationSubscriber
177 * \note The subscriber is not started after construction.
178 * User should add one or more handlers to onNotification, and invoke .start().
179 */
180 NotificationSubscriber(Face& face, const Name& prefix,
181 time::milliseconds interestLifetime = time::seconds(60))
182 : NotificationSubscriberBase(face, prefix, interestLifetime)
183 {
184 }
185
186public:
187 /** \brief fires when a Notification is received
188 * \note Removing all handlers will cause the subscriber to stop.
189 */
190 signal::Signal<NotificationSubscriber, Notification> onNotification;
191
192private:
193 virtual bool
194 hasSubscriber() const override
195 {
196 return !onNotification.isEmpty();
197 }
198
199 virtual bool
200 decodeAndDeliver(const Data& data) override
201 {
202 Notification notification;
203 try {
204 notification.wireDecode(data.getContent().blockFromValue());
205 }
206 catch (const tlv::Error&) {
207 return false;
208 }
209
210 onNotification(notification);
211 return true;
212 }
213};
214
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700215} // namespace util
216} // namespace ndn
217
218#endif // NDN_UTIL_NOTIFICATION_SUBSCRIBER_HPP