[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 fb6642a..5ebec16 100644
--- a/src/detail/face-impl.hpp
+++ b/src/detail/face-impl.hpp
@@ -40,6 +40,13 @@
 #include "../management/nfd-controller.hpp"
 #include "../management/nfd-command-options.hpp"
 
+#include <ns3/ptr.h>
+#include <ns3/node.h>
+#include <ns3/node-list.h>
+#include <ns3/ndnSIM/model/ndn-l3-protocol.hpp>
+
+#include "ns3/ndnSIM/NFD/daemon/face/local-face.hpp"
+
 namespace ndn {
 
 class Face::Impl : noncopyable
@@ -49,29 +56,80 @@
   typedef std::list<shared_ptr<InterestFilterRecord> > InterestFilterTable;
   typedef ContainerWithOnEmptySignal<shared_ptr<RegisteredPrefix>> RegisteredPrefixTable;
 
+  class NfdFace : public ::nfd::LocalFace
+  {
+  public:
+    NfdFace(Impl& face, const ::nfd::FaceUri& localUri, const ::nfd::FaceUri& remoteUri)
+      : ::nfd::LocalFace(localUri, remoteUri)
+      , m_appFaceImpl(face)
+    {
+    }
+
+  public: // from ::nfd::LocalFace
+    /**
+     * @brief Send Interest towards application
+     */
+    virtual void
+    sendInterest(const Interest& interest)
+    {
+      NS_LOG_DEBUG("<< Interest " << interest);
+      shared_ptr<const Interest> interestPtr = interest.shared_from_this();
+      m_appFaceImpl.m_scheduler.scheduleEvent(time::seconds(0), [this, interestPtr] {
+          m_appFaceImpl.processInterestFilters(*interestPtr);
+        });
+    }
+
+    /**
+     * @brief Send Data towards application
+     */
+    virtual void
+    sendData(const Data& data)
+    {
+      NS_LOG_DEBUG("<< Data " << data.getName());
+      shared_ptr<const Data> dataPtr = data.shared_from_this();
+      m_appFaceImpl.m_scheduler.scheduleEvent(time::seconds(0), [this, dataPtr] {
+          m_appFaceImpl.satisfyPendingInterests(*dataPtr);
+        });
+    }
+
+    /** \brief Close the face
+     *
+     *  This terminates all communication on the face and cause
+     *  onFail() method event to be invoked
+     */
+    virtual void
+    close()
+    {
+      this->fail("close");
+    }
+
+  private:
+    friend class Impl;
+    Impl& m_appFaceImpl;
+  };
+
+  ////////////////////////////////////////////////////////////////////////
+
   explicit
   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));
-      // 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
-      // async_read duplications can cause various effects and result in segfault.
-    };
+    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);
 
-    m_pendingInterestTable.onEmpty.connect(postOnEmptyPitOrNoRegisteredPrefixes);
-    m_registeredPrefixTable.onEmpty.connect(postOnEmptyPitOrNoRegisteredPrefixes);
+    auto uri = ::nfd::FaceUri("ndnFace://" + boost::lexical_cast<std::string>(node->GetId()));
+    m_nfdFace = make_shared<NfdFace>(*this, uri, uri);
+
+    node->GetObject<ns3::ndn::L3Protocol>()->addFace(m_nfdFace);
   }
 
   /////////////////////////////////////////////////////////////////////////////////////////////////
   /////////////////////////////////////////////////////////////////////////////////////////////////
 
   void
