tools: Automatically start ndn-autoconfig in nfd-start, if enabled in autoconfig.conf

Change-Id: I09d3fff87f00ce8684e6e304e8327f9d03ca18bf
Refs: #2716
diff --git a/autoconfig.conf.sample b/autoconfig.conf.sample
new file mode 100644
index 0000000..f9a1b3b
--- /dev/null
+++ b/autoconfig.conf.sample
@@ -0,0 +1,3 @@
+# Enable ndn-autoconfig to run in parallel with NFD.  Disabled by default
+# enabled=true
+enabled=false
diff --git a/docs/conf.py b/docs/conf.py
index f50b01b..8fbda38 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -242,9 +242,11 @@
 man_pages = [
     ('manpages/nfd', 'nfd', u'Named Data Networking Forwarding Daemon', None, 1),
     ('manpages/ndn-autoconfig-server', 'ndn-autoconfig-server',
-        u'NFD Auto-configuration Server', None, 1),
+        u'NDN auto-configuration server', None, 1),
     ('manpages/ndn-autoconfig', 'ndn-autoconfig',
-        u'NFD Auto-configuration Client', None, 1),
+        u'NDN auto-configuration client', None, 1),
+    ('manpages/ndn-autoconfig.conf', 'ndn-autoconfig.conf',
+        u'NDN auto-configuration client configuration file', None, 5),
     ('manpages/nfdc', 'nfdc',
         u'NFD utility to manipulate the forwarding table (FIB)', None, 1),
     ('manpages/ndn-tlv-peek', 'ndn-tlv-peek', u'NFD consumer', None, 1),
diff --git a/docs/manpages.rst b/docs/manpages.rst
index f945bf1..d3d97a5 100644
--- a/docs/manpages.rst
+++ b/docs/manpages.rst
@@ -10,6 +10,7 @@
    schema
    manpages/nfd-status-http-server
    manpages/ndn-autoconfig
+   manpages/ndn-autoconfig.conf
    manpages/ndn-autoconfig-server
    misc/local-prefix-discovery
    manpages/nfd-autoreg
diff --git a/docs/manpages/ndn-autoconfig.conf.rst b/docs/manpages/ndn-autoconfig.conf.rst
new file mode 100644
index 0000000..c3fa015
--- /dev/null
+++ b/docs/manpages/ndn-autoconfig.conf.rst
@@ -0,0 +1,22 @@
+.. _ndn-autoconfig.conf:
+
+autoconfig.conf
+===============
+
+Overview
+--------
+
+Configuration of NDN auto-configuration client daemon in INI format.  Comments in the
+configuration file must be prefixed with ``#``.
+
+Example of ``autoconfig.conf``:
+
+.. literalinclude:: ../../autoconfig.conf.sample
+
+Options
+-------
+
+``enabled``
+  (default: false) Enable or disable automatic NDN auto-configuration client daemon.
+
+  When enabled, NDN auto-configuration client daemon is automatically started by ``nfd-start``.
diff --git a/docs/manpages/ndn-autoconfig.rst b/docs/manpages/ndn-autoconfig.rst
index b436c61..f4fbc20 100644
--- a/docs/manpages/ndn-autoconfig.rst
+++ b/docs/manpages/ndn-autoconfig.rst
@@ -8,13 +8,33 @@
 
 ::
 
-    ndn-autoconfig
+    ndn-autoconfig [options]
 
 Description
 -----------
 
 Client tool to run :ref:`NDN hub discovery procedure`.
 
+Options
+-------
+
+``-h`` or ``--help``
+  Print usage information.
+
+``-d`` or ``--daemon``
+  Run ndn-autoconfig in daemon mode, detecting network change events and re-running
+  auto-discovery procedure.  In addition, the auto-discovery procedure is unconditionally
+  re-run every hour.
+
+  NOTE: if connection to NFD fails, the daemon will be terminated.
+
+``-c [FILE]`` or ``--config=[FILE]``
+  Use the specified configuration file. If `enabled = true` is not specified in the
+  configuration file, no actions will be performed.
+
+``-V`` or ``--version``
+  Print version information.
+
 .. _NDN hub discovery procedure:
 
 NDN hub discovery procedure
@@ -40,8 +60,8 @@
 
 After connecting to an NDN router, two prefixes will be automatically registered:
 
-- /ndn
-- /localhop/nfd --- this to inform RIB manager that there is connectivity to the hub
+- ``/ndn``
+- ``/localhop/nfd`` --- this to inform RIB manager that there is connectivity to the hub
 
 Stage 1: multicast discovery
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -131,4 +151,4 @@
 See also
 --------
 
-:ref:`ndn-autoconfig-server`
+:ref:`ndn-autoconfig-server`, :doc:`ndn-autoconfig.conf`
diff --git a/tools/ndn-autoconfig/main.cpp b/tools/ndn-autoconfig/main.cpp
index 2216535..1708bdb 100644
--- a/tools/ndn-autoconfig/main.cpp
+++ b/tools/ndn-autoconfig/main.cpp
@@ -34,6 +34,11 @@
 #include <ndn-cxx/util/scheduler-scoped-event-id.hpp>
 
 #include <boost/noncopyable.hpp>
