[ndnSIM] face: Emulation mode of ndn::Face

Change-Id: Ib345978575104afa436296d2f5a824a39e3a9780
diff --git a/src/detail/face-impl.hpp b/src/detail/face-impl.hpp
index ef49992..b2356c0 100644
--- a/src/detail/face-impl.hpp
+++ b/src/detail/face-impl.hpp
@@ -56,10 +56,9 @@
   Impl(Face& face)
     : m_face(face)
     , m_scheduler(m_face.getIoService())
-    , m_processEventsTimeoutEvent(m_scheduler)
   {
     auto postOnEmptyPitOrNoRegisteredPrefixes = [this] {
-      this->m_face.getIoService().post(bind(&Impl::onEmptyPitOrNoRegisteredPrefixes, this));
+      m_scheduler.scheduleEvent(time::seconds(0), bind(&Impl::onEmptyPitOrNoRegisteredPrefixes, this));
       // without this extra "post", transport can get paused (-async_read) and then resumed
       // (+async_read) from within onInterest/onData callback.  After onInterest/onData
       // finishes, there is another +async_read with the same memory block.  A few of such
@@ -124,7 +123,7 @@
   ensureConnected(bool wantResume)
   {
     if (!m_face.m_transport->isConnected())
-      m_face.m_transport->connect(m_face.m_ioService,
+      m_face.m_transport->connect(m_face.getIoService(),
                                   bind(&Face::onReceiveElement, &m_face, _1));
 
     if (wantResume && !m_face.m_transport->isExpectingData())
@@ -320,23 +319,17 @@
   {
     if (m_pendingInterestTable.empty() && m_registeredPrefixTable.empty()) {
       m_face.m_transport->pause();
-      if (!m_ioServiceWork) {
-        m_processEventsTimeoutEvent.cancel();
-      }
     }
   }
 
 private:
   Face& m_face;
   util::Scheduler m_scheduler;
-  util::scheduler::ScopedEventId m_processEventsTimeoutEvent;
 
   PendingInterestTable m_pendingInterestTable;
   InterestFilterTable m_interestFilterTable;
   RegisteredPrefixTable m_registeredPrefixTable;
 
-  unique_ptr<boost::asio::io_service::work> m_ioServiceWork; // if thread needs to be preserved
-
   friend class Face;
 };
 
diff --git a/src/face.cpp b/src/face.cpp
index 9f64aa6..dde85eb 100644
--- a/src/face.cpp
+++ b/src/face.cpp
@@ -29,58 +29,42 @@
 #include "util/random.hpp"
 #include "util/face-uri.hpp"
 
+#include "ns3/node-list.h"
+#include "ns3/ndnSIM/helper/ndn-stack-helper.hpp"
+#include "ns3/ndnSIM/NFD/daemon/face/generic-link-service.hpp"
+#include "ns3/ndnSIM/NFD/daemon/face/internal-transport.hpp"
+
 namespace ndn {
 
 Face::Face()
-  : m_internalIoService(new boost::asio::io_service())
-  , m_ioService(*m_internalIoService)
-  , m_internalKeyChain(new KeyChain())
-  , m_impl(new Impl(*this))
+  : m_impl(new Impl(*this))
 {
-  construct(nullptr, *m_internalKeyChain);
+  construct(nullptr, ns3::ndn::StackHelper::getKeyChain());
 }
 
 Face::Face(boost::asio::io_service& ioService)
-  : m_ioService(ioService)
-  , m_internalKeyChain(new KeyChain())
-  , m_impl(new Impl(*this))
+  : m_impl(new Impl(*this))
 {
-  construct(nullptr, *m_internalKeyChain);
-}
-
-Face::Face(const std::string& host, const std::string& port/* = "6363"*/)
-  : m_internalIoService(new boost::asio::io_service())
-  , m_ioService(*m_internalIoService)
-  , m_internalKeyChain(new KeyChain())
-  , m_impl(new Impl(*this))
-{
-  construct(make_shared<TcpTransport>(host, port), *m_internalKeyChain);
+  construct(nullptr, ns3::ndn::StackHelper::getKeyChain());
 }
 
 Face::Face(shared_ptr<Transport> transport)
-  : m_internalIoService(new boost::asio::io_service())
-  , m_ioService(*m_internalIoService)
-  , m_internalKeyChain(new KeyChain())
-  , m_impl(new Impl(*this))
+  : m_impl(new Impl(*this))
 {
-  construct(transport, *m_internalKeyChain);
+  construct(transport, ns3::ndn::StackHelper::getKeyChain());
 }
 
 Face::Face(shared_ptr<Transport> transport,
            boost::asio::io_service& ioService)
-  : m_ioService(ioService)
-  , m_internalKeyChain(new KeyChain())
-  , m_impl(new Impl(*this))
+  : m_impl(new Impl(*this))
 {
-  construct(transport, *m_internalKeyChain);
+  construct(transport, ns3::ndn::StackHelper::getKeyChain());
 }
 
 Face::Face(shared_ptr<Transport> transport,
            boost::asio::io_service& ioService,
            KeyChain& keyChain)
-  : m_ioService(ioService)
-  , m_internalKeyChain(nullptr)
-  , m_impl(new Impl(*this))
+  : m_impl(new Impl(*this))
 {
   construct(transport, keyChain);
 }
@@ -88,35 +72,25 @@
 shared_ptr<Transport>
 Face::makeDefaultTransport()
 {
-  // transport=unix:///var/run/nfd.sock
-  // transport=tcp://localhost:6363
+  ns3::Ptr<ns3::Node> node = ns3::NodeList::GetNode(ns3::Simulator::GetContext());
+  NS_ASSERT_MSG(node->GetObject<ns3::ndn::L3Protocol>() != 0,
+                "NDN stack should be installed on the node " << node);
 
-  ConfigFile config;
-  const auto& transportUri = config.getParsedConfiguration()
-                               .get_optional<std::string>("transport");
-  if (!transportUri) {
-    // transport not specified, use default Unix transport.
-    return UnixTransport::create(config);
-  }
+  auto uri = ::nfd::FaceUri("ndnFace://" + boost::lexical_cast<std::string>(node->GetId()));
 
-  std::string protocol;
-  try {
-    util::FaceUri uri(*transportUri);
-    protocol = uri.getScheme();
-  }
-  catch (const util::FaceUri::Error& error) {
-    BOOST_THROW_EXCEPTION(ConfigFile::Error(error.what()));
-  }
+  ::nfd::face::GenericLinkService::Options serviceOpts;
+  serviceOpts.allowLocalFields = true;
 
-  if (protocol == "unix") {
-    return UnixTransport::create(config);
-  }
-  else if (protocol == "tcp" || protocol == "tcp4" || protocol == "tcp6") {
-    return TcpTransport::create(config);
-  }
-  else {
-    BOOST_THROW_EXCEPTION(ConfigFile::Error("Unsupported transport protocol \"" + protocol + "\""));
-  }
+  auto nfdFace = make_shared<::nfd::Face>(make_unique<::nfd::face::GenericLinkService>(serviceOpts),
+                                          make_unique<::nfd::face::InternalForwarderTransport>(uri, uri));
+  auto forwarderTransport = static_cast<::nfd::face::InternalForwarderTransport*>(nfdFace->getTransport());
+
+  auto clientTransport = make_shared<::nfd::face::InternalClientTransport>();
+  clientTransport->connectToForwarder(forwarderTransport);
+
+  node->GetObject<ns3::ndn::L3Protocol>()->addFace(nfdFace);;
+
+  return clientTransport;
 }
 
 void
@@ -129,8 +103,6 @@
   m_transport = transport;
 
   m_nfdController.reset(new nfd::Controller(*this, keyChain));
-
-  m_ioService.post([=] { m_impl->ensureConnected(false); });
 }
 
 Face::~Face() = default;
@@ -155,8 +127,10 @@
   }
 
   // If the same ioService thread, dispatch directly calls the method
-  m_ioService.dispatch([=] { m_impl->asyncExpressInterest(interestToExpress, afterSatisfied,
-                                                          afterNacked, afterTimeout); });
+  m_impl->m_scheduler.scheduleEvent(time::seconds(0), [=] {
+      m_impl->asyncExpressInterest(interestToExpress, afterSatisfied,
+                                   afterNacked, afterTimeout);
+    });
 
   return reinterpret_cast<const PendingInterestId*>(interestToExpress.get());
 }
@@ -211,25 +185,25 @@
   }
 
   // If the same ioService thread, dispatch directly calls the method
