plugins/ip-faces: Updating TcpFace implementation

In addition to changes to follow latest API changes in ndnSIM, the
helper ndn::IpFacesHelper allows scheduling TcpFace creation at specific
point of simulation.

Refs #1006 (http://redmine.named-data.net/)
diff --git a/examples/ndn-simple-tcp.cc b/examples/ndn-simple-tcp.cc
index 641348a..f959dc7 100644
--- a/examples/ndn-simple-tcp.cc
+++ b/examples/ndn-simple-tcp.cc
@@ -97,9 +97,8 @@
                        Ipv4Address ("10.1.2.1"),
                        1, 1);
   
-  ndn::IpFacesHelper ipFacesHelper;
-  ipFacesHelper.InstallAll ();
-  ipFacesHelper.CreateTcpFace (nodes.Get (0), Ipv4Address ("10.1.2.2"), "/tcp-route");
+  ndn::IpFacesHelper::InstallAll ();
+  ndn::IpFacesHelper::CreateTcpFace (Seconds (1.0), nodes.Get (0), Ipv4Address ("10.1.2.2"), "/tcp-route");
   
   // Installing applications
 
diff --git a/plugins/ip-faces/ndn-ip-face-stack.cc b/plugins/ip-faces/ndn-ip-face-stack.cc
index cbb5e24..89839ba 100644
--- a/plugins/ip-faces/ndn-ip-face-stack.cc
+++ b/plugins/ip-faces/ndn-ip-face-stack.cc
@@ -26,6 +26,7 @@
 #include "ns3/log.h"
 #include "ns3/assert.h"
 #include "ns3/packet.h"
+#include "ns3/boolean.h"
 
 #include "ns3/socket.h"
 #include "ns3/tcp-socket-factory.h"
diff --git a/plugins/ip-faces/ndn-ip-faces-helper.cc b/plugins/ip-faces/ndn-ip-faces-helper.cc
index efd956f..4d64268 100644
--- a/plugins/ip-faces/ndn-ip-faces-helper.cc
+++ b/plugins/ip-faces/ndn-ip-faces-helper.cc
@@ -60,25 +60,45 @@
 }
 
 
-static void
-CreateTcpFaceStep2 (Ptr<Node> node, Ipv4Address address, const std::string &prefix)
+struct TcpPrefixRegistrator : SimpleRefCount<TcpPrefixRegistrator>
 {
-  Ptr<Face> face = TcpFace::CreateOrGetFace (node, address);
-  ndn::StackHelper::AddRoute (node, prefix, face, 1);
-}
+  TcpPrefixRegistrator (Ptr<Node> node, const std::string &prefix, int16_t metric)
+    : m_node (node)
+    , m_prefix (prefix)
+    , m_metric (metric)
+  {
+  }
+
+  void
+  Run (Ptr<Face> face)
+  {
+    ndn::StackHelper::AddRoute (m_node, m_prefix, face, m_metric);
+  }
+private:
+  Ptr<Node> m_node;
+  std::string m_prefix;
+  int16_t m_metric;
+};
 
 static void
-CreateTcpFaceStep1 (Ptr<Node> node, Ipv4Address address, const std::string &prefix)
+ScheduledCreateTcp (Ptr<Node> node, Ipv4Address address, const std::string &prefix, int16_t metric)
 {
-  TcpFace::CreateOrGetFace (node, address);
-  
-  Simulator::ScheduleWithContext (node->GetId (), Seconds (1.0), CreateTcpFaceStep2, node, address, prefix);
+  Ptr<Face> face = TcpFace::GetFaceByAddress (address);
+  if (face == 0)
+    {
+      Ptr<TcpPrefixRegistrator> registrator = Create<TcpPrefixRegistrator> (node, prefix, metric);
+      TcpFace::CreateOrGetFace (node, address, MakeCallback (&TcpPrefixRegistrator::Run, registrator));
+    }
+  else
+    {
+      ndn::StackHelper::AddRoute (node, prefix, face, metric);
+    }
 }
 
 void
