lsdb: Segment LSAs larger than max segment size

refs: #2965

Change-Id: I5dd091b663db2cc5e2d925144e57ee55a486b3cd
diff --git a/nlsr.conf b/nlsr.conf
index a370f34..d32a463 100644
--- a/nlsr.conf
+++ b/nlsr.conf
@@ -187,7 +187,8 @@
             k-regex ^([^<KEY><NLSR>]*)<NLSR><KEY><ksk-.*><ID-CERT>$
             k-expand \\1
             h-relation equal
-            p-regex ^([^<NLSR><LSA>]*)<NLSR><LSA>(<>*)<><><>$
+            ; the last four components in the prefix should be <lsaType><seqNo><version><segmentNo>
+            p-regex ^([^<NLSR><LSA>]*)<NLSR><LSA>(<>*)<><><><>$
             p-expand \\1\\2
           }
         }
diff --git a/src/lsdb.cpp b/src/lsdb.cpp
index d4b7193..8d7f1ec 100644
--- a/src/lsdb.cpp
+++ b/src/lsdb.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  The University of Memphis,
+ * Copyright (c) 2014-2016,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -19,24 +19,114 @@
  * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  **/
 
-#include <string>
-#include <utility>
-
 #include "lsdb.hpp"
-#include "nlsr.hpp"
-#include "conf-parameter.hpp"
-#include "utility/name-helper.hpp"
+
 #include "logger.hpp"
+#include "nlsr.hpp"
+#include "publisher/segment-publisher.hpp"
+#include "utility/name-helper.hpp"
+
+#include <ndn-cxx/security/signing-helpers.hpp>
+#include <ndn-cxx/util/segment-fetcher.hpp>
+
+#include <string>
 
 namespace nlsr {
 
 INIT_LOGGER("Lsdb");
 
+class LsaContentPublisher : public SegmentPublisher<ndn::Face>
+{
+public:
+  LsaContentPublisher(ndn::Face& face,
+                      ndn::KeyChain& keyChain,
+                      const ndn::time::milliseconds& freshnessPeriod,
+                      const std::string& content)
+    : SegmentPublisher(face, keyChain, freshnessPeriod)
+    , m_content(content)
+  {
+  }
+
+  virtual size_t
+  generate(ndn::EncodingBuffer& outBuffer) {
+    size_t totalLength = 0;
+    totalLength += outBuffer.prependByteArray(reinterpret_cast<const uint8_t*>(m_content.c_str()),
+                                              m_content.size());
+    return totalLength;
+  }
+
+private:
+  const std::string m_content;
+};
+
 const ndn::Name::Component Lsdb::NAME_COMPONENT = ndn::Name::Component("lsdb");
 const ndn::time::seconds Lsdb::GRACE_PERIOD = ndn::time::seconds(10);
 const steady_clock::TimePoint Lsdb::DEFAULT_LSA_RETRIEVAL_DEADLINE = steady_clock::TimePoint::min();
 
-using namespace std;
+Lsdb::Lsdb(Nlsr& nlsr, ndn::Scheduler& scheduler, SyncLogicHandler& sync)
+  : m_nlsr(nlsr)
+  , m_scheduler(scheduler)
+  , m_sync(sync)
+  , m_lsaRefreshTime(0)
+  , m_adjLsaBuildInterval(ADJ_LSA_BUILD_INTERVAL_DEFAULT)
+{
+}
+
+void
+Lsdb::onFetchLsaError(uint32_t errorCode,
+                      const std::string& msg,
+                      ndn::Name& interestName,
+                      uint32_t retransmitNo,
+                      const ndn::time::steady_clock::TimePoint& deadline,
+                      ndn::Name lsaName,
+                      uint64_t seqNo)
+{
+  _LOG_DEBUG("Failed to fetch LSA: " << lsaName << ", Error code: " << errorCode
+                                                << ", Message: " << msg);
+
+  if (ndn::time::steady_clock::now() < deadline) {
+    SequenceNumberMap::const_iterator it = m_highestSeqNo.find(lsaName);
+
+    if (it != m_highestSeqNo.end() && it->second == seqNo) {
+      // If the SegmentFetcher failed due to an Interest timeout, it is safe to re-express
+      // immediately since at the least the LSA Interest lifetime has elapsed.
+      // Otherwise, it is necessary to delay the Interest re-expression to prevent
+      // the potential for constant Interest flooding.
+      ndn::time::seconds delay = m_nlsr.getConfParameter().getLsaInterestLifetime();
+
+      if (errorCode == ndn::util::SegmentFetcher::ErrorCode::INTEREST_TIMEOUT) {
+        delay = ndn::time::seconds(0);
+      }
+
+      m_scheduler.scheduleEvent(delay, std::bind(&Lsdb::expressInterest, this,
+                                                 interestName, retransmitNo + 1, deadline));
+    }
+  }
+}
+
+void
+Lsdb::afterFetchLsa(const ndn::ConstBufferPtr& bufferPtr, ndn::Name& interestName)
+{
+  shared_ptr<ndn::Data> data = make_shared<ndn::Data>(ndn::Name(interestName));
+  data->setContent(bufferPtr);
+
+  _LOG_DEBUG("Received data for LSA(name): " << data->getName());
+
+  ndn::Name lsaName = interestName.getSubName(0, interestName.size()-1);
+  uint64_t seqNo = interestName[-1].toNumber();
+
+  if (m_highestSeqNo.find(lsaName) == m_highestSeqNo.end()) {
+    m_highestSeqNo[lsaName] = seqNo;
+  }
+  else if (seqNo > m_highestSeqNo[lsaName]) {
+    m_highestSeqNo[lsaName] = seqNo;
+  }
+  else if (seqNo < m_highestSeqNo[lsaName]) {
+    return;
+  }
+
+  onContentValidated(data);
+}
 
 void
 Lsdb::cancelScheduleLsaExpiringEvent(ndn::EventId eid)
@@ -50,7 +140,6 @@
   return nlsa1.getKey() == key;
 }
 
