plugins/ip-faces: Implementing UdpFace and fixing bugs with TcpFace

Now UdpFace is fully working. Due to nature of UDP transmission, all
demultiplexing is happening inside IpFaceStack (with TCP, NS-3 is taking
care of that).

Bugfix: Map between IP addresses and Tcp/Udp faces was incorrectly
embedded as a static variable inside Udp/TcpFace implementation, causing
unexpected behavior.

Refs #1006 (http://redmine.named-data.net/)
diff --git a/examples/ndn-simple-udp.cc b/examples/ndn-simple-udp.cc
new file mode 100644
index 0000000..2fa093d
--- /dev/null
+++ b/examples/ndn-simple-udp.cc
@@ -0,0 +1,139 @@
+/* -*-  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  +----------+
+ *           \                                                   /
+ *            -------------------- udp 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-udp
+ */
+
+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.SetForwardingStrategy ("ns3::ndn::fw::BestRoute");
+  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::InstallAll ();
+  ndn::IpFacesHelper::CreateUdpFace (Seconds (1.0), nodes.Get (0), Ipv4Address ("10.1.2.2"), "/udp-route1");
+  ndn::IpFacesHelper::CreateUdpFace (Seconds (1.0), nodes.Get (0), Ipv4Address ("10.1.1.2"), "/udp-route2");
+  
+  // Installing applications
+
+  // Consumer
+  ndn::AppHelper consumerHelper ("ns3::ndn::ConsumerCbr");
+  // consumerHelper.SetAttribute ("Randomize", StringValue ("uniform"));
+  // Consumer will request /udp-route1/0, /udp-route1/1, ...
+  consumerHelper.SetPrefix ("/udp-route1");
+  consumerHelper.SetAttribute ("Frequency", StringValue ("10")); // 10 interests a second
+  consumerHelper.Install (nodes.Get (0)).
+    Start (Seconds (3)); // first node
+
+  // Consumer will request /udp-route1/0, /udp-route1/1, ...
+  consumerHelper.SetPrefix ("/udp-route2");
+  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 ("/udp-route1");
+  producerHelper.SetAttribute ("PayloadSize", StringValue("1024"));
+  producerHelper.Install (nodes.Get (2)); // last node
+
+  producerHelper.SetPrefix ("/udp-route2");
+  producerHelper.SetAttribute ("PayloadSize", StringValue("1024"));
+  producerHelper.Install (nodes.Get (1)); // last node
+
+  Simulator::Stop (Seconds (20.0));
+
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+  return 0;
+}
diff --git a/examples/wscript b/examples/wscript
index c5c35eb..08f6f09 100644
--- a/examples/wscript
+++ b/examples/wscript
@@ -98,3 +98,6 @@
     if 'ip-faces' in bld.env['NDN_plugins']:
         obj = bld.create_ns3_program('ndn-simple-tcp', all_modules)
         obj.source = 'ndn-simple-tcp.cc'
+
+        obj = bld.create_ns3_program('ndn-simple-udp', all_modules)
+        obj.source = 'ndn-simple-udp.cc'
diff --git a/plugins/ip-faces/ndn-ip-face-stack.cc b/plugins/ip-faces/ndn-ip-face-stack.cc
index 89839ba..da1b31d 100644
--- a/plugins/ip-faces/ndn-ip-face-stack.cc
+++ b/plugins/ip-faces/ndn-ip-face-stack.cc
@@ -20,6 +20,7 @@
 
 #include "ndn-ip-face-stack.h"
 #include "ndn-tcp-face.h"
+#include "ndn-udp-face.h"
 
 #include "ns3/ndn-l3-protocol.h"
 
@@ -30,15 +31,18 @@
 
 #include "ns3/socket.h"
 #include "ns3/tcp-socket-factory.h"
+#include "ns3/udp-socket-factory.h"
 #include "ns3/simulator.h"
 
 NS_LOG_COMPONENT_DEFINE ("ndn.IpFaceStack");
 
 namespace ns3 {
 namespace ndn {
-    
+
 NS_OBJECT_ENSURE_REGISTERED (IpFaceStack);
 
+const Callback< void, Ptr<Face> > IpFaceStack::NULL_CREATE_CALLBACK = MakeNullCallback< void, Ptr<Face> > ();
+
 TypeId
 IpFaceStack::GetTypeId (void)
 {
@@ -59,11 +63,11 @@
     ;
   return tid;
 }
-    
+
 IpFaceStack::IpFaceStack ()
 {
 }
-    
+
 IpFaceStack::~IpFaceStack ()
 {
 }
@@ -82,15 +86,15 @@
 }
 
 // Application Methods
-void 
+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 (), L3Protocol::IP_STACK_PORT));
       m_tcpServer->Listen ();
 
