Code modernization
Change-Id: Ia15bb9e988b08bc81c0709d95d7d17e6078a5385
diff --git a/src/logger.hpp b/src/logger.hpp
index 0ed35b3..71cfbc2 100644
--- a/src/logger.hpp
+++ b/src/logger.hpp
@@ -1,6 +1,6 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/**
- * Copyright (C) 2014-2015 University of Arizona.
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2019, Arizona Board of Regents.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,21 +33,74 @@
class Logger
{
public:
+ explicit
Logger(const std::string& module)
: m_module(module)
{
}
void
- shutdownLogger()
+ log(const std::string& logLine, bool printTime, bool printToConsole)
{
- if (m_logFile.is_open())
- {
- log("Terminating Logging Operations" , true, true);
- m_logFile.close();
+ if (m_logLocation.length() > 0) {
+ if (printTime)
+ m_logFile << getTimestamp() << " - ";
+ m_logFile << logLine << std::endl;
+ m_logFile.flush();
+ if (printToConsole) {
+ if (printTime)
+ std::cout << getTimestamp() << " - ";
+ std::cout << logLine << std::endl;
}
+ }
+ else {
+ if (printTime)
+ std::cout << getTimestamp() << " - ";
+ std::cout << logLine << std::endl;
+ }
}
+ void
+ initializeLog(const std::string& instanceId)
+ {
+ m_logLocation = "";
+ const char* envVar = std::getenv("NDN_TRAFFIC_LOGFOLDER");
+ if (envVar != nullptr)
+ m_logLocation = envVar;
+
+ if (m_logLocation.empty()) {
+ std::cout << "Environment variable NDN_TRAFFIC_LOGFOLDER not set.\n"
+ << "Using default output for logging." << std::endl;
+ return;
+ }
+
+ if (boost::filesystem::exists(boost::filesystem::path(m_logLocation))) {
+ if (boost::filesystem::is_directory(boost::filesystem::path(m_logLocation))) {
+ std::string logFilename = m_logLocation + "/" + m_module + "_" + instanceId + ".log";
+ m_logFile.open(logFilename.data(), std::ofstream::out | std::ofstream::trunc);
+ if (m_logFile.is_open()) {
+ std::cout << "Log file initialized: " << logFilename << std::endl;
+ }
+ else {
+ std::cout << "ERROR: Unable to initialize a log file at: " << m_logLocation << std::endl
+ << "Using default output for logging." << std::endl;
+ m_logLocation = "";
+ }
+ }
+ else {
+ std::cout << "NDN_TRAFFIC_LOGFOLDER should be a directory.\n"
+ << "Using default output for logging." << std::endl;
+ m_logLocation = "";
+ }
+ }
+ else {
+ std::cout << "NDN_TRAFFIC_LOGFOLDER does not exist.\n"
+ << "Using default output for logging." << std::endl;
+ m_logLocation = "";
+ }
+ }
+
+private:
static std::string
getTimestamp()
{
@@ -56,71 +109,6 @@
return to_simple_string(now);
}
- void
- log(const std::string& logLine, bool printTime, bool printToConsole)
- {
- if (m_logLocation.length() > 0)
- {
- if (printTime)
- m_logFile << getTimestamp() << " - ";
- m_logFile << logLine << std::endl;
- m_logFile.flush();
- if (printToConsole)
- {
- if (printTime)
- std::cout << getTimestamp() << " - ";
- std::cout << logLine << std::endl;
- }
- }
- else
- {
- if (printTime)
- std::cout << getTimestamp() << " - ";
- std::cout << logLine << std::endl;
- }
- }
-
- void
- initializeLog(const std::string& instanceId)
- {
- const char* envVar = std::getenv("NDN_TRAFFIC_LOGFOLDER");
- m_logLocation = "";
- if (envVar != nullptr)
- m_logLocation = envVar;
-
- std::string logFilename;
- if (boost::filesystem::exists(boost::filesystem::path(m_logLocation)))
- {
- if (boost::filesystem::is_directory(boost::filesystem::path(m_logLocation)))
- {
- logFilename = m_logLocation + "/" + m_module + "_" + instanceId + ".log";
- m_logFile.open(logFilename.c_str(), std::ofstream::out | std::ofstream::trunc);
- if (m_logFile.is_open())
- std::cout << "Log File Initialized: " << logFilename << std::endl;
- else
- {
- std::cout << "ERROR - Unable To Initialize A Log File At: "
- << m_logLocation << std::endl
- << "Using Default Output For Logging." << std::endl;
- m_logLocation = "";
- }
- }
- else
- {
- std::cout << "Environment Variable NDN_TRAFFIC_LOGFOLDER Should Be A Folder."
- << std::endl
- << "Using Default Output For Logging." << std::endl;
- m_logLocation = "";
- }
- }
- else
- {
- std::cout << "Environment Variable NDN_TRAFFIC_LOGFOLDER Not Set." << std::endl
- << "Using Default Output For Logging." << std::endl;
- m_logLocation = "";
- }
- }
-
private:
std::string m_module;
std::string m_logLocation;
diff --git a/src/ndn-traffic-client.cpp b/src/ndn-traffic-client.cpp
index 062b54d..adba253 100644
--- a/src/ndn-traffic-client.cpp
+++ b/src/ndn-traffic-client.cpp
@@ -19,9 +19,16 @@
*/
#include "logger.hpp"
+#include "util.hpp"
+
+#include <ndn-cxx/face.hpp>
+#include <ndn-cxx/name.hpp>
+#include <ndn-cxx/lp/tags.hpp>
+#include <ndn-cxx/util/backports.hpp>
+#include <ndn-cxx/util/random.hpp>
#include <cctype>
-#include <unistd.h>
+#include <limits>
#include <vector>
#include <boost/asio/deadline_timer.hpp>
@@ -29,12 +36,13 @@
#include <boost/asio/signal_set.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/lexical_cast.hpp>
+#include <boost/logic/tribool.hpp>
#include <boost/noncopyable.hpp>
+#include <boost/program_options/options_description.hpp>
+#include <boost/program_options/parsers.hpp>
+#include <boost/program_options/variables_map.hpp>
-#include <ndn-cxx/face.hpp>
-#include <ndn-cxx/name-component.hpp>
-#include <ndn-cxx/lp/tags.hpp>
-#include <ndn-cxx/util/backports.hpp>
+namespace po = boost::program_options;
namespace ndn {
@@ -42,178 +50,14 @@
{
public:
explicit
- NdnTrafficClient(const char* programName)
- : m_programName(programName)
+ NdnTrafficClient(const std::string& configFile)
+ : m_signalSet(m_ioService, SIGINT, SIGTERM)
, m_logger("NdnTrafficClient")
- , m_instanceId(to_string(std::rand()))
- , m_hasError(false)
- , m_hasQuietLogging(false)
- , m_interestInterval(getDefaultInterestInterval())
- , m_nMaximumInterests(-1)
, m_face(m_ioService)
- , m_nInterestsSent(0)
- , m_nInterestsReceived(0)
- , m_nNacks(0)
- , m_nContentInconsistencies(0)
- , m_minimumInterestRoundTripTime(std::numeric_limits<double>::max())
- , m_maximumInterestRoundTripTime(0)
- , m_totalInterestRoundTripTime(0)
+ , m_configurationFile(configFile)
{
}
- class InterestTrafficConfiguration
- {
- public:
- InterestTrafficConfiguration()
- : m_trafficPercentage(-1)
- , m_nameAppendBytes(-1)
- , m_nameAppendSequenceNumber(-1)
- , m_mustBeFresh(-1)
- , m_nonceDuplicationPercentage(-1)
- , m_interestLifetime(getDefaultInterestLifetime())
- , m_nextHopFaceId(0)
- , m_nInterestsSent(0)
- , m_nInterestsReceived(0)
- , m_nNacks(0)
- , m_minimumInterestRoundTripTime(std::numeric_limits<double>::max())
- , m_maximumInterestRoundTripTime(0)
- , m_totalInterestRoundTripTime(0)
- , m_nContentInconsistencies(0)
- {
- }
-
- static time::milliseconds
- getDefaultInterestLifetime()
- {
- return -1_ms;
- }
-
- void
- printTrafficConfiguration(Logger& logger)
- {
- std::string detail;
-
- if (m_trafficPercentage > 0)
- detail += "TrafficPercentage=" + to_string(m_trafficPercentage) + ", ";
- if (!m_name.empty())
- detail += "Name=" + m_name + ", ";
- if (m_nameAppendBytes > 0)
- detail += "NameAppendBytes=" + to_string(m_nameAppendBytes) + ", ";
- if (m_nameAppendSequenceNumber > 0)
- detail += "NameAppendSequenceNumber=" + to_string(m_nameAppendSequenceNumber) + ", ";
- if (m_mustBeFresh >= 0)
- detail += "MustBeFresh=" + to_string(m_mustBeFresh) + ", ";
- if (m_nonceDuplicationPercentage > 0)
- detail += "NonceDuplicationPercentage=" + to_string(m_nonceDuplicationPercentage) + ", ";
- if (m_interestLifetime >= 0_ms)
- detail += "InterestLifetime=" + to_string(m_interestLifetime.count()) + ", ";
- if (m_nextHopFaceId > 0)
- detail += "NextHopFaceId=" + to_string(m_nextHopFaceId) + ", ";
- if (!m_expectedContent.empty())
- detail += "ExpectedContent=" + m_expectedContent + ", ";
- if (detail.length() >= 2)
- detail = detail.substr(0, detail.length() - 2); // Removing suffix ", "
-
- logger.log(detail, false, false);
- }
-
- bool
- extractParameterValue(const std::string& detail, std::string& parameter, std::string& value)
- {
- std::string allowedCharacters = ":/+.,_-%";
- std::size_t i = 0;
-
- parameter = "";
- value = "";
- while (detail[i] != '=' && i < detail.length()) {
- parameter += detail[i];
- i++;
- }
- if (i == detail.length())
- return false;
-
- i++;
- while ((std::isalnum(detail[i]) ||
- allowedCharacters.find(detail[i]) != std::string::npos) &&
- i < detail.length()) {
- value += detail[i];
- i++;
- }
-
- if (parameter.empty() || value.empty())
- return false;
- else
- return true;
- }
-
- bool
- processConfigurationDetail(const std::string& detail, Logger& logger, int lineNumber)
- {
- std::string parameter, value;
- if (extractParameterValue(detail, parameter, value))
- {
- if (parameter == "TrafficPercentage")
- m_trafficPercentage = std::stoi(value);
- else if (parameter == "Name")
- m_name = value;
- else if (parameter == "NameAppendBytes")
- m_nameAppendBytes = std::stoi(value);
- else if (parameter == "NameAppendSequenceNumber")
- m_nameAppendSequenceNumber = std::stoi(value);
- else if (parameter == "MustBeFresh")
- m_mustBeFresh = std::stoi(value);
- else if (parameter == "NonceDuplicationPercentage")
- m_nonceDuplicationPercentage = std::stoi(value);
- else if (parameter == "InterestLifetime")
- m_interestLifetime = time::milliseconds(std::stoi(value));
- else if (parameter == "NextHopFaceId")
- m_nextHopFaceId = std::stoi(value);
- else if (parameter == "ExpectedContent")
- m_expectedContent = value;
- else
- logger.log("Line " + to_string(lineNumber) +
- " \t- Invalid Parameter='" + parameter + "'", false, true);
- }
- else
- {
- logger.log("Line " + to_string(lineNumber) +
- " \t- Improper Traffic Configuration Line- " + detail, false, true);
- return false;
- }
- return true;
- }
-
- bool
- checkTrafficDetailCorrectness()
- {
- return true;
- }
-
- private:
- int m_trafficPercentage;
- std::string m_name;
- int m_nameAppendBytes;
- int m_nameAppendSequenceNumber;
- int m_mustBeFresh;
- int m_nonceDuplicationPercentage;
- time::milliseconds m_interestLifetime;
- uint64_t m_nextHopFaceId;
- int m_nInterestsSent;
- int m_nInterestsReceived;
- int m_nNacks;
-
- //round trip time is stored as milliseconds with fractional
- //sub-millisecond precision
- double m_minimumInterestRoundTripTime;
- double m_maximumInterestRoundTripTime;
- double m_totalInterestRoundTripTime;
-
- int m_nContentInconsistencies;
- std::string m_expectedContent;
-
- friend class NdnTrafficClient;
- }; // class InterestTrafficConfiguration
-
bool
hasError() const
{
@@ -221,145 +65,212 @@
}
void
- usage() const
+ setMaximumInterests(uint64_t maxInterests)
{
- std::cout << "Usage:\n"
- << " " << m_programName << " [options] <Traffic_Configuration_File>\n"
- << "\n"
- << "Generate Interest traffic as per provided Traffic Configuration File.\n"
- << "Interests are continuously generated unless a total number is specified.\n"
- << "Set environment variable NDN_TRAFFIC_LOGFOLDER to redirect output to a log file.\n"
- << "\n"
- << "Options:\n"
- << " [-i interval] - set interest generation interval in milliseconds (default "
- << getDefaultInterestInterval() << ")\n"
- << " [-c count] - set total number of interests to be generated\n"
- << " [-q] - quiet mode: no interest reception/data generation logging\n"
- << " [-h] - print this help text and exit\n";
- exit(EXIT_FAILURE);
- }
-
- static time::milliseconds
- getDefaultInterestInterval()
- {
- return 1_s;
+ m_nMaximumInterests = maxInterests;
}
void
- setInterestInterval(int interestInterval)
+ setInterestInterval(time::milliseconds interval)
{
- if (interestInterval <= 0)
- usage();
- m_interestInterval = time::milliseconds(interestInterval);
- }
-
- void
- setMaximumInterests(int maximumInterests)
- {
- if (maximumInterests <= 0)
- usage();
- m_nMaximumInterests = maximumInterests;
- }
-
- void
- setConfigurationFile(char* configurationFile)
- {
- m_configurationFile = configurationFile;
+ BOOST_ASSERT(interval > 0_ms);
+ m_interestInterval = interval;
}
void
setQuietLogging()
{
- m_hasQuietLogging = true;
+ m_wantQuiet = true;
}
void
- signalHandler()
+ run()
{
- logStatistics();
+ m_logger.initializeLog(to_string(random::generateWord32()));
+ initializeTrafficConfiguration();
- m_logger.shutdownLogger();
- m_face.shutdown();
- m_ioService.stop();
+ if (m_nMaximumInterests == 0) {
+ logStatistics();
+ return;
+ }
- exit(m_hasError ? EXIT_FAILURE : EXIT_SUCCESS);
+ m_signalSet.async_wait([this] (auto&&...) { this->stop(); });
+
+ boost::asio::deadline_timer timer(m_ioService,
+ boost::posix_time::millisec(m_interestInterval.count()));
+ timer.async_wait([this, &timer] (auto&&...) { this->generateTraffic(timer); });
+
+ try {
+ m_face.processEvents();
+ }
+ catch (const std::exception& e) {
+ m_logger.log("ERROR: "s + e.what(), true, true);
+ m_hasError = true;
+ m_ioService.stop();
+ }
}
+private:
+ class InterestTrafficConfiguration
+ {
+ public:
+ void
+ printTrafficConfiguration(Logger& logger) const
+ {
+ std::string detail;
+
+ detail += "TrafficPercentage=" + to_string(m_trafficPercentage) + ", ";
+ if (!m_name.empty())
+ detail += "Name=" + m_name + ", ";
+ if (m_nameAppendBytes)
+ detail += "NameAppendBytes=" + to_string(*m_nameAppendBytes) + ", ";
+ if (m_nameAppendSeqNum)
+ detail += "NameAppendSequenceNumber=" + to_string(*m_nameAppendSeqNum) + ", ";
+ if (!boost::logic::indeterminate(m_mustBeFresh))
+ detail += "MustBeFresh=" + to_string(bool(m_mustBeFresh)) + ", ";
+ if (m_nonceDuplicationPercentage > 0)
+ detail += "NonceDuplicationPercentage=" + to_string(m_nonceDuplicationPercentage) + ", ";
+ if (m_interestLifetime >= 0_ms)
+ detail += "InterestLifetime=" + to_string(m_interestLifetime.count()) + ", ";
+ if (m_nextHopFaceId > 0)
+ detail += "NextHopFaceId=" + to_string(m_nextHopFaceId) + ", ";
+ if (m_expectedContent)
+ detail += "ExpectedContent=" + *m_expectedContent + ", ";
+ if (detail.length() >= 2)
+ detail = detail.substr(0, detail.length() - 2); // Removing suffix ", "
+
+ logger.log(detail, false, false);
+ }
+
+ bool
+ processConfigurationDetail(const std::string& detail, Logger& logger, int lineNumber)
+ {
+ std::string parameter, value;
+ if (parseParameterAndValue(detail, parameter, value)) {
+ if (parameter == "TrafficPercentage")
+ m_trafficPercentage = std::stoul(value);
+ else if (parameter == "Name")
+ m_name = value;
+ else if (parameter == "NameAppendBytes")
+ m_nameAppendBytes = std::stoul(value);
+ else if (parameter == "NameAppendSequenceNumber")
+ m_nameAppendSeqNum = std::stoull(value);
+ else if (parameter == "MustBeFresh")
+ m_mustBeFresh = bool(std::stoul(value));
+ else if (parameter == "NonceDuplicationPercentage")
+ m_nonceDuplicationPercentage = std::stoul(value);
+ else if (parameter == "InterestLifetime")
+ m_interestLifetime = time::milliseconds(std::stoul(value));
+ else if (parameter == "NextHopFaceId")
+ m_nextHopFaceId = std::stoull(value);
+ else if (parameter == "ExpectedContent")
+ m_expectedContent = value;
+ else
+ logger.log("Line " + to_string(lineNumber) +
+ " - Unknown parameter '" + parameter + "'", false, true);
+ }
+ else {
+ logger.log("Line " + to_string(lineNumber) +
+ " - Invalid traffic configuration line: " + detail, false, true);
+ return false;
+ }
+ return true;
+ }
+
+ bool
+ checkTrafficDetailCorrectness() const
+ {
+ return true;
+ }
+
+ public:
+ uint8_t m_trafficPercentage = 0;
+ std::string m_name;
+ optional<std::size_t> m_nameAppendBytes;
+ optional<uint64_t> m_nameAppendSeqNum;
+ boost::logic::tribool m_mustBeFresh = boost::logic::indeterminate;
+ uint8_t m_nonceDuplicationPercentage = 0;
+ time::milliseconds m_interestLifetime = -1_ms;
+ uint64_t m_nextHopFaceId = 0;
+ optional<std::string> m_expectedContent;
+
+ uint64_t m_nInterestsSent = 0;
+ uint64_t m_nInterestsReceived = 0;
+ uint64_t m_nNacks = 0;
+ uint64_t m_nContentInconsistencies = 0;
+
+ // RTT is stored as milliseconds with fractional sub-milliseconds precision
+ double m_minimumInterestRoundTripTime = std::numeric_limits<double>::max();
+ double m_maximumInterestRoundTripTime = 0;
+ double m_totalInterestRoundTripTime = 0;
+ };
+
void
logStatistics()
{
m_logger.log("\n\n== Interest Traffic Report ==\n", false, true);
m_logger.log("Total Traffic Pattern Types = " +
- to_string(m_trafficPatterns.size()), false, true);
+ to_string(m_trafficPatterns.size()), false, true);
m_logger.log("Total Interests Sent = " +
- to_string(m_nInterestsSent), false, true);
+ to_string(m_nInterestsSent), false, true);
m_logger.log("Total Responses Received = " +
- to_string(m_nInterestsReceived), false, true);
+ to_string(m_nInterestsReceived), false, true);
m_logger.log("Total Nacks Received = " +
- to_string(m_nNacks), false, true);
+ to_string(m_nNacks), false, true);
- double loss = 0;
- if (m_nInterestsSent > 0)
+ double loss = 0.0;
+ if (m_nInterestsSent > 0) {
loss = (m_nInterestsSent - m_nInterestsReceived) * 100.0 / m_nInterestsSent;
+ }
m_logger.log("Total Interest Loss = " + to_string(loss) + "%", false, true);
- if (m_nContentInconsistencies != 0 || m_nInterestsSent != m_nInterestsReceived)
- m_hasError = true;
- double average = 0;
- double inconsistency = 0;
- if (m_nInterestsReceived > 0)
- {
- average = m_totalInterestRoundTripTime / m_nInterestsReceived;
- inconsistency = m_nContentInconsistencies * 100.0 / m_nInterestsReceived;
- }
+ double average = 0.0;
+ double inconsistency = 0.0;
+ if (m_nInterestsReceived > 0) {
+ average = m_totalInterestRoundTripTime / m_nInterestsReceived;
+ inconsistency = m_nContentInconsistencies * 100.0 / m_nInterestsReceived;
+ }
m_logger.log("Total Data Inconsistency = " +
- to_string(inconsistency) + "%", false, true);
+ to_string(inconsistency) + "%", false, true);
m_logger.log("Total Round Trip Time = " +
- to_string(m_totalInterestRoundTripTime) + "ms", false, true);
+ to_string(m_totalInterestRoundTripTime) + "ms", false, true);
m_logger.log("Average Round Trip Time = " +
- to_string(average) + "ms\n", false, true);
+ to_string(average) + "ms\n", false, true);
- for (std::size_t patternId = 0; patternId < m_trafficPatterns.size(); patternId++)
- {
- m_logger.log("Traffic Pattern Type #" +
- to_string(patternId + 1), false, true);
- m_trafficPatterns[patternId].printTrafficConfiguration(m_logger);
- m_logger.log("Total Interests Sent = " +
- to_string(m_trafficPatterns[patternId].m_nInterestsSent), false, true);
- m_logger.log("Total Responses Received = " +
- to_string(m_trafficPatterns[patternId].m_nInterestsReceived), false, true);
- m_logger.log("Total Nacks Received = " +
- to_string(m_trafficPatterns[patternId].m_nNacks), false, true);
- loss = 0;
- if (m_trafficPatterns[patternId].m_nInterestsSent > 0)
- {
- loss = (m_trafficPatterns[patternId].m_nInterestsSent -
- m_trafficPatterns[patternId].m_nInterestsReceived);
- loss *= 100.0;
- loss /= m_trafficPatterns[patternId].m_nInterestsSent;
- }
- m_logger.log("Total Interest Loss = " + to_string(loss) + "%", false, true);
- average = 0;
- inconsistency = 0;
- if (m_trafficPatterns[patternId].m_nInterestsReceived > 0)
- {
- average = (m_trafficPatterns[patternId].m_totalInterestRoundTripTime /
- m_trafficPatterns[patternId].m_nInterestsReceived);
- inconsistency = m_trafficPatterns[patternId].m_nContentInconsistencies;
- inconsistency *= 100.0 / m_trafficPatterns[patternId].m_nInterestsReceived;
- }
- m_logger.log("Total Data Inconsistency = " +
- to_string(inconsistency) + "%", false, true);
- m_logger.log("Total Round Trip Time = " +
- to_string(m_trafficPatterns[patternId].m_totalInterestRoundTripTime) +
- "ms", false, true);
- m_logger.log("Average Round Trip Time = " +
- to_string(average) + "ms\n", false, true);
+ for (std::size_t patternId = 0; patternId < m_trafficPatterns.size(); patternId++) {
+ m_logger.log("Traffic Pattern Type #" + to_string(patternId + 1), false, true);
+ m_trafficPatterns[patternId].printTrafficConfiguration(m_logger);
+ m_logger.log("Total Interests Sent = " +
+ to_string(m_trafficPatterns[patternId].m_nInterestsSent), false, true);
+ m_logger.log("Total Responses Received = " +
+ to_string(m_trafficPatterns[patternId].m_nInterestsReceived), false, true);
+ m_logger.log("Total Nacks Received = " +
+ to_string(m_trafficPatterns[patternId].m_nNacks), false, true);
+ loss = 0;
+ if (m_trafficPatterns[patternId].m_nInterestsSent > 0) {
+ loss = (m_trafficPatterns[patternId].m_nInterestsSent -
+ m_trafficPatterns[patternId].m_nInterestsReceived);
+ loss *= 100.0;
+ loss /= m_trafficPatterns[patternId].m_nInterestsSent;
}
+ m_logger.log("Total Interest Loss = " + to_string(loss) + "%", false, true);
+ average = 0;
+ inconsistency = 0;
+ if (m_trafficPatterns[patternId].m_nInterestsReceived > 0) {
+ average = (m_trafficPatterns[patternId].m_totalInterestRoundTripTime /
+ m_trafficPatterns[patternId].m_nInterestsReceived);
+ inconsistency = m_trafficPatterns[patternId].m_nContentInconsistencies;
+ inconsistency *= 100.0 / m_trafficPatterns[patternId].m_nInterestsReceived;
+ }
+ m_logger.log("Total Data Inconsistency = " + to_string(inconsistency) + "%", false, true);
+ m_logger.log("Total Round Trip Time = " +
+ to_string(m_trafficPatterns[patternId].m_totalInterestRoundTripTime) + "ms", false, true);
+ m_logger.log("Average Round Trip Time = " + to_string(average) + "ms\n", false, true);
+ }
}
bool
- checkTrafficPatternCorrectness()
+ checkTrafficPatternCorrectness() const
{
return true;
}
@@ -367,161 +278,188 @@
void
parseConfigurationFile()
{
- std::string patternLine;
std::ifstream patternFile;
- m_logger.log("Analyzing Traffic Configuration File: " + m_configurationFile, true, true);
+ m_logger.log("Parsing traffic configuration file: " + m_configurationFile, true, true);
- patternFile.open(m_configurationFile.c_str());
- if (patternFile.is_open())
- {
- int lineNumber = 0;
- while (getline(patternFile, patternLine))
- {
- lineNumber++;
- if (std::isalpha(patternLine[0]))
- {
- InterestTrafficConfiguration interestData;
- bool shouldSkipLine = false;
- if (interestData.processConfigurationDetail(patternLine, m_logger, lineNumber))
- {
- while (getline(patternFile, patternLine) && std::isalpha(patternLine[0]))
- {
- lineNumber++;
- if (!interestData.processConfigurationDetail(patternLine,
- m_logger, lineNumber))
- {
- shouldSkipLine = true;
- break;
- }
- }
- lineNumber++;
- }
- else
- shouldSkipLine = true;
- if (!shouldSkipLine)
- {
- if (interestData.checkTrafficDetailCorrectness())
- m_trafficPatterns.push_back(interestData);
- }
+ patternFile.open(m_configurationFile.data());
+ if (patternFile.is_open()) {
+ int lineNumber = 0;
+ std::string patternLine;
+ while (getline(patternFile, patternLine)) {
+ lineNumber++;
+ if (std::isalpha(patternLine[0])) {
+ InterestTrafficConfiguration interestData;
+ bool shouldSkipLine = false;
+ if (interestData.processConfigurationDetail(patternLine, m_logger, lineNumber)) {
+ while (getline(patternFile, patternLine) && std::isalpha(patternLine[0])) {
+ lineNumber++;
+ if (!interestData.processConfigurationDetail(patternLine, m_logger, lineNumber)) {
+ shouldSkipLine = true;
+ break;
}
+ }
+ lineNumber++;
}
- patternFile.close();
- if (!checkTrafficPatternCorrectness())
- {
- m_logger.log("ERROR - Traffic Configuration Provided Is Not Proper- " +
- m_configurationFile, false, true);
- m_logger.shutdownLogger();
- exit(EXIT_FAILURE);
+ else {
+ shouldSkipLine = true;
}
- m_logger.log("Traffic Configuration File Processing Completed\n", true, false);
- for (std::size_t patternId = 0; patternId < m_trafficPatterns.size(); patternId++)
- {
- m_logger.log("Traffic Pattern Type #" +
- to_string(patternId + 1), false, false);
- m_trafficPatterns[patternId].printTrafficConfiguration(m_logger);
- m_logger.log("", false, false);
+ if (!shouldSkipLine) {
+ if (interestData.checkTrafficDetailCorrectness()) {
+ m_trafficPatterns.push_back(interestData);
+ }
}
+ }
}
- else
- {
- m_logger.log("ERROR - Unable To Open Traffic Configuration File: " +
+ patternFile.close();
+
+ if (!checkTrafficPatternCorrectness()) {
+ m_logger.log("ERROR: Traffic configuration provided is not proper - " +
m_configurationFile, false, true);
- m_logger.shutdownLogger();
- exit(EXIT_FAILURE);
+ exit(2);
}
+
+ m_logger.log("Traffic configuration file processing completed.\n", true, false);
+ for (std::size_t patternId = 0; patternId < m_trafficPatterns.size(); patternId++) {
+ m_logger.log("Traffic Pattern Type #" + to_string(patternId + 1), false, false);
+ m_trafficPatterns[patternId].printTrafficConfiguration(m_logger);
+ m_logger.log("", false, false);
+ }
+ }
+ else {
+ m_logger.log("ERROR: Unable to open traffic configuration file: " + m_configurationFile, false, true);
+ exit(2);
+ }
}
void
initializeTrafficConfiguration()
{
- if (boost::filesystem::exists(boost::filesystem::path(m_configurationFile)))
- {
- if (boost::filesystem::is_regular_file(boost::filesystem::path(m_configurationFile)))
- {
- parseConfigurationFile();
- }
- else
- {
- m_logger.log("ERROR - Traffic Configuration File Is Not A Regular File: " +
- m_configurationFile, false, true);
- m_logger.shutdownLogger();
- exit(EXIT_FAILURE);
- }
- }
- else
- {
- m_logger.log("ERROR - Traffic Configuration File Does Not Exist: " +
- m_configurationFile, false, true);
- m_logger.shutdownLogger();
- exit(EXIT_FAILURE);
- }
- }
+ namespace fs = boost::filesystem;
- uint32_t
- getOldNonce()
- {
- if (m_nonces.size() == 0)
- return getNewNonce();
- std::size_t randomNonceIndex = std::rand() % m_nonces.size();
- return m_nonces[randomNonceIndex];
+ fs::path configPath(m_configurationFile);
+ if (fs::exists(configPath)) {
+ if (fs::is_regular_file(configPath)) {
+ parseConfigurationFile();
+ }
+ else {
+ m_logger.log("ERROR: Traffic configuration file is not a regular file: " +
+ m_configurationFile, false, true);
+ exit(2);
+ }
+ }
+ else {
+ m_logger.log("ERROR: Traffic configuration file does not exist: " +
+ m_configurationFile, false, true);
+ exit(2);
+ }
}
uint32_t
getNewNonce()
{
- //Performance Enhancement
- if (m_nonces.size() > 1000)
+ if (m_nonces.size() >= 1000)
m_nonces.clear();
- uint32_t randomNonce = static_cast<uint32_t>(std::rand());
+ auto randomNonce = random::generateWord32();
while (std::find(m_nonces.begin(), m_nonces.end(), randomNonce) != m_nonces.end())
- randomNonce = static_cast<uint32_t>(std::rand());
+ randomNonce = random::generateWord32();
m_nonces.push_back(randomNonce);
return randomNonce;
}
+ uint32_t
+ getOldNonce()
+ {
+ if (m_nonces.empty())
+ return getNewNonce();
+
+ std::uniform_int_distribution<std::size_t> dist(0, m_nonces.size() - 1);
+ return m_nonces[dist(random::getRandomNumberEngine())];
+ }
+
static name::Component
generateRandomNameComponent(std::size_t length)
{
- Buffer buffer(length);
+ // per ISO C++ std, cannot instantiate uniform_int_distribution with uint8_t
+ static std::uniform_int_distribution<unsigned short> dist(std::numeric_limits<uint8_t>::min(),
+ std::numeric_limits<uint8_t>::max());
+
+ Buffer buf(length);
for (std::size_t i = 0; i < length; i++) {
- buffer[i] = static_cast<uint8_t>(std::rand() % 256);
+ buf[i] = static_cast<uint8_t>(dist(random::getRandomNumberEngine()));
}
- return name::Component(buffer);
+ return name::Component(buf);
+ }
+
+ Interest
+ prepareInterest(std::size_t patternId)
+ {
+ Interest interest;
+ auto& pattern = m_trafficPatterns[patternId];
+
+ Name name(pattern.m_name);
+ if (pattern.m_nameAppendBytes > 0) {
+ name.append(generateRandomNameComponent(*pattern.m_nameAppendBytes));
+ }
+ if (pattern.m_nameAppendSeqNum) {
+ auto seqNum = *pattern.m_nameAppendSeqNum;
+ name.appendSequenceNumber(seqNum);
+ pattern.m_nameAppendSeqNum = seqNum + 1;
+ }
+ interest.setName(name);
+
+ if (pattern.m_mustBeFresh)
+ interest.setMustBeFresh(true);
+ else if (!pattern.m_mustBeFresh)
+ interest.setMustBeFresh(false);
+
+ static std::uniform_int_distribution<> duplicateNonceDist(1, 100);
+ if (duplicateNonceDist(random::getRandomNumberEngine()) <= pattern.m_nonceDuplicationPercentage)
+ interest.setNonce(getOldNonce());
+ else
+ interest.setNonce(getNewNonce());
+
+ if (pattern.m_interestLifetime >= 0_ms)
+ interest.setInterestLifetime(pattern.m_interestLifetime);
+
+ if (pattern.m_nextHopFaceId > 0)
+ interest.setTag(make_shared<lp::NextHopFaceIdTag>(pattern.m_nextHopFaceId));
+
+ return interest;
}
void
- onData(const ndn::Interest& interest,
- const ndn::Data& data,
- int globalReference,
- int localReference,
- std::size_t patternId,
- time::steady_clock::TimePoint sentTime)
+ onData(const Data& data, int globalRef, int localRef, std::size_t patternId,
+ const time::steady_clock::TimePoint& sentTime)
{
- std::string logLine = "Data Received - PatternType=" + to_string(patternId + 1);
- logLine += ", GlobalID=" + to_string(globalReference);
- logLine += ", LocalID=" + to_string(localReference);
- logLine += ", Name=" + interest.getName().toUri();
+ auto logLine = "Data Received - PatternType=" + to_string(patternId + 1) +
+ ", GlobalID=" + to_string(globalRef) +
+ ", LocalID=" + to_string(localRef) +
+ ", Name=" + data.getName().toUri();
m_nInterestsReceived++;
m_trafficPatterns[patternId].m_nInterestsReceived++;
- if (!m_trafficPatterns[patternId].m_expectedContent.empty()) {
- std::string receivedContent = reinterpret_cast<const char*>(data.getContent().value());
- std::size_t receivedContentLength = data.getContent().value_size();
- receivedContent = receivedContent.substr(0, receivedContentLength);
- if (receivedContent != m_trafficPatterns[patternId].m_expectedContent) {
+
+ if (m_trafficPatterns[patternId].m_expectedContent) {
+ std::string receivedContent(reinterpret_cast<const char*>(data.getContent().value()),
+ data.getContent().value_size());
+ if (receivedContent != *m_trafficPatterns[patternId].m_expectedContent) {
m_nContentInconsistencies++;
m_trafficPatterns[patternId].m_nContentInconsistencies++;
logLine += ", IsConsistent=No";
}
- else
+ else {
logLine += ", IsConsistent=Yes";
+ }
}
- else
+ else {
logLine += ", IsConsistent=NotChecked";
- if (!m_hasQuietLogging)
+ }
+ if (!m_wantQuiet) {
m_logger.log(logLine, true, false);
+ }
+
double roundTripTime = (time::steady_clock::now() - sentTime).count() / 1000000.0;
if (m_minimumInterestRoundTripTime > roundTripTime)
m_minimumInterestRoundTripTime = roundTripTime;
@@ -533,245 +471,224 @@
m_trafficPatterns[patternId].m_maximumInterestRoundTripTime = roundTripTime;
m_totalInterestRoundTripTime += roundTripTime;
m_trafficPatterns[patternId].m_totalInterestRoundTripTime += roundTripTime;
- if (m_nMaximumInterests >= 0 && globalReference == m_nMaximumInterests) {
- logStatistics();
- m_logger.shutdownLogger();
- m_face.shutdown();
- m_ioService.stop();
+
+ if (m_nMaximumInterests == globalRef) {
+ stop();
}
}
void
- onNack(const ndn::Interest& interest,
- const ndn::lp::Nack& nack,
- int globalReference,
- int localReference,
- std::size_t patternId)
+ onNack(const Interest& interest, const lp::Nack& nack,
+ int globalRef, int localRef, std::size_t patternId)
{
- std::string logLine = "Interest Nack'd - PatternType=" + to_string(patternId + 1);
- logLine += ", GlobalID=" + to_string(globalReference);
- logLine += ", LocalID=" + to_string(localReference);
- logLine += ", Name=" + interest.getName().toUri();
- logLine += ", NackReason=" + boost::lexical_cast<std::string>(nack.getReason());
+ auto logLine = "Interest Nack'd - PatternType=" + to_string(patternId + 1) +
+ ", GlobalID=" + to_string(globalRef) +
+ ", LocalID=" + to_string(localRef) +
+ ", Name=" + interest.getName().toUri() +
+ ", NackReason=" + boost::lexical_cast<std::string>(nack.getReason());
m_logger.log(logLine, true, false);
m_nNacks++;
m_trafficPatterns[patternId].m_nNacks++;
- if (m_nMaximumInterests >= 0 && globalReference == m_nMaximumInterests) {
- logStatistics();
- m_logger.shutdownLogger();
- m_face.shutdown();
- m_ioService.stop();
+ if (m_nMaximumInterests == globalRef) {
+ stop();
}
}
void
- onTimeout(const ndn::Interest& interest,
- int globalReference,
- int localReference,
- int patternId)
+ onTimeout(const Interest& interest, int globalRef, int localRef, int patternId)
{
- std::string logLine = "Interest Timed Out - PatternType=" + to_string(patternId + 1);
- logLine += ", GlobalID=" + to_string(globalReference);
- logLine += ", LocalID=" + to_string(localReference);
- logLine += ", Name=" + interest.getName().toUri();
+ auto logLine = "Interest Timed Out - PatternType=" + to_string(patternId + 1) +
+ ", GlobalID=" + to_string(globalRef) +
+ ", LocalID=" + to_string(localRef) +
+ ", Name=" + interest.getName().toUri();
m_logger.log(logLine, true, false);
- if (m_nMaximumInterests >= 0 && globalReference == m_nMaximumInterests)
- {
- logStatistics();
- m_logger.shutdownLogger();
- m_face.shutdown();
- m_ioService.stop();
- }
+
+ if (m_nMaximumInterests == globalRef) {
+ stop();
+ }
}
void
- generateTraffic(boost::asio::deadline_timer* timer)
+ generateTraffic(boost::asio::deadline_timer& timer)
{
- if (m_nMaximumInterests < 0 || m_nInterestsSent < m_nMaximumInterests)
- {
- int trafficKey = std::rand() % 100;
- int cumulativePercentage = 0;
- std::size_t patternId;
- for (patternId = 0; patternId < m_trafficPatterns.size(); patternId++)
- {
- cumulativePercentage += m_trafficPatterns[patternId].m_trafficPercentage;
- if (trafficKey <= cumulativePercentage)
- {
- Name interestName(m_trafficPatterns[patternId].m_name);
- if (m_trafficPatterns[patternId].m_nameAppendBytes > 0)
- interestName.append(
- generateRandomNameComponent(m_trafficPatterns[patternId].m_nameAppendBytes));
- if (m_trafficPatterns[patternId].m_nameAppendSequenceNumber >= 0)
- {
- interestName.append(
- to_string(m_trafficPatterns[patternId].m_nameAppendSequenceNumber));
- m_trafficPatterns[patternId].m_nameAppendSequenceNumber++;
- }
-
- Interest interest(interestName);
-
- if (m_trafficPatterns[patternId].m_mustBeFresh == 0)
- interest.setMustBeFresh(false);
- else if (m_trafficPatterns[patternId].m_mustBeFresh > 0)
- interest.setMustBeFresh(true);
- if (m_trafficPatterns[patternId].m_nonceDuplicationPercentage > 0)
- {
- int duplicationPercentage = std::rand() % 100;
- if (m_trafficPatterns[patternId].m_nonceDuplicationPercentage <=
- duplicationPercentage)
- interest.setNonce(getOldNonce());
- else
- interest.setNonce(getNewNonce());
- }
- else
- interest.setNonce(getNewNonce());
- if (m_trafficPatterns[patternId].m_interestLifetime >= 0_ms)
- interest.setInterestLifetime(m_trafficPatterns[patternId].m_interestLifetime);
-
- if (m_trafficPatterns[patternId].m_nextHopFaceId > 0) {
- interest.setTag(make_shared<lp::NextHopFaceIdTag>(
- m_trafficPatterns[patternId].m_nextHopFaceId));
- }
-
- try {
- m_nInterestsSent++;
- m_trafficPatterns[patternId].m_nInterestsSent++;
- auto sentTime = time::steady_clock::now();
- m_face.expressInterest(interest,
- bind(&NdnTrafficClient::onData,
- this, _1, _2, m_nInterestsSent,
- m_trafficPatterns[patternId].m_nInterestsSent,
- patternId, sentTime),
- bind(&NdnTrafficClient::onNack,
- this, _1, _2, m_nInterestsSent,
- m_trafficPatterns[patternId].m_nInterestsSent,
- patternId),
- bind(&NdnTrafficClient::onTimeout,
- this, _1, m_nInterestsSent,
- m_trafficPatterns[patternId].m_nInterestsSent,
- patternId));
-
- if (!m_hasQuietLogging) {
- std::string logLine =
- "Sending Interest - PatternType=" + to_string(patternId + 1) +
- ", GlobalID=" + to_string(m_nInterestsSent) +
- ", LocalID=" +
- to_string(m_trafficPatterns[patternId].m_nInterestsSent) +
- ", Name=" + interest.getName().toUri();
- m_logger.log(logLine, true, false);
- }
-
- timer->expires_at(timer->expires_at() +
- boost::posix_time::millisec(m_interestInterval.count()));
- timer->async_wait(bind(&NdnTrafficClient::generateTraffic, this, timer));
- }
- catch (const std::exception& e) {
- m_logger.log("ERROR: "s + e.what(), true, true);
- }
- break;
- }
- }
- if (patternId == m_trafficPatterns.size())
- {
- timer->expires_at(timer->expires_at() +
- boost::posix_time::millisec(m_interestInterval.count()));
- timer->async_wait(bind(&NdnTrafficClient::generateTraffic, this, timer));
- }
- }
- }
-
- void
- run()
- {
- boost::asio::signal_set signalSet(m_ioService, SIGINT, SIGTERM);
- signalSet.async_wait(bind(&NdnTrafficClient::signalHandler, this));
- m_logger.initializeLog(m_instanceId);
- initializeTrafficConfiguration();
-
- if (m_nMaximumInterests == 0) {
- logStatistics();
- m_logger.shutdownLogger();
+ if (m_nMaximumInterests && m_nInterestsSent >= *m_nMaximumInterests) {
return;
}
- boost::asio::deadline_timer deadlineTimer(m_ioService,
- boost::posix_time::millisec(m_interestInterval.count()));
- deadlineTimer.async_wait(bind(&NdnTrafficClient::generateTraffic, this, &deadlineTimer));
+ static std::uniform_int_distribution<> trafficDist(1, 100);
+ int trafficKey = trafficDist(random::getRandomNumberEngine());
- try {
- m_face.processEvents();
+ int cumulativePercentage = 0;
+ std::size_t patternId = 0;
+ for (; patternId < m_trafficPatterns.size(); patternId++) {
+ cumulativePercentage += m_trafficPatterns[patternId].m_trafficPercentage;
+ if (trafficKey <= cumulativePercentage) {
+ auto interest = prepareInterest(patternId);
+ try {
+ m_nInterestsSent++;
+ m_trafficPatterns[patternId].m_nInterestsSent++;
+ auto sentTime = time::steady_clock::now();
+ m_face.expressInterest(interest,
+ bind(&NdnTrafficClient::onData, this, _2, m_nInterestsSent,
+ m_trafficPatterns[patternId].m_nInterestsSent, patternId, sentTime),
+ bind(&NdnTrafficClient::onNack, this, _1, _2, m_nInterestsSent,
+ m_trafficPatterns[patternId].m_nInterestsSent, patternId),
+ bind(&NdnTrafficClient::onTimeout, this, _1, m_nInterestsSent,
+ m_trafficPatterns[patternId].m_nInterestsSent, patternId));
+
+ if (!m_wantQuiet) {
+ auto logLine = "Sending Interest - PatternType=" + to_string(patternId + 1) +
+ ", GlobalID=" + to_string(m_nInterestsSent) +
+ ", LocalID=" + to_string(m_trafficPatterns[patternId].m_nInterestsSent) +
+ ", Name=" + interest.getName().toUri();
+ m_logger.log(logLine, true, false);
+ }
+
+ timer.expires_at(timer.expires_at() +
+ boost::posix_time::millisec(m_interestInterval.count()));
+ timer.async_wait([this, &timer] (auto&&...) { this->generateTraffic(timer); });
+ }
+ catch (const std::exception& e) {
+ m_logger.log("ERROR: "s + e.what(), true, true);
+ }
+ break;
+ }
}
- catch (const std::exception& e) {
- m_logger.log("ERROR: "s + e.what(), true, true);
- m_logger.shutdownLogger();
- m_hasError = true;
- m_ioService.stop();
+ if (patternId == m_trafficPatterns.size()) {
+ timer.expires_at(timer.expires_at() +
+ boost::posix_time::millisec(m_interestInterval.count()));
+ timer.async_wait([this, &timer] (auto&&...) { this->generateTraffic(timer); });
}
}
+ void
+ stop()
+ {
+ if (m_nContentInconsistencies > 0 || m_nInterestsSent != m_nInterestsReceived) {
+ m_hasError = true;
+ }
+
+ logStatistics();
+ m_face.shutdown();
+ m_ioService.stop();
+ }
+
private:
- std::string m_programName;
- Logger m_logger;
- std::string m_instanceId;
- bool m_hasError;
- bool m_hasQuietLogging;
- time::milliseconds m_interestInterval;
- int m_nMaximumInterests;
- std::string m_configurationFile;
boost::asio::io_service m_ioService;
+ boost::asio::signal_set m_signalSet;
+ Logger m_logger;
Face m_face;
+
+ std::string m_configurationFile;
+ optional<uint64_t> m_nMaximumInterests;
+ time::milliseconds m_interestInterval = 1_s;
+ bool m_wantQuiet = false;
+
std::vector<InterestTrafficConfiguration> m_trafficPatterns;
std::vector<uint32_t> m_nonces;
- int m_nInterestsSent;
- int m_nInterestsReceived;
- int m_nNacks;
- int m_nContentInconsistencies;
+ uint64_t m_nInterestsSent = 0;
+ uint64_t m_nInterestsReceived = 0;
+ uint64_t m_nNacks = 0;
+ uint64_t m_nContentInconsistencies = 0;
// RTT is stored as milliseconds with fractional sub-milliseconds precision
- double m_minimumInterestRoundTripTime;
- double m_maximumInterestRoundTripTime;
- double m_totalInterestRoundTripTime;
+ double m_minimumInterestRoundTripTime = std::numeric_limits<double>::max();
+ double m_maximumInterestRoundTripTime = 0;
+ double m_totalInterestRoundTripTime = 0;
+
+ bool m_hasError = false;
};
} // namespace ndn
+static void
+usage(std::ostream& os, const std::string& programName, const po::options_description& desc)
+{
+ os << "Usage: " << programName << " [options] <Traffic_Configuration_File>\n"
+ << "\n"
+ << "Generate Interest traffic as per provided Traffic_Configuration_File.\n"
+ << "Interests are continuously generated unless a total number is specified.\n"
+ << "Set the environment variable NDN_TRAFFIC_LOGFOLDER to redirect output to a log file.\n"
+ << "\n"
+ << desc;
+}
+
int
main(int argc, char* argv[])
{
- std::srand(std::time(nullptr));
+ std::string configFile;
- ndn::NdnTrafficClient client(argv[0]);
- int option;
- while ((option = getopt(argc, argv, "hqi:c:")) != -1) {
- switch (option) {
- case 'h':
- client.usage();
- break;
- case 'i':
- client.setInterestInterval(atoi(optarg));
- break;
- case 'c':
- client.setMaximumInterests(atoi(optarg));
- break;
- case 'q':
- client.setQuietLogging();
- break;
- default:
- client.usage();
- break;
- }
+ po::options_description visibleOptions("Options");
+ visibleOptions.add_options()
+ ("help,h", "print this help message and exit")
+ ("count,c", po::value<int>(), "total number of Interests to be generated")
+ ("interval,i", po::value<ndn::time::milliseconds::rep>()->default_value(1000),
+ "Interest generation interval in milliseconds")
+ ("quiet,q", po::bool_switch(), "turn off logging of Interest generation/Data reception")
+ ;
+
+ po::options_description hiddenOptions;
+ hiddenOptions.add_options()
+ ("config-file", po::value<std::string>(&configFile))
+ ;
+
+ po::positional_options_description posOptions;
+ posOptions.add("config-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(posOptions).run(), vm);
+ po::notify(vm);
+ }
+ catch (const po::error& e) {
+ std::cerr << "ERROR: " << e.what() << std::endl;
+ return 2;
+ }
+ catch (const boost::bad_any_cast& e) {
+ std::cerr << "ERROR: " << e.what() << std::endl;
+ return 2;
}
- argc -= optind;
- argv += optind;
+ if (vm.count("help") > 0) {
+ usage(std::cout, argv[0], visibleOptions);
+ return 0;
+ }
- if (!argc)
- client.usage();
+ if (configFile.empty()) {
+ usage(std::cerr, argv[0], visibleOptions);
+ return 2;
+ }
- client.setConfigurationFile(argv[0]);
+ ndn::NdnTrafficClient client(configFile);
+
+ if (vm.count("count") > 0) {
+ int count = vm["count"].as<int>();
+ if (count < 0) {
+ std::cerr << "ERROR: the argument for option '--count' cannot be negative" << std::endl;
+ return 2;
+ }
+ client.setMaximumInterests(static_cast<uint64_t>(count));
+ }
+
+ if (vm.count("interval") > 0) {
+ ndn::time::milliseconds interval(vm["interval"].as<ndn::time::milliseconds::rep>());
+ if (interval <= ndn::time::milliseconds::zero()) {
+ std::cerr << "ERROR: the argument for option '--interval' must be positive" << std::endl;
+ return 2;
+ }
+ client.setInterestInterval(interval);
+ }
+
+ if (vm["quiet"].as<bool>()) {
+ client.setQuietLogging();
+ }
+
client.run();
- return client.hasError() ? EXIT_FAILURE : EXIT_SUCCESS;
+ return client.hasError() ? 1 : 0;
}
diff --git a/src/ndn-traffic-server.cpp b/src/ndn-traffic-server.cpp
index 83ea6db..a6d8fef 100644
--- a/src/ndn-traffic-server.cpp
+++ b/src/ndn-traffic-server.cpp
@@ -1,6 +1,6 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2014-2018 Arizona Board of Regents.
+ * Copyright (c) 2014-2019, Arizona Board of Regents.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,23 +19,29 @@
*/
#include "logger.hpp"
+#include "util.hpp"
+#include <ndn-cxx/data.hpp>
#include <ndn-cxx/face.hpp>
#include <ndn-cxx/security/key-chain.hpp>
#include <ndn-cxx/security/signing-info.hpp>
#include <ndn-cxx/util/backports.hpp>
+#include <ndn-cxx/util/random.hpp>
+
+#include <cctype>
+#include <limits>
+#include <sstream>
+#include <vector>
#include <boost/asio/io_service.hpp>
#include <boost/asio/signal_set.hpp>
-#include <boost/filesystem.hpp>
#include <boost/noncopyable.hpp>
+#include <boost/program_options/options_description.hpp>
+#include <boost/program_options/parsers.hpp>
+#include <boost/program_options/variables_map.hpp>
+#include <boost/thread/thread.hpp>
-#include <cctype>
-#include <cstdlib>
-#include <fstream>
-#include <string>
-#include <unistd.h>
-#include <vector>
+namespace po = boost::program_options;
namespace ndn {
@@ -43,180 +49,14 @@
{
public:
explicit
- NdnTrafficServer(const char* programName)
- : m_logger("NdnTrafficServer")
- , m_programName(programName)
- , m_hasError(false)
- , m_hasQuietLogging(false)
- , m_nRegistrationsFailed(0)
- , m_nMaximumInterests(-1)
- , m_nInterestsReceived(0)
- , m_contentDelay(time::milliseconds(-1))
- , m_instanceId(to_string(std::rand()))
+ NdnTrafficServer(const std::string& configFile)
+ : m_signalSet(m_ioService, SIGINT, SIGTERM)
+ , m_logger("NdnTrafficServer")
, m_face(m_ioService)
- , m_signalSet(m_ioService, SIGINT, SIGTERM)
+ , m_configurationFile(configFile)
{
}
- class DataTrafficConfiguration
- {
- public:
- DataTrafficConfiguration()
- : m_contentType(-1)
- , m_freshnessPeriod(time::milliseconds(-1))
- , m_contentBytes(-1)
- , m_contentDelay(time::milliseconds(-1))
- , m_nInterestsReceived(0)
- , m_signingInfo()
- {
- }
-
- void
- printTrafficConfiguration(Logger& logger)
- {
- std::stringstream detail;
-
- if (!m_name.empty()) {
- detail << "Name=" << m_name << ", ";
- }
- if (m_contentType >= 0) {
- detail << "ContentType=" << to_string(m_contentType) << ", ";
- }
- if (m_freshnessPeriod >= time::milliseconds(0)) {
- detail << "FreshnessPeriod=" <<
- to_string(static_cast<int>(m_freshnessPeriod.count())) << ", ";
- }
- if (m_contentBytes >= 0) {
- detail << "ContentBytes=" << to_string(m_contentBytes) << ", ";
- }
- if (m_contentDelay >= time::milliseconds(0)) {
- detail << "ContentDelay=" << to_string(m_contentDelay.count()) << ", ";
- }
- if (!m_content.empty()) {
- detail << "Content=" << m_content << ", ";
- }
- detail << "SigningInfo=" << m_signingInfo;
-
- logger.log(detail.str(), false, false);
- }
-
- bool
- extractParameterValue(const std::string& detail, std::string& parameter, std::string& value)
- {
- std::string allowedCharacters = ":/+._-%";
- std::size_t i = 0;
-
- parameter = "";
- value = "";
- while (detail[i] != '=' && i < detail.length()) {
- parameter += detail[i];
- i++;
- }
- if (i == detail.length())
- return false;
-
- i++;
- while ((std::isalnum(detail[i]) ||
- allowedCharacters.find(detail[i]) != std::string::npos) &&
- i < detail.length()) {
- value += detail[i];
- i++;
- }
-
- if (parameter.empty() || value.empty())
- return false;
- else
- return true;
- }
-
- bool
- processConfigurationDetail(const std::string& detail,
- Logger& logger,
- int lineNumber)
- {
- std::string parameter, value;
- if (extractParameterValue(detail, parameter, value)) {
- if (parameter == "Name") {
- m_name = value;
- }
- else if (parameter == "ContentType") {
- m_contentType = std::stoi(value);
- }
- else if (parameter == "FreshnessPeriod") {
- m_freshnessPeriod = time::milliseconds(std::stoi(value));
- }
- else if (parameter == "ContentDelay") {
- m_contentDelay = time::milliseconds(std::stoi(value));
- }
- else if (parameter == "ContentBytes") {
- m_contentBytes = std::stoi(value);
- }
- else if (parameter == "Content") {
- m_content = value;
- }
- else if (parameter == "SigningInfo") {
- m_signingInfo = security::SigningInfo(value);
- }
- else {
- logger.log("Line " + to_string(lineNumber) +
- " \t- Invalid Parameter='" + parameter + "'", false, true);
- }
- }
- else {
- logger.log("Line " + to_string(lineNumber) +
- " \t- Improper Traffic Configuration Line - " + detail, false, true);
- return false;
- }
-
- return true;
- }
-
- bool
- checkTrafficDetailCorrectness()
- {
- return true;
- }
-
- private:
- std::string m_name;
- int m_contentType;
- time::milliseconds m_freshnessPeriod;
- int m_contentBytes;
- time::milliseconds m_contentDelay;
- std::string m_content;
- int m_nInterestsReceived;
- security::SigningInfo m_signingInfo;
-
- friend class NdnTrafficServer;
- };
-
- void
- usage() const
- {
- std::cout << "Usage:\n"
- << " " << m_programName << " [options] <Traffic_Configuration_File>\n"
- << "\n"
- << "Respond to Interests as per provided Traffic Configuration File.\n"
- << "Multiple prefixes can be configured for handling.\n"
- << "Set environment variable NDN_TRAFFIC_LOGFOLDER to redirect output to a log file.\n"
- << "\n"
- << "Options:\n"
- << " [-d interval] - set delay before responding to interest, in milliseconds\n"
- << " [-c count] - specify maximum number of interests to be satisfied\n"
- << " [-q] - quiet mode: no interest reception/data generation logging\n"
- << " [-h] - print this help text and exit\n";
- exit(EXIT_FAILURE);
- }
-
- void
- setMaximumInterests(int maximumInterests)
- {
- if (maximumInterests < 0) {
- usage();
- }
- m_nMaximumInterests = maximumInterests;
- }
-
bool
hasError() const
{
@@ -224,37 +64,148 @@
}
void
- setContentDelay(int contentDelay)
+ setMaximumInterests(uint64_t maxInterests)
{
- if (contentDelay < 0) {
- usage();
- }
- m_contentDelay = time::milliseconds(contentDelay);
+ m_nMaximumInterests = maxInterests;
}
void
- setConfigurationFile(const char* configurationFile)
+ setContentDelay(time::milliseconds delay)
{
- m_configurationFile = configurationFile;
+ BOOST_ASSERT(delay >= 0_ms);
+ m_contentDelay = delay;
}
void
setQuietLogging()
{
- m_hasQuietLogging = true;
+ m_wantQuiet = true;
}
void
- signalHandler()
+ run()
{
- logStatistics();
+ m_logger.initializeLog(to_string(random::generateWord32()));
+ initializeTrafficConfiguration();
- m_face.shutdown();
- m_ioService.stop();
+ if (m_nMaximumInterests == 0) {
+ logStatistics();
+ return;
+ }
- exit(m_hasError ? EXIT_FAILURE : EXIT_SUCCESS);
+ m_signalSet.async_wait([this] (const boost::system::error_code&, int) {
+ if (m_nMaximumInterests && m_nInterestsReceived < *m_nMaximumInterests) {
+ m_hasError = true;
+ }
+ stop();
+ });
+
+ for (std::size_t id = 0; id < m_trafficPatterns.size(); id++) {
+ m_registeredPrefixes.push_back(
+ m_face.setInterestFilter(m_trafficPatterns[id].m_name,
+ [=] (auto&&, const auto& interest) { this->onInterest(interest, id); },
+ nullptr,
+ [=] (auto&&, const auto& reason) { this->onRegisterFailed(reason, id); }));
+ }
+
+ try {
+ m_face.processEvents();
+ }
+ catch (const std::exception& e) {
+ m_logger.log("ERROR: "s + e.what(), true, true);
+ m_hasError = true;
+ m_ioService.stop();
+ }
}
+private:
+ class DataTrafficConfiguration
+ {
+ public:
+ void
+ printTrafficConfiguration(Logger& logger) const
+ {
+ std::ostringstream os;
+
+ if (!m_name.empty()) {
+ os << "Name=" << m_name << ", ";
+ }
+ if (m_contentDelay >= 0_ms) {
+ os << "ContentDelay=" << m_contentDelay.count() << ", ";
+ }
+ if (m_freshnessPeriod >= 0_ms) {
+ os << "FreshnessPeriod=" << m_freshnessPeriod.count() << ", ";
+ }
+ if (m_contentType) {
+ os << "ContentType=" << *m_contentType << ", ";
+ }
+ if (m_contentLength) {
+ os << "ContentBytes=" << *m_contentLength << ", ";
+ }
+ if (!m_content.empty()) {
+ os << "Content=" << m_content << ", ";
+ }
+ os << "SigningInfo=" << m_signingInfo;
+
+ logger.log(os.str(), false, false);
+ }
+
+ bool
+ processConfigurationDetail(const std::string& detail, Logger& logger, int lineNumber)
+ {
+ std::string parameter, value;
+ if (parseParameterAndValue(detail, parameter, value)) {
+ if (parameter == "Name") {
+ m_name = value;
+ }
+ else if (parameter == "ContentDelay") {
+ m_contentDelay = time::milliseconds(std::stoul(value));
+ }
+ else if (parameter == "FreshnessPeriod") {
+ m_freshnessPeriod = time::milliseconds(std::stoul(value));
+ }
+ else if (parameter == "ContentType") {
+ m_contentType = std::stoul(value);
+ }
+ else if (parameter == "ContentBytes") {
+ m_contentLength = std::stoul(value);
+ }
+ else if (parameter == "Content") {
+ m_content = value;
+ }
+ else if (parameter == "SigningInfo") {
+ m_signingInfo = security::SigningInfo(value);
+ }
+ else {
+ logger.log("Line " + to_string(lineNumber) +
+ " - Unknown parameter '" + parameter + "'", false, true);
+ }
+ }
+ else {
+ logger.log("Line " + to_string(lineNumber) +
+ " - Invalid traffic configuration line: " + detail, false, true);
+ return false;
+ }
+ return true;
+ }
+
+ bool
+ checkTrafficDetailCorrectness() const
+ {
+ return true;
+ }
+
+ public:
+ std::string m_name;
+ time::milliseconds m_contentDelay = -1_ms;
+ time::milliseconds m_freshnessPeriod = -1_ms;
+ optional<uint32_t> m_contentType;
+ optional<std::size_t> m_contentLength;
+ std::string m_content;
+ security::SigningInfo m_signingInfo;
+ uint64_t m_nInterestsReceived = 0;
+ };
+
void
logStatistics()
{
@@ -264,20 +215,16 @@
m_logger.log("Total Interests Received = " +
to_string(m_nInterestsReceived), false, true);
- if (m_nInterestsReceived < m_nMaximumInterests) {
- m_hasError = true;
- }
-
for (std::size_t patternId = 0; patternId < m_trafficPatterns.size(); patternId++) {
m_logger.log("\nTraffic Pattern Type #" + to_string(patternId + 1), false, true);
m_trafficPatterns[patternId].printTrafficConfiguration(m_logger);
- m_logger.log("Total Interests Received = " + to_string(
- m_trafficPatterns[patternId].m_nInterestsReceived) + "\n", false, true);
+ m_logger.log("Total Interests Received = " +
+ to_string(m_trafficPatterns[patternId].m_nInterestsReceived) + "\n", false, true);
}
}
bool
- checkTrafficPatternCorrectness()
+ checkTrafficPatternCorrectness() const
{
return true;
}
@@ -285,13 +232,13 @@
void
parseConfigurationFile()
{
- std::string patternLine;
std::ifstream patternFile;
- m_logger.log("Analyzing Traffic Configuration File: " + m_configurationFile, true, true);
+ m_logger.log("Parsing traffic configuration file: " + m_configurationFile, true, true);
- patternFile.open(m_configurationFile.c_str());
+ patternFile.open(m_configurationFile.data());
if (patternFile.is_open()) {
int lineNumber = 0;
+ std::string patternLine;
while (getline(patternFile, patternLine)) {
lineNumber++;
if (std::isalpha(patternLine[0])) {
@@ -320,209 +267,241 @@
patternFile.close();
if (!checkTrafficPatternCorrectness()) {
- m_logger.log("ERROR - Traffic Configuration Provided Is Not Proper - " +
+ m_logger.log("ERROR: Traffic configuration provided is not proper - " +
m_configurationFile, false, true);
- exit(EXIT_FAILURE);
+ exit(2);
}
- m_logger.log("Traffic Configuration File Processing Completed\n", true, false);
+ m_logger.log("Traffic configuration file processing completed.\n", true, false);
for (std::size_t patternId = 0; patternId < m_trafficPatterns.size(); patternId++) {
- m_logger.log("Traffic Pattern Type #" +
- to_string(patternId + 1), false, false);
+ m_logger.log("Traffic Pattern Type #" + to_string(patternId + 1), false, false);
m_trafficPatterns[patternId].printTrafficConfiguration(m_logger);
m_logger.log("", false, false);
}
}
else {
- m_logger.log("ERROR - Unable To Open Traffic Configuration File: " +
- m_configurationFile, false, true);
- exit(EXIT_FAILURE);
+ m_logger.log("ERROR: Unable to open traffic configuration file: " + m_configurationFile, false, true);
+ exit(2);
}
}
void
initializeTrafficConfiguration()
{
- if (boost::filesystem::exists(boost::filesystem::path(m_configurationFile))) {
- if (boost::filesystem::is_regular_file(boost::filesystem::path(m_configurationFile))) {
+ namespace fs = boost::filesystem;
+
+ fs::path configPath(m_configurationFile);
+ if (fs::exists(configPath)) {
+ if (fs::is_regular_file(configPath)) {
parseConfigurationFile();
}
else {
- m_logger.log("ERROR - Traffic Configuration File Is Not A Regular File: " +
+ m_logger.log("ERROR: Traffic configuration file is not a regular file: " +
m_configurationFile, false, true);
- exit(EXIT_FAILURE);
+ exit(2);
}
}
else {
- m_logger.log("ERROR - Traffic Configuration File Does Not Exist: " +
+ m_logger.log("ERROR: Traffic configuration file does not exist: " +
m_configurationFile, false, true);
- exit(EXIT_FAILURE);
+ exit(2);
}
}
static std::string
- getRandomByteString(std::size_t randomSize)
+ getRandomByteString(std::size_t length)
{
- std::string randomString;
- for (std::size_t i = 0; i < randomSize; i++) {
- randomString += static_cast<char>(std::rand() % 128);
+ // per ISO C++ std, cannot instantiate uniform_int_distribution with char
+ static std::uniform_int_distribution<short> dist(std::numeric_limits<char>::min(),
+ std::numeric_limits<char>::max());
+
+ std::string s;
+ s.reserve(length);
+ for (std::size_t i = 0; i < length; i++) {
+ s += static_cast<char>(dist(random::getRandomNumberEngine()));
}
- return randomString;
+ return s;
}
void
- onInterest(const Name& name, const Interest& interest, int patternId)
+ onInterest(const Interest& interest, std::size_t patternId)
{
auto& pattern = m_trafficPatterns[patternId];
- if (m_nMaximumInterests < 0 || m_nInterestsReceived < m_nMaximumInterests) {
+ if (!m_nMaximumInterests || m_nInterestsReceived < *m_nMaximumInterests) {
Data data(interest.getName());
- if (pattern.m_contentType >= 0)
- data.setContentType(pattern.m_contentType);
-
- if (pattern.m_freshnessPeriod >= time::milliseconds(0))
+ if (pattern.m_freshnessPeriod >= 0_ms)
data.setFreshnessPeriod(pattern.m_freshnessPeriod);
+ if (pattern.m_contentType)
+ data.setContentType(*pattern.m_contentType);
+
std::string content;
- if (pattern.m_contentBytes >= 0)
- content = getRandomByteString(pattern.m_contentBytes);
+ if (pattern.m_contentLength > 0)
+ content = getRandomByteString(*pattern.m_contentLength);
if (!pattern.m_content.empty())
content = pattern.m_content;
+ data.setContent(reinterpret_cast<const uint8_t*>(content.data()), content.length());
- data.setContent(reinterpret_cast<const uint8_t*>(content.c_str()), content.length());
m_keyChain.sign(data, pattern.m_signingInfo);
m_nInterestsReceived++;
pattern.m_nInterestsReceived++;
- if (!m_hasQuietLogging) {
- std::string logLine =
- "Interest Received - PatternType=" + to_string(patternId + 1) +
- ", GlobalID=" + to_string(m_nInterestsReceived) +
- ", LocalID=" + to_string(pattern.m_nInterestsReceived) +
- ", Name=" + pattern.m_name;
+ if (!m_wantQuiet) {
+ auto logLine = "Interest received - PatternType=" + to_string(patternId + 1) +
+ ", GlobalID=" + to_string(m_nInterestsReceived) +
+ ", LocalID=" + to_string(pattern.m_nInterestsReceived) +
+ ", Name=" + pattern.m_name;
m_logger.log(logLine, true, false);
}
- if (pattern.m_contentDelay > time::milliseconds(-1))
- usleep(pattern.m_contentDelay.count() * 1000);
- if (m_contentDelay > time::milliseconds(-1))
- usleep(m_contentDelay.count() * 1000);
+ if (pattern.m_contentDelay > 0_ms)
+ boost::this_thread::sleep_for(pattern.m_contentDelay);
+ if (m_contentDelay > 0_ms)
+ boost::this_thread::sleep_for(m_contentDelay);
+
m_face.put(data);
}
- if (m_nMaximumInterests >= 0 && m_nInterestsReceived == m_nMaximumInterests) {
+
+ if (m_nMaximumInterests && m_nInterestsReceived >= *m_nMaximumInterests) {
logStatistics();
- for (auto registeredPrefix : m_registeredPrefixes) {
- m_face.unsetInterestFilter(registeredPrefix);
- }
+ m_registeredPrefixes.clear();
m_signalSet.cancel();
}
}
void
- onRegisterFailed(const ndn::Name& prefix, const std::string& reason, int patternId)
+ onRegisterFailed(const std::string& reason, std::size_t patternId)
{
- std::string logLine;
- logLine += "Prefix Registration Failed - PatternType=" + to_string(patternId + 1);
- logLine += ", Name=" + m_trafficPatterns[patternId].m_name;
+ auto logLine = "Prefix registration failed - PatternType=" + to_string(patternId + 1) +
+ ", Name=" + m_trafficPatterns[patternId].m_name +
+ ", Reason=" + reason;
m_logger.log(logLine, true, true);
m_nRegistrationsFailed++;
if (m_nRegistrationsFailed == m_trafficPatterns.size()) {
m_hasError = true;
- signalHandler();
+ stop();
}
}
void
- run()
+ stop()
{
- m_signalSet.async_wait(bind(&NdnTrafficServer::signalHandler, this));
-
- m_logger.initializeLog(m_instanceId);
- initializeTrafficConfiguration();
- if (m_nMaximumInterests == 0) {
- logStatistics();
- return;
- }
-
- for (std::size_t patternId = 0; patternId < m_trafficPatterns.size(); patternId++) {
- m_registeredPrefixes.push_back(
- m_face.setInterestFilter(m_trafficPatterns[patternId].m_name,
- bind(&NdnTrafficServer::onInterest, this, _1, _2, patternId),
- nullptr,
- bind(&NdnTrafficServer::onRegisterFailed, this, _1, _2, patternId)));
- }
-
- try {
- m_face.processEvents();
- }
- catch (const std::exception& e) {
- m_logger.log("ERROR: " + std::string(e.what()), true, true);
- m_hasError = true;
- m_ioService.stop();
- }
+ logStatistics();
+ m_face.shutdown();
+ m_ioService.stop();
}
private:
- KeyChain m_keyChain;
- Logger m_logger;
- std::string m_programName;
- bool m_hasError;
- bool m_hasQuietLogging;
- std::size_t m_nRegistrationsFailed;
- int m_nMaximumInterests;
- int m_nInterestsReceived;
- time::milliseconds m_contentDelay;
- std::string m_instanceId;
- std::string m_configurationFile;
-
boost::asio::io_service m_ioService;
- Face m_face;
boost::asio::signal_set m_signalSet;
+ Logger m_logger;
+ Face m_face;
+ KeyChain m_keyChain;
+
+ std::string m_configurationFile;
+ optional<uint64_t> m_nMaximumInterests;
+ time::milliseconds m_contentDelay = 0_ms;
+ bool m_wantQuiet = false;
+
std::vector<DataTrafficConfiguration> m_trafficPatterns;
- std::vector<const RegisteredPrefixId*> m_registeredPrefixes;
+ std::vector<ScopedRegisteredPrefixHandle> m_registeredPrefixes;
+ uint64_t m_nRegistrationsFailed = 0;
+ uint64_t m_nInterestsReceived = 0;
+ bool m_hasError = false;
};
} // namespace ndn
+static void
+usage(std::ostream& os, const std::string& programName, const po::options_description& desc)
+{
+ os << "Usage: " << programName << " [options] <Traffic_Configuration_File>\n"
+ << "\n"
+ << "Respond to Interests as per provided Traffic_Configuration_File.\n"
+ << "Multiple prefixes can be configured for handling.\n"
+ << "Set the environment variable NDN_TRAFFIC_LOGFOLDER to redirect output to a log file.\n"
+ << "\n"
+ << desc;
+}
+
int
main(int argc, char* argv[])
{
- std::srand(std::time(nullptr));
+ std::string configFile;
- ndn::NdnTrafficServer server(argv[0]);
- int option;
- while ((option = getopt(argc, argv, "hqc:d:")) != -1) {
- switch (option) {
- case 'h':
- server.usage();
- break;
- case 'c':
- server.setMaximumInterests(atoi(optarg));
- break;
- case 'd':
- server.setContentDelay(atoi(optarg));
- break;
- case 'q':
- server.setQuietLogging();
- break;
- default:
- server.usage();
- break;
+ po::options_description visibleOptions("Options");
+ visibleOptions.add_options()
+ ("help,h", "print this help message and exit")
+ ("count,c", po::value<int>(), "maximum number of Interests to respond to")
+ ("delay,d", po::value<ndn::time::milliseconds::rep>()->default_value(0),
+ "wait this amount of milliseconds before responding to each Interest")
+ ("quiet,q", po::bool_switch(), "turn off logging of Interest reception/Data generation")
+ ;
+
+ po::options_description hiddenOptions;
+ hiddenOptions.add_options()
+ ("config-file", po::value<std::string>(&configFile))
+ ;
+
+ po::positional_options_description posOptions;
+ posOptions.add("config-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(posOptions).run(), vm);
+ po::notify(vm);
+ }
+ catch (const po::error& e) {
+ std::cerr << "ERROR: " << e.what() << std::endl;
+ return 2;
+ }
+ catch (const boost::bad_any_cast& e) {
+ std::cerr << "ERROR: " << e.what() << std::endl;
+ return 2;
+ }
+
+ if (vm.count("help") > 0) {
+ usage(std::cout, argv[0], visibleOptions);
+ return 0;
+ }
+
+ if (configFile.empty()) {
+ usage(std::cerr, argv[0], visibleOptions);
+ return 2;
+ }
+
+ ndn::NdnTrafficServer server(configFile);
+
+ if (vm.count("count") > 0) {
+ int count = vm["count"].as<int>();
+ if (count < 0) {
+ std::cerr << "ERROR: the argument for option '--count' cannot be negative" << std::endl;
+ return 2;
}
+ server.setMaximumInterests(static_cast<uint64_t>(count));
}
- argc -= optind;
- argv += optind;
-
- if (!argc) {
- server.usage();
+ if (vm.count("delay") > 0) {
+ ndn::time::milliseconds delay(vm["delay"].as<ndn::time::milliseconds::rep>());
+ if (delay < ndn::time::milliseconds::zero()) {
+ std::cerr << "ERROR: the argument for option '--delay' cannot be negative" << std::endl;
+ return 2;
+ }
+ server.setContentDelay(delay);
}
- server.setConfigurationFile(argv[0]);
+ if (vm["quiet"].as<bool>()) {
+ server.setQuietLogging();
+ }
+
server.run();
- return server.hasError() ? EXIT_FAILURE : EXIT_SUCCESS;
+ return server.hasError() ? 1 : 0;
}
diff --git a/src/util.hpp b/src/util.hpp
new file mode 100644
index 0000000..65052d8
--- /dev/null
+++ b/src/util.hpp
@@ -0,0 +1,61 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2019, Arizona Board of Regents.
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Jerald Paul Abraham <jeraldabraham@email.arizona.edu>
+ */
+
+#ifndef NTG_UTIL_HPP
+#define NTG_UTIL_HPP
+
+#include <cctype>
+#include <string>
+
+namespace ndn {
+
+static inline bool
+parseParameterAndValue(const std::string& input, std::string& parameter, std::string& value)
+{
+ static const std::string allowedCharacters = ":/+._-%";
+ parameter = "";
+ value = "";
+
+ std::size_t i = 0;
+ // parse the parameter name
+ while (i < input.length() && input[i] != '=') {
+ parameter += input[i];
+ i++;
+ }
+ if (i == input.length()) {
+ return false;
+ }
+
+ // skip the equal sign
+ i++;
+
+ // parse the value
+ while (i < input.length() &&
+ (std::isalnum(input[i]) || allowedCharacters.find(input[i]) != std::string::npos)) {
+ value += input[i];
+ i++;
+ }
+
+ return !parameter.empty() && !value.empty() && i == input.length();
+}
+
+} // namespace ndn
+
+#endif // NTG_UTIL_HPP