-
 bool
 Lsdb::buildAndInstallOwnNameLsa()
 {
@@ -640,7 +729,7 @@
 }
 
 void
-Lsdb::setThisRouterPrefix(string trp)
+Lsdb::setThisRouterPrefix(std::string trp)
 {
   m_thisRouterPrefix = trp;
 }
@@ -748,7 +837,6 @@
   }
 }
 
-
 void
 Lsdb::expressInterest(const ndn::Name& interestName, uint32_t timeoutCount,
                       steady_clock::TimePoint deadline)
@@ -758,8 +846,6 @@
   }
 
   ndn::Name lsaName = interestName.getSubName(0, interestName.size()-1);
-
-  ndn::Interest interest(interestName);
   uint64_t seqNo = interestName[-1].toNumber();
 
   if (m_highestSeqNo.find(lsaName) == m_highestSeqNo.end()) {
@@ -772,14 +858,15 @@
     return;
   }
 
+  ndn::Interest interest(interestName);
   interest.setInterestLifetime(m_nlsr.getConfParameter().getLsaInterestLifetime());
 
-  _LOG_DEBUG("Expressing Interest for LSA: " << interestName << " Seq number: " << seqNo);
-  m_nlsr.getNlsrFace().expressInterest(interest,
-                                       ndn::bind(&Lsdb::onContent,
-                                                 this, _2, deadline, lsaName, seqNo),
-                                       ndn::bind(&Lsdb::processInterestTimedOut,
-                                                 this, _1, timeoutCount, deadline, lsaName, seqNo));
+  _LOG_DEBUG("Fetching Data for LSA: " << interestName << " Seq number: " << seqNo);
+  ndn::util::SegmentFetcher::fetch(m_nlsr.getNlsrFace(), interest,
+                                   m_nlsr.getValidator(),
+                                   ndn::bind(&Lsdb::afterFetchLsa, this, _1, interestName),
+                                   ndn::bind(&Lsdb::onFetchLsaError, this, _1, _2, interestName,
+                                             timeoutCount, deadline, lsaName, seqNo));
 }
 
 void
