model: Enabling face operations based on NFD's face

Refs: #2215
diff --git a/model/ndn-app-face.cpp b/model/ndn-app-face.cpp
index 0af1432..9759771 100644
--- a/model/ndn-app-face.cpp
+++ b/model/ndn-app-face.cpp
@@ -36,8 +36,9 @@
 namespace ndn {
 
 AppFace::AppFace(Ptr<App> app)
-  // : Face(app->GetNode())
-  : m_app(app)
+  : LocalFace(FaceUri("appFace://"), FaceUri("appFace://"))
+  , m_node(app->GetNode())
+  , m_app(app)
 {
   NS_LOG_FUNCTION(this << app);
 
@@ -49,18 +50,31 @@
   NS_LOG_FUNCTION_NOARGS();
 }
 
-bool
-AppFace::SendInterest(shared_ptr<const Interest> interest)
+void
+AppFace::close()
 {
-  NS_LOG_FUNCTION(this << interest);
-  return false;
 }
 
-bool
-AppFace::SendData(shared_ptr<const Data> data)
+void
+AppFace::sendInterest(const Interest& interest)
 {
-  NS_LOG_FUNCTION(this << data);
-  return false;
+  NS_LOG_FUNCTION(this << &interest);
+
+  this->onSendInterest(interest);
+
+  // to decouple callbacks
+  Simulator::ScheduleNow(&App::OnInterest, m_app, interest.shared_from_this());
+}
+
+void
+AppFace::sendData(const Data& data)
+{
+  NS_LOG_FUNCTION(this << &data);
+
+  this->onSendData(data);
+
+  // to decouple callbacks
+  Simulator::ScheduleNow(&App::OnData, m_app, data.shared_from_this());
 }
 
 } // namespace ndn
diff --git a/model/ndn-app-face.hpp b/model/ndn-app-face.hpp
index 9abc4cf..eeef73e 100644
--- a/model/ndn-app-face.hpp
+++ b/model/ndn-app-face.hpp
@@ -23,13 +23,13 @@
 #define NDN_APP_FACE_H
 
 #include "ns3/ndnSIM/model/ndn-common.hpp"
