/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** * Copyright (c) 2014, 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 namespace ndn { 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 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 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"); 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); m_face.expressInterest(interest, bind(&NfdStatus::fetchSegments, this, _2, &NfdStatus::afterFetchedChannelStatusInformation), bind(&NfdStatus::onTimeout, this)); } void afterFetchedChannelStatusInformation() { ConstBufferPtr buf = m_buffer->buf(); if (m_isOutputXml) { std::cout << ""; Block block; size_t offset = 0; while (offset < buf->size()) { bool ok = Block::fromBuffer(buf, offset, block); if (!ok) { 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; Block block; size_t offset = 0; while (offset < buf->size()) { bool ok = Block::fromBuffer(buf, offset, block); if (!ok) { 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); m_face.expressInterest(interest, bind(&NfdStatus::fetchSegments, this, _2, &NfdStatus::afterFetchedFaceStatusInformation), bind(&NfdStatus::onTimeout, this)); } void afterFetchedFaceStatusInformation() { ConstBufferPtr buf = m_buffer->buf(); if (m_isOutputXml) { std::cout << ""; Block block; size_t offset = 0; while (offset < buf->size()) { bool ok = Block::fromBuffer(buf, offset, block); if (!ok) { 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; Block block; size_t offset = 0; while (offset < buf->size()) { bool ok = Block::fromBuffer(buf, offset, block); if (!ok) { 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); m_face.expressInterest(interest, bind(&NfdStatus::fetchSegments, this, _2, &NfdStatus::afterFetchedFibEnumerationInformation), bind(&NfdStatus::onTimeout, this)); } void afterFetchedFibEnumerationInformation() { ConstBufferPtr buf = m_buffer->buf(); if (m_isOutputXml) { std::cout << ""; Block block; size_t offset = 0; while (offset < buf->size()) { bool ok = Block::fromBuffer(buf, offset, block); if (!ok) { 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 (std::list::const_iterator nextHop = fibEntry.getNextHopRecords().begin(); nextHop != fibEntry.getNextHopRecords().end(); ++nextHop) { std::cout << "" ; std::cout << "" << nextHop->getFaceId() << ""; std::cout << "" << nextHop->getCost() << ""; std::cout << ""; } std::cout << ""; std::cout << ""; } std::cout << ""; } else { std::cout << "FIB:" << 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 FibEntry TLV" << std::endl; break; } offset += block.size(); nfd::FibEntry fibEntry(block); std::cout << " " << fibEntry.getPrefix() << " nexthops={"; for (std::list::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; } } runNextStep(); } ////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// void fetchStrategyChoiceInformation() { m_buffer = make_shared(); Interest interest("/localhost/nfd/strategy-choice/list"); interest.setChildSelector(1); interest.setMustBeFresh(true); m_face.expressInterest(interest, bind(&NfdStatus::fetchSegments, this, _2, &NfdStatus::afterFetchedStrategyChoiceInformationInformation), bind(&NfdStatus::onTimeout, this)); } void afterFetchedStrategyChoiceInformationInformation() { ConstBufferPtr buf = m_buffer->buf(); if (m_isOutputXml) { std::cout << ""; Block block; size_t offset = 0; while (offset < buf->size()) { bool ok = Block::fromBuffer(buf, offset, block); if (!ok) { 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; Block block; size_t offset = 0; while (offset < buf->size()) { bool ok = Block::fromBuffer(buf, offset, block); if (!ok) { 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); 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 << ""; 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 << ""; std::string prefix(ribEntry.getName().toUri()); escapeSpecialCharacters(&prefix); std::cout << "" << prefix << ""; std::cout << ""; for (std::list::const_iterator nextRoute = ribEntry.begin(); nextRoute != ribEntry.end(); ++nextRoute) { 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; 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::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(); 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; }; } 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; }