blob: d508e6ce8d7193921b79def80f12599bc8227f26 [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Arizona Board of Regents.
*
* This file is part of ndn-tools (Named Data Networking Essential Tools).
* See AUTHORS.md for complete list of ndn-tools authors and contributors.
*
* ndn-tools 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.
*
* ndn-tools 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
* ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Copyright (C) 2014 Arizona Board of Regents
*
* This file is part of ndn-tlv-ping (Ping Application for Named Data Networking).
*
* ndn-tlv-ping is a 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.
*
* ndn-tlv-ping 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
* ndn-tlv-ping, e.g., in LICENSE file. If not, see <http://www.gnu.org/licenses/>.
*
* @author: Jerald Paul Abraham <jeraldabraham@email.arizona.edu>
*/
#include <ndn-cxx/face.hpp>
#include <ndn-cxx/name.hpp>
#include <ndn-cxx/security/key-chain.hpp>
#include <boost/asio.hpp>
#include <boost/noncopyable.hpp>
namespace ndn {
namespace ping {
class NdnPingServer : boost::noncopyable
{
public:
explicit
NdnPingServer(char* programName)
: m_programName(programName)
, m_hasError(false)
, m_isPrintTimestampSet(false)
, m_freshnessPeriod(getMinimumFreshnessPeriod())
, m_maximumPings(-1)
, m_totalPings(0)
, m_face(m_ioService)
{
}
void
usage()
{
std::cout << "\n Usage:\n " << m_programName << " ndn:/name/prefix [options]\n"
" Starts a NDN ping server that responds to Interests with name"
" ndn:/name/prefix/ping/number.\n"
" [-x freshness] - set FreshnessSeconds\n"
" [-p] - specify number of pings to be satisfied (>=1)\n"
" [-t] - print timestamp\n"
" [-h] - print this message and exit\n\n";
exit(1);
}
time::milliseconds
getMinimumFreshnessPeriod()
{
return time::milliseconds(1000);
}
void
setFreshnessPeriod(int freshnessPeriod)
{
if (freshnessPeriod <= 0)
usage();
m_freshnessPeriod = time::milliseconds(freshnessPeriod);
}
void
setMaximumPings(int maximumPings)
{
if (maximumPings <= 0)
usage();
m_maximumPings = maximumPings;
}
void
setPrefix(char* prefix)
{
m_prefix = prefix;
}
void
setPrintTimestamp()
{
m_isPrintTimestampSet = true;
}
bool
hasError() const
{
return m_hasError;
}
void
onInterest(const Name& name, const Interest& interest)
{
Name interestName = interest.getName();
if (m_isPrintTimestampSet)
std::cout << time::toIsoString(time::system_clock::now()) << " - ";
std::cout << "Interest Received - Ping Reference = "
<< interestName.at(-1).toUri() << std::endl;
char responseContent[] = "NDN TLV Ping Response";
shared_ptr<Data> data = make_shared<Data>(interestName);
data->setFreshnessPeriod(m_freshnessPeriod);
data->setContent(reinterpret_cast<const uint8_t*>(responseContent),
sizeof(responseContent));
m_keyChain.sign(*data);
m_face.put(*data);
++m_totalPings;
if (m_maximumPings > 0 && m_maximumPings == m_totalPings) {
std::cout << "\n\nTotal Ping Interests Processed = " << m_totalPings << std::endl;
std::cout << "Shutting Down Ping Server (" << m_name << ").\n" << std::endl;
m_face.shutdown();
m_ioService.stop();
}
}
void
onRegisterFailed(const ndn::Name& prefix, const std::string& reason)
{
std::cerr << "ERROR: Failed to register prefix in local hub's daemon" << std::endl;
std::cerr << "REASON: " << reason << std::endl;
m_hasError = true;
m_face.shutdown();
m_ioService.stop();
}
void
signalHandler()
{
std::cout << "\n\nTotal Ping Interests Processed = " << m_totalPings << std::endl;
std::cout << "Shutting Down Ping Server (" << m_name.toUri() << ").\n" << std::endl;
m_face.shutdown();
exit(1);
}
void
run()
{
std::cout << "\n=== Ping Server " << m_prefix <<" ===\n" << std::endl;
boost::asio::signal_set signalSet(m_ioService, SIGINT, SIGTERM);
signalSet.async_wait(bind([this]() { signalHandler(); }));
m_name = m_prefix;
m_name.append("ping");
m_face.setInterestFilter(m_name,
bind(&NdnPingServer::onInterest,
this, _1, _2),
bind(&NdnPingServer::onRegisterFailed,
this, _1,_2));
try {
m_face.processEvents();
}
catch (std::exception& e) {
std::cerr << "ERROR: " << e.what() << std::endl;
m_hasError = true;
m_ioService.stop();
}
}
private:
char* m_programName;
bool m_hasError;
bool m_isPrintTimestampSet;
time::milliseconds m_freshnessPeriod;
int m_maximumPings;
int m_totalPings;
char* m_prefix;
Name m_name;
boost::asio::io_service m_ioService;
KeyChain m_keyChain;
Face m_face;
};
int
main(int argc, char* argv[])
{
int res;
NdnPingServer program(argv[0]);
while ((res = getopt(argc, argv, "hdtp:x:")) != -1)
{
switch (res) {
case 'h':
program.usage();
break;
case 'p':
program.setMaximumPings(atoi(optarg));
break;
case 'x':
program.setFreshnessPeriod(atoi(optarg));
break;
case 't':
program.setPrintTimestamp();
break;
default:
program.usage();
break;
}
}
argc -= optind;
argv += optind;
if (argv[0] == 0)
program.usage();
program.setPrefix(argv[0]);
program.run();
std::cout << std::endl;
if (program.hasError())
return 1;
else
return 0;
}
} // namespace ping
} // namespace ndn
int
main(int argc, char** argv)
{
return ndn::ping::main(argc, argv);
}