-
-#include "ndn-face.hpp"
-#include "ns3/traced-callback.h"
+#include "ns3/ndnSIM/NFD/daemon/face/local-face.hpp"
+#include "ns3/ndnSIM/model/ndn-face.hpp"
 
 namespace ns3 {
 
 class Packet;
+class Node;
 
 namespace ndn {
 
@@ -43,25 +43,39 @@
  * component responsible for actual delivery of data packet to and
  * from Ndn stack
  *
- * \see AppFace, NdnNetDeviceFace, NdnIpv4Face, NdnUdpFace
+ * \see AppFace, NdnNetDeviceFace
  */
-class AppFace : public Face {
+class AppFace : public nfd::LocalFace {
 public:
   /**
    * \brief Default constructor
    */
   AppFace(Ptr<App> app);
+
   virtual ~AppFace();
 
-  ////////////////////////////////////////////////////////////////////
-  // methods overloaded from Face
-  virtual bool
-  SendInterest(shared_ptr<const Interest> interest);
+public: // from nfd::Face
+  /**
+   * @brief Send Interest towards application
+   *
+   * @note To send Interest from application, use `AppFace::onReceiveInterest(interest)`
+   */
+  virtual void
+  sendInterest(const Interest& interest);
 
-  virtual bool
-  SendData(shared_ptr<const Data> data);
+  /**
+   * @brief Send Data towards application
+   *
+   * @note To send Data from application, use `AppFace::onReceiveData(data)`
+   */
+  virtual void
+  sendData(const Data& data);
+
+  virtual void
+  close();
 
 private:
+  Ptr<Node> m_node;
   Ptr<App> m_app;
 };
 
diff --git a/model/ndn-common.cpp b/model/ndn-common.cpp
new file mode 100644
index 0000000..e2a498a
--- /dev/null
+++ b/model/ndn-common.cpp
@@ -0,0 +1,28 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2011-2015  Regents of the University of California.
+ *
+ * This file is part of ndnSIM. See AUTHORS for complete list of ndnSIM authors and
+ * contributors.
+ *
+ * ndnSIM 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.
+ *
+ * ndnSIM 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
+ * ndnSIM, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "ndn-common.hpp"
+
+namespace ns3 {
+namespace ndn {
+
+ATTRIBUTE_HELPER_CPP(Name);
+
+} // namespace ndn
+} // namespace ns3
diff --git a/model/ndn-common.hpp b/model/ndn-common.hpp
index 97e722a..8b1a692 100644
--- a/model/ndn-common.hpp
+++ b/model/ndn-common.hpp
@@ -22,6 +22,8 @@
 
 #include "ns3/nstime.h"
 #include "ns3/simulator.h"
+#include "ns3/attribute.h"
+#include "ns3/attribute-helper.h"
 
 #include <ndn-cxx/interest.hpp>
 #include <ndn-cxx/encoding/block.hpp>
@@ -39,6 +41,8 @@
 using ::ndn::Name;
 namespace name = ::ndn::name;
 
+ATTRIBUTE_HELPER_HEADER(Name);
+
 namespace time = ::ndn::time;
 
 using ::ndn::Exclude;
diff --git a/model/ndn-face.hpp b/model/ndn-face.hpp
index 73d4fb3..e1b35e0 100644
--- a/model/ndn-face.hpp
+++ b/model/ndn-face.hpp
@@ -20,21 +20,27 @@
 #ifndef NDNSIM_NDN_FACE_HPP
 #define NDNSIM_NDN_FACE_HPP
 
-#include <boost/noncopyable.hpp>
+#include "ns3/ndnSIM/NFD/daemon/face/face.hpp"
+#include <ndn-cxx/util/face-uri.hpp>
 
 namespace ns3 {
 namespace ndn {
 
-class Face : boost::noncopyable {
-};
+using nfd::Face;
+using ::ndn::util::FaceUri;
+
+} // namespace ndn
+} // namespace ns3
+
+namespace nfd {
 
 inline std::ostream&
 operator<<(std::ostream& os, const Face& face)
 {
+  os << face.getLocalUri();
   return os;
 }
 
-} // namespace ndn
-} // namespace ns3
+} // namespace nfd
 
 #endif // NDNSIM_NDN_FACE_HPP
diff --git a/model/ndn-global-router.hpp b/model/ndn-global-router.hpp
index 74cf5f1..0465cb8 100644
--- a/model/ndn-global-router.hpp
+++ b/model/ndn-global-router.hpp
@@ -22,6 +22,7 @@
 #define NDN_GLOBAL_ROUTER_H
 
 #include "ns3/ndnSIM/model/ndn-common.hpp"
+#include "ns3/ndnSIM/model/ndn-face.hpp"
 
 #include "ns3/object.h"
 #include "ns3/ptr.h"
@@ -36,7 +37,6 @@
 namespace ndn {
 
 class L3Protocol;
-class Face;
 
 /**
  * @ingroup ndn
diff --git a/model/ndn-l3-protocol.hpp b/model/ndn-l3-protocol.hpp
index 73ca77b..03618d5 100644
--- a/model/ndn-l3-protocol.hpp
+++ b/model/ndn-l3-protocol.hpp
@@ -22,6 +22,7 @@
 #define NDN_L3_PROTOCOL_H
 
 #include "ns3/ndnSIM/model/ndn-common.hpp"
+#include "ns3/ndnSIM/model/ndn-face.hpp"
 
 #include <list>
 #include <vector>
@@ -33,14 +34,11 @@
 namespace ns3 {
 
 class Packet;
-class NetDevice;
 class Node;
 class Header;
 
 namespace ndn {
 
-class Face;
-
 /**
  * \defgroup ndn ndnSIM: NDN simulation module
  *
@@ -64,8 +62,6 @@
  */
 class L3Protocol : public Object {
 public:
-  typedef std::vector<shared_ptr<Face>> FaceList;
-
   /**
    * \brief Interface ID
    *
diff --git a/model/ndn-net-device-face.cpp b/model/ndn-net-device-face.cpp
index ae9de5d..03d95db 100644
--- a/model/ndn-net-device-face.cpp
+++ b/model/ndn-net-device-face.cpp
@@ -22,6 +22,8 @@
 #include "ndn-net-device-face.hpp"
 #include "ndn-l3-protocol.hpp"
 
+#include "ndn-ns3.hpp"
+
 #include "ns3/net-device.h"
 #include "ns3/log.h"
 #include "ns3/packet.h"
@@ -32,29 +34,39 @@
 #include "ns3/point-to-point-net-device.h"
 #include "ns3/channel.h"
 
+#include "../utils/ndn-fw-hop-count-tag.hpp"
+
 NS_LOG_COMPONENT_DEFINE("ndn.NetDeviceFace");
 
 namespace ns3 {
 namespace ndn {
 
-/**
- * By default, Ndn face are created in the "down" state.  Before
- * becoming useable, the user must invoke SetUp on the face
- */
 NetDeviceFace::NetDeviceFace(Ptr<Node> node, const Ptr<NetDevice>& netDevice)
-  // : Face(node)
-  : m_netDevice(netDevice)
+  : Face(FaceUri("netDeviceFace://"), FaceUri("netDeviceFace://"))
+  , m_node(node)
+  , m_netDevice(netDevice)
 {
   NS_LOG_FUNCTION(this << netDevice);
 
-  // SetMetric(1); // default metric
+  setMetric(1); // default metric
 
   NS_ASSERT_MSG(m_netDevice != 0, "NetDeviceFace needs to be assigned a valid NetDevice");
+
+  m_node->RegisterProtocolHandler(MakeCallback(&NetDeviceFace::receiveFromNetDevice, this),
+                                  L3Protocol::ETHERNET_FRAME_TYPE, m_netDevice,
+                                  true /*promiscuous mode*/);
 }
 
 NetDeviceFace::~NetDeviceFace()
 {
   NS_LOG_FUNCTION_NOARGS();
+
+  m_node->UnregisterProtocolHandler(MakeCallback(&NetDeviceFace::receiveFromNetDevice, this));
+}
+
+void
+NetDeviceFace::close()
+{
 }
 
 Ptr<NetDevice>
@@ -63,21 +75,70 @@
   return m_netDevice;
 }
 
-bool
-NetDeviceFace::Send(Ptr<Packet> packet)
+void
+NetDeviceFace::send(Ptr<Packet> packet)
 {
-  return false;
+  NS_ASSERT_MSG(packet->GetSize() <= m_netDevice->GetMtu(),
+                "Packet size " << packet->GetSize() << " exceeds device MTU "
+                               << m_netDevice->GetMtu());
+
+  FwHopCountTag tag;
+  packet->RemovePacketTag(tag);
+  tag.Increment();
+  packet->AddPacketTag(tag);
+
+  m_netDevice->Send(packet, m_netDevice->GetBroadcast(), L3Protocol::ETHERNET_FRAME_TYPE);
+}
+
+void
+NetDeviceFace::sendInterest(const Interest& interest)
+{
+  NS_LOG_FUNCTION(this << &interest);
+
+  this->onSendInterest(interest);
+
+  Ptr<Packet> packet = Convert::ToPacket(interest);
+  send(packet);
+}
+
+void
+NetDeviceFace::sendData(const Data& data)
+{
+  NS_LOG_FUNCTION(this << &data);
+
+  this->onSendData(data);
+
+  Ptr<Packet> packet = Convert::ToPacket(data);
+  send(packet);
 }
 
 // callback
 void
-NetDeviceFace::ReceiveFromNetDevice(Ptr<NetDevice> device, Ptr<const Packet> p, uint16_t protocol,
+NetDeviceFace::receiveFromNetDevice(Ptr<NetDevice> device, Ptr<const Packet> p, uint16_t protocol,
                                     const Address& from, const Address& to,
                                     NetDevice::PacketType packetType)
 {
   NS_LOG_FUNCTION(device << p << protocol << from << to << packetType);
-  // Receive(p);
+
+  Ptr<Packet> packet = p->Copy();
+  try {
+    uint32_t type = Convert::getPacketType(p);
+    if (type == ::ndn::tlv::Interest) {
+      shared_ptr<const Interest> i = Convert::FromPacket<Interest>(packet);
+      this->onReceiveInterest(*i);
+    }
+    else if (type == ::ndn::tlv::Data) {
+      shared_ptr<const Data> d = Convert::FromPacket<Data>(packet);
+      this->onReceiveData(*d);
+    }
+    else {
+      NS_LOG_ERROR("Unsupported TLV packet");
+    }
+  }
+  catch (::ndn::tlv::Error&) {
+    NS_LOG_ERROR("Unrecognized TLV packet");
+  }
 }
 
-} // namespace ndnsim
+} // namespace ndn
 } // namespace ns3
