tools/nfd-status: plain text status command

Change-Id: Id0f5eebd7d811ee8f4f76eb867687f78c445ad97
Refs: #1328
diff --git a/tools/nfd-status.cpp b/tools/nfd-status.cpp
new file mode 100644
index 0000000..2c27c9a
--- /dev/null
+++ b/tools/nfd-status.cpp
@@ -0,0 +1,319 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2014 University of Arizona.
+ *
+ * Author: Jerald Paul Abraham <jeraldabraham@email.arizona.edu>
+ */
+
+#include <ndn-cpp-dev/face.hpp>
+#include <ndn-cpp-dev/name.hpp>
+#include <ndn-cpp-dev/interest.hpp>
+
+#include <ndn-cpp-dev/management/nfd-fib-entry.hpp>
+#include <ndn-cpp-dev/management/nfd-face-status.hpp>
+#include <ndn-cpp-dev/management/nfd-status.hpp>
+
+namespace ndn {
+
+class NfdStatus
+{
+public:
+  NfdStatus(char* toolName)
+    : m_toolName(toolName)
+    , m_needVersionRetrieval(false)
+    , m_needFaceStatusRetrieval(false)
+    , m_needFibEnumerationRetrieval(false)
+    , m_face()
+  {
+  }
+
+  void
+  usage()
+  {
+    std::cout << "\nUsage: " << m_toolName << " [options]\n"
+      "Shows NFD Status Information\n"
+      "Displays Version Information (NFD Version, Start Timestamp, Current Timestamp).\n"
+      "Face Status Information via NFD Face Status Protocol (FaceID, URI, Counters).\n"
+      "FIB Information via NFD FIB Enumeration Protocol (Prefix, Nexthop).\n"
+      "If no options are provided, all information is retrieved.\n"
+      "  [-v] - retrieve version information\n"
+      "  [-f] - retrieve face status information\n"
+      "  [-b] - retrieve FIB information\n"
+      "  [-h] - print help and exit\n\n";
+  }
+
+  void
+  enableVersionRetrieval()
+  {
+    m_needVersionRetrieval = true;
+  }
+
+  void
+  enableFaceStatusRetrieval()
+  {
+    m_needFaceStatusRetrieval = true;
+  }
+
+  void
+  enableFibEnumerationRetrieval()
+  {
+    m_needFibEnumerationRetrieval = true;
+  }
+
+  void
+  onTimeout()
+  {
+    std::cerr << "Request timed out" << std::endl;
+  }
+
+  void
+  fetchSegments(const Data& data, void (NfdStatus::*onDone)())
+  {
+    m_buffer->write((const char*)data.getContent().value(),
+                    data.getContent().value_size());
+
+    uint64_t currentSegment = data.getName().get(-1).toSegment();
+
+    const name::Component& finalBlockId = data.getMetaInfo().getFinalBlockId();
+    if (finalBlockId.empty() ||
+        finalBlockId.toSegment() > currentSegment)
+      {
+        m_face.expressInterest(data.getName().getPrefix(-1).appendSegment(currentSegment+1),
+                               bind(&NfdStatus::fetchSegments, this, _2, onDone),
+                               bind(&NfdStatus::onTimeout, this));
+      }
+    else
+      {
+        return (this->*onDone)();
+      }
+  }
+
+  void
+  afterFetchedVersionInformation(const Data& data)
+  {
+    std::cout << "General NFD status:" << std::endl;
+
+    nfd::Status status(data.getContent());
+    std::cout << "               version="
+              << status.getNfdVersion() << std::endl;
+    std::cout << "             startTime="
+              << time::toIsoString(status.getStartTimestamp()) << std::endl;
+    std::cout << "           currentTime="
+              << time::toIsoString(status.getCurrentTimestamp()) << std::endl;
+    std::cout << "                uptime="
+              << time::duration_cast<time::seconds>(status.getCurrentTimestamp()
+                                                    - status.getStartTimestamp()) << std::endl;
+
+    std::cout << "      nNameTreeEntries=" << status.getNNameTreeEntries()     << std::endl;
+    std::cout << "           nFibEntries=" << status.getNFibEntries()          << std::endl;
+    std::cout << "           nPitEntries=" << status.getNPitEntries()          << std::endl;
+    std::cout << "  nMeasurementsEntries=" << status.getNMeasurementsEntries() << std::endl;
+    std::cout << "            nCsEntries=" << status.getNCsEntries()           << std::endl;
+    std::cout << "          nInInterests=" << status.getNInInterests()         << std::endl;
+    std::cout << "         nOutInterests=" << status.getNOutInterests()        << std::endl;
+    std::cout << "              nInDatas=" << status.getNInDatas()             << std::endl;
+    std::cout << "             nOutDatas=" << status.getNOutDatas()            << std::endl;
+
+    if (m_needFaceStatusRetrieval)
+      {
+        fetchFaceStatusInformation();
+      }
+    else if (m_needFibEnumerationRetrieval)
+      {
+        fetchFibEnumerationInformation();
+      }
+  }
+
+  void
+  fetchVersionInformation()
+  {
+    Interest interest("/localhost/nfd/status");
+    interest.setChildSelector(1);
+    interest.setMustBeFresh(true);
+    m_face.expressInterest(
+                           interest,
+                           bind(&NfdStatus::afterFetchedVersionInformation, this, _2),
+                           bind(&NfdStatus::onTimeout, this));
+  }
+
+  void
+  afterFetchedFaceStatusInformation()
+  {
+    try
+      {
+        std::cout << "Faces:" << std::endl;
+
+        ConstBufferPtr buf = m_buffer->buf();
+
+        size_t offset = 0;
+        while (offset < buf->size())
+          {
+            Block block(buf, buf->begin() + offset, buf->end(), false);
+            offset += block.size();
+
+            nfd::FaceStatus faceStatus(block);
+
+            std::cout << "  faceid=" << faceStatus.getFaceId()
+                      << " uri=" << faceStatus.getUri()
+                      << " counters={"
+                      << "in={" << faceStatus.getInInterest() << "i "
+                                << faceStatus.getInData() << "d}"
+                      << " out={" << faceStatus.getOutInterest() << "i "
+                                 << faceStatus.getOutData() << "d}"
+                      << "}" << std::endl;
+          }
+
+      }
+    catch(Tlv::Error& e)
+      {
+        std::cerr << e.what() << std::endl;
+      }
+
+    if (m_needFibEnumerationRetrieval)
+      {
+        fetchFibEnumerationInformation();
+      }
+  }
+
+  void
+  fetchFaceStatusInformation()
+  {
+    m_buffer = make_shared<OBufferStream>();
+
+    Interest interest("/localhost/nfd/faces/list");
+    interest.setChildSelector(1);
+    interest.setMustBeFresh(true);
+
+    m_face.expressInterest(interest,
+                           bind(&NfdStatus::fetchSegments, this, _2,
+                                &NfdStatus::afterFetchedFaceStatusInformation),
+                           bind(&NfdStatus::onTimeout, this));
+  }
+
+  void
+  afterFetchedFibEnumerationInformation()
+  {
+    try
+      {
+        std::cout << "FIB:" << std::endl;
+
+        ConstBufferPtr buf = m_buffer->buf();
+
+        size_t offset = 0;
+        while (offset < buf->size())
+          {
+            Block block(buf, buf->begin() + offset, buf->end(), false);
+            offset += block.size();
+
+            nfd::FibEntry fibEntry(block);
+
+            std::cout << "  " << fibEntry.getPrefix() << " nexthops={";
+            for (std::list<nfd::NextHopRecord>::const_iterator
+                   nextHop = fibEntry.getNextHopRecords().begin();
+                 nextHop != fibEntry.getNextHopRecords().end();
+                 ++nextHop)
+              {
+                if (nextHop != fibEntry.getNextHopRecords().begin())
+                  std::cout << ", ";
+                std::cout << "faceid=" << nextHop->getFaceId()
+                          << " (cost=" << nextHop->getCost() << ")";
+              }
+            std::cout << "}" << std::endl;
+          }
+      }
+    catch(Tlv::Error& e)
+      {
+        std::cerr << e.what() << std::endl;
+      }
+  }
+
+  void
+  fetchFibEnumerationInformation()
+  {
+    m_buffer = make_shared<OBufferStream>();
+
+    Interest interest("/localhost/nfd/fib/list");
+    interest.setChildSelector(1);
+    interest.setMustBeFresh(true);
+    m_face.expressInterest(interest,
+                           bind(&NfdStatus::fetchSegments, this, _2,
+                                &NfdStatus::afterFetchedFibEnumerationInformation),
+                           bind(&NfdStatus::onTimeout, this));
+  }
+
+  void
+  fetchInformation()
+  {
+    if (!m_needVersionRetrieval &&
+        !m_needFaceStatusRetrieval &&
+        !m_needFibEnumerationRetrieval)
+      {
+        enableVersionRetrieval();
+        enableFaceStatusRetrieval();
+        enableFibEnumerationRetrieval();
+      }
+
+    if (m_needVersionRetrieval)
+      {
+        fetchVersionInformation();
+      }
+    else if (m_needFaceStatusRetrieval)
+      {
+        fetchFaceStatusInformation();
+      }
+    else if (m_needFibEnumerationRetrieval)
+      {
+        fetchFibEnumerationInformation();
+      }
+
+    m_face.processEvents();
+  }
+
+private:
+  std::string m_toolName;
+  bool m_needVersionRetrieval;
+  bool m_needFaceStatusRetrieval;
+  bool m_needFibEnumerationRetrieval;
+  Face m_face;
+
+  shared_ptr<OBufferStream> m_buffer;
+};
+
+}
+
+int main( int argc, char* argv[] )
+{
+  int option;
+  ndn::NfdStatus nfdStatus (argv[0]);
+
+  while ((option = getopt(argc, argv, "hvfb")) != -1) {
+    switch (option) {
+    case 'h':
+      nfdStatus.usage();
+      break;
+    case 'v':
+      nfdStatus.enableVersionRetrieval();
+      break;
+    case 'f':
+      nfdStatus.enableFaceStatusRetrieval();
+      break;
+    case 'b':
+      nfdStatus.enableFibEnumerationRetrieval();
+      break;
+    default :
+      nfdStatus.usage();
+      return 1;
+      break;
+    }
+  }
+
+  try {
+    nfdStatus.fetchInformation();
+  }
+  catch(std::exception& e) {
+    std::cerr << "ERROR: " << e.what() << std::endl;
+    return 2;
+  }
+
+  return 0;
+}