[ndnSIM] fw: Keep both the CS of NFD and ndnSIM

Change-Id: I0c7abbc09a1be393eddfe8ef3cd7ab60b1622996
Ref: #2231
diff --git a/daemon/fw/forwarder.cpp b/daemon/fw/forwarder.cpp
index 69a93de..5d7abdf 100644
--- a/daemon/fw/forwarder.cpp
+++ b/daemon/fw/forwarder.cpp
@@ -31,6 +31,8 @@
 #include "table/cleanup.hpp"
 #include <ndn-cxx/lp/tags.hpp>
 
+#include "face/null-face.hpp"
+
 namespace nfd {
 
 NFD_LOG_INIT("Forwarder");
@@ -47,7 +49,10 @@
   , m_pit(m_nameTree)
   , m_measurements(m_nameTree)
   , m_strategyChoice(*this)
+  , m_csFace(face::makeNullFace(FaceUri("contentstore://")))
 {
+  getFaceTable().addReserved(m_csFace, face::FACEID_CONTENT_STORE);
+
   m_faceTable.afterAdd.connect([this] (Face& face) {
     face.afterReceiveInterest.connect(
       [this, &face] (const Interest& interest) {
@@ -126,11 +131,23 @@
   // cancel unsatisfy & straggler timer
   this->cancelUnsatisfyAndStragglerTimer(*pitEntry);
 
-  // is pending?
-  if (!pitEntry->hasInRecords()) {
-    m_cs.find(interest,
-              bind(&Forwarder::onContentStoreHit, this, ref(inFace), pitEntry, _1, _2),
-              bind(&Forwarder::onContentStoreMiss, this, ref(inFace), pitEntry, _1));
+  const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
+  bool isPending = inRecords.begin() != inRecords.end();
+  if (!isPending) {
+    if (m_csFromNdnSim == nullptr) {
+      m_cs.find(interest,
+                bind(&Forwarder::onContentStoreHit, this, ref(inFace), pitEntry, _1, _2),
+                bind(&Forwarder::onContentStoreMiss, this, ref(inFace), pitEntry, _1));
+    }
+    else {
+      shared_ptr<Data> match = m_csFromNdnSim->Lookup(interest.shared_from_this());
+      if (match != nullptr) {
+        this->onContentStoreHit(inFace, pitEntry, interest, *match);
+      }
+      else {
+        this->onContentStoreMiss(inFace, pitEntry, interest);
+      }
+    }
   }
   else {
     this->onContentStoreMiss(inFace, pitEntry, interest);
@@ -198,6 +215,10 @@
   NFD_LOG_DEBUG("onContentStoreHit interest=" << interest.getName());
   ++m_counters.nCsHits;
 
+  beforeSatisfyInterest(*pitEntry, *m_csFace, data);
+  this->dispatchToStrategy(*pitEntry,
+    [&] (fw::Strategy& strategy) { strategy.beforeSatisfyInterest(pitEntry, *m_csFace, data); });
+
   data.setTag(make_shared<lp::IncomingFaceIdTag>(face::FACEID_CONTENT_STORE));
   // XXX should we lookup PIT for other Interests that also match csMatch?
 
@@ -245,6 +266,7 @@
   NFD_LOG_DEBUG("onInterestUnsatisfied interest=" << pitEntry->getName());
 
   // invoke PIT unsatisfied callback
+  beforeExpirePendingInterest(*pitEntry);
   this->dispatchToStrategy(*pitEntry,
     [&] (fw::Strategy& strategy) { strategy.beforeExpirePendingInterest(pitEntry); });
 
@@ -294,7 +316,10 @@
   }
 
   // CS insert
-  m_cs.insert(data);
+  if (m_csFromNdnSim == nullptr)
+    m_cs.insert(data);
+  else
+    m_csFromNdnSim->Add(data.shared_from_this());
 
   std::set<Face*> pendingDownstreams;
   // foreach PitEntry
@@ -313,6 +338,7 @@
     }
 
     // invoke PIT satisfy callback
+    beforeSatisfyInterest(*pitEntry, inFace, data);
     this->dispatchToStrategy(*pitEntry,
       [&] (fw::Strategy& strategy) { strategy.beforeSatisfyInterest(pitEntry, inFace, data); });
 
@@ -345,7 +371,10 @@
   fw::UnsolicitedDataDecision decision = m_unsolicitedDataPolicy->decide(inFace, data);
   if (decision == fw::UnsolicitedDataDecision::CACHE) {
     // CS insert
-    m_cs.insert(data, true);
+    if (m_csFromNdnSim == nullptr)
+      m_cs.insert(data, true);
+    else
+      m_csFromNdnSim->Add(data.shared_from_this());
   }
 
   NFD_LOG_DEBUG("onDataUnsolicited face=" << inFace.getId() <<
diff --git a/daemon/fw/forwarder.hpp b/daemon/fw/forwarder.hpp
index d2e73a8..58792ed 100644
--- a/daemon/fw/forwarder.hpp
+++ b/daemon/fw/forwarder.hpp
@@ -39,6 +39,8 @@
 #include "table/dead-nonce-list.hpp"
 #include "table/network-region-table.hpp"
 
+#include "ns3/ndnSIM/model/cs/ndn-content-store.hpp"
+
 namespace nfd {
 
 namespace fw {
@@ -182,6 +184,24 @@
     return m_networkRegionTable;
   }
 
+public: // allow enabling ndnSIM content store (will be removed in the future)
+  void
+  setCsFromNdnSim(ns3::Ptr<ns3::ndn::ContentStore> cs)
+  {
+    m_csFromNdnSim = cs;
+  }
+
+public:
+  /** \brief trigger before PIT entry is satisfied
+   *  \sa Strategy::beforeSatisfyInterest
+   */
+  signal::Signal<Forwarder, pit::Entry, Face, Data> beforeSatisfyInterest;
+
+  /** \brief trigger before PIT entry expires
+   *  \sa Strategy::beforeExpirePendingInterest
+   */
+  signal::Signal<Forwarder, pit::Entry> beforeExpirePendingInterest;
+
 PUBLIC_WITH_TESTS_ELSE_PRIVATE: // pipelines
   /** \brief incoming Interest pipeline
    */
@@ -299,6 +319,9 @@
   StrategyChoice     m_strategyChoice;
   DeadNonceList      m_deadNonceList;
   NetworkRegionTable m_networkRegionTable;
+  shared_ptr<Face>   m_csFace;
+
+  ns3::Ptr<ns3::ndn::ContentStore> m_csFromNdnSim;
 
   // allow Strategy (base class) to enter pipelines
   friend class fw::Strategy;