-  satisfyPendingInterests(Data& data)
+  satisfyPendingInterests(const Data& data)
   {
     for (auto entry = m_pendingInterestTable.begin(); entry != m_pendingInterestTable.end(); ) {
       if ((*entry)->getInterest().matchesData(data)) {
@@ -87,7 +145,7 @@
   }
 
   void
-  processInterestFilters(Interest& interest)
+  processInterestFilters(const Interest& interest)
   {
     for (const auto& filter : m_interestFilterTable) {
       if (filter->doesMatch(interest.getName())) {
@@ -100,37 +158,16 @@
   /////////////////////////////////////////////////////////////////////////////////////////////////
 
   void
-  ensureConnected(bool wantResume)
-  {
-    if (!m_face.m_transport->isConnected())
-      m_face.m_transport->connect(m_face.m_ioService,
-                                  bind(&Face::onReceiveElement, &m_face, _1));
-
-    if (wantResume && !m_face.m_transport->isExpectingData())
-      m_face.m_transport->resume();
-  }
-
-  void
   asyncExpressInterest(const shared_ptr<const Interest>& interest,
                        const OnData& onData, const OnTimeout& onTimeout)
   {
-    this->ensureConnected(true);
-
     auto entry =
       m_pendingInterestTable.insert(make_shared<PendingInterest>(interest,
                                                                  onData, onTimeout,
                                                                  ref(m_scheduler))).first;
     (*entry)->setDeleter([this, entry] { m_pendingInterestTable.erase(entry); });
 
-    if (!interest->getLocalControlHeader().empty(nfd::LocalControlHeader::ENCODE_NEXT_HOP)) {
-      // encode only NextHopFaceId towards the forwarder
-      m_face.m_transport->send(interest->getLocalControlHeader()
-                               .wireEncode(*interest, nfd::LocalControlHeader::ENCODE_NEXT_HOP),
-                               interest->wireEncode());
-    }
-    else {
-      m_face.m_transport->send(interest->wireEncode());
-    }
+    m_nfdFace->emitSignal(onReceiveInterest, *interest);
   }
 
   void
@@ -142,17 +179,7 @@
   void
   asyncPutData(const shared_ptr<const Data>& data)
   {
-    this->ensureConnected(true);
-
-    if (!data->getLocalControlHeader().empty(nfd::LocalControlHeader::ENCODE_CACHING_POLICY)) {
-      m_face.m_transport->send(
-        data->getLocalControlHeader().wireEncode(*data,
-                                                 nfd::LocalControlHeader::ENCODE_CACHING_POLICY),
-        data->wireEncode());
-    }
-    else {
-      m_face.m_transport->send(data->wireEncode());
-    }
+    m_nfdFace->emitSignal(onReceiveData, *data);
   }
 
   /////////////////////////////////////////////////////////////////////////////////////////////////
@@ -266,27 +293,15 @@
     }
   }
 
-  void
-  onEmptyPitOrNoRegisteredPrefixes()
-  {
-    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
+  shared_ptr<NfdFace> m_nfdFace;
 
   friend class Face;
 };
diff --git a/src/detail/pending-interest.hpp b/src/detail/pending-interest.hpp
index 41f6b37..9cea52c 100644
--- a/src/detail/pending-interest.hpp
+++ b/src/detail/pending-interest.hpp
@@ -76,9 +76,9 @@
    * @note If the DataCallback is an empty function, this method does nothing.
    */
   void
-  invokeDataCallback(Data& data)
+  invokeDataCallback(const Data& data)
   {
-    m_onData(*m_interest, data);
+    m_onData(*m_interest, const_cast<Data&>(data));
   }
 
   /**
diff --git a/src/face.cpp b/src/face.cpp
index 98581b3..433453c 100644
--- a/src/face.cpp
+++ b/src/face.cpp
@@ -20,6 +20,10 @@
  */
 
 #include "face.hpp"
+
+#include "ns3/log.h"
+NS_LOG_COMPONENT_DEFINE("ndn-cxx.Face");
+
 #include "detail/face-impl.hpp"
 
 #include "encoding/tlv.hpp"
@@ -29,106 +33,28 @@
 #include "util/random.hpp"
 #include "util/face-uri.hpp"
 
+#include "ns3/ndnSIM/helper/ndn-stack-helper.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(*m_internalKeyChain);
+  construct();
 }
 
-Face::Face(boost::asio::io_service& ioService)
-  : m_ioService(ioService)
-  , m_internalKeyChain(new KeyChain())
-  , m_impl(new Impl(*this))
+Face::Face(boost::asio::io_service&)
+  : m_impl(new Impl(*this))
 {
-  construct(*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);
-}
-
-Face::Face(const shared_ptr<Transport>& transport)
-  : m_internalIoService(new boost::asio::io_service())
-  , m_ioService(*m_internalIoService)
-  , m_internalKeyChain(new KeyChain())
-  , m_impl(new Impl(*this))
-{
-  construct(transport, *m_internalKeyChain);
-}
-
-Face::Face(const shared_ptr<Transport>& transport,
-           boost::asio::io_service& ioService)
-  : m_ioService(ioService)
-  , m_internalKeyChain(new KeyChain())
-  , m_impl(new Impl(*this))
-{
-  construct(transport, *m_internalKeyChain);
-}
-
-Face::Face(shared_ptr<Transport> transport,
-           boost::asio::io_service& ioService,
-           KeyChain& keyChain)
-  : m_ioService(ioService)
-  , m_internalKeyChain(nullptr)
-  , m_impl(new Impl(*this))
-{
-  construct(transport, keyChain);
+  construct();
 }
 
 void
-Face::construct(KeyChain& keyChain)
+Face::construct()
 {
-  // transport=unix:///var/run/nfd.sock
-  // transport=tcp://localhost:6363
+  static ::ndn::KeyChain keyChain("pib-dummy", "tpm-dummy");
 
-  ConfigFile config;
-  const auto& transportType = config.getParsedConfiguration()
-                                .get_optional<std::string>("transport");
-  if (!transportType) {
-    // transport not specified, use default Unix transport.
-    construct(UnixTransport::create(config), keyChain);
-    return;
-  }
-
-  unique_ptr<util::FaceUri> uri;
-  try {
-    uri.reset(new util::FaceUri(*transportType));
-  }
-  catch (const util::FaceUri::Error& error) {
-    BOOST_THROW_EXCEPTION(ConfigFile::Error(error.what()));
-  }
-
-  const std::string protocol = uri->getScheme();
-
-  if (protocol == "unix") {
-    construct(UnixTransport::create(config), keyChain);
-  }
-  else if (protocol == "tcp" || protocol == "tcp4" || protocol == "tcp6") {
-    construct(TcpTransport::create(config), keyChain);
-  }
-  else {
-    BOOST_THROW_EXCEPTION(ConfigFile::Error("Unsupported transport protocol \"" + protocol + "\""));
-  }
-}
-
-void
-Face::construct(shared_ptr<Transport> transport, KeyChain& keyChain)
-{
-  m_nfdController.reset(new nfd::Controller(*this, keyChain));
-
-  m_transport = transport;
-
-  m_impl->ensureConnected(false);
+  m_nfdController.reset(new nfd::Controller(*this, ns3::ndn::StackHelper::getKeyChain()));
 }
 
 Face::~Face() = default;
@@ -136,14 +62,12 @@
 const PendingInterestId*
 Face::expressInterest(const Interest& interest, const OnData& onData, const OnTimeout& onTimeout)
 {
+  NS_LOG_INFO (">> Interest: " << interest.getName());
+
   shared_ptr<Interest> interestToExpress = make_shared<Interest>(interest);
-
-  // Use `interestToExpress` to avoid wire format creation for the original Interest
-  if (interestToExpress->wireEncode().size() > MAX_NDN_PACKET_SIZE)
-    BOOST_THROW_EXCEPTION(Error("Interest size exceeds maximum limit"));
-
-  // If the same ioService thread, dispatch directly calls the method
-  m_ioService.dispatch([=] { m_impl->asyncExpressInterest(interestToExpress, onData, onTimeout); });
+  m_impl->m_scheduler.scheduleEvent(time::seconds(0), [=] {
+      m_impl->asyncExpressInterest(interestToExpress, onData, onTimeout);
+    });
 
   return reinterpret_cast<const PendingInterestId*>(interestToExpress.get());
 }
@@ -154,36 +78,37 @@
                       const OnData& onData, const OnTimeout& onTimeout/* = OnTimeout()*/)
 {
   return expressInterest(Interest(tmpl)
-                         .setName(name)
-                         .setNonce(0),
+                           .setName(name)
+                           .setNonce(0),
                          onData, onTimeout);
 }
 
 void
 Face::put(const Data& data)
 {
-  // Use original `data`, since wire format should already exist for the original Data
-  if (data.wireEncode().size() > MAX_NDN_PACKET_SIZE)
-    BOOST_THROW_EXCEPTION(Error("Data size exceeds maximum limit"));
+  NS_LOG_INFO (">> Data: " << data.getName());
 
   shared_ptr<const Data> dataPtr;
   try {
     dataPtr = data.shared_from_this();
   }
   catch (const bad_weak_ptr& e) {
-    std::cerr << "Face::put WARNING: the supplied Data should be created using make_shared<Data>()"
-              << std::endl;
+    NS_LOG_INFO("Face::put WARNING: the supplied Data should be created using make_shared<Data>()");
     dataPtr = make_shared<Data>(data);
   }
 
-  // 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::removePendingInterest(const PendingInterestId* pendingInterestId)
 {
-  m_ioService.post([=] { m_impl->asyncRemovePendingInterest(pendingInterestId); });
+  m_impl->m_scheduler.scheduleEvent(time::seconds(0),
+                                    [=] {
+                                      m_impl->asyncRemovePendingInterest(pendingInterestId);
+                                    });
 }
 
 size_t
@@ -194,46 +119,49 @@
 
 const RegisteredPrefixId*
 Face::setInterestFilter(const InterestFilter& interestFilter,
-                  const OnInterest& onInterest,
-                  const RegisterPrefixFailureCallback& onFailure,
-                  const security::SigningInfo& signingInfo,
-                  uint64_t flags)
+                        const OnInterest& onInterest,
+                        const RegisterPrefixFailureCallback& onFailure,
+                        const security::SigningInfo& signingInfo,
+                        uint64_t flags)
 {
-    return setInterestFilter(interestFilter,
-                             onInterest,
-                             RegisterPrefixSuccessCallback(),
-                             onFailure,
-                             signingInfo,
-                             flags);
+  return setInterestFilter(interestFilter,
+                           onInterest,
+                           RegisterPrefixSuccessCallback(),
+                           onFailure,
+                           signingInfo,
+                           flags);
 }
 
 const RegisteredPrefixId*
 Face::setInterestFilter(const InterestFilter& interestFilter,
-                  const OnInterest& onInterest,
-                  const RegisterPrefixSuccessCallback& onSuccess,
-                  const RegisterPrefixFailureCallback& onFailure,
-                  const security::SigningInfo& signingInfo,
-                  uint64_t flags)
+                        const OnInterest& onInterest,
+                        const RegisterPrefixSuccessCallback& onSuccess,
+                        const RegisterPrefixFailureCallback& onFailure,
+                        const security::SigningInfo& signingInfo,
+                        uint64_t flags)
 {
-    shared_ptr<InterestFilterRecord> filter =
-      make_shared<InterestFilterRecord>(interestFilter, onInterest);
+  shared_ptr<InterestFilterRecord> filter =
+    make_shared<InterestFilterRecord>(interestFilter, onInterest);
 
-    nfd::CommandOptions options;
-    options.setSigningInfo(signingInfo);
+  nfd::CommandOptions options;
+  options.setSigningInfo(signingInfo);
 
-    return m_impl->registerPrefix(interestFilter.getPrefix(), filter,
-                                  onSuccess, onFailure,
-                                  flags, options);
+  return m_impl->registerPrefix(interestFilter.getPrefix(), filter,
+                                onSuccess, onFailure,
+                                flags, options);
 }
 
 const InterestFilterId*
 Face::setInterestFilter(const InterestFilter& interestFilter,
                         const OnInterest& onInterest)
 {
+  NS_LOG_INFO("Set Interest Filter << " << interestFilter);
+
   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());
 }