-IpFacesHelper::CreateTcpFace (Ptr<Node> node, Ipv4Address address, const std::string &prefix)
+IpFacesHelper::CreateTcpFace (const Time &when, Ptr<Node> node, Ipv4Address address, const std::string &prefix, int16_t metric/* = 1*/)
 {
-  Simulator::ScheduleWithContext (node->GetId (), Seconds (1.0), CreateTcpFaceStep1, node, address, prefix);
+  Simulator::ScheduleWithContext (node->GetId (), when, ScheduledCreateTcp, node, address, prefix, metric);
 }
 
 
diff --git a/plugins/ip-faces/ndn-ip-faces-helper.h b/plugins/ip-faces/ndn-ip-faces-helper.h
index 3ea8859..d5d6d9c 100644
--- a/plugins/ip-faces/ndn-ip-faces-helper.h
+++ b/plugins/ip-faces/ndn-ip-faces-helper.h
@@ -23,6 +23,7 @@
 #define NDN_IP_FACES_HELPER_H
 
 #include "ns3/ptr.h"
+#include "ns3/nstime.h"
 #include "ns3/ipv4-address.h"
 
 namespace ns3 {
@@ -44,27 +45,38 @@
    * @brief Install IpFaceStack interface on a node
    * @param node Node to install IpFaceStack interface
    */
-  void
+  static void
   Install (Ptr<Node> node);
 
   /**
    * @brief Install IpFaceStack interface on nodes
    * @param nodes NodeContainer to install IpFaceStack interface
    */
-  void
+  static void
   Install (const NodeContainer &nodes);
 
   /**
    * @brief Install IpFaceStack interface on all nodes
    */
-  void
+  static void
   InstallAll ();
 
   /**
    * @brief Create TCP face
+   * @param when    Time when to create face (use `Seconds (0)' if face should be created right away)
+   * @param node    Node to add TCP face (will initiate connection)
+   * @param address IP address to connect (using standard 9695 port)
+   * @param prefix  Prefix to associate with the face
+   * @param metric  Metric that will be assigned to the face
+   *
+   * This call schedules connection initiation and after successful connection it will add new face
+   * to NDN stack and add the requested route
+   *
+   * If face has been already created before (same IP address), then this call will simply
+   * update FIB with requested prefix
    */
-  void
-  CreateTcpFace (Ptr<Node> node, Ipv4Address address, const std::string &prefix);
+  static void
+  CreateTcpFace (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 4ef8908..68a7d08 100644
--- a/plugins/ip-faces/ndn-tcp-face.cc
+++ b/plugins/ip-faces/ndn-tcp-face.cc
@@ -110,6 +110,8 @@
 
 NS_OBJECT_ENSURE_REGISTERED (TcpFace);
 
+const Callback< void, Ptr<Face> > TcpFace::NULL_CREATE_CALLBACK = MakeNullCallback< void, Ptr<Face> > ();
+
 TypeId
 TcpFace::GetTypeId ()
 {
@@ -144,19 +146,31 @@
 }
 
 void
-TcpFace::RegisterProtocolHandler (ProtocolHandler handler)
+TcpFace::RegisterProtocolHandlers (const InterestHandler &interestHandler, const DataHandler &dataHandler)
 {
   NS_LOG_FUNCTION (this);
 
-  Face::RegisterProtocolHandler (handler);
-
+  Face::RegisterProtocolHandlers (interestHandler, dataHandler);
   m_socket->SetRecvCallback (MakeCallback (&TcpFace::ReceiveFromTcp, this));
 }
 
-bool
-TcpFace::SendImpl (Ptr<Packet> packet)
+void
+TcpFace:: UnRegisterProtocolHandlers ()
 {
+  m_socket->SetRecvCallback (MakeNullCallback< void, Ptr<Socket> > ());
+  Face::UnRegisterProtocolHandlers ();
+}
+
+bool
+TcpFace::Send (Ptr<Packet> packet)
+{
+  if (!Face::Send (packet))
+    {
+      return false;
+    }
+  
   NS_LOG_FUNCTION (this << packet);
+
   Ptr<Packet> boundary = Create<Packet> ();
   TcpBoundaryHeader hdr (packet);
   boundary->AddHeader (hdr);
@@ -247,7 +261,7 @@
 }
 
 Ptr<TcpFace>
-TcpFace::CreateOrGetFace (Ptr<Node> node, Ipv4Address address)
+TcpFace::CreateOrGetFace (Ptr<Node> node, Ipv4Address address, Callback< void, Ptr<Face> > onCreate)
 {
   NS_LOG_FUNCTION (address);
 
@@ -257,6 +271,8 @@
   
   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 > > ());
@@ -268,6 +284,12 @@
 }
 
 void
+TcpFace::SetCreateCallback (Callback< void, Ptr<Face> > callback)
+{
+  m_onCreateCallback = callback;
+}
+
+void
 TcpFace::OnConnect (Ptr<Socket> socket)
 {
   NS_LOG_FUNCTION (this << socket);
@@ -279,6 +301,12 @@
 
   socket->SetCloseCallbacks (MakeCallback (&TcpFace::OnTcpConnectionClosed, this),
                              MakeCallback (&TcpFace::OnTcpConnectionClosed, this));
+
+  if (!m_onCreateCallback.IsNull ())
+    {
+      m_onCreateCallback (this);
+      m_onCreateCallback = NULL_CREATE_CALLBACK;
+    }
 }
     
 std::ostream&
diff --git a/plugins/ip-faces/ndn-tcp-face.h b/plugins/ip-faces/ndn-tcp-face.h
index 6e9763e..8b4a90c 100644
--- a/plugins/ip-faces/ndn-tcp-face.h
+++ b/plugins/ip-faces/ndn-tcp-face.h
@@ -24,6 +24,7 @@
 #include "ns3/ndn-face.h"
 #include "ns3/socket.h"
 #include "ns3/ptr.h"
+#include "ns3/callback.h"
 
 #include <map>
 
@@ -48,7 +49,8 @@
    * 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);
