chunks: fix aimd hanging with files less than chunk size

refs: #4439

Change-Id: Ie3ef5d81e6baf154ade97beda183bc6b16764085
diff --git a/tests/chunks/pipeline-interests-aimd.t.cpp b/tests/chunks/pipeline-interests-aimd.t.cpp
index 2deed18..19f1316 100644
--- a/tests/chunks/pipeline-interests-aimd.t.cpp
+++ b/tests/chunks/pipeline-interests-aimd.t.cpp
@@ -496,6 +496,27 @@
   std::cerr.rdbuf(oldBuf); // reset
 }
 
+BOOST_AUTO_TEST_CASE(StopsWhenFileSizeLessThanChunkSize)
+{
+  // test to see if the program doesn't hang,
+  // when transfer is complete, for files less than the chunk size
+  // (i.e. when only one segment is sent/received)
+
+  createPipeline();
+  nDataSegments = 1;
+
+  runWithData(*makeDataWithSegment(0));
+  advanceClocks(io, time::nanoseconds(1));
+
+  face.receive(*makeDataWithSegment(1));
+  advanceClocks(io, time::nanoseconds(1));
+
+  BOOST_CHECK_EQUAL(aimdPipeline->m_hasFinalBlockId, true);
+  BOOST_CHECK_EQUAL(aimdPipeline->m_segmentInfo.size(), 0);
+  BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
+}
+
+
 BOOST_AUTO_TEST_SUITE_END() // TestPipelineInterestsAimd
 BOOST_AUTO_TEST_SUITE_END() // Chunks
 
diff --git a/tools/chunks/catchunks/pipeline-interests-aimd.cpp b/tools/chunks/catchunks/pipeline-interests-aimd.cpp
index eac9dfd..961a064 100644
--- a/tools/chunks/catchunks/pipeline-interests-aimd.cpp
+++ b/tools/chunks/catchunks/pipeline-interests-aimd.cpp
@@ -70,6 +70,14 @@
 void
 PipelineInterestsAimd::doRun()
 {
+  if (allSegmentsReceived()) {
+    cancel();
+    if (!m_options.isQuiet) {
+      printSummary();
+    }
+    return;
+  }
+
   // schedule the event to check retransmission timer
   m_checkRtoEvent = m_scheduler.scheduleEvent(m_options.rtoCheckInterval, [this] { checkRto(); });
 
@@ -121,7 +129,7 @@
   if (isStopping())
     return;
 
-  if (m_hasFinalBlockId && segNo > m_lastSegmentNo && !isRetransmission)
+  if (m_hasFinalBlockId && segNo > m_lastSegmentNo)
     return;
 
   if (!isRetransmission && m_hasFailure)
@@ -291,8 +299,7 @@
   }
 
   BOOST_ASSERT(m_nReceived > 0);
-  if (m_hasFinalBlockId &&
-      static_cast<uint64_t>(m_nReceived - 1) >= m_lastSegmentNo) { // all segments have been received
+  if (allSegmentsReceived()) {
     cancel();
     if (!m_options.isQuiet) {
       printSummary();
@@ -435,6 +442,12 @@
   }
 }
 
+bool
+PipelineInterestsAimd::allSegmentsReceived() const
+{
+  return m_hasFinalBlockId && static_cast<uint64_t>(m_nReceived - 1) >= m_lastSegmentNo;
+}
+
 void
 PipelineInterestsAimd::printSummary() const
 {
@@ -442,7 +455,7 @@
   std::cerr << "Total # of lost/retransmitted segments: " << m_nRetransmitted
             << " (caused " << m_nLossEvents << " window decreases)\n"
             << "Packet loss rate: "
-            << (static_cast<double>(m_nRetransmitted) / static_cast<double>(m_nSent)) * 100 << "%\n"
+            << (m_nSent == 0 ? 0 : (static_cast<double>(m_nRetransmitted) / static_cast<double>(m_nSent) * 100))  << "%\n"
             << "Total # of received congestion marks: " << m_nCongMarks << "\n"
             << "RTT ";
 
diff --git a/tools/chunks/catchunks/pipeline-interests-aimd.hpp b/tools/chunks/catchunks/pipeline-interests-aimd.hpp
index 0257e7b..c2e5166 100644
--- a/tools/chunks/catchunks/pipeline-interests-aimd.hpp
+++ b/tools/chunks/catchunks/pipeline-interests-aimd.hpp
@@ -184,6 +184,9 @@
   void
   cancelInFlightSegmentsGreaterThan(uint64_t segNo);
 
+  bool
+  allSegmentsReceived() const;
+
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   void
   printSummary() const final;