plugins/ip-faces: ip-faces plugin, which implements ndn::TcpFace

This commit also includes a basic example showing how to work with
TcpFace.  The code compiles and passes basic tests, but requires more
work and proper documentation

Refs #1006 (http://redmine.named-data.net/)
diff --git a/examples/ndn-simple-tcp.cc b/examples/ndn-simple-tcp.cc
new file mode 100644
index 0000000..641348a
--- /dev/null
+++ b/examples/ndn-simple-tcp.cc
@@ -0,0 +1,127 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+// ndn-simple-tcp.cc
+#include "ns3/core-module.h"
+#include "ns3/network-module.h"
+#include "ns3/point-to-point-module.h"
+#include "ns3/internet-module.h"
+#include "ns3/ndnSIM-module.h"
+
+using namespace ns3;
+
+/**
+ * This scenario simulates a very simple network topology:
+ *
+ *
+ *      +----------+     1Mbps      +--------+     1Mbps      +----------+
+ *      | consumer | <------------> | router | <------------> | producer |
+ *      +----------+         10ms   +--------+          10ms  +----------+
+ *           \                                                   /
+ *            -------------------- tcp face --------------------
+ *
+ * Consumer requests data from producer with frequency 10 interests per second
+ * (interests contain constantly increasing sequence number).
+ *
+ * For every received interest, producer replies with a data packet, containing
+ * 1024 bytes of virtual payload.
+ *
+ * To run scenario and see what is happening, use the following command:
+ *
+ *     NS_LOG=ndn.Consumer:ndn.Producer ./waf --run=ndn-simple-tcp
+ */
+
+int 
+main (int argc, char *argv[])
+{
+  Packet::EnablePrinting ();
+  
+  // setting default parameters for PointToPoint links and channels
+  Config::SetDefault ("ns3::PointToPointNetDevice::DataRate", StringValue ("1Mbps"));
+  Config::SetDefault ("ns3::PointToPointChannel::Delay", StringValue ("10ms"));
+  Config::SetDefault ("ns3::DropTailQueue::MaxPackets", StringValue ("20"));
+
+  // Read optional command-line parameters (e.g., enable visualizer with ./waf --run=<> --visualize
+  CommandLine cmd;
+  cmd.Parse (argc, argv);
+
+  // Creating nodes
+  NodeContainer nodes;
+  nodes.Create (3);
+
+  // Connecting nodes using two links
+  PointToPointHelper p2p;
+  NetDeviceContainer link1 = p2p.Install (nodes.Get (0), nodes.Get (1));
+  NetDeviceContainer link2 = p2p.Install (nodes.Get (1), nodes.Get (2));
+
+  // Install NDN stack on all nodes
+  ndn::StackHelper ndnHelper;
+  ndnHelper.SetDefaultRoutes (false);
+  ndnHelper.InstallAll ();
+
+  InternetStackHelper ipStack;
+  ipStack.SetIpv6StackInstall (false);
+  ipStack.InstallAll ();
+
+  Ipv4AddressHelper ipAddressHelper;
+  ipAddressHelper.SetBase (Ipv4Address ("10.1.1.0"), Ipv4Mask ("255.255.255.0"));
+  ipAddressHelper.Assign (link1);
+  
+  ipAddressHelper.SetBase (Ipv4Address ("10.1.2.0"), Ipv4Mask ("255.255.255.0"));
+  ipAddressHelper.Assign (link2);
+
+  Ipv4StaticRoutingHelper ipStaticRouting;
+  ipStaticRouting.GetStaticRouting (nodes.Get (0)->GetObject<Ipv4> ())->
+    AddNetworkRouteTo (Ipv4Address ("10.1.2.0"), Ipv4Mask ("255.255.255.0"),
+                       Ipv4Address ("10.1.1.2"),
+                       1, 1);
+
+  ipStaticRouting.GetStaticRouting (nodes.Get (2)->GetObject<Ipv4> ())->
+    AddNetworkRouteTo (Ipv4Address ("10.1.1.0"), Ipv4Mask ("255.255.255.0"),
+                       Ipv4Address ("10.1.2.1"),
+                       1, 1);
+  
+  ndn::IpFacesHelper ipFacesHelper;
+  ipFacesHelper.InstallAll ();
+  ipFacesHelper.CreateTcpFace (nodes.Get (0), Ipv4Address ("10.1.2.2"), "/tcp-route");
+  
+  // Installing applications
+
+  // Consumer
+  ndn::AppHelper consumerHelper ("ns3::ndn::ConsumerCbr");
+  // Consumer will request /tcp-route/0, /tcp-route/1, ...
+  consumerHelper.SetPrefix ("/tcp-route");
+  consumerHelper.SetAttribute ("Frequency", StringValue ("10")); // 10 interests a second
+  consumerHelper.Install (nodes.Get (0)).
+    Start (Seconds (3)); // first node
+
+  // Producer
+  ndn::AppHelper producerHelper ("ns3::ndn::Producer");
+  // Producer will reply to all requests starting with /prefix
+  producerHelper.SetPrefix ("/tcp-route");
+  producerHelper.SetAttribute ("PayloadSize", StringValue("1024"));
+  producerHelper.Install (nodes.Get (2)); // last node
+
+  Simulator::Stop (Seconds (20.0));
+
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+  return 0;
+}
diff --git a/examples/wscript b/examples/wscript
index 49a0c5c..c5c35eb 100644
--- a/examples/wscript
+++ b/examples/wscript
@@ -94,3 +94,7 @@
 
     obj = bld.create_ns3_program('ndn-simple-with-link-failure', all_modules)
     obj.source = 'ndn-simple-with-link-failure.cc'
