mgmt: Reinitialize multicast faces and partially reload config file on HUP signal
The following elements from the config file are reloaded:
- effective user/group
- log levels
- multicast faces (enable/disable)
- security
Change-Id: I6ddf124702b30610dd0404d8fbaa9a9d800f02bf
Refs: #1584
diff --git a/core/face-uri.hpp b/core/face-uri.hpp
index 94474c7..9173d8a 100644
--- a/core/face-uri.hpp
+++ b/core/face-uri.hpp
@@ -123,6 +123,15 @@
std::string
toString() const;
+public: // EqualityComparable concept
+ /// equality operator
+ bool
+ operator==(const FaceUri& rhs) const;
+
+ /// inequality operator
+ bool
+ operator!=(const FaceUri& rhs) const;
+
private:
std::string m_scheme;
std::string m_host;
@@ -172,6 +181,22 @@
return os.str();
}
+inline bool
+FaceUri::operator==(const FaceUri& rhs) const
+{
+ return (m_scheme == rhs.m_scheme &&
+ m_host == rhs.m_host &&
+ m_isV6 == rhs.m_isV6 &&
+ m_port == rhs.m_port &&
+ m_path == rhs.m_path);
+}
+
+inline bool
+FaceUri::operator!=(const FaceUri& rhs) const
+{
+ return !(*this == rhs);
+}
+
inline std::ostream&
operator<<(std::ostream& os, const FaceUri& uri)
{
diff --git a/core/logger-factory.cpp b/core/logger-factory.cpp
index 61ca866..b0ef3cd 100644
--- a/core/logger-factory.cpp
+++ b/core/logger-factory.cpp
@@ -87,6 +87,25 @@
level + "\"");
}
+LogLevel
+LoggerFactory::extractLevel(const ConfigSection& item, const std::string& key)
+{
+ std::string levelString;
+ try
+ {
+ levelString = item.get_value<std::string>();
+ }
+ catch (const boost::property_tree::ptree_error& error)
+ {
+ }
+
+ if (levelString.empty())
+ {
+ throw LoggerFactory::Error("No logging level found for option \"" + key + "\"");
+ }
+
+ return parseLevel(levelString);
+}
void
LoggerFactory::onConfig(const ConfigSection& section,
@@ -107,33 +126,29 @@
// Forwarder WARN
// }
- // std::cerr << "loading logging configuration" << std::endl;
+ if (!isDryRun)
+ {
+ ConfigSection::const_assoc_iterator item = section.find("default_level");
+ if (item != section.not_found())
+ {
+ LogLevel level = extractLevel(item->second, "default_level");
+ setDefaultLevel(level);
+ }
+ else
+ {
+ setDefaultLevel(LOG_INFO);
+ }
+ }
+
for (ConfigSection::const_iterator item = section.begin();
item != section.end();
++item)
{
- std::string levelString;
- try
- {
- levelString = item->second.get_value<std::string>();
- }
- catch (const boost::property_tree::ptree_error& error)
- {
- }
-
- if (levelString.empty())
- {
- throw LoggerFactory::Error("No logging level found for option \"" + item->first + "\"");
- }
-
- LogLevel level = parseLevel(levelString);
+ LogLevel level = extractLevel(item->second, item->first);
if (item->first == "default_level")
{
- if (!isDryRun)
- {
- setDefaultLevel(level);
- }
+ // do nothing
}
else
{
diff --git a/core/logger-factory.hpp b/core/logger-factory.hpp
index b5aa31d..cbf7424 100644
--- a/core/logger-factory.hpp
+++ b/core/logger-factory.hpp
@@ -81,6 +81,9 @@
LogLevel
parseLevel(const std::string& level);
+ LogLevel
+ extractLevel(const ConfigSection& item, const std::string& key);
+
private:
typedef std::map<std::string, LogLevel> LevelMap;
diff --git a/daemon/face/ethernet-factory.cpp b/daemon/face/ethernet-factory.cpp
index 0408f03..a399a64 100644
--- a/daemon/face/ethernet-factory.cpp
+++ b/daemon/face/ethernet-factory.cpp
@@ -69,7 +69,8 @@
EthernetFactory::findMulticastFace(const std::string& interfaceName,
const ethernet::Address& address) const
{
- MulticastFacesMap::const_iterator i = m_multicastFaces.find(std::make_pair(interfaceName, address));
+ MulticastFaceMap::const_iterator i =
+ m_multicastFaces.find(std::make_pair(interfaceName, address));
if (i != m_multicastFaces.end())
return i->second;
else
diff --git a/daemon/face/ethernet-factory.hpp b/daemon/face/ethernet-factory.hpp
index 738164a..5630141 100644
--- a/daemon/face/ethernet-factory.hpp
+++ b/daemon/face/ethernet-factory.hpp
@@ -38,11 +38,19 @@
/**
* \brief Exception of EthernetFactory
*/
- struct Error : public ProtocolFactory::Error
+ class Error : public ProtocolFactory::Error
{
- Error(const std::string& what) : ProtocolFactory::Error(what) {}
+ public:
+ explicit
+ Error(const std::string& what)
+ : ProtocolFactory::Error(what)
+ {
+ }
};
+ typedef std::map< std::pair<std::string, ethernet::Address>,
+ shared_ptr<EthernetFace> > MulticastFaceMap;
+
// from ProtocolFactory
virtual void
createFace(const FaceUri& uri,
@@ -68,6 +76,12 @@
createMulticastFace(const shared_ptr<NetworkInterfaceInfo>& interface,
const ethernet::Address& address);
+ /**
+ * \brief Get map of configured multicast faces
+ */
+ const MulticastFaceMap&
+ getMulticastFaces() const;
+
private:
void
afterFaceFailed(const std::string& interfaceName,
@@ -86,11 +100,17 @@
const ethernet::Address& address) const;
private:
- typedef std::map< std::pair<std::string, ethernet::Address>,
- shared_ptr<EthernetFace> > MulticastFacesMap;
- MulticastFacesMap m_multicastFaces;
+ MulticastFaceMap m_multicastFaces;
};
+
+inline const EthernetFactory::MulticastFaceMap&
+EthernetFactory::getMulticastFaces() const
+{
+ return m_multicastFaces;
+}
+
+
} // namespace nfd
#endif // NFD_DAEMON_FACE_ETHERNET_FACTORY_HPP
diff --git a/daemon/face/udp-channel.hpp b/daemon/face/udp-channel.hpp
index 73403aa..4db6e43 100644
--- a/daemon/face/udp-channel.hpp
+++ b/daemon/face/udp-channel.hpp
@@ -74,6 +74,10 @@
* \param onFaceCreated Callback to notify successful creation of the face
* \param onAcceptFailed Callback to notify when channel fails
*
+ * Once a face is created, if it doesn't send/receive anything for
+ * a period of time equal to timeout, it will be destroyed
+ * \todo this functionality has to be implemented
+ *
* \throws UdpChannel::Error if called multiple times
*/
void
diff --git a/daemon/face/udp-factory.hpp b/daemon/face/udp-factory.hpp
index fa146ad..89cf37c 100644
--- a/daemon/face/udp-factory.hpp
+++ b/daemon/face/udp-factory.hpp
@@ -40,11 +40,18 @@
/**
* \brief Exception of UdpFactory
*/
- struct Error : public ProtocolFactory::Error
+ class Error : public ProtocolFactory::Error
{
- Error(const std::string& what) : ProtocolFactory::Error(what) {}
+ public:
+ explicit
+ Error(const std::string& what)
+ : ProtocolFactory::Error(what)
+ {
+ }
};
+ typedef std::map< udp::Endpoint, shared_ptr<MulticastUdpFace> > MulticastFaceMap;
+
explicit
UdpFactory(const std::string& defaultPort = "6363");
@@ -74,7 +81,7 @@
*/
shared_ptr<UdpChannel>
createChannel(const udp::Endpoint& localEndpoint,
- const time::seconds& timeout = time::seconds(600));
+ const time::seconds& timeout = time::seconds(600));
/**
* \brief Create UDP-based channel using specified host and port number
@@ -89,17 +96,13 @@
* Example: fe80::5e96:9dff:fe7d:9c8d%en1
* Otherwise, you can use ::
*
- * Once a face is created, if it doesn't send/receive anything for
- * a period of time equal to timeout, it will be destroyed
- * @todo this funcionality has to be implemented
- *
* \throws UdpChannel::Error if the bind on the socket fails
* \throws UdpFactory::Error
*/
shared_ptr<UdpChannel>
createChannel(const std::string& localHost,
- const std::string& localPort,
- const time::seconds& timeout = time::seconds(600));
+ const std::string& localPort,
+ const time::seconds& timeout = time::seconds(600));
/**
* \brief Create MulticastUdpFace using udp::Endpoint
@@ -147,13 +150,12 @@
const FaceCreatedCallback& onCreated,
const FaceConnectFailedCallback& onConnectFailed);
-protected:
- typedef std::map< udp::Endpoint, shared_ptr<MulticastUdpFace> > MulticastFaceMap;
/**
- * \brief Keeps tracking of the MulticastUdpFace created
+ * \brief Get map of configured multicast faces
*/
- MulticastFaceMap m_multicastFaces;
+ const MulticastFaceMap&
+ getMulticastFaces() const;
private:
@@ -197,14 +199,24 @@
const FaceCreatedCallback& onCreated,
const FaceConnectFailedCallback& onConnectFailed);
+private:
typedef std::map< udp::Endpoint, shared_ptr<UdpChannel> > ChannelMap;
+
ChannelMap m_channels;
+ MulticastFaceMap m_multicastFaces;
std::string m_defaultPort;
-
std::set<udp::Endpoint> m_prohibitedEndpoints;
};
+
+inline const UdpFactory::MulticastFaceMap&
+UdpFactory::getMulticastFaces() const
+{
+ return m_multicastFaces;
+}
+
+
} // namespace nfd
#endif // NFD_DAEMON_FACE_UDP_FACTORY_HPP
diff --git a/daemon/main.cpp b/daemon/main.cpp
index 697b65b..0e90bd0 100644
--- a/daemon/main.cpp
+++ b/daemon/main.cpp
@@ -53,28 +53,41 @@
class Nfd : noncopyable
{
public:
+ explicit
+ Nfd(const std::string& configFile)
+ : m_configFile(configFile)
+ , m_originalStreamBuf(0)
+ {
+ }
+
+ ~Nfd()
+ {
+ if (static_cast<bool>(m_originalStreamBuf)) {
+ std::clog.rdbuf(m_originalStreamBuf);
+ }
+ }
void
- initialize(const std::string& configFile)
+ initialize()
{
- initializeLogging(configFile);
+ initializeLogging();
m_forwarder = make_shared<Forwarder>();
- initializeManagement(configFile);
+ initializeManagement();
PrivilegeHelper::drop();
}
void
- initializeLogging(const std::string& configFile)
+ initializeLogging()
{
ConfigFile config(&ConfigFile::ignoreUnknownSection);
LoggerFactory::getInstance().setConfigFile(config);
- config.parse(configFile, true);
- config.parse(configFile, false);
+ config.parse(m_configFile, true);
+ config.parse(m_configFile, false);
}
class IgnoreRibAndLogSections
@@ -103,7 +116,7 @@
};
void
- initializeManagement(const std::string& configFile)
+ initializeManagement()
{
m_internalFace = make_shared<InternalFace>();
@@ -131,8 +144,8 @@
m_faceManager->setConfigFile(config);
// parse config file
- config.parse(configFile, true);
- config.parse(configFile, false);
+ config.parse(m_configFile, true);
+ config.parse(m_configFile, false);
// add FIB entry for NFD Management Protocol
shared_ptr<fib::Entry> entry = m_forwarder->getFib().insert("/localhost/nfd").first;
@@ -231,12 +244,46 @@
}
else
{
- /// \todo May be try to reload config file (at least security section)
signalSet.async_wait(bind(&Nfd::terminate, this, _1, _2, ref(signalSet)));
}
}
+ void
+ reload(const boost::system::error_code& error,
+ int signalNo,
+ boost::asio::signal_set& signalSet)
+ {
+ if (error)
+ return;
+
+ NFD_LOG_INFO("Caught signal '" << strsignal(signalNo));
+
+ ////////////////////////
+ // Reload config file //
+ ////////////////////////
+
+ // Logging
+ initializeLogging();
+ /// \todo Reopen log file
+
+ // Other stuff
+ ConfigFile config((IgnoreRibAndLogSections()));
+
+ general::setConfigFile(config);
+
+ m_internalFace->getValidator().setConfigFile(config);
+ m_faceManager->setConfigFile(config);
+
+ config.parse(m_configFile, false);
+
+ ////////////////////////
+
+ signalSet.async_wait(bind(&Nfd::reload, this, _1, _2, ref(signalSet)));
+ }
+
private:
+ std::string m_configFile;
+
shared_ptr<Forwarder> m_forwarder;
shared_ptr<InternalFace> m_internalFace;
@@ -244,6 +291,9 @@
shared_ptr<FaceManager> m_faceManager;
shared_ptr<StrategyChoiceManager> m_strategyChoiceManager;
shared_ptr<StatusServer> m_statusServer;
+
+ shared_ptr<std::ofstream> m_logFile;
+ std::basic_streambuf<char>* m_originalStreamBuf;
};
} // namespace nfd
@@ -275,10 +325,10 @@
return 0;
}
- Nfd nfdInstance;
+ Nfd nfdInstance(options.config);
try {
- nfdInstance.initialize(options.config);
+ nfdInstance.initialize();
}
catch (boost::filesystem::filesystem_error& e) {
if (e.code() == boost::system::errc::permission_denied) {
@@ -302,16 +352,16 @@
return 3;
}
+ boost::asio::signal_set terminationSignalSet(getGlobalIoService());
+ terminationSignalSet.add(SIGINT);
+ terminationSignalSet.add(SIGTERM);
+ terminationSignalSet.async_wait(bind(&Nfd::terminate, &nfdInstance, _1, _2,
+ ref(terminationSignalSet)));
-
-
- boost::asio::signal_set signalSet(getGlobalIoService());
- signalSet.add(SIGINT);
- signalSet.add(SIGTERM);
- signalSet.add(SIGHUP);
- signalSet.add(SIGUSR1);
- signalSet.add(SIGUSR2);
- signalSet.async_wait(bind(&Nfd::terminate, &nfdInstance, _1, _2, ref(signalSet)));
+ boost::asio::signal_set reloadSignalSet(getGlobalIoService());
+ reloadSignalSet.add(SIGHUP);
+ reloadSignalSet.async_wait(bind(&Nfd::reload, &nfdInstance, _1, _2,
+ ref(reloadSignalSet)));
try {
getGlobalIoService().run();
diff --git a/daemon/mgmt/command-validator.cpp b/daemon/mgmt/command-validator.cpp
index ea596b1..396cfe4 100644
--- a/daemon/mgmt/command-validator.cpp
+++ b/daemon/mgmt/command-validator.cpp
@@ -71,6 +71,8 @@
const ConfigSection EMPTY_SECTION;
+ m_validator.reset();
+
if (section.begin() == section.end())
{
throw ConfigFile::Error("No authorize sections found");
diff --git a/daemon/mgmt/face-manager.cpp b/daemon/mgmt/face-manager.cpp
index 3833dc4..e33bbe7 100644
--- a/daemon/mgmt/face-manager.cpp
+++ b/daemon/mgmt/face-manager.cpp
@@ -236,6 +236,19 @@
if (!isDryRun)
{
+ if (m_factories.count("unix") > 0)
+ {
+ return;
+ // shared_ptr<UnixStreamFactory> factory
+ // = static_pointer_cast<UnixStreamFactory>(m_factories["unix"]);
+ // shared_ptr<UnixStreamChannel> unixChannel = factory->findChannel(path);
+
+ // if (static_cast<bool>(unixChannel))
+ // {
+ // return;
+ // }
+ }
+
shared_ptr<UnixStreamFactory> factory = make_shared<UnixStreamFactory>();
shared_ptr<UnixStreamChannel> unixChannel = factory->createChannel(path);
@@ -249,7 +262,8 @@
m_factories.insert(std::make_pair("unix", factory));
}
#else
- throw ConfigFile::Error("NFD was compiled without UNIX sockets support, cannot process \"unix\" section");
+ throw ConfigFile::Error("NFD was compiled without UNIX sockets support, "
+ "cannot process \"unix\" section");
#endif // HAVE_UNIX_SOCKETS
}
@@ -314,6 +328,11 @@
if (!isDryRun)
{
+ if (m_factories.count("tcp") > 0)
+ {
+ return;
+ }
+
shared_ptr<TcpFactory> factory = ndn::make_shared<TcpFactory>(port);
m_factories.insert(std::make_pair("tcp", factory));
@@ -485,10 +504,18 @@
if (!isDryRun)
{
- shared_ptr<UdpFactory> factory = ndn::make_shared<UdpFactory>(port);
- m_factories.insert(std::make_pair("udp", factory));
+ shared_ptr<UdpFactory> factory;
+ bool isReload = false;
+ if (m_factories.count("udp") > 0) {
+ isReload = true;
+ factory = static_pointer_cast<UdpFactory>(m_factories["udp"]);
+ }
+ else {
+ factory = ndn::make_shared<UdpFactory>(port);
+ m_factories.insert(std::make_pair("udp", factory));
+ }
- if (enableV4)
+ if (!isReload && enableV4)
{
shared_ptr<UdpChannel> v4Channel =
factory->createChannel("0.0.0.0", port, time::seconds(timeout));
@@ -499,7 +526,7 @@
m_factories.insert(std::make_pair("udp4", factory));
}
- if (enableV6)
+ if (!isReload && enableV6)
{
shared_ptr<UdpChannel> v6Channel =
factory->createChannel("::", port, time::seconds(timeout));
@@ -534,6 +561,15 @@
}
#endif
+ std::list<shared_ptr<MulticastUdpFace> > multicastFacesToRemove;
+ for (UdpFactory::MulticastFaceMap::const_iterator i =
+ factory->getMulticastFaces().begin();
+ i != factory->getMulticastFaces().end();
+ ++i)
+ {
+ multicastFacesToRemove.push_back(i->second);
+ }
+
for (std::list<shared_ptr<NetworkInterfaceInfo> >::const_iterator i =
ipv4MulticastInterfaces.begin();
i != ipv4MulticastInterfaces.end();
@@ -547,6 +583,34 @@
isNicNameNecessary ? nic->name : "");
addCreatedFaceToForwarder(newFace);
+ multicastFacesToRemove.remove(newFace);
+ }
+
+ for (std::list<shared_ptr<MulticastUdpFace> >::iterator i =
+ multicastFacesToRemove.begin();
+ i != multicastFacesToRemove.end();
+ ++i)
+ {
+ (*i)->close();
+ }
+ }
+ else
+ {
+ std::list<shared_ptr<MulticastUdpFace> > multicastFacesToRemove;
+ for (UdpFactory::MulticastFaceMap::const_iterator i =
+ factory->getMulticastFaces().begin();
+ i != factory->getMulticastFaces().end();
+ ++i)
+ {
+ multicastFacesToRemove.push_back(i->second);
+ }
+
+ for (std::list<shared_ptr<MulticastUdpFace> >::iterator i =
+ multicastFacesToRemove.begin();
+ i != multicastFacesToRemove.end();
+ ++i)
+ {
+ (*i)->close();
}
}
}
@@ -598,11 +662,26 @@
if (!isDryRun)
{
- shared_ptr<EthernetFactory> factory = make_shared<EthernetFactory>();
- m_factories.insert(std::make_pair("ether", factory));
+ shared_ptr<EthernetFactory> factory;
+ if (m_factories.count("ether") > 0) {
+ factory = static_pointer_cast<EthernetFactory>(m_factories["ether"]);
+ }
+ else {
+ factory = ndn::make_shared<EthernetFactory>();
+ m_factories.insert(std::make_pair("ether", factory));
+ }
if (useMcast)
{
+ std::list<shared_ptr<EthernetFace> > multicastFacesToRemove;
+ for (EthernetFactory::MulticastFaceMap::const_iterator i =
+ factory->getMulticastFaces().begin();
+ i != factory->getMulticastFaces().end();
+ ++i)
+ {
+ multicastFacesToRemove.push_back(i->second);
+ }
+
for (std::list<shared_ptr<NetworkInterfaceInfo> >::const_iterator i = nicList.begin();
i != nicList.end();
++i)
@@ -616,6 +695,7 @@
factory->createMulticastFace(nic, mcastGroup);
addCreatedFaceToForwarder(newFace);
+ multicastFacesToRemove.remove(newFace);
}
catch (const EthernetFactory::Error& factoryError)
{
@@ -627,6 +707,33 @@
}
}
}
+
+ for (std::list<shared_ptr<EthernetFace> >::iterator i =
+ multicastFacesToRemove.begin();
+ i != multicastFacesToRemove.end();
+ ++i)
+ {
+ (*i)->close();
+ }
+ }
+ else
+ {
+ std::list<shared_ptr<EthernetFace> > multicastFacesToRemove;
+ for (EthernetFactory::MulticastFaceMap::const_iterator i =
+ factory->getMulticastFaces().begin();
+ i != factory->getMulticastFaces().end();
+ ++i)
+ {
+ multicastFacesToRemove.push_back(i->second);
+ }
+
+ for (std::list<shared_ptr<EthernetFace> >::iterator i =
+ multicastFacesToRemove.begin();
+ i != multicastFacesToRemove.end();
+ ++i)
+ {
+ (*i)->close();
+ }
}
}
#else
@@ -704,6 +811,11 @@
if (!isDryRun)
{
+ if (m_factories.count("websocket") > 0)
+ {
+ return;
+ }
+
shared_ptr<WebSocketFactory> factory = ndn::make_shared<WebSocketFactory>(port);
m_factories.insert(std::make_pair("websocket", factory));
uint16_t portNo = boost::lexical_cast<uint16_t>(port);
@@ -743,7 +855,8 @@
const size_t commandNComps = command.size();
const Name::Component& verb = command.get(COMMAND_PREFIX.size());
- UnsignedVerbDispatchTable::const_iterator unsignedVerbProcessor = m_unsignedVerbDispatch.find(verb);
+ UnsignedVerbDispatchTable::const_iterator unsignedVerbProcessor =
+ m_unsignedVerbDispatch.find(verb);
if (unsignedVerbProcessor != m_unsignedVerbDispatch.end())
{
NFD_LOG_DEBUG("command result: processing verb: " << verb);
@@ -1014,4 +1127,15 @@
m_statusPublisher.publish();
}
+shared_ptr<ProtocolFactory>
+FaceManager::findFactory(const std::string& protocol)
+{
+ FactoryMap::iterator factory = m_factories.find(protocol);
+ if (factory != m_factories.end())
+ return factory->second;
+ else
+ return shared_ptr<ProtocolFactory>();
+}
+
+
} // namespace nfd
diff --git a/daemon/mgmt/face-manager.hpp b/daemon/mgmt/face-manager.hpp
index 649ed4c..1040970 100644
--- a/daemon/mgmt/face-manager.hpp
+++ b/daemon/mgmt/face-manager.hpp
@@ -76,6 +76,9 @@
void
listFaces(const Interest& request);
+ shared_ptr<ProtocolFactory>
+ findFactory(const std::string& protocol);
+
PROTECTED_WITH_TESTS_ELSE_PRIVATE:
void
diff --git a/tests/core/logger.cpp b/tests/core/logger.cpp
index febadfc..9ae7fa4 100644
--- a/tests/core/logger.cpp
+++ b/tests/core/logger.cpp
@@ -493,6 +493,7 @@
const std::string LOG_CONFIG =
"log\n"
"{\n"
+ " default_level DEBUG\n"
" TestMadeUpModule INFO\n"
"}\n";
diff --git a/tests/daemon/mgmt/face-manager.cpp b/tests/daemon/mgmt/face-manager.cpp
index e43c142..6ad6197 100644
--- a/tests/daemon/mgmt/face-manager.cpp
+++ b/tests/daemon/mgmt/face-manager.cpp
@@ -30,6 +30,8 @@
#include "../face/dummy-face.hpp"
#include "fw/face-table.hpp"
#include "fw/forwarder.hpp"
+#include "face/udp-factory.hpp"
+#include "face/ethernet-factory.hpp"
#include "common.hpp"
#include "tests/test-common.hpp"
@@ -653,6 +655,37 @@
"Unrecognized option \"hello\" in \"udp\" section"));
}
+
+BOOST_AUTO_TEST_CASE(TestProcessSectionUdpMulticastReinit)
+{
+ const std::string CONFIG_WITH_MCAST =
+ "face_system\n"
+ "{\n"
+ " udp\n"
+ " {\n"
+ " mcast yes\n"
+ " }\n"
+ "}\n";
+ BOOST_CHECK_NO_THROW(parseConfig(CONFIG_WITH_MCAST, false));
+
+ shared_ptr<UdpFactory> factory = static_pointer_cast<UdpFactory>(getManager().findFactory("udp"));
+ BOOST_REQUIRE(static_cast<bool>(factory));
+
+ BOOST_CHECK_GT(factory->getMulticastFaces().size(), 0);
+
+ const std::string CONFIG_WITHOUT_MCAST =
+ "face_system\n"
+ "{\n"
+ " udp\n"
+ " {\n"
+ " mcast no\n"
+ " }\n"
+ "}\n";
+ BOOST_CHECK_NO_THROW(parseConfig(CONFIG_WITHOUT_MCAST, false));
+ BOOST_CHECK_EQUAL(factory->getMulticastFaces().size(), 0);
+}
+
+
#ifdef HAVE_LIBPCAP
BOOST_AUTO_TEST_CASE(TestProcessSectionEther)
@@ -734,6 +767,37 @@
"Unrecognized option \"hello\" in \"ether\" section"));
}
+BOOST_AUTO_TEST_CASE(TestProcessSectionEtherMulticastReinit)
+{
+ const std::string CONFIG_WITH_MCAST =
+ "face_system\n"
+ "{\n"
+ " ether\n"
+ " {\n"
+ " mcast yes\n"
+ " }\n"
+ "}\n";
+ BOOST_CHECK_NO_THROW(parseConfig(CONFIG_WITH_MCAST, false));
+
+ shared_ptr<EthernetFactory> factory =
+ static_pointer_cast<EthernetFactory>(getManager().findFactory("ether"));
+ BOOST_REQUIRE(static_cast<bool>(factory));
+
+ BOOST_CHECK_GT(factory->getMulticastFaces().size(), 0);
+
+ const std::string CONFIG_WITHOUT_MCAST =
+ "face_system\n"
+ "{\n"
+ " ether\n"
+ " {\n"
+ " mcast no\n"
+ " }\n"
+ "}\n";
+ BOOST_CHECK_NO_THROW(parseConfig(CONFIG_WITHOUT_MCAST, false));
+ BOOST_CHECK_EQUAL(factory->getMulticastFaces().size(), 0);
+}
+
+
#endif
BOOST_AUTO_TEST_CASE(TestFireInterestFilter)