@@ -100,11 +104,10 @@
 
   if (m_enableUdp)
     {
-      // m_udpServer = Socket::CreateSocket (m_node, UdpSocketFactory::GetTypeId ());  
-      // m_udpServer->Bind (InetSocketAddress (Ipv4Address::GetAny (), L3Protocol::IP_STACK_PORT));
-      
-      // m_udpServer->SetRecvCallback (MakeCallback (&IpFaceStack::HandleRead, this));
-      // #error "Broken"
+      m_udpServer = Socket::CreateSocket (m_node, UdpSocketFactory::GetTypeId ());
+      m_udpServer->Bind (InetSocketAddress (Ipv4Address::GetAny (), L3Protocol::IP_STACK_PORT));
+
+      m_udpServer->SetRecvCallback (MakeCallback (&IpFaceStack::OnUdpPacket, this));
     }
 }
 
@@ -119,7 +122,7 @@
 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 ());
 
@@ -130,5 +133,93 @@
                              MakeCallback (&TcpFace::OnTcpConnectionClosed, face));
 }
 
+void
+IpFaceStack::OnUdpPacket (Ptr< Socket > socket)
+{
+  NS_LOG_FUNCTION (this << socket);
+
+  Ptr<Packet> packet;
+  Address from;
+  while ((packet = socket->RecvFrom (from)))
+    {
+      Ptr<UdpFace> face = CreateOrGetUdpFace (InetSocketAddress::ConvertFrom (from).GetIpv4 ());
+      face->ReceiveFromUdp (packet);
+    }
+}
+
+Ptr<TcpFace>
+IpFaceStack::GetTcpFaceByAddress (const Ipv4Address &address)
+{
+  TcpFaceMap::iterator i = m_tcpFaceMap.find (address);
+  if (i != m_tcpFaceMap.end ())
+    return i->second;
+  else
+    return 0;
+}
+
+void
+IpFaceStack::DestroyTcpFace (Ptr<TcpFace> face)
+{
+  m_tcpFaceMap.erase (face->GetAddress ());
+}
+
+Ptr<UdpFace>
+IpFaceStack::GetUdpFaceByAddress (const Ipv4Address &address)
+{
+  UdpFaceMap::iterator i = m_udpFaceMap.find (address);
+  if (i != m_udpFaceMap.end ())
+    return i->second;
+  else
+    return 0;
+}
+
+Ptr<TcpFace>
+IpFaceStack::CreateOrGetTcpFace (Ipv4Address address, Callback< void, Ptr<Face> > onCreate)
+{
+  NS_LOG_FUNCTION (address);
+
+  TcpFaceMap::iterator i = m_tcpFaceMap.find (address);
+  if (i != m_tcpFaceMap.end ())
+    return i->second;
+
+  Ptr<Socket> socket = Socket::CreateSocket (m_node, TcpSocketFactory::GetTypeId ());
+  Ptr<TcpFace> face = CreateObject<TcpFace> (m_node, socket, address);
+
+  face->SetCreateCallback (onCreate);
+
+  socket->SetConnectCallback (MakeCallback (&TcpFace::OnConnect, face),
+                              MakeNullCallback< void, Ptr< Socket > > ());
+  socket->Connect (InetSocketAddress (address, L3Protocol::IP_STACK_PORT));
+
+  m_tcpFaceMap.insert (std::make_pair (address, face));
+
+  return face;
+}
+
+Ptr<UdpFace>
+IpFaceStack::CreateOrGetUdpFace (Ipv4Address address)
+{
+  NS_LOG_FUNCTION (address);
+
+  UdpFaceMap::iterator i = m_udpFaceMap.find (address);
+  if (i != m_udpFaceMap.end ())
+    return i->second;
+
+  Ptr<Socket> socket = Socket::CreateSocket (m_node, UdpSocketFactory::GetTypeId ());
+  socket->Bind (InetSocketAddress (Ipv4Address::GetAny (), L3Protocol::IP_STACK_PORT)); // not sure if it going to work...
+  // socket->Bind ();
+  socket->Connect (InetSocketAddress (address, L3Protocol::IP_STACK_PORT));
+
+  Ptr<UdpFace> face = CreateObject<UdpFace> (m_node, socket, address);
+  Ptr<L3Protocol> ndn = m_node->GetObject<L3Protocol> ();
+
+  ndn->AddFace (face);
+  face->SetUp (true);
+
+  m_udpFaceMap.insert (std::make_pair (address, face));
+  return 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
index bf15b3e..ecb80b6 100644
--- a/plugins/ip-faces/ndn-ip-face-stack.h
+++ b/plugins/ip-faces/ndn-ip-face-stack.h
@@ -37,11 +37,13 @@
 namespace ndn {
 
 class Face;
+class TcpFace;
+class UdpFace;
 
 /**
  * @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
@@ -55,6 +57,41 @@
   IpFaceStack ();
   virtual ~IpFaceStack ();
 
+  /**
+   * @brief Lookup TcpFace for a given address
+   */
+  Ptr<TcpFace>
+  GetTcpFaceByAddress (const Ipv4Address &addr);
+
+  /**
+   * @brief Destroy TcpFace, e.g., after TCP connection got dropped
+   */
+  void
+  DestroyTcpFace (Ptr<TcpFace> face);
+
+  /**
+   * @brief Lookup UdpFace for a given address
+   */
+  Ptr<UdpFace>
+  GetUdpFaceByAddress (const Ipv4Address &addr);
+
+  /**
+   * @brief Method allowing creation and lookup of faces
+   *
+   * All created UDP faces are stored internally in the map, and if the same face is created, it will simply be looked up
+   */
+  Ptr<TcpFace>
+  CreateOrGetTcpFace (Ipv4Address address,
+                      Callback< void, Ptr<Face> > onCreate = NULL_CREATE_CALLBACK);
+
+  /**
+   * @brief 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
+   */
+  Ptr<UdpFace>
+  CreateOrGetUdpFace (Ipv4Address address);
+
 protected:
   void
   NotifyNewAggregate ();
@@ -62,7 +99,7 @@
 private:
   void
   StartServer ();
-  
+
   bool
   OnTcpConnectionRequest (Ptr< Socket > sock, const Address &addr);
 
@@ -72,14 +109,25 @@
   void
   OnTcpConnectionClosed (Ptr< Socket > sock);
 
+  void
+  OnUdpPacket (Ptr< Socket > sock);
+
+public:
+  const static Callback< void, Ptr<Face> > NULL_CREATE_CALLBACK;
+
 protected:
   Ptr<Node> m_node;
-  
+
   bool m_enableTcp;
   bool m_enableUdp;
-  
+
   Ptr<Socket> m_tcpServer;
   Ptr<Socket> m_udpServer;
+
+  typedef std::map< Ipv4Address, Ptr<TcpFace> > TcpFaceMap;
+  typedef std::map< Ipv4Address, Ptr<UdpFace> > UdpFaceMap;
+  TcpFaceMap m_tcpFaceMap;
+  UdpFaceMap m_udpFaceMap;
 };
 
 } // namespace ndn
