Merge branch 'import-dissect' into master
refs #2931
Change-Id: Iecf80a6672e5c89dc80bf15ed58ec170c886b724
diff --git a/manpages/conf.py b/manpages/conf.py
index 1476da8..3c0f6bb 100644
--- a/manpages/conf.py
+++ b/manpages/conf.py
@@ -11,4 +11,5 @@
('ndnping', 'ndnping', 'reachability testing client', None, 1),
('ndnpingserver', 'ndnpingserver', 'reachability testing server', None, 1),
('ndndump', 'ndndump', 'traffic analysis tool', None, 8),
+ ('ndn-dissect', 'ndn-dissect', 'NDN packet format inspector', None, 1),
]
diff --git a/manpages/ndn-dissect.rst b/manpages/ndn-dissect.rst
new file mode 100644
index 0000000..be92682
--- /dev/null
+++ b/manpages/ndn-dissect.rst
@@ -0,0 +1,38 @@
+ndn-dissect
+===========
+
+Usage
+-----
+
+::
+
+ ndn-dissect [-hV] [input-file]
+
+Description
+-----------
+
+``ndn-dissect`` is an NDN packet format inspector.
+It reads zero or more NDN packets from either an input file or the standard input,
+and displays the Type-Length-Value (TLV) structure of those packets on the standard output.
+
+Options
+-------
+
+``-h``
+ Print help and exit.
+
+``-V``
+ Print version and exit.
+
+``input-file``
+ The file to read packets from.
+ If no :option:`input-file` is given, the standard input is used.
+
+Examples
+--------
+
+Inspect the response to Interest ``ndn:/app1/video``
+
+::
+
+ ndnpeek ndn:/app1/video | ndn-dissect
diff --git a/tools/dissect/README.md b/tools/dissect/README.md
new file mode 100644
index 0000000..b0da01a
--- /dev/null
+++ b/tools/dissect/README.md
@@ -0,0 +1,13 @@
+# ndn-dissect
+
+**ndn-dissect** is an NDN packet format inspector.
+It reads zero or more NDN packets from either an input file or the standard input,
+and displays the Type-Length-Value (TLV) structure of those packets on the standard output.
+
+Usage example:
+
+1. start NFD on local machine
+2. execute `echo 'HELLO WORLD' | ndnpoke ndn:/localhost/demo/hello`
+3. on another console, execute `ndnpeek ndn:/localhost/demo/hello | ndn-dissect`
+
+For more information, consult the manpage.
diff --git a/tools/dissect/main.cpp b/tools/dissect/main.cpp
new file mode 100644
index 0000000..fa1a962
--- /dev/null
+++ b/tools/dissect/main.cpp
@@ -0,0 +1,114 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015, 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.
+ *
+ * ndn-tools is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-tools 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
+ * ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ndn-dissect.hpp"
+#include "core/version.hpp"
+
+#include <boost/program_options/options_description.hpp>
+#include <boost/program_options/variables_map.hpp>
+#include <boost/program_options/parsers.hpp>
+
+namespace po = boost::program_options;
+
+namespace ndn {
+namespace dissect {
+
+void
+usage(std::ostream& os, const std::string& appName, const po::options_description& options)
+{
+ os << "Usage:\n"
+ << " " << appName << " [input-file] \n"
+ << "\n"
+ << options;
+}
+
+int
+main(int argc, char* argv[])
+{
+ po::options_description visibleOptions;
+ visibleOptions.add_options()
+ ("help,h", "Print help and exit.")
+ ("version,V", "Print version and exit.")
+ ;
+
+ std::string inputFileName;
+ po::options_description hiddenOptions;
+ hiddenOptions.add_options()
+ ("input-file", po::value<std::string>(&inputFileName));
+ ;
+ po::positional_options_description positionalArguments;
+ positionalArguments
+ .add("input-file", -1);
+
+ po::options_description allOptions;
+ allOptions
+ .add(visibleOptions)
+ .add(hiddenOptions)
+ ;
+
+ po::variables_map vm;
+ try {
+ po::store(po::command_line_parser(argc, argv)
+ .options(allOptions)
+ .positional(positionalArguments)
+ .run(),
+ vm);
+ po::notify(vm);
+ }
+ catch (po::error& e) {
+ std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
+ usage(std::cerr, argv[0], visibleOptions);
+ return 2;
+ }
+
+ if (vm.count("help") > 0) {
+ usage(std::cout, argv[0], visibleOptions);
+ return 0;
+ }
+
+ if (vm.count("version") > 0) {
+ std::cout << "ndn-dissect " << tools::VERSION << std::endl;
+ return 0;
+ }
+
+ std::ifstream inputFile;
+ std::istream* inputStream;
+
+ if (vm.count("input-file") > 0 && inputFileName != "-") {
+ inputFile.open(inputFileName);
+ inputStream = &inputFile;
+ }
+ else {
+ inputStream = &std::cin;
+ }
+
+ NdnDissect program;
+ program.dissect(std::cout, *inputStream);
+
+ return 0;
+}
+
+} // namespace dissect
+} // namespace ndn
+
+int
+main(int argc, char** argv)
+{
+ return ndn::dissect::main(argc, argv);
+}
diff --git a/tools/dissect/ndn-dissect.cpp b/tools/dissect/ndn-dissect.cpp
new file mode 100644
index 0000000..f37195e
--- /dev/null
+++ b/tools/dissect/ndn-dissect.cpp
@@ -0,0 +1,148 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015, 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.
+ *
+ * ndn-tools is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-tools 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
+ * ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ * Copyright (c) 2013-2014 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
+ */
+
+#include "ndn-dissect.hpp"
+
+#include <algorithm>
+#include <map>
+
+#include <ndn-cxx/name-component.hpp>
+#include <ndn-cxx/util/indented-stream.hpp>
+
+namespace ndn {
+namespace dissect {
+
+std::map<uint32_t, std::string> TLV_DICT = {
+ {tlv::Interest , "Interest"},
+ {tlv::Data , "Data"},
+ {tlv::Name , "Name"},
+ {tlv::NameComponent , "NameComponent"},
+ {tlv::ImplicitSha256DigestComponent, "ImplicitSha256DigestComponent"},
+ {tlv::Selectors , "Selectors"},
+ {tlv::Nonce , "Nonce"},
+ {tlv::InterestLifetime , "InterestLifetime"},
+ {tlv::MinSuffixComponents , "MinSuffixComponents"},
+ {tlv::MaxSuffixComponents , "MaxSuffixComponents"},
+ {tlv::PublisherPublicKeyLocator , "PublisherPublicKeyLocator"},
+ {tlv::Exclude , "Exclude"},
+ {tlv::ChildSelector , "ChildSelector"},
+ {tlv::MustBeFresh , "MustBeFresh"},
+ {tlv::Any , "Any"},
+ {tlv::MetaInfo , "MetaInfo"},
+ {tlv::Content , "Content"},
+ {tlv::SignatureInfo , "SignatureInfo"},
+ {tlv::SignatureValue , "SignatureValue"},
+ {tlv::ContentType , "ContentType"},
+ {tlv::FreshnessPeriod , "FreshnessPeriod"},
+ {tlv::FinalBlockId , "FinalBlockId"},
+ {tlv::SignatureType , "SignatureType"},
+ {tlv::KeyLocator , "KeyLocator"},
+ {tlv::KeyDigest , "KeyDigest"},
+};
+
+void
+NdnDissect::printType(std::ostream& os, uint32_t type)
+{
+ os << type << " (";
+
+ if (TLV_DICT.count(type) != 0) {
+ os << TLV_DICT[type];
+ }
+ else if (type < tlv::AppPrivateBlock1) {
+ os << "RESERVED_1";
+ }
+ else if (tlv::AppPrivateBlock1 <= type && type < 253) {
+ os << "APP_TAG_1";
+ }
+ else if (253 <= type && type < tlv::AppPrivateBlock2) {
+ os << "RESERVED_3";
+ }
+ else {
+ os << "APP_TAG_3";
+ }
+ os << ")";
+}
+
+void
+NdnDissect::printBlock(std::ostream& os, const Block& block)
+{
+ this->printType(os, block.type());
+ os << " (size: " << block.value_size() << ")";
+
+ try {
+ // if (block.type() != tlv::Content && block.type() != tlv::SignatureValue)
+ block.parse();
+ }
+ catch (tlv::Error& e) {
+ // pass (e.g., leaf block reached)
+
+ // @todo: Figure how to deterministically figure out that value is not recursive TLV block
+ }
+
+ if (block.elements().empty()) {
+ os << " [[";
+ name::Component(block.value(), block.value_size()).toUri(os);
+ os<< "]]";
+ }
+ os << std::endl;
+
+ util::IndentedStream os2(os, " ");
+ std::for_each(block.elements_begin(), block.elements_end(),
+ [this, &os2] (const Block& element) {
+ this->printBlock(os2, element);
+ });
+}
+
+void
+NdnDissect::dissect(std::ostream& os, std::istream& is)
+{
+ while (is.peek() != std::char_traits<char>::eof()) {
+ try {
+ Block block = Block::fromStream(is);
+ this->printBlock(os, block);
+ }
+ catch (std::exception& e) {
+ std::cerr << "ERROR: " << e.what() << std::endl;
+ }
+ }
+}
+
+} // namespace dissect
+} // namespace ndn
diff --git a/tools/dissect/ndn-dissect.hpp b/tools/dissect/ndn-dissect.hpp
new file mode 100644
index 0000000..a90b845
--- /dev/null
+++ b/tools/dissect/ndn-dissect.hpp
@@ -0,0 +1,41 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015, 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.
+ *
+ * ndn-tools is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-tools 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
+ * ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ndn-cxx/encoding/block.hpp>
+#include <fstream>
+
+namespace ndn {
+namespace dissect {
+
+class NdnDissect : noncopyable
+{
+public:
+ void
+ dissect(std::ostream& os, std::istream& is);
+
+private:
+ void
+ printType(std::ostream& os, uint32_t type);
+
+ void
+ printBlock(std::ostream& os, const Block& block);
+};
+
+} // namespace dissect
+} // namespace ndn
diff --git a/tools/dissect/wscript b/tools/dissect/wscript
new file mode 100644
index 0000000..070ece2
--- /dev/null
+++ b/tools/dissect/wscript
@@ -0,0 +1,17 @@
+# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+top = '../..'
+
+def build(bld):
+ bld(features='cxx',
+ name='dissect-objects',
+ source=bld.path.ant_glob('*.cpp', excl='main.cpp'),
+ includes='.',
+ export_includes='.',
+ use='core-objects',
+ )
+
+ bld(features='cxx cxxprogram',
+ target='../../bin/ndn-dissect',
+ source='main.cpp',
+ use='dissect-objects',
+ )