face: scoped Interest filter
refs #3919
Change-Id: I4e1aed63b2fabe463e9572b99bb3d97b278cabd6
diff --git a/ndn-cxx/face.cpp b/ndn-cxx/face.cpp
index 4e09421..bf832d6 100644
--- a/ndn-cxx/face.cpp
+++ b/ndn-cxx/face.cpp
@@ -227,7 +227,7 @@
} IO_CAPTURE_WEAK_IMPL_END
}
-const RegisteredPrefixId*
+RegisteredPrefixHandle
Face::setInterestFilter(const InterestFilter& interestFilter,
const InterestCallback& onInterest,
const RegisterPrefixFailureCallback& onFailure,
@@ -237,7 +237,7 @@
return setInterestFilter(interestFilter, onInterest, nullptr, onFailure, signingInfo, flags);
}
-const RegisteredPrefixId*
+RegisteredPrefixHandle
Face::setInterestFilter(const InterestFilter& interestFilter,
const InterestCallback& onInterest,
const RegisterPrefixSuccessCallback& onSuccess,
@@ -250,11 +250,12 @@
nfd::CommandOptions options;
options.setSigningInfo(signingInfo);
- return m_impl->registerPrefix(interestFilter.getPrefix(), filter,
- onSuccess, onFailure, flags, options);
+ auto id = m_impl->registerPrefix(interestFilter.getPrefix(), filter,
+ onSuccess, onFailure, flags, options);
+ return RegisteredPrefixHandle(*this, id);
}
-const InterestFilterId*
+InterestFilterHandle
Face::setInterestFilter(const InterestFilter& interestFilter,
const InterestCallback& onInterest)
{
@@ -264,7 +265,8 @@
impl->asyncSetInterestFilter(filter);
} IO_CAPTURE_WEAK_IMPL_END
- return reinterpret_cast<const InterestFilterId*>(filter.get());
+ auto id = reinterpret_cast<const InterestFilterId*>(filter.get());
+ return InterestFilterHandle(*this, id);
}
RegisteredPrefixHandle
@@ -436,4 +438,10 @@
m_id = nullptr;
}
+InterestFilterHandle::InterestFilterHandle(Face& face, const InterestFilterId* id)
+ : CancelHandle([&face, id] { face.unsetInterestFilter(id); })
+ , m_id(id)
+{
+}
+
} // namespace ndn
diff --git a/ndn-cxx/face.hpp b/ndn-cxx/face.hpp
index b33abd4..05454ca 100644
--- a/ndn-cxx/face.hpp
+++ b/ndn-cxx/face.hpp
@@ -40,6 +40,7 @@
class RegisteredPrefixId;
class RegisteredPrefixHandle;
class InterestFilterId;
+class InterestFilterHandle;
namespace nfd {
class Controller;
@@ -275,10 +276,9 @@
* @param signingInfo (optional) Signing parameters. When omitted, a default parameters
* used in the signature will be used.
*
- * @return Opaque registered prefix ID which can be used with unsetInterestFilter or
- * removeRegisteredPrefix
+ * @return A handle for unregistering the prefix.
*/
- const RegisteredPrefixId*
+ RegisteredPrefixHandle
setInterestFilter(const InterestFilter& interestFilter,
const InterestCallback& onInterest,
const RegisterPrefixFailureCallback& onFailure,
@@ -303,10 +303,9 @@
* @param signingInfo (optional) Signing parameters. When omitted, a default parameters
* used in the signature will be used.
*
- * @return Opaque registered prefix ID which can be used with unsetInterestFilter or
- * removeRegisteredPrefix
+ * @return A handle for unregistering the prefix.
*/
- const RegisteredPrefixId*
+ RegisteredPrefixHandle
setInterestFilter(const InterestFilter& interestFilter,
const InterestCallback& onInterest,
const RegisterPrefixSuccessCallback& onSuccess,
@@ -324,9 +323,9 @@
* forwarder. It will always succeed. To register prefix with the forwarder, use
* registerPrefix, or use the setInterestFilter overload taking two callbacks.
*
- * @return Opaque interest filter ID which can be used with unsetInterestFilter
+ * @return A handle for unsetting the Interest filter.
*/
- const InterestFilterId*
+ InterestFilterHandle
setInterestFilter(const InterestFilter& interestFilter,
const InterestCallback& onInterest);
@@ -344,7 +343,7 @@
* used in the signature will be used.
* @param flags Prefix registration flags
*
- * @return The registered prefix ID which can be used with unregisterPrefix
+ * @return A handle for unregistering the prefix.
* @see nfd::RouteFlags
*/
RegisteredPrefixHandle
@@ -364,7 +363,7 @@
* unsetInterestFilter will use the same credentials as original
* setInterestFilter/registerPrefix command
*
- * @param registeredPrefixId The ID returned from registerPrefix
+ * @param registeredPrefixId a handle returned from registerPrefix
*/
void
unsetInterestFilter(const RegisteredPrefixId* registeredPrefixId);
@@ -375,7 +374,7 @@
* This method always succeeds and will **NOT** send any request to the connected
* forwarder.
*
- * @param interestFilterId The ID returned from setInterestFilter.
+ * @param interestFilterId a handle returned from setInterestFilter.
*/
void
unsetInterestFilter(const InterestFilterId* interestFilterId);
@@ -389,7 +388,7 @@
* If registeredPrefixId was obtained using setInterestFilter, the corresponding
* InterestFilter will be unset too.
*
- * @param registeredPrefixId The ID returned from registerPrefix
+ * @param registeredPrefixId a handle returned from registerPrefix
* @param onSuccess Callback to be called when operation succeeds
* @param onFailure Callback to be called when operation fails
*/
@@ -586,6 +585,53 @@
*/
using ScopedRegisteredPrefixHandle = detail::ScopedCancelHandle;
+/** \brief A handle of registered Interest filter.
+ *
+ * \code
+ * InterestFilterHandle hdl = face.setInterestFilter(prefix, onInterest);
+ * hdl.cancel(); // unset the Interest filter
+ * \endcode
+ *
+ * \warning Unsetting the same Interest filter more than once, using same or different
+ * InterestFilterHandle or ScopedInterestFilterHandle, may trigger undefined behavior.
+ * \warning Unsetting an Interest filter after the face has been destructed may trigger
+ * undefined behavior.
+ */
+class InterestFilterHandle : public detail::CancelHandle
+{
+public:
+ InterestFilterHandle() = default;
+
+ InterestFilterHandle(Face& face, const InterestFilterId* id);
+
+ operator const InterestFilterId*() const
+ {
+ return m_id;
+ }
+
+private:
+ const InterestFilterId* m_id = nullptr;
+};
+
+/** \brief A scoped handle of registered Interest filter.
+ *
+ * Upon destruction of this handle, the Interest filter is unset 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.
+ *
+ * \code
+ * {
+ * ScopedInterestFilterHandle hdl = face.setInterestFilter(prefix, onInterest);
+ * } // hdl goes out of scope, unsetting the Interest filter
+ * \endcode
+ *
+ * \warning Unsetting the same Interest filter more than once, using same or different
+ * InterestFilterHandle or ScopedInterestFilterHandle, may trigger undefined behavior.
+ * \warning Unsetting an Interest filter after the face has been destructed may trigger
+ * undefined behavior.
+ */
+using ScopedInterestFilterHandle = detail::ScopedCancelHandle;
+
} // namespace ndn
#endif // NDN_FACE_HPP
diff --git a/ndn-cxx/mgmt/dispatcher.cpp b/ndn-cxx/mgmt/dispatcher.cpp
index 2c33ef9..6cc80c5 100644
--- a/ndn-cxx/mgmt/dispatcher.cpp
+++ b/ndn-cxx/mgmt/dispatcher.cpp
@@ -56,7 +56,7 @@
{
std::vector<Name> topPrefixNames;
std::transform(m_topLevelPrefixes.begin(), m_topLevelPrefixes.end(), std::back_inserter(topPrefixNames),
- [] (const auto& entry) { return entry.second.topPrefix; });
+ [] (const auto& entry) { return entry.first; });
for (const auto& name : topPrefixNames) {
removeTopPrefix(name);
@@ -76,10 +76,9 @@
}
TopPrefixEntry& topPrefixEntry = m_topLevelPrefixes[prefix];
- topPrefixEntry.topPrefix = prefix;
if (wantRegister) {
- topPrefixEntry.registeredPrefixId = m_face.registerPrefix(prefix,
+ topPrefixEntry.registeredPrefix = m_face.registerPrefix(prefix,
nullptr,
[] (const Name&, const std::string& reason) {
BOOST_THROW_EXCEPTION(std::runtime_error("prefix registration failed: " + reason));
@@ -89,28 +88,15 @@
for (const auto& entry : m_handlers) {
Name fullPrefix = Name(prefix).append(entry.first);
- const auto* filterId = m_face.setInterestFilter(fullPrefix, bind(entry.second, prefix, _2));
- topPrefixEntry.interestFilters.push_back(filterId);
+ auto filterHdl = m_face.setInterestFilter(fullPrefix, bind(entry.second, prefix, _2));
+ topPrefixEntry.interestFilters.push_back(filterHdl);
}
}
void
Dispatcher::removeTopPrefix(const Name& prefix)
{
- auto it = m_topLevelPrefixes.find(prefix);
- if (it == m_topLevelPrefixes.end()) {
- return;
- }
-
- const TopPrefixEntry& topPrefixEntry = it->second;
- if (topPrefixEntry.registeredPrefixId != nullptr) {
- m_face.unregisterPrefix(topPrefixEntry.registeredPrefixId, nullptr, nullptr);
- }
- for (const auto& filter : topPrefixEntry.interestFilters) {
- m_face.unsetInterestFilter(filter);
- }
-
- m_topLevelPrefixes.erase(it);
+ m_topLevelPrefixes.erase(prefix);
}
bool
@@ -348,7 +334,7 @@
return;
}
- Name streamName(m_topLevelPrefixes.begin()->second.topPrefix);
+ Name streamName(m_topLevelPrefixes.begin()->first);
streamName.append(relPrefix);
streamName.appendSequenceNumber(m_streams[streamName]++);
diff --git a/ndn-cxx/mgmt/dispatcher.hpp b/ndn-cxx/mgmt/dispatcher.hpp
index ab96c00..a3a2325 100644
--- a/ndn-cxx/mgmt/dispatcher.hpp
+++ b/ndn-cxx/mgmt/dispatcher.hpp
@@ -439,9 +439,8 @@
private:
struct TopPrefixEntry
{
- Name topPrefix;
- const RegisteredPrefixId* registeredPrefixId = nullptr;
- std::vector<const InterestFilterId*> interestFilters;
+ ScopedRegisteredPrefixHandle registeredPrefix;
+ std::vector<ScopedInterestFilterHandle> interestFilters;
};
std::unordered_map<Name, TopPrefixEntry> m_topLevelPrefixes;
diff --git a/tests/unit/face.t.cpp b/tests/unit/face.t.cpp
index c9b8205..7f4ba07 100644
--- a/tests/unit/face.t.cpp
+++ b/tests/unit/face.t.cpp
@@ -651,6 +651,7 @@
this->advanceClocks(5_s, 20); // wait for command timeout
}));
}
+
BOOST_AUTO_TEST_CASE(RegisterUnregisterPrefixHandle)
{
RegisteredPrefixHandle hdl;
@@ -777,6 +778,24 @@
BOOST_CHECK_EQUAL(hit, 1);
}
+BOOST_AUTO_TEST_CASE(SetInterestFilterHandle)
+{
+ int hit = 0;
+ auto hdl = face.setInterestFilter(Name("/"), bind([&hit] { ++hit; }));
+ face.processEvents(-1_ms);
+
+ face.receive(*makeInterest("/A"));
+ face.processEvents(-1_ms);
+ BOOST_CHECK_EQUAL(hit, 1);
+
+ hdl.cancel();
+ face.processEvents(-1_ms);
+
+ face.receive(*makeInterest("/B"));
+ face.processEvents(-1_ms);
+ BOOST_CHECK_EQUAL(hit, 1);
+}
+
BOOST_AUTO_TEST_SUITE_END() // Producer
BOOST_AUTO_TEST_SUITE(IoRoutines)