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/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