face+fw: store and return PitToken from downstream

refs #4532

Change-Id: I97b95232a242186601459622f17983d1bef806d6
diff --git a/daemon/face/generic-link-service.cpp b/daemon/face/generic-link-service.cpp
index 5a3664c..2ab9f7e 100644
--- a/daemon/face/generic-link-service.cpp
+++ b/daemon/face/generic-link-service.cpp
@@ -25,6 +25,7 @@
 
 #include "generic-link-service.hpp"
 
+#include <ndn-cxx/lp/pit-token.hpp>
 #include <ndn-cxx/lp/tags.hpp>
 
 #include <cmath>
@@ -129,28 +130,33 @@
 GenericLinkService::encodeLpFields(const ndn::PacketBase& netPkt, lp::Packet& lpPacket)
 {
   if (m_options.allowLocalFields) {
-    shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = netPkt.getTag<lp::IncomingFaceIdTag>();
+    auto incomingFaceIdTag = netPkt.getTag<lp::IncomingFaceIdTag>();
     if (incomingFaceIdTag != nullptr) {
       lpPacket.add<lp::IncomingFaceIdField>(*incomingFaceIdTag);
     }
   }
 
-  shared_ptr<lp::CongestionMarkTag> congestionMarkTag = netPkt.getTag<lp::CongestionMarkTag>();
+  auto congestionMarkTag = netPkt.getTag<lp::CongestionMarkTag>();
   if (congestionMarkTag != nullptr) {
     lpPacket.add<lp::CongestionMarkField>(*congestionMarkTag);
   }
 
   if (m_options.allowSelfLearning) {
-    shared_ptr<lp::NonDiscoveryTag> nonDiscoveryTag = netPkt.getTag<lp::NonDiscoveryTag>();
+    auto nonDiscoveryTag = netPkt.getTag<lp::NonDiscoveryTag>();
     if (nonDiscoveryTag != nullptr) {
       lpPacket.add<lp::NonDiscoveryField>(*nonDiscoveryTag);
     }
 
-    shared_ptr<lp::PrefixAnnouncementTag> prefixAnnouncementTag = netPkt.getTag<lp::PrefixAnnouncementTag>();
+    auto prefixAnnouncementTag = netPkt.getTag<lp::PrefixAnnouncementTag>();
     if (prefixAnnouncementTag != nullptr) {
       lpPacket.add<lp::PrefixAnnouncementField>(*prefixAnnouncementTag);
     }
   }
+
+  auto pitToken = netPkt.getTag<lp::PitToken>();
+  if (pitToken != nullptr) {
+    lpPacket.add<lp::PitTokenField>(*pitToken);
+  }
 }
 
 void
@@ -388,6 +394,10 @@
     return;
   }
 
+  if (firstPkt.has<lp::PitTokenField>()) {
+    interest->setTag(make_shared<lp::PitToken>(firstPkt.get<lp::PitTokenField>()));
+  }
+
   this->receiveInterest(*interest, endpointId);
 }
 
diff --git a/daemon/fw/strategy.cpp b/daemon/fw/strategy.cpp
index b4ccda8..b0b9362 100644
--- a/daemon/fw/strategy.cpp
+++ b/daemon/fw/strategy.cpp
@@ -27,6 +27,8 @@
 #include "forwarder.hpp"
 #include "common/logger.hpp"
 
+#include <ndn-cxx/lp/pit-token.hpp>
+
 #include <boost/range/adaptor/map.hpp>
 #include <boost/range/algorithm/copy.hpp>
 
@@ -192,15 +194,40 @@
 }
 
 void
+Strategy::sendInterest(const shared_ptr<pit::Entry>& pitEntry,
+                       const FaceEndpoint& egress, const Interest& interest)
+{
+  if (interest.getTag<lp::PitToken>() != nullptr) {
+    Interest interest2 = interest; // make a copy to preserve tag on original packet
+    interest2.removeTag<lp::PitToken>();
+    m_forwarder.onOutgoingInterest(pitEntry, egress, interest2);
+    return;
+  }
+  m_forwarder.onOutgoingInterest(pitEntry, egress, interest);
+}
+
+void
 Strategy::sendData(const shared_ptr<pit::Entry>& pitEntry, const Data& data,
                    const FaceEndpoint& egress)
 {
   BOOST_ASSERT(pitEntry->getInterest().matchesData(data));
 
+  shared_ptr<lp::PitToken> pitToken;
+  auto inRecord = pitEntry->getInRecord(egress.face);
+  if (inRecord != pitEntry->in_end()) {
+    pitToken = inRecord->getInterest().getTag<lp::PitToken>();
+  }
+
   // delete the PIT entry's in-record based on egress,
   // since Data is sent to face and endpoint from which the Interest was received
   pitEntry->deleteInRecord(egress.face);
 
+  if (pitToken != nullptr) {
+    Data data2 = data; // make a copy so each downstream can get a different PIT token
+    data2.setTag(pitToken);
+    m_forwarder.onOutgoingData(data2, egress);
+    return;
+  }
   m_forwarder.onOutgoingData(data, egress);
 }
 
diff --git a/daemon/fw/strategy.hpp b/daemon/fw/strategy.hpp
index cc1b2b8..8c62329 100644
--- a/daemon/fw/strategy.hpp
+++ b/daemon/fw/strategy.hpp
@@ -241,10 +241,7 @@
    */
   VIRTUAL_WITH_TESTS void
   sendInterest(const shared_ptr<pit::Entry>& pitEntry,
-               const FaceEndpoint& egress, const Interest& interest)
-  {
-    m_forwarder.onOutgoingInterest(pitEntry, egress, interest);
-  }
+               const FaceEndpoint& egress, const Interest& interest);
 
   /** \brief send \p data to \p egress
    *  \param pitEntry PIT entry