diff --git a/model/ndn-net-device-face.hpp b/model/ndn-net-device-face.hpp
index f832b52..5432ee1 100644
--- a/model/ndn-net-device-face.hpp
+++ b/model/ndn-net-device-face.hpp
@@ -22,8 +22,8 @@
 #define NDN_NET_DEVICE_FACE_H
 
 #include "ns3/ndnSIM/model/ndn-common.hpp"
+#include "ns3/ndnSIM/model/ndn-face.hpp"
 
-#include "ndn-face.hpp"
 #include "ns3/net-device.h"
 
 namespace ns3 {
@@ -53,11 +53,18 @@
    * this face will be associate
    */
   NetDeviceFace(Ptr<Node> node, const Ptr<NetDevice>& netDevice);
+
   virtual ~NetDeviceFace();
 
-protected:
-  virtual bool
-  Send(Ptr<Packet> p);
+public: // from nfd::Face
+  virtual void
+  sendInterest(const Interest& interest);
+
+  virtual void
+  sendData(const Data& data);
+
+  virtual void
+  close();
 
 public:
   /**
@@ -69,12 +76,16 @@
   GetNetDevice() const;
 
 private:
+  void
+  send(Ptr<Packet> packet);
+
   /// \brief callback from lower layers
   void
-  ReceiveFromNetDevice(Ptr<NetDevice> device, Ptr<const Packet> p, uint16_t protocol,
+  receiveFromNetDevice(Ptr<NetDevice> device, Ptr<const Packet> p, uint16_t protocol,
                        const Address& from, const Address& to, NetDevice::PacketType packetType);
 
 private:
+  Ptr<Node> m_node;
   Ptr<NetDevice> m_netDevice; ///< \brief Smart pointer to NetDevice
 };
 
diff --git a/wscript b/wscript
index 7bd46d3..0810d72 100644
--- a/wscript
+++ b/wscript
@@ -87,7 +87,7 @@
                                       excl=['model/ip-faces/*',
                                             'apps/*',
                                             'helper/*',
-                                            'utils/**/*'])
+                                            'utils/*/*'])
 
     module.full_headers = [p.path_from(bld.path) for p in bld.path.ant_glob(
         ['%s/**/*.hpp' % dir for dir in module_dirs])]