| /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */ |
| /** |
| * Copyright (C) 2014-2016 The University of Arizona. |
| * |
| * 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> |
| */ |
| |
| #include <cctype> |
| #include <cstdlib> |
| #include <fstream> |
| #include <string> |
| #include <unistd.h> |
| #include <vector> |
| |
| #include <boost/asio.hpp> |
| #include <boost/date_time/posix_time/posix_time.hpp> |
| #include <boost/filesystem.hpp> |
| #include <boost/noncopyable.hpp> |
| |
| #include <ndn-cxx/exclude.hpp> |
| #include <ndn-cxx/face.hpp> |
| #include <ndn-cxx/name-component.hpp> |
| #include <ndn-cxx/util/backports.hpp> |
| |
| #include "logger.hpp" |
| |
| namespace ndn { |
| |
| class NdnTrafficClient : boost::noncopyable |
| { |
| public: |
| explicit |
| NdnTrafficClient(const char* programName) |
| : m_programName(programName) |
| , 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) |
| { |
| } |
| |
| class InterestTrafficConfiguration |
| { |
| public: |
| InterestTrafficConfiguration() |
| : m_trafficPercentage(-1) |
| , m_nameAppendBytes(-1) |
| , m_nameAppendSequenceNumber(-1) |
| , m_minSuffixComponents(-1) |
| , m_maxSuffixComponents(-1) |
| , m_excludeBeforeBytes(-1) |
| , m_excludeAfterBytes(-1) |
| , m_childSelector(-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 time::milliseconds(-1); |
| } |
| |
| 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_minSuffixComponents >= 0) |
| detail += "MinSuffixComponents=" + to_string(m_minSuffixComponents) + ", "; |
| if (m_maxSuffixComponents >= 0) |
| detail += "MaxSuffixComponents=" + to_string(m_maxSuffixComponents) + ", "; |
| if (!m_excludeBefore.empty()) |
| detail += "ExcludeBefore=" + m_excludeBefore + ", "; |
| if (!m_excludeAfter.empty()) |
| detail += "ExcludeAfter=" + m_excludeAfter + ", "; |
| if (m_excludeBeforeBytes > 0) |
| detail += "ExcludeBeforeBytes=" + to_string(m_excludeBeforeBytes) + ", "; |
| if (m_excludeAfterBytes > 0) |
| detail += "ExcludeAfterBytes=" + to_string(m_excludeAfterBytes) + ", "; |
| if (m_childSelector >= 0) |
| detail += "ChildSelector=" + to_string(m_childSelector) + ", "; |
| if (m_mustBeFresh >= 0) |
| detail += "MustBeFresh=" + to_string(m_mustBeFresh) + ", "; |
| if (m_nonceDuplicationPercentage > 0) |
| detail += "NonceDuplicationPercentage=" + to_string(m_nonceDuplicationPercentage) + ", "; |
| if (m_interestLifetime >= time::milliseconds(0)) |
| 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 == "MinSuffixComponents") |
| m_minSuffixComponents = std::stoi(value); |
| else if (parameter == "MaxSuffixComponents") |
| m_maxSuffixComponents = std::stoi(value); |
| else if (parameter == "ExcludeBefore") |
| m_excludeBefore = value; |
| else if (parameter == "ExcludeAfter") |
| m_excludeAfter = value; |
| else if (parameter == "ExcludeBeforeBytes") |
| m_excludeBeforeBytes = std::stoi(value); |
| else if (parameter == "ExcludeAfterBytes") |
| m_excludeAfterBytes = std::stoi(value); |
| else if (parameter == "ChildSelector") |
| m_childSelector = 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_minSuffixComponents; |
| int m_maxSuffixComponents; |
| std::string m_excludeBefore; |
| std::string m_excludeAfter; |
| int m_excludeBeforeBytes; |
| int m_excludeAfterBytes; |
| int m_childSelector; |
| 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 |
| { |
| return m_hasError; |
| } |
| |
| void |
| usage() const |
| { |
| 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 time::milliseconds(1000); |
| } |
| |
| void |
| setInterestInterval(int interestInterval) |
| { |
| 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; |
| } |
| |
| void |
| setQuietLogging() |
| { |
| m_hasQuietLogging = true; |
| } |
| |
| void |
| signalHandler() |
| { |
| logStatistics(); |
| |
| m_logger.shutdownLogger(); |
| m_face.shutdown(); |
| m_ioService.stop(); |
| |
| exit(m_hasError ? EXIT_FAILURE : EXIT_SUCCESS); |
| } |
| |
| 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); |
| m_logger.log("Total Interests Sent = " + |
| to_string(m_nInterestsSent), false, true); |
| m_logger.log("Total Responses Received = " + |
| to_string(m_nInterestsReceived), false, true); |
| m_logger.log("Total Nacks Received = " + |
| to_string(m_nNacks), false, true); |
| |
| double loss = 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; |
| } |
| m_logger.log("Total Data Inconsistency = " + |
| to_string(inconsistency) + "%", false, true); |
| m_logger.log("Total Round Trip Time = " + |
| to_string(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() |
| { |
| return true; |
| } |
| |
| void |
| parseConfigurationFile() |
| { |
| std::string patternLine; |
| std::ifstream patternFile; |
| m_logger.log("Analyzing 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.close(); |
| if (!checkTrafficPatternCorrectness()) |
| { |
| m_logger.log("ERROR - Traffic Configuration Provided Is Not Proper- " + |
| m_configurationFile, false, true); |
| m_logger.shutdownLogger(); |
| exit(EXIT_FAILURE); |
| } |
| 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); |
| m_logger.shutdownLogger(); |
| exit(EXIT_FAILURE); |
| } |
| } |
| |
| 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); |
| } |
| } |
| |
| uint32_t |
| getOldNonce() |
| { |
| if (m_nonces.size() == 0) |
| return getNewNonce(); |
| int randomNonceIndex = std::rand() % m_nonces.size(); |
| return m_nonces[randomNonceIndex]; |
| } |
| |
| uint32_t |
| getNewNonce() |
| { |
| //Performance Enhancement |
| if (m_nonces.size() > 1000) |
| m_nonces.clear(); |
| |
| uint32_t randomNonce = static_cast<uint32_t>(std::rand()); |
| while (std::find(m_nonces.begin(), m_nonces.end(), randomNonce) != m_nonces.end()) |
| randomNonce = static_cast<uint32_t>(std::rand()); |
| |
| m_nonces.push_back(randomNonce); |
| return randomNonce; |
| } |
| |
| static name::Component |
| generateRandomNameComponent(size_t length) |
| { |
| Buffer buffer(length); |
| for (size_t i = 0; i < length; i++) { |
| buffer[i] = static_cast<uint8_t>(std::rand() % 256); |
| } |
| return name::Component(buffer); |
| } |
| |
| void |
| onData(const ndn::Interest& interest, |
| const ndn::Data& data, |
| int globalReference, |
| int localReference, |
| int patternId, |
| 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(); |
| |
| m_nInterestsReceived++; |
| m_trafficPatterns[patternId].m_nInterestsReceived++; |
| if (!m_trafficPatterns[patternId].m_expectedContent.empty()) |
| { |
| std::string receivedContent = reinterpret_cast<const char*>(data.getContent().value()); |
| int receivedContentLength = data.getContent().value_size(); |
| receivedContent = receivedContent.substr(0, receivedContentLength); |
| if (receivedContent != m_trafficPatterns[patternId].m_expectedContent) |
| { |
| m_nContentInconsistencies++; |
| m_trafficPatterns[patternId].m_nContentInconsistencies++; |
| logLine += ", IsConsistent=No"; |
| } |
| else |
| logLine += ", IsConsistent=Yes"; |
| } |
| else |
| logLine += ", IsConsistent=NotChecked"; |
| if (!m_hasQuietLogging) |
| m_logger.log(logLine, true, false); |
| double roundTripTime = (time::steady_clock::now() - sentTime).count() / 1000000.0; |
| if (m_minimumInterestRoundTripTime > roundTripTime) |
| m_minimumInterestRoundTripTime = roundTripTime; |
| if (m_maximumInterestRoundTripTime < roundTripTime) |
| m_maximumInterestRoundTripTime = roundTripTime; |
| if (m_trafficPatterns[patternId].m_minimumInterestRoundTripTime > roundTripTime) |
| m_trafficPatterns[patternId].m_minimumInterestRoundTripTime = roundTripTime; |
| if (m_trafficPatterns[patternId].m_maximumInterestRoundTripTime < roundTripTime) |
| 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(); |
| } |
| } |
| |
| void |
| onNack(const ndn::Interest& interest, |
| const ndn::lp::Nack& nack, |
| int globalReference, |
| int localReference, |
| int 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=" + to_string((int)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(); |
| } |
| } |
| |
| void |
| onTimeout(const ndn::Interest& interest, |
| int globalReference, |
| int localReference, |
| 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(); |
| m_logger.log(logLine, true, false); |
| if (m_nMaximumInterests >= 0 && globalReference == m_nMaximumInterests) |
| { |
| logStatistics(); |
| m_logger.shutdownLogger(); |
| m_face.shutdown(); |
| m_ioService.stop(); |
| } |
| } |
| |
| void |
| 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_minSuffixComponents >= 0) |
| interest.setMinSuffixComponents( |
| m_trafficPatterns[patternId].m_minSuffixComponents); |
| if (m_trafficPatterns[patternId].m_maxSuffixComponents >= 0) |
| interest.setMaxSuffixComponents( |
| m_trafficPatterns[patternId].m_maxSuffixComponents); |
| |
| Exclude exclude; |
| if (!m_trafficPatterns[patternId].m_excludeBefore.empty() && |
| !m_trafficPatterns[patternId].m_excludeAfter.empty()) |
| { |
| exclude.excludeRange( |
| name::Component( |
| m_trafficPatterns[patternId].m_excludeAfter), |
| name::Component(m_trafficPatterns[patternId].m_excludeBefore)); |
| interest.setExclude(exclude); |
| } |
| else if (!m_trafficPatterns[patternId].m_excludeBefore.empty()) |
| { |
| exclude.excludeBefore( |
| name::Component(m_trafficPatterns[patternId].m_excludeBefore)); |
| interest.setExclude(exclude); |
| } |
| else if (!m_trafficPatterns[patternId].m_excludeAfter.empty()) |
| { |
| exclude.excludeAfter( |
| name::Component(m_trafficPatterns[patternId].m_excludeAfter)); |
| interest.setExclude(exclude); |
| } |
| if (m_trafficPatterns[patternId].m_excludeBeforeBytes > 0 && |
| m_trafficPatterns[patternId].m_excludeAfterBytes > 0) |
| { |
| exclude.excludeRange( |
| generateRandomNameComponent( |
| m_trafficPatterns[patternId].m_excludeAfterBytes), |
| generateRandomNameComponent( |
| m_trafficPatterns[patternId].m_excludeBeforeBytes)); |
| interest.setExclude(exclude); |
| } |
| else if (m_trafficPatterns[patternId].m_excludeBeforeBytes > 0) |
| { |
| exclude.excludeBefore( |
| generateRandomNameComponent( |
| m_trafficPatterns[patternId].m_excludeBeforeBytes)); |
| interest.setExclude(exclude); |
| } |
| else if (m_trafficPatterns[patternId].m_excludeAfterBytes > 0) |
| { |
| exclude.excludeAfter( |
| generateRandomNameComponent( |
| m_trafficPatterns[patternId].m_excludeAfterBytes)); |
| interest.setExclude(exclude); |
| } |
| |
| if (m_trafficPatterns[patternId].m_childSelector >= 0) |
| interest.setChildSelector(m_trafficPatterns[patternId].m_childSelector); |
| |
| 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 >= time::milliseconds(0)) |
| 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++; |
| time::steady_clock::TimePoint 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: " + std::string(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(); |
| return; |
| } |
| |
| boost::asio::deadline_timer deadlineTimer(m_ioService, |
| boost::posix_time::millisec(m_interestInterval.count())); |
| deadlineTimer.async_wait(bind(&NdnTrafficClient::generateTraffic, this, &deadlineTimer)); |
| |
| try { |
| m_face.processEvents(); |
| } |
| catch (const std::exception& e) { |
| m_logger.log("ERROR: " + std::string(e.what()), true, true); |
| m_logger.shutdownLogger(); |
| m_hasError = true; |
| 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; |
| Face m_face; |
| std::vector<InterestTrafficConfiguration> m_trafficPatterns; |
| std::vector<uint32_t> m_nonces; |
| int m_nInterestsSent; |
| int m_nInterestsReceived; |
| int m_nNacks; |
| int m_nContentInconsistencies; |
| |
| //round trip time is stored as milliseconds with fractional |
| //sub-milliseconds precision |
| double m_minimumInterestRoundTripTime; |
| double m_maximumInterestRoundTripTime; |
| double m_totalInterestRoundTripTime; |
| }; |
| |
| } // namespace ndn |
| |
| int |
| main(int argc, char* argv[]) |
| { |
| std::srand(std::time(nullptr)); |
| |
| 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; |
| } |
| } |
| |
| argc -= optind; |
| argv += optind; |
| |
| if (!argc) |
| client.usage(); |
| |
| client.setConfigurationFile(argv[0]); |
| client.run(); |
| |
| return client.hasError() ? EXIT_FAILURE : EXIT_SUCCESS; |
| } |