@@ -788,7 +875,7 @@
   const ndn::Name& interestName(interest.getName());
   _LOG_DEBUG("Interest received for LSA: " << interestName);
 
-  string chkString("LSA");
+  std::string chkString("LSA");
   int32_t lsaPosition = util::getNameComponentPosition(interest.getName(), chkString);
 
   if (lsaPosition >= 0) {
@@ -820,16 +907,12 @@
 void
 Lsdb::putLsaData(const ndn::Interest& interest, const std::string& content)
 {
-  ndn::shared_ptr<ndn::Data> data = ndn::make_shared<ndn::Data>();
-  data->setName(ndn::Name(interest.getName()).appendVersion());
-  data->setFreshnessPeriod(m_lsaRefreshTime);
-  data->setContent(reinterpret_cast<const uint8_t*>(content.c_str()), content.size());
-  m_nlsr.getKeyChain().sign(*data, m_nlsr.getDefaultCertName());
-  ndn::SignatureSha256WithRsa signature(data->getSignature());
-  ndn::Name signingCertName = signature.getKeyLocator().getName();
-  _LOG_DEBUG("Sending data for LSA(name): " << interest.getName());
-  _LOG_DEBUG("Data signed with: " << signingCertName);
-  m_nlsr.getNlsrFace().put(*data);
+  LsaContentPublisher publisher(m_nlsr.getNlsrFace(),
+                                m_nlsr.getKeyChain(),
+                                m_lsaRefreshTime,
+                                content);
+  publisher.publish(interest.getName(),
+                    ndn::security::signingByCertificate(m_nlsr.getDefaultCertName()));
 }
 
 void
@@ -875,58 +958,23 @@
 }
 
 void