diff --git a/plugins/ip-faces/ndn-ip-faces-helper.cc b/plugins/ip-faces/ndn-ip-faces-helper.cc
index 4d64268..26a766d 100644
--- a/plugins/ip-faces/ndn-ip-faces-helper.cc
+++ b/plugins/ip-faces/ndn-ip-faces-helper.cc
@@ -27,6 +27,7 @@
 #include "ns3/log.h"
 #include "ns3/simulator.h"
 #include "ndn-tcp-face.h"
+#include "ndn-udp-face.h"
 
 NS_LOG_COMPONENT_DEFINE ("ndn.IpFacesHelper");
 
@@ -83,11 +84,14 @@
 static void
 ScheduledCreateTcp (Ptr<Node> node, Ipv4Address address, const std::string &prefix, int16_t metric)
 {
-  Ptr<Face> face = TcpFace::GetFaceByAddress (address);
+  Ptr<IpFaceStack> stack = node->GetObject<IpFaceStack> ();
+  NS_ASSERT_MSG (stack != 0, "ndn::IpFaceStack needs to be installed on the node");
+
+  Ptr<Face> face = stack->GetTcpFaceByAddress (address);
   if (face == 0)
     {
       Ptr<TcpPrefixRegistrator> registrator = Create<TcpPrefixRegistrator> (node, prefix, metric);
-      TcpFace::CreateOrGetFace (node, address, MakeCallback (&TcpPrefixRegistrator::Run, registrator));
+      stack->CreateOrGetTcpFace (address, MakeCallback (&TcpPrefixRegistrator::Run, registrator));
     }
   else
     {
@@ -101,6 +105,21 @@
   Simulator::ScheduleWithContext (node->GetId (), when, ScheduledCreateTcp, node, address, prefix, metric);
 }
 
+static void
+ScheduledCreateUdp (Ptr<Node> node, Ipv4Address address, const std::string &prefix, int16_t metric)
+{
+  Ptr<IpFaceStack> stack = node->GetObject<IpFaceStack> ();
+  NS_ASSERT_MSG (stack != 0, "ndn::IpFaceStack needs to be installed on the node");
+
+  Ptr<Face> face = stack->CreateOrGetUdpFace (address);
+  ndn::StackHelper::AddRoute (node, prefix, face, metric);
+}
+
+void
+IpFacesHelper::CreateUdpFace (const Time &when, Ptr<Node> node, Ipv4Address address, const std::string &prefix, int16_t metric/* = 1*/)
+{
+  Simulator::ScheduleWithContext (node->GetId (), when, ScheduledCreateUdp, node, address, prefix, metric);
+}
 
 } // namespace ndn
 } // namespace ns3
