rib: ReadvertiseDestination availability

refs: #3818

Change-Id: Ifc2875ba38025595f3d6a8f8207f5ec126f93c90
diff --git a/rib/readvertise/nfd-rib-readvertise-destination.cpp b/rib/readvertise/nfd-rib-readvertise-destination.cpp
index 849f6cb..dcf3d93 100644
--- a/rib/readvertise/nfd-rib-readvertise-destination.cpp
+++ b/rib/readvertise/nfd-rib-readvertise-destination.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2016,  Regents of the University of California,
+ * Copyright (c) 2014-2017,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -32,11 +32,15 @@
 using ndn::nfd::ControlResponse;
 
 NfdRibReadvertiseDestination::NfdRibReadvertiseDestination(ndn::nfd::Controller& controller,
-                                                           //ndn::KeyChain& keyChain,
-                                                           const ndn::Name& commandPrefix)
+                                                           const ndn::Name& commandPrefix,
+                                                           Rib& rib)
   : m_controller(controller)
   , m_commandPrefix(commandPrefix)
 {
+  m_ribAddConn = rib.afterInsertEntry.connect(
+    std::bind(&NfdRibReadvertiseDestination::handleRibAdd, this, _1));
+  m_ribRemoveConn = rib.afterEraseEntry.connect(
+    std::bind(&NfdRibReadvertiseDestination::handleRibRemove, this, _1));
 }
 
 void
@@ -63,5 +67,21 @@
     [=] (const ControlResponse& cr) { failureCb(cr.getText()); });
 }
 
+void
+NfdRibReadvertiseDestination::handleRibAdd(const ndn::Name& name)
+{
+  if (name == m_commandPrefix) {
+    setAvailability(true);
+  }
+}
+
+void
+NfdRibReadvertiseDestination::handleRibRemove(const ndn::Name& name)
+{
+  if (name == m_commandPrefix) {
+    setAvailability(false);
+  }
+}
+
 } // namespace rib
 } // namespace nfd
diff --git a/rib/readvertise/nfd-rib-readvertise-destination.hpp b/rib/readvertise/nfd-rib-readvertise-destination.hpp
index b0cb565..b737d3a 100644
--- a/rib/readvertise/nfd-rib-readvertise-destination.hpp
+++ b/rib/readvertise/nfd-rib-readvertise-destination.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2016,  Regents of the University of California,
+ * Copyright (c) 2014-2017,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -44,7 +44,8 @@
 {
 public:
   NfdRibReadvertiseDestination(ndn::nfd::Controller& controller,
-                               const ndn::Name& commandPrefix);
+                               const ndn::Name& commandPrefix,
+                               Rib& rib);
 
   /** \brief add a name prefix into NFD RIB
    */
@@ -61,8 +62,18 @@
            std::function<void(const std::string&)> failureCb) override;
 
 private:
+  void
+  handleRibAdd(const ndn::Name& name);
+
+  void
+  handleRibRemove(const ndn::Name& name);
+
+private:
   ndn::nfd::Controller& m_controller;
   Name m_commandPrefix;
+
+  signal::ScopedConnection m_ribAddConn;
+  signal::ScopedConnection m_ribRemoveConn;
 };
 
 } // namespace rib
diff --git a/rib/readvertise/readvertise-destination.cpp b/rib/readvertise/readvertise-destination.cpp
new file mode 100644
index 0000000..c064b23
--- /dev/null
+++ b/rib/readvertise/readvertise-destination.cpp
@@ -0,0 +1,41 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2017,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD 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.
+ *
+ * NFD 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
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "readvertise-destination.hpp"
+
+namespace nfd {
+namespace rib {
+
+void
+ReadvertiseDestination::setAvailability(bool isAvailable)
+{
+  if (m_isAvailable != isAvailable) {
+    m_isAvailable = isAvailable;
+    afterAvailabilityChange(isAvailable);
+  }
+}
+
+} // namespace rib
+} // namespace nfd
diff --git a/rib/readvertise/readvertise-destination.hpp b/rib/readvertise/readvertise-destination.hpp
index b31e6f0..204d2b6 100644
--- a/rib/readvertise/readvertise-destination.hpp
+++ b/rib/readvertise/readvertise-destination.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2016,  Regents of the University of California,
+ * Copyright (c) 2014-2017,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -50,6 +50,25 @@
   withdraw(nfd::rib::ReadvertisedRoute& rr,
            std::function<void()> successCb,
            std::function<void(const std::string&)> failureCb) = 0;
+
+  bool
+  isAvailable() const
+  {
+    return m_isAvailable;
+  };
+
+protected:
+  void
+  setAvailability(bool isAvailable);
+
+public:
+  /** \brief signals when the destination becomes available or unavailable
+   */
+  ndn::util::signal::Signal<ReadvertiseDestination, bool>
+  afterAvailabilityChange;
+
+private:
+  bool m_isAvailable = false;
 };
 
 } // namespace rib
diff --git a/tests/rib/readvertise/nfd-rib-readvertise-destination.t.cpp b/tests/rib/readvertise/nfd-rib-readvertise-destination.t.cpp
index 433c92f..61cfb62 100644
--- a/tests/rib/readvertise/nfd-rib-readvertise-destination.t.cpp
+++ b/tests/rib/readvertise/nfd-rib-readvertise-destination.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2016,  Regents of the University of California,
+ * Copyright (c) 2014-2017,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -46,7 +46,7 @@
     , nFailureCallbacks(0)
     , face(getGlobalIoService(), m_keyChain, {true, false})
     , controller(face, m_keyChain)
-    , dest(controller, Name("/localhop/nfd/rib/readvertise"))
+    , dest(controller, Name("/localhop/nfd/rib/readvertise"), rib)
     , successCallback([this] () {
         nSuccessCallbacks++;
       })
@@ -63,6 +63,7 @@
 protected:
   ndn::util::DummyClientFace face;
   ndn::nfd::Controller controller;
+  Rib rib;
   NfdRibReadvertiseDestination dest;
   std::function<void()> successCallback;
   std::function<void(const std::string&)> failureCallback;
@@ -231,6 +232,30 @@
   scenario.checkCommandOutcome(this);
 }
 
+BOOST_AUTO_TEST_CASE(DestinationAvailability)
+{
+  std::vector<bool> availabilityChangeHistory;
+  Name prefix("/localhop/nfd/rib/readvertise");
+  Route route;
+
+  dest.afterAvailabilityChange.connect(
+    std::bind(&std::vector<bool>::push_back, &availabilityChangeHistory, _1));
+  BOOST_CHECK_EQUAL(dest.isAvailable(), false);
+
+  rib.insert(prefix, route);
+  this->advanceClocks(time::milliseconds(100), 1);
+  BOOST_CHECK_EQUAL(dest.isAvailable(), true);
+  BOOST_CHECK_EQUAL(availabilityChangeHistory.size(), 1);
+  BOOST_CHECK_EQUAL(availabilityChangeHistory.back(), true);
+
+  rib.erase(prefix, route);
+
+  this->advanceClocks(time::milliseconds(100), 1);
+  BOOST_CHECK_EQUAL(dest.isAvailable(), false);
+  BOOST_CHECK_EQUAL(availabilityChangeHistory.size(), 2);
+  BOOST_CHECK_EQUAL(availabilityChangeHistory.back(), false);
+}
+
 BOOST_AUTO_TEST_SUITE_END() // TestNfdRibReadvertiseDestination
 
 } // namespace tests