blob: 239f940c1e9a162187a5cd7a4eeaf0fffc34e44e [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (C) 2014 Named Data Networking Project
* See COPYING for copyright and distribution information.
*/
#include "nrd.hpp"
namespace ndn {
namespace nrd {
const Name Nrd::COMMAND_PREFIX = "/localhost/nrd";
const Name Nrd::REMOTE_COMMAND_PREFIX = "/localhop/nrd";
const size_t Nrd::COMMAND_UNSIGNED_NCOMPS =
Nrd::COMMAND_PREFIX.size() +
1 + // verb
1; // verb options
const size_t Nrd::COMMAND_SIGNED_NCOMPS =
Nrd::COMMAND_UNSIGNED_NCOMPS +
4; // (timestamp, nonce, signed info tlv, signature tlv)
const Nrd::VerbAndProcessor Nrd::COMMAND_VERBS[] =
{
VerbAndProcessor(
Name::Component("register"),
&Nrd::insertEntry
),
VerbAndProcessor(
Name::Component("unregister"),
&Nrd::deleteEntry
),
};
void
Nrd::setInterestFilterFailed(const Name& name, const std::string& msg)
{
std::cerr << "Error in setting interest filter (" << name << "): " << msg << std::endl;
m_face.shutdown();
}
Nrd::Nrd()
: m_nfdController(new nfd::Controller(m_face)),
m_verbDispatch(COMMAND_VERBS,
COMMAND_VERBS + (sizeof(COMMAND_VERBS) / sizeof(VerbAndProcessor)))
{
//check whether the components of localhop and localhost prefixes are same
BOOST_ASSERT(COMMAND_PREFIX.size() == REMOTE_COMMAND_PREFIX.size ());
std::cerr << "Setting interest filter on: " << COMMAND_PREFIX.toUri() << std::endl;
m_face.setController(m_nfdController);
m_face.setInterestFilter(COMMAND_PREFIX.toUri(),
bind(&Nrd::onRibRequest, this, _2),
bind(&Nrd::setInterestFilterFailed, this, _1, _2));
std::cerr << "Setting interest filter on: " << REMOTE_COMMAND_PREFIX.toUri() << std::endl;
m_face.setInterestFilter(REMOTE_COMMAND_PREFIX.toUri(),
bind(&Nrd::onRibRequest, this, _2),
bind(&Nrd::setInterestFilterFailed, this, _1, _2));
}
void
Nrd::sendResponse(const Name& name,
const nfd::ControlResponse& response)
{
const Block& encodedControl = response.wireEncode();
Data responseData(name);
responseData.setContent(encodedControl);
m_keyChain.sign(responseData);
m_face.put(responseData);
}
void
Nrd::sendResponse(const Name& name,
uint32_t code,
const std::string& text)
{
nfd::ControlResponse response(code, text);
sendResponse(name, response);
}
void
Nrd::onRibRequest(const Interest& request)
{
const Name& command = request.getName();
const size_t commandNComps = command.size();
if (COMMAND_UNSIGNED_NCOMPS <= commandNComps &&
commandNComps < COMMAND_SIGNED_NCOMPS)
{
std::cerr << "Error: Signature required" << std::endl;
sendResponse(command, 401, "Signature required");
return;
}
else if (commandNComps < COMMAND_SIGNED_NCOMPS ||
!(COMMAND_PREFIX.isPrefixOf(command) ||
REMOTE_COMMAND_PREFIX.isPrefixOf(command)))
{
std::cerr << "Error: Malformed Command" << std::endl;
sendResponse(command, 400, "Malformed command");
return;
}
//REMOTE_COMMAND_PREFIX number of componenets are same as
// NRD_COMMAND_PREFIX's so no extra checks are required.
const Name::Component& verb = command.get(COMMAND_PREFIX.size());
VerbDispatchTable::const_iterator verbProcessor = m_verbDispatch.find(verb);
if (verbProcessor != m_verbDispatch.end())
{
PrefixRegOptions options;
if (!extractOptions(request, options))
{
sendResponse(command, 400, "Malformed command");
return;
}
/// \todo authorize command
if (false)
{
sendResponse(request.getName(), 403, "Unauthorized command");
return;
}
// \todo add proper log support
std::cout << "Received options (name, faceid, cost): " << options.getName() <<
", " << options.getFaceId() << ", " << options.getCost() << std::endl;
nfd::ControlResponse response;
(verbProcessor->second)(this, request, options);
}
else
{
sendResponse(request.getName(), 501, "Unsupported command");
}
}
bool
Nrd::extractOptions(const Interest& request,
PrefixRegOptions& extractedOptions)
{
const Name& command = request.getName();
//REMOTE_COMMAND_PREFIX is same in size of NRD_COMMAND_PREFIX
//so no extra processing is required.
const size_t optionCompIndex = COMMAND_PREFIX.size() + 1;
try
{
Block rawOptions = request.getName()[optionCompIndex].blockFromValue();
extractedOptions.wireDecode(rawOptions);
}
catch (const ndn::Tlv::Error& e)
{
return false;
}
if (extractedOptions.getFaceId() == 0)
{
std::cout <<"IncomingFaceId: " << request.getIncomingFaceId() << std::endl;
extractedOptions.setFaceId(request.getIncomingFaceId());
}
return true;
}
void
Nrd::onCommandError(const std::string& error,
const Interest& request,
const PrefixRegOptions& options)
{
nfd::ControlResponse response;
response.setCode(400);
response.setText(error);
std::cout << "Error: " << error << std::endl;
sendResponse(request.getName(), response);
m_managedRib.erase(options);
}
void
Nrd::onUnRegSuccess(const Interest& request, const PrefixRegOptions& options)
{
nfd::ControlResponse response;
response.setCode(200);
response.setText("Success");
response.setBody(options.wireEncode());
std::cout << "Success: Name unregistered (" <<
options.getName() << ", " <<
options.getFaceId() << ")" << std::endl;
sendResponse(request.getName(), response);
m_managedRib.erase(options);
}
void
Nrd::onRegSuccess(const Interest& request, const PrefixRegOptions& options)
{
nfd::ControlResponse response;
response.setCode(200);
response.setText("Success");
response.setBody(options.wireEncode());
std::cout << "Success: Name registered (" << options.getName() << ", " <<
options.getFaceId() << ")" << std::endl;
sendResponse(request.getName(), response);
}
void
Nrd::insertEntry(const Interest& request, const PrefixRegOptions& options)
{
// For right now, just pass the options to fib as it is,
// without processing flags. Later options will be first added to
// Rib tree, then nrd will generate fib updates based on flags and then
// will add next hops one by one..
m_managedRib.insert(options);
m_nfdController->fibAddNextHop(options.getName(), options.getFaceId(),
options.getCost(),
bind(&Nrd::onRegSuccess, this, request, options),
bind(&Nrd::onCommandError, this, _1, request, options));
}
void
Nrd::deleteEntry(const Interest& request, const PrefixRegOptions& options)
{
m_nfdController->fibRemoveNextHop(options.getName(),
options.getFaceId(),
bind(&Nrd::onUnRegSuccess, this, request, options),
bind(&Nrd::onCommandError, this, _1, request, options));
}
void
Nrd::listen()
{
std::cout << "NRD started: listening for incoming interests" << std::endl;
m_face.processEvents();
}
void
Nrd::onControlHeaderSuccess()
{
std::cout << "Local control header enabled" << std::endl;
}
void
Nrd::onControlHeaderError()
{
std::cout << "Error: couldn't enable local control header" << std::endl;
m_face.shutdown();
}
void
Nrd::enableLocalControlHeader()
{
Name enable("/localhost/nfd/control-header/in-faceid/enable");
Interest enableCommand(enable);
m_keyChain.sign(enableCommand);
m_face.expressInterest(enableCommand,
ndn::bind(&Nrd::onControlHeaderSuccess, this),
ndn::bind(&Nrd::onControlHeaderError, this));
}
} // namespace nrd
} // namespace ndn