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
This commit is contained in:
Junxiao Shi committed 2014-08-10 19:23:09 -07:00
1 parent b3033247ee
commit 15b12e759d
18 files changed
+750 -537

No files matched your search

+26 -13
View File
@@ -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 <http://www.gnu.org/licenses/>.
**/
*/
#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<TArgs> m_eventName;
* EventEmitter<TArgs> 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 T1 = empty, typename T2 = empty,
typename T3 = empty, typename T4 = empty>
typename T3 = empty, typename T4 = empty>
class EventEmitter : noncopyable
{
public:
@@ -199,6 +202,8 @@ EventEmitter<empty, empty, empty, empty>::operator()()
std::vector<Handler>::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<T1, empty, empty, empty>::operator()(const T1& a1)
typename std::vector<Handler>::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<T1, T2, empty, empty>::operator()
typename std::vector<Handler>::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<T1, T2, T3, empty>::operator()
typename std::vector<Handler>::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<T1, T2, T3, T4>::operator()
typename std::vector<Handler>::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;
}
}
-165
View File
@@ -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 <http://www.gnu.org/licenses/>.
**/
#include "face-monitor.hpp"
#include "core/logger.hpp"
#include <ndn-cxx/face.hpp>
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<bool>(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<bool>(notificationCallback))
m_notificationCallbacks.push_back(notificationCallback);
if (static_cast<bool>(timeoutCallback))
m_timeoutCallbacks.push_back(timeoutCallback);
}
void
FaceMonitor::onTimeout()
{
if (m_isStopped)
return;
std::vector<TimeoutCallback>::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<NotificationCallback>::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
+14 -71
View File
@@ -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 <http://www.gnu.org/licenses/>.
**/
*/
#ifndef NFD_CORE_FACE_MONITOR_HPP
#define NFD_CORE_FACE_MONITOR_HPP
#include "common.hpp"
#include "notification-subscriber.hpp"
#include <ndn-cxx/management/nfd-face-event-notification.hpp>
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<FaceEventNotification>
{
public:
typedef function<void(const ndn::nfd::FaceEventNotification&)> NotificationCallback;
typedef function<void()> TimeoutCallback;
typedef std::vector<NotificationCallback> NotificationCallbacks;
typedef std::vector<TimeoutCallback> 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<FaceEventNotification>(face, "ndn:/localhost/nfd/faces/events")
{
}
};
} // namespace nfd
@@ -23,63 +23,59 @@
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#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 <ndn-cxx/encoding/encoding-buffer.hpp>
#include <ndn-cxx/security/key-chain.hpp>
namespace nfd {
class NotificationStream
/** \brief provides a publisher of Notification Stream
* \sa http://redmine.named-data.net/projects/nfd/wiki/Notification
*/
template <class FaceBase>
class NotificationStream : noncopyable
{
public:
NotificationStream(shared_ptr<AppFace> 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 <typename T> void
postNotification(const T& notification);
template<typename T> void
postNotification(const T& notification)
{
Name dataName = m_prefix;
dataName.appendSequenceNumber(m_sequenceNo);
shared_ptr<Data> data = make_shared<Data>(dataName);
data->setContent(notification.wireEncode());
data->setFreshnessPeriod(time::seconds(1));
m_keyChain.sign(*data);
m_face.put(*data);
++m_sequenceNo;
}
private:
shared_ptr<AppFace> 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<AppFace> face,
const Name& prefix,
ndn::KeyChain& keyChain)
: m_face(face)
, m_prefix(prefix)
, m_sequenceNo(0)
, m_keyChain(keyChain)
{
}
template <typename T>
inline void
NotificationStream::postNotification(const T& notification)
{
Name dataName(m_prefix);
dataName.appendSegment(m_sequenceNo);
shared_ptr<Data> data(make_shared<Data>(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
+214
View File
@@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef NFD_CORE_NOTIFICATION_SUBSCRIBER_HPP
#define NFD_CORE_NOTIFICATION_SUBSCRIBER_HPP
#include "event-emitter.hpp"
#include <ndn-cxx/face.hpp>
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<typename T>
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<uint64_t>::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<T> 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<Data> onDecodeError;
private:
void
sendInitialInterest()
{
if (this->shouldStop())
return;
shared_ptr<Interest> interest = make_shared<Interest>(m_prefix);
interest->setMustBeFresh(true);
interest->setChildSelector(1);
interest->setInterestLifetime(getInterestLifetime());
m_lastInterestId = m_face.expressInterest(*interest,
bind(&NotificationSubscriber<T>::afterReceiveData, this, _2),
bind(&NotificationSubscriber<T>::afterTimeout, this));
}
void
sendNextInterest()
{
if (this->shouldStop())
return;
BOOST_ASSERT(m_lastSequenceNo !=
std::numeric_limits<uint64_t>::max());// overflow or missing initial reply
Name nextName = m_prefix;
nextName.appendSequenceNumber(m_lastSequenceNo + 1);
shared_ptr<Interest> interest = make_shared<Interest>(nextName);
interest->setInterestLifetime(getInterestLifetime());
m_lastInterestId = m_face.expressInterest(*interest,
bind(&NotificationSubscriber<T>::afterReceiveData, this, _2),
bind(&NotificationSubscriber<T>::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
+28 -29
View File
@@ -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 FaceBase>
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> data(make_shared<Data>(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> data = make_shared<Data>(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
+1 -1
View File
@@ -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)))
+2 -2
View File
@@ -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 <ndn-cxx/management/nfd-control-parameters.hpp>
#include <ndn-cxx/management/nfd-control-response.hpp>
@@ -174,7 +174,7 @@ private:
FaceTable& m_faceTable;
FaceStatusPublisher m_faceStatusPublisher;
ChannelStatusPublisher m_channelStatusPublisher;
NotificationStream m_notificationStream;
NotificationStream<AppFace> m_notificationStream;
typedef function<void(FaceManager*,
const Interest&,
+2 -2
View File
@@ -118,8 +118,8 @@ RibManager::registerWithNfd()
}
NFD_LOG_INFO("Start monitoring face create/destroy events");
m_faceMonitor.addSubscriber(bind(&RibManager::onNotification, this, _1));
m_faceMonitor.startNotifications();
m_faceMonitor.onNotification += bind(&RibManager::onNotification, this, _1);
m_faceMonitor.start();
fetchActiveFaces();
}
+69
View File
@@ -0,0 +1,69 @@
/* -*- 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 <http://www.gnu.org/licenses/>.
*/
#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<DummyClientFace> face = makeDummyClientFace();
ndn::KeyChain keyChain;
NotificationStream<DummyClientFace> 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
+223
View File
@@ -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 <http://www.gnu.org/licenses/>.
*/
#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<SimpleNotification>::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<SimpleNotification>::getInterestLifetime())
return name[-1].toSequenceNumber();
else
return 0;
}
protected:
Name streamPrefix;
shared_ptr<DummyClientFace> publisherFace;
ndn::KeyChain publisherKeyChain;
NotificationStream<DummyClientFace> notificationStream;
shared_ptr<DummyClientFace> subscriberFace;
NotificationSubscriber<SimpleNotification> 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<SimpleNotification>::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
+5 -5
View File
@@ -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 <ndn-cxx/encoding/tlv.hpp>
@@ -38,10 +38,10 @@ namespace tests {
NFD_LOG_INIT("SegmentPublisherTest");
template<int64_t N=10000>
class TestSegmentPublisher : public SegmentPublisher<DummyFace>
class TestSegmentPublisher : public SegmentPublisher<DummyClientFace>
{
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<DummyFace> m_face;
shared_ptr<DummyClientFace> m_face;
TestSegmentPublisher<N> m_publisher;
ndn::EncodingBuffer m_buffer;
ndn::KeyChain m_keyChain;
+94
View File
@@ -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 <http://www.gnu.org/licenses/>.
*/
#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<const uint8_t*>(m_message.c_str()),
m_message.size());
return buffer.block();
}
void
wireDecode(const Block& block)
{
m_message.assign(reinterpret_cast<const char*>(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
-142
View File
@@ -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 <http://www.gnu.org/licenses/>.
*/
#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<const char*>(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<const uint8_t*>(m_message.c_str()),
m_message.size());
return buffer.block();
}
private:
const std::string m_message;
};
BOOST_AUTO_TEST_CASE(TestPostEvent)
{
shared_ptr<InternalFace> face(make_shared<InternalFace>());
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
@@ -23,8 +23,8 @@
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#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 <ndn-cxx/face.hpp>
#include <ndn-cxx/transport/transport.hpp>
@@ -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<bool>(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<DummyTransport> transport)
DummyClientFace(shared_ptr<DummyClientTransport> 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<Interest> m_sentInterests;
/** \brief sent Datas
* \note After .put, .processEvents must be called before
* the Interest would show up here.
*/
std::vector<Data> m_sentDatas;
private:
shared_ptr<DummyTransport> m_transport;
shared_ptr<DummyClientTransport> m_transport;
};
inline shared_ptr<DummyFace>
makeDummyFace()
inline shared_ptr<DummyClientFace>
makeDummyClientFace()
{
return make_shared<DummyFace>(make_shared<DummyTransport>());
return make_shared<DummyClientFace>(make_shared<DummyClientTransport>());
}
} // namespace tests
} // namespace nfd
#endif // NFD_TESTS_DUMMY_FACE_HPP
#endif // NFD_TESTS_DUMMY_CLIENT_FACE_HPP
+3 -3
View File
@@ -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<RibManager>(ndn::ref(*face));
manager->registerWithNfd();
@@ -81,7 +81,7 @@ public:
public:
shared_ptr<RibManager> manager;
shared_ptr<nfd::tests::DummyFace> face;
shared_ptr<nfd::tests::DummyClientFace> face;
const Name COMMAND_PREFIX;
const Name::Component ADD_NEXTHOP_VERB;
+2 -2
View File
@@ -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<nfd::tests::DummyFace> face = nfd::tests::makeDummyFace();
shared_ptr<nfd::tests::DummyClientFace> face = nfd::tests::makeDummyClientFace();
RibStatusPublisher publisher(rib, *face, "/localhost/nfd/rib/list", keyChain);
publisher.publish();
+6 -46
View File
@@ -26,7 +26,6 @@
#include <ndn-cxx/face.hpp>
#include <ndn-cxx/name.hpp>
#include <ndn-cxx/management/nfd-face-event-notification.hpp>
#include <ndn-cxx/management/nfd-controller.hpp>
#include <boost/program_options/options_description.hpp>
@@ -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(<undefined>)
, 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<ndn::Name> m_autoregPrefixes;
uint64_t m_cost;
std::vector<Network> m_whiteList;