-  m_ioService.dispatch([=] { m_impl->asyncPutData(dataPtr); });
+  m_impl->m_scheduler.scheduleEvent(time::seconds(0), [=] { m_impl->asyncPutData(dataPtr); });
 }
 
 void
 Face::put(const lp::Nack& nack)
 {
-  m_ioService.dispatch([=] { m_impl->asyncPutNack(make_shared<lp::Nack>(nack)); });
+  m_impl->m_scheduler.scheduleEvent(time::seconds(0), [=] { m_impl->asyncPutNack(make_shared<lp::Nack>(nack)); });
 }
 
 void
 Face::removePendingInterest(const PendingInterestId* pendingInterestId)
 {
-  m_ioService.post([=] { m_impl->asyncRemovePendingInterest(pendingInterestId); });
+  m_impl->m_scheduler.scheduleEvent(time::seconds(0), [=] { m_impl->asyncRemovePendingInterest(pendingInterestId); });
 }
 
 void
 Face::removeAllPendingInterests()
 {
-  m_ioService.post([=] { m_impl->asyncRemoveAllPendingInterests(); });
+  m_impl->m_scheduler.scheduleEvent(time::seconds(0), [=] { m_impl->asyncRemoveAllPendingInterests(); });
 }
 
 size_t
@@ -279,7 +253,9 @@
   shared_ptr<InterestFilterRecord> filter =
     make_shared<InterestFilterRecord>(interestFilter, onInterest);
 
