face: Gracefully handle tlv::Error when received TLV block is malformed

Change-Id: I954b13d0e26fec7bc7fe23edcbc015dfac654ef8
Refs: #1494
diff --git a/tests/daemon/face/tcp.cpp b/tests/daemon/face/tcp.cpp
index bc3ac30..166f257 100644
--- a/tests/daemon/face/tcp.cpp
+++ b/tests/daemon/face/tcp.cpp
@@ -23,10 +23,14 @@
  **/
 
 #include "face/tcp-factory.hpp"
+#include "core/resolver.hpp"
+#include "core/network-interface.hpp"
 #include <ndn-cxx/security/key-chain.hpp>
 
 #include "tests/test-common.hpp"
 #include "tests/limited-io.hpp"
+#include "dummy-stream-sender.hpp"
+#include "packet-datasets.hpp"
 
 namespace nfd {
 namespace tests {
@@ -223,28 +227,19 @@
 
   // integrated tests needs to check that TcpFace for non-loopback fails these tests...
 
-  Interest interest1("ndn:/TpnzGvW9R");
-  Data     data1    ("ndn:/KfczhUqVix");
-  data1.setContent(0, 0);
-  Interest interest2("ndn:/QWiIMfj5sL");
-  Data     data2    ("ndn:/XNBV796f");
-  data2.setContent(0, 0);
+  shared_ptr<Interest> interest1 = makeInterest("ndn:/TpnzGvW9R");
+  shared_ptr<Data>     data1     = makeData("ndn:/KfczhUqVix");
+  shared_ptr<Interest> interest2 = makeInterest("ndn:/QWiIMfj5sL");
+  shared_ptr<Data>     data2     = makeData("ndn:/XNBV796f");
 
-  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);
-
-  face1->sendInterest(interest1);
-  face1->sendInterest(interest1);
-  face1->sendInterest(interest1);
-  face1->sendData    (data1    );
-  face2->sendInterest(interest2);
-  face2->sendData    (data2    );
-  face2->sendData    (data2    );
-  face2->sendData    (data2    );
+  face1->sendInterest(*interest1);
+  face1->sendInterest(*interest1);
+  face1->sendInterest(*interest1);
+  face1->sendData    (*data1    );
+  face2->sendInterest(*interest2);
+  face2->sendData    (*data2    );
+  face2->sendData    (*data2    );
+  face2->sendData    (*data2    );
 
   BOOST_CHECK_MESSAGE(limitedIo.run(8, time::seconds(10)) == LimitedIo::EXCEED_OPS,
                       "TcpChannel error: cannot send or receive Interest/Data packets");
@@ -255,10 +250,10 @@
   BOOST_REQUIRE_EQUAL(face2_receivedInterests.size(), 3);
   BOOST_REQUIRE_EQUAL(face2_receivedDatas    .size(), 1);
 
-  BOOST_CHECK_EQUAL(face1_receivedInterests[0].getName(), interest2.getName());
-  BOOST_CHECK_EQUAL(face1_receivedDatas    [0].getName(), data2.getName());
-  BOOST_CHECK_EQUAL(face2_receivedInterests[0].getName(), interest1.getName());
-  BOOST_CHECK_EQUAL(face2_receivedDatas    [0].getName(), data1.getName());
+  BOOST_CHECK_EQUAL(face1_receivedInterests[0].getName(), interest2->getName());
+  BOOST_CHECK_EQUAL(face1_receivedDatas    [0].getName(), data2->getName());
+  BOOST_CHECK_EQUAL(face2_receivedInterests[0].getName(), interest1->getName());
+  BOOST_CHECK_EQUAL(face2_receivedDatas    [0].getName(), data1->getName());
 
   const FaceCounters& counters1 = face1->getCounters();
   BOOST_CHECK_EQUAL(counters1.getNInInterests() , 1);
@@ -309,24 +304,15 @@
 
   // integrated tests needs to check that TcpFace for non-loopback fails these tests...
 
-  Interest interest1("ndn:/TpnzGvW9R");
-  Data     data1    ("ndn:/KfczhUqVix");
-  data1.setContent(0, 0);
-  Interest interest2("ndn:/QWiIMfj5sL");
-  Data     data2    ("ndn:/XNBV796f");
-  data2.setContent(0, 0);
+  shared_ptr<Interest> interest1 = makeInterest("ndn:/TpnzGvW9R");
+  shared_ptr<Data>     data1     = makeData("ndn:/KfczhUqVix");
+  shared_ptr<Interest> interest2 = makeInterest("ndn:/QWiIMfj5sL");
+  shared_ptr<Data>     data2     = makeData("ndn:/XNBV796f");
 
-  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);
-
-  face1->sendInterest(interest1);
-  face1->sendData    (data1    );
-  face2->sendInterest(interest2);
-  face2->sendData    (data2    );
+  face1->sendInterest(*interest1);
+  face1->sendData    (*data1    );
+  face2->sendInterest(*interest2);
+  face2->sendData    (*data2    );
 
   BOOST_CHECK_MESSAGE(limitedIo.run(4, time::seconds(10)) == LimitedIo::EXCEED_OPS,
                       "TcpChannel error: cannot send or receive Interest/Data packets");
@@ -337,10 +323,10 @@
   BOOST_REQUIRE_EQUAL(face2_receivedInterests.size(), 1);
   BOOST_REQUIRE_EQUAL(face2_receivedDatas    .size(), 1);
 