@@ -304,21 +232,22 @@
 
 const RegisteredPrefixId*
 Face::registerPrefix(const Name& prefix,
-               const RegisterPrefixSuccessCallback& onSuccess,
-               const RegisterPrefixFailureCallback& onFailure,
-               const security::SigningInfo& signingInfo,
-               uint64_t flags)
+                     const RegisterPrefixSuccessCallback& onSuccess,
+                     const RegisterPrefixFailureCallback& onFailure,
+                     const security::SigningInfo& signingInfo,
+                     uint64_t flags)
 {
 
-    nfd::CommandOptions options;
-    options.setSigningInfo(signingInfo);
+  nfd::CommandOptions options;
+  options.setSigningInfo(signingInfo);
 
-    return m_impl->registerPrefix(prefix, shared_ptr<InterestFilterRecord>(),
-                                  onSuccess, onFailure,
-                                  flags, options);
+  return m_impl->registerPrefix(prefix, shared_ptr<InterestFilterRecord>(),
+                                onSuccess, onFailure,
+                                flags, options);
 }
 
 #ifdef NDN_FACE_KEEP_DEPRECATED_REGISTRATION_SIGNING
+
 const RegisteredPrefixId*
 Face::registerPrefix(const Name& prefix,
                      const RegisterPrefixSuccessCallback& onSuccess,
@@ -350,15 +279,18 @@
 void
 Face::unsetInterestFilter(const RegisteredPrefixId* registeredPrefixId)
 {
-  m_ioService.post([=] { m_impl->asyncUnregisterPrefix(registeredPrefixId,
-                                                       UnregisterPrefixSuccessCallback(),
-                                                       UnregisterPrefixFailureCallback()); });
+  m_impl->m_scheduler.scheduleEvent(time::seconds(0), [=] {
+      m_impl->asyncUnregisterPrefix(registeredPrefixId,
+                                    UnregisterPrefixSuccessCallback(),
+                                    UnregisterPrefixFailureCallback()); });
 }
 
 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
@@ -366,89 +298,26 @@
                        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), [=] {
+      m_impl->m_pendingInterestTable.clear();
+      m_impl->m_registeredPrefixTable.clear();
 
-void
-Face::asyncShutdown()
-{
-  m_impl->m_pendingInterestTable.clear();
-  m_impl->m_registeredPrefixTable.clear();
-
-  if (m_transport->isConnected())
-    m_transport->close();
-
-  m_impl->m_ioServiceWork.reset();
-}
-
-void
-Face::onReceiveElement(const Block& blockFromDaemon)
-{
-  const Block& block = nfd::LocalControlHeader::getPayload(blockFromDaemon);
-
-  if (block.type() == tlv::Interest)
-    {
-      shared_ptr<Interest> interest = make_shared<Interest>(block);
-      if (&block != &blockFromDaemon)
-        interest->getLocalControlHeader().wireDecode(blockFromDaemon);
-
-      m_impl->processInterestFilters(*interest);
-    }
-  else if (block.type() == tlv::Data)
-    {
-      shared_ptr<Data> data = make_shared<Data>(block);
-      if (&block != &blockFromDaemon)
-        data->getLocalControlHeader().wireDecode(blockFromDaemon);
-
-      m_impl->satisfyPendingInterests(*data);
-    }
-  // ignore any other type
+      m_impl->m_nfdFace->close();
+    });
 }
 
 } // namespace ndn
