Prevent creation of faces to endpoints owned by NFD instance Prevent creation of UDP broadcast faces (255.255.255.255 and those belonging to machine's interfaces) in response to face creation command Sanity check configuration file port numbers in face manager refs: #1414, #1427 Change-Id: Ia3f0a9337f3d97c34388773eab05bc39ad6dd804
808 lines
25 KiB
C++
808 lines
25 KiB
C++
/* -*- 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 "face-manager.hpp"
|
|
#include "face-flags.hpp"
|
|
|
|
#include "core/logger.hpp"
|
|
#include "core/face-uri.hpp"
|
|
#include "core/network-interface.hpp"
|
|
#include "fw/face-table.hpp"
|
|
#include "face/tcp-factory.hpp"
|
|
#include "face/udp-factory.hpp"
|
|
|
|
#include <ndn-cpp-dev/management/nfd-face-event-notification.hpp>
|
|
|
|
#ifdef HAVE_UNIX_SOCKETS
|
|
#include "face/unix-stream-factory.hpp"
|
|
#endif // HAVE_UNIX_SOCKETS
|
|
|
|
#ifdef HAVE_PCAP
|
|
#include "face/ethernet-factory.hpp"
|
|
#endif // HAVE_PCAP
|
|
|
|
namespace nfd {
|
|
|
|
NFD_LOG_INIT("FaceManager");
|
|
|
|
const Name FaceManager::COMMAND_PREFIX("/localhost/nfd/faces");
|
|
|
|
const size_t FaceManager::COMMAND_UNSIGNED_NCOMPS =
|
|
FaceManager::COMMAND_PREFIX.size() +
|
|
1 + // verb
|
|
1; // verb parameters
|
|
|
|
const size_t FaceManager::COMMAND_SIGNED_NCOMPS =
|
|
FaceManager::COMMAND_UNSIGNED_NCOMPS +
|
|
4; // (timestamp, nonce, signed info tlv, signature tlv)
|
|
|
|
const FaceManager::SignedVerbAndProcessor FaceManager::SIGNED_COMMAND_VERBS[] =
|
|
{
|
|
SignedVerbAndProcessor(
|
|
Name::Component("create"),
|
|
&FaceManager::createFace
|
|
),
|
|
|
|
SignedVerbAndProcessor(
|
|
Name::Component("destroy"),
|
|
&FaceManager::destroyFace
|
|
),
|
|
|
|
SignedVerbAndProcessor(
|
|
Name::Component("enable-local-control"),
|
|
&FaceManager::enableLocalControl
|
|
),
|
|
|
|
SignedVerbAndProcessor(
|
|
Name::Component("disable-local-control"),
|
|
&FaceManager::disableLocalControl
|
|
),
|
|
};
|
|
|
|
const FaceManager::UnsignedVerbAndProcessor FaceManager::UNSIGNED_COMMAND_VERBS[] =
|
|
{
|
|
UnsignedVerbAndProcessor(
|
|
Name::Component("list"),
|
|
&FaceManager::listFaces
|
|
),
|
|
|
|
UnsignedVerbAndProcessor(
|
|
Name::Component("events"),
|
|
&FaceManager::ignoreUnsignedVerb
|
|
),
|
|
};
|
|
|
|
const Name FaceManager::LIST_COMMAND_PREFIX("/localhost/nfd/faces/list");
|
|
const size_t FaceManager::LIST_COMMAND_NCOMPS = LIST_COMMAND_PREFIX.size();
|
|
|
|
const Name FaceManager::EVENTS_COMMAND_PREFIX("/localhost/nfd/faces/events");
|
|
|
|
FaceManager::FaceManager(FaceTable& faceTable,
|
|
shared_ptr<InternalFace> face)
|
|
: ManagerBase(face, FACE_MANAGER_PRIVILEGE)
|
|
, m_faceTable(faceTable)
|
|
, m_statusPublisher(m_faceTable, m_face, LIST_COMMAND_PREFIX)
|
|
, m_notificationStream(m_face, EVENTS_COMMAND_PREFIX)
|
|
, m_signedVerbDispatch(SIGNED_COMMAND_VERBS,
|
|
SIGNED_COMMAND_VERBS +
|
|
(sizeof(SIGNED_COMMAND_VERBS) / sizeof(SignedVerbAndProcessor)))
|
|
, m_unsignedVerbDispatch(UNSIGNED_COMMAND_VERBS,
|
|
UNSIGNED_COMMAND_VERBS +
|
|
(sizeof(UNSIGNED_COMMAND_VERBS) / sizeof(UnsignedVerbAndProcessor)))
|
|
|
|
{
|
|
face->setInterestFilter("/localhost/nfd/faces",
|
|
bind(&FaceManager::onFaceRequest, this, _2));
|
|
|
|
m_faceTable.onAdd += bind(&FaceManager::onAddFace, this, _1);
|
|
m_faceTable.onRemove += bind(&FaceManager::onRemoveFace, this, _1);
|
|
}
|
|
|
|
FaceManager::~FaceManager()
|
|
{
|
|
|
|
}
|
|
|
|
void
|
|
FaceManager::setConfigFile(ConfigFile& configFile)
|
|
{
|
|
configFile.addSectionHandler("face_system",
|
|
bind(&FaceManager::onConfig, this, _1, _2, _3));
|
|
}
|
|
|
|
|
|
void
|
|
FaceManager::onConfig(const ConfigSection& configSection,
|
|
bool isDryRun,
|
|
const std::string& filename)
|
|
{
|
|
bool hasSeenUnix = false;
|
|
bool hasSeenTcp = false;
|
|
bool hasSeenUdp = false;
|
|
bool hasSeenEther = false;
|
|
|
|
const std::list<shared_ptr<NetworkInterfaceInfo> > nicList(listNetworkInterfaces());
|
|
|
|
for (ConfigSection::const_iterator item = configSection.begin();
|
|
item != configSection.end();
|
|
++item)
|
|
{
|
|
if (item->first == "unix")
|
|
{
|
|
if (hasSeenUnix)
|
|
throw Error("Duplicate \"unix\" section");
|
|
hasSeenUnix = true;
|
|
|
|
processSectionUnix(item->second, isDryRun);
|
|
}
|
|
else if (item->first == "tcp")
|
|
{
|
|
if (hasSeenTcp)
|
|
throw Error("Duplicate \"tcp\" section");
|
|
hasSeenTcp = true;
|
|
|
|
processSectionTcp(item->second, isDryRun);
|
|
}
|
|
else if (item->first == "udp")
|
|
{
|
|
if (hasSeenUdp)
|
|
throw Error("Duplicate \"udp\" section");
|
|
hasSeenUdp = true;
|
|
|
|
processSectionUdp(item->second, isDryRun, nicList);
|
|
}
|
|
else if (item->first == "ether")
|
|
{
|
|
if (hasSeenEther)
|
|
throw Error("Duplicate \"ether\" section");
|
|
hasSeenEther = true;
|
|
|
|
processSectionEther(item->second, isDryRun, nicList);
|
|
}
|
|
else
|
|
{
|
|
throw Error("Unrecognized option \"" + item->first + "\"");
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
FaceManager::processSectionUnix(const ConfigSection& configSection, bool isDryRun)
|
|
{
|
|
// ; the unix section contains settings of UNIX stream faces and channels
|
|
// unix
|
|
// {
|
|
// listen yes ; set to 'no' to disable UNIX stream listener, default 'yes'
|
|
// path /var/run/nfd.sock ; UNIX stream listener path
|
|
// }
|
|
|
|
#if defined(HAVE_UNIX_SOCKETS)
|
|
|
|
bool needToListen = true;
|
|
std::string path = "/var/run/nfd.sock";
|
|
|
|
for (ConfigSection::const_iterator i = configSection.begin();
|
|
i != configSection.end();
|
|
++i)
|
|
{
|
|
if (i->first == "path")
|
|
{
|
|
path = i->second.get_value<std::string>();
|
|
}
|
|
else if (i->first == "listen")
|
|
{
|
|
needToListen = parseYesNo(i, i->first, "unix");
|
|
}
|
|
else
|
|
{
|
|
throw ConfigFile::Error("Unrecognized option \"" + i->first + "\" in \"unix\" section");
|
|
}
|
|
}
|
|
|
|
if (!isDryRun)
|
|
{
|
|
shared_ptr<UnixStreamFactory> factory = make_shared<UnixStreamFactory>();
|
|
shared_ptr<UnixStreamChannel> unixChannel = factory->createChannel(path);
|
|
|
|
if (needToListen)
|
|
{
|
|
// Should acceptFailed callback be used somehow?
|
|
unixChannel->listen(bind(&FaceTable::add, &m_faceTable, _1),
|
|
UnixStreamChannel::ConnectFailedCallback());
|
|
}
|
|
|
|
m_factories.insert(std::make_pair("unix", factory));
|
|
}
|
|
#else
|
|
throw ConfigFile::Error("NFD was compiled without UNIX sockets support, cannot process \"unix\" section");
|
|
#endif // HAVE_UNIX_SOCKETS
|
|
|
|
}
|
|
|
|
void
|
|
FaceManager::processSectionTcp(const ConfigSection& configSection, bool isDryRun)
|
|
{
|
|
// ; the tcp section contains settings of TCP faces and channels
|
|
// tcp
|
|
// {
|
|
// listen yes ; set to 'no' to disable TCP listener, default 'yes'
|
|
// port 6363 ; TCP listener port number
|
|
// }
|
|
|
|
std::string port = "6363";
|
|
bool needToListen = true;
|
|
|
|
for (ConfigSection::const_iterator i = configSection.begin();
|
|
i != configSection.end();
|
|
++i)
|
|
{
|
|
if (i->first == "port")
|
|
{
|
|
port = i->second.get_value<std::string>();
|
|
try
|
|
{
|
|
uint16_t portNo = boost::lexical_cast<uint16_t>(port);
|
|
NFD_LOG_TRACE("TCP port set to " << portNo);
|
|
}
|
|
catch (const std::bad_cast& error)
|
|
{
|
|
throw ConfigFile::Error("Invalid value for option " +
|
|
i->first + "\" in \"udp\" section");
|
|
}
|
|
}
|
|
else if (i->first == "listen")
|
|
{
|
|
needToListen = parseYesNo(i, i->first, "tcp");
|
|
}
|
|
else
|
|
{
|
|
throw ConfigFile::Error("Unrecognized option \"" + i->first + "\" in \"tcp\" section");
|
|
}
|
|
}
|
|
|
|
if (!isDryRun)
|
|
{
|
|
shared_ptr<TcpFactory> factory = make_shared<TcpFactory>(boost::cref(port));
|
|
|
|
using namespace boost::asio::ip;
|
|
|
|
shared_ptr<TcpChannel> ipv4Channel = factory->createChannel("0.0.0.0", port);
|
|
shared_ptr<TcpChannel> ipv6Channel = factory->createChannel("::", port);
|
|
|
|
if (needToListen)
|
|
{
|
|
// Should acceptFailed callback be used somehow?
|
|
|
|
ipv4Channel->listen(bind(&FaceTable::add, &m_faceTable, _1),
|
|
TcpChannel::ConnectFailedCallback());
|
|
ipv6Channel->listen(bind(&FaceTable::add, &m_faceTable, _1),
|
|
TcpChannel::ConnectFailedCallback());
|
|
}
|
|
|
|
m_factories.insert(std::make_pair("tcp", factory));
|
|
m_factories.insert(std::make_pair("tcp4", factory));
|
|
m_factories.insert(std::make_pair("tcp6", factory));
|
|
}
|
|
}
|
|
|
|
void
|
|
FaceManager::processSectionUdp(const ConfigSection& configSection,
|
|
bool isDryRun,
|
|
const std::list<shared_ptr<NetworkInterfaceInfo> >& nicList)
|
|
{
|
|
// ; the udp section contains settings of UDP faces and channels
|
|
// udp
|
|
// {
|
|
// port 6363 ; UDP unicast port number
|
|
// idle_timeout 30 ; idle time (seconds) before closing a UDP unicast face
|
|
// keep_alive_interval 25; interval (seconds) between keep-alive refreshes
|
|
|
|
// ; NFD creates one UDP multicast face per NIC
|
|
// mcast yes ; set to 'no' to disable UDP multicast, default 'yes'
|
|
// mcast_port 56363 ; UDP multicast port number
|
|
// mcast_group 224.0.23.170 ; UDP multicast group (IPv4 only)
|
|
// }
|
|
|
|
std::string port = "6363";
|
|
size_t timeout = 30;
|
|
size_t keepAliveInterval = 25;
|
|
bool useMcast = true;
|
|
std::string mcastGroup = "224.0.23.170";
|
|
std::string mcastPort = "56363";
|
|
|
|
|
|
for (ConfigSection::const_iterator i = configSection.begin();
|
|
i != configSection.end();
|
|
++i)
|
|
{
|
|
if (i->first == "port")
|
|
{
|
|
port = i->second.get_value<std::string>();
|
|
try
|
|
{
|
|
uint16_t portNo = boost::lexical_cast<uint16_t>(port);
|
|
NFD_LOG_TRACE("UDP port set to " << portNo);
|
|
}
|
|
catch (const std::bad_cast& error)
|
|
{
|
|
throw ConfigFile::Error("Invalid value for option " +
|
|
i->first + "\" in \"udp\" section");
|
|
}
|
|
}
|
|
else if (i->first == "idle_timeout")
|
|
{
|
|
try
|
|
{
|
|
timeout = i->second.get_value<size_t>();
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
throw ConfigFile::Error("Invalid value for option \"" +
|
|
i->first + "\" in \"udp\" section");
|
|
}
|
|
}
|
|
else if (i->first == "keep_alive_interval")
|
|
{
|
|
try
|
|
{
|
|
keepAliveInterval = i->second.get_value<size_t>();
|
|
|
|
/// \todo Make use of keepAliveInterval
|
|
(void)(keepAliveInterval);
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
throw ConfigFile::Error("Invalid value for option \"" +
|
|
i->first + "\" in \"udp\" section");
|
|
}
|
|
}
|
|
else if (i->first == "mcast")
|
|
{
|
|
useMcast = parseYesNo(i, i->first, "udp");
|
|
}
|
|
else if (i->first == "mcast_port")
|
|
{
|
|
mcastPort = i->second.get_value<std::string>();
|
|
try
|
|
{
|
|
uint16_t portNo = boost::lexical_cast<uint16_t>(mcastPort);
|
|
NFD_LOG_TRACE("UDP multicast port set to " << portNo);
|
|
}
|
|
catch (const std::bad_cast& error)
|
|
{
|
|
throw ConfigFile::Error("Invalid value for option " +
|
|
i->first + "\" in \"udp\" section");
|
|
}
|
|
}
|
|
else if (i->first == "mcast_group")
|
|
{
|
|
using namespace boost::asio::ip;
|
|
mcastGroup = i->second.get_value<std::string>();
|
|
try
|
|
{
|
|
address mcastGroupTest = address::from_string(mcastGroup);
|
|
if (!mcastGroupTest.is_v4())
|
|
{
|
|
throw ConfigFile::Error("Invalid value for option \"" +
|
|
i->first + "\" in \"udp\" section");
|
|
}
|
|
}
|
|
catch(const std::runtime_error& e)
|
|
{
|
|
throw ConfigFile::Error("Invalid value for option \"" +
|
|
i->first + "\" in \"udp\" section");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw ConfigFile::Error("Unrecognized option \"" + i->first + "\" in \"udp\" section");
|
|
}
|
|
}
|
|
|
|
/// \todo what is keep alive interval used for?
|
|
|
|
if (!isDryRun)
|
|
{
|
|
shared_ptr<UdpFactory> factory = make_shared<UdpFactory>(boost::cref(port));
|
|
|
|
shared_ptr<UdpChannel> v4Channel =
|
|
factory->createChannel("0.0.0.0", port, time::seconds(timeout));
|
|
|
|
shared_ptr<UdpChannel> v6Channel =
|
|
factory->createChannel("::", port, time::seconds(timeout));
|
|
|
|
v4Channel->listen(bind(&FaceTable::add, &m_faceTable, _1),
|
|
UdpChannel::ConnectFailedCallback());
|
|
|
|
v6Channel->listen(bind(&FaceTable::add, &m_faceTable, _1),
|
|
UdpChannel::ConnectFailedCallback());
|
|
|
|
m_factories.insert(std::make_pair("udp", factory));
|
|
m_factories.insert(std::make_pair("udp4", factory));
|
|
m_factories.insert(std::make_pair("udp6", factory));
|
|
|
|
if (useMcast)
|
|
{
|
|
for (std::list<shared_ptr<NetworkInterfaceInfo> >::const_iterator i = nicList.begin();
|
|
i != nicList.end();
|
|
++i)
|
|
{
|
|
const shared_ptr<NetworkInterfaceInfo>& nic = *i;
|
|
if (nic->isUp() && nic->isMulticastCapable() && !nic->ipv4Addresses.empty())
|
|
{
|
|
shared_ptr<MulticastUdpFace> newFace =
|
|
factory->createMulticastFace(nic->ipv4Addresses[0].to_string(),
|
|
mcastGroup, mcastPort);
|
|
|
|
addCreatedFaceToForwarder(newFace);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
FaceManager::processSectionEther(const ConfigSection& configSection,
|
|
bool isDryRun,
|
|
const std::list<shared_ptr<NetworkInterfaceInfo> >& nicList)
|
|
{
|
|
// ; the ether section contains settings of Ethernet faces and channels
|
|
// ether
|
|
// {
|
|
// ; NFD creates one Ethernet multicast face per NIC
|
|
// mcast yes ; set to 'no' to disable Ethernet multicast, default 'yes'
|
|
// mcast_group 01:00:5E:00:17:AA ; Ethernet multicast group
|
|
// }
|
|
|
|
#if defined(HAVE_PCAP)
|
|
|
|
using ethernet::Address;
|
|
|
|
bool useMcast = true;
|
|
Address mcastGroup(ethernet::getDefaultMulticastAddress());
|
|
|
|
for (ConfigSection::const_iterator i = configSection.begin();
|
|
i != configSection.end();
|
|
++i)
|
|
{
|
|
if (i->first == "mcast")
|
|
{
|
|
useMcast = parseYesNo(i, i->first, "ether");
|
|
}
|
|
|
|
else if (i->first == "mcast_group")
|
|
{
|
|
mcastGroup = Address::fromString(i->second.get_value<std::string>());
|
|
if (mcastGroup.isNull())
|
|
{
|
|
throw ConfigFile::Error("Invalid value for option \"" +
|
|
i->first + "\" in \"ether\" section");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw ConfigFile::Error("Unrecognized option \"" + i->first + "\" in \"ether\" section");
|
|
}
|
|
}
|
|
|
|
if (!isDryRun)
|
|
{
|
|
shared_ptr<EthernetFactory> factory = make_shared<EthernetFactory>();
|
|
m_factories.insert(std::make_pair("ether", factory));
|
|
|
|
if (useMcast)
|
|
{
|
|
for (std::list<shared_ptr<NetworkInterfaceInfo> >::const_iterator i = nicList.begin();
|
|
i != nicList.end();
|
|
++i)
|
|
{
|
|
const shared_ptr<NetworkInterfaceInfo>& nic = *i;
|
|
if (nic->isUp() && nic->isMulticastCapable())
|
|
{
|
|
try
|
|
{
|
|
shared_ptr<EthernetFace> newFace =
|
|
factory->createMulticastFace(nic, mcastGroup);
|
|
|
|
addCreatedFaceToForwarder(newFace);
|
|
}
|
|
catch (const EthernetFactory::Error& factoryError)
|
|
{
|
|
NFD_LOG_ERROR(factoryError.what() << ", continuing");
|
|
}
|
|
catch (const EthernetFace::Error& faceError)
|
|
{
|
|
NFD_LOG_ERROR(faceError.what() << ", continuing");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
throw ConfigFile::Error("NFD was compiled without libpcap, cannot process \"ether\" section");
|
|
#endif // HAVE_PCAP
|
|
}
|
|
|
|
|
|
void
|
|
FaceManager::onFaceRequest(const Interest& request)
|
|
{
|
|
const Name& command = request.getName();
|
|
const size_t commandNComps = command.size();
|
|
const Name::Component& verb = command.get(COMMAND_PREFIX.size());
|
|
|
|
UnsignedVerbDispatchTable::const_iterator unsignedVerbProcessor = m_unsignedVerbDispatch.find(verb);
|
|
if (unsignedVerbProcessor != m_unsignedVerbDispatch.end())
|
|
{
|
|
NFD_LOG_DEBUG("command result: processing verb: " << verb);
|
|
(unsignedVerbProcessor->second)(this, boost::cref(request));
|
|
}
|
|
else if (COMMAND_UNSIGNED_NCOMPS <= commandNComps &&
|
|
commandNComps < COMMAND_SIGNED_NCOMPS)
|
|
{
|
|
NFD_LOG_DEBUG("command result: unsigned verb: " << command);
|
|
sendResponse(command, 401, "Signature required");
|
|
}
|
|
else if (commandNComps < COMMAND_SIGNED_NCOMPS ||
|
|
!COMMAND_PREFIX.isPrefixOf(command))
|
|
{
|
|
NFD_LOG_DEBUG("command result: malformed");
|
|
sendResponse(command, 400, "Malformed command");
|
|
}
|
|
else
|
|
{
|
|
validate(request,
|
|
bind(&FaceManager::onValidatedFaceRequest, this, _1),
|
|
bind(&ManagerBase::onCommandValidationFailed, this, _1, _2));
|
|
}
|
|
}
|
|
|
|
void
|
|
FaceManager::onValidatedFaceRequest(const shared_ptr<const Interest>& request)
|
|
{
|
|
const Name& command = request->getName();
|
|
const Name::Component& verb = command[COMMAND_PREFIX.size()];
|
|
const Name::Component& parameterComponent = command[COMMAND_PREFIX.size() + 1];
|
|
|
|
SignedVerbDispatchTable::const_iterator signedVerbProcessor = m_signedVerbDispatch.find(verb);
|
|
if (signedVerbProcessor != m_signedVerbDispatch.end())
|
|
{
|
|
ControlParameters parameters;
|
|
if (!extractParameters(parameterComponent, parameters))
|
|
{
|
|
sendResponse(command, 400, "Malformed command");
|
|
return;
|
|
}
|
|
|
|
NFD_LOG_DEBUG("command result: processing verb: " << verb);
|
|
(signedVerbProcessor->second)(this, *request, parameters);
|
|
}
|
|
else
|
|
{
|
|
NFD_LOG_DEBUG("command result: unsupported verb: " << verb);
|
|
sendResponse(command, 501, "Unsupported command");
|
|
}
|
|
|
|
}
|
|
|
|
void
|
|
FaceManager::addCreatedFaceToForwarder(const shared_ptr<Face>& newFace)
|
|
{
|
|
m_faceTable.add(newFace);
|
|
|
|
//NFD_LOG_DEBUG("Created face " << newFace->getRemoteUri() << " ID " << newFace->getId());
|
|
}
|
|
|
|
void
|
|
FaceManager::onCreated(const Name& requestName,
|
|
ControlParameters& parameters,
|
|
const shared_ptr<Face>& newFace)
|
|
{
|
|
addCreatedFaceToForwarder(newFace);
|
|
parameters.setFaceId(newFace->getId());
|
|
|
|
sendResponse(requestName, 200, "Success", parameters.wireEncode());
|
|
}
|
|
|
|
void
|
|
FaceManager::onConnectFailed(const Name& requestName, const std::string& reason)
|
|
{
|
|
NFD_LOG_DEBUG("Failed to create face: " << reason);
|
|
sendResponse(requestName, 408, reason);
|
|
}
|
|
|
|
void
|
|
FaceManager::createFace(const Interest& request,
|
|
ControlParameters& parameters)
|
|
{
|
|
const Name& requestName = request.getName();
|
|
ndn::nfd::FaceCreateCommand command;
|
|
|
|
if (!validateParameters(command, parameters))
|
|
{
|
|
sendResponse(requestName, 400, "Malformed command");
|
|
NFD_LOG_TRACE("invalid control parameters URI");
|
|
return;
|
|
}
|
|
|
|
FaceUri uri;
|
|
if (!uri.parse(parameters.getUri()))
|
|
{
|
|
sendResponse(requestName, 400, "Malformed command");
|
|
NFD_LOG_TRACE("failed to parse URI");
|
|
return;
|
|
}
|
|
|
|
FactoryMap::iterator factory = m_factories.find(uri.getScheme());
|
|
if (factory == m_factories.end())
|
|
{
|
|
sendResponse(requestName, 501, "Unsupported protocol");
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
factory->second->createFace(uri,
|
|
bind(&FaceManager::onCreated,
|
|
this, requestName, parameters, _1),
|
|
bind(&FaceManager::onConnectFailed,
|
|
this, requestName, _1));
|
|
}
|
|
catch (const std::runtime_error& error)
|
|
{
|
|
std::string errorMessage = "NFD error: ";
|
|
errorMessage += error.what();
|
|
|
|
NFD_LOG_ERROR(errorMessage);
|
|
sendResponse(requestName, 500, errorMessage);
|
|
}
|
|
catch (const std::logic_error& error)
|
|
{
|
|
std::string errorMessage = "NFD error: ";
|
|
errorMessage += error.what();
|
|
|
|
NFD_LOG_ERROR(errorMessage);
|
|
sendResponse(requestName, 500, errorMessage);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
FaceManager::destroyFace(const Interest& request,
|
|
ControlParameters& parameters)
|
|
{
|
|
const Name& requestName = request.getName();
|
|
ndn::nfd::FaceDestroyCommand command;
|
|
|
|
if (!validateParameters(command, parameters))
|
|
{
|
|
sendResponse(requestName, 400, "Malformed command");
|
|
return;
|
|
}
|
|
|
|
shared_ptr<Face> target = m_faceTable.get(parameters.getFaceId());
|
|
if (static_cast<bool>(target))
|
|
{
|
|
target->close();
|
|
}
|
|
|
|
sendResponse(requestName, 200, "Success", parameters.wireEncode());
|
|
|
|
}
|
|
|
|
void
|
|
FaceManager::onAddFace(shared_ptr<Face> face)
|
|
{
|
|
ndn::nfd::FaceEventNotification notification;
|
|
notification.setKind(ndn::nfd::FACE_EVENT_CREATED)
|
|
.setFaceId(face->getId())
|
|
.setRemoteUri(face->getRemoteUri().toString())
|
|
.setLocalUri(face->getLocalUri().toString())
|
|
.setFlags(getFaceFlags(*face));
|
|
|
|
m_notificationStream.postNotification(notification);
|
|
}
|
|
|
|
void
|
|
FaceManager::onRemoveFace(shared_ptr<Face> face)
|
|
{
|
|
ndn::nfd::FaceEventNotification notification;
|
|
notification.setKind(ndn::nfd::FACE_EVENT_DESTROYED)
|
|
.setFaceId(face->getId())
|
|
.setRemoteUri(face->getRemoteUri().toString())
|
|
.setLocalUri(face->getLocalUri().toString())
|
|
.setFlags(getFaceFlags(*face));
|
|
|
|
m_notificationStream.postNotification(notification);
|
|
}
|
|
|
|
|
|
bool
|
|
FaceManager::extractLocalControlParameters(const Interest& request,
|
|
ControlParameters& parameters,
|
|
ControlCommand& command,
|
|
shared_ptr<LocalFace>& outFace,
|
|
LocalControlFeature& outFeature)
|
|
{
|
|
if (!validateParameters(command, parameters))
|
|
{
|
|
sendResponse(request.getName(), 400, "Malformed command");
|
|
return false;
|
|
}
|
|
|
|
shared_ptr<Face> face = m_faceTable.get(request.getIncomingFaceId());
|
|
|
|
if (!static_cast<bool>(face))
|
|
{
|
|
NFD_LOG_DEBUG("command result: faceid " << request.getIncomingFaceId() << " not found");
|
|
sendResponse(request.getName(), 410, "Face not found");
|
|
return false;
|
|
}
|
|
else if (!face->isLocal())
|
|
{
|
|
NFD_LOG_DEBUG("command result: cannot enable local control on non-local faceid " <<
|
|
face->getId());
|
|
sendResponse(request.getName(), 412, "Face is non-local");
|
|
return false;
|
|
}
|
|
|
|
outFace = dynamic_pointer_cast<LocalFace>(face);
|
|
outFeature = static_cast<LocalControlFeature>(parameters.getLocalControlFeature());
|
|
|
|
return true;
|
|
}
|
|
|
|
void
|
|
FaceManager::enableLocalControl(const Interest& request,
|
|
ControlParameters& parameters)
|
|
{
|
|
ndn::nfd::FaceEnableLocalControlCommand command;
|
|
|
|
|
|
shared_ptr<LocalFace> face;
|
|
LocalControlFeature feature;
|
|
|
|
if (extractLocalControlParameters(request, parameters, command, face, feature))
|
|
{
|
|
face->setLocalControlHeaderFeature(feature, true);
|
|
sendResponse(request.getName(), 200, "Success", parameters.wireEncode());
|
|
}
|
|
}
|
|
|
|
void
|
|
FaceManager::disableLocalControl(const Interest& request,
|
|
ControlParameters& parameters)
|
|
{
|
|
ndn::nfd::FaceDisableLocalControlCommand command;
|
|
shared_ptr<LocalFace> face;
|
|
LocalControlFeature feature;
|
|
|
|
if (extractLocalControlParameters(request, parameters, command, face, feature))
|
|
{
|
|
face->setLocalControlHeaderFeature(feature, false);
|
|
sendResponse(request.getName(), 200, "Success", parameters.wireEncode());
|
|
}
|
|
}
|
|
|
|
void
|
|
FaceManager::listFaces(const Interest& request)
|
|
{
|
|
const Name& command = request.getName();
|
|
const size_t commandNComps = command.size();
|
|
|
|
if (commandNComps < LIST_COMMAND_NCOMPS ||
|
|
!LIST_COMMAND_PREFIX.isPrefixOf(command))
|
|
{
|
|
NFD_LOG_DEBUG("command result: malformed");
|
|
sendResponse(command, 400, "Malformed command");
|
|
return;
|
|
}
|
|
|
|
m_statusPublisher.publish();
|
|
}
|
|
|
|
} // namespace nfd
|