-  BOOST_CHECK_EQUAL(face1_receivedInterests[0].getName(), interest2.getName());
-  BOOST_CHECK_EQUAL(face1_receivedDatas    [0].getName(), data2.getName());
-  BOOST_CHECK_EQUAL(face2_receivedInterests[0].getName(), interest1.getName());
-  BOOST_CHECK_EQUAL(face2_receivedDatas    [0].getName(), data1.getName());
+  BOOST_CHECK_EQUAL(face1_receivedInterests[0].getName(), interest2->getName());
+  BOOST_CHECK_EQUAL(face1_receivedDatas    [0].getName(), data2->getName());
+  BOOST_CHECK_EQUAL(face2_receivedInterests[0].getName(), interest1->getName());
+  BOOST_CHECK_EQUAL(face2_receivedDatas    [0].getName(), data1->getName());
 }
 
 BOOST_FIXTURE_TEST_CASE(MultipleAccepts, EndToEndFixture)
@@ -434,6 +420,127 @@
 }
 
 
+
+
+class SimpleEndToEndFixture : protected BaseFixture
+{
+public:
+  void
+  onFaceCreated(const shared_ptr<Face>& face)
+  {
+    face->onReceiveInterest +=
+      bind(&SimpleEndToEndFixture::onReceiveInterest, this, _1);
+    face->onReceiveData +=
+      bind(&SimpleEndToEndFixture::onReceiveData, this, _1);
+    face->onFail +=
+      bind(&SimpleEndToEndFixture::onFail, this, face);
+
+    if (static_cast<bool>(dynamic_pointer_cast<LocalFace>(face))) {
+      static_pointer_cast<LocalFace>(face)->setLocalControlHeaderFeature(
+        LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID);
+
+      static_pointer_cast<LocalFace>(face)->setLocalControlHeaderFeature(
+        LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID);
+    }
+
+    limitedIo.afterOp();
+  }
+
+  void
+  onConnectFailed(const std::string& reason)
+  {
+    BOOST_CHECK_MESSAGE(false, reason);
+
+    limitedIo.afterOp();
+  }
+
+  void
+  onReceiveInterest(const Interest& interest)
+  {
+    receivedInterests.push_back(interest);
+
+    limitedIo.afterOp();
+  }
+
+  void
+  onReceiveData(const Data& data)
+  {
+    receivedDatas.push_back(data);
+
+    limitedIo.afterOp();
+  }
+
+  void
+  onFail(const shared_ptr<Face>& face)
+  {
+    limitedIo.afterOp();
+  }
+
+public:
+  LimitedIo limitedIo;
+
+  std::vector<Interest> receivedInterests;
+  std::vector<Data> receivedDatas;
+};
+
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(LocalFaceCorruptedInput, Dataset,
+                                 CorruptedPackets, SimpleEndToEndFixture)
+{
+  TcpFactory factory;
+
+  shared_ptr<TcpChannel> channel = factory.createChannel("127.0.0.1", "20070");
+  channel->listen(bind(&SimpleEndToEndFixture::onFaceCreated,   this, _1),
+                  bind(&SimpleEndToEndFixture::onConnectFailed, this, _1));
+  BOOST_REQUIRE_EQUAL(channel->isListening(), true);
+
+  DummyStreamSender<boost::asio::ip::tcp, Dataset> sender;
+  sender.start(Resolver<boost::asio::ip::tcp>::syncResolve("127.0.0.1", "20070"));
+
+  BOOST_CHECK_MESSAGE(limitedIo.run(LimitedIo::UNLIMITED_OPS,
+                                    time::seconds(1)) == LimitedIo::EXCEED_TIME,
+                      "Exception thrown for " + Dataset::getName());
+}
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(FaceCorruptedInput, Dataset,
+                                 CorruptedPackets, SimpleEndToEndFixture)
+{
+  // tests with non-local Face
+  std::string someIpv4Address;
+  std::list< shared_ptr<NetworkInterfaceInfo> > ifs = listNetworkInterfaces();
+  for (std::list< shared_ptr<NetworkInterfaceInfo> >::const_iterator i = ifs.begin();
+       i != ifs.end();
+       ++i)
+    {
+      if (!(*i)->isLoopback() && (*i)->isUp() && !(*i)->ipv4Addresses.empty())
+        {
+          someIpv4Address = (*i)->ipv4Addresses[0].to_string();
+          break;
+        }
+    }
+  if (someIpv4Address.empty())
+    {
+      BOOST_TEST_MESSAGE("Test with non-local Face cannot be run "
+                         "(no non-local interface with IPv4 address available)");
+      return;
+    }
+
+  TcpFactory factory;
+
+  shared_ptr<TcpChannel> channel = factory.createChannel(someIpv4Address, "20070");
+  channel->listen(bind(&SimpleEndToEndFixture::onFaceCreated,   this, _1),
+                  bind(&SimpleEndToEndFixture::onConnectFailed, this, _1));
+  BOOST_REQUIRE_EQUAL(channel->isListening(), true);
+
+
+  DummyStreamSender<boost::asio::ip::tcp, Dataset> sender;
+  sender.start(Resolver<boost::asio::ip::tcp>::syncResolve(someIpv4Address, "20070"));
+
+  BOOST_CHECK_MESSAGE(limitedIo.run(LimitedIo::UNLIMITED_OPS,
+                                    time::seconds(1)) == LimitedIo::EXCEED_TIME,
+                      "Exception thrown for " + Dataset::getName());
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace tests