route: communicate routing changes using signals

The RoutingTable now has a signal that it emits upon finishing
calculation, which other modules can subscribe to. The NamePrefixTable
now references this emitted container to update its local copies of
routing information.

Change-Id: Id601776258ad0367cc47461ea8f86a710eada132
refs: #4249
diff --git a/src/nlsr.cpp b/src/nlsr.cpp
index 32bda23..02915e4 100644
--- a/src/nlsr.cpp
+++ b/src/nlsr.cpp
@@ -53,7 +53,7 @@
   , m_isRoutingTableCalculating(false)
   , m_routingTable(scheduler)
   , m_fib(m_nlsrFace, scheduler, m_adjacencyList, m_confParam, m_keyChain)
-  , m_namePrefixTable(*this)
+  , m_namePrefixTable(*this, m_routingTable.afterRoutingChange)
   , m_localhostDispatcher(m_nlsrFace, m_keyChain)
   , m_routerNameDispatcher(m_nlsrFace, m_keyChain)
   , m_lsdbDatasetHandler(m_nlsrLsdb,
diff --git a/src/route/name-prefix-table.cpp b/src/route/name-prefix-table.cpp
index 3b67bcb..bd7269a 100644
--- a/src/route/name-prefix-table.cpp
+++ b/src/route/name-prefix-table.cpp
@@ -33,6 +33,20 @@
 
 INIT_LOGGER("NamePrefixTable");
 
+NamePrefixTable::NamePrefixTable(Nlsr& nlsr, std::shared_ptr<AfterRoutingChange>& afterRoutingChangeSignal)
+  : m_nlsr(nlsr)
+{
+  m_afterRoutingChangeConnection = afterRoutingChangeSignal->connect(
+    [this] (const std::list<RoutingTableEntry>& entries) {
+      updateWithNewRoute(entries);
+    });
+}
+
+NamePrefixTable::~NamePrefixTable()
+{
+  m_afterRoutingChangeConnection.disconnect();
+}
+
 bool
 npteCompare(std::shared_ptr<NamePrefixTableEntry>& npte, const ndn::Name& name)
 {
@@ -196,17 +210,20 @@
 }
 
 void
-NamePrefixTable::updateWithNewRoute()
+NamePrefixTable::updateWithNewRoute(const std::list<RoutingTableEntry>& entries)
 {
   _LOG_DEBUG("Updating table with newly calculated routes");
 
   // Iterate over each pool entry we have
   for (auto&& poolEntryPair : m_rtpool) {
     auto&& poolEntry = poolEntryPair.second;
-    RoutingTableEntry* sourceEntry =
-      m_nlsr.getRoutingTable().findRoutingTableEntry(poolEntry->getDestination());
+    auto sourceEntry = std::find_if(entries.begin(), entries.end(),
+                                    [&poolEntry] (const RoutingTableEntry& entry) {
+                                      return poolEntry->getDestination() == entry.getDestination();
+                                    });
     // If this pool entry has a corresponding entry in the routing table now
-    if (sourceEntry != nullptr && poolEntry->getNexthopList() != sourceEntry->getNexthopList()) {
+    if (sourceEntry != entries.end()
+        && poolEntry->getNexthopList() != sourceEntry->getNexthopList()) {
       _LOG_DEBUG("Routing entry: " << poolEntry->getDestination() << " has changed next-hops.");
       poolEntry->setNexthopList(sourceEntry->getNexthopList());
       for (const auto& nameEntry : poolEntry->namePrefixTableEntries) {
@@ -214,14 +231,13 @@
         addEntry(nameEntryFullPtr->getNamePrefix(), poolEntry->getDestination());
       }
     }
-    else if (sourceEntry == nullptr) {
+    else if (sourceEntry == entries.end()) {
       _LOG_DEBUG("Routing entry: " << poolEntry->getDestination() << " now has no next-hops.");
       poolEntry->getNexthopList().reset();
       for (const auto& nameEntry : poolEntry->namePrefixTableEntries) {
         auto nameEntryFullPtr = nameEntry.second.lock();
         addEntry(nameEntryFullPtr->getNamePrefix(), poolEntry->getDestination());
       }
-
     }
     else {
       _LOG_TRACE("No change in routing entry:" << poolEntry->getDestination()
diff --git a/src/route/name-prefix-table.hpp b/src/route/name-prefix-table.hpp
index a4dabc4..f4901ba 100644
--- a/src/route/name-prefix-table.hpp
+++ b/src/route/name-prefix-table.hpp
@@ -24,7 +24,7 @@
 
 #include "name-prefix-table-entry.hpp"
 #include "routing-table-pool-entry.hpp"
-
+#include "signals.hpp"
 #include "test-access-control.hpp"
 
 #include <list>
@@ -41,10 +41,9 @@
   using NptEntryList = std::list<std::shared_ptr<NamePrefixTableEntry>>;
   using const_iterator = NptEntryList::const_iterator;
 
-  NamePrefixTable(Nlsr& nlsr)
-    : m_nlsr(nlsr)
-  {
-  }
+  NamePrefixTable(Nlsr& nlsr, std::shared_ptr<AfterRoutingChange>& afterRoutingChangeSignal);
+
+  ~NamePrefixTable();
 
   /*! \brief Adds a destination to the specified name prefix.
     \param name The name prefix
@@ -78,14 +77,14 @@
 
   /*! \brief Updates all routing information in the NPT.
 
-    Naively iterates over all the NPT entries, then over each of their
-    RoutingTablePoolEntries, passing the name/destination pair back to
-    addEntry after updating the pool entry with new information. This
-    ensures that the FIB is appropriately apprised of any changes to a
-    prefix's preferred next hops.
+    Takes in a list of entries that are assumed to be exhaustive, and
+    updates each pool entry with the next hop information contained in
+    the corresponding entry in entries. If no entry is found, it is
+    assumed that the destination for that pool entry is inaccessible,
+    and its next hop information is deleted.
    */
   void
-  updateWithNewRoute();
+  updateWithNewRoute(const std::list<RoutingTableEntry>& entries);
 
   /*! \brief Adds a pool entry to the pool.
     \param rtpe The entry.
@@ -126,7 +125,7 @@
 
 private:
   Nlsr& m_nlsr;
-
+  ndn::util::signal::Connection m_afterRoutingChangeConnection;
 };
 
 inline NamePrefixTable::const_iterator
diff --git a/src/route/routing-table.cpp b/src/route/routing-table.cpp
index 238852a..547e943 100644
--- a/src/route/routing-table.cpp
+++ b/src/route/routing-table.cpp
@@ -34,6 +34,14 @@
 
 INIT_LOGGER("RoutingTable");
 
+RoutingTable::RoutingTable(ndn::Scheduler& scheduler)
+  : afterRoutingChange{std::make_shared<AfterRoutingChange>()}
+  , m_scheduler(scheduler)
+  , m_NO_NEXT_HOP{-12345}
+  , m_routingCalcInterval{static_cast<uint32_t>(ROUTING_CALC_INTERVAL_DEFAULT)}
+{
+}
+
 void
 RoutingTable::calculate(Nlsr& pnlsr)
 {
@@ -81,7 +89,7 @@
         }
         // Inform the NPT that updates have been made
         _LOG_DEBUG("Calling Update NPT With new Route");
-        pnlsr.getNamePrefixTable().updateWithNewRoute();
+        (*afterRoutingChange)(m_rTable);
         writeLog(pnlsr.getConfParameter().getHyperbolicState());
         pnlsr.getNamePrefixTable().writeLog();
         pnlsr.getFib().writeLog();
@@ -98,7 +106,7 @@
       clearDryRoutingTable(); // for dry run options
       // need to update NPT here
       _LOG_DEBUG("Calling Update NPT With new Route");
-      pnlsr.getNamePrefixTable().updateWithNewRoute();
+      (*afterRoutingChange)(m_rTable);
       writeLog(pnlsr.getConfParameter().getHyperbolicState());
       pnlsr.getNamePrefixTable().writeLog();
       pnlsr.getFib().writeLog();
diff --git a/src/route/routing-table.hpp b/src/route/routing-table.hpp
index b138c9d..274853e 100644
--- a/src/route/routing-table.hpp
+++ b/src/route/routing-table.hpp
@@ -17,14 +17,14 @@
  * You should have received a copy of the GNU General Public License along with
  * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  *
- * \author A K M Mahmudul Hoque <ahoque1@memphis.edu>
- *
  **/
+
 #ifndef NLSR_ROUTING_TABLE_HPP
 #define NLSR_ROUTING_TABLE_HPP
 
 #include "conf-parameter.hpp"
 #include "routing-table-entry.hpp"
+#include "signals.hpp"
 
 #include <iostream>
 #include <utility>
@@ -40,12 +40,7 @@
 class RoutingTable
 {
 public:
-  RoutingTable(ndn::Scheduler& scheduler)
-    : m_scheduler(scheduler)
-    , m_NO_NEXT_HOP(-12345)
-    , m_routingCalcInterval(static_cast<uint32_t>(ROUTING_CALC_INTERVAL_DEFAULT))
-  {
-  }
+  RoutingTable(ndn::Scheduler& scheduler);
 
   /*! \brief Calculates a list of next hops for each router in the network.
    * \param pnlsr The NLSR object that contains the LSAs needed for adj. info.
@@ -119,12 +114,17 @@
   void
   writeLog(int hyperbolicState);
 
+public:
+  std::shared_ptr<AfterRoutingChange> afterRoutingChange;
+
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+  std::list<RoutingTableEntry> m_rTable;
+
 private:
   ndn::Scheduler& m_scheduler;
 
   const int m_NO_NEXT_HOP;
 
-  std::list<RoutingTableEntry> m_rTable;
   std::list<RoutingTableEntry> m_dryTable;
 
   ndn::time::seconds m_routingCalcInterval;
diff --git a/src/signals.hpp b/src/signals.hpp
new file mode 100644
index 0000000..b8518b0
--- /dev/null
+++ b/src/signals.hpp
@@ -0,0 +1,36 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2017,  The University of Memphis,
+ *                           Regents of the University of California
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ **/
+
+#ifndef NLSR_SIGNALS_HPP
+#define NLSR_SIGNALS_HPP
+
+#include <ndn-cxx/util/signal.hpp>
+
+namespace nlsr {
+
+class RoutingTable;
+class RoutingTableEntry;
+
+using AfterRoutingChange = ndn::util::Signal<RoutingTable, const std::list<RoutingTableEntry>&>;
+
+} // namespace nlsr
+
+#endif // NLSR_SIGNALS_HPP