/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
* Washington University in St. Louis,
* Beijing Institute of Technology,
* The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
*
* NFD 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.
*
* NFD 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
* NFD, e.g., in COPYING.md file. If not, see .
*
* @author Jerald Paul Abraham
*/
#include "version.hpp"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace ndn {
using util::SegmentFetcher;
class NfdStatus
{
public:
explicit
NfdStatus(char* toolName)
: m_toolName(toolName)
, m_needVersionRetrieval(false)
, m_needChannelStatusRetrieval(false)
, m_needFaceStatusRetrieval(false)
, m_needFibEnumerationRetrieval(false)
, m_needRibStatusRetrieval(false)
, m_needStrategyChoiceRetrieval(false)
, m_isOutputXml(false)
{
}
void
usage()
{
std::cout << "Usage: \n " << m_toolName << " [options]\n\n"
"Show NFD version and status information\n\n"
"Options:\n"
" [-h] - print this help message\n"
" [-v] - retrieve version information\n"
" [-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"
" [-V] - show version information of nfd-status and exit\n"
"\n"
"If no options are provided, all information is retrieved.\n"
"If -x is provided, other options(-v, -c, etc.) are ignored, and all information is printed in XML format.\n"
;
}
void
enableVersionRetrieval()
{
m_needVersionRetrieval = true;
}
void
enableChannelStatusRetrieval()
{
m_needChannelStatusRetrieval = true;
}
void
enableFaceStatusRetrieval()
{
m_needFaceStatusRetrieval = true;
}
void
enableFibEnumerationRetrieval()
{
m_needFibEnumerationRetrieval = true;
}
void
enableStrategyChoiceRetrieval()
{
m_needStrategyChoiceRetrieval = true;
}
void
enableRibStatusRetrieval()
{
m_needRibStatusRetrieval = true;
}
void
enableXmlOutput()
{
m_isOutputXml = true;
}
void
onTimeout()
{
std::cerr << "Request timed out" << std::endl;
runNextStep();
}
void
onErrorFetch(uint32_t errorCode, const std::string& errorMsg)
{
std::cerr << "Error code:" << errorCode << ", message:" << errorMsg << std::endl;
runNextStep();
}
void
escapeSpecialCharacters(std::string *data)
{
using boost::algorithm::replace_all;
replace_all(*data, "&", "&");
replace_all(*data, "\"", """);
replace_all(*data, "\'", "'");
replace_all(*data, "<", "<");
replace_all(*data, ">", ">");
}
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
void
fetchVersionInformation()
{
Interest interest("/localhost/nfd/status/general");
interest.setChildSelector(1);
interest.setMustBeFresh(true);
m_face.expressInterest(
interest,
bind(&NfdStatus::afterFetchedVersionInformation, this, _2),
bind(&NfdStatus::onTimeout, this));
}
void
afterFetchedVersionInformation(const Data& data)
{
nfd::ForwarderStatus status(data.getContent());
std::string nfdId;
if (data.getSignature().hasKeyLocator())
{
const ndn::KeyLocator& locator = data.getSignature().getKeyLocator();
if (locator.getType() == KeyLocator::KeyLocator_Name)
nfdId = locator.getName().toUri();
//todo: KeyDigest supporting
}
if (m_isOutputXml)
{
std::cout << "";
std::cout << ""
<< nfdId << "";
std::cout << ""
<< status.getNfdVersion() << "";
std::cout << ""
<< time::toString(status.getStartTimestamp(), "%Y-%m-%dT%H:%M:%S%F")
<< "";
std::cout << ""
<< time::toString(status.getCurrentTimestamp(), "%Y-%m-%dT%H:%M:%S%F")
<< "";
std::cout << "PT"
<< time::duration_cast(status.getCurrentTimestamp()
- status.getStartTimestamp()).count()
<< "S";
std::cout << "" << status.getNNameTreeEntries()
<< "";
std::cout << "" << status.getNFibEntries()
<< "";
std::cout << "" << status.getNPitEntries()
<< "";
std::cout << "" << status.getNMeasurementsEntries()
<< "";
std::cout << "" << status.getNCsEntries()
<< "";
std::cout << "";
std::cout << "";
std::cout << "" << status.getNInInterests()
<< "";
std::cout << "" << status.getNInDatas()
<< "";
std::cout << "";
std::cout << "";
std::cout << "" << status.getNOutInterests()
<< "";
std::cout << "" << status.getNOutDatas()
<< "";
std::cout << "";
std::cout << "";
std::cout << "";
}
else
{
std::cout << "General NFD status:" << std::endl;
std::cout << " nfdId="
<< nfdId << std::endl;
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(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;
}
runNextStep();
}
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
void
fetchChannelStatusInformation()
{
m_buffer = make_shared();
Interest interest("/localhost/nfd/faces/channels");
interest.setChildSelector(1);
interest.setMustBeFresh(true);
SegmentFetcher::fetch(m_face, interest,
m_validator,
bind(&NfdStatus::afterFetchedChannelStatusInformation, this, _1),
bind(&NfdStatus::onErrorFetch, this, _1, _2));
}
void
afterFetchedChannelStatusInformation(const ConstBufferPtr& dataset)
{
if (m_isOutputXml) {
std::cout << "";
size_t offset = 0;
while (offset < dataset->size()) {
bool isOk = false;
Block block;
std::tie(isOk, block) = Block::fromBuffer(dataset, offset);
if (!isOk) {
std::cerr << "ERROR: cannot decode ChannelStatus TLV" << std::endl;
break;
}
offset += block.size();
nfd::ChannelStatus channelStatus(block);
std::cout << "";
std::string localUri(channelStatus.getLocalUri());
escapeSpecialCharacters(&localUri);
std::cout << "" << localUri << "";
std::cout << "";
}
std::cout << "";
}
else {
std::cout << "Channels:" << std::endl;
size_t offset = 0;
while (offset < dataset->size()) {
bool isOk = false;
Block block;
std::tie(isOk, block) = Block::fromBuffer(dataset, offset);
if (!isOk) {
std::cerr << "ERROR: cannot decode ChannelStatus TLV" << std::endl;
break;
}
offset += block.size();
nfd::ChannelStatus channelStatus(block);
std::cout << " " << channelStatus.getLocalUri() << std::endl;
}
}
runNextStep();
}
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
void
fetchFaceStatusInformation()
{
m_buffer = make_shared();
Interest interest("/localhost/nfd/faces/list");
interest.setChildSelector(1);
interest.setMustBeFresh(true);
SegmentFetcher::fetch(m_face, interest,
m_validator,
bind(&NfdStatus::afterFetchedFaceStatusInformation, this, _1),
bind(&NfdStatus::onErrorFetch, this, _1, _2));
}
void
afterFetchedFaceStatusInformation(const ConstBufferPtr& dataset)
{
if (m_isOutputXml) {
std::cout << "";
size_t offset = 0;
while (offset < dataset->size()) {
bool isOk = false;
Block block;
std::tie(isOk, block) = Block::fromBuffer(dataset, offset);
if (!isOk) {
std::cerr << "ERROR: cannot decode FaceStatus TLV" << std::endl;
break;
}
offset += block.size();
nfd::FaceStatus faceStatus(block);
std::cout << "";
std::cout << "" << faceStatus.getFaceId() << "";
std::string remoteUri(faceStatus.getRemoteUri());
escapeSpecialCharacters(&remoteUri);
std::cout << "" << remoteUri << "";
std::string localUri(faceStatus.getLocalUri());
escapeSpecialCharacters(&localUri);
std::cout << "" << localUri << "";
if (faceStatus.hasExpirationPeriod()) {
std::cout << "PT"
<< time::duration_cast(faceStatus.getExpirationPeriod())
.count() << "S"
<< "";
}
std::cout << "" << faceStatus.getFaceScope()
<< "";
std::cout << "" << faceStatus.getFacePersistency()
<< "";
std::cout << "" << faceStatus.getLinkType()
<< "";
std::cout << "";
std::cout << "";
std::cout << "" << faceStatus.getNInInterests()
<< "";
std::cout << "" << faceStatus.getNInDatas()
<< "";
std::cout << "";
std::cout << "";
std::cout << "" << faceStatus.getNOutInterests()
<< "";
std::cout << "" << faceStatus.getNOutDatas()
<< "";
std::cout << "";
std::cout << "";
std::cout << "";
std::cout << "" << faceStatus.getNInBytes()
<< "";
std::cout << "" << faceStatus.getNOutBytes()
<< "";
std::cout << "";
std::cout << "";
}
std::cout << "";
}
else {
std::cout << "Faces:" << std::endl;
size_t offset = 0;
while (offset < dataset->size()) {
bool isOk = false;
Block block;
std::tie(isOk, block) = Block::fromBuffer(dataset, offset);
if (!isOk) {
std::cerr << "ERROR: cannot decode FaceStatus TLV" << std::endl;
break;
}
offset += block.size();
nfd::FaceStatus faceStatus(block);
std::cout << " faceid=" << faceStatus.getFaceId()
<< " remote=" << faceStatus.getRemoteUri()
<< " local=" << faceStatus.getLocalUri();
if (faceStatus.hasExpirationPeriod()) {
std::cout << " expires="
<< time::duration_cast(faceStatus.getExpirationPeriod())
.count() << "s";
}
std::cout << " counters={"
<< "in={" << faceStatus.getNInInterests() << "i "
<< faceStatus.getNInDatas() << "d "
<< faceStatus.getNInBytes() << "B}"
<< " out={" << faceStatus.getNOutInterests() << "i "
<< faceStatus.getNOutDatas() << "d "
<< faceStatus.getNOutBytes() << "B}"
<< "}";
std::cout << " " << faceStatus.getFaceScope()
<< " " << faceStatus.getFacePersistency()
<< " " << faceStatus.getLinkType();
std::cout << std::endl;
}
}
runNextStep();
}
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
void
fetchFibEnumerationInformation()
{
m_buffer = make_shared();
Interest interest("/localhost/nfd/fib/list");
interest.setChildSelector(1);
interest.setMustBeFresh(true);
SegmentFetcher::fetch(m_face, interest,
m_validator,
bind(&NfdStatus::afterFetchedFibEnumerationInformation, this, _1),
bind(&NfdStatus::onErrorFetch, this, _1, _2));
}
void
afterFetchedFibEnumerationInformation(const ConstBufferPtr& dataset)
{
if (m_isOutputXml) {
std::cout << "";
size_t offset = 0;
while (offset < dataset->size()) {
bool isOk = false;
Block block;
std::tie(isOk, block) = Block::fromBuffer(dataset, offset);
if (!isOk) {
std::cerr << "ERROR: cannot decode FibEntry TLV";
break;
}
offset += block.size();
nfd::FibEntry fibEntry(block);
std::cout << "";
std::string prefix(fibEntry.getPrefix().toUri());
escapeSpecialCharacters(&prefix);
std::cout << "" << prefix << "";
std::cout << "";
for (const nfd::NextHopRecord& nextHop : fibEntry.getNextHopRecords()) {
std::cout << "" ;
std::cout << "" << nextHop.getFaceId() << "";
std::cout << "" << nextHop.getCost() << "";
std::cout << "";
}
std::cout << "";
std::cout << "";
}
std::cout << "";
}
else {
std::cout << "FIB:" << std::endl;
size_t offset = 0;
while (offset < dataset->size()) {
bool isOk = false;
Block block;
std::tie(isOk, block) = Block::fromBuffer(dataset, offset);
if (!isOk) {
std::cerr << "ERROR: cannot decode FibEntry TLV" << std::endl;
break;
}
offset += block.size();
nfd::FibEntry fibEntry(block);
std::cout << " " << fibEntry.getPrefix() << " nexthops={";
bool isFirst = true;
for (const nfd::NextHopRecord& nextHop : fibEntry.getNextHopRecords()) {
if (isFirst)
isFirst = false;
else
std::cout << ", ";
std::cout << "faceid=" << nextHop.getFaceId()
<< " (cost=" << nextHop.getCost() << ")";
}
std::cout << "}" << std::endl;
}
}
runNextStep();
}
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
void
fetchStrategyChoiceInformation()
{
m_buffer = make_shared();
Interest interest("/localhost/nfd/strategy-choice/list");
interest.setChildSelector(1);
interest.setMustBeFresh(true);
SegmentFetcher::fetch(m_face, interest,
m_validator,
bind(&NfdStatus::afterFetchedStrategyChoiceInformationInformation, this, _1),
bind(&NfdStatus::onErrorFetch, this, _1, _2));
}
void
afterFetchedStrategyChoiceInformationInformation(const ConstBufferPtr& dataset)
{
if (m_isOutputXml) {
std::cout << "";
size_t offset = 0;
while (offset < dataset->size()) {
bool isOk = false;
Block block;
std::tie(isOk, block) = Block::fromBuffer(dataset, offset);
if (!isOk) {
std::cerr << "ERROR: cannot decode StrategyChoice TLV";
break;
}
offset += block.size();
nfd::StrategyChoice strategyChoice(block);
std::cout << "";
std::string name(strategyChoice.getName().toUri());
escapeSpecialCharacters(&name);
std::cout << "" << name << "";
std::cout << "";
std::string strategy(strategyChoice.getStrategy().toUri());
escapeSpecialCharacters(&strategy);
std::cout << "" << strategy << "";
std::cout << "";
std::cout << "";
}
std::cout << "";
}
else {
std::cout << "Strategy choices:" << std::endl;
size_t offset = 0;
while (offset < dataset->size()) {
bool isOk = false;
Block block;
std::tie(isOk, block) = Block::fromBuffer(dataset, offset);
if (!isOk) {
std::cerr << "ERROR: cannot decode StrategyChoice TLV" << std::endl;
break;
}
offset += block.size();
nfd::StrategyChoice strategyChoice(block);
std::cout << " " << strategyChoice.getName()
<< " strategy=" << strategyChoice.getStrategy() << std::endl;
}
}
runNextStep();
}
void
fetchRibStatusInformation()
{
m_buffer = make_shared();
Interest interest("/localhost/nfd/rib/list");
interest.setChildSelector(1);
interest.setMustBeFresh(true);
SegmentFetcher::fetch(m_face, interest,
m_validator,
bind(&NfdStatus::afterFetchedRibStatusInformation, this, _1),
bind(&NfdStatus::onErrorFetch, this, _1, _2));
}
void
afterFetchedRibStatusInformation(const ConstBufferPtr& dataset)
{
if (m_isOutputXml) {
std::cout << "";
size_t offset = 0;
while (offset < dataset->size()) {
bool isOk = false;
Block block;
std::tie(isOk, block) = Block::fromBuffer(dataset, offset);
if (!isOk) {
std::cerr << "ERROR: cannot decode RibEntry TLV";
break;
}
offset += block.size();
nfd::RibEntry ribEntry(block);
std::cout << "";
std::string prefix(ribEntry.getName().toUri());
escapeSpecialCharacters(&prefix);
std::cout << "" << prefix << "";
std::cout << "";
for (const nfd::Route& nextRoute : ribEntry) {
std::cout << "" ;
std::cout << "" << nextRoute.getFaceId() << "";
std::cout << "" << nextRoute.getOrigin() << "";
std::cout << "" << nextRoute.getCost() << "";
std::cout << "";
if (nextRoute.isChildInherit())
std::cout << "";
if (nextRoute.isRibCapture())
std::cout << "";
std::cout << "";
if (!nextRoute.hasInfiniteExpirationPeriod()) {
std::cout << "PT"
<< time::duration_cast(nextRoute.getExpirationPeriod())
.count() << "S"
<< "";
}
std::cout << "";
}
std::cout << "";
std::cout << "";
}
std::cout << "";
}
else {
std::cout << "RIB:" << std::endl;
size_t offset = 0;
while (offset < dataset->size()) {
bool isOk = false;
Block block;
std::tie(isOk, block) = Block::fromBuffer(dataset, offset);
if (!isOk) {
std::cerr << "ERROR: cannot decode RibEntry TLV" << std::endl;
break;
}
offset += block.size();
nfd::RibEntry ribEntry(block);
std::cout << " " << ribEntry.getName().toUri() << " route={";
bool isFirst = true;
for (const nfd::Route& nextRoute : ribEntry) {
if (isFirst)
isFirst = false;
else
std::cout << ", ";
std::cout << "faceid=" << nextRoute.getFaceId()
<< " (origin=" << nextRoute.getOrigin()
<< " cost=" << nextRoute.getCost();
if (!nextRoute.hasInfiniteExpirationPeriod()) {
std::cout << " expires="
<< time::duration_cast(nextRoute.getExpirationPeriod())
.count() << "s";
}
if (nextRoute.isChildInherit())
std::cout << " ChildInherit";
if (nextRoute.isRibCapture())
std::cout << " RibCapture";
std::cout << ")";
}
std::cout << "}" << std::endl;
}
}
runNextStep();
}
void
fetchInformation()
{
if (m_isOutputXml ||
(!m_needVersionRetrieval &&
!m_needChannelStatusRetrieval &&
!m_needFaceStatusRetrieval &&
!m_needFibEnumerationRetrieval &&
!m_needRibStatusRetrieval &&
!m_needStrategyChoiceRetrieval))
{
enableVersionRetrieval();
enableChannelStatusRetrieval();
enableFaceStatusRetrieval();
enableFibEnumerationRetrieval();
enableRibStatusRetrieval();
enableStrategyChoiceRetrieval();
}
if (m_isOutputXml)
m_fetchSteps.push_back(bind(&NfdStatus::printXmlHeader, this));
if (m_needVersionRetrieval)
m_fetchSteps.push_back(bind(&NfdStatus::fetchVersionInformation, this));
if (m_needChannelStatusRetrieval)
m_fetchSteps.push_back(bind(&NfdStatus::fetchChannelStatusInformation, this));
if (m_needFaceStatusRetrieval)
m_fetchSteps.push_back(bind(&NfdStatus::fetchFaceStatusInformation, this));
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));
if (m_isOutputXml)
m_fetchSteps.push_back(bind(&NfdStatus::printXmlFooter, this));
runNextStep();
m_face.processEvents();
}
private:
void
printXmlHeader()
{
std::cout << "";
std::cout << "";
runNextStep();
}
void
printXmlFooter()
{
std::cout << "";
runNextStep();
}
void
runNextStep()
{
if (m_fetchSteps.empty())
return;
function nextStep = m_fetchSteps.front();
m_fetchSteps.pop_front();
nextStep();
}
private:
std::string m_toolName;
bool m_needVersionRetrieval;
bool m_needChannelStatusRetrieval;
bool m_needFaceStatusRetrieval;
bool m_needFibEnumerationRetrieval;
bool m_needRibStatusRetrieval;
bool m_needStrategyChoiceRetrieval;
bool m_isOutputXml;
Face m_face;
shared_ptr m_buffer;
std::deque > m_fetchSteps;
ndn::ValidatorNull m_validator;
};
}
int main(int argc, char* argv[])
{
int option;
ndn::NfdStatus nfdStatus(argv[0]);
while ((option = getopt(argc, argv, "hvcfbrsxV")) != -1) {
switch (option) {
case 'h':
nfdStatus.usage();
return 0;
case 'v':
nfdStatus.enableVersionRetrieval();
break;
case 'c':
nfdStatus.enableChannelStatusRetrieval();
break;
case 'f':
nfdStatus.enableFaceStatusRetrieval();
break;
case 'b':
nfdStatus.enableFibEnumerationRetrieval();
break;
case 'r':
nfdStatus.enableRibStatusRetrieval();
break;
case 's':
nfdStatus.enableStrategyChoiceRetrieval();
break;
case 'x':
nfdStatus.enableXmlOutput();
break;
case 'V':
std::cout << NFD_VERSION_BUILD_STRING << std::endl;
return 0;
default:
nfdStatus.usage();
return 1;
}
}
try {
nfdStatus.fetchInformation();
}
catch (std::exception& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
return 2;
}
return 0;
}