src: add SigningInfo and version number to SegmentPublisher

refs: #4783

Change-Id: Id5dc8d6096ff729be0b8d0f971004281e0c09eb1
diff --git a/src/consumer.cpp b/src/consumer.cpp
index 04f8b4a..84adc2a 100644
--- a/src/consumer.cpp
+++ b/src/consumer.cpp
@@ -101,7 +101,7 @@
 
   m_helloFetcher->afterSegmentValidated.connect([this] (const ndn::Data& data) {
                                                   if (data.getFinalBlock()) {
-                                                    m_helloDataName = data.getName().getPrefix(-1);
+                                                    m_helloDataName = data.getName().getPrefix(-2);
                                                   }
                                                 });
 
@@ -189,7 +189,7 @@
 
   m_syncFetcher->afterSegmentValidated.connect([this] (const ndn::Data& data) {
                                                  if (data.getFinalBlock()) {
-                                                   m_syncDataName = data.getName().getPrefix(-1);
+                                                   m_syncDataName = data.getName().getPrefix(-2);
                                                    m_syncDataContentType = data.getContentType();
                                                  }
 
diff --git a/src/full-producer.cpp b/src/full-producer.cpp
index 0953f93..133eebe 100644
--- a/src/full-producer.cpp
+++ b/src/full-producer.cpp
@@ -137,16 +137,14 @@
 
   ndn::Name nameWithoutSyncPrefix = interest.getName().getSubName(prefixName.size());
   ndn::Name interestName;
-  uint64_t interestSeq = 0;
 
   if (nameWithoutSyncPrefix.size() == 1) {
-    // Get /IBF from /IBF
+    // Get /<prefix>/IBF from /<prefix>/IBF
     interestName = interest.getName();
   }
-  else if (nameWithoutSyncPrefix.size() == 2) {
-    // Get /IBF from /IBF/<seq-no>
-    interestName = interest.getName().getPrefix(-1);
-    interestSeq = interest.getName().get(-1).toSegment();
+  else if (nameWithoutSyncPrefix.size() == 3) {
+    // Get /<prefix>/IBF from /<prefix>/IBF/<version>/<segment-no>
+    interestName = interest.getName().getPrefix(-2);
   }
   else {
     return;
@@ -207,9 +205,6 @@
 
   if (!state.getContent().empty()) {
     NDN_LOG_DEBUG("Sending sync content: " << state);
-    if (interestSeq != 0) {
-      interestName.appendSegment(interestSeq);
-    }
     sendSyncData(interestName, state.wireEncode());
     return;
   }
diff --git a/src/partial-producer.cpp b/src/partial-producer.cpp
index b0d29f1..e1570fe 100644
--- a/src/partial-producer.cpp
+++ b/src/partial-producer.cpp
@@ -74,14 +74,14 @@
 void
 PartialProducer::onHelloInterest(const ndn::Name& prefix, const ndn::Interest& interest)
 {
-  // Last component or third last component (in case of interest with IBF and segment)
-  // needs to be hello
-  if (interest.getName().get(interest.getName().size()-1).toUri() != "hello" &&
-      interest.getName().get(interest.getName().size()-3).toUri() != "hello") {
+  if (m_segmentPublisher.replyFromStore(interest.getName())) {
     return;
   }
 
-  if (m_segmentPublisher.replyFromStore(interest.getName())) {
+  // Last component or fourth last component (in case of interest with version and segment)
+  // needs to be hello
+  if (interest.getName().get(interest.getName().size()-1).toUri() != "hello" &&
+      interest.getName().get(interest.getName().size()-4).toUri() != "hello") {
     return;
   }
 
@@ -104,17 +104,25 @@
 void
 PartialProducer::onSyncInterest(const ndn::Name& prefix, const ndn::Interest& interest)
 {
-  NDN_LOG_DEBUG("Sync Interest Received, nonce: " << interest.getNonce() <<
-                " hash: " << std::hash<std::string>{}(interest.getName().toUri()));
-
-  ndn::Name interestName = interest.getName();
-
-  if (interestName.get(interestName.size() - 5).toUri() != "sync" &&
-      interestName.get(interestName.size() - 7).toUri() != "sync") {
+  if (m_segmentPublisher.replyFromStore(interest.getName())) {
     return;
   }
 
-  if (m_segmentPublisher.replyFromStore(interest.getName())) {
+  NDN_LOG_DEBUG("Sync Interest Received, nonce: " << interest.getNonce() <<
+                " hash: " << std::hash<std::string>{}(interest.getName().toUri()));
+
+  ndn::Name nameWithoutSyncPrefix = interest.getName().getSubName(prefix.size());
+  ndn::Name interestName;
+
+  if (nameWithoutSyncPrefix.size() == 4) {
+    // Get /<prefix>/BF/IBF/ from /<prefix>/BF/IBF (3 components of BF + 1 for IBF)
+    interestName = interest.getName();
+  }
+  else if (nameWithoutSyncPrefix.size() == 6) {
+    // Get <prefix>/BF/IBF/ from /<prefix>/BF/IBF/<version>/<segment-no>
+    interestName = interest.getName().getPrefix(-2);
+  }
+  else {
     return;
   }
 
diff --git a/src/partial-producer.hpp b/src/partial-producer.hpp
index cb014fc..de12fb8 100644
--- a/src/partial-producer.hpp
+++ b/src/partial-producer.hpp
@@ -97,6 +97,7 @@
   void
   satisfyPendingSyncInterests(const ndn::Name& prefix);
 
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   /**
    * @brief Receive hello interest from consumer and respond with hello data
    *
@@ -105,7 +106,6 @@
   void
   onHelloInterest(const ndn::Name& prefix, const ndn::Interest& interest);
 
-PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   /**
    * @brief Receive sync interest from consumer
    *
diff --git a/src/segment-publisher.cpp b/src/segment-publisher.cpp
index d78d47f..394dfc5 100644
--- a/src/segment-publisher.cpp
+++ b/src/segment-publisher.cpp
@@ -34,7 +34,8 @@
 
 void
 SegmentPublisher::publish(const ndn::Name& interestName, const ndn::Name& dataName,
-                          const ndn::Block& block, ndn::time::milliseconds freshness)
+                          const ndn::Block& block, ndn::time::milliseconds freshness,
+                          const ndn::security::SigningInfo& signingInfo)
 {
   uint64_t interestSegment = 0;
   if (interestName[-1].isSegment()) {
@@ -52,6 +53,9 @@
 
   uint64_t totalSegments = buffer.size() / maxPacketSize;
 
+  ndn::Name segmentPrefix(dataName);
+  segmentPrefix.appendVersion();
+
   uint64_t segmentNo = 0;
   do {
     const uint8_t* segmentEnd = segmentBegin + maxPacketSize;
@@ -59,7 +63,7 @@
       segmentEnd = end;
     }
 
-    ndn::Name segmentName(dataName);
+    ndn::Name segmentName(segmentPrefix);
     segmentName.appendSegment(segmentNo);
 
     // We get a std::exception: bad_weak_ptr from m_ims if we don't use shared_ptr for data
@@ -70,7 +74,7 @@
 
     segmentBegin = segmentEnd;
 
-    m_keyChain.sign(*data);
+    m_keyChain.sign(*data, signingInfo);
 
     // Put on face only the segment which has a pending interest
     // otherwise the segment is unsolicited
diff --git a/src/segment-publisher.hpp b/src/segment-publisher.hpp
index b23ac52..8e00624 100644
--- a/src/segment-publisher.hpp
+++ b/src/segment-publisher.hpp
@@ -54,7 +54,9 @@
    */
   void
   publish(const ndn::Name& interestName, const ndn::Name& dataName,
-          const ndn::Block& block, ndn::time::milliseconds freshness);
+          const ndn::Block& block, ndn::time::milliseconds freshness,
+          const ndn::security::SigningInfo& signingInfo =
+            ndn::security::v2::KeyChain::getDefaultSigningInfo());
 
   /**
    * @brief Try to reply from memory, return false if we cannot find the segment.
diff --git a/tests/test-full-sync.cpp b/tests/test-full-sync.cpp
index 01a5375..d8335b0 100644
--- a/tests/test-full-sync.cpp
+++ b/tests/test-full-sync.cpp
@@ -394,6 +394,46 @@
   }
 }
 
+BOOST_AUTO_TEST_CASE(DelayedSecondSegment)
+{
+  addNode(0);
+
+  for (int i = 0; i < 300; i++) {
+    Name prefixToPublish("userNode0-" + to_string(i));
+    nodes[0]->addUserNode(prefixToPublish);
+    nodes[0]->publishName(prefixToPublish);
+  }
+
+  advanceClocks(ndn::time::milliseconds(10), 100);
+
+  Name syncInterestName(syncPrefix);
+  IBLT iblt(40);
+  iblt.appendToName(syncInterestName);
+
+  nodes[0]->onSyncInterest(syncPrefix, Interest(syncInterestName));
+
+  advanceClocks(ndn::time::milliseconds(10));
+
+  BOOST_CHECK_EQUAL(nodes[0]->m_segmentPublisher.m_ims.size(), 2);
+  // Expire contents from segmentPublisher
+  advanceClocks(ndn::time::milliseconds(10), 100);
+  BOOST_CHECK_EQUAL(nodes[0]->m_segmentPublisher.m_ims.size(), 0);
+
+  // Get data name from face and increase segment number to form next interest
+  Name dataName = faces[0]->sentData.front().getName();
+  Name interestName = dataName.getSubName(0, dataName.size() - 1);
+  interestName.appendSegment(1);
+  faces[0]->sentData.clear();
+
+  nodes[0]->onSyncInterest(syncPrefix, Interest(interestName));
+  advanceClocks(ndn::time::milliseconds(10));
+
+  // Should have repopulated SegmentPublisher
+  BOOST_CHECK_EQUAL(nodes[0]->m_segmentPublisher.m_ims.size(), 2);
+  // Should have received the second data segment this time
+  BOOST_CHECK_EQUAL(faces[0]->sentData.front().getName()[-1].toSegment(), 1);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace psync
\ No newline at end of file
diff --git a/tests/test-partial-producer.cpp b/tests/test-partial-producer.cpp
index 2ff1a5d..9555c7d 100644
--- a/tests/test-partial-producer.cpp
+++ b/tests/test-partial-producer.cpp
@@ -83,6 +83,7 @@
 
   Name syncInterestName(syncPrefix);
   syncInterestName.append("sync");
+  Name syncInterestPrefix = syncInterestName;
 
   BloomFilter bf(20, 0.001);
   bf.appendToName(syncInterestName);
@@ -92,7 +93,7 @@
   Interest syncInterest(syncInterestName);
   syncInterest.setInterestLifetime(time::milliseconds(1000));
   syncInterest.setNonce(1);
-  BOOST_REQUIRE_NO_THROW(producer.onSyncInterest(syncInterestName, syncInterest));
+  BOOST_REQUIRE_NO_THROW(producer.onSyncInterest(syncInterestPrefix, syncInterest));
   face.processEvents(time::milliseconds(10));
   BOOST_CHECK_EQUAL(producer.m_pendingEntries.size(), 1);
 
@@ -100,7 +101,7 @@
 
   // Same interest again - size of pending interest should remain same, but expirationEvent should change
   syncInterest.setNonce(2);
-  BOOST_REQUIRE_NO_THROW(producer.onSyncInterest(syncInterestName, syncInterest));
+  BOOST_REQUIRE_NO_THROW(producer.onSyncInterest(syncInterestPrefix, syncInterest));
   face.processEvents(time::milliseconds(10));
   BOOST_CHECK_EQUAL(producer.m_pendingEntries.size(), 1);
 
diff --git a/tests/test-partial-sync.cpp b/tests/test-partial-sync.cpp
index 6d07644..d4c1784 100644
--- a/tests/test-partial-sync.cpp
+++ b/tests/test-partial-sync.cpp
@@ -362,6 +362,19 @@
   consumers[0]->sendHelloInterest();
   advanceClocks(ndn::time::milliseconds(10));
   BOOST_CHECK_EQUAL(numHelloDataRcvd, 1);
+
+  // Simulate sending delayed interest for second segment
+  Name dataName = face.sentData.back().getName();
+  face.sentData.clear();
+  BOOST_CHECK_EQUAL(producer->m_segmentPublisher.m_ims.size(), 2);
+
+  advanceClocks(ndn::time::milliseconds(1000));
+  BOOST_CHECK_EQUAL(producer->m_segmentPublisher.m_ims.size(), 0);
+
+  producer->onHelloInterest(consumers[0]->m_helloInterestPrefix, Interest(dataName));
+  advanceClocks(ndn::time::milliseconds(10));
+  BOOST_CHECK_EQUAL(producer->m_segmentPublisher.m_ims.size(), 2);
+  BOOST_CHECK_EQUAL(face.sentData.front().getName()[-1].toSegment(), 1);
 }
 
 BOOST_AUTO_TEST_CASE(SegmentedSync)
@@ -382,6 +395,13 @@
   advanceClocks(ndn::time::milliseconds(10));
   BOOST_CHECK_EQUAL(numHelloDataRcvd, 1);
 
+  // To be used later to simulate sending delayed segmented interest
+  ndn::Name syncInterestName(consumers[0]->m_syncInterestPrefix);
+  consumers[0]->m_bloomFilter.appendToName(syncInterestName);
+  syncInterestName.append(consumers[0]->m_iblt);
+  syncInterestName.appendVersion();
+  syncInterestName.appendSegment(1);
+
   oldSeqMap = producer->m_prefixes;
   for (int i = 1; i < 10; i++) {
     producer->updateSeqNo(longNameToExceedDataSize.toUri() + "-" + to_string(i), 1);
@@ -392,6 +412,20 @@
 
   advanceClocks(ndn::time::milliseconds(1500));
   BOOST_CHECK_EQUAL(numSyncDataRcvd, 1);
+
+  // Simulate sending delayed interest for second segment
+  face.sentData.clear();
+  consumerFaces[0]->sentData.clear();
+
+  BOOST_CHECK_EQUAL(producer->m_segmentPublisher.m_ims.size(), 2);
+
+  advanceClocks(ndn::time::milliseconds(2000));
+  BOOST_CHECK_EQUAL(producer->m_segmentPublisher.m_ims.size(), 0);
+
+  producer->onSyncInterest(consumers[0]->m_syncInterestPrefix, Interest(syncInterestName));
+  advanceClocks(ndn::time::milliseconds(10));
+  BOOST_CHECK_EQUAL(producer->m_segmentPublisher.m_ims.size(), 2);
+  BOOST_CHECK_EQUAL(face.sentData.front().getName()[-1].toSegment(), 1);
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/test-segment-publisher.cpp b/tests/test-segment-publisher.cpp
index 39881d8..db81f30 100644
--- a/tests/test-segment-publisher.cpp
+++ b/tests/test-segment-publisher.cpp
@@ -126,7 +126,7 @@
   BOOST_CHECK_EQUAL(numRepliesFromStore, 2);
 
   numRepliesFromStore = 0;
-  face.expressInterest(Interest(Name("/hello/world/").appendSegment(0)),
+  face.expressInterest(Interest(Name("/hello/world/")),
                        [this] (const Interest& interest, const Data& data) {
                          numComplete++;
                        },