face: Implementing InterestFilter abstraction to be used with setInterestFilter
This commit minimally changes the API, primarily altering the internal
structures preparing for separation of `registerPrefix` (=send a command
to local forwarder to register FIB/RIB entry) and `setInterestFilter`
(=update library's InterestFilter->Callback dispatch table).
The existing setInterestFilter methods preserve all previous functionality
(any string URI or ndn::Name can be supplied as a first parameter),
but also allow InterestFilter as the filtering parameter.
InterestFilter, provides a way to select Interest either based on prefix,
as before, or based on prefix and regular expression.
Change-Id: Id71404f2163f82c261018d21db172111c4b0da69
Refs: #1275
diff --git a/src/detail/registered-prefix.hpp b/src/detail/registered-prefix.hpp
index 3a17785..8957d5e 100644
--- a/src/detail/registered-prefix.hpp
+++ b/src/detail/registered-prefix.hpp
@@ -19,47 +19,91 @@
namespace ndn {
+class InterestFilterRecord
+{
+public:
+ typedef function<void (const InterestFilter&, const Interest&)> OnInterest;
+
+ InterestFilterRecord(const InterestFilter& filter, const OnInterest& onInterest)
+ : m_filter(filter)
+ , m_onInterest(onInterest)
+ {
+ }
+
+ /**
+ * @brief Check if Interest name matches the filter
+ * @param name Interest Name
+ */
+ bool
+ doesMatch(const Name& name) const
+ {
+ return m_filter.doesMatch(name);
+ }
+
+ void
+ operator()(const Interest& interest) const
+ {
+ m_onInterest(m_filter, interest);
+ }
+
+ const InterestFilter&
+ getFilter() const
+ {
+ return m_filter;
+ }
+
+private:
+ InterestFilter m_filter;
+ OnInterest m_onInterest;
+};
+
+
class RegisteredPrefix
{
public:
- typedef function<void (const Name&, const Interest&)> OnInterest;
+ explicit
+ RegisteredPrefix(const Name& prefix)
+ : m_prefix(prefix)
+ {
+ }
- /**
- * Create a new PrefixEntry.
- * @param prefix A shared_ptr for the prefix.
- * @param onInterest A function object to call when a matching data packet is received.
- */
- RegisteredPrefix(const Name& prefix, const OnInterest& onInterest)
- : m_prefix(new Name(prefix))
- , m_onInterest(onInterest)
+ RegisteredPrefix(const Name& prefix, shared_ptr<InterestFilterRecord> filter)
+ : m_prefix(prefix)
+ , m_filter(filter)
{
}
const Name&
getPrefix() const
{
- return* m_prefix;
+ return m_prefix;
}
- const OnInterest&
- getOnInterest() const
+ const shared_ptr<InterestFilterRecord>&
+ getFilter() const
{
- return m_onInterest;
+ return m_filter;
}
private:
- shared_ptr<Name> m_prefix;
- const OnInterest m_onInterest;
+ Name m_prefix;
+
+ // to support old interface of combined (un)setInterestFilter
+ shared_ptr<InterestFilterRecord> m_filter;
};
-
-struct RegisteredPrefixId;
+/**
+ * @brief Opaque class representing ID of the registered prefix
+ */
+class RegisteredPrefixId;
/**
- * @brief Functor to match pending interests against PendingInterestId
+ * @brief Functor to match RegisteredPrefixId
*/
-struct MatchRegisteredPrefixId
+class MatchRegisteredPrefixId
{
+public:
+ explicit
MatchRegisteredPrefixId(const RegisteredPrefixId* registeredPrefixId)
: m_id(registeredPrefixId)
{
@@ -74,6 +118,33 @@
const RegisteredPrefixId* m_id;
};
+
+/**
+ * @brief Opaque class representing ID of the Interest filter
+ */
+class InterestFilterId;
+
+/**
+ * @brief Functor to match InterestFilterId
+ */
+class MatchInterestFilterId
+{
+public:
+ explicit
+ MatchInterestFilterId(const InterestFilterId* interestFilterId)
+ : m_id(interestFilterId)
+ {
+ }
+
+ bool
+ operator()(const shared_ptr<InterestFilter>& interestFilterId) const
+ {
+ return (reinterpret_cast<const InterestFilterId*>(interestFilterId.get()) == m_id);
+ }
+private:
+ const InterestFilterId* m_id;
+};
+
} // namespace ndn
#endif // NDN_DETAIL_REGISTERED_PREFIX_HPP
diff --git a/src/face.cpp b/src/face.cpp
index 44de6cc..2041a7b 100644
--- a/src/face.cpp
+++ b/src/face.cpp
@@ -219,21 +219,18 @@
m_pendingInterestTable.remove_if(MatchPendingInterestId(pendingInterestId));
}
-void
-Face::finalizeSetInterestFilter(const shared_ptr<RegisteredPrefix>& registeredPrefix)
-{
- m_registeredPrefixTable.push_back(registeredPrefix);
-}
-
const RegisteredPrefixId*
-Face::setInterestFilter(const Name& prefix,
+Face::setInterestFilter(const InterestFilter& interestFilter,
const OnInterest& onInterest,
const OnSetInterestFilterFailed& onSetInterestFilterFailed)
{
- shared_ptr<RegisteredPrefix> prefixToRegister(new RegisteredPrefix(prefix, onInterest));
+ shared_ptr<InterestFilterRecord> filter =
+ make_shared<InterestFilterRecord>(cref(interestFilter), onInterest);
+ shared_ptr<RegisteredPrefix> prefixToRegister =
+ make_shared<RegisteredPrefix>(cref(interestFilter.getPrefix()), filter);
m_fwController->selfRegisterPrefix(prefixToRegister->getPrefix(),
- bind(&Face::finalizeSetInterestFilter, this, prefixToRegister),
+ bind(&Face::afterPrefixRegistered, this, prefixToRegister),
bind(onSetInterestFilterFailed,
prefixToRegister->getPrefix(), _1));
@@ -241,15 +238,18 @@
}
const RegisteredPrefixId*
-Face::setInterestFilter(const Name& prefix,
+Face::setInterestFilter(const InterestFilter& interestFilter,
const OnInterest& onInterest,
const OnSetInterestFilterFailed& onSetInterestFilterFailed,
const IdentityCertificate& certificate)
{
- shared_ptr<RegisteredPrefix> prefixToRegister(new RegisteredPrefix(prefix, onInterest));
+ shared_ptr<InterestFilterRecord> filter =
+ make_shared<InterestFilterRecord>(cref(interestFilter), onInterest);
+ shared_ptr<RegisteredPrefix> prefixToRegister =
+ make_shared<RegisteredPrefix>(cref(interestFilter.getPrefix()), filter);
m_fwController->selfRegisterPrefix(prefixToRegister->getPrefix(),
- bind(&Face::finalizeSetInterestFilter, this, prefixToRegister),
+ bind(&Face::afterPrefixRegistered, this, prefixToRegister),
bind(onSetInterestFilterFailed,
prefixToRegister->getPrefix(), _1),
certificate);
@@ -258,15 +258,19 @@
}
const RegisteredPrefixId*
-Face::setInterestFilter(const Name& prefix,
+Face::setInterestFilter(const InterestFilter& interestFilter,
const OnInterest& onInterest,
const OnSetInterestFilterFailed& onSetInterestFilterFailed,
const Name& identity)
{
- shared_ptr<RegisteredPrefix> prefixToRegister(new RegisteredPrefix(prefix, onInterest));
+ // without ptr_lib:: here, reference to cref becomes ambiguous on OSX 10.9
+ shared_ptr<InterestFilterRecord> filter =
+ make_shared<InterestFilterRecord>(cref(interestFilter), onInterest);
+ shared_ptr<RegisteredPrefix> prefixToRegister =
+ make_shared<RegisteredPrefix>(cref(interestFilter.getPrefix()), filter);
m_fwController->selfRegisterPrefix(prefixToRegister->getPrefix(),
- bind(&Face::finalizeSetInterestFilter, this, prefixToRegister),
+ bind(&Face::afterPrefixRegistered, this, prefixToRegister),
bind(onSetInterestFilterFailed,
prefixToRegister->getPrefix(), _1),
identity);
@@ -275,6 +279,18 @@
}
void
+Face::afterPrefixRegistered(const shared_ptr<RegisteredPrefix>& registeredPrefix)
+{
+ m_registeredPrefixTable.push_back(registeredPrefix);
+
+ if (static_cast<bool>(registeredPrefix->getFilter()))
+ {
+ // it was a combined operation
+ m_interestFilterTable.push_back(registeredPrefix->getFilter());
+ }
+}
+
+void
Face::unsetInterestFilter(const RegisteredPrefixId* registeredPrefixId)
{
m_ioService->post(bind(&Face::asyncUnsetInterestFilter, this, registeredPrefixId));
@@ -304,8 +320,15 @@
MatchRegisteredPrefixId(registeredPrefixId));
if (i != m_registeredPrefixTable.end())
{
+ const shared_ptr<InterestFilterRecord>& filter = (*i)->getFilter();
+ if (static_cast<bool>(filter))
+ {
+ // it was a combined operation
+ m_interestFilterTable.remove(filter);
+ }
+
m_fwController->selfDeregisterPrefix((*i)->getPrefix(),
- bind(&Face::finalizeUnsetInterestFilter, this, i),
+ bind(&Face::finalizeUnregisterPrefix, this, i),
Controller::FailCallback());
}
@@ -321,8 +344,15 @@
MatchRegisteredPrefixId(registeredPrefixId));
if (i != m_registeredPrefixTable.end())
{
+ const shared_ptr<InterestFilterRecord>& filter = (*i)->getFilter();
+ if (static_cast<bool>(filter))
+ {
+ // it was a combined operation
+ m_interestFilterTable.remove(filter);
+ }
+
m_fwController->selfDeregisterPrefix((*i)->getPrefix(),
- bind(&Face::finalizeUnsetInterestFilter, this, i),
+ bind(&Face::finalizeUnregisterPrefix, this, i),
Controller::FailCallback(),
certificate);
}
@@ -339,8 +369,15 @@
MatchRegisteredPrefixId(registeredPrefixId));
if (i != m_registeredPrefixTable.end())
{
+ const shared_ptr<InterestFilterRecord>& filter = (*i)->getFilter();
+ if (static_cast<bool>(filter))
+ {
+ // it was a combined operation
+ m_interestFilterTable.remove(filter);
+ }
+
m_fwController->selfDeregisterPrefix((*i)->getPrefix(),
- bind(&Face::finalizeUnsetInterestFilter, this, i),
+ bind(&Face::finalizeUnregisterPrefix, this, i),
Controller::FailCallback(),
identity);
}
@@ -349,7 +386,7 @@
}
void
-Face::finalizeUnsetInterestFilter(RegisteredPrefixTable::iterator item)
+Face::finalizeUnregisterPrefix(RegisteredPrefixTable::iterator item)
{
m_registeredPrefixTable.erase(item);
@@ -529,13 +566,13 @@
void
Face::processInterestFilters(Interest& interest)
{
- for (RegisteredPrefixTable::iterator i = m_registeredPrefixTable.begin();
- i != m_registeredPrefixTable.end();
+ for (InterestFilterTable::iterator i = m_interestFilterTable.begin();
+ i != m_interestFilterTable.end();
++i)
{
- if ((*i)->getPrefix().isPrefixOf(interest.getName()))
+ if ((*i)->doesMatch(interest.getName()))
{
- (*i)->getOnInterest()((*i)->getPrefix(), interest);
+ (**i)(interest);
}
}
}
diff --git a/src/face.hpp b/src/face.hpp
index d0efc03..1758e27 100644
--- a/src/face.hpp
+++ b/src/face.hpp
@@ -31,9 +31,6 @@
namespace ndn {
-struct PendingInterestId;
-struct RegisteredPrefixId;
-
/**
* An OnData function object is used to pass a callback to expressInterest.
*/
@@ -47,12 +44,12 @@
/**
* An OnInterest function object is used to pass a callback to registerPrefix.
*/
-typedef function<void (const Name&, const Interest&)> OnInterest;
+typedef function<void (const InterestFilter&, const Interest&)> OnInterest;
/**
* An OnRegisterFailed function object is used to report when registerPrefix fails.
*/
-typedef function<void(const Name&, const std::string&)> OnSetInterestFilterFailed;
+typedef function<void(const InterestFilter&, const std::string&)> OnSetInterestFilterFailed;
@@ -203,7 +200,7 @@
* @brief Register prefix with the connected NDN hub and call onInterest when a matching
* interest is received.
*
- * @param prefix A reference to a Name for the prefix to register
+ * @param interestFilter Interest filter (prefix part will be registered with the forwarder)
* @param onInterest A function object to call when a matching interest is received
*
* @param onRegisterFailed A function object to call if failed to retrieve the connected
@@ -214,7 +211,7 @@
* @return The registered prefix ID which can be used with removeRegisteredPrefix.
*/
const RegisteredPrefixId*
- setInterestFilter(const Name& prefix,
+ setInterestFilter(const InterestFilter& interestFilter,
const OnInterest& onInterest,
const OnSetInterestFilterFailed& onSetInterestFilterFailed);
@@ -222,7 +219,7 @@
* @brief Register prefix with the connected NDN hub and call onInterest when a matching
* interest is received.
*
- * @param prefix A reference to a Name for the prefix to register
+ * @param interestFilter Interest filter (prefix part will be registered with the forwarder)
* @param onInterest A function object to call when a matching interest is received
*
* @param onRegisterFailed A function object to call if failed to retrieve the connected
@@ -236,7 +233,7 @@
* @return The registered prefix ID which can be used with removeRegisteredPrefix.
*/
const RegisteredPrefixId*
- setInterestFilter(const Name& prefix,
+ setInterestFilter(const InterestFilter& interestFilter,
const OnInterest& onInterest,
const OnSetInterestFilterFailed& onSetInterestFilterFailed,
const IdentityCertificate& certificate);
@@ -245,7 +242,7 @@
* @brief Register prefix with the connected NDN hub and call onInterest when a matching
* interest is received.
*
- * @param prefix A reference to a Name for the prefix to register
+ * @param interestFilter Interest filter (prefix part will be registered with the forwarder)
* @param onInterest A function object to call when a matching interest is received
*
* @param onRegisterFailed A function object to call if failed to retrieve the connected
@@ -259,7 +256,7 @@
* @return The registered prefix ID which can be used with removeRegisteredPrefix.
*/
const RegisteredPrefixId*
- setInterestFilter(const Name& prefix,
+ setInterestFilter(const InterestFilter& interestFilter,
const OnInterest& onInterest,
const OnSetInterestFilterFailed& onSetInterestFilterFailed,
const Name& identity);
@@ -373,6 +370,7 @@
};
typedef std::list<shared_ptr<PendingInterest> > PendingInterestTable;
+ typedef std::list<shared_ptr<InterestFilterRecord> > InterestFilterTable;
typedef std::list<shared_ptr<RegisteredPrefix> > RegisteredPrefixTable;
void
@@ -383,6 +381,9 @@
asyncRemovePendingInterest(const PendingInterestId* pendingInterestId);
void
+ afterPrefixRegistered(const shared_ptr<RegisteredPrefix>& registeredPrefix);
+
+ void
asyncUnsetInterestFilter(const RegisteredPrefixId* registeredPrefixId);
void
@@ -394,10 +395,7 @@
const Name& identity);
void
- finalizeSetInterestFilter(const shared_ptr<RegisteredPrefix>& registeredPrefix);
-
- void
- finalizeUnsetInterestFilter(RegisteredPrefixTable::iterator item);
+ finalizeUnregisterPrefix(RegisteredPrefixTable::iterator item);
void
onReceiveElement(const Block& wire);
@@ -427,6 +425,7 @@
shared_ptr<Transport> m_transport;
PendingInterestTable m_pendingInterestTable;
+ InterestFilterTable m_interestFilterTable;
RegisteredPrefixTable m_registeredPrefixTable;
shared_ptr<Controller> m_fwController;
diff --git a/src/interest-filter.hpp b/src/interest-filter.hpp
new file mode 100644
index 0000000..4cb77af
--- /dev/null
+++ b/src/interest-filter.hpp
@@ -0,0 +1,181 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (c) 2013-2014, Regents of the University of California.
+ * All rights reserved.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * This file licensed under New BSD License. See COPYING for detailed information about
+ * ndn-cxx library copyright, permissions, and redistribution restrictions.
+ */
+
+#ifndef NDN_INTEREST_FILTER_HPP
+#define NDN_INTEREST_FILTER_HPP
+
+#include "util/regex/regex-pattern-list-matcher.hpp"
+#include "name.hpp"
+
+namespace ndn {
+
+class InterestFilter
+{
+public:
+ class Error : public std::runtime_error
+ {
+ public:
+ explicit
+ Error(const std::string& what)
+ : std::runtime_error(what)
+ {
+ }
+ };
+
+ /**
+ * @brief Create an Interest filter to match Interests by prefix
+ *
+ * This filter will match all Interests, whose name start with the given prefix
+ *
+ * Any Name can be implicitly converted to the InterestFilter.
+ */
+ InterestFilter(const Name& prefix);
+
+ /**
+ * @brief Create an Interest filter to match Interests by prefix URI
+ *
+ * This filter will match all Interests, whose name start with the given prefix
+ *
+ * Any const char* can be implicitly converted to the InterestFilter.
+ */
+ InterestFilter(const char* prefixUri);
+
+ /**
+ * @brief Create an Interest filter to match Interests by prefix URI
+ *
+ * This filter will match all Interests, whose name start with the given prefix
+ *
+ * Any std::string can be implicitly converted to the InterestFilter.
+ */
+ InterestFilter(const std::string& prefixUri);
+
+ /**
+ * @brief Create an Interest filter to match Interest by prefix and regular expression
+ *
+ * This filter will match all Interests, whose name start with the given prefix and
+ * other components of the Interest name match the given regular expression.
+ * For example, the following InterestFilter:
+ *
+ * InterestFilter("/hello", "<world><>+")
+ *
+ * will match all Interests, whose name has prefix `/hello`, which is followed by
+ * component `world` and has at least one more component after it. Examples:
+ *
+ * /hello/world/!
+ * /hello/world/x/y/z
+ *
+ * Note that regular expression will need to match all components (e.g., there is
+ * an implicit heading `^` and trailing `$` symbols in the regular expression).
+ */
+ InterestFilter(const Name& prefix, const std::string& regexFilter);
+
+ /**
+ * @brief Implicit conversion to Name (to provide backwards compatibility for onInterest callback)
+ */
+ operator const Name&() const
+ {
+ if (static_cast<bool>(m_regexFilter)) {
+ throw Error("Please update OnInterest callback to accept const InterestFilter& "
+ "(non-trivial Interest filter is being used)");
+ }
+ return m_prefix;
+ }
+
+ /**
+ * @brief Check if specified name matches the filter
+ */
+ bool
+ doesMatch(const Name& name) const;
+
+ const Name&
+ getPrefix() const
+ {
+ return m_prefix;
+ }
+
+ bool
+ hasRegexFilter() const
+ {
+ return static_cast<bool>(m_regexFilter);
+ }
+
+ const RegexPatternListMatcher&
+ getRegexFilter() const
+ {
+ return *m_regexFilter;
+ }
+
+private:
+ Name m_prefix;
+ shared_ptr<RegexPatternListMatcher> m_regexFilter;
+};
+
+inline
+InterestFilter::InterestFilter(const Name& prefix)
+ : m_prefix(prefix)
+{
+}
+
+inline
+InterestFilter::InterestFilter(const char* prefixUri)
+ : m_prefix(prefixUri)
+{
+}
+
+inline
+InterestFilter::InterestFilter(const std::string& prefixUri)
+ : m_prefix(prefixUri)
+{
+}
+
+inline
+InterestFilter::InterestFilter(const Name& prefix, const std::string& regexFilter)
+ : m_prefix(prefix)
+ , m_regexFilter(new RegexPatternListMatcher(regexFilter, shared_ptr<RegexBackrefManager>()))
+{
+}
+
+inline bool
+InterestFilter::doesMatch(const Name& name) const
+{
+ if (name.size() < m_prefix.size())
+ return false;
+
+ if (hasRegexFilter()) {
+ // perform prefix match and regular expression match for the remaining components
+ bool isMatch = m_prefix.isPrefixOf(name);
+
+ if (!isMatch)
+ return false;
+
+ return m_regexFilter->match(name, m_prefix.size(), name.size() - m_prefix.size());
+ }
+ else {
+ // perform just prefix match
+
+ return m_prefix.isPrefixOf(name);
+ }
+}
+
+inline std::ostream&
+operator<<(std::ostream& os, const InterestFilter& filter)
+{
+ os << filter.getPrefix();
+ if (filter.hasRegexFilter()) {
+ os << "?regex=" << filter.getRegexFilter();
+ }
+ return os;
+}
+
+} // namespace ndn
+
+#endif // NDN_INTEREST_FILTER_HPP
diff --git a/src/interest.hpp b/src/interest.hpp
index 0e07f81..d67579e 100644
--- a/src/interest.hpp
+++ b/src/interest.hpp
@@ -18,6 +18,7 @@
#include "common.hpp"
#include "name.hpp"
#include "selectors.hpp"
+#include "interest-filter.hpp"
#include "management/nfd-local-control-header.hpp"
namespace ndn {
diff --git a/src/util/regex/regex-matcher.hpp b/src/util/regex/regex-matcher.hpp
index 88cefe0..efe906f 100644
--- a/src/util/regex/regex-matcher.hpp
+++ b/src/util/regex/regex-matcher.hpp
@@ -92,6 +92,13 @@
std::vector<name::Component> m_matchResult;
};
+inline std::ostream&
+operator<<(std::ostream& os, const RegexMatcher& regex)
+{
+ os << regex.getExpr();
+ return os;
+}
+
} // namespace ndn
#include "regex-backref-manager.hpp"