lsa-segment-storage: fix segfault in scheduled erase of lsa segment

refs: #4520

Change-Id: I597604b4be9e063a08ff5031faa8d305408b676d
diff --git a/src/lsa-segment-storage.cpp b/src/lsa-segment-storage.cpp
index fa656d3..3e85bd0 100644
--- a/src/lsa-segment-storage.cpp
+++ b/src/lsa-segment-storage.cpp
@@ -23,15 +23,14 @@
 #include "logger.hpp"
 #include "lsa.hpp"
 #include "utility/name-helper.hpp"
+#include "conf-parameter.hpp"
 
 namespace nlsr {
 
 INIT_LOGGER(LsaSegmentStorage);
 
-LsaSegmentStorage::LsaSegmentStorage(ndn::Scheduler& scheduler,
-                                     const ndn::time::seconds lsaDeletionTimepoint)
+LsaSegmentStorage::LsaSegmentStorage(ndn::Scheduler& scheduler)
   : m_scheduler(scheduler)
-  , m_lsaDeletionTimepoint(lsaDeletionTimepoint)
 {
 }
 
@@ -98,8 +97,23 @@
       NLSR_LOG_TRACE("The received segment is already in the storage.");
     }
 
+    std::string content(reinterpret_cast<const char*>(lsaSegment.getContent().value()),
+                        lsaSegment.getContent().value_size());
+
+    ndn::time::seconds expirationTime(LSA_REFRESH_TIME_DEFAULT);
+
+    std::vector<std::string> options;
+    boost::split(options, content, boost::is_any_of("|"));
+
+    try {
+      expirationTime = ndn::time::duration_cast<ndn::time::seconds>
+                       (ndn::time::system_clock::now() - ndn::time::fromIsoString(options.at(3)));
+    } catch (const std::exception& e) {
+      NLSR_LOG_ERROR("Cannot extract expiration time from LSA content: " << e.what());
+    }
+
     // schedule the segment deletion
-    scheduleLsaSegmentDeletion(lsaSegmentsKey);
+    scheduleLsaSegmentDeletion(lsaSegmentsKey, expirationTime);
   }
   else {
     NLSR_LOG_ERROR("The received LSA segment has empty name.");
@@ -114,7 +128,7 @@
 
   std::vector<decltype(m_lsaSegments)::key_type> lsaToDelete;
 
-  for (auto& segment : m_lsaSegments) {
+  for (const auto& segment : m_lsaSegments) {
     ndn::Name segmentKey = segment.first;
     auto oldSeqNo = segmentKey.get(-2).toNumber();
     auto existingLsaKey = segmentKey.getPrefix(segmentKey.size() - 2);
@@ -128,16 +142,19 @@
     }
   }
 
-  for (auto& segmentKey : lsaToDelete) {
+  for (const auto& segmentKey : lsaToDelete) {
     m_lsaSegments.erase(segmentKey);
   }
 }
 
 void
-LsaSegmentStorage::scheduleLsaSegmentDeletion(const ndn::Name& lsaSegmentsKey)
+LsaSegmentStorage::scheduleLsaSegmentDeletion(const ndn::Name& lsaSegmentsKey,
+                                              ndn::time::seconds expirationTime)
 {
-  m_scheduler.scheduleEvent(m_lsaDeletionTimepoint,
-                            [&, this] {
+  NLSR_LOG_TRACE("Scheduling LSA segment deletion for "
+                 << lsaSegmentsKey << " in: " << expirationTime);
+  m_scheduler.scheduleEvent(expirationTime,
+                            [lsaSegmentsKey, this] {
                               m_lsaSegments.erase(lsaSegmentsKey);
                             });
 }
diff --git a/src/lsa-segment-storage.hpp b/src/lsa-segment-storage.hpp
index 468b2fe..474f422 100644
--- a/src/lsa-segment-storage.hpp
+++ b/src/lsa-segment-storage.hpp
@@ -36,8 +36,7 @@
 class LsaSegmentStorage
 {
 public:
-  LsaSegmentStorage(ndn::Scheduler& scheduler,
-                    const ndn::time::seconds lsaDeletionTimepoint);
+  LsaSegmentStorage(ndn::Scheduler& scheduler);
 
   /*! \brief Get connected to the signal emitted by SegmentFetcher
    * \param fetcher The SegmentFetcher to whose signal LsaSegmentStorage will subscribe to.
@@ -69,7 +68,7 @@
   /*! \brief Schedules the deletion of a LSA data given the segmentKey
    */
   void
-  scheduleLsaSegmentDeletion(const ndn::Name& segmentKey);
+  scheduleLsaSegmentDeletion(const ndn::Name& segmentKey, ndn::time::seconds expirationTime);
 
 
 private:
@@ -79,8 +78,6 @@
   // Value: corresponding LSA data packet
   //        Data name: /<router-prefix>/<LS type>/<sequence no.>/<version no.>/<segment no.>
   std::unordered_map<ndn::Name, ndn::Data> m_lsaSegments;
-
-  const ndn::time::seconds m_lsaDeletionTimepoint;
 };
 
 } // namespace nlsr
diff --git a/src/lsdb.cpp b/src/lsdb.cpp
index 5ebef48..a38dd55 100644
--- a/src/lsdb.cpp
+++ b/src/lsdb.cpp
@@ -72,8 +72,7 @@
                    const uint64_t& sequenceNumber) {
              return isLsaNew(routerName, lsaType, sequenceNumber);
            }, m_nlsr.getConfParameter())
