face: don't use memory address as PendingInterestId
Using memory address as PendingInterestId may cause false
removal of PendingInterest record if the memory allocator places
a different Interest at the same position in the heap.
refs #2865
Change-Id: Icf4d11509ad5c2acd56f180a333a68aa96f31768
diff --git a/ndn-cxx/face.cpp b/ndn-cxx/face.cpp
index 6522e64..5d4cb65 100644
--- a/ndn-cxx/face.cpp
+++ b/ndn-cxx/face.cpp
@@ -179,14 +179,16 @@
const NackCallback& afterNacked,
const TimeoutCallback& afterTimeout)
{
+ auto id = m_impl->generatePendingInterestId();
+
auto interest2 = make_shared<Interest>(interest);
interest2->getNonce();
IO_CAPTURE_WEAK_IMPL(post) {
- impl->asyncExpressInterest(interest2, afterSatisfied, afterNacked, afterTimeout);
+ impl->asyncExpressInterest(id, interest2, afterSatisfied, afterNacked, afterTimeout);
} IO_CAPTURE_WEAK_IMPL_END
- return PendingInterestHandle(*this, reinterpret_cast<const PendingInterestId*>(interest2.get()));
+ return PendingInterestHandle(*this, id);
}
void
diff --git a/ndn-cxx/impl/face-impl.hpp b/ndn-cxx/impl/face-impl.hpp
index 2f68557..14599ab 100644
--- a/ndn-cxx/impl/face-impl.hpp
+++ b/ndn-cxx/impl/face-impl.hpp
@@ -67,6 +67,7 @@
Impl(Face& face)
: m_face(face)
, m_scheduler(m_face.getIoService())
+ , m_lastPendingInterestId(0)
{
auto postOnEmptyPitOrNoRegisteredPrefixes = [this] {
this->m_face.getIoService().post([this] { this->onEmptyPitOrNoRegisteredPrefixes(); });
@@ -81,8 +82,16 @@
}
public: // consumer
+ const PendingInterestId*
+ generatePendingInterestId()
+ {
+ auto id = ++m_lastPendingInterestId;
+ return reinterpret_cast<const PendingInterestId*>(id);
+ }
+
void
- asyncExpressInterest(shared_ptr<const Interest> interest,
+ asyncExpressInterest(const PendingInterestId* id,
+ shared_ptr<const Interest> interest,
const DataCallback& afterSatisfied,
const NackCallback& afterNacked,
const TimeoutCallback& afterTimeout)
@@ -92,7 +101,7 @@
const Interest& interest2 = *interest;
auto i = m_pendingInterestTable.insert(make_shared<PendingInterest>(
- std::move(interest), afterSatisfied, afterNacked, afterTimeout, ref(m_scheduler))).first;
+ id, std::move(interest), afterSatisfied, afterNacked, afterTimeout, ref(m_scheduler))).first;
// In dispatchInterest, an InterestCallback may respond with Data right away and delete
// the PendingInterestTable entry. shared_ptr is retained to ensure PendingInterest instance
// remains valid in this case.
@@ -418,6 +427,7 @@
util::Scheduler m_scheduler;
util::scheduler::ScopedEventId m_processEventsTimeoutEvent;
+ std::atomic_uintptr_t m_lastPendingInterestId;
PendingInterestTable m_pendingInterestTable;
InterestFilterTable m_interestFilterTable;
RegisteredPrefixTable m_registeredPrefixTable;
diff --git a/ndn-cxx/impl/pending-interest.hpp b/ndn-cxx/impl/pending-interest.hpp
index 6495f56..ac14304 100644
--- a/ndn-cxx/impl/pending-interest.hpp
+++ b/ndn-cxx/impl/pending-interest.hpp
@@ -31,6 +31,11 @@
namespace ndn {
/**
+ * @brief Opaque type to identify a PendingInterest
+ */
+class PendingInterestId;
+
+/**
* @brief Indicates where a pending Interest came from
*/
enum class PendingInterestOrigin
@@ -63,19 +68,15 @@
*
* The timeout is set based on the current time and InterestLifetime.
* This class will invoke the timeout callback unless the record is deleted before timeout.
- *
- * @param interest the Interest
- * @param dataCallback invoked when matching Data packet is received
- * @param nackCallback invoked when Nack matching Interest is received
- * @param timeoutCallback invoked when Interest times out
- * @param scheduler Scheduler for scheduling the timeout event
*/
- PendingInterest(shared_ptr<const Interest> interest,
+ PendingInterest(const PendingInterestId* id,
+ shared_ptr<const Interest> interest,
const DataCallback& dataCallback,
const NackCallback& nackCallback,
const TimeoutCallback& timeoutCallback,
Scheduler& scheduler)
- : m_interest(std::move(interest))
+ : m_id(id)
+ , m_interest(std::move(interest))
, m_origin(PendingInterestOrigin::APP)
, m_dataCallback(dataCallback)
, m_nackCallback(nackCallback)
@@ -92,16 +93,20 @@
* @param scheduler Scheduler for scheduling the timeout event
*/
PendingInterest(shared_ptr<const Interest> interest, Scheduler& scheduler)
- : m_interest(std::move(interest))
+ : m_id(nullptr)
+ , m_interest(std::move(interest))
, m_origin(PendingInterestOrigin::FORWARDER)
, m_nNotNacked(0)
{
scheduleTimeoutEvent(scheduler);
}
- /**
- * @brief Get the Interest
- */
+ const PendingInterestId*
+ getId() const
+ {
+ return m_id;
+ }
+
shared_ptr<const Interest>
getInterest() const
{
@@ -199,6 +204,7 @@
}
private:
+ const PendingInterestId* m_id;
shared_ptr<const Interest> m_interest;
PendingInterestOrigin m_origin;
DataCallback m_dataCallback;
@@ -211,11 +217,6 @@
};
/**
- * @brief Opaque type to identify a PendingInterest
- */
-class PendingInterestId;
-
-/**
* @brief Functor to match PendingInterestId
*/
class MatchPendingInterestId
@@ -230,7 +231,7 @@
bool
operator()(const shared_ptr<const PendingInterest>& pendingInterest) const
{
- return reinterpret_cast<const PendingInterestId*>(pendingInterest->getInterest().get()) == m_id;
+ return pendingInterest->getId() == m_id;
}
private: