face: Implementation of encode/decode of LocalControlHeader

LocalControlHeader can only be used on faces that are derived from
LocalFace.  UnixStreamFace is directly inherited from LocalFace,
TCP face has two specializations: generic TcpFace (strictly not local),
and LocalTcpFace.

refs #1213

Change-Id: I8a158c3bc4bb929eedd15757cfddecc0d1049f9f
diff --git a/tests/face/dummy-face.hpp b/tests/face/dummy-face.hpp
index 7de128d..92100b6 100644
--- a/tests/face/dummy-face.hpp
+++ b/tests/face/dummy-face.hpp
@@ -8,6 +8,7 @@
 #define NFD_TEST_FACE_DUMMY_FACE_HPP
 
 #include "face/face.hpp"
+#include "face/local-face.hpp"
 
 namespace nfd {
 
@@ -15,15 +16,10 @@
  *  \brief provides a Face that cannot communicate
  *  for unit testing only
  */
-class DummyFace : public Face
+template<class FaceBase>
+class DummyFaceImpl : public FaceBase
 {
 public:
-  explicit
-  DummyFace(bool isLocal = false)
-    : m_isLocal(isLocal)
-  {
-  }
-  
   virtual void
   sendInterest(const Interest& interest)
   {
@@ -39,16 +35,12 @@
   {
   }
 
-  virtual bool
-  isLocal() const
-  {
-    return m_isLocal;
-  }
-
 private:
-  bool m_isLocal;
 };
 
+typedef DummyFaceImpl<Face> DummyFace;
+typedef DummyFaceImpl<LocalFace> DummyLocalFace;
+
 } // namespace nfd
 
 #endif // TEST_FACE_DUMMY_FACE_HPP
diff --git a/tests/face/face.cpp b/tests/face/face.cpp
index 07e3fb4..3fb4ea4 100644
--- a/tests/face/face.cpp
+++ b/tests/face/face.cpp
@@ -5,6 +5,7 @@
  */
 
 #include "face/face.hpp"
+#include "face/local-face.hpp"
 #include "dummy-face.hpp"
 
 #include <boost/test/unit_test.hpp>
@@ -22,7 +23,7 @@
 
 BOOST_AUTO_TEST_CASE(LocalControlHeaderEnabled)
 {
-  DummyFace face;
+  DummyLocalFace face;
   
   BOOST_CHECK_EQUAL(face.isLocalControlHeaderEnabled(), false);
   
diff --git a/tests/face/tcp.cpp b/tests/face/tcp.cpp
index d64d1ce..8014f52 100644
--- a/tests/face/tcp.cpp
+++ b/tests/face/tcp.cpp
@@ -32,7 +32,7 @@
 {
 public:
   void
-  channel1_onFaceCreated(const shared_ptr<TcpFace>& newFace)
+  channel1_onFaceCreated(const shared_ptr<Face>& newFace)
   {
     BOOST_CHECK(!static_cast<bool>(m_face1));
     m_face1 = newFace;
@@ -78,7 +78,7 @@
   }
 
   void
-  channel2_onFaceCreated(const shared_ptr<TcpFace>& newFace)
+  channel2_onFaceCreated(const shared_ptr<Face>& newFace)
   {
     BOOST_CHECK(!static_cast<bool>(m_face2));
     m_face2 = newFace;
@@ -124,7 +124,7 @@
   }
 
   void
-  channel_onFaceCreated(const shared_ptr<TcpFace>& newFace)
+  channel_onFaceCreated(const shared_ptr<Face>& newFace)
   {
     m_faces.push_back(newFace);
     this->afterIo();
@@ -163,14 +163,14 @@
 
   int m_ioRemaining;
 
-  shared_ptr<TcpFace> m_face1;
+  shared_ptr<Face> m_face1;
   std::vector<Interest> m_face1_receivedInterests;
   std::vector<Data> m_face1_receivedDatas;
-  shared_ptr<TcpFace> m_face2;
+  shared_ptr<Face> m_face2;
   std::vector<Interest> m_face2_receivedInterests;
   std::vector<Data> m_face2_receivedDatas;
 
-  std::list< shared_ptr<TcpFace> > m_faces;
+  std::list< shared_ptr<Face> > m_faces;
 };
 
 
@@ -202,7 +202,15 @@
 
   BOOST_REQUIRE(static_cast<bool>(m_face1));
   BOOST_REQUIRE(static_cast<bool>(m_face2));
-    
+
+  BOOST_CHECK_EQUAL(m_face1->isLocal(), true);
+  BOOST_CHECK_EQUAL(m_face2->isLocal(), true);
+
+  BOOST_CHECK_EQUAL(static_cast<bool>(dynamic_pointer_cast<LocalFace>(m_face1)), true);
+  BOOST_CHECK_EQUAL(static_cast<bool>(dynamic_pointer_cast<LocalFace>(m_face2)), true);
+
+  // integrated tests needs to check that TcpFace for non-loopback fails these tests...
+  
   abortEvent =
     scheduler.scheduleEvent(time::seconds(1),
                             bind(&EndToEndFixture::abortTestCase, this,
diff --git a/tests/face/unix-stream.cpp b/tests/face/unix-stream.cpp
index fee5827..9d6a6cf 100644
--- a/tests/face/unix-stream.cpp
+++ b/tests/face/unix-stream.cpp
@@ -61,7 +61,7 @@
 
     this->afterIo();
   }
-  
+
   void
   face1_onReceiveInterest(const Interest& interest)
   {
@@ -69,7 +69,7 @@
 
     this->afterIo();
   }
-  
+
   void
   face1_onReceiveData(const Data& data)
   {
@@ -85,7 +85,7 @@
 
     this->afterIo();
   }
-  
+
   void
   face2_onReceiveData(const Data& data)
   {
@@ -310,6 +310,138 @@
   BOOST_CHECK_EQUAL(m_face2_receivedDatas    [0].getName(), data1.getName());
 }
 
+static inline void
+noOp()
+{
+}
+
+BOOST_FIXTURE_TEST_CASE(UnixStreamFaceLocalControlHeader, EndToEndFixture)
+{
+  UnixStreamChannelFactory factory(m_ioService);
+  Scheduler scheduler(m_ioService); // to limit the amount of time the test may take
+
+  EventId abortEvent =
+    scheduler.scheduleEvent(time::seconds(1),
+                            bind(&EndToEndFixture::abortTestCase, this,
+                                 "UnixStreamChannel error: cannot connect or cannot accept connection"));
+
+  shared_ptr<UnixStreamChannel> channel1 = factory.create("foo");
+  channel1->listen(bind(&EndToEndFixture::channel1_onFaceCreated,   this, _1),
+                   bind(&EndToEndFixture::channel1_onConnectFailed, this, _1));
+
+  shared_ptr<stream_protocol::socket> client =
+      make_shared<stream_protocol::socket>(boost::ref(m_ioService));
+  client->async_connect(stream_protocol::endpoint("foo"),
+                        bind(&EndToEndFixture::client_onConnect, this, _1));
+
+  m_ioRemaining = 2;
+  m_ioService.run();
+  m_ioService.reset();
+  scheduler.cancelEvent(abortEvent);
+
+  BOOST_REQUIRE(static_cast<bool>(m_face1));
+
+  abortEvent =
+    scheduler.scheduleEvent(time::seconds(1),
+                            bind(&EndToEndFixture::abortTestCase, this,
+                                 "UnixStreamChannel error: cannot send or receive Interest/Data packets"));
+
+  m_face2 = make_shared<UnixStreamFace>(client);
+  m_face2->onReceiveInterest +=
+    bind(&EndToEndFixture::face2_onReceiveInterest, this, _1);
+  m_face2->onReceiveData +=
+    bind(&EndToEndFixture::face2_onReceiveData, this, _1);
+
+  Interest interest1("ndn:/TpnzGvW9R");
+  Data     data1    ("ndn:/KfczhUqVix");
+  data1.setContent(0, 0);
+  Interest interest2("ndn:/QWiIMfj5sL");
+  Data     data2    ("ndn:/XNBV796f");
+  data2.setContent(0, 0);
+
+  ndn::SignatureSha256WithRsa fakeSignature;
+  fakeSignature.setValue(ndn::dataBlock(tlv::SignatureValue, reinterpret_cast<const uint8_t*>(0), 0));
+
+  // set fake signature on data1 and data2
+  data1.setSignature(fakeSignature);
+  data2.setSignature(fakeSignature);
+
+  m_face1->setLocalControlHeaderFeature(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID);
+  m_face1->setLocalControlHeaderFeature(LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID);
+
+  BOOST_CHECK(m_face1->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID));
+  BOOST_CHECK(m_face1->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID));
+
+  m_face2->setLocalControlHeaderFeature(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID);
+  m_face2->setLocalControlHeaderFeature(LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID);
+
+  BOOST_CHECK(m_face2->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_IN_FACEID));
+  BOOST_CHECK(m_face2->isLocalControlHeaderEnabled(LOCAL_CONTROL_HEADER_FEATURE_NEXTHOP_FACEID));
+
+  ////////////////////////////////////////////////////////
+
+  interest1.setIncomingFaceId(11);
+  interest1.setNextHopFaceId(111);
+
+  m_face1->sendInterest(interest1);
+
+  data1.setIncomingFaceId(22);
+  data1.getLocalControlHeader().setNextHopFaceId(222);
+
+  m_face1->sendData    (data1);
+
+  //
+
+  m_ioRemaining = 2;
+  m_ioService.run();
+  m_ioService.reset();
+
+  BOOST_REQUIRE_EQUAL(m_face2_receivedInterests.size(), 1);
+  BOOST_REQUIRE_EQUAL(m_face2_receivedDatas    .size(), 1);
+
+  // sending allows only IncomingFaceId, receiving allows only NextHopFaceId
+  BOOST_CHECK_EQUAL(m_face2_receivedInterests[0].getLocalControlHeader().hasIncomingFaceId(), false);
+  BOOST_CHECK_EQUAL(m_face2_receivedInterests[0].getLocalControlHeader().hasNextHopFaceId(), false);
+
+  BOOST_CHECK_EQUAL(m_face2_receivedDatas[0].getLocalControlHeader().hasIncomingFaceId(), false);
+  BOOST_CHECK_EQUAL(m_face2_receivedDatas[0].getLocalControlHeader().hasNextHopFaceId(), false);
+
+  ////////////////////////////////////////////////////////
+
+  using namespace boost::asio;
+
+  std::vector<const_buffer> interestWithHeader;
+  Block iHeader  = interest1.getLocalControlHeader().wireEncode(interest1, true, true);
+  Block iPayload = interest1.wireEncode();
+  interestWithHeader.push_back(buffer(iHeader.wire(),  iHeader.size()));
+  interestWithHeader.push_back(buffer(iPayload.wire(), iPayload.size()));
+
+  std::vector<const_buffer> dataWithHeader;
+  Block dHeader  = data1.getLocalControlHeader().wireEncode(data1, true, true);
+  Block dPayload = data1.wireEncode();
+  dataWithHeader.push_back(buffer(dHeader.wire(),  dHeader.size()));
+  dataWithHeader.push_back(buffer(dPayload.wire(), dPayload.size()));
+
+  //
+
+  client->async_send(interestWithHeader, bind(&noOp));
+  client->async_send(dataWithHeader, bind(&noOp));
+
+  m_ioRemaining = 2;
+  m_ioService.run();
+  m_ioService.reset();
+
+  BOOST_REQUIRE_EQUAL(m_face1_receivedInterests.size(), 1);
+  BOOST_REQUIRE_EQUAL(m_face1_receivedDatas    .size(), 1);
+
+  BOOST_CHECK_EQUAL(m_face1_receivedInterests[0].getLocalControlHeader().hasIncomingFaceId(), false);
+  BOOST_CHECK_EQUAL(m_face1_receivedInterests[0].getLocalControlHeader().hasNextHopFaceId(), true);
+  BOOST_CHECK_EQUAL(m_face1_receivedInterests[0].getNextHopFaceId(), 111);
+
+  BOOST_CHECK_EQUAL(m_face1_receivedDatas[0].getLocalControlHeader().hasIncomingFaceId(), false);
+  BOOST_CHECK_EQUAL(m_face1_receivedDatas[0].getLocalControlHeader().hasNextHopFaceId(), false);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace nfd
diff --git a/tests/fw/forwarder.cpp b/tests/fw/forwarder.cpp
index ed8f6a7..e066f52 100644
--- a/tests/fw/forwarder.cpp
+++ b/tests/fw/forwarder.cpp
@@ -38,12 +38,6 @@
   {
   }
 
-  virtual bool
-  isLocal() const
-  {
-    return false;
-  }
-
   void
   receiveInterest(const Interest& interest)
   {
@@ -129,25 +123,6 @@
   BOOST_CHECK_EQUAL(face1->m_sentDatas[0].getIncomingFaceId(), face2->getId());
 }
 
-
-class ForwarderTestLocalFace : public DummyFace {
-public:
-  explicit
-  ForwarderTestLocalFace(bool isLocal)
-    : m_isLocal(isLocal)
-  {
-  }
-
-  virtual bool
-  isLocal() const
-  {
-    return m_isLocal;
-  }
-
-private:
-  bool m_isLocal;
-};
-
 class ScopeLocalhostTestForwarder : public Forwarder
 {
 public:
@@ -182,8 +157,8 @@
 {
   boost::asio::io_service io;
   ScopeLocalhostTestForwarder forwarder(io);
-  shared_ptr<ForwarderTestLocalFace> face1 = make_shared<ForwarderTestLocalFace>(true);
-  shared_ptr<ForwarderTestLocalFace> face2 = make_shared<ForwarderTestLocalFace>(false);
+  shared_ptr<DummyLocalFace> face1 = make_shared<DummyLocalFace>();
+  shared_ptr<DummyFace>      face2 = make_shared<DummyFace>();
   forwarder.addFace(face1);
   forwarder.addFace(face2);
   
diff --git a/tests/mgmt/local-control-header-manager.cpp b/tests/mgmt/local-control-header-manager.cpp
index b9c1d32..b7fdf58 100644
--- a/tests/mgmt/local-control-header-manager.cpp
+++ b/tests/mgmt/local-control-header-manager.cpp
@@ -6,6 +6,7 @@
 
 #include "mgmt/local-control-header-manager.hpp"
 #include "face/face.hpp"
+#include "face/local-face.hpp"
 #include "mgmt/internal-face.hpp"
 #include "../face/dummy-face.hpp"
 
@@ -94,7 +95,7 @@
 
 BOOST_FIXTURE_TEST_CASE(InFaceId, LocalControlHeaderManagerFixture)
 {
-  shared_ptr<Face> dummy = make_shared<DummyFace>();
+  shared_ptr<LocalFace> dummy = make_shared<DummyLocalFace>();
   addFace(dummy);
 
   shared_ptr<InternalFace> face(make_shared<InternalFace>());
@@ -136,7 +137,7 @@
 
 BOOST_FIXTURE_TEST_CASE(NextHopFaceId, LocalControlHeaderManagerFixture)
 {
-  shared_ptr<Face> dummy = make_shared<DummyFace>();
+  shared_ptr<LocalFace> dummy = make_shared<DummyLocalFace>();
   addFace(dummy);
 
   shared_ptr<InternalFace> face(make_shared<InternalFace>());
@@ -179,7 +180,7 @@
 
 BOOST_FIXTURE_TEST_CASE(ShortCommand, LocalControlHeaderManagerFixture)
 {
-  shared_ptr<Face> dummy = make_shared<DummyFace>();
+  shared_ptr<LocalFace> dummy = make_shared<DummyLocalFace>();
   addFace(dummy);
 
   shared_ptr<InternalFace> face(make_shared<InternalFace>());
@@ -204,7 +205,7 @@
 
 BOOST_FIXTURE_TEST_CASE(ShortCommandModule, LocalControlHeaderManagerFixture)
 {
-  shared_ptr<Face> dummy = make_shared<DummyFace>();
+  shared_ptr<LocalFace> dummy = make_shared<DummyLocalFace>();
   addFace(dummy);
 
   shared_ptr<InternalFace> face(make_shared<InternalFace>());
@@ -229,7 +230,7 @@
 
 BOOST_FIXTURE_TEST_CASE(UnsupportedModule, LocalControlHeaderManagerFixture)
 {
-  shared_ptr<Face> dummy = make_shared<DummyFace>();
+  shared_ptr<LocalFace> dummy = make_shared<DummyLocalFace>();
   addFace(dummy);
 
   shared_ptr<InternalFace> face(make_shared<InternalFace>());
@@ -254,7 +255,7 @@
 
 BOOST_FIXTURE_TEST_CASE(InFaceIdUnsupportedVerb, LocalControlHeaderManagerFixture)
 {
-  shared_ptr<Face> dummy = make_shared<DummyFace>();
+  shared_ptr<LocalFace> dummy = make_shared<DummyLocalFace>();
   addFace(dummy);
 
   shared_ptr<InternalFace> face(make_shared<InternalFace>());
@@ -279,7 +280,7 @@
 
 BOOST_FIXTURE_TEST_CASE(NextHopFaceIdUnsupportedVerb, LocalControlHeaderManagerFixture)
 {
-  shared_ptr<Face> dummy = make_shared<DummyFace>();
+  shared_ptr<LocalFace> dummy = make_shared<DummyLocalFace>();
   addFace(dummy);
 
   shared_ptr<InternalFace> face(make_shared<InternalFace>());