tools: visualize RIB dataset in nfd-status

refs #1749

Change-Id: Ia11b88187635ffa4eda4b829afd6a20120765d58
diff --git a/tools/nfd-status.cpp b/tools/nfd-status.cpp
index d06e8fb..affd2d8 100644
--- a/tools/nfd-status.cpp
+++ b/tools/nfd-status.cpp
@@ -36,6 +36,7 @@
 #include <ndn-cxx/management/nfd-channel-status.hpp>
 #include <ndn-cxx/management/nfd-face-status.hpp>
 #include <ndn-cxx/management/nfd-fib-entry.hpp>
+#include <ndn-cxx/management/nfd-rib-entry.hpp>
 #include <ndn-cxx/management/nfd-strategy-choice.hpp>
 
 #include <boost/algorithm/string/replace.hpp>
@@ -53,6 +54,7 @@
     , m_needChannelStatusRetrieval(false)
     , m_needFaceStatusRetrieval(false)
     , m_needFibEnumerationRetrieval(false)
+    , m_needRibStatusRetrieval(false)
     , m_needStrategyChoiceRetrieval(false)
     , m_isOutputXml(false)
   {
@@ -69,6 +71,7 @@
       "  [-c] - retrieve channel status information\n"
       "  [-f] - retrieve face status information\n"
       "  [-b] - retrieve FIB information\n"
+      "  [-r] - retrieve RIB information\n"
       "  [-s] - retrieve configured strategy choice for NDN namespaces\n"
       "  [-x] - output NFD status information in XML format\n"
       "\n"
@@ -110,6 +113,12 @@
   }
 
   void
+  enableRibStatusRetrieval()
+  {
+    m_needRibStatusRetrieval = true;
+  }
+
+  void
   enableXmlOutput()
   {
     m_isOutputXml = true;
@@ -381,13 +390,13 @@
             std::cout << "<incomingPackets>";
             std::cout << "<nInterests>"       << faceStatus.getNInInterests()
                       << "</nInterests>";
-            std::cout << "<nDatas>"           << faceStatus.getNInInterests()
+            std::cout << "<nDatas>"           << faceStatus.getNInDatas()
                       << "</nDatas>";
             std::cout << "</incomingPackets>";
             std::cout << "<outgoingPackets>";
             std::cout << "<nInterests>"       << faceStatus.getNOutInterests()
                       << "</nInterests>";
-            std::cout << "<nDatas>"           << faceStatus.getNOutInterests()
+            std::cout << "<nDatas>"           << faceStatus.getNOutDatas()
                       << "</nDatas>";
             std::cout << "</outgoingPackets>";
             std::cout << "</packetCounters>";
@@ -629,6 +638,118 @@
   }
 
   void
