face: remove deprecated PendingInterestId, InterestFilterId, RegisteredPrefixId
Plus some refactoring in Face::Impl
Refs: #4885
Change-Id: I5c46aaef35eb618d6f4934d4629c473c7fdde456
diff --git a/ndn-cxx/face.cpp b/ndn-cxx/face.cpp
index 32aa630..8b20ae3 100644
--- a/ndn-cxx/face.cpp
+++ b/ndn-cxx/face.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -173,25 +173,17 @@
interest2->getNonce();
IO_CAPTURE_WEAK_IMPL(post) {
- impl->asyncExpressInterest(id, interest2, afterSatisfied, afterNacked, afterTimeout);
+ impl->expressInterest(id, interest2, afterSatisfied, afterNacked, afterTimeout);
} IO_CAPTURE_WEAK_IMPL_END
- return PendingInterestHandle(*this, reinterpret_cast<const PendingInterestId*>(id));
-}
-
-void
-Face::cancelPendingInterest(const PendingInterestId* pendingInterestId)
-{
- IO_CAPTURE_WEAK_IMPL(post) {
- impl->asyncRemovePendingInterest(reinterpret_cast<RecordId>(pendingInterestId));
- } IO_CAPTURE_WEAK_IMPL_END
+ return PendingInterestHandle(m_impl, id);
}
void
Face::removeAllPendingInterests()
{
IO_CAPTURE_WEAK_IMPL(post) {
- impl->asyncRemoveAllPendingInterests();
+ impl->removeAllPendingInterests();
} IO_CAPTURE_WEAK_IMPL_END
}
@@ -205,7 +197,7 @@
Face::put(Data data)
{
IO_CAPTURE_WEAK_IMPL(post) {
- impl->asyncPutData(data);
+ impl->putData(data);
} IO_CAPTURE_WEAK_IMPL_END
}
@@ -213,7 +205,7 @@
Face::put(lp::Nack nack)
{
IO_CAPTURE_WEAK_IMPL(post) {
- impl->asyncPutNack(nack);
+ impl->putNack(nack);
} IO_CAPTURE_WEAK_IMPL_END
}
@@ -236,7 +228,7 @@
auto id = m_impl->registerPrefix(filter.getPrefix(), onSuccess, onFailure, flags, options,
filter, onInterest);
- return RegisteredPrefixHandle(*this, reinterpret_cast<const RegisteredPrefixId*>(id));
+ return RegisteredPrefixHandle(m_impl, id);
}
InterestFilterHandle
@@ -245,18 +237,10 @@
auto id = m_impl->m_interestFilterTable.allocateId();
IO_CAPTURE_WEAK_IMPL(post) {
- impl->asyncSetInterestFilter(id, filter, onInterest);
+ impl->setInterestFilter(id, filter, onInterest);
} IO_CAPTURE_WEAK_IMPL_END
- return InterestFilterHandle(*this, reinterpret_cast<const InterestFilterId*>(id));
-}
-
-void
-Face::clearInterestFilter(const InterestFilterId* interestFilterId)
-{
- IO_CAPTURE_WEAK_IMPL(post) {
- impl->asyncUnsetInterestFilter(reinterpret_cast<RecordId>(interestFilterId));
- } IO_CAPTURE_WEAK_IMPL_END
+ return InterestFilterHandle(m_impl, id);
}
RegisteredPrefixHandle
@@ -270,18 +254,7 @@
options.setSigningInfo(signingInfo);
auto id = m_impl->registerPrefix(prefix, onSuccess, onFailure, flags, options, nullopt, nullptr);
- return RegisteredPrefixHandle(*this, reinterpret_cast<const RegisteredPrefixId*>(id));
-}
-
-void
-Face::unregisterPrefixImpl(const RegisteredPrefixId* registeredPrefixId,
- const UnregisterPrefixSuccessCallback& onSuccess,
- const UnregisterPrefixFailureCallback& onFailure)
-{
- IO_CAPTURE_WEAK_IMPL(post) {
- impl->asyncUnregisterPrefix(reinterpret_cast<RecordId>(registeredPrefixId),
- onSuccess, onFailure);
- } IO_CAPTURE_WEAK_IMPL_END
+ return RegisteredPrefixHandle(m_impl, id);
}
void
@@ -376,38 +349,61 @@
}
}
-PendingInterestHandle::PendingInterestHandle(Face& face, const PendingInterestId* id)
- : CancelHandle([&face, id] { face.cancelPendingInterest(id); })
+PendingInterestHandle::PendingInterestHandle(weak_ptr<Face::Impl> weakImpl, detail::RecordId id)
+ : CancelHandle([w = std::move(weakImpl), id] {
+ auto impl = w.lock();
+ if (impl != nullptr) {
+ impl->asyncRemovePendingInterest(id);
+ }
+ })
{
}
-RegisteredPrefixHandle::RegisteredPrefixHandle(Face& face, const RegisteredPrefixId* id)
- : CancelHandle([&face, id] { face.unregisterPrefixImpl(id, nullptr, nullptr); })
- , m_face(&face)
+RegisteredPrefixHandle::RegisteredPrefixHandle(weak_ptr<Face::Impl> weakImpl, detail::RecordId id)
+ : CancelHandle([=] { unregister(weakImpl, id, nullptr, nullptr); })
+ , m_weakImpl(std::move(weakImpl))
, m_id(id)
{
- // The lambda passed to CancelHandle constructor cannot call this->unregister,
- // because base class destructor cannot access the member fields of this subclass.
+ // The lambda passed to CancelHandle constructor cannot call the non-static unregister(),
+ // because the base class destructor cannot access the member fields of this subclass.
}
void
RegisteredPrefixHandle::unregister(const UnregisterPrefixSuccessCallback& onSuccess,
const UnregisterPrefixFailureCallback& onFailure)
{
- if (m_id == nullptr) {
- if (onFailure != nullptr) {
+ if (m_id == 0) {
+ if (onFailure) {
onFailure("RegisteredPrefixHandle is empty");
}
return;
}
- m_face->unregisterPrefixImpl(m_id, onSuccess, onFailure);
- m_face = nullptr;
- m_id = nullptr;
+ unregister(m_weakImpl, m_id, onSuccess, onFailure);
+ *this = {};
}
-InterestFilterHandle::InterestFilterHandle(Face& face, const InterestFilterId* id)
- : CancelHandle([&face, id] { face.clearInterestFilter(id); })
+void
+RegisteredPrefixHandle::unregister(const weak_ptr<Face::Impl>& weakImpl, detail::RecordId id,
+ const UnregisterPrefixSuccessCallback& onSuccess,
+ const UnregisterPrefixFailureCallback& onFailure)
+{
+ auto impl = weakImpl.lock();
+ if (impl != nullptr) {
+ impl->asyncUnregisterPrefix(id, onSuccess, onFailure);
+ }
+ else if (onFailure) {
+ onFailure("Face already closed");
+ }
+}
+
+InterestFilterHandle::InterestFilterHandle(weak_ptr<Face::Impl> weakImpl, detail::RecordId id)
+ : CancelHandle([w = std::move(weakImpl), id] {
+ auto impl = w.lock();
+ if (impl != nullptr) {
+ impl->asyncUnsetInterestFilter(id);
+ }
+ })
{
}
diff --git a/ndn-cxx/face.hpp b/ndn-cxx/face.hpp
index f1b32a9..39d1d39 100644
--- a/ndn-cxx/face.hpp
+++ b/ndn-cxx/face.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -36,30 +36,31 @@
class Transport;
-class PendingInterestId;
class PendingInterestHandle;
-class RegisteredPrefixId;
class RegisteredPrefixHandle;
-class InterestFilterId;
class InterestFilterHandle;
+namespace detail {
+using RecordId = uint64_t;
+} // namespace detail
+
/**
- * @brief Callback invoked when expressed Interest gets satisfied with a Data packet
+ * @brief Callback invoked when an expressed Interest is satisfied by a Data packet
*/
typedef function<void(const Interest&, const Data&)> DataCallback;
/**
- * @brief Callback invoked when Nack is sent in response to expressed Interest
+ * @brief Callback invoked when a Nack is received in response to an expressed Interest
*/
typedef function<void(const Interest&, const lp::Nack&)> NackCallback;
/**
- * @brief Callback invoked when expressed Interest times out
+ * @brief Callback invoked when an expressed Interest times out
*/
typedef function<void(const Interest&)> TimeoutCallback;
/**
- * @brief Callback invoked when incoming Interest matches the specified InterestFilter
+ * @brief Callback invoked when an incoming Interest matches the specified InterestFilter
*/
typedef function<void(const InterestFilter&, const Interest&)> InterestCallback;
@@ -74,12 +75,12 @@
typedef function<void(const Name&, const std::string&)> RegisterPrefixFailureCallback;
/**
- * @brief Callback invoked when unregisterPrefix or unsetInterestFilter command succeeds
+ * @brief Callback invoked when unregistering a prefix succeeds
*/
typedef function<void()> UnregisterPrefixSuccessCallback;
/**
- * @brief Callback invoked when unregisterPrefix or unsetInterestFilter command fails
+ * @brief Callback invoked when unregistering a prefix fails
*/
typedef function<void(const std::string&)> UnregisterPrefixFailureCallback;
@@ -237,16 +238,6 @@
const TimeoutCallback& afterTimeout);
/**
- * @deprecated use PendingInterestHandle::cancel()
- */
- [[deprecated]]
- void
- removePendingInterest(const PendingInterestId* pendingInterestId)
- {
- cancelPendingInterest(pendingInterestId);
- }
-
- /**
* @brief Cancel all previously expressed Interests
*/
void
@@ -312,14 +303,14 @@
uint64_t flags = nfd::ROUTE_FLAG_CHILD_INHERIT);
/**
- * @brief Set InterestFilter to dispatch incoming matching interest to onInterest callback
+ * @brief Set an InterestFilter to dispatch matching incoming Interests to @p onInterest callback.
*
* @param filter Interest filter
* @param onInterest A callback to be called when a matching interest is received
*
* This method modifies library's FIB only, and does not register the prefix with the
- * forwarder. It will always succeed. To register prefix with the forwarder, use
- * registerPrefix, or use the setInterestFilter overload taking two callbacks.
+ * forwarder. It will always succeed. To register a prefix with the forwarder, use
+ * registerPrefix() or one of the other two setInterestFilter() overloads.
*
* @return A handle for unsetting the Interest filter.
*/
@@ -351,38 +342,6 @@
uint64_t flags = nfd::ROUTE_FLAG_CHILD_INHERIT);
/**
- * @deprecated use RegisteredPrefixHandle::unregister()
- */
- [[deprecated]]
- void
- unsetInterestFilter(const RegisteredPrefixId* registeredPrefixId)
- {
- unregisterPrefixImpl(registeredPrefixId, nullptr, nullptr);
- }
-
- /**
- * @deprecated use InterestFilterHandle::cancel()
- */
- [[deprecated]]
- void
- unsetInterestFilter(const InterestFilterId* interestFilterId)
- {
- clearInterestFilter(interestFilterId);
- }
-
- /**
- * @deprecated use RegisteredPrefixHandle::unregister()
- */
- [[deprecated]]
- void
- unregisterPrefix(const RegisteredPrefixId* registeredPrefixId,
- const UnregisterPrefixSuccessCallback& onSuccess,
- const UnregisterPrefixFailureCallback& onFailure)
- {
- unregisterPrefixImpl(registeredPrefixId, onSuccess, onFailure);
- }
-
- /**
* @brief Publish data packet
* @param data the Data; a copy will be made, so that the caller is not required to
* maintain the argument unchanged
@@ -408,9 +367,9 @@
/**
* @brief Process any data to receive or call timeout callbacks.
*
- * This call will block forever (default timeout == 0) to process IO on the face.
- * To exit cleanly on a producer, unset any Interest filters with unsetInterestFilter() and wait
- * for processEvents() to return. To exit after an error, one can call shutdown().
+ * This call will block forever (with the default timeout of 0) to process I/O on the face.
+ * To exit cleanly on a producer, clear any Interest filters and wait for processEvents() to
+ * return. To exit after an error, one can call shutdown().
* In consumer applications, processEvents() will return when all expressed Interests have been
* satisfied, Nacked, or timed out. To terminate earlier, a consumer application should cancel
* all previously expressed and still-pending Interests.
@@ -442,16 +401,17 @@
}
/**
- * @brief Shutdown face operations
+ * @brief Shutdown face operations.
*
- * This method cancels all pending operations and closes connection to NDN Forwarder.
+ * This method cancels all pending operations and closes the connection to the NDN forwarder.
*
* Note that this method does not stop the io_service if it is shared between multiple Faces or
* with other IO objects (e.g., Scheduler).
*
- * @warning Calling this method could cause outgoing packets to be lost. Producers that shut down
- * immediately after sending a Data packet should instead use unsetInterestFilter() to
+ * @warning Calling this method may cause outgoing packets to be lost. Producers that shut down
+ * immediately after sending a Data packet should instead clear all Interest filters to
* shut down cleanly.
+ * @sa processEvents()
*/
void
shutdown();
@@ -488,7 +448,6 @@
/**
* @throw Face::Error on unsupported protocol
- * @note shared_ptr is passed by value because ownership is transferred to this function
*/
void
construct(shared_ptr<Transport> transport, KeyChain& keyChain);
@@ -496,17 +455,6 @@
void
onReceiveElement(const Block& blockFromDaemon);
- void
- cancelPendingInterest(const PendingInterestId* pendingInterestId);
-
- void
- clearInterestFilter(const InterestFilterId* interestFilterId);
-
- void
- unregisterPrefixImpl(const RegisteredPrefixId* registeredPrefixId,
- const UnregisterPrefixSuccessCallback& onSuccess,
- const UnregisterPrefixFailureCallback& onFailure);
-
private:
/// the io_service owned by this Face, may be null
unique_ptr<boost::asio::io_service> m_internalIoService;
@@ -532,25 +480,25 @@
friend InterestFilterHandle;
};
-/** \brief A handle of pending Interest.
+/** \brief Handle for a pending Interest.
*
* \code
* PendingInterestHandle hdl = face.expressInterest(interest, satisfyCb, nackCb, timeoutCb);
* hdl.cancel(); // cancel the pending Interest
* \endcode
- *
- * \warning Canceling a pending Interest after the face has been destructed may trigger undefined
- * behavior.
*/
class PendingInterestHandle : public detail::CancelHandle
{
public:
PendingInterestHandle() noexcept = default;
- PendingInterestHandle(Face& face, const PendingInterestId* id);
+private:
+ PendingInterestHandle(weak_ptr<Face::Impl> impl, detail::RecordId id);
+
+ friend Face;
};
-/** \brief A scoped handle of pending Interest.
+/** \brief Scoped handle for a pending Interest.
*
* Upon destruction of this handle, the pending Interest is canceled automatically.
* Most commonly, the application keeps a ScopedPendingInterestHandle as a class member field,
@@ -561,13 +509,10 @@
* ScopedPendingInterestHandle hdl = face.expressInterest(interest, satisfyCb, nackCb, timeoutCb);
* } // hdl goes out of scope, canceling the pending Interest
* \endcode
- *
- * \warning Canceling a pending Interest after the face has been destructed may trigger undefined
- * behavior.
*/
using ScopedPendingInterestHandle = detail::ScopedCancelHandle<PendingInterestHandle>;
-/** \brief A handle of registered prefix.
+/** \brief Handle for a registered prefix.
*/
class RegisteredPrefixHandle : public detail::CancelHandle
{
@@ -578,22 +523,28 @@
// see https://stackoverflow.com/a/44693603
}
- RegisteredPrefixHandle(Face& face, const RegisteredPrefixId* id);
-
/** \brief Unregister the prefix.
- * \warning Unregistering a prefix after the face has been destructed may trigger undefined
- * behavior.
*/
void
unregister(const UnregisterPrefixSuccessCallback& onSuccess = nullptr,
const UnregisterPrefixFailureCallback& onFailure = nullptr);
private:
- Face* m_face = nullptr;
- const RegisteredPrefixId* m_id = nullptr;
+ RegisteredPrefixHandle(weak_ptr<Face::Impl> impl, detail::RecordId id);
+
+ static void
+ unregister(const weak_ptr<Face::Impl>& impl, detail::RecordId id,
+ const UnregisterPrefixSuccessCallback& onSuccess,
+ const UnregisterPrefixFailureCallback& onFailure);
+
+private:
+ weak_ptr<Face::Impl> m_weakImpl;
+ detail::RecordId m_id = 0;
+
+ friend Face;
};
-/** \brief A scoped handle of registered prefix.
+/** \brief Scoped handle for a registered prefix.
*
* Upon destruction of this handle, the prefix is unregistered automatically.
* Most commonly, the application keeps a ScopedRegisteredPrefixHandle as a class member field,
@@ -605,33 +556,30 @@
* ScopedRegisteredPrefixHandle hdl = face.registerPrefix(prefix, onSuccess, onFailure);
* } // hdl goes out of scope, unregistering the prefix
* \endcode
- *
- * \warning Unregistering a prefix after the face has been destructed may trigger undefined
- * behavior.
*/
using ScopedRegisteredPrefixHandle = detail::ScopedCancelHandle<RegisteredPrefixHandle>;
-/** \brief A handle of registered Interest filter.
+/** \brief Handle for a registered Interest filter.
*
* \code
* InterestFilterHandle hdl = face.setInterestFilter(prefix, onInterest);
* hdl.cancel(); // unset the Interest filter
* \endcode
- *
- * \warning Unsetting an Interest filter after the face has been destructed may trigger
- * undefined behavior.
*/
class InterestFilterHandle : public detail::CancelHandle
{
public:
InterestFilterHandle() noexcept = default;
- InterestFilterHandle(Face& face, const InterestFilterId* id);
+private:
+ InterestFilterHandle(weak_ptr<Face::Impl> impl, detail::RecordId id);
+
+ friend Face;
};
-/** \brief A scoped handle of registered Interest filter.
+/** \brief Scoped handle for a registered Interest filter.
*
- * Upon destruction of this handle, the Interest filter is unset automatically.
+ * Upon destruction of this handle, the Interest filter is canceled automatically.
* Most commonly, the application keeps a ScopedInterestFilterHandle as a class member field,
* so that it can cleanup its Interest filter when the class instance is destructed.
*
@@ -640,9 +588,6 @@
* ScopedInterestFilterHandle hdl = face.setInterestFilter(prefix, onInterest);
* } // hdl goes out of scope, unsetting the Interest filter
* \endcode
- *
- * \warning Unsetting an Interest filter after the face has been destructed may trigger
- * undefined behavior.
*/
using ScopedInterestFilterHandle = detail::ScopedCancelHandle<InterestFilterHandle>;
diff --git a/ndn-cxx/impl/face-impl.hpp b/ndn-cxx/impl/face-impl.hpp
index 2e98467..97736e8 100644
--- a/ndn-cxx/impl/face-impl.hpp
+++ b/ndn-cxx/impl/face-impl.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -23,6 +23,7 @@
#define NDN_IMPL_FACE_IMPL_HPP
#include "ndn-cxx/face.hpp"
+#include "ndn-cxx/impl/interest-filter-record.hpp"
#include "ndn-cxx/impl/lp-field-tag.hpp"
#include "ndn-cxx/impl/pending-interest.hpp"
#include "ndn-cxx/impl/registered-prefix.hpp"
@@ -55,36 +56,39 @@
/** @brief implementation detail of Face
*/
-class Face::Impl : noncopyable
+class Face::Impl : public std::enable_shared_from_this<Face::Impl>
{
public:
- using PendingInterestTable = RecordContainer<PendingInterest>;
- using InterestFilterTable = RecordContainer<InterestFilterRecord>;
- using RegisteredPrefixTable = RecordContainer<RegisteredPrefix>;
-
Impl(Face& face, KeyChain& keyChain)
: m_face(face)
, m_scheduler(m_face.getIoService())
, m_nfdController(m_face, keyChain)
{
- auto postOnEmptyPitOrNoRegisteredPrefixes = [this] {
- this->m_face.getIoService().post([this] { this->onEmptyPitOrNoRegisteredPrefixes(); });
- // without this extra "post", transport can get paused (-async_read) and then resumed
+ auto onEmptyPitOrNoRegisteredPrefixes = [this] {
+ // Without this extra "post", transport can get paused (-async_read) and then resumed
// (+async_read) from within onInterest/onData callback. After onInterest/onData
// finishes, there is another +async_read with the same memory block. A few of such
// async_read duplications can cause various effects and result in segfault.
+ m_face.getIoService().post([this] {
+ if (m_pendingInterestTable.empty() && m_registeredPrefixTable.empty()) {
+ m_face.m_transport->pause();
+ if (!m_ioServiceWork) {
+ m_processEventsTimeoutEvent.cancel();
+ }
+ }
+ });
};
- m_pendingInterestTable.onEmpty.connect(postOnEmptyPitOrNoRegisteredPrefixes);
- m_registeredPrefixTable.onEmpty.connect(postOnEmptyPitOrNoRegisteredPrefixes);
+ m_pendingInterestTable.onEmpty.connect(onEmptyPitOrNoRegisteredPrefixes);
+ m_registeredPrefixTable.onEmpty.connect(onEmptyPitOrNoRegisteredPrefixes);
}
public: // consumer
void
- asyncExpressInterest(RecordId id, shared_ptr<const Interest> interest,
- const DataCallback& afterSatisfied,
- const NackCallback& afterNacked,
- const TimeoutCallback& afterTimeout)
+ expressInterest(detail::RecordId id, shared_ptr<const Interest> interest,
+ const DataCallback& afterSatisfied,
+ const NackCallback& afterNacked,
+ const TimeoutCallback& afterTimeout)
{
NDN_LOG_DEBUG("<I " << *interest);
this->ensureConnected(true);
@@ -104,13 +108,18 @@
}
void
- asyncRemovePendingInterest(RecordId id)
+ asyncRemovePendingInterest(detail::RecordId id)
{
- m_pendingInterestTable.erase(id);
+ m_face.getIoService().post([id, w = weak_ptr<Impl>{shared_from_this()}] { // use weak_from_this() in C++17
+ auto impl = w.lock();
+ if (impl != nullptr) {
+ impl->m_pendingInterestTable.erase(id);
+ }
+ });
}
void
- asyncRemoveAllPendingInterests()
+ removeAllPendingInterests()
{
m_pendingInterestTable.clear();
}
@@ -176,21 +185,21 @@
public: // producer
void
- asyncSetInterestFilter(RecordId id, const InterestFilter& filter,
- const InterestCallback& onInterest)
+ setInterestFilter(detail::RecordId id, const InterestFilter& filter, const InterestCallback& onInterest)
{
NDN_LOG_INFO("setting InterestFilter: " << filter);
m_interestFilterTable.put(id, filter, onInterest);
}
void
- asyncUnsetInterestFilter(RecordId id)
+ asyncUnsetInterestFilter(detail::RecordId id)
{
- const InterestFilterRecord* record = m_interestFilterTable.get(id);
- if (record != nullptr) {
- NDN_LOG_INFO("unsetting InterestFilter: " << record->getFilter());
- m_interestFilterTable.erase(id);
- }
+ m_face.getIoService().post([id, w = weak_ptr<Impl>{shared_from_this()}] { // use weak_from_this() in C++17
+ auto impl = w.lock();
+ if (impl != nullptr) {
+ impl->unsetInterestFilter(id);
+ }
+ });
}
void
@@ -202,20 +211,7 @@
}
void
- dispatchInterest(PendingInterest& entry, const Interest& interest)
- {
- m_interestFilterTable.forEach([&] (const InterestFilterRecord& filter) {
- if (!filter.doesMatch(entry)) {
- return;
- }
- NDN_LOG_DEBUG(" matches " << filter.getFilter());
- entry.recordForwarding();
- filter.invokeInterestCallback(interest);
- });
- }
-
- void
- asyncPutData(const Data& data)
+ putData(const Data& data)
{
NDN_LOG_DEBUG("<D " << data.getName());
bool shouldSendToForwarder = satisfyPendingInterests(data);
@@ -234,7 +230,7 @@
}
void
- asyncPutNack(const lp::Nack& nack)
+ putNack(const lp::Nack& nack)
{
NDN_LOG_DEBUG("<N " << nack.getInterest() << '~' << nack.getHeader().getReason());
optional<lp::Nack> outNack = nackPendingInterests(nack);
@@ -254,7 +250,7 @@
}
public: // prefix registration
- RecordId
+ detail::RecordId
registerPrefix(const Name& prefix,
const RegisterPrefixSuccessCallback& onSuccess,
const RegisterPrefixFailureCallback& onFailure,
@@ -269,16 +265,15 @@
[=] (const nfd::ControlParameters&) {
NDN_LOG_INFO("registered prefix: " << prefix);
- RecordId filterId = 0;
+ detail::RecordId filterId = 0;
if (filter) {
NDN_LOG_INFO("setting InterestFilter: " << *filter);
- InterestFilterRecord& filterRecord = m_interestFilterTable.insert(*filter, onInterest);
+ auto& filterRecord = m_interestFilterTable.insert(*filter, onInterest);
filterId = filterRecord.getId();
}
-
m_registeredPrefixTable.put(id, prefix, options, filterId);
- if (onSuccess != nullptr) {
+ if (onSuccess) {
onSuccess(prefix);
}
},
@@ -292,39 +287,16 @@
}
void
- asyncUnregisterPrefix(RecordId id,
+ asyncUnregisterPrefix(detail::RecordId id,
const UnregisterPrefixSuccessCallback& onSuccess,
const UnregisterPrefixFailureCallback& onFailure)
{
- const RegisteredPrefix* record = m_registeredPrefixTable.get(id);
- if (record == nullptr) {
- if (onFailure != nullptr) {
- onFailure("Unrecognized RegisteredPrefixHandle");
+ m_face.getIoService().post([=, w = weak_ptr<Impl>{shared_from_this()}] { // use weak_from_this() in C++17
+ auto impl = w.lock();
+ if (impl != nullptr) {
+ impl->unregisterPrefix(id, onSuccess, onFailure);
}
- return;
- }
-
- if (record->getFilterId() != 0) {
- asyncUnsetInterestFilter(record->getFilterId());
- }
-
- NDN_LOG_INFO("unregistering prefix: " << record->getPrefix());
-
- m_nfdController.start<nfd::RibUnregisterCommand>(
- nfd::ControlParameters().setName(record->getPrefix()),
- [=] (const nfd::ControlParameters&) {
- NDN_LOG_INFO("unregistered prefix: " << record->getPrefix());
- m_registeredPrefixTable.erase(id);
-
- if (onSuccess != nullptr) {
- onSuccess();
- }
- },
- [=] (const nfd::ControlResponse& resp) {
- NDN_LOG_INFO("unregister prefix failed: " << record->getPrefix());
- onFailure(resp.getText());
- },
- record->getCommandOptions());
+ });
}
public: // IO routine
@@ -342,17 +314,6 @@
}
void
- onEmptyPitOrNoRegisteredPrefixes()
- {
- if (m_pendingInterestTable.empty() && m_registeredPrefixTable.empty()) {
- m_face.m_transport->pause();
- if (!m_ioServiceWork) {
- m_processEventsTimeoutEvent.cancel();
- }
- }
- }
-
- void
shutdown()
{
m_ioServiceWork.reset();
@@ -384,15 +345,75 @@
return wire;
}
+ void
+ dispatchInterest(PendingInterest& entry, const Interest& interest)
+ {
+ m_interestFilterTable.forEach([&] (const InterestFilterRecord& filter) {
+ if (!filter.doesMatch(entry)) {
+ return;
+ }
+ NDN_LOG_DEBUG(" matches " << filter.getFilter());
+ entry.recordForwarding();
+ filter.invokeInterestCallback(interest);
+ });
+ }
+
+ void
+ unsetInterestFilter(detail::RecordId id)
+ {
+ const auto* record = m_interestFilterTable.get(id);
+ if (record != nullptr) {
+ NDN_LOG_INFO("unsetting InterestFilter: " << record->getFilter());
+ m_interestFilterTable.erase(id);
+ }
+ }
+
+ void
+ unregisterPrefix(detail::RecordId id,
+ const UnregisterPrefixSuccessCallback& onSuccess,
+ const UnregisterPrefixFailureCallback& onFailure)
+ {
+ const auto* record = m_registeredPrefixTable.get(id);
+ if (record == nullptr) {
+ if (onFailure) {
+ onFailure("Unrecognized RegisteredPrefixHandle");
+ }
+ return;
+ }
+
+ if (record->getFilterId() != 0) {
+ unsetInterestFilter(record->getFilterId());
+ }
+
+ NDN_LOG_INFO("unregistering prefix: " << record->getPrefix());
+
+ m_nfdController.start<nfd::RibUnregisterCommand>(
+ nfd::ControlParameters().setName(record->getPrefix()),
+ [=] (const nfd::ControlParameters&) {
+ NDN_LOG_INFO("unregistered prefix: " << record->getPrefix());
+ m_registeredPrefixTable.erase(id);
+ if (onSuccess) {
+ onSuccess();
+ }
+ },
+ [=] (const nfd::ControlResponse& resp) {
+ NDN_LOG_INFO("unregister prefix failed: " << record->getPrefix());
+ if (onFailure) {
+ onFailure(resp.getText());
+ }
+ },
+ record->getCommandOptions());
+ }
+
private:
Face& m_face;
Scheduler m_scheduler;
scheduler::ScopedEventId m_processEventsTimeoutEvent;
nfd::Controller m_nfdController;
- PendingInterestTable m_pendingInterestTable;
- InterestFilterTable m_interestFilterTable;
- RegisteredPrefixTable m_registeredPrefixTable;
+ detail::RecordContainer<PendingInterest> m_pendingInterestTable;
+ detail::RecordContainer<InterestFilterRecord> m_interestFilterTable;
+ detail::RecordContainer<RegisteredPrefix> m_registeredPrefixTable;
unique_ptr<boost::asio::io_service::work> m_ioServiceWork; // if thread needs to be preserved
diff --git a/ndn-cxx/impl/interest-filter-record.hpp b/ndn-cxx/impl/interest-filter-record.hpp
index e3c7ea6..3dc40fe 100644
--- a/ndn-cxx/impl/interest-filter-record.hpp
+++ b/ndn-cxx/impl/interest-filter-record.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -23,32 +23,25 @@
#define NDN_IMPL_INTEREST_FILTER_RECORD_HPP
#include "ndn-cxx/impl/pending-interest.hpp"
+#include "ndn-cxx/impl/record-container.hpp"
namespace ndn {
/**
- * @brief Opaque type to identify an InterestFilterRecord
+ * @brief Associates an InterestFilter with an Interest callback.
*/
-class InterestFilterId;
-
-static_assert(sizeof(const InterestFilterId*) == sizeof(RecordId), "");
-
-/**
- * @brief associates an InterestFilter with Interest callback
- */
-class InterestFilterRecord : public RecordBase<InterestFilterRecord>
+class InterestFilterRecord : public detail::RecordBase<InterestFilterRecord>
{
public:
/**
* @brief Construct an Interest filter record
*
* @param filter an InterestFilter that represents what Interest should invoke the callback
- * @param interestCallback invoked when matching Interest is received
+ * @param callback invoked when matching Interest is received
*/
- InterestFilterRecord(const InterestFilter& filter,
- const InterestCallback& interestCallback)
+ InterestFilterRecord(const InterestFilter& filter, const InterestCallback& callback)
: m_filter(filter)
- , m_interestCallback(interestCallback)
+ , m_interestCallback(callback)
{
}
diff --git a/ndn-cxx/impl/pending-interest.hpp b/ndn-cxx/impl/pending-interest.hpp
index a766056..7ace1dc 100644
--- a/ndn-cxx/impl/pending-interest.hpp
+++ b/ndn-cxx/impl/pending-interest.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -32,14 +32,7 @@
namespace ndn {
/**
- * @brief Opaque type to identify a PendingInterest
- */
-class PendingInterestId;
-
-static_assert(sizeof(const PendingInterestId*) == sizeof(RecordId), "");
-
-/**
- * @brief Indicates where a pending Interest came from
+ * @brief Indicates where a pending Interest came from.
*/
enum class PendingInterestOrigin
{
@@ -60,9 +53,9 @@
}
/**
- * @brief Stores a pending Interest and associated callbacks
+ * @brief Stores a pending Interest and associated callbacks.
*/
-class PendingInterest : public RecordBase<PendingInterest>
+class PendingInterest : public detail::RecordBase<PendingInterest>
{
public:
/**
@@ -79,18 +72,16 @@
, m_dataCallback(dataCallback)
, m_nackCallback(nackCallback)
, m_timeoutCallback(timeoutCallback)
- , m_nNotNacked(0)
{
scheduleTimeoutEvent(scheduler);
}
/**
- * @brief Construct a pending Interest record for an Interest from NFD
+ * @brief Construct a pending Interest record for an Interest from the forwarder
*/
PendingInterest(shared_ptr<const Interest> interest, Scheduler& scheduler)
: m_interest(std::move(interest))
, m_origin(PendingInterestOrigin::FORWARDER)
- , m_nNotNacked(0)
{
scheduleTimeoutEvent(scheduler);
}
@@ -121,7 +112,7 @@
/**
* @brief Record an incoming Nack against a forwarded Interest
* @return least severe Nack if all destinations where the Interest was forwarded have Nacked;
- * otherwise, nullopt
+ * otherwise, nullopt
*/
optional<lp::Nack>
recordNack(const lp::Nack& nack)
@@ -143,7 +134,7 @@
void
invokeDataCallback(const Data& data)
{
- if (m_dataCallback != nullptr) {
+ if (m_dataCallback) {
m_dataCallback(*m_interest, data);
}
}
@@ -155,7 +146,7 @@
void
invokeNackCallback(const lp::Nack& nack)
{
- if (m_nackCallback != nullptr) {
+ if (m_nackCallback) {
m_nackCallback(*m_interest, nack);
}
}
@@ -188,9 +179,8 @@
NackCallback m_nackCallback;
TimeoutCallback m_timeoutCallback;
scheduler::ScopedEventId m_timeoutEvent;
- int m_nNotNacked; ///< number of Interest destinations that have not Nacked
+ int m_nNotNacked = 0; ///< number of Interest destinations that have not Nacked
optional<lp::Nack> m_leastSevereNack;
- std::function<void()> m_deleter;
};
} // namespace ndn
diff --git a/ndn-cxx/impl/record-container.hpp b/ndn-cxx/impl/record-container.hpp
index 94b2f5e..efbb8f5 100644
--- a/ndn-cxx/impl/record-container.hpp
+++ b/ndn-cxx/impl/record-container.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -28,8 +28,9 @@
#include <atomic>
namespace ndn {
+namespace detail {
-using RecordId = uintptr_t;
+using RecordId = uint64_t;
template<typename T>
class RecordContainer;
@@ -194,6 +195,7 @@
std::atomic<RecordId> m_lastId{0};
};
+} // namespace detail
} // namespace ndn
#endif // NDN_IMPL_RECORD_CONTAINER_HPP
diff --git a/ndn-cxx/impl/registered-prefix.hpp b/ndn-cxx/impl/registered-prefix.hpp
index 423aec1..37fe179 100644
--- a/ndn-cxx/impl/registered-prefix.hpp
+++ b/ndn-cxx/impl/registered-prefix.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -22,27 +22,19 @@
#ifndef NDN_IMPL_REGISTERED_PREFIX_HPP
#define NDN_IMPL_REGISTERED_PREFIX_HPP
-#include "ndn-cxx/impl/interest-filter-record.hpp"
+#include "ndn-cxx/impl/record-container.hpp"
#include "ndn-cxx/mgmt/nfd/command-options.hpp"
-#include "ndn-cxx/mgmt/nfd/control-parameters.hpp"
namespace ndn {
/**
- * @brief Opaque type to identify a RegisteredPrefix
+ * @brief Stores information about a prefix registered in an NDN forwarder.
*/
-class RegisteredPrefixId;
-
-static_assert(sizeof(const RegisteredPrefixId*) == sizeof(RecordId), "");
-
-/**
- * @brief stores information about a prefix registered in NDN forwarder
- */
-class RegisteredPrefix : public RecordBase<RegisteredPrefix>
+class RegisteredPrefix : public detail::RecordBase<RegisteredPrefix>
{
public:
RegisteredPrefix(const Name& prefix, const nfd::CommandOptions& options,
- RecordId filterId = 0)
+ detail::RecordId filterId = 0)
: m_prefix(prefix)
, m_options(options)
, m_filterId(filterId)
@@ -61,7 +53,7 @@
return m_options;
}
- RecordId
+ detail::RecordId
getFilterId() const
{
return m_filterId;
@@ -70,7 +62,7 @@
private:
Name m_prefix;
nfd::CommandOptions m_options;
- RecordId m_filterId;
+ detail::RecordId m_filterId;
};
} // namespace ndn
diff --git a/ndn-cxx/mgmt/dispatcher.hpp b/ndn-cxx/mgmt/dispatcher.hpp
index 308e89a..d41f415 100644
--- a/ndn-cxx/mgmt/dispatcher.hpp
+++ b/ndn-cxx/mgmt/dispatcher.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -151,17 +151,16 @@
*
* Procedure for adding a top-level prefix:
* 1. if the new top-level prefix overlaps with an existing top-level prefix
- * (one top-level prefix is a prefix of another top-level prefix), throw std::domain_error
- * 2. if wantRegister is true, invoke face.registerPrefix for the top-level prefix;
+ * (one top-level prefix is a prefix of another top-level prefix), throw std::domain_error.
+ * 2. if \p wantRegister is true, invoke Face::registerPrefix for the top-level prefix;
* the returned RegisteredPrefixHandle shall be recorded internally, indexed by the top-level
- * prefix
- * 3. foreach relPrefix from ControlCommands and StatusDatasets,
- * join the top-level prefix with the relPrefix to obtain the full prefix,
- * and invoke non-registering overload of face.setInterestFilter,
+ * prefix.
+ * 3. for each `relPrefix` from ControlCommands and StatusDatasets,
+ * join the top-level prefix with `relPrefix` to obtain the full prefix,
+ * and invoke non-registering overload of Face::setInterestFilter,
* with the InterestHandler set to an appropriate private method to handle incoming Interests
- * for the ControlCommand or StatusDataset;
- * the returned InterestFilterHandle shall be recorded internally, indexed by the top-level
- * prefix
+ * for the ControlCommand or StatusDataset; the returned InterestFilterHandle shall be
+ * recorded internally, indexed by the top-level prefix.
*/
void
addTopPrefix(const Name& prefix, bool wantRegister = true,
@@ -171,9 +170,9 @@
* \param prefix a top-level prefix, e.g., "/localhost/nfd"
*
* Procedure for removing a top-level prefix:
- * 1. if the top-level prefix has not been added, abort these steps
- * 2. if the top-level prefix has been added with wantRegister, unregister the prefix
- * 3. unset each Interest filter recorded during addTopPrefix,
+ * 1. if the top-level prefix has not been added, abort these steps.
+ * 2. if the top-level prefix has been added with `wantRegister`, unregister the prefix.
+ * 3. clear all Interest filters set during addTopPrefix().
*/
void
removeTopPrefix(const Name& prefix);
diff --git a/tests/unit/face.t.cpp b/tests/unit/face.t.cpp
index eb01f8f..ef1cab3 100644
--- a/tests/unit/face.t.cpp
+++ b/tests/unit/face.t.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -43,7 +43,7 @@
template<typename PrefixRegReply = WantPrefixRegReply>
class FaceFixture : public IdentityManagementTimeFixture
{
-public:
+protected:
FaceFixture()
: face(io, m_keyChain, {true, !std::is_same<PrefixRegReply, NoPrefixRegReply>::value})
{
@@ -59,8 +59,8 @@
const RegisterPrefixFailureCallback& failure)> f)
{
boost::logic::tribool result = boost::logic::indeterminate;
- f([&] (const Name&) { result = true; },
- [&] (const Name&, const std::string&) { result = false; });
+ f([&] (auto) { result = true; },
+ [&] (auto, auto) { result = false; });
advanceClocks(1_ms);
BOOST_REQUIRE(!boost::logic::indeterminate(result));
@@ -75,22 +75,23 @@
const UnregisterPrefixFailureCallback& failure)> f)
{
boost::logic::tribool result = boost::logic::indeterminate;
- f([&] { result = true; }, [&] (const std::string&) { result = false; });
+ f([&] { result = true; },
+ [&] (auto) { result = false; });
advanceClocks(1_ms);
BOOST_REQUIRE(!boost::logic::indeterminate(result));
return static_cast<bool>(result);
}
-public:
+protected:
DummyClientFace face;
};
BOOST_FIXTURE_TEST_SUITE(TestFace, FaceFixture<>)
-BOOST_AUTO_TEST_SUITE(Consumer)
+BOOST_AUTO_TEST_SUITE(ExpressInterest)
-BOOST_AUTO_TEST_CASE(ExpressInterestData)
+BOOST_AUTO_TEST_CASE(ReplyData)
{
size_t nData = 0;
face.expressInterest(*makeInterest("/Hello/World", true, 50_ms),
@@ -122,21 +123,17 @@
BOOST_CHECK_EQUAL(nTimeouts, 1);
}
-BOOST_AUTO_TEST_CASE(ExpressMultipleInterestData)
+BOOST_AUTO_TEST_CASE(MultipleData)
{
size_t nData = 0;
face.expressInterest(*makeInterest("/Hello/World", true, 50_ms),
- [&] (const Interest& i, const Data& d) {
- ++nData;
- },
+ [&] (const auto&, const auto&) { ++nData; },
bind([] { BOOST_FAIL("Unexpected Nack"); }),
bind([] { BOOST_FAIL("Unexpected timeout"); }));
face.expressInterest(*makeInterest("/Hello/World/a", true, 50_ms),
- [&] (const Interest& i, const Data& d) {
- ++nData;
- },
+ [&] (const auto&, const auto&) { ++nData; },
bind([] { BOOST_FAIL("Unexpected Nack"); }),
bind([] { BOOST_FAIL("Unexpected timeout"); }));
@@ -151,7 +148,7 @@
BOOST_CHECK_EQUAL(face.sentData.size(), 0);
}
-BOOST_AUTO_TEST_CASE(ExpressInterestEmptyDataCallback)
+BOOST_AUTO_TEST_CASE(EmptyDataCallback)
{
face.expressInterest(*makeInterest("/Hello/World", true),
nullptr,
@@ -165,7 +162,7 @@
} while (false));
}
-BOOST_AUTO_TEST_CASE(ExpressInterestTimeout)
+BOOST_AUTO_TEST_CASE(Timeout)
{
size_t nTimeouts = 0;
face.expressInterest(*makeInterest("/Hello/World", false, 50_ms),
@@ -184,7 +181,7 @@
BOOST_CHECK_EQUAL(face.sentNacks.size(), 0);
}
-BOOST_AUTO_TEST_CASE(ExpressInterestEmptyTimeoutCallback)
+BOOST_AUTO_TEST_CASE(EmptyTimeoutCallback)
{
face.expressInterest(*makeInterest("/Hello/World", false, 50_ms),
bind([] { BOOST_FAIL("Unexpected Data"); }),
@@ -197,7 +194,7 @@
} while (false));
}
-BOOST_AUTO_TEST_CASE(ExpressInterestNack)
+BOOST_AUTO_TEST_CASE(ReplyNack)
{
size_t nNacks = 0;
@@ -223,24 +220,20 @@
BOOST_CHECK_EQUAL(face.sentInterests.size(), 1);
}
-BOOST_AUTO_TEST_CASE(ExpressMultipleInterestNack)
+BOOST_AUTO_TEST_CASE(MultipleNacks)
{
size_t nNacks = 0;
auto interest = makeInterest("/Hello/World", false, 50_ms, 1);
face.expressInterest(*interest,
bind([] { BOOST_FAIL("Unexpected Data"); }),
- [&] (const Interest& i, const lp::Nack& n) {
- ++nNacks;
- },
+ [&] (const auto&, const auto&) { ++nNacks; },
bind([] { BOOST_FAIL("Unexpected timeout"); }));
interest->setNonce(2);
face.expressInterest(*interest,
bind([] { BOOST_FAIL("Unexpected Data"); }),
- [&] (const Interest& i, const lp::Nack& n) {
- ++nNacks;
- },
+ [&] (const auto&, const auto&) { ++nNacks; },
bind([] { BOOST_FAIL("Unexpected timeout"); }));
advanceClocks(40_ms);
@@ -253,7 +246,7 @@
BOOST_CHECK_EQUAL(face.sentInterests.size(), 2);
}
-BOOST_AUTO_TEST_CASE(ExpressInterestEmptyNackCallback)
+BOOST_AUTO_TEST_CASE(EmptyNackCallback)
{
face.expressInterest(*makeInterest("/Hello/World"),
bind([] { BOOST_FAIL("Unexpected Data"); }),
@@ -267,24 +260,67 @@
} while (false));
}
-BOOST_AUTO_TEST_CASE(CancelPendingInterestHandle)
+BOOST_AUTO_TEST_CASE(PutDataFromDataCallback) // Bug 4596
+{
+ face.expressInterest(*makeInterest("/localhost/notification/1"),
+ [&] (const auto&, const auto&) {
+ face.put(*makeData("/chronosync/sampleDigest/1"));
+ }, nullptr, nullptr);
+ advanceClocks(10_ms);
+ BOOST_CHECK_EQUAL(face.sentInterests.back().getName(), "/localhost/notification/1");
+
+ face.receive(*makeInterest("/chronosync/sampleDigest", true));
+ advanceClocks(10_ms);
+
+ face.put(*makeData("/localhost/notification/1"));
+ advanceClocks(10_ms);
+ BOOST_CHECK_EQUAL(face.sentData.back().getName(), "/chronosync/sampleDigest/1");
+}
+
+BOOST_AUTO_TEST_CASE(DestroyWithPendingInterest)
+{
+ auto face2 = make_unique<DummyClientFace>(io, m_keyChain);
+ face2->expressInterest(*makeInterest("/Hello/World", false, 50_ms),
+ nullptr, nullptr, nullptr);
+ advanceClocks(50_ms, 2);
+ face2.reset();
+
+ advanceClocks(50_ms, 2); // should not crash - Bug 2518
+
+ // avoid "test case [...] did not check any assertions" message from Boost.Test
+ BOOST_CHECK(true);
+}
+
+BOOST_AUTO_TEST_CASE(Handle)
{
auto hdl = face.expressInterest(*makeInterest("/Hello/World", true, 50_ms),
bind([] { BOOST_FAIL("Unexpected data"); }),
bind([] { BOOST_FAIL("Unexpected nack"); }),
bind([] { BOOST_FAIL("Unexpected timeout"); }));
- advanceClocks(10_ms);
-
+ advanceClocks(1_ms);
hdl.cancel();
- advanceClocks(10_ms);
-
+ advanceClocks(1_ms);
face.receive(*makeData("/Hello/World/%21"));
advanceClocks(200_ms, 5);
+ // cancel after destructing face
+ auto face2 = make_unique<DummyClientFace>(io, m_keyChain);
+ auto hdl2 = face2->expressInterest(*makeInterest("/Hello/World", true, 50_ms),
+ bind([] { BOOST_FAIL("Unexpected data"); }),
+ bind([] { BOOST_FAIL("Unexpected nack"); }),
+ bind([] { BOOST_FAIL("Unexpected timeout"); }));
+ advanceClocks(1_ms);
+ face2.reset();
+ advanceClocks(1_ms);
+ hdl2.cancel(); // should not crash
+ advanceClocks(1_ms);
+
// avoid "test case [...] did not check any assertions" message from Boost.Test
BOOST_CHECK(true);
}
+BOOST_AUTO_TEST_SUITE_END() // ExpressInterest
+
BOOST_AUTO_TEST_CASE(RemoveAllPendingInterests)
{
face.expressInterest(*makeInterest("/Hello/World/0", false, 50_ms),
@@ -309,40 +345,6 @@
advanceClocks(200_ms, 5);
}
-BOOST_AUTO_TEST_CASE(DestructionWithoutCancellingPendingInterests) // Bug #2518
-{
- {
- DummyClientFace face2(io, m_keyChain);
- face2.expressInterest(*makeInterest("/Hello/World", false, 50_ms),
- nullptr, nullptr, nullptr);
- advanceClocks(50_ms, 2);
- }
-
- advanceClocks(50_ms, 2); // should not crash
-
- // avoid "test case [...] did not check any assertions" message from Boost.Test
- BOOST_CHECK(true);
-}
-
-BOOST_AUTO_TEST_CASE(DataCallbackPutData) // Bug 4596
-{
- face.expressInterest(*makeInterest("/localhost/notification/1"),
- [&] (const Interest& i, const Data& d) {
- face.put(*makeData("/chronosync/sampleDigest/1"));
- }, nullptr, nullptr);
- advanceClocks(10_ms);
- BOOST_CHECK_EQUAL(face.sentInterests.back().getName(), "/localhost/notification/1");
-
- face.receive(*makeInterest("/chronosync/sampleDigest", true));
- advanceClocks(10_ms);
-
- face.put(*makeData("/localhost/notification/1"));
- advanceClocks(10_ms);
- BOOST_CHECK_EQUAL(face.sentData.back().getName(), "/chronosync/sampleDigest/1");
-}
-
-BOOST_AUTO_TEST_SUITE_END() // Consumer
-
BOOST_AUTO_TEST_SUITE(Producer)
BOOST_AUTO_TEST_CASE(PutData)
@@ -511,7 +513,72 @@
BOOST_CHECK_EQUAL(hasNack, true);
}
-BOOST_AUTO_TEST_CASE(SetUnsetInterestFilter)
+BOOST_AUTO_TEST_SUITE_END() // Producer
+
+BOOST_AUTO_TEST_SUITE(RegisterPrefix)
+
+BOOST_FIXTURE_TEST_CASE(Failure, FaceFixture<NoPrefixRegReply>)
+{
+ BOOST_CHECK(!runPrefixReg([&] (const auto& success, const auto& failure) {
+ face.registerPrefix("/Hello/World", success, failure);
+ this->advanceClocks(5_s, 20); // wait for command timeout
+ }));
+}
+
+BOOST_AUTO_TEST_CASE(Handle)
+{
+ RegisteredPrefixHandle hdl;
+ auto doReg = [&] {
+ return runPrefixReg([&] (const auto& success, const auto& failure) {
+ hdl = face.registerPrefix("/Hello/World", success, failure);
+ });
+ };
+ auto doUnreg = [&] {
+ return runPrefixUnreg([&] (const auto& success, const auto& failure) {
+ hdl.unregister(success, failure);
+ });
+ };
+
+ // despite the "undefined behavior" warning, we try not to crash, but no API guarantee for this
+ BOOST_CHECK(!doUnreg());
+
+ // cancel after unregister
+ BOOST_CHECK(doReg());
+ BOOST_CHECK(doUnreg());
+ hdl.cancel();
+ advanceClocks(1_ms);
+
+ // unregister after cancel
+ BOOST_CHECK(doReg());
+ hdl.cancel();
+ advanceClocks(1_ms);
+ BOOST_CHECK(!doUnreg());
+
+ // cancel after destructing face
+ auto face2 = make_unique<DummyClientFace>(io, m_keyChain);
+ hdl = face2->registerPrefix("/Hello/World/2", nullptr,
+ bind([] { BOOST_FAIL("Unexpected registerPrefix failure"); }));
+ advanceClocks(1_ms);
+ face2.reset();
+ advanceClocks(1_ms);
+ hdl.cancel(); // should not crash
+ advanceClocks(1_ms);
+
+ // unregister after destructing face
+ auto face3 = make_unique<DummyClientFace>(io, m_keyChain);
+ hdl = face3->registerPrefix("/Hello/World/3", nullptr,
+ bind([] { BOOST_FAIL("Unexpected registerPrefix failure"); }));
+ advanceClocks(1_ms);
+ face3.reset();
+ advanceClocks(1_ms);
+ BOOST_CHECK(!doUnreg());
+}
+
+BOOST_AUTO_TEST_SUITE_END() // RegisterPrefix
+
+BOOST_AUTO_TEST_SUITE(SetInterestFilter)
+
+BOOST_AUTO_TEST_CASE(SetAndCancel)
{
size_t nInterests = 0;
size_t nRegs = 0;
@@ -543,15 +610,9 @@
face.receive(*makeInterest("/Hello/World/%21/3"));
BOOST_CHECK_EQUAL(nInterests, 2);
-
- face.unsetInterestFilter(static_cast<const RegisteredPrefixId*>(nullptr));
- advanceClocks(25_ms, 4);
-
- face.unsetInterestFilter(static_cast<const InterestFilterId*>(nullptr));
- advanceClocks(25_ms, 4);
}
-BOOST_AUTO_TEST_CASE(SetInterestFilterEmptyInterestCallback)
+BOOST_AUTO_TEST_CASE(EmptyInterestCallback)
{
face.setInterestFilter("/A", nullptr);
advanceClocks(1_ms);
@@ -562,7 +623,7 @@
} while (false));
}
-BOOST_AUTO_TEST_CASE(SetUnsetInterestFilterWithoutSucessCallback)
+BOOST_AUTO_TEST_CASE(WithoutSuccessCallback)
{
size_t nInterests = 0;
auto hdl = face.setInterestFilter("/Hello/World",
@@ -590,15 +651,9 @@
face.receive(*makeInterest("/Hello/World/%21/3"));
BOOST_CHECK_EQUAL(nInterests, 2);
-
- face.unsetInterestFilter(static_cast<const RegisteredPrefixId*>(nullptr));
- advanceClocks(25_ms, 4);
-
- face.unsetInterestFilter(static_cast<const InterestFilterId*>(nullptr));
- advanceClocks(25_ms, 4);
}
-BOOST_FIXTURE_TEST_CASE(SetInterestFilterFail, FaceFixture<NoPrefixRegReply>)
+BOOST_FIXTURE_TEST_CASE(Failure, FaceFixture<NoPrefixRegReply>)
{
// don't enable registration reply
size_t nRegFailed = 0;
@@ -614,7 +669,7 @@
BOOST_CHECK_EQUAL(nRegFailed, 1);
}
-BOOST_FIXTURE_TEST_CASE(SetInterestFilterFailWithoutSuccessCallback, FaceFixture<NoPrefixRegReply>)
+BOOST_FIXTURE_TEST_CASE(FailureWithoutSuccessCallback, FaceFixture<NoPrefixRegReply>)
{
// don't enable registration reply
size_t nRegFailed = 0;
@@ -629,31 +684,6 @@
BOOST_CHECK_EQUAL(nRegFailed, 1);
}
-BOOST_FIXTURE_TEST_CASE(RegisterUnregisterPrefixFail, FaceFixture<NoPrefixRegReply>)
-{
- BOOST_CHECK(!runPrefixReg([&] (const auto& success, const auto& failure) {
- face.registerPrefix("/Hello/World", success, failure);
- this->advanceClocks(5_s, 20); // wait for command timeout
- }));
-}
-
-BOOST_AUTO_TEST_CASE(RegisterUnregisterPrefixHandle)
-{
- RegisteredPrefixHandle hdl;
- BOOST_CHECK(!runPrefixUnreg([&] (const auto& success, const auto& failure) {
- // despite the "undefined behavior" warning, we try not to crash, but no API guarantee for this
- hdl.unregister(success, failure);
- }));
-
- BOOST_CHECK(runPrefixReg([&] (const auto& success, const auto& failure) {
- hdl = face.registerPrefix("/Hello/World", success, failure);
- }));
-
- BOOST_CHECK(runPrefixUnreg([&] (const auto& success, const auto& failure) {
- hdl.unregister(success, failure);
- }));
-}
-
BOOST_AUTO_TEST_CASE(SimilarFilters)
{
size_t nInInterests1 = 0;
@@ -684,21 +714,7 @@
BOOST_CHECK_EQUAL(nInInterests3, 0);
}
-BOOST_AUTO_TEST_CASE(SetRegexFilterError)
-{
- face.setInterestFilter(InterestFilter("/Hello/World", "<><b><c>?"),
- [] (const Name&, const Interest&) {
- BOOST_FAIL("InterestFilter::Error should have been triggered");
- },
- nullptr,
- bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); }));
-
- advanceClocks(25_ms, 4);
-
- BOOST_REQUIRE_THROW(face.receive(*makeInterest("/Hello/World/XXX/b/c")), InterestFilter::Error);
-}
-
-BOOST_AUTO_TEST_CASE(SetRegexFilter)
+BOOST_AUTO_TEST_CASE(RegexFilter)
{
size_t nInInterests = 0;
face.setInterestFilter(InterestFilter("/Hello/World", "<><b><c>?"),
@@ -721,7 +737,21 @@
BOOST_CHECK_EQUAL(nInInterests, 2);
}
-BOOST_AUTO_TEST_CASE(SetRegexFilterAndRegister)
+BOOST_AUTO_TEST_CASE(RegexFilterError)
+{
+ face.setInterestFilter(InterestFilter("/Hello/World", "<><b><c>?"),
+ [] (const Name&, const Interest&) {
+ BOOST_FAIL("InterestFilter::Error should have been triggered");
+ },
+ nullptr,
+ bind([] { BOOST_FAIL("Unexpected setInterestFilter failure"); }));
+
+ advanceClocks(25_ms, 4);
+
+ BOOST_CHECK_THROW(face.receive(*makeInterest("/Hello/World/XXX/b/c")), InterestFilter::Error);
+}
+
+BOOST_AUTO_TEST_CASE(RegexFilterAndRegisterPrefix)
{
size_t nInInterests = 0;
face.setInterestFilter(InterestFilter("/Hello/World", "<><b><c>?"),
@@ -748,7 +778,7 @@
BOOST_CHECK_EQUAL(nInInterests, 2);
}
-BOOST_FIXTURE_TEST_CASE(SetInterestFilterNoReg, FaceFixture<NoPrefixRegReply>) // Bug 2318
+BOOST_FIXTURE_TEST_CASE(WithoutRegisterPrefix, FaceFixture<NoPrefixRegReply>) // Bug 2318
{
// This behavior is specific to DummyClientFace.
// Regular Face won't accept incoming packets until something is sent.
@@ -763,10 +793,10 @@
BOOST_CHECK_EQUAL(hit, 1);
}
-BOOST_AUTO_TEST_CASE(SetInterestFilterHandle)
+BOOST_AUTO_TEST_CASE(Handle)
{
int hit = 0;
- auto hdl = face.setInterestFilter(Name("/"), bind([&hit] { ++hit; }));
+ InterestFilterHandle hdl = face.setInterestFilter(Name("/"), bind([&hit] { ++hit; }));
face.processEvents(-1_ms);
face.receive(*makeInterest("/A"));
@@ -779,11 +809,18 @@
face.receive(*makeInterest("/B"));
face.processEvents(-1_ms);
BOOST_CHECK_EQUAL(hit, 1);
+
+ // cancel after destructing face
+ auto face2 = make_unique<DummyClientFace>(io, m_keyChain);
+ InterestFilterHandle hdl2 = face2->setInterestFilter("/Hello/World/2", nullptr);
+ advanceClocks(1_ms);
+ face2.reset();
+ advanceClocks(1_ms);
+ hdl2.cancel(); // should not crash
+ advanceClocks(1_ms);
}
-BOOST_AUTO_TEST_SUITE_END() // Producer
-
-BOOST_AUTO_TEST_SUITE(IoRoutines)
+BOOST_AUTO_TEST_SUITE_END() // SetInterestFilter
BOOST_AUTO_TEST_CASE(ProcessEvents)
{
@@ -813,8 +850,6 @@
BOOST_CHECK(true);
}
-BOOST_AUTO_TEST_SUITE_END() // IoRoutines
-
BOOST_AUTO_TEST_SUITE(Transport)
using ndn::Transport;