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;
+}