tools: simplify autoconfig MulticastDiscovery stage

refs #4158

Change-Id: Ib44804a0ac97b59d567fe8c0493c7d9ec4915137
diff --git a/tools/ndn-autoconfig/multicast-discovery.cpp b/tools/ndn-autoconfig/multicast-discovery.cpp
index f9b4797..c74d5f3 100644
--- a/tools/ndn-autoconfig/multicast-discovery.cpp
+++ b/tools/ndn-autoconfig/multicast-discovery.cpp
@@ -24,146 +24,132 @@
  */
 
 #include "multicast-discovery.hpp"
-
+#include <boost/lexical_cast.hpp>
 #include <ndn-cxx/encoding/tlv-nfd.hpp>
 
 namespace ndn {
 namespace tools {
 namespace autoconfig {
 
-static const Name LOCALHOP_HUB_DISCOVERY_PREFIX = "/localhop/ndn-autoconf/hub";
+using nfd::ControlParameters;
+using nfd::ControlResponse;
+
+static const Name HUB_DISCOVERY_PREFIX("/localhop/ndn-autoconf/hub");
+static const uint64_t HUB_DISCOVERY_ROUTE_COST(1);
+static const time::milliseconds HUB_DISCOVERY_ROUTE_EXPIRATION = time::seconds(30);
+static const time::milliseconds HUB_DISCOVERY_INTEREST_LIFETIME = time::seconds(4);
 
 MulticastDiscovery::MulticastDiscovery(Face& face, nfd::Controller& controller)
   : m_face(face)
   , m_controller(controller)
-  , m_nRequestedRegs(0)
-  , m_nFinishedRegs(0)
 {
 }
 
 void
 MulticastDiscovery::doStart()
 {
-  this->collectMulticastFaces();
-}
-
-void
-MulticastDiscovery::collectMulticastFaces()
-{
   nfd::FaceQueryFilter filter;
   filter.setLinkType(nfd::LINK_TYPE_MULTI_ACCESS);
+
   m_controller.fetch<nfd::FaceQueryDataset>(
     filter,
     bind(&MulticastDiscovery::registerHubDiscoveryPrefix, this, _1),
-    bind(&MulticastDiscovery::fail, this, _2)
-  );
+    [this] (uint32_t code, const std::string& reason) {
+      this->fail("Error " + to_string(code) + " when querying multi-access faces: " + reason);
+    });
 }
 
 void
 MulticastDiscovery::registerHubDiscoveryPrefix(const std::vector<nfd::FaceStatus>& dataset)
 {
-  std::vector<uint64_t> multicastFaces;
-  std::transform(dataset.begin(), dataset.end(), std::back_inserter(multicastFaces),
-                 [] (const nfd::FaceStatus& faceStatus) { return faceStatus.getFaceId(); });
+  if (dataset.empty()) {
+    this->fail("No multi-access faces available");
+    return;
+  }
 
-  if (multicastFaces.empty()) {
-    this->fail("No multicast faces available, skipping multicast discovery stage");
+  m_nRegs = dataset.size();
+  m_nRegSuccess = 0;
+  m_nRegFailure = 0;
+
+  for (const auto& faceStatus : dataset) {
+    ControlParameters parameters;
+    parameters.setName(HUB_DISCOVERY_PREFIX)
+              .setFaceId(faceStatus.getFaceId())
+              .setCost(HUB_DISCOVERY_ROUTE_COST)
+              .setExpirationPeriod(HUB_DISCOVERY_ROUTE_EXPIRATION);
+
+    m_controller.start<nfd::RibRegisterCommand>(
+      parameters,
+      [this] (const ControlParameters&) {
+        ++m_nRegSuccess;
+        afterReg();
+      },
+      [this, faceStatus] (const ControlResponse& resp) {
+        std::cerr << "Error " << resp.getCode() << " when registering hub discovery prefix "
+                  << "for face " << faceStatus.getFaceId() << " (" << faceStatus.getRemoteUri()
+                  << "): " << resp.getText() << std::endl;
+        ++m_nRegFailure;
+        afterReg();
+      });
+  }
+}
+
+void
+MulticastDiscovery::afterReg()
+{
+  if (m_nRegSuccess + m_nRegFailure < m_nRegs) {
+    return; // continue waiting
+  }
+  if (m_nRegSuccess > 0) {
+    this->setStrategy();
   }
   else {
-    nfd::ControlParameters parameters;
-    parameters
-      .setName(LOCALHOP_HUB_DISCOVERY_PREFIX)
-      .setCost(1)
-      .setExpirationPeriod(time::seconds(30));
-
-    m_nRequestedRegs = multicastFaces.size();
-    m_nFinishedRegs = 0;
-
-    for (const auto& face : multicastFaces) {
-      parameters.setFaceId(face);
-      m_controller.start<nfd::RibRegisterCommand>(
-        parameters,
-        bind(&MulticastDiscovery::onRegisterSuccess, this),
-        bind(&MulticastDiscovery::onRegisterFailure, this, _1));
-    }
-  }
-}
-
-void
-MulticastDiscovery::onRegisterSuccess()
-{
-  ++m_nFinishedRegs;
-
-  if (m_nRequestedRegs == m_nFinishedRegs) {
-    MulticastDiscovery::setStrategy();
-  }
-}
-
-void
-MulticastDiscovery::onRegisterFailure(const nfd::ControlResponse& response)
-{
-  std::cerr << "ERROR: " << response.getText() << " (code: " << response.getCode() << ")" << std::endl;
-  --m_nRequestedRegs;
-
-  if (m_nRequestedRegs == m_nFinishedRegs) {
-    if (m_nRequestedRegs > 0) {
-      MulticastDiscovery::setStrategy();
-    }
-    else {
-      this->fail("Failed to register " + LOCALHOP_HUB_DISCOVERY_PREFIX.toUri() +
-                 " for all multicast faces, skipping multicast discovery stage");
-    }
+    this->fail("Cannot register hub discovery prefix for any face");
   }
 }
 
 void
 MulticastDiscovery::setStrategy()
 {
-  nfd::ControlParameters parameters;
-  parameters
-    .setName(LOCALHOP_HUB_DISCOVERY_PREFIX)
-    .setStrategy("/localhost/nfd/strategy/multicast");
+  ControlParameters parameters;
+  parameters.setName(HUB_DISCOVERY_PREFIX)
+            .setStrategy("/localhost/nfd/strategy/multicast"),
 
   m_controller.start<nfd::StrategyChoiceSetCommand>(
     parameters,
     bind(&MulticastDiscovery::requestHubData, this),
-    bind(&MulticastDiscovery::onSetStrategyFailure, this, _1));
-}
-
-void
-MulticastDiscovery::onSetStrategyFailure(const nfd::ControlResponse& response)
-{
-  this->fail("Failed to set multicast strategy for " +
-             LOCALHOP_HUB_DISCOVERY_PREFIX.toUri() + " namespace (" + response.getText() + "). "
-             "Skipping multicast discovery stage");
+    [this] (const ControlResponse& resp) {
+      this->fail("Error " + to_string(resp.getCode()) + " when setting multicast strategy: " +
+                 resp.getText());
+    });
 }
 
 void
 MulticastDiscovery::requestHubData()
 {
-  Interest interest(LOCALHOP_HUB_DISCOVERY_PREFIX);
-  interest.setInterestLifetime(time::milliseconds(4000)); // 4 seconds
+  Interest interest(HUB_DISCOVERY_PREFIX);
+  interest.setInterestLifetime(HUB_DISCOVERY_INTEREST_LIFETIME);
   interest.setMustBeFresh(true);
 
   m_face.expressInterest(interest,
-                         bind(&MulticastDiscovery::onSuccess, this, _2),
-                         bind(&MulticastDiscovery::fail, this, "HUB Data not received: nacked"),
-                         bind(&MulticastDiscovery::fail, this, "HUB Data not received: timeout"));
-}
+    [this] (const Interest&, const Data& data) {
+      const Block& content = data.getContent();
+      content.parse();
 
-void
-MulticastDiscovery::onSuccess(const Data& data)
-{
-  const Block& content = data.getContent();
-  content.parse();
+      auto i = content.find(tlv::nfd::Uri);
+      if (i == content.elements_end()) {
+        this->fail("Malformed hub Data: missing Uri element");
+        return;
+      }
 
-  // Get Uri
-  Block::element_const_iterator blockValue = content.find(tlv::nfd::Uri);
-  if (blockValue == content.elements_end()) {
-    this->fail("Incorrect reply to multicast discovery stage");
-    return;
-  }
-  this->provideHubFaceUri(std::string(reinterpret_cast<const char*>(blockValue->value()), blockValue->value_size()));
+      this->provideHubFaceUri(std::string(reinterpret_cast<const char*>(i->value()), i->value_size()));
+    },
+    [this] (const Interest&, const lp::Nack& nack) {
+      this->fail("Nack-" + boost::lexical_cast<std::string>(nack.getReason()) + " when retrieving hub Data");
+    },
+    [this] (const Interest&) {
+      this->fail("Timeout when retrieving hub Data");
+    });
 }
 
 } // namespace autoconfig