diff --git a/plugins/ip-faces/ndn-ip-faces-helper.h b/plugins/ip-faces/ndn-ip-faces-helper.h
index d5d6d9c..ccaf3cd 100644
--- a/plugins/ip-faces/ndn-ip-faces-helper.h
+++ b/plugins/ip-faces/ndn-ip-faces-helper.h
@@ -77,6 +77,12 @@
    */
   static void
   CreateTcpFace (const Time &when, Ptr<Node> node, Ipv4Address address, const std::string &prefix, int16_t metric = 1);
+
+  /**
+   * @brief Create TCP face
+   */
+  static void
+  CreateUdpFace (const Time &when, Ptr<Node> node, Ipv4Address address, const std::string &prefix, int16_t metric = 1);
 };
 
 } // namespace ndn
diff --git a/plugins/ip-faces/ndn-tcp-face.cc b/plugins/ip-faces/ndn-tcp-face.cc
index 68a7d08..07c3d4d 100644
--- a/plugins/ip-faces/ndn-tcp-face.cc
+++ b/plugins/ip-faces/ndn-tcp-face.cc
@@ -20,6 +20,8 @@
  */
 
 #include "ndn-tcp-face.h"
+#include "ndn-ip-face-stack.h"
+
 #include "ns3/ndn-l3-protocol.h"
 
 #include "ns3/log.h"