diff --git a/src/face.hpp b/src/face.hpp
index ab526c3..9c6ccb0 100644
--- a/src/face.hpp
+++ b/src/face.hpp
@@ -94,7 +94,6 @@
  */
 typedef function<void(const std::string&)> UnregisterPrefixFailureCallback;
 
-
 /**
  * @brief Abstraction to communicate with local or remote NDN forwarder
  */
@@ -149,48 +148,6 @@
   explicit
   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 A shared_ptr to a Transport object used for communication
-   *
-   * @throws Face::Error on unsupported protocol
-   */
-  explicit
-  Face(const shared_ptr<Transport>& transport);
-
-  /**
-   * @brief Create a new Face using the given Transport and IO service object
-   *
-   * @sa Face(boost::asio::io_service&)
-   *
-   * @throws Face::Error on unsupported protocol
-   */
-  Face(const shared_ptr<Transport>& transport,
-       boost::asio::io_service& ioService);
-
-  /**
-   * @brief Create a new Face using the given Transport and IO service object
-   * @param transport the Transport used for communication
-   * @param ioService the io_service that controls all IO operations
-   * @param keyChain the KeyChain to sign commands
-   * @throws Face::Error on unsupported protocol
-   * @note shared_ptr is passed by value because ownership is shared with this class
-   */
-  Face(shared_ptr<Transport> transport,
-       boost::asio::io_service& ioService,
-       KeyChain& keyChain);
-
   ~Face();
 
 public: // consumer