-  getIoService().post([=] { m_impl->asyncSetInterestFilter(filter); });
+  m_impl->m_scheduler.scheduleEvent(time::seconds(0), [=] {
+      m_impl->asyncSetInterestFilter(filter);
+    });
 
   return reinterpret_cast<const InterestFilterId*>(filter.get());
 }
@@ -396,7 +372,7 @@
 void
 Face::unsetInterestFilter(const RegisteredPrefixId* registeredPrefixId)
 {
-  m_ioService.post([=] { m_impl->asyncUnregisterPrefix(registeredPrefixId,
+  m_impl->m_scheduler.scheduleEvent(time::seconds(0), [=] { m_impl->asyncUnregisterPrefix(registeredPrefixId,
                                                        UnregisterPrefixSuccessCallback(),
                                                        UnregisterPrefixFailureCallback()); });
 }
@@ -404,7 +380,7 @@
 void
 Face::unsetInterestFilter(const InterestFilterId* interestFilterId)
 {
-  m_ioService.post([=] { m_impl->asyncUnsetInterestFilter(interestFilterId); });
+  m_impl->m_scheduler.scheduleEvent(time::seconds(0), [=] { m_impl->asyncUnsetInterestFilter(interestFilterId); });
 }
 
 void
@@ -412,53 +388,19 @@
                        const UnregisterPrefixSuccessCallback& onSuccess,
                        const UnregisterPrefixFailureCallback& onFailure)
 {
-  m_ioService.post([=] { m_impl->asyncUnregisterPrefix(registeredPrefixId,onSuccess, onFailure); });
+  m_impl->m_scheduler.scheduleEvent(time::seconds(0), [=] { m_impl->asyncUnregisterPrefix(registeredPrefixId,onSuccess, onFailure); });
 }
 
 void
 Face::processEvents(const time::milliseconds& timeout/* = time::milliseconds::zero()*/,
                     bool keepThread/* = false*/)
 {
-  if (m_ioService.stopped()) {
-    m_ioService.reset(); // ensure that run()/poll() will do some work
-  }
-
-  try {
-    if (timeout < time::milliseconds::zero()) {
-        // do not block if timeout is negative, but process pending events
-        m_ioService.poll();
-        return;
-      }
-
-    if (timeout > time::milliseconds::zero()) {
-      boost::asio::io_service& ioService = m_ioService;
-      unique_ptr<boost::asio::io_service::work>& work = m_impl->m_ioServiceWork;
-      m_impl->m_processEventsTimeoutEvent =
-        m_impl->m_scheduler.scheduleEvent(timeout, [&ioService, &work] {
-            ioService.stop();
-            work.reset();
-          });
-    }
-
-    if (keepThread) {
-      // work will ensure that m_ioService is running until work object exists
-      m_impl->m_ioServiceWork.reset(new boost::asio::io_service::work(m_ioService));
-    }
-
-    m_ioService.run();
-  }
-  catch (...) {
-    m_impl->m_ioServiceWork.reset();
-    m_impl->m_pendingInterestTable.clear();
-    m_impl->m_registeredPrefixTable.clear();
-    throw;
-  }
 }
 
 void
 Face::shutdown()
 {
-  m_ioService.post([this] { this->asyncShutdown(); });
+  m_impl->m_scheduler.scheduleEvent(time::seconds(0), [this] { this->asyncShutdown(); });
 }
 
 void
@@ -469,8 +411,6 @@
 
   if (m_transport->isConnected())
     m_transport->close();
-
-  m_impl->m_ioServiceWork.reset();
 }
 
 /**
diff --git a/src/face.hpp b/src/face.hpp
index 1fa2aca..b6d2680 100644
--- a/src/face.hpp
+++ b/src/face.hpp
@@ -168,16 +168,6 @@
   Face(boost::asio::io_service& ioService);
 
   /**
-   * @brief Create a new Face using TcpTransport
-   *
-   * @param host The host of the NDN forwarder
-   * @param port (optional) The port or service name of the NDN forwarder (**default**: "6363")
-   *
-   * @throws Face::Error on unsupported protocol
-   */
-  Face(const std::string& host, const std::string& port = "6363");
-
-  /**
    * @brief Create a new Face using the given Transport
    * @param transport the Transport used for communication. If nullptr, then the default
    *                  transport will be used.
@@ -668,12 +658,12 @@
   shutdown();
 
   /**
-   * @brief Get reference to IO service object
+   * @brief Return nullptr (cannot use IoService in simulations), preserved for API compatibility
    */
   boost::asio::io_service&
   getIoService()
   {
-    return m_ioService;
+    return *static_cast<boost::asio::io_service*>(nullptr);
   }
 
 NDN_CXX_PUBLIC_WITH_TESTS_ELSE_PROTECTED:
@@ -705,21 +695,8 @@
   asyncShutdown();
 
 private:
-  /// the IO service owned by this Face, could be null
-  unique_ptr<boost::asio::io_service> m_internalIoService;
-  /// the IO service used by this Face
-  boost::asio::io_service& m_ioService;
-
   shared_ptr<Transport> m_transport;
 
-  /** @brief if not null, a pointer to an internal KeyChain owned by Face
-   *  @note if a KeyChain is supplied to constructor, this pointer will be null,
-   *        and the passed KeyChain is given to nfdController;
-   *        currently Face does not keep the KeyChain passed in constructor
-   *        because it's not needed, but this may change in the future
-   */
-  unique_ptr<KeyChain> m_internalKeyChain;
-
   unique_ptr<nfd::Controller> m_nfdController;
 
   class Impl;