diff --git a/core/config-file.hpp b/core/config-file.hpp index 890a22cb..363c66df 100644 --- a/core/config-file.hpp +++ b/core/config-file.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** - * Copyright (c) 2014-2016, Regents of the University of California, + * Copyright (c) 2014-2017, Regents of the University of California, * Arizona Board of Regents, * Colorado State University, * University Pierre & Marie Curie, Sorbonne University, @@ -32,18 +32,26 @@ namespace nfd { +/** \brief a config file section + */ typedef boost::property_tree::ptree ConfigSection; -/// \brief callback for config file sections -typedef function ConfigSectionHandler; +/** \brief an optional config file section + */ +typedef boost::optional OptionalConfigSection; -/// \brief callback for config file sections without a subscribed handler -typedef function UnknownConfigSectionHandler; +/** \brief callback to process a config file section + */ +typedef function ConfigSectionHandler; + +/** \brief callback to process a config file section without a \p ConfigSectionHandler + */ +typedef function UnknownConfigSectionHandler; /** \brief configuration file parsing utility */ diff --git a/daemon/face/channel.hpp b/daemon/face/channel.hpp index 19beb7f8..1c0452dd 100644 --- a/daemon/face/channel.hpp +++ b/daemon/face/channel.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** - * Copyright (c) 2014-2016, Regents of the University of California, + * Copyright (c) 2014-2017, Regents of the University of California, * Arizona Board of Regents, * Colorado State University, * University Pierre & Marie Curie, Sorbonne University, @@ -43,7 +43,12 @@ typedef function& newFace)> FaceCreatedCallback; */ typedef function FaceCreationFailedCallback; - +/** \brief represent a channel that communicates on a local endpoint + * \sa FaceSystem + * + * A channel can listen on a local endpoint and initiate outgoing connection from a local endpoint. + * A channel creates Face objects and retains shared ownership of them. + */ class Channel : noncopyable { public: diff --git a/daemon/face/face-system.cpp b/daemon/face/face-system.cpp index 0d4a308a..8433a163 100644 --- a/daemon/face/face-system.cpp +++ b/daemon/face/face-system.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** - * Copyright (c) 2014-2016, Regents of the University of California, + * Copyright (c) 2014-2017, Regents of the University of California, * Arizona Board of Regents, * Colorado State University, * University Pierre & Marie Curie, Sorbonne University, @@ -25,8 +25,6 @@ #include "face-system.hpp" #include "core/logger.hpp" -#include "core/network-interface.hpp" -#include "core/network-interface-predicate.hpp" #include "fw/face-table.hpp" // ProtocolFactory includes, sorted alphabetically @@ -51,25 +49,34 @@ NFD_LOG_INIT("FaceSystem"); FaceSystem::FaceSystem(FaceTable& faceTable) : m_faceTable(faceTable) { + ///\todo #3904 make a registry, and construct instances from registry + m_factories["tcp"] = make_shared(); } std::set FaceSystem::listProtocolFactories() const { std::set factories; - for (const auto& p : m_factories) { + for (const auto& p : m_factoryByScheme) { factories.insert(p.second.get()); } return factories; } ProtocolFactory* -FaceSystem::getProtocolFactory(const std::string& scheme) +FaceSystem::getFactoryById(const std::string& id) { - auto found = m_factories.find(scheme); + auto found = m_factories.find(id); return found == m_factories.end() ? nullptr : found->second.get(); } +ProtocolFactory* +FaceSystem::getFactoryByScheme(const std::string& scheme) +{ + auto found = m_factoryByScheme.find(scheme); + return found == m_factoryByScheme.end() ? nullptr : found->second.get(); +} + void FaceSystem::setConfigFile(ConfigFile& configFile) { @@ -79,31 +86,61 @@ FaceSystem::setConfigFile(ConfigFile& configFile) void FaceSystem::processConfig(const ConfigSection& configSection, bool isDryRun, const std::string& filename) { + ConfigContext context; + context.isDryRun = isDryRun; + context.addFace = bind(&FaceTable::add, &m_faceTable, _1); + context.m_nicList = listNetworkInterfaces(); + + // process sections in protocol factories + for (const auto& pair : m_factories) { + const std::string& sectionName = pair.first; + shared_ptr factory = pair.second; + + std::set oldProvidedSchemes = factory->getProvidedSchemes(); + factory->processConfig(configSection.get_child_optional(sectionName), context); + + if (!isDryRun) { + for (const std::string& scheme : factory->getProvidedSchemes()) { + m_factoryByScheme[scheme] = factory; + oldProvidedSchemes.erase(scheme); + } + for (const std::string& scheme : oldProvidedSchemes) { + m_factoryByScheme.erase(scheme); + } + } + } + + // process other sections std::set seenSections; - auto nicList = listNetworkInterfaces(); + for (const auto& pair : configSection) { + const std::string& sectionName = pair.first; + const ConfigSection& subSection = pair.second; - for (const auto& item : configSection) { - if (!seenSections.insert(item.first).second) { - BOOST_THROW_EXCEPTION(ConfigFile::Error("Duplicate \"" + item.first + "\" section")); + if (!seenSections.insert(sectionName).second) { + BOOST_THROW_EXCEPTION(ConfigFile::Error("Duplicate section face_system." + sectionName)); } - if (item.first == "unix") { - processSectionUnix(item.second, isDryRun); + if (m_factories.count(sectionName) > 0) { + continue; } - else if (item.first == "tcp") { - processSectionTcp(item.second, isDryRun); + + ///\todo #3521 nicfaces + + ///\todo #3904 process these in protocol factory + if (sectionName == "unix") { + processSectionUnix(subSection, isDryRun); } - else if (item.first == "udp") { - processSectionUdp(item.second, isDryRun, nicList); + else if (sectionName == "udp") { + processSectionUdp(subSection, isDryRun, context.m_nicList); } - else if (item.first == "ether") { - processSectionEther(item.second, isDryRun, nicList); + else if (sectionName == "ether") { + processSectionEther(subSection, isDryRun, context.m_nicList); } - else if (item.first == "websocket") { - processSectionWebSocket(item.second, isDryRun); + else if (sectionName == "websocket") { + processSectionWebSocket(subSection, isDryRun); } else { - BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" + item.first + "\"")); + BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option face_system." + sectionName)); } } } @@ -131,12 +168,12 @@ FaceSystem::processSectionUnix(const ConfigSection& configSection, bool isDryRun } if (!isDryRun) { - if (m_factories.count("unix") > 0) { + if (m_factoryByScheme.count("unix") > 0) { return; } auto factory = make_shared(); - m_factories.emplace("unix", factory); + m_factoryByScheme.emplace("unix", factory); auto channel = factory->createChannel(path); channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr); @@ -147,77 +184,6 @@ FaceSystem::processSectionUnix(const ConfigSection& configSection, bool isDryRun #endif // HAVE_UNIX_SOCKETS } -void -FaceSystem::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 - // } - - uint16_t port = 6363; - bool needToListen = true; - bool enableV4 = true; - bool enableV6 = true; - - for (const auto& i : configSection) { - if (i.first == "port") { - port = ConfigFile::parseNumber(i, "tcp"); - NFD_LOG_TRACE("TCP port set to " << port); - } - else if (i.first == "listen") { - needToListen = ConfigFile::parseYesNo(i, "tcp"); - } - else if (i.first == "enable_v4") { - enableV4 = ConfigFile::parseYesNo(i, "tcp"); - } - else if (i.first == "enable_v6") { - enableV6 = ConfigFile::parseYesNo(i, "tcp"); - } - else { - BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" + - i.first + "\" in \"tcp\" section")); - } - } - - if (!enableV4 && !enableV6) { - BOOST_THROW_EXCEPTION(ConfigFile::Error("IPv4 and IPv6 TCP channels have been disabled." - " Remove \"tcp\" section to disable TCP channels or" - " re-enable at least one channel type.")); - } - - if (!isDryRun) { - if (m_factories.count("tcp") > 0) { - return; - } - - auto factory = make_shared(); - m_factories.emplace("tcp", factory); - - if (enableV4) { - tcp::Endpoint endpoint(boost::asio::ip::tcp::v4(), port); - shared_ptr v4Channel = factory->createChannel(endpoint); - if (needToListen) { - v4Channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr); - } - - m_factories.emplace("tcp4", factory); - } - - if (enableV6) { - tcp::Endpoint endpoint(boost::asio::ip::tcp::v6(), port); - shared_ptr v6Channel = factory->createChannel(endpoint); - if (needToListen) { - v6Channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr); - } - - m_factories.emplace("tcp6", factory); - } - } -} - void FaceSystem::processSectionUdp(const ConfigSection& configSection, bool isDryRun, const std::vector& nicList) @@ -310,13 +276,13 @@ FaceSystem::processSectionUdp(const ConfigSection& configSection, bool isDryRun, if (!isDryRun) { shared_ptr factory; bool isReload = false; - if (m_factories.count("udp") > 0) { + if (m_factoryByScheme.count("udp") > 0) { isReload = true; - factory = static_pointer_cast(m_factories["udp"]); + factory = static_pointer_cast(m_factoryByScheme["udp"]); } else { factory = make_shared(); - m_factories.emplace("udp", factory); + m_factoryByScheme.emplace("udp", factory); } if (!isReload && enableV4) { @@ -324,7 +290,7 @@ FaceSystem::processSectionUdp(const ConfigSection& configSection, bool isDryRun, shared_ptr v4Channel = factory->createChannel(endpoint, time::seconds(timeout)); v4Channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr); - m_factories.emplace("udp4", factory); + m_factoryByScheme.emplace("udp4", factory); } if (!isReload && enableV6) { @@ -332,7 +298,7 @@ FaceSystem::processSectionUdp(const ConfigSection& configSection, bool isDryRun, shared_ptr v6Channel = factory->createChannel(endpoint, time::seconds(timeout)); v6Channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr); - m_factories.emplace("udp6", factory); + m_factoryByScheme.emplace("udp6", factory); } std::set> multicastFacesToRemove; @@ -416,12 +382,12 @@ FaceSystem::processSectionEther(const ConfigSection& configSection, bool isDryRu if (!isDryRun) { shared_ptr factory; - if (m_factories.count("ether") > 0) { - factory = static_pointer_cast(m_factories["ether"]); + if (m_factoryByScheme.count("ether") > 0) { + factory = static_pointer_cast(m_factoryByScheme["ether"]); } else { factory = make_shared(); - m_factories.emplace("ether", factory); + m_factoryByScheme.emplace("ether", factory); } std::set> multicastFacesToRemove; @@ -505,12 +471,12 @@ FaceSystem::processSectionWebSocket(const ConfigSection& configSection, bool isD } if (!isDryRun) { - if (m_factories.count("websocket") > 0) { + if (m_factoryByScheme.count("websocket") > 0) { return; } auto factory = make_shared(); - m_factories.emplace("websocket", factory); + m_factoryByScheme.emplace("websocket", factory); shared_ptr channel; @@ -518,13 +484,13 @@ FaceSystem::processSectionWebSocket(const ConfigSection& configSection, bool isD websocket::Endpoint endpoint(boost::asio::ip::address_v6::any(), port); channel = factory->createChannel(endpoint); - m_factories.emplace("websocket46", factory); + m_factoryByScheme.emplace("websocket46", factory); } else if (enableV4) { websocket::Endpoint endpoint(boost::asio::ip::address_v4::any(), port); channel = factory->createChannel(endpoint); - m_factories.emplace("websocket4", factory); + m_factoryByScheme.emplace("websocket4", factory); } if (channel && needToListen) { diff --git a/daemon/face/face-system.hpp b/daemon/face/face-system.hpp index 22b2a140..48e3ea28 100644 --- a/daemon/face/face-system.hpp +++ b/daemon/face/face-system.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** - * Copyright (c) 2014-2016, Regents of the University of California, + * Copyright (c) 2014-2017, Regents of the University of California, * Arizona Board of Regents, * Colorado State University, * University Pierre & Marie Curie, Sorbonne University, @@ -26,20 +26,23 @@ #ifndef NFD_DAEMON_FACE_FACE_SYSTEM_HPP #define NFD_DAEMON_FACE_FACE_SYSTEM_HPP +#include "channel.hpp" #include "core/config-file.hpp" -#include "protocol-factory.hpp" +#include "core/network-interface.hpp" +#include "core/network-interface-predicate.hpp" namespace nfd { class FaceTable; -class NetworkInterfaceInfo; namespace face { +class ProtocolFactory; + /** \brief entry point of the face system * - * FaceSystem class is the entry point of NFD's face system. - * It owns ProtocolFactory objects that are created from face_system section of NFD configuration file. + * NFD's face system is organized as a FaceSystem-ProtocolFactory-Channel-Face hierarchy. + * FaceSystem class is the entry point of NFD's face system and owns ProtocolFactory objects. */ class FaceSystem : noncopyable { @@ -52,16 +55,44 @@ public: std::set listProtocolFactories() const; - /** \return ProtocolFactory for specified protocol scheme, or nullptr if not found + /** \return ProtocolFactory for the specified registered factory id or nullptr if not found */ ProtocolFactory* - getProtocolFactory(const std::string& scheme); + getFactoryById(const std::string& id); + + /** \return ProtocolFactory for the specified FaceUri scheme or nullptr if not found + */ + ProtocolFactory* + getFactoryByScheme(const std::string& scheme); /** \brief register handler for face_system section of NFD configuration file */ void setConfigFile(ConfigFile& configFile); + /** \brief context for processing a config section in ProtocolFactory + */ + class ConfigContext : noncopyable + { + public: + const std::vector& + listNics() const + { + ///\todo get NIC list from NetworkMonitor + return m_nicList; + } + + public: + bool isDryRun; + FaceCreatedCallback addFace; + ///\todo add NetworkMonitor + + private: + std::vector m_nicList; + + friend class FaceSystem; + }; + private: void processConfig(const ConfigSection& configSection, bool isDryRun, @@ -70,9 +101,6 @@ private: void processSectionUnix(const ConfigSection& configSection, bool isDryRun); - void - processSectionTcp(const ConfigSection& configSection, bool isDryRun); - void processSectionUdp(const ConfigSection& configSection, bool isDryRun, const std::vector& nicList); @@ -85,11 +113,18 @@ private: processSectionWebSocket(const ConfigSection& configSection, bool isDryRun); PUBLIC_WITH_TESTS_ELSE_PRIVATE: + /** \brief config section name => protocol factory + * + * \todo #3904 store unique_ptr here, and reference_wrapper + * in m_factoryByScheme + */ + std::map> m_factories; + /** \brief scheme => protocol factory * * The same protocol factory may be available under multiple schemes. */ - std::map> m_factories; + std::map> m_factoryByScheme; FaceTable& m_faceTable; }; diff --git a/daemon/face/protocol-factory.hpp b/daemon/face/protocol-factory.hpp index ee190638..328d46e9 100644 --- a/daemon/face/protocol-factory.hpp +++ b/daemon/face/protocol-factory.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** - * Copyright (c) 2014-2016, Regents of the University of California, + * Copyright (c) 2014-2017, Regents of the University of California, * Arizona Board of Regents, * Colorado State University, * University Pierre & Marie Curie, Sorbonne University, @@ -27,14 +27,22 @@ #define NFD_DAEMON_FACE_PROTOCOL_FACTORY_HPP #include "channel.hpp" +#include "face-system.hpp" #include +#include +#include namespace nfd { +namespace face { -/** - * \brief Abstract base class for all protocol factories +/** \brief provide support for an underlying protocol + * \sa FaceSystem + * + * A protocol factory provides support for an underlying protocol and owns Channel objects. + * It can process a subsection of face_system config section and create channels and multicast + * faces accordingly. */ -class ProtocolFactory +class ProtocolFactory : noncopyable { public: /** @@ -50,6 +58,29 @@ public: } }; + /** \brief process face_system subsection that corresponds to this ProtocolFactory type + * \param configSection the configuration section or boost::null to indicate it is omitted + * \param context provides access to data structures and contextual information + * \throw ConfigFile::Error invalid configuration + * + * This function updates \p providedSchemes + */ + virtual void + processConfig(OptionalConfigSection configSection, + FaceSystem::ConfigContext& context) + { + ///\todo implement in every subclass and make this pure-virtual + BOOST_THROW_EXCEPTION(Error("processConfig is not implemented")); + } + + /** \return FaceUri schemes accepted by this ProtocolFactory + */ + const std::set& + getProvidedSchemes() + { + return providedSchemes; + } + /** \brief Try to create Face using the supplied FaceUri * * This method should automatically choose channel, based on supplied FaceUri @@ -72,8 +103,27 @@ public: virtual std::vector> getChannels() const = 0; + +protected: + template + static std::vector> + getChannelsFromMap(const ChannelMap& channelMap) + { + std::vector> channels; + boost::copy(channelMap | boost::adaptors::map_values, std::back_inserter(channels)); + return channels; + } + +protected: + /** \brief FaceUri schemes provided by this ProtocolFactory + */ + std::set providedSchemes; }; +} // namespace face + +using face::ProtocolFactory; + } // namespace nfd #endif // NFD_DAEMON_FACE_PROTOCOL_FACTORY_HPP diff --git a/daemon/face/tcp-factory.cpp b/daemon/face/tcp-factory.cpp index 8ae23373..a3028b5f 100644 --- a/daemon/face/tcp-factory.cpp +++ b/daemon/face/tcp-factory.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** - * Copyright (c) 2014-2016, Regents of the University of California, + * Copyright (c) 2014-2017, Regents of the University of California, * Arizona Board of Regents, * Colorado State University, * University Pierre & Marie Curie, Sorbonne University, @@ -25,77 +25,93 @@ #include "tcp-factory.hpp" #include "core/logger.hpp" -#include "core/network-interface.hpp" namespace nfd { +namespace face { namespace ip = boost::asio::ip; NFD_LOG_INIT("TcpFactory"); void -TcpFactory::prohibitEndpoint(const tcp::Endpoint& endpoint) +TcpFactory::processConfig(OptionalConfigSection configSection, + FaceSystem::ConfigContext& context) { - if (endpoint.address().is_v4() && - endpoint.address() == ip::address_v4::any()) { - prohibitAllIpv4Endpoints(endpoint.port()); - } - else if (endpoint.address().is_v6() && - endpoint.address() == ip::address_v6::any()) { - prohibitAllIpv6Endpoints(endpoint.port()); + // tcp + // { + // listen yes + // port 6363 + // enable_v4 yes + // enable_v6 yes + // } + + if (!configSection) { + if (!context.isDryRun && !m_channels.empty()) { + NFD_LOG_WARN("Cannot disable tcp4 and tcp6 channels after initialization"); + } + return; } - NFD_LOG_TRACE("prohibiting TCP " << endpoint); - m_prohibitedEndpoints.insert(endpoint); -} + bool wantListen = true; + uint16_t port = 6363; + bool enableV4 = true; + bool enableV6 = true; -void -TcpFactory::prohibitAllIpv4Endpoints(uint16_t port) -{ - for (const NetworkInterfaceInfo& nic : listNetworkInterfaces()) { - for (const auto& addr : nic.ipv4Addresses) { - if (addr != ip::address_v4::any()) { - prohibitEndpoint(tcp::Endpoint(addr, port)); - } + for (const auto& pair : *configSection) { + const std::string& key = pair.first; + + if (key == "listen") { + wantListen = ConfigFile::parseYesNo(pair, "face_system.tcp"); + } + else if (key == "port") { + port = ConfigFile::parseNumber(pair, "face_system.tcp"); + } + else if (key == "enable_v4") { + enableV4 = ConfigFile::parseYesNo(pair, "face_system.tcp"); + } + else if (key == "enable_v6") { + enableV6 = ConfigFile::parseYesNo(pair, "face_system.tcp"); + } + else { + BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option face_system.tcp." + key)); } } -} -void -TcpFactory::prohibitAllIpv6Endpoints(uint16_t port) -{ - for (const NetworkInterfaceInfo& nic : listNetworkInterfaces()) { - for (const auto& addr : nic.ipv6Addresses) { - if (addr != ip::address_v6::any()) { - prohibitEndpoint(tcp::Endpoint(addr, port)); + if (!enableV4 && !enableV6) { + BOOST_THROW_EXCEPTION(ConfigFile::Error( + "IPv4 and IPv6 TCP channels have been disabled. Remove face_system.tcp section to disable " + "TCP channels or enable at least one channel type.")); + } + + if (!context.isDryRun) { + providedSchemes.insert("tcp"); + + if (enableV4) { + tcp::Endpoint endpoint(ip::tcp::v4(), port); + shared_ptr v4Channel = this->createChannel(endpoint); + if (wantListen && !v4Channel->isListening()) { + v4Channel->listen(context.addFace, nullptr); } + providedSchemes.insert("tcp4"); + } + else if (providedSchemes.count("tcp4") > 0) { + NFD_LOG_WARN("Cannot close tcp4 channel after its creation"); + } + + if (enableV6) { + tcp::Endpoint endpoint(ip::tcp::v6(), port); + shared_ptr v6Channel = this->createChannel(endpoint); + if (wantListen && !v6Channel->isListening()) { + v6Channel->listen(context.addFace, nullptr); + } + providedSchemes.insert("tcp6"); + } + else if (providedSchemes.count("tcp6") > 0) { + NFD_LOG_WARN("Cannot close tcp6 channel after its creation"); } } } -shared_ptr -TcpFactory::createChannel(const tcp::Endpoint& endpoint) -{ - auto channel = findChannel(endpoint); - if (channel) - return channel; - - channel = make_shared(endpoint); - m_channels[endpoint] = channel; - prohibitEndpoint(endpoint); - - NFD_LOG_DEBUG("Channel [" << endpoint << "] created"); - return channel; -} - -shared_ptr -TcpFactory::createChannel(const std::string& localIp, const std::string& localPort) -{ - tcp::Endpoint endpoint(ip::address::from_string(localIp), - boost::lexical_cast(localPort)); - return createChannel(endpoint); -} - void TcpFactory::createFace(const FaceUri& uri, ndn::nfd::FacePersistency persistency, @@ -146,16 +162,75 @@ TcpFactory::createFace(const FaceUri& uri, onFailure(504, "No channels available to connect"); } +void +TcpFactory::prohibitEndpoint(const tcp::Endpoint& endpoint) +{ + if (endpoint.address().is_v4() && + endpoint.address() == ip::address_v4::any()) { + prohibitAllIpv4Endpoints(endpoint.port()); + } + else if (endpoint.address().is_v6() && + endpoint.address() == ip::address_v6::any()) { + prohibitAllIpv6Endpoints(endpoint.port()); + } + + NFD_LOG_TRACE("prohibiting TCP " << endpoint); + m_prohibitedEndpoints.insert(endpoint); +} + +void +TcpFactory::prohibitAllIpv4Endpoints(uint16_t port) +{ + ///\todo prohibited endpoints need to react to dynamic NIC changes + for (const NetworkInterfaceInfo& nic : listNetworkInterfaces()) { + for (const auto& addr : nic.ipv4Addresses) { + if (addr != ip::address_v4::any()) { + prohibitEndpoint(tcp::Endpoint(addr, port)); + } + } + } +} + +void +TcpFactory::prohibitAllIpv6Endpoints(uint16_t port) +{ + ///\todo prohibited endpoints need to react to dynamic NIC changes + for (const NetworkInterfaceInfo& nic : listNetworkInterfaces()) { + for (const auto& addr : nic.ipv6Addresses) { + if (addr != ip::address_v6::any()) { + prohibitEndpoint(tcp::Endpoint(addr, port)); + } + } + } +} + +shared_ptr +TcpFactory::createChannel(const tcp::Endpoint& endpoint) +{ + auto channel = findChannel(endpoint); + if (channel) + return channel; + + channel = make_shared(endpoint); + m_channels[endpoint] = channel; + prohibitEndpoint(endpoint); + + NFD_LOG_DEBUG("Channel [" << endpoint << "] created"); + return channel; +} + +shared_ptr +TcpFactory::createChannel(const std::string& localIp, const std::string& localPort) +{ + tcp::Endpoint endpoint(ip::address::from_string(localIp), + boost::lexical_cast(localPort)); + return createChannel(endpoint); +} + std::vector> TcpFactory::getChannels() const { - std::vector> channels; - channels.reserve(m_channels.size()); - - for (const auto& i : m_channels) - channels.push_back(i.second); - - return channels; + return getChannelsFromMap(m_channels); } shared_ptr @@ -168,4 +243,5 @@ TcpFactory::findChannel(const tcp::Endpoint& localEndpoint) const return nullptr; } +} // namespace face } // namespace nfd diff --git a/daemon/face/tcp-factory.hpp b/daemon/face/tcp-factory.hpp index 2ed6ad1f..161c4901 100644 --- a/daemon/face/tcp-factory.hpp +++ b/daemon/face/tcp-factory.hpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** - * Copyright (c) 2014-2016, Regents of the University of California, + * Copyright (c) 2014-2017, Regents of the University of California, * Arizona Board of Regents, * Colorado State University, * University Pierre & Marie Curie, Sorbonne University, @@ -30,10 +30,26 @@ #include "tcp-channel.hpp" namespace nfd { +namespace face { +/** \brief protocol factory for TCP over IPv4 and IPv6 + */ class TcpFactory : public ProtocolFactory { public: + /** \brief process face_system.tcp config section + */ + void + processConfig(OptionalConfigSection configSection, + FaceSystem::ConfigContext& context) override; + + void + createFace(const FaceUri& uri, + ndn::nfd::FacePersistency persistency, + bool wantLocalFieldsEnabled, + const FaceCreatedCallback& onCreated, + const FaceCreationFailedCallback& onFailure) override; + /** * \brief Create TCP-based channel using tcp::Endpoint * @@ -63,15 +79,7 @@ public: shared_ptr createChannel(const std::string& localIp, const std::string& localPort); -public: // from ProtocolFactory - virtual void - createFace(const FaceUri& uri, - ndn::nfd::FacePersistency persistency, - bool wantLocalFieldsEnabled, - const FaceCreatedCallback& onCreated, - const FaceCreationFailedCallback& onFailure) override; - - virtual std::vector> + std::vector> getChannels() const override; PUBLIC_WITH_TESTS_ELSE_PRIVATE: @@ -101,6 +109,7 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE: std::set m_prohibitedEndpoints; }; +} // namespace face } // namespace nfd #endif // NFD_DAEMON_FACE_TCP_FACTORY_HPP diff --git a/daemon/mgmt/face-manager.cpp b/daemon/mgmt/face-manager.cpp index e8a79ebf..a2bfc3c9 100644 --- a/daemon/mgmt/face-manager.cpp +++ b/daemon/mgmt/face-manager.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** - * Copyright (c) 2014-2016, Regents of the University of California, + * Copyright (c) 2014-2017, Regents of the University of California, * Arizona Board of Regents, * Colorado State University, * University Pierre & Marie Curie, Sorbonne University, @@ -93,7 +93,7 @@ FaceManager::createFace(const Name& topPrefix, const Interest& interest, return; } - ProtocolFactory* factory = m_faceSystem.getProtocolFactory(uri.getScheme()); + ProtocolFactory* factory = m_faceSystem.getFactoryByScheme(uri.getScheme()); if (factory == nullptr) { NFD_LOG_TRACE("received create request for unsupported protocol"); done(ControlResponse(406, "Unsupported protocol")); diff --git a/daemon/mgmt/tables-config-section.cpp b/daemon/mgmt/tables-config-section.cpp index fcd09161..678b6e55 100644 --- a/daemon/mgmt/tables-config-section.cpp +++ b/daemon/mgmt/tables-config-section.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** - * Copyright (c) 2014-2016, Regents of the University of California, + * Copyright (c) 2014-2017, Regents of the University of California, * Arizona Board of Regents, * Colorado State University, * University Pierre & Marie Curie, Sorbonne University, @@ -60,16 +60,14 @@ TablesConfigSection::ensureConfigured() void TablesConfigSection::processConfig(const ConfigSection& section, bool isDryRun) { - typedef boost::optional OptionalNode; - size_t nCsMaxPackets = DEFAULT_CS_MAX_PACKETS; - OptionalNode csMaxPacketsNode = section.get_child_optional("cs_max_packets"); + OptionalConfigSection csMaxPacketsNode = section.get_child_optional("cs_max_packets"); if (csMaxPacketsNode) { nCsMaxPackets = ConfigFile::parseNumber(*csMaxPacketsNode, "cs_max_packets", "tables"); } unique_ptr csPolicy; - OptionalNode csPolicyNode = section.get_child_optional("cs_policy"); + OptionalConfigSection csPolicyNode = section.get_child_optional("cs_policy"); if (csPolicyNode) { std::string policyName = csPolicyNode->get_value(); csPolicy = cs::Policy::create(policyName); @@ -80,7 +78,7 @@ TablesConfigSection::processConfig(const ConfigSection& section, bool isDryRun) } unique_ptr unsolicitedDataPolicy; - OptionalNode unsolicitedDataPolicyNode = section.get_child_optional("cs_unsolicited_policy"); + OptionalConfigSection unsolicitedDataPolicyNode = section.get_child_optional("cs_unsolicited_policy"); if (unsolicitedDataPolicyNode) { std::string policyName = unsolicitedDataPolicyNode->get_value(); unsolicitedDataPolicy = fw::UnsolicitedDataPolicy::create(policyName); @@ -93,12 +91,12 @@ TablesConfigSection::processConfig(const ConfigSection& section, bool isDryRun) unsolicitedDataPolicy = make_unique(); } - OptionalNode strategyChoiceSection = section.get_child_optional("strategy_choice"); + OptionalConfigSection strategyChoiceSection = section.get_child_optional("strategy_choice"); if (strategyChoiceSection) { processStrategyChoiceSection(*strategyChoiceSection, isDryRun); } - OptionalNode networkRegionSection = section.get_child_optional("network_region"); + OptionalConfigSection networkRegionSection = section.get_child_optional("network_region"); if (networkRegionSection) { processNetworkRegionSection(*networkRegionSection, isDryRun); } diff --git a/tests/daemon/face/face-system-fixture.hpp b/tests/daemon/face/face-system-fixture.hpp new file mode 100644 index 00000000..6bdbb412 --- /dev/null +++ b/tests/daemon/face/face-system-fixture.hpp @@ -0,0 +1,95 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (c) 2014-2017, Regents of the University of California, + * Arizona Board of Regents, + * Colorado State University, + * University Pierre & Marie Curie, Sorbonne University, + * Washington University in St. Louis, + * Beijing Institute of Technology, + * The University of Memphis. + * + * This file is part of NFD (Named Data Networking Forwarding Daemon). + * See AUTHORS.md for complete list of NFD authors and contributors. + * + * NFD 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. + * + * NFD 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 + * NFD, e.g., in COPYING.md file. If not, see . + */ + +#ifndef NFD_TESTS_DAEMON_FACE_FACE_SYSTEM_FIXTURE_HPP +#define NFD_TESTS_DAEMON_FACE_FACE_SYSTEM_FIXTURE_HPP + +#include "face/face-system.hpp" +#include "fw/face-table.hpp" + +#include "tests/test-common.hpp" + +namespace nfd { +namespace face { +namespace tests { + +using namespace nfd::tests; + +class FaceSystemFixture : public BaseFixture +{ +public: + FaceSystemFixture() + : faceSystem(faceTable) + { + faceSystem.setConfigFile(configFile); + } + + void + parseConfig(const std::string& text, bool isDryRun) + { + configFile.parse(text, isDryRun, "test-config"); + } + + /** \brief get ProtocolFactory from FaceSystem + * \tparam F ProtocolFactory subclass + * + * If ProtocolFactory with \p scheme does not exist or has an incompatible type, + * this fails the test case. + */ + template + F& + getFactoryById(const std::string& id) + { + F* factory = dynamic_cast(faceSystem.getFactoryById(id)); + BOOST_REQUIRE(factory != nullptr); + return *factory; + } + + /** \brief get ProtocolFactory from FaceSystem + * \tparam F ProtocolFactory subclass + * + * If ProtocolFactory with \p scheme does not exist or has an incompatible type, + * this fails the test case. + */ + template + F& + getFactoryByScheme(const std::string& scheme) + { + F* factory = dynamic_cast(faceSystem.getFactoryByScheme(scheme)); + BOOST_REQUIRE(factory != nullptr); + return *factory; + } + +protected: + ConfigFile configFile; + FaceTable faceTable; + FaceSystem faceSystem; +}; + +} // namespace tests +} // namespace face +} // namespace nfd + +#endif // NFD_TESTS_DAEMON_FACE_FACE_SYSTEM_FIXTURE_HPP diff --git a/tests/daemon/face/face-system.t.cpp b/tests/daemon/face/face-system.t.cpp index bcae7250..36c904ff 100644 --- a/tests/daemon/face/face-system.t.cpp +++ b/tests/daemon/face/face-system.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** - * Copyright (c) 2014-2016, Regents of the University of California, + * Copyright (c) 2014-2017, Regents of the University of California, * Arizona Board of Regents, * Colorado State University, * University Pierre & Marie Curie, Sorbonne University, @@ -24,13 +24,12 @@ */ #include "face/face-system.hpp" -#include "fw/face-table.hpp" +#include "face-system-fixture.hpp" // ProtocolFactory includes, sorted alphabetically #ifdef HAVE_LIBPCAP #include "face/ethernet-factory.hpp" #endif // HAVE_LIBPCAP -#include "face/tcp-factory.hpp" #include "face/udp-factory.hpp" #ifdef HAVE_UNIX_SOCKETS #include "face/unix-stream-factory.hpp" @@ -47,29 +46,169 @@ namespace tests { using namespace nfd::tests; -class FaceSystemFixture : public BaseFixture +BOOST_AUTO_TEST_SUITE(Face) +BOOST_FIXTURE_TEST_SUITE(TestFaceSystem, FaceSystemFixture) + +BOOST_AUTO_TEST_SUITE(ProcessConfig) + +class DummyProtocolFactory : public ProtocolFactory { public: - FaceSystemFixture() - : faceSystem(faceTable) + void + processConfig(OptionalConfigSection configSection, + FaceSystem::ConfigContext& context) override { - faceSystem.setConfigFile(configFile); + processConfigHistory.push_back({configSection, context.isDryRun}); + if (!context.isDryRun) { + this->providedSchemes = this->newProvidedSchemes; + } } void - parseConfig(const std::string& text, bool isDryRun) + createFace(const FaceUri& uri, + ndn::nfd::FacePersistency persistency, + bool wantLocalFieldsEnabled, + const FaceCreatedCallback& onCreated, + const FaceCreationFailedCallback& onFailure) override { - configFile.parse(text, isDryRun, "test-config"); + BOOST_FAIL("createFace should not be called"); } -protected: - FaceTable faceTable; - FaceSystem faceSystem; - ConfigFile configFile; + std::vector> + getChannels() const override + { + BOOST_FAIL("getChannels should not be called"); + return {}; + } + +public: + struct ProcessConfigArgs + { + OptionalConfigSection configSection; + bool isDryRun; + }; + std::vector processConfigHistory; + + std::set newProvidedSchemes; }; -BOOST_AUTO_TEST_SUITE(Face) -BOOST_FIXTURE_TEST_SUITE(TestFaceSystem, FaceSystemFixture) +BOOST_AUTO_TEST_CASE(Normal) +{ + auto f1 = make_shared(); + auto f2 = make_shared(); + faceSystem.m_factories["f1"] = f1; + faceSystem.m_factories["f2"] = f2; + + const std::string CONFIG = R"CONFIG( + face_system + { + f1 + { + key v1 + } + f2 + { + key v2 + } + } + )CONFIG"; + + BOOST_CHECK_NO_THROW(parseConfig(CONFIG, true)); + BOOST_REQUIRE_EQUAL(f1->processConfigHistory.size(), 1); + BOOST_CHECK_EQUAL(f1->processConfigHistory.back().isDryRun, true); + BOOST_CHECK_EQUAL(f1->processConfigHistory.back().configSection->get("key"), "v1"); + BOOST_REQUIRE_EQUAL(f2->processConfigHistory.size(), 1); + BOOST_CHECK_EQUAL(f2->processConfigHistory.back().isDryRun, true); + BOOST_CHECK_EQUAL(f2->processConfigHistory.back().configSection->get("key"), "v2"); + + BOOST_CHECK_NO_THROW(parseConfig(CONFIG, false)); + BOOST_REQUIRE_EQUAL(f1->processConfigHistory.size(), 2); + BOOST_CHECK_EQUAL(f1->processConfigHistory.back().isDryRun, false); + BOOST_CHECK_EQUAL(f1->processConfigHistory.back().configSection->get("key"), "v1"); + BOOST_REQUIRE_EQUAL(f2->processConfigHistory.size(), 2); + BOOST_CHECK_EQUAL(f2->processConfigHistory.back().isDryRun, false); + BOOST_CHECK_EQUAL(f2->processConfigHistory.back().configSection->get("key"), "v2"); +} + +BOOST_AUTO_TEST_CASE(OmittedSection) +{ + auto f1 = make_shared(); + auto f2 = make_shared(); + faceSystem.m_factories["f1"] = f1; + faceSystem.m_factories["f2"] = f2; + + const std::string CONFIG = R"CONFIG( + face_system + { + f1 + { + } + } + )CONFIG"; + + BOOST_CHECK_NO_THROW(parseConfig(CONFIG, true)); + BOOST_REQUIRE_EQUAL(f1->processConfigHistory.size(), 1); + BOOST_CHECK_EQUAL(f1->processConfigHistory.back().isDryRun, true); + BOOST_REQUIRE_EQUAL(f2->processConfigHistory.size(), 1); + BOOST_CHECK_EQUAL(f2->processConfigHistory.back().isDryRun, true); + BOOST_CHECK(!f2->processConfigHistory.back().configSection); + + BOOST_CHECK_NO_THROW(parseConfig(CONFIG, false)); + BOOST_REQUIRE_EQUAL(f1->processConfigHistory.size(), 2); + BOOST_CHECK_EQUAL(f1->processConfigHistory.back().isDryRun, false); + BOOST_REQUIRE_EQUAL(f2->processConfigHistory.size(), 2); + BOOST_CHECK_EQUAL(f2->processConfigHistory.back().isDryRun, false); + BOOST_CHECK(!f2->processConfigHistory.back().configSection); +} + +BOOST_AUTO_TEST_CASE(UnknownSection) +{ + const std::string CONFIG = R"CONFIG( + face_system + { + f0 + { + } + } + )CONFIG"; + + BOOST_CHECK_THROW(parseConfig(CONFIG, true), ConfigFile::Error); + BOOST_CHECK_THROW(parseConfig(CONFIG, false), ConfigFile::Error); +} + +BOOST_AUTO_TEST_CASE(ChangeProvidedSchemes) +{ + auto f1 = make_shared(); + faceSystem.m_factories["f1"] = f1; + + const std::string CONFIG = R"CONFIG( + face_system + { + f1 + { + } + } + )CONFIG"; + + f1->newProvidedSchemes.insert("s1"); + f1->newProvidedSchemes.insert("s2"); + BOOST_CHECK_NO_THROW(parseConfig(CONFIG, false)); + BOOST_CHECK(faceSystem.getFactoryByScheme("f1") == nullptr); + BOOST_CHECK_EQUAL(faceSystem.getFactoryByScheme("s1"), f1.get()); + BOOST_CHECK_EQUAL(faceSystem.getFactoryByScheme("s2"), f1.get()); + + f1->newProvidedSchemes.erase("s2"); + f1->newProvidedSchemes.insert("s3"); + BOOST_CHECK_NO_THROW(parseConfig(CONFIG, false)); + BOOST_CHECK(faceSystem.getFactoryByScheme("f1") == nullptr); + BOOST_CHECK_EQUAL(faceSystem.getFactoryByScheme("s1"), f1.get()); + BOOST_CHECK(faceSystem.getFactoryByScheme("s2") == nullptr); + BOOST_CHECK_EQUAL(faceSystem.getFactoryByScheme("s3"), f1.get()); +} + +BOOST_AUTO_TEST_SUITE_END() // ProcessConfig + +///\todo #3904 move Config* to *Factory test suite #ifdef HAVE_UNIX_SOCKETS BOOST_AUTO_TEST_SUITE(ConfigUnix) @@ -89,9 +228,8 @@ BOOST_AUTO_TEST_CASE(Normal) BOOST_CHECK_NO_THROW(parseConfig(CONFIG, true)); BOOST_CHECK_NO_THROW(parseConfig(CONFIG, false)); - auto factory = dynamic_cast(faceSystem.getProtocolFactory("unix")); - BOOST_REQUIRE(factory != nullptr); - BOOST_CHECK_EQUAL(factory->getChannels().size(), 1); + auto& factory = this->getFactoryByScheme("unix"); + BOOST_CHECK_EQUAL(factory.getChannels().size(), 1); } BOOST_AUTO_TEST_CASE(UnknownOption) @@ -113,83 +251,6 @@ BOOST_AUTO_TEST_CASE(UnknownOption) BOOST_AUTO_TEST_SUITE_END() // ConfigUnix #endif // HAVE_UNIX_SOCKETS -BOOST_AUTO_TEST_SUITE(ConfigTcp) - -BOOST_AUTO_TEST_CASE(Normal) -{ - const std::string CONFIG = R"CONFIG( - face_system - { - tcp - { - listen yes - port 16363 - enable_v4 yes - enable_v6 yes - } - } - )CONFIG"; - - BOOST_CHECK_NO_THROW(parseConfig(CONFIG, true)); - BOOST_CHECK_NO_THROW(parseConfig(CONFIG, false)); - - auto factory = dynamic_cast(faceSystem.getProtocolFactory("tcp")); - BOOST_REQUIRE(factory != nullptr); - BOOST_CHECK_EQUAL(factory->getChannels().size(), 2); -} - -BOOST_AUTO_TEST_CASE(BadListen) -{ - const std::string CONFIG = R"CONFIG( - face_system - { - tcp - { - listen hello - } - } - )CONFIG"; - - BOOST_CHECK_THROW(parseConfig(CONFIG, true), ConfigFile::Error); - BOOST_CHECK_THROW(parseConfig(CONFIG, false), ConfigFile::Error); -} - -BOOST_AUTO_TEST_CASE(ChannelsDisabled) -{ - const std::string CONFIG = R"CONFIG( - face_system - { - tcp - { - port 6363 - enable_v4 no - enable_v6 no - } - } - )CONFIG"; - - BOOST_CHECK_THROW(parseConfig(CONFIG, true), ConfigFile::Error); - BOOST_CHECK_THROW(parseConfig(CONFIG, false), ConfigFile::Error); -} - -BOOST_AUTO_TEST_CASE(UnknownOption) -{ - const std::string CONFIG = R"CONFIG( - face_system - { - tcp - { - hello - } - } - )CONFIG"; - - BOOST_CHECK_THROW(parseConfig(CONFIG, true), ConfigFile::Error); - BOOST_CHECK_THROW(parseConfig(CONFIG, false), ConfigFile::Error); -} - -BOOST_AUTO_TEST_SUITE_END() // ConfigTcp - BOOST_AUTO_TEST_SUITE(ConfigUdp) BOOST_AUTO_TEST_CASE(Normal) @@ -216,9 +277,8 @@ BOOST_AUTO_TEST_CASE(Normal) BOOST_CHECK_NO_THROW(parseConfig(CONFIG, true)); BOOST_CHECK_NO_THROW(parseConfig(CONFIG, false)); - auto factory = dynamic_cast(faceSystem.getProtocolFactory("udp")); - BOOST_REQUIRE(factory != nullptr); - BOOST_CHECK_EQUAL(factory->getChannels().size(), 2); + auto& factory = this->getFactoryByScheme("udp"); + BOOST_CHECK_EQUAL(factory.getChannels().size(), 2); } BOOST_AUTO_TEST_CASE(BadIdleTimeout) @@ -367,10 +427,9 @@ BOOST_AUTO_TEST_CASE(MulticastReinit) BOOST_CHECK_NO_THROW(parseConfig(CONFIG_WITH_MCAST, false)); - auto factory = dynamic_cast(faceSystem.getProtocolFactory("udp")); - BOOST_REQUIRE(factory != nullptr); + auto& factory = this->getFactoryByScheme("udp"); - if (factory->getMulticastFaces().empty()) { + if (factory.getMulticastFaces().empty()) { BOOST_WARN_MESSAGE(false, "skipping assertions that require at least one UDP multicast face"); return; } @@ -387,7 +446,7 @@ BOOST_AUTO_TEST_CASE(MulticastReinit) BOOST_CHECK_NO_THROW(parseConfig(CONFIG_WITHOUT_MCAST, false)); BOOST_REQUIRE_NO_THROW(g_io.poll()); - BOOST_CHECK_EQUAL(factory->getMulticastFaces().size(), 0); + BOOST_CHECK_EQUAL(factory.getMulticastFaces().size(), 0); } BOOST_AUTO_TEST_SUITE_END() // ConfigUdp @@ -419,9 +478,8 @@ BOOST_AUTO_TEST_CASE(Normal) BOOST_CHECK_NO_THROW(parseConfig(CONFIG, true)); BOOST_CHECK_NO_THROW(parseConfig(CONFIG, false)); - auto factory = dynamic_cast(faceSystem.getProtocolFactory("ether")); - BOOST_REQUIRE(factory != nullptr); - BOOST_CHECK_EQUAL(factory->getChannels().size(), 0); + auto& factory = this->getFactoryByScheme("ether"); + BOOST_CHECK_EQUAL(factory.getChannels().size(), 0); } BOOST_AUTO_TEST_CASE(BadMcast) @@ -489,10 +547,9 @@ BOOST_AUTO_TEST_CASE(MulticastReinit) BOOST_CHECK_NO_THROW(parseConfig(CONFIG_WITH_MCAST, false)); - auto factory = dynamic_cast(faceSystem.getProtocolFactory("ether")); - BOOST_REQUIRE(factory != nullptr); + auto& factory = this->getFactoryByScheme("ether"); - if (factory->getMulticastFaces().empty()) { + if (factory.getMulticastFaces().empty()) { BOOST_WARN_MESSAGE(false, "skipping assertions that require at least one Ethernet multicast face"); return; } @@ -509,7 +566,7 @@ BOOST_AUTO_TEST_CASE(MulticastReinit) BOOST_CHECK_NO_THROW(parseConfig(CONFIG_WITHOUT_MCAST, false)); BOOST_REQUIRE_NO_THROW(g_io.poll()); - BOOST_CHECK_EQUAL(factory->getMulticastFaces().size(), 0); + BOOST_CHECK_EQUAL(factory.getMulticastFaces().size(), 0); } BOOST_AUTO_TEST_SUITE_END() // ConfigEther @@ -536,9 +593,8 @@ BOOST_AUTO_TEST_CASE(Normal) BOOST_CHECK_NO_THROW(parseConfig(CONFIG, true)); BOOST_CHECK_NO_THROW(parseConfig(CONFIG, false)); - auto factory = dynamic_cast(faceSystem.getProtocolFactory("websocket")); - BOOST_REQUIRE(factory != nullptr); - BOOST_CHECK_EQUAL(factory->getChannels().size(), 1); + auto& factory = this->getFactoryByScheme("websocket"); + BOOST_CHECK_EQUAL(factory.getChannels().size(), 1); } BOOST_AUTO_TEST_CASE(ChannelsDisabled) diff --git a/tests/daemon/face/tcp-factory.t.cpp b/tests/daemon/face/tcp-factory.t.cpp index a6170117..617c4cc4 100644 --- a/tests/daemon/face/tcp-factory.t.cpp +++ b/tests/daemon/face/tcp-factory.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** - * Copyright (c) 2014-2016, Regents of the University of California, + * Copyright (c) 2014-2017, Regents of the University of California, * Arizona Board of Regents, * Colorado State University, * University Pierre & Marie Curie, Sorbonne University, @@ -25,18 +25,112 @@ #include "face/tcp-factory.hpp" -#include "core/network-interface.hpp" #include "factory-test-common.hpp" +#include "face-system-fixture.hpp" #include "tests/limited-io.hpp" namespace nfd { +namespace face { namespace tests { +using namespace nfd::tests; + BOOST_AUTO_TEST_SUITE(Face) BOOST_FIXTURE_TEST_SUITE(TestTcpFactory, BaseFixture) using nfd::Face; +BOOST_FIXTURE_TEST_SUITE(ProcessConfig, FaceSystemFixture) + +BOOST_AUTO_TEST_CASE(Normal) +{ + const std::string CONFIG = R"CONFIG( + face_system + { + tcp + { + listen yes + port 16363 + enable_v4 yes + enable_v6 yes + } + } + )CONFIG"; + + BOOST_CHECK_NO_THROW(parseConfig(CONFIG, true)); + BOOST_CHECK_NO_THROW(parseConfig(CONFIG, false)); + + auto& factory = this->getFactoryById("tcp"); + BOOST_CHECK_EQUAL(factory.getChannels().size(), 2); +} + +BOOST_AUTO_TEST_CASE(Omitted) +{ + const std::string CONFIG = R"CONFIG( + face_system + { + } + )CONFIG"; + + BOOST_CHECK_NO_THROW(parseConfig(CONFIG, true)); + BOOST_CHECK_NO_THROW(parseConfig(CONFIG, false)); + + auto& factory = this->getFactoryById("tcp"); + BOOST_CHECK_EQUAL(factory.getChannels().size(), 0); +} + +BOOST_AUTO_TEST_CASE(BadListen) +{ + const std::string CONFIG = R"CONFIG( + face_system + { + tcp + { + listen hello + } + } + )CONFIG"; + + BOOST_CHECK_THROW(parseConfig(CONFIG, true), ConfigFile::Error); + BOOST_CHECK_THROW(parseConfig(CONFIG, false), ConfigFile::Error); +} + +BOOST_AUTO_TEST_CASE(ChannelsDisabled) +{ + const std::string CONFIG = R"CONFIG( + face_system + { + tcp + { + port 6363 + enable_v4 no + enable_v6 no + } + } + )CONFIG"; + + BOOST_CHECK_THROW(parseConfig(CONFIG, true), ConfigFile::Error); + BOOST_CHECK_THROW(parseConfig(CONFIG, false), ConfigFile::Error); +} + +BOOST_AUTO_TEST_CASE(UnknownOption) +{ + const std::string CONFIG = R"CONFIG( + face_system + { + tcp + { + hello + } + } + )CONFIG"; + + BOOST_CHECK_THROW(parseConfig(CONFIG, true), ConfigFile::Error); + BOOST_CHECK_THROW(parseConfig(CONFIG, false), ConfigFile::Error); +} + +BOOST_AUTO_TEST_SUITE_END() // ProcessConfig + BOOST_AUTO_TEST_CASE(ChannelMap) { TcpFactory factory; @@ -243,4 +337,5 @@ BOOST_AUTO_TEST_SUITE_END() // TestTcpFactory BOOST_AUTO_TEST_SUITE_END() // Face } // namespace tests +} // namespace face } // namespace nfd diff --git a/tests/daemon/face/udp-factory.t.cpp b/tests/daemon/face/udp-factory.t.cpp index 5e46d971..d6ef39c9 100644 --- a/tests/daemon/face/udp-factory.t.cpp +++ b/tests/daemon/face/udp-factory.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** - * Copyright (c) 2014-2016, Regents of the University of California, + * Copyright (c) 2014-2017, Regents of the University of California, * Arizona Board of Regents, * Colorado State University, * University Pierre & Marie Curie, Sorbonne University, @@ -146,7 +146,7 @@ BOOST_AUTO_TEST_CASE(CreateMulticastFace) BOOST_AUTO_TEST_CASE(FaceCreate) { - UdpFactory factory = UdpFactory(); + UdpFactory factory; createFace(factory, FaceUri("udp4://127.0.0.1:6363"), @@ -177,7 +177,7 @@ BOOST_AUTO_TEST_CASE(FaceCreate) BOOST_AUTO_TEST_CASE(UnsupportedFaceCreate) { - UdpFactory factory = UdpFactory(); + UdpFactory factory; factory.createChannel("127.0.0.1", "20070"); diff --git a/tests/daemon/mgmt/face-manager.t.cpp b/tests/daemon/mgmt/face-manager.t.cpp index 1dbeaf7d..913b5d67 100644 --- a/tests/daemon/mgmt/face-manager.t.cpp +++ b/tests/daemon/mgmt/face-manager.t.cpp @@ -1,6 +1,6 @@ /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** - * Copyright (c) 2014-2016, Regents of the University of California, + * Copyright (c) 2014-2017, Regents of the University of California, * Arizona Board of Regents, * Colorado State University, * University Pierre & Marie Curie, Sorbonne University, @@ -281,7 +281,7 @@ private: BOOST_AUTO_TEST_CASE(ChannelDataset) { auto factory = make_shared(); - m_manager.m_faceSystem.m_factories["test"] = factory; + m_manager.m_faceSystem.m_factoryByScheme["test"] = factory; std::map> addedChannels; size_t nEntries = 404;