+#include <boost/program_options/options_description.hpp>
+#include <boost/program_options/variables_map.hpp>
+#include <boost/program_options/parsers.hpp>
+
+namespace po = boost::program_options;
 
 namespace ndn {
 namespace tools {
@@ -113,21 +118,16 @@
     m_io.stop();
   }
 
+
   static void
-  usage(const char* programName)
+  usage(std::ostream& os,
+        const po::options_description& optionDescription,
+        const char* programName)
   {
-    std::cout << "Usage:\n"
-              << "  " << programName  << " [options]\n"
-              << "\n"
-              << "Options:\n"
-              << "  [-h]  - print usage and exit\n"
-              << "  [-d]  - run in daemon mode.  In daemon mode, " << programName << " will try \n"
-              << "          to detect network change events and re-run auto-discovery procedure.\n"
-              << "          In addition, the auto-discovery procedure is unconditionally re-run\n"
-              << "          every hour.\n"
-              << "          NOTE: if connection to NFD fails, the daemon will be terminated.\n"
-              << "  [-V]  - print version number and exit\n"
-              << std::endl;
+    os << "Usage:\n"
+       << "  " << programName << " [options]\n"
+       << "\n";
+    os << optionDescription;
   }
 
 private:
@@ -162,22 +162,65 @@
 int
 main(int argc, char** argv)
 {
-  int opt;
-  const char* programName = argv[0];
   bool isDaemonMode = false;
+  std::string configFile;
 
-  while ((opt = getopt(argc, argv, "dhV")) != -1) {
-    switch (opt) {
-    case 'd':
-      isDaemonMode = true;
-      break;
-    case 'h':
-      ndn::tools::NdnAutoconfig::usage(programName);
-      return 0;
-    case 'V':
-      std::cout << NFD_VERSION_BUILD_STRING << std::endl;
-      return 0;
+  po::options_description optionDescription("Options");
+  optionDescription.add_options()
+    ("help,h", "produce help message")
+    ("daemon,d", po::bool_switch(&isDaemonMode)->default_value(isDaemonMode),
+     "run in daemon mode, detecting network change events and re-running "
+     "auto-discovery procedure.  In addition, the auto-discovery procedure "
+     "is unconditionally re-run every hour.\n"
+     "NOTE: if connection to NFD fails, the daemon will be terminated.")
+    ("config,c", po::value<std::string>(&configFile), "configuration file. If `enabled = true` "
+     "is not specified, no actions will be performed.")
+    ("version,V", "show version and exit")
+    ;
+
+  po::variables_map options;
+  try {
+    po::store(po::parse_command_line(argc, argv, optionDescription), options);
+    po::notify(options);
+  }
+  catch (const std::exception& e) {
+    std::cerr << "ERROR: " << e.what() << "\n" << std::endl;
+    ndn::tools::NdnAutoconfig::usage(std::cerr, optionDescription, argv[0]);
+    return 1;
+  }
+
+  if (options.count("help")) {
+    ndn::tools::NdnAutoconfig::usage(std::cout, optionDescription, argv[0]);
+    return 0;
+  }
+
+  if (options.count("version")) {
+    std::cout << NFD_VERSION_BUILD_STRING << std::endl;
+    return 0;
+  }
+
+  // Enable (one-shot or daemon mode whenever config file is not specified)
+  bool isEnabled = true;
+
+  po::options_description configFileOptions;
+  configFileOptions.add_options()
+    ("enabled", po::value<bool>(&isEnabled))
+    ;
+
+  if (!configFile.empty()) {
+    isEnabled = false; // Disable by default if config file is specified
+    try {
+      po::store(po::parse_config_file<char>(configFile.c_str(), configFileOptions), options);
+      po::notify(options);
     }
+    catch (const std::exception& e) {
+      std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
+      return 1;
+    }
+  }
+
+  if (!isEnabled) {
+    return 0;
   }
 
   try {
diff --git a/tools/nfd-start.sh b/tools/nfd-start.sh
index 4c14e07..5283f19 100755
--- a/tools/nfd-start.sh
+++ b/tools/nfd-start.sh
@@ -51,7 +51,12 @@
 sudo @BINDIR@/nfd &
 
 if [ -f @SYSCONFDIR@/ndn/nfd-init.sh ]; then
-    sleep 2 # post-start is executed just after nfd process starts, but there is no guarantee
-    # that all initialization has been finished
-    . @SYSCONFDIR@/ndn/nfd-init.sh
+  sleep 2 # post-start is executed just after nfd process starts, but there is no guarantee
+  # that all initialization has been finished
+  . @SYSCONFDIR@/ndn/nfd-init.sh
+fi
+
+if [ -f @SYSCONFDIR@/ndn/autoconfig.conf ]; then
+  sleep 2 # post-start is executed just after nfd process starts, but there is no guarantee
+  @BINDIR@/ndn-autoconfig -d -c "@SYSCONFDIR@/ndn/autoconfig.conf" &
 fi
diff --git a/wscript b/wscript
index 2abe872..4b0ca05 100644
--- a/wscript
+++ b/wscript
@@ -240,6 +240,8 @@
             install_path="${MANDIR}/",
             VERSION=VERSION)
 
+    bld.install_files("${SYSCONFDIR}/ndn", "autoconfig.conf.sample")
+
 def docs(bld):
     from waflib import Options
     Options.commands = ['doxygen', 'sphinx'] + Options.commands