dump: Capture and print network NACK packets

refs: #3463

Change-Id: I3aed0d3668378305404f9713cc110e13eec434e5
diff --git a/tools/dump/ndndump.cpp b/tools/dump/ndndump.cpp
index cf8f839..e964c58 100644
--- a/tools/dump/ndndump.cpp
+++ b/tools/dump/ndndump.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Regents of the University of California.
+ * Copyright (c) 2014-2016,  Regents of the University of California.
  *
  * This file is part of ndn-tools (Named Data Networking Essential Tools).
  * See AUTHORS.md for complete list of ndn-tools authors and contributors.
@@ -47,8 +47,8 @@
 #include "tcpdump/udp.h"
 #include "tcpdump/tcp.h"
 
-} // namespace ndn
 } // namespace dump
+} // namespace ndn
 
 #include <boost/lexical_cast.hpp>
 
@@ -56,12 +56,12 @@
 
 #include <ndn-cxx/interest.hpp>
 #include <ndn-cxx/data.hpp>
+#include <ndn-cxx/lp/nack.hpp>
+#include <ndn-cxx/lp/packet.hpp>
 
 namespace ndn {
 namespace dump {
 
-// const uint8_t NDNLP_HEADER[] = {'N', 'd', 'n', 'l', 'p'};
-
 const size_t MAX_SNAPLEN = 65535;
 
 void
@@ -139,7 +139,7 @@
 
 
 void
-Ndndump::onCapturedPacket(const struct pcap_pkthdr* header, const uint8_t* packet)
+Ndndump::onCapturedPacket(const pcap_pkthdr* header, const uint8_t* packet)
 {
   std::ostringstream os;
   printInterceptTime(os, header);
@@ -162,25 +162,66 @@
   Block block;
   std::tie(isOk, block) = Block::fromBuffer(payload, payloadSize);
   if (!isOk) {
-    // if packet is fragmented, we will not be able to process it
+    // if packet is incomplete, we will not be able to process it
+    if (payloadSize > 0) {
+      std::cout << os.str() << ", " << "INCOMPLETE-PACKET" << ", size: " << payloadSize << std::endl;
+    }
     return;
   }
 
-  /// \todo Detect various header (LocalControlHeader, NDNLP, etc.)
+  lp::Packet lpPacket;
+  Block netPacket;
+
+  if (block.type() == lp::tlv::LpPacket) {
+    lpPacket = lp::Packet(block);
+
+    Buffer::const_iterator begin, end;
+
+    if (lpPacket.has<lp::FragmentField>()) {
+      std::tie(begin, end) = lpPacket.get<lp::FragmentField>();
+    }
+    else {
+      std::cout << os.str() << ", " << "NDNLPv2-IDLE" << std::endl;
+      return;
+    }
+
+    bool isOk = false;
+    std::tie(isOk, netPacket) = Block::fromBuffer(&*begin, std::distance(begin, end));
+    if (!isOk) {
+      // if network packet is fragmented, we will not be able to process it
+      std::cout << os.str() << ", " << "NDNLPv2-FRAGMENT" << std::endl;
+      return;
+    }
+  }
+  else {
+    netPacket = block;
+  }
 
   try {
-    if (block.type() == tlv::Interest) {
-      Interest interest(block);
+    if (netPacket.type() == tlv::Interest) {
+      Interest interest(netPacket);
       if (matchesFilter(interest.getName())) {
-        std::cout << os.str() << ", " << "INTEREST: " << interest << std::endl;
+
+        if (lpPacket.has<lp::NackField>()) {
+          lp::Nack nack(interest);
+          nack.setHeader(lpPacket.get<lp::NackField>());
+
+          std::cout << os.str() << ", " << "NACK: " << nack.getReason() << ", " << interest << std::endl;
+        }
+        else {
+          std::cout << os.str() << ", " << "INTEREST: " << interest << std::endl;
+        }
       }
     }
-    else if (block.type() == tlv::Data) {
-      Data data(block);
+    else if (netPacket.type() == tlv::Data) {
+      Data data(netPacket);
       if (matchesFilter(data.getName())) {
         std::cout << os.str() << ", " << "DATA: " << data.getName() << std::endl;
       }
     }
+    else {
+      std::cout << os.str() << ", " << "UNKNOWN-NETWORK-PACKET" << std::endl;
+    }
   }
   catch (tlv::Error& e) {
     std::cerr << e.what() << std::endl;
@@ -188,7 +229,7 @@
 }
 
 void
-Ndndump::printInterceptTime(std::ostream& os, const struct pcap_pkthdr* header)
+Ndndump::printInterceptTime(std::ostream& os, const pcap_pkthdr* header)
 {
   os << header->ts.tv_sec
      << "."
diff --git a/tools/dump/ndndump.hpp b/tools/dump/ndndump.hpp
index b46c109..594406d 100644
--- a/tools/dump/ndndump.hpp
+++ b/tools/dump/ndndump.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Regents of the University of California.
+ * Copyright (c) 2014-2016,  Regents of the University of California.
  *
  * This file is part of ndn-tools (Named Data Networking Essential Tools).
  * See AUTHORS.md for complete list of ndn-tools authors and contributors.
@@ -37,6 +37,8 @@
 #ifndef NDN_TOOLS_DUMP_NDNDUMP_HPP
 #define NDN_TOOLS_DUMP_NDNDUMP_HPP
 
+#include "core/common.hpp"
+
 #include <pcap.h>
 
 #include <ndn-cxx/name.hpp>
@@ -72,18 +74,19 @@
   void
   run();
 
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+  void
+  onCapturedPacket(const pcap_pkthdr* header, const uint8_t* packet);
+
 private:
   static void
-  onCapturedPacket(uint8_t* userData, const struct pcap_pkthdr* header, const uint8_t* packet)
+  onCapturedPacket(uint8_t* userData, const pcap_pkthdr* header, const uint8_t* packet)
   {
     reinterpret_cast<Ndndump*>(userData)->onCapturedPacket(header, packet);
   }
 
   void
-  onCapturedPacket(const struct pcap_pkthdr* header, const uint8_t* packet);
-
-  void
-  printInterceptTime(std::ostream& os, const struct pcap_pkthdr* header);
+  printInterceptTime(std::ostream& os, const pcap_pkthdr* header);
 
   int
   skipDataLinkHeaderAndGetFrameType(const uint8_t*& payload, ssize_t& payloadSize);
@@ -120,6 +123,8 @@
 
 private:
   pcap_t* m_pcap;
+
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   int m_dataLinkType;
 };