-Lsdb::onContent(const ndn::Data& data,
-                const steady_clock::TimePoint& deadline, ndn::Name lsaName,
-                uint64_t seqNo)
-{
-  _LOG_DEBUG("Received data for LSA(name): " << data.getName());
-  if (data.getSignature().hasKeyLocator()) {
-    if (data.getSignature().getKeyLocator().getType() == ndn::KeyLocator::KeyLocator_Name) {
-      _LOG_DEBUG("Data signed with: " << data.getSignature().getKeyLocator().getName());
-    }
-  }
-  m_nlsr.getValidator().validate(data,
-                                 ndn::bind(&Lsdb::onContentValidated, this, _1),
-                                 ndn::bind(&Lsdb::onContentValidationFailed, this, _1, _2,
-                                           deadline, lsaName, seqNo));
-
-}
-
-void
-Lsdb::retryContentValidation(const ndn::shared_ptr<const ndn::Data>& data,
-                             const steady_clock::TimePoint& deadline, ndn::Name lsaName,
-                             uint64_t seqNo)
-{
-  _LOG_DEBUG("Retrying validation of LSA(name): " << data->getName());
-  if (data->getSignature().hasKeyLocator()) {
-    if (data->getSignature().getKeyLocator().getType() == ndn::KeyLocator::KeyLocator_Name) {
-      _LOG_DEBUG("Data signed with: " << data->getSignature().getKeyLocator().getName());
-    }
-  }
-  m_nlsr.getValidator().validate(*data,
-                                 ndn::bind(&Lsdb::onContentValidated, this, _1),
-                                 ndn::bind(&Lsdb::onContentValidationFailed, this, _1, _2,
-                                           deadline, lsaName, seqNo));
-}
-
-void
 Lsdb::onContentValidated(const ndn::shared_ptr<const ndn::Data>& data)
 {
   const ndn::Name& dataName = data->getName();
   _LOG_DEBUG("Data validation successful for LSA: " << dataName);
 
-  string chkString("LSA");
+  std::string chkString("LSA");
   int32_t lsaPosition = util::getNameComponentPosition(dataName, chkString);
 
   if (lsaPosition >= 0) {
 
     ndn::Name originRouter = m_nlsr.getConfParameter().getNetwork();
-    originRouter.append(dataName.getSubName(lsaPosition + 1, dataName.size() - lsaPosition - 4));
+    originRouter.append(dataName.getSubName(lsaPosition + 1, dataName.size() - lsaPosition - 3));
 
-    uint64_t seqNo = dataName[-2].toNumber();
-    string dataContent(reinterpret_cast<const char*>(data->getContent().value()));
+    uint64_t seqNo = dataName[-1].toNumber();
+    std::string dataContent(reinterpret_cast<const char*>(data->getContent().value()));
 
-    std::string interestedLsType  = dataName[-3].toUri();
+    std::string interestedLsType  = dataName[-2].toUri();
 
     if (interestedLsType == NameLsa::TYPE_STRING) {
       processContentNameLsa(originRouter.append(interestedLsType), seqNo, dataContent);
@@ -944,32 +992,6 @@
 }
 
 void
-Lsdb::onContentValidationFailed(const ndn::shared_ptr<const ndn::Data>& data,
-                                const std::string& msg,
-                                const steady_clock::TimePoint& deadline, ndn::Name lsaName,
-                                uint64_t seqNo)
-{
-  _LOG_DEBUG("Validation Error: " << msg);
-
-  // Delay re-validation by LSA Interest Lifetime.  When error callback will have an error
-  // code, re-validation should be done only when some keys from certification chain failed
-  // to be fetched.  After that change, delaying will no longer be necessary.
-
-  // Stop retrying if delayed re-validation will be scheduled pass the deadline
-  if (steady_clock::now() + m_nlsr.getConfParameter().getLsaInterestLifetime() < deadline) {
-
-    SequenceNumberMap::const_iterator it = m_highestSeqNo.find(lsaName);
-
-    if (it != m_highestSeqNo.end() && it->second == seqNo) {
-      _LOG_DEBUG("Scheduling revalidation attempt");
-      m_scheduler.scheduleEvent(m_nlsr.getConfParameter().getLsaInterestLifetime(),
-                                ndn::bind(&Lsdb::retryContentValidation, this, data,
-                                          deadline, lsaName, seqNo));
-    }
-  }
-}
-
-void
 Lsdb::processContentNameLsa(const ndn::Name& lsaKey,
                             uint64_t lsSeqNo, std::string& dataContent)
 {
@@ -1014,24 +1036,6 @@
   }
 }
 
-void
-Lsdb::processInterestTimedOut(const ndn::Interest& interest, uint32_t retransmitNo,
-                              const ndn::time::steady_clock::TimePoint& deadline, ndn::Name lsaName,
-                              uint64_t seqNo)
-{
-  const ndn::Name& interestName = interest.getName();
-  _LOG_DEBUG("Interest timed out for  LSA: " << interestName);
-
-  if (ndn::time::steady_clock::now() < deadline) {
-
-    SequenceNumberMap::const_iterator it = m_highestSeqNo.find(lsaName);
-
-    if (it != m_highestSeqNo.end() &&  it->second == seqNo) {
-      expressInterest(interestName, retransmitNo + 1, deadline);
-    }
-  }
-}
-
 ndn::time::system_clock::TimePoint
 Lsdb::getLsaExpirationTimePoint()
 {
diff --git a/src/lsdb.hpp b/src/lsdb.hpp
index 417c978..eac7770 100644
--- a/src/lsdb.hpp
+++ b/src/lsdb.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  The University of Memphis,
+ * Copyright (c) 2014-2016,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -24,6 +24,7 @@
 
 #include <utility>
 #include <boost/cstdint.hpp>
+
 #include <ndn-cxx/security/key-chain.hpp>
 #include <ndn-cxx/util/time.hpp>
 
@@ -41,19 +42,12 @@
 class Lsdb
 {
 public:
-  Lsdb(Nlsr& nlsr, ndn::Scheduler& scheduler, SyncLogicHandler& sync)
-    : m_nlsr(nlsr)
-    , m_scheduler(scheduler)
-    , m_sync(sync)
-    , m_lsaRefreshTime(0)
-    , m_adjLsaBuildInterval(static_cast<uint32_t>(ADJ_LSA_BUILD_INTERVAL_DEFAULT))
-  {
-  }
+  Lsdb(Nlsr& nlsr, ndn::Scheduler& scheduler, SyncLogicHandler& sync);
 
   bool
   doesLsaExist(const ndn::Name& key, const std::string& lsType);
-  // function related to Name LSDB
 
+  // functions related to Name LSDB
   bool
   buildAndInstallOwnNameLsa();
 
@@ -75,7 +69,7 @@
   const std::list<NameLsa>&
   getNameLsdb();
 
-  //function related to Cor LSDB
+  // functions related to Cor LSDB
   bool
   buildAndInstallOwnCoordinateLsa();
 
@@ -97,8 +91,7 @@
   const std::list<CoordinateLsa>&
   getCoordinateLsdb();
 
-  //function related to Adj LSDB
-
+  // functions related to Adj LSDB
   void
   scheduleAdjLsaBuild();
 
@@ -141,6 +134,13 @@
   void
   setThisRouterPrefix(std::string trp);
 
+  void
+  expressInterest(const ndn::Name& interestName, uint32_t timeoutCount,
+                  steady_clock::TimePoint deadline = DEFAULT_LSA_RETRIEVAL_DEADLINE);
+
+  void
+  processInterest(const ndn::Name& name, const ndn::Interest& interest);
+
 private:
   bool
   addNameLsa(NameLsa& nlsa);
@@ -187,16 +187,8 @@
   void
   exprireOrRefreshCoordinateLsa(const ndn::Name& lsaKey,
                                 uint64_t seqNo);
-public:
-  void
-  expressInterest(const ndn::Name& interestName, uint32_t timeoutCount,
-                  steady_clock::TimePoint deadline = DEFAULT_LSA_RETRIEVAL_DEADLINE);
 
   void
-  processInterest(const ndn::Name& name, const ndn::Interest& interest);
-
-private:
-  void
   putLsaData(const ndn::Interest& interest, const std::string& content);
 
   void
@@ -215,32 +207,9 @@
                                   uint64_t seqNo);
 
   void
-  onContent(const ndn::Data& data, const steady_clock::TimePoint& deadline,
-            ndn::Name lsaName, uint64_t seqNo);
-
-  /**
-   * @brief Retry validation after it fails
-   *
-   * Data packet validation can fail either because the packet does not have
-   * valid signature (fatal) or because some of the certificate chain Data packets
-   * failed to be fetched (non-fatal).  Currently, the library does not provide
-   * clear indication (besides plain-text message in error callback) of what is
-   * the reason for failure and we will try to re-validate for as long as it the deadline.
-   */
-  void
-  retryContentValidation(const ndn::shared_ptr<const ndn::Data>& data,
-                         const steady_clock::TimePoint& deadline, ndn::Name lsaName,
-                         uint64_t seqNo);
-
-  void
   onContentValidated(const ndn::shared_ptr<const ndn::Data>& data);
 
   void
-  onContentValidationFailed(const ndn::shared_ptr<const ndn::Data>& data, const std::string& msg,
-                            const steady_clock::TimePoint& deadline, ndn::Name lsaName,
-                            uint64_t seqNo);
-
-  void
   processContentNameLsa(const ndn::Name& lsaKey,
                         uint64_t lsSeqNo, std::string& dataContent);
 
@@ -253,10 +222,37 @@
                               uint64_t lsSeqNo, std::string& dataContent);
 
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+  /**
+   * @brief Error callback when SegmentFetcher fails to return an LSA
+   *
+   * In all error cases, a reattempt to fetch the LSA will be made.
+   *
+   * Segment validation can fail either because the packet does not have a
+   * valid signature (fatal) or because some of the certificates in the trust chain
+   * could not be fetched (non-fatal).
+   *
+   * Currently, the library does not provide clear indication (besides a plain-text message
+   * in the error callback) of the reason for the failure nor the segment that failed
+   * to be validated, thus we will continue to try to fetch the LSA until the deadline
+   * is reached.
+   */
   void
-  processInterestTimedOut(const ndn::Interest& interest, uint32_t retransmitNo,
-                          const steady_clock::TimePoint& deadline, ndn::Name lsaName,
-                          uint64_t seqNo);
+  onFetchLsaError(uint32_t errorCode,
+                  const std::string& msg,
+                  ndn::Name& interestName,
+                  uint32_t retransmitNo,
+                  const ndn::time::steady_clock::TimePoint& deadline,
+                  ndn::Name lsaName,
+                  uint64_t seqNo);
+
+  /**
+   * @brief Success callback when SegmentFetcher returns a valid LSA
+   *
+   * \param The base Interest used to fetch the LSA in the format:
+   *        /<network>/NLSR/LSA/<site>/%C1.Router/<router>/<lsa-type>/<seqNo>
+   */
+  void
+  afterFetchLsa(const ndn::ConstBufferPtr& data, ndn::Name& interestName);
 
 private:
   system_clock::TimePoint
diff --git a/src/publisher/segment-publisher.hpp b/src/publisher/segment-publisher.hpp
index 5aefa52..7d959e1 100644
--- a/src/publisher/segment-publisher.hpp
+++ b/src/publisher/segment-publisher.hpp
@@ -68,7 +68,8 @@
   /** \brief Publish data under provided prefix
    */
   void
-  publish(const ndn::Name& prefix)
+  publish(const ndn::Name& prefix,
+          const ndn::security::SigningInfo& signingInfo = ndn::security::KeyChain::DEFAULT_SIGNING_INFO)
   {
     ndn::EncodingBuffer buffer;
     generate(buffer);
@@ -99,7 +100,7 @@
         data->setFinalBlockId(segmentName[-1]);
       }
 
-      publishSegment(data);
+      publishSegment(data, signingInfo);
       ++segmentNo;
     } while (segmentBegin < end);
   }
