From 15b12e759d4472f391fd9be1bfdfa92f9c2e1c81 Mon Sep 17 00:00:00 2001 From: Junxiao Shi Date: Sat, 9 Aug 2014 19:56:24 -0700 Subject: [PATCH] core: use markers in StatusDataset and NotificationStream This commit also refactors FaceMonitor as generic NotificationSubscriber, and refactors AutoregServer to use FaceMonitor. refs #1837 #1838 Change-Id: I8b40dfae118853d1224c8290cf92e7cc0daa116f --- core/event-emitter.hpp | 39 ++- core/face-monitor.cpp | 165 ------------- core/face-monitor.hpp | 85 ++----- {daemon/mgmt => core}/notification-stream.hpp | 84 ++++--- core/notification-subscriber.hpp | 214 +++++++++++++++++ core/segment-publisher.hpp | 57 +++-- daemon/mgmt/face-manager.cpp | 2 +- daemon/mgmt/face-manager.hpp | 4 +- rib/rib-manager.cpp | 4 +- tests/core/notification-stream.cpp | 69 ++++++ tests/core/notification-subscriber.cpp | 223 ++++++++++++++++++ tests/core/segment-publisher.cpp | 10 +- tests/core/simple-notification.hpp | 94 ++++++++ tests/daemon/mgmt/notification-stream.cpp | 142 ----------- .../{dummy-face.hpp => dummy-client-face.hpp} | 33 ++- tests/rib/rib-manager.cpp | 6 +- tests/rib/rib-status-publisher.cpp | 4 +- tools/nfd-autoreg.cpp | 52 +--- 18 files changed, 750 insertions(+), 537 deletions(-) delete mode 100644 core/face-monitor.cpp rename {daemon/mgmt => core}/notification-stream.hpp (55%) create mode 100644 core/notification-subscriber.hpp create mode 100644 tests/core/notification-stream.cpp create mode 100644 tests/core/notification-subscriber.cpp create mode 100644 tests/core/simple-notification.hpp delete mode 100644 tests/daemon/mgmt/notification-stream.cpp rename tests/{dummy-face.hpp => dummy-client-face.hpp} (73%) diff --git a/core/event-emitter.hpp b/core/event-emitter.hpp index 35925f98..e63e1111 100644 --- a/core/event-emitter.hpp +++ b/core/event-emitter.hpp @@ -1,11 +1,12 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** - * Copyright (c) 2014 Regents of the University of California, - * Arizona Board of Regents, - * Colorado State University, - * University Pierre & Marie Curie, Sorbonne University, - * Washington University in St. Louis, - * Beijing Institute of Technology + * Copyright (c) 2014, Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis * * This file is part of NFD (Named Data Networking Forwarding Daemon). * See AUTHORS.md for complete list of NFD authors and contributors. @@ -20,7 +21,7 @@ * * You should have received a copy of the GNU General Public License along with * NFD, e.g., in COPYING.md file. If not, see . - **/ + */ #ifndef NFD_CORE_EVENT_EMITTER_HPP #define NFD_CORE_EVENT_EMITTER_HPP @@ -29,25 +30,27 @@ namespace nfd { -struct empty {}; +struct empty +{ +}; /** \class EventEmitter * \brief provides a lightweight event system * * To declare an event: - * EventEmitter m_eventName; + * EventEmitter onEventName; * To subscribe to an event: - * eventSource->m_eventName += eventHandler; + * eventSource->onEventName += eventHandler; * Multiple functions can subscribe to the same event. * To trigger an event: - * m_eventName(args); + * onEventName(args); * To clear event subscriptions: - * m_eventName.clear(); + * onEventName.clear(); */ // four arguments template + typename T3 = empty, typename T4 = empty> class EventEmitter : noncopyable { public: @@ -199,6 +202,8 @@ EventEmitter::operator()() std::vector::iterator it; for (it = m_handlers.begin(); it != m_handlers.end(); ++it) { (*it)(); + if (m_handlers.empty()) // .clear has been called + return; } } @@ -232,6 +237,8 @@ EventEmitter::operator()(const T1& a1) typename std::vector::iterator it; for (it = m_handlers.begin(); it != m_handlers.end(); ++it) { (*it)(a1); + if (m_handlers.empty()) // .clear has been called + return; } } @@ -266,6 +273,8 @@ EventEmitter::operator() typename std::vector::iterator it; for (it = m_handlers.begin(); it != m_handlers.end(); ++it) { (*it)(a1, a2); + if (m_handlers.empty()) // .clear has been called + return; } } @@ -300,6 +309,8 @@ EventEmitter::operator() typename std::vector::iterator it; for (it = m_handlers.begin(); it != m_handlers.end(); ++it) { (*it)(a1, a2, a3); + if (m_handlers.empty()) // .clear has been called + return; } } @@ -334,6 +345,8 @@ EventEmitter::operator() typename std::vector::iterator it; for (it = m_handlers.begin(); it != m_handlers.end(); ++it) { (*it)(a1, a2, a3, a4); + if (m_handlers.empty()) // .clear has been called + return; } } diff --git a/core/face-monitor.cpp b/core/face-monitor.cpp deleted file mode 100644 index 914e3dfb..00000000 --- a/core/face-monitor.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2014 Regents of the University of California, - * Arizona Board of Regents, - * Colorado State University, - * University Pierre & Marie Curie, Sorbonne University, - * Washington University in St. Louis, - * Beijing Institute of Technology, - * The University of Memphis - * - * This file is part of NFD (Named Data Networking Forwarding Daemon). - * See AUTHORS.md for complete list of NFD authors and contributors. - * - * NFD is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Foundation, - * either version 3 of the License, or (at your option) any later version. - * - * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * NFD, e.g., in COPYING.md file. If not, see . - **/ - -#include "face-monitor.hpp" -#include "core/logger.hpp" - -#include - -namespace nfd { - -NFD_LOG_INIT("FaceMonitor"); - -FaceMonitor::FaceMonitor(ndn::Face& face) - : m_face(face) - , m_isStopped(true) -{ -} - -FaceMonitor::~FaceMonitor() -{ -} - -void -FaceMonitor::removeAllSubscribers() -{ - m_notificationCallbacks.clear(); - m_timeoutCallbacks.clear(); - stopNotifications(); -} - -void -FaceMonitor::stopNotifications() -{ - if (static_cast(m_lastInterestId)) - m_face.removePendingInterest(m_lastInterestId); - m_isStopped = true; -} - -void -FaceMonitor::startNotifications() -{ - if (m_isStopped == false) - return; // Notifications cycle has been started. - m_isStopped = false; - - Interest interest("/localhost/nfd/faces/events"); - interest - .setMustBeFresh(true) - .setChildSelector(1) - .setInterestLifetime(time::seconds(60)) - ; - - NFD_LOG_DEBUG("startNotification: Interest Sent: " << interest); - - m_lastInterestId = m_face.expressInterest(interest, - bind(&FaceMonitor::onNotification, this, _2), - bind(&FaceMonitor::onTimeout, this)); -} - -void -FaceMonitor::addSubscriber(const NotificationCallback& notificationCallback) -{ - addSubscriber(notificationCallback, TimeoutCallback()); -} - -void -FaceMonitor::addSubscriber(const NotificationCallback& notificationCallback, - const TimeoutCallback& timeoutCallback) -{ - if (static_cast(notificationCallback)) - m_notificationCallbacks.push_back(notificationCallback); - - if (static_cast(timeoutCallback)) - m_timeoutCallbacks.push_back(timeoutCallback); -} - -void -FaceMonitor::onTimeout() -{ - if (m_isStopped) - return; - - std::vector::iterator it; - for (it = m_timeoutCallbacks.begin(); - it != m_timeoutCallbacks.end(); ++it) { - (*it)(); - //One of the registered callbacks has cleared the vector, - //return now as the iterator has been invalidated and - //the vector is empty. - if (m_timeoutCallbacks.empty()) { - return; - } - } - - Interest newInterest("/localhost/nfd/faces/events"); - newInterest - .setMustBeFresh(true) - .setChildSelector(1) - .setInterestLifetime(time::seconds(60)) - ; - - NFD_LOG_DEBUG("In onTimeout, sending interest: " << newInterest); - - m_lastInterestId = m_face.expressInterest(newInterest, - bind(&FaceMonitor::onNotification, this, _2), - bind(&FaceMonitor::onTimeout, this)); -} - -void -FaceMonitor::onNotification(const Data& data) -{ - if (m_isStopped) - return; - - m_lastSequence = data.getName().get(-1).toSegment(); - ndn::nfd::FaceEventNotification notification(data.getContent().blockFromValue()); - - std::vector::iterator it; - for (it = m_notificationCallbacks.begin(); - it != m_notificationCallbacks.end(); ++it) { - (*it)(notification); - if (m_notificationCallbacks.empty()) { - //One of the registered callbacks has cleared the vector. - //return back, as no one is interested in notifications anymore. - return; - } - } - - //Setting up next notification - Name nextNotification("/localhost/nfd/faces/events"); - nextNotification.appendSegment(m_lastSequence + 1); - - Interest interest(nextNotification); - interest.setInterestLifetime(time::seconds(60)); - - NFD_LOG_DEBUG("onNotification: Interest sent: " << interest); - - m_lastInterestId = m_face.expressInterest(interest, - bind(&FaceMonitor::onNotification, this, _2), - bind(&FaceMonitor::onTimeout, this)); -} - -} // namespace nfd diff --git a/core/face-monitor.hpp b/core/face-monitor.hpp index 459b1816..521fc236 100644 --- a/core/face-monitor.hpp +++ b/core/face-monitor.hpp @@ -1,12 +1,12 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** - * Copyright (c) 2014 Regents of the University of California, - * Arizona Board of Regents, - * Colorado State University, - * University Pierre & Marie Curie, Sorbonne University, - * Washington University in St. Louis, - * Beijing Institute of Technology, - * The University of Memphis + * Copyright (c) 2014, Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis * * This file is part of NFD (Named Data Networking Forwarding Daemon). * See AUTHORS.md for complete list of NFD authors and contributors. @@ -21,83 +21,26 @@ * * You should have received a copy of the GNU General Public License along with * NFD, e.g., in COPYING.md file. If not, see . - **/ + */ #ifndef NFD_CORE_FACE_MONITOR_HPP #define NFD_CORE_FACE_MONITOR_HPP -#include "common.hpp" +#include "notification-subscriber.hpp" #include -namespace ndn { -class Face; -class PendingInterestId; -} - namespace nfd { using ndn::nfd::FaceEventNotification; -/** - * \brief Helper class to subscribe to face notification events - * - * \todo Write test cases - */ -class FaceMonitor : noncopyable +class FaceMonitor : public NotificationSubscriber { public: - typedef function NotificationCallback; - typedef function TimeoutCallback; - - typedef std::vector NotificationCallbacks; - typedef std::vector TimeoutCallbacks; - - explicit - FaceMonitor(ndn::Face& face); - - ~FaceMonitor(); - - /** \brief Stops all notifications. This method doesn't remove registered callbacks. - */ - void - stopNotifications(); - - /** \brief Resumes notifications for added subscribers. - */ - void - startNotifications(); - - /** \brief Removes all notification subscribers. - */ - void - removeAllSubscribers(); - - /** \brief Adds a notification subscriber. This method doesn't return on timeouts. - */ - void - addSubscriber(const NotificationCallback& notificationCallback); - - /** \brief Adds a notification subscriber. - */ - void - addSubscriber(const NotificationCallback& notificationCallback, - const TimeoutCallback& timeoutCallback); - -private: - void - onTimeout(); - - void - onNotification(const Data& data); - -private: - ndn::Face& m_face; - uint64_t m_lastSequence; - bool m_isStopped; - NotificationCallbacks m_notificationCallbacks; - TimeoutCallbacks m_timeoutCallbacks; - const ndn::PendingInterestId* m_lastInterestId; + FaceMonitor(ndn::Face& face) + : NotificationSubscriber(face, "ndn:/localhost/nfd/faces/events") + { + } }; } // namespace nfd diff --git a/daemon/mgmt/notification-stream.hpp b/core/notification-stream.hpp similarity index 55% rename from daemon/mgmt/notification-stream.hpp rename to core/notification-stream.hpp index 06c3b5a6..9a89b4cc 100644 --- a/daemon/mgmt/notification-stream.hpp +++ b/core/notification-stream.hpp @@ -23,63 +23,59 @@ * NFD, e.g., in COPYING.md file. If not, see . */ -#ifndef NFD_DAEMON_MGMT_NOTIFICATION_STREAM_HPP -#define NFD_DAEMON_MGMT_NOTIFICATION_STREAM_HPP +#ifndef NFD_CORE_NOTIFICATION_STREAM_HPP +#define NFD_CORE_NOTIFICATION_STREAM_HPP -#include "mgmt/app-face.hpp" +#include "common.hpp" + +#include +#include namespace nfd { -class NotificationStream +/** \brief provides a publisher of Notification Stream + * \sa http://redmine.named-data.net/projects/nfd/wiki/Notification + */ +template +class NotificationStream : noncopyable { public: - NotificationStream(shared_ptr face, const Name& prefix, ndn::KeyChain& keyChain); + NotificationStream(FaceBase& face, const Name& prefix, ndn::KeyChain& keyChain) + : m_face(face) + , m_prefix(prefix) + , m_keyChain(keyChain) + , m_sequenceNo(0) + { + } - ~NotificationStream(); + virtual + ~NotificationStream() + { + } - template void - postNotification(const T& notification); + template void + postNotification(const T& notification) + { + Name dataName = m_prefix; + dataName.appendSequenceNumber(m_sequenceNo); + + shared_ptr data = make_shared(dataName); + data->setContent(notification.wireEncode()); + data->setFreshnessPeriod(time::seconds(1)); + + m_keyChain.sign(*data); + m_face.put(*data); + + ++m_sequenceNo; + } private: - shared_ptr m_face; + FaceBase& m_face; const Name m_prefix; - uint64_t m_sequenceNo; ndn::KeyChain& m_keyChain; + uint64_t m_sequenceNo; }; -inline -NotificationStream::NotificationStream(shared_ptr face, - const Name& prefix, - ndn::KeyChain& keyChain) - : m_face(face) - , m_prefix(prefix) - , m_sequenceNo(0) - , m_keyChain(keyChain) -{ -} - -template -inline void -NotificationStream::postNotification(const T& notification) -{ - Name dataName(m_prefix); - dataName.appendSegment(m_sequenceNo); - shared_ptr data(make_shared(dataName)); - data->setContent(notification.wireEncode()); - data->setFreshnessPeriod(time::seconds(1)); - - m_keyChain.sign(*data); - m_face->put(*data); - - ++m_sequenceNo; -} - -inline -NotificationStream::~NotificationStream() -{ -} - } // namespace nfd - -#endif // NFD_DAEMON_MGMT_NOTIFICATION_STREAM_HPP +#endif // NFD_CORE_NOTIFICATION_STREAM_HPP diff --git a/core/notification-subscriber.hpp b/core/notification-subscriber.hpp new file mode 100644 index 00000000..c359c823 --- /dev/null +++ b/core/notification-subscriber.hpp @@ -0,0 +1,214 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2014, Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis + * + * This file is part of NFD (Named Data Networking Forwarding Daemon). + * See AUTHORS.md for complete list of NFD authors and contributors. + * + * NFD is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * NFD, e.g., in COPYING.md file. If not, see . + */ + +#ifndef NFD_CORE_NOTIFICATION_SUBSCRIBER_HPP +#define NFD_CORE_NOTIFICATION_SUBSCRIBER_HPP + +#include "event-emitter.hpp" + +#include + +namespace nfd { + +/** \brief provides a subscriber of Notification Stream + * \sa http://redmine.named-data.net/projects/nfd/wiki/Notification + * \tparam T type of Notification item, appears in payload of Data packets + */ +template +class NotificationSubscriber : noncopyable +{ +public: + /** \brief construct a NotificationSubscriber + * \note The subscriber is not started after construction. + * User should add one or more handlers to onNotification, and invoke .start(). + */ + NotificationSubscriber(ndn::Face& face, const Name& prefix) + : m_face(face) + , m_prefix(prefix) + , m_isRunning(false) + , m_lastSequenceNo(std::numeric_limits::max()) + , m_lastInterestId(0) + { + } + + virtual + ~NotificationSubscriber() + { + } + + /** \return InterestLifetime of Interests to retrieve notifications + * \details This must be greater than FreshnessPeriod of Notification Data packets, + * to ensure correct operation of this subscriber implementation. + */ + static time::milliseconds + getInterestLifetime() + { + return time::milliseconds(60000); + } + + bool + isRunning() const + { + return m_isRunning; + } + + /** \brief start or resume receiving notifications + * \note onNotification must have at least one listener, + * otherwise this operation has no effect. + */ + void + start() + { + if (m_isRunning) // already running + return; + m_isRunning = true; + + this->sendInitialInterest(); + } + + /** \brief stop receiving notifications + */ + void + stop() + { + if (!m_isRunning) // not running + return; + m_isRunning = false; + + if (m_lastInterestId != 0) + m_face.removePendingInterest(m_lastInterestId); + m_lastInterestId = 0; + } + +public: // subscriptions + /** \brief fires when a Notification is received + * \note Removing all handlers will cause the subscriber to stop. + */ + EventEmitter onNotification; + + /** \brief fires when no Notification is received within .getInterestLifetime period + */ + EventEmitter<> onTimeout; + + /** \brief fires when a Data packet in the Notification Stream cannot be decoded as T + */ + EventEmitter onDecodeError; + +private: + void + sendInitialInterest() + { + if (this->shouldStop()) + return; + + shared_ptr interest = make_shared(m_prefix); + interest->setMustBeFresh(true); + interest->setChildSelector(1); + interest->setInterestLifetime(getInterestLifetime()); + + m_lastInterestId = m_face.expressInterest(*interest, + bind(&NotificationSubscriber::afterReceiveData, this, _2), + bind(&NotificationSubscriber::afterTimeout, this)); + } + + void + sendNextInterest() + { + if (this->shouldStop()) + return; + + BOOST_ASSERT(m_lastSequenceNo != + std::numeric_limits::max());// overflow or missing initial reply + + Name nextName = m_prefix; + nextName.appendSequenceNumber(m_lastSequenceNo + 1); + + shared_ptr interest = make_shared(nextName); + interest->setInterestLifetime(getInterestLifetime()); + + m_lastInterestId = m_face.expressInterest(*interest, + bind(&NotificationSubscriber::afterReceiveData, this, _2), + bind(&NotificationSubscriber::afterTimeout, this)); + } + + /** \brief Check if the subscriber is or should be stopped. + * \return true if the subscriber is stopped. + */ + bool + shouldStop() + { + if (!m_isRunning) + return true; + if (onNotification.isEmpty()) { + this->stop(); + return true; + } + return false; + } + + void + afterReceiveData(const Data& data) + { + if (this->shouldStop()) + return; + + T notification; + try { + m_lastSequenceNo = data.getName().get(-1).toSequenceNumber(); + notification.wireDecode(data.getContent().blockFromValue()); + } + catch (tlv::Error&) { + this->onDecodeError(data); + this->sendInitialInterest(); + return; + } + + this->onNotification(notification); + + this->sendNextInterest(); + } + + void + afterTimeout() + { + if (this->shouldStop()) + return; + + this->onTimeout(); + + this->sendInitialInterest(); + } + +private: + ndn::Face& m_face; + Name m_prefix; + bool m_isRunning; + uint64_t m_lastSequenceNo; + const ndn::PendingInterestId* m_lastInterestId; +}; + +} // namespace nfd + +#endif // NFD_CORE_NOTIFICATION_SUBSCRIBER_HPP diff --git a/core/segment-publisher.hpp b/core/segment-publisher.hpp index b1aa4a9c..ccb34265 100644 --- a/core/segment-publisher.hpp +++ b/core/segment-publisher.hpp @@ -33,6 +33,9 @@ namespace nfd { +/** \brief provides a publisher of Status Dataset or other segmented octet stream + * \sa http://redmine.named-data.net/projects/nfd/wiki/StatusDataset + */ template class SegmentPublisher : noncopyable { @@ -59,48 +62,44 @@ public: void publish() { - Name segmentPrefix(m_prefix); - segmentPrefix.appendVersion(); - ndn::EncodingBuffer buffer; - generate(buffer); const uint8_t* rawBuffer = buffer.buf(); const uint8_t* segmentBegin = rawBuffer; const uint8_t* end = rawBuffer + buffer.size(); + Name segmentPrefix(m_prefix); + segmentPrefix.appendVersion(); + uint64_t segmentNo = 0; - do - { - const uint8_t* segmentEnd = segmentBegin + getMaxSegmentSize(); - if (segmentEnd > end) - { - segmentEnd = end; - } - - Name segmentName(segmentPrefix); - segmentName.appendSegment(segmentNo); - - shared_ptr data(make_shared(segmentName)); - data->setContent(segmentBegin, segmentEnd - segmentBegin); - - segmentBegin = segmentEnd; - if (segmentBegin >= end) - { - data->setFinalBlockId(segmentName[-1]); - } - - publishSegment(data); - segmentNo++; + do { + const uint8_t* segmentEnd = segmentBegin + getMaxSegmentSize(); + if (segmentEnd > end) { + segmentEnd = end; } - while (segmentBegin < end); + + Name segmentName(segmentPrefix); + segmentName.appendSegment(segmentNo); + + shared_ptr data = make_shared(segmentName); + data->setContent(segmentBegin, segmentEnd - segmentBegin); + + segmentBegin = segmentEnd; + if (segmentBegin >= end) { + data->setFinalBlockId(segmentName[-1]); + } + + publishSegment(data); + ++segmentNo; + } while (segmentBegin < end); } protected: - + /** \brief In a derived class, write the octets into outBuffer. + */ virtual size_t - generate(ndn::EncodingBuffer& outBuffer) =0; + generate(ndn::EncodingBuffer& outBuffer) = 0; private: void diff --git a/daemon/mgmt/face-manager.cpp b/daemon/mgmt/face-manager.cpp index c8bc267a..b31f8415 100644 --- a/daemon/mgmt/face-manager.cpp +++ b/daemon/mgmt/face-manager.cpp @@ -119,7 +119,7 @@ FaceManager::FaceManager(FaceTable& faceTable, , m_faceTable(faceTable) , m_faceStatusPublisher(m_faceTable, *m_face, FACES_LIST_DATASET_PREFIX, keyChain) , m_channelStatusPublisher(m_factories, *m_face, CHANNELS_LIST_DATASET_PREFIX, keyChain) - , m_notificationStream(m_face, FACE_EVENTS_PREFIX, keyChain) + , m_notificationStream(*m_face, FACE_EVENTS_PREFIX, keyChain) , m_signedVerbDispatch(SIGNED_COMMAND_VERBS, SIGNED_COMMAND_VERBS + (sizeof(SIGNED_COMMAND_VERBS) / sizeof(SignedVerbAndProcessor))) diff --git a/daemon/mgmt/face-manager.hpp b/daemon/mgmt/face-manager.hpp index ec5decf8..6a3994e0 100644 --- a/daemon/mgmt/face-manager.hpp +++ b/daemon/mgmt/face-manager.hpp @@ -27,11 +27,11 @@ #define NFD_DAEMON_MGMT_FACE_MANAGER_HPP #include "common.hpp" +#include "core/notification-stream.hpp" #include "face/local-face.hpp" #include "mgmt/manager-base.hpp" #include "mgmt/face-status-publisher.hpp" #include "mgmt/channel-status-publisher.hpp" -#include "mgmt/notification-stream.hpp" #include #include @@ -174,7 +174,7 @@ private: FaceTable& m_faceTable; FaceStatusPublisher m_faceStatusPublisher; ChannelStatusPublisher m_channelStatusPublisher; - NotificationStream m_notificationStream; + NotificationStream m_notificationStream; typedef function. + */ + +#include "core/notification-stream.hpp" +#include "simple-notification.hpp" + +#include "tests/test-common.hpp" +#include "tests/dummy-client-face.hpp" + + +namespace nfd { +namespace tests { + +BOOST_FIXTURE_TEST_SUITE(CoreNotificationStream, BaseFixture) + +BOOST_AUTO_TEST_CASE(Post) +{ + shared_ptr face = makeDummyClientFace(); + ndn::KeyChain keyChain; + NotificationStream notificationStream(*face, + "/localhost/nfd/NotificationStreamTest", keyChain); + + SimpleNotification event1("msg1"); + notificationStream.postNotification(event1); + face->processEvents(); + BOOST_REQUIRE_EQUAL(face->m_sentDatas.size(), 1); + BOOST_CHECK_EQUAL(face->m_sentDatas[0].getName(), + "/localhost/nfd/NotificationStreamTest/%FE%00"); + SimpleNotification decoded1; + BOOST_CHECK_NO_THROW(decoded1.wireDecode(face->m_sentDatas[0].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(decoded1.getMessage(), "msg1"); + + SimpleNotification event2("msg2"); + notificationStream.postNotification(event2); + face->processEvents(); + BOOST_REQUIRE_EQUAL(face->m_sentDatas.size(), 2); + BOOST_CHECK_EQUAL(face->m_sentDatas[1].getName(), + "/localhost/nfd/NotificationStreamTest/%FE%01"); + SimpleNotification decoded2; + BOOST_CHECK_NO_THROW(decoded2.wireDecode(face->m_sentDatas[1].getContent().blockFromValue())); + BOOST_CHECK_EQUAL(decoded2.getMessage(), "msg2"); +} + +BOOST_AUTO_TEST_SUITE_END() + +} // namespace tests +} // namespace nfd diff --git a/tests/core/notification-subscriber.cpp b/tests/core/notification-subscriber.cpp new file mode 100644 index 00000000..12834f61 --- /dev/null +++ b/tests/core/notification-subscriber.cpp @@ -0,0 +1,223 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2014, Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis + * + * This file is part of NFD (Named Data Networking Forwarding Daemon). + * See AUTHORS.md for complete list of NFD authors and contributors. + * + * NFD is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * NFD, e.g., in COPYING.md file. If not, see . + */ + +#include "core/notification-subscriber.hpp" +#include "core/notification-stream.hpp" +#include "simple-notification.hpp" + +#include "tests/test-common.hpp" +#include "tests/dummy-client-face.hpp" + + +namespace nfd { +namespace tests { + +BOOST_FIXTURE_TEST_SUITE(CoreNotificationSubscriber, BaseFixture) + +class EndToEndFixture : public BaseFixture +{ +public: + EndToEndFixture() + : streamPrefix("ndn:/NotificationSubscriberTest") + , publisherFace(makeDummyClientFace()) + , notificationStream(*publisherFace, streamPrefix, publisherKeyChain) + , subscriberFace(makeDummyClientFace()) + , subscriber(*subscriberFace, streamPrefix) + { + } + + /** \brief post one notification and deliver to subscriber + */ + void + deliverNotification(const std::string& msg) + { + publisherFace->m_sentDatas.clear(); + SimpleNotification notification(msg); + notificationStream.postNotification(notification); + publisherFace->processEvents(); + BOOST_REQUIRE_EQUAL(publisherFace->m_sentDatas.size(), 1); + + lastDeliveredSeqNo = publisherFace->m_sentDatas[0].getName().at(-1).toSequenceNumber(); + + lastNotification.setMessage(""); + subscriberFace->receive(publisherFace->m_sentDatas[0]); + } + + void + afterNotification(const SimpleNotification& notification) + { + lastNotification = notification; + } + + void + clearNotificationHandlers() + { + subscriber.onNotification.clear(); + } + + void + afterTimeout() + { + hasTimeout = true; + } + + void + afterDecodeError(const Data& data) + { + lastDecodeErrorData = data; + } + + /** \return true if subscriberFace has an initial request as sole sent Interest + */ + bool + hasInitialRequest() const + { + if (subscriberFace->m_sentInterests.size() != 1) + return 0; + + const Interest& interest = subscriberFace->m_sentInterests[0]; + return interest.getName() == streamPrefix && + interest.getChildSelector() == 1 && + interest.getMustBeFresh() && + interest.getInterestLifetime() == + NotificationSubscriber::getInterestLifetime(); + } + + /** \return sequence number of the continuation request sent from subscriberFace + * or 0 if there's no such request as sole sent Interest + */ + uint64_t + getRequestSeqNo() const + { + if (subscriberFace->m_sentInterests.size() != 1) + return 0; + + const Interest& interest = subscriberFace->m_sentInterests[0]; + const Name& name = interest.getName(); + if (streamPrefix.isPrefixOf(name) && + name.size() == streamPrefix.size() + 1 && + interest.getInterestLifetime() == + NotificationSubscriber::getInterestLifetime()) + return name[-1].toSequenceNumber(); + else + return 0; + } + +protected: + Name streamPrefix; + shared_ptr publisherFace; + ndn::KeyChain publisherKeyChain; + NotificationStream notificationStream; + shared_ptr subscriberFace; + NotificationSubscriber subscriber; + + uint64_t lastDeliveredSeqNo; + + SimpleNotification lastNotification; + bool hasTimeout; + Data lastDecodeErrorData; +}; + +BOOST_FIXTURE_TEST_CASE(EndToEnd, EndToEndFixture) +{ + BOOST_REQUIRE_EQUAL(subscriber.isRunning(), false); + + // has no effect because onNotification has no handler + subscriber.start(); + BOOST_REQUIRE_EQUAL(subscriber.isRunning(), false); + + subscriber.onNotification += bind(&EndToEndFixture::afterNotification, this, _1); + subscriber.onTimeout += bind(&EndToEndFixture::afterTimeout, this); + subscriber.onDecodeError += bind(&EndToEndFixture::afterDecodeError, this, _1); + + // not received when subscriber is not running + this->deliverNotification("n1"); + subscriberFace->processEvents(time::milliseconds(10)); + BOOST_CHECK(lastNotification.getMessage().empty()); + BOOST_CHECK_EQUAL(subscriberFace->m_sentInterests.size(), 0); + + subscriberFace->m_sentInterests.clear(); + subscriber.start(); + subscriberFace->processEvents(time::milliseconds(10)); + BOOST_REQUIRE_EQUAL(subscriber.isRunning(), true); + BOOST_CHECK(this->hasInitialRequest()); + + // respond to initial request + subscriberFace->m_sentInterests.clear(); + this->deliverNotification("n2"); + subscriberFace->processEvents(time::milliseconds(10)); + BOOST_CHECK_EQUAL(lastNotification.getMessage(), "n2"); + BOOST_CHECK_EQUAL(this->getRequestSeqNo(), lastDeliveredSeqNo + 1); + + // respond to continuation request + subscriberFace->m_sentInterests.clear(); + this->deliverNotification("n3"); + subscriberFace->processEvents(time::milliseconds(10)); + BOOST_CHECK_EQUAL(lastNotification.getMessage(), "n3"); + BOOST_CHECK_EQUAL(this->getRequestSeqNo(), lastDeliveredSeqNo + 1); + + // timeout + subscriberFace->m_sentInterests.clear(); + lastNotification.setMessage(""); + subscriberFace->processEvents( + NotificationSubscriber::getInterestLifetime() + + time::milliseconds(1000)); + BOOST_CHECK(lastNotification.getMessage().empty()); + BOOST_CHECK_EQUAL(hasTimeout, true); + BOOST_CHECK(this->hasInitialRequest()); + + // decode error on sequence number + Name wrongName = streamPrefix; + wrongName.append("%07%07"); + Data wrongData(wrongName); + publisherKeyChain.sign(wrongData); + subscriberFace->receive(wrongData); + subscriberFace->m_sentInterests.clear(); + lastNotification.setMessage(""); + subscriberFace->processEvents(time::milliseconds(10)); + BOOST_CHECK(lastNotification.getMessage().empty()); + BOOST_CHECK_EQUAL(lastDecodeErrorData.getName(), wrongName); + BOOST_CHECK(this->hasInitialRequest()); + + // decode error in payload + subscriberFace->m_sentInterests.clear(); + lastNotification.setMessage(""); + this->deliverNotification("\x07n4"); + subscriberFace->processEvents(time::milliseconds(10)); + BOOST_CHECK(lastNotification.getMessage().empty()); + BOOST_CHECK(this->hasInitialRequest()); + + // stop if handlers are cleared + subscriber.onNotification += bind(&EndToEndFixture::clearNotificationHandlers, this); + subscriberFace->m_sentInterests.clear(); + this->deliverNotification("n5"); + subscriberFace->processEvents(time::milliseconds(10)); + BOOST_CHECK_EQUAL(subscriberFace->m_sentInterests.size(), 0); +} + +BOOST_AUTO_TEST_SUITE_END() + +} // namespace tests +} // namespace nfd diff --git a/tests/core/segment-publisher.cpp b/tests/core/segment-publisher.cpp index f859408c..88176699 100644 --- a/tests/core/segment-publisher.cpp +++ b/tests/core/segment-publisher.cpp @@ -26,7 +26,7 @@ #include "core/segment-publisher.hpp" #include "tests/test-common.hpp" -#include "tests/dummy-face.hpp" +#include "tests/dummy-client-face.hpp" #include @@ -38,10 +38,10 @@ namespace tests { NFD_LOG_INIT("SegmentPublisherTest"); template -class TestSegmentPublisher : public SegmentPublisher +class TestSegmentPublisher : public SegmentPublisher { public: - TestSegmentPublisher(DummyFace& face, + TestSegmentPublisher(DummyClientFace& face, const Name& prefix, ndn::KeyChain& keyChain) : SegmentPublisher(face, prefix, keyChain) @@ -90,7 +90,7 @@ class SegmentPublisherFixture : public BaseFixture { public: SegmentPublisherFixture() - : m_face(makeDummyFace()) + : m_face(makeDummyClientFace()) , m_publisher(*m_face, "/localhost/nfd/SegmentPublisherFixture", m_keyChain) { } @@ -134,7 +134,7 @@ public: } protected: - shared_ptr m_face; + shared_ptr m_face; TestSegmentPublisher m_publisher; ndn::EncodingBuffer m_buffer; ndn::KeyChain m_keyChain; diff --git a/tests/core/simple-notification.hpp b/tests/core/simple-notification.hpp new file mode 100644 index 00000000..3c8fdef0 --- /dev/null +++ b/tests/core/simple-notification.hpp @@ -0,0 +1,94 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2014, Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis + * + * This file is part of NFD (Named Data Networking Forwarding Daemon). + * See AUTHORS.md for complete list of NFD authors and contributors. + * + * NFD is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * NFD, e.g., in COPYING.md file. If not, see . + */ + +#ifndef NFD_TESTS_CORE_SIMPLE_NOTIFICATION_HPP +#define NFD_TESTS_CORE_SIMPLE_NOTIFICATION_HPP + +#include "common.hpp" + +#include "tests/test-common.hpp" + +namespace nfd { +namespace tests { + +class SimpleNotification +{ +public: + SimpleNotification() + { + } + + SimpleNotification(const std::string& message) + : m_message(message) + { + } + + ~SimpleNotification() + { + } + + Block + wireEncode() const + { + ndn::EncodingBuffer buffer; + prependByteArrayBlock(buffer, + 0x8888, + reinterpret_cast(m_message.c_str()), + m_message.size()); + return buffer.block(); + } + + void + wireDecode(const Block& block) + { + m_message.assign(reinterpret_cast(block.value()), + block.value_size()); + + // error for testing + if (!m_message.empty() && m_message[0] == '\x07') + throw tlv::Error("0x07 error"); + } + +public: + const std::string& + getMessage() const + { + return m_message; + } + + void + setMessage(const std::string& message) + { + m_message = message; + } + +private: + std::string m_message; +}; + +} // namespace tests +} // namespace nfd + +#endif // NFD_TESTS_CORE_SIMPLE_NOTIFICATION_HPP diff --git a/tests/daemon/mgmt/notification-stream.cpp b/tests/daemon/mgmt/notification-stream.cpp deleted file mode 100644 index f64e50bc..00000000 --- a/tests/daemon/mgmt/notification-stream.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/** - * Copyright (c) 2014, Regents of the University of California, - * Arizona Board of Regents, - * Colorado State University, - * University Pierre & Marie Curie, Sorbonne University, - * Washington University in St. Louis, - * Beijing Institute of Technology, - * The University of Memphis - * - * This file is part of NFD (Named Data Networking Forwarding Daemon). - * See AUTHORS.md for complete list of NFD authors and contributors. - * - * NFD is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Foundation, - * either version 3 of the License, or (at your option) any later version. - * - * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * NFD, e.g., in COPYING.md file. If not, see . - */ - -#include "mgmt/notification-stream.hpp" -#include "mgmt/internal-face.hpp" - -#include "tests/test-common.hpp" - - -namespace nfd { -namespace tests { - -NFD_LOG_INIT("NotificationStreamTest"); - - - -class NotificationStreamFixture : public BaseFixture -{ -public: - NotificationStreamFixture() - : m_callbackFired(false) - , m_prefix("/localhost/nfd/NotificationStreamTest") - , m_message("TestNotificationMessage") - , m_sequenceNo(0) - { - } - - virtual - ~NotificationStreamFixture() - { - } - - void - validateCallback(const Data& data) - { - Name expectedName(m_prefix); - expectedName.appendSegment(m_sequenceNo); - BOOST_REQUIRE_EQUAL(data.getName(), expectedName); - - ndn::Block payload = data.getContent(); - std::string message; - - message.append(reinterpret_cast(payload.value()), payload.value_size()); - - BOOST_REQUIRE_EQUAL(message, m_message); - - m_callbackFired = true; - ++m_sequenceNo; - } - - void - resetCallbackFired() - { - m_callbackFired = false; - } - -protected: - bool m_callbackFired; - const std::string m_prefix; - const std::string m_message; - uint64_t m_sequenceNo; - ndn::KeyChain m_keyChain; -}; - -BOOST_FIXTURE_TEST_SUITE(MgmtNotificationStream, NotificationStreamFixture) - -class TestNotification -{ -public: - TestNotification(const std::string& message) - : m_message(message) - { - } - - ~TestNotification() - { - } - - Block - wireEncode() const - { - ndn::EncodingBuffer buffer; - - prependByteArrayBlock(buffer, - ndn::Tlv::Content, - reinterpret_cast(m_message.c_str()), - m_message.size()); - return buffer.block(); - } - -private: - const std::string m_message; -}; - -BOOST_AUTO_TEST_CASE(TestPostEvent) -{ - shared_ptr face(make_shared()); - NotificationStream notificationStream(face, "/localhost/nfd/NotificationStreamTest", m_keyChain); - - face->onReceiveData += bind(&NotificationStreamFixture::validateCallback, this, _1); - - TestNotification event1(m_message); - notificationStream.postNotification(event1); - - BOOST_REQUIRE(m_callbackFired); - - resetCallbackFired(); - - TestNotification event2(m_message); - notificationStream.postNotification(event2); - - BOOST_REQUIRE(m_callbackFired); -} - - -BOOST_AUTO_TEST_SUITE_END() - - -} // namespace tests -} // namespace nfd diff --git a/tests/dummy-face.hpp b/tests/dummy-client-face.hpp similarity index 73% rename from tests/dummy-face.hpp rename to tests/dummy-client-face.hpp index 84da29f6..2e8781d3 100644 --- a/tests/dummy-face.hpp +++ b/tests/dummy-client-face.hpp @@ -23,8 +23,8 @@ * NFD, e.g., in COPYING.md file. If not, see . */ -#ifndef NFD_TESTS_DUMMY_FACE_HPP -#define NFD_TESTS_DUMMY_FACE_HPP +#ifndef NFD_TESTS_DUMMY_CLIENT_FACE_HPP +#define NFD_TESTS_DUMMY_CLIENT_FACE_HPP #include #include @@ -32,13 +32,14 @@ namespace nfd { namespace tests { -class DummyTransport : public ndn::Transport +class DummyClientTransport : public ndn::Transport { public: void receive(const Block& block) { - m_receiveCallback(block); + if (static_cast(m_receiveCallback)) + m_receiveCallback(block); } virtual void @@ -79,13 +80,13 @@ public: }; -/** \brief a Face for unit testing +/** \brief a client-side face for unit testing */ -class DummyFace : public ndn::Face +class DummyClientFace : public ndn::Face { public: explicit - DummyFace(shared_ptr transport) + DummyClientFace(shared_ptr transport) : Face(transport) , m_transport(transport) { @@ -103,20 +104,28 @@ public: } public: + /** \brief sent Interests + * \note After .expressInterest, .processEvents must be called before + * the Interest would show up here. + */ std::vector m_sentInterests; + /** \brief sent Datas + * \note After .put, .processEvents must be called before + * the Interest would show up here. + */ std::vector m_sentDatas; private: - shared_ptr m_transport; + shared_ptr m_transport; }; -inline shared_ptr -makeDummyFace() +inline shared_ptr +makeDummyClientFace() { - return make_shared(make_shared()); + return make_shared(make_shared()); } } // namespace tests } // namespace nfd -#endif // NFD_TESTS_DUMMY_FACE_HPP +#endif // NFD_TESTS_DUMMY_CLIENT_FACE_HPP diff --git a/tests/rib/rib-manager.cpp b/tests/rib/rib-manager.cpp index 8a30684a..593517f7 100644 --- a/tests/rib/rib-manager.cpp +++ b/tests/rib/rib-manager.cpp @@ -26,7 +26,7 @@ #include "rib/rib-manager.hpp" #include "tests/test-common.hpp" -#include "tests/dummy-face.hpp" +#include "tests/dummy-client-face.hpp" #include "rib/rib-status-publisher-common.hpp" namespace nfd { @@ -41,7 +41,7 @@ public: , ADD_NEXTHOP_VERB("add-nexthop") , REMOVE_NEXTHOP_VERB("remove-nexthop") { - face = nfd::tests::makeDummyFace(); + face = nfd::tests::makeDummyClientFace(); manager = make_shared(ndn::ref(*face)); manager->registerWithNfd(); @@ -81,7 +81,7 @@ public: public: shared_ptr manager; - shared_ptr face; + shared_ptr face; const Name COMMAND_PREFIX; const Name::Component ADD_NEXTHOP_VERB; diff --git a/tests/rib/rib-status-publisher.cpp b/tests/rib/rib-status-publisher.cpp index ac68c632..5253bba6 100644 --- a/tests/rib/rib-status-publisher.cpp +++ b/tests/rib/rib-status-publisher.cpp @@ -26,7 +26,7 @@ #include "rib/rib-status-publisher.hpp" #include "rib-status-publisher-common.hpp" -#include "tests/dummy-face.hpp" +#include "tests/dummy-client-face.hpp" namespace nfd { namespace rib { @@ -47,7 +47,7 @@ BOOST_AUTO_TEST_CASE(Basic) rib.insert(name, entry); ndn::KeyChain keyChain; - shared_ptr face = nfd::tests::makeDummyFace(); + shared_ptr face = nfd::tests::makeDummyClientFace(); RibStatusPublisher publisher(rib, *face, "/localhost/nfd/rib/list", keyChain); publisher.publish(); diff --git a/tools/nfd-autoreg.cpp b/tools/nfd-autoreg.cpp index 21dbc835..b0c46c9c 100644 --- a/tools/nfd-autoreg.cpp +++ b/tools/nfd-autoreg.cpp @@ -26,7 +26,6 @@ #include #include -#include #include #include @@ -35,6 +34,7 @@ #include "version.hpp" #include "core/face-uri.hpp" +#include "core/face-monitor.hpp" #include "network.hpp" namespace po = boost::program_options; @@ -49,7 +49,7 @@ class AutoregServer : boost::noncopyable public: AutoregServer() : m_controller(m_face) - // , m_lastNotification() + , m_faceMonitor(m_face) , m_cost(255) { } @@ -130,13 +130,8 @@ public: } void - onNotification(const Data& data) + onNotification(const FaceEventNotification& notification) { - m_lastNotification = data.getName().get(-1).toSegment(); - - // process - FaceEventNotification notification(data.getContent().blockFromValue()); - if (notification.getKind() == FACE_EVENT_CREATED && !notification.isLocal() && notification.isOnDemand()) @@ -147,33 +142,6 @@ public: { std::cerr << "IGNORED: " << notification << std::endl; } - - Name nextNotification("/localhost/nfd/faces/events"); - nextNotification - .appendSegment(m_lastNotification + 1); - - // no need to set freshness or child selectors - m_face.expressInterest(nextNotification, - bind(&AutoregServer::onNotification, this, _2), - bind(&AutoregServer::onTimeout, this, _1)); - } - - void - onTimeout(const Interest& timedOutInterest) - { - // re-express the timed out interest, but reset Nonce, since it has to change - - // To be robust against missing notification, use ChildSelector and MustBeFresh - Interest interest("/localhost/nfd/faces/events"); - interest - .setMustBeFresh(true) - .setChildSelector(1) - .setInterestLifetime(time::seconds(60)) - ; - - m_face.expressInterest(interest, - bind(&AutoregServer::onNotification, this, _2), - bind(&AutoregServer::onTimeout, this, _1)); } void @@ -225,16 +193,8 @@ public: std::cout << " " << *network << std::endl; } - Interest interest("/localhost/nfd/faces/events"); - interest - .setMustBeFresh(true) - .setChildSelector(1) - .setInterestLifetime(time::seconds(60)) - ; - - m_face.expressInterest(interest, - bind(&AutoregServer::onNotification, this, _2), - bind(&AutoregServer::onTimeout, this, _1)); + m_faceMonitor.onNotification += bind(&AutoregServer::onNotification, this, _1); + m_faceMonitor.start(); boost::asio::signal_set signalSet(m_face.getIoService(), SIGINT, SIGTERM); signalSet.async_wait(bind(&AutoregServer::signalHandler, this)); @@ -314,7 +274,7 @@ public: private: Face m_face; Controller m_controller; - uint64_t m_lastNotification; + FaceMonitor m_faceMonitor; std::vector m_autoregPrefixes; uint64_t m_cost; std::vector m_whiteList;