fw: introduce afterContentStoreHit strategy trigger

Change-Id: I71ca9e21467d2296203eb9686bff7647b1140271
refs: #4290
diff --git a/daemon/fw/forwarder.cpp b/daemon/fw/forwarder.cpp
index cb7ac9d..93be2e9 100644
--- a/daemon/fw/forwarder.cpp
+++ b/daemon/fw/forwarder.cpp
@@ -213,11 +213,12 @@
   pitEntry->isSatisfied = true;
   pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
 
-  // finalize Interest
-  this->onInterestFinalize(pitEntry);
+  // set PIT expiry timer to now
+  this->setExpiryTimer(pitEntry, 0_ms);
 
-  // goto outgoing Data pipeline
-  this->onOutgoingData(data, *const_pointer_cast<Face>(inFace.shared_from_this()));
+  // dispatch to strategy: after Content Store hit
+  this->dispatchToStrategy(*pitEntry,
+    [&] (fw::Strategy& strategy) { strategy.afterContentStoreHit(pitEntry, inFace, data); });
 }
 
 void
diff --git a/daemon/fw/strategy.cpp b/daemon/fw/strategy.cpp
index d4d6827..a05080f 100644
--- a/daemon/fw/strategy.cpp
+++ b/daemon/fw/strategy.cpp
@@ -157,6 +157,16 @@
 }
 
 void
+Strategy::afterContentStoreHit(const shared_ptr<pit::Entry>& pitEntry,
+                               const Face& inFace, const Data& data)
+{
+  NFD_LOG_DEBUG("afterContentStoreHit pitEntry=" << pitEntry->getName() <<
+                " inFace=" << inFace.getId() << " data=" << data.getName());
+
+  this->sendData(pitEntry, data, inFace);
+}
+
+void
 Strategy::afterReceiveNack(const Face& inFace, const lp::Nack& nack,
                            const shared_ptr<pit::Entry>& pitEntry)
 {
diff --git a/daemon/fw/strategy.hpp b/daemon/fw/strategy.hpp
index 12a06e8..e770e27 100644
--- a/daemon/fw/strategy.hpp
+++ b/daemon/fw/strategy.hpp
@@ -161,6 +161,14 @@
   beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
                         const Face& inFace, const Data& data);
 
+  /** \brief trigger after a Data is matched in CS
+   *
+   *  In the base class this method sends \p data to \p inFace
+   */
+  virtual void
+  afterContentStoreHit(const shared_ptr<pit::Entry>& pitEntry,
+                       const Face& inFace, const Data& data);
+
   /** \brief trigger after Nack is received
    *
    *  This trigger is invoked when an incoming Nack is received in response to
@@ -177,7 +185,7 @@
    *  If a Nack arrives from another upstream during the extended PIT entry lifetime, this trigger will be invoked again.
    *  At that time, this function must invoke \c setExpiryTimer again to continue collecting more responses.
    *
-   *  In this base class this method does nothing.
+   *  In the base class this method does nothing.
    *
    *  \warning The strategy must not retain shared_ptr<pit::Entry>, otherwise undefined behavior
    *           may occur. However, the strategy is allowed to store weak_ptr<pit::Entry>.
@@ -206,6 +214,19 @@
     m_forwarder.onOutgoingInterest(pitEntry, outFace, interest);
   }
 
+  /** \brief send \p data to \p outFace
+   *  \param pitEntry PIT entry
+   *  \param data the Data packet
+   *  \param outFace face through which to send out the Data
+   */
+  VIRTUAL_WITH_TESTS void
+  sendData(const shared_ptr<pit::Entry>& pitEntry, const Data& data, const Face& outFace)
+  {
+    BOOST_ASSERT(pitEntry->getInterest().matchesData(data));
+
+    m_forwarder.onOutgoingData(data, *const_pointer_cast<Face>(outFace.shared_from_this()));
+  }
+
   /** \brief schedule the PIT entry for immediate deletion
    *
    *  This helper function sets the PIT entry expiry time to zero.