-  , m_lsaStorage(scheduler,
-                 ndn::time::seconds(m_nlsr.getConfParameter().getLsaRefreshTime()))
+  , m_lsaStorage(scheduler)
   , m_lsaRefreshTime(0)
   , m_adjLsaBuildInterval(ADJ_LSA_BUILD_INTERVAL_DEFAULT)
   , m_sequencingManager()
diff --git a/tests/test-lsa-segment-storage.cpp b/tests/test-lsa-segment-storage.cpp
index de0ee13..e690ae8 100644
--- a/tests/test-lsa-segment-storage.cpp
+++ b/tests/test-lsa-segment-storage.cpp
@@ -27,6 +27,7 @@
 #include "test-common.hpp"
 #include "nlsr.hpp"
 #include "name-prefix-list.hpp"
+#include "lsa.hpp"
 
 #include <boost/test/unit_test.hpp>
 
@@ -41,18 +42,29 @@
     , nlsr(m_ioService, m_scheduler, face, m_keyChain)
     , lsdb(nlsr.getLsdb())
     , lsaStorage(lsdb.getLsaStorage())
+    , lsaGeneratedBeforeNow(180)
   {
   }
 
-  static shared_ptr<ndn::Data>
+  std::string
+  makeLsaContent()
+  {
+    ndn::Name s1{"name1"};
+    ndn::Name s2{"name2"};
+    NamePrefixList npl1{s1, s2};
+    NameLsa nameLsa("/ndn/other-site/%C1.Router/other-router", 12,
+                    ndn::time::system_clock::now() - lsaGeneratedBeforeNow, npl1);
+    return nameLsa.serialize();
+  }
+
+  shared_ptr<ndn::Data>
   makeLsaSegment(const ndn::Name& baseName, uint64_t segmentNo, bool isFinal)
   {
-    const uint8_t buffer[] = "Hello, world!";
-
     ndn::Name lsaDataName(baseName);
     lsaDataName.appendSegment(segmentNo);
     auto lsaSegment = make_shared<ndn::Data>(ndn::Name(lsaDataName));
-    lsaSegment->setContent(buffer, sizeof(buffer));
+    std::string content = makeLsaContent();
+    lsaSegment->setContent(reinterpret_cast<const uint8_t*>(content.c_str()), content.length());
     if (isFinal) {
       lsaSegment->setFinalBlockId(lsaSegment->getName()[-1]);
     }
@@ -80,6 +92,7 @@
   Nlsr nlsr;
   Lsdb& lsdb;
   LsaSegmentStorage& lsaStorage;
+  ndn::time::seconds lsaGeneratedBeforeNow;
 };
 
 BOOST_FIXTURE_TEST_SUITE(TestLsaSegmentStorage, LsaSegmentStorageFixture)
@@ -148,6 +161,24 @@
   BOOST_CHECK_EQUAL(face.sentData.size(), 1);
 }
 
+BOOST_AUTO_TEST_CASE(ScheduledDeletion)
+{
+  ndn::Name lsaInterestName("/ndn/NLSR/LSA/other-site/%C1.Router/other-router/NAME");
+  lsaInterestName.appendNumber(12);
+
+  ndn::Name lsaDataName(lsaInterestName);
+  lsaDataName.appendVersion();
+
+  auto lsaData = makeLsaSegment(lsaDataName, 0, true);
+  lsaStorage.afterFetcherSignalEmitted(*lsaData);
+
+  BOOST_CHECK(lsaStorage.getLsaSegment(ndn::Interest(lsaInterestName)) != nullptr);
+
+  advanceClocks(ndn::time::milliseconds(lsaGeneratedBeforeNow), 10);
+
+  BOOST_CHECK(lsaStorage.getLsaSegment(ndn::Interest(lsaInterestName)) == nullptr);
+}
+
 BOOST_AUTO_TEST_SUITE_END() // TestLsaSegmentStorage
 
 } // namespace test