@@ -37,8 +39,6 @@
 namespace ns3 {
 namespace ndn {
 
-TcpFace::FaceMap TcpFace::s_map;
-
 class TcpBoundaryHeader : public Header
 {
 public:
@@ -110,8 +110,6 @@
 
 NS_OBJECT_ENSURE_REGISTERED (TcpFace);
 
-const Callback< void, Ptr<Face> > TcpFace::NULL_CREATE_CALLBACK = MakeNullCallback< void, Ptr<Face> > ();
-
 TypeId
 TcpFace::GetTypeId ()
 {
@@ -155,7 +153,7 @@
 }
 
 void
-TcpFace:: UnRegisterProtocolHandlers ()
+TcpFace::UnRegisterProtocolHandlers ()
 {
   m_socket->SetRecvCallback (MakeNullCallback< void, Ptr<Socket> > ());
   Face::UnRegisterProtocolHandlers ();
@@ -241,7 +239,7 @@
 TcpFace::OnTcpConnectionClosed (Ptr<Socket> socket)
 {
   NS_LOG_FUNCTION (this << socket);
-  s_map.erase (m_address);
+  GetNode ()->GetObject<IpFaceStack> ()->DestroyTcpFace (this);
 }
 
 Ipv4Address
@@ -250,39 +248,6 @@
   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, Callback< void, Ptr<Face> > onCreate)
-{
-  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);
-
-  face->SetCreateCallback (onCreate);
-  
-  socket->SetConnectCallback (MakeCallback (&TcpFace::OnConnect, face),
-                              MakeNullCallback< void, Ptr< Socket > > ());
-  socket->Connect (InetSocketAddress (address, L3Protocol::IP_STACK_PORT));
-
-  s_map.insert (std::make_pair (address, face));
-
-  return face;
-}
-
 void
 TcpFace::SetCreateCallback (Callback< void, Ptr<Face> > callback)
 {
@@ -305,7 +270,7 @@
   if (!m_onCreateCallback.IsNull ())
     {
       m_onCreateCallback (this);
-      m_onCreateCallback = NULL_CREATE_CALLBACK;
+      m_onCreateCallback = IpFaceStack::NULL_CREATE_CALLBACK;
     }
 }
     
diff --git a/plugins/ip-faces/ndn-tcp-face.h b/plugins/ip-faces/ndn-tcp-face.h
index 8b4a90c..56cb0e9 100644
--- a/plugins/ip-faces/ndn-tcp-face.h
+++ b/plugins/ip-faces/ndn-tcp-face.h
@@ -42,15 +42,6 @@
 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,
-                   Callback< void, Ptr<Face> > onCreate = NULL_CREATE_CALLBACK);
   
   /**
    * \brief Constructor
@@ -60,14 +51,6 @@
   TcpFace (Ptr<Node> node, Ptr<Socket> socket, Ipv4Address address);
   virtual ~TcpFace();
 
-  ////////////////////////////////////////////////////////////////////
-  // methods overloaded from ndn::Face
-  virtual void
-  RegisterProtocolHandlers (const InterestHandler &interestHandler, const DataHandler &dataHandler);
-
-  virtual void
-  UnRegisterProtocolHandlers ();
-
   void
   OnTcpConnectionClosed (Ptr<Socket> socket);
 
@@ -80,25 +63,25 @@
   void
   SetCreateCallback (Callback< void, Ptr<Face> > callback);
 
-public:
-  const static Callback< void, Ptr<Face> > NULL_CREATE_CALLBACK;
-private:
   void
   OnConnect (Ptr<Socket> socket);
+
+  ////////////////////////////////////////////////////////////////////
+  // methods overloaded from ndn::Face
+  virtual void
+  RegisterProtocolHandlers (const InterestHandler &interestHandler, const DataHandler &dataHandler);
+
+  virtual void
+  UnRegisterProtocolHandlers ();
+
+  virtual std::ostream&
+  Print (std::ostream &os) const;
   
 protected:
   // also from ndn::Face
   virtual bool
   Send (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
@@ -111,9 +94,6 @@
   Ipv4Address m_address;
   uint32_t m_pendingPacketLength;
   Callback< void, Ptr<Face> > m_onCreateCallback;
-
-  typedef std::map<Ipv4Address, Ptr<TcpFace> > FaceMap;
-  static FaceMap s_map;
 };
 
 } // namespace ndn
diff --git a/plugins/ip-faces/ndn-udp-face.cc b/plugins/ip-faces/ndn-udp-face.cc
index 4ebff28..346c623 100644
--- a/plugins/ip-faces/ndn-udp-face.cc
+++ b/plugins/ip-faces/ndn-udp-face.cc
@@ -26,7 +26,7 @@
 #include "ns3/packet.h"
 #include "ns3/node.h"
 #include "ns3/pointer.h"
-#include "ns3/tcp-socket-factory.h"
+#include "ns3/udp-socket-factory.h"
 
 #include "ns3/ndn-name.h"
 
@@ -37,8 +37,6 @@
 namespace ns3 {
 namespace ndn {
 
-UdpFace::FaceMap UdpFace::s_map;
-
 NS_OBJECT_ENSURE_REGISTERED (UdpFace);
 
 TypeId
@@ -73,89 +71,38 @@
   return *this;
 }
 
-void
-UdpFace::RegisterProtocolHandler (ProtocolHandler handler)
+bool
+UdpFace::ReceiveFromUdp (Ptr<const Packet> p)
 {
-  NS_LOG_FUNCTION (this);
-
-  Face::RegisterProtocolHandler (handler);
-
-  m_socket->SetRecvCallback (MakeCallback (&UdpFace::ReceiveFromUdp, this));
+  return Face::Receive (p);
 }
 
 bool
-UdpFace::SendImpl (Ptr<Packet> packet)
+UdpFace::Send (Ptr<Packet> packet)
 {
-  NS_LOG_FUNCTION (this << packet);
-  Ptr<Packet> boundary = Create<Packet> ();
-  TcpBoundaryHeader hdr (packet);
-  boundary->AddHeader (hdr);
+  if (!Face::Send (packet))
+    {
+      return false;
+    }
   
-  m_socket->Send (boundary);
+  NS_LOG_FUNCTION (this << packet);
   m_socket->Send (packet);
 
   return true;
 }
 
-void
-UdpFace::ReceiveFromUdp (Ptr< Socket > clientSocket)
-{
-  NS_LOG_FUNCTION (this << clientSocket);
-
-  Ptr<Packet> packet;
-  Address from;
-  while ((packet = socket->RecvFrom (from)))
-    {
-      Receive (realPacket);
-    }
-  }
-}
-
 Ipv4Address
 UdpFace::GetAddress () const
 {
   return m_address;
 }
 
-Ptr<UdpFace>
-UdpFace::GetFaceByAddress (const Ipv4Address &address)
-{
-  FaceMap::iterator i = s_map.find (address);
-  if (i != s_map.end ())
-    return i->second;
-  else
-    return 0;
-}
-
-Ptr<UdpFace>
-UdpFace::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, UdpSocketFactory::GetTypeId ());
-  Ptr<UdpFace> face = CreateObject<UdpFace> (node, socket, address);
-
-  Ptr<L3Protocol> ndn = GetNode ()->GetObject<L3Protocol> ();
-  
-  ndn->AddFace (this);
-  this->SetUp (true);
-
-  s_map.insert (std::make_pair (address, face));
-
-  return face;
-}
-    
 std::ostream&
 UdpFace::Print (std::ostream& os) const
 {
-  os << "dev=udp(" << GetId () << ")";
+  os << "dev=udp(" << GetId () << "," << GetAddress () << ")";
   return os;
 }
 
 } // namespace ndn
 } // namespace ns3
-
diff --git a/plugins/ip-faces/ndn-udp-face.h b/plugins/ip-faces/ndn-udp-face.h
index 54f5fe3..f4b6a97 100644
--- a/plugins/ip-faces/ndn-udp-face.h
+++ b/plugins/ip-faces/ndn-udp-face.h
@@ -41,14 +41,6 @@
 public:
   static TypeId
   GetTypeId ();
-
-  /**
-   * @brief A singleton method allowing creation and lookup of faces
-   *
-   * All created UDP faces are stored internally in the map, and if the same face is created, it will simply be looked up
-   */
-  static Ptr<UdpFace>
-  CreateOrGetFace (Ptr<Node> node, Ipv4Address address);
   
   /**
    * \brief Constructor
@@ -58,43 +50,29 @@
   UdpFace (Ptr<Node> node, Ptr<Socket> socket, Ipv4Address address);
   virtual ~UdpFace();
 
-  ////////////////////////////////////////////////////////////////////
-  // methods overloaded from NdnFace
-  virtual void
-  RegisterProtocolHandler (ProtocolHandler handler);
-
   Ipv4Address
   GetAddress () const;
 
-  static Ptr<UdpFace>
-  GetFaceByAddress (const Ipv4Address &addr);
-
-protected:
-  // also from NdnFace
   virtual bool
-  SendImpl (Ptr<Packet> p);
+  ReceiveFromUdp (Ptr<const Packet> p);
 
-public:
-  /**
-   * @brief Print out name of the NdnFace to the stream
-   */
+  ////////////////////////////////////////////////////////////////////
+  // methods overloaded from ndn::Face
   virtual std::ostream&
   Print (std::ostream &os) const;
-  ////////////////////////////////////////////////////////////////////
+
+protected:
+  // also from ndn::Face
+  virtual bool
+  Send (Ptr<Packet> p);
 
 private:  
   UdpFace (const UdpFace &); ///< \brief Disabled copy constructor
   UdpFace& operator= (const UdpFace &); ///< \brief Disabled copy operator
 
-  void
-  ReceiveFromUdp (Ptr< Socket > clientSocket);
-
 private:
   Ptr<Socket> m_socket;
   Ipv4Address m_address;
-
-  typedef std::map<Ipv4Address, Ptr<UdpFace> > FaceMap;
-  static FaceMap s_map;
 };
 
 } // namespace ndn