530 lines
14 KiB
C++
530 lines
14 KiB
C++
/**
|
|
*
|
|
* Copyright (C) 2014 University of Arizona.
|
|
* @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>
|
|
|
|
using namespace ndn;
|
|
|
|
class Logger
|
|
{
|
|
public:
|
|
|
|
Logger()
|
|
{
|
|
logLocation_ = "";
|
|
}
|
|
|
|
void
|
|
shutdownLogger()
|
|
{
|
|
if (logFile_.is_open())
|
|
{
|
|
log("Terminating Logging Operations" , true, true);
|
|
logFile_.close();
|
|
}
|
|
}
|
|
|
|
static std::string
|
|
getTimestamp()
|
|
{
|
|
boost::posix_time::ptime now;
|
|
now = boost::posix_time::second_clock::local_time();
|
|
return to_simple_string(now);
|
|
}
|
|
|
|
void
|
|
log( std::string logLine, bool printTime, bool printToConsole )
|
|
{
|
|
if( logLocation_.length() > 0 )
|
|
{
|
|
if (printTime)
|
|
logFile_ << getTimestamp() << " - ";
|
|
logFile_ << logLine << std::endl;
|
|
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( std::string instanceId )
|
|
{
|
|
char* variableValue = std::getenv("NDN_TRAFFIC_LOGFOLDER");
|
|
std::string logFilename;
|
|
logLocation_ = "";
|
|
if (variableValue != NULL)
|
|
logLocation_ = variableValue;
|
|
if (boost::filesystem::exists(boost::filesystem::path(logLocation_)))
|
|
{
|
|
if (boost::filesystem::is_directory(boost::filesystem::path(logLocation_)))
|
|
{
|
|
logFilename = logLocation_+"/NDNTrafficServer_"+instanceId+".log";
|
|
logFile_.open(logFilename.c_str(), std::ofstream::out | std::ofstream::trunc);
|
|
if (logFile_.is_open())
|
|
std::cout << "Log File Initialized: " << logFilename << std::endl;
|
|
else
|
|
{
|
|
std::cout << "ERROR - Unable To Initialize A Log File At: " << logLocation_ << std::endl
|
|
<< "Using Default Output For Logging." << std::endl;
|
|
logLocation_ = "";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::cout << "Environment Variable NDN_TRAFFIC_LOGFOLDER Should Be A Folder." << std::endl
|
|
<< "Using Default Output For Logging." << std::endl;
|
|
logLocation_ = "";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::cout << "Environment Variable NDN_TRAFFIC_LOGFOLDER Not Set." << std::endl
|
|
<< "Using Default Output For Logging." << std::endl;
|
|
logLocation_ = "";
|
|
}
|
|
}
|
|
|
|
private:
|
|
|
|
std::string logLocation_;
|
|
std::ofstream logFile_;
|
|
|
|
};
|
|
|
|
|
|
class NdnTrafficServer
|
|
{
|
|
public:
|
|
|
|
NdnTrafficServer( char* programName ) : 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() >= 0)
|
|
detail = detail.substr(0, detail.length()-2);
|
|
logger.log(detail, false, false);
|
|
}
|
|
|
|
|
|
bool
|
|
extractParameterValue( 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( 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_ << " Printing Usage"
|
|
"\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()
|
|
{
|
|
logger_.shutdownLogger();
|
|
face_.shutdown();
|
|
ioService_.reset();
|
|
logStatistics();
|
|
exit(1);
|
|
}
|
|
|
|
void
|
|
logStatistics()
|
|
{
|
|
int patternId;
|
|
logger_.log("\n\n== Interest Traffic Report ==\n", false, true);
|
|
logger_.log("Total Traffic Pattern Types = "+toString((int)trafficPattern_.size()), false, true);
|
|
logger_.log("Total Interests Received = "+toString(totalInterestReceived_), false, true);
|
|
for (patternId=0; patternId<trafficPattern_.size(); patternId++)
|
|
{
|
|
logger_.log("\nTraffic Pattern Type #"+toString(patternId+1), false, true);
|
|
trafficPattern_[patternId].printTrafficConfiguration(logger_);
|
|
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;
|
|
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, logger_, lineNumber))
|
|
{
|
|
while (getline(patternFile, patternLine) && std::isalpha(patternLine[0]))
|
|
{
|
|
lineNumber++;
|
|
if (!dataData.processConfigurationDetail(patternLine, logger_, lineNumber))
|
|
{
|
|
skipLine = true;
|
|
break;
|
|
}
|
|
}
|
|
lineNumber++;
|
|
}
|
|
else
|
|
skipLine = true;
|
|
if( !skipLine )
|
|
{
|
|
if (dataData.checkTrafficDetailCorrectness())
|
|
trafficPattern_.push_back(dataData);
|
|
}
|
|
}
|
|
}
|
|
patternFile.close();
|
|
if (!checkTrafficPatternCorrectness())
|
|
{
|
|
logger_.log("ERROR - Traffic Configuration Provided Is Not Proper- " + configurationFile_, false, true);
|
|
logger_.shutdownLogger();
|
|
exit(1);
|
|
}
|
|
logger_.log("Traffic Configuration File Processing Completed\n", true, false);
|
|
for (patternId = 0; patternId < trafficPattern_.size(); patternId++)
|
|
{
|
|
logger_.log("Traffic Pattern Type #"+toString(patternId+1), false, false);
|
|
trafficPattern_[patternId].printTrafficConfiguration(logger_);
|
|
logger_.log("", false, false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
logger_.log("ERROR - Unable To Open Traffic Configuration File: " + configurationFile_, false, true);
|
|
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
|
|
{
|
|
logger_.log("ERROR - Traffic Configuration File Is Not A Regular File: " + configurationFile_, false, true);
|
|
logger_.shutdownLogger();
|
|
exit(1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
logger_.log("ERROR - Traffic Configuration File Does Not Exist: " + configurationFile_, false, true);
|
|
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(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;
|
|
logger_.log(logLine, true, false);
|
|
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;
|
|
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));
|
|
logger_.initializeLog(instanceId_);
|
|
initializeTrafficConfiguration();
|
|
|
|
int patternId;
|
|
for (patternId=0; patternId<trafficPattern_.size(); patternId++ )
|
|
{
|
|
face_.setInterestFilter( trafficPattern_[patternId].name,
|
|
func_lib::bind( &NdnTrafficServer::onInterest,
|
|
this, _1, _2,
|
|
patternId),
|
|
func_lib::bind( &NdnTrafficServer::onRegisterFailed,
|
|
this, _1, _2,
|
|
patternId));
|
|
}
|
|
|
|
try {
|
|
face_.processEvents();
|
|
}
|
|
catch(std::exception &e) {
|
|
logger_.log("ERROR: "+(std::string)e.what(), true, true);
|
|
logger_.shutdownLogger();
|
|
}
|
|
}
|
|
|
|
private:
|
|
|
|
KeyChain keyChain_;
|
|
std::string programName_;
|
|
std::string instanceId_;
|
|
int contentDelayTime_;
|
|
int totalRegistrationsFailed_;
|
|
Logger logger_;
|
|
std::string configurationFile_;
|
|
ptr_lib::shared_ptr<boost::asio::io_service> ioService_;
|
|
Face face_;
|
|
std::vector<DataTrafficConfiguration> trafficPattern_;
|
|
int totalInterestReceived_;
|
|
|
|
};
|
|
|
|
int main( int argc, char* argv[] )
|
|
{
|
|
int option;
|
|
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;
|
|
}
|