+  CreateOrGetFace (Ptr<Node> node, Ipv4Address address,
+                   Callback< void, Ptr<Face> > onCreate = NULL_CREATE_CALLBACK);
   
   /**
    * \brief Constructor
@@ -59,9 +61,12 @@
   virtual ~TcpFace();
 
   ////////////////////////////////////////////////////////////////////
-  // methods overloaded from NdnFace
+  // methods overloaded from ndn::Face
   virtual void
-  RegisterProtocolHandler (ProtocolHandler handler);
+  RegisterProtocolHandlers (const InterestHandler &interestHandler, const DataHandler &dataHandler);
+
+  virtual void
+  UnRegisterProtocolHandlers ();
 
   void
   OnTcpConnectionClosed (Ptr<Socket> socket);
@@ -72,14 +77,19 @@
   static Ptr<TcpFace>
   GetFaceByAddress (const Ipv4Address &addr);
 
+  void
+  SetCreateCallback (Callback< void, Ptr<Face> > callback);
+
+public:
+  const static Callback< void, Ptr<Face> > NULL_CREATE_CALLBACK;
 private:
   void
   OnConnect (Ptr<Socket> socket);
   
 protected:
-  // also from NdnFace
+  // also from ndn::Face
   virtual bool
-  SendImpl (Ptr<Packet> p);
+  Send (Ptr<Packet> p);
 
 public:
   /**
@@ -100,6 +110,7 @@
   Ptr<Socket> m_socket;
   Ipv4Address m_address;
   uint32_t m_pendingPacketLength;
+  Callback< void, Ptr<Face> > m_onCreateCallback;
 
   typedef std::map<Ipv4Address, Ptr<TcpFace> > FaceMap;
   static FaceMap s_map;