+  fetchRibStatusInformation()
+  {
+    m_buffer = make_shared<OBufferStream>();
+
+    Interest interest("/localhost/nfd/rib/list");
+    interest.setChildSelector(1);
+    interest.setMustBeFresh(true);
+
+    m_face.expressInterest(interest,
+                           bind(&NfdStatus::fetchSegments, this, _2,
+                                &NfdStatus::afterFetchedRibStatusInformation),
+                           bind(&NfdStatus::onTimeout, this));
+  }
+
+  void
+  afterFetchedRibStatusInformation()
+  {
+    ConstBufferPtr buf = m_buffer->buf();
+    if (m_isOutputXml)
+      {
+        std::cout << "<rib>";
+
+        Block block;
+        size_t offset = 0;
+        while (offset < buf->size())
+          {
+            bool ok = Block::fromBuffer(buf, offset, block);
+            if (!ok)
+              {
+                std::cerr << "ERROR: cannot decode RibEntry TLV";
+                break;
+              }
+            offset += block.size();
+
+            nfd::RibEntry ribEntry(block);
+
+            std::cout << "<ribEntry>";
+            std::string prefix(ribEntry.getName().toUri());
+            escapeSpecialCharacters(&prefix);
+            std::cout << "<prefix>" << prefix << "</prefix>";
+            std::cout << "<routes>";
+            for (std::list<nfd::Route>::const_iterator
+                   nextRoute = ribEntry.begin();
+                 nextRoute != ribEntry.end();
+                 ++nextRoute)
+              {
+                std::cout << "<route>" ;
+                std::cout << "<faceId>"  << nextRoute->getFaceId() << "</faceId>";
+                std::cout << "<origin>"  << nextRoute->getOrigin() << "</origin>";
+                std::cout << "<cost>"    << nextRoute->getCost()   << "</cost>";
+                std::cout << "<flags>"   << nextRoute->getFlags()  << "</flags>";
+                if (!nextRoute->hasInfiniteExpirationPeriod()) {
+                  std::cout << "<expirationPeriod>PT"
+                            << time::duration_cast<time::seconds>(nextRoute->getExpirationPeriod())
+                                 .count() << "S"
+                            << "</expirationPeriod>";
+                }
+                std::cout << "</route>";
+              }
+            std::cout << "</routes>";
+            std::cout << "</ribEntry>";
+          }
+
+        std::cout << "</rib>";
+      }
+    else
+      {
+        std::cout << "Rib:" << std::endl;
+
+        Block block;
+        size_t offset = 0;
+        while (offset < buf->size())
+          {
+            bool ok = Block::fromBuffer(buf, offset, block);
+            if (!ok)
+              {
+                std::cerr << "ERROR: cannot decode RibEntry TLV" << std::endl;
+                break;
+              }
+
+            offset += block.size();
+
+            nfd::RibEntry ribEntry(block);
+
+            std::cout << " " << ribEntry.getName().toUri() << " route={";
+            for (std::list<nfd::Route>::const_iterator
+                   nextRoute = ribEntry.begin();
+                 nextRoute != ribEntry.end();
+                 ++nextRoute)
+              {
+                if (nextRoute != ribEntry.begin())
+                  std::cout << ", ";
+                std::cout << "faceid="   << nextRoute->getFaceId()
+                          << " (origin="  << nextRoute->getOrigin()
+                          << " cost="    << nextRoute->getCost()
+                          << " flags="   << nextRoute->getFlags();
+                if (!nextRoute->hasInfiniteExpirationPeriod()) {
+                  std::cout << " expires="
+                            << time::duration_cast<time::seconds>(nextRoute->getExpirationPeriod())
+                               .count() << "s";
+                }
+                std::cout << ")";
+              }
+            std::cout << "}" << std::endl;
+          }
+       }
+
+    runNextStep();
+  }
+
+
+  void
   fetchInformation()
   {
     if (m_isOutputXml ||
@@ -636,12 +757,14 @@
          !m_needChannelStatusRetrieval &&
          !m_needFaceStatusRetrieval &&
          !m_needFibEnumerationRetrieval &&
+         !m_needRibStatusRetrieval &&
          !m_needStrategyChoiceRetrieval))
       {
         enableVersionRetrieval();
         enableChannelStatusRetrieval();
         enableFaceStatusRetrieval();
         enableFibEnumerationRetrieval();
+        enableRibStatusRetrieval();
         enableStrategyChoiceRetrieval();
       }
 
@@ -660,6 +783,9 @@
     if (m_needFibEnumerationRetrieval)
       m_fetchSteps.push_back(bind(&NfdStatus::fetchFibEnumerationInformation, this));
 
+    if (m_needRibStatusRetrieval)
+      m_fetchSteps.push_back(bind(&NfdStatus::fetchRibStatusInformation, this));
+
     if (m_needStrategyChoiceRetrieval)
       m_fetchSteps.push_back(bind(&NfdStatus::fetchStrategyChoiceInformation, this));
 
@@ -705,6 +831,7 @@
   bool m_needChannelStatusRetrieval;
   bool m_needFaceStatusRetrieval;
   bool m_needFibEnumerationRetrieval;
+  bool m_needRibStatusRetrieval;
   bool m_needStrategyChoiceRetrieval;
   bool m_isOutputXml;
   Face m_face;
@@ -721,7 +848,7 @@
   int option;
   ndn::NfdStatus nfdStatus(argv[0]);
 
-  while ((option = getopt(argc, argv, "hvcfbsxV")) != -1) {
+  while ((option = getopt(argc, argv, "hvcfbrsxV")) != -1) {
     switch (option) {
     case 'h':
       nfdStatus.usage();
@@ -738,6 +865,9 @@
     case 'b':
       nfdStatus.enableFibEnumerationRetrieval();
       break;
+    case 'r':
+      nfdStatus.enableRibStatusRetrieval();
+      break;
     case 's':
       nfdStatus.enableStrategyChoiceRetrieval();
       break;