doc+src: More reorganization and fixing of README
Change-Id: I8ff2dcdabd78f38cc0d5b826883121a9444ef664
diff --git a/src/ndn-traffic-server.cpp b/src/ndn-traffic-server.cpp
new file mode 100644
index 0000000..0769c69
--- /dev/null
+++ b/src/ndn-traffic-server.cpp
@@ -0,0 +1,462 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2014 University of Arizona.
+ *
+ * GNU 3.0 License, see the LICENSE file for more information
+ *
+ * Author: Jerald Paul Abraham <jeraldabraham@email.arizona.edu>
+ */
+
+#include <sstream>
+#include <boost/asio.hpp>
+#include <boost/filesystem.hpp>
+
+#include <ndn-cpp-dev/face.hpp>
+#include <ndn-cpp-dev/security/key-chain.hpp>
+
+#include "logger.hpp"
+
+namespace ndn {
+
+class NdnTrafficServer
+{
+public:
+ NdnTrafficServer(char* programName)
+ : m_logger("NDNTrafficServer")
+ , ioService_(new boost::asio::io_service)
+ , face_(ioService_)
+ , keyChain_()
+ {
+ std::srand(std::time(0));
+ instanceId_ = toString(std::rand());
+ programName_ = programName;
+ contentDelayTime_ = getDefaultContentDelayTime();
+ totalRegistrationsFailed_ = 0;
+ configurationFile_ = "";
+ totalInterestReceived_ = 0;
+ }
+
+ class DataTrafficConfiguration
+ {
+ public:
+ DataTrafficConfiguration()
+ {
+ name = "";
+ contentType = -1;
+ freshnessPeriod = -1;
+ contentBytes = -1;
+ content = "";
+ totalInterestReceived = 0;
+ }
+
+ void
+ printTrafficConfiguration(Logger& logger)
+ {
+ std::string detail;
+ detail = "";
+ if (name != "")
+ detail += "Name="+name+", ";
+ if (contentType >= 0)
+ detail += "ContentType="+toString(contentType)+", ";
+ if (freshnessPeriod >= 0)
+ detail += "FreshnessPeriod="+toString(freshnessPeriod)+", ";
+ if (contentBytes >= 0)
+ detail += "ContentBytes="+toString(contentBytes)+", ";
+ if (content != "")
+ detail += "Content="+content+", ";
+ if (detail.length() >= 2)
+ detail = detail.substr(0, detail.length()-2);
+ logger.log(detail, false, false);
+ }
+
+
+ bool
+ extractParameterValue(const std::string& detail,
+ std::string& parameter, std::string& value)
+ {
+ int i;
+ std::string allowedCharacters = ":/+._-%";
+ parameter = "";
+ value = "";
+ i = 0;
+ 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 == "" || value == "")
+ return false;
+ return true;
+ }
+
+ bool
+ processConfigurationDetail(const std::string& detail,
+ Logger& logger, int lineNumber)
+ {
+ std::string parameter, value;
+ if (extractParameterValue(detail, parameter, value))
+ {
+ if (parameter == "Name")
+ name = value;
+ else if (parameter == "ContentType")
+ contentType = toInteger(value);
+ else if (parameter == "FreshnessPeriod")
+ freshnessPeriod = toInteger(value);
+ else if (parameter == "ContentBytes")
+ contentBytes = toInteger(value);
+ else if (parameter == "Content")
+ content = value;
+ else
+ logger.log("Line "+toString(lineNumber)+
+ " \t- Invalid Parameter='"+parameter+"'", false, true);
+ }
+ else
+ {
+ logger.log("Line "+toString(lineNumber)+
+ " \t- Improper Traffic Configuration Line- "+detail, false, true);
+ return false;
+ }
+ return true;
+ }
+
+ bool
+ checkTrafficDetailCorrectness()
+ {
+ return true;
+ }
+
+ std::string name;
+ int contentType;
+ int freshnessPeriod;
+ int contentBytes;
+ std::string content;
+ int totalInterestReceived;
+
+ };
+
+ std::string
+ getDefaultContent()
+ {
+ return "";
+ }
+
+ static std::string
+ toString(int integerValue)
+ {
+ std::stringstream stream;
+ stream << integerValue;
+ return stream.str();
+ }
+
+ static int
+ toInteger(std::string stringValue)
+ {
+ int integerValue;
+ std::stringstream stream(stringValue);
+ stream >> integerValue;
+ return integerValue;
+ }
+
+ void
+ usage()
+ {
+
+ std::cout << "\nUsage: " << programName_ << " [options] <Traffic_Configuration_File>\n"
+ "Respond to Interest as per provided Traffic Configuration File\n"
+ "Multiple Prefixes can be configured for handling.\n"
+ "Set environment variable NDN_TRAFFIC_LOGFOLDER for redirecting output to a log.\n"
+ " [-d interval] - set delay before responding to interest in milliseconds (minimum "
+ << getDefaultContentDelayTime() << " milliseconds)\n"
+ " [-h] - print help and exit\n\n";
+ exit(1);
+
+ }
+
+ int
+ getDefaultContentDelayTime()
+ {
+ return 0;
+ }
+
+ void
+ setContentDelayTime(int contentDelayTime)
+ {
+ if (contentDelayTime < 0)
+ usage();
+ contentDelayTime_ = contentDelayTime;
+ }
+
+ void
+ setConfigurationFile(char* configurationFile)
+ {
+ configurationFile_ = configurationFile;
+ }
+
+ void
+ signalHandler()
+ {
+ m_logger.shutdownLogger();
+ face_.shutdown();
+ ioService_.reset();
+ logStatistics();
+ exit(1);
+ }
+
+ void
+ logStatistics()
+ {
+ int patternId;
+ m_logger.log("\n\n== Interest Traffic Report ==\n", false, true);
+ m_logger.log("Total Traffic Pattern Types = " +
+ toString((int)trafficPattern_.size()), false, true);
+ m_logger.log("Total Interests Received = " +
+ toString(totalInterestReceived_), false, true);
+
+ for (patternId=0; patternId<trafficPattern_.size(); patternId++)
+ {
+ m_logger.log("\nTraffic Pattern Type #"+toString(patternId+1), false, true);
+ trafficPattern_[patternId].printTrafficConfiguration(m_logger);
+ m_logger.log("Total Interests Received = " +
+ toString(trafficPattern_[patternId].totalInterestReceived)+"\n", false, true);
+ }
+ }
+
+ bool
+ checkTrafficPatternCorrectness()
+ {
+ return true;
+ }
+
+ void
+ analyzeConfigurationFile()
+ {
+ int patternId;
+ int lineNumber;
+ bool skipLine;
+ std::string patternLine;
+ std::ifstream patternFile;
+ m_logger.log("Analyzing Traffic Configuration File: " + configurationFile_, true, true);
+ patternFile.open(configurationFile_.c_str());
+ if (patternFile.is_open())
+ {
+ patternId = 0;
+ lineNumber = 0;
+ while (getline(patternFile, patternLine))
+ {
+ lineNumber++;
+ if (std::isalpha(patternLine[0]))
+ {
+ DataTrafficConfiguration dataData;
+ skipLine = false;
+ patternId++;
+ if (dataData.processConfigurationDetail(patternLine, m_logger, lineNumber))
+ {
+ while (getline(patternFile, patternLine) && std::isalpha(patternLine[0]))
+ {
+ lineNumber++;
+ if (!dataData.processConfigurationDetail(patternLine, m_logger, lineNumber))
+ {
+ skipLine = true;
+ break;
+ }
+ }
+ lineNumber++;
+ }
+ else
+ skipLine = true;
+ if( !skipLine )
+ {
+ if (dataData.checkTrafficDetailCorrectness())
+ trafficPattern_.push_back(dataData);
+ }
+ }
+ }
+ patternFile.close();
+ if (!checkTrafficPatternCorrectness())
+ {
+ m_logger.log("ERROR - Traffic Configuration Provided Is Not Proper- " +
+ configurationFile_, false, true);
+ m_logger.shutdownLogger();
+ exit(1);
+ }
+ m_logger.log("Traffic Configuration File Processing Completed\n", true, false);
+ for (patternId = 0; patternId < trafficPattern_.size(); patternId++)
+ {
+ m_logger.log("Traffic Pattern Type #"+toString(patternId+1), false, false);
+ trafficPattern_[patternId].printTrafficConfiguration(m_logger);
+ m_logger.log("", false, false);
+ }
+ }
+ else
+ {
+ m_logger.log("ERROR - Unable To Open Traffic Configuration File: " +
+ configurationFile_, false, true);
+ m_logger.shutdownLogger();
+ exit(1);
+ }
+ }
+
+ void
+ initializeTrafficConfiguration()
+ {
+ if (boost::filesystem::exists(boost::filesystem::path(configurationFile_)))
+ {
+ if(boost::filesystem::is_regular_file(boost::filesystem::path(configurationFile_)))
+ {
+ analyzeConfigurationFile();
+ }
+ else
+ {
+ m_logger.log("ERROR - Traffic Configuration File Is Not A Regular File: " +
+ configurationFile_, false, true);
+ m_logger.shutdownLogger();
+ exit(1);
+ }
+ }
+ else
+ {
+ m_logger.log("ERROR - Traffic Configuration File Does Not Exist: " +
+ configurationFile_, false, true);
+ m_logger.shutdownLogger();
+ exit(1);
+ }
+ }
+
+ static std::string
+ getRandomByteString(int randomSize)
+ {
+ int i;
+ std::string characterSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvw0123456789";
+ std::string randomData;
+ for (i=0; i<randomSize; i++)
+ randomData += characterSet[std::rand() % characterSet.length()];
+ return randomData;
+ }
+
+ void
+ onInterest(const Name& name, const Interest& interest, int patternId)
+ {
+ std::string content, logLine;
+ content = "";
+ logLine = "";
+
+ Data data(interest.getName());
+ if (trafficPattern_[patternId].contentType >= 0)
+ data.setContentType(trafficPattern_[patternId].contentType);
+ if (trafficPattern_[patternId].freshnessPeriod >= 0)
+ data.setFreshnessPeriod(time::milliseconds(trafficPattern_[patternId].freshnessPeriod));
+ if (trafficPattern_[patternId].contentBytes >= 0)
+ content = getRandomByteString(trafficPattern_[patternId].contentBytes);
+ if (trafficPattern_[patternId].content != "")
+ content = trafficPattern_[patternId].content;
+ data.setContent((const uint8_t*)content.c_str(), content.length());
+ keyChain_.sign(data);
+ totalInterestReceived_++;
+ trafficPattern_[patternId].totalInterestReceived++;
+ logLine += "Interest Received - PatternType="+toString(patternId+1);
+ logLine += ", GlobalID="+toString(totalInterestReceived_);
+ logLine += ", LocalID="+toString(trafficPattern_[patternId].totalInterestReceived);
+ logLine += ", Name="+trafficPattern_[patternId].name;
+ m_logger.log(logLine, true, false);
+ usleep(contentDelayTime_*1000);
+ face_.put(data);
+ }
+
+ void
+ onRegisterFailed(const ndn::Name& prefix, const std::string& reason, int patternId)
+ {
+ std::string logLine;
+ logLine = "";
+ logLine += "Prefix Registration Failed - PatternType="+toString(patternId+1);
+ logLine += ", Name="+trafficPattern_[patternId].name;
+ m_logger.log(logLine, true, true);
+ totalRegistrationsFailed_++;
+ if (totalRegistrationsFailed_ == trafficPattern_.size())
+ signalHandler();
+ }
+
+ void
+ initialize()
+ {
+ boost::asio::signal_set signalSet(*ioService_, SIGINT, SIGTERM);
+ signalSet.async_wait(boost::bind(&NdnTrafficServer::signalHandler, this));
+ m_logger.initializeLog(instanceId_);
+ initializeTrafficConfiguration();
+
+ int patternId;
+ for (patternId=0; patternId<trafficPattern_.size(); patternId++)
+ {
+ face_.setInterestFilter(trafficPattern_[patternId].name,
+ bind(&NdnTrafficServer::onInterest,
+ this, _1, _2,
+ patternId),
+ bind(&NdnTrafficServer::onRegisterFailed,
+ this, _1, _2,
+ patternId));
+ }
+
+ try {
+ face_.processEvents();
+ }
+ catch(std::exception &e) {
+ m_logger.log("ERROR: "+(std::string)e.what(), true, true);
+ m_logger.shutdownLogger();
+ }
+ }
+
+private:
+ KeyChain keyChain_;
+ std::string programName_;
+ std::string instanceId_;
+ int contentDelayTime_;
+ int totalRegistrationsFailed_;
+ Logger m_logger;
+ std::string configurationFile_;
+ ptr_lib::shared_ptr<boost::asio::io_service> ioService_;
+ Face face_;
+ std::vector<DataTrafficConfiguration> trafficPattern_;
+ int totalInterestReceived_;
+};
+
+} // namespace ndn
+
+int
+main(int argc, char* argv[])
+{
+ int option;
+ ndn::NdnTrafficServer ndnTrafficServer (argv[0]);
+ while ((option = getopt(argc, argv, "hd:")) != -1) {
+ switch (option) {
+ case 'h' :
+ ndnTrafficServer.usage();
+ break;
+ case 'd' :
+ ndnTrafficServer.setContentDelayTime(atoi(optarg));
+ break;
+ default :
+ ndnTrafficServer.usage();
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argv[0] == NULL)
+ ndnTrafficServer.usage();
+
+ ndnTrafficServer.setConfigurationFile(argv[0]);
+ ndnTrafficServer.initialize();
+
+ return 0;
+}