diff --git a/tools/ndn-autoconfig/multicast-discovery.hpp b/tools/ndn-autoconfig/multicast-discovery.hpp
index d714306..a1d5884 100644
--- a/tools/ndn-autoconfig/multicast-discovery.hpp
+++ b/tools/ndn-autoconfig/multicast-discovery.hpp
@@ -35,31 +35,28 @@
 namespace tools {
 namespace autoconfig {
 
-/**
- * @brief Multicast discovery stage
+/** \brief multicast discovery stage
  *
- * - Request
+ *  This stage locates an NDN gateway router, commonly known as a "hub", in the local network by
+ *  sending a hub discovery Interest ndn:/localhop/ndn-autoconf/hub via multicast. This class
+ *  configures routes and strategy on local NFD, so that this Interest is multicast to all
+ *  multi-access faces.
  *
- *     The end host sends an Interest over a multicast face.
+ *  If an NDN gateway router is present in the local network, it should reply with a Data
+ *  containing its own FaceUri. The Data payload contains a Uri element, and the value of this
+ *  element is an ASCII-encoded string of the router's FaceUri. The router may use
+ *  ndn-autoconfig-server program to serve this Data.
  *
- *     Interest Name is /localhop/ndn-autoconf/hub.
- *
- * - Response
- *
- *     A producer app on the HUB answer this Interest with a Data packet that contains a
- *     TLV-encoded Uri block.  The value of this block is the URI for the HUB, preferably a
- *     UDP tunnel.
+ *  Signature on this Data is currently not verified. This stage succeeds when the Data is
+ *  successfully decoded.
  */
 class MulticastDiscovery : public Stage
 {
 public:
-  /**
-   * @brief Create multicast discovery stage
-   */
   MulticastDiscovery(Face& face, nfd::Controller& controller);
 
   const std::string&
-  getName() const override
+  getName() const final
   {
     static const std::string STAGE_NAME("multicast discovery");
     return STAGE_NAME;
@@ -67,38 +64,27 @@
 
 private:
   void
-  doStart() override;
-
-  void
-  collectMulticastFaces();
+  doStart() final;
 
   void
   registerHubDiscoveryPrefix(const std::vector<nfd::FaceStatus>& dataset);
 
   void
-  onRegisterSuccess();
-
-  void
-  onRegisterFailure(const nfd::ControlResponse& response);
+  afterReg();
 
   void
   setStrategy();
 
   void
-  onSetStrategyFailure(const nfd::ControlResponse& response);
-
-  // Start to look for a hub (NDN hub discovery first stage)
-  void
   requestHubData();
 
-  void
-  onSuccess(const Data& data);
-
 private:
   Face& m_face;
   nfd::Controller& m_controller;
-  size_t m_nRequestedRegs;
-  size_t m_nFinishedRegs;
+
+  int m_nRegs = 0;
+  int m_nRegSuccess = 0;
+  int m_nRegFailure = 0;
 };
 
 } // namespace autoconfig