nlsr: canonize Adjacent FaceURIs on startup

Change-Id: I6a2b31631918c1ece79c3fc13e392917162efc2d
refs: #4063
diff --git a/src/common.hpp b/src/common.hpp
index 65105d7..4e82370 100644
--- a/src/common.hpp
+++ b/src/common.hpp
@@ -23,6 +23,7 @@
 #define NLSR_COMMON_HPP
 
 #include <ndn-cxx/common.hpp>
+#include <ndn-cxx/util/time.hpp>
 
 namespace nlsr {
 
@@ -31,6 +32,8 @@
 using std::shared_ptr;
 using std::function;
 
-}
+const ndn::time::seconds TIME_ALLOWED_FOR_CANONIZATION = ndn::time::seconds(4);
+
+} // namespace nlsr
 
 #endif // NLSR_COMMON_HPP
diff --git a/src/nlsr-runner.cpp b/src/nlsr-runner.cpp
index d5bf709..29e4737 100644
--- a/src/nlsr-runner.cpp
+++ b/src/nlsr-runner.cpp
@@ -57,8 +57,16 @@
     m_nlsr.daemonize();
   }
 
-  m_nlsr.initialize();
-
+  /**
+   * This really should be part of Nlsr::initialize, but because URI
+   * canonization happens asynchronously and we need to ensure that it
+   * happens before we proceed, the canonization function has to be
+   * the one to call initialize.
+   */
+  m_nlsr.canonizeNeighborUris(m_nlsr.getAdjacencyList().getAdjList().begin(),
+                              [this] (std::list<Adjacent>::iterator iterator) {
+                                m_nlsr.canonizeContinuation(iterator);
+                              });
   try {
     m_nlsr.startEventLoop();
   }
diff --git a/src/nlsr.cpp b/src/nlsr.cpp
index 2bcc157..8a88c1f 100644
--- a/src/nlsr.cpp
+++ b/src/nlsr.cpp
@@ -190,6 +190,40 @@
 }
 
 void
+Nlsr::canonizeContinuation(std::list<Adjacent>::iterator iterator)
+{
+  canonizeNeighborUris(iterator, [this] (std::list<Adjacent>::iterator iterator) {
+      canonizeContinuation(iterator);
+  });
+}
+
+void
+Nlsr::canonizeNeighborUris(std::list<Adjacent>::iterator currentNeighbor,
+                           std::function<void(std::list<Adjacent>::iterator)> then)
+{
+  if (currentNeighbor != m_adjacencyList.getAdjList().end()) {
+    ndn::util::FaceUri uri(currentNeighbor->getConnectingFaceUri());
+    uri.canonize([this, then, currentNeighbor] (ndn::util::FaceUri canonicalUri) {
+        _LOG_DEBUG("Canonized URI: " << currentNeighbor->getConnectingFaceUri()
+                   << " to: " << canonicalUri);
+        currentNeighbor->setConnectingFaceUri(canonicalUri.toString());
+        then(std::next(currentNeighbor));
+      },
+      [this, then, currentNeighbor] (const std::string& reason) {
+        _LOG_ERROR("Could not canonize URI: " << currentNeighbor->getConnectingFaceUri()
+                   << " because: " << reason);
+        then(std::next(currentNeighbor));
+      },
+      m_nlsrFace.getIoService(),
+      TIME_ALLOWED_FOR_CANONIZATION);
+  }
+  // We have finished canonizing all neighbors, so initialize NLSR.
+  else {
+    initialize();
+  }
+}
+
+void
 Nlsr::initialize()
 {
   _LOG_DEBUG("Initializing Nlsr");
diff --git a/src/nlsr.hpp b/src/nlsr.hpp
index eb9132d..574e53a 100644
--- a/src/nlsr.hpp
+++ b/src/nlsr.hpp
@@ -53,13 +53,14 @@
 #include "update/nfd-rib-command-processor.hpp"
 #include "utility/name-helper.hpp"
 
-
 namespace nlsr {
 
 static ndn::Name DEFAULT_BROADCAST_PREFIX("/ndn/broadcast");
 
 class Nlsr
 {
+  friend class NlsrRunner;
+
   class Error : public std::runtime_error
   {
   public:
@@ -323,6 +324,26 @@
     return m_firstHelloInterval;
   }
 
+  /**
+   * \brief Canonize the URI for this and all proceeding neighbors in a list.
+   *
+   * This function canonizes the URI of the Adjacent object pointed to
+   * by currentNeighbor. It then executes the then callback, providing
+   * the next iterator in the list to the callback. A standard
+   * invocation would be to pass the begin() iterator of NLSR's
+   * adjacency list, and to provide Nlsr::canonizeContinuation as the
+   * callback. Because every URI must be canonical before we begin
+   * operations, the canonize function must call initialize itself.
+   *
+   * \sa Nlsr::canonizeContinuation
+   * \sa Nlsr::initialize
+   * \sa NlsrRunner::run
+   */
+  void
+  canonizeNeighborUris(std::list<Adjacent>::iterator currentNeighbor,
+                       std::function<void(std::list<Adjacent>::iterator)> then);
+
+
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   void
   addCertificateToCache(std::shared_ptr<ndn::IdentityCertificate> certificate)
@@ -366,6 +387,17 @@
     m_firstHelloInterval = interval;
   }
 
+  /**
+   * \brief Continues canonizing neighbor URIs.
+   *
+   * For testability reasons, we want what each instance of
+   * canonization does after completion to be controllable. The best
+   * way to do this is to control that by simply passing a
+   * continuation function.
+   */
+  void
+  canonizeContinuation(std::list<Adjacent>::iterator iterator);
+
 public:
   static const ndn::Name LOCALHOST_PREFIX;
 
diff --git a/src/utility/face-controller.cpp b/src/utility/face-controller.cpp
index 62778cd..e6c0a8b 100644
--- a/src/utility/face-controller.cpp
+++ b/src/utility/face-controller.cpp
@@ -31,8 +31,6 @@
 
 using ndn::util::FaceUri;
 
-const ndn::time::seconds FaceController::TIME_ALLOWED_FOR_CANONIZATION = ndn::time::seconds(4);
-
 void
 FaceController::createFace(const std::string& request,
                            const CommandSuccessCallback& onSuccess,
diff --git a/src/utility/face-controller.hpp b/src/utility/face-controller.hpp
index 9e4527e..d44c2ec 100644
--- a/src/utility/face-controller.hpp
+++ b/src/utility/face-controller.hpp
@@ -68,7 +68,6 @@
   ndn::nfd::Controller& m_controller;
 
   static const uint32_t CANONIZE_ERROR_CODE = 408;
-  static const ndn::time::seconds TIME_ALLOWED_FOR_CANONIZATION;
 };
 
 } // namespace util