@@ -567,25 +524,7 @@
 
 public: // IO routine
   /**
-   * @brief Process any data to receive or call timeout callbacks.
-   *
-   * This call will block forever (default timeout == 0) to process IO on the face.
-   * To exit, one expected to call face.shutdown() from one of the callback methods.
-   *
-   * If positive timeout is specified, then processEvents will exit after this timeout, if
-   * not stopped earlier with face.shutdown() or when all active events finish.  The call
-   * can be called repeatedly, if desired.
-   *
-   * If negative timeout is specified, then processEvents will not block and process only
-   * pending events.
-   *
-   * @param timeout     maximum time to block the thread
-   * @param keepThread  Keep thread in a blocked state (in event processing), even when
-   *                    there are no outstanding events (e.g., no Interest/Data is expected)
-   *
-   * @throw This may throw an exception for reading data or in the callback for processing
-   * the data.  If you call this from an main event loop, you may want to catch and
-   * log/disregard all exceptions.
+   * @brief Noop (kept for compatibility)
    */
   void
   processEvents(const time::milliseconds& timeout = time::milliseconds::zero(),
@@ -603,43 +542,22 @@
   shutdown();
 
   /**
-   * @brief Get reference to IO service object
+   * @brief Return nullptr (kept for compatibility)
    */
   boost::asio::io_service&
   getIoService()
   {
-    return m_ioService;
+    return *static_cast<boost::asio::io_service*>(nullptr);
   }
 
 private:
-
-  /**
-   * @throws ConfigFile::Error on parse error and unsupported protocols
-   */
   void
-  construct(KeyChain& keyChain);
-
-  /**
-   * @throws Face::Error on unsupported protocol
-   * @note shared_ptr is passed by value because ownership is transferred to this function
-   */
-  void
-  construct(shared_ptr<Transport> transport, KeyChain& keyChain);
-
-  void
-  onReceiveElement(const Block& wire);
-
-  void
-  asyncShutdown();
+  construct();
 
 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;
+  class Impl;
 
-  shared_ptr<Transport> m_transport;
-
+private:
   /** @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;
@@ -649,8 +567,6 @@
   unique_ptr<KeyChain> m_internalKeyChain;
 
   unique_ptr<nfd::Controller> m_nfdController;
-
-  class Impl;
   unique_ptr<Impl> m_impl;
 };