@@ -112,9 +113,9 @@
 
 private:
   void
-  publishSegment(ndn::shared_ptr<ndn::Data>& data)
+  publishSegment(ndn::shared_ptr<ndn::Data>& data, const ndn::security::SigningInfo& signingInfo)
   {
-    m_keyChain.sign(*data);
+    m_keyChain.sign(*data, signingInfo);
     m_face.put(*data);
   }
 
diff --git a/tests/test-lsdb.cpp b/tests/test-lsdb.cpp
index 7111620..05a71ea 100644
--- a/tests/test-lsdb.cpp
+++ b/tests/test-lsdb.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  The University of Memphis,
+ * Copyright (c) 2014-2016,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -28,6 +28,7 @@
 #include <boost/test/unit_test.hpp>
 
 #include <ndn-cxx/util/dummy-client-face.hpp>
+#include <ndn-cxx/util/segment-fetcher.hpp>
 
 namespace nlsr {
 namespace test {
@@ -38,7 +39,7 @@
 {
 public:
   LsdbFixture()
-    : face(make_shared<ndn::util::DummyClientFace>())
+    : face(make_shared<ndn::util::DummyClientFace>(g_ioService))
     , nlsr(g_ioService, g_scheduler, ndn::ref(*face))
     , sync(*face, nlsr.getLsdb(), nlsr.getConfParameter(), nlsr.getSequencingManager())
     , lsdb(nlsr.getLsdb())
@@ -122,10 +123,11 @@
   interests.clear();
 
   steady_clock::TimePoint deadline = steady_clock::now() +
-                                     ndn::time::seconds(static_cast<int>(LSA_REFRESH_TIME_MAX));
+                                     ndn::time::seconds(LSA_REFRESH_TIME_MAX);
 
   // Simulate an LSA interest timeout
-  lsdb.processInterestTimedOut(oldInterestName, 0, deadline, interestName, oldSeqNo);
+  lsdb.onFetchLsaError(ndn::util::SegmentFetcher::ErrorCode::INTEREST_TIMEOUT, "Timeout",
+                       oldInterestName, 0, deadline, interestName, oldSeqNo);
   face->processEvents(ndn::time::milliseconds(1));
 
   BOOST_REQUIRE(interests.size() > 0);
@@ -149,13 +151,81 @@
   interests.clear();
 
   // Simulate an LSA interest timeout where the sequence number is outdated
-  lsdb.processInterestTimedOut(oldInterestName, 0, deadline, interestName, oldSeqNo);
+  lsdb.onFetchLsaError(ndn::util::SegmentFetcher::ErrorCode::INTEREST_TIMEOUT, "Timeout",
+                       oldInterestName, 0, deadline, interestName, oldSeqNo);
   face->processEvents(ndn::time::milliseconds(1));
 
   // Interest should not be expressed for outdated sequence number
   BOOST_CHECK_EQUAL(interests.size(), 0);
 }
 
+BOOST_AUTO_TEST_CASE(SegmentLsaData)
+{
+  ndn::Name router("/ndn/cs/%C1.Router/router1");
+  uint64_t seqNo = 12;
+  NamePrefixList prefixList;
+
+  NameLsa lsa(router, seqNo, ndn::time::system_clock::now(), prefixList);
+
+  ndn::Name prefix("/ndn/edu/memphis/netlab/research/nlsr/test/prefix/");
+
+  int nPrefixes = 0;
+  while (lsa.getData().size() < ndn::MAX_NDN_PACKET_SIZE) {
+    lsa.addName(ndn::Name(prefix).appendNumber(++nPrefixes));
+  }
+
+  std::string expectedDataContent = lsa.getData();
+  lsdb.installNameLsa(lsa);
+
+  ndn::Name interestName("/ndn/NLSR/LSA/cs/%C1.Router/router1/name/");
+  interestName.appendNumber(seqNo);
+
+  ndn::Interest interest(interestName);
+
+  lsdb.processInterest(ndn::Name(), interest);
+  face->processEvents(ndn::time::milliseconds(1));
+
+  std::vector<ndn::Data> data = face->sentData;
+  std::string recvDataContent;
+  for (unsigned int i = 0; i < data.size(); ++i)
+  {
+    const ndn::Block& nameBlock = data[i].getContent();
+
+    std::string nameBlockContent(reinterpret_cast<char const*>(nameBlock.value()),
+                                 nameBlock.value_size());
+    recvDataContent += nameBlockContent;
+  }
+
+  BOOST_CHECK_EQUAL(expectedDataContent, recvDataContent);
+}
+
+BOOST_AUTO_TEST_CASE(ReceiveSegmentedLsaData)
+{
+  ndn::Name router("/ndn/cs/%C1.Router/router1");
+  uint64_t seqNo = 12;
+  NamePrefixList prefixList;
+
+  NameLsa lsa(router, seqNo, ndn::time::system_clock::now(), prefixList);
+
+  ndn::Name prefix("/prefix/");
+
+  for (int nPrefixes = 0; nPrefixes < 3; ++nPrefixes) {
+    lsa.addName(ndn::Name(prefix).appendNumber(nPrefixes));
+  }
+
+  ndn::Name interestName("/ndn/NLSR/LSA/cs/%C1.Router/router1/name/");
+  interestName.appendNumber(seqNo);
+
+  const ndn::ConstBufferPtr bufferPtr = make_shared<ndn::Buffer>(lsa.getData().c_str(),
+                                                                 lsa.getData().size());
+  lsdb.afterFetchLsa(bufferPtr, interestName);
+
+  NameLsa* foundLsa = lsdb.findNameLsa(lsa.getKey());
+  BOOST_REQUIRE(foundLsa != nullptr);
+
+  BOOST_CHECK_EQUAL(foundLsa->getData(), lsa.getData());
+}
+
 BOOST_AUTO_TEST_CASE(LsdbRemoveAndExists)
 {
   ndn::time::system_clock::TimePoint testTimePoint =  ndn::time::system_clock::now();