main: Enabling system signal handling and small reorganization

Change-Id: I568c5b57e787d44b9d6a758fd7e8cdf22222234e
Refs: 1380
diff --git a/daemon/main.cpp b/daemon/main.cpp
index 44880b2..0f73167 100644
--- a/daemon/main.cpp
+++ b/daemon/main.cpp
@@ -22,141 +22,169 @@
 
 struct ProgramOptions
 {
-  bool m_showUsage;
-  std::string m_config;
+  bool showUsage;
+  std::string config;
 };
 
-static ProgramOptions g_options;
-static Forwarder* g_forwarder;
-static FibManager* g_fibManager;
-static FaceManager* g_faceManager;
-static StrategyChoiceManager* g_strategyChoiceManager;
-static StatusServer* g_statusServer;
-static shared_ptr<InternalFace> g_internalFace;
-
-
-void
-usage(char* programName)
+class Nfd : noncopyable
 {
-  printf(
-    "%s --help\n\tshow this help and exit\n"
-    "%s "
-       "[--config /path/to/nfd.conf]\n"
-       "\trun forwarding daemon\n"
-       "\t--config <configuration file>]: path to configuration file\n"
-    "\n",
-    programName, programName
-  );
-}
+public:
+  explicit
+  Nfd(const std::string& configFile)
+    : m_internalFace(new InternalFace())
+    , m_fibManager(m_forwarder.getFib(),
+                   bind(&Forwarder::getFace, &m_forwarder, _1),
+                   m_internalFace)
+    , m_faceManager(m_forwarder.getFaceTable(), m_internalFace)
+    , m_strategyChoiceManager(m_forwarder.getStrategyChoice(), m_internalFace)
+    , m_statusServer(m_internalFace, m_forwarder)
+  {
+    ConfigFile config;
+    m_internalFace->getValidator().setConfigFile(config);
 
-bool
-parseCommandLine(int argc, char** argv)
-{
-  g_options.m_showUsage = false;
-  g_options.m_config = DEFAULT_CONFIG_FILE;
+    m_forwarder.addFace(m_internalFace);
 
-  while (true) {
-    int option_index = 0;
-    static ::option long_options[] = {
-      { "help"   , no_argument      , 0, 0 },
-      { "config" , required_argument, 0, 0 },
-      { 0        , 0                , 0, 0 }
-    };
-    int c = getopt_long_only(argc, argv, "", long_options, &option_index);
-    if (c == -1) break;
+    m_faceManager.setConfigFile(config);
 
-    switch (c) {
+    // parse config file
+    config.parse(configFile, true);
+    config.parse(configFile, false);
+
+    // add FIB entry for NFD Management Protocol
+    shared_ptr<fib::Entry> entry = m_forwarder.getFib().insert("/localhost/nfd").first;
+    entry->addNextHop(m_internalFace, 0);
+  }
+
+
+  static void
+  printUsage(std::ostream& os, const std::string& programName)
+  {
+    os << "Usage: \n"
+       << "  " << programName << " [options]\n"
+       << "\n"
+       << "Run NFD forwarding daemon\n"
+       << "\n"
+       << "Options:\n"
+       << "  [--help]   - print this help message\n"
+       << "  [--config /path/to/nfd.conf] - path to configuration file "
+       << "(default: " << DEFAULT_CONFIG_FILE << ")\n"
+      ;
+  }
+
+  static bool
+  parseCommandLine(int argc, char** argv, ProgramOptions& options)
+  {
+    options.showUsage = false;
+    options.config = DEFAULT_CONFIG_FILE;
+
+    while (true) {
+      int optionIndex = 0;
+      static ::option longOptions[] = {
+        { "help"   , no_argument      , 0, 0 },
+        { "config" , required_argument, 0, 0 },
+        { 0        , 0                , 0, 0 }
+      };
+      int c = getopt_long_only(argc, argv, "", longOptions, &optionIndex);
+      if (c == -1)
+        break;
+
+      switch (c) {
       case 0:
-        switch (option_index) {
-          case 0://help
-            g_options.m_showUsage = true;
-            break;
-          case 1://config
-            g_options.m_config = ::optarg;
-            break;
+        switch (optionIndex) {
+        case 0: // help
+          options.showUsage = true;
+          break;
+        case 1: // config
+          options.config = ::optarg;
+          break;
+        default:
+          return false;
         }
         break;
+      }
     }
+
+    return true;
   }
 
-  return true;
-}
+  void
+  terminate(const boost::system::error_code& error,
+            int signalNo,
+            boost::asio::signal_set& signalSet)
+  {
+    if (error)
+      return;
 
-void
-initializeMgmt()
-{
-  ConfigFile config;
-
-  g_internalFace = make_shared<InternalFace>();
-  g_internalFace->getValidator().setConfigFile(config);
-  g_forwarder->addFace(g_internalFace);
-
-  g_fibManager = new FibManager(g_forwarder->getFib(),
-                                bind(&Forwarder::getFace, g_forwarder, _1),
-                                g_internalFace);
-
-  g_faceManager = new FaceManager(g_forwarder->getFaceTable(), g_internalFace);
-  g_faceManager->setConfigFile(config);
-
-  g_strategyChoiceManager = new StrategyChoiceManager(g_forwarder->getStrategyChoice(),
-                                                      g_internalFace);
-
-  g_statusServer = new StatusServer(g_internalFace, *g_forwarder);
-
-  config.parse(g_options.m_config, true);
-  config.parse(g_options.m_config, false);
-
-  shared_ptr<fib::Entry> entry = g_forwarder->getFib().insert("/localhost/nfd").first;
-  entry->addNextHop(g_internalFace, 0);
-}
-
-int
-main(int argc, char** argv)
-{
-  bool isCommandLineValid = parseCommandLine(argc, argv);
-  if (!isCommandLineValid) {
-    usage(argv[0]);
-    return 1;
-  }
-  if (g_options.m_showUsage) {
-    usage(argv[0]);
-    return 0;
+    if (signalNo == SIGINT ||
+        signalNo == SIGTERM)
+      {
+        getGlobalIoService().stop();
+        std::cout << "Caught signal '" << strsignal(signalNo) << "', exiting..." << std::endl;
+      }
+    else
+      {
+        /// \todo May be try to reload config file (at least security section)
+        signalSet.async_wait(bind(&Nfd::terminate, this, _1, _2,
+                                  boost::ref(signalSet)));
+      }
   }
 
-  try {
-    g_forwarder = new Forwarder();
-    initializeMgmt();
+private:
+  Forwarder m_forwarder;
+  shared_ptr<InternalFace> m_internalFace;
 
-    /// \todo Add signal processing to gracefully terminate the app
-
-    getGlobalIoService().run();
-  // } catch(ConfigFile::Error& error) {
-  //   NFD_LOG_ERROR("Error: " << error.what());
-  //   NFD_LOG_ERROR("You should either specify --config option or copy sample configuration into "
-  //                 << DEFAULT_CONFIG_FILE);
-  }
-  catch (boost::filesystem::filesystem_error& e) {
-    if (e.code() == boost::system::errc::permission_denied) {
-      NFD_LOG_ERROR("Error: Permissions denied for " << e.path1());
-      NFD_LOG_ERROR(argv[0] << " should be run as superuser");
-    }
-    else {
-      NFD_LOG_ERROR("Error: " << e.what());
-    }
-  }
-  catch (std::exception& e) {
-    NFD_LOG_ERROR("Error: " << e.what());
-    return 1;
-  }
-
-  return 0;
-}
+  FibManager            m_fibManager;
+  FaceManager           m_faceManager;
+  StrategyChoiceManager m_strategyChoiceManager;
+  StatusServer          m_statusServer;
+};
 
 } // namespace nfd
 
 int
 main(int argc, char** argv)
 {
-  return nfd::main(argc, argv);
-}
+  using namespace nfd;
 
+  ProgramOptions options;
+  bool isCommandLineValid = Nfd::parseCommandLine(argc, argv, options);
+  if (!isCommandLineValid) {
+    Nfd::printUsage(std::cerr, argv[0]);
+    return 1;
+  }
+  if (options.showUsage) {
+    Nfd::printUsage(std::cout, argv[0]);
+    return 0;
+  }
+
+  try {
+    Nfd nfdInstance(options.config);
+
+    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,
+                              boost::ref(signalSet)));
+
+    getGlobalIoService().run();
+  }
+  catch (boost::filesystem::filesystem_error& e) {
+    if (e.code() == boost::system::errc::permission_denied) {
+      NFD_LOG_FATAL("Permissions denied for " << e.path1() << ". "
+                    << argv[0] << " should be run as superuser");
+    }
+    else {
+      NFD_LOG_FATAL(e.what());
+    }
+    return 2;
+  }
+  catch (std::exception& e) {
+    NFD_LOG_FATAL(e.what());
+    return 1;
+  }
+
+  return 0;
+}