+
+    if 'ip-faces' in bld.env['NDN_plugins']:
+        obj = bld.create_ns3_program('ndn-simple-tcp', all_modules)
+        obj.source = 'ndn-simple-tcp.cc'
diff --git a/plugins/ip-faces/ndn-ip-face-stack.cc b/plugins/ip-faces/ndn-ip-face-stack.cc
new file mode 100644
index 0000000..94faea4
--- /dev/null
+++ b/plugins/ip-faces/ndn-ip-face-stack.cc
@@ -0,0 +1,127 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "ndn-ip-face-stack.h"
+#include "ndn-tcp-face.h"
+
+#include "ns3/ndn-l3-protocol.h"
+
+#include "ns3/log.h"
+#include "ns3/assert.h"
+#include "ns3/packet.h"
+
+#include "ns3/socket.h"
+#include "ns3/tcp-socket-factory.h"
+#include "ns3/simulator.h"
+
+NS_LOG_COMPONENT_DEFINE ("ndn.IpFaceStack");
+
+namespace ns3 {
+namespace ndn {
+    
+NS_OBJECT_ENSURE_REGISTERED (IpFaceStack);
+
+const uint16_t NDN_IP_STACK_PORT = 9695;
+
+TypeId
+IpFaceStack::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::ndn::IpFaceStack")
+    .SetGroupName ("Ndn")
+    .SetParent<Object> ()
+    .AddConstructor<IpFaceStack> ()
+
+    .AddAttribute ("EnableTCP", "Enable ability to create TCP faces",
+                   BooleanValue (true),
+                   MakeBooleanAccessor (&IpFaceStack::m_enableTcp),
+                   MakeBooleanChecker ())
+
+    // .AddAttribute ("EnableUDP", "Enable ability to create UDP faces",
+    //                BooleanValue (true),
+    //                MakeBooleanAccessor (&IpFaceStack::m_enableUdp),
+    //                MakeBooleanChecker ())
+    ;
+  return tid;
+}
+    
+IpFaceStack::IpFaceStack ()
+{
+}
+    
+IpFaceStack::~IpFaceStack ()
+{
+}
+
+void
+IpFaceStack::NotifyNewAggregate ()
+{
+  if (m_node == 0)
+    {
+      m_node = GetObject<Node> ();
+      if (m_node != 0)
+        {
+          Simulator::ScheduleWithContext (m_node->GetId (), Seconds (0.1), &IpFaceStack::StartServer, this);
+        }
+    }
+}
+
+// Application Methods
+void 
+IpFaceStack::StartServer () // Called at time specified by Start
+{
+  NS_LOG_FUNCTION (this);
+  
+  if (m_enableTcp)
+    {
+      m_tcpServer = Socket::CreateSocket (m_node, TcpSocketFactory::GetTypeId ());
+  
+      m_tcpServer->Bind (InetSocketAddress (Ipv4Address::GetAny (), NDN_IP_STACK_PORT));
+      m_tcpServer->Listen ();
+
+      m_tcpServer->SetAcceptCallback (MakeCallback (&IpFaceStack::OnTcpConnectionRequest, this),
+                                      MakeCallback (&IpFaceStack::OnTcpConnectionAccept, this));
+
+    }
+}
+
+bool
+IpFaceStack::OnTcpConnectionRequest (Ptr< Socket > sock, const Address &addr)
+{
+  NS_LOG_FUNCTION (this << sock << InetSocketAddress::ConvertFrom (addr));
+  return true; // accept all connections from anybody
+}
+
+void
+IpFaceStack::OnTcpConnectionAccept (Ptr<Socket> socket, const Address &addr)
+{
+  NS_LOG_FUNCTION (this << socket << InetSocketAddress::ConvertFrom (addr));
+  
+  Ptr<L3Protocol> ndn = m_node->GetObject<L3Protocol> ();
+  Ptr<TcpFace> face = CreateObject<TcpFace> (m_node, socket, InetSocketAddress::ConvertFrom (addr).GetIpv4 ());
+
+  ndn->AddFace (face);
+  face->SetUp (true);
+
+  socket->SetCloseCallbacks (MakeCallback (&TcpFace::OnTcpConnectionClosed, face),
+                             MakeCallback (&TcpFace::OnTcpConnectionClosed, face));
+}
+
+} // namespace ndn
+} // namespace ns3
diff --git a/plugins/ip-faces/ndn-ip-face-stack.h b/plugins/ip-faces/ndn-ip-face-stack.h
new file mode 100644
index 0000000..83cf4cb
--- /dev/null
+++ b/plugins/ip-faces/ndn-ip-face-stack.h
@@ -0,0 +1,87 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013 University of California, Los Angeles
+ *                    Alexander Afanasyev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_IP_FACE_STACK_H
+#define NDN_IP_FACE_STACK_H
+
+#include "ns3/application.h"
+#include "ns3/socket.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/ptr.h"
+#include "ns3/ndn-name.h"
+
+#include <map>
+
+namespace ns3 {
+
+class Packet;
+
+namespace ndn {
+
+class Face;
+
+/**
+ * @ingroup ndn
+ * @brief Application that provides functionality of creating IP-based faces on NDN nodes
+ * 
+ * The class implements virtual calls onInterest, onNack, and onContentObject
+ */
+class IpFaceStack: public Object
+{
+public:
+  static TypeId GetTypeId ();
+
+  /**
+   * @brief Default constructor
+   */
+  IpFaceStack ();
+  virtual ~IpFaceStack ();
+
+protected:
+  void
+  NotifyNewAggregate ();
+
+private:
+  void
+  StartServer ();
+  
+  bool
+  OnTcpConnectionRequest (Ptr< Socket > sock, const Address &addr);
+
+  void
+  OnTcpConnectionAccept (Ptr< Socket > sock, const Address &addr);
+
+  void
+  OnTcpConnectionClosed (Ptr< Socket > sock);
+
+protected:
+  Ptr<Node> m_node;
+  
+  bool m_enableTcp;
+  // bool m_enableUdp;
+  
+  Ptr<Socket> m_tcpServer;
+};
+
+} // namespace ndn
+} // namespace ns3
+
+#endif // NDN_IP_FACE_STACK_H
diff --git a/plugins/ip-faces/ndn-ip-faces-helper.cc b/plugins/ip-faces/ndn-ip-faces-helper.cc
new file mode 100644
index 0000000..efd956f
--- /dev/null
+++ b/plugins/ip-faces/ndn-ip-faces-helper.cc
@@ -0,0 +1,86 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013 University of California, Los Angeles
+ *                    Alexander Afanasyev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author:  Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "ndn-ip-faces-helper.h"
+#include "ndn-ip-face-stack.h"
+
+#include "ns3/ndn-stack-helper.h"
+#include "ns3/node-container.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include "ndn-tcp-face.h"
+
+NS_LOG_COMPONENT_DEFINE ("ndn.IpFacesHelper");
+
+using namespace std;
+
+namespace ns3 {
+namespace ndn {
+
+void
+IpFacesHelper::Install (Ptr<Node> node)
+{
+  Ptr<IpFaceStack> stack = CreateObject<IpFaceStack> ();
+  node->AggregateObject (stack);
+}
+
+void
+IpFacesHelper::Install (const NodeContainer &nodes)
+{
+  for (NodeContainer::Iterator node = nodes.Begin ();
+       node != nodes.End ();
+       node ++)
+    {
+      Install (*node);
+    }
+}
+
+void
+IpFacesHelper::InstallAll ()
+{
+  Install (NodeContainer::GetGlobal ());
+}
+
+
+static void
+CreateTcpFaceStep2 (Ptr<Node> node, Ipv4Address address, const std::string &prefix)
+{
+  Ptr<Face> face = TcpFace::CreateOrGetFace (node, address);
+  ndn::StackHelper::AddRoute (node, prefix, face, 1);
+}
+
+static void
+CreateTcpFaceStep1 (Ptr<Node> node, Ipv4Address address, const std::string &prefix)
+{
+  TcpFace::CreateOrGetFace (node, address);
+  
+  Simulator::ScheduleWithContext (node->GetId (), Seconds (1.0), CreateTcpFaceStep2, node, address, prefix);
+}
+
+void
+IpFacesHelper::CreateTcpFace (Ptr<Node> node, Ipv4Address address, const std::string &prefix)
+{
+  Simulator::ScheduleWithContext (node->GetId (), Seconds (1.0), CreateTcpFaceStep1, node, address, prefix);
+}
+
+
+} // namespace ndn
+} // namespace ns3
diff --git a/plugins/ip-faces/ndn-ip-faces-helper.h b/plugins/ip-faces/ndn-ip-faces-helper.h
new file mode 100644
index 0000000..3ea8859
--- /dev/null
+++ b/plugins/ip-faces/ndn-ip-faces-helper.h
@@ -0,0 +1,73 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013 University of California, Los Angeles
+ *                    Alexander Afanasyev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author:  Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_IP_FACES_HELPER_H
+#define NDN_IP_FACES_HELPER_H
+
+#include "ns3/ptr.h"
+#include "ns3/ipv4-address.h"
+
+namespace ns3 {
+
+class Node;
+class NodeContainer;
+class Channel;
+
+namespace ndn {
+
+/**
+ * @ingroup ndn
+ * @brief Helper for NDN IP-based face creation
+ */
+class IpFacesHelper
+{
+public:
+  /**
+   * @brief Install IpFaceStack interface on a node
+   * @param node Node to install IpFaceStack interface
+   */
+  void
+  Install (Ptr<Node> node);
+
+  /**
+   * @brief Install IpFaceStack interface on nodes
+   * @param nodes NodeContainer to install IpFaceStack interface
+   */
+  void
+  Install (const NodeContainer &nodes);
+
+  /**
+   * @brief Install IpFaceStack interface on all nodes
+   */
+  void
+  InstallAll ();
+
+  /**
+   * @brief Create TCP face
+   */
+  void
+  CreateTcpFace (Ptr<Node> node, Ipv4Address address, const std::string &prefix);
+};
+
+} // namespace ndn
+} // namespace ns3
+
+#endif // NDN_IP_FACES_HELPER_H
diff --git a/plugins/ip-faces/ndn-tcp-face.cc b/plugins/ip-faces/ndn-tcp-face.cc
new file mode 100644
index 0000000..c1d9321
--- /dev/null
+++ b/plugins/ip-faces/ndn-tcp-face.cc
@@ -0,0 +1,295 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ *
+ */
+
+#include "ndn-tcp-face.h"
+#include "ns3/ndn-l3-protocol.h"
+
+#include "ns3/log.h"
+#include "ns3/packet.h"
+#include "ns3/node.h"
+#include "ns3/pointer.h"
+#include "ns3/tcp-socket-factory.h"
+
+#include "ns3/ndn-name.h"
+
+using namespace std;
+
+NS_LOG_COMPONENT_DEFINE ("ndn.TcpFace");
+
+namespace ns3 {
+namespace ndn {
+
+const uint16_t NDN_IP_STACK_PORT = 9695;
+
+TcpFace::FaceMap TcpFace::s_map;
+
+class TcpBoundaryHeader : public Header
+{
+public:
+  static TypeId GetTypeId (void)
+  {
+    static TypeId tid = TypeId ("ns3::ndn::TcpFace::BoundaryHeader")
+      .SetGroupName ("Ndn")
+      .SetParent<Header> ()
+      ;
+    return tid;
+  }
+
+  TcpBoundaryHeader ()
+    : m_length (0)
+  {
+  }
+  
+  TcpBoundaryHeader (Ptr<Packet> packet)
+    : m_length (packet->GetSize ())
+  {
+    
+  }
+
+  TcpBoundaryHeader (uint32_t length)
+    : m_length (length)
+  {
+  }
+
+  uint32_t
+  GetLength () const
+  {
+    return m_length;
+  }
+  
+  virtual TypeId
+  GetInstanceTypeId (void) const
+  {
+    return TcpBoundaryHeader::GetTypeId ();
+  }
+  
+  virtual void
+  Print (std::ostream &os) const
+  {
+    os << "[" << m_length << "]";
+  }
+  
+  virtual uint32_t
+  GetSerializedSize (void) const
+  {
+    return 4;
+  }
+  
+  virtual void
+  Serialize (Buffer::Iterator start) const
+  {
+    start.WriteU32 (m_length);
+  }
+  
+  virtual uint32_t
+  Deserialize (Buffer::Iterator start)
+  {
+    m_length = start.ReadU32 ();
+    return 4;
+  }
+
+private:
+  uint32_t m_length;
+};
+
+NS_OBJECT_ENSURE_REGISTERED (TcpFace);
+
+TypeId
+TcpFace::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::ndn::TcpFace")
+    .SetParent<Face> ()
+    .SetGroupName ("Ndn")
+    ;
+  return tid;
+}
+
+/**
+ * By default, Ndn face are created in the "down" state.  Before
+ * becoming useable, the user must invoke SetUp on the face
+ */
+TcpFace::TcpFace (Ptr<Node> node, Ptr<Socket> socket, Ipv4Address address)
+  : Face (node)
+  , m_socket (socket)
+  , m_address (address)
+  , m_pendingPacketLength (0)
+{
+  SetMetric (1); // default metric
+}
+
+TcpFace::~TcpFace ()
+{
+  NS_LOG_FUNCTION_NOARGS ();
+}
+
+TcpFace& TcpFace::operator= (const TcpFace &)
+{
+  return *this;
+}
+
+void
+TcpFace::RegisterProtocolHandler (ProtocolHandler handler)
+{
+  NS_LOG_FUNCTION (this);
+
+  Face::RegisterProtocolHandler (handler);
+
+  m_socket->SetRecvCallback (MakeCallback (&TcpFace::ReceiveFromTcp, this));
+}
+
+bool
+TcpFace::SendImpl (Ptr<Packet> packet)
+{
+  NS_LOG_FUNCTION (this << packet);
+  Ptr<Packet> boundary = Create<Packet> ();
+  TcpBoundaryHeader hdr (packet);
+  boundary->AddHeader (hdr);
+  
+  m_socket->Send (boundary);
+  m_socket->Send (packet);
+
+  return true;
+}
+
+void
+TcpFace::ReceiveFromTcp (Ptr< Socket > clientSocket)
+{
+  NS_LOG_FUNCTION (this << clientSocket);
+  TcpBoundaryHeader hdr;
+
+  if (m_pendingPacketLength > 0)
+    {
+      if (clientSocket->GetRxAvailable () >= m_pendingPacketLength)
+        {
+          Ptr<Packet> realPacket = clientSocket->Recv (m_pendingPacketLength, 0);
+          NS_LOG_DEBUG ("+++ Expected " << m_pendingPacketLength << " bytes, got " << realPacket->GetSize () << " bytes");
+          if (realPacket == 0)
+            return;
+          
+          Receive (realPacket);
+        }
+      else
+        return; // still not ready
+    }
+  
+  m_pendingPacketLength = 0;
+  
+  while (clientSocket->GetRxAvailable () >= hdr.GetSerializedSize ())
+    {
+      Ptr<Packet> boundary = clientSocket->Recv (hdr.GetSerializedSize (), 0);
+      if (boundary == 0)
+        return; // no idea why it would happen...
+
+      NS_LOG_DEBUG ("Expected 4 bytes, got " << boundary->GetSize () << " bytes");
+      
+      boundary->RemoveHeader (hdr);
+      NS_LOG_DEBUG ("Header specifies length: " << hdr.GetLength ());
+      m_pendingPacketLength = hdr.GetLength ();
+      
+      if (clientSocket->GetRxAvailable () >= hdr.GetLength ())
+        {
+          Ptr<Packet> realPacket = clientSocket->Recv (hdr.GetLength (), 0);
+          if (realPacket == 0)
+            {
+              NS_LOG_DEBUG ("Got nothing, but requested at least " << hdr.GetLength ());
+              return;
+            }
+          
+          NS_LOG_DEBUG ("Receiving data " << hdr.GetLength () << " bytes, got " << realPacket->GetSize () << " bytes");
+
+          Receive (realPacket);
+          m_pendingPacketLength = 0;
+        }
+      else
+        {
+          return;
+        }
+    }
+}
+
+void
+TcpFace::OnTcpConnectionClosed (Ptr<Socket> socket)
+{
+  NS_LOG_FUNCTION (this << socket);
+  s_map.erase (m_address);
+}
+
+Ipv4Address
+TcpFace::GetAddress () const
+{
+  return m_address;
+}
+
+Ptr<TcpFace>
+TcpFace::GetFaceByAddress (const Ipv4Address &address)
+{
+  FaceMap::iterator i = s_map.find (address);
+  if (i != s_map.end ())
+    return i->second;
+  else
+    return 0;
+}
+
+Ptr<TcpFace>
+TcpFace::CreateOrGetFace (Ptr<Node> node, Ipv4Address address)
+{
+  NS_LOG_FUNCTION (address);
+
+  FaceMap::iterator i = s_map.find (address);
+  if (i != s_map.end ())
+    return i->second;
+  
+  Ptr<Socket> socket = Socket::CreateSocket (node, TcpSocketFactory::GetTypeId ());
+  Ptr<TcpFace> face = CreateObject<TcpFace> (node, socket, address);
+  
+  socket->SetConnectCallback (MakeCallback (&TcpFace::OnConnect, face),
+                              MakeNullCallback< void, Ptr< Socket > > ());
+  socket->Connect (InetSocketAddress (address, NDN_IP_STACK_PORT));
+
+  s_map.insert (std::make_pair (address, face));
+
+  return face;
+}
+
+void
+TcpFace::OnConnect (Ptr<Socket> socket)
+{
+  NS_LOG_FUNCTION (this << socket);
+
+  Ptr<L3Protocol> ndn = GetNode ()->GetObject<L3Protocol> ();
+  
+  ndn->AddFace (this);
+  this->SetUp (true);
+
+  socket->SetCloseCallbacks (MakeCallback (&TcpFace::OnTcpConnectionClosed, this),
+                             MakeCallback (&TcpFace::OnTcpConnectionClosed, this));
+}
+    
+std::ostream&
+TcpFace::Print (std::ostream& os) const
+{
+  os << "dev=tcp(" << GetId () << ")";
+  return os;
+}
+
+} // namespace ndn
+} // namespace ns3
+
diff --git a/plugins/ip-faces/ndn-tcp-face.h b/plugins/ip-faces/ndn-tcp-face.h
new file mode 100644
index 0000000..6e9763e
--- /dev/null
+++ b/plugins/ip-faces/ndn-tcp-face.h
@@ -0,0 +1,111 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Authors: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_TCP_FACE_H
+#define NDN_TCP_FACE_H
+
+#include "ns3/ndn-face.h"
+#include "ns3/socket.h"
+#include "ns3/ptr.h"
+
+#include <map>
+
+namespace ns3 {
+namespace ndn {
+  
+/**
+ * \ingroup ndn-face
+ * \brief Implementation of TCP/IP NDN face
+ *
+ * \see NdnAppFace, NdnNetDeviceFace, NdnIpv4Face, NdnUdpFace
+ */
+class TcpFace : public Face
+{
+public:
+  static TypeId
+  GetTypeId ();
+
+  /**
+   * @brief A singleton method allowing creation and lookup of faces
+   *
+   * All created TCP faces are stored internally in the map, and if the same face is created, it will simply be looked up
+   */
+  static Ptr<TcpFace>
+  CreateOrGetFace (Ptr<Node> node, Ipv4Address address);
+  
+  /**
+   * \brief Constructor
+   *
+   * @param node Node associated with the face
+   */
+  TcpFace (Ptr<Node> node, Ptr<Socket> socket, Ipv4Address address);
+  virtual ~TcpFace();
+
+  ////////////////////////////////////////////////////////////////////
+  // methods overloaded from NdnFace
+  virtual void
+  RegisterProtocolHandler (ProtocolHandler handler);
+
+  void
+  OnTcpConnectionClosed (Ptr<Socket> socket);
+
+  Ipv4Address
+  GetAddress () const;
+
+  static Ptr<TcpFace>
+  GetFaceByAddress (const Ipv4Address &addr);
+
+private:
+  void
+  OnConnect (Ptr<Socket> socket);
+  
+protected:
+  // also from NdnFace
+  virtual bool
+  SendImpl (Ptr<Packet> p);
+
+public:
+  /**
+   * @brief Print out name of the NdnFace to the stream
+   */
+  virtual std::ostream&
+  Print (std::ostream &os) const;
+  ////////////////////////////////////////////////////////////////////
+
+private:  
+  TcpFace (const TcpFace &); ///< \brief Disabled copy constructor
+  TcpFace& operator= (const TcpFace &); ///< \brief Disabled copy operator
+
+  void
+  ReceiveFromTcp (Ptr< Socket > clientSocket);
+
+private:
+  Ptr<Socket> m_socket;
+  Ipv4Address m_address;
+  uint32_t m_pendingPacketLength;
+
+  typedef std::map<Ipv4Address, Ptr<TcpFace> > FaceMap;
+  static FaceMap s_map;
+};
+
+} // namespace ndn
+} // namespace ns3
+
+#endif // NDN_TCP_FACE_H
diff --git a/wscript b/wscript
index f53492a..4cc1ee2 100644
--- a/wscript
+++ b/wscript
@@ -67,7 +67,7 @@
             Logs.error ("Please upgrade your distribution or install custom boost libraries (http://ndnsim.net/faq.html#boost-libraries)")
             return
 
-    conf.env['NDN_plugins'] = ['topology']
+    conf.env['NDN_plugins'] = ['topology', 'ip-faces']
     if Options.options.enable_ndn_plugins:
         conf.env['NDN_plugins'] = conf.env['NDN_plugins'] + Options.options.enable_ndn_plugins.split(',')
 
@@ -181,6 +181,13 @@
         module.source.extend (bld.path.ant_glob(['plugins/mobility/*.cc']))
         module.full_headers.extend ([p.path_from(bld.path) for p in bld.path.ant_glob(['plugins/mobility/**/*.h'])])
 
+    if 'ip-faces' in bld.env['NDN_plugins']:
+        headers.source.extend ([
+            "plugins/ip-faces/ndn-ip-faces-helper.h",
+            ])
+        module.source.extend (bld.path.ant_glob(['plugins/ip-faces/*.cc']))
+        module.full_headers.extend ([p.path_from(bld.path) for p in bld.path.ant_glob(['plugins/ip-faces/**/*.h'])])
+
     # bld.install_files('${INCLUDEDIR}/%s%s/ns3/ndnSIM' % (wutils.APPNAME, wutils.VERSION), ndnSIM_headers, relative_trick=True)
     # bld.install_files('$PREFIX/include', ndnSIM_headers)