fw: Strategy::sendInterest allows changing Nonce

This commit also includes some tweaks in forwarding pipelines.

refs #1596

Change-Id: I65a4129be24089357b28fa9d35a3451e0d9ae258
diff --git a/daemon/fw/forwarder.cpp b/daemon/fw/forwarder.cpp
index 4c8aa36..2f20b5c 100644
--- a/daemon/fw/forwarder.cpp
+++ b/daemon/fw/forwarder.cpp
@@ -23,8 +23,9 @@
  **/
 
 #include "forwarder.hpp"
-#include "available-strategies.hpp"
+#include <ndn-cxx/util/random.hpp>
 #include "core/logger.hpp"
+#include "available-strategies.hpp"
 
 namespace nfd {
 
@@ -145,7 +146,8 @@
 }
 
 void
-Forwarder::onOutgoingInterest(shared_ptr<pit::Entry> pitEntry, Face& outFace)
+Forwarder::onOutgoingInterest(shared_ptr<pit::Entry> pitEntry, Face& outFace,
+                              bool wantNewNonce)
 {
   NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() <<
                 " interest=" << pitEntry->getName());
@@ -162,22 +164,33 @@
   pit::InRecordCollection::const_iterator pickedInRecord = std::max_element(
     inRecords.begin(), inRecords.end(), bind(&compare_pickInterest, _1, _2, &outFace));
   BOOST_ASSERT(pickedInRecord != inRecords.end());
-  const Interest& interest = pickedInRecord->getInterest();
+  shared_ptr<Interest> interest = const_pointer_cast<Interest>(
+    pickedInRecord->getInterest().shared_from_this());
+
+  if (wantNewNonce) {
+    interest = make_shared<Interest>(*interest);
+    interest->setNonce(ndn::random::generateWord32());
+  }
 
   // insert OutRecord
-  pitEntry->insertOrUpdateOutRecord(outFace.shared_from_this(), interest);
+  pitEntry->insertOrUpdateOutRecord(outFace.shared_from_this(), *interest);
 
   // set PIT unsatisfy timer
   this->setUnsatisfyTimer(pitEntry);
 
   // send Interest
-  outFace.sendInterest(interest);
+  outFace.sendInterest(*interest);
   m_counters.getNOutInterests() ++;
 }
 
 void
 Forwarder::onInterestReject(shared_ptr<pit::Entry> pitEntry)
 {
+  if (pitEntry->hasUnexpiredOutRecords()) {
+    NFD_LOG_ERROR("onInterestReject interest=" << pitEntry->getName() <<
+                  " cannot reject forwarded Interest");
+    return;
+  }
   NFD_LOG_DEBUG("onInterestReject interest=" << pitEntry->getName());
 
   // set PIT straggler timer
@@ -194,6 +207,7 @@
                                           pitEntry));
 
   // PIT delete
+  this->cancelUnsatisfyAndStragglerTimer(pitEntry);
   m_pit.erase(pitEntry);
 }
 
@@ -245,16 +259,16 @@
       }
     }
 
+    // invoke PIT satisfy callback
+    this->dispatchToStrategy(pitEntry, bind(&Strategy::beforeSatisfyPendingInterest, _1,
+                                            pitEntry, cref(inFace), cref(data)));
+
     // mark PIT satisfied
     pitEntry->deleteInRecords();
     pitEntry->deleteOutRecord(inFace.shared_from_this());
 
     // set PIT straggler timer
     this->setStragglerTimer(pitEntry);
-
-    // invoke PIT satisfy callback
-    this->dispatchToStrategy(pitEntry, bind(&Strategy::beforeSatisfyPendingInterest, _1,
-                                            pitEntry, cref(inFace), cref(data)));
   }
 
   // foreach pending downstream
diff --git a/daemon/fw/forwarder.hpp b/daemon/fw/forwarder.hpp
index 744338a..acb0451 100644
--- a/daemon/fw/forwarder.hpp
+++ b/daemon/fw/forwarder.hpp
@@ -114,7 +114,8 @@
   /** \brief outgoing Interest pipeline
    */
   VIRTUAL_WITH_TESTS void
-  onOutgoingInterest(shared_ptr<pit::Entry> pitEntry, Face& outFace);
+  onOutgoingInterest(shared_ptr<pit::Entry> pitEntry, Face& outFace,
+                     bool wantNewNonce = false);
 
   /** \brief Interest reject pipeline
    */
diff --git a/daemon/fw/strategy.hpp b/daemon/fw/strategy.hpp
index eaeed26..d690b0f 100644
--- a/daemon/fw/strategy.hpp
+++ b/daemon/fw/strategy.hpp
@@ -113,7 +113,8 @@
   /// send Interest to outFace
   VIRTUAL_WITH_TESTS void
   sendInterest(shared_ptr<pit::Entry> pitEntry,
-               shared_ptr<Face> outFace);
+               shared_ptr<Face> outFace,
+               bool wantNewNonce = false);
 
   /** \brief decide that a pending Interest cannot be forwarded
    *
@@ -150,9 +151,10 @@
 
 inline void
 Strategy::sendInterest(shared_ptr<pit::Entry> pitEntry,
-                       shared_ptr<Face> outFace)
+                       shared_ptr<Face> outFace,
+                       bool wantNewNonce)
 {
-  m_forwarder.onOutgoingInterest(pitEntry, *outFace);
+  m_forwarder.onOutgoingInterest(pitEntry, *outFace, wantNewNonce);
 }
 
 inline void
diff --git a/daemon/table/strategy-info-host.hpp b/daemon/table/strategy-info-host.hpp
index 361eaaf..c7aa7da 100644
--- a/daemon/table/strategy-info-host.hpp
+++ b/daemon/table/strategy-info-host.hpp
@@ -41,7 +41,7 @@
 
   template<typename T>
   shared_ptr<T>
-  getStrategyInfo();
+  getStrategyInfo() const;
 
   template<typename T>
   shared_ptr<T>
@@ -68,7 +68,7 @@
 
 template<typename T>
 shared_ptr<T>
-StrategyInfoHost::getStrategyInfo()
+StrategyInfoHost::getStrategyInfo() const
 {
   return static_pointer_cast<T, fw::StrategyInfo>(m_strategyInfo);
 }
diff --git a/tests/daemon/fw/strategy-tester.hpp b/tests/daemon/fw/strategy-tester.hpp
index e3debef..261c1a9 100644
--- a/tests/daemon/fw/strategy-tester.hpp
+++ b/tests/daemon/fw/strategy-tester.hpp
@@ -51,7 +51,9 @@
 
 protected:
   virtual void
-  sendInterest(shared_ptr<pit::Entry> pitEntry,shared_ptr<Face> outFace);
+  sendInterest(shared_ptr<pit::Entry> pitEntry,
+               shared_ptr<Face> outFace,
+               bool wantNewNonce = false);
 
   virtual void
   rejectPendingInterest(shared_ptr<pit::Entry> pitEntry);
@@ -68,7 +70,8 @@
 template<typename S>
 inline void
 StrategyTester<S>::sendInterest(shared_ptr<pit::Entry> pitEntry,
-                                shared_ptr<Face> outFace)
+                                shared_ptr<Face> outFace,
+                                bool wantNewNonce)
 {
   m_sendInterestHistory.push_back(SendInterestArgs(pitEntry, outFace));
   pitEntry->insertOrUpdateOutRecord(outFace, pitEntry->getInterest());